aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/lib/code-patching.c
diff options
context:
space:
mode:
authorChristophe Leroy <christophe.leroy@c-s.fr>2018-10-01 08:21:10 -0400
committerMichael Ellerman <mpe@ellerman.id.au>2018-10-02 09:34:14 -0400
commitb45ba4a51cde29b2939365ef0c07ad34c8321789 (patch)
tree9ebc2ceaefe339114545aa39877d81e17be2193a /arch/powerpc/lib/code-patching.c
parent242cdad873a75652f97c35aad61270581e0f3a2e (diff)
powerpc/lib: fix book3s/32 boot failure due to code patching
Commit 51c3c62b58b3 ("powerpc: Avoid code patching freed init sections") accesses 'init_mem_is_free' flag too early, before the kernel is relocated. This provokes early boot failure (before the console is active). As it is not necessary to do this verification that early, this patch moves the test into patch_instruction() instead of __patch_instruction(). This modification also has the advantage of avoiding unnecessary remappings. Fixes: 51c3c62b58b3 ("powerpc: Avoid code patching freed init sections") Cc: stable@vger.kernel.org # 4.13+ Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'arch/powerpc/lib/code-patching.c')
-rw-r--r--arch/powerpc/lib/code-patching.c20
1 files changed, 12 insertions, 8 deletions
diff --git a/arch/powerpc/lib/code-patching.c b/arch/powerpc/lib/code-patching.c
index 6ae2777c220d..5ffee298745f 100644
--- a/arch/powerpc/lib/code-patching.c
+++ b/arch/powerpc/lib/code-patching.c
@@ -28,12 +28,6 @@ static int __patch_instruction(unsigned int *exec_addr, unsigned int instr,
28{ 28{
29 int err; 29 int err;
30 30
31 /* Make sure we aren't patching a freed init section */
32 if (init_mem_is_free && init_section_contains(exec_addr, 4)) {
33 pr_debug("Skipping init section patching addr: 0x%px\n", exec_addr);
34 return 0;
35 }
36
37 __put_user_size(instr, patch_addr, 4, err); 31 __put_user_size(instr, patch_addr, 4, err);
38 if (err) 32 if (err)
39 return err; 33 return err;
@@ -148,7 +142,7 @@ static inline int unmap_patch_area(unsigned long addr)
148 return 0; 142 return 0;
149} 143}
150 144
151int patch_instruction(unsigned int *addr, unsigned int instr) 145static int do_patch_instruction(unsigned int *addr, unsigned int instr)
152{ 146{
153 int err; 147 int err;
154 unsigned int *patch_addr = NULL; 148 unsigned int *patch_addr = NULL;
@@ -188,12 +182,22 @@ out:
188} 182}
189#else /* !CONFIG_STRICT_KERNEL_RWX */ 183#else /* !CONFIG_STRICT_KERNEL_RWX */
190 184
191int patch_instruction(unsigned int *addr, unsigned int instr) 185static int do_patch_instruction(unsigned int *addr, unsigned int instr)
192{ 186{
193 return raw_patch_instruction(addr, instr); 187 return raw_patch_instruction(addr, instr);
194} 188}
195 189
196#endif /* CONFIG_STRICT_KERNEL_RWX */ 190#endif /* CONFIG_STRICT_KERNEL_RWX */
191
192int patch_instruction(unsigned int *addr, unsigned int instr)
193{
194 /* Make sure we aren't patching a freed init section */
195 if (init_mem_is_free && init_section_contains(addr, 4)) {
196 pr_debug("Skipping init section patching addr: 0x%px\n", addr);
197 return 0;
198 }
199 return do_patch_instruction(addr, instr);
200}
197NOKPROBE_SYMBOL(patch_instruction); 201NOKPROBE_SYMBOL(patch_instruction);
198 202
199int patch_branch(unsigned int *addr, unsigned long target, int flags) 203int patch_branch(unsigned int *addr, unsigned long target, int flags)