diff options
author | Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca> | 2008-04-24 11:03:33 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-04-25 13:54:07 -0400 |
commit | b7b66baa8bc3f8e0cda6576e31e9bde09382565d (patch) | |
tree | 302533b2a5199d4958b87638b1bba5447c60152e /arch/x86/kernel/alternative.c | |
parent | 8b132ecbcfea8b1b556a832df7290379df79ad79 (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.c | 38 |
1 files changed, 18 insertions, 20 deletions
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 7ab3a9774763..60299f61843f 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 | } |