]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - arch/x86/kernel/alternative.c
x86: Make alternative instruction pointers relative
[karo-tx-linux.git] / arch / x86 / kernel / alternative.c
index a81f2d52f869d842d9301d5f9aea5c23a74369a2..ddb207bb5f9128a0f823adb47820bef631828cfe 100644 (file)
@@ -263,6 +263,7 @@ void __init_or_module apply_alternatives(struct alt_instr *start,
                                         struct alt_instr *end)
 {
        struct alt_instr *a;
+       u8 *instr, *replacement;
        u8 insnbuf[MAX_PATCH_LEN];
 
        DPRINTK("%s: alt table %p -> %p\n", __func__, start, end);
@@ -276,25 +277,29 @@ void __init_or_module apply_alternatives(struct alt_instr *start,
         * order.
         */
        for (a = start; a < end; a++) {
-               u8 *instr = a->instr;
+               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 is a relative jump; fix the offset. */
+               if (*insnbuf == 0xe8 && a->replacementlen == 5)
+                   *(s32 *)(insnbuf + 1) += replacement - instr;
+
+               add_nops(insnbuf + a->replacementlen,
+                        a->instrlen - a->replacementlen);
+
 #ifdef CONFIG_X86_64
                /* vsyscall code is not mapped yet. resolve it manually. */
                if (instr >= (u8 *)VSYSCALL_START && instr < (u8*)VSYSCALL_END) {
                        instr = __va(instr - (u8*)VSYSCALL_START + (u8*)__pa_symbol(&__vsyscall_0));
-                       DPRINTK("%s: vsyscall fixup: %p => %p\n",
-                               __func__, a->instr, instr);
                }
 #endif
-               memcpy(insnbuf, a->replacement, a->replacementlen);
-               if (*insnbuf == 0xe8 && a->replacementlen == 5)
-                   *(s32 *)(insnbuf + 1) += a->replacement - a->instr;
-               add_nops(insnbuf + a->replacementlen,
-                        a->instrlen - a->replacementlen);
                text_poke_early(instr, insnbuf, a->instrlen);
        }
 }