diff options
Diffstat (limited to 'arch/powerpc/lib/code-patching.c')
| -rw-r--r-- | arch/powerpc/lib/code-patching.c | 61 | 
1 files changed, 10 insertions, 51 deletions
diff --git a/arch/powerpc/lib/code-patching.c b/arch/powerpc/lib/code-patching.c index 00c68e7fb11e..6edf0697a526 100644 --- a/arch/powerpc/lib/code-patching.c +++ b/arch/powerpc/lib/code-patching.c @@ -8,6 +8,7 @@  #include <linux/init.h>  #include <linux/cpuhotplug.h>  #include <linux/uaccess.h> +#include <linux/jump_label.h>  #include <asm/tlbflush.h>  #include <asm/page.h> @@ -32,7 +33,7 @@ static int __patch_instruction(u32 *exec_addr, ppc_inst_t instr, u32 *patch_addr  	return 0;  failed: -	return -EFAULT; +	return -EPERM;  }  int raw_patch_instruction(u32 *addr, ppc_inst_t instr) @@ -78,6 +79,8 @@ static int text_area_cpu_down(unsigned int cpu)  	return 0;  } +static __ro_after_init DEFINE_STATIC_KEY_FALSE(poking_init_done); +  /*   * Although BUG_ON() is rude, in this case it should only happen if ENOMEM, and   * we judge it as being preferable to a kernel that will crash later when @@ -88,6 +91,7 @@ void __init poking_init(void)  	BUG_ON(!cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,  		"powerpc/text_poke:online", text_area_cpu_up,  		text_area_cpu_down)); +	static_branch_enable(&poking_init_done);  }  /* @@ -97,7 +101,7 @@ static int map_patch_area(void *addr, unsigned long text_poke_addr)  {  	unsigned long pfn; -	if (is_vmalloc_or_module_addr(addr)) +	if (IS_ENABLED(CONFIG_MODULES) && is_vmalloc_or_module_addr(addr))  		pfn = vmalloc_to_pfn(addr);  	else  		pfn = __pa_symbol(addr) >> PAGE_SHIFT; @@ -170,7 +174,7 @@ static int do_patch_instruction(u32 *addr, ppc_inst_t instr)  	 * when text_poke_area is not ready, but we still need  	 * to allow patching. We just do the plain old patching  	 */ -	if (!this_cpu_read(text_poke_area)) +	if (!static_branch_likely(&poking_init_done))  		return raw_patch_instruction(addr, instr);  	local_irq_save(flags); @@ -188,10 +192,12 @@ static int do_patch_instruction(u32 *addr, ppc_inst_t instr)  #endif /* CONFIG_STRICT_KERNEL_RWX */ +__ro_after_init DEFINE_STATIC_KEY_FALSE(init_mem_is_free); +  int patch_instruction(u32 *addr, ppc_inst_t instr)  {  	/* Make sure we aren't patching a freed init section */ -	if (system_state >= SYSTEM_FREEING_INITMEM && init_section_contains(addr, 4)) +	if (static_branch_likely(&init_mem_is_free) && init_section_contains(addr, 4))  		return 0;  	return do_patch_instruction(addr, instr); @@ -208,33 +214,6 @@ int patch_branch(u32 *addr, unsigned long target, int flags)  	return patch_instruction(addr, instr);  } -bool is_offset_in_branch_range(long offset) -{ -	/* -	 * Powerpc branch instruction is : -	 * -	 *  0         6                 30   31 -	 *  +---------+----------------+---+---+ -	 *  | opcode  |     LI         |AA |LK | -	 *  +---------+----------------+---+---+ -	 *  Where AA = 0 and LK = 0 -	 * -	 * LI is a signed 24 bits integer. The real branch offset is computed -	 * by: imm32 = SignExtend(LI:'0b00', 32); -	 * -	 * So the maximum forward branch should be: -	 *   (0x007fffff << 2) = 0x01fffffc =  0x1fffffc -	 * The maximum backward branch should be: -	 *   (0xff800000 << 2) = 0xfe000000 = -0x2000000 -	 */ -	return (offset >= -0x2000000 && offset <= 0x1fffffc && !(offset & 0x3)); -} - -bool is_offset_in_cond_branch_range(long offset) -{ -	return offset >= -0x8000 && offset <= 0x7fff && !(offset & 0x3); -} -  /*   * Helper to check if a given instruction is a conditional branch   * Derived from the conditional checks in analyse_instr() @@ -257,26 +236,6 @@ bool is_conditional_branch(ppc_inst_t instr)  }  NOKPROBE_SYMBOL(is_conditional_branch); -int create_branch(ppc_inst_t *instr, const u32 *addr, -		  unsigned long target, int flags) -{ -	long offset; - -	*instr = ppc_inst(0); -	offset = target; -	if (! (flags & BRANCH_ABSOLUTE)) -		offset = offset - (unsigned long)addr; - -	/* Check we can represent the target in the instruction format */ -	if (!is_offset_in_branch_range(offset)) -		return 1; - -	/* Mask out the flags and target, so they don't step on each other. */ -	*instr = ppc_inst(0x48000000 | (flags & 0x3) | (offset & 0x03FFFFFC)); - -	return 0; -} -  int create_cond_branch(ppc_inst_t *instr, const u32 *addr,  		       unsigned long target, int flags)  {  | 
