Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 78ff7fae authored by Masami Hiramatsu's avatar Masami Hiramatsu Committed by Ingo Molnar
Browse files

x86: implement atomic text_poke() via fixmap



Use fixmaps instead of vmap/vunmap in text_poke() for avoiding
page allocation and delayed unmapping.

At the result of above change, text_poke() becomes atomic and can be called
from stop_machine() etc.

Signed-off-by: default avatarMasami Hiramatsu <mhiramat@redhat.com>
Acked-by: default avatarMathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
LKML-Reference: <49B14352.2040705@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 3945dab4
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -111,6 +111,8 @@ enum fixed_addresses {
#ifdef CONFIG_PARAVIRT
#ifdef CONFIG_PARAVIRT
	FIX_PARAVIRT_BOOTMAP,
	FIX_PARAVIRT_BOOTMAP,
#endif
#endif
	FIX_TEXT_POKE0,	/* reserve 2 pages for text_poke() */
	FIX_TEXT_POKE1,
	__end_of_permanent_fixed_addresses,
	__end_of_permanent_fixed_addresses,
#ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT
#ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT
	FIX_OHCI1394_BASE,
	FIX_OHCI1394_BASE,
+15 −9
Original line number Original line Diff line number Diff line
@@ -13,7 +13,9 @@
#include <asm/nmi.h>
#include <asm/nmi.h>
#include <asm/vsyscall.h>
#include <asm/vsyscall.h>
#include <asm/cacheflush.h>
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
#include <asm/io.h>
#include <asm/io.h>
#include <asm/fixmap.h>


#define MAX_PATCH_LEN (255-1)
#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
 * 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
 * in a way that permits an atomic write. It also makes sure we fit on a single
 * page.
 * page.
 *
 * Note: Must be called under text_mutex.
 */
 */
void *__kprobes text_poke(void *addr, const void *opcode, size_t len)
void *__kprobes text_poke(void *addr, const void *opcode, size_t len)
{
{
	unsigned long flags;
	char *vaddr;
	char *vaddr;
	int nr_pages = 2;
	struct page *pages[2];
	struct page *pages[2];
	int i;
	int i;


	might_sleep();
	if (!core_kernel_text((unsigned long)addr)) {
	if (!core_kernel_text((unsigned long)addr)) {
		pages[0] = vmalloc_to_page(addr);
		pages[0] = vmalloc_to_page(addr);
		pages[1] = vmalloc_to_page(addr + PAGE_SIZE);
		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);
		pages[1] = virt_to_page(addr + PAGE_SIZE);
	}
	}
	BUG_ON(!pages[0]);
	BUG_ON(!pages[0]);
	if (!pages[1])
	set_fixmap(FIX_TEXT_POKE0, page_to_phys(pages[0]));
		nr_pages = 1;
	if (pages[1])
	vaddr = vmap(pages, nr_pages, VM_MAP, PAGE_KERNEL);
		set_fixmap(FIX_TEXT_POKE1, page_to_phys(pages[1]));
	BUG_ON(!vaddr);
	vaddr = (char *)fix_to_virt(FIX_TEXT_POKE0);
	local_irq_disable();
	local_irq_save(flags);
	memcpy(&vaddr[(unsigned long)addr & ~PAGE_MASK], opcode, len);
	memcpy(&vaddr[(unsigned long)addr & ~PAGE_MASK], opcode, len);
	local_irq_enable();
	local_irq_restore(flags);
	vunmap(vaddr);
	clear_fixmap(FIX_TEXT_POKE0);
	if (pages[1])
		clear_fixmap(FIX_TEXT_POKE1);
	local_flush_tlb();
	sync_core();
	sync_core();
	/* Could also do a CLFLUSH here to speed up CPU recovery; but
	/* Could also do a CLFLUSH here to speed up CPU recovery; but
	   that causes hangs on some VIA CPUs. */
	   that causes hangs on some VIA CPUs. */