Commit 7f6c5b046978d68e69bdc73433ead41612a2a1c9

Authored by Andi Kleen
Committed by Linus Torvalds
1 parent 6e54d95f73

[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>

Showing 1 changed file with 10 additions and 2 deletions Side-by-side Diff

arch/x86_64/kernel/setup.c
... ... @@ -478,6 +478,8 @@
478 478 k8nops + 1 + 2 + 3 + 4 + 5 + 6 + 7,
479 479 };
480 480  
  481 +extern char __vsyscall_0;
  482 +
481 483 /* Replace instructions with better alternatives for this CPU type.
482 484  
483 485 This runs before SMP is initialized to avoid SMP problems with
484 486  
... ... @@ -489,11 +491,17 @@
489 491 struct alt_instr *a;
490 492 int diff, i, k;
491 493 for (a = start; (void *)a < end; a++) {
  494 + u8 *instr;
  495 +
492 496 if (!boot_cpu_has(a->cpuid))
493 497 continue;
494 498  
495 499 BUG_ON(a->replacementlen > a->instrlen);
496   - __inline_memcpy(a->instr, a->replacement, a->replacementlen);
  500 + instr = a->instr;
  501 + /* vsyscall code is not mapped yet. resolve it manually. */
  502 + if (instr >= (u8 *)VSYSCALL_START && instr < (u8*)VSYSCALL_END)
  503 + instr = __va(instr - (u8*)VSYSCALL_START + (u8*)__pa_symbol(&__vsyscall_0));
  504 + __inline_memcpy(instr, a->replacement, a->replacementlen);
497 505 diff = a->instrlen - a->replacementlen;
498 506  
499 507 /* Pad the rest with nops */
... ... @@ -501,7 +509,7 @@
501 509 k = diff;
502 510 if (k > ASM_NOP_MAX)
503 511 k = ASM_NOP_MAX;
504   - __inline_memcpy(a->instr + i, k8_nops[k], k);
  512 + __inline_memcpy(instr + i, k8_nops[k], k);
505 513 }
506 514 }
507 515 }