RISC-V: take text_mutex during alternative patching
authorConor Dooley <conor.dooley@microchip.com>
Fri, 12 May 2023 07:58:18 +0000 (08:58 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 17 May 2023 09:53:41 +0000 (11:53 +0200)
commit 9493e6f3ce02f44c21aa19f3cbf3b9aa05479d06 upstream.

Guenter reported a splat during boot, that Samuel pointed out was the
lockdep assertion failing in patch_insn_write():

WARNING: CPU: 0 PID: 0 at arch/riscv/kernel/patch.c:63 patch_insn_write+0x222/0x2f6
epc : patch_insn_write+0x222/0x2f6
 ra : patch_insn_write+0x21e/0x2f6
epc : ffffffff800068c6 ra : ffffffff800068c2 sp : ffffffff81803df0
 gp : ffffffff81a1ab78 tp : ffffffff81814f80 t0 : ffffffffffffe000
 t1 : 0000000000000001 t2 : 4c45203a76637369 s0 : ffffffff81803e40
 s1 : 0000000000000004 a0 : 0000000000000000 a1 : ffffffffffffffff
 a2 : 0000000000000004 a3 : 0000000000000000 a4 : 0000000000000001
 a5 : 0000000000000000 a6 : 0000000000000000 a7 : 0000000052464e43
 s2 : ffffffff80b4889c s3 : 000000000000082c s4 : ffffffff80b48828
 s5 : 0000000000000828 s6 : ffffffff8131a0a0 s7 : 0000000000000fff
 s8 : 0000000008000200 s9 : ffffffff8131a520 s10: 0000000000000018
 s11: 000000000000000b t3 : 0000000000000001 t4 : 000000000000000d
 t5 : ffffffffd8180000 t6 : ffffffff81803bc8
status: 0000000200000100 badaddr: 0000000000000000 cause: 0000000000000003
[<ffffffff800068c6>] patch_insn_write+0x222/0x2f6
[<ffffffff80006a36>] patch_text_nosync+0xc/0x2a
[<ffffffff80003b86>] riscv_cpufeature_patch_func+0x52/0x98
[<ffffffff80003348>] _apply_alternatives+0x46/0x86
[<ffffffff80c02d36>] apply_boot_alternatives+0x3c/0xfa
[<ffffffff80c03ad8>] setup_arch+0x584/0x5b8
[<ffffffff80c0075a>] start_kernel+0xa2/0x8f8

This issue was exposed by 702e64550b12 ("riscv: fpu: switch has_fpu() to
riscv_has_extension_likely()"), as it is the patching in has_fpu() that
triggers the splats in Guenter's report.

Take the text_mutex before doing any code patching to satisfy lockdep.

Fixes: ff689fd21cb1 ("riscv: add RISC-V Svpbmt extension support")
Fixes: a35707c3d850 ("riscv: add memory-type errata for T-Head")
Fixes: 1a0e5dbd3723 ("riscv: sifive: Add SiFive alternative ports")
Reported-by: Guenter Roeck <linux@roeck-us.net>
Link: https://lore.kernel.org/all/20230212154333.GA3760469@roeck-us.net/
Signed-off-by: Conor Dooley <conor.dooley@microchip.com>
Reviewed-by: Samuel Holland <samuel@sholland.org>
Tested-by: Guenter Roeck <linux@roeck-us.net>
Link: https://lore.kernel.org/r/20230212194735.491785-1-conor@kernel.org
Cc: stable@vger.kernel.org
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
arch/riscv/errata/sifive/errata.c
arch/riscv/errata/thead/errata.c
arch/riscv/kernel/cpufeature.c

index 1031038423e748a79ee4919bfad45cb3592172aa..5b77d7310e391ac65e55818f421e10650644eaa5 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/memory.h>
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/bug.h>
@@ -107,7 +108,9 @@ void __init_or_module sifive_errata_patch_func(struct alt_entry *begin,
 
                tmp = (1U << alt->errata_id);
                if (cpu_req_errata & tmp) {
+                       mutex_lock(&text_mutex);
                        patch_text_nosync(alt->old_ptr, alt->alt_ptr, alt->alt_len);
+                       mutex_lock(&text_mutex);
                        cpu_apply_errata |= tmp;
                }
        }
index 21546937db39bf5fb968af60a7ee5b096242925b..32a34ed735098ff5503bda0d9786686874321d9d 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <linux/bug.h>
 #include <linux/kernel.h>
+#include <linux/memory.h>
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/uaccess.h>
@@ -78,11 +79,14 @@ void __init_or_module thead_errata_patch_func(struct alt_entry *begin, struct al
                tmp = (1U << alt->errata_id);
                if (cpu_req_errata & tmp) {
                        /* On vm-alternatives, the mmu isn't running yet */
-                       if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
+                       if (stage == RISCV_ALTERNATIVES_EARLY_BOOT) {
                                memcpy((void *)__pa_symbol(alt->old_ptr),
                                       (void *)__pa_symbol(alt->alt_ptr), alt->alt_len);
-                       else
+                       } else {
+                               mutex_lock(&text_mutex);
                                patch_text_nosync(alt->old_ptr, alt->alt_ptr, alt->alt_len);
+                               mutex_unlock(&text_mutex);
+                       }
                }
        }
 
index 694267d1fe8149a6a29aab095e441aafaa07b0ec..fd1238df61497d1f8c480222b9d5a8889fb22eaa 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/bitmap.h>
 #include <linux/ctype.h>
 #include <linux/libfdt.h>
+#include <linux/memory.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <asm/alternative.h>
@@ -316,8 +317,11 @@ void __init_or_module riscv_cpufeature_patch_func(struct alt_entry *begin,
                }
 
                tmp = (1U << alt->errata_id);
-               if (cpu_req_feature & tmp)
+               if (cpu_req_feature & tmp) {
+                       mutex_lock(&text_mutex);
                        patch_text_nosync(alt->old_ptr, alt->alt_ptr, alt->alt_len);
+                       mutex_unlock(&text_mutex);
+               }
        }
 }
 #endif