[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>
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
index e7a4d2c..8090a0a 100644
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -478,6 +478,8 @@
      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 @@
 	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 @@
 			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);
 		} 
 	}
 }