aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/alternative.c
diff options
context:
space:
mode:
authorMathieu Desnoyers <mathieu.desnoyers@polymtl.ca>2008-04-24 11:03:33 -0400
committerIngo Molnar <mingo@elte.hu>2008-04-25 13:54:07 -0400
commitb7b66baa8bc3f8e0cda6576e31e9bde09382565d (patch)
tree302533b2a5199d4958b87638b1bba5447c60152e /arch/x86/kernel/alternative.c
parent8b132ecbcfea8b1b556a832df7290379df79ad79 (diff)
x86: clean up text_poke()
Clean up the codepath, remove alignment restrictions and do sanity checking of the end result, to make sure we patched the right site. Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/alternative.c')
-rw-r--r--arch/x86/kernel/alternative.c38
1 files changed, 18 insertions, 20 deletions
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index 7ab3a977476..60299f61843 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -511,31 +511,29 @@ void *__kprobes text_poke(void *addr, const void *opcode, size_t len)
511 unsigned long flags; 511 unsigned long flags;
512 char *vaddr; 512 char *vaddr;
513 int nr_pages = 2; 513 int nr_pages = 2;
514 struct page *pages[2];
515 int i;
514 516
515 BUG_ON(len > sizeof(long)); 517 if (!core_kernel_text((unsigned long)addr)) {
516 BUG_ON((((long)addr + len - 1) & ~(sizeof(long) - 1)) 518 pages[0] = vmalloc_to_page(addr);
517 - ((long)addr & ~(sizeof(long) - 1))); 519 pages[1] = vmalloc_to_page(addr + PAGE_SIZE);
518 if (core_kernel_text((unsigned long)addr)) {
519 struct page *pages[2] = { virt_to_page(addr),
520 virt_to_page(addr + PAGE_SIZE) };
521 if (!pages[1])
522 nr_pages = 1;
523 vaddr = vmap(pages, nr_pages, VM_MAP, PAGE_KERNEL);
524 BUG_ON(!vaddr);
525 local_irq_save(flags);
526 memcpy(&vaddr[(unsigned long)addr & ~PAGE_MASK], opcode, len);
527 local_irq_restore(flags);
528 vunmap(vaddr);
529 } else { 520 } else {
530 /* 521 pages[0] = virt_to_page(addr);
531 * modules are in vmalloc'ed memory, always writable. 522 pages[1] = virt_to_page(addr + PAGE_SIZE);
532 */
533 local_irq_save(flags);
534 memcpy(addr, opcode, len);
535 local_irq_restore(flags);
536 } 523 }
524 BUG_ON(!pages[0]);
525 if (!pages[1])
526 nr_pages = 1;
527 vaddr = vmap(pages, nr_pages, VM_MAP, PAGE_KERNEL);
528 BUG_ON(!vaddr);
529 local_irq_save(flags);
530 memcpy(&vaddr[(unsigned long)addr & ~PAGE_MASK], opcode, len);
531 local_irq_restore(flags);
532 vunmap(vaddr);
537 sync_core(); 533 sync_core();
538 /* Could also do a CLFLUSH here to speed up CPU recovery; but 534 /* Could also do a CLFLUSH here to speed up CPU recovery; but
539 that causes hangs on some VIA CPUs. */ 535 that causes hangs on some VIA CPUs. */
536 for (i = 0; i < len; i++)
537 BUG_ON(((char *)addr)[i] != ((char *)opcode)[i]);
540 return addr; 538 return addr;
541} 539}