|
@@ -13,7 +13,9 @@
|
|
|
#include <asm/nmi.h>
|
|
|
#include <asm/vsyscall.h>
|
|
|
#include <asm/cacheflush.h>
|
|
|
+#include <asm/tlbflush.h>
|
|
|
#include <asm/io.h>
|
|
|
+#include <asm/fixmap.h>
|
|
|
|
|
|
#define MAX_PATCH_LEN (255-1)
|
|
|
|
|
@@ -505,15 +507,16 @@ void *text_poke_early(void *addr, const void *opcode, size_t len)
|
|
|
* It means the size must be writable atomically and the address must be aligned
|
|
|
* in a way that permits an atomic write. It also makes sure we fit on a single
|
|
|
* page.
|
|
|
+ *
|
|
|
+ * Note: Must be called under text_mutex.
|
|
|
*/
|
|
|
void *__kprobes text_poke(void *addr, const void *opcode, size_t len)
|
|
|
{
|
|
|
+ unsigned long flags;
|
|
|
char *vaddr;
|
|
|
- int nr_pages = 2;
|
|
|
struct page *pages[2];
|
|
|
int i;
|
|
|
|
|
|
- might_sleep();
|
|
|
if (!core_kernel_text((unsigned long)addr)) {
|
|
|
pages[0] = vmalloc_to_page(addr);
|
|
|
pages[1] = vmalloc_to_page(addr + PAGE_SIZE);
|
|
@@ -523,14 +526,17 @@ void *__kprobes text_poke(void *addr, const void *opcode, size_t len)
|
|
|
pages[1] = virt_to_page(addr + PAGE_SIZE);
|
|
|
}
|
|
|
BUG_ON(!pages[0]);
|
|
|
- if (!pages[1])
|
|
|
- nr_pages = 1;
|
|
|
- vaddr = vmap(pages, nr_pages, VM_MAP, PAGE_KERNEL);
|
|
|
- BUG_ON(!vaddr);
|
|
|
- local_irq_disable();
|
|
|
+ set_fixmap(FIX_TEXT_POKE0, page_to_phys(pages[0]));
|
|
|
+ if (pages[1])
|
|
|
+ set_fixmap(FIX_TEXT_POKE1, page_to_phys(pages[1]));
|
|
|
+ vaddr = (char *)fix_to_virt(FIX_TEXT_POKE0);
|
|
|
+ local_irq_save(flags);
|
|
|
memcpy(&vaddr[(unsigned long)addr & ~PAGE_MASK], opcode, len);
|
|
|
- local_irq_enable();
|
|
|
- vunmap(vaddr);
|
|
|
+ local_irq_restore(flags);
|
|
|
+ clear_fixmap(FIX_TEXT_POKE0);
|
|
|
+ if (pages[1])
|
|
|
+ clear_fixmap(FIX_TEXT_POKE1);
|
|
|
+ local_flush_tlb();
|
|
|
sync_core();
|
|
|
/* Could also do a CLFLUSH here to speed up CPU recovery; but
|
|
|
that causes hangs on some VIA CPUs. */
|