aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndi Kleen <ak@suse.de>2006-01-11 22:45:21 +0100
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-11 19:04:58 -0800
commit7f6c5b046978d68e69bdc73433ead41612a2a1c9 (patch)
tree60f74adc6166496fbd84143272ad3b88254f9b72
parent6e54d95f73bbc79171802a1983e0c3835676db88 (diff)
downloadlinux-7f6c5b046978d68e69bdc73433ead41612a2a1c9.tar.gz
[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>
-rw-r--r--arch/x86_64/kernel/setup.c12
1 files changed, 10 insertions, 2 deletions
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
index e7a4d2cd39686..8090a0a468827 100644
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -478,6 +478,8 @@ static unsigned char *k8_nops[ASM_NOP_MAX+1] = {
k8nops + 1 + 2 + 3 + 4 + 5 + 6 + 7,
};
+extern char __vsyscall_0;
+
/* Replace instructions with better alternatives for this CPU type.
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;
int diff, i, k;
for (a = start; (void *)a < end; a++) {
+ u8 *instr;
+
if (!boot_cpu_has(a->cpuid))
continue;
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;
/* Pad the rest with nops */
@@ -501,7 +509,7 @@ void apply_alternatives(void *start, void *end)
k = diff;
if (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);
}
}
}