[PATCH] x86_64: Support alternative() in vsyscalls
The real vsyscall .text addresses are not mapped when the alternative() replacement runs early, so use some black magic to access them using the direct mapping. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
6e54d95f73
commit
7f6c5b0469
1 changed files with 10 additions and 2 deletions
|
@ -478,6 +478,8 @@ static unsigned char *k8_nops[ASM_NOP_MAX+1] = {
|
||||||
k8nops + 1 + 2 + 3 + 4 + 5 + 6 + 7,
|
k8nops + 1 + 2 + 3 + 4 + 5 + 6 + 7,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern char __vsyscall_0;
|
||||||
|
|
||||||
/* Replace instructions with better alternatives for this CPU type.
|
/* Replace instructions with better alternatives for this CPU type.
|
||||||
|
|
||||||
This runs before SMP is initialized to avoid SMP problems with
|
This runs before SMP is initialized to avoid SMP problems with
|
||||||
|
@ -489,11 +491,17 @@ void apply_alternatives(void *start, void *end)
|
||||||
struct alt_instr *a;
|
struct alt_instr *a;
|
||||||
int diff, i, k;
|
int diff, i, k;
|
||||||
for (a = start; (void *)a < end; a++) {
|
for (a = start; (void *)a < end; a++) {
|
||||||
|
u8 *instr;
|
||||||
|
|
||||||
if (!boot_cpu_has(a->cpuid))
|
if (!boot_cpu_has(a->cpuid))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
BUG_ON(a->replacementlen > a->instrlen);
|
BUG_ON(a->replacementlen > a->instrlen);
|
||||||
__inline_memcpy(a->instr, a->replacement, a->replacementlen);
|
instr = a->instr;
|
||||||
|
/* 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));
|
||||||
|
__inline_memcpy(instr, a->replacement, a->replacementlen);
|
||||||
diff = a->instrlen - a->replacementlen;
|
diff = a->instrlen - a->replacementlen;
|
||||||
|
|
||||||
/* Pad the rest with nops */
|
/* Pad the rest with nops */
|
||||||
|
@ -501,7 +509,7 @@ void apply_alternatives(void *start, void *end)
|
||||||
k = diff;
|
k = diff;
|
||||||
if (k > ASM_NOP_MAX)
|
if (k > ASM_NOP_MAX)
|
||||||
k = ASM_NOP_MAX;
|
k = ASM_NOP_MAX;
|
||||||
__inline_memcpy(a->instr + i, k8_nops[k], k);
|
__inline_memcpy(instr + i, k8_nops[k], k);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue