/* * Replace instructions with better alternatives for this CPU type. * This runs before SMP is initialized to avoid SMP problems with * self modifying code. This implies that asymmetric systems where * APs have less capabilities than the boot processor are not handled. * Tough. Make sure you disable such features by hand. */ static void __init apply_alternatives(struct alt_instr *start, struct alt_instr *end) { struct alt_instr *a; u8 *instr, *replacement; u8 insnbuf[MAX_PATCH_LEN]; ASSERT(!local_irq_is_enabled()); printk(KERN_INFO "alt table %p -> %p\n", start, end); /* * The scan order should be from start to end. A later scanned * alternative code can overwrite a previous scanned alternative code. * Some kernel functions (e.g. memcpy, memset, etc) use this order to * patch code. * * So be careful if you want to change the scan order to any other * order. */ for ( a = start; a < end; a++ ) { instr = (u8 *)&a->instr_offset + a->instr_offset; replacement = (u8 *)&a->repl_offset + a->repl_offset; BUG_ON(a->replacementlen > a->instrlen); BUG_ON(a->instrlen > sizeof(insnbuf)); BUG_ON(a->cpuid >= NCAPINTS * 32); if ( !boot_cpu_has(a->cpuid) ) continue; memcpy(insnbuf, replacement, a->replacementlen); /* 0xe8/0xe9 are relative branches; fix the offset. */ if ( (*insnbuf & 0xfe) == 0xe8 && a->replacementlen == 5 ) *(s32 *)(insnbuf + 1) += replacement - instr; add_nops(insnbuf + a->replacementlen, a->instrlen - a->replacementlen); text_poke_early(instr, insnbuf, a->instrlen); } }
void arch_jump_label_text_poke_early(jump_label_t addr) { text_poke_early((void *)addr, ideal_nops[NOP_ATOMIC5], JUMP_LABEL_NOP_SIZE); }