staticunsignedchar *ftrace_call_replace(unsignedlong ip, unsignedlong addr)
{ /* Place the address in the memory table. */
__raw_writel(addr, ftrace_replaced_code);
/* *Modifyingcodemusttakeextracare.OnanSMPmachine,if *thecodebeingmodifiedisalsobeingexecutedonanotherCPU *thatCPUwillhaveundefinedresultsandpossiblytakeaGPF. *Weusekstop_machinetostopotherCPUSfromexecutingcode. *ButthisdoesnotstopNMIsfromhappening.Westillneed *toprotectagainstthat.Weseparateoutthemodificationof *thecodetotakecareofthis. * *Twobuffersareadded:AnIPbufferanda"code"buffer. * *1)PuttheinstructionpointerintotheIPbuffer *andthenewcodeintothe"code"buffer. *2)WaitforanyrunningNMIstofinishandsetaflagthatsays *wearemodifyingcode,itisdoneinanatomicoperation. *3)Writethecode *4)cleartheflag. *5)WaitforanyrunningNMIstofinish. * *IfanNMIisexecuted,thefirstthingitdoesistocall *"ftrace_nmi_enter".Thiswillcheckiftheflagissettowrite *andifitis,itwillwritewhatisintheIPand"code"buffers. * *Thetrickis,itdoesnotmatterifeveryoneiswritingthesame *contenttothecodelocation.Also,ifaCPUisexecutingcode *itisOKtowritetothatcodelocationifthecontentsbeingwritten *arethesameaswhatexists.
*/ #define MOD_CODE_WRITE_FLAG (1 << 31) /* set when NMI should do the write */ static atomic_t nmi_running = ATOMIC_INIT(0); staticint mod_code_status; /* holds return value of text write */ staticvoid *mod_code_ip; /* holds the IP to write to */ staticvoid *mod_code_newcode; /* holds the text to write to the IP */
staticvoid clear_mod_flag(void)
{ int old = atomic_read(&nmi_running);
/* if we fail, then kill any new writers */ if (mod_code_status)
clear_mod_flag();
}
void arch_ftrace_nmi_enter(void)
{ if (atomic_inc_return(&nmi_running) & MOD_CODE_WRITE_FLAG) {
smp_rmb();
ftrace_mod_code();
} /* Must have previous changes seen before executions */
smp_mb();
}
void arch_ftrace_nmi_exit(void)
{ /* Finish all executions before clearing nmi_running */
smp_mb();
atomic_dec(&nmi_running);
}
staticvoid wait_for_nmi_and_set_mod_flag(void)
{ if (!atomic_cmpxchg(&nmi_running, 0, MOD_CODE_WRITE_FLAG)) return;
do {
cpu_relax();
} while (atomic_cmpxchg(&nmi_running, 0, MOD_CODE_WRITE_FLAG));
}
staticvoid wait_for_nmi(void)
{ if (!atomic_read(&nmi_running)) return;
do {
cpu_relax();
} while (atomic_read(&nmi_running));
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.