diff options
Diffstat (limited to 'arch/powerpc/kernel/module_64.c')
| -rw-r--r-- | arch/powerpc/kernel/module_64.c | 42 | 
1 files changed, 34 insertions, 8 deletions
diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c index 6baa676e7cb6..5d77d3f5fbb5 100644 --- a/arch/powerpc/kernel/module_64.c +++ b/arch/powerpc/kernel/module_64.c @@ -422,11 +422,17 @@ static inline int create_stub(const Elf64_Shdr *sechdrs,  			      const char *name)  {  	long reladdr; +	func_desc_t desc; +	int i;  	if (is_mprofile_ftrace_call(name))  		return create_ftrace_stub(entry, addr, me); -	memcpy(entry->jump, ppc64_stub_insns, sizeof(ppc64_stub_insns)); +	for (i = 0; i < sizeof(ppc64_stub_insns) / sizeof(u32); i++) { +		if (patch_instruction(&entry->jump[i], +				      ppc_inst(ppc64_stub_insns[i]))) +			return 0; +	}  	/* Stub uses address relative to r2. */  	reladdr = (unsigned long)entry - my_r2(sechdrs, me); @@ -437,10 +443,24 @@ static inline int create_stub(const Elf64_Shdr *sechdrs,  	}  	pr_debug("Stub %p get data from reladdr %li\n", entry, reladdr); -	entry->jump[0] |= PPC_HA(reladdr); -	entry->jump[1] |= PPC_LO(reladdr); -	entry->funcdata = func_desc(addr); -	entry->magic = STUB_MAGIC; +	if (patch_instruction(&entry->jump[0], +			      ppc_inst(entry->jump[0] | PPC_HA(reladdr)))) +		return 0; + +	if (patch_instruction(&entry->jump[1], +			  ppc_inst(entry->jump[1] | PPC_LO(reladdr)))) +		return 0; + +	// func_desc_t is 8 bytes if ABIv2, else 16 bytes +	desc = func_desc(addr); +	for (i = 0; i < sizeof(func_desc_t) / sizeof(u32); i++) { +		if (patch_instruction(((u32 *)&entry->funcdata) + i, +				      ppc_inst(((u32 *)(&desc))[i]))) +			return 0; +	} + +	if (patch_instruction(&entry->magic, ppc_inst(STUB_MAGIC))) +		return 0;  	return 1;  } @@ -495,8 +515,11 @@ static int restore_r2(const char *name, u32 *instruction, struct module *me)  			me->name, *instruction, instruction);  		return 0;  	} +  	/* ld r2,R2_STACK_OFFSET(r1) */ -	*instruction = PPC_INST_LD_TOC; +	if (patch_instruction(instruction, ppc_inst(PPC_INST_LD_TOC))) +		return 0; +  	return 1;  } @@ -636,9 +659,12 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,  			}  			/* Only replace bits 2 through 26 */ -			*(uint32_t *)location -				= (*(uint32_t *)location & ~0x03fffffc) +			value = (*(uint32_t *)location & ~0x03fffffc)  				| (value & 0x03fffffc); + +			if (patch_instruction((u32 *)location, ppc_inst(value))) +				return -EFAULT; +  			break;  		case R_PPC64_REL64:  |