From eb16b3727c05ed36420c90eca1e8f0e279514c1c Mon Sep 17 00:00:00 2001 From: Nylon Chen Date: Fri, 11 Apr 2025 15:38:49 +0800 Subject: [PATCH 01/91] riscv: misaligned: Add handling for ZCB instructions Add support for the Zcb extension's compressed half-word instructions (C.LHU, C.LH, and C.SH) in the RISC-V misaligned access trap handler. Signed-off-by: Zong Li Signed-off-by: Nylon Chen Fixes: 956d705dd279 ("riscv: Unaligned load/store handling for M_MODE") Reviewed-by: Alexandre Ghiti Link: https://lore.kernel.org/r/20250411073850.3699180-2-nylon.chen@sifive.com Signed-off-by: Alexandre Ghiti --- arch/riscv/kernel/traps_misaligned.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c index 4354c87c0376fd..dde5d11dc1b50d 100644 --- a/arch/riscv/kernel/traps_misaligned.c +++ b/arch/riscv/kernel/traps_misaligned.c @@ -88,6 +88,13 @@ #define INSN_MATCH_C_FSWSP 0xe002 #define INSN_MASK_C_FSWSP 0xe003 +#define INSN_MATCH_C_LHU 0x8400 +#define INSN_MASK_C_LHU 0xfc43 +#define INSN_MATCH_C_LH 0x8440 +#define INSN_MASK_C_LH 0xfc43 +#define INSN_MATCH_C_SH 0x8c00 +#define INSN_MASK_C_SH 0xfc43 + #define INSN_LEN(insn) ((((insn) & 0x3) < 0x3) ? 2 : 4) #if defined(CONFIG_64BIT) @@ -431,6 +438,13 @@ static int handle_scalar_misaligned_load(struct pt_regs *regs) fp = 1; len = 4; #endif + } else if ((insn & INSN_MASK_C_LHU) == INSN_MATCH_C_LHU) { + len = 2; + insn = RVC_RS2S(insn) << SH_RD; + } else if ((insn & INSN_MASK_C_LH) == INSN_MATCH_C_LH) { + len = 2; + shift = 8 * (sizeof(ulong) - len); + insn = RVC_RS2S(insn) << SH_RD; } else { regs->epc = epc; return -1; @@ -530,6 +544,9 @@ static int handle_scalar_misaligned_store(struct pt_regs *regs) len = 4; val.data_ulong = GET_F32_RS2C(insn, regs); #endif + } else if ((insn & INSN_MASK_C_SH) == INSN_MATCH_C_SH) { + len = 2; + val.data_ulong = GET_RS2S(insn, regs); } else { regs->epc = epc; return -1; From 23d099a5de90801b8c2668436c46f044b3d95cc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= Date: Tue, 22 Apr 2025 18:23:08 +0200 Subject: [PATCH 02/91] riscv: misaligned: factorize trap handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since both load/store and user/kernel should use almost the same path and that we are going to add some code around that, factorize it. Signed-off-by: Clément Léger Link: https://lore.kernel.org/r/20250422162324.956065-2-cleger@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/kernel/traps.c | 66 +++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c index 8ff8e8b36524b7..b1d991c78a2337 100644 --- a/arch/riscv/kernel/traps.c +++ b/arch/riscv/kernel/traps.c @@ -198,47 +198,53 @@ asmlinkage __visible __trap_section void do_trap_insn_illegal(struct pt_regs *re DO_ERROR_INFO(do_trap_load_fault, SIGSEGV, SEGV_ACCERR, "load access fault"); -asmlinkage __visible __trap_section void do_trap_load_misaligned(struct pt_regs *regs) +enum misaligned_access_type { + MISALIGNED_STORE, + MISALIGNED_LOAD, +}; +static const struct { + const char *type_str; + int (*handler)(struct pt_regs *regs); +} misaligned_handler[] = { + [MISALIGNED_STORE] = { + .type_str = "Oops - store (or AMO) address misaligned", + .handler = handle_misaligned_store, + }, + [MISALIGNED_LOAD] = { + .type_str = "Oops - load address misaligned", + .handler = handle_misaligned_load, + }, +}; + +static void do_trap_misaligned(struct pt_regs *regs, enum misaligned_access_type type) { - if (user_mode(regs)) { + irqentry_state_t state; + + if (user_mode(regs)) irqentry_enter_from_user_mode(regs); + else + state = irqentry_nmi_enter(regs); - if (handle_misaligned_load(regs)) - do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc, - "Oops - load address misaligned"); + if (misaligned_handler[type].handler(regs)) + do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc, + misaligned_handler[type].type_str); + if (user_mode(regs)) irqentry_exit_to_user_mode(regs); - } else { - irqentry_state_t state = irqentry_nmi_enter(regs); - - if (handle_misaligned_load(regs)) - do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc, - "Oops - load address misaligned"); - + else irqentry_nmi_exit(regs, state); - } } -asmlinkage __visible __trap_section void do_trap_store_misaligned(struct pt_regs *regs) +asmlinkage __visible __trap_section void do_trap_load_misaligned(struct pt_regs *regs) { - if (user_mode(regs)) { - irqentry_enter_from_user_mode(regs); - - if (handle_misaligned_store(regs)) - do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc, - "Oops - store (or AMO) address misaligned"); - - irqentry_exit_to_user_mode(regs); - } else { - irqentry_state_t state = irqentry_nmi_enter(regs); - - if (handle_misaligned_store(regs)) - do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc, - "Oops - store (or AMO) address misaligned"); + do_trap_misaligned(regs, MISALIGNED_LOAD); +} - irqentry_nmi_exit(regs, state); - } +asmlinkage __visible __trap_section void do_trap_store_misaligned(struct pt_regs *regs) +{ + do_trap_misaligned(regs, MISALIGNED_STORE); } + DO_ERROR_INFO(do_trap_store_fault, SIGSEGV, SEGV_ACCERR, "store (or AMO) access fault"); DO_ERROR_INFO(do_trap_ecall_s, From 8786815c4af79e58e11e80254b45c20ca5aa3474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= Date: Tue, 22 Apr 2025 18:23:09 +0200 Subject: [PATCH 03/91] riscv: misaligned: enable IRQs while handling misaligned accesses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can safely reenable IRQs if coming from userspace. This allows to access user memory that could potentially trigger a page fault. Fixes: b686ecdeacf6 ("riscv: misaligned: Restrict user access to kernel memory") Signed-off-by: Clément Léger Link: https://lore.kernel.org/r/20250422162324.956065-3-cleger@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/kernel/traps.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c index b1d991c78a2337..9c83848797a78b 100644 --- a/arch/riscv/kernel/traps.c +++ b/arch/riscv/kernel/traps.c @@ -220,19 +220,23 @@ static void do_trap_misaligned(struct pt_regs *regs, enum misaligned_access_type { irqentry_state_t state; - if (user_mode(regs)) + if (user_mode(regs)) { irqentry_enter_from_user_mode(regs); - else + local_irq_enable(); + } else { state = irqentry_nmi_enter(regs); + } if (misaligned_handler[type].handler(regs)) do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc, misaligned_handler[type].type_str); - if (user_mode(regs)) + if (user_mode(regs)) { + local_irq_disable(); irqentry_exit_to_user_mode(regs); - else + } else { irqentry_nmi_exit(regs, state); + } } asmlinkage __visible __trap_section void do_trap_load_misaligned(struct pt_regs *regs) From 6f1ddb7d7b699303852c5455943f5fe22af2e71b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= Date: Tue, 22 Apr 2025 18:23:10 +0200 Subject: [PATCH 04/91] riscv: misaligned: use get_user() instead of __get_user() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we can safely handle user memory accesses while in the misaligned access handlers, use get_user() instead of __get_user() to have user memory access checks. Signed-off-by: Clément Léger Reviewed-by: Alexandre Ghiti Link: https://lore.kernel.org/r/20250422162324.956065-4-cleger@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/kernel/traps_misaligned.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c index dde5d11dc1b50d..77c788660223b3 100644 --- a/arch/riscv/kernel/traps_misaligned.c +++ b/arch/riscv/kernel/traps_misaligned.c @@ -275,7 +275,7 @@ static unsigned long get_f32_rs(unsigned long insn, u8 fp_reg_offset, int __ret; \ \ if (user_mode(regs)) { \ - __ret = __get_user(insn, (type __user *) insn_addr); \ + __ret = get_user(insn, (type __user *) insn_addr); \ } else { \ insn = *(type *)insn_addr; \ __ret = 0; \ From 81de1afb2dd1e36c124155b31165fb77e6bf6f3b Mon Sep 17 00:00:00 2001 From: Nam Cao Date: Sun, 4 May 2025 12:19:20 +0200 Subject: [PATCH 05/91] riscv: Fix kernel crash due to PR_SET_TAGGED_ADDR_CTRL When userspace does PR_SET_TAGGED_ADDR_CTRL, but Supm extension is not available, the kernel crashes: Oops - illegal instruction [#1] [snip] epc : set_tagged_addr_ctrl+0x112/0x15a ra : set_tagged_addr_ctrl+0x74/0x15a epc : ffffffff80011ace ra : ffffffff80011a30 sp : ffffffc60039be10 [snip] status: 0000000200000120 badaddr: 0000000010a79073 cause: 0000000000000002 set_tagged_addr_ctrl+0x112/0x15a __riscv_sys_prctl+0x352/0x73c do_trap_ecall_u+0x17c/0x20c andle_exception+0x150/0x15c Fix it by checking if Supm is available. Fixes: 09d6775f503b ("riscv: Add support for userspace pointer masking") Signed-off-by: Nam Cao Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20250504101920.3393053-1-namcao@linutronix.de Signed-off-by: Alexandre Ghiti --- arch/riscv/kernel/process.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index 7c244de7718008..3db2c0c07acd07 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -275,6 +275,9 @@ long set_tagged_addr_ctrl(struct task_struct *task, unsigned long arg) unsigned long pmm; u8 pmlen; + if (!riscv_has_extension_unlikely(RISCV_ISA_EXT_SUPM)) + return -EINVAL; + if (is_compat_thread(ti)) return -EINVAL; From b72da57be8b21db0022d4bc15ed69110c49a09c6 Mon Sep 17 00:00:00 2001 From: Alexandre Ghiti Date: Tue, 8 Apr 2025 09:28:51 +0200 Subject: [PATCH 06/91] scripts: Do not strip .rela.dyn section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .rela.dyn section contains runtime relocations and is only emitted for a relocatable kernel. riscv uses this section to relocate the kernel at runtime but that section is stripped from vmlinux. That prevents kexec to successfully load vmlinux since it does not contain the relocations info needed. Fixes: 559d1e45a16d ("riscv: Use --emit-relocs in order to move .rela.dyn in init") Tested-by: Björn Töpel Reviewed-by: Björn Töpel Acked-by: Ard Biesheuvel Link: https://lore.kernel.org/r/20250408072851.90275-1-alexghiti@rivosinc.com Signed-off-by: Alexandre Ghiti --- scripts/Makefile.vmlinux | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Makefile.vmlinux b/scripts/Makefile.vmlinux index b0a6cd5b818c9f..85d60d98640169 100644 --- a/scripts/Makefile.vmlinux +++ b/scripts/Makefile.vmlinux @@ -13,7 +13,7 @@ ifdef CONFIG_ARCH_VMLINUX_NEEDS_RELOCS vmlinux-final := vmlinux.unstripped quiet_cmd_strip_relocs = RSTRIP $@ - cmd_strip_relocs = $(OBJCOPY) --remove-section='.rel*' $< $@ + cmd_strip_relocs = $(OBJCOPY) --remove-section='.rel*' --remove-section=!'.rel*.dyn' $< $@ vmlinux: $(vmlinux-final) FORCE $(call if_changed,strip_relocs) From 33bf768fd0caf6428a2e1e8323c3e0c76d2a402b Mon Sep 17 00:00:00 2001 From: Andy Chiu Date: Tue, 8 Apr 2025 02:08:25 +0800 Subject: [PATCH 07/91] riscv: ftrace: support fastcc in Clang for WITH_ARGS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some caller-saved registers which are not defined as function arguments in the ABI can still be passed as arguments when the kernel is compiled with Clang. As a result, we must save and restore those registers to prevent ftrace from clobbering them. - [1]: https://reviews.llvm.org/D68559 Reported-by: Evgenii Shatokhin Closes: https://lore.kernel.org/linux-riscv/7e7c7914-445d-426d-89a0-59a9199c45b1@yadro.com/ Fixes: 7caa9765465f ("ftrace: riscv: move from REGS to ARGS") Acked-by: Nathan Chancellor Reviewed-by: Björn Töpel Signed-off-by: Andy Chiu Tested-by: Björn Töpel Link: https://lore.kernel.org/r/20250407180838.42877-1-andybnac@gmail.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/ftrace.h | 7 +++++++ arch/riscv/kernel/asm-offsets.c | 7 +++++++ arch/riscv/kernel/mcount-dyn.S | 16 ++++++++++++++-- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h index d627f63ee289c7..d8b2138bd9c664 100644 --- a/arch/riscv/include/asm/ftrace.h +++ b/arch/riscv/include/asm/ftrace.h @@ -146,6 +146,13 @@ struct __arch_ftrace_regs { unsigned long a5; unsigned long a6; unsigned long a7; +#ifdef CONFIG_CC_IS_CLANG + unsigned long t2; + unsigned long t3; + unsigned long t4; + unsigned long t5; + unsigned long t6; +#endif }; }; }; diff --git a/arch/riscv/kernel/asm-offsets.c b/arch/riscv/kernel/asm-offsets.c index 16490755304e0c..7c43c8e26ae7f7 100644 --- a/arch/riscv/kernel/asm-offsets.c +++ b/arch/riscv/kernel/asm-offsets.c @@ -501,6 +501,13 @@ void asm_offsets(void) DEFINE(FREGS_SP, offsetof(struct __arch_ftrace_regs, sp)); DEFINE(FREGS_S0, offsetof(struct __arch_ftrace_regs, s0)); DEFINE(FREGS_T1, offsetof(struct __arch_ftrace_regs, t1)); +#ifdef CONFIG_CC_IS_CLANG + DEFINE(FREGS_T2, offsetof(struct __arch_ftrace_regs, t2)); + DEFINE(FREGS_T3, offsetof(struct __arch_ftrace_regs, t3)); + DEFINE(FREGS_T4, offsetof(struct __arch_ftrace_regs, t4)); + DEFINE(FREGS_T5, offsetof(struct __arch_ftrace_regs, t5)); + DEFINE(FREGS_T6, offsetof(struct __arch_ftrace_regs, t6)); +#endif DEFINE(FREGS_A0, offsetof(struct __arch_ftrace_regs, a0)); DEFINE(FREGS_A1, offsetof(struct __arch_ftrace_regs, a1)); DEFINE(FREGS_A2, offsetof(struct __arch_ftrace_regs, a2)); diff --git a/arch/riscv/kernel/mcount-dyn.S b/arch/riscv/kernel/mcount-dyn.S index 745dd4c4a69c35..e988bd26b28bd5 100644 --- a/arch/riscv/kernel/mcount-dyn.S +++ b/arch/riscv/kernel/mcount-dyn.S @@ -96,7 +96,13 @@ REG_S x8, FREGS_S0(sp) #endif REG_S x6, FREGS_T1(sp) - +#ifdef CONFIG_CC_IS_CLANG + REG_S x7, FREGS_T2(sp) + REG_S x28, FREGS_T3(sp) + REG_S x29, FREGS_T4(sp) + REG_S x30, FREGS_T5(sp) + REG_S x31, FREGS_T6(sp) +#endif // save the arguments REG_S x10, FREGS_A0(sp) REG_S x11, FREGS_A1(sp) @@ -115,7 +121,13 @@ REG_L x8, FREGS_S0(sp) #endif REG_L x6, FREGS_T1(sp) - +#ifdef CONFIG_CC_IS_CLANG + REG_L x7, FREGS_T2(sp) + REG_L x28, FREGS_T3(sp) + REG_L x29, FREGS_T4(sp) + REG_L x30, FREGS_T5(sp) + REG_L x31, FREGS_T6(sp) +#endif // restore the arguments REG_L x10, FREGS_A0(sp) REG_L x11, FREGS_A1(sp) From c2509cfa466e24072357375fc66cf206d6353996 Mon Sep 17 00:00:00 2001 From: Andy Chiu Date: Tue, 8 Apr 2025 02:08:26 +0800 Subject: [PATCH 08/91] riscv: ftrace factor out code defined by !WITH_ARG DYNAMIC_FTRACE selects DYNAMIC_FTRACE_WITH_ARGS and mcount-dyn.S in riscv, so we can remove ifdef jargons of WITH_ARG when it is known that DYNAMIC_FTRACE is true. Signed-off-by: Andy Chiu Link: https://lore.kernel.org/r/20250407180838.42877-2-andybnac@gmail.com Signed-off-by: Alexandre Ghiti --- arch/riscv/kernel/ftrace.c | 15 --------------- arch/riscv/kernel/mcount-dyn.S | 34 ---------------------------------- 2 files changed, 49 deletions(-) diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c index 674dcdfae7a149..1fd10555c58039 100644 --- a/arch/riscv/kernel/ftrace.c +++ b/arch/riscv/kernel/ftrace.c @@ -210,7 +210,6 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, } #ifdef CONFIG_DYNAMIC_FTRACE -#ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct ftrace_regs *fregs) { @@ -231,19 +230,5 @@ void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, if (!function_graph_enter_regs(old, ip, frame_pointer, parent, fregs)) *parent = return_hooker; } -#else /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */ -extern void ftrace_graph_call(void); -int ftrace_enable_ftrace_graph_caller(void) -{ - return __ftrace_modify_call((unsigned long)&ftrace_graph_call, - (unsigned long)&prepare_ftrace_return, true, true); -} - -int ftrace_disable_ftrace_graph_caller(void) -{ - return __ftrace_modify_call((unsigned long)&ftrace_graph_call, - (unsigned long)&prepare_ftrace_return, false, true); -} -#endif /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */ #endif /* CONFIG_DYNAMIC_FTRACE */ #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ diff --git a/arch/riscv/kernel/mcount-dyn.S b/arch/riscv/kernel/mcount-dyn.S index e988bd26b28bd5..3f06b40bb6c8cc 100644 --- a/arch/riscv/kernel/mcount-dyn.S +++ b/arch/riscv/kernel/mcount-dyn.S @@ -56,8 +56,6 @@ addi sp, sp, ABI_SIZE_ON_STACK .endm -#ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS - /** * SAVE_ABI_REGS - save regs against the ftrace_regs struct * @@ -149,36 +147,6 @@ mv a3, sp .endm -#endif /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */ - -#ifndef CONFIG_DYNAMIC_FTRACE_WITH_ARGS -SYM_FUNC_START(ftrace_caller) - SAVE_ABI - - addi a0, t0, -FENTRY_RA_OFFSET - la a1, function_trace_op - REG_L a2, 0(a1) - mv a1, ra - mv a3, sp - -SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL) - call ftrace_stub - -#ifdef CONFIG_FUNCTION_GRAPH_TRACER - addi a0, sp, ABI_RA - REG_L a1, ABI_T0(sp) - addi a1, a1, -FENTRY_RA_OFFSET -#ifdef HAVE_FUNCTION_GRAPH_FP_TEST - mv a2, s0 -#endif -SYM_INNER_LABEL(ftrace_graph_call, SYM_L_GLOBAL) - call ftrace_stub -#endif - RESTORE_ABI - jr t0 -SYM_FUNC_END(ftrace_caller) - -#else /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */ SYM_FUNC_START(ftrace_caller) mv t1, zero SAVE_ABI_REGS @@ -194,8 +162,6 @@ SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL) jr t1 SYM_FUNC_END(ftrace_caller) -#endif /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */ - #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS SYM_CODE_START(ftrace_stub_direct_tramp) jr t0 From de482eefcf5dc2e08553cce6be66052063b66c8f Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 10 Apr 2025 07:05:22 +0000 Subject: [PATCH 09/91] riscv: save the SR_SUM status over switches When threads/tasks are switched we need to ensure the old execution's SR_SUM state is saved and the new thread has the old SR_SUM state restored. The issue was seen under heavy load especially with the syz-stress tool running, with crashes as follows in schedule_tail: Unable to handle kernel access to user memory without uaccess routines at virtual address 000000002749f0d0 Oops [#1] Modules linked in: CPU: 1 PID: 4875 Comm: syz-executor.0 Not tainted 5.12.0-rc2-syzkaller-00467-g0d7588ab9ef9 #0 Hardware name: riscv-virtio,qemu (DT) epc : schedule_tail+0x72/0xb2 kernel/sched/core.c:4264 ra : task_pid_vnr include/linux/sched.h:1421 [inline] ra : schedule_tail+0x70/0xb2 kernel/sched/core.c:4264 epc : ffffffe00008c8b0 ra : ffffffe00008c8ae sp : ffffffe025d17ec0 gp : ffffffe005d25378 tp : ffffffe00f0d0000 t0 : 0000000000000000 t1 : 0000000000000001 t2 : 00000000000f4240 s0 : ffffffe025d17ee0 s1 : 000000002749f0d0 a0 : 000000000000002a a1 : 0000000000000003 a2 : 1ffffffc0cfac500 a3 : ffffffe0000c80cc a4 : 5ae9db91c19bbe00 a5 : 0000000000000000 a6 : 0000000000f00000 a7 : ffffffe000082eba s2 : 0000000000040000 s3 : ffffffe00eef96c0 s4 : ffffffe022c77fe0 s5 : 0000000000004000 s6 : ffffffe067d74e00 s7 : ffffffe067d74850 s8 : ffffffe067d73e18 s9 : ffffffe067d74e00 s10: ffffffe00eef96e8 s11: 000000ae6cdf8368 t3 : 5ae9db91c19bbe00 t4 : ffffffc4043cafb2 t5 : ffffffc4043cafba t6 : 0000000000040000 status: 0000000000000120 badaddr: 000000002749f0d0 cause: 000000000000000f Call Trace: [] schedule_tail+0x72/0xb2 kernel/sched/core.c:4264 [] ret_from_exception+0x0/0x14 Dumping ftrace buffer: (ftrace buffer empty) ---[ end trace b5f8f9231dc87dda ]--- The issue comes from the put_user() in schedule_tail (kernel/sched/core.c) doing the following: asmlinkage __visible void schedule_tail(struct task_struct *prev) { ... if (current->set_child_tid) put_user(task_pid_vnr(current), current->set_child_tid); ... } the put_user() macro causes the code sequence to come out as follows: 1: __enable_user_access() 2: reg = task_pid_vnr(current); 3: *current->set_child_tid = reg; 4: __disable_user_access() The problem is that we may have a sleeping function as argument which could clear SR_SUM causing the panic above. This was fixed by evaluating the argument of the put_user() macro outside the user-enabled section in commit 285a76bb2cf5 ("riscv: evaluate put_user() arg before enabling user access")" In order for riscv to take advantage of unsafe_get/put_XXX() macros and to avoid the same issue we had with put_user() and sleeping functions we must ensure code flow can go through switch_to() from within a region of code with SR_SUM enabled and come back with SR_SUM still enabled. This patch addresses the problem allowing future work to enable full use of unsafe_get/put_XXX() macros without needing to take a CSR bit flip cost on every access. Make switch_to() save and restore SR_SUM. Reported-by: syzbot+e74b94fe601ab9552d69@syzkaller.appspotmail.com Signed-off-by: Ben Dooks Signed-off-by: Cyril Bur Reviewed-by: Alexandre Ghiti Link: https://lore.kernel.org/r/20250410070526.3160847-2-cyrilbur@tenstorrent.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/processor.h | 1 + arch/riscv/kernel/asm-offsets.c | 5 +++++ arch/riscv/kernel/entry.S | 8 ++++++++ 3 files changed, 14 insertions(+) diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h index 5f56eb9d114a95..58fd11c89fe9fd 100644 --- a/arch/riscv/include/asm/processor.h +++ b/arch/riscv/include/asm/processor.h @@ -103,6 +103,7 @@ struct thread_struct { struct __riscv_d_ext_state fstate; unsigned long bad_cause; unsigned long envcfg; + unsigned long status; u32 riscv_v_flags; u32 vstate_ctrl; struct __riscv_v_ext_state vstate; diff --git a/arch/riscv/kernel/asm-offsets.c b/arch/riscv/kernel/asm-offsets.c index 16490755304e0c..969c65b1fe41df 100644 --- a/arch/riscv/kernel/asm-offsets.c +++ b/arch/riscv/kernel/asm-offsets.c @@ -34,6 +34,7 @@ void asm_offsets(void) OFFSET(TASK_THREAD_S9, task_struct, thread.s[9]); OFFSET(TASK_THREAD_S10, task_struct, thread.s[10]); OFFSET(TASK_THREAD_S11, task_struct, thread.s[11]); + OFFSET(TASK_THREAD_STATUS, task_struct, thread.status); OFFSET(TASK_TI_CPU, task_struct, thread_info.cpu); OFFSET(TASK_TI_PREEMPT_COUNT, task_struct, thread_info.preempt_count); @@ -346,6 +347,10 @@ void asm_offsets(void) offsetof(struct task_struct, thread.s[11]) - offsetof(struct task_struct, thread.ra) ); + DEFINE(TASK_THREAD_STATUS_RA, + offsetof(struct task_struct, thread.status) + - offsetof(struct task_struct, thread.ra) + ); DEFINE(TASK_THREAD_F0_F0, offsetof(struct task_struct, thread.fstate.f[0]) diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S index 33a5a9f2a0d4e1..00bd0de9faa28b 100644 --- a/arch/riscv/kernel/entry.S +++ b/arch/riscv/kernel/entry.S @@ -397,9 +397,17 @@ SYM_FUNC_START(__switch_to) REG_S s9, TASK_THREAD_S9_RA(a3) REG_S s10, TASK_THREAD_S10_RA(a3) REG_S s11, TASK_THREAD_S11_RA(a3) + + /* save the user space access flag */ + li s0, SR_SUM + csrr s1, CSR_STATUS + REG_S s1, TASK_THREAD_STATUS_RA(a3) + /* Save the kernel shadow call stack pointer */ scs_save_current /* Restore context from next->thread */ + REG_L s0, TASK_THREAD_STATUS_RA(a4) + csrs CSR_STATUS, s0 REG_L ra, TASK_THREAD_RA_RA(a4) REG_L sp, TASK_THREAD_SP_RA(a4) REG_L s0, TASK_THREAD_S0_RA(a4) From abd5987ca226d8730f1ddbd4fceb4a8b5d2f7b9d Mon Sep 17 00:00:00 2001 From: Andy Chiu Date: Tue, 8 Apr 2025 02:08:27 +0800 Subject: [PATCH 10/91] riscv: ftrace: align patchable functions to 4 Byte boundary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are changing ftrace code patching in order to remove dependency from stop_machine() and enable kernel preemption. This requires us to align functions entry at a 4-B align address. However, -falign-functions on older versions of GCC alone was not strong enoungh to align all functions. In fact, cold functions are not aligned after turning on optimizations. We consider this is a bug in GCC and turn off guess-branch-probility as a workaround to align all functions. GCC bug id: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88345 The option -fmin-function-alignment is able to align all functions properly on newer versions of gcc. So, we add a cc-option to test if the toolchain supports it. Suggested-by: Evgenii Shatokhin Signed-off-by: Andy Chiu Reviewed-by: Björn Töpel Link: https://lore.kernel.org/r/20250407180838.42877-3-andybnac@gmail.com Signed-off-by: Alexandre Ghiti --- arch/riscv/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index bbec87b7930999..7dbed10843d282 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -150,6 +150,7 @@ config RISCV select HAVE_DEBUG_KMEMLEAK select HAVE_DMA_CONTIGUOUS if MMU select HAVE_DYNAMIC_FTRACE if !XIP_KERNEL && MMU && (CLANG_SUPPORTS_DYNAMIC_FTRACE || GCC_SUPPORTS_DYNAMIC_FTRACE) + select FUNCTION_ALIGNMENT_4B if HAVE_DYNAMIC_FTRACE && RISCV_ISA_C select HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS select HAVE_DYNAMIC_FTRACE_WITH_ARGS if HAVE_DYNAMIC_FTRACE select HAVE_FTRACE_GRAPH_FUNC @@ -236,6 +237,7 @@ config CLANG_SUPPORTS_DYNAMIC_FTRACE config GCC_SUPPORTS_DYNAMIC_FTRACE def_bool CC_IS_GCC depends on $(cc-option,-fpatchable-function-entry=8) + depends on CC_HAS_MIN_FUNCTION_ALIGNMENT || !RISCV_ISA_C config HAVE_SHADOW_CALL_STACK def_bool $(cc-option,-fsanitize=shadow-call-stack) From 16d7285ea288efd80a1e4171f5609a41ba5e8beb Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Thu, 10 Apr 2025 07:05:23 +0000 Subject: [PATCH 11/91] riscv: implement user_access_begin() and families Currently, when a function like strncpy_from_user() is called, the userspace access protection is disabled and enabled for every word read. By implementing user_access_begin() and families, the protection is disabled at the beginning of the copy and enabled at the end. The __inttype macro is borrowed from x86 implementation. Signed-off-by: Jisheng Zhang Signed-off-by: Cyril Bur Reviewed-by: Alexandre Ghiti Link: https://lore.kernel.org/r/20250410070526.3160847-3-cyrilbur@tenstorrent.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/uaccess.h | 76 ++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/arch/riscv/include/asm/uaccess.h b/arch/riscv/include/asm/uaccess.h index fee56b0c805865..c9a461467bf47a 100644 --- a/arch/riscv/include/asm/uaccess.h +++ b/arch/riscv/include/asm/uaccess.h @@ -61,6 +61,19 @@ static inline unsigned long __untagged_addr_remote(struct mm_struct *mm, unsigne #define __disable_user_access() \ __asm__ __volatile__ ("csrc sstatus, %0" : : "r" (SR_SUM) : "memory") +/* + * This is the smallest unsigned integer type that can fit a value + * (up to 'long long') + */ +#define __inttype(x) __typeof__( \ + __typefits(x, char, \ + __typefits(x, short, \ + __typefits(x, int, \ + __typefits(x, long, 0ULL))))) + +#define __typefits(x, type, not) \ + __builtin_choose_expr(sizeof(x) <= sizeof(type), (unsigned type)0, not) + /* * The exception table consists of pairs of addresses: the first is the * address of an instruction that is allowed to fault, and the second is @@ -368,6 +381,69 @@ do { \ goto err_label; \ } while (0) +static __must_check __always_inline bool user_access_begin(const void __user *ptr, size_t len) +{ + if (unlikely(!access_ok(ptr, len))) + return 0; + __enable_user_access(); + return 1; +} +#define user_access_begin user_access_begin +#define user_access_end __disable_user_access + +static inline unsigned long user_access_save(void) { return 0UL; } +static inline void user_access_restore(unsigned long enabled) { } + +/* + * We want the unsafe accessors to always be inlined and use + * the error labels - thus the macro games. + */ +#define unsafe_put_user(x, ptr, label) do { \ + long __err = 0; \ + __put_user_nocheck(x, (ptr), __err); \ + if (__err) \ + goto label; \ +} while (0) + +#define unsafe_get_user(x, ptr, label) do { \ + long __err = 0; \ + __inttype(*(ptr)) __gu_val; \ + __get_user_nocheck(__gu_val, (ptr), __err); \ + (x) = (__force __typeof__(*(ptr)))__gu_val; \ + if (__err) \ + goto label; \ +} while (0) + +#define unsafe_copy_loop(dst, src, len, type, op, label) \ + while (len >= sizeof(type)) { \ + op(*(type *)(src), (type __user *)(dst), label); \ + dst += sizeof(type); \ + src += sizeof(type); \ + len -= sizeof(type); \ + } + +#define unsafe_copy_to_user(_dst, _src, _len, label) \ +do { \ + char __user *__ucu_dst = (_dst); \ + const char *__ucu_src = (_src); \ + size_t __ucu_len = (_len); \ + unsafe_copy_loop(__ucu_dst, __ucu_src, __ucu_len, u64, unsafe_put_user, label); \ + unsafe_copy_loop(__ucu_dst, __ucu_src, __ucu_len, u32, unsafe_put_user, label); \ + unsafe_copy_loop(__ucu_dst, __ucu_src, __ucu_len, u16, unsafe_put_user, label); \ + unsafe_copy_loop(__ucu_dst, __ucu_src, __ucu_len, u8, unsafe_put_user, label); \ +} while (0) + +#define unsafe_copy_from_user(_dst, _src, _len, label) \ +do { \ + char *__ucu_dst = (_dst); \ + const char __user *__ucu_src = (_src); \ + size_t __ucu_len = (_len); \ + unsafe_copy_loop(__ucu_src, __ucu_dst, __ucu_len, u64, unsafe_get_user, label); \ + unsafe_copy_loop(__ucu_src, __ucu_dst, __ucu_len, u32, unsafe_get_user, label); \ + unsafe_copy_loop(__ucu_src, __ucu_dst, __ucu_len, u16, unsafe_get_user, label); \ + unsafe_copy_loop(__ucu_src, __ucu_dst, __ucu_len, u8, unsafe_get_user, label); \ +} while (0) + #else /* CONFIG_MMU */ #include #endif /* CONFIG_MMU */ From 0afc68753c65c8b6dd45a2b2f735b4bbcdc381f4 Mon Sep 17 00:00:00 2001 From: Andy Chiu Date: Tue, 8 Apr 2025 02:08:28 +0800 Subject: [PATCH 12/91] kernel: ftrace: export ftrace_sync_ipi The following ftrace patch for riscv uses a data store to update ftrace function. Therefore, a romote fence is required to order it against function_trace_op updates. The mechanism is similar to the fence between function_trace_op and update_ftrace_func in the generic ftrace, so we leverage the same ftrace_sync_ipi function. [ alex: Fix build warning when !CONFIG_DYNAMIC_FTRACE ] Signed-off-by: Andy Chiu Link: https://lore.kernel.org/r/20250407180838.42877-4-andybnac@gmail.com Signed-off-by: Alexandre Ghiti --- include/linux/ftrace.h | 2 ++ kernel/trace/ftrace.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index fbabc3d848b375..30374478cb0774 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -635,6 +635,8 @@ enum { #define ftrace_get_symaddr(fentry_ip) (0) #endif +void ftrace_sync_ipi(void *data); + #ifdef CONFIG_DYNAMIC_FTRACE void ftrace_arch_code_modify_prepare(void); diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 6981830c312859..5783c4a6e0f786 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -188,7 +188,7 @@ static void ftrace_pid_func(unsigned long ip, unsigned long parent_ip, op->saved_func(ip, parent_ip, op, fregs); } -static void ftrace_sync_ipi(void *data) +void ftrace_sync_ipi(void *data) { /* Probably not needed, but do it anyway */ smp_rmb(); From b7f56b9fdd08cf29e2a2b593eec799e39b8aaa1f Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Thu, 10 Apr 2025 07:05:24 +0000 Subject: [PATCH 13/91] riscv: uaccess: use input constraints for ptr of __put_user() Putting ptr in the inputs as opposed to output may seem incorrect but this is done for a few reasons: - Not having it in the output permits the use of asm goto in a subsequent patch. There are bugs in gcc [1] which would otherwise prevent it. - Since the output memory is userspace there isn't any real benefit from telling the compiler about the memory clobber. - x86, arm and powerpc all use this technique. Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113921 # 1 Signed-off-by: Jisheng Zhang [Cyril Bur: Rewritten commit message] Signed-off-by: Cyril Bur Reviewed-by: Alexandre Ghiti Reviewed-by: Charlie Jenkins Tested-by: Charlie Jenkins Link: https://lore.kernel.org/r/20250410070526.3160847-4-cyrilbur@tenstorrent.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/uaccess.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/riscv/include/asm/uaccess.h b/arch/riscv/include/asm/uaccess.h index c9a461467bf47a..da36057847f08b 100644 --- a/arch/riscv/include/asm/uaccess.h +++ b/arch/riscv/include/asm/uaccess.h @@ -219,11 +219,11 @@ do { \ __typeof__(*(ptr)) __x = x; \ __asm__ __volatile__ ( \ "1:\n" \ - " " insn " %z2, %1\n" \ + " " insn " %z1, %2\n" \ "2:\n" \ _ASM_EXTABLE_UACCESS_ERR(1b, 2b, %0) \ - : "+r" (err), "=m" (*(ptr)) \ - : "rJ" (__x)); \ + : "+r" (err) \ + : "rJ" (__x), "m"(*(ptr))); \ } while (0) #ifdef CONFIG_64BIT @@ -236,16 +236,16 @@ do { \ u64 __x = (__typeof__((x)-(x)))(x); \ __asm__ __volatile__ ( \ "1:\n" \ - " sw %z3, %1\n" \ + " sw %z1, %3\n" \ "2:\n" \ - " sw %z4, %2\n" \ + " sw %z2, %4\n" \ "3:\n" \ _ASM_EXTABLE_UACCESS_ERR(1b, 3b, %0) \ _ASM_EXTABLE_UACCESS_ERR(2b, 3b, %0) \ - : "+r" (err), \ - "=m" (__ptr[__LSW]), \ - "=m" (__ptr[__MSW]) \ - : "rJ" (__x), "rJ" (__x >> 32)); \ + : "+r" (err) \ + : "rJ" (__x), "rJ" (__x >> 32), \ + "m" (__ptr[__LSW]), \ + "m" (__ptr[__MSW])); \ } while (0) #endif /* CONFIG_64BIT */ From ec10ec6ce07953e236f7ad6d309e244612dad5dd Mon Sep 17 00:00:00 2001 From: Andy Chiu Date: Tue, 8 Apr 2025 02:08:29 +0800 Subject: [PATCH 14/91] riscv: ftrace: prepare ftrace for atomic code patching MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We use an AUIPC+JALR pair to jump into a ftrace trampoline. Since instruction fetch can break down to 4 byte at a time, it is impossible to update two instructions without a race. In order to mitigate it, we initialize the patchable entry to AUIPC + NOP4. Then, the run-time code patching can change NOP4 to JALR to eable/disable ftrcae from a function. This limits the reach of each ftrace entry to +-2KB displacing from ftrace_caller. Starting from the trampoline, we add a level of indirection for it to reach ftrace caller target. Now, it loads the target address from a memory location, then perform the jump. This enable the kernel to update the target atomically. The new don't-stop-the-world text patching on change only one RISC-V instruction: | -8: &ftrace_ops of the associated tracer function. | : | 0: auipc t0, hi(ftrace_caller) | 4: jalr t0, lo(ftrace_caller) | | -8: &ftrace_nop_ops | : | 0: auipc t0, hi(ftrace_caller) | 4: nop This means that f+0x0 is fixed, and should not be claimed by ftrace, e.g. kprobe should be able to put a probe in f+0x0. Thus, we adjust the offset and MCOUNT_INSN_SIZE accordingly. [ alex: Fix build errors with !CONFIG_DYNAMIC_FTRACE ] Co-developed-by: Björn Töpel Signed-off-by: Björn Töpel Signed-off-by: Andy Chiu Link: https://lore.kernel.org/r/20250407180838.42877-5-andybnac@gmail.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/ftrace.h | 49 +++++------- arch/riscv/kernel/ftrace.c | 137 +++++++++++++++++--------------- arch/riscv/kernel/mcount-dyn.S | 9 +-- 3 files changed, 98 insertions(+), 97 deletions(-) diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h index d8b2138bd9c664..6a5c0a7fb8268a 100644 --- a/arch/riscv/include/asm/ftrace.h +++ b/arch/riscv/include/asm/ftrace.h @@ -20,10 +20,9 @@ extern void *return_address(unsigned int level); #define ftrace_return_address(n) return_address(n) void _mcount(void); -static inline unsigned long ftrace_call_adjust(unsigned long addr) -{ - return addr; -} +unsigned long ftrace_call_adjust(unsigned long addr); +unsigned long arch_ftrace_get_symaddr(unsigned long fentry_ip); +#define ftrace_get_symaddr(fentry_ip) arch_ftrace_get_symaddr(fentry_ip) /* * Let's do like x86/arm64 and ignore the compat syscalls. @@ -57,12 +56,21 @@ struct dyn_arch_ftrace { * 2) jalr: setting low-12 offset to ra, jump to ra, and set ra to * return address (original pc + 4) * + * The first 2 instructions for each tracable function is compiled to 2 nop + * instructions. Then, the kernel initializes the first instruction to auipc at + * boot time (). The second instruction is patched to jalr to + * start the trace. + * + *: + * 0: nop + * 4: nop + * *: - * 0: auipc t0/ra, 0x? - * 4: jalr t0/ra, ?(t0/ra) + * 0: auipc t0, 0x? + * 4: jalr t0, ?(t0) * *: - * 0: nop + * 0: auipc t0, 0x? * 4: nop * * Dynamic ftrace generates probes to call sites, so we must deal with @@ -75,10 +83,9 @@ struct dyn_arch_ftrace { #define AUIPC_OFFSET_MASK (0xfffff000) #define AUIPC_PAD (0x00001000) #define JALR_SHIFT 20 -#define JALR_RA (0x000080e7) -#define AUIPC_RA (0x00000097) #define JALR_T0 (0x000282e7) #define AUIPC_T0 (0x00000297) +#define JALR_RANGE (JALR_SIGN_MASK - 1) #define to_jalr_t0(offset) \ (((offset & JALR_OFFSET_MASK) << JALR_SHIFT) | JALR_T0) @@ -96,26 +103,14 @@ do { \ call[1] = to_jalr_t0(offset); \ } while (0) -#define to_jalr_ra(offset) \ - (((offset & JALR_OFFSET_MASK) << JALR_SHIFT) | JALR_RA) - -#define to_auipc_ra(offset) \ - ((offset & JALR_SIGN_MASK) ? \ - (((offset & AUIPC_OFFSET_MASK) + AUIPC_PAD) | AUIPC_RA) : \ - ((offset & AUIPC_OFFSET_MASK) | AUIPC_RA)) - -#define make_call_ra(caller, callee, call) \ -do { \ - unsigned int offset = \ - (unsigned long) (callee) - (unsigned long) (caller); \ - call[0] = to_auipc_ra(offset); \ - call[1] = to_jalr_ra(offset); \ -} while (0) - /* - * Let auipc+jalr be the basic *mcount unit*, so we make it 8 bytes here. + * Only the jalr insn in the auipc+jalr is patched, so we make it 4 + * bytes here. */ -#define MCOUNT_INSN_SIZE 8 +#define MCOUNT_INSN_SIZE 4 +#define MCOUNT_AUIPC_SIZE 4 +#define MCOUNT_JALR_SIZE 4 +#define MCOUNT_NOP4_SIZE 4 #ifndef __ASSEMBLY__ struct dyn_ftrace; diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c index 1fd10555c58039..ea04f09f9d4d3f 100644 --- a/arch/riscv/kernel/ftrace.c +++ b/arch/riscv/kernel/ftrace.c @@ -8,11 +8,22 @@ #include #include #include +#include #include #include #include #ifdef CONFIG_DYNAMIC_FTRACE +unsigned long ftrace_call_adjust(unsigned long addr) +{ + return addr + MCOUNT_AUIPC_SIZE; +} + +unsigned long arch_ftrace_get_symaddr(unsigned long fentry_ip) +{ + return fentry_ip - MCOUNT_AUIPC_SIZE; +} + void ftrace_arch_code_modify_prepare(void) __acquires(&text_mutex) { mutex_lock(&text_mutex); @@ -32,51 +43,32 @@ void ftrace_arch_code_modify_post_process(void) __releases(&text_mutex) mutex_unlock(&text_mutex); } -static int ftrace_check_current_call(unsigned long hook_pos, - unsigned int *expected) +static int __ftrace_modify_call(unsigned long source, unsigned long target, bool validate) { + unsigned int call[2], offset; unsigned int replaced[2]; - unsigned int nops[2] = {RISCV_INSN_NOP4, RISCV_INSN_NOP4}; - /* we expect nops at the hook position */ - if (!expected) - expected = nops; + offset = target - source; + call[1] = to_jalr_t0(offset); - /* - * Read the text we want to modify; - * return must be -EFAULT on read error - */ - if (copy_from_kernel_nofault(replaced, (void *)hook_pos, - MCOUNT_INSN_SIZE)) - return -EFAULT; - - /* - * Make sure it is what we expect it to be; - * return must be -EINVAL on failed comparison - */ - if (memcmp(expected, replaced, sizeof(replaced))) { - pr_err("%p: expected (%08x %08x) but got (%08x %08x)\n", - (void *)hook_pos, expected[0], expected[1], replaced[0], - replaced[1]); - return -EINVAL; + if (validate) { + call[0] = to_auipc_t0(offset); + /* + * Read the text we want to modify; + * return must be -EFAULT on read error + */ + if (copy_from_kernel_nofault(replaced, (void *)source, 2 * MCOUNT_INSN_SIZE)) + return -EFAULT; + + if (replaced[0] != call[0]) { + pr_err("%p: expected (%08x) but got (%08x)\n", + (void *)source, call[0], replaced[0]); + return -EINVAL; + } } - return 0; -} - -static int __ftrace_modify_call(unsigned long hook_pos, unsigned long target, - bool enable, bool ra) -{ - unsigned int call[2]; - unsigned int nops[2] = {RISCV_INSN_NOP4, RISCV_INSN_NOP4}; - - if (ra) - make_call_ra(hook_pos, target, call); - else - make_call_t0(hook_pos, target, call); - - /* Replace the auipc-jalr pair at once. Return -EPERM on write error. */ - if (patch_insn_write((void *)hook_pos, enable ? call : nops, MCOUNT_INSN_SIZE)) + /* Replace the jalr at once. Return -EPERM on write error. */ + if (patch_insn_write((void *)(source + MCOUNT_AUIPC_SIZE), call + 1, MCOUNT_JALR_SIZE)) return -EPERM; return 0; @@ -84,22 +76,21 @@ static int __ftrace_modify_call(unsigned long hook_pos, unsigned long target, int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) { - unsigned int call[2]; - - make_call_t0(rec->ip, addr, call); + unsigned long distance, orig_addr, pc = rec->ip - MCOUNT_AUIPC_SIZE; - if (patch_insn_write((void *)rec->ip, call, MCOUNT_INSN_SIZE)) - return -EPERM; + orig_addr = (unsigned long)&ftrace_caller; + distance = addr > orig_addr ? addr - orig_addr : orig_addr - addr; + if (distance > JALR_RANGE) + return -EINVAL; - return 0; + return __ftrace_modify_call(pc, addr, false); } -int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, - unsigned long addr) +int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long addr) { - unsigned int nops[2] = {RISCV_INSN_NOP4, RISCV_INSN_NOP4}; + u32 nop4 = RISCV_INSN_NOP4; - if (patch_insn_write((void *)rec->ip, nops, MCOUNT_INSN_SIZE)) + if (patch_insn_write((void *)rec->ip, &nop4, MCOUNT_NOP4_SIZE)) return -EPERM; return 0; @@ -114,21 +105,38 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, */ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec) { - int out; + unsigned long pc = rec->ip - MCOUNT_AUIPC_SIZE; + unsigned int nops[2], offset; + int ret; + + offset = (unsigned long) &ftrace_caller - pc; + nops[0] = to_auipc_t0(offset); + nops[1] = RISCV_INSN_NOP4; mutex_lock(&text_mutex); - out = ftrace_make_nop(mod, rec, MCOUNT_ADDR); + ret = patch_insn_write((void *)pc, nops, 2 * MCOUNT_INSN_SIZE); mutex_unlock(&text_mutex); - return out; + return ret; } +ftrace_func_t ftrace_call_dest = ftrace_stub; int ftrace_update_ftrace_func(ftrace_func_t func) { - int ret = __ftrace_modify_call((unsigned long)&ftrace_call, - (unsigned long)func, true, true); - - return ret; + WRITE_ONCE(ftrace_call_dest, func); + /* + * The data fence ensure that the update to ftrace_call_dest happens + * before the write to function_trace_op later in the generic ftrace. + * If the sequence is not enforced, then an old ftrace_call_dest may + * race loading a new function_trace_op set in ftrace_modify_all_code + * + * If we are in stop_machine, then we don't need to call remote fence + * as there is no concurrent read-side of ftrace_call_dest. + */ + smp_wmb(); + if (!irqs_disabled()) + smp_call_function(ftrace_sync_ipi, NULL, 1); + return 0; } struct ftrace_modify_param { @@ -166,23 +174,22 @@ void arch_ftrace_update_code(int command) stop_machine(__ftrace_modify_code, ¶m, cpu_online_mask); } -#endif +#else /* CONFIG_DYNAMIC_FTRACE */ +unsigned long ftrace_call_adjust(unsigned long addr) +{ + return addr; +} +#endif /* CONFIG_DYNAMIC_FTRACE */ #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, unsigned long addr) { + unsigned long caller = rec->ip - MCOUNT_AUIPC_SIZE; unsigned int call[2]; - unsigned long caller = rec->ip; - int ret; make_call_t0(caller, old_addr, call); - ret = ftrace_check_current_call(caller, call); - - if (ret) - return ret; - - return __ftrace_modify_call(caller, addr, true, false); + return __ftrace_modify_call(caller, addr, true); } #endif diff --git a/arch/riscv/kernel/mcount-dyn.S b/arch/riscv/kernel/mcount-dyn.S index 3f06b40bb6c8cc..8aa554d5609626 100644 --- a/arch/riscv/kernel/mcount-dyn.S +++ b/arch/riscv/kernel/mcount-dyn.S @@ -13,7 +13,6 @@ .text -#define FENTRY_RA_OFFSET 8 #define ABI_SIZE_ON_STACK 80 #define ABI_A0 0 #define ABI_A1 8 @@ -62,8 +61,7 @@ * After the stack is established, * * 0(sp) stores the PC of the traced function which can be accessed -* by &(fregs)->epc in tracing function. Note that the real -* function entry address should be computed with -FENTRY_RA_OFFSET. +* by &(fregs)->epc in tracing function. * * 8(sp) stores the function return address (i.e. parent IP) that * can be accessed by &(fregs)->ra in tracing function. @@ -140,7 +138,7 @@ .endm .macro PREPARE_ARGS - addi a0, t0, -FENTRY_RA_OFFSET + addi a0, t0, -MCOUNT_JALR_SIZE // ip (callsite's jalr insn) la a1, function_trace_op REG_L a2, 0(a1) mv a1, ra @@ -153,7 +151,8 @@ SYM_FUNC_START(ftrace_caller) PREPARE_ARGS SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL) - call ftrace_stub + REG_L ra, ftrace_call_dest + jalr ra, 0(ra) RESTORE_ABI_REGS bnez t1, .Ldirect From 9f4dd8c286a1b9bfa844b04a3a06a68fb8b44f9f Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Thu, 10 Apr 2025 07:05:25 +0000 Subject: [PATCH 15/91] riscv: uaccess: use 'asm goto' for put_user() With 'asm goto' we don't need to test the error etc, the exception just jumps to the error handling directly. Because there are no output clobbers which could trigger gcc bugs [1] the use of asm_goto_output() macro is not necessary here. Not using asm_goto_output() is desirable as the generated output asm will be cleaner. Use of the volatile keyword is redundant as per gcc 14.2.0 manual section 6.48.2.7 Goto Labels: > Also note that an asm goto statement is always implicitly considered volatile. Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113921 # 1 Signed-off-by: Jisheng Zhang [Cyril Bur: Rewritten commit message] Signed-off-by: Cyril Bur Reviewed-by: Alexandre Ghiti Link: https://lore.kernel.org/r/20250410070526.3160847-5-cyrilbur@tenstorrent.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/uaccess.h | 71 +++++++++++++++----------------- 1 file changed, 33 insertions(+), 38 deletions(-) diff --git a/arch/riscv/include/asm/uaccess.h b/arch/riscv/include/asm/uaccess.h index da36057847f08b..719c9179a7517d 100644 --- a/arch/riscv/include/asm/uaccess.h +++ b/arch/riscv/include/asm/uaccess.h @@ -214,61 +214,66 @@ do { \ ((x) = (__force __typeof__(x))0, -EFAULT); \ }) -#define __put_user_asm(insn, x, ptr, err) \ +#define __put_user_asm(insn, x, ptr, label) \ do { \ __typeof__(*(ptr)) __x = x; \ - __asm__ __volatile__ ( \ + asm goto( \ "1:\n" \ - " " insn " %z1, %2\n" \ - "2:\n" \ - _ASM_EXTABLE_UACCESS_ERR(1b, 2b, %0) \ - : "+r" (err) \ - : "rJ" (__x), "m"(*(ptr))); \ + " " insn " %z0, %1\n" \ + _ASM_EXTABLE(1b, %l2) \ + : : "rJ" (__x), "m"(*(ptr)) : : label); \ } while (0) #ifdef CONFIG_64BIT -#define __put_user_8(x, ptr, err) \ - __put_user_asm("sd", x, ptr, err) +#define __put_user_8(x, ptr, label) \ + __put_user_asm("sd", x, ptr, label) #else /* !CONFIG_64BIT */ -#define __put_user_8(x, ptr, err) \ +#define __put_user_8(x, ptr, label) \ do { \ u32 __user *__ptr = (u32 __user *)(ptr); \ u64 __x = (__typeof__((x)-(x)))(x); \ - __asm__ __volatile__ ( \ + asm goto( \ "1:\n" \ - " sw %z1, %3\n" \ + " sw %z0, %2\n" \ "2:\n" \ - " sw %z2, %4\n" \ - "3:\n" \ - _ASM_EXTABLE_UACCESS_ERR(1b, 3b, %0) \ - _ASM_EXTABLE_UACCESS_ERR(2b, 3b, %0) \ - : "+r" (err) \ - : "rJ" (__x), "rJ" (__x >> 32), \ + " sw %z1, %3\n" \ + _ASM_EXTABLE(1b, %l4) \ + _ASM_EXTABLE(2b, %l4) \ + : : "rJ" (__x), "rJ" (__x >> 32), \ "m" (__ptr[__LSW]), \ - "m" (__ptr[__MSW])); \ + "m" (__ptr[__MSW]) : : label); \ } while (0) #endif /* CONFIG_64BIT */ -#define __put_user_nocheck(x, __gu_ptr, __pu_err) \ +#define __put_user_nocheck(x, __gu_ptr, label) \ do { \ switch (sizeof(*__gu_ptr)) { \ case 1: \ - __put_user_asm("sb", (x), __gu_ptr, __pu_err); \ + __put_user_asm("sb", (x), __gu_ptr, label); \ break; \ case 2: \ - __put_user_asm("sh", (x), __gu_ptr, __pu_err); \ + __put_user_asm("sh", (x), __gu_ptr, label); \ break; \ case 4: \ - __put_user_asm("sw", (x), __gu_ptr, __pu_err); \ + __put_user_asm("sw", (x), __gu_ptr, label); \ break; \ case 8: \ - __put_user_8((x), __gu_ptr, __pu_err); \ + __put_user_8((x), __gu_ptr, label); \ break; \ default: \ BUILD_BUG(); \ } \ } while (0) +#define __put_user_error(x, ptr, err) \ +do { \ + __label__ err_label; \ + __put_user_nocheck(x, ptr, err_label); \ + break; \ +err_label: \ + (err) = -EFAULT; \ +} while (0) + /** * __put_user: - Write a simple value into user space, with less checking. * @x: Value to copy to user space. @@ -299,7 +304,7 @@ do { \ __chk_user_ptr(__gu_ptr); \ \ __enable_user_access(); \ - __put_user_nocheck(__val, __gu_ptr, __pu_err); \ + __put_user_error(__val, __gu_ptr, __pu_err); \ __disable_user_access(); \ \ __pu_err; \ @@ -373,13 +378,7 @@ do { \ } while (0) #define __put_kernel_nofault(dst, src, type, err_label) \ -do { \ - long __kr_err = 0; \ - \ - __put_user_nocheck(*((type *)(src)), (type *)(dst), __kr_err); \ - if (unlikely(__kr_err)) \ - goto err_label; \ -} while (0) + __put_user_nocheck(*((type *)(src)), (type *)(dst), err_label) static __must_check __always_inline bool user_access_begin(const void __user *ptr, size_t len) { @@ -398,12 +397,8 @@ static inline void user_access_restore(unsigned long enabled) { } * We want the unsafe accessors to always be inlined and use * the error labels - thus the macro games. */ -#define unsafe_put_user(x, ptr, label) do { \ - long __err = 0; \ - __put_user_nocheck(x, (ptr), __err); \ - if (__err) \ - goto label; \ -} while (0) +#define unsafe_put_user(x, ptr, label) \ + __put_user_nocheck(x, (ptr), label) #define unsafe_get_user(x, ptr, label) do { \ long __err = 0; \ From 224924ba30671fd527fb3855e5469ae341720976 Mon Sep 17 00:00:00 2001 From: Andy Chiu Date: Tue, 8 Apr 2025 02:08:30 +0800 Subject: [PATCH 16/91] riscv: ftrace: do not use stop_machine to update code Now it is safe to remove dependency from stop_machine() for us to patch code in ftrace. Signed-off-by: Andy Chiu Link: https://lore.kernel.org/r/20250407180838.42877-6-andybnac@gmail.com Signed-off-by: Alexandre Ghiti --- arch/riscv/kernel/ftrace.c | 64 ++++++-------------------------------- 1 file changed, 10 insertions(+), 54 deletions(-) diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c index ea04f09f9d4d3f..b133c60808fe01 100644 --- a/arch/riscv/kernel/ftrace.c +++ b/arch/riscv/kernel/ftrace.c @@ -24,23 +24,13 @@ unsigned long arch_ftrace_get_symaddr(unsigned long fentry_ip) return fentry_ip - MCOUNT_AUIPC_SIZE; } -void ftrace_arch_code_modify_prepare(void) __acquires(&text_mutex) +void arch_ftrace_update_code(int command) { mutex_lock(&text_mutex); - - /* - * The code sequences we use for ftrace can't be patched while the - * kernel is running, so we need to use stop_machine() to modify them - * for now. This doesn't play nice with text_mutex, we use this flag - * to elide the check. - */ - riscv_patch_in_stop_machine = true; -} - -void ftrace_arch_code_modify_post_process(void) __releases(&text_mutex) -{ - riscv_patch_in_stop_machine = false; + command |= FTRACE_MAY_SLEEP; + ftrace_modify_all_code(command); mutex_unlock(&text_mutex); + flush_icache_all(); } static int __ftrace_modify_call(unsigned long source, unsigned long target, bool validate) @@ -129,51 +119,17 @@ int ftrace_update_ftrace_func(ftrace_func_t func) * before the write to function_trace_op later in the generic ftrace. * If the sequence is not enforced, then an old ftrace_call_dest may * race loading a new function_trace_op set in ftrace_modify_all_code - * - * If we are in stop_machine, then we don't need to call remote fence - * as there is no concurrent read-side of ftrace_call_dest. */ smp_wmb(); - if (!irqs_disabled()) - smp_call_function(ftrace_sync_ipi, NULL, 1); - return 0; -} - -struct ftrace_modify_param { - int command; - atomic_t cpu_count; -}; - -static int __ftrace_modify_code(void *data) -{ - struct ftrace_modify_param *param = data; - - if (atomic_inc_return(¶m->cpu_count) == num_online_cpus()) { - ftrace_modify_all_code(param->command); - /* - * Make sure the patching store is effective *before* we - * increment the counter which releases all waiting CPUs - * by using the release variant of atomic increment. The - * release pairs with the call to local_flush_icache_all() - * on the waiting CPU. - */ - atomic_inc_return_release(¶m->cpu_count); - } else { - while (atomic_read(¶m->cpu_count) <= num_online_cpus()) - cpu_relax(); - - local_flush_icache_all(); - } - + /* + * Updating ftrace dpes not take stop_machine path, so irqs should not + * be disabled. + */ + WARN_ON(irqs_disabled()); + smp_call_function(ftrace_sync_ipi, NULL, 1); return 0; } -void arch_ftrace_update_code(int command) -{ - struct ftrace_modify_param param = { command, ATOMIC_INIT(0) }; - - stop_machine(__ftrace_modify_code, ¶m, cpu_online_mask); -} #else /* CONFIG_DYNAMIC_FTRACE */ unsigned long ftrace_call_adjust(unsigned long addr) { From ed5d6b9ed2089593f944d140a583498d0cefdad7 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Thu, 10 Apr 2025 07:05:26 +0000 Subject: [PATCH 17/91] riscv: uaccess: use 'asm_goto_output' for get_user() With 'asm goto' we don't need to test the error etc, the exception just jumps to the error handling directly. Unlike put_user(), get_user() must work around GCC bugs [1] when using output clobbers in an asm goto statement. Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113921 # 1 Signed-off-by: Jisheng Zhang [Cyril Bur: Rewritten commit message] Signed-off-by: Cyril Bur Reviewed-by: Alexandre Ghiti Link: https://lore.kernel.org/r/20250410070526.3160847-6-cyrilbur@tenstorrent.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/uaccess.h | 95 +++++++++++++++++++++++--------- 1 file changed, 68 insertions(+), 27 deletions(-) diff --git a/arch/riscv/include/asm/uaccess.h b/arch/riscv/include/asm/uaccess.h index 719c9179a7517d..87d01168f80af6 100644 --- a/arch/riscv/include/asm/uaccess.h +++ b/arch/riscv/include/asm/uaccess.h @@ -96,27 +96,58 @@ static inline unsigned long __untagged_addr_remote(struct mm_struct *mm, unsigne * call. */ -#define __get_user_asm(insn, x, ptr, err) \ +#ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT +#define __get_user_asm(insn, x, ptr, label) \ + asm_goto_output( \ + "1:\n" \ + " " insn " %0, %1\n" \ + _ASM_EXTABLE_UACCESS_ERR(1b, %l2, %0) \ + : "=&r" (x) \ + : "m" (*(ptr)) : : label) +#else /* !CONFIG_CC_HAS_ASM_GOTO_OUTPUT */ +#define __get_user_asm(insn, x, ptr, label) \ do { \ - __typeof__(x) __x; \ + long __gua_err = 0; \ __asm__ __volatile__ ( \ "1:\n" \ " " insn " %1, %2\n" \ "2:\n" \ _ASM_EXTABLE_UACCESS_ERR_ZERO(1b, 2b, %0, %1) \ - : "+r" (err), "=&r" (__x) \ + : "+r" (__gua_err), "=&r" (x) \ : "m" (*(ptr))); \ - (x) = __x; \ + if (__gua_err) \ + goto label; \ } while (0) +#endif /* CONFIG_CC_HAS_ASM_GOTO_OUTPUT */ #ifdef CONFIG_64BIT -#define __get_user_8(x, ptr, err) \ - __get_user_asm("ld", x, ptr, err) +#define __get_user_8(x, ptr, label) \ + __get_user_asm("ld", x, ptr, label) #else /* !CONFIG_64BIT */ -#define __get_user_8(x, ptr, err) \ + +#ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT +#define __get_user_8(x, ptr, label) \ + u32 __user *__ptr = (u32 __user *)(ptr); \ + u32 __lo, __hi; \ + asm_goto_output( \ + "1:\n" \ + " lw %0, %2\n" \ + "2:\n" \ + " lw %1, %3\n" \ + _ASM_EXTABLE_UACCESS_ERR(1b, %l4, %0) \ + _ASM_EXTABLE_UACCESS_ERR(2b, %l4, %0) \ + : "=&r" (__lo), "=r" (__hi) \ + : "m" (__ptr[__LSW]), "m" (__ptr[__MSW]) \ + : : label); \ + (x) = (__typeof__(x))((__typeof__((x) - (x)))( \ + (((u64)__hi << 32) | __lo))); \ + +#else /* !CONFIG_CC_HAS_ASM_GOTO_OUTPUT */ +#define __get_user_8(x, ptr, label) \ do { \ u32 __user *__ptr = (u32 __user *)(ptr); \ u32 __lo, __hi; \ + long __gu8_err = 0; \ __asm__ __volatile__ ( \ "1:\n" \ " lw %1, %3\n" \ @@ -125,35 +156,51 @@ do { \ "3:\n" \ _ASM_EXTABLE_UACCESS_ERR_ZERO(1b, 3b, %0, %1) \ _ASM_EXTABLE_UACCESS_ERR_ZERO(2b, 3b, %0, %1) \ - : "+r" (err), "=&r" (__lo), "=r" (__hi) \ + : "+r" (__gu8_err), "=&r" (__lo), "=r" (__hi) \ : "m" (__ptr[__LSW]), "m" (__ptr[__MSW])); \ - if (err) \ + if (__gu8_err) { \ __hi = 0; \ - (x) = (__typeof__(x))((__typeof__((x)-(x)))( \ + goto label; \ + } \ + (x) = (__typeof__(x))((__typeof__((x) - (x)))( \ (((u64)__hi << 32) | __lo))); \ } while (0) +#endif /* CONFIG_CC_HAS_ASM_GOTO_OUTPUT */ + #endif /* CONFIG_64BIT */ -#define __get_user_nocheck(x, __gu_ptr, __gu_err) \ +#define __get_user_nocheck(x, __gu_ptr, label) \ do { \ switch (sizeof(*__gu_ptr)) { \ case 1: \ - __get_user_asm("lb", (x), __gu_ptr, __gu_err); \ + __get_user_asm("lb", (x), __gu_ptr, label); \ break; \ case 2: \ - __get_user_asm("lh", (x), __gu_ptr, __gu_err); \ + __get_user_asm("lh", (x), __gu_ptr, label); \ break; \ case 4: \ - __get_user_asm("lw", (x), __gu_ptr, __gu_err); \ + __get_user_asm("lw", (x), __gu_ptr, label); \ break; \ case 8: \ - __get_user_8((x), __gu_ptr, __gu_err); \ + __get_user_8((x), __gu_ptr, label); \ break; \ default: \ BUILD_BUG(); \ } \ } while (0) +#define __get_user_error(x, ptr, err) \ +do { \ + __label__ __gu_failed; \ + \ + __get_user_nocheck(x, ptr, __gu_failed); \ + err = 0; \ + break; \ +__gu_failed: \ + x = 0; \ + err = -EFAULT; \ +} while (0) + /** * __get_user: - Get a simple variable from user space, with less checking. * @x: Variable to store result. @@ -178,13 +225,16 @@ do { \ ({ \ const __typeof__(*(ptr)) __user *__gu_ptr = untagged_addr(ptr); \ long __gu_err = 0; \ + __typeof__(x) __gu_val; \ \ __chk_user_ptr(__gu_ptr); \ \ __enable_user_access(); \ - __get_user_nocheck(x, __gu_ptr, __gu_err); \ + __get_user_error(__gu_val, __gu_ptr, __gu_err); \ __disable_user_access(); \ \ + (x) = __gu_val; \ + \ __gu_err; \ }) @@ -369,13 +419,7 @@ unsigned long __must_check clear_user(void __user *to, unsigned long n) } #define __get_kernel_nofault(dst, src, type, err_label) \ -do { \ - long __kr_err = 0; \ - \ - __get_user_nocheck(*((type *)(dst)), (type *)(src), __kr_err); \ - if (unlikely(__kr_err)) \ - goto err_label; \ -} while (0) + __get_user_nocheck(*((type *)(dst)), (type *)(src), err_label) #define __put_kernel_nofault(dst, src, type, err_label) \ __put_user_nocheck(*((type *)(src)), (type *)(dst), err_label) @@ -401,12 +445,9 @@ static inline void user_access_restore(unsigned long enabled) { } __put_user_nocheck(x, (ptr), label) #define unsafe_get_user(x, ptr, label) do { \ - long __err = 0; \ __inttype(*(ptr)) __gu_val; \ - __get_user_nocheck(__gu_val, (ptr), __err); \ + __get_user_nocheck(__gu_val, (ptr), label); \ (x) = (__force __typeof__(*(ptr)))__gu_val; \ - if (__err) \ - goto label; \ } while (0) #define unsafe_copy_loop(dst, src, len, type, op, label) \ From 7b0f44158ef4a48cb9ec09352ff000846e4e69e0 Mon Sep 17 00:00:00 2001 From: Andy Chiu Date: Tue, 8 Apr 2025 02:08:31 +0800 Subject: [PATCH 18/91] riscv: vector: Support calling schedule() for preemptible Vector Each function entry implies a call to ftrace infrastructure. And it may call into schedule in some cases. So, it is possible for preemptible kernel-mode Vector to implicitly call into schedule. Since all V-regs are caller-saved, it is possible to drop all V context when a thread voluntarily call schedule(). Besides, we currently don't pass argument through vector register, so we don't have to save/restore V-regs in ftrace trampoline. Signed-off-by: Andy Chiu Link: https://lore.kernel.org/r/20250407180838.42877-7-andybnac@gmail.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/processor.h | 5 +++++ arch/riscv/include/asm/vector.h | 22 +++++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h index 5f56eb9d114a95..9c1cc716b89129 100644 --- a/arch/riscv/include/asm/processor.h +++ b/arch/riscv/include/asm/processor.h @@ -79,6 +79,10 @@ struct pt_regs; * Thus, the task does not own preempt_v. Any use of Vector will have to * save preempt_v, if dirty, and fallback to non-preemptible kernel-mode * Vector. + * - bit 29: The thread voluntarily calls schedule() while holding an active + * preempt_v. All preempt_v context should be dropped in such case because + * V-regs are caller-saved. Only sstatus.VS=ON is persisted across a + * schedule() call. * - bit 30: The in-kernel preempt_v context is saved, and requries to be * restored when returning to the context that owns the preempt_v. * - bit 31: The in-kernel preempt_v context is dirty, as signaled by the @@ -93,6 +97,7 @@ struct pt_regs; #define RISCV_PREEMPT_V 0x00000100 #define RISCV_PREEMPT_V_DIRTY 0x80000000 #define RISCV_PREEMPT_V_NEED_RESTORE 0x40000000 +#define RISCV_PREEMPT_V_IN_SCHEDULE 0x20000000 /* CPU-specific state of a task */ struct thread_struct { diff --git a/arch/riscv/include/asm/vector.h b/arch/riscv/include/asm/vector.h index e8a83f55be2ba5..45c9b426fcc523 100644 --- a/arch/riscv/include/asm/vector.h +++ b/arch/riscv/include/asm/vector.h @@ -120,6 +120,11 @@ static __always_inline void riscv_v_disable(void) csr_clear(CSR_SSTATUS, SR_VS); } +static __always_inline bool riscv_v_is_on(void) +{ + return !!(csr_read(CSR_SSTATUS) & SR_VS); +} + static __always_inline void __vstate_csr_save(struct __riscv_v_ext_state *dest) { asm volatile ( @@ -366,6 +371,11 @@ static inline void __switch_to_vector(struct task_struct *prev, struct pt_regs *regs; if (riscv_preempt_v_started(prev)) { + if (riscv_v_is_on()) { + WARN_ON(prev->thread.riscv_v_flags & RISCV_V_CTX_DEPTH_MASK); + riscv_v_disable(); + prev->thread.riscv_v_flags |= RISCV_PREEMPT_V_IN_SCHEDULE; + } if (riscv_preempt_v_dirty(prev)) { __riscv_v_vstate_save(&prev->thread.kernel_vstate, prev->thread.kernel_vstate.datap); @@ -376,10 +386,16 @@ static inline void __switch_to_vector(struct task_struct *prev, riscv_v_vstate_save(&prev->thread.vstate, regs); } - if (riscv_preempt_v_started(next)) - riscv_preempt_v_set_restore(next); - else + if (riscv_preempt_v_started(next)) { + if (next->thread.riscv_v_flags & RISCV_PREEMPT_V_IN_SCHEDULE) { + next->thread.riscv_v_flags &= ~RISCV_PREEMPT_V_IN_SCHEDULE; + riscv_v_enable(); + } else { + riscv_preempt_v_set_restore(next); + } + } else { riscv_v_vstate_set_restore(next, task_pt_regs(next)); + } } void riscv_v_vstate_ctrl_init(struct task_struct *tsk); From 39e7f74e0939e7b9cd7300120c2496cba17a8320 Mon Sep 17 00:00:00 2001 From: Andy Chiu Date: Tue, 8 Apr 2025 02:08:32 +0800 Subject: [PATCH 19/91] riscv: add a data fence for CMODX in the kernel mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RISC-V spec explicitly calls out that a local fence.i is not enough for the code modification to be visble from a remote hart. In fact, it states: To make a store to instruction memory visible to all RISC-V harts, the writing hart also has to execute a data FENCE before requesting that all remote RISC-V harts execute a FENCE.I. Although current riscv drivers for IPI use ordered MMIO when sending IPIs in order to synchronize the action between previous csd writes, riscv does not restrict itself to any particular flavor of IPI. Any driver or firmware implementation that does not order data writes before the IPI may pose a risk for code-modifying race. Thus, add a fence here to order data writes before making the IPI. Signed-off-by: Andy Chiu Reviewed-by: Björn Töpel Link: https://lore.kernel.org/r/20250407180838.42877-8-andybnac@gmail.com Signed-off-by: Alexandre Ghiti --- arch/riscv/mm/cacheflush.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/arch/riscv/mm/cacheflush.c b/arch/riscv/mm/cacheflush.c index b8167272988723..b2e4b81763f888 100644 --- a/arch/riscv/mm/cacheflush.c +++ b/arch/riscv/mm/cacheflush.c @@ -24,7 +24,20 @@ void flush_icache_all(void) if (num_online_cpus() < 2) return; - else if (riscv_use_sbi_for_rfence()) + + /* + * Make sure all previous writes to the D$ are ordered before making + * the IPI. The RISC-V spec states that a hart must execute a data fence + * before triggering a remote fence.i in order to make the modification + * visable for remote harts. + * + * IPIs on RISC-V are triggered by MMIO writes to either CLINT or + * S-IMSIC, so the fence ensures previous data writes "happen before" + * the MMIO. + */ + RISCV_FENCE(w, o); + + if (riscv_use_sbi_for_rfence()) sbi_remote_fence_i(NULL); else on_each_cpu(ipi_remote_fence_i, NULL, 1); From ecca5b076267ef2084518ce034058cdbc5bb7bb1 Mon Sep 17 00:00:00 2001 From: Andy Chiu Date: Tue, 8 Apr 2025 02:08:33 +0800 Subject: [PATCH 20/91] riscv: ftrace: support PREEMPT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now, we can safely enable dynamic ftrace with kernel preemption. Signed-off-by: Andy Chiu Reviewed-by: Björn Töpel Link: https://lore.kernel.org/r/20250407180838.42877-9-andybnac@gmail.com Signed-off-by: Alexandre Ghiti --- arch/riscv/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 7dbed10843d282..dc0fc11b6e9627 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -157,7 +157,7 @@ config RISCV select HAVE_FTRACE_MCOUNT_RECORD if !XIP_KERNEL select HAVE_FUNCTION_GRAPH_TRACER if HAVE_DYNAMIC_FTRACE_WITH_ARGS select HAVE_FUNCTION_GRAPH_FREGS - select HAVE_FUNCTION_TRACER if !XIP_KERNEL && !PREEMPTION + select HAVE_FUNCTION_TRACER if !XIP_KERNEL select HAVE_EBPF_JIT if MMU select HAVE_GUP_FAST if MMU select HAVE_FUNCTION_ARG_ACCESS_API From fd3a21f078f9879776c999b8e9f7d01ef50d92b9 Mon Sep 17 00:00:00 2001 From: Puranjay Mohan Date: Tue, 8 Apr 2025 02:08:34 +0800 Subject: [PATCH 21/91] riscv: Implement HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch enables support for DYNAMIC_FTRACE_WITH_CALL_OPS on RISC-V. This allows each ftrace callsite to provide an ftrace_ops to the common ftrace trampoline, allowing each callsite to invoke distinct tracer functions without the need to fall back to list processing or to allocate custom trampolines for each callsite. This significantly speeds up cases where multiple distinct trace functions are used and callsites are mostly traced by a single tracer. The idea and most of the implementation is taken from the ARM64's implementation of the same feature. The idea is to place a pointer to the ftrace_ops as a literal at a fixed offset from the function entry point, which can be recovered by the common ftrace trampoline. We use -fpatchable-function-entry to reserve 8 bytes above the function entry by emitting 2 4 byte or 4 2 byte nops depending on the presence of CONFIG_RISCV_ISA_C. These 8 bytes are patched at runtime with a pointer to the associated ftrace_ops for that callsite. Functions are aligned to 8 bytes to make sure that the accesses to this literal are atomic. This approach allows for directly invoking ftrace_ops::func even for ftrace_ops which are dynamically-allocated (or part of a module), without going via ftrace_ops_list_func. We've benchamrked this with the ftrace_ops sample module on Spacemit K1 Jupiter: Without this patch: baseline (Linux rivos 6.14.0-09584-g7d06015d936c #3 SMP Sat Mar 29 +-----------------------+-----------------+----------------------------+ | Number of tracers | Total time (ns) | Per-call average time | |-----------------------+-----------------+----------------------------| | Relevant | Irrelevant | 100000 calls | Total (ns) | Overhead (ns) | |----------+------------+-----------------+------------+---------------| | 0 | 0 | 1357958 | 13 | - | | 0 | 1 | 1302375 | 13 | - | | 0 | 2 | 1302375 | 13 | - | | 0 | 10 | 1379084 | 13 | - | | 0 | 100 | 1302458 | 13 | - | | 0 | 200 | 1302333 | 13 | - | |----------+------------+-----------------+------------+---------------| | 1 | 0 | 13677833 | 136 | 123 | | 1 | 1 | 18500916 | 185 | 172 | | 1 | 2 | 22856459 | 228 | 215 | | 1 | 10 | 58824709 | 588 | 575 | | 1 | 100 | 505141584 | 5051 | 5038 | | 1 | 200 | 1580473126 | 15804 | 15791 | |----------+------------+-----------------+------------+---------------| | 1 | 0 | 13561000 | 135 | 122 | | 2 | 0 | 19707292 | 197 | 184 | | 10 | 0 | 67774750 | 677 | 664 | | 100 | 0 | 714123125 | 7141 | 7128 | | 200 | 0 | 1918065668 | 19180 | 19167 | +----------+------------+-----------------+------------+---------------+ Note: per-call overhead is estimated relative to the baseline case with 0 relevant tracers and 0 irrelevant tracers. With this patch: v4-rc4 (Linux rivos 6.14.0-09598-gd75747611c93 #4 SMP Sat Mar 29 +-----------------------+-----------------+----------------------------+ | Number of tracers | Total time (ns) | Per-call average time | |-----------------------+-----------------+----------------------------| | Relevant | Irrelevant | 100000 calls | Total (ns) | Overhead (ns) | |----------+------------+-----------------+------------+---------------| | 0 | 0 | 1459917 | 14 | - | | 0 | 1 | 1408000 | 14 | - | | 0 | 2 | 1383792 | 13 | - | | 0 | 10 | 1430709 | 14 | - | | 0 | 100 | 1383791 | 13 | - | | 0 | 200 | 1383750 | 13 | - | |----------+------------+-----------------+------------+---------------| | 1 | 0 | 5238041 | 52 | 38 | | 1 | 1 | 5228542 | 52 | 38 | | 1 | 2 | 5325917 | 53 | 40 | | 1 | 10 | 5299667 | 52 | 38 | | 1 | 100 | 5245250 | 52 | 39 | | 1 | 200 | 5238459 | 52 | 39 | |----------+------------+-----------------+------------+---------------| | 1 | 0 | 5239083 | 52 | 38 | | 2 | 0 | 19449417 | 194 | 181 | | 10 | 0 | 67718584 | 677 | 663 | | 100 | 0 | 709840708 | 7098 | 7085 | | 200 | 0 | 2203580626 | 22035 | 22022 | +----------+------------+-----------------+------------+---------------+ Note: per-call overhead is estimated relative to the baseline case with 0 relevant tracers and 0 irrelevant tracers. As can be seen from the above: a) Whenever there is a single relevant tracer function associated with a tracee, the overhead of invoking the tracer is constant, and does not scale with the number of tracers which are *not* associated with that tracee. b) The overhead for a single relevant tracer has dropped to ~1/3 of the overhead prior to this series (from 122ns to 38ns). This is largely due to permitting calls to dynamically-allocated ftrace_ops without going through ftrace_ops_list_func. Signed-off-by: Puranjay Mohan [update kconfig, asm, refactor] Signed-off-by: Andy Chiu Tested-by: Björn Töpel Link: https://lore.kernel.org/r/20250407180838.42877-10-andybnac@gmail.com Signed-off-by: Alexandre Ghiti --- arch/riscv/Kconfig | 2 + arch/riscv/Makefile | 4 +- arch/riscv/kernel/asm-offsets.c | 3 ++ arch/riscv/kernel/ftrace.c | 67 +++++++++++++++++++++++++++++++++ arch/riscv/kernel/mcount-dyn.S | 35 +++++++++++++++-- 5 files changed, 105 insertions(+), 6 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index dc0fc11b6e9627..ec986c9120e3e9 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -99,6 +99,7 @@ config RISCV select EDAC_SUPPORT select FRAME_POINTER if PERF_EVENTS || (FUNCTION_TRACER && !DYNAMIC_FTRACE) select FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY if DYNAMIC_FTRACE + select FUNCTION_ALIGNMENT_8B if DYNAMIC_FTRACE_WITH_CALL_OPS select GENERIC_ARCH_TOPOLOGY select GENERIC_ATOMIC64 if !64BIT select GENERIC_CLOCKEVENTS_BROADCAST if SMP @@ -152,6 +153,7 @@ config RISCV select HAVE_DYNAMIC_FTRACE if !XIP_KERNEL && MMU && (CLANG_SUPPORTS_DYNAMIC_FTRACE || GCC_SUPPORTS_DYNAMIC_FTRACE) select FUNCTION_ALIGNMENT_4B if HAVE_DYNAMIC_FTRACE && RISCV_ISA_C select HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS + select HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS if (DYNAMIC_FTRACE_WITH_ARGS && !CFI_CLANG) select HAVE_DYNAMIC_FTRACE_WITH_ARGS if HAVE_DYNAMIC_FTRACE select HAVE_FTRACE_GRAPH_FUNC select HAVE_FTRACE_MCOUNT_RECORD if !XIP_KERNEL diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index 539d2aef5cab98..df57654a615e00 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -15,9 +15,9 @@ ifeq ($(CONFIG_DYNAMIC_FTRACE),y) LDFLAGS_vmlinux += --no-relax KBUILD_CPPFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY ifeq ($(CONFIG_RISCV_ISA_C),y) - CC_FLAGS_FTRACE := -fpatchable-function-entry=4 + CC_FLAGS_FTRACE := -fpatchable-function-entry=8,4 else - CC_FLAGS_FTRACE := -fpatchable-function-entry=2 + CC_FLAGS_FTRACE := -fpatchable-function-entry=4,2 endif endif diff --git a/arch/riscv/kernel/asm-offsets.c b/arch/riscv/kernel/asm-offsets.c index 7c43c8e26ae7f7..2d96197a8abfb5 100644 --- a/arch/riscv/kernel/asm-offsets.c +++ b/arch/riscv/kernel/asm-offsets.c @@ -493,6 +493,9 @@ void asm_offsets(void) DEFINE(STACKFRAME_SIZE_ON_STACK, ALIGN(sizeof(struct stackframe), STACK_ALIGN)); OFFSET(STACKFRAME_FP, stackframe, fp); OFFSET(STACKFRAME_RA, stackframe, ra); +#ifdef CONFIG_FUNCTION_TRACER + DEFINE(FTRACE_OPS_FUNC, offsetof(struct ftrace_ops, func)); +#endif #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS DEFINE(FREGS_SIZE_ON_STACK, ALIGN(sizeof(struct __arch_ftrace_regs), STACK_ALIGN)); diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c index b133c60808fe01..d56fc6e9fba091 100644 --- a/arch/riscv/kernel/ftrace.c +++ b/arch/riscv/kernel/ftrace.c @@ -16,6 +16,9 @@ #ifdef CONFIG_DYNAMIC_FTRACE unsigned long ftrace_call_adjust(unsigned long addr) { + if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS)) + return addr + 8; + return addr + MCOUNT_AUIPC_SIZE; } @@ -64,9 +67,52 @@ static int __ftrace_modify_call(unsigned long source, unsigned long target, bool return 0; } +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS +static const struct ftrace_ops *riscv64_rec_get_ops(struct dyn_ftrace *rec) +{ + const struct ftrace_ops *ops = NULL; + + if (rec->flags & FTRACE_FL_CALL_OPS_EN) { + ops = ftrace_find_unique_ops(rec); + WARN_ON_ONCE(!ops); + } + + if (!ops) + ops = &ftrace_list_ops; + + return ops; +} + +static int ftrace_rec_set_ops(const struct dyn_ftrace *rec, + const struct ftrace_ops *ops) +{ + unsigned long literal = rec->ip - 8; + + return patch_text_nosync((void *)literal, &ops, sizeof(ops)); +} + +static int ftrace_rec_set_nop_ops(struct dyn_ftrace *rec) +{ + return ftrace_rec_set_ops(rec, &ftrace_nop_ops); +} + +static int ftrace_rec_update_ops(struct dyn_ftrace *rec) +{ + return ftrace_rec_set_ops(rec, riscv64_rec_get_ops(rec)); +} +#else +static int ftrace_rec_set_nop_ops(struct dyn_ftrace *rec) { return 0; } +static int ftrace_rec_update_ops(struct dyn_ftrace *rec) { return 0; } +#endif + int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) { unsigned long distance, orig_addr, pc = rec->ip - MCOUNT_AUIPC_SIZE; + int ret; + + ret = ftrace_rec_update_ops(rec); + if (ret) + return ret; orig_addr = (unsigned long)&ftrace_caller; distance = addr > orig_addr ? addr - orig_addr : orig_addr - addr; @@ -79,6 +125,11 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long addr) { u32 nop4 = RISCV_INSN_NOP4; + int ret; + + ret = ftrace_rec_set_nop_ops(rec); + if (ret) + return ret; if (patch_insn_write((void *)rec->ip, &nop4, MCOUNT_NOP4_SIZE)) return -EPERM; @@ -99,6 +150,10 @@ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec) unsigned int nops[2], offset; int ret; + ret = ftrace_rec_set_nop_ops(rec); + if (ret) + return ret; + offset = (unsigned long) &ftrace_caller - pc; nops[0] = to_auipc_t0(offset); nops[1] = RISCV_INSN_NOP4; @@ -113,6 +168,13 @@ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec) ftrace_func_t ftrace_call_dest = ftrace_stub; int ftrace_update_ftrace_func(ftrace_func_t func) { + /* + * When using CALL_OPS, the function to call is associated with the + * call site, and we don't have a global function pointer to update. + */ + if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS)) + return 0; + WRITE_ONCE(ftrace_call_dest, func); /* * The data fence ensure that the update to ftrace_call_dest happens @@ -143,8 +205,13 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, { unsigned long caller = rec->ip - MCOUNT_AUIPC_SIZE; unsigned int call[2]; + int ret; make_call_t0(caller, old_addr, call); + ret = ftrace_rec_update_ops(rec); + if (ret) + return ret; + return __ftrace_modify_call(caller, addr, true); } #endif diff --git a/arch/riscv/kernel/mcount-dyn.S b/arch/riscv/kernel/mcount-dyn.S index 8aa554d5609626..699684eea7f0b1 100644 --- a/arch/riscv/kernel/mcount-dyn.S +++ b/arch/riscv/kernel/mcount-dyn.S @@ -139,10 +139,34 @@ .macro PREPARE_ARGS addi a0, t0, -MCOUNT_JALR_SIZE // ip (callsite's jalr insn) +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS + /* + * When CALL_OPS is enabled (2 or 4) nops [8B] are placed before the + * function entry, these are later overwritten with the pointer to the + * associated struct ftrace_ops. + * + * -8: &ftrace_ops of the associated tracer function. + *: + * 0: auipc t0/ra, 0x? + * 4: jalr t0/ra, ?(t0/ra) + * + * -8: &ftrace_nop_ops + *: + * 0: nop + * 4: nop + * + * t0 is set to ip+8 after the jalr is executed at the callsite, + * so we find the associated op at t0-16. + */ + mv a1, ra // parent_ip + REG_L a2, -16(t0) // op + REG_L ra, FTRACE_OPS_FUNC(a2) // op->func +#else la a1, function_trace_op - REG_L a2, 0(a1) - mv a1, ra - mv a3, sp + REG_L a2, 0(a1) // op + mv a1, ra // parent_ip +#endif + mv a3, sp // regs .endm SYM_FUNC_START(ftrace_caller) @@ -150,10 +174,13 @@ SYM_FUNC_START(ftrace_caller) SAVE_ABI_REGS PREPARE_ARGS +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS + jalr ra +#else SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL) REG_L ra, ftrace_call_dest jalr ra, 0(ra) - +#endif RESTORE_ABI_REGS bnez t1, .Ldirect jr t0 From f3977ded1b3b78e83a0becbc122f08c617937163 Mon Sep 17 00:00:00 2001 From: Alexandre Ghiti Date: Mon, 21 Apr 2025 16:24:38 +0200 Subject: [PATCH 22/91] riscv: Introduce Zicbop instructions The S-type instructions are first introduced and then used to define the encoding of the Zicbop prefetching instructions. Co-developed-by: Guo Ren Signed-off-by: Guo Ren Tested-by: Andrea Parri Link: https://lore.kernel.org/r/20250421142441.395849-2-alexghiti@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/insn-def.h | 60 +++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/arch/riscv/include/asm/insn-def.h b/arch/riscv/include/asm/insn-def.h index 71060a2f838e24..02c92c1657d2e4 100644 --- a/arch/riscv/include/asm/insn-def.h +++ b/arch/riscv/include/asm/insn-def.h @@ -18,6 +18,13 @@ #define INSN_I_RD_SHIFT 7 #define INSN_I_OPCODE_SHIFT 0 +#define INSN_S_SIMM7_SHIFT 25 +#define INSN_S_RS2_SHIFT 20 +#define INSN_S_RS1_SHIFT 15 +#define INSN_S_FUNC3_SHIFT 12 +#define INSN_S_SIMM5_SHIFT 7 +#define INSN_S_OPCODE_SHIFT 0 + #ifdef __ASSEMBLY__ #ifdef CONFIG_AS_HAS_INSN @@ -30,6 +37,10 @@ .insn i \opcode, \func3, \rd, \rs1, \simm12 .endm + .macro insn_s, opcode, func3, rs2, simm12, rs1 + .insn s \opcode, \func3, \rs2, \simm12(\rs1) + .endm + #else #include @@ -51,10 +62,20 @@ (\simm12 << INSN_I_SIMM12_SHIFT)) .endm + .macro insn_s, opcode, func3, rs2, simm12, rs1 + .4byte ((\opcode << INSN_S_OPCODE_SHIFT) | \ + (\func3 << INSN_S_FUNC3_SHIFT) | \ + (.L__gpr_num_\rs2 << INSN_S_RS2_SHIFT) | \ + (.L__gpr_num_\rs1 << INSN_S_RS1_SHIFT) | \ + ((\simm12 & 0x1f) << INSN_S_SIMM5_SHIFT) | \ + (((\simm12 >> 5) & 0x7f) << INSN_S_SIMM7_SHIFT)) + .endm + #endif #define __INSN_R(...) insn_r __VA_ARGS__ #define __INSN_I(...) insn_i __VA_ARGS__ +#define __INSN_S(...) insn_s __VA_ARGS__ #else /* ! __ASSEMBLY__ */ @@ -66,6 +87,9 @@ #define __INSN_I(opcode, func3, rd, rs1, simm12) \ ".insn i " opcode ", " func3 ", " rd ", " rs1 ", " simm12 "\n" +#define __INSN_S(opcode, func3, rs2, simm12, rs1) \ + ".insn s " opcode ", " func3 ", " rs2 ", " simm12 "(" rs1 ")\n" + #else #include @@ -92,12 +116,26 @@ " (\\simm12 << " __stringify(INSN_I_SIMM12_SHIFT) "))\n" \ " .endm\n" +#define DEFINE_INSN_S \ + __DEFINE_ASM_GPR_NUMS \ +" .macro insn_s, opcode, func3, rs2, simm12, rs1\n" \ +" .4byte ((\\opcode << " __stringify(INSN_S_OPCODE_SHIFT) ") |" \ +" (\\func3 << " __stringify(INSN_S_FUNC3_SHIFT) ") |" \ +" (.L__gpr_num_\\rs2 << " __stringify(INSN_S_RS2_SHIFT) ") |" \ +" (.L__gpr_num_\\rs1 << " __stringify(INSN_S_RS1_SHIFT) ") |" \ +" ((\\simm12 & 0x1f) << " __stringify(INSN_S_SIMM5_SHIFT) ") |" \ +" (((\\simm12 >> 5) & 0x7f) << " __stringify(INSN_S_SIMM7_SHIFT) "))\n" \ +" .endm\n" + #define UNDEFINE_INSN_R \ " .purgem insn_r\n" #define UNDEFINE_INSN_I \ " .purgem insn_i\n" +#define UNDEFINE_INSN_S \ +" .purgem insn_s\n" + #define __INSN_R(opcode, func3, func7, rd, rs1, rs2) \ DEFINE_INSN_R \ "insn_r " opcode ", " func3 ", " func7 ", " rd ", " rs1 ", " rs2 "\n" \ @@ -108,6 +146,11 @@ "insn_i " opcode ", " func3 ", " rd ", " rs1 ", " simm12 "\n" \ UNDEFINE_INSN_I +#define __INSN_S(opcode, func3, rs2, simm12, rs1) \ + DEFINE_INSN_S \ + "insn_s " opcode ", " func3 ", " rs2 ", " simm12 ", " rs1 "\n" \ + UNDEFINE_INSN_S + #endif #endif /* ! __ASSEMBLY__ */ @@ -120,6 +163,10 @@ __INSN_I(RV_##opcode, RV_##func3, RV_##rd, \ RV_##rs1, RV_##simm12) +#define INSN_S(opcode, func3, rs2, simm12, rs1) \ + __INSN_S(RV_##opcode, RV_##func3, RV_##rs2, \ + RV_##simm12, RV_##rs1) + #define RV_OPCODE(v) __ASM_STR(v) #define RV_FUNC3(v) __ASM_STR(v) #define RV_FUNC7(v) __ASM_STR(v) @@ -133,6 +180,7 @@ #define RV___RS2(v) __RV_REG(v) #define RV_OPCODE_MISC_MEM RV_OPCODE(15) +#define RV_OPCODE_OP_IMM RV_OPCODE(19) #define RV_OPCODE_SYSTEM RV_OPCODE(115) #define HFENCE_VVMA(vaddr, asid) \ @@ -196,6 +244,18 @@ INSN_I(OPCODE_MISC_MEM, FUNC3(2), __RD(0), \ RS1(base), SIMM12(4)) +#define PREFETCH_I(base, offset) \ + INSN_S(OPCODE_OP_IMM, FUNC3(6), __RS2(0), \ + SIMM12((offset) & 0xfe0), RS1(base)) + +#define PREFETCH_R(base, offset) \ + INSN_S(OPCODE_OP_IMM, FUNC3(6), __RS2(1), \ + SIMM12((offset) & 0xfe0), RS1(base)) + +#define PREFETCH_W(base, offset) \ + INSN_S(OPCODE_OP_IMM, FUNC3(6), __RS2(3), \ + SIMM12((offset) & 0xfe0), RS1(base)) + #define RISCV_PAUSE ".4byte 0x100000f" #define ZAWRS_WRS_NTO ".4byte 0x00d00073" #define ZAWRS_WRS_STO ".4byte 0x01d00073" From f4b83295efd220f763f78f6feb3c9b4147d5eae4 Mon Sep 17 00:00:00 2001 From: Andy Chiu Date: Tue, 8 Apr 2025 02:08:35 +0800 Subject: [PATCH 23/91] riscv: ftrace: support direct call using call_ops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit jump to FTRACE_ADDR if distance is out of reach Co-developed-by: Björn Töpel Signed-off-by: Björn Töpel Signed-off-by: Andy Chiu Link: https://lore.kernel.org/r/20250407180838.42877-11-andybnac@gmail.com Signed-off-by: Alexandre Ghiti --- arch/riscv/Kconfig | 2 +- arch/riscv/include/asm/ftrace.h | 6 ++++ arch/riscv/kernel/asm-offsets.c | 3 ++ arch/riscv/kernel/ftrace.c | 13 ++++----- arch/riscv/kernel/mcount-dyn.S | 51 +++++++++++++++++++++------------ 5 files changed, 48 insertions(+), 27 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index ec986c9120e3e9..8fdca6345fa316 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -152,7 +152,7 @@ config RISCV select HAVE_DMA_CONTIGUOUS if MMU select HAVE_DYNAMIC_FTRACE if !XIP_KERNEL && MMU && (CLANG_SUPPORTS_DYNAMIC_FTRACE || GCC_SUPPORTS_DYNAMIC_FTRACE) select FUNCTION_ALIGNMENT_4B if HAVE_DYNAMIC_FTRACE && RISCV_ISA_C - select HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS + select HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS if HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS select HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS if (DYNAMIC_FTRACE_WITH_ARGS && !CFI_CLANG) select HAVE_DYNAMIC_FTRACE_WITH_ARGS if HAVE_DYNAMIC_FTRACE select HAVE_FTRACE_GRAPH_FUNC diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h index 6a5c0a7fb8268a..22ebea3c2b26c1 100644 --- a/arch/riscv/include/asm/ftrace.h +++ b/arch/riscv/include/asm/ftrace.h @@ -130,6 +130,9 @@ struct __arch_ftrace_regs { unsigned long sp; unsigned long s0; unsigned long t1; +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS + unsigned long direct_tramp; +#endif union { unsigned long args[8]; struct { @@ -223,10 +226,13 @@ void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct ftrace_regs *fregs); #define ftrace_graph_func ftrace_graph_func +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS static inline void arch_ftrace_set_direct_caller(struct ftrace_regs *fregs, unsigned long addr) { arch_ftrace_regs(fregs)->t1 = addr; } +#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */ + #endif /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */ #endif /* __ASSEMBLY__ */ diff --git a/arch/riscv/kernel/asm-offsets.c b/arch/riscv/kernel/asm-offsets.c index 2d96197a8abfb5..b26334075697bf 100644 --- a/arch/riscv/kernel/asm-offsets.c +++ b/arch/riscv/kernel/asm-offsets.c @@ -495,6 +495,9 @@ void asm_offsets(void) OFFSET(STACKFRAME_RA, stackframe, ra); #ifdef CONFIG_FUNCTION_TRACER DEFINE(FTRACE_OPS_FUNC, offsetof(struct ftrace_ops, func)); +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS + DEFINE(FTRACE_OPS_DIRECT_CALL, offsetof(struct ftrace_ops, direct_call)); +#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */ #endif #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c index d56fc6e9fba091..4c6c24380cfd9d 100644 --- a/arch/riscv/kernel/ftrace.c +++ b/arch/riscv/kernel/ftrace.c @@ -17,7 +17,7 @@ unsigned long ftrace_call_adjust(unsigned long addr) { if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS)) - return addr + 8; + return addr + 8 + MCOUNT_AUIPC_SIZE; return addr + MCOUNT_AUIPC_SIZE; } @@ -83,10 +83,9 @@ static const struct ftrace_ops *riscv64_rec_get_ops(struct dyn_ftrace *rec) return ops; } -static int ftrace_rec_set_ops(const struct dyn_ftrace *rec, - const struct ftrace_ops *ops) +static int ftrace_rec_set_ops(const struct dyn_ftrace *rec, const struct ftrace_ops *ops) { - unsigned long literal = rec->ip - 8; + unsigned long literal = ALIGN_DOWN(rec->ip - 12, 8); return patch_text_nosync((void *)literal, &ops, sizeof(ops)); } @@ -117,7 +116,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) orig_addr = (unsigned long)&ftrace_caller; distance = addr > orig_addr ? addr - orig_addr : orig_addr - addr; if (distance > JALR_RANGE) - return -EINVAL; + addr = FTRACE_ADDR; return __ftrace_modify_call(pc, addr, false); } @@ -204,15 +203,13 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, unsigned long addr) { unsigned long caller = rec->ip - MCOUNT_AUIPC_SIZE; - unsigned int call[2]; int ret; - make_call_t0(caller, old_addr, call); ret = ftrace_rec_update_ops(rec); if (ret) return ret; - return __ftrace_modify_call(caller, addr, true); + return __ftrace_modify_call(caller, FTRACE_ADDR, true); } #endif diff --git a/arch/riscv/kernel/mcount-dyn.S b/arch/riscv/kernel/mcount-dyn.S index 699684eea7f0b1..48f6c4f7dca0cc 100644 --- a/arch/riscv/kernel/mcount-dyn.S +++ b/arch/riscv/kernel/mcount-dyn.S @@ -82,12 +82,9 @@ * +++++++++ **/ .macro SAVE_ABI_REGS - mv t4, sp // Save original SP in T4 addi sp, sp, -FREGS_SIZE_ON_STACK - REG_S t0, FREGS_EPC(sp) REG_S x1, FREGS_RA(sp) - REG_S t4, FREGS_SP(sp) // Put original SP on stack #ifdef HAVE_FUNCTION_GRAPH_FP_TEST REG_S x8, FREGS_S0(sp) #endif @@ -108,9 +105,12 @@ REG_S x15, FREGS_A5(sp) REG_S x16, FREGS_A6(sp) REG_S x17, FREGS_A7(sp) + mv a0, sp + addi a0, a0, FREGS_SIZE_ON_STACK + REG_S a0, FREGS_SP(sp) // Put original SP on stack .endm - .macro RESTORE_ABI_REGS, all=0 + .macro RESTORE_ABI_REGS REG_L t0, FREGS_EPC(sp) REG_L x1, FREGS_RA(sp) #ifdef HAVE_FUNCTION_GRAPH_FP_TEST @@ -139,6 +139,19 @@ .macro PREPARE_ARGS addi a0, t0, -MCOUNT_JALR_SIZE // ip (callsite's jalr insn) +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS + mv a1, ra // parent_ip + REG_L a2, -16(t0) // op + REG_L ra, FTRACE_OPS_FUNC(a2) // op->func +#else + la a1, function_trace_op + REG_L a2, 0(a1) // op + mv a1, ra // parent_ip +#endif + mv a3, sp // regs + .endm + +SYM_FUNC_START(ftrace_caller) #ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS /* * When CALL_OPS is enabled (2 or 4) nops [8B] are placed before the @@ -158,19 +171,17 @@ * t0 is set to ip+8 after the jalr is executed at the callsite, * so we find the associated op at t0-16. */ - mv a1, ra // parent_ip - REG_L a2, -16(t0) // op - REG_L ra, FTRACE_OPS_FUNC(a2) // op->func -#else - la a1, function_trace_op - REG_L a2, 0(a1) // op - mv a1, ra // parent_ip -#endif - mv a3, sp // regs - .endm + REG_L t1, -16(t0) // op Should be SZ_REG instead of 16 -SYM_FUNC_START(ftrace_caller) - mv t1, zero +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS + /* + * If the op has a direct call, handle it immediately without + * saving/restoring registers. + */ + REG_L t1, FTRACE_OPS_DIRECT_CALL(t1) + bnez t1, ftrace_caller_direct +#endif +#endif SAVE_ABI_REGS PREPARE_ARGS @@ -182,10 +193,14 @@ SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL) jalr ra, 0(ra) #endif RESTORE_ABI_REGS - bnez t1, .Ldirect +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS + bnez t1, ftrace_caller_direct +#endif jr t0 -.Ldirect: +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS +SYM_INNER_LABEL(ftrace_caller_direct, SYM_L_LOCAL) jr t1 +#endif SYM_FUNC_END(ftrace_caller) #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS From 24b68b33773caec1d4a079c0ade1ca362bc08ae6 Mon Sep 17 00:00:00 2001 From: Alexandre Ghiti Date: Mon, 21 Apr 2025 16:24:39 +0200 Subject: [PATCH 24/91] riscv: Add support for Zicbop Zicbop introduces cache blocks prefetching instructions, add the necessary support for the kernel to use it in the coming commits. Co-developed-by: Guo Ren Signed-off-by: Guo Ren Tested-by: Andrea Parri Link: https://lore.kernel.org/r/20250421142441.395849-3-alexghiti@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/Kconfig | 15 +++++++++++++++ arch/riscv/include/asm/barrier.h | 5 ----- arch/riscv/include/asm/cacheflush.h | 1 + arch/riscv/include/asm/hwcap.h | 1 + arch/riscv/include/asm/insn-def.h | 6 ++++++ arch/riscv/include/asm/processor.h | 1 - arch/riscv/kernel/cpufeature.c | 21 +++++++++++++++++++++ arch/riscv/mm/cacheflush.c | 14 +++++++++++--- 8 files changed, 55 insertions(+), 9 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index bbec87b7930999..28765ce563dec9 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -842,6 +842,21 @@ config RISCV_ISA_ZICBOZ If you don't know what to do here, say Y. +config RISCV_ISA_ZICBOP + bool "Zicbop extension support for cache block prefetch" + depends on MMU + depends on RISCV_ALTERNATIVE + default y + help + Adds support to dynamically detect the presence of the ZICBOP + extension (Cache Block Prefetch Operations) and enable its + usage. + + The Zicbop extension can be used to prefetch cache blocks for + read/write fetch. + + If you don't know what to do here, say Y. + config TOOLCHAIN_NEEDS_EXPLICIT_ZICSR_ZIFENCEI def_bool y # https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=aed44286efa8ae8717a77d94b51ac3614e2ca6dc diff --git a/arch/riscv/include/asm/barrier.h b/arch/riscv/include/asm/barrier.h index e1d9bf1deca685..b8c5726d86acb1 100644 --- a/arch/riscv/include/asm/barrier.h +++ b/arch/riscv/include/asm/barrier.h @@ -14,11 +14,6 @@ #include #include -#define nop() __asm__ __volatile__ ("nop") -#define __nops(n) ".rept " #n "\nnop\n.endr\n" -#define nops(n) __asm__ __volatile__ (__nops(n)) - - /* These barriers need to enforce ordering on both devices or memory. */ #define __mb() RISCV_FENCE(iorw, iorw) #define __rmb() RISCV_FENCE(ir, ir) diff --git a/arch/riscv/include/asm/cacheflush.h b/arch/riscv/include/asm/cacheflush.h index b59ffeb668d6a5..6086b38d54279d 100644 --- a/arch/riscv/include/asm/cacheflush.h +++ b/arch/riscv/include/asm/cacheflush.h @@ -85,6 +85,7 @@ static inline void flush_icache_range(unsigned long start, unsigned long end) extern unsigned int riscv_cbom_block_size; extern unsigned int riscv_cboz_block_size; +extern unsigned int riscv_cbop_block_size; void riscv_init_cbo_blocksizes(void); #ifdef CONFIG_RISCV_DMA_NONCOHERENT diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h index e3cbf203cdde7f..affd63e11b0a34 100644 --- a/arch/riscv/include/asm/hwcap.h +++ b/arch/riscv/include/asm/hwcap.h @@ -105,6 +105,7 @@ #define RISCV_ISA_EXT_ZVFBFWMA 96 #define RISCV_ISA_EXT_ZAAMO 97 #define RISCV_ISA_EXT_ZALRSC 98 +#define RISCV_ISA_EXT_ZICBOP 99 #define RISCV_ISA_EXT_XLINUXENVCFG 127 diff --git a/arch/riscv/include/asm/insn-def.h b/arch/riscv/include/asm/insn-def.h index 02c92c1657d2e4..d5adbaec1d010d 100644 --- a/arch/riscv/include/asm/insn-def.h +++ b/arch/riscv/include/asm/insn-def.h @@ -263,4 +263,10 @@ #define RISCV_INSN_NOP4 _AC(0x00000013, U) +#ifndef __ASSEMBLY__ +#define nop() __asm__ __volatile__ ("nop") +#define __nops(n) ".rept " #n "\nnop\n.endr\n" +#define nops(n) __asm__ __volatile__ (__nops(n)) +#endif + #endif /* __ASM_INSN_DEF_H */ diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h index 5f56eb9d114a95..09d4c963399ac7 100644 --- a/arch/riscv/include/asm/processor.h +++ b/arch/riscv/include/asm/processor.h @@ -52,7 +52,6 @@ #endif #ifndef __ASSEMBLY__ -#include struct task_struct; struct pt_regs; diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c index 2054f6c4b0ae1f..743d53415572e0 100644 --- a/arch/riscv/kernel/cpufeature.c +++ b/arch/riscv/kernel/cpufeature.c @@ -32,6 +32,7 @@ #define NUM_ALPHA_EXTS ('z' - 'a' + 1) static bool any_cpu_has_zicboz; +static bool any_cpu_has_zicbop; static bool any_cpu_has_zicbom; unsigned long elf_hwcap __read_mostly; @@ -119,6 +120,21 @@ static int riscv_ext_zicboz_validate(const struct riscv_isa_ext_data *data, return 0; } +static int riscv_ext_zicbop_validate(const struct riscv_isa_ext_data *data, + const unsigned long *isa_bitmap) +{ + if (!riscv_cbop_block_size) { + pr_err("Zicbop detected in ISA string, disabling as no cbop-block-size found\n"); + return -EINVAL; + } + if (!is_power_of_2(riscv_cbop_block_size)) { + pr_err("Zicbop disabled as cbop-block-size present, but is not a power-of-2\n"); + return -EINVAL; + } + any_cpu_has_zicbop = true; + return 0; +} + static int riscv_ext_f_validate(const struct riscv_isa_ext_data *data, const unsigned long *isa_bitmap) { @@ -442,6 +458,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = { __RISCV_ISA_EXT_SUPERSET_VALIDATE(v, RISCV_ISA_EXT_v, riscv_v_exts, riscv_ext_vector_float_validate), __RISCV_ISA_EXT_DATA(h, RISCV_ISA_EXT_h), __RISCV_ISA_EXT_SUPERSET_VALIDATE(zicbom, RISCV_ISA_EXT_ZICBOM, riscv_xlinuxenvcfg_exts, riscv_ext_zicbom_validate), + __RISCV_ISA_EXT_DATA_VALIDATE(zicbop, RISCV_ISA_EXT_ZICBOP, riscv_ext_zicbop_validate), __RISCV_ISA_EXT_SUPERSET_VALIDATE(zicboz, RISCV_ISA_EXT_ZICBOZ, riscv_xlinuxenvcfg_exts, riscv_ext_zicboz_validate), __RISCV_ISA_EXT_DATA(ziccrse, RISCV_ISA_EXT_ZICCRSE), __RISCV_ISA_EXT_DATA(zicntr, RISCV_ISA_EXT_ZICNTR), @@ -1112,6 +1129,10 @@ void __init riscv_user_isa_enable(void) current->thread.envcfg |= ENVCFG_CBCFE; else if (any_cpu_has_zicbom) pr_warn("Zicbom disabled as it is unavailable on some harts\n"); + + if (!riscv_has_extension_unlikely(RISCV_ISA_EXT_ZICBOP) && + any_cpu_has_zicbop) + pr_warn("Zicbop disabled as it is unavailable on some harts\n"); } #ifdef CONFIG_RISCV_ALTERNATIVE diff --git a/arch/riscv/mm/cacheflush.c b/arch/riscv/mm/cacheflush.c index b8167272988723..6265052ef8b6bb 100644 --- a/arch/riscv/mm/cacheflush.c +++ b/arch/riscv/mm/cacheflush.c @@ -101,6 +101,9 @@ EXPORT_SYMBOL_GPL(riscv_cbom_block_size); unsigned int riscv_cboz_block_size; EXPORT_SYMBOL_GPL(riscv_cboz_block_size); +unsigned int riscv_cbop_block_size; +EXPORT_SYMBOL_GPL(riscv_cbop_block_size); + static void __init cbo_get_block_size(struct device_node *node, const char *name, u32 *block_size, unsigned long *first_hartid) @@ -125,8 +128,8 @@ static void __init cbo_get_block_size(struct device_node *node, void __init riscv_init_cbo_blocksizes(void) { - unsigned long cbom_hartid, cboz_hartid; - u32 cbom_block_size = 0, cboz_block_size = 0; + unsigned long cbom_hartid, cboz_hartid, cbop_hartid; + u32 cbom_block_size = 0, cboz_block_size = 0, cbop_block_size = 0; struct device_node *node; struct acpi_table_header *rhct; acpi_status status; @@ -138,13 +141,15 @@ void __init riscv_init_cbo_blocksizes(void) &cbom_block_size, &cbom_hartid); cbo_get_block_size(node, "riscv,cboz-block-size", &cboz_block_size, &cboz_hartid); + cbo_get_block_size(node, "riscv,cbop-block-size", + &cbop_block_size, &cbop_hartid); } } else { status = acpi_get_table(ACPI_SIG_RHCT, 0, &rhct); if (ACPI_FAILURE(status)) return; - acpi_get_cbo_block_size(rhct, &cbom_block_size, &cboz_block_size, NULL); + acpi_get_cbo_block_size(rhct, &cbom_block_size, &cboz_block_size, &cbop_block_size); acpi_put_table((struct acpi_table_header *)rhct); } @@ -153,6 +158,9 @@ void __init riscv_init_cbo_blocksizes(void) if (cboz_block_size) riscv_cboz_block_size = cboz_block_size; + + if (cbop_block_size) + riscv_cbop_block_size = cbop_block_size; } #ifdef CONFIG_SMP From 98d01fe28991183dbeddaf1bcf4b7ed70ca96c4d Mon Sep 17 00:00:00 2001 From: Song Shuai Date: Wed, 9 Apr 2025 21:29:58 +0200 Subject: [PATCH 25/91] riscv: kexec_file: Split the loading of kernel and others MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is the preparative patch for kexec_file_load Image support. It separates the elf_kexec_load() as two parts: - the first part loads the vmlinux (or Image) - the second part loads other segments (e.g. initrd,fdt,purgatory) And the second part is exported as the load_extra_segments() function which would be used in both kexec-elf.c and kexec-image.c. No functional change intended. Signed-off-by: Song Shuai Signed-off-by: Björn Töpel Link: https://lore.kernel.org/r/20250409193004.643839-2-bjorn@kernel.org Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/kexec.h | 5 + arch/riscv/kernel/Makefile | 2 +- arch/riscv/kernel/elf_kexec.c | 485 ------------------------- arch/riscv/kernel/kexec_elf.c | 144 ++++++++ arch/riscv/kernel/machine_kexec_file.c | 360 ++++++++++++++++++ 5 files changed, 510 insertions(+), 486 deletions(-) delete mode 100644 arch/riscv/kernel/elf_kexec.c create mode 100644 arch/riscv/kernel/kexec_elf.c diff --git a/arch/riscv/include/asm/kexec.h b/arch/riscv/include/asm/kexec.h index 2b56769cb530cb..518825fe4160c0 100644 --- a/arch/riscv/include/asm/kexec.h +++ b/arch/riscv/include/asm/kexec.h @@ -67,6 +67,11 @@ int arch_kexec_apply_relocations_add(struct purgatory_info *pi, struct kimage; int arch_kimage_file_post_load_cleanup(struct kimage *image); #define arch_kimage_file_post_load_cleanup arch_kimage_file_post_load_cleanup + +int load_extra_segments(struct kimage *image, unsigned long kernel_start, + unsigned long kernel_len, char *initrd, + unsigned long initrd_len, char *cmdline, + unsigned long cmdline_len); #endif #endif diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index f7480c9c6f8d73..2c07a62a1d555a 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -107,7 +107,7 @@ obj-$(CONFIG_HOTPLUG_CPU) += cpu-hotplug.o obj-$(CONFIG_PARAVIRT) += paravirt.o obj-$(CONFIG_KGDB) += kgdb.o obj-$(CONFIG_KEXEC_CORE) += kexec_relocate.o crash_save_regs.o machine_kexec.o -obj-$(CONFIG_KEXEC_FILE) += elf_kexec.o machine_kexec_file.o +obj-$(CONFIG_KEXEC_FILE) += kexec_elf.o machine_kexec_file.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_VMCORE_INFO) += vmcore_info.o diff --git a/arch/riscv/kernel/elf_kexec.c b/arch/riscv/kernel/elf_kexec.c deleted file mode 100644 index e783a72d051f43..00000000000000 --- a/arch/riscv/kernel/elf_kexec.c +++ /dev/null @@ -1,485 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Load ELF vmlinux file for the kexec_file_load syscall. - * - * Copyright (C) 2021 Huawei Technologies Co, Ltd. - * - * Author: Liao Chang (liaochang1@huawei.com) - * - * Based on kexec-tools' kexec-elf-riscv.c, heavily modified - * for kernel. - */ - -#define pr_fmt(fmt) "kexec_image: " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int arch_kimage_file_post_load_cleanup(struct kimage *image) -{ - kvfree(image->arch.fdt); - image->arch.fdt = NULL; - - vfree(image->elf_headers); - image->elf_headers = NULL; - image->elf_headers_sz = 0; - - return kexec_image_post_load_cleanup_default(image); -} - -static int riscv_kexec_elf_load(struct kimage *image, struct elfhdr *ehdr, - struct kexec_elf_info *elf_info, unsigned long old_pbase, - unsigned long new_pbase) -{ - int i; - int ret = 0; - size_t size; - struct kexec_buf kbuf; - const struct elf_phdr *phdr; - - kbuf.image = image; - - for (i = 0; i < ehdr->e_phnum; i++) { - phdr = &elf_info->proghdrs[i]; - if (phdr->p_type != PT_LOAD) - continue; - - size = phdr->p_filesz; - if (size > phdr->p_memsz) - size = phdr->p_memsz; - - kbuf.buffer = (void *) elf_info->buffer + phdr->p_offset; - kbuf.bufsz = size; - kbuf.buf_align = phdr->p_align; - kbuf.mem = phdr->p_paddr - old_pbase + new_pbase; - kbuf.memsz = phdr->p_memsz; - kbuf.top_down = false; - ret = kexec_add_buffer(&kbuf); - if (ret) - break; - } - - return ret; -} - -/* - * Go through the available phsyical memory regions and find one that hold - * an image of the specified size. - */ -static int elf_find_pbase(struct kimage *image, unsigned long kernel_len, - struct elfhdr *ehdr, struct kexec_elf_info *elf_info, - unsigned long *old_pbase, unsigned long *new_pbase) -{ - int i; - int ret; - struct kexec_buf kbuf; - const struct elf_phdr *phdr; - unsigned long lowest_paddr = ULONG_MAX; - unsigned long lowest_vaddr = ULONG_MAX; - - for (i = 0; i < ehdr->e_phnum; i++) { - phdr = &elf_info->proghdrs[i]; - if (phdr->p_type != PT_LOAD) - continue; - - if (lowest_paddr > phdr->p_paddr) - lowest_paddr = phdr->p_paddr; - - if (lowest_vaddr > phdr->p_vaddr) - lowest_vaddr = phdr->p_vaddr; - } - - kbuf.image = image; - kbuf.buf_min = lowest_paddr; - kbuf.buf_max = ULONG_MAX; - - /* - * Current riscv boot protocol requires 2MB alignment for - * RV64 and 4MB alignment for RV32 - * - */ - kbuf.buf_align = PMD_SIZE; - kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; - kbuf.memsz = ALIGN(kernel_len, PAGE_SIZE); - kbuf.top_down = false; - ret = arch_kexec_locate_mem_hole(&kbuf); - if (!ret) { - *old_pbase = lowest_paddr; - *new_pbase = kbuf.mem; - image->start = ehdr->e_entry - lowest_vaddr + kbuf.mem; - } - return ret; -} - -#ifdef CONFIG_CRASH_DUMP -static int get_nr_ram_ranges_callback(struct resource *res, void *arg) -{ - unsigned int *nr_ranges = arg; - - (*nr_ranges)++; - return 0; -} - -static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg) -{ - struct crash_mem *cmem = arg; - - cmem->ranges[cmem->nr_ranges].start = res->start; - cmem->ranges[cmem->nr_ranges].end = res->end; - cmem->nr_ranges++; - - return 0; -} - -static int prepare_elf_headers(void **addr, unsigned long *sz) -{ - struct crash_mem *cmem; - unsigned int nr_ranges; - int ret; - - nr_ranges = 1; /* For exclusion of crashkernel region */ - walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback); - - cmem = kmalloc(struct_size(cmem, ranges, nr_ranges), GFP_KERNEL); - if (!cmem) - return -ENOMEM; - - cmem->max_nr_ranges = nr_ranges; - cmem->nr_ranges = 0; - ret = walk_system_ram_res(0, -1, cmem, prepare_elf64_ram_headers_callback); - if (ret) - goto out; - - /* Exclude crashkernel region */ - ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end); - if (!ret) - ret = crash_prepare_elf64_headers(cmem, true, addr, sz); - -out: - kfree(cmem); - return ret; -} - -static char *setup_kdump_cmdline(struct kimage *image, char *cmdline, - unsigned long cmdline_len) -{ - int elfcorehdr_strlen; - char *cmdline_ptr; - - cmdline_ptr = kzalloc(COMMAND_LINE_SIZE, GFP_KERNEL); - if (!cmdline_ptr) - return NULL; - - elfcorehdr_strlen = sprintf(cmdline_ptr, "elfcorehdr=0x%lx ", - image->elf_load_addr); - - if (elfcorehdr_strlen + cmdline_len > COMMAND_LINE_SIZE) { - pr_err("Appending elfcorehdr= exceeds cmdline size\n"); - kfree(cmdline_ptr); - return NULL; - } - - memcpy(cmdline_ptr + elfcorehdr_strlen, cmdline, cmdline_len); - /* Ensure it's nul terminated */ - cmdline_ptr[COMMAND_LINE_SIZE - 1] = '\0'; - return cmdline_ptr; -} -#endif - -static void *elf_kexec_load(struct kimage *image, char *kernel_buf, - unsigned long kernel_len, char *initrd, - unsigned long initrd_len, char *cmdline, - unsigned long cmdline_len) -{ - int ret; - void *fdt; - unsigned long old_kernel_pbase = ULONG_MAX; - unsigned long new_kernel_pbase = 0UL; - unsigned long initrd_pbase = 0UL; - unsigned long kernel_start; - struct elfhdr ehdr; - struct kexec_buf kbuf; - struct kexec_elf_info elf_info; - char *modified_cmdline = NULL; - - ret = kexec_build_elf_info(kernel_buf, kernel_len, &ehdr, &elf_info); - if (ret) - return ERR_PTR(ret); - - ret = elf_find_pbase(image, kernel_len, &ehdr, &elf_info, - &old_kernel_pbase, &new_kernel_pbase); - if (ret) - goto out; - kernel_start = image->start; - - /* Add the kernel binary to the image */ - ret = riscv_kexec_elf_load(image, &ehdr, &elf_info, - old_kernel_pbase, new_kernel_pbase); - if (ret) - goto out; - - kbuf.image = image; - kbuf.buf_min = new_kernel_pbase + kernel_len; - kbuf.buf_max = ULONG_MAX; - -#ifdef CONFIG_CRASH_DUMP - /* Add elfcorehdr */ - if (image->type == KEXEC_TYPE_CRASH) { - void *headers; - unsigned long headers_sz; - ret = prepare_elf_headers(&headers, &headers_sz); - if (ret) { - pr_err("Preparing elf core header failed\n"); - goto out; - } - - kbuf.buffer = headers; - kbuf.bufsz = headers_sz; - kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; - kbuf.memsz = headers_sz; - kbuf.buf_align = ELF_CORE_HEADER_ALIGN; - kbuf.top_down = true; - - ret = kexec_add_buffer(&kbuf); - if (ret) { - vfree(headers); - goto out; - } - image->elf_headers = headers; - image->elf_load_addr = kbuf.mem; - image->elf_headers_sz = headers_sz; - - kexec_dprintk("Loaded elf core header at 0x%lx bufsz=0x%lx memsz=0x%lx\n", - image->elf_load_addr, kbuf.bufsz, kbuf.memsz); - - /* Setup cmdline for kdump kernel case */ - modified_cmdline = setup_kdump_cmdline(image, cmdline, - cmdline_len); - if (!modified_cmdline) { - pr_err("Setting up cmdline for kdump kernel failed\n"); - ret = -EINVAL; - goto out; - } - cmdline = modified_cmdline; - } -#endif - -#ifdef CONFIG_ARCH_SUPPORTS_KEXEC_PURGATORY - /* Add purgatory to the image */ - kbuf.top_down = true; - kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; - ret = kexec_load_purgatory(image, &kbuf); - if (ret) { - pr_err("Error loading purgatory ret=%d\n", ret); - goto out; - } - kexec_dprintk("Loaded purgatory at 0x%lx\n", kbuf.mem); - - ret = kexec_purgatory_get_set_symbol(image, "riscv_kernel_entry", - &kernel_start, - sizeof(kernel_start), 0); - if (ret) - pr_err("Error update purgatory ret=%d\n", ret); -#endif /* CONFIG_ARCH_SUPPORTS_KEXEC_PURGATORY */ - - /* Add the initrd to the image */ - if (initrd != NULL) { - kbuf.buffer = initrd; - kbuf.bufsz = kbuf.memsz = initrd_len; - kbuf.buf_align = PAGE_SIZE; - kbuf.top_down = true; - kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; - ret = kexec_add_buffer(&kbuf); - if (ret) - goto out; - initrd_pbase = kbuf.mem; - kexec_dprintk("Loaded initrd at 0x%lx\n", initrd_pbase); - } - - /* Add the DTB to the image */ - fdt = of_kexec_alloc_and_setup_fdt(image, initrd_pbase, - initrd_len, cmdline, 0); - if (!fdt) { - pr_err("Error setting up the new device tree.\n"); - ret = -EINVAL; - goto out; - } - - fdt_pack(fdt); - kbuf.buffer = fdt; - kbuf.bufsz = kbuf.memsz = fdt_totalsize(fdt); - kbuf.buf_align = PAGE_SIZE; - kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; - kbuf.top_down = true; - ret = kexec_add_buffer(&kbuf); - if (ret) { - pr_err("Error add DTB kbuf ret=%d\n", ret); - goto out_free_fdt; - } - /* Cache the fdt buffer address for memory cleanup */ - image->arch.fdt = fdt; - kexec_dprintk("Loaded device tree at 0x%lx\n", kbuf.mem); - goto out; - -out_free_fdt: - kvfree(fdt); -out: - kfree(modified_cmdline); - kexec_free_elf_info(&elf_info); - return ret ? ERR_PTR(ret) : NULL; -} - -#define RV_X(x, s, n) (((x) >> (s)) & ((1 << (n)) - 1)) -#define RISCV_IMM_BITS 12 -#define RISCV_IMM_REACH (1LL << RISCV_IMM_BITS) -#define RISCV_CONST_HIGH_PART(x) \ - (((x) + (RISCV_IMM_REACH >> 1)) & ~(RISCV_IMM_REACH - 1)) -#define RISCV_CONST_LOW_PART(x) ((x) - RISCV_CONST_HIGH_PART(x)) - -#define ENCODE_ITYPE_IMM(x) \ - (RV_X(x, 0, 12) << 20) -#define ENCODE_BTYPE_IMM(x) \ - ((RV_X(x, 1, 4) << 8) | (RV_X(x, 5, 6) << 25) | \ - (RV_X(x, 11, 1) << 7) | (RV_X(x, 12, 1) << 31)) -#define ENCODE_UTYPE_IMM(x) \ - (RV_X(x, 12, 20) << 12) -#define ENCODE_JTYPE_IMM(x) \ - ((RV_X(x, 1, 10) << 21) | (RV_X(x, 11, 1) << 20) | \ - (RV_X(x, 12, 8) << 12) | (RV_X(x, 20, 1) << 31)) -#define ENCODE_CBTYPE_IMM(x) \ - ((RV_X(x, 1, 2) << 3) | (RV_X(x, 3, 2) << 10) | (RV_X(x, 5, 1) << 2) | \ - (RV_X(x, 6, 2) << 5) | (RV_X(x, 8, 1) << 12)) -#define ENCODE_CJTYPE_IMM(x) \ - ((RV_X(x, 1, 3) << 3) | (RV_X(x, 4, 1) << 11) | (RV_X(x, 5, 1) << 2) | \ - (RV_X(x, 6, 1) << 7) | (RV_X(x, 7, 1) << 6) | (RV_X(x, 8, 2) << 9) | \ - (RV_X(x, 10, 1) << 8) | (RV_X(x, 11, 1) << 12)) -#define ENCODE_UJTYPE_IMM(x) \ - (ENCODE_UTYPE_IMM(RISCV_CONST_HIGH_PART(x)) | \ - (ENCODE_ITYPE_IMM(RISCV_CONST_LOW_PART(x)) << 32)) -#define ENCODE_UITYPE_IMM(x) \ - (ENCODE_UTYPE_IMM(x) | (ENCODE_ITYPE_IMM(x) << 32)) - -#define CLEAN_IMM(type, x) \ - ((~ENCODE_##type##_IMM((uint64_t)(-1))) & (x)) - -int arch_kexec_apply_relocations_add(struct purgatory_info *pi, - Elf_Shdr *section, - const Elf_Shdr *relsec, - const Elf_Shdr *symtab) -{ - const char *strtab, *name, *shstrtab; - const Elf_Shdr *sechdrs; - Elf64_Rela *relas; - int i, r_type; - - /* String & section header string table */ - sechdrs = (void *)pi->ehdr + pi->ehdr->e_shoff; - strtab = (char *)pi->ehdr + sechdrs[symtab->sh_link].sh_offset; - shstrtab = (char *)pi->ehdr + sechdrs[pi->ehdr->e_shstrndx].sh_offset; - - relas = (void *)pi->ehdr + relsec->sh_offset; - - for (i = 0; i < relsec->sh_size / sizeof(*relas); i++) { - const Elf_Sym *sym; /* symbol to relocate */ - unsigned long addr; /* final location after relocation */ - unsigned long val; /* relocated symbol value */ - unsigned long sec_base; /* relocated symbol value */ - void *loc; /* tmp location to modify */ - - sym = (void *)pi->ehdr + symtab->sh_offset; - sym += ELF64_R_SYM(relas[i].r_info); - - if (sym->st_name) - name = strtab + sym->st_name; - else - name = shstrtab + sechdrs[sym->st_shndx].sh_name; - - loc = pi->purgatory_buf; - loc += section->sh_offset; - loc += relas[i].r_offset; - - if (sym->st_shndx == SHN_ABS) - sec_base = 0; - else if (sym->st_shndx >= pi->ehdr->e_shnum) { - pr_err("Invalid section %d for symbol %s\n", - sym->st_shndx, name); - return -ENOEXEC; - } else - sec_base = pi->sechdrs[sym->st_shndx].sh_addr; - - val = sym->st_value; - val += sec_base; - val += relas[i].r_addend; - - addr = section->sh_addr + relas[i].r_offset; - - r_type = ELF64_R_TYPE(relas[i].r_info); - - switch (r_type) { - case R_RISCV_BRANCH: - *(u32 *)loc = CLEAN_IMM(BTYPE, *(u32 *)loc) | - ENCODE_BTYPE_IMM(val - addr); - break; - case R_RISCV_JAL: - *(u32 *)loc = CLEAN_IMM(JTYPE, *(u32 *)loc) | - ENCODE_JTYPE_IMM(val - addr); - break; - /* - * With no R_RISCV_PCREL_LO12_S, R_RISCV_PCREL_LO12_I - * sym is expected to be next to R_RISCV_PCREL_HI20 - * in purgatory relsec. Handle it like R_RISCV_CALL - * sym, instead of searching the whole relsec. - */ - case R_RISCV_PCREL_HI20: - case R_RISCV_CALL_PLT: - case R_RISCV_CALL: - *(u64 *)loc = CLEAN_IMM(UITYPE, *(u64 *)loc) | - ENCODE_UJTYPE_IMM(val - addr); - break; - case R_RISCV_RVC_BRANCH: - *(u32 *)loc = CLEAN_IMM(CBTYPE, *(u32 *)loc) | - ENCODE_CBTYPE_IMM(val - addr); - break; - case R_RISCV_RVC_JUMP: - *(u32 *)loc = CLEAN_IMM(CJTYPE, *(u32 *)loc) | - ENCODE_CJTYPE_IMM(val - addr); - break; - case R_RISCV_ADD16: - *(u16 *)loc += val; - break; - case R_RISCV_SUB16: - *(u16 *)loc -= val; - break; - case R_RISCV_ADD32: - *(u32 *)loc += val; - break; - case R_RISCV_SUB32: - *(u32 *)loc -= val; - break; - /* It has been applied by R_RISCV_PCREL_HI20 sym */ - case R_RISCV_PCREL_LO12_I: - case R_RISCV_ALIGN: - case R_RISCV_RELAX: - break; - case R_RISCV_64: - *(u64 *)loc = val; - break; - default: - pr_err("Unknown rela relocation: %d\n", r_type); - return -ENOEXEC; - } - } - return 0; -} - -const struct kexec_file_ops elf_kexec_ops = { - .probe = kexec_elf_probe, - .load = elf_kexec_load, -}; diff --git a/arch/riscv/kernel/kexec_elf.c b/arch/riscv/kernel/kexec_elf.c new file mode 100644 index 00000000000000..f4755d49b89eda --- /dev/null +++ b/arch/riscv/kernel/kexec_elf.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Load ELF vmlinux file for the kexec_file_load syscall. + * + * Copyright (C) 2021 Huawei Technologies Co, Ltd. + * + * Author: Liao Chang (liaochang1@huawei.com) + * + * Based on kexec-tools' kexec-elf-riscv.c, heavily modified + * for kernel. + */ + +#define pr_fmt(fmt) "kexec_image: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +static int riscv_kexec_elf_load(struct kimage *image, struct elfhdr *ehdr, + struct kexec_elf_info *elf_info, unsigned long old_pbase, + unsigned long new_pbase) +{ + int i; + int ret = 0; + size_t size; + struct kexec_buf kbuf; + const struct elf_phdr *phdr; + + kbuf.image = image; + + for (i = 0; i < ehdr->e_phnum; i++) { + phdr = &elf_info->proghdrs[i]; + if (phdr->p_type != PT_LOAD) + continue; + + size = phdr->p_filesz; + if (size > phdr->p_memsz) + size = phdr->p_memsz; + + kbuf.buffer = (void *) elf_info->buffer + phdr->p_offset; + kbuf.bufsz = size; + kbuf.buf_align = phdr->p_align; + kbuf.mem = phdr->p_paddr - old_pbase + new_pbase; + kbuf.memsz = phdr->p_memsz; + kbuf.top_down = false; + ret = kexec_add_buffer(&kbuf); + if (ret) + break; + } + + return ret; +} + +/* + * Go through the available phsyical memory regions and find one that hold + * an image of the specified size. + */ +static int elf_find_pbase(struct kimage *image, unsigned long kernel_len, + struct elfhdr *ehdr, struct kexec_elf_info *elf_info, + unsigned long *old_pbase, unsigned long *new_pbase) +{ + int i; + int ret; + struct kexec_buf kbuf; + const struct elf_phdr *phdr; + unsigned long lowest_paddr = ULONG_MAX; + unsigned long lowest_vaddr = ULONG_MAX; + + for (i = 0; i < ehdr->e_phnum; i++) { + phdr = &elf_info->proghdrs[i]; + if (phdr->p_type != PT_LOAD) + continue; + + if (lowest_paddr > phdr->p_paddr) + lowest_paddr = phdr->p_paddr; + + if (lowest_vaddr > phdr->p_vaddr) + lowest_vaddr = phdr->p_vaddr; + } + + kbuf.image = image; + kbuf.buf_min = lowest_paddr; + kbuf.buf_max = ULONG_MAX; + + /* + * Current riscv boot protocol requires 2MB alignment for + * RV64 and 4MB alignment for RV32 + * + */ + kbuf.buf_align = PMD_SIZE; + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; + kbuf.memsz = ALIGN(kernel_len, PAGE_SIZE); + kbuf.top_down = false; + ret = arch_kexec_locate_mem_hole(&kbuf); + if (!ret) { + *old_pbase = lowest_paddr; + *new_pbase = kbuf.mem; + image->start = ehdr->e_entry - lowest_vaddr + kbuf.mem; + } + return ret; +} + +static void *elf_kexec_load(struct kimage *image, char *kernel_buf, + unsigned long kernel_len, char *initrd, + unsigned long initrd_len, char *cmdline, + unsigned long cmdline_len) +{ + int ret; + unsigned long old_kernel_pbase = ULONG_MAX; + unsigned long new_kernel_pbase = 0UL; + struct elfhdr ehdr; + struct kexec_elf_info elf_info; + + ret = kexec_build_elf_info(kernel_buf, kernel_len, &ehdr, &elf_info); + if (ret) + return ERR_PTR(ret); + + ret = elf_find_pbase(image, kernel_len, &ehdr, &elf_info, + &old_kernel_pbase, &new_kernel_pbase); + if (ret) + goto out; + + /* Add the kernel binary to the image */ + ret = riscv_kexec_elf_load(image, &ehdr, &elf_info, + old_kernel_pbase, new_kernel_pbase); + if (ret) + goto out; + + ret = load_extra_segments(image, image->start, kernel_len, + initrd, initrd_len, cmdline, cmdline_len); +out: + kexec_free_elf_info(&elf_info); + return ret ? ERR_PTR(ret) : NULL; +} + +const struct kexec_file_ops elf_kexec_ops = { + .probe = kexec_elf_probe, + .load = elf_kexec_load, +}; diff --git a/arch/riscv/kernel/machine_kexec_file.c b/arch/riscv/kernel/machine_kexec_file.c index b0bf8c1722c0cc..99bd5a5f423468 100644 --- a/arch/riscv/kernel/machine_kexec_file.c +++ b/arch/riscv/kernel/machine_kexec_file.c @@ -7,8 +7,368 @@ * Author: Liao Chang (liaochang1@huawei.com) */ #include +#include +#include +#include +#include +#include +#include +#include +#include const struct kexec_file_ops * const kexec_file_loaders[] = { &elf_kexec_ops, NULL }; + +int arch_kimage_file_post_load_cleanup(struct kimage *image) +{ + kvfree(image->arch.fdt); + image->arch.fdt = NULL; + + vfree(image->elf_headers); + image->elf_headers = NULL; + image->elf_headers_sz = 0; + + return kexec_image_post_load_cleanup_default(image); +} + +#ifdef CONFIG_CRASH_DUMP +static int get_nr_ram_ranges_callback(struct resource *res, void *arg) +{ + unsigned int *nr_ranges = arg; + + (*nr_ranges)++; + return 0; +} + +static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg) +{ + struct crash_mem *cmem = arg; + + cmem->ranges[cmem->nr_ranges].start = res->start; + cmem->ranges[cmem->nr_ranges].end = res->end; + cmem->nr_ranges++; + + return 0; +} + +static int prepare_elf_headers(void **addr, unsigned long *sz) +{ + struct crash_mem *cmem; + unsigned int nr_ranges; + int ret; + + nr_ranges = 1; /* For exclusion of crashkernel region */ + walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback); + + cmem = kmalloc(struct_size(cmem, ranges, nr_ranges), GFP_KERNEL); + if (!cmem) + return -ENOMEM; + + cmem->max_nr_ranges = nr_ranges; + cmem->nr_ranges = 0; + ret = walk_system_ram_res(0, -1, cmem, prepare_elf64_ram_headers_callback); + if (ret) + goto out; + + /* Exclude crashkernel region */ + ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end); + if (!ret) + ret = crash_prepare_elf64_headers(cmem, true, addr, sz); + +out: + kfree(cmem); + return ret; +} + +static char *setup_kdump_cmdline(struct kimage *image, char *cmdline, + unsigned long cmdline_len) +{ + int elfcorehdr_strlen; + char *cmdline_ptr; + + cmdline_ptr = kzalloc(COMMAND_LINE_SIZE, GFP_KERNEL); + if (!cmdline_ptr) + return NULL; + + elfcorehdr_strlen = sprintf(cmdline_ptr, "elfcorehdr=0x%lx ", + image->elf_load_addr); + + if (elfcorehdr_strlen + cmdline_len > COMMAND_LINE_SIZE) { + pr_err("Appending elfcorehdr= exceeds cmdline size\n"); + kfree(cmdline_ptr); + return NULL; + } + + memcpy(cmdline_ptr + elfcorehdr_strlen, cmdline, cmdline_len); + /* Ensure it's nul terminated */ + cmdline_ptr[COMMAND_LINE_SIZE - 1] = '\0'; + return cmdline_ptr; +} +#endif + +#define RV_X(x, s, n) (((x) >> (s)) & ((1 << (n)) - 1)) +#define RISCV_IMM_BITS 12 +#define RISCV_IMM_REACH (1LL << RISCV_IMM_BITS) +#define RISCV_CONST_HIGH_PART(x) \ + (((x) + (RISCV_IMM_REACH >> 1)) & ~(RISCV_IMM_REACH - 1)) +#define RISCV_CONST_LOW_PART(x) ((x) - RISCV_CONST_HIGH_PART(x)) + +#define ENCODE_ITYPE_IMM(x) \ + (RV_X(x, 0, 12) << 20) +#define ENCODE_BTYPE_IMM(x) \ + ((RV_X(x, 1, 4) << 8) | (RV_X(x, 5, 6) << 25) | \ + (RV_X(x, 11, 1) << 7) | (RV_X(x, 12, 1) << 31)) +#define ENCODE_UTYPE_IMM(x) \ + (RV_X(x, 12, 20) << 12) +#define ENCODE_JTYPE_IMM(x) \ + ((RV_X(x, 1, 10) << 21) | (RV_X(x, 11, 1) << 20) | \ + (RV_X(x, 12, 8) << 12) | (RV_X(x, 20, 1) << 31)) +#define ENCODE_CBTYPE_IMM(x) \ + ((RV_X(x, 1, 2) << 3) | (RV_X(x, 3, 2) << 10) | (RV_X(x, 5, 1) << 2) | \ + (RV_X(x, 6, 2) << 5) | (RV_X(x, 8, 1) << 12)) +#define ENCODE_CJTYPE_IMM(x) \ + ((RV_X(x, 1, 3) << 3) | (RV_X(x, 4, 1) << 11) | (RV_X(x, 5, 1) << 2) | \ + (RV_X(x, 6, 1) << 7) | (RV_X(x, 7, 1) << 6) | (RV_X(x, 8, 2) << 9) | \ + (RV_X(x, 10, 1) << 8) | (RV_X(x, 11, 1) << 12)) +#define ENCODE_UJTYPE_IMM(x) \ + (ENCODE_UTYPE_IMM(RISCV_CONST_HIGH_PART(x)) | \ + (ENCODE_ITYPE_IMM(RISCV_CONST_LOW_PART(x)) << 32)) +#define ENCODE_UITYPE_IMM(x) \ + (ENCODE_UTYPE_IMM(x) | (ENCODE_ITYPE_IMM(x) << 32)) + +#define CLEAN_IMM(type, x) \ + ((~ENCODE_##type##_IMM((uint64_t)(-1))) & (x)) + +int arch_kexec_apply_relocations_add(struct purgatory_info *pi, + Elf_Shdr *section, + const Elf_Shdr *relsec, + const Elf_Shdr *symtab) +{ + const char *strtab, *name, *shstrtab; + const Elf_Shdr *sechdrs; + Elf64_Rela *relas; + int i, r_type; + + /* String & section header string table */ + sechdrs = (void *)pi->ehdr + pi->ehdr->e_shoff; + strtab = (char *)pi->ehdr + sechdrs[symtab->sh_link].sh_offset; + shstrtab = (char *)pi->ehdr + sechdrs[pi->ehdr->e_shstrndx].sh_offset; + + relas = (void *)pi->ehdr + relsec->sh_offset; + + for (i = 0; i < relsec->sh_size / sizeof(*relas); i++) { + const Elf_Sym *sym; /* symbol to relocate */ + unsigned long addr; /* final location after relocation */ + unsigned long val; /* relocated symbol value */ + unsigned long sec_base; /* relocated symbol value */ + void *loc; /* tmp location to modify */ + + sym = (void *)pi->ehdr + symtab->sh_offset; + sym += ELF64_R_SYM(relas[i].r_info); + + if (sym->st_name) + name = strtab + sym->st_name; + else + name = shstrtab + sechdrs[sym->st_shndx].sh_name; + + loc = pi->purgatory_buf; + loc += section->sh_offset; + loc += relas[i].r_offset; + + if (sym->st_shndx == SHN_ABS) + sec_base = 0; + else if (sym->st_shndx >= pi->ehdr->e_shnum) { + pr_err("Invalid section %d for symbol %s\n", + sym->st_shndx, name); + return -ENOEXEC; + } else + sec_base = pi->sechdrs[sym->st_shndx].sh_addr; + + val = sym->st_value; + val += sec_base; + val += relas[i].r_addend; + + addr = section->sh_addr + relas[i].r_offset; + + r_type = ELF64_R_TYPE(relas[i].r_info); + + switch (r_type) { + case R_RISCV_BRANCH: + *(u32 *)loc = CLEAN_IMM(BTYPE, *(u32 *)loc) | + ENCODE_BTYPE_IMM(val - addr); + break; + case R_RISCV_JAL: + *(u32 *)loc = CLEAN_IMM(JTYPE, *(u32 *)loc) | + ENCODE_JTYPE_IMM(val - addr); + break; + /* + * With no R_RISCV_PCREL_LO12_S, R_RISCV_PCREL_LO12_I + * sym is expected to be next to R_RISCV_PCREL_HI20 + * in purgatory relsec. Handle it like R_RISCV_CALL + * sym, instead of searching the whole relsec. + */ + case R_RISCV_PCREL_HI20: + case R_RISCV_CALL_PLT: + case R_RISCV_CALL: + *(u64 *)loc = CLEAN_IMM(UITYPE, *(u64 *)loc) | + ENCODE_UJTYPE_IMM(val - addr); + break; + case R_RISCV_RVC_BRANCH: + *(u32 *)loc = CLEAN_IMM(CBTYPE, *(u32 *)loc) | + ENCODE_CBTYPE_IMM(val - addr); + break; + case R_RISCV_RVC_JUMP: + *(u32 *)loc = CLEAN_IMM(CJTYPE, *(u32 *)loc) | + ENCODE_CJTYPE_IMM(val - addr); + break; + case R_RISCV_ADD16: + *(u16 *)loc += val; + break; + case R_RISCV_SUB16: + *(u16 *)loc -= val; + break; + case R_RISCV_ADD32: + *(u32 *)loc += val; + break; + case R_RISCV_SUB32: + *(u32 *)loc -= val; + break; + /* It has been applied by R_RISCV_PCREL_HI20 sym */ + case R_RISCV_PCREL_LO12_I: + case R_RISCV_ALIGN: + case R_RISCV_RELAX: + break; + case R_RISCV_64: + *(u64 *)loc = val; + break; + default: + pr_err("Unknown rela relocation: %d\n", r_type); + return -ENOEXEC; + } + } + return 0; +} + + +int load_extra_segments(struct kimage *image, unsigned long kernel_start, + unsigned long kernel_len, char *initrd, + unsigned long initrd_len, char *cmdline, + unsigned long cmdline_len) +{ + int ret; + void *fdt; + unsigned long initrd_pbase = 0UL; + struct kexec_buf kbuf; + char *modified_cmdline = NULL; + + kbuf.image = image; + kbuf.buf_min = kernel_start + kernel_len; + kbuf.buf_max = ULONG_MAX; + +#ifdef CONFIG_CRASH_DUMP + /* Add elfcorehdr */ + if (image->type == KEXEC_TYPE_CRASH) { + void *headers; + unsigned long headers_sz; + ret = prepare_elf_headers(&headers, &headers_sz); + if (ret) { + pr_err("Preparing elf core header failed\n"); + goto out; + } + + kbuf.buffer = headers; + kbuf.bufsz = headers_sz; + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; + kbuf.memsz = headers_sz; + kbuf.buf_align = ELF_CORE_HEADER_ALIGN; + kbuf.top_down = true; + + ret = kexec_add_buffer(&kbuf); + if (ret) { + vfree(headers); + goto out; + } + image->elf_headers = headers; + image->elf_load_addr = kbuf.mem; + image->elf_headers_sz = headers_sz; + + kexec_dprintk("Loaded elf core header at 0x%lx bufsz=0x%lx memsz=0x%lx\n", + image->elf_load_addr, kbuf.bufsz, kbuf.memsz); + + /* Setup cmdline for kdump kernel case */ + modified_cmdline = setup_kdump_cmdline(image, cmdline, + cmdline_len); + if (!modified_cmdline) { + pr_err("Setting up cmdline for kdump kernel failed\n"); + ret = -EINVAL; + goto out; + } + cmdline = modified_cmdline; + } +#endif + +#ifdef CONFIG_ARCH_SUPPORTS_KEXEC_PURGATORY + /* Add purgatory to the image */ + kbuf.top_down = true; + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; + ret = kexec_load_purgatory(image, &kbuf); + if (ret) { + pr_err("Error loading purgatory ret=%d\n", ret); + goto out; + } + kexec_dprintk("Loaded purgatory at 0x%lx\n", kbuf.mem); + + ret = kexec_purgatory_get_set_symbol(image, "riscv_kernel_entry", + &kernel_start, + sizeof(kernel_start), 0); + if (ret) + pr_err("Error update purgatory ret=%d\n", ret); +#endif /* CONFIG_ARCH_SUPPORTS_KEXEC_PURGATORY */ + + /* Add the initrd to the image */ + if (initrd != NULL) { + kbuf.buffer = initrd; + kbuf.bufsz = kbuf.memsz = initrd_len; + kbuf.buf_align = PAGE_SIZE; + kbuf.top_down = true; + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; + ret = kexec_add_buffer(&kbuf); + if (ret) + goto out; + initrd_pbase = kbuf.mem; + kexec_dprintk("Loaded initrd at 0x%lx\n", initrd_pbase); + } + + /* Add the DTB to the image */ + fdt = of_kexec_alloc_and_setup_fdt(image, initrd_pbase, + initrd_len, cmdline, 0); + if (!fdt) { + pr_err("Error setting up the new device tree.\n"); + ret = -EINVAL; + goto out; + } + + fdt_pack(fdt); + kbuf.buffer = fdt; + kbuf.bufsz = kbuf.memsz = fdt_totalsize(fdt); + kbuf.buf_align = PAGE_SIZE; + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; + kbuf.top_down = true; + ret = kexec_add_buffer(&kbuf); + if (ret) { + pr_err("Error add DTB kbuf ret=%d\n", ret); + goto out_free_fdt; + } + /* Cache the fdt buffer address for memory cleanup */ + image->arch.fdt = fdt; + kexec_dprintk("Loaded device tree at 0x%lx\n", kbuf.mem); + goto out; + +out_free_fdt: + kvfree(fdt); +out: + kfree(modified_cmdline); + return ret; +} From 1aefa6c723b29ef6dc0290c644f3fdb86d6ce1dc Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Wed, 26 Mar 2025 07:34:51 +0000 Subject: [PATCH 26/91] riscv/kexec_file: Fix comment in purgatory relocator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apparently sec_base doesn't mean relocated symbol value, which seems a copy-pasting error in the comment. Assigned with the address of section indexed by sym->st_shndx, it should represent base address of the relevant section. Let's fix the comment to avoid possible confusion. Fixes: 838b3e28488f ("RISC-V: Load purgatory in kexec_file") Signed-off-by: Yao Zi Reviewed-by: Björn Töpel Link: https://lore.kernel.org/r/20250326073450.57648-2-ziyao@disroot.org Signed-off-by: Alexandre Ghiti --- arch/riscv/kernel/elf_kexec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/kernel/elf_kexec.c b/arch/riscv/kernel/elf_kexec.c index e783a72d051f43..0dc5450f2c7fcb 100644 --- a/arch/riscv/kernel/elf_kexec.c +++ b/arch/riscv/kernel/elf_kexec.c @@ -390,7 +390,7 @@ int arch_kexec_apply_relocations_add(struct purgatory_info *pi, const Elf_Sym *sym; /* symbol to relocate */ unsigned long addr; /* final location after relocation */ unsigned long val; /* relocated symbol value */ - unsigned long sec_base; /* relocated symbol value */ + unsigned long sec_base; /* relocated section base address */ void *loc; /* tmp location to modify */ sym = (void *)pi->ehdr + symtab->sh_offset; From af0498dfe8c2bb496b3f569db29a31dd755f2635 Mon Sep 17 00:00:00 2001 From: Andy Chiu Date: Tue, 8 Apr 2025 02:08:36 +0800 Subject: [PATCH 27/91] riscv: Documentation: add a description about dynamic ftrace Add a section in cmodx to describe how dynamic ftrace works on riscv, limitations, and assumptions. Signed-off-by: Andy Chiu Link: https://lore.kernel.org/r/20250407180838.42877-12-andybnac@gmail.com Signed-off-by: Alexandre Ghiti --- Documentation/arch/riscv/cmodx.rst | 46 +++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/Documentation/arch/riscv/cmodx.rst b/Documentation/arch/riscv/cmodx.rst index 8c48bcff3df9d2..e009873b2d17ee 100644 --- a/Documentation/arch/riscv/cmodx.rst +++ b/Documentation/arch/riscv/cmodx.rst @@ -10,13 +10,45 @@ modified by the program itself. Instruction storage and the instruction cache program must enforce its own synchronization with the unprivileged fence.i instruction. -However, the default Linux ABI prohibits the use of fence.i in userspace -applications. At any point the scheduler may migrate a task onto a new hart. If -migration occurs after the userspace synchronized the icache and instruction -storage with fence.i, the icache on the new hart will no longer be clean. This -is due to the behavior of fence.i only affecting the hart that it is called on. -Thus, the hart that the task has been migrated to may not have synchronized -instruction storage and icache. +CMODX in the Kernel Space +--------------------- + +Dynamic ftrace +--------------------- + +Essentially, dynamic ftrace directs the control flow by inserting a function +call at each patchable function entry, and patches it dynamically at runtime to +enable or disable the redirection. In the case of RISC-V, 2 instructions, +AUIPC + JALR, are required to compose a function call. However, it is impossible +to patch 2 instructions and expect that a concurrent read-side executes them +without a race condition. This series makes atmoic code patching possible in +RISC-V ftrace. Kernel preemption makes things even worse as it allows the old +state to persist across the patching process with stop_machine(). + +In order to get rid of stop_machine() and run dynamic ftrace with full kernel +preemption, we partially initialize each patchable function entry at boot-time, +setting the first instruction to AUIPC, and the second to NOP. Now, atmoic +patching is possible because the kernel only has to update one instruction. +According to Ziccif, as long as an instruction is naturally aligned, the ISA +guarantee an atomic update. + +By fixing down the first instruction, AUIPC, the range of the ftrace trampoline +is limited to +-2K from the predetermined target, ftrace_caller, due to the lack +of immediate encoding space in RISC-V. To address the issue, we introduce +CALL_OPS, where an 8B naturally align metadata is added in front of each +pacthable function. The metadata is resolved at the first trampoline, then the +execution can be derect to another custom trampoline. + +CMODX in the User Space +--------------------- + +Though fence.i is an unprivileged instruction, the default Linux ABI prohibits +the use of fence.i in userspace applications. At any point the scheduler may +migrate a task onto a new hart. If migration occurs after the userspace +synchronized the icache and instruction storage with fence.i, the icache on the +new hart will no longer be clean. This is due to the behavior of fence.i only +affecting the hart that it is called on. Thus, the hart that the task has been +migrated to may not have synchronized instruction storage and icache. There are two ways to solve this problem: use the riscv_flush_icache() syscall, or use the ``PR_RISCV_SET_ICACHE_FLUSH_CTX`` prctl() and emit fence.i in From ebf8a1000aa0a7723f980d90de7bc5c0c8d0af18 Mon Sep 17 00:00:00 2001 From: Guo Ren Date: Mon, 21 Apr 2025 16:24:40 +0200 Subject: [PATCH 28/91] riscv: Add ARCH_HAS_PREFETCH[W] support with Zicbop Enable Linux prefetch and prefetchw primitives using Zicbop. Signed-off-by: Guo Ren Signed-off-by: Guo Ren Link: https://lore.kernel.org/r/20231231082955.16516-3-guoren@kernel.org Tested-by: Andrea Parri Link: https://lore.kernel.org/r/20250421142441.395849-4-alexghiti@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/processor.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h index 09d4c963399ac7..39dfab495a4cb0 100644 --- a/arch/riscv/include/asm/processor.h +++ b/arch/riscv/include/asm/processor.h @@ -13,6 +13,9 @@ #include #include +#include +#include +#include #define arch_get_mmap_end(addr, len, flags) \ ({ \ @@ -135,6 +138,27 @@ static inline void arch_thread_struct_whitelist(unsigned long *offset, #define KSTK_EIP(tsk) (task_pt_regs(tsk)->epc) #define KSTK_ESP(tsk) (task_pt_regs(tsk)->sp) +#define PREFETCH_ASM(x) \ + ALTERNATIVE(__nops(1), PREFETCH_R(x, 0), 0, \ + RISCV_ISA_EXT_ZICBOP, CONFIG_RISCV_ISA_ZICBOP) + +#define PREFETCHW_ASM(x) \ + ALTERNATIVE(__nops(1), PREFETCH_W(x, 0), 0, \ + RISCV_ISA_EXT_ZICBOP, CONFIG_RISCV_ISA_ZICBOP) + +#ifdef CONFIG_RISCV_ISA_ZICBOP +#define ARCH_HAS_PREFETCH +static inline void prefetch(const void *x) +{ + __asm__ __volatile__(PREFETCH_ASM(%0) : : "r" (x) : "memory"); +} + +#define ARCH_HAS_PREFETCHW +static inline void prefetchw(const void *x) +{ + __asm__ __volatile__(PREFETCHW_ASM(%0) : : "r" (x) : "memory"); +} +#endif /* CONFIG_RISCV_ISA_ZICBOP */ /* Do necessary setup to start up a newly executed thread. */ extern void start_thread(struct pt_regs *regs, From 6a8666eb2f096a11922c41a7dfed2b970c41bb61 Mon Sep 17 00:00:00 2001 From: Song Shuai Date: Wed, 9 Apr 2025 21:29:59 +0200 Subject: [PATCH 29/91] riscv: kexec_file: Support loading Image binary file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch creates image_kexec_ops to load Image binary file for kexec_file_load() syscall. Signed-off-by: Song Shuai Signed-off-by: Björn Töpel Link: https://lore.kernel.org/r/20250409193004.643839-3-bjorn@kernel.org Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/image.h | 2 + arch/riscv/include/asm/kexec.h | 1 + arch/riscv/kernel/Makefile | 2 +- arch/riscv/kernel/kexec_image.c | 96 ++++++++++++++++++++++++++ arch/riscv/kernel/machine_kexec_file.c | 1 + 5 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 arch/riscv/kernel/kexec_image.c diff --git a/arch/riscv/include/asm/image.h b/arch/riscv/include/asm/image.h index e0b319af3681a6..8927a6ea1127e2 100644 --- a/arch/riscv/include/asm/image.h +++ b/arch/riscv/include/asm/image.h @@ -30,6 +30,8 @@ RISCV_HEADER_VERSION_MINOR) #ifndef __ASSEMBLY__ +#define riscv_image_flag_field(flags, field)\ + (((flags) >> field##_SHIFT) & field##_MASK) /** * struct riscv_image_header - riscv kernel image header * @code0: Executable code diff --git a/arch/riscv/include/asm/kexec.h b/arch/riscv/include/asm/kexec.h index 518825fe4160c0..b9ee8346cc8c9a 100644 --- a/arch/riscv/include/asm/kexec.h +++ b/arch/riscv/include/asm/kexec.h @@ -56,6 +56,7 @@ extern riscv_kexec_method riscv_kexec_norelocate; #ifdef CONFIG_KEXEC_FILE extern const struct kexec_file_ops elf_kexec_ops; +extern const struct kexec_file_ops image_kexec_ops; struct purgatory_info; int arch_kexec_apply_relocations_add(struct purgatory_info *pi, diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index 2c07a62a1d555a..7ce2307738c2a6 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -107,7 +107,7 @@ obj-$(CONFIG_HOTPLUG_CPU) += cpu-hotplug.o obj-$(CONFIG_PARAVIRT) += paravirt.o obj-$(CONFIG_KGDB) += kgdb.o obj-$(CONFIG_KEXEC_CORE) += kexec_relocate.o crash_save_regs.o machine_kexec.o -obj-$(CONFIG_KEXEC_FILE) += kexec_elf.o machine_kexec_file.o +obj-$(CONFIG_KEXEC_FILE) += kexec_elf.o kexec_image.o machine_kexec_file.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_VMCORE_INFO) += vmcore_info.o diff --git a/arch/riscv/kernel/kexec_image.c b/arch/riscv/kernel/kexec_image.c new file mode 100644 index 00000000000000..26a81774a78a36 --- /dev/null +++ b/arch/riscv/kernel/kexec_image.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * RISC-V Kexec image loader + * + */ + +#define pr_fmt(fmt) "kexec_file(Image): " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +static int image_probe(const char *kernel_buf, unsigned long kernel_len) +{ + const struct riscv_image_header *h = (const struct riscv_image_header *)kernel_buf; + + if (!h || kernel_len < sizeof(*h)) + return -EINVAL; + + /* According to Documentation/riscv/boot-image-header.rst, + * use "magic2" field to check when version >= 0.2. + */ + + if (h->version >= RISCV_HEADER_VERSION && + memcmp(&h->magic2, RISCV_IMAGE_MAGIC2, sizeof(h->magic2))) + return -EINVAL; + + return 0; +} + +static void *image_load(struct kimage *image, + char *kernel, unsigned long kernel_len, + char *initrd, unsigned long initrd_len, + char *cmdline, unsigned long cmdline_len) +{ + struct riscv_image_header *h; + u64 flags; + bool be_image, be_kernel; + struct kexec_buf kbuf; + int ret; + + /* Check Image header */ + h = (struct riscv_image_header *)kernel; + if (!h->image_size) { + ret = -EINVAL; + goto out; + } + + /* Check endianness */ + flags = le64_to_cpu(h->flags); + be_image = riscv_image_flag_field(flags, RISCV_IMAGE_FLAG_BE); + be_kernel = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN); + if (be_image != be_kernel) { + ret = -EINVAL; + goto out; + } + + /* Load the kernel image */ + kbuf.image = image; + kbuf.buf_min = 0; + kbuf.buf_max = ULONG_MAX; + kbuf.top_down = false; + + kbuf.buffer = kernel; + kbuf.bufsz = kernel_len; + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; + kbuf.memsz = le64_to_cpu(h->image_size); + kbuf.buf_align = le64_to_cpu(h->text_offset); + + ret = kexec_add_buffer(&kbuf); + if (ret) { + pr_err("Error add kernel image ret=%d\n", ret); + goto out; + } + + image->start = kbuf.mem; + + pr_info("Loaded kernel at 0x%lx bufsz=0x%lx memsz=0x%lx\n", + kbuf.mem, kbuf.bufsz, kbuf.memsz); + + ret = load_extra_segments(image, kbuf.mem, kbuf.memsz, + initrd, initrd_len, cmdline, cmdline_len); + +out: + return ret ? ERR_PTR(ret) : NULL; +} + +const struct kexec_file_ops image_kexec_ops = { + .probe = image_probe, + .load = image_load, +}; diff --git a/arch/riscv/kernel/machine_kexec_file.c b/arch/riscv/kernel/machine_kexec_file.c index 99bd5a5f423468..e36104af2e247f 100644 --- a/arch/riscv/kernel/machine_kexec_file.c +++ b/arch/riscv/kernel/machine_kexec_file.c @@ -18,6 +18,7 @@ const struct kexec_file_ops * const kexec_file_loaders[] = { &elf_kexec_ops, + &image_kexec_ops, NULL }; From 0778d303eaba43c4ae9b9a8b14a8ed062300ba8c Mon Sep 17 00:00:00 2001 From: Alexandre Ghiti Date: Fri, 21 Mar 2025 13:39:54 +0100 Subject: [PATCH 30/91] riscv: Add support for PUD THP Add the necessary page table functions to deal with PUD THP, this enables the use of PUD pfnmap. Link: https://lore.kernel.org/r/20250321123954.225097-1-alexghiti@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/Kconfig | 1 + arch/riscv/include/asm/pgtable-64.h | 5 +- arch/riscv/include/asm/pgtable.h | 97 +++++++++++++++++++++++++++++ arch/riscv/include/asm/tlbflush.h | 2 + arch/riscv/mm/pgtable.c | 10 +++ arch/riscv/mm/tlbflush.c | 7 +++ 6 files changed, 120 insertions(+), 2 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index bbec87b7930999..63ef4aa0350657 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -143,6 +143,7 @@ config RISCV select HAVE_ARCH_THREAD_STRUCT_WHITELIST select HAVE_ARCH_TRACEHOOK select HAVE_ARCH_TRANSPARENT_HUGEPAGE if 64BIT && MMU + select HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD if 64BIT && MMU select HAVE_ARCH_USERFAULTFD_MINOR if 64BIT && USERFAULTFD select HAVE_ARCH_VMAP_STACK if MMU && 64BIT select HAVE_ASM_MODVERSIONS diff --git a/arch/riscv/include/asm/pgtable-64.h b/arch/riscv/include/asm/pgtable-64.h index 0897dd99ab8d5b..a2c00235c447c1 100644 --- a/arch/riscv/include/asm/pgtable-64.h +++ b/arch/riscv/include/asm/pgtable-64.h @@ -184,7 +184,7 @@ static inline int pud_none(pud_t pud) static inline int pud_bad(pud_t pud) { - return !pud_present(pud); + return !pud_present(pud) || (pud_val(pud) & _PAGE_LEAF); } #define pud_leaf pud_leaf @@ -401,6 +401,7 @@ p4d_t *p4d_offset(pgd_t *pgd, unsigned long address); #ifdef CONFIG_TRANSPARENT_HUGEPAGE static inline int pte_devmap(pte_t pte); static inline pte_t pmd_pte(pmd_t pmd); +static inline pte_t pud_pte(pud_t pud); static inline int pmd_devmap(pmd_t pmd) { @@ -409,7 +410,7 @@ static inline int pmd_devmap(pmd_t pmd) static inline int pud_devmap(pud_t pud) { - return 0; + return pte_devmap(pud_pte(pud)); } static inline int pgd_devmap(pgd_t pgd) diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h index 428e48e5f57d06..b84e2ff83cb7b0 100644 --- a/arch/riscv/include/asm/pgtable.h +++ b/arch/riscv/include/asm/pgtable.h @@ -902,6 +902,103 @@ static inline pmd_t pmdp_establish(struct vm_area_struct *vma, #define pmdp_collapse_flush pmdp_collapse_flush extern pmd_t pmdp_collapse_flush(struct vm_area_struct *vma, unsigned long address, pmd_t *pmdp); + +static inline pud_t pud_wrprotect(pud_t pud) +{ + return pte_pud(pte_wrprotect(pud_pte(pud))); +} + +static inline int pud_trans_huge(pud_t pud) +{ + return pud_leaf(pud); +} + +static inline int pud_dirty(pud_t pud) +{ + return pte_dirty(pud_pte(pud)); +} + +static inline pud_t pud_mkyoung(pud_t pud) +{ + return pte_pud(pte_mkyoung(pud_pte(pud))); +} + +static inline pud_t pud_mkold(pud_t pud) +{ + return pte_pud(pte_mkold(pud_pte(pud))); +} + +static inline pud_t pud_mkdirty(pud_t pud) +{ + return pte_pud(pte_mkdirty(pud_pte(pud))); +} + +static inline pud_t pud_mkclean(pud_t pud) +{ + return pte_pud(pte_mkclean(pud_pte(pud))); +} + +static inline pud_t pud_mkwrite(pud_t pud) +{ + return pte_pud(pte_mkwrite_novma(pud_pte(pud))); +} + +static inline pud_t pud_mkhuge(pud_t pud) +{ + return pud; +} + +static inline pud_t pud_mkdevmap(pud_t pud) +{ + return pte_pud(pte_mkdevmap(pud_pte(pud))); +} + +static inline int pudp_set_access_flags(struct vm_area_struct *vma, + unsigned long address, pud_t *pudp, + pud_t entry, int dirty) +{ + return ptep_set_access_flags(vma, address, (pte_t *)pudp, pud_pte(entry), dirty); +} + +static inline int pudp_test_and_clear_young(struct vm_area_struct *vma, + unsigned long address, pud_t *pudp) +{ + return ptep_test_and_clear_young(vma, address, (pte_t *)pudp); +} + +static inline int pud_young(pud_t pud) +{ + return pte_young(pud_pte(pud)); +} + +static inline void update_mmu_cache_pud(struct vm_area_struct *vma, + unsigned long address, pud_t *pudp) +{ + pte_t *ptep = (pte_t *)pudp; + + update_mmu_cache(vma, address, ptep); +} + +static inline pud_t pudp_establish(struct vm_area_struct *vma, + unsigned long address, pud_t *pudp, pud_t pud) +{ + page_table_check_pud_set(vma->vm_mm, pudp, pud); + return __pud(atomic_long_xchg((atomic_long_t *)pudp, pud_val(pud))); +} + +static inline pud_t pud_mkinvalid(pud_t pud) +{ + return __pud(pud_val(pud) & ~(_PAGE_PRESENT | _PAGE_PROT_NONE)); +} + +extern pud_t pudp_invalidate(struct vm_area_struct *vma, unsigned long address, + pud_t *pudp); + +static inline pud_t pud_modify(pud_t pud, pgprot_t newprot) +{ + return pte_pud(pte_modify(pud_pte(pud), newprot)); +} + #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ /* diff --git a/arch/riscv/include/asm/tlbflush.h b/arch/riscv/include/asm/tlbflush.h index ce0dd0fed7646a..1a20dd746a49f3 100644 --- a/arch/riscv/include/asm/tlbflush.h +++ b/arch/riscv/include/asm/tlbflush.h @@ -56,6 +56,8 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end); #define __HAVE_ARCH_FLUSH_PMD_TLB_RANGE void flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); +void flush_pud_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end); #endif bool arch_tlbbatch_should_defer(struct mm_struct *mm); diff --git a/arch/riscv/mm/pgtable.c b/arch/riscv/mm/pgtable.c index 4ae67324f99233..8b6c0a112a8db4 100644 --- a/arch/riscv/mm/pgtable.c +++ b/arch/riscv/mm/pgtable.c @@ -154,4 +154,14 @@ pmd_t pmdp_collapse_flush(struct vm_area_struct *vma, flush_tlb_mm(vma->vm_mm); return pmd; } + +pud_t pudp_invalidate(struct vm_area_struct *vma, unsigned long address, + pud_t *pudp) +{ + VM_WARN_ON_ONCE(!pud_present(*pudp)); + pud_t old = pudp_establish(vma, address, pudp, pud_mkinvalid(*pudp)); + + flush_pud_tlb_range(vma, address, address + HPAGE_PUD_SIZE); + return old; +} #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ diff --git a/arch/riscv/mm/tlbflush.c b/arch/riscv/mm/tlbflush.c index f9e27ba1df99ff..97c8fde3cbfe4f 100644 --- a/arch/riscv/mm/tlbflush.c +++ b/arch/riscv/mm/tlbflush.c @@ -182,6 +182,13 @@ void flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start, __flush_tlb_range(vma->vm_mm, mm_cpumask(vma->vm_mm), start, end - start, PMD_SIZE); } + +void flush_pud_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end) +{ + __flush_tlb_range(vma->vm_mm, mm_cpumask(vma->vm_mm), + start, end - start, PUD_SIZE); +} #endif bool arch_tlbbatch_should_defer(struct mm_struct *mm) From 324810c2be2ab94788fc94f6027c0232d29bde66 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 9 Apr 2025 10:14:51 -0700 Subject: [PATCH 31/91] riscv: module: Optimize PLT/GOT entry counting perf reports that 99.63% of the cycles from `modprobe amdgpu` are spent inside module_frob_arch_sections(). This is because amdgpu.ko contains about 300000 relocations in its .rela.text section, and the algorithm in count_max_entries() takes quadratic time. Apply two optimizations from the arm64 code, which together reduce the total execution time by 99.58%. First, sort the relocations so duplicate entries are adjacent. Second, reduce the number of relocations that must be sorted by filtering to only relocations that need PLT/GOT entries, as done in commit d4e0340919fb ("arm64/module: Optimize module load time by optimizing PLT counting"). Unlike the arm64 code, here the filtering and sorting is done in a scratch buffer, because the HI20 relocation search optimization in apply_relocate_add() depends on the original order of the relocations. This allows accumulating PLT/GOT relocations across sections so sorting and counting is only done once per module. Signed-off-by: Samuel Holland Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/20250409171526.862481-3-samuel.holland@sifive.com Signed-off-by: Alexandre Ghiti --- arch/riscv/kernel/module-sections.c | 81 +++++++++++++++++++++++------ 1 file changed, 65 insertions(+), 16 deletions(-) diff --git a/arch/riscv/kernel/module-sections.c b/arch/riscv/kernel/module-sections.c index 91d0b355ceeff6..75551ac6504c5d 100644 --- a/arch/riscv/kernel/module-sections.c +++ b/arch/riscv/kernel/module-sections.c @@ -9,6 +9,7 @@ #include #include #include +#include unsigned long module_emit_got_entry(struct module *mod, unsigned long val) { @@ -55,44 +56,70 @@ unsigned long module_emit_plt_entry(struct module *mod, unsigned long val) return (unsigned long)&plt[i]; } -static int is_rela_equal(const Elf_Rela *x, const Elf_Rela *y) +#define cmp_3way(a, b) ((a) < (b) ? -1 : (a) > (b)) + +static int cmp_rela(const void *a, const void *b) { - return x->r_info == y->r_info && x->r_addend == y->r_addend; + const Elf_Rela *x = a, *y = b; + int i; + + /* sort by type, symbol index and addend */ + i = cmp_3way(x->r_info, y->r_info); + if (i == 0) + i = cmp_3way(x->r_addend, y->r_addend); + return i; } static bool duplicate_rela(const Elf_Rela *rela, int idx) { - int i; - for (i = 0; i < idx; i++) { - if (is_rela_equal(&rela[i], &rela[idx])) - return true; - } - return false; + /* + * Entries are sorted by type, symbol index and addend. That means + * that, if a duplicate entry exists, it must be in the preceding slot. + */ + return idx > 0 && cmp_rela(rela + idx, rela + idx - 1) == 0; } -static void count_max_entries(Elf_Rela *relas, int num, +static void count_max_entries(const Elf_Rela *relas, size_t num, unsigned int *plts, unsigned int *gots) { - for (int i = 0; i < num; i++) { + for (size_t i = 0; i < num; i++) { + if (duplicate_rela(relas, i)) + continue; + switch (ELF_R_TYPE(relas[i].r_info)) { case R_RISCV_CALL_PLT: case R_RISCV_PLT32: - if (!duplicate_rela(relas, i)) - (*plts)++; + (*plts)++; break; case R_RISCV_GOT_HI20: - if (!duplicate_rela(relas, i)) - (*gots)++; + (*gots)++; break; + default: + unreachable(); } } } +static bool rela_needs_plt_got_entry(const Elf_Rela *rela) +{ + switch (ELF_R_TYPE(rela->r_info)) { + case R_RISCV_CALL_PLT: + case R_RISCV_GOT_HI20: + case R_RISCV_PLT32: + return true; + default: + return false; + } +} + int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, char *secstrings, struct module *mod) { + size_t num_scratch_relas = 0; unsigned int num_plts = 0; unsigned int num_gots = 0; + Elf_Rela *scratch = NULL; + size_t scratch_size = 0; int i; /* @@ -122,9 +149,10 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, /* Calculate the maxinum number of entries */ for (i = 0; i < ehdr->e_shnum; i++) { + size_t num_relas = sechdrs[i].sh_size / sizeof(Elf_Rela); Elf_Rela *relas = (void *)ehdr + sechdrs[i].sh_offset; - int num_rela = sechdrs[i].sh_size / sizeof(Elf_Rela); Elf_Shdr *dst_sec = sechdrs + sechdrs[i].sh_info; + size_t scratch_size_needed; if (sechdrs[i].sh_type != SHT_RELA) continue; @@ -133,7 +161,28 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, if (!(dst_sec->sh_flags & SHF_EXECINSTR)) continue; - count_max_entries(relas, num_rela, &num_plts, &num_gots); + /* + * apply_relocate_add() relies on HI20 and LO12 relocation pairs being + * close together, so sort a copy of the section to avoid interfering. + */ + scratch_size_needed = (num_scratch_relas + num_relas) * sizeof(*scratch); + if (scratch_size_needed > scratch_size) { + scratch_size = scratch_size_needed; + scratch = kvrealloc(scratch, scratch_size, GFP_KERNEL); + if (!scratch) + return -ENOMEM; + } + + for (size_t j = 0; j < num_relas; j++) + if (rela_needs_plt_got_entry(&relas[j])) + scratch[num_scratch_relas++] = relas[j]; + } + + if (scratch) { + /* sort the accumulated PLT/GOT relocations so duplicates are adjacent */ + sort(scratch, num_scratch_relas, sizeof(*scratch), cmp_rela, NULL); + count_max_entries(scratch, num_scratch_relas, &num_plts, &num_gots); + kvfree(scratch); } mod->arch.plt.shdr->sh_type = SHT_NOBITS; From fe5dbeeedcfdce3f7ae1e791f0452e3100c246c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B0=A2=E8=87=B4=E9=82=A6=20=28XIE=20Zhibang=29?= Date: Fri, 28 Mar 2025 10:14:22 +0000 Subject: [PATCH 32/91] RISC-V: Kconfig: Fix help text of CMDLINE_EXTEND MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is the built-in command line appended to the bootloader command line, not the bootloader command line appended to the built-in command line. Fixes: 3aed8c43267e ("RISC-V: Update Kconfig to better handle CMDLINE") Signed-off-by: 谢致邦 (XIE Zhibang) Link: https://lore.kernel.org/r/tencent_A93C7FB46BFD20054AD2FEF4645913FF550A@qq.com Signed-off-by: Alexandre Ghiti --- arch/riscv/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 674cf6ff7188f3..78640cd353fde6 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -1176,8 +1176,8 @@ config CMDLINE_FALLBACK config CMDLINE_EXTEND bool "Extend bootloader kernel arguments" help - The command-line arguments provided during boot will be - appended to the built-in command line. This is useful in + The built-in command line will be appended to the command- + line arguments provided during boot. This is useful in cases where the provided arguments are insufficient and you don't want to or cannot modify them. From a2711b0c33fa09ef1c1f853c90ebf85fdd34a939 Mon Sep 17 00:00:00 2001 From: Guo Ren Date: Mon, 21 Apr 2025 16:24:41 +0200 Subject: [PATCH 33/91] riscv: xchg: Prefetch the destination word for sc.w The cost of changing a cacheline from shared to exclusive state can be significant, especially when this is triggered by an exclusive store, since it may result in having to retry the transaction. This patch makes use of prefetch.w to prefetch cachelines for write prior to lr/sc loops when using the xchg_small atomic routine. This patch is inspired by commit 0ea366f5e1b6 ("arm64: atomics: prefetch the destination word for write prior to stxr"). Signed-off-by: Guo Ren Signed-off-by: Guo Ren Link: https://lore.kernel.org/r/20231231082955.16516-4-guoren@kernel.org Tested-by: Andrea Parri Link: https://lore.kernel.org/r/20250421142441.395849-5-alexghiti@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/cmpxchg.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/riscv/include/asm/cmpxchg.h b/arch/riscv/include/asm/cmpxchg.h index 2ec119eb147bb6..0b749e71021624 100644 --- a/arch/riscv/include/asm/cmpxchg.h +++ b/arch/riscv/include/asm/cmpxchg.h @@ -13,6 +13,7 @@ #include #include #include +#include #define __arch_xchg_masked(sc_sfx, swap_sfx, prepend, sc_append, \ swap_append, r, p, n) \ @@ -37,6 +38,7 @@ \ __asm__ __volatile__ ( \ prepend \ + PREFETCHW_ASM(%5) \ "0: lr.w %0, %2\n" \ " and %1, %0, %z4\n" \ " or %1, %1, %z3\n" \ @@ -44,7 +46,7 @@ " bnez %1, 0b\n" \ sc_append \ : "=&r" (__retx), "=&r" (__rc), "+A" (*(__ptr32b)) \ - : "rJ" (__newx), "rJ" (~__mask) \ + : "rJ" (__newx), "rJ" (~__mask), "rJ" (__ptr32b) \ : "memory"); \ \ r = (__typeof__(*(p)))((__retx & __mask) >> __s); \ From d4bed96716a0dd9c60131625e36ee8fcb16db32b Mon Sep 17 00:00:00 2001 From: Haibo Xu Date: Wed, 9 Apr 2025 10:51:56 +0800 Subject: [PATCH 34/91] perf symbols: Ignore mapping symbols on riscv RISCV ELF use mapping symbols with special names $x, $d to identify regions of RISCV code or code with different ISAs[1]. These symbols don't identify functions, so will confuse the perf output. The patch filters out these symbols at load time, similar to "4886f2ca perf symbols: Ignore mapping symbols on aarch64". [1] https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/ master/riscv-elf.adoc#mapping-symbol Signed-off-by: Haibo Xu Acked-by: Namhyung Kim Link: https://lore.kernel.org/r/20250409025202.201046-1-haibo1.xu@intel.com Signed-off-by: Alexandre Ghiti --- tools/perf/util/symbol-elf.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index fbf6d0f73af915..55b1409b0593d7 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -1733,6 +1733,12 @@ dso__load_sym_internal(struct dso *dso, struct map *map, struct symsrc *syms_ss, continue; } + /* Reject RISCV ELF "mapping symbols" */ + if (ehdr.e_machine == EM_RISCV) { + if (elf_name[0] == '$' && strchr("dx", elf_name[1])) + continue; + } + if (runtime_ss->opdsec && sym.st_shndx == runtime_ss->opdidx) { u32 offset = sym.st_value - syms_ss->opdshdr.sh_addr; u64 *opd = opddata->d_buf + offset; From ad8367b96011cc6c87c95d098f8048bddd4ae787 Mon Sep 17 00:00:00 2001 From: Tiezhu Yang Date: Tue, 22 Apr 2025 19:31:56 +0800 Subject: [PATCH 35/91] riscv: Make regs_irqs_disabled() more clear The return value of regs_irqs_disabled() is true or false, so change its type to reflect that and also make it always inline. Suggested-by: Huacai Chen Signed-off-by: Tiezhu Yang Reviewed-by: Alexandre Ghiti Link: https://lore.kernel.org/r/20250422113156.25742-1-yangtiezhu@loongson.cn Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/ptrace.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/include/asm/ptrace.h b/arch/riscv/include/asm/ptrace.h index 2910231977cb71..a7dc0e33075796 100644 --- a/arch/riscv/include/asm/ptrace.h +++ b/arch/riscv/include/asm/ptrace.h @@ -175,7 +175,7 @@ static inline unsigned long regs_get_kernel_argument(struct pt_regs *regs, return 0; } -static inline int regs_irqs_disabled(struct pt_regs *regs) +static __always_inline bool regs_irqs_disabled(struct pt_regs *regs) { return !(regs->status & SR_PIE); } From 7c30767f6abcadc5b01671bb267334e1f787269a Mon Sep 17 00:00:00 2001 From: Alexandre Ghiti Date: Mon, 21 Apr 2025 16:14:13 +0200 Subject: [PATCH 36/91] riscv: hwprobe: export Zabha extension MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Export Zabha through the hwprobe syscall. Reviewed-by: Clément Léger Link: https://lore.kernel.org/r/20250421141413.394444-1-alexghiti@rivosinc.com Signed-off-by: Alexandre Ghiti --- Documentation/arch/riscv/hwprobe.rst | 4 ++++ arch/riscv/include/uapi/asm/hwprobe.h | 1 + arch/riscv/kernel/sys_hwprobe.c | 1 + 3 files changed, 6 insertions(+) diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst index f60bf599175597..a4998ad2dfe09e 100644 --- a/Documentation/arch/riscv/hwprobe.rst +++ b/Documentation/arch/riscv/hwprobe.rst @@ -271,6 +271,10 @@ The following keys are defined: * :c:macro:`RISCV_HWPROBE_EXT_ZICBOM`: The Zicbom extension is supported, as ratified in commit 3dd606f ("Create cmobase-v1.0.pdf") of riscv-CMOs. + * :c:macro:`RISCV_HWPROBE_EXT_ZABHA`: The Zabha extension is supported as + ratified in commit 49f49c842ff9 ("Update to Rafified state") of + riscv-zabha. + * :c:macro:`RISCV_HWPROBE_KEY_CPUPERF_0`: Deprecated. Returns similar values to :c:macro:`RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF`, but the key was mistakenly classified as a bitmask rather than a value. diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h index 3c2fce939673b9..fca15f2bf6f3cc 100644 --- a/arch/riscv/include/uapi/asm/hwprobe.h +++ b/arch/riscv/include/uapi/asm/hwprobe.h @@ -81,6 +81,7 @@ struct riscv_hwprobe { #define RISCV_HWPROBE_EXT_ZICBOM (1ULL << 55) #define RISCV_HWPROBE_EXT_ZAAMO (1ULL << 56) #define RISCV_HWPROBE_EXT_ZALRSC (1ULL << 57) +#define RISCV_HWPROBE_EXT_ZABHA (1ULL << 58) #define RISCV_HWPROBE_KEY_CPUPERF_0 5 #define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0) #define RISCV_HWPROBE_MISALIGNED_EMULATED (1 << 0) diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c index 249aec8594a92a..ed3123396a96be 100644 --- a/arch/riscv/kernel/sys_hwprobe.c +++ b/arch/riscv/kernel/sys_hwprobe.c @@ -96,6 +96,7 @@ static void hwprobe_isa_ext0(struct riscv_hwprobe *pair, * presence in the hart_isa bitmap, are made. */ EXT_KEY(ZAAMO); + EXT_KEY(ZABHA); EXT_KEY(ZACAS); EXT_KEY(ZALRSC); EXT_KEY(ZAWRS); From 466c1a843ae05bc27a7945cddce11833a0b81858 Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Mon, 5 May 2025 14:27:38 -0700 Subject: [PATCH 37/91] MAINTAINERS: Update Atish's email address My personal upstream email account was previously based on gmail which has become difficult to manage upstream activities lately. Update it to the more reliable linux.dev account. Signed-off-by: Atish Patra Link: https://lore.kernel.org/r/20250505-update_email_address-v1-1-1c24db506fdb@rivosinc.com Signed-off-by: Alexandre Ghiti --- .mailmap | 3 ++- MAINTAINERS | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.mailmap b/.mailmap index 9afde79e1936e5..f7a81702309e51 100644 --- a/.mailmap +++ b/.mailmap @@ -105,7 +105,8 @@ Arun Kumar Neelakantam Ashok Raj Nagarajan Ashwin Chaugule Asutosh Das -Atish Patra +Atish Patra +Atish Patra Avaneesh Kumar Dwivedi Axel Dyks Axel Lin diff --git a/MAINTAINERS b/MAINTAINERS index 69511c3b2b76fb..11a50154c84be4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13070,7 +13070,7 @@ F: arch/powerpc/kvm/ KERNEL VIRTUAL MACHINE FOR RISC-V (KVM/riscv) M: Anup Patel -R: Atish Patra +R: Atish Patra L: kvm@vger.kernel.org L: kvm-riscv@lists.infradead.org L: linux-riscv@lists.infradead.org @@ -20877,7 +20877,7 @@ F: arch/riscv/boot/dts/sifive/ F: arch/riscv/boot/dts/starfive/ RISC-V PMU DRIVERS -M: Atish Patra +M: Atish Patra R: Anup Patel L: linux-riscv@lists.infradead.org S: Supported From 25185c6206f84ad4ea9b4e989dcc2c83d66e18e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miquel=20Sabat=C3=A9=20Sol=C3=A0?= Date: Thu, 1 May 2025 15:03:09 +0200 Subject: [PATCH 38/91] riscv: Improve Kconfig help for RISCV_ISA_V_PREEMPTIVE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix a couple of spelling issues plus some minor details on the grammar. Signed-off-by: Miquel Sabaté Solà Link: https://lore.kernel.org/r/20250501130309.14803-1-mikisabate@gmail.com Reviewed-by: Alexandre Ghiti Signed-off-by: Alexandre Ghiti --- arch/riscv/Kconfig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index a93af30727ee45..98a3ecdc65f6be 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -669,12 +669,12 @@ config RISCV_ISA_V_PREEMPTIVE default y help Usually, in-kernel SIMD routines are run with preemption disabled. - Functions which envoke long running SIMD thus must yield core's + Functions which invoke long running SIMD thus must yield the core's vector unit to prevent blocking other tasks for too long. - This config allows kernel to run SIMD without explicitly disable - preemption. Enabling this config will result in higher memory - consumption due to the allocation of per-task's kernel Vector context. + This config allows the kernel to run SIMD without explicitly disabling + preemption. Enabling this config will result in higher memory consumption + due to the allocation of per-task's kernel Vector context. config RISCV_ISA_ZAWRS bool "Zawrs extension support for more efficient busy waiting" From e3c23dafd3cdc78db37b34964b83cb4b7a6d47e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= Date: Tue, 22 Apr 2025 18:23:11 +0200 Subject: [PATCH 39/91] Documentation/sysctl: add riscv to unaligned-trap supported archs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit riscv supports the "unaligned-trap" sysctl variable, add it to the list of supported architectures. Signed-off-by: Clément Léger Reviewed-by: Alexandre Ghiti Link: https://lore.kernel.org/r/20250422162324.956065-5-cleger@rivosinc.com Signed-off-by: Alexandre Ghiti --- Documentation/admin-guide/sysctl/kernel.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst index dd49a89a62d354..a38e91c4d92cb5 100644 --- a/Documentation/admin-guide/sysctl/kernel.rst +++ b/Documentation/admin-guide/sysctl/kernel.rst @@ -1595,8 +1595,8 @@ unaligned-trap On architectures where unaligned accesses cause traps, and where this feature is supported (``CONFIG_SYSCTL_ARCH_UNALIGN_ALLOW``; currently, -``arc``, ``parisc`` and ``loongarch``), controls whether unaligned traps -are caught and emulated (instead of failing). +``arc``, ``parisc``, ``loongarch`` and ``riscv``), controls whether unaligned +traps are caught and emulated (instead of failing). = ======================================================== 0 Do not emulate unaligned accesses. From 15deee841b563ad7797aacb874d3346a13dad1f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= Date: Tue, 22 Apr 2025 18:23:12 +0200 Subject: [PATCH 40/91] selftests: riscv: add misaligned access testing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This selftest tests (almost) all the currently emulated instruction (except for the RV32 compressed ones which are left as a future exercise for a RV32 user). For the FPU instructions, all the FPU registers are tested. [ alex: Fix indentation and empty line at eof ] Signed-off-by: Clément Léger Link: https://lore.kernel.org/r/20250422162324.956065-6-cleger@rivosinc.com Signed-off-by: Alexandre Ghiti --- .../selftests/riscv/misaligned/.gitignore | 1 + .../selftests/riscv/misaligned/Makefile | 12 + .../selftests/riscv/misaligned/common.S | 33 +++ .../testing/selftests/riscv/misaligned/fpu.S | 180 +++++++++++++ tools/testing/selftests/riscv/misaligned/gp.S | 102 +++++++ .../selftests/riscv/misaligned/misaligned.c | 254 ++++++++++++++++++ 6 files changed, 582 insertions(+) create mode 100644 tools/testing/selftests/riscv/misaligned/.gitignore create mode 100644 tools/testing/selftests/riscv/misaligned/Makefile create mode 100644 tools/testing/selftests/riscv/misaligned/common.S create mode 100644 tools/testing/selftests/riscv/misaligned/fpu.S create mode 100644 tools/testing/selftests/riscv/misaligned/gp.S create mode 100644 tools/testing/selftests/riscv/misaligned/misaligned.c diff --git a/tools/testing/selftests/riscv/misaligned/.gitignore b/tools/testing/selftests/riscv/misaligned/.gitignore new file mode 100644 index 00000000000000..5eff15a1f9812a --- /dev/null +++ b/tools/testing/selftests/riscv/misaligned/.gitignore @@ -0,0 +1 @@ +misaligned diff --git a/tools/testing/selftests/riscv/misaligned/Makefile b/tools/testing/selftests/riscv/misaligned/Makefile new file mode 100644 index 00000000000000..1aa40110c50d29 --- /dev/null +++ b/tools/testing/selftests/riscv/misaligned/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2021 ARM Limited +# Originally tools/testing/arm64/abi/Makefile + +CFLAGS += -I$(top_srcdir)/tools/include + +TEST_GEN_PROGS := misaligned + +include ../../lib.mk + +$(OUTPUT)/misaligned: misaligned.c fpu.S gp.S + $(CC) -g3 -static -o$@ -march=rv64imafdc $(CFLAGS) $(LDFLAGS) $^ diff --git a/tools/testing/selftests/riscv/misaligned/common.S b/tools/testing/selftests/riscv/misaligned/common.S new file mode 100644 index 00000000000000..8fa00035bd5dca --- /dev/null +++ b/tools/testing/selftests/riscv/misaligned/common.S @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2025 Rivos Inc. + * + * Authors: + * Clément Léger + */ + +.macro lb_sb temp, offset, src, dst + lb \temp, \offset(\src) + sb \temp, \offset(\dst) +.endm + +.macro copy_long_to temp, src, dst + lb_sb \temp, 0, \src, \dst, + lb_sb \temp, 1, \src, \dst, + lb_sb \temp, 2, \src, \dst, + lb_sb \temp, 3, \src, \dst, + lb_sb \temp, 4, \src, \dst, + lb_sb \temp, 5, \src, \dst, + lb_sb \temp, 6, \src, \dst, + lb_sb \temp, 7, \src, \dst, +.endm + +.macro sp_stack_prologue offset + addi sp, sp, -8 + sub sp, sp, \offset +.endm + +.macro sp_stack_epilogue offset + add sp, sp, \offset + addi sp, sp, 8 +.endm diff --git a/tools/testing/selftests/riscv/misaligned/fpu.S b/tools/testing/selftests/riscv/misaligned/fpu.S new file mode 100644 index 00000000000000..d008bff58310fa --- /dev/null +++ b/tools/testing/selftests/riscv/misaligned/fpu.S @@ -0,0 +1,180 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2025 Rivos Inc. + * + * Authors: + * Clément Léger + */ + +#include "common.S" + +#define CASE_ALIGN 4 + +.macro fpu_load_inst fpreg, inst, precision, load_reg +.align CASE_ALIGN + \inst \fpreg, 0(\load_reg) + fmv.\precision fa0, \fpreg + j 2f +.endm + +#define flw(__fpreg) fpu_load_inst __fpreg, flw, s, s1 +#define fld(__fpreg) fpu_load_inst __fpreg, fld, d, s1 +#define c_flw(__fpreg) fpu_load_inst __fpreg, c.flw, s, s1 +#define c_fld(__fpreg) fpu_load_inst __fpreg, c.fld, d, s1 +#define c_fldsp(__fpreg) fpu_load_inst __fpreg, c.fldsp, d, sp + +.macro fpu_store_inst fpreg, inst, precision, store_reg +.align CASE_ALIGN + fmv.\precision \fpreg, fa0 + \inst \fpreg, 0(\store_reg) + j 2f +.endm + +#define fsw(__fpreg) fpu_store_inst __fpreg, fsw, s, s1 +#define fsd(__fpreg) fpu_store_inst __fpreg, fsd, d, s1 +#define c_fsw(__fpreg) fpu_store_inst __fpreg, c.fsw, s, s1 +#define c_fsd(__fpreg) fpu_store_inst __fpreg, c.fsd, d, s1 +#define c_fsdsp(__fpreg) fpu_store_inst __fpreg, c.fsdsp, d, sp + +.macro fp_test_prologue + move s1, a1 + /* + * Compute jump offset to store the correct FP register since we don't + * have indirect FP register access (or at least we don't use this + * extension so that works on all archs) + */ + sll t0, a0, CASE_ALIGN + la t2, 1f + add t0, t0, t2 + jr t0 +.align CASE_ALIGN +1: +.endm + +.macro fp_test_prologue_compressed + /* FP registers for compressed instructions starts from 8 to 16 */ + addi a0, a0, -8 + fp_test_prologue +.endm + +#define fp_test_body_compressed(__inst_func) \ + __inst_func(f8); \ + __inst_func(f9); \ + __inst_func(f10); \ + __inst_func(f11); \ + __inst_func(f12); \ + __inst_func(f13); \ + __inst_func(f14); \ + __inst_func(f15); \ +2: + +#define fp_test_body(__inst_func) \ + __inst_func(f0); \ + __inst_func(f1); \ + __inst_func(f2); \ + __inst_func(f3); \ + __inst_func(f4); \ + __inst_func(f5); \ + __inst_func(f6); \ + __inst_func(f7); \ + __inst_func(f8); \ + __inst_func(f9); \ + __inst_func(f10); \ + __inst_func(f11); \ + __inst_func(f12); \ + __inst_func(f13); \ + __inst_func(f14); \ + __inst_func(f15); \ + __inst_func(f16); \ + __inst_func(f17); \ + __inst_func(f18); \ + __inst_func(f19); \ + __inst_func(f20); \ + __inst_func(f21); \ + __inst_func(f22); \ + __inst_func(f23); \ + __inst_func(f24); \ + __inst_func(f25); \ + __inst_func(f26); \ + __inst_func(f27); \ + __inst_func(f28); \ + __inst_func(f29); \ + __inst_func(f30); \ + __inst_func(f31); \ +2: +.text + +#define __gen_test_inst(__inst, __suffix) \ +.global test_ ## __inst; \ +test_ ## __inst:; \ + fp_test_prologue ## __suffix; \ + fp_test_body ## __suffix(__inst); \ + ret + +#define gen_test_inst_compressed(__inst) \ + .option arch,+c; \ + __gen_test_inst(c_ ## __inst, _compressed) + +#define gen_test_inst(__inst) \ + .balign 16; \ + .option push; \ + .option arch,-c; \ + __gen_test_inst(__inst, ); \ + .option pop + +.macro fp_test_prologue_load_compressed_sp + copy_long_to t0, a1, sp +.endm + +.macro fp_test_epilogue_load_compressed_sp +.endm + +.macro fp_test_prologue_store_compressed_sp +.endm + +.macro fp_test_epilogue_store_compressed_sp + copy_long_to t0, sp, a1 +.endm + +#define gen_inst_compressed_sp(__inst, __type) \ + .global test_c_ ## __inst ## sp; \ + test_c_ ## __inst ## sp:; \ + sp_stack_prologue a2; \ + fp_test_prologue_## __type ## _compressed_sp; \ + fp_test_prologue_compressed; \ + fp_test_body_compressed(c_ ## __inst ## sp); \ + fp_test_epilogue_## __type ## _compressed_sp; \ + sp_stack_epilogue a2; \ + ret + +#define gen_test_load_compressed_sp(__inst) gen_inst_compressed_sp(__inst, load) +#define gen_test_store_compressed_sp(__inst) gen_inst_compressed_sp(__inst, store) + +/* + * float_fsw_reg - Set a FP register from a register containing the value + * a0 = FP register index to be set + * a1 = addr where to store register value + * a2 = address offset + * a3 = value to be store + */ +gen_test_inst(fsw) + +/* + * float_flw_reg - Get a FP register value and return it + * a0 = FP register index to be retrieved + * a1 = addr to load register from + * a2 = address offset + */ +gen_test_inst(flw) + +gen_test_inst(fsd) +#ifdef __riscv_compressed +gen_test_inst_compressed(fsd) +gen_test_store_compressed_sp(fsd) +#endif + +gen_test_inst(fld) +#ifdef __riscv_compressed +gen_test_inst_compressed(fld) +gen_test_load_compressed_sp(fld) +#endif diff --git a/tools/testing/selftests/riscv/misaligned/gp.S b/tools/testing/selftests/riscv/misaligned/gp.S new file mode 100644 index 00000000000000..e2456a2c1f89ff --- /dev/null +++ b/tools/testing/selftests/riscv/misaligned/gp.S @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2025 Rivos Inc. + * + * Authors: + * Clément Léger + */ + +#include "common.S" + +.text + +.macro __gen_test_inst inst, src_reg + \inst a2, 0(\src_reg) + move a0, a2 +.endm + +.macro gen_func_header func_name, rvc + .option arch,\rvc + .global test_\func_name + test_\func_name: +.endm + +.macro gen_test_inst inst + .option push + gen_func_header \inst, -c + __gen_test_inst \inst, a0 + .option pop + ret +.endm + +.macro __gen_test_inst_c name, src_reg + .option push + gen_func_header c_\name, +c + __gen_test_inst c.\name, \src_reg + .option pop + ret +.endm + +.macro gen_test_inst_c name + __gen_test_inst_c \name, a0 +.endm + + +.macro gen_test_inst_load_c_sp name + .option push + gen_func_header c_\name\()sp, +c + sp_stack_prologue a1 + copy_long_to t0, a0, sp + c.ldsp a0, 0(sp) + sp_stack_epilogue a1 + .option pop + ret +.endm + +.macro lb_sp_sb_a0 reg, offset + lb_sb \reg, \offset, sp, a0 +.endm + +.macro gen_test_inst_store_c_sp inst_name + .option push + gen_func_header c_\inst_name\()sp, +c + /* Misalign stack pointer */ + sp_stack_prologue a1 + /* Misalign access */ + c.sdsp a2, 0(sp) + copy_long_to t0, sp, a0 + sp_stack_epilogue a1 + .option pop + ret +.endm + + + /* + * a0 = addr to load from + * a1 = address offset + * a2 = value to be loaded + */ +gen_test_inst lh +gen_test_inst lhu +gen_test_inst lw +gen_test_inst lwu +gen_test_inst ld +#ifdef __riscv_compressed +gen_test_inst_c lw +gen_test_inst_c ld +gen_test_inst_load_c_sp ld +#endif + +/* + * a0 = addr where to store value + * a1 = address offset + * a2 = value to be stored + */ +gen_test_inst sh +gen_test_inst sw +gen_test_inst sd +#ifdef __riscv_compressed +gen_test_inst_c sw +gen_test_inst_c sd +gen_test_inst_store_c_sp sd +#endif diff --git a/tools/testing/selftests/riscv/misaligned/misaligned.c b/tools/testing/selftests/riscv/misaligned/misaligned.c new file mode 100644 index 00000000000000..c66aa87ec03ec9 --- /dev/null +++ b/tools/testing/selftests/riscv/misaligned/misaligned.c @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2025 Rivos Inc. + * + * Authors: + * Clément Léger + */ +#include +#include +#include +#include +#include "../../kselftest_harness.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define stringify(s) __stringify(s) +#define __stringify(s) #s + +#define VAL16 0x1234 +#define VAL32 0xDEADBEEF +#define VAL64 0x45674321D00DF789 + +#define VAL_float 78951.234375 +#define VAL_double 567890.512396965789589290 + +static bool float_equal(float a, float b) +{ + float scaled_epsilon; + float difference = fabsf(a - b); + + // Scale to the largest value. + a = fabsf(a); + b = fabsf(b); + if (a > b) + scaled_epsilon = FLT_EPSILON * a; + else + scaled_epsilon = FLT_EPSILON * b; + + return difference <= scaled_epsilon; +} + +static bool double_equal(double a, double b) +{ + double scaled_epsilon; + double difference = fabsf(a - b); + + // Scale to the largest value. + a = fabs(a); + b = fabs(b); + if (a > b) + scaled_epsilon = DBL_EPSILON * a; + else + scaled_epsilon = DBL_EPSILON * b; + + return difference <= scaled_epsilon; +} + +#define fpu_load_proto(__inst, __type) \ +extern __type test_ ## __inst(unsigned long fp_reg, void *addr, unsigned long offset, __type value) + +fpu_load_proto(flw, float); +fpu_load_proto(fld, double); +fpu_load_proto(c_flw, float); +fpu_load_proto(c_fld, double); +fpu_load_proto(c_fldsp, double); + +#define fpu_store_proto(__inst, __type) \ +extern void test_ ## __inst(unsigned long fp_reg, void *addr, unsigned long offset, __type value) + +fpu_store_proto(fsw, float); +fpu_store_proto(fsd, double); +fpu_store_proto(c_fsw, float); +fpu_store_proto(c_fsd, double); +fpu_store_proto(c_fsdsp, double); + +#define gp_load_proto(__inst, __type) \ +extern __type test_ ## __inst(void *addr, unsigned long offset, __type value) + +gp_load_proto(lh, uint16_t); +gp_load_proto(lhu, uint16_t); +gp_load_proto(lw, uint32_t); +gp_load_proto(lwu, uint32_t); +gp_load_proto(ld, uint64_t); +gp_load_proto(c_lw, uint32_t); +gp_load_proto(c_ld, uint64_t); +gp_load_proto(c_ldsp, uint64_t); + +#define gp_store_proto(__inst, __type) \ +extern void test_ ## __inst(void *addr, unsigned long offset, __type value) + +gp_store_proto(sh, uint16_t); +gp_store_proto(sw, uint32_t); +gp_store_proto(sd, uint64_t); +gp_store_proto(c_sw, uint32_t); +gp_store_proto(c_sd, uint64_t); +gp_store_proto(c_sdsp, uint64_t); + +#define TEST_GP_LOAD(__inst, __type_size) \ +TEST(gp_load_ ## __inst) \ +{ \ + int offset, ret; \ + uint8_t buf[16] __attribute__((aligned(16))); \ + \ + ret = prctl(PR_SET_UNALIGN, PR_UNALIGN_NOPRINT); \ + ASSERT_EQ(ret, 0); \ + \ + for (offset = 1; offset < __type_size / 8; offset++) { \ + uint ## __type_size ## _t val = VAL ## __type_size; \ + uint ## __type_size ## _t *ptr = (uint ## __type_size ## _t *) (buf + offset); \ + memcpy(ptr, &val, sizeof(val)); \ + val = test_ ## __inst(ptr, offset, val); \ + EXPECT_EQ(VAL ## __type_size, val); \ + } \ +} + +TEST_GP_LOAD(lh, 16); +TEST_GP_LOAD(lhu, 16); +TEST_GP_LOAD(lw, 32); +TEST_GP_LOAD(lwu, 32); +TEST_GP_LOAD(ld, 64); +#ifdef __riscv_compressed +TEST_GP_LOAD(c_lw, 32); +TEST_GP_LOAD(c_ld, 64); +TEST_GP_LOAD(c_ldsp, 64); +#endif + +#define TEST_GP_STORE(__inst, __type_size) \ +TEST(gp_load_ ## __inst) \ +{ \ + int offset, ret; \ + uint8_t buf[16] __attribute__((aligned(16))); \ + \ + ret = prctl(PR_SET_UNALIGN, PR_UNALIGN_NOPRINT); \ + ASSERT_EQ(ret, 0); \ + \ + for (offset = 1; offset < __type_size / 8; offset++) { \ + uint ## __type_size ## _t val = VAL ## __type_size; \ + uint ## __type_size ## _t *ptr = (uint ## __type_size ## _t *) (buf + offset); \ + memset(ptr, 0, sizeof(val)); \ + test_ ## __inst(ptr, offset, val); \ + memcpy(&val, ptr, sizeof(val)); \ + EXPECT_EQ(VAL ## __type_size, val); \ + } \ +} +TEST_GP_STORE(sh, 16); +TEST_GP_STORE(sw, 32); +TEST_GP_STORE(sd, 64); +#ifdef __riscv_compressed +TEST_GP_STORE(c_sw, 32); +TEST_GP_STORE(c_sd, 64); +TEST_GP_STORE(c_sdsp, 64); +#endif + +#define __TEST_FPU_LOAD(__type, __inst, __reg_start, __reg_end) \ +TEST(fpu_load_ ## __inst) \ +{ \ + int i, ret, offset, fp_reg; \ + uint8_t buf[16] __attribute__((aligned(16))); \ + \ + ret = prctl(PR_SET_UNALIGN, PR_UNALIGN_NOPRINT); \ + ASSERT_EQ(ret, 0); \ + \ + for (fp_reg = __reg_start; fp_reg < __reg_end; fp_reg++) { \ + for (offset = 1; offset < 4; offset++) { \ + void *load_addr = (buf + offset); \ + __type val = VAL_ ## __type ; \ + \ + memcpy(load_addr, &val, sizeof(val)); \ + val = test_ ## __inst(fp_reg, load_addr, offset, val); \ + EXPECT_TRUE(__type ##_equal(val, VAL_## __type)); \ + } \ + } \ +} +#define TEST_FPU_LOAD(__type, __inst) \ + __TEST_FPU_LOAD(__type, __inst, 0, 32) +#define TEST_FPU_LOAD_COMPRESSED(__type, __inst) \ + __TEST_FPU_LOAD(__type, __inst, 8, 16) + +TEST_FPU_LOAD(float, flw) +TEST_FPU_LOAD(double, fld) +#ifdef __riscv_compressed +TEST_FPU_LOAD_COMPRESSED(double, c_fld) +TEST_FPU_LOAD_COMPRESSED(double, c_fldsp) +#endif + +#define __TEST_FPU_STORE(__type, __inst, __reg_start, __reg_end) \ +TEST(fpu_store_ ## __inst) \ +{ \ + int i, ret, offset, fp_reg; \ + uint8_t buf[16] __attribute__((aligned(16))); \ + \ + ret = prctl(PR_SET_UNALIGN, PR_UNALIGN_NOPRINT); \ + ASSERT_EQ(ret, 0); \ + \ + for (fp_reg = __reg_start; fp_reg < __reg_end; fp_reg++) { \ + for (offset = 1; offset < 4; offset++) { \ + \ + void *store_addr = (buf + offset); \ + __type val = VAL_ ## __type ; \ + \ + test_ ## __inst(fp_reg, store_addr, offset, val); \ + memcpy(&val, store_addr, sizeof(val)); \ + EXPECT_TRUE(__type ## _equal(val, VAL_## __type)); \ + } \ + } \ +} +#define TEST_FPU_STORE(__type, __inst) \ + __TEST_FPU_STORE(__type, __inst, 0, 32) +#define TEST_FPU_STORE_COMPRESSED(__type, __inst) \ + __TEST_FPU_STORE(__type, __inst, 8, 16) + +TEST_FPU_STORE(float, fsw) +TEST_FPU_STORE(double, fsd) +#ifdef __riscv_compressed +TEST_FPU_STORE_COMPRESSED(double, c_fsd) +TEST_FPU_STORE_COMPRESSED(double, c_fsdsp) +#endif + +TEST_SIGNAL(gen_sigbus, SIGBUS) +{ + uint32_t *ptr; + uint8_t buf[16] __attribute__((aligned(16))); + int ret; + + ret = prctl(PR_SET_UNALIGN, PR_UNALIGN_SIGBUS); + ASSERT_EQ(ret, 0); + + ptr = (uint32_t *)(buf + 1); + *ptr = 0xDEADBEEFULL; +} + +int main(int argc, char **argv) +{ + int ret, val; + + ret = prctl(PR_GET_UNALIGN, &val); + if (ret == -1 && errno == EINVAL) + ksft_exit_skip("SKIP GET_UNALIGN_CTL not supported\n"); + + exit(test_harness_run(argc, argv)); +} From eff517783b48821b60d155b538c2d26f37569167 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= Date: Thu, 24 Apr 2025 19:31:48 +0200 Subject: [PATCH 41/91] riscv: sbi: add Firmware Feature (FWFT) SBI extensions definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Firmware Features extension (FWFT) was added as part of the SBI 3.0 specification. Add SBI definitions to use this extension. Signed-off-by: Clément Léger Reviewed-by: Samuel Holland Tested-by: Samuel Holland Reviewed-by: Deepak Gupta Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/20250424173204.1948385-2-cleger@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/sbi.h | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index 3d250824178bd5..bb077d0c912fb5 100644 --- a/arch/riscv/include/asm/sbi.h +++ b/arch/riscv/include/asm/sbi.h @@ -35,6 +35,7 @@ enum sbi_ext_id { SBI_EXT_DBCN = 0x4442434E, SBI_EXT_STA = 0x535441, SBI_EXT_NACL = 0x4E41434C, + SBI_EXT_FWFT = 0x46574654, /* Experimentals extensions must lie within this range */ SBI_EXT_EXPERIMENTAL_START = 0x08000000, @@ -402,6 +403,33 @@ enum sbi_ext_nacl_feature { #define SBI_NACL_SHMEM_SRET_X(__i) ((__riscv_xlen / 8) * (__i)) #define SBI_NACL_SHMEM_SRET_X_LAST 31 +/* SBI function IDs for FW feature extension */ +#define SBI_EXT_FWFT_SET 0x0 +#define SBI_EXT_FWFT_GET 0x1 + +enum sbi_fwft_feature_t { + SBI_FWFT_MISALIGNED_EXC_DELEG = 0x0, + SBI_FWFT_LANDING_PAD = 0x1, + SBI_FWFT_SHADOW_STACK = 0x2, + SBI_FWFT_DOUBLE_TRAP = 0x3, + SBI_FWFT_PTE_AD_HW_UPDATING = 0x4, + SBI_FWFT_POINTER_MASKING_PMLEN = 0x5, + SBI_FWFT_LOCAL_RESERVED_START = 0x6, + SBI_FWFT_LOCAL_RESERVED_END = 0x3fffffff, + SBI_FWFT_LOCAL_PLATFORM_START = 0x40000000, + SBI_FWFT_LOCAL_PLATFORM_END = 0x7fffffff, + + SBI_FWFT_GLOBAL_RESERVED_START = 0x80000000, + SBI_FWFT_GLOBAL_RESERVED_END = 0xbfffffff, + SBI_FWFT_GLOBAL_PLATFORM_START = 0xc0000000, + SBI_FWFT_GLOBAL_PLATFORM_END = 0xffffffff, +}; + +#define SBI_FWFT_PLATFORM_FEATURE_BIT BIT(30) +#define SBI_FWFT_GLOBAL_FEATURE_BIT BIT(31) + +#define SBI_FWFT_SET_FLAG_LOCK BIT(0) + /* SBI spec version fields */ #define SBI_SPEC_VERSION_DEFAULT 0x1 #define SBI_SPEC_VERSION_MAJOR_SHIFT 24 @@ -419,6 +447,11 @@ enum sbi_ext_nacl_feature { #define SBI_ERR_ALREADY_STARTED -7 #define SBI_ERR_ALREADY_STOPPED -8 #define SBI_ERR_NO_SHMEM -9 +#define SBI_ERR_INVALID_STATE -10 +#define SBI_ERR_BAD_RANGE -11 +#define SBI_ERR_TIMEOUT -12 +#define SBI_ERR_IO -13 +#define SBI_ERR_DENIED_LOCKED -14 extern unsigned long sbi_spec_version; struct sbiret { From ef11a9a1434078a791f615157dd9fc4b1abdf1a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= Date: Thu, 24 Apr 2025 19:31:49 +0200 Subject: [PATCH 42/91] riscv: sbi: remove useless parenthesis MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A few parenthesis in check for SBI version/extension were useless, remove them. Signed-off-by: Clément Léger Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/20250424173204.1948385-3-cleger@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/kernel/sbi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/riscv/kernel/sbi.c b/arch/riscv/kernel/sbi.c index 1989b8cade1b98..1d44c35305a96a 100644 --- a/arch/riscv/kernel/sbi.c +++ b/arch/riscv/kernel/sbi.c @@ -609,7 +609,7 @@ void __init sbi_init(void) } else { __sbi_rfence = __sbi_rfence_v01; } - if ((sbi_spec_version >= sbi_mk_version(0, 3)) && + if (sbi_spec_version >= sbi_mk_version(0, 3) && sbi_probe_extension(SBI_EXT_SRST)) { pr_info("SBI SRST extension detected\n"); pm_power_off = sbi_srst_power_off; @@ -617,8 +617,8 @@ void __init sbi_init(void) sbi_srst_reboot_nb.priority = 192; register_restart_handler(&sbi_srst_reboot_nb); } - if ((sbi_spec_version >= sbi_mk_version(2, 0)) && - (sbi_probe_extension(SBI_EXT_DBCN) > 0)) { + if (sbi_spec_version >= sbi_mk_version(2, 0) && + sbi_probe_extension(SBI_EXT_DBCN) > 0) { pr_info("SBI DBCN extension detected\n"); sbi_debug_console_available = true; } From c8b8d199785ecc7dd9b3df2f2b97d9adc17ac395 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= Date: Thu, 24 Apr 2025 19:31:50 +0200 Subject: [PATCH 43/91] riscv: sbi: add new SBI error mappings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A few new errors have been added with SBI V3.0, maps them as close as possible to errno values. Signed-off-by: Clément Léger Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/20250424173204.1948385-4-cleger@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/sbi.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index bb077d0c912fb5..7ec249fea880f4 100644 --- a/arch/riscv/include/asm/sbi.h +++ b/arch/riscv/include/asm/sbi.h @@ -536,11 +536,21 @@ static inline int sbi_err_map_linux_errno(int err) case SBI_SUCCESS: return 0; case SBI_ERR_DENIED: + case SBI_ERR_DENIED_LOCKED: return -EPERM; case SBI_ERR_INVALID_PARAM: + case SBI_ERR_INVALID_STATE: return -EINVAL; + case SBI_ERR_BAD_RANGE: + return -ERANGE; case SBI_ERR_INVALID_ADDRESS: return -EFAULT; + case SBI_ERR_NO_SHMEM: + return -ENOMEM; + case SBI_ERR_TIMEOUT: + return -ETIME; + case SBI_ERR_IO: + return -EIO; case SBI_ERR_NOT_SUPPORTED: case SBI_ERR_FAILURE: default: From af4384768f3e4771072ad2dc0ab034906404d8d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= Date: Thu, 24 Apr 2025 19:31:51 +0200 Subject: [PATCH 44/91] riscv: sbi: add FWFT extension interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This SBI extensions enables supervisor mode to control feature that are under M-mode control (For instance, Svadu menvcfg ADUE bit, Ssdbltrp DTE, etc). Add an interface to set local features for a specific cpu mask as well as for the online cpu mask. Signed-off-by: Clément Léger Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/20250424173204.1948385-5-cleger@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/sbi.h | 17 +++++++++++ arch/riscv/kernel/sbi.c | 57 ++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index 7ec249fea880f4..3bbef56bcefcc9 100644 --- a/arch/riscv/include/asm/sbi.h +++ b/arch/riscv/include/asm/sbi.h @@ -503,6 +503,23 @@ int sbi_remote_hfence_vvma_asid(const struct cpumask *cpu_mask, unsigned long asid); long sbi_probe_extension(int ext); +int sbi_fwft_set(u32 feature, unsigned long value, unsigned long flags); +int sbi_fwft_set_cpumask(const cpumask_t *mask, u32 feature, + unsigned long value, unsigned long flags); +/** + * sbi_fwft_set_online_cpus() - Set a feature on all online cpus + * @feature: The feature to be set + * @value: The feature value to be set + * @flags: FWFT feature set flags + * + * Return: 0 on success, appropriate linux error code otherwise. + */ +static inline int sbi_fwft_set_online_cpus(u32 feature, unsigned long value, + unsigned long flags) +{ + return sbi_fwft_set_cpumask(cpu_online_mask, feature, value, flags); +} + /* Check if current SBI specification version is 0.1 or not */ static inline int sbi_spec_is_0_1(void) { diff --git a/arch/riscv/kernel/sbi.c b/arch/riscv/kernel/sbi.c index 1d44c35305a96a..d57e4dae7dac19 100644 --- a/arch/riscv/kernel/sbi.c +++ b/arch/riscv/kernel/sbi.c @@ -299,6 +299,63 @@ static int __sbi_rfence_v02(int fid, const struct cpumask *cpu_mask, return 0; } +/** + * sbi_fwft_set() - Set a feature on the local hart + * @feature: The feature ID to be set + * @value: The feature value to be set + * @flags: FWFT feature set flags + * + * Return: 0 on success, appropriate linux error code otherwise. + */ +int sbi_fwft_set(u32 feature, unsigned long value, unsigned long flags) +{ + return -EOPNOTSUPP; +} + +struct fwft_set_req { + u32 feature; + unsigned long value; + unsigned long flags; + atomic_t error; +}; + +static void cpu_sbi_fwft_set(void *arg) +{ + struct fwft_set_req *req = arg; + int ret; + + ret = sbi_fwft_set(req->feature, req->value, req->flags); + if (ret) + atomic_set(&req->error, ret); +} + +/** + * sbi_fwft_set_cpumask() - Set a feature for the specified cpumask + * @mask: CPU mask of cpus that need the feature to be set + * @feature: The feature ID to be set + * @value: The feature value to be set + * @flags: FWFT feature set flags + * + * Return: 0 on success, appropriate linux error code otherwise. + */ +int sbi_fwft_set_cpumask(const cpumask_t *mask, u32 feature, + unsigned long value, unsigned long flags) +{ + struct fwft_set_req req = { + .feature = feature, + .value = value, + .flags = flags, + .error = ATOMIC_INIT(0), + }; + + if (feature & SBI_FWFT_GLOBAL_FEATURE_BIT) + return -EINVAL; + + on_each_cpu_mask(mask, cpu_sbi_fwft_set, &req, 1); + + return atomic_read(&req.error); +} + /** * sbi_set_timer() - Program the timer for next timer event. * @stime_value: The value after which next timer event should fire. From b65362cab5b86d4534b075f821fac0d4faff93ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= Date: Thu, 24 Apr 2025 19:31:52 +0200 Subject: [PATCH 45/91] riscv: sbi: add SBI FWFT extension calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add FWFT extension calls. This will be ratified in SBI V3.0 hence, it is provided as a separate commit that can be left out if needed. Signed-off-by: Clément Léger Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/20250424173204.1948385-6-cleger@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/kernel/sbi.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/arch/riscv/kernel/sbi.c b/arch/riscv/kernel/sbi.c index d57e4dae7dac19..070014ff35d49c 100644 --- a/arch/riscv/kernel/sbi.c +++ b/arch/riscv/kernel/sbi.c @@ -299,6 +299,8 @@ static int __sbi_rfence_v02(int fid, const struct cpumask *cpu_mask, return 0; } +static bool sbi_fwft_supported; + /** * sbi_fwft_set() - Set a feature on the local hart * @feature: The feature ID to be set @@ -309,7 +311,15 @@ static int __sbi_rfence_v02(int fid, const struct cpumask *cpu_mask, */ int sbi_fwft_set(u32 feature, unsigned long value, unsigned long flags) { - return -EOPNOTSUPP; + struct sbiret ret; + + if (!sbi_fwft_supported) + return -EOPNOTSUPP; + + ret = sbi_ecall(SBI_EXT_FWFT, SBI_EXT_FWFT_SET, + feature, value, flags, 0, 0, 0); + + return sbi_err_map_linux_errno(ret.error); } struct fwft_set_req { @@ -348,6 +358,9 @@ int sbi_fwft_set_cpumask(const cpumask_t *mask, u32 feature, .error = ATOMIC_INIT(0), }; + if (!sbi_fwft_supported) + return -EOPNOTSUPP; + if (feature & SBI_FWFT_GLOBAL_FEATURE_BIT) return -EINVAL; @@ -679,6 +692,11 @@ void __init sbi_init(void) pr_info("SBI DBCN extension detected\n"); sbi_debug_console_available = true; } + if (sbi_spec_version >= sbi_mk_version(3, 0) && + sbi_probe_extension(SBI_EXT_FWFT)) { + pr_info("SBI FWFT extension detected\n"); + sbi_fwft_supported = true; + } } else { __sbi_set_timer = __sbi_set_timer_v01; __sbi_send_ipi = __sbi_send_ipi_v01; From 8d27ed16935fdf3d3ffc4ce6228fba12815b9f62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= Date: Thu, 24 Apr 2025 19:31:53 +0200 Subject: [PATCH 46/91] riscv: misaligned: request misaligned exception from SBI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that the kernel can handle misaligned accesses in S-mode, request misaligned access exception delegation from SBI. This uses the FWFT SBI extension defined in SBI version 3.0. Signed-off-by: Clément Léger Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/20250424173204.1948385-7-cleger@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/cpufeature.h | 3 +- arch/riscv/kernel/traps_misaligned.c | 71 +++++++++++++++++++++- arch/riscv/kernel/unaligned_access_speed.c | 8 ++- 3 files changed, 77 insertions(+), 5 deletions(-) diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h index f56b409361fbe0..dbe5970d4fe6aa 100644 --- a/arch/riscv/include/asm/cpufeature.h +++ b/arch/riscv/include/asm/cpufeature.h @@ -67,8 +67,9 @@ void __init riscv_user_isa_enable(void); _RISCV_ISA_EXT_DATA(_name, _id, _sub_exts, ARRAY_SIZE(_sub_exts), _validate) bool __init check_unaligned_access_emulated_all_cpus(void); +void unaligned_access_init(void); +int cpu_online_unaligned_access_init(unsigned int cpu); #if defined(CONFIG_RISCV_SCALAR_MISALIGNED) -void check_unaligned_access_emulated(struct work_struct *work __always_unused); void unaligned_emulation_finish(void); bool unaligned_ctl_available(void); DECLARE_PER_CPU(long, misaligned_access_speed); diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c index 4354c87c0376fd..fb51cfcf43522d 100644 --- a/arch/riscv/kernel/traps_misaligned.c +++ b/arch/riscv/kernel/traps_misaligned.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #define INSN_MATCH_LB 0x3 @@ -629,7 +630,7 @@ bool __init check_vector_unaligned_access_emulated_all_cpus(void) static bool unaligned_ctl __read_mostly; -void check_unaligned_access_emulated(struct work_struct *work __always_unused) +static void check_unaligned_access_emulated(struct work_struct *work __always_unused) { int cpu = smp_processor_id(); long *mas_ptr = per_cpu_ptr(&misaligned_access_speed, cpu); @@ -640,6 +641,13 @@ void check_unaligned_access_emulated(struct work_struct *work __always_unused) __asm__ __volatile__ ( " "REG_L" %[tmp], 1(%[ptr])\n" : [tmp] "=r" (tmp_val) : [ptr] "r" (&tmp_var) : "memory"); +} + +static int cpu_online_check_unaligned_access_emulated(unsigned int cpu) +{ + long *mas_ptr = per_cpu_ptr(&misaligned_access_speed, cpu); + + check_unaligned_access_emulated(NULL); /* * If unaligned_ctl is already set, this means that we detected that all @@ -648,9 +656,10 @@ void check_unaligned_access_emulated(struct work_struct *work __always_unused) */ if (unlikely(unaligned_ctl && (*mas_ptr != RISCV_HWPROBE_MISALIGNED_SCALAR_EMULATED))) { pr_crit("CPU misaligned accesses non homogeneous (expected all emulated)\n"); - while (true) - cpu_relax(); + return -EINVAL; } + + return 0; } bool __init check_unaligned_access_emulated_all_cpus(void) @@ -682,4 +691,60 @@ bool __init check_unaligned_access_emulated_all_cpus(void) { return false; } +static int cpu_online_check_unaligned_access_emulated(unsigned int cpu) +{ + return 0; +} +#endif + +#ifdef CONFIG_RISCV_SBI + +static bool misaligned_traps_delegated; + +static int cpu_online_sbi_unaligned_setup(unsigned int cpu) +{ + if (sbi_fwft_set(SBI_FWFT_MISALIGNED_EXC_DELEG, 1, 0) && + misaligned_traps_delegated) { + pr_crit("Misaligned trap delegation non homogeneous (expected delegated)"); + return -EINVAL; + } + + return 0; +} + +void __init unaligned_access_init(void) +{ + int ret; + + ret = sbi_fwft_set_online_cpus(SBI_FWFT_MISALIGNED_EXC_DELEG, 1, 0); + if (ret) + return; + + misaligned_traps_delegated = true; + pr_info("SBI misaligned access exception delegation ok\n"); + /* + * Note that we don't have to take any specific action here, if + * the delegation is successful, then + * check_unaligned_access_emulated() will verify that indeed the + * platform traps on misaligned accesses. + */ +} +#else +void __init unaligned_access_init(void) {} + +static int cpu_online_sbi_unaligned_setup(unsigned int cpu __always_unused) +{ + return 0; +} #endif + +int cpu_online_unaligned_access_init(unsigned int cpu) +{ + int ret; + + ret = cpu_online_sbi_unaligned_setup(cpu); + if (ret) + return ret; + + return cpu_online_check_unaligned_access_emulated(cpu); +} diff --git a/arch/riscv/kernel/unaligned_access_speed.c b/arch/riscv/kernel/unaligned_access_speed.c index b8ba13819d05e5..ae2068425fbcd2 100644 --- a/arch/riscv/kernel/unaligned_access_speed.c +++ b/arch/riscv/kernel/unaligned_access_speed.c @@ -236,6 +236,11 @@ arch_initcall_sync(lock_and_set_unaligned_access_static_branch); static int riscv_online_cpu(unsigned int cpu) { + int ret = cpu_online_unaligned_access_init(cpu); + + if (ret) + return ret; + /* We are already set since the last check */ if (per_cpu(misaligned_access_speed, cpu) != RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN) { goto exit; @@ -248,7 +253,6 @@ static int riscv_online_cpu(unsigned int cpu) { static struct page *buf; - check_unaligned_access_emulated(NULL); buf = alloc_pages(GFP_KERNEL, MISALIGNED_BUFFER_ORDER); if (!buf) { pr_warn("Allocation failure, not measuring misaligned performance\n"); @@ -439,6 +443,8 @@ static int __init check_unaligned_access_all_cpus(void) { int cpu; + unaligned_access_init(); + if (unaligned_scalar_speed_param != RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN) { pr_info("scalar unaligned access speed set to '%s' (%lu) by command line\n", speed_str[unaligned_scalar_speed_param], unaligned_scalar_speed_param); From f11ec5da61ffda4d0a1245066f01d035aea95647 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= Date: Thu, 24 Apr 2025 19:31:54 +0200 Subject: [PATCH 47/91] riscv: misaligned: use on_each_cpu() for scalar misaligned access probing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit schedule_on_each_cpu() was used without any good reason while documented as very slow. This call was in the boot path, so better use on_each_cpu() for scalar misaligned checking. Vector misaligned check still needs to use schedule_on_each_cpu() since it requires irqs to be enabled but that's less of a problem since this code is ran in a kthread. Add a comment to explicit that. Signed-off-by: Clément Léger Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/20250424173204.1948385-8-cleger@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/kernel/traps_misaligned.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c index fb51cfcf43522d..51e0c998ae9ff3 100644 --- a/arch/riscv/kernel/traps_misaligned.c +++ b/arch/riscv/kernel/traps_misaligned.c @@ -610,6 +610,10 @@ bool __init check_vector_unaligned_access_emulated_all_cpus(void) { int cpu; + /* + * While being documented as very slow, schedule_on_each_cpu() is used since + * kernel_vector_begin() expects irqs to be enabled or it will panic() + */ schedule_on_each_cpu(check_vector_unaligned_access_emulated); for_each_online_cpu(cpu) @@ -630,7 +634,7 @@ bool __init check_vector_unaligned_access_emulated_all_cpus(void) static bool unaligned_ctl __read_mostly; -static void check_unaligned_access_emulated(struct work_struct *work __always_unused) +static void check_unaligned_access_emulated(void *arg __always_unused) { int cpu = smp_processor_id(); long *mas_ptr = per_cpu_ptr(&misaligned_access_speed, cpu); @@ -671,7 +675,7 @@ bool __init check_unaligned_access_emulated_all_cpus(void) * accesses emulated since tasks requesting such control can run on any * CPU. */ - schedule_on_each_cpu(check_unaligned_access_emulated); + on_each_cpu(check_unaligned_access_emulated, NULL, 1); for_each_online_cpu(cpu) if (per_cpu(misaligned_access_speed, cpu) From fc241d0558e66ceb7133b3dfec816f7242080bde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= Date: Thu, 24 Apr 2025 19:31:55 +0200 Subject: [PATCH 48/91] riscv: misaligned: use correct CONFIG_ ifdef for misaligned_access_speed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit misaligned_access_speed is defined under CONFIG_RISCV_SCALAR_MISALIGNED but was used under CONFIG_RISCV_PROBE_UNALIGNED_ACCESS. Fix that by using the correct config option. Signed-off-by: Clément Léger Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/20250424173204.1948385-9-cleger@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/kernel/traps_misaligned.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c index 51e0c998ae9ff3..ffa81bf7418bb7 100644 --- a/arch/riscv/kernel/traps_misaligned.c +++ b/arch/riscv/kernel/traps_misaligned.c @@ -362,7 +362,7 @@ static int handle_scalar_misaligned_load(struct pt_regs *regs) perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, addr); -#ifdef CONFIG_RISCV_PROBE_UNALIGNED_ACCESS +#ifdef CONFIG_RISCV_SCALAR_MISALIGNED *this_cpu_ptr(&misaligned_access_speed) = RISCV_HWPROBE_MISALIGNED_SCALAR_EMULATED; #endif From 0046a37a37732c39a5d0a6daaad686490a61ada1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= Date: Thu, 24 Apr 2025 19:31:56 +0200 Subject: [PATCH 49/91] riscv: misaligned: move emulated access uniformity check in a function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split the code that check for the uniformity of misaligned accesses performance on all cpus from check_unaligned_access_emulated_all_cpus() to its own function which will be used for delegation check. No functional changes intended. Signed-off-by: Clément Léger Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/20250424173204.1948385-10-cleger@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/kernel/traps_misaligned.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c index ffa81bf7418bb7..f28de91e424e8d 100644 --- a/arch/riscv/kernel/traps_misaligned.c +++ b/arch/riscv/kernel/traps_misaligned.c @@ -666,10 +666,20 @@ static int cpu_online_check_unaligned_access_emulated(unsigned int cpu) return 0; } -bool __init check_unaligned_access_emulated_all_cpus(void) +static bool all_cpus_unaligned_scalar_access_emulated(void) { int cpu; + for_each_online_cpu(cpu) + if (per_cpu(misaligned_access_speed, cpu) != + RISCV_HWPROBE_MISALIGNED_SCALAR_EMULATED) + return false; + + return true; +} + +bool __init check_unaligned_access_emulated_all_cpus(void) +{ /* * We can only support PR_UNALIGN controls if all CPUs have misaligned * accesses emulated since tasks requesting such control can run on any @@ -677,10 +687,8 @@ bool __init check_unaligned_access_emulated_all_cpus(void) */ on_each_cpu(check_unaligned_access_emulated, NULL, 1); - for_each_online_cpu(cpu) - if (per_cpu(misaligned_access_speed, cpu) - != RISCV_HWPROBE_MISALIGNED_SCALAR_EMULATED) - return false; + if (!all_cpus_unaligned_scalar_access_emulated()) + return false; unaligned_ctl = true; return true; From 66a77b1083fdc908ccb8d49435287fbed1178153 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= Date: Thu, 24 Apr 2025 19:31:57 +0200 Subject: [PATCH 50/91] riscv: misaligned: add a function to check misalign trap delegability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Checking for the delegability of the misaligned access trap is needed for the KVM FWFT extension implementation. Add a function to get the delegability of the misaligned trap exception. Signed-off-by: Clément Léger Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/20250424173204.1948385-11-cleger@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/cpufeature.h | 5 +++++ arch/riscv/kernel/traps_misaligned.c | 17 +++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h index dbe5970d4fe6aa..3a87f612035ca9 100644 --- a/arch/riscv/include/asm/cpufeature.h +++ b/arch/riscv/include/asm/cpufeature.h @@ -72,12 +72,17 @@ int cpu_online_unaligned_access_init(unsigned int cpu); #if defined(CONFIG_RISCV_SCALAR_MISALIGNED) void unaligned_emulation_finish(void); bool unaligned_ctl_available(void); +bool misaligned_traps_can_delegate(void); DECLARE_PER_CPU(long, misaligned_access_speed); #else static inline bool unaligned_ctl_available(void) { return false; } +static inline bool misaligned_traps_can_delegate(void) +{ + return false; +} #endif bool __init check_vector_unaligned_access_emulated_all_cpus(void); diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c index f28de91e424e8d..1f4525b08c2237 100644 --- a/arch/riscv/kernel/traps_misaligned.c +++ b/arch/riscv/kernel/traps_misaligned.c @@ -709,10 +709,10 @@ static int cpu_online_check_unaligned_access_emulated(unsigned int cpu) } #endif -#ifdef CONFIG_RISCV_SBI - static bool misaligned_traps_delegated; +#ifdef CONFIG_RISCV_SBI + static int cpu_online_sbi_unaligned_setup(unsigned int cpu) { if (sbi_fwft_set(SBI_FWFT_MISALIGNED_EXC_DELEG, 1, 0) && @@ -748,6 +748,7 @@ static int cpu_online_sbi_unaligned_setup(unsigned int cpu __always_unused) { return 0; } + #endif int cpu_online_unaligned_access_init(unsigned int cpu) @@ -760,3 +761,15 @@ int cpu_online_unaligned_access_init(unsigned int cpu) return cpu_online_check_unaligned_access_emulated(cpu); } + +bool misaligned_traps_can_delegate(void) +{ + /* + * Either we successfully requested misaligned traps delegation for all + * CPUS or the SBI does not implemented FWFT extension but delegated the + * exception by default. + */ + return misaligned_traps_delegated || + all_cpus_unaligned_scalar_access_emulated(); +} +EXPORT_SYMBOL_GPL(misaligned_traps_can_delegate); From 1ff07ab841f261a20b7a2fe4c9266817ae807e04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= Date: Thu, 24 Apr 2025 19:31:58 +0200 Subject: [PATCH 51/91] RISC-V: KVM: add SBI extension init()/deinit() functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The FWFT SBI extension will need to dynamically allocate memory and do init time specific initialization. Add an init/deinit callbacks that allows to do so. Signed-off-by: Clément Léger Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/20250424173204.1948385-12-cleger@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/kvm_vcpu_sbi.h | 9 +++++++++ arch/riscv/kvm/vcpu.c | 2 ++ arch/riscv/kvm/vcpu_sbi.c | 26 ++++++++++++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/arch/riscv/include/asm/kvm_vcpu_sbi.h b/arch/riscv/include/asm/kvm_vcpu_sbi.h index 4ed6203cdd3079..bcb90757b1495a 100644 --- a/arch/riscv/include/asm/kvm_vcpu_sbi.h +++ b/arch/riscv/include/asm/kvm_vcpu_sbi.h @@ -49,6 +49,14 @@ struct kvm_vcpu_sbi_extension { /* Extension specific probe function */ unsigned long (*probe)(struct kvm_vcpu *vcpu); + + /* + * Init/deinit function called once during VCPU init/destroy. These + * might be use if the SBI extensions need to allocate or do specific + * init time only configuration. + */ + int (*init)(struct kvm_vcpu *vcpu); + void (*deinit)(struct kvm_vcpu *vcpu); }; void kvm_riscv_vcpu_sbi_forward(struct kvm_vcpu *vcpu, struct kvm_run *run); @@ -69,6 +77,7 @@ const struct kvm_vcpu_sbi_extension *kvm_vcpu_sbi_find_ext( bool riscv_vcpu_supports_sbi_ext(struct kvm_vcpu *vcpu, int idx); int kvm_riscv_vcpu_sbi_ecall(struct kvm_vcpu *vcpu, struct kvm_run *run); void kvm_riscv_vcpu_sbi_init(struct kvm_vcpu *vcpu); +void kvm_riscv_vcpu_sbi_deinit(struct kvm_vcpu *vcpu); int kvm_riscv_vcpu_get_reg_sbi_sta(struct kvm_vcpu *vcpu, unsigned long reg_num, unsigned long *reg_val); diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c index 60d684c76c5873..877bcc85c06709 100644 --- a/arch/riscv/kvm/vcpu.c +++ b/arch/riscv/kvm/vcpu.c @@ -185,6 +185,8 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) { + kvm_riscv_vcpu_sbi_deinit(vcpu); + /* Cleanup VCPU AIA context */ kvm_riscv_vcpu_aia_deinit(vcpu); diff --git a/arch/riscv/kvm/vcpu_sbi.c b/arch/riscv/kvm/vcpu_sbi.c index d1c83a77735e05..3139f171c20fcd 100644 --- a/arch/riscv/kvm/vcpu_sbi.c +++ b/arch/riscv/kvm/vcpu_sbi.c @@ -508,5 +508,31 @@ void kvm_riscv_vcpu_sbi_init(struct kvm_vcpu *vcpu) scontext->ext_status[idx] = ext->default_disabled ? KVM_RISCV_SBI_EXT_STATUS_DISABLED : KVM_RISCV_SBI_EXT_STATUS_ENABLED; + + if (ext->init && ext->init(vcpu) != 0) + scontext->ext_status[idx] = KVM_RISCV_SBI_EXT_STATUS_UNAVAILABLE; + } +} + +void kvm_riscv_vcpu_sbi_deinit(struct kvm_vcpu *vcpu) +{ + struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context; + const struct kvm_riscv_sbi_extension_entry *entry; + const struct kvm_vcpu_sbi_extension *ext; + int idx, i; + + for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) { + entry = &sbi_ext[i]; + ext = entry->ext_ptr; + idx = entry->ext_idx; + + if (idx < 0 || idx >= ARRAY_SIZE(scontext->ext_status)) + continue; + + if (scontext->ext_status[idx] == KVM_RISCV_SBI_EXT_STATUS_UNAVAILABLE || + !ext->deinit) + continue; + + ext->deinit(vcpu); } } From 1bd16c28cb8608953dc412b791c04ae444a69166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= Date: Thu, 24 Apr 2025 19:31:59 +0200 Subject: [PATCH 52/91] RISC-V: KVM: add SBI extension reset callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, only the STA extension needed a reset function but that's going to be the case for FWFT as well. Add a reset callback that can be implemented by SBI extensions. [ alex: Remove blank line at eof ] Signed-off-by: Clément Léger Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/20250424173204.1948385-13-cleger@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/kvm_host.h | 1 - arch/riscv/include/asm/kvm_vcpu_sbi.h | 2 ++ arch/riscv/kvm/vcpu.c | 2 +- arch/riscv/kvm/vcpu_sbi.c | 23 +++++++++++++++++++++++ arch/riscv/kvm/vcpu_sbi_sta.c | 3 ++- 5 files changed, 28 insertions(+), 3 deletions(-) diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h index 0e9c2fab637872..4fa02e08214205 100644 --- a/arch/riscv/include/asm/kvm_host.h +++ b/arch/riscv/include/asm/kvm_host.h @@ -407,7 +407,6 @@ void __kvm_riscv_vcpu_power_on(struct kvm_vcpu *vcpu); void kvm_riscv_vcpu_power_on(struct kvm_vcpu *vcpu); bool kvm_riscv_vcpu_stopped(struct kvm_vcpu *vcpu); -void kvm_riscv_vcpu_sbi_sta_reset(struct kvm_vcpu *vcpu); void kvm_riscv_vcpu_record_steal_time(struct kvm_vcpu *vcpu); #endif /* __RISCV_KVM_HOST_H__ */ diff --git a/arch/riscv/include/asm/kvm_vcpu_sbi.h b/arch/riscv/include/asm/kvm_vcpu_sbi.h index bcb90757b1495a..cb68b3a57c8f8d 100644 --- a/arch/riscv/include/asm/kvm_vcpu_sbi.h +++ b/arch/riscv/include/asm/kvm_vcpu_sbi.h @@ -57,6 +57,7 @@ struct kvm_vcpu_sbi_extension { */ int (*init)(struct kvm_vcpu *vcpu); void (*deinit)(struct kvm_vcpu *vcpu); + void (*reset)(struct kvm_vcpu *vcpu); }; void kvm_riscv_vcpu_sbi_forward(struct kvm_vcpu *vcpu, struct kvm_run *run); @@ -78,6 +79,7 @@ bool riscv_vcpu_supports_sbi_ext(struct kvm_vcpu *vcpu, int idx); int kvm_riscv_vcpu_sbi_ecall(struct kvm_vcpu *vcpu, struct kvm_run *run); void kvm_riscv_vcpu_sbi_init(struct kvm_vcpu *vcpu); void kvm_riscv_vcpu_sbi_deinit(struct kvm_vcpu *vcpu); +void kvm_riscv_vcpu_sbi_reset(struct kvm_vcpu *vcpu); int kvm_riscv_vcpu_get_reg_sbi_sta(struct kvm_vcpu *vcpu, unsigned long reg_num, unsigned long *reg_val); diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c index 877bcc85c06709..542747e2c7f508 100644 --- a/arch/riscv/kvm/vcpu.c +++ b/arch/riscv/kvm/vcpu.c @@ -94,7 +94,7 @@ static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu) vcpu->arch.hfence_tail = 0; memset(vcpu->arch.hfence_queue, 0, sizeof(vcpu->arch.hfence_queue)); - kvm_riscv_vcpu_sbi_sta_reset(vcpu); + kvm_riscv_vcpu_sbi_reset(vcpu); /* Reset the guest CSRs for hotplug usecase */ if (loaded) diff --git a/arch/riscv/kvm/vcpu_sbi.c b/arch/riscv/kvm/vcpu_sbi.c index 3139f171c20fcd..4ebdfae7dca600 100644 --- a/arch/riscv/kvm/vcpu_sbi.c +++ b/arch/riscv/kvm/vcpu_sbi.c @@ -536,3 +536,26 @@ void kvm_riscv_vcpu_sbi_deinit(struct kvm_vcpu *vcpu) ext->deinit(vcpu); } } + +void kvm_riscv_vcpu_sbi_reset(struct kvm_vcpu *vcpu) +{ + struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context; + const struct kvm_riscv_sbi_extension_entry *entry; + const struct kvm_vcpu_sbi_extension *ext; + int idx, i; + + for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) { + entry = &sbi_ext[i]; + ext = entry->ext_ptr; + idx = entry->ext_idx; + + if (idx < 0 || idx >= ARRAY_SIZE(scontext->ext_status)) + continue; + + if (scontext->ext_status[idx] != KVM_RISCV_SBI_EXT_STATUS_ENABLED || + !ext->reset) + continue; + + ext->reset(vcpu); + } +} diff --git a/arch/riscv/kvm/vcpu_sbi_sta.c b/arch/riscv/kvm/vcpu_sbi_sta.c index 5f35427114c1da..cc6cb7c8f0e411 100644 --- a/arch/riscv/kvm/vcpu_sbi_sta.c +++ b/arch/riscv/kvm/vcpu_sbi_sta.c @@ -16,7 +16,7 @@ #include #include -void kvm_riscv_vcpu_sbi_sta_reset(struct kvm_vcpu *vcpu) +static void kvm_riscv_vcpu_sbi_sta_reset(struct kvm_vcpu *vcpu) { vcpu->arch.sta.shmem = INVALID_GPA; vcpu->arch.sta.last_steal = 0; @@ -156,6 +156,7 @@ const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_sta = { .extid_end = SBI_EXT_STA, .handler = kvm_sbi_ext_sta_handler, .probe = kvm_sbi_ext_sta_probe, + .reset = kvm_riscv_vcpu_sbi_sta_reset, }; int kvm_riscv_vcpu_get_reg_sbi_sta(struct kvm_vcpu *vcpu, From 48d8aa40efe24e77ebd8c6db64765430b88e41b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= Date: Thu, 24 Apr 2025 19:32:00 +0200 Subject: [PATCH 53/91] RISC-V: KVM: add support for FWFT SBI extension MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add basic infrastructure to support the FWFT extension in KVM. Signed-off-by: Clément Léger Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/20250424173204.1948385-14-cleger@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/kvm_host.h | 4 + arch/riscv/include/asm/kvm_vcpu_sbi.h | 1 + arch/riscv/include/asm/kvm_vcpu_sbi_fwft.h | 29 +++ arch/riscv/include/uapi/asm/kvm.h | 1 + arch/riscv/kvm/Makefile | 1 + arch/riscv/kvm/vcpu_sbi.c | 4 + arch/riscv/kvm/vcpu_sbi_fwft.c | 216 +++++++++++++++++++++ 7 files changed, 256 insertions(+) create mode 100644 arch/riscv/include/asm/kvm_vcpu_sbi_fwft.h create mode 100644 arch/riscv/kvm/vcpu_sbi_fwft.c diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h index 4fa02e08214205..c3f880763b9aa8 100644 --- a/arch/riscv/include/asm/kvm_host.h +++ b/arch/riscv/include/asm/kvm_host.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -281,6 +282,9 @@ struct kvm_vcpu_arch { /* Performance monitoring context */ struct kvm_pmu pmu_context; + /* Firmware feature SBI extension context */ + struct kvm_sbi_fwft fwft_context; + /* 'static' configurations which are set only once */ struct kvm_vcpu_config cfg; diff --git a/arch/riscv/include/asm/kvm_vcpu_sbi.h b/arch/riscv/include/asm/kvm_vcpu_sbi.h index cb68b3a57c8f8d..ffd03fed0c0638 100644 --- a/arch/riscv/include/asm/kvm_vcpu_sbi.h +++ b/arch/riscv/include/asm/kvm_vcpu_sbi.h @@ -98,6 +98,7 @@ extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_hsm; extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_dbcn; extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_susp; extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_sta; +extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_fwft; extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_experimental; extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_vendor; diff --git a/arch/riscv/include/asm/kvm_vcpu_sbi_fwft.h b/arch/riscv/include/asm/kvm_vcpu_sbi_fwft.h new file mode 100644 index 00000000000000..9ba84135575870 --- /dev/null +++ b/arch/riscv/include/asm/kvm_vcpu_sbi_fwft.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2025 Rivos Inc. + * + * Authors: + * Clément Léger + */ + +#ifndef __KVM_VCPU_RISCV_FWFT_H +#define __KVM_VCPU_RISCV_FWFT_H + +#include + +struct kvm_sbi_fwft_feature; + +struct kvm_sbi_fwft_config { + const struct kvm_sbi_fwft_feature *feature; + bool supported; + unsigned long flags; +}; + +/* FWFT data structure per vcpu */ +struct kvm_sbi_fwft { + struct kvm_sbi_fwft_config *configs; +}; + +#define vcpu_to_fwft(vcpu) (&(vcpu)->arch.fwft_context) + +#endif /* !__KVM_VCPU_RISCV_FWFT_H */ diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h index 5f59fd226cc57a..5ba77a3d9f6e4e 100644 --- a/arch/riscv/include/uapi/asm/kvm.h +++ b/arch/riscv/include/uapi/asm/kvm.h @@ -204,6 +204,7 @@ enum KVM_RISCV_SBI_EXT_ID { KVM_RISCV_SBI_EXT_DBCN, KVM_RISCV_SBI_EXT_STA, KVM_RISCV_SBI_EXT_SUSP, + KVM_RISCV_SBI_EXT_FWFT, KVM_RISCV_SBI_EXT_MAX, }; diff --git a/arch/riscv/kvm/Makefile b/arch/riscv/kvm/Makefile index 4e0bba91d2841d..06e2d52a9b88a3 100644 --- a/arch/riscv/kvm/Makefile +++ b/arch/riscv/kvm/Makefile @@ -26,6 +26,7 @@ kvm-y += vcpu_onereg.o kvm-$(CONFIG_RISCV_PMU_SBI) += vcpu_pmu.o kvm-y += vcpu_sbi.o kvm-y += vcpu_sbi_base.o +kvm-y += vcpu_sbi_fwft.o kvm-y += vcpu_sbi_hsm.o kvm-$(CONFIG_RISCV_PMU_SBI) += vcpu_sbi_pmu.o kvm-y += vcpu_sbi_replace.o diff --git a/arch/riscv/kvm/vcpu_sbi.c b/arch/riscv/kvm/vcpu_sbi.c index 4ebdfae7dca600..96b9044a73b8bf 100644 --- a/arch/riscv/kvm/vcpu_sbi.c +++ b/arch/riscv/kvm/vcpu_sbi.c @@ -78,6 +78,10 @@ static const struct kvm_riscv_sbi_extension_entry sbi_ext[] = { .ext_idx = KVM_RISCV_SBI_EXT_STA, .ext_ptr = &vcpu_sbi_ext_sta, }, + { + .ext_idx = KVM_RISCV_SBI_EXT_FWFT, + .ext_ptr = &vcpu_sbi_ext_fwft, + }, { .ext_idx = KVM_RISCV_SBI_EXT_EXPERIMENTAL, .ext_ptr = &vcpu_sbi_ext_experimental, diff --git a/arch/riscv/kvm/vcpu_sbi_fwft.c b/arch/riscv/kvm/vcpu_sbi_fwft.c new file mode 100644 index 00000000000000..b0f66c7bf010e9 --- /dev/null +++ b/arch/riscv/kvm/vcpu_sbi_fwft.c @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2025 Rivos Inc. + * + * Authors: + * Clément Léger + */ + +#include +#include +#include +#include +#include +#include +#include + +struct kvm_sbi_fwft_feature { + /** + * @id: Feature ID + */ + enum sbi_fwft_feature_t id; + + /** + * @supported: Check if the feature is supported on the vcpu + * + * This callback is optional, if not provided the feature is assumed to + * be supported + */ + bool (*supported)(struct kvm_vcpu *vcpu); + + /** + * @set: Set the feature value + * + * Return SBI_SUCCESS on success or an SBI error (SBI_ERR_*) + * + * This callback is mandatory + */ + long (*set)(struct kvm_vcpu *vcpu, struct kvm_sbi_fwft_config *conf, unsigned long value); + + /** + * @get: Get the feature current value + * + * Return SBI_SUCCESS on success or an SBI error (SBI_ERR_*) + * + * This callback is mandatory + */ + long (*get)(struct kvm_vcpu *vcpu, struct kvm_sbi_fwft_config *conf, unsigned long *value); +}; + +static const enum sbi_fwft_feature_t kvm_fwft_defined_features[] = { + SBI_FWFT_MISALIGNED_EXC_DELEG, + SBI_FWFT_LANDING_PAD, + SBI_FWFT_SHADOW_STACK, + SBI_FWFT_DOUBLE_TRAP, + SBI_FWFT_PTE_AD_HW_UPDATING, + SBI_FWFT_POINTER_MASKING_PMLEN, +}; + +static bool kvm_fwft_is_defined_feature(enum sbi_fwft_feature_t feature) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(kvm_fwft_defined_features); i++) { + if (kvm_fwft_defined_features[i] == feature) + return true; + } + + return false; +} + +static const struct kvm_sbi_fwft_feature features[] = { +}; + +static struct kvm_sbi_fwft_config * +kvm_sbi_fwft_get_config(struct kvm_vcpu *vcpu, enum sbi_fwft_feature_t feature) +{ + int i; + struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu); + + for (i = 0; i < ARRAY_SIZE(features); i++) { + if (fwft->configs[i].feature->id == feature) + return &fwft->configs[i]; + } + + return NULL; +} + +static int kvm_fwft_get_feature(struct kvm_vcpu *vcpu, u32 feature, + struct kvm_sbi_fwft_config **conf) +{ + struct kvm_sbi_fwft_config *tconf; + + tconf = kvm_sbi_fwft_get_config(vcpu, feature); + if (!tconf) { + if (kvm_fwft_is_defined_feature(feature)) + return SBI_ERR_NOT_SUPPORTED; + + return SBI_ERR_DENIED; + } + + if (!tconf->supported) + return SBI_ERR_NOT_SUPPORTED; + + *conf = tconf; + + return SBI_SUCCESS; +} + +static int kvm_sbi_fwft_set(struct kvm_vcpu *vcpu, u32 feature, + unsigned long value, unsigned long flags) +{ + int ret; + struct kvm_sbi_fwft_config *conf; + + ret = kvm_fwft_get_feature(vcpu, feature, &conf); + if (ret) + return ret; + + if ((flags & ~SBI_FWFT_SET_FLAG_LOCK) != 0) + return SBI_ERR_INVALID_PARAM; + + if (conf->flags & SBI_FWFT_SET_FLAG_LOCK) + return SBI_ERR_DENIED_LOCKED; + + conf->flags = flags; + + return conf->feature->set(vcpu, conf, value); +} + +static int kvm_sbi_fwft_get(struct kvm_vcpu *vcpu, unsigned long feature, + unsigned long *value) +{ + int ret; + struct kvm_sbi_fwft_config *conf; + + ret = kvm_fwft_get_feature(vcpu, feature, &conf); + if (ret) + return ret; + + return conf->feature->get(vcpu, conf, value); +} + +static int kvm_sbi_ext_fwft_handler(struct kvm_vcpu *vcpu, struct kvm_run *run, + struct kvm_vcpu_sbi_return *retdata) +{ + int ret; + struct kvm_cpu_context *cp = &vcpu->arch.guest_context; + unsigned long funcid = cp->a6; + + switch (funcid) { + case SBI_EXT_FWFT_SET: + ret = kvm_sbi_fwft_set(vcpu, cp->a0, cp->a1, cp->a2); + break; + case SBI_EXT_FWFT_GET: + ret = kvm_sbi_fwft_get(vcpu, cp->a0, &retdata->out_val); + break; + default: + ret = SBI_ERR_NOT_SUPPORTED; + break; + } + + retdata->err_val = ret; + + return 0; +} + +static int kvm_sbi_ext_fwft_init(struct kvm_vcpu *vcpu) +{ + struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu); + const struct kvm_sbi_fwft_feature *feature; + struct kvm_sbi_fwft_config *conf; + int i; + + fwft->configs = kcalloc(ARRAY_SIZE(features), sizeof(struct kvm_sbi_fwft_config), + GFP_KERNEL); + if (!fwft->configs) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(features); i++) { + feature = &features[i]; + conf = &fwft->configs[i]; + if (feature->supported) + conf->supported = feature->supported(vcpu); + else + conf->supported = true; + + conf->feature = feature; + } + + return 0; +} + +static void kvm_sbi_ext_fwft_deinit(struct kvm_vcpu *vcpu) +{ + struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu); + + kfree(fwft->configs); +} + +static void kvm_sbi_ext_fwft_reset(struct kvm_vcpu *vcpu) +{ + int i; + struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu); + + for (i = 0; i < ARRAY_SIZE(features); i++) + fwft->configs[i].flags = 0; +} + +const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_fwft = { + .extid_start = SBI_EXT_FWFT, + .extid_end = SBI_EXT_FWFT, + .handler = kvm_sbi_ext_fwft_handler, + .init = kvm_sbi_ext_fwft_init, + .deinit = kvm_sbi_ext_fwft_deinit, + .reset = kvm_sbi_ext_fwft_reset, +}; From cc70a8c6c092da0330b4f1052353a82d8a65083e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= Date: Thu, 24 Apr 2025 19:32:01 +0200 Subject: [PATCH 54/91] RISC-V: KVM: add support for SBI_FWFT_MISALIGNED_DELEG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SBI_FWFT_MISALIGNED_DELEG needs hedeleg to be modified to delegate misaligned load/store exceptions. Save and restore it during CPU load/put. Signed-off-by: Clément Léger Reviewed-by: Deepak Gupta Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/20250424173204.1948385-15-cleger@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/kvm/vcpu.c | 3 +++ arch/riscv/kvm/vcpu_sbi_fwft.c | 36 ++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c index 542747e2c7f508..d98e379945c369 100644 --- a/arch/riscv/kvm/vcpu.c +++ b/arch/riscv/kvm/vcpu.c @@ -646,6 +646,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) { void *nsh; struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; + struct kvm_vcpu_config *cfg = &vcpu->arch.cfg; vcpu->cpu = -1; @@ -671,6 +672,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) csr->vstval = nacl_csr_read(nsh, CSR_VSTVAL); csr->hvip = nacl_csr_read(nsh, CSR_HVIP); csr->vsatp = nacl_csr_read(nsh, CSR_VSATP); + cfg->hedeleg = nacl_csr_read(nsh, CSR_HEDELEG); } else { csr->vsstatus = csr_read(CSR_VSSTATUS); csr->vsie = csr_read(CSR_VSIE); @@ -681,6 +683,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) csr->vstval = csr_read(CSR_VSTVAL); csr->hvip = csr_read(CSR_HVIP); csr->vsatp = csr_read(CSR_VSATP); + cfg->hedeleg = csr_read(CSR_HEDELEG); } } diff --git a/arch/riscv/kvm/vcpu_sbi_fwft.c b/arch/riscv/kvm/vcpu_sbi_fwft.c index b0f66c7bf010e9..d16ee477042f69 100644 --- a/arch/riscv/kvm/vcpu_sbi_fwft.c +++ b/arch/riscv/kvm/vcpu_sbi_fwft.c @@ -14,6 +14,8 @@ #include #include +#define MIS_DELEG (BIT_ULL(EXC_LOAD_MISALIGNED) | BIT_ULL(EXC_STORE_MISALIGNED)) + struct kvm_sbi_fwft_feature { /** * @id: Feature ID @@ -68,7 +70,41 @@ static bool kvm_fwft_is_defined_feature(enum sbi_fwft_feature_t feature) return false; } +static bool kvm_sbi_fwft_misaligned_delegation_supported(struct kvm_vcpu *vcpu) +{ + return misaligned_traps_can_delegate(); +} + +static long kvm_sbi_fwft_set_misaligned_delegation(struct kvm_vcpu *vcpu, + struct kvm_sbi_fwft_config *conf, + unsigned long value) +{ + if (value == 1) + csr_set(CSR_HEDELEG, MIS_DELEG); + else if (value == 0) + csr_clear(CSR_HEDELEG, MIS_DELEG); + else + return SBI_ERR_INVALID_PARAM; + + return SBI_SUCCESS; +} + +static long kvm_sbi_fwft_get_misaligned_delegation(struct kvm_vcpu *vcpu, + struct kvm_sbi_fwft_config *conf, + unsigned long *value) +{ + *value = (csr_read(CSR_HEDELEG) & MIS_DELEG) == MIS_DELEG; + + return SBI_SUCCESS; +} + static const struct kvm_sbi_fwft_feature features[] = { + { + .id = SBI_FWFT_MISALIGNED_EXC_DELEG, + .supported = kvm_sbi_fwft_misaligned_delegation_supported, + .set = kvm_sbi_fwft_set_misaligned_delegation, + .get = kvm_sbi_fwft_get_misaligned_delegation, + }, }; static struct kvm_sbi_fwft_config * From 69c013a8cc443e7b0125841b8fd16a2c38e2f0ad Mon Sep 17 00:00:00 2001 From: Deepak Gupta Date: Fri, 2 May 2025 16:30:32 -0700 Subject: [PATCH 55/91] mm: VM_SHADOW_STACK definition for riscv VM_HIGH_ARCH_5 is used for riscv Reviewed-by: Zong Li Reviewed-by: Alexandre Ghiti Signed-off-by: Deepak Gupta Link: https://lore.kernel.org/r/20250502-v5_user_cfi_series-v15-1-914966471885@rivosinc.com Signed-off-by: Alexandre Ghiti --- include/linux/mm.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/linux/mm.h b/include/linux/mm.h index bf55206935c467..fb622151bcd7c6 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -352,6 +352,13 @@ extern unsigned int kobjsize(const void *objp); # define VM_SHADOW_STACK VM_HIGH_ARCH_6 #endif +#if defined(CONFIG_RISCV_USER_CFI) +/* + * Following x86 and picking up the same bitpos. + */ +# define VM_SHADOW_STACK VM_HIGH_ARCH_5 +#endif + #ifndef VM_SHADOW_STACK # define VM_SHADOW_STACK VM_NONE #endif From 91b18beabc2cbba45206c7f8a93b8ff9e49f79e6 Mon Sep 17 00:00:00 2001 From: Deepak Gupta Date: Fri, 2 May 2025 16:30:33 -0700 Subject: [PATCH 56/91] dt-bindings: riscv: zicfilp and zicfiss in dt-bindings (extensions.yaml) Make an entry for cfi extensions in extensions.yaml. Signed-off-by: Deepak Gupta Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250502-v5_user_cfi_series-v15-2-914966471885@rivosinc.com Signed-off-by: Alexandre Ghiti --- .../devicetree/bindings/riscv/extensions.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml index bcab59e0cc2e1d..c9e68bdbf0999a 100644 --- a/Documentation/devicetree/bindings/riscv/extensions.yaml +++ b/Documentation/devicetree/bindings/riscv/extensions.yaml @@ -444,6 +444,20 @@ properties: The standard Zicboz extension for cache-block zeroing as ratified in commit 3dd606f ("Create cmobase-v1.0.pdf") of riscv-CMOs. + - const: zicfilp + description: | + The standard Zicfilp extension for enforcing forward edge + control-flow integrity as ratified in commit 3f8e450 ("merge + pull request #227 from ved-rivos/0709") of riscv-cfi + github repo. + + - const: zicfiss + description: | + The standard Zicfiss extension for enforcing backward edge + control-flow integrity as ratified in commit 3f8e450 ("merge + pull request #227 from ved-rivos/0709") of riscv-cfi + github repo. + - const: zicntr description: The standard Zicntr extension for base counters and timers, as From 850f8f037cb3fbaa5f89dffb25bc36a61c1053ba Mon Sep 17 00:00:00 2001 From: Deepak Gupta Date: Fri, 2 May 2025 16:30:34 -0700 Subject: [PATCH 57/91] riscv: zicfiss / zicfilp enumeration This patch adds support for detecting zicfiss and zicfilp. zicfiss and zicfilp stands for unprivleged integer spec extension for shadow stack and branch tracking on indirect branches, respectively. This patch looks for zicfiss and zicfilp in device tree and accordinlgy lights up bit in cpu feature bitmap. Furthermore this patch adds detection utility functions to return whether shadow stack or landing pads are supported by cpu. Reviewed-by: Zong Li Reviewed-by: Alexandre Ghiti Signed-off-by: Deepak Gupta Link: https://lore.kernel.org/r/20250502-v5_user_cfi_series-v15-3-914966471885@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/cpufeature.h | 12 ++++++++++++ arch/riscv/include/asm/hwcap.h | 2 ++ arch/riscv/include/asm/processor.h | 1 + arch/riscv/kernel/cpufeature.c | 13 +++++++++++++ 4 files changed, 28 insertions(+) diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h index f56b409361fbe0..35137ab9cf5e75 100644 --- a/arch/riscv/include/asm/cpufeature.h +++ b/arch/riscv/include/asm/cpufeature.h @@ -140,4 +140,16 @@ static __always_inline bool riscv_cpu_has_extension_unlikely(int cpu, const unsi return __riscv_isa_extension_available(hart_isa[cpu].isa, ext); } +static inline bool cpu_supports_shadow_stack(void) +{ + return (IS_ENABLED(CONFIG_RISCV_USER_CFI) && + riscv_has_extension_unlikely(RISCV_ISA_EXT_ZICFISS)); +} + +static inline bool cpu_supports_indirect_br_lp_instr(void) +{ + return (IS_ENABLED(CONFIG_RISCV_USER_CFI) && + riscv_has_extension_unlikely(RISCV_ISA_EXT_ZICFILP)); +} + #endif diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h index e3cbf203cdde7f..abc33ca1302ed6 100644 --- a/arch/riscv/include/asm/hwcap.h +++ b/arch/riscv/include/asm/hwcap.h @@ -105,6 +105,8 @@ #define RISCV_ISA_EXT_ZVFBFWMA 96 #define RISCV_ISA_EXT_ZAAMO 97 #define RISCV_ISA_EXT_ZALRSC 98 +#define RISCV_ISA_EXT_ZICFILP 99 +#define RISCV_ISA_EXT_ZICFISS 100 #define RISCV_ISA_EXT_XLINUXENVCFG 127 diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h index 5f56eb9d114a95..e3aba3336e6323 100644 --- a/arch/riscv/include/asm/processor.h +++ b/arch/riscv/include/asm/processor.h @@ -13,6 +13,7 @@ #include #include +#include #define arch_get_mmap_end(addr, len, flags) \ ({ \ diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c index 2054f6c4b0ae1f..98e55467557b53 100644 --- a/arch/riscv/kernel/cpufeature.c +++ b/arch/riscv/kernel/cpufeature.c @@ -258,6 +258,15 @@ static int riscv_ext_svadu_validate(const struct riscv_isa_ext_data *data, return 0; } +static int riscv_cfi_validate(const struct riscv_isa_ext_data *data, + const unsigned long *isa_bitmap) +{ + if (!IS_ENABLED(CONFIG_RISCV_USER_CFI)) + return -EINVAL; + + return 0; +} + static const unsigned int riscv_a_exts[] = { RISCV_ISA_EXT_ZAAMO, RISCV_ISA_EXT_ZALRSC, @@ -444,6 +453,10 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = { __RISCV_ISA_EXT_SUPERSET_VALIDATE(zicbom, RISCV_ISA_EXT_ZICBOM, riscv_xlinuxenvcfg_exts, riscv_ext_zicbom_validate), __RISCV_ISA_EXT_SUPERSET_VALIDATE(zicboz, RISCV_ISA_EXT_ZICBOZ, riscv_xlinuxenvcfg_exts, riscv_ext_zicboz_validate), __RISCV_ISA_EXT_DATA(ziccrse, RISCV_ISA_EXT_ZICCRSE), + __RISCV_ISA_EXT_SUPERSET_VALIDATE(zicfilp, RISCV_ISA_EXT_ZICFILP, riscv_xlinuxenvcfg_exts, + riscv_cfi_validate), + __RISCV_ISA_EXT_SUPERSET_VALIDATE(zicfiss, RISCV_ISA_EXT_ZICFISS, riscv_xlinuxenvcfg_exts, + riscv_cfi_validate), __RISCV_ISA_EXT_DATA(zicntr, RISCV_ISA_EXT_ZICNTR), __RISCV_ISA_EXT_DATA(zicond, RISCV_ISA_EXT_ZICOND), __RISCV_ISA_EXT_DATA(zicsr, RISCV_ISA_EXT_ZICSR), From 6fb84730683ea34ab62d637017ee601712be6458 Mon Sep 17 00:00:00 2001 From: Deepak Gupta Date: Fri, 2 May 2025 16:30:35 -0700 Subject: [PATCH 58/91] riscv: zicfiss / zicfilp extension csr and bit definitions zicfiss and zicfilp extension gets enabled via b3 and b2 in *envcfg CSR. menvcfg controls enabling for S/HS mode. henvcfg control enabling for VS while senvcfg controls enabling for U/VU mode. zicfilp extension extends *status CSR to hold `expected landing pad` bit. A trap or interrupt can occur between an indirect jmp/call and target instr. `expected landing pad` bit from CPU is recorded into xstatus CSR so that when supervisor performs xret, `expected landing pad` state of CPU can be restored. zicfiss adds one new CSR - CSR_SSP: CSR_SSP contains current shadow stack pointer. Signed-off-by: Deepak Gupta Reviewed-by: Charlie Jenkins Link: https://lore.kernel.org/r/20250502-v5_user_cfi_series-v15-4-914966471885@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/csr.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h index 6fed42e377059c..2f49b9663640da 100644 --- a/arch/riscv/include/asm/csr.h +++ b/arch/riscv/include/asm/csr.h @@ -18,6 +18,15 @@ #define SR_MPP _AC(0x00001800, UL) /* Previously Machine */ #define SR_SUM _AC(0x00040000, UL) /* Supervisor User Memory Access */ +/* zicfilp landing pad status bit */ +#define SR_SPELP _AC(0x00800000, UL) +#define SR_MPELP _AC(0x020000000000, UL) +#ifdef CONFIG_RISCV_M_MODE +#define SR_ELP SR_MPELP +#else +#define SR_ELP SR_SPELP +#endif + #define SR_FS _AC(0x00006000, UL) /* Floating-point Status */ #define SR_FS_OFF _AC(0x00000000, UL) #define SR_FS_INITIAL _AC(0x00002000, UL) @@ -212,6 +221,8 @@ #define ENVCFG_PMM_PMLEN_16 (_AC(0x3, ULL) << 32) #define ENVCFG_CBZE (_AC(1, UL) << 7) #define ENVCFG_CBCFE (_AC(1, UL) << 6) +#define ENVCFG_LPE (_AC(1, UL) << 2) +#define ENVCFG_SSE (_AC(1, UL) << 3) #define ENVCFG_CBIE_SHIFT 4 #define ENVCFG_CBIE (_AC(0x3, UL) << ENVCFG_CBIE_SHIFT) #define ENVCFG_CBIE_ILL _AC(0x0, UL) @@ -230,6 +241,11 @@ #define SMSTATEEN0_HSENVCFG (_ULL(1) << SMSTATEEN0_HSENVCFG_SHIFT) #define SMSTATEEN0_SSTATEEN0_SHIFT 63 #define SMSTATEEN0_SSTATEEN0 (_ULL(1) << SMSTATEEN0_SSTATEEN0_SHIFT) +/* + * zicfiss user mode csr + * CSR_SSP holds current shadow stack pointer. + */ +#define CSR_SSP 0x011 /* mseccfg bits */ #define MSECCFG_PMM ENVCFG_PMM From 85e2a2d4973fa06ed932d2922f7b1dbfa7f6797a Mon Sep 17 00:00:00 2001 From: Deepak Gupta Date: Fri, 2 May 2025 16:30:36 -0700 Subject: [PATCH 59/91] riscv: usercfi state for task and save/restore of CSR_SSP on trap entry/exit Carves out space in arch specific thread struct for cfi status and shadow stack in usermode on riscv. This patch does following - defines a new structure cfi_status with status bit for cfi feature - defines shadow stack pointer, base and size in cfi_status structure - defines offsets to new member fields in thread in asm-offsets.c - Saves and restore shadow stack pointer on trap entry (U --> S) and exit (S --> U) Shadow stack save/restore is gated on feature availiblity and implemented using alternative. CSR can be context switched in `switch_to` as well but soon as kernel shadow stack support gets rolled in, shadow stack pointer will need to be switched at trap entry/exit point (much like `sp`). It can be argued that kernel using shadow stack deployment scenario may not be as prevalant as user mode using this feature. But even if there is some minimal deployment of kernel shadow stack, that means that it needs to be supported. And thus save/restore of shadow stack pointer in entry.S instead of in `switch_to.h`. Reviewed-by: Charlie Jenkins Reviewed-by: Zong Li Reviewed-by: Alexandre Ghiti Signed-off-by: Deepak Gupta Link: https://lore.kernel.org/r/20250502-v5_user_cfi_series-v15-5-914966471885@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/processor.h | 1 + arch/riscv/include/asm/thread_info.h | 3 +++ arch/riscv/include/asm/usercfi.h | 23 +++++++++++++++++++++++ arch/riscv/kernel/asm-offsets.c | 4 ++++ arch/riscv/kernel/entry.S | 28 ++++++++++++++++++++++++++++ 5 files changed, 59 insertions(+) create mode 100644 arch/riscv/include/asm/usercfi.h diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h index e3aba3336e6323..d851bb5c6da0b0 100644 --- a/arch/riscv/include/asm/processor.h +++ b/arch/riscv/include/asm/processor.h @@ -14,6 +14,7 @@ #include #include +#include #define arch_get_mmap_end(addr, len, flags) \ ({ \ diff --git a/arch/riscv/include/asm/thread_info.h b/arch/riscv/include/asm/thread_info.h index f5916a70879a87..e066f41176cace 100644 --- a/arch/riscv/include/asm/thread_info.h +++ b/arch/riscv/include/asm/thread_info.h @@ -73,6 +73,9 @@ struct thread_info { */ unsigned long a0, a1, a2; #endif +#ifdef CONFIG_RISCV_USER_CFI + struct cfi_state user_cfi_state; +#endif }; #ifdef CONFIG_SHADOW_CALL_STACK diff --git a/arch/riscv/include/asm/usercfi.h b/arch/riscv/include/asm/usercfi.h new file mode 100644 index 00000000000000..94b214c295c0dc --- /dev/null +++ b/arch/riscv/include/asm/usercfi.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 + * Copyright (C) 2024 Rivos, Inc. + * Deepak Gupta + */ +#ifndef _ASM_RISCV_USERCFI_H +#define _ASM_RISCV_USERCFI_H + +#ifndef __ASSEMBLY__ +#include + +#ifdef CONFIG_RISCV_USER_CFI +struct cfi_state { + unsigned long ubcfi_en : 1; /* Enable for backward cfi. */ + unsigned long user_shdw_stk; /* Current user shadow stack pointer */ + unsigned long shdw_stk_base; /* Base address of shadow stack */ + unsigned long shdw_stk_size; /* size of shadow stack */ +}; + +#endif /* CONFIG_RISCV_USER_CFI */ + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_RISCV_USERCFI_H */ diff --git a/arch/riscv/kernel/asm-offsets.c b/arch/riscv/kernel/asm-offsets.c index 16490755304e0c..f33945432f8f6f 100644 --- a/arch/riscv/kernel/asm-offsets.c +++ b/arch/riscv/kernel/asm-offsets.c @@ -49,6 +49,10 @@ void asm_offsets(void) #endif OFFSET(TASK_TI_CPU_NUM, task_struct, thread_info.cpu); +#ifdef CONFIG_RISCV_USER_CFI + OFFSET(TASK_TI_CFI_STATE, task_struct, thread_info.user_cfi_state); + OFFSET(TASK_TI_USER_SSP, task_struct, thread_info.user_cfi_state.user_shdw_stk); +#endif OFFSET(TASK_THREAD_F0, task_struct, thread.fstate.f[0]); OFFSET(TASK_THREAD_F1, task_struct, thread.fstate.f[1]); OFFSET(TASK_THREAD_F2, task_struct, thread.fstate.f[2]); diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S index 33a5a9f2a0d4e1..c4bfe2085c411d 100644 --- a/arch/riscv/kernel/entry.S +++ b/arch/riscv/kernel/entry.S @@ -91,6 +91,32 @@ REG_L a0, TASK_TI_A0(tp) .endm +/* + * If previous mode was U, capture shadow stack pointer and save it away + * Zero CSR_SSP at the same time for sanitization. + */ +.macro save_userssp tmp, status + ALTERNATIVE("nops(4)", + __stringify( \ + andi \tmp, \status, SR_SPP; \ + bnez \tmp, skip_ssp_save; \ + csrrw \tmp, CSR_SSP, x0; \ + REG_S \tmp, TASK_TI_USER_SSP(tp); \ + skip_ssp_save:), + 0, + RISCV_ISA_EXT_ZICFISS, + CONFIG_RISCV_USER_CFI) +.endm + +.macro restore_userssp tmp + ALTERNATIVE("nops(2)", + __stringify( \ + REG_L \tmp, TASK_TI_USER_SSP(tp); \ + csrw CSR_SSP, \tmp), + 0, + RISCV_ISA_EXT_ZICFISS, + CONFIG_RISCV_USER_CFI) +.endm SYM_CODE_START(handle_exception) /* @@ -147,6 +173,7 @@ SYM_CODE_START(handle_exception) REG_L s0, TASK_TI_USER_SP(tp) csrrc s1, CSR_STATUS, t0 + save_userssp s2, s1 csrr s2, CSR_EPC csrr s3, CSR_TVAL csrr s4, CSR_CAUSE @@ -236,6 +263,7 @@ SYM_CODE_START_NOALIGN(ret_from_exception) * structures again. */ csrw CSR_SCRATCH, tp + restore_userssp s3 1: #ifdef CONFIG_RISCV_ISA_V_PREEMPTIVE move a0, sp From 6ec64b8d75cb70f19de3ef9c1d94945c03668d72 Mon Sep 17 00:00:00 2001 From: Deepak Gupta Date: Fri, 2 May 2025 16:30:37 -0700 Subject: [PATCH 60/91] riscv/mm : ensure PROT_WRITE leads to VM_READ | VM_WRITE `arch_calc_vm_prot_bits` is implemented on risc-v to return VM_READ | VM_WRITE if PROT_WRITE is specified. Similarly `riscv_sys_mmap` is updated to convert all incoming PROT_WRITE to (PROT_WRITE | PROT_READ). This is to make sure that any existing apps using PROT_WRITE still work. Earlier `protection_map[VM_WRITE]` used to pick read-write PTE encodings. Now `protection_map[VM_WRITE]` will always pick PAGE_SHADOWSTACK PTE encodings for shadow stack. Above changes ensure that existing apps continue to work because underneath kernel will be picking `protection_map[VM_WRITE|VM_READ]` PTE encodings. Reviewed-by: Zong Li Reviewed-by: Alexandre Ghiti Signed-off-by: Deepak Gupta Link: https://lore.kernel.org/r/20250502-v5_user_cfi_series-v15-6-914966471885@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/mman.h | 25 +++++++++++++++++++++++++ arch/riscv/include/asm/pgtable.h | 1 + arch/riscv/kernel/sys_riscv.c | 10 ++++++++++ arch/riscv/mm/init.c | 2 +- 4 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 arch/riscv/include/asm/mman.h diff --git a/arch/riscv/include/asm/mman.h b/arch/riscv/include/asm/mman.h new file mode 100644 index 00000000000000..392c9c2d2e7856 --- /dev/null +++ b/arch/riscv/include/asm/mman.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_MMAN_H__ +#define __ASM_MMAN_H__ + +#include +#include +#include + +static inline unsigned long arch_calc_vm_prot_bits(unsigned long prot, + unsigned long pkey __always_unused) +{ + unsigned long ret = 0; + + /* + * If PROT_WRITE was specified, force it to VM_READ | VM_WRITE. + * Only VM_WRITE means shadow stack. + */ + if (prot & PROT_WRITE) + ret = (VM_READ | VM_WRITE); + return ret; +} + +#define arch_calc_vm_prot_bits(prot, pkey) arch_calc_vm_prot_bits(prot, pkey) + +#endif /* ! __ASM_MMAN_H__ */ diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h index 428e48e5f57d06..dba257cc4e2d9b 100644 --- a/arch/riscv/include/asm/pgtable.h +++ b/arch/riscv/include/asm/pgtable.h @@ -182,6 +182,7 @@ extern struct pt_alloc_ops pt_ops __meminitdata; #define PAGE_READ_EXEC __pgprot(_PAGE_BASE | _PAGE_READ | _PAGE_EXEC) #define PAGE_WRITE_EXEC __pgprot(_PAGE_BASE | _PAGE_READ | \ _PAGE_EXEC | _PAGE_WRITE) +#define PAGE_SHADOWSTACK __pgprot(_PAGE_BASE | _PAGE_WRITE) #define PAGE_COPY PAGE_READ #define PAGE_COPY_EXEC PAGE_READ_EXEC diff --git a/arch/riscv/kernel/sys_riscv.c b/arch/riscv/kernel/sys_riscv.c index d77afe05578f23..43a448bf254b4f 100644 --- a/arch/riscv/kernel/sys_riscv.c +++ b/arch/riscv/kernel/sys_riscv.c @@ -7,6 +7,7 @@ #include #include +#include static long riscv_sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, @@ -16,6 +17,15 @@ static long riscv_sys_mmap(unsigned long addr, unsigned long len, if (unlikely(offset & (~PAGE_MASK >> page_shift_offset))) return -EINVAL; + /* + * If PROT_WRITE is specified then extend that to PROT_READ + * protection_map[VM_WRITE] is now going to select shadow stack encodings. + * So specifying PROT_WRITE actually should select protection_map [VM_WRITE | VM_READ] + * If user wants to create shadow stack then they should use `map_shadow_stack` syscall. + */ + if (unlikely((prot & PROT_WRITE) && !(prot & PROT_READ))) + prot |= PROT_READ; + return ksys_mmap_pgoff(addr, len, prot, flags, fd, offset >> (PAGE_SHIFT - page_shift_offset)); } diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c index ab475ec6ca429e..78b27164bf83b2 100644 --- a/arch/riscv/mm/init.c +++ b/arch/riscv/mm/init.c @@ -375,7 +375,7 @@ pgd_t early_pg_dir[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE); static const pgprot_t protection_map[16] = { [VM_NONE] = PAGE_NONE, [VM_READ] = PAGE_READ, - [VM_WRITE] = PAGE_COPY, + [VM_WRITE] = PAGE_SHADOWSTACK, [VM_WRITE | VM_READ] = PAGE_COPY, [VM_EXEC] = PAGE_EXEC, [VM_EXEC | VM_READ] = PAGE_READ_EXEC, From 99a6f737496dd74eaa2f20f8887f0601bd4ac334 Mon Sep 17 00:00:00 2001 From: Deepak Gupta Date: Fri, 2 May 2025 16:30:38 -0700 Subject: [PATCH 61/91] riscv mm: manufacture shadow stack pte This patch implements creating shadow stack pte (on riscv). Creating shadow stack PTE on riscv means that clearing RWX and then setting W=1. Reviewed-by: Alexandre Ghiti Reviewed-by: Zong Li Signed-off-by: Deepak Gupta Link: https://lore.kernel.org/r/20250502-v5_user_cfi_series-v15-7-914966471885@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/pgtable.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h index dba257cc4e2d9b..f21c888f59eb85 100644 --- a/arch/riscv/include/asm/pgtable.h +++ b/arch/riscv/include/asm/pgtable.h @@ -433,6 +433,11 @@ static inline pte_t pte_mkwrite_novma(pte_t pte) return __pte(pte_val(pte) | _PAGE_WRITE); } +static inline pte_t pte_mkwrite_shstk(pte_t pte) +{ + return __pte((pte_val(pte) & ~(_PAGE_LEAF)) | _PAGE_WRITE); +} + /* static inline pte_t pte_mkexec(pte_t pte) */ static inline pte_t pte_mkdirty(pte_t pte) @@ -778,6 +783,11 @@ static inline pmd_t pmd_mkwrite_novma(pmd_t pmd) return pte_pmd(pte_mkwrite_novma(pmd_pte(pmd))); } +static inline pmd_t pmd_mkwrite_shstk(pmd_t pte) +{ + return __pmd((pmd_val(pte) & ~(_PAGE_LEAF)) | _PAGE_WRITE); +} + static inline pmd_t pmd_wrprotect(pmd_t pmd) { return pte_pmd(pte_wrprotect(pmd_pte(pmd))); From 6fd11bcb4db8dc47e850fb16a295f21314759c8c Mon Sep 17 00:00:00 2001 From: Deepak Gupta Date: Fri, 2 May 2025 16:30:39 -0700 Subject: [PATCH 62/91] riscv mmu: teach pte_mkwrite to manufacture shadow stack PTEs pte_mkwrite creates PTEs with WRITE encodings for underlying arch. Underlying arch can have two types of writeable mappings. One that can be written using regular store instructions. Another one that can only be written using specialized store instructions (like shadow stack stores). pte_mkwrite can select write PTE encoding based on VMA range (i.e. VM_SHADOW_STACK) Reviewed-by: Alexandre Ghiti Reviewed-by: Zong Li Signed-off-by: Deepak Gupta Link: https://lore.kernel.org/r/20250502-v5_user_cfi_series-v15-8-914966471885@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/pgtable.h | 7 +++++++ arch/riscv/mm/pgtable.c | 17 +++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h index f21c888f59eb85..60d4821627d29e 100644 --- a/arch/riscv/include/asm/pgtable.h +++ b/arch/riscv/include/asm/pgtable.h @@ -428,6 +428,10 @@ static inline pte_t pte_wrprotect(pte_t pte) /* static inline pte_t pte_mkread(pte_t pte) */ +struct vm_area_struct; +pte_t pte_mkwrite(pte_t pte, struct vm_area_struct *vma); +#define pte_mkwrite pte_mkwrite + static inline pte_t pte_mkwrite_novma(pte_t pte) { return __pte(pte_val(pte) | _PAGE_WRITE); @@ -778,6 +782,9 @@ static inline pmd_t pmd_mkyoung(pmd_t pmd) return pte_pmd(pte_mkyoung(pmd_pte(pmd))); } +pmd_t pmd_mkwrite(pmd_t pmd, struct vm_area_struct *vma); +#define pmd_mkwrite pmd_mkwrite + static inline pmd_t pmd_mkwrite_novma(pmd_t pmd) { return pte_pmd(pte_mkwrite_novma(pmd_pte(pmd))); diff --git a/arch/riscv/mm/pgtable.c b/arch/riscv/mm/pgtable.c index 4ae67324f99233..be5d38546bb372 100644 --- a/arch/riscv/mm/pgtable.c +++ b/arch/riscv/mm/pgtable.c @@ -155,3 +155,20 @@ pmd_t pmdp_collapse_flush(struct vm_area_struct *vma, return pmd; } #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ + +pte_t pte_mkwrite(pte_t pte, struct vm_area_struct *vma) +{ + if (vma->vm_flags & VM_SHADOW_STACK) + return pte_mkwrite_shstk(pte); + + return pte_mkwrite_novma(pte); +} + +pmd_t pmd_mkwrite(pmd_t pmd, struct vm_area_struct *vma) +{ + if (vma->vm_flags & VM_SHADOW_STACK) + return pmd_mkwrite_shstk(pmd); + + return pmd_mkwrite_novma(pmd); +} + From 61b80a47492d286e1ae50e4d41a81cb290d9605e Mon Sep 17 00:00:00 2001 From: Deepak Gupta Date: Fri, 2 May 2025 16:30:40 -0700 Subject: [PATCH 63/91] riscv mmu: write protect and shadow stack `fork` implements copy on write (COW) by making pages readonly in child and parent both. ptep_set_wrprotect and pte_wrprotect clears _PAGE_WRITE in PTE. Assumption is that page is readable and on fault copy on write happens. To implement COW on shadow stack pages, clearing up W bit makes them XWR = 000. This will result in wrong PTE setting which says no perms but V=1 and PFN field pointing to final page. Instead desired behavior is to turn it into a readable page, take an access (load/store) fault on sspush/sspop (shadow stack) and then perform COW on such pages. This way regular reads would still be allowed and not lead to COW maintaining current behavior of COW on non-shadow stack but writeable memory. On the other hand it doesn't interfere with existing COW for read-write memory. Assumption is always that _PAGE_READ must have been set and thus setting _PAGE_READ is harmless. Reviewed-by: Alexandre Ghiti Reviewed-by: Zong Li Signed-off-by: Deepak Gupta Link: https://lore.kernel.org/r/20250502-v5_user_cfi_series-v15-9-914966471885@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/pgtable.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h index 60d4821627d29e..4e3431ccf63480 100644 --- a/arch/riscv/include/asm/pgtable.h +++ b/arch/riscv/include/asm/pgtable.h @@ -423,7 +423,7 @@ static inline int pte_devmap(pte_t pte) static inline pte_t pte_wrprotect(pte_t pte) { - return __pte(pte_val(pte) & ~(_PAGE_WRITE)); + return __pte((pte_val(pte) & ~(_PAGE_WRITE)) | (_PAGE_READ)); } /* static inline pte_t pte_mkread(pte_t pte) */ @@ -624,7 +624,15 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long address, pte_t *ptep) { - atomic_long_and(~(unsigned long)_PAGE_WRITE, (atomic_long_t *)ptep); + pte_t read_pte = READ_ONCE(*ptep); + /* + * ptep_set_wrprotect can be called for shadow stack ranges too. + * shadow stack memory is XWR = 010 and thus clearing _PAGE_WRITE will lead to + * encoding 000b which is wrong encoding with V = 1. This should lead to page fault + * but we dont want this wrong configuration to be set in page tables. + */ + atomic_long_set((atomic_long_t *)ptep, + ((pte_val(read_pte) & ~(unsigned long)_PAGE_WRITE) | _PAGE_READ)); } #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH From 4a39b386ceb8bc3cfeba25f02c651d64b9ca019c Mon Sep 17 00:00:00 2001 From: Deepak Gupta Date: Fri, 2 May 2025 16:30:41 -0700 Subject: [PATCH 64/91] riscv/mm: Implement map_shadow_stack() syscall As discussed extensively in the changelog for the addition of this syscall on x86 ("x86/shstk: Introduce map_shadow_stack syscall") the existing mmap() and madvise() syscalls do not map entirely well onto the security requirements for shadow stack memory since they lead to windows where memory is allocated but not yet protected or stacks which are not properly and safely initialised. Instead a new syscall map_shadow_stack() has been defined which allocates and initialises a shadow stack page. This patch implements this syscall for riscv. riscv doesn't require token to be setup by kernel because user mode can do that by itself. However to provide compatibility and portability with other architectues, user mode can specify token set flag. Reviewed-by: Zong Li Signed-off-by: Deepak Gupta Link: https://lore.kernel.org/r/20250502-v5_user_cfi_series-v15-10-914966471885@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/kernel/Makefile | 1 + arch/riscv/kernel/usercfi.c | 143 ++++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 arch/riscv/kernel/usercfi.c diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index f7480c9c6f8d73..dc43bf87afb247 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -125,3 +125,4 @@ obj-$(CONFIG_ACPI) += acpi.o obj-$(CONFIG_ACPI_NUMA) += acpi_numa.o obj-$(CONFIG_GENERIC_CPU_VULNERABILITIES) += bugs.o +obj-$(CONFIG_RISCV_USER_CFI) += usercfi.o diff --git a/arch/riscv/kernel/usercfi.c b/arch/riscv/kernel/usercfi.c new file mode 100644 index 00000000000000..0b3bbb41490abf --- /dev/null +++ b/arch/riscv/kernel/usercfi.c @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 Rivos, Inc. + * Deepak Gupta + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SHSTK_ENTRY_SIZE sizeof(void *) + +/* + * Writes on shadow stack can either be `sspush` or `ssamoswap`. `sspush` can happen + * implicitly on current shadow stack pointed to by CSR_SSP. `ssamoswap` takes pointer to + * shadow stack. To keep it simple, we plan to use `ssamoswap` to perform writes on shadow + * stack. + */ +static noinline unsigned long amo_user_shstk(unsigned long *addr, unsigned long val) +{ + /* + * Never expect -1 on shadow stack. Expect return addresses and zero + */ + unsigned long swap = -1; + + __enable_user_access(); + asm goto( + ".option push\n" + ".option arch, +zicfiss\n" + "1: ssamoswap.d %[swap], %[val], %[addr]\n" + _ASM_EXTABLE(1b, %l[fault]) + ".option pop\n" + : [swap] "=r" (swap), [addr] "+A" (*addr) + : [val] "r" (val) + : "memory" + : fault + ); + __disable_user_access(); + return swap; +fault: + __disable_user_access(); + return -1; +} + +/* + * Create a restore token on the shadow stack. A token is always XLEN wide + * and aligned to XLEN. + */ +static int create_rstor_token(unsigned long ssp, unsigned long *token_addr) +{ + unsigned long addr; + + /* Token must be aligned */ + if (!IS_ALIGNED(ssp, SHSTK_ENTRY_SIZE)) + return -EINVAL; + + /* On RISC-V we're constructing token to be function of address itself */ + addr = ssp - SHSTK_ENTRY_SIZE; + + if (amo_user_shstk((unsigned long __user *)addr, (unsigned long)ssp) == -1) + return -EFAULT; + + if (token_addr) + *token_addr = addr; + + return 0; +} + +static unsigned long allocate_shadow_stack(unsigned long addr, unsigned long size, + unsigned long token_offset, bool set_tok) +{ + int flags = MAP_ANONYMOUS | MAP_PRIVATE; + struct mm_struct *mm = current->mm; + unsigned long populate, tok_loc = 0; + + if (addr) + flags |= MAP_FIXED_NOREPLACE; + + mmap_write_lock(mm); + addr = do_mmap(NULL, addr, size, PROT_READ, flags, + VM_SHADOW_STACK | VM_WRITE, 0, &populate, NULL); + mmap_write_unlock(mm); + + if (!set_tok || IS_ERR_VALUE(addr)) + goto out; + + if (create_rstor_token(addr + token_offset, &tok_loc)) { + vm_munmap(addr, size); + return -EINVAL; + } + + addr = tok_loc; + +out: + return addr; +} + +SYSCALL_DEFINE3(map_shadow_stack, unsigned long, addr, unsigned long, size, unsigned int, flags) +{ + bool set_tok = flags & SHADOW_STACK_SET_TOKEN; + unsigned long aligned_size = 0; + + if (!cpu_supports_shadow_stack()) + return -EOPNOTSUPP; + + /* Anything other than set token should result in invalid param */ + if (flags & ~SHADOW_STACK_SET_TOKEN) + return -EINVAL; + + /* + * Unlike other architectures, on RISC-V, SSP pointer is held in CSR_SSP and is available + * CSR in all modes. CSR accesses are performed using 12bit index programmed in instruction + * itself. This provides static property on register programming and writes to CSR can't + * be unintentional from programmer's perspective. As long as programmer has guarded areas + * which perform writes to CSR_SSP properly, shadow stack pivoting is not possible. Since + * CSR_SSP is writeable by user mode, it itself can setup a shadow stack token subsequent + * to allocation. Although in order to provide portablity with other architecture (because + * `map_shadow_stack` is arch agnostic syscall), RISC-V will follow expectation of a token + * flag in flags and if provided in flags, setup a token at the base. + */ + + /* If there isn't space for a token */ + if (set_tok && size < SHSTK_ENTRY_SIZE) + return -ENOSPC; + + if (addr && (addr & (PAGE_SIZE - 1))) + return -EINVAL; + + aligned_size = PAGE_ALIGN(size); + if (aligned_size < size) + return -EOVERFLOW; + + return allocate_shadow_stack(addr, aligned_size, size, set_tok); +} From 3db2d5e7829f3d2983782cd4939ff18ae553eb55 Mon Sep 17 00:00:00 2001 From: Deepak Gupta Date: Fri, 2 May 2025 16:30:42 -0700 Subject: [PATCH 65/91] riscv/shstk: If needed allocate a new shadow stack on clone Userspace specifies CLONE_VM to share address space and spawn new thread. `clone` allow userspace to specify a new stack for new thread. However there is no way to specify new shadow stack base address without changing API. This patch allocates a new shadow stack whenever CLONE_VM is given. In case of CLONE_VFORK, parent is suspended until child finishes and thus can child use parent shadow stack. In case of !CLONE_VM, COW kicks in because entire address space is copied from parent to child. `clone3` is extensible and can provide mechanisms using which shadow stack as an input parameter can be provided. This is not settled yet and being extensively discussed on mailing list. Once that's settled, this commit will adapt to that. Reviewed-by: Zong Li Signed-off-by: Deepak Gupta Link: https://lore.kernel.org/r/20250502-v5_user_cfi_series-v15-11-914966471885@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/mmu_context.h | 7 ++ arch/riscv/include/asm/usercfi.h | 25 ++++++ arch/riscv/kernel/process.c | 9 ++ arch/riscv/kernel/usercfi.c | 120 +++++++++++++++++++++++++++ 4 files changed, 161 insertions(+) diff --git a/arch/riscv/include/asm/mmu_context.h b/arch/riscv/include/asm/mmu_context.h index 8c4bc49a3a0f5b..dbf27a78df6c87 100644 --- a/arch/riscv/include/asm/mmu_context.h +++ b/arch/riscv/include/asm/mmu_context.h @@ -48,6 +48,13 @@ static inline unsigned long mm_untag_mask(struct mm_struct *mm) } #endif +#define deactivate_mm deactivate_mm +static inline void deactivate_mm(struct task_struct *tsk, + struct mm_struct *mm) +{ + shstk_release(tsk); +} + #include #endif /* _ASM_RISCV_MMU_CONTEXT_H */ diff --git a/arch/riscv/include/asm/usercfi.h b/arch/riscv/include/asm/usercfi.h index 94b214c295c0dc..0581587490c255 100644 --- a/arch/riscv/include/asm/usercfi.h +++ b/arch/riscv/include/asm/usercfi.h @@ -8,6 +8,9 @@ #ifndef __ASSEMBLY__ #include +struct task_struct; +struct kernel_clone_args; + #ifdef CONFIG_RISCV_USER_CFI struct cfi_state { unsigned long ubcfi_en : 1; /* Enable for backward cfi. */ @@ -16,6 +19,28 @@ struct cfi_state { unsigned long shdw_stk_size; /* size of shadow stack */ }; +unsigned long shstk_alloc_thread_stack(struct task_struct *tsk, + const struct kernel_clone_args *args); +void shstk_release(struct task_struct *tsk); +void set_shstk_base(struct task_struct *task, unsigned long shstk_addr, unsigned long size); +unsigned long get_shstk_base(struct task_struct *task, unsigned long *size); +void set_active_shstk(struct task_struct *task, unsigned long shstk_addr); +bool is_shstk_enabled(struct task_struct *task); + +#else + +#define shstk_alloc_thread_stack(tsk, args) 0 + +#define shstk_release(tsk) + +#define get_shstk_base(task, size) 0UL + +#define set_shstk_base(task, shstk_addr, size) + +#define set_active_shstk(task, shstk_addr) + +#define is_shstk_enabled(task) false + #endif /* CONFIG_RISCV_USER_CFI */ #endif /* __ASSEMBLY__ */ diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index 7c244de7718008..99acb6342a3764 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -29,6 +29,7 @@ #include #include #include +#include #if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_STACKPROTECTOR_PER_TASK) #include @@ -211,6 +212,7 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) unsigned long clone_flags = args->flags; unsigned long usp = args->stack; unsigned long tls = args->tls; + unsigned long ssp = 0; struct pt_regs *childregs = task_pt_regs(p); /* Ensure all threads in this mm have the same pointer masking mode. */ @@ -229,11 +231,18 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) p->thread.s[0] = (unsigned long)args->fn; p->thread.s[1] = (unsigned long)args->fn_arg; } else { + /* allocate new shadow stack if needed. In case of CLONE_VM we have to */ + ssp = shstk_alloc_thread_stack(p, args); + if (IS_ERR_VALUE(ssp)) + return PTR_ERR((void *)ssp); + *childregs = *(current_pt_regs()); /* Turn off status.VS */ riscv_v_vstate_off(childregs); if (usp) /* User fork */ childregs->sp = usp; + /* if needed, set new ssp */ + ssp ? set_active_shstk(p, ssp) : 0; if (clone_flags & CLONE_SETTLS) childregs->tp = tls; childregs->a0 = 0; /* Return value of fork() */ diff --git a/arch/riscv/kernel/usercfi.c b/arch/riscv/kernel/usercfi.c index 0b3bbb41490abf..ec3d78efd6f3cd 100644 --- a/arch/riscv/kernel/usercfi.c +++ b/arch/riscv/kernel/usercfi.c @@ -19,6 +19,41 @@ #define SHSTK_ENTRY_SIZE sizeof(void *) +bool is_shstk_enabled(struct task_struct *task) +{ + return task->thread_info.user_cfi_state.ubcfi_en; +} + +void set_shstk_base(struct task_struct *task, unsigned long shstk_addr, unsigned long size) +{ + task->thread_info.user_cfi_state.shdw_stk_base = shstk_addr; + task->thread_info.user_cfi_state.shdw_stk_size = size; +} + +unsigned long get_shstk_base(struct task_struct *task, unsigned long *size) +{ + if (size) + *size = task->thread_info.user_cfi_state.shdw_stk_size; + return task->thread_info.user_cfi_state.shdw_stk_base; +} + +void set_active_shstk(struct task_struct *task, unsigned long shstk_addr) +{ + task->thread_info.user_cfi_state.user_shdw_stk = shstk_addr; +} + +/* + * If size is 0, then to be compatible with regular stack we want it to be as big as + * regular stack. Else PAGE_ALIGN it and return back + */ +static unsigned long calc_shstk_size(unsigned long size) +{ + if (size) + return PAGE_ALIGN(size); + + return PAGE_ALIGN(min_t(unsigned long long, rlimit(RLIMIT_STACK), SZ_4G)); +} + /* * Writes on shadow stack can either be `sspush` or `ssamoswap`. `sspush` can happen * implicitly on current shadow stack pointed to by CSR_SSP. `ssamoswap` takes pointer to @@ -141,3 +176,88 @@ SYSCALL_DEFINE3(map_shadow_stack, unsigned long, addr, unsigned long, size, unsi return allocate_shadow_stack(addr, aligned_size, size, set_tok); } + +/* + * This gets called during clone/clone3/fork. And is needed to allocate a shadow stack for + * cases where CLONE_VM is specified and thus a different stack is specified by user. We + * thus need a separate shadow stack too. How does separate shadow stack is specified by + * user is still being debated. Once that's settled, remove this part of the comment. + * This function simply returns 0 if shadow stack are not supported or if separate shadow + * stack allocation is not needed (like in case of !CLONE_VM) + */ +unsigned long shstk_alloc_thread_stack(struct task_struct *tsk, + const struct kernel_clone_args *args) +{ + unsigned long addr, size; + + /* If shadow stack is not supported, return 0 */ + if (!cpu_supports_shadow_stack()) + return 0; + + /* + * If shadow stack is not enabled on the new thread, skip any + * switch to a new shadow stack. + */ + if (!is_shstk_enabled(tsk)) + return 0; + + /* + * For CLONE_VFORK the child will share the parents shadow stack. + * Set base = 0 and size = 0, this is special means to track this state + * so the freeing logic run for child knows to leave it alone. + */ + if (args->flags & CLONE_VFORK) { + set_shstk_base(tsk, 0, 0); + return 0; + } + + /* + * For !CLONE_VM the child will use a copy of the parents shadow + * stack. + */ + if (!(args->flags & CLONE_VM)) + return 0; + + /* + * reaching here means, CLONE_VM was specified and thus a separate shadow + * stack is needed for new cloned thread. Note: below allocation is happening + * using current mm. + */ + size = calc_shstk_size(args->stack_size); + addr = allocate_shadow_stack(0, size, 0, false); + if (IS_ERR_VALUE(addr)) + return addr; + + set_shstk_base(tsk, addr, size); + + return addr + size; +} + +void shstk_release(struct task_struct *tsk) +{ + unsigned long base = 0, size = 0; + /* If shadow stack is not supported or not enabled, nothing to release */ + if (!cpu_supports_shadow_stack() || !is_shstk_enabled(tsk)) + return; + + /* + * When fork() with CLONE_VM fails, the child (tsk) already has a + * shadow stack allocated, and exit_thread() calls this function to + * free it. In this case the parent (current) and the child share + * the same mm struct. Move forward only when they're same. + */ + if (!tsk->mm || tsk->mm != current->mm) + return; + + /* + * We know shadow stack is enabled but if base is NULL, then + * this task is not managing its own shadow stack (CLONE_VFORK). So + * skip freeing it. + */ + base = get_shstk_base(tsk, &size); + if (!base) + return; + + vm_munmap(base, size); + set_shstk_base(tsk, 0, 0); +} From 8ebd0a480aadea3dc72c27e8031c2878538f8860 Mon Sep 17 00:00:00 2001 From: Deepak Gupta Date: Fri, 2 May 2025 16:30:43 -0700 Subject: [PATCH 66/91] riscv: Implements arch agnostic shadow stack prctls Implement architecture agnostic prctls() interface for setting and getting shadow stack status. prctls implemented are PR_GET_SHADOW_STACK_STATUS, PR_SET_SHADOW_STACK_STATUS and PR_LOCK_SHADOW_STACK_STATUS. As part of PR_SET_SHADOW_STACK_STATUS/PR_GET_SHADOW_STACK_STATUS, only PR_SHADOW_STACK_ENABLE is implemented because RISCV allows each mode to write to their own shadow stack using `sspush` or `ssamoswap`. PR_LOCK_SHADOW_STACK_STATUS locks current configuration of shadow stack enabling. Reviewed-by: Zong Li Signed-off-by: Deepak Gupta Link: https://lore.kernel.org/r/20250502-v5_user_cfi_series-v15-12-914966471885@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/usercfi.h | 16 +++++ arch/riscv/kernel/process.c | 8 +++ arch/riscv/kernel/usercfi.c | 110 +++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+) diff --git a/arch/riscv/include/asm/usercfi.h b/arch/riscv/include/asm/usercfi.h index 0581587490c255..b530ff5baa6eeb 100644 --- a/arch/riscv/include/asm/usercfi.h +++ b/arch/riscv/include/asm/usercfi.h @@ -7,6 +7,7 @@ #ifndef __ASSEMBLY__ #include +#include struct task_struct; struct kernel_clone_args; @@ -14,6 +15,7 @@ struct kernel_clone_args; #ifdef CONFIG_RISCV_USER_CFI struct cfi_state { unsigned long ubcfi_en : 1; /* Enable for backward cfi. */ + unsigned long ubcfi_locked : 1; unsigned long user_shdw_stk; /* Current user shadow stack pointer */ unsigned long shdw_stk_base; /* Base address of shadow stack */ unsigned long shdw_stk_size; /* size of shadow stack */ @@ -26,6 +28,12 @@ void set_shstk_base(struct task_struct *task, unsigned long shstk_addr, unsigned unsigned long get_shstk_base(struct task_struct *task, unsigned long *size); void set_active_shstk(struct task_struct *task, unsigned long shstk_addr); bool is_shstk_enabled(struct task_struct *task); +bool is_shstk_locked(struct task_struct *task); +bool is_shstk_allocated(struct task_struct *task); +void set_shstk_lock(struct task_struct *task); +void set_shstk_status(struct task_struct *task, bool enable); + +#define PR_SHADOW_STACK_SUPPORTED_STATUS_MASK (PR_SHADOW_STACK_ENABLE) #else @@ -41,6 +49,14 @@ bool is_shstk_enabled(struct task_struct *task); #define is_shstk_enabled(task) false +#define is_shstk_locked(task) false + +#define is_shstk_allocated(task) false + +#define set_shstk_lock(task) + +#define set_shstk_status(task, enable) + #endif /* CONFIG_RISCV_USER_CFI */ #endif /* __ASSEMBLY__ */ diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index 99acb6342a3764..cd11667593fe07 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -153,6 +153,14 @@ void start_thread(struct pt_regs *regs, unsigned long pc, regs->epc = pc; regs->sp = sp; + /* + * clear shadow stack state on exec. + * libc will set it later via prctl. + */ + set_shstk_status(current, false); + set_shstk_base(current, 0, 0); + set_active_shstk(current, 0); + #ifdef CONFIG_64BIT regs->status &= ~SR_UXL; diff --git a/arch/riscv/kernel/usercfi.c b/arch/riscv/kernel/usercfi.c index ec3d78efd6f3cd..08620bdae69645 100644 --- a/arch/riscv/kernel/usercfi.c +++ b/arch/riscv/kernel/usercfi.c @@ -24,6 +24,16 @@ bool is_shstk_enabled(struct task_struct *task) return task->thread_info.user_cfi_state.ubcfi_en; } +bool is_shstk_allocated(struct task_struct *task) +{ + return task->thread_info.user_cfi_state.shdw_stk_base; +} + +bool is_shstk_locked(struct task_struct *task) +{ + return task->thread_info.user_cfi_state.ubcfi_locked; +} + void set_shstk_base(struct task_struct *task, unsigned long shstk_addr, unsigned long size) { task->thread_info.user_cfi_state.shdw_stk_base = shstk_addr; @@ -42,6 +52,26 @@ void set_active_shstk(struct task_struct *task, unsigned long shstk_addr) task->thread_info.user_cfi_state.user_shdw_stk = shstk_addr; } +void set_shstk_status(struct task_struct *task, bool enable) +{ + if (!cpu_supports_shadow_stack()) + return; + + task->thread_info.user_cfi_state.ubcfi_en = enable ? 1 : 0; + + if (enable) + task->thread.envcfg |= ENVCFG_SSE; + else + task->thread.envcfg &= ~ENVCFG_SSE; + + csr_write(CSR_ENVCFG, task->thread.envcfg); +} + +void set_shstk_lock(struct task_struct *task) +{ + task->thread_info.user_cfi_state.ubcfi_locked = 1; +} + /* * If size is 0, then to be compatible with regular stack we want it to be as big as * regular stack. Else PAGE_ALIGN it and return back @@ -261,3 +291,83 @@ void shstk_release(struct task_struct *tsk) vm_munmap(base, size); set_shstk_base(tsk, 0, 0); } + +int arch_get_shadow_stack_status(struct task_struct *t, unsigned long __user *status) +{ + unsigned long bcfi_status = 0; + + if (!cpu_supports_shadow_stack()) + return -EINVAL; + + /* this means shadow stack is enabled on the task */ + bcfi_status |= (is_shstk_enabled(t) ? PR_SHADOW_STACK_ENABLE : 0); + + return copy_to_user(status, &bcfi_status, sizeof(bcfi_status)) ? -EFAULT : 0; +} + +int arch_set_shadow_stack_status(struct task_struct *t, unsigned long status) +{ + unsigned long size = 0, addr = 0; + bool enable_shstk = false; + + if (!cpu_supports_shadow_stack()) + return -EINVAL; + + /* Reject unknown flags */ + if (status & ~PR_SHADOW_STACK_SUPPORTED_STATUS_MASK) + return -EINVAL; + + /* bcfi status is locked and further can't be modified by user */ + if (is_shstk_locked(t)) + return -EINVAL; + + enable_shstk = status & PR_SHADOW_STACK_ENABLE; + /* Request is to enable shadow stack and shadow stack is not enabled already */ + if (enable_shstk && !is_shstk_enabled(t)) { + /* shadow stack was allocated and enable request again + * no need to support such usecase and return EINVAL. + */ + if (is_shstk_allocated(t)) + return -EINVAL; + + size = calc_shstk_size(0); + addr = allocate_shadow_stack(0, size, 0, false); + if (IS_ERR_VALUE(addr)) + return -ENOMEM; + set_shstk_base(t, addr, size); + set_active_shstk(t, addr + size); + } + + /* + * If a request to disable shadow stack happens, let's go ahead and release it + * Although, if CLONE_VFORKed child did this, then in that case we will end up + * not releasing the shadow stack (because it might be needed in parent). Although + * we will disable it for VFORKed child. And if VFORKed child tries to enable again + * then in that case, it'll get entirely new shadow stack because following condition + * are true + * - shadow stack was not enabled for vforked child + * - shadow stack base was anyways pointing to 0 + * This shouldn't be a big issue because we want parent to have availability of shadow + * stack whenever VFORKed child releases resources via exit or exec but at the same + * time we want VFORKed child to break away and establish new shadow stack if it desires + * + */ + if (!enable_shstk) + shstk_release(t); + + set_shstk_status(t, enable_shstk); + return 0; +} + +int arch_lock_shadow_stack_status(struct task_struct *task, + unsigned long arg) +{ + /* If shtstk not supported or not enabled on task, nothing to lock here */ + if (!cpu_supports_shadow_stack() || + !is_shstk_enabled(task) || arg != 0) + return -EINVAL; + + set_shstk_lock(task); + + return 0; +} From 0c62a3b03b1f8f2b7fec87454232b268b44e6765 Mon Sep 17 00:00:00 2001 From: Deepak Gupta Date: Fri, 2 May 2025 16:30:44 -0700 Subject: [PATCH 67/91] prctl: arch-agnostic prctl for indirect branch tracking Three architectures (x86, aarch64, riscv) have support for indirect branch tracking feature in a very similar fashion. On a very high level, indirect branch tracking is a CPU feature where CPU tracks branches which uses memory operand to perform control transfer in program. As part of this tracking on indirect branches, CPU goes in a state where it expects a landing pad instr on target and if not found then CPU raises some fault (architecture dependent) x86 landing pad instr - `ENDBRANCH` arch64 landing pad instr - `BTI` riscv landing instr - `lpad` Given that three major arches have support for indirect branch tracking, This patch makes `prctl` for indirect branch tracking arch agnostic. To allow userspace to enable this feature for itself, following prtcls are defined: - PR_GET_INDIR_BR_LP_STATUS: Gets current configured status for indirect branch tracking. - PR_SET_INDIR_BR_LP_STATUS: Sets a configuration for indirect branch tracking. Following status options are allowed - PR_INDIR_BR_LP_ENABLE: Enables indirect branch tracking on user thread. - PR_INDIR_BR_LP_DISABLE; Disables indirect branch tracking on user thread. - PR_LOCK_INDIR_BR_LP_STATUS: Locks configured status for indirect branch tracking for user thread. Reviewed-by: Mark Brown Reviewed-by: Zong Li Signed-off-by: Deepak Gupta Link: https://lore.kernel.org/r/20250502-v5_user_cfi_series-v15-13-914966471885@rivosinc.com Signed-off-by: Alexandre Ghiti --- include/linux/cpu.h | 4 ++++ include/uapi/linux/prctl.h | 27 +++++++++++++++++++++++++++ kernel/sys.c | 30 ++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+) diff --git a/include/linux/cpu.h b/include/linux/cpu.h index e3049543008b9c..ea8b351b5bc52f 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -204,4 +204,8 @@ static inline bool cpu_mitigations_auto_nosmt(void) } #endif +int arch_get_indir_br_lp_status(struct task_struct *t, unsigned long __user *status); +int arch_set_indir_br_lp_status(struct task_struct *t, unsigned long status); +int arch_lock_indir_br_lp_status(struct task_struct *t, unsigned long status); + #endif /* _LINUX_CPU_H_ */ diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h index 15c18ef4eb11a0..2e09b19317a3c0 100644 --- a/include/uapi/linux/prctl.h +++ b/include/uapi/linux/prctl.h @@ -364,4 +364,31 @@ struct prctl_mm_map { # define PR_TIMER_CREATE_RESTORE_IDS_ON 1 # define PR_TIMER_CREATE_RESTORE_IDS_GET 2 +/* + * Get the current indirect branch tracking configuration for the current + * thread, this will be the value configured via PR_SET_INDIR_BR_LP_STATUS. + */ +#define PR_GET_INDIR_BR_LP_STATUS 78 + +/* + * Set the indirect branch tracking configuration. PR_INDIR_BR_LP_ENABLE will + * enable cpu feature for user thread, to track all indirect branches and ensure + * they land on arch defined landing pad instruction. + * x86 - If enabled, an indirect branch must land on `ENDBRANCH` instruction. + * arch64 - If enabled, an indirect branch must land on `BTI` instruction. + * riscv - If enabled, an indirect branch must land on `lpad` instruction. + * PR_INDIR_BR_LP_DISABLE will disable feature for user thread and indirect + * branches will no more be tracked by cpu to land on arch defined landing pad + * instruction. + */ +#define PR_SET_INDIR_BR_LP_STATUS 79 +# define PR_INDIR_BR_LP_ENABLE (1UL << 0) + +/* + * Prevent further changes to the specified indirect branch tracking + * configuration. All bits may be locked via this call, including + * undefined bits. + */ +#define PR_LOCK_INDIR_BR_LP_STATUS 80 + #endif /* _LINUX_PRCTL_H */ diff --git a/kernel/sys.c b/kernel/sys.c index c434968e9f5dd6..91a1dc093c2ae3 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -2340,6 +2340,21 @@ int __weak arch_lock_shadow_stack_status(struct task_struct *t, unsigned long st return -EINVAL; } +int __weak arch_get_indir_br_lp_status(struct task_struct *t, unsigned long __user *status) +{ + return -EINVAL; +} + +int __weak arch_set_indir_br_lp_status(struct task_struct *t, unsigned long status) +{ + return -EINVAL; +} + +int __weak arch_lock_indir_br_lp_status(struct task_struct *t, unsigned long status) +{ + return -EINVAL; +} + #define PR_IO_FLUSHER (PF_MEMALLOC_NOIO | PF_LOCAL_THROTTLE) #ifdef CONFIG_ANON_VMA_NAME @@ -2820,6 +2835,21 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, return -EINVAL; error = posixtimer_create_prctl(arg2); break; + case PR_GET_INDIR_BR_LP_STATUS: + if (arg3 || arg4 || arg5) + return -EINVAL; + error = arch_get_indir_br_lp_status(me, (unsigned long __user *)arg2); + break; + case PR_SET_INDIR_BR_LP_STATUS: + if (arg3 || arg4 || arg5) + return -EINVAL; + error = arch_set_indir_br_lp_status(me, arg2); + break; + case PR_LOCK_INDIR_BR_LP_STATUS: + if (arg3 || arg4 || arg5) + return -EINVAL; + error = arch_lock_indir_br_lp_status(me, arg2); + break; default: trace_task_prctl_unknown(option, arg2, arg3, arg4, arg5); error = -EINVAL; From 1327cff447946e33e94aede23edee7b407eba334 Mon Sep 17 00:00:00 2001 From: Deepak Gupta Date: Fri, 2 May 2025 16:30:45 -0700 Subject: [PATCH 68/91] riscv: Implements arch agnostic indirect branch tracking prctls prctls implemented are: PR_SET_INDIR_BR_LP_STATUS, PR_GET_INDIR_BR_LP_STATUS and PR_LOCK_INDIR_BR_LP_STATUS Reviewed-by: Zong Li Signed-off-by: Deepak Gupta Link: https://lore.kernel.org/r/20250502-v5_user_cfi_series-v15-14-914966471885@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/usercfi.h | 14 ++++++ arch/riscv/kernel/entry.S | 2 +- arch/riscv/kernel/process.c | 5 ++ arch/riscv/kernel/usercfi.c | 79 ++++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 1 deletion(-) diff --git a/arch/riscv/include/asm/usercfi.h b/arch/riscv/include/asm/usercfi.h index b530ff5baa6eeb..cea7908cdb3af8 100644 --- a/arch/riscv/include/asm/usercfi.h +++ b/arch/riscv/include/asm/usercfi.h @@ -16,6 +16,8 @@ struct kernel_clone_args; struct cfi_state { unsigned long ubcfi_en : 1; /* Enable for backward cfi. */ unsigned long ubcfi_locked : 1; + unsigned long ufcfi_en : 1; /* Enable for forward cfi. Note that ELP goes in sstatus */ + unsigned long ufcfi_locked : 1; unsigned long user_shdw_stk; /* Current user shadow stack pointer */ unsigned long shdw_stk_base; /* Base address of shadow stack */ unsigned long shdw_stk_size; /* size of shadow stack */ @@ -32,6 +34,10 @@ bool is_shstk_locked(struct task_struct *task); bool is_shstk_allocated(struct task_struct *task); void set_shstk_lock(struct task_struct *task); void set_shstk_status(struct task_struct *task, bool enable); +bool is_indir_lp_enabled(struct task_struct *task); +bool is_indir_lp_locked(struct task_struct *task); +void set_indir_lp_status(struct task_struct *task, bool enable); +void set_indir_lp_lock(struct task_struct *task); #define PR_SHADOW_STACK_SUPPORTED_STATUS_MASK (PR_SHADOW_STACK_ENABLE) @@ -57,6 +63,14 @@ void set_shstk_status(struct task_struct *task, bool enable); #define set_shstk_status(task, enable) +#define is_indir_lp_enabled(task) false + +#define is_indir_lp_locked(task) false + +#define set_indir_lp_status(task, enable) + +#define set_indir_lp_lock(task) + #endif /* CONFIG_RISCV_USER_CFI */ #endif /* __ASSEMBLY__ */ diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S index c4bfe2085c411d..978115567bca61 100644 --- a/arch/riscv/kernel/entry.S +++ b/arch/riscv/kernel/entry.S @@ -169,7 +169,7 @@ SYM_CODE_START(handle_exception) * Disable the FPU/Vector to detect illegal usage of floating point * or vector in kernel space. */ - li t0, SR_SUM | SR_FS_VS + li t0, SR_SUM | SR_FS_VS | SR_ELP REG_L s0, TASK_TI_USER_SP(tp) csrrc s1, CSR_STATUS, t0 diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index cd11667593fe07..4587201dd81def 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -160,6 +160,11 @@ void start_thread(struct pt_regs *regs, unsigned long pc, set_shstk_status(current, false); set_shstk_base(current, 0, 0); set_active_shstk(current, 0); + /* + * disable indirect branch tracking on exec. + * libc will enable it later via prctl. + */ + set_indir_lp_status(current, false); #ifdef CONFIG_64BIT regs->status &= ~SR_UXL; diff --git a/arch/riscv/kernel/usercfi.c b/arch/riscv/kernel/usercfi.c index 08620bdae69645..2ebe789caa6be7 100644 --- a/arch/riscv/kernel/usercfi.c +++ b/arch/riscv/kernel/usercfi.c @@ -72,6 +72,35 @@ void set_shstk_lock(struct task_struct *task) task->thread_info.user_cfi_state.ubcfi_locked = 1; } +bool is_indir_lp_enabled(struct task_struct *task) +{ + return task->thread_info.user_cfi_state.ufcfi_en; +} + +bool is_indir_lp_locked(struct task_struct *task) +{ + return task->thread_info.user_cfi_state.ufcfi_locked; +} + +void set_indir_lp_status(struct task_struct *task, bool enable) +{ + if (!cpu_supports_indirect_br_lp_instr()) + return; + + task->thread_info.user_cfi_state.ufcfi_en = enable ? 1 : 0; + + if (enable) + task->thread.envcfg |= ENVCFG_LPE; + else + task->thread.envcfg &= ~ENVCFG_LPE; + + csr_write(CSR_ENVCFG, task->thread.envcfg); +} + +void set_indir_lp_lock(struct task_struct *task) +{ + task->thread_info.user_cfi_state.ufcfi_locked = 1; +} /* * If size is 0, then to be compatible with regular stack we want it to be as big as * regular stack. Else PAGE_ALIGN it and return back @@ -371,3 +400,53 @@ int arch_lock_shadow_stack_status(struct task_struct *task, return 0; } + +int arch_get_indir_br_lp_status(struct task_struct *t, unsigned long __user *status) +{ + unsigned long fcfi_status = 0; + + if (!cpu_supports_indirect_br_lp_instr()) + return -EINVAL; + + /* indirect branch tracking is enabled on the task or not */ + fcfi_status |= (is_indir_lp_enabled(t) ? PR_INDIR_BR_LP_ENABLE : 0); + + return copy_to_user(status, &fcfi_status, sizeof(fcfi_status)) ? -EFAULT : 0; +} + +int arch_set_indir_br_lp_status(struct task_struct *t, unsigned long status) +{ + bool enable_indir_lp = false; + + if (!cpu_supports_indirect_br_lp_instr()) + return -EINVAL; + + /* indirect branch tracking is locked and further can't be modified by user */ + if (is_indir_lp_locked(t)) + return -EINVAL; + + /* Reject unknown flags */ + if (status & ~PR_INDIR_BR_LP_ENABLE) + return -EINVAL; + + enable_indir_lp = (status & PR_INDIR_BR_LP_ENABLE); + set_indir_lp_status(t, enable_indir_lp); + + return 0; +} + +int arch_lock_indir_br_lp_status(struct task_struct *task, + unsigned long arg) +{ + /* + * If indirect branch tracking is not supported or not enabled on task, + * nothing to lock here + */ + if (!cpu_supports_indirect_br_lp_instr() || + !is_indir_lp_enabled(task) || arg != 0) + return -EINVAL; + + set_indir_lp_lock(task); + + return 0; +} From c82bada84dbb6223fcd3bfe925ae6077600ccfd2 Mon Sep 17 00:00:00 2001 From: Deepak Gupta Date: Fri, 2 May 2025 16:30:46 -0700 Subject: [PATCH 69/91] riscv/traps: Introduce software check exception zicfiss / zicfilp introduces a new exception to priv isa `software check exception` with cause code = 18. This patch implements software check exception. Additionally it implements a cfi violation handler which checks for code in xtval. If xtval=2, it means that sw check exception happened because of an indirect branch not landing on 4 byte aligned PC or not landing on `lpad` instruction or label value embedded in `lpad` not matching label value setup in `x7`. If xtval=3, it means that sw check exception happened because of mismatch between link register (x1 or x5) and top of shadow stack (on execution of `sspopchk`). In case of cfi violation, SIGSEGV is raised with code=SEGV_CPERR. SEGV_CPERR was introduced by x86 shadow stack patches. Reviewed-by: Zong Li Signed-off-by: Deepak Gupta Link: https://lore.kernel.org/r/20250502-v5_user_cfi_series-v15-15-914966471885@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/asm-prototypes.h | 1 + arch/riscv/include/asm/entry-common.h | 2 ++ arch/riscv/kernel/entry.S | 3 ++ arch/riscv/kernel/traps.c | 43 +++++++++++++++++++++++++ 4 files changed, 49 insertions(+) diff --git a/arch/riscv/include/asm/asm-prototypes.h b/arch/riscv/include/asm/asm-prototypes.h index cd627ec289f163..5a27cefd7805d6 100644 --- a/arch/riscv/include/asm/asm-prototypes.h +++ b/arch/riscv/include/asm/asm-prototypes.h @@ -51,6 +51,7 @@ DECLARE_DO_ERROR_INFO(do_trap_ecall_u); DECLARE_DO_ERROR_INFO(do_trap_ecall_s); DECLARE_DO_ERROR_INFO(do_trap_ecall_m); DECLARE_DO_ERROR_INFO(do_trap_break); +DECLARE_DO_ERROR_INFO(do_trap_software_check); asmlinkage void handle_bad_stack(struct pt_regs *regs); asmlinkage void do_page_fault(struct pt_regs *regs); diff --git a/arch/riscv/include/asm/entry-common.h b/arch/riscv/include/asm/entry-common.h index b28ccc6cdeea49..34ed149af5d1b4 100644 --- a/arch/riscv/include/asm/entry-common.h +++ b/arch/riscv/include/asm/entry-common.h @@ -40,4 +40,6 @@ static inline int handle_misaligned_store(struct pt_regs *regs) } #endif +bool handle_user_cfi_violation(struct pt_regs *regs); + #endif /* _ASM_RISCV_ENTRY_COMMON_H */ diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S index 978115567bca61..8d25837a938451 100644 --- a/arch/riscv/kernel/entry.S +++ b/arch/riscv/kernel/entry.S @@ -474,6 +474,9 @@ SYM_DATA_START_LOCAL(excp_vect_table) RISCV_PTR do_page_fault /* load page fault */ RISCV_PTR do_trap_unknown RISCV_PTR do_page_fault /* store page fault */ + RISCV_PTR do_trap_unknown /* cause=16 */ + RISCV_PTR do_trap_unknown /* cause=17 */ + RISCV_PTR do_trap_software_check /* cause=18 is sw check exception */ SYM_DATA_END_LABEL(excp_vect_table, SYM_L_LOCAL, excp_vect_table_end) #ifndef CONFIG_MMU diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c index 8ff8e8b36524b7..3f7709f4595aa2 100644 --- a/arch/riscv/kernel/traps.c +++ b/arch/riscv/kernel/traps.c @@ -354,6 +354,49 @@ void do_trap_ecall_u(struct pt_regs *regs) } +#define CFI_TVAL_FCFI_CODE 2 +#define CFI_TVAL_BCFI_CODE 3 +/* handle cfi violations */ +bool handle_user_cfi_violation(struct pt_regs *regs) +{ + bool ret = false; + unsigned long tval = csr_read(CSR_TVAL); + + if ((tval == CFI_TVAL_FCFI_CODE && cpu_supports_indirect_br_lp_instr()) || + (tval == CFI_TVAL_BCFI_CODE && cpu_supports_shadow_stack())) { + do_trap_error(regs, SIGSEGV, SEGV_CPERR, regs->epc, + "Oops - control flow violation"); + ret = true; + } + + return ret; +} + +/* + * software check exception is defined with risc-v cfi spec. Software check + * exception is raised when:- + * a) An indirect branch doesn't land on 4 byte aligned PC or `lpad` + * instruction or `label` value programmed in `lpad` instr doesn't + * match with value setup in `x7`. reported code in `xtval` is 2. + * b) `sspopchk` instruction finds a mismatch between top of shadow stack (ssp) + * and x1/x5. reported code in `xtval` is 3. + */ +asmlinkage __visible __trap_section void do_trap_software_check(struct pt_regs *regs) +{ + if (user_mode(regs)) { + irqentry_enter_from_user_mode(regs); + + /* not a cfi violation, then merge into flow of unknown trap handler */ + if (!handle_user_cfi_violation(regs)) + do_trap_unknown(regs); + + irqentry_exit_to_user_mode(regs); + } else { + /* sw check exception coming from kernel is a bug in kernel */ + die(regs, "Kernel BUG"); + } +} + #ifdef CONFIG_MMU asmlinkage __visible noinstr void do_page_fault(struct pt_regs *regs) { From b5a058e306bc82bd34b01691a08e6554dbdfd896 Mon Sep 17 00:00:00 2001 From: Andy Chiu Date: Fri, 2 May 2025 16:30:47 -0700 Subject: [PATCH 70/91] riscv: signal: abstract header saving for setup_sigcontext The function save_v_state() served two purposes. First, it saved extension context into the signal stack. Then, it constructed the extension header if there was no fault. The second part is independent of the extension itself. As a result, we can pull that part out, so future extensions may reuse it. This patch adds arch_ext_list and makes setup_sigcontext() go through all possible extensions' save() callback. The callback returns a positive value indicating the size of the successfully saved extension. Then the kernel proceeds to construct the header for that extension. The kernel skips an extension if it does not exist, or if the saving fails for some reasons. The error code is propagated out on the later case. This patch does not introduce any functional changes. Signed-off-by: Andy Chiu Link: https://lore.kernel.org/r/20250502-v5_user_cfi_series-v15-16-914966471885@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/vector.h | 3 ++ arch/riscv/kernel/signal.c | 62 ++++++++++++++++++++++----------- 2 files changed, 44 insertions(+), 21 deletions(-) diff --git a/arch/riscv/include/asm/vector.h b/arch/riscv/include/asm/vector.h index e8a83f55be2ba5..05390538ea8a19 100644 --- a/arch/riscv/include/asm/vector.h +++ b/arch/riscv/include/asm/vector.h @@ -407,6 +407,9 @@ static inline bool riscv_v_vstate_ctrl_user_allowed(void) { return false; } #define riscv_v_thread_free(tsk) do {} while (0) #define riscv_v_setup_ctx_cache() do {} while (0) #define riscv_v_thread_alloc(tsk) do {} while (0) +#define get_cpu_vector_context() do {} while (0) +#define put_cpu_vector_context() do {} while (0) +#define riscv_v_vstate_set_restore(task, regs) do {} while (0) #endif /* CONFIG_RISCV_ISA_V */ diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c index 08378fea3a1119..a5e3d54fe54b1e 100644 --- a/arch/riscv/kernel/signal.c +++ b/arch/riscv/kernel/signal.c @@ -68,18 +68,19 @@ static long save_fp_state(struct pt_regs *regs, #define restore_fp_state(task, regs) (0) #endif -#ifdef CONFIG_RISCV_ISA_V - -static long save_v_state(struct pt_regs *regs, void __user **sc_vec) +static long save_v_state(struct pt_regs *regs, void __user *sc_vec) { - struct __riscv_ctx_hdr __user *hdr; struct __sc_riscv_v_state __user *state; void __user *datap; long err; - hdr = *sc_vec; - /* Place state to the user's signal context space after the hdr */ - state = (struct __sc_riscv_v_state __user *)(hdr + 1); + if (!IS_ENABLED(CONFIG_RISCV_ISA_V) || + !((has_vector() || has_xtheadvector()) && + riscv_v_vstate_query(regs))) + return 0; + + /* Place state to the user's signal context spac */ + state = (struct __sc_riscv_v_state __user *)sc_vec; /* Point datap right after the end of __sc_riscv_v_state */ datap = state + 1; @@ -97,15 +98,11 @@ static long save_v_state(struct pt_regs *regs, void __user **sc_vec) err |= __put_user((__force void *)datap, &state->v_state.datap); /* Copy the whole vector content to user space datap. */ err |= __copy_to_user(datap, current->thread.vstate.datap, riscv_v_vsize); - /* Copy magic to the user space after saving all vector conetext */ - err |= __put_user(RISCV_V_MAGIC, &hdr->magic); - err |= __put_user(riscv_v_sc_size, &hdr->size); if (unlikely(err)) - return err; + return -EFAULT; - /* Only progress the sv_vec if everything has done successfully */ - *sc_vec += riscv_v_sc_size; - return 0; + /* Only return the size if everything has done successfully */ + return riscv_v_sc_size; } /* @@ -142,10 +139,20 @@ static long __restore_v_state(struct pt_regs *regs, void __user *sc_vec) */ return copy_from_user(current->thread.vstate.datap, datap, riscv_v_vsize); } -#else -#define save_v_state(task, regs) (0) -#define __restore_v_state(task, regs) (0) -#endif + +struct arch_ext_priv { + __u32 magic; + long (*save)(struct pt_regs *regs, void __user *sc_vec); +}; + +struct arch_ext_priv arch_ext_list[] = { + { + .magic = RISCV_V_MAGIC, + .save = &save_v_state, + }, +}; + +const size_t nr_arch_exts = ARRAY_SIZE(arch_ext_list); static long restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) @@ -270,7 +277,8 @@ static long setup_sigcontext(struct rt_sigframe __user *frame, { struct sigcontext __user *sc = &frame->uc.uc_mcontext; struct __riscv_ctx_hdr __user *sc_ext_ptr = &sc->sc_extdesc.hdr; - long err; + struct arch_ext_priv *arch_ext; + long err, i, ext_size; /* sc_regs is structured the same as the start of pt_regs */ err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs)); @@ -278,8 +286,20 @@ static long setup_sigcontext(struct rt_sigframe __user *frame, if (has_fpu()) err |= save_fp_state(regs, &sc->sc_fpregs); /* Save the vector state. */ - if ((has_vector() || has_xtheadvector()) && riscv_v_vstate_query(regs)) - err |= save_v_state(regs, (void __user **)&sc_ext_ptr); + for (i = 0; i < nr_arch_exts; i++) { + arch_ext = &arch_ext_list[i]; + if (!arch_ext->save) + continue; + + ext_size = arch_ext->save(regs, sc_ext_ptr + 1); + if (ext_size <= 0) { + err |= ext_size; + } else { + err |= __put_user(arch_ext->magic, &sc_ext_ptr->magic); + err |= __put_user(ext_size, &sc_ext_ptr->size); + sc_ext_ptr = (void *)sc_ext_ptr + ext_size; + } + } /* Write zero to fp-reserved space and check it on restore_sigcontext */ err |= __put_user(0, &sc->sc_extdesc.reserved); /* And put END __riscv_ctx_hdr at the end. */ From a4fa9c9ee390251d88ac2f1ef53ad1e0b10a9ae5 Mon Sep 17 00:00:00 2001 From: Deepak Gupta Date: Fri, 2 May 2025 16:30:48 -0700 Subject: [PATCH 71/91] riscv/signal: save and restore of shadow stack for signal Save shadow stack pointer in sigcontext structure while delivering signal. Restore shadow stack pointer from sigcontext on sigreturn. As part of save operation, kernel uses `ssamoswap` to save snapshot of current shadow stack on shadow stack itself (can be called as a save token). During restore on sigreturn, kernel retrieves token from top of shadow stack and validates it. This allows that user mode can't arbitrary pivot to any shadow stack address without having a token and thus provide strong security assurance between signaly delivery and sigreturn window. Use ABI compatible way of saving/restoring shadow stack pointer into signal stack. This follows what Vector extension, where extra registers are placed in a form of extension header + extension body in the stack. The extension header indicates the size of the extra architectural states plus the size of header itself, and a magic identifier of the extension. Then, the extensions body contains the new architectural states in the form defined by uapi. Signed-off-by: Andy Chiu Signed-off-by: Deepak Gupta Link: https://lore.kernel.org/r/20250502-v5_user_cfi_series-v15-17-914966471885@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/usercfi.h | 10 +++ arch/riscv/include/uapi/asm/ptrace.h | 4 ++ arch/riscv/include/uapi/asm/sigcontext.h | 1 + arch/riscv/kernel/signal.c | 86 ++++++++++++++++++++++++ arch/riscv/kernel/usercfi.c | 56 +++++++++++++++ 5 files changed, 157 insertions(+) diff --git a/arch/riscv/include/asm/usercfi.h b/arch/riscv/include/asm/usercfi.h index cea7908cdb3af8..68da5b7b79fd16 100644 --- a/arch/riscv/include/asm/usercfi.h +++ b/arch/riscv/include/asm/usercfi.h @@ -8,6 +8,7 @@ #ifndef __ASSEMBLY__ #include #include +#include struct task_struct; struct kernel_clone_args; @@ -34,6 +35,9 @@ bool is_shstk_locked(struct task_struct *task); bool is_shstk_allocated(struct task_struct *task); void set_shstk_lock(struct task_struct *task); void set_shstk_status(struct task_struct *task, bool enable); +unsigned long get_active_shstk(struct task_struct *task); +int restore_user_shstk(struct task_struct *tsk, unsigned long shstk_ptr); +int save_user_shstk(struct task_struct *tsk, unsigned long *saved_shstk_ptr); bool is_indir_lp_enabled(struct task_struct *task); bool is_indir_lp_locked(struct task_struct *task); void set_indir_lp_status(struct task_struct *task, bool enable); @@ -71,6 +75,12 @@ void set_indir_lp_lock(struct task_struct *task); #define set_indir_lp_lock(task) +#define restore_user_shstk(tsk, shstk_ptr) -EINVAL + +#define save_user_shstk(tsk, saved_shstk_ptr) -EINVAL + +#define get_active_shstk(task) 0UL + #endif /* CONFIG_RISCV_USER_CFI */ #endif /* __ASSEMBLY__ */ diff --git a/arch/riscv/include/uapi/asm/ptrace.h b/arch/riscv/include/uapi/asm/ptrace.h index a38268b19c3d3d..659ea3af56802a 100644 --- a/arch/riscv/include/uapi/asm/ptrace.h +++ b/arch/riscv/include/uapi/asm/ptrace.h @@ -127,6 +127,10 @@ struct __riscv_v_regset_state { */ #define RISCV_MAX_VLENB (8192) +struct __sc_riscv_cfi_state { + unsigned long ss_ptr; /* shadow stack pointer */ +}; + #endif /* __ASSEMBLY__ */ #endif /* _UAPI_ASM_RISCV_PTRACE_H */ diff --git a/arch/riscv/include/uapi/asm/sigcontext.h b/arch/riscv/include/uapi/asm/sigcontext.h index cd4f175dc83763..f37e4beffe036a 100644 --- a/arch/riscv/include/uapi/asm/sigcontext.h +++ b/arch/riscv/include/uapi/asm/sigcontext.h @@ -10,6 +10,7 @@ /* The Magic number for signal context frame header. */ #define RISCV_V_MAGIC 0x53465457 +#define RISCV_ZICFISS_MAGIC 0x9487 #define END_MAGIC 0x0 /* The size of END signal context header. */ diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c index a5e3d54fe54b1e..1bcda11e068016 100644 --- a/arch/riscv/kernel/signal.c +++ b/arch/riscv/kernel/signal.c @@ -22,11 +22,13 @@ #include #include #include +#include unsigned long signal_minsigstksz __ro_after_init; extern u32 __user_rt_sigreturn[2]; static size_t riscv_v_sc_size __ro_after_init; +static size_t riscv_zicfiss_sc_size __ro_after_init; #define DEBUG_SIG 0 @@ -140,6 +142,62 @@ static long __restore_v_state(struct pt_regs *regs, void __user *sc_vec) return copy_from_user(current->thread.vstate.datap, datap, riscv_v_vsize); } +static long save_cfiss_state(struct pt_regs *regs, void __user *sc_cfi) +{ + struct __sc_riscv_cfi_state __user *state = sc_cfi; + unsigned long ss_ptr = 0; + long err = 0; + + if (!is_shstk_enabled(current)) + return 0; + + /* + * Save a pointer to shadow stack itself on shadow stack as a form of token. + * A token on shadow gives following properties + * - Safe save and restore for shadow stack switching. Any save of shadow stack + * must have had saved a token on shadow stack. Similarly any restore of shadow + * stack must check the token before restore. Since writing to shadow stack with + * address of shadow stack itself is not easily allowed. A restore without a save + * is quite difficult for an attacker to perform. + * - A natural break. A token in shadow stack provides a natural break in shadow stack + * So a single linear range can be bucketed into different shadow stack segments. Any + * sspopchk will detect the condition and fault to kernel as sw check exception. + */ + err |= save_user_shstk(current, &ss_ptr); + err |= __put_user(ss_ptr, &state->ss_ptr); + if (unlikely(err)) + return -EFAULT; + + return riscv_zicfiss_sc_size; +} + +static long __restore_cfiss_state(struct pt_regs *regs, void __user *sc_cfi) +{ + struct __sc_riscv_cfi_state __user *state = sc_cfi; + unsigned long ss_ptr = 0; + long err; + + /* + * Restore shadow stack as a form of token stored on shadow stack itself as a safe + * way to restore. + * A token on shadow gives following properties + * - Safe save and restore for shadow stack switching. Any save of shadow stack + * must have had saved a token on shadow stack. Similarly any restore of shadow + * stack must check the token before restore. Since writing to shadow stack with + * address of shadow stack itself is not easily allowed. A restore without a save + * is quite difficult for an attacker to perform. + * - A natural break. A token in shadow stack provides a natural break in shadow stack + * So a single linear range can be bucketed into different shadow stack segments. + * sspopchk will detect the condition and fault to kernel as sw check exception. + */ + err = __copy_from_user(&ss_ptr, &state->ss_ptr, sizeof(unsigned long)); + + if (unlikely(err)) + return err; + + return restore_user_shstk(current, ss_ptr); +} + struct arch_ext_priv { __u32 magic; long (*save)(struct pt_regs *regs, void __user *sc_vec); @@ -150,6 +208,10 @@ struct arch_ext_priv arch_ext_list[] = { .magic = RISCV_V_MAGIC, .save = &save_v_state, }, + { + .magic = RISCV_ZICFISS_MAGIC, + .save = &save_cfiss_state, + }, }; const size_t nr_arch_exts = ARRAY_SIZE(arch_ext_list); @@ -202,6 +264,12 @@ static long restore_sigcontext(struct pt_regs *regs, err = __restore_v_state(regs, sc_ext_ptr); break; + case RISCV_ZICFISS_MAGIC: + if (!is_shstk_enabled(current) || size != riscv_zicfiss_sc_size) + return -EINVAL; + + err = __restore_cfiss_state(regs, sc_ext_ptr); + break; default: return -EINVAL; } @@ -223,6 +291,16 @@ static size_t get_rt_frame_size(bool cal_all) total_context_size += riscv_v_sc_size; } + if (is_shstk_enabled(current)) + total_context_size += riscv_zicfiss_sc_size; + + /* + * Preserved a __riscv_ctx_hdr for END signal context header if an + * extension uses __riscv_extra_ext_header + */ + if (total_context_size) + total_context_size += sizeof(struct __riscv_ctx_hdr); + frame_size += total_context_size; frame_size = round_up(frame_size, 16); @@ -359,6 +437,11 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, #ifdef CONFIG_MMU regs->ra = (unsigned long)VDSO_SYMBOL( current->mm->context.vdso, rt_sigreturn); + + /* if bcfi is enabled x1 (ra) and x5 (t0) must match. not sure if we need this? */ + if (is_shstk_enabled(current)) + regs->t0 = regs->ra; + #else /* * For the nommu case we don't have a VDSO. Instead we push two @@ -487,6 +570,9 @@ void __init init_rt_signal_env(void) { riscv_v_sc_size = sizeof(struct __riscv_ctx_hdr) + sizeof(struct __sc_riscv_v_state) + riscv_v_vsize; + + riscv_zicfiss_sc_size = sizeof(struct __riscv_ctx_hdr) + + sizeof(struct __sc_riscv_cfi_state); /* * Determine the stack space required for guaranteed signal delivery. * The signal_minsigstksz will be populated into the AT_MINSIGSTKSZ entry diff --git a/arch/riscv/kernel/usercfi.c b/arch/riscv/kernel/usercfi.c index 2ebe789caa6be7..8bc3e1e3f7122e 100644 --- a/arch/riscv/kernel/usercfi.c +++ b/arch/riscv/kernel/usercfi.c @@ -52,6 +52,11 @@ void set_active_shstk(struct task_struct *task, unsigned long shstk_addr) task->thread_info.user_cfi_state.user_shdw_stk = shstk_addr; } +unsigned long get_active_shstk(struct task_struct *task) +{ + return task->thread_info.user_cfi_state.user_shdw_stk; +} + void set_shstk_status(struct task_struct *task, bool enable) { if (!cpu_supports_shadow_stack()) @@ -169,6 +174,57 @@ static int create_rstor_token(unsigned long ssp, unsigned long *token_addr) return 0; } +/* + * Save user shadow stack pointer on shadow stack itself and return pointer to saved location + * returns -EFAULT if operation was unsuccessful + */ +int save_user_shstk(struct task_struct *tsk, unsigned long *saved_shstk_ptr) +{ + unsigned long ss_ptr = 0; + unsigned long token_loc = 0; + int ret = 0; + + if (saved_shstk_ptr == NULL) + return -EINVAL; + + ss_ptr = get_active_shstk(tsk); + ret = create_rstor_token(ss_ptr, &token_loc); + + if (!ret) { + *saved_shstk_ptr = token_loc; + set_active_shstk(tsk, token_loc); + } + + return ret; +} + +/* + * Restores user shadow stack pointer from token on shadow stack for task `tsk` + * returns -EFAULT if operation was unsuccessful + */ +int restore_user_shstk(struct task_struct *tsk, unsigned long shstk_ptr) +{ + unsigned long token = 0; + + token = amo_user_shstk((unsigned long __user *)shstk_ptr, 0); + + if (token == -1) + return -EFAULT; + + /* invalid token, return EINVAL */ + if ((token - shstk_ptr) != SHSTK_ENTRY_SIZE) { + pr_info_ratelimited( + "%s[%d]: bad restore token in %s: pc=%p sp=%p, token=%p, shstk_ptr=%p\n", + tsk->comm, task_pid_nr(tsk), __func__, (void *)(task_pt_regs(tsk)->epc), + (void *)(task_pt_regs(tsk)->sp), (void *)token, (void *)shstk_ptr); + return -EINVAL; + } + + /* all checks passed, set active shstk and return success */ + set_active_shstk(tsk, token); + return 0; +} + static unsigned long allocate_shadow_stack(unsigned long addr, unsigned long size, unsigned long token_offset, bool set_tok) { From 71117d7447c253d9357b999dc573b340f645f26f Mon Sep 17 00:00:00 2001 From: Deepak Gupta Date: Fri, 2 May 2025 16:30:49 -0700 Subject: [PATCH 72/91] riscv/kernel: update __show_regs to print shadow stack register Updating __show_regs to print captured shadow stack pointer as well. On tasks where shadow stack is disabled, it'll simply print 0. Signed-off-by: Deepak Gupta Reviewed-by: Alexandre Ghiti Link: https://lore.kernel.org/r/20250502-v5_user_cfi_series-v15-18-914966471885@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/kernel/process.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index 4587201dd81def..6bb53ce72ed54f 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -90,8 +90,8 @@ void __show_regs(struct pt_regs *regs) regs->s8, regs->s9, regs->s10); pr_cont(" s11: " REG_FMT " t3 : " REG_FMT " t4 : " REG_FMT "\n", regs->s11, regs->t3, regs->t4); - pr_cont(" t5 : " REG_FMT " t6 : " REG_FMT "\n", - regs->t5, regs->t6); + pr_cont(" t5 : " REG_FMT " t6 : " REG_FMT " ssp : " REG_FMT "\n", + regs->t5, regs->t6, get_active_shstk(current)); pr_cont("status: " REG_FMT " badaddr: " REG_FMT " cause: " REG_FMT "\n", regs->status, regs->badaddr, regs->cause); From 65d9bb2f54ccd4c4fd19d47c6ebc5461c4e17bd2 Mon Sep 17 00:00:00 2001 From: Deepak Gupta Date: Fri, 2 May 2025 16:30:50 -0700 Subject: [PATCH 73/91] riscv/ptrace: riscv cfi status and state via ptrace and in core files Expose a new register type NT_RISCV_USER_CFI for risc-v cfi status and state. Intentionally both landing pad and shadow stack status and state are rolled into cfi state. Creating two different NT_RISCV_USER_XXX would not be useful and wastage of a note type. Enabling, disabling and locking of feature is not allowed via ptrace set interface. However setting `elp` state or setting shadow stack pointer are allowed via ptrace set interface . It is expected `gdb` might have use to fixup `elp` state or `shadow stack` pointer. Signed-off-by: Deepak Gupta Link: https://lore.kernel.org/r/20250502-v5_user_cfi_series-v15-19-914966471885@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/uapi/asm/ptrace.h | 30 +++++++++ arch/riscv/kernel/ptrace.c | 95 ++++++++++++++++++++++++++++ include/uapi/linux/elf.h | 2 + 3 files changed, 127 insertions(+) diff --git a/arch/riscv/include/uapi/asm/ptrace.h b/arch/riscv/include/uapi/asm/ptrace.h index 659ea3af56802a..42c3fc8bd5139f 100644 --- a/arch/riscv/include/uapi/asm/ptrace.h +++ b/arch/riscv/include/uapi/asm/ptrace.h @@ -131,6 +131,36 @@ struct __sc_riscv_cfi_state { unsigned long ss_ptr; /* shadow stack pointer */ }; +#define PTRACE_CFI_LP_EN_BIT 0 +#define PTRACE_CFI_LP_LOCK_BIT 1 +#define PTRACE_CFI_ELP_BIT 2 +#define PTRACE_CFI_SS_EN_BIT 3 +#define PTRACE_CFI_SS_LOCK_BIT 4 +#define PTRACE_CFI_SS_PTR_BIT 5 + +#define PTRACE_CFI_LP_EN_STATE (1 << PTRACE_CFI_LP_EN_BIT) +#define PTRACE_CFI_LP_LOCK_STATE (1 << PTRACE_CFI_LP_LOCK_BIT) +#define PTRACE_CFI_ELP_STATE (1 << PTRACE_CFI_ELP_BIT) +#define PTRACE_CFI_SS_EN_STATE (1 << PTRACE_CFI_SS_EN_BIT) +#define PTRACE_CFI_SS_LOCK_STATE (1 << PTRACE_CFI_SS_LOCK_BIT) +#define PTRACE_CFI_SS_PTR_STATE (1 << PTRACE_CFI_SS_PTR_BIT) + +#define PRACE_CFI_STATE_INVALID_MASK ~(PTRACE_CFI_LP_EN_STATE | \ + PTRACE_CFI_LP_LOCK_STATE | \ + PTRACE_CFI_ELP_STATE | \ + PTRACE_CFI_SS_EN_STATE | \ + PTRACE_CFI_SS_LOCK_STATE | \ + PTRACE_CFI_SS_PTR_STATE) + +struct __cfi_status { + __u64 cfi_state; +}; + +struct user_cfi_state { + struct __cfi_status cfi_status; + __u64 shstk_ptr; +}; + #endif /* __ASSEMBLY__ */ #endif /* _UAPI_ASM_RISCV_PTRACE_H */ diff --git a/arch/riscv/kernel/ptrace.c b/arch/riscv/kernel/ptrace.c index ea67e9fb7a5836..933a3d26d33ca5 100644 --- a/arch/riscv/kernel/ptrace.c +++ b/arch/riscv/kernel/ptrace.c @@ -19,6 +19,7 @@ #include #include #include +#include enum riscv_regset { REGSET_X, @@ -31,6 +32,9 @@ enum riscv_regset { #ifdef CONFIG_RISCV_ISA_SUPM REGSET_TAGGED_ADDR_CTRL, #endif +#ifdef CONFIG_RISCV_USER_CFI + REGSET_CFI, +#endif }; static int riscv_gpr_get(struct task_struct *target, @@ -184,6 +188,87 @@ static int tagged_addr_ctrl_set(struct task_struct *target, } #endif +#ifdef CONFIG_RISCV_USER_CFI +static int riscv_cfi_get(struct task_struct *target, + const struct user_regset *regset, + struct membuf to) +{ + struct user_cfi_state user_cfi; + struct pt_regs *regs; + + memset(&user_cfi, 0, sizeof(user_cfi)); + regs = task_pt_regs(target); + + if (is_indir_lp_enabled(target)) { + user_cfi.cfi_status.cfi_state |= PTRACE_CFI_LP_EN_STATE; + user_cfi.cfi_status.cfi_state |= is_indir_lp_locked(target) ? + PTRACE_CFI_LP_LOCK_STATE : 0; + user_cfi.cfi_status.cfi_state |= (regs->status & SR_ELP) ? + PTRACE_CFI_ELP_STATE : 0; + } + + if (is_shstk_enabled(target)) { + user_cfi.cfi_status.cfi_state |= (PTRACE_CFI_SS_EN_STATE | + PTRACE_CFI_SS_PTR_STATE); + user_cfi.cfi_status.cfi_state |= is_shstk_locked(target) ? + PTRACE_CFI_SS_LOCK_STATE : 0; + user_cfi.shstk_ptr = get_active_shstk(target); + } + + return membuf_write(&to, &user_cfi, sizeof(user_cfi)); +} + +/* + * Does it make sense to allowing enable / disable of cfi via ptrace? + * Not allowing enable / disable / locking control via ptrace for now. + * Setting shadow stack pointer is allowed. GDB might use it to unwind or + * some other fixup. Similarly gdb might want to suppress elp and may want + * to reset elp state. + */ +static int riscv_cfi_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + int ret; + struct user_cfi_state user_cfi; + struct pt_regs *regs; + + regs = task_pt_regs(target); + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &user_cfi, 0, -1); + if (ret) + return ret; + + /* + * Not allowing enabling or locking shadow stack or landing pad + * There is no disabling of shadow stack or landing pad via ptrace + * rsvd field should be set to zero so that if those fields are needed in future + */ + if ((user_cfi.cfi_status.cfi_state & + (PTRACE_CFI_LP_EN_STATE | PTRACE_CFI_LP_LOCK_STATE | + PTRACE_CFI_SS_EN_STATE | PTRACE_CFI_SS_LOCK_STATE)) || + (user_cfi.cfi_status.cfi_state & PRACE_CFI_STATE_INVALID_MASK)) + return -EINVAL; + + /* If lpad is enabled on target and ptrace requests to set / clear elp, do that */ + if (is_indir_lp_enabled(target)) { + if (user_cfi.cfi_status.cfi_state & + PTRACE_CFI_ELP_STATE) /* set elp state */ + regs->status |= SR_ELP; + else + regs->status &= ~SR_ELP; /* clear elp state */ + } + + /* If shadow stack enabled on target, set new shadow stack pointer */ + if (is_shstk_enabled(target) && + (user_cfi.cfi_status.cfi_state & PTRACE_CFI_SS_PTR_STATE)) + set_active_shstk(target, user_cfi.shstk_ptr); + + return 0; +} +#endif + static const struct user_regset riscv_user_regset[] = { [REGSET_X] = { .core_note_type = NT_PRSTATUS, @@ -224,6 +309,16 @@ static const struct user_regset riscv_user_regset[] = { .set = tagged_addr_ctrl_set, }, #endif +#ifdef CONFIG_RISCV_USER_CFI + [REGSET_CFI] = { + .core_note_type = NT_RISCV_USER_CFI, + .align = sizeof(__u64), + .n = sizeof(struct user_cfi_state) / sizeof(__u64), + .size = sizeof(__u64), + .regset_get = riscv_cfi_get, + .set = riscv_cfi_set, + }, +#endif }; static const struct user_regset_view riscv_user_native_view = { diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h index 819ded2d39de2b..ee30dcd80901fc 100644 --- a/include/uapi/linux/elf.h +++ b/include/uapi/linux/elf.h @@ -545,6 +545,8 @@ typedef struct elf64_shdr { #define NT_RISCV_VECTOR 0x901 /* RISC-V vector registers */ #define NN_RISCV_TAGGED_ADDR_CTRL "LINUX" #define NT_RISCV_TAGGED_ADDR_CTRL 0x902 /* RISC-V tagged address control (prctl()) */ +#define NN_RISCV_USER_CFI "LINUX" +#define NT_RISCV_USER_CFI 0x903 /* RISC-V shadow stack state */ #define NN_LOONGARCH_CPUCFG "LINUX" #define NT_LOONGARCH_CPUCFG 0xa00 /* LoongArch CPU config registers */ #define NN_LOONGARCH_CSR "LINUX" From c6fb2eb0ed0362ae9fe37f3757004f8a8cd74b09 Mon Sep 17 00:00:00 2001 From: Deepak Gupta Date: Fri, 2 May 2025 16:30:51 -0700 Subject: [PATCH 74/91] riscv/hwprobe: zicfilp / zicfiss enumeration in hwprobe Adding enumeration of zicfilp and zicfiss extensions in hwprobe syscall. Reviewed-by: Zong Li Signed-off-by: Deepak Gupta Link: https://lore.kernel.org/r/20250502-v5_user_cfi_series-v15-20-914966471885@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/uapi/asm/hwprobe.h | 2 ++ arch/riscv/kernel/sys_hwprobe.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h index 3c2fce939673b9..9bc96881dc9bc2 100644 --- a/arch/riscv/include/uapi/asm/hwprobe.h +++ b/arch/riscv/include/uapi/asm/hwprobe.h @@ -81,6 +81,8 @@ struct riscv_hwprobe { #define RISCV_HWPROBE_EXT_ZICBOM (1ULL << 55) #define RISCV_HWPROBE_EXT_ZAAMO (1ULL << 56) #define RISCV_HWPROBE_EXT_ZALRSC (1ULL << 57) +#define RISCV_HWPROBE_EXT_ZICFILP (1ULL << 58) +#define RISCV_HWPROBE_EXT_ZICFISS (1ULL << 59) #define RISCV_HWPROBE_KEY_CPUPERF_0 5 #define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0) #define RISCV_HWPROBE_MISALIGNED_EMULATED (1 << 0) diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c index 249aec8594a92a..c86cba0e450640 100644 --- a/arch/riscv/kernel/sys_hwprobe.c +++ b/arch/riscv/kernel/sys_hwprobe.c @@ -111,6 +111,8 @@ static void hwprobe_isa_ext0(struct riscv_hwprobe *pair, EXT_KEY(ZCMOP); EXT_KEY(ZICBOM); EXT_KEY(ZICBOZ); + EXT_KEY(ZICFILP); + EXT_KEY(ZICFISS); EXT_KEY(ZICNTR); EXT_KEY(ZICOND); EXT_KEY(ZIHINTNTL); From 3190a7df0ad5e0e5c1bf2d4c707a2973727e9ce7 Mon Sep 17 00:00:00 2001 From: Deepak Gupta Date: Fri, 2 May 2025 16:30:52 -0700 Subject: [PATCH 75/91] riscv: kernel command line option to opt out of user cfi This commit adds a kernel command line option using which user cfi can be disabled. User backward cfi and forward cfi can be enabled independently. Kernel command line parameter "riscv_nousercfi" can take below values: - "all" : Disable forward and backward cfi both. - "bcfi" : Disable backward cfi. - "fcfi" : Disable forward cfi Signed-off-by: Deepak Gupta Link: https://lore.kernel.org/r/20250502-v5_user_cfi_series-v15-21-914966471885@rivosinc.com Signed-off-by: Alexandre Ghiti --- .../admin-guide/kernel-parameters.txt | 8 +++ arch/riscv/include/asm/usercfi.h | 7 +++ arch/riscv/kernel/usercfi.c | 59 +++++++++++++++---- 3 files changed, 63 insertions(+), 11 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index d9fd26b95b3409..e5757b5128a351 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -6234,6 +6234,14 @@ replacement properties are not found. See the Kconfig entry for RISCV_ISA_FALLBACK. + riscv_nousercfi= + all Disable user cfi ABI to userspace even if cpu extension + are available. + bcfi Disable user backward cfi ABI to userspace even if + shadow stack extension is available. + fcfi Disable user forward cfi ABI to userspace even if landing + pad extension is available. + ro [KNL] Mount root device read-only on boot rodata= [KNL,EARLY] diff --git a/arch/riscv/include/asm/usercfi.h b/arch/riscv/include/asm/usercfi.h index 68da5b7b79fd16..6867ba6bd5a5a5 100644 --- a/arch/riscv/include/asm/usercfi.h +++ b/arch/riscv/include/asm/usercfi.h @@ -5,6 +5,10 @@ #ifndef _ASM_RISCV_USERCFI_H #define _ASM_RISCV_USERCFI_H +#define CMDLINE_DISABLE_RISCV_USERCFI_FCFI 1 +#define CMDLINE_DISABLE_RISCV_USERCFI_BCFI 2 +#define CMDLINE_DISABLE_RISCV_USERCFI 3 + #ifndef __ASSEMBLY__ #include #include @@ -83,6 +87,9 @@ void set_indir_lp_lock(struct task_struct *task); #endif /* CONFIG_RISCV_USER_CFI */ +bool is_user_shstk_enabled(void); +bool is_user_lpad_enabled(void); + #endif /* __ASSEMBLY__ */ #endif /* _ASM_RISCV_USERCFI_H */ diff --git a/arch/riscv/kernel/usercfi.c b/arch/riscv/kernel/usercfi.c index 8bc3e1e3f7122e..5ef357f43ad789 100644 --- a/arch/riscv/kernel/usercfi.c +++ b/arch/riscv/kernel/usercfi.c @@ -17,6 +17,8 @@ #include #include +unsigned int riscv_nousercfi; + #define SHSTK_ENTRY_SIZE sizeof(void *) bool is_shstk_enabled(struct task_struct *task) @@ -59,7 +61,7 @@ unsigned long get_active_shstk(struct task_struct *task) void set_shstk_status(struct task_struct *task, bool enable) { - if (!cpu_supports_shadow_stack()) + if (!is_user_shstk_enabled()) return; task->thread_info.user_cfi_state.ubcfi_en = enable ? 1 : 0; @@ -89,7 +91,7 @@ bool is_indir_lp_locked(struct task_struct *task) void set_indir_lp_status(struct task_struct *task, bool enable) { - if (!cpu_supports_indirect_br_lp_instr()) + if (!is_user_lpad_enabled()) return; task->thread_info.user_cfi_state.ufcfi_en = enable ? 1 : 0; @@ -259,7 +261,7 @@ SYSCALL_DEFINE3(map_shadow_stack, unsigned long, addr, unsigned long, size, unsi bool set_tok = flags & SHADOW_STACK_SET_TOKEN; unsigned long aligned_size = 0; - if (!cpu_supports_shadow_stack()) + if (!is_user_shstk_enabled()) return -EOPNOTSUPP; /* Anything other than set token should result in invalid param */ @@ -306,7 +308,7 @@ unsigned long shstk_alloc_thread_stack(struct task_struct *tsk, unsigned long addr, size; /* If shadow stack is not supported, return 0 */ - if (!cpu_supports_shadow_stack()) + if (!is_user_shstk_enabled()) return 0; /* @@ -352,7 +354,7 @@ void shstk_release(struct task_struct *tsk) { unsigned long base = 0, size = 0; /* If shadow stack is not supported or not enabled, nothing to release */ - if (!cpu_supports_shadow_stack() || !is_shstk_enabled(tsk)) + if (!is_user_shstk_enabled() || !is_shstk_enabled(tsk)) return; /* @@ -381,7 +383,7 @@ int arch_get_shadow_stack_status(struct task_struct *t, unsigned long __user *st { unsigned long bcfi_status = 0; - if (!cpu_supports_shadow_stack()) + if (!is_user_shstk_enabled()) return -EINVAL; /* this means shadow stack is enabled on the task */ @@ -395,7 +397,7 @@ int arch_set_shadow_stack_status(struct task_struct *t, unsigned long status) unsigned long size = 0, addr = 0; bool enable_shstk = false; - if (!cpu_supports_shadow_stack()) + if (!is_user_shstk_enabled()) return -EINVAL; /* Reject unknown flags */ @@ -448,7 +450,7 @@ int arch_lock_shadow_stack_status(struct task_struct *task, unsigned long arg) { /* If shtstk not supported or not enabled on task, nothing to lock here */ - if (!cpu_supports_shadow_stack() || + if (!is_user_shstk_enabled() || !is_shstk_enabled(task) || arg != 0) return -EINVAL; @@ -461,7 +463,7 @@ int arch_get_indir_br_lp_status(struct task_struct *t, unsigned long __user *sta { unsigned long fcfi_status = 0; - if (!cpu_supports_indirect_br_lp_instr()) + if (!is_user_lpad_enabled()) return -EINVAL; /* indirect branch tracking is enabled on the task or not */ @@ -474,7 +476,7 @@ int arch_set_indir_br_lp_status(struct task_struct *t, unsigned long status) { bool enable_indir_lp = false; - if (!cpu_supports_indirect_br_lp_instr()) + if (!is_user_lpad_enabled()) return -EINVAL; /* indirect branch tracking is locked and further can't be modified by user */ @@ -498,7 +500,7 @@ int arch_lock_indir_br_lp_status(struct task_struct *task, * If indirect branch tracking is not supported or not enabled on task, * nothing to lock here */ - if (!cpu_supports_indirect_br_lp_instr() || + if (!is_user_lpad_enabled() || !is_indir_lp_enabled(task) || arg != 0) return -EINVAL; @@ -506,3 +508,38 @@ int arch_lock_indir_br_lp_status(struct task_struct *task, return 0; } + +bool is_user_shstk_enabled(void) +{ + return (cpu_supports_shadow_stack() && + !(riscv_nousercfi & CMDLINE_DISABLE_RISCV_USERCFI_BCFI)); +} + +bool is_user_lpad_enabled(void) +{ + return (cpu_supports_indirect_br_lp_instr() && + !(riscv_nousercfi & CMDLINE_DISABLE_RISCV_USERCFI_FCFI)); +} + +static int __init setup_global_riscv_enable(char *str) +{ + if (strcmp(str, "all") == 0) + riscv_nousercfi = CMDLINE_DISABLE_RISCV_USERCFI; + + if (strcmp(str, "fcfi") == 0) + riscv_nousercfi |= CMDLINE_DISABLE_RISCV_USERCFI_FCFI; + + if (strcmp(str, "bcfi") == 0) + riscv_nousercfi |= CMDLINE_DISABLE_RISCV_USERCFI_BCFI; + + if (riscv_nousercfi) + pr_info("riscv user cfi disabled via cmdline" + "shadow stack status : %s, landing pad status : %s\n", + (riscv_nousercfi & CMDLINE_DISABLE_RISCV_USERCFI_BCFI) ? "disabled" : + "enabled", (riscv_nousercfi & CMDLINE_DISABLE_RISCV_USERCFI_FCFI) ? + "disabled" : "enabled"); + + return 1; +} + +__setup("riscv_nousercfi=", setup_global_riscv_enable); From 47c129a8340a093394a2f092ece2a9ca55591ba1 Mon Sep 17 00:00:00 2001 From: Deepak Gupta Date: Fri, 2 May 2025 16:30:53 -0700 Subject: [PATCH 76/91] riscv: enable kernel access to shadow stack memory via FWFT sbi call Kernel will have to perform shadow stack operations on user shadow stack. Like during signal delivery and sigreturn, shadow stack token must be created and validated respectively. Thus shadow stack access for kernel must be enabled. In future when kernel shadow stacks are enabled for linux kernel, it must be enabled as early as possible for better coverage and prevent imbalance between regular stack and shadow stack. After `relocate_enable_mmu` has been done, this is as early as possible it can enabled. Reviewed-by: Zong Li Signed-off-by: Deepak Gupta Link: https://lore.kernel.org/r/20250502-v5_user_cfi_series-v15-22-914966471885@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/kernel/asm-offsets.c | 4 ++++ arch/riscv/kernel/head.S | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/arch/riscv/kernel/asm-offsets.c b/arch/riscv/kernel/asm-offsets.c index f33945432f8f6f..7ab41f01aa17e7 100644 --- a/arch/riscv/kernel/asm-offsets.c +++ b/arch/riscv/kernel/asm-offsets.c @@ -514,4 +514,8 @@ void asm_offsets(void) DEFINE(FREGS_A6, offsetof(struct __arch_ftrace_regs, a6)); DEFINE(FREGS_A7, offsetof(struct __arch_ftrace_regs, a7)); #endif + DEFINE(SBI_EXT_FWFT, SBI_EXT_FWFT); + DEFINE(SBI_EXT_FWFT_SET, SBI_EXT_FWFT_SET); + DEFINE(SBI_FWFT_SHADOW_STACK, SBI_FWFT_SHADOW_STACK); + DEFINE(SBI_FWFT_SET_FLAG_LOCK, SBI_FWFT_SET_FLAG_LOCK); } diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S index 356d5397b2a252..7eae9a17235110 100644 --- a/arch/riscv/kernel/head.S +++ b/arch/riscv/kernel/head.S @@ -15,6 +15,7 @@ #include #include #include +#include #include "efi-header.S" __HEAD @@ -164,6 +165,19 @@ secondary_start_sbi: call relocate_enable_mmu #endif call .Lsetup_trap_vector +#if defined(CONFIG_RISCV_SBI) && defined(CONFIG_RISCV_USER_CFI) + li a7, SBI_EXT_FWFT + li a6, SBI_EXT_FWFT_SET + li a0, SBI_FWFT_SHADOW_STACK + li a1, 1 /* enable supervisor to access shadow stack access */ + li a2, SBI_FWFT_SET_FLAG_LOCK + ecall + beqz a0, 1f + la a1, riscv_nousercfi + li a0, CMDLINE_DISABLE_RISCV_USERCFI_BCFI + REG_S a0, (a1) +1: +#endif scs_load_current call smp_callin #endif /* CONFIG_SMP */ @@ -320,6 +334,19 @@ SYM_CODE_START(_start_kernel) la tp, init_task la sp, init_thread_union + THREAD_SIZE addi sp, sp, -PT_SIZE_ON_STACK +#if defined(CONFIG_RISCV_SBI) && defined(CONFIG_RISCV_USER_CFI) + li a7, SBI_EXT_FWFT + li a6, SBI_EXT_FWFT_SET + li a0, SBI_FWFT_SHADOW_STACK + li a1, 1 /* enable supervisor to access shadow stack access */ + li a2, SBI_FWFT_SET_FLAG_LOCK + ecall + beqz a0, 1f + la a1, riscv_nousercfi + li a0, CMDLINE_DISABLE_RISCV_USERCFI_BCFI + REG_S a0, (a1) +1: +#endif scs_load_current #ifdef CONFIG_KASAN From 15633518388016ef640cf57c6dc18b9502087f8a Mon Sep 17 00:00:00 2001 From: Jim Shu Date: Fri, 2 May 2025 16:30:54 -0700 Subject: [PATCH 77/91] arch/riscv: compile vdso with landing pad user mode tasks compiled with zicfilp may call indirectly into vdso (like hwprobe indirect calls). Add landing pad compile support in vdso. vdso with landing pad in it will be nop for tasks which have not enabled landing pad. This patch allows to run user mode tasks with cfi eanbled and do no harm. Future work can be done on this to do below - labeled landing pad on vdso functions (whenever labeling support shows up in gnu-toolchain) - emit shadow stack instructions only in vdso compiled objects as part of kernel compile. Signed-off-by: Jim Shu Reviewed-by: Zong Li Signed-off-by: Deepak Gupta Link: https://lore.kernel.org/r/20250502-v5_user_cfi_series-v15-23-914966471885@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/Makefile | 5 ++- arch/riscv/include/asm/assembler.h | 44 +++++++++++++++++++++++++++ arch/riscv/kernel/vdso/Makefile | 6 ++++ arch/riscv/kernel/vdso/flush_icache.S | 4 +++ arch/riscv/kernel/vdso/getcpu.S | 4 +++ arch/riscv/kernel/vdso/rt_sigreturn.S | 4 +++ arch/riscv/kernel/vdso/sys_hwprobe.S | 4 +++ 7 files changed, 70 insertions(+), 1 deletion(-) diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index 539d2aef5cab98..c2dd09bb9db380 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -88,9 +88,12 @@ riscv-march-$(CONFIG_TOOLCHAIN_HAS_ZACAS) := $(riscv-march-y)_zacas # Check if the toolchain supports Zabha riscv-march-$(CONFIG_TOOLCHAIN_HAS_ZABHA) := $(riscv-march-y)_zabha +KBUILD_BASE_ISA = -march=$(shell echo $(riscv-march-y) | sed -E 's/(rv32ima|rv64ima)fd([^v_]*)v?/\1\2/') +export KBUILD_BASE_ISA + # Remove F,D,V from isa string for all. Keep extensions between "fd" and "v" by # matching non-v and non-multi-letter extensions out with the filter ([^v_]*) -KBUILD_CFLAGS += -march=$(shell echo $(riscv-march-y) | sed -E 's/(rv32ima|rv64ima)fd([^v_]*)v?/\1\2/') +KBUILD_CFLAGS += $(KBUILD_BASE_ISA) KBUILD_AFLAGS += -march=$(riscv-march-y) diff --git a/arch/riscv/include/asm/assembler.h b/arch/riscv/include/asm/assembler.h index 44b1457d3e9567..a058ea5e9c5828 100644 --- a/arch/riscv/include/asm/assembler.h +++ b/arch/riscv/include/asm/assembler.h @@ -80,3 +80,47 @@ .endm #endif /* __ASM_ASSEMBLER_H */ + +#if defined(CONFIG_RISCV_USER_CFI) && (__riscv_xlen == 64) +.macro vdso_lpad +lpad 0 +.endm +#else +.macro vdso_lpad +.endm +#endif + +/* + * This macro emits a program property note section identifying + * architecture features which require special handling, mainly for + * use in assembly files included in the VDSO. + */ +#define NT_GNU_PROPERTY_TYPE_0 5 +#define GNU_PROPERTY_RISCV_FEATURE_1_AND 0xc0000000 + +#define GNU_PROPERTY_RISCV_FEATURE_1_ZICFILP (1U << 0) +#define GNU_PROPERTY_RISCV_FEATURE_1_ZICFISS (1U << 1) + +#if defined(CONFIG_RISCV_USER_CFI) && (__riscv_xlen == 64) +#define GNU_PROPERTY_RISCV_FEATURE_1_DEFAULT \ + (GNU_PROPERTY_RISCV_FEATURE_1_ZICFILP) +#endif + +#ifdef GNU_PROPERTY_RISCV_FEATURE_1_DEFAULT +.macro emit_riscv_feature_1_and, feat = GNU_PROPERTY_RISCV_FEATURE_1_DEFAULT + .pushsection .note.gnu.property, "a" + .p2align 3 + .word 4 + .word 16 + .word NT_GNU_PROPERTY_TYPE_0 + .asciz "GNU" + .word GNU_PROPERTY_RISCV_FEATURE_1_AND + .word 4 + .word \feat + .word 0 + .popsection +.endm +#else +.macro emit_riscv_feature_1_and, feat = 0 +.endm +#endif diff --git a/arch/riscv/kernel/vdso/Makefile b/arch/riscv/kernel/vdso/Makefile index ad73607abc2808..441c5431d27ea2 100644 --- a/arch/riscv/kernel/vdso/Makefile +++ b/arch/riscv/kernel/vdso/Makefile @@ -13,12 +13,18 @@ vdso-syms += flush_icache vdso-syms += hwprobe vdso-syms += sys_hwprobe +ifdef CONFIG_RISCV_USER_CFI +LPAD_MARCH = _zicfilp_zicfiss -fcf-protection=full +endif + # Files to link into the vdso obj-vdso = $(patsubst %, %.o, $(vdso-syms)) note.o ccflags-y := -fno-stack-protector ccflags-y += -DDISABLE_BRANCH_PROFILING ccflags-y += -fno-builtin +ccflags-y += $(KBUILD_BASE_ISA)$(LPAD_MARCH) +asflags-y += $(KBUILD_BASE_ISA)$(LPAD_MARCH) ifneq ($(c-gettimeofday-y),) CFLAGS_vgettimeofday.o += -fPIC -include $(c-gettimeofday-y) diff --git a/arch/riscv/kernel/vdso/flush_icache.S b/arch/riscv/kernel/vdso/flush_icache.S index 8f884227e8bca7..e4c56970905e93 100644 --- a/arch/riscv/kernel/vdso/flush_icache.S +++ b/arch/riscv/kernel/vdso/flush_icache.S @@ -5,11 +5,13 @@ #include #include +#include .text /* int __vdso_flush_icache(void *start, void *end, unsigned long flags); */ SYM_FUNC_START(__vdso_flush_icache) .cfi_startproc + vdso_lpad #ifdef CONFIG_SMP li a7, __NR_riscv_flush_icache ecall @@ -20,3 +22,5 @@ SYM_FUNC_START(__vdso_flush_icache) ret .cfi_endproc SYM_FUNC_END(__vdso_flush_icache) + +emit_riscv_feature_1_and diff --git a/arch/riscv/kernel/vdso/getcpu.S b/arch/riscv/kernel/vdso/getcpu.S index 9c1bd531907f2f..5c1ecc4e146540 100644 --- a/arch/riscv/kernel/vdso/getcpu.S +++ b/arch/riscv/kernel/vdso/getcpu.S @@ -5,14 +5,18 @@ #include #include +#include .text /* int __vdso_getcpu(unsigned *cpu, unsigned *node, void *unused); */ SYM_FUNC_START(__vdso_getcpu) .cfi_startproc + vdso_lpad /* For now, just do the syscall. */ li a7, __NR_getcpu ecall ret .cfi_endproc SYM_FUNC_END(__vdso_getcpu) + +emit_riscv_feature_1_and diff --git a/arch/riscv/kernel/vdso/rt_sigreturn.S b/arch/riscv/kernel/vdso/rt_sigreturn.S index 3dc022aa8931ad..e82987dc37394b 100644 --- a/arch/riscv/kernel/vdso/rt_sigreturn.S +++ b/arch/riscv/kernel/vdso/rt_sigreturn.S @@ -5,12 +5,16 @@ #include #include +#include .text SYM_FUNC_START(__vdso_rt_sigreturn) .cfi_startproc .cfi_signal_frame + vdso_lpad li a7, __NR_rt_sigreturn ecall .cfi_endproc SYM_FUNC_END(__vdso_rt_sigreturn) + +emit_riscv_feature_1_and diff --git a/arch/riscv/kernel/vdso/sys_hwprobe.S b/arch/riscv/kernel/vdso/sys_hwprobe.S index 77e57f8305216c..f1694451a60c0f 100644 --- a/arch/riscv/kernel/vdso/sys_hwprobe.S +++ b/arch/riscv/kernel/vdso/sys_hwprobe.S @@ -3,13 +3,17 @@ #include #include +#include .text SYM_FUNC_START(riscv_hwprobe) .cfi_startproc + vdso_lpad li a7, __NR_riscv_hwprobe ecall ret .cfi_endproc SYM_FUNC_END(riscv_hwprobe) + +emit_riscv_feature_1_and From 47b09470a6078191a7bc278c74b3dc1fa5ae44d5 Mon Sep 17 00:00:00 2001 From: Deepak Gupta Date: Fri, 2 May 2025 16:30:55 -0700 Subject: [PATCH 78/91] riscv: create a config for shadow stack and landing pad instr support This patch creates a config for shadow stack support and landing pad instr support. Shadow stack support and landing instr support can be enabled by selecting `CONFIG_RISCV_USER_CFI`. Selecting `CONFIG_RISCV_USER_CFI` wires up path to enumerate CPU support and if cpu support exists, kernel will support cpu assisted user mode cfi. If CONFIG_RISCV_USER_CFI is selected, select `ARCH_USES_HIGH_VMA_FLAGS`, `ARCH_HAS_USER_SHADOW_STACK` and DYNAMIC_SIGFRAME for riscv. Reviewed-by: Zong Li Signed-off-by: Deepak Gupta Link: https://lore.kernel.org/r/20250502-v5_user_cfi_series-v15-24-914966471885@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/Kconfig | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index bbec87b7930999..19d5a3d5e0d6ac 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -256,6 +256,27 @@ config ARCH_HAS_BROKEN_DWARF5 # https://github.com/llvm/llvm-project/commit/7ffabb61a5569444b5ac9322e22e5471cc5e4a77 depends on LD_IS_LLD && LLD_VERSION < 180000 +config RISCV_USER_CFI + def_bool y + bool "riscv userspace control flow integrity" + depends on 64BIT && $(cc-option,-mabi=lp64 -march=rv64ima_zicfiss) + depends on RISCV_ALTERNATIVE + select RISCV_SBI + select ARCH_HAS_USER_SHADOW_STACK + select ARCH_USES_HIGH_VMA_FLAGS + select DYNAMIC_SIGFRAME + help + Provides CPU assisted control flow integrity to userspace tasks. + Control flow integrity is provided by implementing shadow stack for + backward edge and indirect branch tracking for forward edge in program. + Shadow stack protection is a hardware feature that detects function + return address corruption. This helps mitigate ROP attacks. + Indirect branch tracking enforces that all indirect branches must land + on a landing pad instruction else CPU will fault. This mitigates against + JOP / COP attacks. Applications must be enabled to use it, and old user- + space does not get protection "for free". + default y + config ARCH_MMAP_RND_BITS_MIN default 18 if 64BIT default 8 From ffdeac6cf59058aa9bf784704b826fe8d36d326f Mon Sep 17 00:00:00 2001 From: Deepak Gupta Date: Fri, 2 May 2025 16:30:56 -0700 Subject: [PATCH 79/91] riscv: Documentation for landing pad / indirect branch tracking Adding documentation on landing pad aka indirect branch tracking on riscv and kernel interfaces exposed so that user tasks can enable it. Reviewed-by: Zong Li Signed-off-by: Deepak Gupta Link: https://lore.kernel.org/r/20250502-v5_user_cfi_series-v15-25-914966471885@rivosinc.com Signed-off-by: Alexandre Ghiti --- Documentation/arch/riscv/index.rst | 1 + Documentation/arch/riscv/zicfilp.rst | 115 +++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 Documentation/arch/riscv/zicfilp.rst diff --git a/Documentation/arch/riscv/index.rst b/Documentation/arch/riscv/index.rst index eecf347ce84944..be7237b6968213 100644 --- a/Documentation/arch/riscv/index.rst +++ b/Documentation/arch/riscv/index.rst @@ -14,6 +14,7 @@ RISC-V architecture uabi vector cmodx + zicfilp features diff --git a/Documentation/arch/riscv/zicfilp.rst b/Documentation/arch/riscv/zicfilp.rst new file mode 100644 index 00000000000000..dcf43de73a063a --- /dev/null +++ b/Documentation/arch/riscv/zicfilp.rst @@ -0,0 +1,115 @@ +.. SPDX-License-Identifier: GPL-2.0 + +:Author: Deepak Gupta +:Date: 12 January 2024 + +==================================================== +Tracking indirect control transfers on RISC-V Linux +==================================================== + +This document briefly describes the interface provided to userspace by Linux +to enable indirect branch tracking for user mode applications on RISC-V + +1. Feature Overview +-------------------- + +Memory corruption issues usually result into crashes, however when in hands of +an adversary and if used creatively can result into a variety security issues. + +One of those security issues can be code re-use attacks on program where adversary +can use corrupt function pointers and chain them together to perform jump oriented +programming (JOP) or call oriented programming (COP) and thus compromising control +flow integrity (CFI) of the program. + +Function pointers live in read-write memory and thus are susceptible to corruption +and allows an adversary to reach any program counter (PC) in address space. On +RISC-V zicfilp extension enforces a restriction on such indirect control +transfers: + +- indirect control transfers must land on a landing pad instruction ``lpad``. + There are two exception to this rule: + + - rs1 = x1 or rs1 = x5, i.e. a return from a function and returns are + protected using shadow stack (see zicfiss.rst) + + - rs1 = x7. On RISC-V compiler usually does below to reach function + which is beyond the offset possible J-type instruction:: + + auipc x7, + jalr (x7) + + Such form of indirect control transfer are still immutable and don't rely + on memory and thus rs1=x7 is exempted from tracking and considered software + guarded jumps. + +``lpad`` instruction is pseudo of ``auipc rd, `` with ``rd=x0`` and +is a HINT nop. ``lpad`` instruction must be aligned on 4 byte boundary and +compares 20 bit immediate with x7. If ``imm_20bit`` == 0, CPU doesn't perform +any comparision with ``x7``. If ``imm_20bit`` != 0, then ``imm_20bit`` must +match ``x7`` else CPU will raise ``software check exception`` (``cause=18``) +with ``*tval = 2``. + +Compiler can generate a hash over function signatures and setup them (truncated +to 20bit) in x7 at callsites and function prologues can have ``lpad`` with same +function hash. This further reduces number of program counters a call site can +reach. + +2. ELF and psABI +----------------- + +Toolchain sets up :c:macro:`GNU_PROPERTY_RISCV_FEATURE_1_FCFI` for property +:c:macro:`GNU_PROPERTY_RISCV_FEATURE_1_AND` in notes section of the object file. + +3. Linux enabling +------------------ + +User space programs can have multiple shared objects loaded in its address space +and it's a difficult task to make sure all the dependencies have been compiled +with support of indirect branch. Thus it's left to dynamic loader to enable +indirect branch tracking for the program. + +4. prctl() enabling +-------------------- + +:c:macro:`PR_SET_INDIR_BR_LP_STATUS` / :c:macro:`PR_GET_INDIR_BR_LP_STATUS` / +:c:macro:`PR_LOCK_INDIR_BR_LP_STATUS` are three prctls added to manage indirect +branch tracking. prctls are arch agnostic and returns -EINVAL on other arches. + +* prctl(PR_SET_INDIR_BR_LP_STATUS, unsigned long arg) + +If arg1 is :c:macro:`PR_INDIR_BR_LP_ENABLE` and if CPU supports ``zicfilp`` +then kernel will enable indirect branch tracking for the task. Dynamic loader +can issue this :c:macro:`prctl` once it has determined that all the objects +loaded in address space support indirect branch tracking. Additionally if there +is a `dlopen` to an object which wasn't compiled with ``zicfilp``, dynamic +loader can issue this prctl with arg1 set to 0 (i.e. +:c:macro:`PR_INDIR_BR_LP_ENABLE` being clear) + +* prctl(PR_GET_INDIR_BR_LP_STATUS, unsigned long arg) + +Returns current status of indirect branch tracking. If enabled it'll return +:c:macro:`PR_INDIR_BR_LP_ENABLE` + +* prctl(PR_LOCK_INDIR_BR_LP_STATUS, unsigned long arg) + +Locks current status of indirect branch tracking on the task. User space may +want to run with strict security posture and wouldn't want loading of objects +without ``zicfilp`` support in it and thus would want to disallow disabling of +indirect branch tracking. In that case user space can use this prctl to lock +current settings. + +5. violations related to indirect branch tracking +-------------------------------------------------- + +Pertaining to indirect branch tracking, CPU raises software check exception in +following conditions: + +- missing ``lpad`` after indirect call / jmp +- ``lpad`` not on 4 byte boundary +- ``imm_20bit`` embedded in ``lpad`` instruction doesn't match with ``x7`` + +In all 3 cases, ``*tval = 2`` is captured and software check exception is +raised (``cause=18``) + +Linux kernel will treat this as :c:macro:`SIGSEV`` with code = +:c:macro:`SEGV_CPERR` and follow normal course of signal delivery. From 918742853bf8e8c355c6b07152818a69adecbc41 Mon Sep 17 00:00:00 2001 From: Deepak Gupta Date: Fri, 2 May 2025 16:30:57 -0700 Subject: [PATCH 80/91] riscv: Documentation for shadow stack on riscv Adding documentation on shadow stack for user mode on riscv and kernel interfaces exposed so that user tasks can enable it. Reviewed-by: Zong Li Signed-off-by: Deepak Gupta Link: https://lore.kernel.org/r/20250502-v5_user_cfi_series-v15-26-914966471885@rivosinc.com Signed-off-by: Alexandre Ghiti --- Documentation/arch/riscv/index.rst | 1 + Documentation/arch/riscv/zicfiss.rst | 179 +++++++++++++++++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 Documentation/arch/riscv/zicfiss.rst diff --git a/Documentation/arch/riscv/index.rst b/Documentation/arch/riscv/index.rst index be7237b6968213..e240eb0ceb70c4 100644 --- a/Documentation/arch/riscv/index.rst +++ b/Documentation/arch/riscv/index.rst @@ -15,6 +15,7 @@ RISC-V architecture vector cmodx zicfilp + zicfiss features diff --git a/Documentation/arch/riscv/zicfiss.rst b/Documentation/arch/riscv/zicfiss.rst new file mode 100644 index 00000000000000..b50089e6a52be1 --- /dev/null +++ b/Documentation/arch/riscv/zicfiss.rst @@ -0,0 +1,179 @@ +.. SPDX-License-Identifier: GPL-2.0 + +:Author: Deepak Gupta +:Date: 12 January 2024 + +========================================================= +Shadow stack to protect function returns on RISC-V Linux +========================================================= + +This document briefly describes the interface provided to userspace by Linux +to enable shadow stack for user mode applications on RISC-V + +1. Feature Overview +-------------------- + +Memory corruption issues usually result into crashes, however when in hands of +an adversary and if used creatively can result into a variety security issues. + +One of those security issues can be code re-use attacks on program where +adversary can use corrupt return addresses present on stack and chain them +together to perform return oriented programming (ROP) and thus compromising +control flow integrity (CFI) of the program. + +Return addresses live on stack and thus in read-write memory and thus are +susceptible to corruption and which allows an adversary to reach any program +counter (PC) in address space. On RISC-V ``zicfiss`` extension provides an +alternate stack termed as shadow stack on which return addresses can be safely +placed in prolog of the function and retrieved in epilog. ``zicfiss`` extension +makes following changes: + +- PTE encodings for shadow stack virtual memory + An earlier reserved encoding in first stage translation i.e. + PTE.R=0, PTE.W=1, PTE.X=0 becomes PTE encoding for shadow stack pages. + +- ``sspush x1/x5`` instruction pushes (stores) ``x1/x5`` to shadow stack. + +- ``sspopchk x1/x5`` instruction pops (loads) from shadow stack and compares + with ``x1/x5`` and if un-equal, CPU raises ``software check exception`` with + ``*tval = 3`` + +Compiler toolchain makes sure that function prologue have ``sspush x1/x5`` to +save return address on shadow stack in addition to regular stack. Similarly +function epilogs have ``ld x5, offset(x2)`` followed by ``sspopchk x5`` to +ensure that popped value from regular stack matches with popped value from +shadow stack. + +2. Shadow stack protections and linux memory manager +----------------------------------------------------- + +As mentioned earlier, shadow stacks get new page table encodings and thus have +some special properties assigned to them and instructions that operate on them +as below: + +- Regular stores to shadow stack memory raises access store faults. This way + shadow stack memory is protected from stray inadvertent writes. + +- Regular loads to shadow stack memory are allowed. This allows stack trace + utilities or backtrace functions to read true callstack (not tampered). + +- Only shadow stack instructions can generate shadow stack load or shadow stack + store. + +- Shadow stack load / shadow stack store on read-only memory raises AMO/store + page fault. Thus both ``sspush x1/x5`` and ``sspopchk x1/x5`` will raise AMO/ + store page fault. This simplies COW handling in kernel during fork, kernel + can convert shadow stack pages into read-only memory (as it does for regular + read-write memory) and as soon as subsequent ``sspush`` or ``sspopchk`` in + userspace is encountered, then kernel can perform COW. + +- Shadow stack load / shadow stack store on read-write, read-write-execute + memory raises an access fault. This is a fatal condition because shadow stack + should never be operating on read-write, read-write-execute memory. + +3. ELF and psABI +----------------- + +Toolchain sets up :c:macro:`GNU_PROPERTY_RISCV_FEATURE_1_BCFI` for property +:c:macro:`GNU_PROPERTY_RISCV_FEATURE_1_AND` in notes section of the object file. + +4. Linux enabling +------------------ + +User space programs can have multiple shared objects loaded in its address space +and it's a difficult task to make sure all the dependencies have been compiled +with support of shadow stack. Thus it's left to dynamic loader to enable +shadow stack for the program. + +5. prctl() enabling +-------------------- + +:c:macro:`PR_SET_SHADOW_STACK_STATUS` / :c:macro:`PR_GET_SHADOW_STACK_STATUS` / +:c:macro:`PR_LOCK_SHADOW_STACK_STATUS` are three prctls added to manage shadow +stack enabling for tasks. prctls are arch agnostic and returns -EINVAL on other +arches. + +* prctl(PR_SET_SHADOW_STACK_STATUS, unsigned long arg) + +If arg1 :c:macro:`PR_SHADOW_STACK_ENABLE` and if CPU supports ``zicfiss`` then +kernel will enable shadow stack for the task. Dynamic loader can issue this +:c:macro:`prctl` once it has determined that all the objects loaded in address +space have support for shadow stack. Additionally if there is a +:c:macro:`dlopen` to an object which wasn't compiled with ``zicfiss``, dynamic +loader can issue this prctl with arg1 set to 0 (i.e. +:c:macro:`PR_SHADOW_STACK_ENABLE` being clear) + +* prctl(PR_GET_SHADOW_STACK_STATUS, unsigned long *arg) + +Returns current status of indirect branch tracking. If enabled it'll return +:c:macro:`PR_SHADOW_STACK_ENABLE`. + +* prctl(PR_LOCK_SHADOW_STACK_STATUS, unsigned long arg) + +Locks current status of shadow stack enabling on the task. User space may want +to run with strict security posture and wouldn't want loading of objects +without ``zicfiss`` support in it and thus would want to disallow disabling of +shadow stack on current task. In that case user space can use this prctl to +lock current settings. + +5. violations related to returns with shadow stack enabled +----------------------------------------------------------- + +Pertaining to shadow stack, CPU raises software check exception in following +condition: + +- On execution of ``sspopchk x1/x5``, ``x1/x5`` didn't match top of shadow + stack. If mismatch happens then cpu does ``*tval = 3`` and raise software + check exception. + +Linux kernel will treat this as :c:macro:`SIGSEV`` with code = +:c:macro:`SEGV_CPERR` and follow normal course of signal delivery. + +6. Shadow stack tokens +----------------------- +Regular stores on shadow stacks are not allowed and thus can't be tampered +with via arbitrary stray writes due to bugs. However method of pivoting / +switching to shadow stack is simply writing to csr ``CSR_SSP`` and that will +change active shadow stack for the program. Instances of writes to ``CSR_SSP`` +in the address space of the program should be mostly limited to context +switching, stack unwind, longjmp or similar mechanisms (like context switching +of green threads) in languages like go, rust. This can be problematic because +an attacker can use memory corruption bugs and eventually use such context +switching routines to pivot to any shadow stack. Shadow stack tokens can help +mitigate this problem by making sure that: + +- When software is switching away from a shadow stack, shadow stack pointer + should be saved on shadow stack itself and call it ``shadow stack token`` + +- When software is switching to a shadow stack, it should read the + ``shadow stack token`` from shadow stack pointer and verify that + ``shadow stack token`` itself is pointer to shadow stack itself. + +- Once the token verification is done, software can perform the write to + ``CSR_SSP`` to switch shadow stack. + +Here software can be user mode task runtime itself which is managing various +contexts as part of single thread. Software can be kernel as well when kernel +has to deliver a signal to user task and must save shadow stack pointer. Kernel +can perform similar procedure by saving a token on user shadow stack itself. +This way whenever :c:macro:`sigreturn` happens, kernel can read the token and +verify the token and then switch to shadow stack. Using this mechanism, kernel +helps user task so that any corruption issue in user task is not exploited by +adversary by arbitrarily using :c:macro:`sigreturn`. Adversary will have to +make sure that there is a ``shadow stack token`` in addition to invoking +:c:macro:`sigreturn` + +7. Signal shadow stack +----------------------- +Following structure has been added to sigcontext for RISC-V:: + + struct __sc_riscv_cfi_state { + unsigned long ss_ptr; + }; + +As part of signal delivery, shadow stack token is saved on current shadow stack +itself and updated pointer is saved away in :c:macro:`ss_ptr` field in +:c:macro:`__sc_riscv_cfi_state` under :c:macro:`sigcontext`. Existing shadow +stack allocation is used for signal delivery. During :c:macro:`sigreturn`, +kernel will obtain :c:macro:`ss_ptr` from :c:macro:`sigcontext` and verify the +saved token on shadow stack itself and switch shadow stack. From 2eef70bb5dc95d5144cdacc87f166db6423a150e Mon Sep 17 00:00:00 2001 From: Deepak Gupta Date: Fri, 2 May 2025 16:30:58 -0700 Subject: [PATCH 81/91] kselftest/riscv: kselftest for user mode cfi Adds kselftest for RISC-V control flow integrity implementation for user mode. There is not a lot going on in kernel for enabling landing pad for user mode. cfi selftest are intended to be compiled with zicfilp and zicfiss enabled compiler. Thus kselftest simply checks if landing pad / shadow stack for the process are enabled or not and executes ptrace selftests on cfi. selftest then register a signal handler for SIGSEGV. Any control flow violation are reported as SIGSEGV with si_code = SEGV_CPERR. Test will fail on receiving any SEGV_CPERR. Shadow stack part has more changes in kernel and thus there are separate tests for that - Exercise `map_shadow_stack` syscall - `fork` test to make sure COW works for shadow stack pages - gup tests Kernel uses FOLL_FORCE when access happens to memory via /proc//mem. Not breaking that for shadow stack. - signal test. Make sure signal delivery results in token creation on shadow stack and consumes (and verifies) token on sigreturn - shadow stack protection test. attempts to write using regular store instruction on shadow stack memory must result in access faults - ptrace test: adds landing pad violation, clears ELP and continues Test outut ========== """ TAP version 13 1..5 This is to ensure shadow stack is indeed enabled and working This is to ensure shadow stack is indeed enabled and working ok 1 shstk fork test ok 2 map shadow stack syscall ok 3 shadow stack gup tests ok 4 shadow stack signal tests ok 5 memory protections of shadow stack memory """ Signed-off-by: Deepak Gupta squash Signed-off-by: Deepak Gupta Link: https://lore.kernel.org/r/20250502-v5_user_cfi_series-v15-27-914966471885@rivosinc.com Signed-off-by: Alexandre Ghiti --- tools/testing/selftests/riscv/Makefile | 2 +- tools/testing/selftests/riscv/cfi/.gitignore | 3 + tools/testing/selftests/riscv/cfi/Makefile | 10 + .../testing/selftests/riscv/cfi/cfi_rv_test.h | 82 ++++ .../selftests/riscv/cfi/riscv_cfi_test.c | 173 ++++++++ .../testing/selftests/riscv/cfi/shadowstack.c | 385 ++++++++++++++++++ .../testing/selftests/riscv/cfi/shadowstack.h | 27 ++ 7 files changed, 681 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/riscv/cfi/.gitignore create mode 100644 tools/testing/selftests/riscv/cfi/Makefile create mode 100644 tools/testing/selftests/riscv/cfi/cfi_rv_test.h create mode 100644 tools/testing/selftests/riscv/cfi/riscv_cfi_test.c create mode 100644 tools/testing/selftests/riscv/cfi/shadowstack.c create mode 100644 tools/testing/selftests/riscv/cfi/shadowstack.h diff --git a/tools/testing/selftests/riscv/Makefile b/tools/testing/selftests/riscv/Makefile index 099b8c1f46f89f..5671b4405a1294 100644 --- a/tools/testing/selftests/riscv/Makefile +++ b/tools/testing/selftests/riscv/Makefile @@ -5,7 +5,7 @@ ARCH ?= $(shell uname -m 2>/dev/null || echo not) ifneq (,$(filter $(ARCH),riscv)) -RISCV_SUBTARGETS ?= abi hwprobe mm sigreturn vector +RISCV_SUBTARGETS ?= abi hwprobe mm sigreturn vector cfi else RISCV_SUBTARGETS := endif diff --git a/tools/testing/selftests/riscv/cfi/.gitignore b/tools/testing/selftests/riscv/cfi/.gitignore new file mode 100644 index 00000000000000..82545863bac639 --- /dev/null +++ b/tools/testing/selftests/riscv/cfi/.gitignore @@ -0,0 +1,3 @@ +cfitests +riscv_cfi_test +shadowstack diff --git a/tools/testing/selftests/riscv/cfi/Makefile b/tools/testing/selftests/riscv/cfi/Makefile new file mode 100644 index 00000000000000..1fa27cc10fb535 --- /dev/null +++ b/tools/testing/selftests/riscv/cfi/Makefile @@ -0,0 +1,10 @@ +CFLAGS += -I$(top_srcdir)/tools/include + +CFLAGS += -march=rv64gc_zicfilp_zicfiss -fcf-protection=full + +TEST_GEN_PROGS := cfitests + +include ../../lib.mk + +$(OUTPUT)/cfitests: riscv_cfi_test.c shadowstack.c + $(CC) -o$@ $(CFLAGS) $(LDFLAGS) $^ diff --git a/tools/testing/selftests/riscv/cfi/cfi_rv_test.h b/tools/testing/selftests/riscv/cfi/cfi_rv_test.h new file mode 100644 index 00000000000000..1c8043f2b778b7 --- /dev/null +++ b/tools/testing/selftests/riscv/cfi/cfi_rv_test.h @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef SELFTEST_RISCV_CFI_H +#define SELFTEST_RISCV_CFI_H +#include +#include +#include "shadowstack.h" + +#define CHILD_EXIT_CODE_SSWRITE 10 +#define CHILD_EXIT_CODE_SIG_TEST 11 + +#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +({ \ + register long _num __asm__ ("a7") = (num); \ + register long _arg1 __asm__ ("a0") = (long)(arg1); \ + register long _arg2 __asm__ ("a1") = (long)(arg2); \ + register long _arg3 __asm__ ("a2") = (long)(arg3); \ + register long _arg4 __asm__ ("a3") = (long)(arg4); \ + register long _arg5 __asm__ ("a4") = (long)(arg5); \ + \ + __asm__ volatile( \ + "ecall\n" \ + : "+r" \ + (_arg1) \ + : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ + "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ +}) + +#define my_syscall3(num, arg1, arg2, arg3) \ +({ \ + register long _num __asm__ ("a7") = (num); \ + register long _arg1 __asm__ ("a0") = (long)(arg1); \ + register long _arg2 __asm__ ("a1") = (long)(arg2); \ + register long _arg3 __asm__ ("a2") = (long)(arg3); \ + \ + __asm__ volatile( \ + "ecall\n" \ + : "+r" (_arg1) \ + : "r"(_arg2), "r"(_arg3), \ + "r"(_num) \ + : "memory", "cc" \ + ); \ + _arg1; \ +}) + +#ifndef __NR_prctl +#define __NR_prctl 167 +#endif + +#ifndef __NR_map_shadow_stack +#define __NR_map_shadow_stack 453 +#endif + +#define CSR_SSP 0x011 + +#ifdef __ASSEMBLY__ +#define __ASM_STR(x) x +#else +#define __ASM_STR(x) #x +#endif + +#define csr_read(csr) \ +({ \ + register unsigned long __v; \ + __asm__ __volatile__ ("csrr %0, " __ASM_STR(csr) \ + : "=r" (__v) : \ + : "memory"); \ + __v; \ +}) + +#define csr_write(csr, val) \ +({ \ + unsigned long __v = (unsigned long)(val); \ + __asm__ __volatile__ ("csrw " __ASM_STR(csr) ", %0" \ + : : "rK" (__v) \ + : "memory"); \ +}) + +#endif diff --git a/tools/testing/selftests/riscv/cfi/riscv_cfi_test.c b/tools/testing/selftests/riscv/cfi/riscv_cfi_test.c new file mode 100644 index 00000000000000..486a2e77905329 --- /dev/null +++ b/tools/testing/selftests/riscv/cfi/riscv_cfi_test.c @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include "../../kselftest.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cfi_rv_test.h" + +/* do not optimize cfi related test functions */ +#pragma GCC push_options +#pragma GCC optimize("O0") + +void sigsegv_handler(int signum, siginfo_t *si, void *uc) +{ + struct ucontext *ctx = (struct ucontext *)uc; + + if (si->si_code == SEGV_CPERR) { + ksft_print_msg("Control flow violation happened somewhere\n"); + ksft_print_msg("PC where violation happened %lx\n", ctx->uc_mcontext.gregs[0]); + exit(-1); + } + + /* all other cases are expected to be of shadow stack write case */ + exit(CHILD_EXIT_CODE_SSWRITE); +} + +bool register_signal_handler(void) +{ + struct sigaction sa = {}; + + sa.sa_sigaction = sigsegv_handler; + sa.sa_flags = SA_SIGINFO; + if (sigaction(SIGSEGV, &sa, NULL)) { + ksft_print_msg("Registering signal handler for landing pad violation failed\n"); + return false; + } + + return true; +} + +long ptrace(int request, pid_t pid, void *addr, void *data); + +bool cfi_ptrace_test(void) +{ + pid_t pid; + int status, ret = 0; + unsigned long ptrace_test_num = 0, total_ptrace_tests = 2; + + struct user_cfi_state cfi_reg; + struct iovec iov; + + pid = fork(); + + if (pid == -1) { + ksft_exit_fail_msg("%s: fork failed\n", __func__); + exit(1); + } + + if (pid == 0) { + /* allow to be traced */ + ptrace(PTRACE_TRACEME, 0, NULL, NULL); + raise(SIGSTOP); + asm volatile ( + "la a5, 1f\n" + "jalr a5 \n" + "nop \n" + "nop \n" + "1: nop\n" + : : : "a5"); + exit(11); + /* child shouldn't go beyond here */ + } + + /* parent's code goes here */ + iov.iov_base = &cfi_reg; + iov.iov_len = sizeof(cfi_reg); + + while (ptrace_test_num < total_ptrace_tests) { + memset(&cfi_reg, 0, sizeof(cfi_reg)); + waitpid(pid, &status, 0); + if (WIFSTOPPED(status)) { + errno = 0; + ret = ptrace(PTRACE_GETREGSET, pid, (void *)NT_RISCV_USER_CFI, &iov); + if (ret == -1 && errno) + ksft_exit_fail_msg("%s: PTRACE_GETREGSET failed\n", __func__); + } else + ksft_exit_fail_msg("%s: child didn't stop, failed\n", __func__); + + switch (ptrace_test_num) { +#define CFI_ENABLE_MASK (PTRACE_CFI_LP_EN_STATE | \ + PTRACE_CFI_SS_EN_STATE | \ + PTRACE_CFI_SS_PTR_STATE) + case 0: + if ((cfi_reg.cfi_status.cfi_state & CFI_ENABLE_MASK) != CFI_ENABLE_MASK) + ksft_exit_fail_msg("%s: ptrace_getregset failed, %llu\n", __func__, + cfi_reg.cfi_status.cfi_state); + if (!cfi_reg.shstk_ptr) + ksft_exit_fail_msg("%s: NULL shadow stack pointer, test failed\n", + __func__); + break; + case 1: + if (!(cfi_reg.cfi_status.cfi_state & PTRACE_CFI_ELP_STATE)) + ksft_exit_fail_msg("%s: elp must have been set\n", __func__); + /* clear elp state. not interested in anything else */ + cfi_reg.cfi_status.cfi_state = 0; + + ret = ptrace(PTRACE_SETREGSET, pid, (void *)NT_RISCV_USER_CFI, &iov); + if (ret == -1 && errno) + ksft_exit_fail_msg("%s: PTRACE_GETREGSET failed\n", __func__); + break; + default: + ksft_exit_fail_msg("%s: unreachable switch case\n", __func__); + break; + } + ptrace(PTRACE_CONT, pid, NULL, NULL); + ptrace_test_num++; + } + + waitpid(pid, &status, 0); + if (WEXITSTATUS(status) != 11) + ksft_print_msg("%s, bad return code from child\n", __func__); + + ksft_print_msg("%s, ptrace test succeeded\n", __func__); + return true; +} + +int main(int argc, char *argv[]) +{ + int ret = 0; + unsigned long lpad_status = 0, ss_status = 0; + + ksft_print_header(); + + ksft_print_msg("Starting risc-v tests\n"); + + /* + * Landing pad test. Not a lot of kernel changes to support landing + * pad for user mode except lighting up a bit in senvcfg via a prctl + * Enable landing pad through out the execution of test binary + */ + ret = my_syscall5(__NR_prctl, PR_GET_INDIR_BR_LP_STATUS, &lpad_status, 0, 0, 0); + if (ret) + ksft_exit_fail_msg("Get landing pad status failed with %d\n", ret); + + if (!(lpad_status & PR_INDIR_BR_LP_ENABLE)) + ksft_exit_fail_msg("Landing pad is not enabled, should be enabled via glibc\n"); + + ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS, &ss_status, 0, 0, 0); + if (ret) + ksft_exit_fail_msg("Get shadow stack failed with %d\n", ret); + + if (!(ss_status & PR_SHADOW_STACK_ENABLE)) + ksft_exit_fail_msg("Shadow stack is not enabled, should be enabled via glibc\n"); + + if (!register_signal_handler()) + ksft_exit_fail_msg("Registering signal handler for SIGSEGV failed\n"); + + ksft_print_msg("Landing pad and shadow stack are enabled for binary\n"); + cfi_ptrace_test(); + + execute_shadow_stack_tests(); + + return 0; +} + +#pragma GCC pop_options diff --git a/tools/testing/selftests/riscv/cfi/shadowstack.c b/tools/testing/selftests/riscv/cfi/shadowstack.c new file mode 100644 index 00000000000000..53387dbd9cf53e --- /dev/null +++ b/tools/testing/selftests/riscv/cfi/shadowstack.c @@ -0,0 +1,385 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include "../../kselftest.h" +#include +#include +#include +#include +#include +#include "shadowstack.h" +#include "cfi_rv_test.h" + +static struct shadow_stack_tests shstk_tests[] = { + { "shstk fork test\n", shadow_stack_fork_test }, + { "map shadow stack syscall\n", shadow_stack_map_test }, + { "shadow stack gup tests\n", shadow_stack_gup_tests }, + { "shadow stack signal tests\n", shadow_stack_signal_test}, + { "memory protections of shadow stack memory\n", shadow_stack_protection_test } +}; + +#define RISCV_SHADOW_STACK_TESTS ARRAY_SIZE(shstk_tests) + +/* do not optimize shadow stack related test functions */ +#pragma GCC push_options +#pragma GCC optimize("O0") + +void zar(void) +{ + unsigned long ssp = 0; + + ssp = csr_read(CSR_SSP); + ksft_print_msg("Spewing out shadow stack ptr: %lx\n" + " This is to ensure shadow stack is indeed enabled and working\n", + ssp); +} + +void bar(void) +{ + zar(); +} + +void foo(void) +{ + bar(); +} + +void zar_child(void) +{ + unsigned long ssp = 0; + + ssp = csr_read(CSR_SSP); + ksft_print_msg("Spewing out shadow stack ptr: %lx\n" + " This is to ensure shadow stack is indeed enabled and working\n", + ssp); +} + +void bar_child(void) +{ + zar_child(); +} + +void foo_child(void) +{ + bar_child(); +} + +typedef void (call_func_ptr)(void); +/* + * call couple of functions to test push pop. + */ +int shadow_stack_call_tests(call_func_ptr fn_ptr, bool parent) +{ + ksft_print_msg("dummy calls for sspush and sspopchk in context of %s\n", + parent ? "parent" : "child"); + + (fn_ptr)(); + + return 0; +} + +/* forks a thread, and ensure shadow stacks fork out */ +bool shadow_stack_fork_test(unsigned long test_num, void *ctx) +{ + int pid = 0, child_status = 0, parent_pid = 0, ret = 0; + unsigned long ss_status = 0; + + ksft_print_msg("Exercising shadow stack fork test\n"); + + ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS, &ss_status, 0, 0, 0); + if (ret) { + ksft_exit_skip("Shadow stack get status prctl failed with errorcode %d\n", ret); + return false; + } + + if (!(ss_status & PR_SHADOW_STACK_ENABLE)) + ksft_exit_skip("Shadow stack is not enabled, should be enabled via glibc\n"); + + parent_pid = getpid(); + pid = fork(); + + if (pid) { + ksft_print_msg("Parent pid %d and child pid %d\n", parent_pid, pid); + shadow_stack_call_tests(&foo, true); + } else { + shadow_stack_call_tests(&foo_child, false); + } + + if (pid) { + ksft_print_msg("Waiting on child to finish\n"); + wait(&child_status); + } else { + /* exit child gracefully */ + exit(0); + } + + if (pid && WIFSIGNALED(child_status)) { + ksft_print_msg("Child faulted, fork test failed\n"); + return false; + } + + return true; +} + +/* exercise `map_shadow_stack`, pivot to it and call some functions to ensure it works */ +#define SHADOW_STACK_ALLOC_SIZE 4096 +bool shadow_stack_map_test(unsigned long test_num, void *ctx) +{ + unsigned long shdw_addr; + int ret = 0; + + ksft_print_msg("Exercising shadow stack map test\n"); + + shdw_addr = my_syscall3(__NR_map_shadow_stack, NULL, SHADOW_STACK_ALLOC_SIZE, 0); + + if (((long)shdw_addr) <= 0) { + ksft_print_msg("map_shadow_stack failed with error code %d\n", + (int)shdw_addr); + return false; + } + + ret = munmap((void *)shdw_addr, SHADOW_STACK_ALLOC_SIZE); + + if (ret) { + ksft_print_msg("munmap failed with error code %d\n", ret); + return false; + } + + return true; +} + +/* + * shadow stack protection tests. map a shadow stack and + * validate all memory protections work on it + */ +bool shadow_stack_protection_test(unsigned long test_num, void *ctx) +{ + unsigned long shdw_addr; + unsigned long *write_addr = NULL; + int ret = 0, pid = 0, child_status = 0; + + ksft_print_msg("Exercising shadow stack protection test (WPT)\n"); + + shdw_addr = my_syscall3(__NR_map_shadow_stack, NULL, SHADOW_STACK_ALLOC_SIZE, 0); + + if (((long)shdw_addr) <= 0) { + ksft_print_msg("map_shadow_stack failed with error code %d\n", + (int)shdw_addr); + return false; + } + + write_addr = (unsigned long *)shdw_addr; + pid = fork(); + + /* no child was created, return false */ + if (pid == -1) + return false; + + /* + * try to perform a store from child on shadow stack memory + * it should result in SIGSEGV + */ + if (!pid) { + /* below write must lead to SIGSEGV */ + *write_addr = 0xdeadbeef; + } else { + wait(&child_status); + } + + /* test fail, if 0xdeadbeef present on shadow stack address */ + if (*write_addr == 0xdeadbeef) { + ksft_print_msg("Shadow stack WPT failed\n"); + return false; + } + + /* if child reached here, then fail */ + if (!pid) { + ksft_print_msg("Shadow stack WPT failed: child reached unreachable state\n"); + return false; + } + + /* if child exited via signal handler but not for write on ss */ + if (WIFEXITED(child_status) && + WEXITSTATUS(child_status) != CHILD_EXIT_CODE_SSWRITE) { + ksft_print_msg("Shadow stack WPT failed: child wasn't signaled for write\n"); + return false; + } + + ret = munmap(write_addr, SHADOW_STACK_ALLOC_SIZE); + if (ret) { + ksft_print_msg("Shadow stack WPT failed: munmap failed, error code %d\n", + ret); + return false; + } + + return true; +} + +#define SS_MAGIC_WRITE_VAL 0xbeefdead + +int gup_tests(int mem_fd, unsigned long *shdw_addr) +{ + unsigned long val = 0; + + lseek(mem_fd, (unsigned long)shdw_addr, SEEK_SET); + if (read(mem_fd, &val, sizeof(val)) < 0) { + ksft_print_msg("Reading shadow stack mem via gup failed\n"); + return 1; + } + + val = SS_MAGIC_WRITE_VAL; + lseek(mem_fd, (unsigned long)shdw_addr, SEEK_SET); + if (write(mem_fd, &val, sizeof(val)) < 0) { + ksft_print_msg("Writing shadow stack mem via gup failed\n"); + return 1; + } + + if (*shdw_addr != SS_MAGIC_WRITE_VAL) { + ksft_print_msg("GUP write to shadow stack memory failed\n"); + return 1; + } + + return 0; +} + +bool shadow_stack_gup_tests(unsigned long test_num, void *ctx) +{ + unsigned long shdw_addr = 0; + unsigned long *write_addr = NULL; + int fd = 0; + bool ret = false; + + ksft_print_msg("Exercising shadow stack gup tests\n"); + shdw_addr = my_syscall3(__NR_map_shadow_stack, NULL, SHADOW_STACK_ALLOC_SIZE, 0); + + if (((long)shdw_addr) <= 0) { + ksft_print_msg("map_shadow_stack failed with error code %d\n", (int)shdw_addr); + return false; + } + + write_addr = (unsigned long *)shdw_addr; + + fd = open("/proc/self/mem", O_RDWR); + if (fd == -1) + return false; + + if (gup_tests(fd, write_addr)) { + ksft_print_msg("gup tests failed\n"); + goto out; + } + + ret = true; +out: + if (shdw_addr && munmap(write_addr, SHADOW_STACK_ALLOC_SIZE)) { + ksft_print_msg("munmap failed with error code %d\n", ret); + ret = false; + } + + return ret; +} + +volatile bool break_loop; + +void sigusr1_handler(int signo) +{ + break_loop = true; +} + +bool sigusr1_signal_test(void) +{ + struct sigaction sa = {}; + + sa.sa_handler = sigusr1_handler; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + if (sigaction(SIGUSR1, &sa, NULL)) { + ksft_print_msg("Registering signal handler for SIGUSR1 failed\n"); + return false; + } + + return true; +} + +/* + * shadow stack signal test. shadow stack must be enabled. + * register a signal, fork another thread which is waiting + * on signal. Send a signal from parent to child, verify + * that signal was received by child. If not test fails + */ +bool shadow_stack_signal_test(unsigned long test_num, void *ctx) +{ + int pid = 0, child_status = 0, ret = 0; + unsigned long ss_status = 0; + + ksft_print_msg("Exercising shadow stack signal test\n"); + + ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS, &ss_status, 0, 0, 0); + if (ret) { + ksft_print_msg("Shadow stack get status prctl failed with errorcode %d\n", ret); + return false; + } + + if (!(ss_status & PR_SHADOW_STACK_ENABLE)) + ksft_print_msg("Shadow stack is not enabled, should be enabled via glibc\n"); + + /* this should be caught by signal handler and do an exit */ + if (!sigusr1_signal_test()) { + ksft_print_msg("Registering sigusr1 handler failed\n"); + exit(-1); + } + + pid = fork(); + + if (pid == -1) { + ksft_print_msg("Signal test: fork failed\n"); + goto out; + } + + if (pid == 0) { + while (!break_loop) + sleep(1); + + exit(11); + /* child shouldn't go beyond here */ + } + + /* send SIGUSR1 to child */ + kill(pid, SIGUSR1); + wait(&child_status); + +out: + + return (WIFEXITED(child_status) && + WEXITSTATUS(child_status) == 11); +} + +int execute_shadow_stack_tests(void) +{ + int ret = 0; + unsigned long test_count = 0; + unsigned long shstk_status = 0; + bool test_pass = false; + + ksft_print_msg("Executing RISC-V shadow stack self tests\n"); + ksft_set_plan(RISCV_SHADOW_STACK_TESTS); + + ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS, &shstk_status, 0, 0, 0); + + if (ret != 0) + ksft_exit_fail_msg("Get shadow stack status failed with %d\n", ret); + + /* + * If we are here that means get shadow stack status succeeded and + * thus shadow stack support is baked in the kernel. + */ + while (test_count < RISCV_SHADOW_STACK_TESTS) { + test_pass = (*shstk_tests[test_count].t_func)(test_count, NULL); + ksft_test_result(test_pass, shstk_tests[test_count].name); + test_count++; + } + + ksft_finished(); + + return 0; +} + +#pragma GCC pop_options diff --git a/tools/testing/selftests/riscv/cfi/shadowstack.h b/tools/testing/selftests/riscv/cfi/shadowstack.h new file mode 100644 index 00000000000000..0be510167de30a --- /dev/null +++ b/tools/testing/selftests/riscv/cfi/shadowstack.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef SELFTEST_SHADOWSTACK_TEST_H +#define SELFTEST_SHADOWSTACK_TEST_H +#include +#include + +/* + * a cfi test returns true for success or false for fail + * takes a number for test number to index into array and void pointer. + */ +typedef bool (*shstk_test_func)(unsigned long test_num, void *); + +struct shadow_stack_tests { + char *name; + shstk_test_func t_func; +}; + +bool shadow_stack_fork_test(unsigned long test_num, void *ctx); +bool shadow_stack_map_test(unsigned long test_num, void *ctx); +bool shadow_stack_protection_test(unsigned long test_num, void *ctx); +bool shadow_stack_gup_tests(unsigned long test_num, void *ctx); +bool shadow_stack_signal_test(unsigned long test_num, void *ctx); + +int execute_shadow_stack_tests(void); + +#endif From a89632908e24311f21c4bc441d9b9208286cb13a Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Wed, 15 Jan 2025 10:30:41 -0800 Subject: [PATCH 82/91] drivers/perf: riscv: Add SBI v3.0 flag There are new PMU related features introduced in SBI v3.0. 1. Raw Event v2 which allows mhpmeventX value to be 56 bit wide. 2. Get Event info function to do a bulk query at one shot. Signed-off-by: Atish Patra Link: https://lore.kernel.org/r/20250115-pmu_event_info-v2-1-84815b70383b@rivosinc.com Signed-off-by: Alexandre Ghiti --- drivers/perf/riscv_pmu_sbi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c index 698de8ddf895ba..cfd6946fca42e6 100644 --- a/drivers/perf/riscv_pmu_sbi.c +++ b/drivers/perf/riscv_pmu_sbi.c @@ -63,6 +63,7 @@ PMU_FORMAT_ATTR(event, "config:0-47"); PMU_FORMAT_ATTR(firmware, "config:62-63"); static bool sbi_v2_available; +static bool sbi_v3_available; static DEFINE_STATIC_KEY_FALSE(sbi_pmu_snapshot_available); #define sbi_pmu_snapshot_available() \ static_branch_unlikely(&sbi_pmu_snapshot_available) @@ -1452,6 +1453,9 @@ static int __init pmu_sbi_devinit(void) if (sbi_spec_version >= sbi_mk_version(2, 0)) sbi_v2_available = true; + if (sbi_spec_version >= sbi_mk_version(3, 0)) + sbi_v3_available = true; + ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_RISCV_STARTING, "perf/riscv/pmu:starting", pmu_sbi_starting_cpu, pmu_sbi_dying_cpu); From 2c888287408dcea03d7f4390f0230d9724aa8222 Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Wed, 15 Jan 2025 10:30:42 -0800 Subject: [PATCH 83/91] drivers/perf: riscv: Add raw event v2 support SBI v3.0 introduced a new raw event type that allows wider mhpmeventX width to be programmed via CFG_MATCH. Use the raw event v2 if SBI v3.0 is available. Signed-off-by: Atish Patra Link: https://lore.kernel.org/r/20250115-pmu_event_info-v2-2-84815b70383b@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/sbi.h | 4 ++++ drivers/perf/riscv_pmu_sbi.c | 16 ++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index 3d250824178bd5..6ce385a3a7bb7d 100644 --- a/arch/riscv/include/asm/sbi.h +++ b/arch/riscv/include/asm/sbi.h @@ -160,7 +160,10 @@ struct riscv_pmu_snapshot_data { #define RISCV_PMU_RAW_EVENT_MASK GENMASK_ULL(47, 0) #define RISCV_PMU_PLAT_FW_EVENT_MASK GENMASK_ULL(61, 0) +/* SBI v3.0 allows extended hpmeventX width value */ +#define RISCV_PMU_RAW_EVENT_V2_MASK GENMASK_ULL(55, 0) #define RISCV_PMU_RAW_EVENT_IDX 0x20000 +#define RISCV_PMU_RAW_EVENT_V2_IDX 0x30000 #define RISCV_PLAT_FW_EVENT 0xFFFF /** General pmu event codes specified in SBI PMU extension */ @@ -218,6 +221,7 @@ enum sbi_pmu_event_type { SBI_PMU_EVENT_TYPE_HW = 0x0, SBI_PMU_EVENT_TYPE_CACHE = 0x1, SBI_PMU_EVENT_TYPE_RAW = 0x2, + SBI_PMU_EVENT_TYPE_RAW_V2 = 0x3, SBI_PMU_EVENT_TYPE_FW = 0xf, }; diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c index cfd6946fca42e6..273ed70098a388 100644 --- a/drivers/perf/riscv_pmu_sbi.c +++ b/drivers/perf/riscv_pmu_sbi.c @@ -59,7 +59,7 @@ asm volatile(ALTERNATIVE( \ #define PERF_EVENT_FLAG_USER_ACCESS BIT(SYSCTL_USER_ACCESS) #define PERF_EVENT_FLAG_LEGACY BIT(SYSCTL_LEGACY) -PMU_FORMAT_ATTR(event, "config:0-47"); +PMU_FORMAT_ATTR(event, "config:0-55"); PMU_FORMAT_ATTR(firmware, "config:62-63"); static bool sbi_v2_available; @@ -527,8 +527,10 @@ static int pmu_sbi_event_map(struct perf_event *event, u64 *econfig) break; case PERF_TYPE_RAW: /* - * As per SBI specification, the upper 16 bits must be unused - * for a hardware raw event. + * As per SBI v0.3 specification, + * -- the upper 16 bits must be unused for a hardware raw event. + * As per SBI v3.0 specification, + * -- the upper 8 bits must be unused for a hardware raw event. * Bits 63:62 are used to distinguish between raw events * 00 - Hardware raw event * 10 - SBI firmware events @@ -537,8 +539,14 @@ static int pmu_sbi_event_map(struct perf_event *event, u64 *econfig) switch (config >> 62) { case 0: + if (sbi_v3_available) { + /* Return error any bits [56-63] is set as it is not allowed by the spec */ + if (!(config & ~RISCV_PMU_RAW_EVENT_V2_MASK)) { + *econfig = config & RISCV_PMU_RAW_EVENT_V2_MASK; + ret = RISCV_PMU_RAW_EVENT_V2_IDX; + } /* Return error any bits [48-63] is set as it is not allowed by the spec */ - if (!(config & ~RISCV_PMU_RAW_EVENT_MASK)) { + } else if (!(config & ~RISCV_PMU_RAW_EVENT_MASK)) { *econfig = config & RISCV_PMU_RAW_EVENT_MASK; ret = RISCV_PMU_RAW_EVENT_IDX; } From b858a727748d48c7389b28721a7b55fb32a9e816 Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Wed, 15 Jan 2025 10:30:43 -0800 Subject: [PATCH 84/91] RISC-V: KVM: Add support for Raw event v2 SBI v3.0 introuced a new raw event type v2 for wider mhpmeventX programming. Add the support in kvm for that. Signed-off-by: Atish Patra Link: https://lore.kernel.org/r/20250115-pmu_event_info-v2-3-84815b70383b@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/kvm/vcpu_pmu.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/riscv/kvm/vcpu_pmu.c b/arch/riscv/kvm/vcpu_pmu.c index 78ac3216a54ddb..15d71a7b75ba63 100644 --- a/arch/riscv/kvm/vcpu_pmu.c +++ b/arch/riscv/kvm/vcpu_pmu.c @@ -60,6 +60,7 @@ static u32 kvm_pmu_get_perf_event_type(unsigned long eidx) type = PERF_TYPE_HW_CACHE; break; case SBI_PMU_EVENT_TYPE_RAW: + case SBI_PMU_EVENT_TYPE_RAW_V2: case SBI_PMU_EVENT_TYPE_FW: type = PERF_TYPE_RAW; break; @@ -128,6 +129,9 @@ static u64 kvm_pmu_get_perf_event_config(unsigned long eidx, uint64_t evt_data) case SBI_PMU_EVENT_TYPE_RAW: config = evt_data & RISCV_PMU_RAW_EVENT_MASK; break; + case SBI_PMU_EVENT_TYPE_RAW_V2: + config = evt_data & RISCV_PMU_RAW_EVENT_V2_MASK; + break; case SBI_PMU_EVENT_TYPE_FW: if (ecode < SBI_PMU_FW_MAX) config = (1ULL << 63) | ecode; From c708803cf2e39d1efda586042c5fe5a5a4257a87 Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Wed, 15 Jan 2025 10:30:44 -0800 Subject: [PATCH 85/91] drivers/perf: riscv: Implement PMU event info function With the new SBI PMU event info function, we can query the availability of the all standard SBI PMU events at boot time with a single ecall. This improves the bootime by avoiding making an SBI call for each standard PMU event. Since this function is defined only in SBI v3.0, invoke this only if the underlying SBI implementation is v3.0 or higher. Signed-off-by: Atish Patra Link: https://lore.kernel.org/r/20250115-pmu_event_info-v2-4-84815b70383b@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/sbi.h | 9 +++++ drivers/perf/riscv_pmu_sbi.c | 68 ++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index 6ce385a3a7bb7d..77b6997eb6c5f8 100644 --- a/arch/riscv/include/asm/sbi.h +++ b/arch/riscv/include/asm/sbi.h @@ -135,6 +135,7 @@ enum sbi_ext_pmu_fid { SBI_EXT_PMU_COUNTER_FW_READ, SBI_EXT_PMU_COUNTER_FW_READ_HI, SBI_EXT_PMU_SNAPSHOT_SET_SHMEM, + SBI_EXT_PMU_EVENT_GET_INFO, }; union sbi_pmu_ctr_info { @@ -158,6 +159,14 @@ struct riscv_pmu_snapshot_data { u64 reserved[447]; }; +struct riscv_pmu_event_info { + u32 event_idx; + u32 output; + u64 event_data; +}; + +#define RISCV_PMU_EVENT_INFO_OUTPUT_MASK 0x01 + #define RISCV_PMU_RAW_EVENT_MASK GENMASK_ULL(47, 0) #define RISCV_PMU_PLAT_FW_EVENT_MASK GENMASK_ULL(61, 0) /* SBI v3.0 allows extended hpmeventX width value */ diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c index 273ed70098a388..111c09cba24140 100644 --- a/drivers/perf/riscv_pmu_sbi.c +++ b/drivers/perf/riscv_pmu_sbi.c @@ -299,6 +299,66 @@ static struct sbi_pmu_event_data pmu_cache_event_map[PERF_COUNT_HW_CACHE_MAX] }, }; +static int pmu_sbi_check_event_info(void) +{ + int num_events = ARRAY_SIZE(pmu_hw_event_map) + PERF_COUNT_HW_CACHE_MAX * + PERF_COUNT_HW_CACHE_OP_MAX * PERF_COUNT_HW_CACHE_RESULT_MAX; + struct riscv_pmu_event_info *event_info_shmem; + phys_addr_t base_addr; + int i, j, k, result = 0, count = 0; + struct sbiret ret; + + event_info_shmem = kcalloc(num_events, sizeof(*event_info_shmem), GFP_KERNEL); + if (!event_info_shmem) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(pmu_hw_event_map); i++) + event_info_shmem[count++].event_idx = pmu_hw_event_map[i].event_idx; + + for (i = 0; i < ARRAY_SIZE(pmu_cache_event_map); i++) { + for (int j = 0; j < ARRAY_SIZE(pmu_cache_event_map[i]); j++) { + for (int k = 0; k < ARRAY_SIZE(pmu_cache_event_map[i][j]); k++) + event_info_shmem[count++].event_idx = + pmu_cache_event_map[i][j][k].event_idx; + } + } + + base_addr = __pa(event_info_shmem); + if (IS_ENABLED(CONFIG_32BIT)) + ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_EVENT_GET_INFO, lower_32_bits(base_addr), + upper_32_bits(base_addr), count, 0, 0, 0); + else + ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_EVENT_GET_INFO, base_addr, 0, + count, 0, 0, 0); + if (ret.error) { + result = -EOPNOTSUPP; + goto free_mem; + } + + for (i = 0; i < ARRAY_SIZE(pmu_hw_event_map); i++) { + if (!(event_info_shmem[i].output & RISCV_PMU_EVENT_INFO_OUTPUT_MASK)) + pmu_hw_event_map[i].event_idx = -ENOENT; + } + + count = ARRAY_SIZE(pmu_hw_event_map); + + for (i = 0; i < ARRAY_SIZE(pmu_cache_event_map); i++) { + for (j = 0; j < ARRAY_SIZE(pmu_cache_event_map[i]); j++) { + for (k = 0; k < ARRAY_SIZE(pmu_cache_event_map[i][j]); k++) { + if (!(event_info_shmem[count].output & + RISCV_PMU_EVENT_INFO_OUTPUT_MASK)) + pmu_cache_event_map[i][j][k].event_idx = -ENOENT; + count++; + } + } + } + +free_mem: + kfree(event_info_shmem); + + return result; +} + static void pmu_sbi_check_event(struct sbi_pmu_event_data *edata) { struct sbiret ret; @@ -316,6 +376,14 @@ static void pmu_sbi_check_event(struct sbi_pmu_event_data *edata) static void pmu_sbi_check_std_events(struct work_struct *work) { + int ret; + + if (sbi_v3_available) { + ret = pmu_sbi_check_event_info(); + if (!ret) + return; + } + for (int i = 0; i < ARRAY_SIZE(pmu_hw_event_map); i++) pmu_sbi_check_event(&pmu_hw_event_map[i]); From ad956fa0294f90a046144b791664b620baf72519 Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Wed, 15 Jan 2025 10:30:45 -0800 Subject: [PATCH 86/91] drivers/perf: riscv: Export PMU event info function The event mapping function can be used in event info function to find out the corresponding SBI PMU event encoding during the get_event_info function as well. Refactor and export it so that it can be invoked from kvm and internal driver. Signed-off-by: Atish Patra Link: https://lore.kernel.org/r/20250115-pmu_event_info-v2-5-84815b70383b@rivosinc.com Signed-off-by: Alexandre Ghiti --- drivers/perf/riscv_pmu_sbi.c | 124 ++++++++++++++++++--------------- include/linux/perf/riscv_pmu.h | 2 + 2 files changed, 69 insertions(+), 57 deletions(-) diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c index 111c09cba24140..b0ae62ce5d89c3 100644 --- a/drivers/perf/riscv_pmu_sbi.c +++ b/drivers/perf/riscv_pmu_sbi.c @@ -100,6 +100,7 @@ static unsigned int riscv_pmu_irq; /* Cache the available counters in a bitmask */ static unsigned long cmask; +static int pmu_event_find_cache(u64 config); struct sbi_pmu_event_data { union { union { @@ -411,6 +412,71 @@ static bool pmu_sbi_ctr_is_fw(int cidx) return (info->type == SBI_PMU_CTR_TYPE_FW) ? true : false; } +int riscv_pmu_get_event_info(u32 type, u64 config, u64 *econfig) +{ + int ret = -ENOENT; + + switch (type) { + case PERF_TYPE_HARDWARE: + if (config >= PERF_COUNT_HW_MAX) + return -EINVAL; + ret = pmu_hw_event_map[config].event_idx; + break; + case PERF_TYPE_HW_CACHE: + ret = pmu_event_find_cache(config); + break; + case PERF_TYPE_RAW: + /* + * As per SBI v0.3 specification, + * -- the upper 16 bits must be unused for a hardware raw event. + * As per SBI v3.0 specification, + * -- the upper 8 bits must be unused for a hardware raw event. + * Bits 63:62 are used to distinguish between raw events + * 00 - Hardware raw event + * 10 - SBI firmware events + * 11 - Risc-V platform specific firmware event + */ + switch (config >> 62) { + case 0: + if (sbi_v3_available) { + /* Return error any bits [56-63] is set as it is not allowed by the spec */ + if (!(config & ~RISCV_PMU_RAW_EVENT_V2_MASK)) { + if (econfig) + *econfig = config & RISCV_PMU_RAW_EVENT_V2_MASK; + ret = RISCV_PMU_RAW_EVENT_V2_IDX; + } + /* Return error any bits [48-63] is set as it is not allowed by the spec */ + } else if (!(config & ~RISCV_PMU_RAW_EVENT_MASK)) { + if (econfig) + *econfig = config & RISCV_PMU_RAW_EVENT_MASK; + ret = RISCV_PMU_RAW_EVENT_IDX; + } + break; + case 2: + ret = (config & 0xFFFF) | (SBI_PMU_EVENT_TYPE_FW << 16); + break; + case 3: + /* + * For Risc-V platform specific firmware events + * Event code - 0xFFFF + * Event data - raw event encoding + */ + ret = SBI_PMU_EVENT_TYPE_FW << 16 | RISCV_PLAT_FW_EVENT; + if (econfig) + *econfig = config & RISCV_PMU_PLAT_FW_EVENT_MASK; + break; + default: + break; + } + break; + default: + break; + } + + return ret; +} +EXPORT_SYMBOL(riscv_pmu_get_event_info); + /* * Returns the counter width of a programmable counter and number of hardware * counters. As we don't support heterogeneous CPUs yet, it is okay to just @@ -576,7 +642,6 @@ static int pmu_sbi_event_map(struct perf_event *event, u64 *econfig) { u32 type = event->attr.type; u64 config = event->attr.config; - int ret = -ENOENT; /* * Ensure we are finished checking standard hardware events for @@ -584,62 +649,7 @@ static int pmu_sbi_event_map(struct perf_event *event, u64 *econfig) */ flush_work(&check_std_events_work); - switch (type) { - case PERF_TYPE_HARDWARE: - if (config >= PERF_COUNT_HW_MAX) - return -EINVAL; - ret = pmu_hw_event_map[event->attr.config].event_idx; - break; - case PERF_TYPE_HW_CACHE: - ret = pmu_event_find_cache(config); - break; - case PERF_TYPE_RAW: - /* - * As per SBI v0.3 specification, - * -- the upper 16 bits must be unused for a hardware raw event. - * As per SBI v3.0 specification, - * -- the upper 8 bits must be unused for a hardware raw event. - * Bits 63:62 are used to distinguish between raw events - * 00 - Hardware raw event - * 10 - SBI firmware events - * 11 - Risc-V platform specific firmware event - */ - - switch (config >> 62) { - case 0: - if (sbi_v3_available) { - /* Return error any bits [56-63] is set as it is not allowed by the spec */ - if (!(config & ~RISCV_PMU_RAW_EVENT_V2_MASK)) { - *econfig = config & RISCV_PMU_RAW_EVENT_V2_MASK; - ret = RISCV_PMU_RAW_EVENT_V2_IDX; - } - /* Return error any bits [48-63] is set as it is not allowed by the spec */ - } else if (!(config & ~RISCV_PMU_RAW_EVENT_MASK)) { - *econfig = config & RISCV_PMU_RAW_EVENT_MASK; - ret = RISCV_PMU_RAW_EVENT_IDX; - } - break; - case 2: - ret = (config & 0xFFFF) | (SBI_PMU_EVENT_TYPE_FW << 16); - break; - case 3: - /* - * For Risc-V platform specific firmware events - * Event code - 0xFFFF - * Event data - raw event encoding - */ - ret = SBI_PMU_EVENT_TYPE_FW << 16 | RISCV_PLAT_FW_EVENT; - *econfig = config & RISCV_PMU_PLAT_FW_EVENT_MASK; - break; - default: - break; - } - break; - default: - break; - } - - return ret; + return riscv_pmu_get_event_info(type, config, econfig); } static void pmu_sbi_snapshot_free(struct riscv_pmu *pmu) diff --git a/include/linux/perf/riscv_pmu.h b/include/linux/perf/riscv_pmu.h index 701974639ff2ca..4a5e3209c473bf 100644 --- a/include/linux/perf/riscv_pmu.h +++ b/include/linux/perf/riscv_pmu.h @@ -91,6 +91,8 @@ struct riscv_pmu *riscv_pmu_alloc(void); int riscv_pmu_get_hpm_info(u32 *hw_ctr_width, u32 *num_hw_ctr); #endif +int riscv_pmu_get_event_info(u32 type, u64 config, u64 *econfig); + #endif /* CONFIG_RISCV_PMU */ #endif /* _RISCV_PMU_H */ From eb15b56e48bbe8545eb028cd6c810ea269c8b7b0 Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Wed, 15 Jan 2025 10:30:46 -0800 Subject: [PATCH 87/91] KVM: Add a helper function to validate vcpu gpa range The arch specific code may need to validate a gpa range if it is a shared memory between the host and the guest. Currently, there are few places where it is used in RISC-V implementation. Given the nature of the function it may be used for other architectures. Hence, a common helper function is added. Signed-off-by: Atish Patra Link: https://lore.kernel.org/r/20250115-pmu_event_info-v2-6-84815b70383b@rivosinc.com Signed-off-by: Alexandre Ghiti --- include/linux/kvm_host.h | 2 ++ virt/kvm/kvm_main.c | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 291d49b9bf0549..adda61cc4072c0 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1383,6 +1383,8 @@ static inline int kvm_vcpu_map_readonly(struct kvm_vcpu *vcpu, gpa_t gpa, unsigned long kvm_vcpu_gfn_to_hva(struct kvm_vcpu *vcpu, gfn_t gfn); unsigned long kvm_vcpu_gfn_to_hva_prot(struct kvm_vcpu *vcpu, gfn_t gfn, bool *writable); +int kvm_vcpu_validate_gpa_range(struct kvm_vcpu *vcpu, gpa_t gpa, unsigned long len, + bool write_access); int kvm_vcpu_read_guest_page(struct kvm_vcpu *vcpu, gfn_t gfn, void *data, int offset, int len); int kvm_vcpu_read_guest_atomic(struct kvm_vcpu *vcpu, gpa_t gpa, void *data, diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index e85b33a92624d9..3f52f5571fa68b 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -3301,6 +3301,27 @@ int kvm_vcpu_write_guest(struct kvm_vcpu *vcpu, gpa_t gpa, const void *data, } EXPORT_SYMBOL_GPL(kvm_vcpu_write_guest); +int kvm_vcpu_validate_gpa_range(struct kvm_vcpu *vcpu, gpa_t gpa, unsigned long len, + bool write_access) +{ + gfn_t gfn = gpa >> PAGE_SHIFT; + int seg; + int offset = offset_in_page(gpa); + bool writable = false; + unsigned long hva; + + while ((seg = next_segment(len, offset)) != 0) { + hva = kvm_vcpu_gfn_to_hva_prot(vcpu, gfn, &writable); + if (kvm_is_error_hva(hva) || (writable ^ write_access)) + return -EPERM; + offset = 0; + len -= seg; + ++gfn; + } + return 0; +} +EXPORT_SYMBOL_GPL(kvm_vcpu_validate_gpa_range); + static int __kvm_gfn_to_hva_cache_init(struct kvm_memslots *slots, struct gfn_to_hva_cache *ghc, gpa_t gpa, unsigned long len) From 5e638ec57aba76d4767483454fd6118d3845e0b1 Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Wed, 15 Jan 2025 10:30:47 -0800 Subject: [PATCH 88/91] RISC-V: KVM: Use the new gpa range validate helper function Remove the duplicate code and use the new helper function to validate the shared memory gpa address. Signed-off-by: Atish Patra Link: https://lore.kernel.org/r/20250115-pmu_event_info-v2-7-84815b70383b@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/kvm/vcpu_pmu.c | 5 +---- arch/riscv/kvm/vcpu_sbi_sta.c | 6 ++---- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/arch/riscv/kvm/vcpu_pmu.c b/arch/riscv/kvm/vcpu_pmu.c index 15d71a7b75ba63..163bd4403fd098 100644 --- a/arch/riscv/kvm/vcpu_pmu.c +++ b/arch/riscv/kvm/vcpu_pmu.c @@ -409,8 +409,6 @@ int kvm_riscv_vcpu_pmu_snapshot_set_shmem(struct kvm_vcpu *vcpu, unsigned long s int snapshot_area_size = sizeof(struct riscv_pmu_snapshot_data); int sbiret = 0; gpa_t saddr; - unsigned long hva; - bool writable; if (!kvpmu || flags) { sbiret = SBI_ERR_INVALID_PARAM; @@ -432,8 +430,7 @@ int kvm_riscv_vcpu_pmu_snapshot_set_shmem(struct kvm_vcpu *vcpu, unsigned long s goto out; } - hva = kvm_vcpu_gfn_to_hva_prot(vcpu, saddr >> PAGE_SHIFT, &writable); - if (kvm_is_error_hva(hva) || !writable) { + if (kvm_vcpu_validate_gpa_range(vcpu, saddr, PAGE_SIZE, true)) { sbiret = SBI_ERR_INVALID_ADDRESS; goto out; } diff --git a/arch/riscv/kvm/vcpu_sbi_sta.c b/arch/riscv/kvm/vcpu_sbi_sta.c index 5f35427114c1da..67dfb613df6a8d 100644 --- a/arch/riscv/kvm/vcpu_sbi_sta.c +++ b/arch/riscv/kvm/vcpu_sbi_sta.c @@ -85,8 +85,6 @@ static int kvm_sbi_sta_steal_time_set_shmem(struct kvm_vcpu *vcpu) unsigned long shmem_phys_hi = cp->a1; u32 flags = cp->a2; struct sbi_sta_struct zero_sta = {0}; - unsigned long hva; - bool writable; gpa_t shmem; int ret; @@ -111,8 +109,8 @@ static int kvm_sbi_sta_steal_time_set_shmem(struct kvm_vcpu *vcpu) return SBI_ERR_INVALID_ADDRESS; } - hva = kvm_vcpu_gfn_to_hva_prot(vcpu, shmem >> PAGE_SHIFT, &writable); - if (kvm_is_error_hva(hva) || !writable) + /* The spec requires the shmem to be 64-byte aligned. */ + if (kvm_vcpu_validate_gpa_range(vcpu, shmem, 64, true)) return SBI_ERR_INVALID_ADDRESS; ret = kvm_vcpu_write_guest(vcpu, shmem, &zero_sta, sizeof(zero_sta)); From 3601a57bd9ff776aada71c22265df6aa1ae0e8b2 Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Wed, 15 Jan 2025 10:30:48 -0800 Subject: [PATCH 89/91] RISC-V: KVM: Implement get event info function The new get_event_info funciton allows the guest to query the presence of multiple events with single SBI call. Currently, the perf driver in linux guest invokes it for all the standard SBI PMU events. Support the SBI function implementation in KVM as well. Signed-off-by: Atish Patra Link: https://lore.kernel.org/r/20250115-pmu_event_info-v2-8-84815b70383b@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/kvm_vcpu_pmu.h | 3 ++ arch/riscv/kvm/vcpu_pmu.c | 66 +++++++++++++++++++++++++++ arch/riscv/kvm/vcpu_sbi_pmu.c | 3 ++ 3 files changed, 72 insertions(+) diff --git a/arch/riscv/include/asm/kvm_vcpu_pmu.h b/arch/riscv/include/asm/kvm_vcpu_pmu.h index 1d85b661750884..9a930afc8f5713 100644 --- a/arch/riscv/include/asm/kvm_vcpu_pmu.h +++ b/arch/riscv/include/asm/kvm_vcpu_pmu.h @@ -98,6 +98,9 @@ void kvm_riscv_vcpu_pmu_init(struct kvm_vcpu *vcpu); int kvm_riscv_vcpu_pmu_snapshot_set_shmem(struct kvm_vcpu *vcpu, unsigned long saddr_low, unsigned long saddr_high, unsigned long flags, struct kvm_vcpu_sbi_return *retdata); +int kvm_riscv_vcpu_pmu_event_info(struct kvm_vcpu *vcpu, unsigned long saddr_low, + unsigned long saddr_high, unsigned long num_events, + unsigned long flags, struct kvm_vcpu_sbi_return *retdata); void kvm_riscv_vcpu_pmu_deinit(struct kvm_vcpu *vcpu); void kvm_riscv_vcpu_pmu_reset(struct kvm_vcpu *vcpu); diff --git a/arch/riscv/kvm/vcpu_pmu.c b/arch/riscv/kvm/vcpu_pmu.c index 163bd4403fd098..70a6bdfc42f5e8 100644 --- a/arch/riscv/kvm/vcpu_pmu.c +++ b/arch/riscv/kvm/vcpu_pmu.c @@ -453,6 +453,72 @@ int kvm_riscv_vcpu_pmu_snapshot_set_shmem(struct kvm_vcpu *vcpu, unsigned long s return 0; } +int kvm_riscv_vcpu_pmu_event_info(struct kvm_vcpu *vcpu, unsigned long saddr_low, + unsigned long saddr_high, unsigned long num_events, + unsigned long flags, struct kvm_vcpu_sbi_return *retdata) +{ + struct riscv_pmu_event_info *einfo; + int shmem_size = num_events * sizeof(*einfo); + gpa_t shmem; + u32 eidx, etype; + u64 econfig; + int ret; + + if (flags != 0 || (saddr_low & (SZ_16 - 1))) { + ret = SBI_ERR_INVALID_PARAM; + goto out; + } + + shmem = saddr_low; + if (saddr_high != 0) { + if (IS_ENABLED(CONFIG_32BIT)) { + shmem |= ((gpa_t)saddr_high << 32); + } else { + ret = SBI_ERR_INVALID_ADDRESS; + goto out; + } + } + + if (kvm_vcpu_validate_gpa_range(vcpu, shmem, shmem_size, true)) { + ret = SBI_ERR_INVALID_ADDRESS; + goto out; + } + + einfo = kzalloc(shmem_size, GFP_KERNEL); + if (!einfo) + return -ENOMEM; + + ret = kvm_vcpu_read_guest(vcpu, shmem, einfo, shmem_size); + if (ret) { + ret = SBI_ERR_FAILURE; + goto free_mem; + } + + for (int i = 0; i < num_events; i++) { + eidx = einfo[i].event_idx; + etype = kvm_pmu_get_perf_event_type(eidx); + econfig = kvm_pmu_get_perf_event_config(eidx, einfo[i].event_data); + ret = riscv_pmu_get_event_info(etype, econfig, NULL); + if (ret > 0) + einfo[i].output = 1; + else + einfo[i].output = 0; + } + + kvm_vcpu_write_guest(vcpu, shmem, einfo, shmem_size); + if (ret) { + ret = SBI_ERR_FAILURE; + goto free_mem; + } + +free_mem: + kfree(einfo); +out: + retdata->err_val = ret; + + return 0; +} + int kvm_riscv_vcpu_pmu_num_ctrs(struct kvm_vcpu *vcpu, struct kvm_vcpu_sbi_return *retdata) { diff --git a/arch/riscv/kvm/vcpu_sbi_pmu.c b/arch/riscv/kvm/vcpu_sbi_pmu.c index e4be34e03e8384..a020d979d1795a 100644 --- a/arch/riscv/kvm/vcpu_sbi_pmu.c +++ b/arch/riscv/kvm/vcpu_sbi_pmu.c @@ -73,6 +73,9 @@ static int kvm_sbi_ext_pmu_handler(struct kvm_vcpu *vcpu, struct kvm_run *run, case SBI_EXT_PMU_SNAPSHOT_SET_SHMEM: ret = kvm_riscv_vcpu_pmu_snapshot_set_shmem(vcpu, cp->a0, cp->a1, cp->a2, retdata); break; + case SBI_EXT_PMU_EVENT_GET_INFO: + ret = kvm_riscv_vcpu_pmu_event_info(vcpu, cp->a0, cp->a1, cp->a2, cp->a3, retdata); + break; default: retdata->err_val = SBI_ERR_NOT_SUPPORTED; } From 064667ef562469116b1e416f4a344d8a996fa20a Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Wed, 15 Jan 2025 10:30:49 -0800 Subject: [PATCH 90/91] RISC-V: KVM: Upgrade the supported SBI version to 3.0 Upgrade the SBI version to v3.0 so that corresponding features can be enabled in the guest. Signed-off-by: Atish Patra Link: https://lore.kernel.org/r/20250115-pmu_event_info-v2-9-84815b70383b@rivosinc.com Signed-off-by: Alexandre Ghiti --- arch/riscv/include/asm/kvm_vcpu_sbi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/include/asm/kvm_vcpu_sbi.h b/arch/riscv/include/asm/kvm_vcpu_sbi.h index 4ed6203cdd3079..194299e0ab0ef0 100644 --- a/arch/riscv/include/asm/kvm_vcpu_sbi.h +++ b/arch/riscv/include/asm/kvm_vcpu_sbi.h @@ -11,7 +11,7 @@ #define KVM_SBI_IMPID 3 -#define KVM_SBI_VERSION_MAJOR 2 +#define KVM_SBI_VERSION_MAJOR 3 #define KVM_SBI_VERSION_MINOR 0 enum kvm_riscv_sbi_ext_status { From eed07919b6144f236840fe3c737dd03c872bf588 Mon Sep 17 00:00:00 2001 From: Alexandre Ghiti Date: Tue, 6 May 2025 11:43:35 +0000 Subject: [PATCH 91/91] Adding CI files Signed-off-by: Alexandre Ghiti --- .github/.MISSING_LINARO_DEP.swp | Bin 0 -> 12288 bytes .github/.swp | Bin 0 -> 12288 bytes .github/MISSING_LINARO_DEP | 11 + .github/scripts/.patches.sh.swp | Bin 0 -> 12288 bytes .github/scripts/build_ubuntu_defconfig.sh | 31 + .github/scripts/ci/__init__.py | 2 + .github/scripts/ci/base.py | 120 + .github/scripts/ci/shelltest.py | 67 + .github/scripts/cleanup_pr.py | 238 + .github/scripts/config.json | 28 + .github/scripts/defconfig.sh | 18 + .github/scripts/isolated_tests.sh | 40 + .github/scripts/kselftest.sh | 22 + .github/scripts/libhugetlbfs.sh | 31 + .github/scripts/libs/__init__.py | 6 + .github/scripts/libs/context.py | 95 + .github/scripts/libs/email.py | 66 + .github/scripts/libs/githubtool.py | 77 + .github/scripts/libs/patchwork.py | 181 + .github/scripts/libs/repotool.py | 92 + .github/scripts/libs/utils.py | 105 + .github/scripts/ltp.sh | 43 + .github/scripts/pw_ci.py | 343 + .../scripts/pw_tests/build_rv32_defconfig.sh | 26 + .../pw_tests/build_rv64_clang_allmodconfig.sh | 88 + .../pw_tests/build_rv64_gcc_allmodconfig.sh | 88 + .../build_rv64_nommu_k210_defconfig.sh | 26 + .../build_rv64_nommu_virt_defconfig.sh | 26 + .github/scripts/pw_tests/checkpatch.sh | 34 + .github/scripts/pw_tests/dtb_warn_rv64.sh | 61 + .github/scripts/pw_tests/header_inline.sh | 19 + .github/scripts/pw_tests/kdoc.sh | 50 + .github/scripts/pw_tests/module_param.sh | 21 + .github/scripts/pw_tests/verify_fixes.sh | 212 + .github/scripts/pw_tests/verify_signedoff.sh | 81 + .github/scripts/requirements.txt | 5 + .github/scripts/series.sh | 40 + .github/scripts/series/build_all.sh | 18 + .github/scripts/series/build_kernel.sh | 94 + .../scripts/series/build_only_defconfig.sh | 13 + .../scripts/series/build_only_kselftest.sh | 15 + .github/scripts/series/build_selftest.sh | 63 + .../scripts/series/generate_build_configs.sh | 36 + .github/scripts/series/generate_kconfigs.sh | 65 + .github/scripts/series/generate_metadata.py | 37 + .../series/generate_qemu_test_configs.sh | 24 + .github/scripts/series/generate_test_runs.sh | 47 + .../scripts/series/github_ci_squad_results.py | 78 + .../kconfigs/defconfig/early_boot_alternative | 2 + .../defconfig/early_boot_alternative_reloc | 3 + .../scripts/series/kconfigs/defconfig/flatmem | 3 + .../kconfigs/defconfig/hardened_usercopy_slub | 2 + .../scripts/series/kconfigs/defconfig/kasan | 2 + .../series/kconfigs/defconfig/kasan_inline | 2 + .../defconfig/kasan_sparsemem_novmemmmap | 5 + .../defconfig/kasan_sparsemem_vmemmmap | 5 + .../series/kconfigs/defconfig/kasan_vmalloc | 2 + .../scripts/series/kconfigs/defconfig/kfence | 3 + .../series/kconfigs/defconfig/legacy_sbi | 4 + .../scripts/series/kconfigs/defconfig/lockdep | 3 + .../scripts/series/kconfigs/defconfig/medany | 2 + .../scripts/series/kconfigs/defconfig/medlow | 2 + .github/scripts/series/kconfigs/defconfig/noc | 3 + .../scripts/series/kconfigs/defconfig/nosmp | 1 + .github/scripts/series/kconfigs/defconfig/pmu | 4 + .../scripts/series/kconfigs/defconfig/preempt | 2 + .../series/kconfigs/defconfig/preempt_rt | 1 + .../series/kconfigs/defconfig/qspinlock | 1 + .../series/kconfigs/defconfig/randomize_base | 2 + .../scripts/series/kconfigs/defconfig/rseq | 1 + .../series/kconfigs/defconfig/rseq_debug | 3 + .../scripts/series/kconfigs/defconfig/size | 1 + .../series/kconfigs/defconfig/sparsemem | 3 + .../series/kconfigs/defconfig/spinwait | 1 + .../series/kconfigs/defconfig/strict_rwx | 1 + .../scripts/series/kconfigs/defconfig/svnapot | 1 + .../series/kconfigs/defconfig/ticket_spinlock | 1 + .../series/kconfigs/defconfig/vmap_stack | 1 + .../scripts/series/kconfigs/ubuntu_defconfig | 5504 +++++++++++++++++ .github/scripts/series/kernel_builder.sh | 35 + .github/scripts/series/kernel_tester.sh | 42 + .github/scripts/series/kselftest_prep.sh | 10 + ...tests-bpf-Add-RISC-V-specific-config.patch | 47 + .../0002-selftests-bpf-Rename-fallback.patch | 70 + ...sts-iommu-Add-RISC-V-specific-config.patch | 30 + ...004-selftests-exec-Remove-static-pie.patch | 40 + .../0005-selftests-hid-Fix-broken-build.patch | 30 + ...Add-missing-net-lib-kselftest-target.patch | 28 + .../patches/0007-BPF-kselftest-fix.patch | 32 + .../patches/0008-BPF-selftest-install.patch | 35 + ...s-clone3-Avoid-fragile-struct-poking.patch | 66 + ...s-clone3-Avoid-fragile-struct-poking.patch | 48 + ...pf-Add-missing-per-arch-include-path.patch | 54 + .../patches/0012-Missing-iommu-config.patch | 29 + .github/scripts/series/post_to_squad.py | 296 + .github/scripts/series/prepare_rootfs.sh | 111 + .github/scripts/series/qemu_test_utils.sh | 95 + .github/scripts/series/selftest_builder.sh | 24 + .github/scripts/series/test_all.sh | 17 + .github/scripts/series/test_kernel.sh | 212 + .github/scripts/series/test_only_defconfig.sh | 15 + .github/scripts/series/test_only_kselftest.sh | 24 + .../scripts/series/tuxrun_to_squad_json.py | 54 + .github/scripts/series/unpack_fw.sh | 25 + .github/scripts/series/utils.sh | 48 + .github/scripts/sync.sh | 122 + .github/scripts/sync_patchwork.py | 452 ++ .github/scripts/xfstests.sh | 46 + .github/workflows/kselftest.yml | 59 + .github/workflows/libhugetlbfs.yml | 59 + .github/workflows/patchwork.yml | 64 + .github/workflows/series.yml | 52 + .github/workflows/sync.yml | 82 + .github/workflows/testsuites.yml | 212 + 114 files changed, 11119 insertions(+) create mode 100644 .github/.MISSING_LINARO_DEP.swp create mode 100644 .github/.swp create mode 100644 .github/MISSING_LINARO_DEP create mode 100644 .github/scripts/.patches.sh.swp create mode 100755 .github/scripts/build_ubuntu_defconfig.sh create mode 100644 .github/scripts/ci/__init__.py create mode 100644 .github/scripts/ci/base.py create mode 100644 .github/scripts/ci/shelltest.py create mode 100755 .github/scripts/cleanup_pr.py create mode 100644 .github/scripts/config.json create mode 100755 .github/scripts/defconfig.sh create mode 100755 .github/scripts/isolated_tests.sh create mode 100755 .github/scripts/kselftest.sh create mode 100755 .github/scripts/libhugetlbfs.sh create mode 100755 .github/scripts/libs/__init__.py create mode 100755 .github/scripts/libs/context.py create mode 100755 .github/scripts/libs/email.py create mode 100755 .github/scripts/libs/githubtool.py create mode 100755 .github/scripts/libs/patchwork.py create mode 100755 .github/scripts/libs/repotool.py create mode 100755 .github/scripts/libs/utils.py create mode 100755 .github/scripts/ltp.sh create mode 100755 .github/scripts/pw_ci.py create mode 100644 .github/scripts/pw_tests/build_rv32_defconfig.sh create mode 100644 .github/scripts/pw_tests/build_rv64_clang_allmodconfig.sh create mode 100644 .github/scripts/pw_tests/build_rv64_gcc_allmodconfig.sh create mode 100644 .github/scripts/pw_tests/build_rv64_nommu_k210_defconfig.sh create mode 100644 .github/scripts/pw_tests/build_rv64_nommu_virt_defconfig.sh create mode 100644 .github/scripts/pw_tests/checkpatch.sh create mode 100644 .github/scripts/pw_tests/dtb_warn_rv64.sh create mode 100644 .github/scripts/pw_tests/header_inline.sh create mode 100644 .github/scripts/pw_tests/kdoc.sh create mode 100644 .github/scripts/pw_tests/module_param.sh create mode 100644 .github/scripts/pw_tests/verify_fixes.sh create mode 100644 .github/scripts/pw_tests/verify_signedoff.sh create mode 100644 .github/scripts/requirements.txt create mode 100755 .github/scripts/series.sh create mode 100755 .github/scripts/series/build_all.sh create mode 100755 .github/scripts/series/build_kernel.sh create mode 100755 .github/scripts/series/build_only_defconfig.sh create mode 100755 .github/scripts/series/build_only_kselftest.sh create mode 100755 .github/scripts/series/build_selftest.sh create mode 100755 .github/scripts/series/generate_build_configs.sh create mode 100755 .github/scripts/series/generate_kconfigs.sh create mode 100644 .github/scripts/series/generate_metadata.py create mode 100644 .github/scripts/series/generate_qemu_test_configs.sh create mode 100755 .github/scripts/series/generate_test_runs.sh create mode 100644 .github/scripts/series/github_ci_squad_results.py create mode 100644 .github/scripts/series/kconfigs/defconfig/early_boot_alternative create mode 100644 .github/scripts/series/kconfigs/defconfig/early_boot_alternative_reloc create mode 100644 .github/scripts/series/kconfigs/defconfig/flatmem create mode 100644 .github/scripts/series/kconfigs/defconfig/hardened_usercopy_slub create mode 100644 .github/scripts/series/kconfigs/defconfig/kasan create mode 100644 .github/scripts/series/kconfigs/defconfig/kasan_inline create mode 100644 .github/scripts/series/kconfigs/defconfig/kasan_sparsemem_novmemmmap create mode 100644 .github/scripts/series/kconfigs/defconfig/kasan_sparsemem_vmemmmap create mode 100644 .github/scripts/series/kconfigs/defconfig/kasan_vmalloc create mode 100644 .github/scripts/series/kconfigs/defconfig/kfence create mode 100644 .github/scripts/series/kconfigs/defconfig/legacy_sbi create mode 100644 .github/scripts/series/kconfigs/defconfig/lockdep create mode 100644 .github/scripts/series/kconfigs/defconfig/medany create mode 100644 .github/scripts/series/kconfigs/defconfig/medlow create mode 100644 .github/scripts/series/kconfigs/defconfig/noc create mode 100644 .github/scripts/series/kconfigs/defconfig/nosmp create mode 100644 .github/scripts/series/kconfigs/defconfig/pmu create mode 100644 .github/scripts/series/kconfigs/defconfig/preempt create mode 100644 .github/scripts/series/kconfigs/defconfig/preempt_rt create mode 100644 .github/scripts/series/kconfigs/defconfig/qspinlock create mode 100644 .github/scripts/series/kconfigs/defconfig/randomize_base create mode 100644 .github/scripts/series/kconfigs/defconfig/rseq create mode 100644 .github/scripts/series/kconfigs/defconfig/rseq_debug create mode 100644 .github/scripts/series/kconfigs/defconfig/size create mode 100644 .github/scripts/series/kconfigs/defconfig/sparsemem create mode 100644 .github/scripts/series/kconfigs/defconfig/spinwait create mode 100644 .github/scripts/series/kconfigs/defconfig/strict_rwx create mode 100644 .github/scripts/series/kconfigs/defconfig/svnapot create mode 100644 .github/scripts/series/kconfigs/defconfig/ticket_spinlock create mode 100644 .github/scripts/series/kconfigs/defconfig/vmap_stack create mode 100644 .github/scripts/series/kconfigs/ubuntu_defconfig create mode 100755 .github/scripts/series/kernel_builder.sh create mode 100755 .github/scripts/series/kernel_tester.sh create mode 100644 .github/scripts/series/kselftest_prep.sh create mode 100644 .github/scripts/series/patches/0001-selftests-bpf-Add-RISC-V-specific-config.patch create mode 100644 .github/scripts/series/patches/0002-selftests-bpf-Rename-fallback.patch create mode 100644 .github/scripts/series/patches/0003-selftests-iommu-Add-RISC-V-specific-config.patch create mode 100644 .github/scripts/series/patches/0004-selftests-exec-Remove-static-pie.patch create mode 100644 .github/scripts/series/patches/0005-selftests-hid-Fix-broken-build.patch create mode 100644 .github/scripts/series/patches/0006-Add-missing-net-lib-kselftest-target.patch create mode 100644 .github/scripts/series/patches/0007-BPF-kselftest-fix.patch create mode 100644 .github/scripts/series/patches/0008-BPF-selftest-install.patch create mode 100644 .github/scripts/series/patches/0009-selftests-clone3-Avoid-fragile-struct-poking.patch create mode 100644 .github/scripts/series/patches/0010-selftests-clone3-Avoid-fragile-struct-poking.patch create mode 100644 .github/scripts/series/patches/0011-selftests-bpf-Add-missing-per-arch-include-path.patch create mode 100644 .github/scripts/series/patches/0012-Missing-iommu-config.patch create mode 100755 .github/scripts/series/post_to_squad.py create mode 100755 .github/scripts/series/prepare_rootfs.sh create mode 100644 .github/scripts/series/qemu_test_utils.sh create mode 100755 .github/scripts/series/selftest_builder.sh create mode 100755 .github/scripts/series/test_all.sh create mode 100755 .github/scripts/series/test_kernel.sh create mode 100755 .github/scripts/series/test_only_defconfig.sh create mode 100755 .github/scripts/series/test_only_kselftest.sh create mode 100644 .github/scripts/series/tuxrun_to_squad_json.py create mode 100755 .github/scripts/series/unpack_fw.sh create mode 100644 .github/scripts/series/utils.sh create mode 100755 .github/scripts/sync.sh create mode 100755 .github/scripts/sync_patchwork.py create mode 100755 .github/scripts/xfstests.sh create mode 100644 .github/workflows/kselftest.yml create mode 100644 .github/workflows/libhugetlbfs.yml create mode 100644 .github/workflows/patchwork.yml create mode 100644 .github/workflows/series.yml create mode 100644 .github/workflows/sync.yml create mode 100644 .github/workflows/testsuites.yml diff --git a/.github/.MISSING_LINARO_DEP.swp b/.github/.MISSING_LINARO_DEP.swp new file mode 100644 index 0000000000000000000000000000000000000000..b546c7c082c77021af06bf399b922c0af4b6f973 GIT binary patch literal 12288 zcmeI&O-|cD7zW^hElR2As=KeSu@_0400OZFr~+n{AKL0pm${6HkN^ zubm6(zmEI)XJ9)PYEt^mv1qqu&9-9?2KL!kuWz57d^`6}dlw7thHeNzU^#(?yW8zp z)!d!!FZ5~4UG6fN1px>^00Izz00bZa0SK(5fSRtcUwY;1^VM(6>)M+-KSY551Rwwb z2tWV=5P$##AOHafKwt$0c)-}*2gaUss_*}=@Bh!6j6LYw>)h)6*5Numogc9mJ9(1KmY;|fB*y_009U<00RHBz-TlgBT>^P7kMCZa@@g?{E&DMgn`Kt;g`PT z85t()4==o-?exywq35`LI;IX8Qt{%NE0Jd=OE2YB$>k)H`bYVM(mW`WP?F(`EJ~G^ z3OTk$)i5FRNKzbTx*<{?hjfz{#jMw;OG{4bn@6P#$tcRqt6H84rK(R=M@5>KnR@T6 o{K2Obi9}DWnp2U*R;RvRR;IjuUb;@X)ot#XEDrp?J^Lnm0SO<4)&Kwi literal 0 HcmV?d00001 diff --git a/.github/.swp b/.github/.swp new file mode 100644 index 0000000000000000000000000000000000000000..caedf94e7f3548178847415665e7f7a7cec372b4 GIT binary patch literal 12288 zcmeI&&2G~`5CGsU2P6(q1TQeaB{|?UsrsW_pvoyoAOvmiV|!{Zv3Jexx}iDn^EL<` z5@sDoLP(X$r6STq+N`~q_0D{Aijs8ieEu4alZoQj!}zv-ecqiatmsow>Yz7^*UUGK zyJovAi+~8+iom_I{mFPQ9`)?$6L|dS>{d>dLqtFXL_h>YKmy-UYP(Xjf1%VV*W6d6V+FBftZjxq`3Nyrg2QCI-&N1$c%s?^C%hnY z^Sa)0U6Z4OgW)u0l5v)VURPJlT-(d&6pzM&y286Q)a5C$(#ZH;~f kuV`hEBL?Ba`fA9uC*06Xh!kSTk12{S6{{R30 literal 0 HcmV?d00001 diff --git a/.github/MISSING_LINARO_DEP b/.github/MISSING_LINARO_DEP new file mode 100644 index 00000000000000..03e32d8c3d934c --- /dev/null +++ b/.github/MISSING_LINARO_DEP @@ -0,0 +1,11 @@ +gdb (ltp vma05) +libnuma (ltp vma02-4) +swap file (swapping01) +fusermount (run_fuse_test.sh) +libfuse (run_fuse_test.sh) +mkisofs genisoimage xorrisofs (isofs.sh) +all modules (binfmt_misc0X) +mksquashfs +LTP_TIMEOUT_MUL > 1 (starvation) +libubsan () +XXX (ltp-aiodio MUST be added) diff --git a/.github/scripts/.patches.sh.swp b/.github/scripts/.patches.sh.swp new file mode 100644 index 0000000000000000000000000000000000000000..4e54ba5636d544bee67ef4e865cac9a70f633971 GIT binary patch literal 12288 zcmeI2%a0pH5Ql4XL5Mt1P>?vKGWJTg*cm@INXTHpk_7FFAgtX4B4s0MJnpr7cV0}l zlMRmH&LR8-AOU{|cZ4{@l`D@Ea3B}Nul>qHWR)BvRZE|GW@@IV>g%3^c%y{GfEajs11D&`*{HkcO5Qns>Gaj7A3~lG17bi7hygJm2E>3E5CdZ1 znKfYZ75WU>ADdUOHt$y+>F1}?i2*Sn2E>3E5CdXB42S_SAO^&M7!U)`pn!#awyEe14A@{O^HS3hUc}SV-Z{L`BZ{TJ0JdYa_9yh`Igj;C* zW`!1cvA@sf+4uLe9x{A1VFaQqHY#tgaW6DO#QT%Qrr}xNwaQpkUven_ z5O3Vk%!nT?>B=wl@|BCt7CN` l%WoHYFtk_Hp>1)q-dyKxeKRw>l|})T&eeK4t+~&K{sT2shtvQ7 literal 0 HcmV?d00001 diff --git a/.github/scripts/build_ubuntu_defconfig.sh b/.github/scripts/build_ubuntu_defconfig.sh new file mode 100755 index 00000000000000..783826e0d06b8a --- /dev/null +++ b/.github/scripts/build_ubuntu_defconfig.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2024 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +set -euox pipefail +d=$(dirname "${BASH_SOURCE[0]}") +. $d/series/utils.sh + +logs=$(get_logs_dir) +f=${logs}/build_ubuntu_defconfig.log + +date -Iseconds | tee -a ${f} +echo "Build an ubuntu kernel" | tee -a ${f} +echo "Top 16 commits" | tee -a ${f} +git log -16 --abbrev=12 --pretty="commit %h (\"%s\")" | tee -a ${f} + +kernel_base_sha=$(git log -1 --pretty=%H $(git log -1 --reverse --pretty=%H .github)^) +echo "build_name $(git describe --tags ${kernel_base_sha})" | tee -a ${f} +build_name=$(git describe --tags ${kernel_base_sha}) + +# Build the kernel that will run LTP +export CI_TRIPLE="riscv64-unknown-linux-gnu" +# Use a CFI-enabled toolchain +export PATH=/build/INSTALL_Sept24/bin:$PATH +cp $d/series/kconfigs/ubuntu_defconfig arch/riscv/configs/ +$d/series/kernel_builder.sh rv64 testsuites plain gcc | tee -a ${f} + +kernel_dir="/build/$(gen_kernel_name rv64 testsuites plain gcc)" +echo $build_name > $kernel_dir/kernel_version +#tar cJvf --exclude $(basename $kernel_path) modules.tar.xz /build/$(gen_kernel_name rv64 testsuites plain gcc)/ diff --git a/.github/scripts/ci/__init__.py b/.github/scripts/ci/__init__.py new file mode 100644 index 00000000000000..05c3610326d57f --- /dev/null +++ b/.github/scripts/ci/__init__.py @@ -0,0 +1,2 @@ +from .base import Base, EndTest, Verdict, submit_pw_check +from .shelltest import ShellTest diff --git a/.github/scripts/ci/base.py b/.github/scripts/ci/base.py new file mode 100644 index 00000000000000..d62af70b5141bf --- /dev/null +++ b/.github/scripts/ci/base.py @@ -0,0 +1,120 @@ +from abc import ABC, abstractmethod +from enum import Enum +import time +import sys + +from libs import utils + +sys.path.insert(0, '../libs') +from libs import log_debug + +class Verdict(Enum): + PENDING = 0 + PASS = 1 + FAIL = 2 + ERROR = 3 + SKIP = 4 + WARNING = 5 + + +class EndTest(Exception): + """ + End of Test + """ + +class Base(ABC): + """ + Base class for CI Tests. + """ + def __init__(self): + self.start_time = 0 + self.end_time = 0 + self.verdict = Verdict.PENDING + self.output = "" + + def success(self): + self.end_timer() + self.verdict = Verdict.PASS + + def error(self, msg): + self.verdict = Verdict.ERROR + self.output = msg + self.end_timer() + raise EndTest + + def warning(self, msg): + self.verdict = Verdict.WARNING + self.output = msg + self.end_timer() + + def skip(self, msg): + self.verdict = Verdict.SKIP + self.output = msg + self.end_timer() + raise EndTest + + def add_failure(self, msg): + self.verdict = Verdict.FAIL + if not self.output: + self.output = msg + else: + self.output += "\n" + msg + + def add_failure_end_test(self, msg): + self.add_failure(msg) + self.end_timer() + raise EndTest + + def start_timer(self): + self.start_time = time.time() + + def end_timer(self): + self.end_time = time.time() + + def elapsed(self): + if self.start_time == 0: + return 0 + if self.end_time == 0: + self.end_timer() + return self.end_time - self.start_time + + def log_err(self, msg): + utils.log_error(f"CI: {self.name}: {msg}") + + def log_info(self, msg): + utils.log_info(f"CI: {self.name}: {msg}") + + def log_dbg(self, msg): + utils.log_debug(f"CI: {self.name}: {msg}") + + @abstractmethod + def run(self, worktree=None): + """ + The child class should implement run() method + If the test fail, it should raise the EndTest exception + """ + pass + + @abstractmethod + def post_run(self): + """ + The child class should implement post_run() method + """ + pass + + +def submit_pw_check(pw, patch, name, verdict, desc, url=None, dry_run=False): + + utils.log_debug(f"Submitting the result to PW: dry_run={dry_run}") + + if not dry_run: + state = 0 + + if verdict == Verdict.PASS: + state = 1 + if verdict == Verdict.WARNING: + state = 2 + if verdict == Verdict.FAIL: + state = 3 + + pw.post_check(patch, name, state, desc, url) diff --git a/.github/scripts/ci/shelltest.py b/.github/scripts/ci/shelltest.py new file mode 100644 index 00000000000000..7f3f56c3ba6f52 --- /dev/null +++ b/.github/scripts/ci/shelltest.py @@ -0,0 +1,67 @@ +from gettext import install +import os +import sys + +sys.path.insert(0, '../libs') +from libs import RepoTool, cmd_run + +from ci import Base, Verdict, EndTest, submit_pw_check + +class ShellTest(Base): + """Run shell test class + This class runs a shell based test + """ + + def __init__(self, ci_data, patch, name, desc, sh): + + # Common + self.name = name + self.desc = desc + self.ci_data = ci_data + + self.sh = sh + self.patch = patch + + super().__init__() + + self.log_dbg("Initialization completed") + + def run(self, worktree=None): + + self.log_dbg("Run") + self.start_timer() + + current_script_path = os.path.dirname(os.path.abspath(__file__)) + + cwd = worktree if worktree else self.ci_data.src_dir + cmd = ["bash", f"{current_script_path}/../pw_tests/{self.sh}"] + (ret, stdout, stderr) = cmd_run(cmd, cwd=cwd) + + if ret == 0: + submit_pw_check(self.ci_data.pw, self.patch, + self.name, Verdict.PASS, + self.name, + None, self.ci_data.config['dry_run']) + self.success() + elif ret == 250: + url = self.ci_data.gh.create_gist(f"pw{self.ci_data.series['id']}-p{self.patch['id']}", + f"{self.name}-WARNING", + stdout + '\n' + stderr) + submit_pw_check(self.ci_data.pw, self.patch, + self.name, Verdict.WARNING, + self.name, + url, self.ci_data.config['dry_run']) + self.warning(stdout + '\n' + stderr) + else: + url = self.ci_data.gh.create_gist(f"pw{self.ci_data.series['id']}-p{self.patch['id']}", + f"{self.name}-FAIL", + stdout + '\n' + stderr) + submit_pw_check(self.ci_data.pw, self.patch, + self.name, Verdict.FAIL, + self.name, + url, self.ci_data.config['dry_run']) + self.error(stdout + '\n' + stderr) + + def post_run(self): + + self.log_dbg("Post Run...") diff --git a/.github/scripts/cleanup_pr.py b/.github/scripts/cleanup_pr.py new file mode 100755 index 00000000000000..691a00c7d353ab --- /dev/null +++ b/.github/scripts/cleanup_pr.py @@ -0,0 +1,238 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +import os +import sys +import logging +import argparse + +from datetime import datetime +from github import Github + +from libs import init_logger, log_debug, log_error, log_info, pr_get_sid +from libs import GithubTool + +dry_run = False + +MAGIC_LINE = "BlueZ Testbot Message:" +MAGIC_LINE_2 = "BlueZ Testbot Message #2:" +MAGIC_LINE_3 = "BlueZ Testbot Message #3:" +MAGIC_LINE_4 = "BlueZ Testbot Message #4:" + +PATCH_SUBMISSION_MSG = ''' +This is an automated message and please do not change or delete. + +Dear submitter, + +Thanks for submitting the pull request to the BlueZ github repo. +Currently, the BlueZ repo in Github is only for CI and testing purposes, +and not accepting any pull request at this moment. + +If you still want us to review your patch and merge them, please send your +patch to the Linux Bluetooth mailing list(linux-bluetooth@vger.kernel.org). + +For more detail about submitting a patch to the mailing list, +Please refer \"Submitting patches\" section in the HACKING file in the source. + +Note that this pull request will be closed in the near future. + +Best regards, +BlueZ Team +''' + +PATCH_SUBMISSION_MSG_2 = ''' +This is an automated message and please do not change or delete. + +Dear submitter, + +This is a friendly reminder that this pull request will be closed within +a week or two. + +If you already submitted the patches to the Linux Bluetooth mailing list +(linux-bluetooth@vger.kernel.org) for review, Please close this pull +request. + +If you haven't submitted the patches but still want us to review your patch, +please send your patch to the Linux Bluetooth mailing list +(linux-bluetooth@vger.kernel.org). + +For more detail about submitting a patch to the mailing list, +Please refer \"Submitting patches\" section in the HACKING file in the source. + +Note that this pull request will be closed in a week or two. + +Best regards, +BlueZ Team +''' + +PATCH_SUBMISSION_MSG_3 = ''' +This is an automated message and please do not change or delete. + +Dear submitter, + +Thanks for submitting the pull request to the BlueZ github repo. +Currently, the BlueZ repo in Github is only for CI and testing purposes, +and not accepting any pull request at this moment. + +If you still want us to review your patch and merge them, please send your +patch to the Linux Bluetooth mailing list(linux-bluetooth@vger.kernel.org). + +For more detail about submitting a patch to the mailing list, +Please refer \"Submitting patches\" section in the HACKING file in the source. + +Note that this pull request will be closed in the near future. + +Best regards, +BlueZ Team +''' + +PATCH_SUBMISSION_MSG_4 = ''' +This is an automated message and please do not change or delete. + +Closing without taking any action. + +Best regards, +BlueZ Team +''' + +def get_comment_str(magic_line): + """ + Generate the comment string including magic_line + """ + if magic_line == MAGIC_LINE: + msg = PATCH_SUBMISSION_MSG + if magic_line == MAGIC_LINE_2: + msg = PATCH_SUBMISSION_MSG_2 + if magic_line == MAGIC_LINE_3: + msg = PATCH_SUBMISSION_MSG_3 + if magic_line == MAGIC_LINE_4: + msg = PATCH_SUBMISSION_MSG_4 + + return magic_line + "\n\n" + msg + +def get_magic_line(body): + if (body.find(MAGIC_LINE) >= 0): + return MAGIC_LINE + if (body.find(MAGIC_LINE_2) >= 0): + return MAGIC_LINE_2 + if (body.find(MAGIC_LINE_3) >= 0): + return MAGIC_LINE_3 + if (body.find(MAGIC_LINE_4) >= 0): + return MAGIC_LINE_4 + return None + +def pr_add_comment(gh, pr, magic_line): + """ + Add the comment based on magic line + """ + comment = get_comment_str(magic_line) + + log_debug(f"Add PR comments{magic_line}:\n{comment}") + + if dry_run: + log_info("Dry-Run: Skip adding comment to PR") + return + + gh.pr_post_comment(pr, comment) + +def pr_close(gh, pr): + """ + Close pull request + """ + log_debug(f"Close PR{pr.number}") + + if dry_run: + log_info("Dry-Run: Skip closing PR") + return + + gh.pr_close(pr) + +def get_latest_comment(gh, pr): + """ + Search through the comments and find the latest comment + """ + comments = gh.pr_get_issue_comments(pr) + if not comments: + log_error("Unable to get the comments") + return None + + log_info(f"PR#{pr.number} Comment count: {comments.totalCount}") + + for comment in comments.reversed: + magic_line = get_magic_line(comment.body) + if magic_line != None: + log_debug(f"The most recent comment: {magic_line}") + return magic_line + + log_debug("No bluez comment found") + return None + +def update_pull_request(gh, pr, days_created): + + if days_created > 14: + log_debug("Days created > 14") + log_debug("PR is more than 2 weeks and close the PR") + pr_close(gh, pr) + +def manage_pr(gh): + + prs = gh.get_prs(force=True) + log_info(f"Pull Request count: {prs.totalCount}") + + # Handle each PR + for pr in prs: + log_debug(f"Check PR#_{pr.number}") + + # Check if this PR is created with Patchwork series. + # If yes, stop processing. + pw_sid = pr_get_sid(pr.title) + if pw_sid: + log_info(f"PR is created with Patchwork SID: {pw_sid}") + continue + + # Calcuate the number of days since PR was created + delta = datetime.now().astimezone(pr.created_at.tzinfo) - pr.created_at + days_created = delta.days + + log_debug(f"PR opended {days_created} days ago") + + # Update the PR + update_pull_request(gh, pr, days_created) + +def parse_args(): + """ Parse input argument """ + + ap = argparse.ArgumentParser(description="Clean up PR") + ap.add_argument('-d', '--dry-run', action='store_true', default=False, + help='Run it without updating the PR') + # Positional paramter + ap.add_argument("repo", + help="Name of Github repository. i.e. bluez/bluez") + return ap.parse_args() + +def main(): + + global dry_run + + init_logger("ManagePR", verbose=True) + + args = parse_args() + + # Make sure GITHUB_TOKEN exists + if 'GITHUB_TOKEN' not in os.environ: + log_error("Set GITHUB_TOKEN environment variable") + sys.exit(1) + + # Initialize github repo object + try: + gh = GithubTool(args.repo, os.environ['GITHUB_TOKEN']) + except: + log_error("Failed to initialize GithubTool class") + sys.exit(1) + + dry_run = args.dry_run + + manage_pr(gh) + +if __name__ == "__main__": + main() + diff --git a/.github/scripts/config.json b/.github/scripts/config.json new file mode 100644 index 00000000000000..050c106f8da16c --- /dev/null +++ b/.github/scripts/config.json @@ -0,0 +1,28 @@ +{ + "email": { + "server": "smtp.gmail.com", + "port": 587, + "user": "linux.riscv.bot@gmail.com", + "starttls": true, + "default-to": "linux-riscv-reports@googlegroups.com", + "only-maintainers": false, + "maintainers": [ + "linux.riscv.bot@gmail.com" + ] + }, + "patchwork": { + "url": "https://patchwork.kernel.org", + "project_name": "Linux RISC-V" + }, + "space_details": { + "kernel": { + "include": [ + ], + "exclude": [ + "pull request", + "git pull", + "git,pull" + ] + } + } +} diff --git a/.github/scripts/defconfig.sh b/.github/scripts/defconfig.sh new file mode 100755 index 00000000000000..f133b00006bb00 --- /dev/null +++ b/.github/scripts/defconfig.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2024 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail +d=$(dirname "${BASH_SOURCE[0]}") +. $d/series/utils.sh + +logs=$(get_logs_dir) +f=${logs}/defconfig.log + +date -Iseconds | tee -a ${f} +echo "Top 16 commits" | tee -a ${f} +git log -16 --abbrev=12 --pretty="commit %h (\"%s\")" | tee -a ${f} + +${d}/series/build_only_defconfig.sh | tee -a ${f} +${d}/series/test_only_defconfig.sh | tee -a ${f} diff --git a/.github/scripts/isolated_tests.sh b/.github/scripts/isolated_tests.sh new file mode 100755 index 00000000000000..8bdd2cee090677 --- /dev/null +++ b/.github/scripts/isolated_tests.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2025 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +set -euox pipefail +d=$(dirname "${BASH_SOURCE[0]}") +. $d/series/utils.sh + +logs=$(get_logs_dir) +f=${logs}/isolated-tests.log + +KERNEL_PATH=$(find "$1" -name '*vmlinuz*') +mv $KERNEL_PATH $KERNEL_PATH.gz +gunzip $KERNEL_PATH.gz + +ROOTFS_PATH=$(find /rootfs/ -name 'rootfs_rv64_ubuntu*.ext4') +# Resize the fs +truncate -s +4G $ROOTFS_PATH +resize2fs $ROOTFS_PATH + +build_name=$(cat "$1/kernel_version") + +# The Docker image comes with a prebuilt python environment with all tuxrun +# dependencies +source /build/.env/bin/activate + +isolated_tests=( "cfi" ) + +mkdir -p /build/squad_json/ +parallel_log=$(mktemp -p ${ci_root}) + +for test in ${isolated_tests[@]}; do + /build/tuxrun/run --runtime null --device qemu-riscv64 --kernel $KERNEL_PATH --tests ${test} --results /build/squad_json/${test}.json --log-file-text /build/squad_json/${test}.log --timeouts ${test}=480 --overlay /build/isolated-${test}.tar.xz --rootfs $ROOTFS_PATH --boot-args "rw" || true + # Convert JSON to squad datamodel + python3 /build/my-linux/.github/scripts/series/tuxrun_to_squad_json.py --result-path /build/squad_json/${test}.json --testsuite ${test} + python3 /build/my-linux/.github/scripts/series/generate_metadata.py --logs-path /build/squad_json/ --job-url ${GITHUB_JOB_URL} --branch ${GITHUB_BRANCH_NAME} + + curl --header "Authorization: token $SQUAD_TOKEN" --form tests=@/build/squad_json/${test}.squad.json --form log=@/build/squad_json/${test}.log --form metadata=@/build/squad_json/metadata.json https://mazarinen.tail1c623.ts.net/api/submit/riscv-linux/linux-all/${build_name}/qemu +done diff --git a/.github/scripts/kselftest.sh b/.github/scripts/kselftest.sh new file mode 100755 index 00000000000000..19ba8442561392 --- /dev/null +++ b/.github/scripts/kselftest.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2023 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail +d=$(dirname "${BASH_SOURCE[0]}") +. $d/series/utils.sh + +logs=$(get_logs_dir) +f=${logs}/kselftest.log + +date -Iseconds | tee -a ${f} +echo "Build, boot, and run kselftests on various kernels" | tee -a ${f} +echo "Top 16 commits" | tee -a ${f} +git log -16 --abbrev=12 --pretty="commit %h (\"%s\")" | tee -a ${f} + +kernel_base_sha=$(git log -1 --pretty=%H $(git log -1 --reverse --pretty=%H .github)^) +echo "build_name $(git describe --tags ${kernel_base_sha})" | tee -a ${f} + +${d}/series/build_only_kselftest.sh | tee -a ${f} +${d}/series/test_only_kselftest.sh | tee -a ${f} diff --git a/.github/scripts/libhugetlbfs.sh b/.github/scripts/libhugetlbfs.sh new file mode 100755 index 00000000000000..f7af7bee7abb25 --- /dev/null +++ b/.github/scripts/libhugetlbfs.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2024 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +set -euox pipefail +d=$(dirname "${BASH_SOURCE[0]}") +. $d/series/utils.sh + +logs=$(get_logs_dir) +f=${logs}/libhugetlbfs.log + +KERNEL_PATH=$(find "$1" -name '*vmlinu[zx]*') +mv $KERNEL_PATH $KERNEL_PATH.gz +gunzip $KERNEL_PATH.gz + +build_name=$(cat "$1/kernel_version") + +# The Docker image comes with a prebuilt python environment with all tuxrun +# dependencies +source /build/.env/bin/activate + +mkdir -p /build/squad_json/ + +/build/tuxrun/run --runtime null --device qemu-riscv64 --kernel $KERNEL_PATH --tests libhugetlbfs --results /build/squad_json/libhugetlbfs.json --log-file-text /build/squad_json/libhugetlbfs.log --timeouts libhugetlbfs=480 --overlay /build/libhugetlbfs.tar.xz || true + +# Convert JSON to squad datamodel +python3 /build/my-linux/.github/scripts/series/tuxrun_to_squad_json.py --result-path /build/squad_json/libhugetlbfs.json --testsuite libhugetlbfs +python3 /build/my-linux/.github/scripts/series/generate_metadata.py --logs-path /build/squad_json/ --job-url ${GITHUB_JOB_URL} --branch ${GITHUB_BRANCH_NAME} + +curl --header "Authorization: token $SQUAD_TOKEN" --form tests=@/build/squad_json/libhugetlbfs.squad.json --form log=@/build/squad_json/libhugetlbfs.log --form metadata=@/build/squad_json/metadata.json https://mazarinen.tail1c623.ts.net/api/submit/riscv-linux/linux-all/${build_name}/qemu diff --git a/.github/scripts/libs/__init__.py b/.github/scripts/libs/__init__.py new file mode 100755 index 00000000000000..eb89c4fbbc9ca2 --- /dev/null +++ b/.github/scripts/libs/__init__.py @@ -0,0 +1,6 @@ +from .utils import init_logger, log_debug, log_error, log_info, cmd_run, pr_get_sid +from .patchwork import Patchwork, PostException +from .email import EmailTool +from .repotool import RepoTool +from .githubtool import GithubTool +from .context import Context diff --git a/.github/scripts/libs/context.py b/.github/scripts/libs/context.py new file mode 100755 index 00000000000000..dc15589e16ba66 --- /dev/null +++ b/.github/scripts/libs/context.py @@ -0,0 +1,95 @@ +import os +import json + +from libs import EmailTool, GithubTool, Patchwork, RepoTool +from libs import log_info, log_debug, log_error + + +class ContextError(Exception): + pass + + +class Context(): + """Collection of data for bzcafe. It is useful for CI""" + + def __init__(self, config_file=None, github_repo=None, src_dir=None, + patch_root=None, **kwargs): + + # Init config + log_info(f"Initialize config file: {config_file}") + self.config = None + if config_file: + with open(os.path.abspath(config_file), 'r') as f: + self.config = json.load(f) + + # Init patchwork + log_info("Initialize patchwork") + try: + self.pw = Patchwork(self.config['patchwork']['url'], + self.config['patchwork']['project_name']) + except: + log_error("Failed to initialize Patchwork class") + raise ContextError + + # If token and username is available, set it here + if 'PATCHWORK_TOKEN' in os.environ and os.environ['PATCHWORK_TOKEN'] != "": + log_debug("Found Patchwork Token in environment variable") + self.pw.set_token(os.environ['PATCHWORK_TOKEN']) + + if 'PATCHWORK_USER' in os.environ and os.environ['PATCHWORK_USER'] != "": + log_debug("Found Patchwork User in environment variable") + self.pw.set_user(int(os.environ['PATCHWORK_USER'])) + + # Init github + log_info(f"Initialize Github: {github_repo}") + if 'GITHUB_TOKEN' not in os.environ: + log_error("Set GITHUB_TOKEN environment variable") + raise ContextError + + if 'GIST_TOKEN' not in os.environ: + log_error("Set GIST_TOKEN environment variable") + raise ContextError + + try: + self.gh = GithubTool(github_repo, os.environ['GITHUB_TOKEN'], + os.environ['GIST_TOKEN']) + except: + log_error("Failed to initialize GithubTool class") + raise ContextError + + # Init email + log_info("Initailze EmailTool") + token = None + if 'EMAIL_TOKEN' in os.environ: + token = os.environ['EMAIL_TOKEN'] + log_info("Email Token is read from environment variable") + + self.email = EmailTool(token=token, config=self.config['email']) + + # Init src_dir + log_info(f"Initialize Source directory: {src_dir}") + try: + self.src_repo = RepoTool(os.path.basename(src_dir), src_dir) + except: + log_error("Failed to initialize RepoTool class") + raise ContextError + self.src_dir = self.src_repo.path() + self.patch_root = patch_root + + # Custome confguration + for kw in kwargs: + log_info(f"Storing {kw}:{kwargs[kw]}") + self.config[kw] = kwargs[kw] + + # These are the frequently used variables by CI + self.series = None + self.patches = None + self.shas = None + + log_info("Context Initialization Completed") + + def update_series(self, series, shas): + self.series = series + self.patches = series['patches'] + self.shas = shas + diff --git a/.github/scripts/libs/email.py b/.github/scripts/libs/email.py new file mode 100755 index 00000000000000..23654a351e3d43 --- /dev/null +++ b/.github/scripts/libs/email.py @@ -0,0 +1,66 @@ +from asyncio import SendfileNotAvailableError +import smtplib +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText + +import libs + +class EmailTool: + + def __init__(self, server=None, port=None, sender=None, receivers=[], + startls=True, token=None, config=None): + self._server = server + self._port = port + self._sender = sender + self._receivers = receivers + self._starttls = startls + self._token = token + self._message = MIMEMultipart() + + if config: + if 'server' in config: + self._server = config['server'] + if 'port' in config: + self._port = config['port'] + if 'user' in config: + self._sender = config['user'] + if 'startls' in config: + self._startls = config['startls'] + + def send(self): + try: + session = smtplib.SMTP(self._server, self._port) + session.ehlo() + if self._starttls: + session.starttls() + session.ehlo() + session.login(self._sender, self._token) + session.sendmail(self._sender, self._receivers, self._message.as_string()) + except Exception as e: + libs.log_error("Failed to Send email") + libs.log_error(e) + finally: + session.quit() + + libs.log_info("Email sent successfully") + + def set_receivers(self, receivers): + self._receivers = receivers + libs.log_info("Receivers are updated") + + def set_token(self, token): + self._token = token + libs.log_info("Email Token is updated") + + def _update_header(self, headers): + for key, value in headers.items(): + self._message.add_header(key, value) + + def compose(self, title, body, headers): + self._message['From'] = self._sender + self._message['To'] = ", ".join(self._receivers) + self._message['Subject'] = title + self._message.attach(MIMEText(body, 'plain')) + self._update_header(headers) + + libs.log_debug(f"EMAIL Message: \n{self._message}") diff --git a/.github/scripts/libs/githubtool.py b/.github/scripts/libs/githubtool.py new file mode 100755 index 00000000000000..97bf7cf49d1ed4 --- /dev/null +++ b/.github/scripts/libs/githubtool.py @@ -0,0 +1,77 @@ +from github import Github, InputFileContent +import re + +class GithubTool: + + def __init__(self, repo, token=None, gist_token=None): + self._repo = Github(token).get_repo(repo) + self._user = Github(gist_token).get_user() + self._pr = None + self._prs = None + + def get_pr_commits(self, pr_id): + pr = self.get_pr(pr_id, True) + + return pr.get_commits() + + def get_pr(self, pr_id, force=False): + if force or self._pr == None: + self._pr = self._repo.get_pull(pr_id) + + return self._pr + + def get_prs(self, force=False): + if force or not self._prs: + self._prs = self._repo.get_pulls() + + return self._prs + + def create_pr(self, title, body, base, head): + + return self._repo.create_pull(base, head, title=title, body=body, + maintainer_can_modify=True) + + def close_pr(self, pr_id): + pr = self.get_pr(pr_id, force=True) + pr.edit(state="closed") + + git_ref = self._repo.get_git_ref(f"heads/{pr.head.ref}") + git_ref.delete() + + def pr_exist_title(self, str): + if not self._prs: + self._prs = self.get_prs(force=True) + + for pr in self._prs: + if re.search(str, pr.title, re.IGNORECASE): + return True + + return False + + def pr_post_comment(self, pr, comment): + + try: + pr.create_issue_comment(comment) + except: + return False + + return True + + def pr_get_issue_comments(self, pr): + try: + comments = pr.get_issue_comments() + except: + return None + + return comments + + def pr_close(self, pr): + pr.edit(state="closed") + + def create_gist(self, title, test, body): + gist = self._user.create_gist( + public=True, + description=title, + files={test: InputFileContent(body)}) + + return gist.html_url diff --git a/.github/scripts/libs/patchwork.py b/.github/scripts/libs/patchwork.py new file mode 100755 index 00000000000000..c1f8cbb3abd978 --- /dev/null +++ b/.github/scripts/libs/patchwork.py @@ -0,0 +1,181 @@ +import datetime +import requests +from requests.adapters import HTTPAdapter +from urllib3.util.retry import Retry + +import libs + +class PostException(Exception): + pass + + +class Patchwork(): + + def __init__(self, server, project_name, user=None, token=None, api=None): + self._session = requests.Session() + retry = Retry(connect=10, backoff_factor=1) + adapter = HTTPAdapter(max_retries=retry) + self._session.mount('http://', adapter) + self._session.mount('https://', adapter) + self._server = server + self._token = token + self._user = user + self._project_name = project_name + self._api = "/api" if api == None else f"/api/{api}" + self._project_id= self._get_project_id(project_name) + + libs.log_info(f"Connected to Patchwork Server: {self._server}: {self._project_id}") + + def set_token(self, token): + self._token = token + + def set_user(self, user): + self._user = user + + def _request(self, url): + libs.log_debug(f"PW GET URL: {url}") + resp = self._session.get(url) + if resp.status_code != 200: + raise requests.HTTPError(f"GET {resp.status_code}") + + return resp + + def _get(self, req): + return self._request(f'{self._server}{self._api}/{req}') + + def _get_project(self, name): + projects = self.get_all('projects') + for project in projects: + if project['name'] == name: + return project + + libs.log_error(f"No matched project found: {name}") + return None + + def _get_project_id(self, name): + project = self._get_project(name) + if project: + return project['id'] + + raise ValueError + + def _post(self, req, headers, data): + url = f'{self._server}{self._api}/{req}' + libs.log_debug(f"PW POST URL: {url}") + return self._session.post(url, headers=headers, data=data) + + def get(self, type, identifier): + return self._get(f'{type}/{identifier}/').json() + + def get_all(self, type, filters=None): + if filters is None: + filters={} + params = '' + for key, val in filters.items(): + if val is not None: + params += f'{key}={val}&' + + items = [] + + response = self._get(f'{type}/?{params}') + while response: + for entry in response.json(): + items.append(entry) + + if 'Link' not in response.headers: + break + + links = response.headers['Link'].split(',') + response = None + for link in links: + info = link.split(';') + if info[1].strip() == 'rel="next"': + response = self._request(info[0][1:-1]) + + return items + + def post_check(self, patch, context, state, desc, url=None): + headers = {} + if self._token: + headers['Authorization'] = f'Token {self._token}' + + data = { + 'user': self._user, + 'state': state, + 'target_url': url if url else "", + 'context': context, + 'description': desc + } + + resp = self._post(f"patches/{patch['id']}/checks/", data=data, + headers=headers) + if resp.status_code != 201 and resp.status_code != 200: + libs.log_error(f"PW POST failed: {resp.status_code}") + raise PostException(f"POST {resp.status_code}") + + def get_series_mbox(self, id): + url = f'{self._server}/series/{id}/mbox/' + return self._request(url).content.decode() + + def get_patch_mbox(self, id): + patch = self.get_patch(id) + return self._request(patch['mbox']).content.decode() + + def get_series(self, series_id): + return self.get('series', series_id) + + def get_patch(self, patch_id): + return self.get('patches', patch_id) + + def get_patches_by_state(self, state, archived=False, days_lookback=0): + filter = {} + + filter['project'] = self._project_id + filter['state'] = state + filter['archived'] = 'true' if archived else 'false' + if days_lookback > 0: + today = datetime.datetime.utcnow().date() + lookback = today - datetime.timedelta(days=days_lookback) + filter['since'] = lookback.strftime("%Y-%m-%dT%H:%M:%S") + + + return self.get_all('patches', filter) + + def get_series_by_state(self, state, archived=False, days_lookback=0): + series_ids = [] + series_list = [] + + patches = self.get_patches_by_state(state, archived, days_lookback) + if len(patches) == 0: + return series + + for patch in patches: + # Skip if patch has no series + if 'series' not in patch: + continue + + for series in patch['series']: + # Check if series id already exist + if series['id'] not in series_ids: + series_ids.append(series['id']) + series_list.append(self.get_series(series['id'])) + + return series_list + + def save_patch_mbox(self, patch_id, filename): + patch_mbox = self.get_patch_mbox(patch_id) + + with open(filename, 'w+') as f: + f.write(patch_mbox) + + return filename + + def save_patch_msg(self, patch_id, filename): + patch = self.get_patch(patch_id) + + with open(filename, 'w+') as f: + f.write(patch['name']) + f.write('\n\n') + f.write(patch['content']) + + return filename diff --git a/.github/scripts/libs/repotool.py b/.github/scripts/libs/repotool.py new file mode 100755 index 00000000000000..5276f465c62e98 --- /dev/null +++ b/.github/scripts/libs/repotool.py @@ -0,0 +1,92 @@ +import os +from typing import List + +import libs + + +class RepoToolNotRepo(Exception): + pass + + +class RepoTool: + + def __init__(self, name, path, remote=None): + self._name = name + self._path = os.path.abspath(path) + self._remote = "origin" + self._branch = "master" + + if remote: + self._remote = remote + + # Last executed stdout and stderr + self.stdout = None + self.stderr = None + + self._verify_repo() + libs.log_info(f'Git Repo({self._name}) verified: {self._path}') + + def path(self): + return self._path + + def git(self, args: List[str]): + (ret, self.stdout, self.stderr) = libs.cmd_run(["git"] + args, + cwd=self._path) + return ret + + def _verify_repo(self): + cmd = ["branch", "--show-current"] + + ret = self.git(cmd) + # except: + # libs.log_error("Failed to verify repo") + # raise RepoToolNotRepo + return ret + + def git_checkout(self, branch, create_branch=False): + cmd = ["checkout"] + + if create_branch: + cmd += ["-B"] + + cmd += [branch] + + return self.git(cmd) + + def git_push(self, branch, remote=None, force=False): + cmd = ["push"] + + if force: + cmd += ["-f"] + + if remote: + cmd += [remote] + else: + cmd += [self._remote] + + cmd += [branch] + + return self.git(cmd) + + def git_reset(self, target, hard=False): + cmd = ["reset", target] + + if hard: + cmd += ["--hard"] + + return self.git(cmd) + + def git_am(self, patch=None, abort=False): + cmd = ["am"] + + if abort: + cmd += ["--abort"] + else: + cmd += ["-s", patch] + + return self.git(cmd) + + def git_clean(self): + # Recursively remove all untracked files, not limited to gitignore + return self.git(["clean", "-d", "--force", "-x"]) + diff --git a/.github/scripts/libs/utils.py b/.github/scripts/libs/utils.py new file mode 100755 index 00000000000000..fada7b6c3a379c --- /dev/null +++ b/.github/scripts/libs/utils.py @@ -0,0 +1,105 @@ +import logging +import os +import subprocess +import time +import re +from typing import List, Dict, Tuple + +# Global logging object +logger = None + +def init_logger(name, verbose=False): + global logger + + logger = logging.getLogger(name) + logger.setLevel(logging.INFO) + if verbose: + logger.setLevel(logging.DEBUG) + + ch = logging.StreamHandler() + formatter = logging.Formatter('%(asctime)s:%(levelname)-8s:%(message)s') + ch.setFormatter(formatter) + + logger.addHandler(ch) + + logger.info("Logger initialized: level=%s", + logging.getLevelName(logger.getEffectiveLevel())) + +def log_info(msg): + if logger is not None: + logger.info(msg) + +def log_error(msg): + if logger is not None: + logger.error(msg) + +def log_debug(msg): + if logger is not None: + logger.debug(msg) + +def pr_get_sid(pr_title): + """ + Parse PR title prefix and get PatchWork Series ID + PR Title Prefix = "[PW_S_ID:] XXXXX" + """ + + try: + sid = re.search(r'^\[PW_SID:([0-9]+)\]', pr_title).group(1) + except AttributeError: + log_error(f"Unable to find the series_id from title {pr_title}") + sid = None + + return sid + +def cmd_run(cmd: List[str], shell: bool = False, add_env: Dict[str, str] = None, + cwd: str = None, pass_fds=()) -> Tuple[str, str, str]: + log_info(f"------------- CMD_RUN -------------") + log_info(f"CMD: {cmd}") + + stdout = "" + + # Update ENV + env = os.environ.copy() + if add_env: + env.update(add_env) + + start_time = time.time() + + proc = subprocess.Popen(cmd, shell=shell, env=env, cwd=cwd, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, + bufsize=1, universal_newlines=True, + pass_fds=pass_fds) + log_debug(f"PROC args: {proc.args}") + + # Print the stdout in realtime + for line in proc.stdout: + log_debug("> " + line.rstrip('\n')) + stdout += line + + # STDOUT returned by proc.communicate() is empty because it was all consumed + # by the above read. + _stdout, stderr = proc.communicate() + proc.stdout.close() + proc.stderr.close() + + stderr = "\n" + stderr + if stderr[-1] == "\n": + stderr = stderr[:-1] + + log_info(f'RET: {proc.returncode}') + # No need to print STDOUT here again. It is already printed above + # log_debug(f'STDOUT:{stdout}') + # Print STDOUT only if ret != 0 + if proc.returncode: + log_debug(f'STDERR:{stderr}') + + if proc.returncode != 0: + if stderr and stderr[:-1] == "\n": + stderr = stderr[:-1] + + elapsed = time.time() - start_time + + log_info(f"------------- CMD_RUN END ({elapsed:.2f} s) -------------") + return proc.returncode, stdout, stderr + + diff --git a/.github/scripts/ltp.sh b/.github/scripts/ltp.sh new file mode 100755 index 00000000000000..2c513d921a594e --- /dev/null +++ b/.github/scripts/ltp.sh @@ -0,0 +1,43 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2023 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +set -euox pipefail +d=$(dirname "${BASH_SOURCE[0]}") +. $d/series/utils.sh + +logs=$(get_logs_dir) +f=${logs}/ltp.log + +KERNEL_PATH=$(find "$1" -name '*vmlinu[zx]*') +mv $KERNEL_PATH $KERNEL_PATH.gz +gunzip $KERNEL_PATH.gz + +build_name=$(cat "$1/kernel_version") + +# The Docker image comes with a prebuilt python environment with all tuxrun +# dependencies +source /build/.env/bin/activate + +# TODO ltp-controllers is too slow for now because of cgroup_fj_stress.sh +# but I haven't found an easy to skip this one from tuxrun +ltp_tests=( "ltp-commands" "ltp-syscalls" "ltp-mm" "ltp-hugetlb" "ltp-crypto" "ltp-cve" "ltp-containers" "ltp-fs" "ltp-sched" ) + +mkdir -p /build/squad_json/ +parallel_log=$(mktemp -p ${ci_root}) + +for ltp_test in ${ltp_tests[@]}; do + echo "/build/tuxrun/run --runtime null --device qemu-riscv64 --kernel $KERNEL_PATH --tests $ltp_test --results /build/squad_json/$ltp_test.json --log-file-text /build/squad_json/$ltp_test.log --timeouts $ltp_test=480 || true" +done | parallel -j $(($(nproc)/4)) --colsep ' ' --joblog ${parallel_log} + +cat ${parallel_log} +rm ${parallel_log} + +for ltp_test in ${ltp_tests[@]}; do + # Convert JSON to squad datamodel + python3 /build/my-linux/.github/scripts/series/tuxrun_to_squad_json.py --result-path /build/squad_json/$ltp_test.json --testsuite $ltp_test + python3 /build/my-linux/.github/scripts/series/generate_metadata.py --logs-path /build/squad_json/ --job-url ${GITHUB_JOB_URL} --branch ${GITHUB_BRANCH_NAME} + + curl --header "Authorization: token $SQUAD_TOKEN" --form tests=@/build/squad_json/$ltp_test.squad.json --form log=@/build/squad_json/$ltp_test.log --form metadata=@/build/squad_json/metadata.json https://mazarinen.tail1c623.ts.net/api/submit/riscv-linux/linux-all/${build_name}/qemu +done diff --git a/.github/scripts/pw_ci.py b/.github/scripts/pw_ci.py new file mode 100755 index 00000000000000..48e7067ad3955c --- /dev/null +++ b/.github/scripts/pw_ci.py @@ -0,0 +1,343 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +import os +import sys +import argparse +import tempfile + +from libs import init_logger, log_debug, log_error, log_info, pr_get_sid +from libs import Context + +import ci + +def check_args(args): + if not os.path.exists(os.path.abspath(args.config)): + log_error(f"Invalid parameter(config) {args.config}") + return False + + if not os.path.exists(os.path.abspath(args.src_dir)): + log_error(f"Invalid parameter(src_dir) {args.src_dir}") + return False + + return True + +def parse_args(): + ap = argparse.ArgumentParser(description="Run CI tests") + ap.add_argument('-c', '--config', default='./config.json', + help='Configuration file to use. default=./config.json') + ap.add_argument('-s', '--src-dir', required=True, + help='Source directory') + ap.add_argument('-d', '--dry-run', action='store_true', default=False, + help='Run it without uploading the result. default=False') + + # Positional parameter + ap.add_argument("repo", + help="Name of Github repository. i.e. bluez/bluez") + return ap.parse_args() + +# Email Message Templates + +EMAIL_MESSAGE = '''This is automated email and please do not reply to this email! + +Dear submitter, + +Thank you for submitting the patches to the Linux RISC-V mailing list. +This is a CI test results with your patch series: +PW Link:{pw_link} + +---Test result--- +{content} + +--- +Regards, +Linux RISC-V bot + +''' + +def github_pr_post_result(ci_data, i, patch, test): + pr = ci_data.gh.get_pr(ci_data.config['pr_num'], force=True) + + comment = f'Patch {i+1}: "{patch['name']}"\n' + comment += f"**{test.name}**\n" + comment += f"Desc: {test.desc}\n" + comment += f"Duration: {test.elapsed():.2f} seconds\n" + comment += f"**Result: {test.verdict.name}**\n" + + if test.output: + comment += f"Output:\n```\n{test.output}\n```" + + return ci_data.gh.pr_post_comment(pr, comment) + +def is_maintainers_only(email_config): + if 'only-maintainers' in email_config and email_config['only-maintainers']: + return True + return False + +def get_receivers(email_config, submitter): + log_debug("Get the list of email receivers") + + receivers = [] + if is_maintainers_only(email_config): + # Send only to the maintainers + receivers.extend(email_config['maintainers']) + else: + # Send to default-to and submitter + receivers.append(email_config['default-to']) + receivers.append(submitter) + + return receivers + +def send_email(ci_data, content): + headers = {} + email_config = ci_data.config['email'] + + body = EMAIL_MESSAGE.format(pw_link=ci_data.series['web_url'], + content=content) + + headers['In-Reply-To'] = ci_data.patches[0]['msgid'] + headers['References'] = ci_data.patches[0]['msgid'] + + if not is_maintainers_only(email_config): + headers['Reply-To'] = email_config['default-to'] + + receivers = get_receivers(email_config, ci_data.series['submitter']['email']) + ci_data.email.set_receivers(receivers) + ci_data.email.compose("Re: " + ci_data.series['name'], body, headers) + + if ci_data.config['dry_run']: + log_info("Dry-Run is set. Skip sending email") + return + + log_info("Sending Email...") + ci_data.email.send() + +def report_ci(ci_data, test_list): + """Generate the CI result and send email""" + results = "" + summary = "Test Summary:\n" + + line = "{head:<100}{name:<35}{result:<10}{elapsed:.2f} seconds\n" + fail_msg = '{head}\nTest: {name} - {result}\nDesc: {desc}\nOutput:\n{output}\n' + + for i in range(len(test_list)): + sha, tests = test_list[i] + patch = ci_data.patches[i] # 'name' + + for test in tests: + if test.verdict == ci.Verdict.PASS: + # No need to add result of passed tests to simplify the email + summary += line.format(head=f'Patch {i+1}: "{patch['name']}"', + name=test.name, result='PASS', + elapsed=test.elapsed()) + continue + + # Rest of the verdicts use same output format + results += "##############################\n" + results += fail_msg.format(head=f'Patch {i+1}: "{patch['name']}"', + name=test.name, result=test.verdict.name, + desc=test.desc, output=test.output) + summary += line.format(head=f'Patch {i+1}: "{patch['name']}"', + name=test.name, result=test.verdict.name, + elapsed=test.elapsed()) + + if results != "": + results = "Details\n" + results + + send_email(ci_data, summary + '\n' + results) + +def create_test_list(ci_data): + test_list = [] + # XXX ci_config = ci_data.config['space_details']['kernel']['ci'] + + ######################################## + # Test List + ######################################## + + i = 0 + for sha in ci_data.shas: + tests = [] + + tests.append(ci.ShellTest(ci_data, ci_data.patches[i], + "build-rv32-defconfig", + "Builds riscv32 defconfig", + "build_rv32_defconfig.sh")) + + tests.append(ci.ShellTest(ci_data, ci_data.patches[i], + "build-rv64-clang-allmodconfig", + "Builds riscv64 allmodconfig with Clang, and checks for errors and added warnings", + "build_rv64_clang_allmodconfig.sh")) + + tests.append(ci.ShellTest(ci_data, ci_data.patches[i], + "build-rv64-gcc-allmodconfig", + "Builds riscv64 allmodconfig with GCC, and checks for errors and added warnings", + "build_rv64_gcc_allmodconfig.sh")) + + tests.append(ci.ShellTest(ci_data, ci_data.patches[i], + "build-rv64-nommu-k210-defconfig", + "Builds riscv64 defconfig with NOMMU for K210", + "build_rv64_nommu_k210_defconfig.sh")) + + tests.append(ci.ShellTest(ci_data, ci_data.patches[i], + "build-rv64-nommu-k210-virt", + "Builds riscv64 defconfig with NOMMU for the virt platform", + "build_rv64_nommu_virt_defconfig.sh")) + + tests.append(ci.ShellTest(ci_data, ci_data.patches[i], + "checkpatch", + "Runs checkpatch.pl on the patch", + "checkpatch.sh")) + + tests.append(ci.ShellTest(ci_data, ci_data.patches[i], + "dtb-warn-rv64", + "Checks for Device Tree warnings/errors", + "dtb_warn_rv64.sh")) + + tests.append(ci.ShellTest(ci_data, ci_data.patches[i], + "header-inline", + "Detects static functions without inline keyword in header files", + "header_inline.sh")) + + tests.append(ci.ShellTest(ci_data, ci_data.patches[i], + "kdoc", + "Detects for kdoc errors", + "kdoc.sh")) + + tests.append(ci.ShellTest(ci_data, ci_data.patches[i], + "module-param", + "Detect module_param changes", + "module_param.sh")) + + tests.append(ci.ShellTest(ci_data, ci_data.patches[i], + "verify-fixes", + "Verifies that the Fixes: tags exist", + "verify_fixes.sh")) + + tests.append(ci.ShellTest(ci_data, ci_data.patches[i], + "verify-signedoff", + "Verifies that Signed-off-by: tags are correct", + "verify_signedoff.sh")) + t = (sha, tests) + test_list.append(t) + i += 1 + + return test_list + +def run_ci(ci_data): + num_fails = 0 + + test_list = create_test_list(ci_data) + + log_info(f"Test list is created: {len(test_list)}") + log_debug("+--------------------------+") + log_debug("| Run CI |") + log_debug("+--------------------------+") + + for i in range(len(test_list)): + sha, tests = test_list[i] + patch = ci_data.patches[i] # 'name' + with tempfile.TemporaryDirectory(dir="/build") as worktree: + cmd = ['worktree', 'add', worktree, sha] + if ci_data.src_repo.git(cmd): + log_error(f"Failed to create worktree") + continue + + for test in tests: + log_info("##############################") + log_info(f'## CI: Patch {i+1}: "{patch['name']}"') + log_info(f"## CI: {test.name}") + log_info("##############################") + + try: + test.run(worktree=worktree) + except ci.EndTest as e: + log_error(f"Test Ended(Failure): {test.name}:{test.verdict.name}") + except Exception as e: + log_error(f"Test Ended(Exception): {test.name}: {e.__class__}") + finally: + test.post_run() + + if test.verdict != ci.Verdict.PASS: + num_fails += 1 + + if ci_data.config['dry_run']: + log_info("Skip submitting result to Github: dry_run=True") + continue + + log_debug("Submit the result to github") + if not github_pr_post_result(ci_data, i, patch, test): + log_error("Failed to submit the result to Github") + + log_info(f"Total number of failed test: {num_fails}") + log_debug("+--------------------------+") + log_debug("| ReportCI |") + log_debug("+--------------------------+") + report_ci(ci_data, test_list) + + return num_fails + +def main(): + global config, pw, gh, src_repo, email + + init_logger("PW_CI", verbose=True) + + if 'GITHUB_REF' not in os.environ: + log_error("GITHUB_REF environment not set") + sys.exit(1) + + pr_num = int(os.environ['GITHUB_REF'].removeprefix("refs/pull/").removesuffix("/merge")) + + args = parse_args() + if not check_args(args): + sys.exit(1) + + ci_data = Context(config_file=os.path.abspath(args.config), + github_repo=args.repo, + src_dir=args.src_dir, + dry_run=args.dry_run, + pr_num=pr_num, + space='kernel') + + pr = ci_data.gh.get_pr(pr_num, force=True) + sid = pr_get_sid(pr.title) + + # If PR is not created for Patchwork (no key string), ignore this PR and + # stop running the CI + if not sid: + log_error("Not a valid PR. No need to run") + sys.exit(1) + + cmd = ['log', '-1', '--pretty=%H', '.github/scripts/sync_patchwork.py'] + if ci_data.src_repo.git(cmd): + log_error("Failed to get base commit") + sys.exit(1) + + base_sha = ci_data.src_repo.stdout.strip() + + if len(base_sha) == 0: + log_error("Failed to get base commit") + sys.exit(1) + + cmd = ['rev-list', '--reverse', f'{base_sha}..HEAD'] + if ci_data.src_repo.git(cmd): + log_error("Failed to list of commits") + sys.exit(1) + + shas = ci_data.src_repo.stdout.split() + if len(shas) == 0: + log_error("Failed to get list of commits") + sys.exit(1) + + ci_data.update_series(ci_data.pw.get_series(sid), shas) + + if len(ci_data.shas) != len(ci_data.patches): + log_error("Git and patchwork mismatch") + sys.exit(1) + + num_fails = run_ci(ci_data) + + log_debug("----- DONE -----") + + sys.exit(num_fails) + +if __name__ == "__main__": + main() diff --git a/.github/scripts/pw_tests/build_rv32_defconfig.sh b/.github/scripts/pw_tests/build_rv32_defconfig.sh new file mode 100644 index 00000000000000..45e2891b9722ff --- /dev/null +++ b/.github/scripts/pw_tests/build_rv32_defconfig.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) 2022 by Rivos Inc. + +tmpdir=$(mktemp -d -p /build) +tmpfile=$(mktemp -p /build) +rc=0 + +tuxmake --wrapper ccache --target-arch riscv --directory . \ + --environment=KBUILD_BUILD_TIMESTAMP=@1621270510 \ + --environment=KBUILD_BUILD_USER=tuxmake --environment=KBUILD_BUILD_HOST=tuxmake \ + -o $tmpdir --toolchain llvm -z none -k rv32_defconfig \ + CROSS_COMPILE=riscv64-linux- \ + >$tmpfile 2>&1 || rc=1 + +if [ $rc -ne 0 ]; then + echo "Full log:" + cat $tmpfile + echo "warnings/errors:" + grep "\(warning\|error\):" $tmpfile +fi + +rm -rf $tmpdir $tmpfile + +exit $rc diff --git a/.github/scripts/pw_tests/build_rv64_clang_allmodconfig.sh b/.github/scripts/pw_tests/build_rv64_clang_allmodconfig.sh new file mode 100644 index 00000000000000..0a27666da8328b --- /dev/null +++ b/.github/scripts/pw_tests/build_rv64_clang_allmodconfig.sh @@ -0,0 +1,88 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2019 Netronome Systems, Inc. + +# Modified tests/patch/build_defconfig_warn.sh for RISC-V builds + +tmpfile_e=$(mktemp -p /build) +tmpfile_o=$(mktemp -p /build) +tmpfile_n=$(mktemp -p /build) +tmpdir_b=$(mktemp -d -p /build) +tmpdir_o=$(mktemp -d -p /build) + +rc=0 + +build() { + tuxmake --wrapper ccache --target-arch riscv -e PATH=$PATH --directory . \ + --environment=KBUILD_BUILD_TIMESTAMP=@1621270510 \ + --environment=KBUILD_BUILD_USER=tuxmake --environment=KBUILD_BUILD_HOST=tuxmake \ + -o $tmpdir_o -b $tmpdir_b --toolchain llvm -z none --kconfig allmodconfig \ + -K CONFIG_WERROR=n -K CONFIG_RANDSTRUCT_NONE=y -K CONFIG_SAMPLES=n \ + -K CONFIG_DRM_WERROR=n \ + W=1 CROSS_COMPILE=riscv64-linux- \ + config default \ + >$1 2>&1 +} + +echo "Redirect to $tmpfile_o and $tmpfile_n" +echo "Tree base:" +HEAD=$(git rev-parse HEAD) +git log -1 --pretty='%h ("%s")' HEAD~ + +echo "Building the whole tree with the patch" +time build $tmpfile_e || rc=1 +if [ $rc -eq 1 ]; then + echo "error:" + grep "\(error\):" $tmpfile_e + rm -rf $tmpdir_o $tmpfile_o $tmpfile_n $tmpdir_b $tmpfile_e + exit $rc +fi + +git checkout -q HEAD~ +echo "Building the tree before the patch" +time build $tmpfile_o +incumbent=$(grep -c "\(warning\|error\):" $tmpfile_o) + +git checkout -q $HEAD +echo "Building the tree with the patch" +time build $tmpfile_n || rc=1 +if [ $rc -eq 1 ]; then + echo "error/warning:" + grep "\(warning\|error\):" $tmpfile_n + rm -rf $tmpdir_o $tmpfile_o $tmpfile_n $tmpdir_b + exit $rc +fi + +current=$(grep -c "\(warning\|error\):" $tmpfile_n) +if [ $current -gt $incumbent ]; then + echo "New errors added:" + + tmpfile_errors_before=$(mktemp -p /build) + tmpfile_errors_now=$(mktemp -p /build) + grep "\(warning\|error\):" $tmpfile_o | sort | uniq -c > $tmpfile_errors_before + grep "\(warning\|error\):" $tmpfile_n | sort | uniq -c > $tmpfile_errors_now + + diff -U 0 $tmpfile_errors_before $tmpfile_errors_now + + rm $tmpfile_errors_before $tmpfile_errors_now + + echo "Per-file breakdown" + tmpfile_fo=$(mktemp -p /build) + tmpfile_fn=$(mktemp -p /build) + + echo "error/warning file pre:" + grep "\(warning\|error\):" $tmpfile_o | sed -n 's@\(^\.\./[/a-zA-Z0-9_.-]*.[ch]\):.*@\1@p' | sort | uniq -c \ + > $tmpfile_fo + echo "error/warning file post:" + grep "\(warning\|error\):" $tmpfile_n | sed -n 's@\(^\.\./[/a-zA-Z0-9_.-]*.[ch]\):.*@\1@p' | sort | uniq -c \ + > $tmpfile_fn + + diff -U 0 $tmpfile_fo $tmpfile_fn + rm $tmpfile_fo $tmpfile_fn + echo "pre: $incumbent post: $current" + rc=1 +fi + +rm -rf $tmpdir_o $tmpfile_o $tmpfile_n $tmpdir_b $tmpfile_e +exit $rc diff --git a/.github/scripts/pw_tests/build_rv64_gcc_allmodconfig.sh b/.github/scripts/pw_tests/build_rv64_gcc_allmodconfig.sh new file mode 100644 index 00000000000000..36c2b8334fb416 --- /dev/null +++ b/.github/scripts/pw_tests/build_rv64_gcc_allmodconfig.sh @@ -0,0 +1,88 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2019 Netronome Systems, Inc. + +# Modified tests/patch/build_defconfig_warn.sh for RISC-V builds + +tmpfile_e=$(mktemp -p /build) +tmpfile_o=$(mktemp -p /build) +tmpfile_n=$(mktemp -p /build) +tmpdir_b=$(mktemp -d -p /build) +tmpdir_o=$(mktemp -d -p /build) + +rc=0 + +build() { + tuxmake --wrapper ccache --target-arch riscv -e PATH=$PATH --directory . \ + --environment=KBUILD_BUILD_TIMESTAMP=@1621270510 \ + --environment=KBUILD_BUILD_USER=tuxmake --environment=KBUILD_BUILD_HOST=tuxmake \ + -o $tmpdir_o -b $tmpdir_b --toolchain gcc -z none --kconfig allmodconfig \ + -K CONFIG_WERROR=n -K CONFIG_GCC_PLUGINS=n \ + -K CONFIG_DRM_WERROR=n \ + W=1 CROSS_COMPILE=riscv64-linux- \ + config default \ + >$1 2>&1 +} + +echo "Redirect to $tmpfile_o and $tmpfile_n" +echo "Tree base:" +HEAD=$(git rev-parse HEAD) +git log -1 --pretty='%h ("%s")' HEAD~ + +echo "Building the whole tree with the patch" +time build $tmpfile_e || rc=1 +if [ $rc -eq 1 ]; then + echo "error:" + grep "\(error\):" $tmpfile_e + rm -rf $tmpdir_o $tmpfile_o $tmpfile_n $tmpdir_b $tmpfile_e + exit $rc +fi + +git checkout -q HEAD~ +echo "Building the tree before the patch" +time build $tmpfile_o +incumbent=$(grep -c "\(warning\|error\):" $tmpfile_o) + +git checkout -q $HEAD +echo "Building the tree with the patch" +time build $tmpfile_n || rc=1 +if [ $rc -eq 1 ]; then + echo "error/warning:" + grep "\(warning\|error\):" $tmpfile_n + rm -rf $tmpdir_o $tmpfile_o $tmpfile_n $tmpdir_b + exit $rc +fi + +current=$(grep -c "\(warning\|error\):" $tmpfile_n) +if [ $current -gt $incumbent ]; then + echo "New errors added:" + + tmpfile_errors_before=$(mktemp -p /build) + tmpfile_errors_now=$(mktemp -p /build) + grep "\(warning\|error\):" $tmpfile_o | sort | uniq -c > $tmpfile_errors_before + grep "\(warning\|error\):" $tmpfile_n | sort | uniq -c > $tmpfile_errors_now + + diff -U 0 $tmpfile_errors_before $tmpfile_errors_now + + rm $tmpfile_errors_before $tmpfile_errors_now + + echo "Per-file breakdown" + tmpfile_fo=$(mktemp -p /build) + tmpfile_fn=$(mktemp -p /build) + + echo "error/warning file pre:" + grep "\(warning\|error\):" $tmpfile_o | sed -n 's@\(^\.\./[/a-zA-Z0-9_.-]*.[ch]\):.*@\1@p' | sort | uniq -c \ + > $tmpfile_fo + grep "\(warning\|error\):" $tmpfile_n | sed -n 's@\(^\.\./[/a-zA-Z0-9_.-]*.[ch]\):.*@\1@p' | sort | uniq -c \ + > $tmpfile_fn + + diff -U 0 $tmpfile_fo $tmpfile_fn + rm $tmpfile_fo $tmpfile_fn + echo "pre: $incumbent post: $current" + + rc=1 +fi + +rm -rf $tmpdir_o $tmpfile_o $tmpfile_n $tmpdir_b $tmpfile_e +exit $rc diff --git a/.github/scripts/pw_tests/build_rv64_nommu_k210_defconfig.sh b/.github/scripts/pw_tests/build_rv64_nommu_k210_defconfig.sh new file mode 100644 index 00000000000000..18a610bae2df63 --- /dev/null +++ b/.github/scripts/pw_tests/build_rv64_nommu_k210_defconfig.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) 2022 by Rivos Inc. + +tmpdir=$(mktemp -d -p /build) +tmpfile=$(mktemp -p /build) +rc=0 + +tuxmake --wrapper ccache --target-arch riscv --directory . \ + --environment=KBUILD_BUILD_TIMESTAMP=@1621270510 \ + --environment=KBUILD_BUILD_USER=tuxmake --environment=KBUILD_BUILD_HOST=tuxmake \ + -o $tmpdir --toolchain gcc -z none -k nommu_k210_defconfig \ + CROSS_COMPILE=riscv64-linux- \ + >$tmpfile 2>&1 || rc=1 + +if [ $rc -ne 0 ]; then + echo "Full log:" + cat $tmpfile + echo "warnings/errors:" + grep "\(warning\|error\):" $tmpfile +fi + +rm -rf $tmpdir $tmpfile + +exit $rc diff --git a/.github/scripts/pw_tests/build_rv64_nommu_virt_defconfig.sh b/.github/scripts/pw_tests/build_rv64_nommu_virt_defconfig.sh new file mode 100644 index 00000000000000..7e919812342c41 --- /dev/null +++ b/.github/scripts/pw_tests/build_rv64_nommu_virt_defconfig.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) 2022 by Rivos Inc. + +tmpdir=$(mktemp -d -p /build) +tmpfile=$(mktemp -p /build) +rc=0 + +tuxmake --wrapper ccache --target-arch riscv --directory . \ + --environment=KBUILD_BUILD_TIMESTAMP=@1621270510 \ + --environment=KBUILD_BUILD_USER=tuxmake --environment=KBUILD_BUILD_HOST=tuxmake \ + -o $tmpdir --toolchain gcc -z none -k nommu_virt_defconfig \ + CROSS_COMPILE=riscv64-linux- \ + >$tmpfile 2>&1 || rc=1 + +if [ $rc -ne 0 ]; then + echo "Full log:" + cat $tmpfile + echo "warnings/errors:" + grep "\(warning\|error\):" $tmpfile +fi + +rm -rf $tmpdir $tmpfile + +exit $rc diff --git a/.github/scripts/pw_tests/checkpatch.sh b/.github/scripts/pw_tests/checkpatch.sh new file mode 100644 index 00000000000000..ca3946efbf6038 --- /dev/null +++ b/.github/scripts/pw_tests/checkpatch.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2019 Netronome Systems, Inc. + +IGNORED=\ +COMMIT_LOG_LONG_LINE,\ +MACRO_ARG_REUSE,\ +ALLOC_SIZEOF_STRUCT,\ +NO_AUTHOR_SIGN_OFF,\ +GIT_COMMIT_ID,\ +CAMELCASE + +tmpfile=$(mktemp -p /build) + +./scripts/checkpatch.pl --strict --ignore=$IGNORED -g HEAD | tee $tmpfile + +grep 'total: 0 errors, 0 warnings, 0 checks' $tmpfile +ret=$? + +# return 250 (warning) if there are not errors +[ $ret -ne 0 ] && grep -P 'total: 0 errors, \d+ warnings, \d+ checks' $tmpfile && ret=250 + +if [ $ret -ne 0 ]; then + grep '\(WARNING\|ERROR\|CHECK\): ' $tmpfile | LC_COLLATE=C sort -u +else + grep 'total: ' $tmpfile | LC_COLLATE=C sort -u +fi + +rm $tmpfile + +exit $ret + +# ./scripts/checkpatch.pl --ignore=SPACING_CAST,LONG_LINE,LONG_LINE_COMMENT,LONG_LINE_STRING,LINE_SPACING_STRUCT,FILE_PATH_CHANGES,CAMELCASE,OPEN_ENDED_LINE,AVOID_EXTERNS_HEADER,UNCOMMENTED_DEFINITION diff --git a/.github/scripts/pw_tests/dtb_warn_rv64.sh b/.github/scripts/pw_tests/dtb_warn_rv64.sh new file mode 100644 index 00000000000000..1ab4cfcb8c4fa3 --- /dev/null +++ b/.github/scripts/pw_tests/dtb_warn_rv64.sh @@ -0,0 +1,61 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2019 Netronome Systems, Inc. + +# Modified tests/patch/build_defconfig_warn.sh for RISC-V builds + +tmpfile_o=$(mktemp -p /build) +tmpfile_n=$(mktemp -p /build) + +tmpdir_o=$(mktemp -d -p /build) +tmpdir_n=$(mktemp -d -p /build) + +rc=0 + +echo "Redirect to $tmpfile_o and $tmpfile_n" + +HEAD=$(git rev-parse HEAD) + +echo "Tree base:" +git log -1 --pretty='%h ("%s")' HEAD~ + +git checkout -q HEAD~ + +echo "Building the tree before the patch" + +make -C . O=$tmpdir_o ARCH=riscv CROSS_COMPILE=riscv64-linux- \ + defconfig + +make -C . O=$tmpdir_o ARCH=riscv CROSS_COMPILE=riscv64-linux- \ + dtbs_check W=1 -j$(nproc) \ + 2> >(tee $tmpfile_o) + +incumbent=$(cat $tmpfile_o | grep -v "From schema" | wc -l) + +echo "Building the tree with the patch" + +git checkout -q $HEAD + +make -C . O=$tmpdir_n ARCH=riscv CROSS_COMPILE=riscv64-linux- \ + defconfig + +make -C . O=$tmpdir_n ARCH=riscv CROSS_COMPILE=riscv64-linux- \ + dtbs_check W=1 -j$(nproc) \ + 2> >(tee $tmpfile_n) || rc=1 + +current=$(cat $tmpfile_n | grep -v "From schema" | wc -l) + +if [ $current -gt $incumbent ]; then + echo "Errors and warnings before: $incumbent this patch: $current" + echo "New errors added" + sed -i 's|^.*arch|arch|g' $tmpfile_o + sed -i 's|^.*arch|arch|g' $tmpfile_n + diff -U 0 $tmpfile_o $tmpfile_n + + rc=1 +fi + +rm -rf $tmpdir_o $tmpdir_n $tmpfile_o $tmpfile_n + +exit $rc diff --git a/.github/scripts/pw_tests/header_inline.sh b/.github/scripts/pw_tests/header_inline.sh new file mode 100644 index 00000000000000..3b33d5ebd91ab0 --- /dev/null +++ b/.github/scripts/pw_tests/header_inline.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) 2020 Facebook + +inlines=$( + git show -- '*.h' | grep -C1 -P '^\+static (?!(__always_)?inline).*\('; + git show -- '*.h' | grep -C1 -P '^\+(static )?(?!(__always_)?inline )((unsigned|long|short) )*(char|bool|void|int|u[0-9]*) [0-9A-Za-z_]*\(.*\) *{' + ) + +if [ -z "$inlines" ]; then + exit 0 +fi + +msg="Detected static functions without inline keyword in header files:" +echo -e "$msg\n$inlines" +count=$( (echo "---"; echo "$inlines") | grep '^---$' | wc -l) +echo "$msg $count" +exit 1 diff --git a/.github/scripts/pw_tests/kdoc.sh b/.github/scripts/pw_tests/kdoc.sh new file mode 100644 index 00000000000000..2fc8141e84790d --- /dev/null +++ b/.github/scripts/pw_tests/kdoc.sh @@ -0,0 +1,50 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2019 Netronome Systems, Inc. +# Copyright (c) 2020 Facebook + +tmpfile_o=$(mktemp -p /build) +tmpfile_n=$(mktemp -p /build) +rc=0 + +files=$(git show --pretty="" --name-only HEAD) + +HEAD=$(git rev-parse HEAD) + +echo "Checking the tree before the patch" +git checkout -q HEAD~ +./scripts/kernel-doc -none $files 2> >(tee $tmpfile_o) + +incumbent=$(grep -v 'Error: Cannot open file ' $tmpfile_o | wc -l) + +echo "Checking the tree with the patch" + +git checkout -q $HEAD +./scripts/kernel-doc -none $files 2> >(tee $tmpfile_n) + +current=$(grep -v 'Error: Cannot open file ' $tmpfile_n | wc -l) + + +if [ $current -gt $incumbent ]; then + echo "Errors and warnings before: $incumbent this patch: $current" + echo "New warnings added" + diff $tmpfile_o $tmpfile_n + + echo "Per-file breakdown" + tmpfile_fo=$(mktemp -p /build) + tmpfile_fn=$(mktemp -p /build) + + grep -i "\(warn\|error\)" $tmpfile_o | sed -n 's@\(^\.\./[/a-zA-Z0-9_.-]*.[ch]\):.*@\1@p' | sort | uniq -c \ + >$tmpfile_fo + grep -i "\(warn\|error\)" $tmpfile_n | sed -n 's@\(^\.\./[/a-zA-Z0-9_.-]*.[ch]\):.*@\1@p' | sort | uniq -c \ + >$tmpfile_fn + + diff $tmpfile_fo $tmpfile_fn + rm $tmpfile_fo $tmpfile_fn + rc=1 +fi + +rm $tmpfile_o $tmpfile_n + +exit $rc diff --git a/.github/scripts/pw_tests/module_param.sh b/.github/scripts/pw_tests/module_param.sh new file mode 100644 index 00000000000000..3af83b63699b14 --- /dev/null +++ b/.github/scripts/pw_tests/module_param.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) 2020 Facebook + +params=$(git show | grep -i '^\+.*module_param') +new_params=$(git show | grep -ic '^\+.*module_param') +old_params=$(git show | grep -ic '^\-.*module_param') + +echo "Was $old_params now: $new_params" + +if [ -z "$params" ]; then + exit 0 +fi + +echo -e "Detected module_param\n$params" +if [ $new_params -eq $old_params ]; then + exit 250 +fi + +exit 1 diff --git a/.github/scripts/pw_tests/verify_fixes.sh b/.github/scripts/pw_tests/verify_fixes.sh new file mode 100644 index 00000000000000..23795485e4ffab --- /dev/null +++ b/.github/scripts/pw_tests/verify_fixes.sh @@ -0,0 +1,212 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2019 Stephen Rothwell +# Copyright (C) 2019 Greg Kroah-Hartman +# Copyright (c) 2020 Facebook +# +# Verify that the "Fixes:" tag is correct in a kernel commit +# +# usage: +# verify_fixes.sh GIT_RANGE +# +# To test just the HEAD commit do: +# verify_fixes.sh HEAD^..HEAD +# +# +# Thanks to Stephen Rothwell for the majority of this code +# + +# Only thing you might want to change here, the location of where Linus's git +# tree is on your system: + +########################################## +# No need to touch anything below here + +split_re='^([Cc][Oo][Mm][Mm][Ii][Tt])?[[:space:]]*([[:xdigit:]]{5,})([[:space:]]*)(.*)$' +nl=$'\n' +tab=$'\t' + +help() +{ + echo "error, git range not found" + echo "usage:" + echo " $0 GIT_RANGE" + exit 1 +} + +# Strip the leading and training spaces from a string +strip_spaces() +{ + [[ "$1" =~ ^[[:space:]]*(.*[^[:space:]])[[:space:]]*$ ]] + echo "${BASH_REMATCH[1]}" +} + +verify_fixes() +{ + git_range=$1 + error=0 + commits=$(git rev-list --no-merges -i --grep='^[[:space:]]*Fixes:' "${git_range}") + if [ -z "$commits" ]; then + echo "No Fixes tag" + return 0 + fi + + for c in $commits; do + + commit_log=$(git log -1 --format='%h ("%s")' "$c") +# commit_msg="In commit: +# $commit_log +#" + commit_msg="Commit: $commit_log +" + + fixes_lines=$(git log -1 --format='%B' "$c" | + grep -i '^[[:space:]]*Fixes:') + + while read -r fline; do + [[ "$fline" =~ ^[[:space:]]*[Ff][Ii][Xx][Ee][Ss]:[[:space:]]*(.*)$ ]] + f="${BASH_REMATCH[1]}" +# fixes_msg=" Fixes tag: +# $fline +# Has these problem(s): +#" + fixes_msg=" Fixes tag: $fline + Has these problem(s): +" + sha= + subject= + msg= + + if git log -1 --format='%B' "$c" | tr '\n' '#' | grep -qF "##$fline##"; then + msg="${msg:+${msg}${nl}}${tab}${tab}- empty lines surround the Fixes tag" + error=$(( error + 1 )) + fi + + if [[ "$f" =~ $split_re ]]; then + first="${BASH_REMATCH[1]}" + sha="${BASH_REMATCH[2]}" + spaces="${BASH_REMATCH[3]}" + subject="${BASH_REMATCH[4]}" + if [ "$first" ]; then + msg="${msg:+${msg}${nl}}${tab}${tab}- leading word '$first' unexpected" + error=$(( error + 1 )) + fi + if [ -z "$subject" ]; then + msg="${msg:+${msg}${nl}}${tab}${tab}- missing subject" + error=$(( error + 1 )) + elif [ -z "$spaces" ]; then + msg="${msg:+${msg}${nl}}${tab}${tab}- missing space between the SHA1 and the subject" + error=$(( error + 1 )) + fi + else + printf '%s%s\t\t- %s\n' "$commit_msg" "$fixes_msg" 'No SHA1 recognised' + error=$(( error + 1 )) + commit_msg='' + continue + fi + if ! git rev-parse -q --verify "$sha" >/dev/null; then + printf '%s%s\t\t- %s\n' "$commit_msg" "$fixes_msg" 'Target SHA1 does not exist' + error=$(( error + 1 )) + commit_msg='' + continue + fi + + if [ "${#sha}" -lt 12 ]; then + msg="${msg:+${msg}${nl}}${tab}${tab}- SHA1 should be at least 12 digits long${nl}${tab}${tab} Can be fixed by setting core.abbrev to 12 (or more) or (for git v2.11${nl}${tab}${tab} or later) just making sure it is not set (or set to \"auto\")." + error=$(( error + 1 )) + fi + # reduce the subject to the part between () if there + if [[ "$subject" =~ ^\((.*)\) ]]; then + subject="${BASH_REMATCH[1]}" + elif [[ "$subject" =~ ^\((.*) ]]; then + subject="${BASH_REMATCH[1]}" + msg="${msg:+${msg}${nl}}${tab}${tab}- Subject has leading but no trailing parentheses" + error=$(( error + 1 )) + fi + + # strip matching quotes at the start and end of the subject + # the unicode characters in the classes are + # U+201C LEFT DOUBLE QUOTATION MARK + # U+201D RIGHT DOUBLE QUOTATION MARK + # U+2018 LEFT SINGLE QUOTATION MARK + # U+2019 RIGHT SINGLE QUOTATION MARK + re1=$'^[\"\u201C](.*)[\"\u201D]$' + re2=$'^[\'\u2018](.*)[\'\u2019]$' + re3=$'^[\"\'\u201C\u2018](.*)$' + if [[ "$subject" =~ $re1 ]]; then + subject="${BASH_REMATCH[1]}" + elif [[ "$subject" =~ $re2 ]]; then + subject="${BASH_REMATCH[1]}" + elif [[ "$subject" =~ $re3 ]]; then + subject="${BASH_REMATCH[1]}" + msg="${msg:+${msg}${nl}}${tab}${tab}- Subject has leading but no trailing quotes" + error=$(( error + 1 )) + fi + + subject=$(strip_spaces "$subject") + + target_subject=$(git log -1 --format='%s' "$sha") + target_subject=$(strip_spaces "$target_subject") + + # match with ellipses + case "$subject" in + *...) subject="${subject%...}" + target_subject="${target_subject:0:${#subject}}" + ;; + ...*) subject="${subject#...}" + target_subject="${target_subject: -${#subject}}" + ;; + *\ ...\ *) + s1="${subject% ... *}" + s2="${subject#* ... }" + subject="$s1 $s2" + t1="${target_subject:0:${#s1}}" + t2="${target_subject: -${#s2}}" + target_subject="$t1 $t2" + ;; + esac + subject=$(strip_spaces "$subject") + target_subject=$(strip_spaces "$target_subject") + + if [ "$subject" != "${target_subject:0:${#subject}}" ]; then + msg="${msg:+${msg}${nl}}${tab}${tab}- Subject does not match target commit subject${nl}${tab}${tab} Just use${nl}${tab}${tab}${tab}git log -1 --format='Fixes: %h (\"%s\")'" + error=$(( error + 1 )) + fi + lsha=$(git rev-parse -q --verify "$sha") + if [ -z "$lsha" ]; then + count=$(git rev-list --count "$sha".."$c") + if [ "$count" -eq 0 ]; then + msg="${msg:+${msg}${nl}}${tab}${tab}- Target is not an ancestor of this commit" + error=$(( error + 1 )) + fi + fi + + if [ "$msg" ]; then + printf '%s%s%s\n' "$commit_msg" "$fixes_msg" "$msg" + commit_msg='' + # Make sure we don't accidentally miss anything. + if [ $error -eq 0 ]; then + echo 'Whoops! $error out of sync with $msg' + error=1 + fi + fi + done <<< "$fixes_lines" + done + +if [ ${error} -ne 0 ] ; then + echo "Problems with Fixes tag: $error" + exit 1 + fi + echo "Fixes tag looks correct" + return 0 +} + +git_range="HEAD~..HEAD" + +if [ "${git_range}" == "" ] ; then + help +fi + +verify_fixes "${git_range}" +exit 0 diff --git a/.github/scripts/pw_tests/verify_signedoff.sh b/.github/scripts/pw_tests/verify_signedoff.sh new file mode 100644 index 00000000000000..efd2366cb52195 --- /dev/null +++ b/.github/scripts/pw_tests/verify_signedoff.sh @@ -0,0 +1,81 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2019 Stephen Rothwell +# Copyright (C) 2019 Greg Kroah-Hartman +# +# Verify that the signed-off-by chain looks correct for a range of git commits. +# +# usage: +# verify_signedoff.sh GIT_RANGE +# +# To test just the HEAD commit do: +# verify_signedoff.sh HEAD^..HEAD +# +# +# Thanks to Stephen Rothwell for the majority of this code +# + +help() +{ + echo "error, git range not found" + echo "usage:" + echo " $0 GIT_RANGE" + exit 1 +} + +verify_signedoff() +{ + git_range=$1 + error=false + for c in $(git rev-list --no-merges "${git_range}"); do + ae=$(git log -1 --format='%ae' "$c") + aE=$(git log -1 --format='%aE' "$c") + an=$(git log -1 --format='%an' "$c") + aN=$(git log -1 --format='%aN' "$c") + ce=$(git log -1 --format='%ce' "$c") + cE=$(git log -1 --format='%cE' "$c") + cn=$(git log -1 --format='%cn' "$c") + cN=$(git log -1 --format='%cN' "$c") + sob=$(git log -1 --format='%b' "$c" | grep -i '^[[:space:]]*Signed-off-by:') + + am=false + cm=false + grep -i -q "<$ae>" <<<"$sob" || + grep -i -q "<$aE>" <<<"$sob" || + grep -i -q ":[[:space:]]*${an}[[:space:]]*<" <<<"$sob" || + grep -i -q ":[[:space:]]*${aN}[[:space:]]*<" <<<"$sob" || + am=true + grep -i -q "<$ce>" <<<"$sob" || + grep -i -q "<$cE>" <<<"$sob" || + grep -i -q ":[[:space:]]*${cn}[[:space:]]*<" <<<"$sob" || + grep -i -q ":[[:space:]]*${cN}[[:space:]]*<" <<<"$sob" || + cm=true + + if "$am" || "$cm"; then + printf "Commit %s\n" "$(git show -s --abbrev-commit --abbrev=12 --pretty=format:"%h (\"%s\")%n" "${c}")" + "$am" && printf "\tauthor Signed-off-by missing\n" + "$cm" && printf "\tcommitter Signed-off-by missing\n" + printf "\tauthor email: %s\n" "$ae" + printf "\tcommitter email: %s\n" "$ce" + readarray -t s <<< "${sob}" + printf "\t%s\n" "${s[@]}" + printf "\n" + error=true + fi + done + if "$error"; then + echo "Errors in tree with Signed-off-by, please fix!" + exit 1 + fi + echo "Signed-off-by tag matches author and committer" +} + +git_range="HEAD~..HEAD" + +if [ "${git_range}" == "" ] ; then + help +fi + +verify_signedoff "${git_range}" +exit 0 diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt new file mode 100644 index 00000000000000..118fc389f3ad00 --- /dev/null +++ b/.github/scripts/requirements.txt @@ -0,0 +1,5 @@ +PyGithub +python-lsp-server +requests +ply +GitPython diff --git a/.github/scripts/series.sh b/.github/scripts/series.sh new file mode 100755 index 00000000000000..3713e781d9ec28 --- /dev/null +++ b/.github/scripts/series.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2023 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail +d=$(dirname "${BASH_SOURCE[0]}") +. $d/series/utils.sh + + +logs=$(get_logs_dir) +f=${logs}/series.log + +date -Iseconds | tee -a ${f} +echo "Build, and boot various kernels" | tee -a ${f} +echo "Top 16 commits" | tee -a ${f} +git log -16 --abbrev=12 --pretty="commit %h (\"%s\")" | tee -a ${f} + +kernel_base_sha=$(git log -1 --pretty=%H $(git log -1 --reverse --pretty=%H .github)^) +echo "build_name $(git describe --tags ${kernel_base_sha})" | tee -a ${f} +build_name=$(git describe --tags ${kernel_base_sha}) + +${d}/series/build_all.sh | tee -a ${f} +${d}/series/test_all.sh | tee -a ${f} + +# Some logs contain invalid bytes (not utf-8) and then makes the following +# script fail so convert them all. +for f in `ls ${logs}`; do + iconv -c -t utf-8 ${logs}/${f} > ${logs}/${f}_tmp + mv ${logs}/${f}_tmp ${logs}/${f} +done + +python3 ${d}/series/github_ci_squad_results.py --logs-path ${logs} +python3 ${d}/series/generate_metadata.py --logs-path ${logs} \ + --job-url ${GITHUB_JOB_URL} --branch ${GITHUB_BRANCH_NAME} + +curl --header "Authorization: token ${SQUAD_TOKEN}" \ + --form tests=@${logs}/squad.json \ + --form metadata=@${logs}/metadata.json \ + https://mazarinen.tail1c623.ts.net/api/submit/riscv-linux/linux-all/${build_name}/qemu diff --git a/.github/scripts/series/build_all.sh b/.github/scripts/series/build_all.sh new file mode 100755 index 00000000000000..44082e2861ef8e --- /dev/null +++ b/.github/scripts/series/build_all.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2023 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +d=$(dirname "${BASH_SOURCE[0]}") +. $d/utils.sh + +rc=0 +while read xlen config fragment toolchain; do + ${d}/kernel_builder.sh $xlen $config $fragment $toolchain || rc=1 + if [[ $config == "kselftest" ]]; then + ${d}/selftest_builder.sh $xlen $config $fragment $toolchain || rc=1 + fi +done < <($d/generate_build_configs.sh) +exit 0 diff --git a/.github/scripts/series/build_kernel.sh b/.github/scripts/series/build_kernel.sh new file mode 100755 index 00000000000000..1d43196c68db47 --- /dev/null +++ b/.github/scripts/series/build_kernel.sh @@ -0,0 +1,94 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2023 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +set -x +set -euo pipefail + +d=$(dirname "${BASH_SOURCE[0]}") +. $d/utils.sh + +lnxroot=$(pwd) + +# E.g. build_kernel.sh rv32 defconfig /path/to/fragment llvm +# build_kernel.sh rv64 defconfig plain gcc + +xlen=$1 +config=$2 +fragment=$3 +toolchain=$4 + +install=${ci_root}/$(gen_kernel_name $xlen $config $fragment $toolchain) +output=${install}_build +triple=${ci_triple} + +keep_build=0 # enable for kselftest + +make_gcc() { + make O=$output ARCH=riscv CROSS_COMPILE=${triple}- \ + "CC=ccache ${triple}-gcc" 'HOSTCC=ccache gcc' $* +} + +make_llvm() { + make O=$output ARCH=riscv CROSS_COMPILE=${triple}- \ + LLVM=1 LLVM_IAS=1 'CC=ccache clang' 'HOSTCC=ccache clang' $* +} + +make_wrap() { + if [[ $toolchain == "llvm" ]]; then + make_llvm $* + elif [[ $toolchain == "gcc-old" ]]; then + oldpath=${PATH} + export PATH=/opt/gcc-old/riscv64-linux/bin:${oldpath} + make_gcc $* + export PATH=${oldpath} + else + make_gcc $* + fi +} + +rm -rf ${output} +rm -rf ${install} +mkdir -p ${output} +mkdir -p ${install} + +if [[ $config == "allmodconfig" || $config == "randconfig" ]]; then + make_wrap KCONFIG_ALLCONFIG=$lnxroot/arch/riscv/configs/${xlen//rv/}-bit.config $config + $lnxroot/scripts/kconfig/merge_config.sh -m -O $output $output/.config \ + <(echo "CONFIG_WERROR=n") \ + <(echo "CONFIG_DRM_WERROR=n") \ + <(echo "CONFIG_GCC_PLUGINS=n") +elif [[ $config == "kselftest" ]]; then + apply_patches + trap unapply_patches EXIT + make_wrap defconfig + make_wrap kselftest-merge + $lnxroot/scripts/kconfig/merge_config.sh -y -m -O $output $output/.config \ + <(echo "CONFIG_KERNEL_UNCOMPRESSED=y") + make_wrap olddefconfig + keep_build=1 +elif [[ $config == "testsuites" ]]; then + make_wrap ubuntu_defconfig +else + if [[ $fragment == "plain" ]]; then + $lnxroot/scripts/kconfig/merge_config.sh -y -m -O $output $lnxroot/arch/riscv/configs/$config \ + $lnxroot/arch/riscv/configs/${xlen//rv/}-bit.config \ + <(echo "CONFIG_KERNEL_UNCOMPRESSED=y") + else + $lnxroot/scripts/kconfig/merge_config.sh -y -m -O $output $lnxroot/arch/riscv/configs/$config \ + $fragment \ + $lnxroot/arch/riscv/configs/${xlen//rv/}-bit.config \ + <(echo "CONFIG_KERNEL_UNCOMPRESSED=y") + fi + make_wrap olddefconfig +fi + +make_wrap -j $(nproc) -Oline + +make_wrap INSTALL_PATH=${install} install +make_wrap INSTALL_MOD_STRIP=1 INSTALL_MOD_PATH=${install} modules_install || true + +if ! (( ${keep_build} )); then + rm -rf ${output} +fi diff --git a/.github/scripts/series/build_only_defconfig.sh b/.github/scripts/series/build_only_defconfig.sh new file mode 100755 index 00000000000000..23aad429a41c2d --- /dev/null +++ b/.github/scripts/series/build_only_defconfig.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2024 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +d=$(dirname "${BASH_SOURCE[0]}") +. $d/utils.sh + +rc=0 +${d}/kernel_builder.sh rv64 defconfig plain gcc || rc=1 +exit $rc diff --git a/.github/scripts/series/build_only_kselftest.sh b/.github/scripts/series/build_only_kselftest.sh new file mode 100755 index 00000000000000..b935e6d814a34c --- /dev/null +++ b/.github/scripts/series/build_only_kselftest.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2023 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +d=$(dirname "${BASH_SOURCE[0]}") +. $d/utils.sh +. $d/kselftest_prep.sh + +rc=0 +${d}/kernel_builder.sh rv64 kselftest plain gcc || rc=1 +${d}/selftest_builder.sh rv64 kselftest plain gcc || rc=1 +exit $rc diff --git a/.github/scripts/series/build_selftest.sh b/.github/scripts/series/build_selftest.sh new file mode 100755 index 00000000000000..9f9100ad02a0e7 --- /dev/null +++ b/.github/scripts/series/build_selftest.sh @@ -0,0 +1,63 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2024 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +set -x +set -euo pipefail + +d=$(dirname "${BASH_SOURCE[0]}") +. $d/utils.sh + +lnxroot=$(pwd) + +# E.g. build_selftest.sh rv64 kselftest-bpf plain gcc + +xlen=$1 +config=$2 +fragment=$3 +toolchain=$4 + +if ! [[ "$config" =~ ^kselftest ]]; then + echo "Not a selftest config: please try kselftest kselftest-bpf kselftest-net" + exit 1 +fi + +install=${ci_root}/$(gen_kernel_name $xlen $config $fragment $toolchain) +output=${install}_build +triple=${ci_triple} + +if ! [[ -d $output ]]; then + echo "Cannot find kernel build" + exit 1 +fi + +make_gcc() { + make O=$output ARCH=riscv CROSS_COMPILE=${triple}- \ + "CC=${triple}-gcc" 'HOSTCC=gcc' $* +} + +make_llvm() { + make O=$output ARCH=riscv CROSS_COMPILE=${triple}- \ + LLVM=1 LLVM_IAS=1 'CC=clang' 'HOSTCC=clang' $* +} + +make_wrap() { + if [ $toolchain == "llvm" ]; then + make_llvm $* + else + make_gcc $* + fi +} + +apply_patches +trap unapply_patches EXIT + +make_wrap -j $(($(nproc)-1)) headers + +make_wrap SKIP_TARGETS="bpf" -j $(($(nproc)-1)) -C tools/testing/selftests install +make_wrap TARGETS="bpf" SKIP_TARGETS="" -j $(($(nproc)-1)) -C tools/testing/selftests +make_wrap TARGETS="bpf" SKIP_TARGETS="" COLLECTION="bpf" -j $(($(nproc)-1)) \ + -C tools/testing/selftests/bpf emit_tests | grep -e '^bpf:' \ + >> $output/kselftest/kselftest_install/kselftest-list.txt +cp -R $output/kselftest/bpf $output/kselftest/kselftest_install diff --git a/.github/scripts/series/generate_build_configs.sh b/.github/scripts/series/generate_build_configs.sh new file mode 100755 index 00000000000000..2e657bbbb70863 --- /dev/null +++ b/.github/scripts/series/generate_build_configs.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2023 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +d=$(dirname "${BASH_SOURCE[0]}") + +toolchains="gcc llvm" + +# SKIP_BUILD_CONFIG_TOOLCHAIN= + +do_generate_toolchain () { + local toolchain=$1 + + if [ ! -z "${SKIP_BUILD_CONFIG_TOOLCHAIN:-}" ] && echo $toolchain | egrep -wq "$SKIP_BUILD_CONFIG_TOOLCHAIN"; then + return 1 + fi + return 0 +} + +while read xlen config fragment; do + if [ $xlen == "rv32" ] && [[ "$config" =~ "k210" ]]; then + continue + fi + + if do_generate_toolchain "gcc"; then + echo $xlen $config $fragment gcc + fi + if do_generate_toolchain "llvm"; then + echo $xlen $config $fragment llvm + fi +done < <($d/generate_kconfigs.sh) + +echo rv64 allmodconfig plain gcc-old diff --git a/.github/scripts/series/generate_kconfigs.sh b/.github/scripts/series/generate_kconfigs.sh new file mode 100755 index 00000000000000..6456e1a83b0b10 --- /dev/null +++ b/.github/scripts/series/generate_kconfigs.sh @@ -0,0 +1,65 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2023 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +d=$(dirname "${BASH_SOURCE[0]}") +lnxroot=$(pwd) +kconfigs=$d/kconfigs + +builtin_skip="rv32_defconfig" +builtin_allow="" + +print() { + if [ ! -z "${SKIP_KCONFIG:-}" ]; then + if echo $* | egrep -q "$SKIP_KCONFIG"; then + return + fi + fi + if [ ! -z "$builtin_skip" ]; then + if echo $* | egrep -q "$builtin_skip"; then + return + fi + fi + if [ ! -z "${ALLOW_KCONFIG:-}" ]; then + if echo $* | egrep -q "$ALLOW_KCONFIG"; then + echo $* + fi + return + fi + if [ ! -z "$builtin_allow" ]; then + if echo $* | egrep -q "$builtin_allow"; then + echo $* + fi + return + fi + + echo $* +} + +# Too much? Override by uncommenting below: +# print rv64 defconfig "plain" && exit 0 + +defconfigs=$(find $lnxroot/arch/riscv/configs/ -type f -name '*defconfig' -printf '%f\n') +for i in $defconfigs; do + for xlen in 32 64; do + frags=$(echo $i && find $kconfigs/$i -type f -printf '%f\n' 2>/dev/null || :) + for frag in $frags; do + if [ $frag == $i ]; then + fn=${xlen}__${i} + fr="plain" + else + fn=${xlen}_${frag}__$i + fr=$(readlink -f $kconfigs/$i/$frag) + fi + + print rv$xlen $i $fr + done + done +done + +#special case set KCONFIG_ALLCONFIG +print rv32 allmodconfig "plain" +print rv64 allmodconfig "plain" diff --git a/.github/scripts/series/generate_metadata.py b/.github/scripts/series/generate_metadata.py new file mode 100644 index 00000000000000..de6d97be0c1299 --- /dev/null +++ b/.github/scripts/series/generate_metadata.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 + +import argparse +import json +import os + +def parse_args(): + parser = argparse.ArgumentParser(description = 'Output Squad metadata') + parser.add_argument("--logs-path", default = "", + help = 'Path to the logs directory') + parser.add_argument("--job-url", default = "", + help = 'URL to the current Github job') + parser.add_argument("--branch", default = "", + help = 'Branch name of the current Github job') + + return parser.parse_args() + +def generate_squad_json(logs_path, job_url, branch): + dict_results = {} + + dict_results["job_url"] = job_url + dict_results["branch"] = branch + + report_log_path = os.path.join(logs_path, "series_report_warn_bug") + if os.path.isfile(report_log_path): + with open(report_log_path, 'r') as f: + dict_results["report"] = f.read() + else: + dict_results["report"] = "Empty" + + with open(logs_path + "/" + "metadata.json", "w") as f: + json.dump(dict_results, f) + +if __name__ == "__main__": + args = parse_args() + generate_squad_json(args.logs_path, args.job_url, args.branch) + diff --git a/.github/scripts/series/generate_qemu_test_configs.sh b/.github/scripts/series/generate_qemu_test_configs.sh new file mode 100644 index 00000000000000..e62ea9fb06c916 --- /dev/null +++ b/.github/scripts/series/generate_qemu_test_configs.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2024 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +xlen=$1 +config=$2 +fragment=$3 +toolchain=$4 +rootfs=$5 + +rv64_cpus=( + "rv64" + "rv64,v=true,vlen=256,elen=64,h=true,zbkb=on,zbkc=on,zbkx=on,zkr=on,zkt=on,svinval=on,svnapot=on,svpbmt=on" +) + +list_cpus+=( "sifive-u54" ) + + +rv32_cpus=( + "rv32" +) diff --git a/.github/scripts/series/generate_test_runs.sh b/.github/scripts/series/generate_test_runs.sh new file mode 100755 index 00000000000000..4d987e7e7abf92 --- /dev/null +++ b/.github/scripts/series/generate_test_runs.sh @@ -0,0 +1,47 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2023 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +d=$(dirname "${BASH_SOURCE[0]}") + +rv64_rootfs="alpine ubuntu" +rv32_rootfs="buildroot_glibc" + +# SKIP_TEST_RUN_ROOTFS= + +print() { + if [ ! -z "${SKIP_TEST_RUN_ROOTFS:-}" ]; then + if echo $* | egrep -wq "$SKIP_TEST_RUN_ROOTFS"; then + return + fi + fi + + echo $* +} + +while read xlen config fragment image toolchain; do + if [[ "$config" =~ "nommu" ]]; then + continue + fi + if [[ "$config" =~ "allmodconfig" ]]; then + continue + fi + if [[ "$config" =~ "randconfig" ]]; then + continue + fi + if [[ "$config" =~ "kselftest" ]]; then + print $xlen $config $fragment $image $toolchain ubuntu + continue + fi + + if [[ $xlen == "rv64" ]]; then + print $xlen $config $fragment $image $toolchain alpine + print $xlen $config $fragment $image $toolchain ubuntu + else + print $xlen $config $fragment $image $toolchain buildroot_glibc + print $xlen $config $fragment $image $toolchain buildroot_musl + fi +done < <($d/generate_build_configs.sh) diff --git a/.github/scripts/series/github_ci_squad_results.py b/.github/scripts/series/github_ci_squad_results.py new file mode 100644 index 00000000000000..4da6e7607de169 --- /dev/null +++ b/.github/scripts/series/github_ci_squad_results.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 + +import argparse +import json + +def parse_args(): + parser = argparse.ArgumentParser(description = 'Output Squad tests results for the Github CI') + parser.add_argument("--logs-path", default = "", + help = 'Path to the log files') + + return parser.parse_args() + +def generate_squad_json(logs_path): + dict_results = {} + + with open(logs_path + "/series.log", "r") as f: + logs_content = f.readlines() + + for line in logs_content: + # ::notice::OK Build kernel rv64__nommu_k210_sdcard_defconfig__plain__gcc took 15.74s + if not line.startswith("::notice::") and not line.startswith("::error::"): + continue + + # We parse only the Builds to get the build name and then + # we add all the corresponding tests + + # Either "Build" or "Test" + type_result = line.split(" ")[1] + if type_result == "Test": + break + + build_name = line.split(" ")[3] + time = line.split(" ")[-1] + + with open(logs_path + "/build_kernel___" + build_name + ".log", "r") as f: + build_content = f.read() + + if line.split(" ")[0] == "::error::FAIL": + dict_results[build_name + "/build"] = { "result": "fail", "time": time, "log": build_content } + continue + + dict_results[build_name + "/build"] = { "result": "pass", "time": time, "log": build_content } + + # The build succeeded, so look for the associated tests + for test_line in logs_content: + if not test_line.startswith("::notice::") and not test_line.startswith("::error::"): + continue + + type_result = test_line.split(" ")[1] + if type_result == "Build": + continue + + test_build_name = test_line.split(" ")[3] + if test_build_name != build_name: + continue + + rootfs = test_line.split(" ")[4] + test_type = test_line.split(" ")[5] + "__" + test_line.split(" ")[6] + "__" + test_line.split(" ")[7] + "__" + test_line.split(" ")[8] + + log_name = "test_kernel" + "___" + test_build_name + "___" + rootfs + "___" + test_type + ".log" + with open(logs_path + "/" + log_name, "r") as f: + log_content = f.read() + + if test_line.split(" ")[0] == "::error::FAIL": + result = "fail" + else: + result = "pass" + + dict_results[build_name + "/" + rootfs + "___" + test_type] = { "result": result, "log": log_content } + + + with open(logs_path + "/squad.json", "w") as f: + json.dump(dict_results, f) + +if __name__ == "__main__": + args = parse_args() + generate_squad_json(args.logs_path) + diff --git a/.github/scripts/series/kconfigs/defconfig/early_boot_alternative b/.github/scripts/series/kconfigs/defconfig/early_boot_alternative new file mode 100644 index 00000000000000..e0876280809bfd --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/early_boot_alternative @@ -0,0 +1,2 @@ +CONFIG_RISCV_ALTERNATIVE=y +CONFIG_RISCV_ALTERNATIVE_EARLY=y diff --git a/.github/scripts/series/kconfigs/defconfig/early_boot_alternative_reloc b/.github/scripts/series/kconfigs/defconfig/early_boot_alternative_reloc new file mode 100644 index 00000000000000..55bd04829bdc15 --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/early_boot_alternative_reloc @@ -0,0 +1,3 @@ +CONFIG_RELOCATABLE=y +CONFIG_RISCV_ALTERNATIVE=y +CONFIG_RISCV_ALTERNATIVE_EARLY=y diff --git a/.github/scripts/series/kconfigs/defconfig/flatmem b/.github/scripts/series/kconfigs/defconfig/flatmem new file mode 100644 index 00000000000000..a0e1ed12d66f58 --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/flatmem @@ -0,0 +1,3 @@ +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM_MANUAL=y +CONFIG_FLATMEM=y diff --git a/.github/scripts/series/kconfigs/defconfig/hardened_usercopy_slub b/.github/scripts/series/kconfigs/defconfig/hardened_usercopy_slub new file mode 100644 index 00000000000000..d1a8be99f2f7c4 --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/hardened_usercopy_slub @@ -0,0 +1,2 @@ +CONFIG_SLUB=y +CONFIG_HARDENED_USERCOPY=y diff --git a/.github/scripts/series/kconfigs/defconfig/kasan b/.github/scripts/series/kconfigs/defconfig/kasan new file mode 100644 index 00000000000000..642c037c8e96d6 --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/kasan @@ -0,0 +1,2 @@ +CONFIG_KASAN=y +# CONFIG_KASAN_VMALLOC is not set diff --git a/.github/scripts/series/kconfigs/defconfig/kasan_inline b/.github/scripts/series/kconfigs/defconfig/kasan_inline new file mode 100644 index 00000000000000..d18d056f78f1fc --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/kasan_inline @@ -0,0 +1,2 @@ +CONFIG_KASAN=y +CONFIG_KASAN_INLINE=y diff --git a/.github/scripts/series/kconfigs/defconfig/kasan_sparsemem_novmemmmap b/.github/scripts/series/kconfigs/defconfig/kasan_sparsemem_novmemmmap new file mode 100644 index 00000000000000..c9b4f0c2efec94 --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/kasan_sparsemem_novmemmmap @@ -0,0 +1,5 @@ +CONFIG_KASAN=y +# CONFIG_FLATMEM_MANUAL is not set +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +# CONFIG_SPARSEMEM_VMEMMAP is not set diff --git a/.github/scripts/series/kconfigs/defconfig/kasan_sparsemem_vmemmmap b/.github/scripts/series/kconfigs/defconfig/kasan_sparsemem_vmemmmap new file mode 100644 index 00000000000000..669064147997bb --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/kasan_sparsemem_vmemmmap @@ -0,0 +1,5 @@ +CONFIG_KASAN=y +# CONFIG_FLATMEM_MANUAL is not set +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_SPARSEMEM_VMEMMAP=y diff --git a/.github/scripts/series/kconfigs/defconfig/kasan_vmalloc b/.github/scripts/series/kconfigs/defconfig/kasan_vmalloc new file mode 100644 index 00000000000000..183e7b2d2ce285 --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/kasan_vmalloc @@ -0,0 +1,2 @@ +CONFIG_KASAN=y +CONFIG_KASAN_VMALLOC=y diff --git a/.github/scripts/series/kconfigs/defconfig/kfence b/.github/scripts/series/kconfigs/defconfig/kfence new file mode 100644 index 00000000000000..9037f9b6ad4402 --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/kfence @@ -0,0 +1,3 @@ +CONFIG_KFENCE=y +CONFIG_KFENCE_SAMPLE_INTERVAL=100 +CONFIG_KFENCE_NUM_OBJECTS=255 diff --git a/.github/scripts/series/kconfigs/defconfig/legacy_sbi b/.github/scripts/series/kconfigs/defconfig/legacy_sbi new file mode 100644 index 00000000000000..02ed0014719dc7 --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/legacy_sbi @@ -0,0 +1,4 @@ +CONFIG_NONPORTABLE=y +CONFIG_RISCV_SBI_V01=y +CONFIG_HVC_RISCV_SBI=y +CONFIG_SERIAL_EARLYCON_RISCV_SBI=y diff --git a/.github/scripts/series/kconfigs/defconfig/lockdep b/.github/scripts/series/kconfigs/defconfig/lockdep new file mode 100644 index 00000000000000..608538fff563ab --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/lockdep @@ -0,0 +1,3 @@ +CONFIG_PROVE_LOCKING=y +CONFIG_DEBUG_LOCK_ALLOC=y +CONFIG_DEBUG_LOCKING_API_SELFTESTS=y diff --git a/.github/scripts/series/kconfigs/defconfig/medany b/.github/scripts/series/kconfigs/defconfig/medany new file mode 100644 index 00000000000000..20d4f94c1cbe25 --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/medany @@ -0,0 +1,2 @@ +# CONFIG_CMODEL_MEDLOW is not set +CONFIG_CMODEL_MEDANY=y diff --git a/.github/scripts/series/kconfigs/defconfig/medlow b/.github/scripts/series/kconfigs/defconfig/medlow new file mode 100644 index 00000000000000..79cac7912772f9 --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/medlow @@ -0,0 +1,2 @@ +# CONFIG_CMODEL_MEDANY is not set +CONFIG_CMODEL_MEDLOW=y diff --git a/.github/scripts/series/kconfigs/defconfig/noc b/.github/scripts/series/kconfigs/defconfig/noc new file mode 100644 index 00000000000000..9a4a7a1d838922 --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/noc @@ -0,0 +1,3 @@ +# CONFIG_RISCV_ISA_C is not set +CONFIG_NONPORTABLE=y +# CONFIG_EFI is not set diff --git a/.github/scripts/series/kconfigs/defconfig/nosmp b/.github/scripts/series/kconfigs/defconfig/nosmp new file mode 100644 index 00000000000000..0c26a8626295e3 --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/nosmp @@ -0,0 +1 @@ +# CONFIG_SMP is not set diff --git a/.github/scripts/series/kconfigs/defconfig/pmu b/.github/scripts/series/kconfigs/defconfig/pmu new file mode 100644 index 00000000000000..c57cb3510168fb --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/pmu @@ -0,0 +1,4 @@ +CONFIG_PERF_EVENTS=y +CONFIG_RISCV_SBI=y +CONFIG_RISCV_PMU=y +CONFIG_RISCV_PMU_SBI=y diff --git a/.github/scripts/series/kconfigs/defconfig/preempt b/.github/scripts/series/kconfigs/defconfig/preempt new file mode 100644 index 00000000000000..2b346554f869ec --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/preempt @@ -0,0 +1,2 @@ +CONFIG_PREEMPT=y +CONFIG_DEBUG_PREEMPT=y diff --git a/.github/scripts/series/kconfigs/defconfig/preempt_rt b/.github/scripts/series/kconfigs/defconfig/preempt_rt new file mode 100644 index 00000000000000..ffab30de80e489 --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/preempt_rt @@ -0,0 +1 @@ +CONFIG_PREEMPT_RT=y diff --git a/.github/scripts/series/kconfigs/defconfig/qspinlock b/.github/scripts/series/kconfigs/defconfig/qspinlock new file mode 100644 index 00000000000000..7791363d351038 --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/qspinlock @@ -0,0 +1 @@ +CONFIG_RISCV_QUEUED_SPINLOCKS=y diff --git a/.github/scripts/series/kconfigs/defconfig/randomize_base b/.github/scripts/series/kconfigs/defconfig/randomize_base new file mode 100644 index 00000000000000..7f9170d16348aa --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/randomize_base @@ -0,0 +1,2 @@ +CONFIG_RELOCATABLE=y +CONFIG_RANDOMIZE_BASE=y diff --git a/.github/scripts/series/kconfigs/defconfig/rseq b/.github/scripts/series/kconfigs/defconfig/rseq new file mode 100644 index 00000000000000..adc7767df654e6 --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/rseq @@ -0,0 +1 @@ +CONFIG_RSEQ=y diff --git a/.github/scripts/series/kconfigs/defconfig/rseq_debug b/.github/scripts/series/kconfigs/defconfig/rseq_debug new file mode 100644 index 00000000000000..72a197a93f3465 --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/rseq_debug @@ -0,0 +1,3 @@ +CONFIG_RSEQ=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_RSEQ=y diff --git a/.github/scripts/series/kconfigs/defconfig/size b/.github/scripts/series/kconfigs/defconfig/size new file mode 100644 index 00000000000000..7a224853ad00a7 --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/size @@ -0,0 +1 @@ +CONFIG_CC_OPTIMIZE_FOR_SIZE=y diff --git a/.github/scripts/series/kconfigs/defconfig/sparsemem b/.github/scripts/series/kconfigs/defconfig/sparsemem new file mode 100644 index 00000000000000..cc1d59050946d7 --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/sparsemem @@ -0,0 +1,3 @@ +# CONFIG_FLATMEM_MANUAL is not set +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y diff --git a/.github/scripts/series/kconfigs/defconfig/spinwait b/.github/scripts/series/kconfigs/defconfig/spinwait new file mode 100644 index 00000000000000..270b49711e2898 --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/spinwait @@ -0,0 +1 @@ +CONFIG_RISCV_BOOT_SPINWAIT=y diff --git a/.github/scripts/series/kconfigs/defconfig/strict_rwx b/.github/scripts/series/kconfigs/defconfig/strict_rwx new file mode 100644 index 00000000000000..8c57b454ad2611 --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/strict_rwx @@ -0,0 +1 @@ +CONFIG_STRICT_KERNEL_RWX=y diff --git a/.github/scripts/series/kconfigs/defconfig/svnapot b/.github/scripts/series/kconfigs/defconfig/svnapot new file mode 100644 index 00000000000000..102afb0cff137a --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/svnapot @@ -0,0 +1 @@ +CONFIG_RISCV_ISA_SVNAPOT=y diff --git a/.github/scripts/series/kconfigs/defconfig/ticket_spinlock b/.github/scripts/series/kconfigs/defconfig/ticket_spinlock new file mode 100644 index 00000000000000..05b5fa71b09a80 --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/ticket_spinlock @@ -0,0 +1 @@ +CONFIG_RISCV_TICKET_SPINLOCKS=y diff --git a/.github/scripts/series/kconfigs/defconfig/vmap_stack b/.github/scripts/series/kconfigs/defconfig/vmap_stack new file mode 100644 index 00000000000000..8bd986875fc752 --- /dev/null +++ b/.github/scripts/series/kconfigs/defconfig/vmap_stack @@ -0,0 +1 @@ +CONFIG_VMAP_STACK=y diff --git a/.github/scripts/series/kconfigs/ubuntu_defconfig b/.github/scripts/series/kconfigs/ubuntu_defconfig new file mode 100644 index 00000000000000..42d97eded1eeda --- /dev/null +++ b/.github/scripts/series/kconfigs/ubuntu_defconfig @@ -0,0 +1,5504 @@ +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_WATCH_QUEUE=y +CONFIG_USELIB=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BPF_JIT=y +CONFIG_BPF_JIT_ALWAYS_ON=y +CONFIG_BPF_LSM=y +CONFIG_PREEMPT_VOLUNTARY=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_PSI=y +CONFIG_IKHEADERS=m +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_NUMA_BALANCING=y +CONFIG_MEMCG=y +CONFIG_BLK_CGROUP=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_RDMA=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_HUGETLB=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_PERF=y +CONFIG_CGROUP_BPF=y +CONFIG_CGROUP_MISC=y +CONFIG_NAMESPACES=y +CONFIG_USER_NS=y +CONFIG_CHECKPOINT_RESTORE=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_EXPERT=y +CONFIG_SGETMASK_SYSCALL=y +CONFIG_KALLSYMS_ALL=y +CONFIG_PC104=y +CONFIG_PROFILING=y +CONFIG_SOC_MICROCHIP_POLARFIRE=y +CONFIG_SOC_SIFIVE=y +CONFIG_SOC_STARFIVE=y +CONFIG_SOC_VIRT=y +CONFIG_SMP=y +CONFIG_NR_CPUS=32 +CONFIG_NUMA=y +# CONFIG_RISCV_ISA_SVPBMT is not set +CONFIG_KEXEC=y +CONFIG_KEXEC_FILE=y +CONFIG_CRASH_DUMP=y +# CONFIG_COMPAT is not set +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_CPU_IDLE_GOV_TEO=y +CONFIG_VIRTUALIZATION=y +CONFIG_KVM=y +CONFIG_JUMP_LABEL=y +CONFIG_COMPAT_32BIT_TIME=y +# CONFIG_VMAP_STACK is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_MODULE_SIG_SHA512=y +CONFIG_BLK_DEV_ZONED=y +CONFIG_BLK_DEV_THROTTLING=y +CONFIG_BLK_WBT=y +CONFIG_BLK_CGROUP_FC_APPID=y +CONFIG_BLK_CGROUP_IOCOST=y +CONFIG_BLK_CGROUP_IOPRIO=y +CONFIG_BLK_SED_OPAL=y +CONFIG_BLK_INLINE_ENCRYPTION=y +CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_AIX_PARTITION=y +CONFIG_OSF_PARTITION=y +CONFIG_AMIGA_PARTITION=y +CONFIG_ATARI_PARTITION=y +CONFIG_MAC_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +CONFIG_LDM_PARTITION=y +CONFIG_SGI_PARTITION=y +CONFIG_ULTRIX_PARTITION=y +CONFIG_SUN_PARTITION=y +CONFIG_KARMA_PARTITION=y +CONFIG_SYSV68_PARTITION=y +CONFIG_CMDLINE_PARTITION=y +CONFIG_MQ_IOSCHED_KYBER=m +CONFIG_IOSCHED_BFQ=m +CONFIG_BINFMT_FLAT=y +CONFIG_BINFMT_FLAT_OLD=y +CONFIG_BINFMT_ZFLAT=y +CONFIG_BINFMT_MISC=m +CONFIG_ZSWAP=y +CONFIG_Z3FOLD=m +CONFIG_ZSMALLOC=y +CONFIG_SLAB_FREELIST_RANDOM=y +CONFIG_SLAB_FREELIST_HARDENED=y +CONFIG_SHUFFLE_PAGE_ALLOCATOR=y +# CONFIG_COMPAT_BRK is not set +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_TRANSPARENT_HUGEPAGE=y +CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y +CONFIG_CMA=y +CONFIG_CMA_SYSFS=y +CONFIG_CMA_AREAS=7 +CONFIG_IDLE_PAGE_TRACKING=y +CONFIG_ANON_VMA_NAME=y +CONFIG_USERFAULTFD=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_PACKET_DIAG=m +CONFIG_UNIX=y +CONFIG_UNIX_DIAG=m +CONFIG_TLS=m +CONFIG_TLS_DEVICE=y +CONFIG_XFRM_USER=m +CONFIG_XFRM_INTERFACE=m +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=m +CONFIG_SMC=m +CONFIG_SMC_DIAG=m +CONFIG_XDP_SOCKETS=y +CONFIG_XDP_SOCKETS_DIAG=m +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_FIB_TRIE_STATS=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE_DEMUX=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_MROUTE_MULTIPLE_TABLES=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_NET_IPVTI=m +CONFIG_NET_FOU_IP_TUNNELS=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_ESP_OFFLOAD=m +CONFIG_INET_ESPINTCP=y +CONFIG_INET_IPCOMP=m +CONFIG_INET_DIAG=m +CONFIG_INET_UDP_DIAG=m +CONFIG_INET_RAW_DIAG=m +CONFIG_INET_DIAG_DESTROY=y +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_HSTCP=m +CONFIG_TCP_CONG_HYBLA=m +CONFIG_TCP_CONG_NV=m +CONFIG_TCP_CONG_SCALABLE=m +CONFIG_TCP_CONG_LP=m +CONFIG_TCP_CONG_VENO=m +CONFIG_TCP_CONG_YEAH=m +CONFIG_TCP_CONG_ILLINOIS=m +CONFIG_TCP_CONG_DCTCP=m +CONFIG_TCP_CONG_CDG=m +CONFIG_TCP_CONG_BBR=m +CONFIG_TCP_MD5SIG=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_ESP_OFFLOAD=m +CONFIG_INET6_ESPINTCP=y +CONFIG_INET6_IPCOMP=m +CONFIG_IPV6_MIP6=m +CONFIG_IPV6_ILA=m +CONFIG_IPV6_VTI=m +CONFIG_IPV6_SIT=m +CONFIG_IPV6_SIT_6RD=y +CONFIG_IPV6_GRE=m +CONFIG_IPV6_SUBTREES=y +CONFIG_IPV6_MROUTE=y +CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y +CONFIG_IPV6_PIMSM_V2=y +CONFIG_IPV6_SEG6_LWTUNNEL=y +CONFIG_IPV6_SEG6_HMAC=y +CONFIG_IPV6_IOAM6_LWTUNNEL=y +CONFIG_MPTCP=y +CONFIG_NETWORK_PHY_TIMESTAMPING=y +CONFIG_NETFILTER=y +CONFIG_BRIDGE_NETFILTER=m +CONFIG_NETFILTER_NETLINK_HOOK=m +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_ZONES=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_TIMEOUT=y +CONFIG_NF_CONNTRACK_TIMESTAMP=y +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_SNMP=m +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_SANE=m +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_NETLINK=m +CONFIG_NF_CT_NETLINK_TIMEOUT=m +CONFIG_NF_CT_NETLINK_HELPER=m +CONFIG_NETFILTER_NETLINK_GLUE_CT=y +CONFIG_NF_TABLES=m +CONFIG_NF_TABLES_INET=y +CONFIG_NF_TABLES_NETDEV=y +CONFIG_NFT_NUMGEN=m +CONFIG_NFT_CT=m +CONFIG_NFT_FLOW_OFFLOAD=m +CONFIG_NFT_CONNLIMIT=m +CONFIG_NFT_LOG=m +CONFIG_NFT_LIMIT=m +CONFIG_NFT_MASQ=m +CONFIG_NFT_REDIR=m +CONFIG_NFT_NAT=m +CONFIG_NFT_TUNNEL=m +CONFIG_NFT_QUEUE=m +CONFIG_NFT_QUOTA=m +CONFIG_NFT_REJECT=m +CONFIG_NFT_COMPAT=m +CONFIG_NFT_HASH=m +CONFIG_NFT_FIB_INET=m +CONFIG_NFT_XFRM=m +CONFIG_NFT_SOCKET=m +CONFIG_NFT_OSF=m +CONFIG_NFT_TPROXY=m +CONFIG_NFT_SYNPROXY=m +CONFIG_NFT_DUP_NETDEV=m +CONFIG_NFT_FWD_NETDEV=m +CONFIG_NFT_FIB_NETDEV=m +CONFIG_NFT_REJECT_NETDEV=m +CONFIG_NF_FLOW_TABLE_INET=m +CONFIG_NF_FLOW_TABLE=m +CONFIG_NETFILTER_XT_SET=m +CONFIG_NETFILTER_XT_TARGET_AUDIT=m +CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m +CONFIG_NETFILTER_XT_TARGET_CT=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_HMARK=m +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m +CONFIG_NETFILTER_XT_TARGET_LED=m +CONFIG_NETFILTER_XT_TARGET_LOG=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_TEE=m +CONFIG_NETFILTER_XT_TARGET_TPROXY=m +CONFIG_NETFILTER_XT_TARGET_TRACE=m +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +CONFIG_NETFILTER_XT_MATCH_BPF=m +CONFIG_NETFILTER_XT_MATCH_CGROUP=m +CONFIG_NETFILTER_XT_MATCH_CLUSTER=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_CPU=m +CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_IPCOMP=m +CONFIG_NETFILTER_XT_MATCH_IPRANGE=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_NFACCT=m +CONFIG_NETFILTER_XT_MATCH_OSF=m +CONFIG_NETFILTER_XT_MATCH_OWNER=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_RATEEST=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_RECENT=m +CONFIG_NETFILTER_XT_MATCH_SOCKET=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_IP_SET=m +CONFIG_IP_SET_BITMAP_IP=m +CONFIG_IP_SET_BITMAP_IPMAC=m +CONFIG_IP_SET_BITMAP_PORT=m +CONFIG_IP_SET_HASH_IP=m +CONFIG_IP_SET_HASH_IPMARK=m +CONFIG_IP_SET_HASH_IPPORT=m +CONFIG_IP_SET_HASH_IPPORTIP=m +CONFIG_IP_SET_HASH_IPPORTNET=m +CONFIG_IP_SET_HASH_IPMAC=m +CONFIG_IP_SET_HASH_MAC=m +CONFIG_IP_SET_HASH_NETPORTNET=m +CONFIG_IP_SET_HASH_NET=m +CONFIG_IP_SET_HASH_NETNET=m +CONFIG_IP_SET_HASH_NETPORT=m +CONFIG_IP_SET_HASH_NETIFACE=m +CONFIG_IP_SET_LIST_SET=m +CONFIG_IP_VS=m +CONFIG_IP_VS_IPV6=y +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_SCTP=y +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_FO=m +CONFIG_IP_VS_OVF=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_MH=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m +CONFIG_IP_VS_FTP=m +CONFIG_IP_VS_PE_SIP=m +CONFIG_NFT_DUP_IPV4=m +CONFIG_NFT_FIB_IPV4=m +CONFIG_NF_TABLES_ARP=y +CONFIG_NF_LOG_ARP=m +CONFIG_NF_LOG_IPV4=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_RPFILTER=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_SYNPROXY=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_SECURITY=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +CONFIG_NFT_DUP_IPV6=m +CONFIG_NFT_FIB_IPV6=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_RPFILTER=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_SRH=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IP6_NF_TARGET_SYNPROXY=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_RAW=m +CONFIG_IP6_NF_SECURITY=m +CONFIG_IP6_NF_NAT=m +CONFIG_IP6_NF_TARGET_MASQUERADE=m +CONFIG_IP6_NF_TARGET_NPT=m +CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m +CONFIG_NFT_BRIDGE_REJECT=m +CONFIG_NF_CONNTRACK_BRIDGE=m +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_IP6=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_NFLOG=m +CONFIG_BPFILTER=y +CONFIG_IP_DCCP=m +# CONFIG_IP_DCCP_CCID3 is not set +CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1=y +CONFIG_SCTP_COOKIE_HMAC_MD5=y +CONFIG_RDS=m +CONFIG_RDS_RDMA=m +CONFIG_RDS_TCP=m +CONFIG_TIPC=m +CONFIG_TIPC_MEDIA_IB=y +CONFIG_ATM=m +CONFIG_ATM_CLIP=m +CONFIG_ATM_LANE=m +CONFIG_ATM_MPOA=m +CONFIG_ATM_BR2684=m +CONFIG_L2TP=m +CONFIG_L2TP_DEBUGFS=m +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=m +CONFIG_L2TP_ETH=m +CONFIG_BRIDGE=m +CONFIG_BRIDGE_VLAN_FILTERING=y +CONFIG_BRIDGE_MRP=y +CONFIG_BRIDGE_CFM=y +CONFIG_NET_DSA=m +CONFIG_VLAN_8021Q=m +CONFIG_VLAN_8021Q_GVRP=y +CONFIG_VLAN_8021Q_MVRP=y +CONFIG_LLC2=m +CONFIG_ATALK=m +CONFIG_DEV_APPLETALK=m +CONFIG_X25=m +CONFIG_LAPB=m +CONFIG_PHONET=m +CONFIG_6LOWPAN=m +CONFIG_IEEE802154=m +CONFIG_IEEE802154_6LOWPAN=m +CONFIG_MAC802154=m +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_MULTIQ=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFB=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_CBS=m +CONFIG_NET_SCH_ETF=m +CONFIG_NET_SCH_TAPRIO=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_DRR=m +CONFIG_NET_SCH_MQPRIO=m +CONFIG_NET_SCH_SKBPRIO=m +CONFIG_NET_SCH_CHOKE=m +CONFIG_NET_SCH_QFQ=m +CONFIG_NET_SCH_CODEL=m +CONFIG_NET_SCH_FQ_CODEL=m +CONFIG_NET_SCH_CAKE=m +CONFIG_NET_SCH_FQ=m +CONFIG_NET_SCH_HHF=m +CONFIG_NET_SCH_PIE=m +CONFIG_NET_SCH_FQ_PIE=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_SCH_PLUG=m +CONFIG_NET_SCH_ETS=m +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=m +CONFIG_NET_CLS_CGROUP=m +CONFIG_NET_CLS_BPF=m +CONFIG_NET_CLS_FLOWER=m +CONFIG_NET_CLS_MATCHALL=m +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_U32=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_EMATCH_CANID=m +CONFIG_NET_EMATCH_IPSET=m +CONFIG_NET_EMATCH_IPT=m +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_GACT=m +CONFIG_GACT_PROB=y +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_SAMPLE=m +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_NAT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_SIMP=m +CONFIG_NET_ACT_SKBEDIT=m +CONFIG_NET_ACT_CSUM=m +CONFIG_NET_ACT_MPLS=m +CONFIG_NET_ACT_VLAN=m +CONFIG_NET_ACT_BPF=m +CONFIG_NET_ACT_CONNMARK=m +CONFIG_NET_ACT_CTINFO=m +CONFIG_NET_ACT_SKBMOD=m +CONFIG_NET_ACT_TUNNEL_KEY=m +CONFIG_NET_ACT_CT=m +CONFIG_NET_ACT_GATE=m +CONFIG_NET_TC_SKB_EXT=y +CONFIG_DCB=y +CONFIG_DNS_RESOLVER=y +CONFIG_BATMAN_ADV=m +# CONFIG_BATMAN_ADV_BATMAN_V is not set +CONFIG_BATMAN_ADV_NC=y +CONFIG_OPENVSWITCH=m +CONFIG_VSOCKETS=m +CONFIG_VIRTIO_VSOCKETS=m +CONFIG_NETLINK_DIAG=m +CONFIG_MPLS_ROUTING=m +CONFIG_MPLS_IPTUNNEL=m +CONFIG_HSR=m +CONFIG_QRTR_SMD=m +CONFIG_QRTR_TUN=m +CONFIG_NET_NCSI=y +CONFIG_NCSI_OEM_CMD_GET_MAC=y +CONFIG_CGROUP_NET_PRIO=y +CONFIG_BPF_STREAM_PARSER=y +CONFIG_NET_PKTGEN=m +CONFIG_NET_DROP_MONITOR=y +CONFIG_HAMRADIO=y +CONFIG_AX25=m +CONFIG_NETROM=m +CONFIG_ROSE=m +CONFIG_MKISS=m +CONFIG_6PACK=m +CONFIG_BPQETHER=m +CONFIG_BAYCOM_SER_FDX=m +CONFIG_BAYCOM_SER_HDX=m +CONFIG_BAYCOM_PAR=m +CONFIG_YAM=m +CONFIG_CAN=m +CONFIG_CAN_J1939=m +CONFIG_CAN_ISOTP=m +CONFIG_BT=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_CMTP=m +CONFIG_BT_HIDP=m +CONFIG_BT_HS=y +CONFIG_BT_6LOWPAN=m +CONFIG_BT_LEDS=y +CONFIG_BT_MSFTEXT=y +CONFIG_BT_AOSPEXT=y +CONFIG_BT_HCIBTUSB=m +CONFIG_BT_HCIBTUSB_AUTOSUSPEND=y +CONFIG_BT_HCIBTUSB_MTK=y +CONFIG_BT_HCIBTSDIO=m +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_ATH3K=y +CONFIG_BT_HCIUART_LL=y +CONFIG_BT_HCIUART_INTEL=y +CONFIG_BT_HCIUART_BCM=y +CONFIG_BT_HCIUART_RTL=y +CONFIG_BT_HCIUART_QCA=y +CONFIG_BT_HCIUART_AG6XX=y +CONFIG_BT_HCIUART_MRVL=y +CONFIG_BT_HCIBCM203X=m +CONFIG_BT_HCIBPA10X=m +CONFIG_BT_HCIBFUSB=m +CONFIG_BT_HCIVHCI=m +CONFIG_BT_MRVL=m +CONFIG_BT_MRVL_SDIO=m +CONFIG_BT_ATH3K=m +CONFIG_BT_MTKSDIO=m +CONFIG_BT_MTKUART=m +CONFIG_BT_VIRTIO=m +CONFIG_AF_RXRPC_IPV6=y +CONFIG_RXKAD=y +CONFIG_AF_KCM=m +CONFIG_MCTP=y +CONFIG_CFG80211=m +CONFIG_CFG80211_DEBUGFS=y +CONFIG_MAC80211=m +CONFIG_MAC80211_MESH=y +CONFIG_MAC80211_MESSAGE_TRACING=y +CONFIG_RFKILL=y +CONFIG_RFKILL_INPUT=y +CONFIG_RFKILL_GPIO=m +CONFIG_NET_9P=y +CONFIG_NET_9P_VIRTIO=y +CONFIG_NET_9P_RDMA=m +CONFIG_CAIF=m +CONFIG_CAIF_USB=m +CONFIG_CEPH_LIB_USE_DNS_RESOLVER=y +CONFIG_NFC=m +CONFIG_NFC_DIGITAL=m +CONFIG_NFC_NCI=m +CONFIG_NFC_NCI_SPI=m +CONFIG_NFC_NCI_UART=m +CONFIG_NFC_HCI=m +CONFIG_NFC_SHDLC=y +CONFIG_NFC_TRF7970A=m +CONFIG_NFC_SIM=m +CONFIG_NFC_PORT100=m +CONFIG_NFC_VIRTUAL_NCI=m +CONFIG_NFC_FDP=m +CONFIG_NFC_FDP_I2C=m +CONFIG_NFC_PN544_I2C=m +CONFIG_NFC_PN533_USB=m +CONFIG_NFC_PN533_I2C=m +CONFIG_NFC_PN532_UART=m +CONFIG_NFC_MICROREAD_I2C=m +CONFIG_NFC_MRVL_USB=m +CONFIG_NFC_MRVL_UART=m +CONFIG_NFC_MRVL_I2C=m +CONFIG_NFC_MRVL_SPI=m +CONFIG_NFC_ST21NFCA_I2C=m +CONFIG_NFC_ST_NCI_I2C=m +CONFIG_NFC_ST_NCI_SPI=m +CONFIG_NFC_NXP_NCI=m +CONFIG_NFC_NXP_NCI_I2C=m +CONFIG_NFC_S3FWRN5_I2C=m +CONFIG_NFC_S3FWRN82_UART=m +CONFIG_NFC_ST95HF=m +CONFIG_NET_IFE=m +CONFIG_PCI=y +CONFIG_PCIEAER=y +CONFIG_PCIE_DPC=y +CONFIG_PCIE_PTM=y +CONFIG_PCI_REALLOC_ENABLE_AUTO=y +CONFIG_PCI_STUB=m +CONFIG_PCI_PF_STUB=m +CONFIG_PCI_IOV=y +CONFIG_PCI_PRI=y +CONFIG_PCI_PASID=y +CONFIG_HOTPLUG_PCI_CPCI=y +CONFIG_HOTPLUG_PCI_SHPC=y +CONFIG_PCI_FTPCI100=y +CONFIG_PCI_HOST_GENERIC=y +CONFIG_PCIE_XILINX=y +CONFIG_PCIE_MICROCHIP_HOST=y +CONFIG_PCIE_DW_PLAT_HOST=y +CONFIG_PCIE_DW_PLAT_EP=y +CONFIG_PCIE_FU740=y +CONFIG_PCIE_CADENCE_PLAT_HOST=y +CONFIG_PCIE_CADENCE_PLAT_EP=y +CONFIG_PCI_J721E_HOST=y +CONFIG_PCI_J721E_EP=y +CONFIG_PCI_ENDPOINT=y +CONFIG_PCI_ENDPOINT_CONFIGFS=y +CONFIG_PCI_EPF_NTB=m +CONFIG_CXL_BUS=m +CONFIG_RAPIDIO=y +CONFIG_RAPIDIO_TSI721=m +CONFIG_RAPIDIO_DMA_ENGINE=y +CONFIG_RAPIDIO_ENUM_BASIC=m +CONFIG_RAPIDIO_CHMAN=m +CONFIG_RAPIDIO_MPORT_CDEV=m +CONFIG_RAPIDIO_CPS_XX=m +CONFIG_RAPIDIO_CPS_GEN2=m +CONFIG_RAPIDIO_RXS_GEN3=m +CONFIG_UEVENT_HELPER=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_DEVTMPFS_SAFE=y +CONFIG_FW_LOADER_COMPRESS=y +CONFIG_FW_LOADER_COMPRESS_ZSTD=y +CONFIG_MOXTET=m +CONFIG_MHI_BUS_PCI_GENERIC=m +CONFIG_MHI_BUS_EP=m +CONFIG_CONNECTOR=y +CONFIG_FIRMWARE_MEMMAP=y +CONFIG_EFI_VARS_PSTORE=m +CONFIG_EFI_BOOTLOADER_CONTROL=m +CONFIG_EFI_CAPSULE_LOADER=m +CONFIG_EFI_TEST=m +CONFIG_RESET_ATTACK_MITIGATION=y +CONFIG_EFI_COCO_SECRET=y +CONFIG_GNSS=m +CONFIG_GNSS_MTK_SERIAL=m +CONFIG_GNSS_SIRF_SERIAL=m +CONFIG_GNSS_UBX_SERIAL=m +CONFIG_GNSS_USB=m +CONFIG_MTD=m +CONFIG_MTD_AR7_PARTS=m +CONFIG_MTD_CMDLINE_PARTS=m +CONFIG_MTD_REDBOOT_PARTS=m +CONFIG_MTD_BLOCK=m +CONFIG_MTD_BLOCK_RO=m +CONFIG_FTL=m +CONFIG_NFTL=m +CONFIG_NFTL_RW=y +CONFIG_INFTL=m +CONFIG_RFD_FTL=m +CONFIG_SSFDC=m +CONFIG_SM_FTL=m +CONFIG_MTD_OOPS=m +CONFIG_MTD_PSTORE=m +CONFIG_MTD_SWAP=m +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_CFI_INTELEXT=m +CONFIG_MTD_CFI_STAA=m +CONFIG_MTD_ROM=m +CONFIG_MTD_ABSENT=m +CONFIG_MTD_PHYSMAP=m +CONFIG_MTD_PHYSMAP_OF=y +CONFIG_MTD_PHYSMAP_GPIO_ADDR=y +CONFIG_MTD_PCI=m +CONFIG_MTD_INTEL_VR_NOR=m +CONFIG_MTD_PLATRAM=m +CONFIG_MTD_PMC551=m +CONFIG_MTD_DATAFLASH=m +CONFIG_MTD_DATAFLASH_OTP=y +CONFIG_MTD_MCHP23K256=m +CONFIG_MTD_MCHP48L640=m +CONFIG_MTD_SST25L=m +CONFIG_MTD_SLRAM=m +CONFIG_MTD_PHRAM=m +CONFIG_MTD_MTDRAM=m +CONFIG_MTD_BLOCK2MTD=m +CONFIG_MTD_ONENAND=m +CONFIG_MTD_ONENAND_VERIFY_WRITE=y +CONFIG_MTD_ONENAND_GENERIC=m +CONFIG_MTD_ONENAND_2X_PROGRAM=y +CONFIG_MTD_RAW_NAND=m +CONFIG_MTD_NAND_DENALI_PCI=m +CONFIG_MTD_NAND_DENALI_DT=m +CONFIG_MTD_NAND_CAFE=m +CONFIG_MTD_NAND_MXIC=m +CONFIG_MTD_NAND_GPIO=m +CONFIG_MTD_NAND_PLATFORM=m +CONFIG_MTD_NAND_CADENCE=m +CONFIG_MTD_NAND_ARASAN=m +CONFIG_MTD_NAND_INTEL_LGM=m +CONFIG_MTD_NAND_NANDSIM=m +CONFIG_MTD_NAND_RICOH=m +CONFIG_MTD_NAND_DISKONCHIP=m +CONFIG_MTD_SPI_NAND=m +CONFIG_MTD_NAND_ECC_SW_BCH=y +CONFIG_MTD_LPDDR=m +CONFIG_MTD_SPI_NOR=m +CONFIG_MTD_UBI=m +CONFIG_MTD_UBI_FASTMAP=y +CONFIG_MTD_UBI_GLUEBI=m +CONFIG_MTD_UBI_BLOCK=y +CONFIG_MTD_HYPERBUS=m +CONFIG_OF_OVERLAY=y +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_SERIAL=m +CONFIG_PARPORT_PC_FIFO=y +CONFIG_PARPORT_1284=y +CONFIG_BLK_DEV_NULL_BLK=m +CONFIG_BLK_DEV_PCIESSD_MTIP32XX=m +CONFIG_ZRAM=m +CONFIG_ZRAM_WRITEBACK=y +CONFIG_ZRAM_MEMORY_TRACKING=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_DRBD=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=m +CONFIG_BLK_DEV_RAM_SIZE=65536 +CONFIG_CDROM_PKTCDVD=m +CONFIG_ATA_OVER_ETH=m +CONFIG_VIRTIO_BLK=y +CONFIG_BLK_DEV_RBD=m +CONFIG_BLK_DEV_RNBD_CLIENT=m +CONFIG_BLK_DEV_RNBD_SERVER=m +CONFIG_BLK_DEV_NVME=m +CONFIG_NVME_MULTIPATH=y +CONFIG_NVME_HWMON=y +CONFIG_NVME_RDMA=m +CONFIG_NVME_FC=m +CONFIG_NVME_TCP=m +CONFIG_NVME_TARGET=m +CONFIG_NVME_TARGET_PASSTHRU=y +CONFIG_NVME_TARGET_LOOP=m +CONFIG_NVME_TARGET_RDMA=m +CONFIG_NVME_TARGET_FC=m +CONFIG_NVME_TARGET_TCP=m +CONFIG_AD525X_DPOT=m +CONFIG_AD525X_DPOT_I2C=m +CONFIG_AD525X_DPOT_SPI=m +CONFIG_DUMMY_IRQ=m +CONFIG_PHANTOM=m +CONFIG_ICS932S401=m +CONFIG_ENCLOSURE_SERVICES=m +CONFIG_HI6421V600_IRQ=m +CONFIG_HP_ILO=m +CONFIG_APDS9802ALS=m +CONFIG_ISL29003=m +CONFIG_ISL29020=m +CONFIG_SENSORS_TSL2550=m +CONFIG_SENSORS_BH1770=m +CONFIG_SENSORS_APDS990X=m +CONFIG_HMC6352=m +CONFIG_DS1682=m +CONFIG_LATTICE_ECP3_CONFIG=m +CONFIG_SRAM=y +CONFIG_DW_XDATA_PCIE=m +CONFIG_OPEN_DICE=m +CONFIG_C2PORT=m +CONFIG_EEPROM_AT24=m +CONFIG_EEPROM_AT25=m +CONFIG_EEPROM_LEGACY=m +CONFIG_EEPROM_MAX6875=m +CONFIG_EEPROM_93XX46=m +CONFIG_EEPROM_IDT_89HPESX=m +CONFIG_EEPROM_EE1004=m +CONFIG_TI_ST=m +CONFIG_SENSORS_LIS3_SPI=m +CONFIG_SENSORS_LIS3_I2C=m +CONFIG_GENWQE=m +CONFIG_ECHO=m +CONFIG_BCM_VK=m +CONFIG_BCM_VK_TTY=y +CONFIG_MISC_ALCOR_PCI=m +CONFIG_MISC_RTSX_PCI=m +CONFIG_MISC_RTSX_USB=m +CONFIG_UACCE=m +CONFIG_PVPANIC=y +CONFIG_PVPANIC_MMIO=m +CONFIG_PVPANIC_PCI=m +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=m +CONFIG_BLK_DEV_SR=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=m +CONFIG_SCSI_ENCLOSURE=m +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_SAS_ATA=y +CONFIG_ISCSI_TCP=m +CONFIG_SCSI_CXGB3_ISCSI=m +CONFIG_SCSI_CXGB4_ISCSI=m +CONFIG_SCSI_BNX2_ISCSI=m +CONFIG_SCSI_BNX2X_FCOE=m +CONFIG_BE2ISCSI=m +CONFIG_BLK_DEV_3W_XXXX_RAID=m +CONFIG_SCSI_HPSA=m +CONFIG_SCSI_3W_9XXX=m +CONFIG_SCSI_3W_SAS=m +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_AIC7XXX=m +CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 +# CONFIG_AIC7XXX_DEBUG_ENABLE is not set +CONFIG_SCSI_AIC79XX=m +# CONFIG_AIC79XX_DEBUG_ENABLE is not set +CONFIG_SCSI_AIC94XX=m +# CONFIG_AIC94XX_DEBUG is not set +CONFIG_SCSI_MVSAS=m +# CONFIG_SCSI_MVSAS_DEBUG is not set +CONFIG_SCSI_MVUMI=m +CONFIG_SCSI_ADVANSYS=m +CONFIG_SCSI_ARCMSR=m +CONFIG_SCSI_ESAS2R=m +CONFIG_MEGARAID_NEWGEN=y +CONFIG_MEGARAID_MM=m +CONFIG_MEGARAID_MAILBOX=m +CONFIG_MEGARAID_LEGACY=m +CONFIG_MEGARAID_SAS=m +CONFIG_SCSI_MPT2SAS=m +CONFIG_SCSI_MPI3MR=m +CONFIG_SCSI_SMARTPQI=m +CONFIG_SCSI_HPTIOP=m +CONFIG_SCSI_MYRB=m +CONFIG_SCSI_MYRS=m +CONFIG_LIBFC=m +CONFIG_LIBFCOE=m +CONFIG_FCOE=m +CONFIG_SCSI_SNIC=m +CONFIG_SCSI_DMX3191D=m +CONFIG_SCSI_IPS=m +CONFIG_SCSI_INITIO=m +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_PPA=m +CONFIG_SCSI_IMM=m +CONFIG_SCSI_STEX=m +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_IPR=m +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_QLA_FC=m +CONFIG_TCM_QLA2XXX=m +CONFIG_SCSI_QLA_ISCSI=m +CONFIG_QEDI=m +CONFIG_QEDF=m +CONFIG_SCSI_EFCT=m +CONFIG_SCSI_DC395x=m +CONFIG_SCSI_AM53C974=m +CONFIG_SCSI_WD719X=m +CONFIG_SCSI_DEBUG=m +CONFIG_SCSI_PMCRAID=m +CONFIG_SCSI_PM8001=m +CONFIG_SCSI_BFA_FC=m +CONFIG_SCSI_VIRTIO=m +CONFIG_SCSI_CHELSIO_FCOE=m +CONFIG_SCSI_DH=y +CONFIG_SCSI_DH_RDAC=m +CONFIG_SCSI_DH_HP_SW=m +CONFIG_SCSI_DH_EMC=m +CONFIG_SCSI_DH_ALUA=m +CONFIG_ATA=y +CONFIG_SATA_AHCI=m +CONFIG_SATA_MOBILE_LPM_POLICY=3 +CONFIG_SATA_AHCI_PLATFORM=m +CONFIG_AHCI_CEVA=m +CONFIG_AHCI_QORIQ=m +CONFIG_SATA_INIC162X=m +CONFIG_SATA_ACARD_AHCI=m +CONFIG_SATA_SIL24=m +CONFIG_PDC_ADMA=m +CONFIG_SATA_QSTOR=m +CONFIG_SATA_SX4=m +CONFIG_ATA_PIIX=m +CONFIG_SATA_DWC=m +CONFIG_SATA_DWC_OLD_DMA=y +CONFIG_SATA_MV=m +CONFIG_SATA_NV=m +CONFIG_SATA_PROMISE=m +CONFIG_SATA_SIL=m +CONFIG_SATA_SIS=m +CONFIG_SATA_SVW=m +CONFIG_SATA_ULI=m +CONFIG_SATA_VIA=m +CONFIG_SATA_VITESSE=m +CONFIG_PATA_ALI=m +CONFIG_PATA_AMD=m +CONFIG_PATA_ARTOP=m +CONFIG_PATA_ATIIXP=m +CONFIG_PATA_ATP867X=m +CONFIG_PATA_CMD64X=m +CONFIG_PATA_CYPRESS=m +CONFIG_PATA_EFAR=m +CONFIG_PATA_HPT366=m +CONFIG_PATA_HPT37X=m +CONFIG_PATA_HPT3X2N=m +CONFIG_PATA_HPT3X3=m +CONFIG_PATA_IT8213=m +CONFIG_PATA_IT821X=m +CONFIG_PATA_JMICRON=m +CONFIG_PATA_MARVELL=m +CONFIG_PATA_NETCELL=m +CONFIG_PATA_NINJA32=m +CONFIG_PATA_NS87415=m +CONFIG_PATA_OLDPIIX=m +CONFIG_PATA_OPTIDMA=m +CONFIG_PATA_PDC2027X=m +CONFIG_PATA_PDC_OLD=m +CONFIG_PATA_RADISYS=m +CONFIG_PATA_RDC=m +CONFIG_PATA_SCH=m +CONFIG_PATA_SERVERWORKS=m +CONFIG_PATA_SIL680=m +CONFIG_PATA_TOSHIBA=m +CONFIG_PATA_TRIFLEX=m +CONFIG_PATA_VIA=m +CONFIG_PATA_WINBOND=m +CONFIG_PATA_CMD640_PCI=m +CONFIG_PATA_MPIIX=m +CONFIG_PATA_NS87410=m +CONFIG_PATA_OPTI=m +CONFIG_PATA_OF_PLATFORM=m +CONFIG_PATA_RZ1000=m +CONFIG_ATA_GENERIC=m +CONFIG_PATA_LEGACY=m +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=m +CONFIG_MD_MULTIPATH=m +CONFIG_MD_FAULTY=m +CONFIG_MD_CLUSTER=m +CONFIG_BCACHE=m +CONFIG_BCACHE_ASYNC_REGISTRATION=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_UNSTRIPED=m +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_THIN_PROVISIONING=m +CONFIG_DM_CACHE=m +CONFIG_DM_WRITECACHE=m +CONFIG_DM_EBS=m +CONFIG_DM_ERA=m +CONFIG_DM_CLONE=m +CONFIG_DM_MIRROR=m +CONFIG_DM_LOG_USERSPACE=m +CONFIG_DM_RAID=m +CONFIG_DM_ZERO=m +CONFIG_DM_MULTIPATH=m +CONFIG_DM_MULTIPATH_QL=m +CONFIG_DM_MULTIPATH_ST=m +CONFIG_DM_MULTIPATH_HST=m +CONFIG_DM_MULTIPATH_IOA=m +CONFIG_DM_DELAY=m +CONFIG_DM_INIT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_FLAKEY=m +CONFIG_DM_VERITY=m +CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG=y +CONFIG_DM_SWITCH=m +CONFIG_DM_LOG_WRITES=m +CONFIG_DM_INTEGRITY=m +CONFIG_DM_ZONED=m +CONFIG_TARGET_CORE=m +CONFIG_TCM_IBLOCK=m +CONFIG_TCM_FILEIO=m +CONFIG_TCM_PSCSI=m +CONFIG_TCM_USER2=m +CONFIG_LOOPBACK_TARGET=m +CONFIG_TCM_FC=m +CONFIG_ISCSI_TARGET=m +CONFIG_ISCSI_TARGET_CXGB4=m +CONFIG_SBP_TARGET=m +CONFIG_FUSION=y +CONFIG_FUSION_SPI=m +CONFIG_FUSION_FC=m +CONFIG_FUSION_SAS=m +CONFIG_FUSION_CTL=m +CONFIG_FUSION_LAN=m +CONFIG_FUSION_LOGGING=y +CONFIG_FIREWIRE=m +CONFIG_FIREWIRE_OHCI=m +CONFIG_FIREWIRE_SBP2=m +CONFIG_FIREWIRE_NET=m +CONFIG_FIREWIRE_NOSY=m +CONFIG_BONDING=m +CONFIG_DUMMY=m +CONFIG_WIREGUARD=m +CONFIG_EQUALIZER=m +CONFIG_NET_FC=y +CONFIG_IFB=m +CONFIG_NET_TEAM=m +CONFIG_NET_TEAM_MODE_BROADCAST=m +CONFIG_NET_TEAM_MODE_ROUNDROBIN=m +CONFIG_NET_TEAM_MODE_RANDOM=m +CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m +CONFIG_NET_TEAM_MODE_LOADBALANCE=m +CONFIG_MACVLAN=m +CONFIG_MACVTAP=m +CONFIG_IPVLAN=m +CONFIG_IPVTAP=m +CONFIG_VXLAN=m +CONFIG_GENEVE=m +CONFIG_BAREUDP=m +CONFIG_GTP=m +CONFIG_AMT=m +CONFIG_MACSEC=m +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NTB_NETDEV=m +CONFIG_RIONET=m +CONFIG_TUN=y +CONFIG_VETH=m +CONFIG_VIRTIO_NET=m +CONFIG_NLMON=m +CONFIG_NET_VRF=m +CONFIG_VSOCKMON=m +CONFIG_MHI_NET=m +CONFIG_ARCNET=m +CONFIG_ARCNET_1201=m +CONFIG_ARCNET_1051=m +CONFIG_ARCNET_RAW=m +CONFIG_ARCNET_CAP=m +CONFIG_ARCNET_COM90xx=m +CONFIG_ARCNET_COM90xxIO=m +CONFIG_ARCNET_RIM_I=m +CONFIG_ARCNET_COM20020=m +CONFIG_ARCNET_COM20020_PCI=m +CONFIG_ATM_DUMMY=m +CONFIG_ATM_TCP=m +CONFIG_ATM_LANAI=m +CONFIG_ATM_ENI=m +CONFIG_ATM_NICSTAR=m +CONFIG_ATM_IDT77252=m +CONFIG_ATM_IA=m +CONFIG_ATM_FORE200E=m +CONFIG_ATM_HE=m +CONFIG_ATM_HE_USE_SUNI=y +CONFIG_ATM_SOLOS=m +CONFIG_CAIF_DRIVERS=y +CONFIG_CAIF_TTY=m +CONFIG_CAIF_VIRTIO=m +CONFIG_B53_SPI_DRIVER=m +CONFIG_B53_MDIO_DRIVER=m +CONFIG_B53_MMAP_DRIVER=m +CONFIG_B53_SRAB_DRIVER=m +CONFIG_B53_SERDES=m +CONFIG_NET_DSA_BCM_SF2=m +CONFIG_NET_DSA_HIRSCHMANN_HELLCREEK=m +CONFIG_NET_DSA_LANTIQ_GSWIP=m +CONFIG_NET_DSA_MT7530=m +CONFIG_NET_DSA_MV88E6060=m +CONFIG_NET_DSA_MICROCHIP_KSZ_COMMON=m +CONFIG_NET_DSA_MICROCHIP_KSZ9477_I2C=m +CONFIG_NET_DSA_MICROCHIP_KSZ8863_SMI=m +CONFIG_NET_DSA_MV88E6XXX=m +CONFIG_NET_DSA_MV88E6XXX_PTP=y +CONFIG_NET_DSA_MSCC_SEVILLE=m +CONFIG_NET_DSA_AR9331=m +CONFIG_NET_DSA_QCA8K=m +CONFIG_NET_DSA_SJA1105=m +CONFIG_NET_DSA_SJA1105_PTP=y +CONFIG_NET_DSA_SJA1105_TAS=y +CONFIG_NET_DSA_SJA1105_VL=y +CONFIG_NET_DSA_XRS700X_I2C=m +CONFIG_NET_DSA_XRS700X_MDIO=m +CONFIG_NET_DSA_REALTEK=m +CONFIG_NET_DSA_REALTEK_RTL8365MB=m +CONFIG_NET_DSA_REALTEK_RTL8366RB=m +CONFIG_NET_DSA_SMSC_LAN9303_I2C=m +CONFIG_NET_DSA_SMSC_LAN9303_MDIO=m +CONFIG_NET_DSA_VITESSE_VSC73XX_SPI=m +CONFIG_NET_DSA_VITESSE_VSC73XX_PLATFORM=m +CONFIG_VORTEX=m +CONFIG_TYPHOON=m +CONFIG_ADAPTEC_STARFIRE=m +CONFIG_ET131X=m +CONFIG_SLICOSS=m +CONFIG_ACENIC=m +CONFIG_ALTERA_TSE=m +CONFIG_ENA_ETHERNET=m +CONFIG_AMD8111_ETH=m +CONFIG_PCNET32=m +CONFIG_AQTION=m +CONFIG_SPI_AX88796C=m +CONFIG_ATL2=m +CONFIG_ATL1=m +CONFIG_ATL1E=m +CONFIG_ATL1C=m +CONFIG_ALX=m +CONFIG_B44=m +CONFIG_BCMGENET=m +CONFIG_TIGON3=m +CONFIG_BNX2X=m +CONFIG_SYSTEMPORT=m +CONFIG_BNXT=m +CONFIG_BNXT_DCB=y +CONFIG_MACB=m +CONFIG_MACB_PCI=m +CONFIG_THUNDER_NIC_PF=m +CONFIG_THUNDER_NIC_VF=m +CONFIG_LIQUIDIO=m +CONFIG_LIQUIDIO_VF=m +CONFIG_CHELSIO_T1=m +CONFIG_CHELSIO_T1_1G=y +CONFIG_CHELSIO_T4_DCB=y +CONFIG_CHELSIO_T4_FCOE=y +CONFIG_CHELSIO_T4VF=m +CONFIG_CHELSIO_IPSEC_INLINE=m +CONFIG_CHELSIO_TLS_DEVICE=m +CONFIG_ENIC=m +CONFIG_GEMINI_ETHERNET=m +CONFIG_DM9051=m +CONFIG_DNET=m +CONFIG_NET_TULIP=y +CONFIG_DE2104X=m +CONFIG_TULIP=m +CONFIG_WINBOND_840=m +CONFIG_DM9102=m +CONFIG_ULI526X=m +CONFIG_DL2K=m +CONFIG_SUNDANCE=m +CONFIG_TSNEP=m +CONFIG_EZCHIP_NPS_MANAGEMENT_ENET=m +CONFIG_FUN_ETH=m +CONFIG_E100=m +CONFIG_E1000=m +CONFIG_E1000E=m +CONFIG_IGB=m +CONFIG_IGBVF=m +CONFIG_IXGB=m +CONFIG_IXGBE=m +CONFIG_IXGBE_DCB=y +CONFIG_IXGBEVF=m +CONFIG_I40E=m +CONFIG_I40E_DCB=y +CONFIG_I40EVF=m +CONFIG_ICE=m +CONFIG_FM10K=m +CONFIG_IGC=m +CONFIG_JME=m +CONFIG_LITEX_LITEETH=m +CONFIG_MVMDIO=m +CONFIG_SKGE=m +CONFIG_SKGE_GENESIS=y +CONFIG_SKY2=m +CONFIG_OCTEON_EP=m +CONFIG_PRESTERA=m +CONFIG_MLX4_EN=m +CONFIG_MLX5_CORE=m +CONFIG_MLX5_FPGA=y +CONFIG_MLX5_CORE_EN=y +CONFIG_MLX5_CORE_IPOIB=y +CONFIG_MLX5_EN_IPSEC=y +CONFIG_MLX5_EN_TLS=y +CONFIG_MLX5_SF=y +CONFIG_MLXSW_CORE=m +CONFIG_KS8842=m +CONFIG_KS8851=m +CONFIG_KS8851_MLL=m +CONFIG_KSZ884X_PCI=m +CONFIG_ENC28J60=m +CONFIG_ENCX24J600=m +CONFIG_LAN743X=m +CONFIG_LAN966X_SWITCH=m +CONFIG_MSCC_OCELOT_SWITCH=m +CONFIG_MYRI10GE=m +CONFIG_NI_XGE_MANAGEMENT_ENET=m +CONFIG_NATSEMI=m +CONFIG_NS83820=m +CONFIG_S2IO=m +CONFIG_NFP=m +CONFIG_NE2K_PCI=m +CONFIG_FORCEDETH=m +CONFIG_ETHOC=m +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m +CONFIG_IONIC=m +CONFIG_QLA3XXX=m +CONFIG_QLCNIC=m +CONFIG_NETXEN_NIC=m +CONFIG_QED=m +CONFIG_QEDE=m +CONFIG_BNA=m +CONFIG_QCA7000_SPI=m +CONFIG_QCA7000_UART=m +CONFIG_QCOM_EMAC=m +CONFIG_RMNET=m +CONFIG_R6040=m +CONFIG_8139CP=m +CONFIG_8139TOO=m +CONFIG_8139TOO_8129=y +CONFIG_R8169=m +CONFIG_ROCKER=m +CONFIG_SXGBE_ETH=m +CONFIG_SC92031=m +CONFIG_SIS900=m +CONFIG_SIS190=m +CONFIG_SFC=m +CONFIG_SFC_FALCON=m +CONFIG_SFC_SIENA=m +CONFIG_SFC_SIENA_SRIOV=y +CONFIG_EPIC100=m +CONFIG_SMSC911X=m +CONFIG_SMSC9420=m +CONFIG_STMMAC_ETH=m +CONFIG_DWMAC_DWC_QOS_ETH=m +CONFIG_DWMAC_LOONGSON=m +CONFIG_STMMAC_PCI=m +CONFIG_HAPPYMEAL=m +CONFIG_SUNGEM=m +CONFIG_CASSINI=m +CONFIG_NIU=m +CONFIG_DWC_XLGMAC=m +CONFIG_DWC_XLGMAC_PCI=m +CONFIG_TEHUTI=m +CONFIG_TLAN=m +CONFIG_MSE102X=m +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y +CONFIG_VIA_VELOCITY=m +CONFIG_WIZNET_W5100=m +CONFIG_WIZNET_W5300=m +CONFIG_WIZNET_W5100_SPI=m +CONFIG_XILINX_EMACLITE=m +CONFIG_XILINX_AXI_EMAC=m +CONFIG_XILINX_LL_TEMAC=m +CONFIG_FDDI=y +CONFIG_DEFXX=m +CONFIG_SKFP=m +CONFIG_PHYLIB=y +CONFIG_LED_TRIGGER_PHY=y +CONFIG_SFP=m +CONFIG_AMD_PHY=m +CONFIG_ADIN_PHY=m +CONFIG_ADIN1100_PHY=m +CONFIG_AQUANTIA_PHY=m +CONFIG_BROADCOM_PHY=m +CONFIG_BCM54140_PHY=m +CONFIG_BCM84881_PHY=m +CONFIG_BCM87XX_PHY=m +CONFIG_CICADA_PHY=m +CONFIG_CORTINA_PHY=m +CONFIG_DAVICOM_PHY=m +CONFIG_ICPLUS_PHY=m +CONFIG_LXT_PHY=m +CONFIG_INTEL_XWAY_PHY=m +CONFIG_LSI_ET1011C_PHY=m +CONFIG_MARVELL_PHY=m +CONFIG_MARVELL_10G_PHY=m +CONFIG_MARVELL_88X2222_PHY=m +CONFIG_MAXLINEAR_GPHY=m +CONFIG_MICROCHIP_T1_PHY=m +CONFIG_MICROSEMI_PHY=m +CONFIG_MOTORCOMM_PHY=m +CONFIG_NATIONAL_PHY=m +CONFIG_NXP_C45_TJA11XX_PHY=m +CONFIG_NXP_TJA11XX_PHY=m +CONFIG_AT803X_PHY=m +CONFIG_QSEMI_PHY=m +CONFIG_RENESAS_PHY=m +CONFIG_ROCKCHIP_PHY=m +CONFIG_STE10XP=m +CONFIG_TERANETICS_PHY=m +CONFIG_DP83822_PHY=m +CONFIG_DP83TC811_PHY=m +CONFIG_DP83848_PHY=m +CONFIG_DP83867_PHY=m +CONFIG_DP83869_PHY=m +CONFIG_DP83TD510_PHY=m +CONFIG_XILINX_GMII2RGMII=m +CONFIG_MICREL_KS8995MA=m +CONFIG_CAN_VCAN=m +CONFIG_CAN_VXCAN=m +CONFIG_CAN_FLEXCAN=m +CONFIG_CAN_GRCAN=m +CONFIG_CAN_JANZ_ICAN3=m +CONFIG_CAN_KVASER_PCIEFD=m +CONFIG_CAN_SLCAN=m +CONFIG_CAN_C_CAN=m +CONFIG_CAN_C_CAN_PLATFORM=m +CONFIG_CAN_C_CAN_PCI=m +CONFIG_CAN_CC770=m +CONFIG_CAN_CC770_ISA=m +CONFIG_CAN_CC770_PLATFORM=m +CONFIG_CAN_CTUCANFD_PCI=m +CONFIG_CAN_CTUCANFD_PLATFORM=m +CONFIG_CAN_IFI_CANFD=m +CONFIG_CAN_M_CAN=m +CONFIG_CAN_M_CAN_PCI=m +CONFIG_CAN_M_CAN_PLATFORM=m +CONFIG_CAN_M_CAN_TCAN4X5X=m +CONFIG_CAN_PEAK_PCIEFD=m +CONFIG_CAN_SJA1000=m +CONFIG_CAN_EMS_PCI=m +CONFIG_CAN_F81601=m +CONFIG_CAN_KVASER_PCI=m +CONFIG_CAN_PEAK_PCI=m +CONFIG_CAN_PLX_PCI=m +CONFIG_CAN_SJA1000_ISA=m +CONFIG_CAN_SJA1000_PLATFORM=m +CONFIG_CAN_SOFTING=m +CONFIG_CAN_HI311X=m +CONFIG_CAN_MCP251X=m +CONFIG_CAN_MCP251XFD=m +CONFIG_CAN_8DEV_USB=m +CONFIG_CAN_EMS_USB=m +CONFIG_CAN_ETAS_ES58X=m +CONFIG_CAN_GS_USB=m +CONFIG_CAN_KVASER_USB=m +CONFIG_CAN_MCBA_USB=m +CONFIG_CAN_PEAK_USB=m +CONFIG_CAN_UCAN=m +CONFIG_MCTP_SERIAL=m +CONFIG_MDIO_GPIO=m +CONFIG_MDIO_HISI_FEMAC=m +CONFIG_MDIO_MVUSB=m +CONFIG_MDIO_OCTEON=m +CONFIG_MDIO_IPQ4019=m +CONFIG_MDIO_IPQ8064=m +CONFIG_MDIO_BUS_MUX_GPIO=m +CONFIG_MDIO_BUS_MUX_MULTIPLEXER=m +CONFIG_MDIO_BUS_MUX_MMIOREG=m +CONFIG_PLIP=m +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOATM=m +CONFIG_PPPOE=m +CONFIG_PPTP=m +CONFIG_PPPOL2TP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLIP_SMART=y +CONFIG_SLIP_MODE_SLIP6=y +CONFIG_USB_NET_DRIVERS=m +CONFIG_USB_CATC=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_RTL8152=m +CONFIG_USB_LAN78XX=m +CONFIG_USB_NET_CDC_EEM=m +CONFIG_USB_NET_HUAWEI_CDC_NCM=m +CONFIG_USB_NET_CDC_MBIM=m +CONFIG_USB_NET_DM9601=m +CONFIG_USB_NET_SR9700=m +CONFIG_USB_NET_SR9800=m +CONFIG_USB_NET_SMSC75XX=m +CONFIG_USB_NET_SMSC95XX=m +CONFIG_USB_NET_GL620A=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_MCS7830=m +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_KC2190=y +CONFIG_USB_NET_CX82310_ETH=m +CONFIG_USB_NET_KALMIA=m +CONFIG_USB_NET_QMI_WWAN=m +CONFIG_USB_HSO=m +CONFIG_USB_NET_INT51X1=m +CONFIG_USB_CDC_PHONET=m +CONFIG_USB_IPHETH=m +CONFIG_USB_SIERRA_NET=m +CONFIG_USB_VL600=m +CONFIG_USB_NET_CH9200=m +CONFIG_USB_NET_AQC111=m +CONFIG_ADM8211=m +CONFIG_ATH5K=m +CONFIG_ATH9K=m +CONFIG_ATH9K_AHB=y +CONFIG_ATH9K_DEBUGFS=y +CONFIG_ATH9K_STATION_STATISTICS=y +CONFIG_ATH9K_CHANNEL_CONTEXT=y +CONFIG_ATH9K_PCI_NO_EEPROM=m +CONFIG_ATH9K_HTC=m +CONFIG_ATH9K_HTC_DEBUGFS=y +CONFIG_ATH9K_HWRNG=y +CONFIG_ATH9K_COMMON_SPECTRAL=y +CONFIG_CARL9170=m +CONFIG_CARL9170_HWRNG=y +CONFIG_ATH6KL=m +CONFIG_ATH6KL_SDIO=m +CONFIG_ATH6KL_USB=m +CONFIG_AR5523=m +CONFIG_WIL6210=m +CONFIG_WIL6210_TRACING=y +CONFIG_ATH10K=m +CONFIG_ATH10K_PCI=m +CONFIG_ATH10K_AHB=y +CONFIG_ATH10K_SDIO=m +CONFIG_ATH10K_USB=m +CONFIG_ATH10K_DEBUGFS=y +CONFIG_ATH10K_SPECTRAL=y +CONFIG_ATH10K_TRACING=y +CONFIG_WCN36XX=m +CONFIG_ATH11K=m +CONFIG_ATH11K_PCI=m +CONFIG_ATH11K_DEBUGFS=y +CONFIG_ATH11K_TRACING=y +CONFIG_ATH11K_SPECTRAL=y +CONFIG_ATMEL=m +CONFIG_PCI_ATMEL=m +CONFIG_AT76C50X_USB=m +CONFIG_B43=m +CONFIG_B43LEGACY=m +# CONFIG_B43LEGACY_DEBUG is not set +CONFIG_BRCMSMAC=m +CONFIG_BRCMFMAC=m +CONFIG_BRCMFMAC_USB=y +CONFIG_BRCMFMAC_PCIE=y +CONFIG_BRCM_TRACING=y +CONFIG_IPW2100=m +CONFIG_IPW2100_MONITOR=y +CONFIG_IPW2200=m +CONFIG_IPW2200_MONITOR=y +CONFIG_IPW2200_PROMISCUOUS=y +CONFIG_IPW2200_QOS=y +CONFIG_IWL4965=m +CONFIG_IWL3945=m +CONFIG_IWLEGACY_DEBUGFS=y +CONFIG_IWLWIFI=m +CONFIG_IWLDVM=m +CONFIG_IWLMVM=m +CONFIG_IWLWIFI_DEBUGFS=y +CONFIG_HOSTAP=m +CONFIG_HOSTAP_FIRMWARE=y +CONFIG_HOSTAP_FIRMWARE_NVRAM=y +CONFIG_HOSTAP_PLX=m +CONFIG_HOSTAP_PCI=m +CONFIG_HERMES=m +CONFIG_PLX_HERMES=m +CONFIG_TMD_HERMES=m +CONFIG_NORTEL_HERMES=m +CONFIG_ORINOCO_USB=m +CONFIG_P54_COMMON=m +CONFIG_P54_USB=m +CONFIG_P54_PCI=m +CONFIG_P54_SPI=m +CONFIG_LIBERTAS=m +CONFIG_LIBERTAS_USB=m +CONFIG_LIBERTAS_SDIO=m +CONFIG_LIBERTAS_SPI=m +CONFIG_LIBERTAS_MESH=y +CONFIG_LIBERTAS_THINFIRM=m +CONFIG_LIBERTAS_THINFIRM_USB=m +CONFIG_MWIFIEX=m +CONFIG_MWIFIEX_SDIO=m +CONFIG_MWIFIEX_PCIE=m +CONFIG_MWIFIEX_USB=m +CONFIG_MWL8K=m +CONFIG_MT7601U=m +CONFIG_MT76x0U=m +CONFIG_MT76x0E=m +CONFIG_MT76x2E=m +CONFIG_MT76x2U=m +CONFIG_MT7603E=m +CONFIG_MT7615E=m +CONFIG_MT7663U=m +CONFIG_MT7663S=m +CONFIG_MT7915E=m +CONFIG_MT7921E=m +CONFIG_MT7921S=m +CONFIG_MT7921U=m +CONFIG_WILC1000_SDIO=m +CONFIG_WILC1000_SPI=m +CONFIG_WILC1000_HW_OOB_INTR=y +CONFIG_PLFXLC=m +CONFIG_RT2X00=m +CONFIG_RT2400PCI=m +CONFIG_RT2500PCI=m +CONFIG_RT61PCI=m +CONFIG_RT2800PCI=m +CONFIG_RT2500USB=m +CONFIG_RT73USB=m +CONFIG_RT2800USB=m +CONFIG_RT2800USB_RT3573=y +CONFIG_RT2800USB_RT53XX=y +CONFIG_RT2800USB_RT55XX=y +CONFIG_RT2800USB_UNKNOWN=y +CONFIG_RTL8180=m +CONFIG_RTL8187=m +CONFIG_RTL8192CE=m +CONFIG_RTL8192SE=m +CONFIG_RTL8192DE=m +CONFIG_RTL8723AE=m +CONFIG_RTL8723BE=m +CONFIG_RTL8188EE=m +CONFIG_RTL8192EE=m +CONFIG_RTL8821AE=m +CONFIG_RTL8192CU=m +# CONFIG_RTLWIFI_DEBUG is not set +CONFIG_RTL8XXXU=m +CONFIG_RTL8XXXU_UNTESTED=y +CONFIG_RTW88=m +CONFIG_RTW88_8822BE=m +CONFIG_RTW88_8822CE=m +CONFIG_RTW88_8723DE=m +CONFIG_RTW88_8821CE=m +CONFIG_RTW88_DEBUG=y +CONFIG_RTW88_DEBUGFS=y +CONFIG_RTW89=m +CONFIG_RTW89_8852AE=m +CONFIG_RTW89_8852CE=m +CONFIG_RTW89_DEBUGMSG=y +CONFIG_RTW89_DEBUGFS=y +CONFIG_RSI_91X=m +# CONFIG_RSI_DEBUGFS is not set +CONFIG_WFX=m +CONFIG_CW1200=m +CONFIG_CW1200_WLAN_SDIO=m +CONFIG_CW1200_WLAN_SPI=m +CONFIG_WL1251=m +CONFIG_WL1251_SPI=m +CONFIG_WL1251_SDIO=m +CONFIG_WL12XX=m +CONFIG_WL18XX=m +CONFIG_WLCORE_SPI=m +CONFIG_WLCORE_SDIO=m +CONFIG_USB_ZD1201=m +CONFIG_ZD1211RW=m +CONFIG_QTNFMAC_PCIE=m +CONFIG_MAC80211_HWSIM=m +CONFIG_USB_NET_RNDIS_WLAN=m +CONFIG_VIRT_WIFI=m +CONFIG_WAN=y +CONFIG_HDLC=m +CONFIG_HDLC_RAW=m +CONFIG_HDLC_RAW_ETH=m +CONFIG_HDLC_CISCO=m +CONFIG_HDLC_FR=m +CONFIG_HDLC_PPP=m +CONFIG_HDLC_X25=m +CONFIG_PCI200SYN=m +CONFIG_WANXL=m +CONFIG_PC300TOO=m +CONFIG_FARSYNC=m +CONFIG_LAPBETHER=m +CONFIG_IEEE802154_FAKELB=m +CONFIG_IEEE802154_AT86RF230=m +CONFIG_IEEE802154_MRF24J40=m +CONFIG_IEEE802154_CC2520=m +CONFIG_IEEE802154_ATUSB=m +CONFIG_IEEE802154_ADF7242=m +CONFIG_IEEE802154_CA8210=m +CONFIG_IEEE802154_CA8210_DEBUGFS=y +CONFIG_IEEE802154_MCR20A=m +CONFIG_IEEE802154_HWSIM=m +CONFIG_WWAN=m +CONFIG_WWAN_HWSIM=m +CONFIG_MHI_WWAN_CTRL=m +CONFIG_MHI_WWAN_MBIM=m +CONFIG_RPMSG_WWAN_CTRL=m +CONFIG_MTK_T7XX=m +CONFIG_VMXNET3=m +CONFIG_USB4_NET=m +CONFIG_NETDEVSIM=m +CONFIG_ISDN=y +CONFIG_MISDN=m +CONFIG_MISDN_DSP=m +CONFIG_MISDN_L1OIP=m +CONFIG_MISDN_HFCPCI=m +CONFIG_MISDN_HFCMULTI=m +CONFIG_MISDN_HFCUSB=m +CONFIG_MISDN_AVMFRITZ=m +CONFIG_MISDN_SPEEDFAX=m +CONFIG_MISDN_INFINEON=m +CONFIG_MISDN_W6692=m +CONFIG_MISDN_NETJET=m +CONFIG_INPUT_LEDS=m +CONFIG_INPUT_SPARSEKMAP=m +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=m +CONFIG_KEYBOARD_ADC=m +CONFIG_KEYBOARD_ADP5520=m +CONFIG_KEYBOARD_ADP5588=m +CONFIG_KEYBOARD_ADP5589=m +CONFIG_KEYBOARD_QT1050=m +CONFIG_KEYBOARD_QT1070=m +CONFIG_KEYBOARD_QT2160=m +CONFIG_KEYBOARD_DLINK_DIR685=m +CONFIG_KEYBOARD_LKKBD=m +CONFIG_KEYBOARD_GPIO=m +CONFIG_KEYBOARD_GPIO_POLLED=m +CONFIG_KEYBOARD_TCA6416=m +CONFIG_KEYBOARD_TCA8418=m +CONFIG_KEYBOARD_MATRIX=m +CONFIG_KEYBOARD_LM8323=m +CONFIG_KEYBOARD_LM8333=m +CONFIG_KEYBOARD_MAX7359=m +CONFIG_KEYBOARD_MCS=m +CONFIG_KEYBOARD_MPR121=m +CONFIG_KEYBOARD_NEWTON=m +CONFIG_KEYBOARD_OPENCORES=m +CONFIG_KEYBOARD_SAMSUNG=m +CONFIG_KEYBOARD_GOLDFISH_EVENTS=m +CONFIG_KEYBOARD_STOWAWAY=m +CONFIG_KEYBOARD_SUNKBD=m +CONFIG_KEYBOARD_STMPE=m +CONFIG_KEYBOARD_IQS62X=m +CONFIG_KEYBOARD_OMAP4=m +CONFIG_KEYBOARD_TC3589X=m +CONFIG_KEYBOARD_TM2_TOUCHKEY=m +CONFIG_KEYBOARD_TWL4030=m +CONFIG_KEYBOARD_XTKBD=m +CONFIG_KEYBOARD_CAP11XX=m +CONFIG_KEYBOARD_BCM=m +CONFIG_KEYBOARD_MTK_PMIC=m +CONFIG_KEYBOARD_CYPRESS_SF=m +CONFIG_MOUSE_PS2=m +CONFIG_MOUSE_PS2_ELANTECH=y +CONFIG_MOUSE_PS2_SENTELIC=y +CONFIG_MOUSE_PS2_TOUCHKIT=y +CONFIG_MOUSE_SERIAL=m +CONFIG_MOUSE_APPLETOUCH=m +CONFIG_MOUSE_BCM5974=m +CONFIG_MOUSE_CYAPA=m +CONFIG_MOUSE_ELAN_I2C=m +CONFIG_MOUSE_ELAN_I2C_SMBUS=y +CONFIG_MOUSE_VSXXXAA=m +CONFIG_MOUSE_GPIO=m +CONFIG_MOUSE_SYNAPTICS_I2C=m +CONFIG_MOUSE_SYNAPTICS_USB=m +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_ANALOG=m +CONFIG_JOYSTICK_A3D=m +CONFIG_JOYSTICK_ADC=m +CONFIG_JOYSTICK_ADI=m +CONFIG_JOYSTICK_COBRA=m +CONFIG_JOYSTICK_GF2K=m +CONFIG_JOYSTICK_GRIP=m +CONFIG_JOYSTICK_GRIP_MP=m +CONFIG_JOYSTICK_GUILLEMOT=m +CONFIG_JOYSTICK_INTERACT=m +CONFIG_JOYSTICK_SIDEWINDER=m +CONFIG_JOYSTICK_TMDC=m +CONFIG_JOYSTICK_IFORCE=m +CONFIG_JOYSTICK_IFORCE_USB=m +CONFIG_JOYSTICK_IFORCE_232=m +CONFIG_JOYSTICK_WARRIOR=m +CONFIG_JOYSTICK_MAGELLAN=m +CONFIG_JOYSTICK_SPACEORB=m +CONFIG_JOYSTICK_SPACEBALL=m +CONFIG_JOYSTICK_STINGER=m +CONFIG_JOYSTICK_TWIDJOY=m +CONFIG_JOYSTICK_ZHENHUA=m +CONFIG_JOYSTICK_DB9=m +CONFIG_JOYSTICK_GAMECON=m +CONFIG_JOYSTICK_TURBOGRAFX=m +CONFIG_JOYSTICK_AS5011=m +CONFIG_JOYSTICK_JOYDUMP=m +CONFIG_JOYSTICK_XPAD=m +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_JOYSTICK_WALKERA0701=m +CONFIG_JOYSTICK_PSXPAD_SPI=m +CONFIG_JOYSTICK_PSXPAD_SPI_FF=y +CONFIG_JOYSTICK_PXRC=m +CONFIG_JOYSTICK_QWIIC=m +CONFIG_JOYSTICK_FSIA6B=m +CONFIG_JOYSTICK_SENSEHAT=m +CONFIG_INPUT_TABLET=y +CONFIG_TABLET_USB_ACECAD=m +CONFIG_TABLET_USB_AIPTEK=m +CONFIG_TABLET_USB_HANWANG=m +CONFIG_TABLET_USB_KBTAB=m +CONFIG_TABLET_USB_PEGASUS=m +CONFIG_TABLET_SERIAL_WACOM4=m +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_88PM860X=m +CONFIG_TOUCHSCREEN_ADS7846=m +CONFIG_TOUCHSCREEN_AD7877=m +CONFIG_TOUCHSCREEN_AD7879=m +CONFIG_TOUCHSCREEN_AD7879_I2C=m +CONFIG_TOUCHSCREEN_AD7879_SPI=m +CONFIG_TOUCHSCREEN_ADC=m +CONFIG_TOUCHSCREEN_AR1021_I2C=m +CONFIG_TOUCHSCREEN_ATMEL_MXT=m +CONFIG_TOUCHSCREEN_ATMEL_MXT_T37=y +CONFIG_TOUCHSCREEN_AUO_PIXCIR=m +CONFIG_TOUCHSCREEN_BU21013=m +CONFIG_TOUCHSCREEN_BU21029=m +CONFIG_TOUCHSCREEN_CHIPONE_ICN8318=m +CONFIG_TOUCHSCREEN_CY8CTMA140=m +CONFIG_TOUCHSCREEN_CY8CTMG110=m +CONFIG_TOUCHSCREEN_CYTTSP_CORE=m +CONFIG_TOUCHSCREEN_CYTTSP_I2C=m +CONFIG_TOUCHSCREEN_CYTTSP_SPI=m +CONFIG_TOUCHSCREEN_CYTTSP4_CORE=m +CONFIG_TOUCHSCREEN_CYTTSP4_I2C=m +CONFIG_TOUCHSCREEN_CYTTSP4_SPI=m +CONFIG_TOUCHSCREEN_DA9034=m +CONFIG_TOUCHSCREEN_DA9052=m +CONFIG_TOUCHSCREEN_DYNAPRO=m +CONFIG_TOUCHSCREEN_HAMPSHIRE=m +CONFIG_TOUCHSCREEN_EETI=m +CONFIG_TOUCHSCREEN_EGALAX=m +CONFIG_TOUCHSCREEN_EGALAX_SERIAL=m +CONFIG_TOUCHSCREEN_EXC3000=m +CONFIG_TOUCHSCREEN_FUJITSU=m +CONFIG_TOUCHSCREEN_GOODIX=m +CONFIG_TOUCHSCREEN_HIDEEP=m +CONFIG_TOUCHSCREEN_HYCON_HY46XX=m +CONFIG_TOUCHSCREEN_ILI210X=m +CONFIG_TOUCHSCREEN_ILITEK=m +CONFIG_TOUCHSCREEN_S6SY761=m +CONFIG_TOUCHSCREEN_GUNZE=m +CONFIG_TOUCHSCREEN_EKTF2127=m +CONFIG_TOUCHSCREEN_ELAN=m +CONFIG_TOUCHSCREEN_ELO=m +CONFIG_TOUCHSCREEN_WACOM_W8001=m +CONFIG_TOUCHSCREEN_WACOM_I2C=m +CONFIG_TOUCHSCREEN_MAX11801=m +CONFIG_TOUCHSCREEN_MCS5000=m +CONFIG_TOUCHSCREEN_MMS114=m +CONFIG_TOUCHSCREEN_MELFAS_MIP4=m +CONFIG_TOUCHSCREEN_MSG2638=m +CONFIG_TOUCHSCREEN_MTOUCH=m +CONFIG_TOUCHSCREEN_IMAGIS=m +CONFIG_TOUCHSCREEN_IMX6UL_TSC=m +CONFIG_TOUCHSCREEN_INEXIO=m +CONFIG_TOUCHSCREEN_MK712=m +CONFIG_TOUCHSCREEN_PENMOUNT=m +CONFIG_TOUCHSCREEN_EDT_FT5X06=m +CONFIG_TOUCHSCREEN_TOUCHRIGHT=m +CONFIG_TOUCHSCREEN_TOUCHWIN=m +CONFIG_TOUCHSCREEN_TI_AM335X_TSC=m +CONFIG_TOUCHSCREEN_PIXCIR=m +CONFIG_TOUCHSCREEN_WDT87XX_I2C=m +CONFIG_TOUCHSCREEN_WM831X=m +CONFIG_TOUCHSCREEN_WM97XX=m +CONFIG_TOUCHSCREEN_USB_COMPOSITE=m +CONFIG_TOUCHSCREEN_MC13783=m +CONFIG_TOUCHSCREEN_TOUCHIT213=m +CONFIG_TOUCHSCREEN_TSC_SERIO=m +CONFIG_TOUCHSCREEN_TSC2004=m +CONFIG_TOUCHSCREEN_TSC2005=m +CONFIG_TOUCHSCREEN_TSC2007=m +CONFIG_TOUCHSCREEN_TSC2007_IIO=y +CONFIG_TOUCHSCREEN_PCAP=m +CONFIG_TOUCHSCREEN_RM_TS=m +CONFIG_TOUCHSCREEN_SILEAD=m +CONFIG_TOUCHSCREEN_SIS_I2C=m +CONFIG_TOUCHSCREEN_ST1232=m +CONFIG_TOUCHSCREEN_STMFTS=m +CONFIG_TOUCHSCREEN_STMPE=m +CONFIG_TOUCHSCREEN_SUR40=m +CONFIG_TOUCHSCREEN_SURFACE3_SPI=m +CONFIG_TOUCHSCREEN_SX8654=m +CONFIG_TOUCHSCREEN_TPS6507X=m +CONFIG_TOUCHSCREEN_ZET6223=m +CONFIG_TOUCHSCREEN_ZFORCE=m +CONFIG_TOUCHSCREEN_COLIBRI_VF50=m +CONFIG_TOUCHSCREEN_ROHM_BU21023=m +CONFIG_TOUCHSCREEN_IQS5XX=m +CONFIG_TOUCHSCREEN_ZINITIX=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_88PM860X_ONKEY=m +CONFIG_INPUT_88PM80X_ONKEY=m +CONFIG_INPUT_AD714X=m +CONFIG_INPUT_ARIZONA_HAPTICS=m +CONFIG_INPUT_ATC260X_ONKEY=m +CONFIG_INPUT_ATMEL_CAPTOUCH=m +CONFIG_INPUT_BMA150=m +CONFIG_INPUT_E3X0_BUTTON=m +CONFIG_INPUT_MAX77650_ONKEY=m +CONFIG_INPUT_MAX77693_HAPTIC=m +CONFIG_INPUT_MAX8925_ONKEY=m +CONFIG_INPUT_MAX8997_HAPTIC=m +CONFIG_INPUT_MC13783_PWRBUTTON=m +CONFIG_INPUT_MMA8450=m +CONFIG_INPUT_GPIO_BEEPER=m +CONFIG_INPUT_GPIO_DECODER=m +CONFIG_INPUT_GPIO_VIBRA=m +CONFIG_INPUT_CPCAP_PWRBUTTON=m +CONFIG_INPUT_ATI_REMOTE2=m +CONFIG_INPUT_KEYSPAN_REMOTE=m +CONFIG_INPUT_KXTJ9=m +CONFIG_INPUT_POWERMATE=m +CONFIG_INPUT_YEALINK=m +CONFIG_INPUT_CM109=m +CONFIG_INPUT_REGULATOR_HAPTIC=m +CONFIG_INPUT_RETU_PWRBUTTON=m +CONFIG_INPUT_TPS65218_PWRBUTTON=m +CONFIG_INPUT_AXP20X_PEK=m +CONFIG_INPUT_TWL4030_PWRBUTTON=m +CONFIG_INPUT_TWL4030_VIBRA=m +CONFIG_INPUT_TWL6040_VIBRA=m +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_PALMAS_PWRBUTTON=m +CONFIG_INPUT_PCF50633_PMU=m +CONFIG_INPUT_PCF8574=m +CONFIG_INPUT_PWM_BEEPER=m +CONFIG_INPUT_PWM_VIBRA=m +CONFIG_INPUT_RK805_PWRKEY=m +CONFIG_INPUT_GPIO_ROTARY_ENCODER=m +CONFIG_INPUT_DA7280_HAPTICS=m +CONFIG_INPUT_DA9052_ONKEY=m +CONFIG_INPUT_DA9055_ONKEY=m +CONFIG_INPUT_DA9063_ONKEY=m +CONFIG_INPUT_WM831X_ON=m +CONFIG_INPUT_PCAP=m +CONFIG_INPUT_ADXL34X=m +CONFIG_INPUT_IMS_PCU=m +CONFIG_INPUT_IQS269A=m +CONFIG_INPUT_IQS626A=m +CONFIG_INPUT_IQS7222=m +CONFIG_INPUT_CMA3000=m +CONFIG_INPUT_CMA3000_I2C=m +CONFIG_INPUT_DRV260X_HAPTICS=m +CONFIG_INPUT_DRV2665_HAPTICS=m +CONFIG_INPUT_DRV2667_HAPTICS=m +CONFIG_INPUT_RAVE_SP_PWRBUTTON=m +CONFIG_INPUT_STPMIC1_ONKEY=m +CONFIG_RMI4_I2C=m +CONFIG_RMI4_SPI=m +CONFIG_RMI4_SMB=m +CONFIG_RMI4_F34=y +CONFIG_RMI4_F3A=y +CONFIG_RMI4_F54=y +CONFIG_SERIO_SERPORT=m +CONFIG_SERIO_PARKBD=m +CONFIG_SERIO_PCIPS2=m +CONFIG_SERIO_RAW=m +CONFIG_SERIO_ALTERA_PS2=m +CONFIG_SERIO_PS2MULT=m +CONFIG_SERIO_ARC_PS2=m +CONFIG_SERIO_APBPS2=m +CONFIG_SERIO_GPIO_PS2=m +CONFIG_USERIO=m +CONFIG_GAMEPORT_NS558=m +CONFIG_GAMEPORT_L4=m +CONFIG_GAMEPORT_EMU10K1=m +CONFIG_GAMEPORT_FM801=m +CONFIG_LEGACY_PTY_COUNT=0 +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +CONFIG_SERIAL_8250_FINTEK=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_EXAR=m +CONFIG_SERIAL_8250_MEN_MCB=m +CONFIG_SERIAL_8250_NR_UARTS=48 +CONFIG_SERIAL_8250_RUNTIME_UARTS=32 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_RSA=y +CONFIG_SERIAL_8250_DW=m +CONFIG_SERIAL_8250_RT288X=y +CONFIG_SERIAL_8250_PERICOM=m +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SERIAL_KGDB_NMI=y +CONFIG_SERIAL_MAX3100=m +CONFIG_SERIAL_MAX310X=y +CONFIG_SERIAL_UARTLITE=m +CONFIG_SERIAL_JSM=m +CONFIG_SERIAL_SCCNXP=y +CONFIG_SERIAL_SCCNXP_CONSOLE=y +CONFIG_SERIAL_SC16IS7XX=m +CONFIG_SERIAL_SC16IS7XX_SPI=y +CONFIG_SERIAL_ALTERA_JTAGUART=m +CONFIG_SERIAL_ALTERA_UART=m +CONFIG_SERIAL_XILINX_PS_UART=m +CONFIG_SERIAL_ARC=m +CONFIG_SERIAL_RP2=m +CONFIG_SERIAL_FSL_LPUART=m +CONFIG_SERIAL_CONEXANT_DIGICOLOR=m +CONFIG_SERIAL_MEN_Z135=m +CONFIG_SERIAL_SPRD=m +CONFIG_SERIAL_LITEUART=m +CONFIG_SERIAL_NONSTANDARD=y +CONFIG_MOXA_INTELLIO=m +CONFIG_MOXA_SMARTIO=m +CONFIG_SYNCLINK_GT=m +CONFIG_N_HDLC=m +CONFIG_GOLDFISH_TTY=m +CONFIG_N_GSM=m +CONFIG_NOZOMI=m +CONFIG_NULL_TTY=m +CONFIG_RPMSG_TTY=m +CONFIG_SERIAL_DEV_BUS=y +CONFIG_TTY_PRINTK=y +CONFIG_PRINTER=m +CONFIG_PPDEV=m +CONFIG_VIRTIO_CONSOLE=y +CONFIG_IPMI_HANDLER=m +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_SSIF=m +CONFIG_IPMI_WATCHDOG=m +CONFIG_IPMI_POWEROFF=m +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_TIMERIOMEM=m +CONFIG_HW_RANDOM_BA431=m +CONFIG_HW_RANDOM_VIRTIO=m +CONFIG_HW_RANDOM_POLARFIRE_SOC=m +CONFIG_HW_RANDOM_CCTRNG=m +CONFIG_HW_RANDOM_XIPHERA=m +CONFIG_APPLICOM=m +CONFIG_TCG_TIS=y +CONFIG_TCG_TIS_SPI=m +CONFIG_TCG_TIS_SPI_CR50=y +CONFIG_TCG_TIS_I2C_CR50=m +CONFIG_TCG_TIS_I2C_ATMEL=m +CONFIG_TCG_TIS_I2C_INFINEON=m +CONFIG_TCG_TIS_I2C_NUVOTON=m +CONFIG_TCG_ATMEL=m +CONFIG_TCG_VTPM_PROXY=m +CONFIG_TCG_TIS_ST33ZP24_I2C=m +CONFIG_TCG_TIS_ST33ZP24_SPI=m +CONFIG_XILLYBUS=m +CONFIG_XILLYBUS_PCIE=m +CONFIG_XILLYBUS_OF=m +CONFIG_XILLYUSB=m +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_ARB_GPIO_CHALLENGE=m +CONFIG_I2C_MUX_GPIO=m +CONFIG_I2C_MUX_GPMUX=m +CONFIG_I2C_MUX_LTC4306=m +CONFIG_I2C_MUX_PCA9541=m +CONFIG_I2C_MUX_PCA954x=m +CONFIG_I2C_MUX_PINCTRL=m +CONFIG_I2C_MUX_REG=m +CONFIG_I2C_DEMUX_PINCTRL=m +CONFIG_I2C_MUX_MLXCPLD=m +CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI1563=m +CONFIG_I2C_ALI15X3=m +CONFIG_I2C_AMD756=m +CONFIG_I2C_AMD8111=m +CONFIG_I2C_I801=m +CONFIG_I2C_ISCH=m +CONFIG_I2C_PIIX4=m +CONFIG_I2C_NFORCE2=m +CONFIG_I2C_NVIDIA_GPU=m +CONFIG_I2C_SIS5595=m +CONFIG_I2C_SIS630=m +CONFIG_I2C_SIS96X=m +CONFIG_I2C_VIA=m +CONFIG_I2C_VIAPRO=m +CONFIG_I2C_CBUS_GPIO=m +CONFIG_I2C_DESIGNWARE_PLATFORM=y +CONFIG_I2C_DESIGNWARE_PCI=m +CONFIG_I2C_GPIO=m +CONFIG_I2C_KEMPLD=m +CONFIG_I2C_OCORES=m +CONFIG_I2C_PCA_PLATFORM=m +CONFIG_I2C_RK3X=m +CONFIG_I2C_SIMTEC=m +CONFIG_I2C_XILINX=m +CONFIG_I2C_DIOLAN_U2C=m +CONFIG_I2C_DLN2=m +CONFIG_I2C_CP2615=m +CONFIG_I2C_PARPORT=m +CONFIG_I2C_ROBOTFUZZ_OSIF=m +CONFIG_I2C_TAOS_EVM=m +CONFIG_I2C_TINY_USB=m +CONFIG_I2C_VIPERBOARD=m +CONFIG_I2C_FSI=m +CONFIG_I2C_VIRTIO=m +CONFIG_I2C_STUB=m +CONFIG_I3C=m +CONFIG_CDNS_I3C_MASTER=m +CONFIG_DW_I3C_MASTER=m +CONFIG_SVC_I3C_MASTER=m +CONFIG_MIPI_I3C_HCI=m +CONFIG_SPI=y +CONFIG_SPI_ALTERA=m +CONFIG_SPI_ALTERA_DFL=m +CONFIG_SPI_AXI_SPI_ENGINE=m +CONFIG_SPI_BUTTERFLY=m +CONFIG_SPI_CADENCE=m +CONFIG_SPI_CADENCE_XSPI=m +CONFIG_SPI_DESIGNWARE=m +CONFIG_SPI_DW_DMA=y +CONFIG_SPI_DW_PCI=m +CONFIG_SPI_DW_MMIO=m +CONFIG_SPI_DLN2=m +CONFIG_SPI_FSI=m +CONFIG_SPI_NXP_FLEXSPI=m +CONFIG_SPI_GPIO=m +CONFIG_SPI_LM70_LLP=m +CONFIG_SPI_FSL_SPI=y +CONFIG_SPI_OC_TINY=m +CONFIG_SPI_PXA2XX=m +CONFIG_SPI_SC18IS602=m +CONFIG_SPI_SIFIVE=y +CONFIG_SPI_MXIC=m +CONFIG_SPI_XCOMM=m +CONFIG_SPI_ZYNQMP_GQSPI=m +CONFIG_SPI_AMD=m +CONFIG_SPI_MUX=m +CONFIG_SPI_SPIDEV=m +CONFIG_SPI_LOOPBACK_TEST=m +CONFIG_SPI_TLE62X0=m +CONFIG_SPI_SLAVE=y +CONFIG_SPI_SLAVE_TIME=m +CONFIG_SPI_SLAVE_SYSTEM_CONTROL=m +CONFIG_SPMI=m +CONFIG_SPMI_HISI3670=m +CONFIG_HSI=m +CONFIG_HSI_CHAR=m +CONFIG_PPS_CLIENT_LDISC=m +CONFIG_PPS_CLIENT_PARPORT=m +CONFIG_PPS_CLIENT_GPIO=m +CONFIG_DP83640_PHY=m +CONFIG_PTP_1588_CLOCK_INES=m +CONFIG_PTP_1588_CLOCK_IDT82P33=m +CONFIG_PTP_1588_CLOCK_IDTCM=m +CONFIG_PTP_1588_CLOCK_OCP=m +CONFIG_PINCTRL_AS3722=y +CONFIG_PINCTRL_AXP209=m +CONFIG_PINCTRL_DA9062=m +CONFIG_PINCTRL_MAX77620=m +CONFIG_PINCTRL_MCP23S08=m +CONFIG_PINCTRL_MICROCHIP_SGPIO=y +CONFIG_PINCTRL_OCELOT=y +CONFIG_PINCTRL_PALMAS=y +CONFIG_PINCTRL_RK805=m +CONFIG_PINCTRL_SINGLE=y +CONFIG_PINCTRL_STMFX=m +CONFIG_PINCTRL_SX150X=y +CONFIG_PINCTRL_LOCHNAGAR=m +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_74XX_MMIO=m +CONFIG_GPIO_ALTERA=m +CONFIG_GPIO_CADENCE=m +CONFIG_GPIO_DWAPB=m +CONFIG_GPIO_EXAR=m +CONFIG_GPIO_FTGPIO010=y +CONFIG_GPIO_GENERIC_PLATFORM=y +CONFIG_GPIO_GRGPIO=m +CONFIG_GPIO_HLWD=m +CONFIG_GPIO_LOGICVC=m +CONFIG_GPIO_MB86S7X=m +CONFIG_GPIO_MENZ127=m +CONFIG_GPIO_SIFIVE=y +CONFIG_GPIO_SIOX=m +CONFIG_GPIO_SYSCON=m +CONFIG_GPIO_WCD934X=m +CONFIG_GPIO_ADNP=m +CONFIG_GPIO_GW_PLD=m +CONFIG_GPIO_MAX7300=m +CONFIG_GPIO_MAX732X=m +CONFIG_GPIO_PCA953X=m +CONFIG_GPIO_PCA953X_IRQ=y +CONFIG_GPIO_PCA9570=m +CONFIG_GPIO_PCF857X=m +CONFIG_GPIO_TPIC2810=m +CONFIG_GPIO_ADP5520=m +CONFIG_GPIO_ARIZONA=m +CONFIG_GPIO_BD71815=m +CONFIG_GPIO_BD71828=m +CONFIG_GPIO_BD9571MWV=m +CONFIG_GPIO_DA9052=m +CONFIG_GPIO_DA9055=m +CONFIG_GPIO_DLN2=m +CONFIG_GPIO_JANZ_TTL=m +CONFIG_GPIO_KEMPLD=m +CONFIG_GPIO_LP3943=m +CONFIG_GPIO_LP873X=m +CONFIG_GPIO_LP87565=m +CONFIG_GPIO_MADERA=m +CONFIG_GPIO_MAX77620=m +CONFIG_GPIO_MAX77650=m +CONFIG_GPIO_PALMAS=y +CONFIG_GPIO_RC5T583=y +CONFIG_GPIO_STMPE=y +CONFIG_GPIO_TC3589X=y +CONFIG_GPIO_TPS65086=m +CONFIG_GPIO_TPS65218=m +CONFIG_GPIO_TPS6586X=y +CONFIG_GPIO_TPS65910=y +CONFIG_GPIO_TPS65912=m +CONFIG_GPIO_TWL4030=m +CONFIG_GPIO_TWL6040=m +CONFIG_GPIO_WM831X=m +CONFIG_GPIO_WM8350=m +CONFIG_GPIO_WM8994=m +CONFIG_GPIO_PCI_IDIO_16=m +CONFIG_GPIO_PCIE_IDIO_24=m +CONFIG_GPIO_RDC321X=m +CONFIG_GPIO_74X164=m +CONFIG_GPIO_MAX3191X=m +CONFIG_GPIO_MAX7301=m +CONFIG_GPIO_MC33880=m +CONFIG_GPIO_PISOSR=m +CONFIG_GPIO_XRA1403=m +CONFIG_GPIO_MOXTET=m +CONFIG_GPIO_VIPERBOARD=m +CONFIG_GPIO_AGGREGATOR=m +CONFIG_GPIO_VIRTIO=m +CONFIG_GPIO_SIM=m +CONFIG_W1_MASTER_MATROX=m +CONFIG_W1_MASTER_DS2490=m +CONFIG_W1_MASTER_DS2482=m +CONFIG_W1_MASTER_GPIO=m +CONFIG_W1_MASTER_SGI=m +CONFIG_W1_SLAVE_THERM=m +CONFIG_W1_SLAVE_SMEM=m +CONFIG_W1_SLAVE_DS2405=m +CONFIG_W1_SLAVE_DS2408=m +CONFIG_W1_SLAVE_DS2413=m +CONFIG_W1_SLAVE_DS2406=m +CONFIG_W1_SLAVE_DS2423=m +CONFIG_W1_SLAVE_DS2805=m +CONFIG_W1_SLAVE_DS2430=m +CONFIG_W1_SLAVE_DS2431=m +CONFIG_W1_SLAVE_DS2433=m +CONFIG_W1_SLAVE_DS2438=m +CONFIG_W1_SLAVE_DS250X=m +CONFIG_W1_SLAVE_DS28E04=m +CONFIG_W1_SLAVE_DS28E17=m +CONFIG_POWER_RESET_AS3722=y +CONFIG_POWER_RESET_ATC260X=m +CONFIG_POWER_RESET_GPIO=y +CONFIG_POWER_RESET_GPIO_RESTART=y +CONFIG_POWER_RESET_LTC2952=y +CONFIG_POWER_RESET_MT6323=y +CONFIG_POWER_RESET_REGULATOR=y +CONFIG_POWER_RESET_RESTART=y +CONFIG_POWER_RESET_TPS65086=y +CONFIG_SYSCON_REBOOT_MODE=m +CONFIG_NVMEM_REBOOT_MODE=m +CONFIG_GENERIC_ADC_BATTERY=m +CONFIG_IP5XXX_POWER=m +CONFIG_MAX8925_POWER=m +CONFIG_WM831X_BACKUP=m +CONFIG_WM831X_POWER=m +CONFIG_WM8350_POWER=m +CONFIG_TEST_POWER=m +CONFIG_BATTERY_88PM860X=m +CONFIG_CHARGER_ADP5061=m +CONFIG_BATTERY_ACT8945A=m +CONFIG_BATTERY_CW2015=m +CONFIG_BATTERY_DS2760=m +CONFIG_BATTERY_DS2780=m +CONFIG_BATTERY_DS2781=m +CONFIG_BATTERY_DS2782=m +CONFIG_BATTERY_SAMSUNG_SDI=y +CONFIG_BATTERY_SBS=m +CONFIG_CHARGER_SBS=m +CONFIG_MANAGER_SBS=m +CONFIG_BATTERY_BQ27XXX=m +CONFIG_BATTERY_DA9030=m +CONFIG_BATTERY_DA9052=m +CONFIG_CHARGER_DA9150=m +CONFIG_BATTERY_DA9150=m +CONFIG_CHARGER_AXP20X=m +CONFIG_BATTERY_AXP20X=m +CONFIG_AXP20X_POWER=m +CONFIG_BATTERY_MAX17040=m +CONFIG_BATTERY_MAX17042=m +CONFIG_BATTERY_MAX1721X=m +CONFIG_BATTERY_TWL4030_MADC=m +CONFIG_CHARGER_88PM860X=m +CONFIG_CHARGER_PCF50633=m +CONFIG_BATTERY_RX51=m +CONFIG_CHARGER_ISP1704=m +CONFIG_CHARGER_MAX8903=m +CONFIG_CHARGER_TWL4030=m +CONFIG_CHARGER_LP8727=m +CONFIG_CHARGER_LP8788=m +CONFIG_CHARGER_GPIO=m +CONFIG_CHARGER_MANAGER=y +CONFIG_CHARGER_LT3651=m +CONFIG_CHARGER_LTC4162L=m +CONFIG_CHARGER_MAX14577=m +CONFIG_CHARGER_DETECTOR_MAX14656=m +CONFIG_CHARGER_MAX77650=m +CONFIG_CHARGER_MAX77693=m +CONFIG_CHARGER_MAX77976=m +CONFIG_CHARGER_MAX8997=m +CONFIG_CHARGER_MAX8998=m +CONFIG_CHARGER_MP2629=m +CONFIG_CHARGER_MT6360=m +CONFIG_CHARGER_BQ2415X=m +CONFIG_CHARGER_BQ24190=m +CONFIG_CHARGER_BQ24257=m +CONFIG_CHARGER_BQ24735=m +CONFIG_CHARGER_BQ2515X=m +CONFIG_CHARGER_BQ25890=m +CONFIG_CHARGER_BQ25980=m +CONFIG_CHARGER_BQ256XX=m +CONFIG_CHARGER_SMB347=m +CONFIG_CHARGER_TPS65090=m +CONFIG_BATTERY_GAUGE_LTC2941=m +CONFIG_BATTERY_GOLDFISH=m +CONFIG_BATTERY_RT5033=m +CONFIG_CHARGER_RT9455=m +CONFIG_CHARGER_UCS1002=m +CONFIG_CHARGER_BD99954=m +CONFIG_RN5T618_POWER=m +CONFIG_BATTERY_UG3105=m +CONFIG_SENSORS_AD7314=m +CONFIG_SENSORS_AD7414=m +CONFIG_SENSORS_AD7418=m +CONFIG_SENSORS_ADM1025=m +CONFIG_SENSORS_ADM1026=m +CONFIG_SENSORS_ADM1029=m +CONFIG_SENSORS_ADM1031=m +CONFIG_SENSORS_ADM1177=m +CONFIG_SENSORS_ADM9240=m +CONFIG_SENSORS_ADT7310=m +CONFIG_SENSORS_ADT7410=m +CONFIG_SENSORS_ADT7411=m +CONFIG_SENSORS_ADT7462=m +CONFIG_SENSORS_ADT7470=m +CONFIG_SENSORS_ADT7475=m +CONFIG_SENSORS_AHT10=m +CONFIG_SENSORS_AQUACOMPUTER_D5NEXT=m +CONFIG_SENSORS_AS370=m +CONFIG_SENSORS_ASC7621=m +CONFIG_SENSORS_AXI_FAN_CONTROL=m +CONFIG_SENSORS_ATXP1=m +CONFIG_SENSORS_CORSAIR_CPRO=m +CONFIG_SENSORS_CORSAIR_PSU=m +CONFIG_SENSORS_DRIVETEMP=m +CONFIG_SENSORS_DS620=m +CONFIG_SENSORS_DS1621=m +CONFIG_SENSORS_DA9052_ADC=m +CONFIG_SENSORS_DA9055=m +CONFIG_SENSORS_I5K_AMB=m +CONFIG_SENSORS_F71805F=m +CONFIG_SENSORS_F71882FG=m +CONFIG_SENSORS_F75375S=m +CONFIG_SENSORS_GSC=m +CONFIG_SENSORS_MC13783_ADC=m +CONFIG_SENSORS_FTSTEUTATES=m +CONFIG_SENSORS_GL518SM=m +CONFIG_SENSORS_GL520SM=m +CONFIG_SENSORS_G760A=m +CONFIG_SENSORS_G762=m +CONFIG_SENSORS_GPIO_FAN=m +CONFIG_SENSORS_HIH6130=m +CONFIG_SENSORS_IBMAEM=m +CONFIG_SENSORS_IBMPEX=m +CONFIG_SENSORS_IIO_HWMON=m +CONFIG_SENSORS_IT87=m +CONFIG_SENSORS_JC42=m +CONFIG_SENSORS_POWR1220=m +CONFIG_SENSORS_LINEAGE=m +CONFIG_SENSORS_LOCHNAGAR=m +CONFIG_SENSORS_LTC2945=m +CONFIG_SENSORS_LTC2947_I2C=m +CONFIG_SENSORS_LTC2947_SPI=m +CONFIG_SENSORS_LTC2990=m +CONFIG_SENSORS_LTC2992=m +CONFIG_SENSORS_LTC4151=m +CONFIG_SENSORS_LTC4215=m +CONFIG_SENSORS_LTC4222=m +CONFIG_SENSORS_LTC4245=m +CONFIG_SENSORS_LTC4260=m +CONFIG_SENSORS_LTC4261=m +CONFIG_SENSORS_MAX1111=m +CONFIG_SENSORS_MAX127=m +CONFIG_SENSORS_MAX16065=m +CONFIG_SENSORS_MAX1619=m +CONFIG_SENSORS_MAX1668=m +CONFIG_SENSORS_MAX197=m +CONFIG_SENSORS_MAX31722=m +CONFIG_SENSORS_MAX31730=m +CONFIG_SENSORS_MAX6620=m +CONFIG_SENSORS_MAX6621=m +CONFIG_SENSORS_MAX6639=m +CONFIG_SENSORS_MAX6650=m +CONFIG_SENSORS_MAX6697=m +CONFIG_SENSORS_MAX31790=m +CONFIG_SENSORS_MCP3021=m +CONFIG_SENSORS_TC654=m +CONFIG_SENSORS_TPS23861=m +CONFIG_SENSORS_MENF21BMC_HWMON=m +CONFIG_SENSORS_MR75203=m +CONFIG_SENSORS_ADCXX=m +CONFIG_SENSORS_LM63=m +CONFIG_SENSORS_LM70=m +CONFIG_SENSORS_LM73=m +CONFIG_SENSORS_LM75=m +CONFIG_SENSORS_LM77=m +CONFIG_SENSORS_LM78=m +CONFIG_SENSORS_LM80=m +CONFIG_SENSORS_LM83=m +CONFIG_SENSORS_LM85=m +CONFIG_SENSORS_LM87=m +CONFIG_SENSORS_LM90=m +CONFIG_SENSORS_LM92=m +CONFIG_SENSORS_LM93=m +CONFIG_SENSORS_LM95234=m +CONFIG_SENSORS_LM95241=m +CONFIG_SENSORS_LM95245=m +CONFIG_SENSORS_PC87360=m +CONFIG_SENSORS_PC87427=m +CONFIG_SENSORS_NTC_THERMISTOR=m +CONFIG_SENSORS_NCT6683=m +CONFIG_SENSORS_NCT6775_I2C=m +CONFIG_SENSORS_NCT7802=m +CONFIG_SENSORS_NCT7904=m +CONFIG_SENSORS_NPCM7XX=m +CONFIG_SENSORS_NZXT_KRAKEN2=m +CONFIG_SENSORS_NZXT_SMART2=m +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_PECI_CPUTEMP=m +CONFIG_SENSORS_PECI_DIMMTEMP=m +CONFIG_PMBUS=m +CONFIG_SENSORS_ADM1266=m +CONFIG_SENSORS_ADM1275=m +CONFIG_SENSORS_BEL_PFE=m +CONFIG_SENSORS_BPA_RS600=m +CONFIG_SENSORS_DELTA_AHE50DC_FAN=m +CONFIG_SENSORS_FSP_3Y=m +CONFIG_SENSORS_IBM_CFFPS=m +CONFIG_SENSORS_DPS920AB=m +CONFIG_SENSORS_INSPUR_IPSPS=m +CONFIG_SENSORS_IR35221=m +CONFIG_SENSORS_IR36021=m +CONFIG_SENSORS_IR38064=m +CONFIG_SENSORS_IR38064_REGULATOR=y +CONFIG_SENSORS_IRPS5401=m +CONFIG_SENSORS_ISL68137=m +CONFIG_SENSORS_LM25066=m +CONFIG_SENSORS_LM25066_REGULATOR=y +CONFIG_SENSORS_LTC2978=m +CONFIG_SENSORS_LTC2978_REGULATOR=y +CONFIG_SENSORS_LTC3815=m +CONFIG_SENSORS_MAX15301=m +CONFIG_SENSORS_MAX16064=m +CONFIG_SENSORS_MAX16601=m +CONFIG_SENSORS_MAX20730=m +CONFIG_SENSORS_MAX20751=m +CONFIG_SENSORS_MAX31785=m +CONFIG_SENSORS_MAX34440=m +CONFIG_SENSORS_MAX8688=m +CONFIG_SENSORS_MP2888=m +CONFIG_SENSORS_MP2975=m +CONFIG_SENSORS_MP5023=m +CONFIG_SENSORS_PIM4328=m +CONFIG_SENSORS_PLI1209BC=m +CONFIG_SENSORS_PLI1209BC_REGULATOR=y +CONFIG_SENSORS_PM6764TR=m +CONFIG_SENSORS_PXE1610=m +CONFIG_SENSORS_Q54SJ108A2=m +CONFIG_SENSORS_STPDDC60=m +CONFIG_SENSORS_TPS40422=m +CONFIG_SENSORS_TPS53679=m +CONFIG_SENSORS_UCD9000=m +CONFIG_SENSORS_UCD9200=m +CONFIG_SENSORS_XDPE152=m +CONFIG_SENSORS_XDPE122=m +CONFIG_SENSORS_XDPE122_REGULATOR=y +CONFIG_SENSORS_ZL6100=m +CONFIG_SENSORS_PWM_FAN=m +CONFIG_SENSORS_SBTSI=m +CONFIG_SENSORS_SBRMI=m +CONFIG_SENSORS_SHT15=m +CONFIG_SENSORS_SHT21=m +CONFIG_SENSORS_SHT3x=m +CONFIG_SENSORS_SHT4x=m +CONFIG_SENSORS_SHTC1=m +CONFIG_SENSORS_SIS5595=m +CONFIG_SENSORS_DME1737=m +CONFIG_SENSORS_EMC1403=m +CONFIG_SENSORS_EMC2103=m +CONFIG_SENSORS_EMC6W201=m +CONFIG_SENSORS_SMSC47M1=m +CONFIG_SENSORS_SMSC47M192=m +CONFIG_SENSORS_SMSC47B397=m +CONFIG_SENSORS_SCH5627=m +CONFIG_SENSORS_SCH5636=m +CONFIG_SENSORS_STTS751=m +CONFIG_SENSORS_SMM665=m +CONFIG_SENSORS_ADC128D818=m +CONFIG_SENSORS_ADS7828=m +CONFIG_SENSORS_ADS7871=m +CONFIG_SENSORS_AMC6821=m +CONFIG_SENSORS_INA209=m +CONFIG_SENSORS_INA2XX=m +CONFIG_SENSORS_INA238=m +CONFIG_SENSORS_INA3221=m +CONFIG_SENSORS_TC74=m +CONFIG_SENSORS_THMC50=m +CONFIG_SENSORS_TMP102=m +CONFIG_SENSORS_TMP103=m +CONFIG_SENSORS_TMP108=m +CONFIG_SENSORS_TMP401=m +CONFIG_SENSORS_TMP421=m +CONFIG_SENSORS_TMP464=m +CONFIG_SENSORS_TMP513=m +CONFIG_SENSORS_VIA686A=m +CONFIG_SENSORS_VT1211=m +CONFIG_SENSORS_VT8231=m +CONFIG_SENSORS_W83773G=m +CONFIG_SENSORS_W83781D=m +CONFIG_SENSORS_W83791D=m +CONFIG_SENSORS_W83792D=m +CONFIG_SENSORS_W83793=m +CONFIG_SENSORS_W83795=m +CONFIG_SENSORS_W83L785TS=m +CONFIG_SENSORS_W83L786NG=m +CONFIG_SENSORS_W83627HF=m +CONFIG_SENSORS_W83627EHF=m +CONFIG_SENSORS_WM831X=m +CONFIG_SENSORS_WM8350=m +CONFIG_THERMAL_NETLINK=y +CONFIG_THERMAL_STATISTICS=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_GOV_FAIR_SHARE=y +CONFIG_THERMAL_GOV_BANG_BANG=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_CPU_THERMAL=y +CONFIG_CPU_IDLE_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_THERMAL_EMULATION=y +CONFIG_THERMAL_MMIO=m +CONFIG_MAX77620_THERMAL=m +CONFIG_DA9062_THERMAL=m +CONFIG_GENERIC_ADC_THERMAL=m +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_CORE=y +CONFIG_WATCHDOG_SYSFS=y +CONFIG_WATCHDOG_PRETIMEOUT_GOV=y +CONFIG_WATCHDOG_PRETIMEOUT_GOV_PANIC=m +CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_NOOP=y +CONFIG_SOFT_WATCHDOG=m +CONFIG_SOFT_WATCHDOG_PRETIMEOUT=y +CONFIG_BD957XMUF_WATCHDOG=m +CONFIG_DA9052_WATCHDOG=m +CONFIG_DA9055_WATCHDOG=m +CONFIG_DA9063_WATCHDOG=m +CONFIG_DA9062_WATCHDOG=m +CONFIG_GPIO_WATCHDOG=m +CONFIG_MENF21BMC_WATCHDOG=m +CONFIG_MENZ069_WATCHDOG=m +CONFIG_WM831X_WATCHDOG=m +CONFIG_WM8350_WATCHDOG=m +CONFIG_XILINX_WATCHDOG=m +CONFIG_ZIIRAVE_WATCHDOG=m +CONFIG_RAVE_SP_WATCHDOG=m +CONFIG_CADENCE_WATCHDOG=m +CONFIG_DW_WATCHDOG=m +CONFIG_RN5T618_WATCHDOG=m +CONFIG_TWL4030_WATCHDOG=m +CONFIG_MAX63XX_WATCHDOG=m +CONFIG_MAX77620_WATCHDOG=m +CONFIG_RETU_WATCHDOG=m +CONFIG_STPMIC1_WATCHDOG=m +CONFIG_ALIM7101_WDT=m +CONFIG_I6300ESB_WDT=m +CONFIG_KEMPLD_WDT=m +CONFIG_MEN_A21_WDT=m +CONFIG_PCIPCWATCHDOG=m +CONFIG_WDTPCI=m +CONFIG_USBPCWATCHDOG=m +CONFIG_SSB_SDIOHOST=y +CONFIG_SSB_DRIVER_GPIO=y +CONFIG_BCMA_HOST_SOC=y +CONFIG_BCMA_DRIVER_GMAC_CMN=y +CONFIG_BCMA_DRIVER_GPIO=y +CONFIG_MFD_ACT8945A=m +CONFIG_MFD_AS3711=y +CONFIG_MFD_AS3722=y +CONFIG_PMIC_ADP5520=y +CONFIG_MFD_AAT2870_CORE=y +CONFIG_MFD_ATMEL_FLEXCOM=m +CONFIG_MFD_ATMEL_HLCDC=m +CONFIG_MFD_BCM590XX=m +CONFIG_MFD_BD9571MWV=m +CONFIG_MFD_AXP20X_I2C=m +CONFIG_MFD_MADERA=m +CONFIG_MFD_MADERA_I2C=m +CONFIG_MFD_MADERA_SPI=m +CONFIG_MFD_CS47L15=y +CONFIG_MFD_CS47L35=y +CONFIG_MFD_CS47L85=y +CONFIG_MFD_CS47L90=y +CONFIG_MFD_CS47L92=y +CONFIG_PMIC_DA903X=y +CONFIG_MFD_DA9052_SPI=y +CONFIG_MFD_DA9052_I2C=y +CONFIG_MFD_DA9055=y +CONFIG_MFD_DA9062=m +CONFIG_MFD_DA9063=y +CONFIG_MFD_DA9150=m +CONFIG_MFD_DLN2=m +CONFIG_MFD_GATEWORKS_GSC=m +CONFIG_MFD_MC13XXX_SPI=m +CONFIG_MFD_MC13XXX_I2C=m +CONFIG_MFD_MP2629=m +CONFIG_MFD_HI6421_PMIC=m +CONFIG_MFD_HI6421_SPMI=m +CONFIG_LPC_ICH=m +CONFIG_MFD_IQS62X=m +CONFIG_MFD_JANZ_CMODIO=m +CONFIG_MFD_KEMPLD=m +CONFIG_MFD_88PM800=m +CONFIG_MFD_88PM805=m +CONFIG_MFD_88PM860X=y +CONFIG_MFD_MAX14577=y +CONFIG_MFD_MAX77620=y +CONFIG_MFD_MAX77650=m +CONFIG_MFD_MAX77686=y +CONFIG_MFD_MAX77693=y +CONFIG_MFD_MAX77714=m +CONFIG_MFD_MAX77843=y +CONFIG_MFD_MAX8907=m +CONFIG_MFD_MAX8925=y +CONFIG_MFD_MAX8997=y +CONFIG_MFD_MAX8998=y +CONFIG_MFD_MT6360=m +CONFIG_MFD_MT6397=m +CONFIG_MFD_MENF21BMC=m +CONFIG_EZX_PCAP=y +CONFIG_MFD_CPCAP=m +CONFIG_MFD_VIPERBOARD=m +CONFIG_MFD_NTXEC=m +CONFIG_MFD_RETU=m +CONFIG_MFD_PCF50633=m +CONFIG_PCF50633_ADC=m +CONFIG_PCF50633_GPIO=m +CONFIG_MFD_RT4831=m +CONFIG_MFD_RT5033=m +CONFIG_MFD_RC5T583=y +CONFIG_MFD_RK808=m +CONFIG_MFD_RN5T618=m +CONFIG_MFD_SEC_CORE=y +CONFIG_MFD_SI476X_CORE=m +CONFIG_MFD_SM501=m +CONFIG_MFD_SM501_GPIO=y +CONFIG_MFD_SKY81452=m +CONFIG_MFD_STMPE=y +CONFIG_STMPE_SPI=y +CONFIG_MFD_TI_AM335X_TSCADC=m +CONFIG_MFD_LP3943=m +CONFIG_MFD_LP8788=y +CONFIG_MFD_TI_LMU=m +CONFIG_MFD_PALMAS=y +CONFIG_TPS6105X=m +CONFIG_TPS65010=m +CONFIG_TPS6507X=m +CONFIG_MFD_TPS65086=m +CONFIG_MFD_TPS65090=y +CONFIG_MFD_TI_LP873X=m +CONFIG_MFD_TI_LP87565=m +CONFIG_MFD_TPS65218=m +CONFIG_MFD_TPS6586X=y +CONFIG_MFD_TPS65910=y +CONFIG_MFD_TPS65912_I2C=y +CONFIG_MFD_TPS65912_SPI=y +CONFIG_TWL4030_CORE=y +CONFIG_TWL6040_CORE=y +CONFIG_MFD_LM3533=m +CONFIG_MFD_TC3589X=y +CONFIG_MFD_VX855=m +CONFIG_MFD_LOCHNAGAR=y +CONFIG_MFD_ARIZONA_I2C=m +CONFIG_MFD_ARIZONA_SPI=m +CONFIG_MFD_CS47L24=y +CONFIG_MFD_WM5102=y +CONFIG_MFD_WM5110=y +CONFIG_MFD_WM8997=y +CONFIG_MFD_WM8998=y +CONFIG_MFD_WM8400=y +CONFIG_MFD_WM831X_I2C=y +CONFIG_MFD_WM831X_SPI=y +CONFIG_MFD_WM8350_I2C=y +CONFIG_MFD_WM8994=m +CONFIG_MFD_ROHM_BD718XX=m +CONFIG_MFD_ROHM_BD71828=m +CONFIG_MFD_ROHM_BD957XMUF=m +CONFIG_MFD_STPMIC1=m +CONFIG_MFD_WCD934X=m +CONFIG_MFD_ATC260X_I2C=m +CONFIG_MFD_QCOM_PM8008=m +CONFIG_RAVE_SP_CORE=m +CONFIG_MFD_RSMU_I2C=m +CONFIG_MFD_RSMU_SPI=m +CONFIG_REGULATOR_VIRTUAL_CONSUMER=m +CONFIG_REGULATOR_USERSPACE_CONSUMER=m +CONFIG_REGULATOR_88PG86X=m +CONFIG_REGULATOR_88PM800=m +CONFIG_REGULATOR_88PM8607=m +CONFIG_REGULATOR_ACT8865=m +CONFIG_REGULATOR_ACT8945A=m +CONFIG_REGULATOR_AD5398=m +CONFIG_REGULATOR_AAT2870=m +CONFIG_REGULATOR_ARIZONA_LDO1=m +CONFIG_REGULATOR_ARIZONA_MICSUPP=m +CONFIG_REGULATOR_AS3711=m +CONFIG_REGULATOR_AS3722=m +CONFIG_REGULATOR_ATC260X=m +CONFIG_REGULATOR_AXP20X=m +CONFIG_REGULATOR_BCM590XX=m +CONFIG_REGULATOR_BD71815=m +CONFIG_REGULATOR_BD71828=m +CONFIG_REGULATOR_BD718XX=m +CONFIG_REGULATOR_BD9571MWV=m +CONFIG_REGULATOR_BD957XMUF=m +CONFIG_REGULATOR_CPCAP=m +CONFIG_REGULATOR_DA903X=m +CONFIG_REGULATOR_DA9052=m +CONFIG_REGULATOR_DA9055=m +CONFIG_REGULATOR_DA9062=m +CONFIG_REGULATOR_DA9063=m +CONFIG_REGULATOR_DA9121=m +CONFIG_REGULATOR_DA9210=m +CONFIG_REGULATOR_DA9211=m +CONFIG_REGULATOR_FAN53555=m +CONFIG_REGULATOR_FAN53880=m +CONFIG_REGULATOR_GPIO=m +CONFIG_REGULATOR_HI6421=m +CONFIG_REGULATOR_HI6421V530=m +CONFIG_REGULATOR_HI6421V600=m +CONFIG_REGULATOR_ISL9305=m +CONFIG_REGULATOR_ISL6271A=m +CONFIG_REGULATOR_LM363X=m +CONFIG_REGULATOR_LOCHNAGAR=m +CONFIG_REGULATOR_LP3971=m +CONFIG_REGULATOR_LP3972=m +CONFIG_REGULATOR_LP872X=m +CONFIG_REGULATOR_LP873X=m +CONFIG_REGULATOR_LP8755=m +CONFIG_REGULATOR_LP87565=m +CONFIG_REGULATOR_LP8788=m +CONFIG_REGULATOR_LTC3589=m +CONFIG_REGULATOR_LTC3676=m +CONFIG_REGULATOR_MAX14577=m +CONFIG_REGULATOR_MAX1586=m +CONFIG_REGULATOR_MAX77620=m +CONFIG_REGULATOR_MAX77650=m +CONFIG_REGULATOR_MAX8649=m +CONFIG_REGULATOR_MAX8660=m +CONFIG_REGULATOR_MAX8893=m +CONFIG_REGULATOR_MAX8907=m +CONFIG_REGULATOR_MAX8925=m +CONFIG_REGULATOR_MAX8952=m +CONFIG_REGULATOR_MAX8973=m +CONFIG_REGULATOR_MAX8997=m +CONFIG_REGULATOR_MAX8998=m +CONFIG_REGULATOR_MAX20086=m +CONFIG_REGULATOR_MAX77686=m +CONFIG_REGULATOR_MAX77693=m +CONFIG_REGULATOR_MAX77802=m +CONFIG_REGULATOR_MAX77826=m +CONFIG_REGULATOR_MC13783=m +CONFIG_REGULATOR_MC13892=m +CONFIG_REGULATOR_MCP16502=m +CONFIG_REGULATOR_MP5416=m +CONFIG_REGULATOR_MP8859=m +CONFIG_REGULATOR_MP886X=m +CONFIG_REGULATOR_MPQ7920=m +CONFIG_REGULATOR_MT6311=m +CONFIG_REGULATOR_MT6315=m +CONFIG_REGULATOR_MT6323=m +CONFIG_REGULATOR_MT6358=m +CONFIG_REGULATOR_MT6359=m +CONFIG_REGULATOR_MT6360=m +CONFIG_REGULATOR_MT6397=m +CONFIG_REGULATOR_PALMAS=m +CONFIG_REGULATOR_PCA9450=m +CONFIG_REGULATOR_PCAP=m +CONFIG_REGULATOR_PCF50633=m +CONFIG_REGULATOR_PF8X00=m +CONFIG_REGULATOR_PFUZE100=m +CONFIG_REGULATOR_PV88060=m +CONFIG_REGULATOR_PV88080=m +CONFIG_REGULATOR_PV88090=m +CONFIG_REGULATOR_PWM=m +CONFIG_REGULATOR_QCOM_SPMI=m +CONFIG_REGULATOR_QCOM_USB_VBUS=m +CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY=m +CONFIG_REGULATOR_RC5T583=m +CONFIG_REGULATOR_RK808=m +CONFIG_REGULATOR_RN5T618=m +CONFIG_REGULATOR_RT4801=m +CONFIG_REGULATOR_RT4831=m +CONFIG_REGULATOR_RT5033=m +CONFIG_REGULATOR_RT5190A=m +CONFIG_REGULATOR_RT5759=m +CONFIG_REGULATOR_RT6160=m +CONFIG_REGULATOR_RT6245=m +CONFIG_REGULATOR_RTQ2134=m +CONFIG_REGULATOR_RTMV20=m +CONFIG_REGULATOR_RTQ6752=m +CONFIG_REGULATOR_S2MPA01=m +CONFIG_REGULATOR_S2MPS11=m +CONFIG_REGULATOR_S5M8767=m +CONFIG_REGULATOR_SKY81452=m +CONFIG_REGULATOR_SLG51000=m +CONFIG_REGULATOR_STPMIC1=m +CONFIG_REGULATOR_SY8106A=m +CONFIG_REGULATOR_SY8824X=m +CONFIG_REGULATOR_SY8827N=m +CONFIG_REGULATOR_TPS51632=m +CONFIG_REGULATOR_TPS62360=m +CONFIG_REGULATOR_TPS6286X=m +CONFIG_REGULATOR_TPS65023=m +CONFIG_REGULATOR_TPS6507X=m +CONFIG_REGULATOR_TPS65086=m +CONFIG_REGULATOR_TPS65090=m +CONFIG_REGULATOR_TPS65132=m +CONFIG_REGULATOR_TPS65218=m +CONFIG_REGULATOR_TPS6524X=m +CONFIG_REGULATOR_TPS6586X=m +CONFIG_REGULATOR_TPS65910=m +CONFIG_REGULATOR_TPS65912=m +CONFIG_REGULATOR_TWL4030=m +CONFIG_REGULATOR_VCTRL=m +CONFIG_REGULATOR_WM831X=m +CONFIG_REGULATOR_WM8350=m +CONFIG_REGULATOR_WM8400=m +CONFIG_REGULATOR_WM8994=m +CONFIG_REGULATOR_QCOM_LABIBB=m +CONFIG_RC_CORE=m +CONFIG_LIRC=y +CONFIG_RC_DECODERS=y +CONFIG_IR_IMON_DECODER=m +CONFIG_IR_JVC_DECODER=m +CONFIG_IR_MCE_KBD_DECODER=m +CONFIG_IR_NEC_DECODER=m +CONFIG_IR_RC5_DECODER=m +CONFIG_IR_RC6_DECODER=m +CONFIG_IR_RCMM_DECODER=m +CONFIG_IR_SANYO_DECODER=m +CONFIG_IR_SHARP_DECODER=m +CONFIG_IR_SONY_DECODER=m +CONFIG_IR_XMP_DECODER=m +CONFIG_RC_DEVICES=y +CONFIG_IR_GPIO_CIR=m +CONFIG_IR_GPIO_TX=m +CONFIG_IR_HIX5HD2=m +CONFIG_IR_IGORPLUGUSB=m +CONFIG_IR_IGUANA=m +CONFIG_IR_IMON=m +CONFIG_IR_IMON_RAW=m +CONFIG_IR_MCEUSB=m +CONFIG_IR_PWM_TX=m +CONFIG_IR_REDRAT3=m +CONFIG_IR_SERIAL=m +CONFIG_IR_SERIAL_TRANSMITTER=y +CONFIG_IR_SPI=m +CONFIG_IR_STREAMZAP=m +CONFIG_IR_TOY=m +CONFIG_IR_TTUSBIR=m +CONFIG_RC_ATI_REMOTE=m +CONFIG_RC_LOOPBACK=m +CONFIG_RC_XBOX_DVD=m +CONFIG_MEDIA_CEC_RC=y +CONFIG_MEDIA_CEC_SUPPORT=y +CONFIG_CEC_CH7322=m +CONFIG_USB_PULSE8_CEC=m +CONFIG_USB_RAINSHADOW_CEC=m +CONFIG_MEDIA_SUPPORT=m +CONFIG_MEDIA_SUPPORT_FILTER=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_ANALOG_TV_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_RADIO_SUPPORT=y +CONFIG_MEDIA_SDR_SUPPORT=y +CONFIG_MEDIA_PLATFORM_SUPPORT=y +CONFIG_MEDIA_TEST_SUPPORT=y +CONFIG_V4L2_FLASH_LED_CLASS=m +CONFIG_DVB_MAX_ADAPTERS=8 +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_USB_GSPCA=m +CONFIG_USB_GSPCA_BENQ=m +CONFIG_USB_GSPCA_CONEX=m +CONFIG_USB_GSPCA_CPIA1=m +CONFIG_USB_GSPCA_DTCS033=m +CONFIG_USB_GSPCA_ETOMS=m +CONFIG_USB_GSPCA_FINEPIX=m +CONFIG_USB_GSPCA_JEILINJ=m +CONFIG_USB_GSPCA_JL2005BCD=m +CONFIG_USB_GSPCA_KINECT=m +CONFIG_USB_GSPCA_KONICA=m +CONFIG_USB_GSPCA_MARS=m +CONFIG_USB_GSPCA_MR97310A=m +CONFIG_USB_GSPCA_NW80X=m +CONFIG_USB_GSPCA_OV519=m +CONFIG_USB_GSPCA_OV534=m +CONFIG_USB_GSPCA_OV534_9=m +CONFIG_USB_GSPCA_PAC207=m +CONFIG_USB_GSPCA_PAC7302=m +CONFIG_USB_GSPCA_PAC7311=m +CONFIG_USB_GSPCA_SE401=m +CONFIG_USB_GSPCA_SN9C2028=m +CONFIG_USB_GSPCA_SN9C20X=m +CONFIG_USB_GSPCA_SONIXB=m +CONFIG_USB_GSPCA_SONIXJ=m +CONFIG_USB_GSPCA_SPCA1528=m +CONFIG_USB_GSPCA_SPCA500=m +CONFIG_USB_GSPCA_SPCA501=m +CONFIG_USB_GSPCA_SPCA505=m +CONFIG_USB_GSPCA_SPCA506=m +CONFIG_USB_GSPCA_SPCA508=m +CONFIG_USB_GSPCA_SPCA561=m +CONFIG_USB_GSPCA_SQ905=m +CONFIG_USB_GSPCA_SQ905C=m +CONFIG_USB_GSPCA_SQ930X=m +CONFIG_USB_GSPCA_STK014=m +CONFIG_USB_GSPCA_STK1135=m +CONFIG_USB_GSPCA_STV0680=m +CONFIG_USB_GSPCA_SUNPLUS=m +CONFIG_USB_GSPCA_T613=m +CONFIG_USB_GSPCA_TOPRO=m +CONFIG_USB_GSPCA_TOUPTEK=m +CONFIG_USB_GSPCA_TV8532=m +CONFIG_USB_GSPCA_VC032X=m +CONFIG_USB_GSPCA_VICAM=m +CONFIG_USB_GSPCA_XIRLINK_CIT=m +CONFIG_USB_GSPCA_ZC3XX=m +CONFIG_USB_GL860=m +CONFIG_USB_M5602=m +CONFIG_USB_STV06XX=m +CONFIG_USB_PWC=m +CONFIG_USB_S2255=m +CONFIG_VIDEO_USBTV=m +CONFIG_USB_VIDEO_CLASS=m +CONFIG_VIDEO_GO7007=m +CONFIG_VIDEO_GO7007_USB=m +CONFIG_VIDEO_GO7007_USB_S2250_BOARD=m +CONFIG_VIDEO_HDPVR=m +CONFIG_VIDEO_PVRUSB2=m +CONFIG_VIDEO_STK1160_COMMON=m +CONFIG_VIDEO_AU0828=m +CONFIG_VIDEO_AU0828_RC=y +CONFIG_VIDEO_CX231XX=m +CONFIG_VIDEO_CX231XX_ALSA=m +CONFIG_VIDEO_CX231XX_DVB=m +CONFIG_DVB_AS102=m +CONFIG_DVB_B2C2_FLEXCOP_USB=m +CONFIG_DVB_USB_V2=m +CONFIG_DVB_USB_AF9015=m +CONFIG_DVB_USB_AF9035=m +CONFIG_DVB_USB_ANYSEE=m +CONFIG_DVB_USB_AU6610=m +CONFIG_DVB_USB_AZ6007=m +CONFIG_DVB_USB_CE6230=m +CONFIG_DVB_USB_DVBSKY=m +CONFIG_DVB_USB_EC168=m +CONFIG_DVB_USB_GL861=m +CONFIG_DVB_USB_LME2510=m +CONFIG_DVB_USB_MXL111SF=m +CONFIG_DVB_USB_RTL28XXU=m +CONFIG_DVB_USB_ZD1301=m +CONFIG_DVB_USB=m +CONFIG_DVB_USB_A800=m +CONFIG_DVB_USB_AF9005=m +CONFIG_DVB_USB_AF9005_REMOTE=m +CONFIG_DVB_USB_AZ6027=m +CONFIG_DVB_USB_CINERGY_T2=m +CONFIG_DVB_USB_CXUSB=m +CONFIG_DVB_USB_CXUSB_ANALOG=y +CONFIG_DVB_USB_DIB0700=m +CONFIG_DVB_USB_DIBUSB_MB=m +CONFIG_DVB_USB_DIBUSB_MC=m +CONFIG_DVB_USB_DIGITV=m +CONFIG_DVB_USB_DTT200U=m +CONFIG_DVB_USB_DTV5100=m +CONFIG_DVB_USB_DW2102=m +CONFIG_DVB_USB_GP8PSK=m +CONFIG_DVB_USB_M920X=m +CONFIG_DVB_USB_NOVA_T_USB2=m +CONFIG_DVB_USB_OPERA1=m +CONFIG_DVB_USB_PCTV452E=m +CONFIG_DVB_USB_TECHNISAT_USB2=m +CONFIG_DVB_USB_TTUSB2=m +CONFIG_DVB_USB_UMT_010=m +CONFIG_DVB_USB_VP702X=m +CONFIG_DVB_USB_VP7045=m +CONFIG_SMS_USB_DRV=m +CONFIG_DVB_TTUSB_BUDGET=m +CONFIG_DVB_TTUSB_DEC=m +CONFIG_VIDEO_EM28XX=m +CONFIG_VIDEO_EM28XX_V4L2=m +CONFIG_VIDEO_EM28XX_ALSA=m +CONFIG_VIDEO_EM28XX_DVB=m +CONFIG_USB_AIRSPY=m +CONFIG_USB_HACKRF=m +CONFIG_USB_MSI2500=m +CONFIG_MEDIA_PCI_SUPPORT=y +CONFIG_VIDEO_SOLO6X10=m +CONFIG_VIDEO_TW5864=m +CONFIG_VIDEO_TW68=m +CONFIG_VIDEO_TW686X=m +CONFIG_VIDEO_DT3155=m +CONFIG_VIDEO_IVTV=m +CONFIG_VIDEO_IVTV_ALSA=m +CONFIG_VIDEO_FB_IVTV=m +CONFIG_VIDEO_BT848=m +CONFIG_DVB_BT8XX=m +CONFIG_VIDEO_CX18=m +CONFIG_VIDEO_CX18_ALSA=m +CONFIG_VIDEO_CX23885=m +CONFIG_MEDIA_ALTERA_CI=m +CONFIG_VIDEO_CX25821=m +CONFIG_VIDEO_CX25821_ALSA=m +CONFIG_VIDEO_CX88=m +CONFIG_VIDEO_CX88_ALSA=m +CONFIG_VIDEO_CX88_BLACKBIRD=m +CONFIG_VIDEO_CX88_DVB=m +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_SAA7134_ALSA=m +CONFIG_VIDEO_SAA7134_DVB=m +CONFIG_VIDEO_SAA7134_GO7007=m +CONFIG_VIDEO_SAA7164=m +CONFIG_DVB_B2C2_FLEXCOP_PCI=m +CONFIG_DVB_DDBRIDGE=m +CONFIG_DVB_DM1105=m +CONFIG_MANTIS_CORE=m +CONFIG_DVB_MANTIS=m +CONFIG_DVB_HOPPER=m +CONFIG_DVB_NETUP_UNIDVB=m +CONFIG_DVB_NGENE=m +CONFIG_DVB_PLUTO2=m +CONFIG_DVB_PT1=m +CONFIG_DVB_PT3=m +CONFIG_DVB_SMIPCIE=m +CONFIG_RADIO_MAXIRADIO=m +CONFIG_RADIO_SAA7706H=m +CONFIG_RADIO_SHARK=m +CONFIG_RADIO_SHARK2=m +CONFIG_RADIO_SI4713=m +CONFIG_RADIO_SI476X=m +CONFIG_RADIO_TEA5764=m +CONFIG_RADIO_TEF6862=m +CONFIG_RADIO_WL1273=m +CONFIG_USB_DSBR=m +CONFIG_USB_KEENE=m +CONFIG_USB_MA901=m +CONFIG_USB_MR800=m +CONFIG_USB_RAREMONO=m +CONFIG_RADIO_SI470X=m +CONFIG_USB_SI470X=m +CONFIG_I2C_SI470X=m +CONFIG_USB_SI4713=m +CONFIG_PLATFORM_SI4713=m +CONFIG_RADIO_WL128X=m +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_SDR_PLATFORM_DRIVERS=y +CONFIG_DVB_PLATFORM_DRIVERS=y +CONFIG_V4L_MEM2MEM_DRIVERS=y +CONFIG_VIDEO_MEM2MEM_DEINTERLACE=m +CONFIG_VIDEO_MUX=m +CONFIG_VIDEO_CADENCE_CSI2RX=m +CONFIG_VIDEO_CADENCE_CSI2TX=m +CONFIG_VIDEO_CAFE_CCIC=m +CONFIG_VIDEO_XILINX=m +CONFIG_VIDEO_XILINX_CSI2RXSS=m +CONFIG_VIDEO_XILINX_TPG=m +CONFIG_SMS_SDIO_DRV=m +CONFIG_V4L_TEST_DRIVERS=y +CONFIG_VIDEO_VIM2M=m +CONFIG_VIDEO_VICODEC=m +CONFIG_VIDEO_VIMC=m +CONFIG_VIDEO_VIVID=m +CONFIG_VIDEO_VIVID_CEC=y +CONFIG_DVB_FIREDTV=m +CONFIG_SMS_SIANO_DEBUGFS=y +CONFIG_VIDEO_HI556=m +CONFIG_VIDEO_HI846=m +CONFIG_VIDEO_HI847=m +CONFIG_VIDEO_IMX208=m +CONFIG_VIDEO_IMX214=m +CONFIG_VIDEO_IMX219=m +CONFIG_VIDEO_IMX258=m +CONFIG_VIDEO_IMX274=m +CONFIG_VIDEO_IMX290=m +CONFIG_VIDEO_IMX319=m +CONFIG_VIDEO_IMX334=m +CONFIG_VIDEO_IMX335=m +CONFIG_VIDEO_IMX355=m +CONFIG_VIDEO_IMX412=m +CONFIG_VIDEO_MT9M001=m +CONFIG_VIDEO_MT9M032=m +CONFIG_VIDEO_MT9M111=m +CONFIG_VIDEO_MT9P031=m +CONFIG_VIDEO_MT9T001=m +CONFIG_VIDEO_MT9T112=m +CONFIG_VIDEO_MT9V032=m +CONFIG_VIDEO_MT9V111=m +CONFIG_VIDEO_NOON010PC30=m +CONFIG_VIDEO_OG01A1B=m +CONFIG_VIDEO_OV02A10=m +CONFIG_VIDEO_OV08D10=m +CONFIG_VIDEO_OV13858=m +CONFIG_VIDEO_OV13B10=m +CONFIG_VIDEO_OV2659=m +CONFIG_VIDEO_OV2680=m +CONFIG_VIDEO_OV2685=m +CONFIG_VIDEO_OV5640=m +CONFIG_VIDEO_OV5645=m +CONFIG_VIDEO_OV5647=m +CONFIG_VIDEO_OV5670=m +CONFIG_VIDEO_OV5675=m +CONFIG_VIDEO_OV5693=m +CONFIG_VIDEO_OV5695=m +CONFIG_VIDEO_OV6650=m +CONFIG_VIDEO_OV7251=m +CONFIG_VIDEO_OV772X=m +CONFIG_VIDEO_OV7740=m +CONFIG_VIDEO_OV8856=m +CONFIG_VIDEO_OV9282=m +CONFIG_VIDEO_OV9640=m +CONFIG_VIDEO_OV9650=m +CONFIG_VIDEO_RDACM20=m +CONFIG_VIDEO_RDACM21=m +CONFIG_VIDEO_RJ54N1=m +CONFIG_VIDEO_S5C73M3=m +CONFIG_VIDEO_S5K5BAF=m +CONFIG_VIDEO_S5K6A3=m +CONFIG_VIDEO_S5K6AA=m +CONFIG_VIDEO_SR030PC30=m +CONFIG_VIDEO_VS6624=m +CONFIG_VIDEO_CCS=m +CONFIG_VIDEO_ET8EK8=m +CONFIG_VIDEO_M5MOLS=m +CONFIG_VIDEO_AD5820=m +CONFIG_VIDEO_AK7375=m +CONFIG_VIDEO_DW9714=m +CONFIG_VIDEO_DW9768=m +CONFIG_VIDEO_DW9807_VCM=m +CONFIG_VIDEO_ADP1653=m +CONFIG_VIDEO_LM3560=m +CONFIG_VIDEO_LM3646=m +CONFIG_VIDEO_TDA1997X=m +CONFIG_VIDEO_TDA9840=m +CONFIG_VIDEO_TEA6415C=m +CONFIG_VIDEO_TEA6420=m +CONFIG_VIDEO_TLV320AIC23B=m +CONFIG_VIDEO_ADV7180=m +CONFIG_VIDEO_ADV7183=m +CONFIG_VIDEO_ADV748X=m +CONFIG_VIDEO_ADV7604=m +CONFIG_VIDEO_ADV7604_CEC=y +CONFIG_VIDEO_ADV7842=m +CONFIG_VIDEO_ADV7842_CEC=y +CONFIG_VIDEO_BT819=m +CONFIG_VIDEO_BT856=m +CONFIG_VIDEO_BT866=m +CONFIG_VIDEO_ISL7998X=m +CONFIG_VIDEO_KS0127=m +CONFIG_VIDEO_MAX9286=m +CONFIG_VIDEO_ML86V7667=m +CONFIG_VIDEO_SAA7110=m +CONFIG_VIDEO_TC358743=m +CONFIG_VIDEO_TC358743_CEC=y +CONFIG_VIDEO_TVP514X=m +CONFIG_VIDEO_TVP7002=m +CONFIG_VIDEO_TW9910=m +CONFIG_VIDEO_VPX3220=m +CONFIG_VIDEO_AD9389B=m +CONFIG_VIDEO_ADV7170=m +CONFIG_VIDEO_ADV7175=m +CONFIG_VIDEO_ADV7343=m +CONFIG_VIDEO_ADV7393=m +CONFIG_VIDEO_AK881X=m +CONFIG_VIDEO_SAA7185=m +CONFIG_VIDEO_THS8200=m +CONFIG_SDR_MAX2175=m +CONFIG_VIDEO_I2C=m +CONFIG_VIDEO_ST_MIPID02=m +CONFIG_VIDEO_THS7303=m +CONFIG_CXD2880_SPI_DRV=m +CONFIG_VIDEO_GS1662=m +CONFIG_DVB_TDA8261=m +CONFIG_DVB_TUA6100=m +CONFIG_DVB_VES1X93=m +CONFIG_DVB_DIB9000=m +CONFIG_DVB_L64781=m +CONFIG_DVB_S5H1432=m +CONFIG_DVB_CXD2880=m +CONFIG_DVB_MN88443X=m +CONFIG_DVB_LGS8GL5=m +CONFIG_DVB_LNBH29=m +CONFIG_DVB_DUMMY_FE=m +CONFIG_DRM=m +CONFIG_DRM_LOAD_EDID_FIRMWARE=y +CONFIG_DRM_DP_AUX_CHARDEV=y +CONFIG_DRM_DP_CEC=y +CONFIG_DRM_I2C_NXP_TDA998X=m +CONFIG_DRM_I2C_NXP_TDA9950=m +CONFIG_DRM_KOMEDA=m +CONFIG_DRM_RADEON=m +CONFIG_DRM_AMDGPU=m +CONFIG_DRM_AMDGPU_SI=y +CONFIG_DRM_AMDGPU_CIK=y +CONFIG_DRM_AMDGPU_USERPTR=y +CONFIG_DRM_AMD_ACP=y +CONFIG_DRM_AMD_DC_HDCP=y +CONFIG_DRM_AMD_DC_SI=y +CONFIG_DRM_NOUVEAU=m +CONFIG_DRM_VGEM=m +CONFIG_DRM_VKMS=m +CONFIG_DRM_UDL=m +CONFIG_DRM_AST=m +CONFIG_DRM_MGAG200=m +CONFIG_DRM_QXL=m +CONFIG_DRM_VIRTIO_GPU=m +CONFIG_DRM_PANEL_ABT_Y030XX067A=m +CONFIG_DRM_PANEL_ARM_VERSATILE=m +CONFIG_DRM_PANEL_ASUS_Z00T_TM5P5_NT35596=m +CONFIG_DRM_PANEL_BOE_BF060Y8M_AJ0=m +CONFIG_DRM_PANEL_BOE_HIMAX8279D=m +CONFIG_DRM_PANEL_BOE_TV101WUM_NL6=m +CONFIG_DRM_PANEL_DSI_CM=m +CONFIG_DRM_PANEL_LVDS=m +CONFIG_DRM_PANEL_ELIDA_KD35T133=m +CONFIG_DRM_PANEL_FEIXIN_K101_IM2BA02=m +CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D=m +CONFIG_DRM_PANEL_ILITEK_IL9322=m +CONFIG_DRM_PANEL_ILITEK_ILI9341=m +CONFIG_DRM_PANEL_ILITEK_ILI9881C=m +CONFIG_DRM_PANEL_INNOLUX_EJ030NA=m +CONFIG_DRM_PANEL_INNOLUX_P079ZCA=m +CONFIG_DRM_PANEL_JDI_LT070ME05000=m +CONFIG_DRM_PANEL_JDI_R63452=m +CONFIG_DRM_PANEL_KHADAS_TS050=m +CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04=m +CONFIG_DRM_PANEL_LEADTEK_LTK050H3146W=m +CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829=m +CONFIG_DRM_PANEL_SAMSUNG_LD9040=m +CONFIG_DRM_PANEL_LG_LB035Q02=m +CONFIG_DRM_PANEL_LG_LG4573=m +CONFIG_DRM_PANEL_NEC_NL8048HL11=m +CONFIG_DRM_PANEL_NEWVISION_NV3052C=m +CONFIG_DRM_PANEL_NOVATEK_NT35510=m +CONFIG_DRM_PANEL_NOVATEK_NT35560=m +CONFIG_DRM_PANEL_NOVATEK_NT35950=m +CONFIG_DRM_PANEL_NOVATEK_NT36672A=m +CONFIG_DRM_PANEL_NOVATEK_NT39016=m +CONFIG_DRM_PANEL_MANTIX_MLAF057WE51=m +CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO=m +CONFIG_DRM_PANEL_ORISETECH_OTM8009A=m +CONFIG_DRM_PANEL_OSD_OSD101T2587_53TS=m +CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00=m +CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN=m +CONFIG_DRM_PANEL_RAYDIUM_RM67191=m +CONFIG_DRM_PANEL_RAYDIUM_RM68200=m +CONFIG_DRM_PANEL_RONBO_RB070D30=m +CONFIG_DRM_PANEL_SAMSUNG_DB7430=m +CONFIG_DRM_PANEL_SAMSUNG_S6D16D0=m +CONFIG_DRM_PANEL_SAMSUNG_S6D27A1=m +CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2=m +CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03=m +CONFIG_DRM_PANEL_SAMSUNG_S6E63M0=m +CONFIG_DRM_PANEL_SAMSUNG_S6E63M0_DSI=m +CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01=m +CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0=m +CONFIG_DRM_PANEL_SAMSUNG_SOFEF00=m +CONFIG_DRM_PANEL_SEIKO_43WVF1G=m +CONFIG_DRM_PANEL_SHARP_LQ101R1SX01=m +CONFIG_DRM_PANEL_SHARP_LS037V7DW01=m +CONFIG_DRM_PANEL_SHARP_LS043T1LE01=m +CONFIG_DRM_PANEL_SHARP_LS060T1SX01=m +CONFIG_DRM_PANEL_SITRONIX_ST7701=m +CONFIG_DRM_PANEL_SITRONIX_ST7703=m +CONFIG_DRM_PANEL_SITRONIX_ST7789V=m +CONFIG_DRM_PANEL_SONY_ACX565AKM=m +CONFIG_DRM_PANEL_SONY_TULIP_TRULY_NT35521=m +CONFIG_DRM_PANEL_TDO_TL070WSH30=m +CONFIG_DRM_PANEL_TPO_TD028TTEC1=m +CONFIG_DRM_PANEL_TPO_TD043MTEA1=m +CONFIG_DRM_PANEL_TPO_TPG110=m +CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA=m +CONFIG_DRM_PANEL_VISIONOX_RM69299=m +CONFIG_DRM_PANEL_WIDECHIPS_WS2401=m +CONFIG_DRM_PANEL_XINPENG_XPP055C272=m +CONFIG_DRM_CHIPONE_ICN6211=m +CONFIG_DRM_CHRONTEL_CH7033=m +CONFIG_DRM_DISPLAY_CONNECTOR=m +CONFIG_DRM_ITE_IT6505=m +CONFIG_DRM_LONTIUM_LT8912B=m +CONFIG_DRM_LONTIUM_LT9211=m +CONFIG_DRM_LONTIUM_LT9611=m +CONFIG_DRM_LONTIUM_LT9611UXC=m +CONFIG_DRM_ITE_IT66121=m +CONFIG_DRM_LVDS_CODEC=m +CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW=m +CONFIG_DRM_NWL_MIPI_DSI=m +CONFIG_DRM_NXP_PTN3460=m +CONFIG_DRM_PARADE_PS8622=m +CONFIG_DRM_PARADE_PS8640=m +CONFIG_DRM_SIL_SII8620=m +CONFIG_DRM_SII902X=m +CONFIG_DRM_SII9234=m +CONFIG_DRM_SIMPLE_BRIDGE=m +CONFIG_DRM_THINE_THC63LVD1024=m +CONFIG_DRM_TOSHIBA_TC358762=m +CONFIG_DRM_TOSHIBA_TC358764=m +CONFIG_DRM_TOSHIBA_TC358767=m +CONFIG_DRM_TOSHIBA_TC358768=m +CONFIG_DRM_TOSHIBA_TC358775=m +CONFIG_DRM_TI_TFP410=m +CONFIG_DRM_TI_SN65DSI83=m +CONFIG_DRM_TI_SN65DSI86=m +CONFIG_DRM_TI_TPD12S015=m +CONFIG_DRM_ANALOGIX_ANX6345=m +CONFIG_DRM_ANALOGIX_ANX78XX=m +CONFIG_DRM_ANALOGIX_ANX7625=m +CONFIG_DRM_I2C_ADV7511=m +CONFIG_DRM_I2C_ADV7511_AUDIO=y +CONFIG_DRM_CDNS_DSI=m +CONFIG_DRM_CDNS_MHDP8546=m +CONFIG_DRM_ARCPGU=m +CONFIG_DRM_BOCHS=m +CONFIG_DRM_CIRRUS_QEMU=m +CONFIG_DRM_GM12U320=m +CONFIG_DRM_PANEL_MIPI_DBI=m +CONFIG_DRM_SIMPLEDRM=m +CONFIG_TINYDRM_HX8357D=m +CONFIG_TINYDRM_ILI9163=m +CONFIG_TINYDRM_ILI9225=m +CONFIG_TINYDRM_ILI9341=m +CONFIG_TINYDRM_ILI9486=m +CONFIG_TINYDRM_MI0283QT=m +CONFIG_TINYDRM_REPAPER=m +CONFIG_TINYDRM_ST7586=m +CONFIG_TINYDRM_ST7735R=m +CONFIG_DRM_GUD=m +CONFIG_DRM_SSD130X=m +CONFIG_DRM_SSD130X_I2C=m +CONFIG_DRM_SSD130X_SPI=m +CONFIG_FB=y +CONFIG_FIRMWARE_EDID=y +CONFIG_FB_CIRRUS=m +CONFIG_FB_PM2=m +CONFIG_FB_PM2_FIFO_DISCONNECT=y +CONFIG_FB_CYBER2000=m +CONFIG_FB_ASILIANT=y +CONFIG_FB_IMSTT=y +CONFIG_FB_UVESA=m +CONFIG_FB_EFI=y +CONFIG_FB_OPENCORES=m +CONFIG_FB_S1D13XXX=m +CONFIG_FB_NVIDIA=m +CONFIG_FB_NVIDIA_I2C=y +CONFIG_FB_RIVA=m +CONFIG_FB_RIVA_I2C=y +CONFIG_FB_I740=m +CONFIG_FB_MATROX=m +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_MATROX_G=y +CONFIG_FB_MATROX_I2C=m +CONFIG_FB_MATROX_MAVEN=m +CONFIG_FB_RADEON=m +CONFIG_FB_ATY128=m +CONFIG_FB_ATY=m +CONFIG_FB_ATY_CT=y +CONFIG_FB_ATY_GX=y +CONFIG_FB_S3=m +CONFIG_FB_SAVAGE=m +CONFIG_FB_SAVAGE_I2C=y +CONFIG_FB_SIS=m +CONFIG_FB_SIS_300=y +CONFIG_FB_SIS_315=y +CONFIG_FB_NEOMAGIC=m +CONFIG_FB_KYRO=m +CONFIG_FB_3DFX=m +# CONFIG_FB_3DFX_I2C is not set +CONFIG_FB_VOODOO1=m +CONFIG_FB_VT8623=m +CONFIG_FB_TRIDENT=m +CONFIG_FB_ARK=m +CONFIG_FB_PM3=m +CONFIG_FB_CARMINE=m +CONFIG_FB_SM501=m +CONFIG_FB_SMSCUFX=m +CONFIG_FB_UDL=m +CONFIG_FB_GOLDFISH=m +CONFIG_FB_METRONOME=m +CONFIG_FB_MB862XX=m +CONFIG_FB_SIMPLE=m +CONFIG_FB_SSD1307=m +CONFIG_FB_SM712=m +CONFIG_LCD_CLASS_DEVICE=m +CONFIG_LCD_L4F00242T03=m +CONFIG_LCD_LMS283GF05=m +CONFIG_LCD_LTV350QV=m +CONFIG_LCD_ILI922X=m +CONFIG_LCD_TDO24M=m +CONFIG_LCD_VGG2432A4=m +CONFIG_LCD_PLATFORM=m +CONFIG_LCD_AMS369FG06=m +CONFIG_LCD_LMS501KF03=m +CONFIG_LCD_HX8357=m +CONFIG_LCD_OTM3225A=m +CONFIG_BACKLIGHT_KTD253=m +CONFIG_BACKLIGHT_LM3533=m +CONFIG_BACKLIGHT_PWM=m +CONFIG_BACKLIGHT_DA903X=m +CONFIG_BACKLIGHT_DA9052=m +CONFIG_BACKLIGHT_MAX8925=m +CONFIG_BACKLIGHT_QCOM_WLED=m +CONFIG_BACKLIGHT_RT4831=m +CONFIG_BACKLIGHT_WM831X=m +CONFIG_BACKLIGHT_ADP5520=m +CONFIG_BACKLIGHT_ADP8860=m +CONFIG_BACKLIGHT_ADP8870=m +CONFIG_BACKLIGHT_88PM860X=m +CONFIG_BACKLIGHT_PCF50633=m +CONFIG_BACKLIGHT_AAT2870=m +CONFIG_BACKLIGHT_LM3630A=m +CONFIG_BACKLIGHT_LM3639=m +CONFIG_BACKLIGHT_LP855X=m +CONFIG_BACKLIGHT_LP8788=m +CONFIG_BACKLIGHT_PANDORA=m +CONFIG_BACKLIGHT_SKY81452=m +CONFIG_BACKLIGHT_AS3711=m +CONFIG_BACKLIGHT_GPIO=m +CONFIG_BACKLIGHT_LV5207LP=m +CONFIG_BACKLIGHT_BD6107=m +CONFIG_BACKLIGHT_ARCXCNN=m +CONFIG_BACKLIGHT_RAVE_SP=m +CONFIG_BACKLIGHT_LED=m +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y +CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y +CONFIG_SOUND=m +# CONFIG_SOUND_OSS_CORE_PRECLAIM is not set +CONFIG_SND=m +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_HRTIMER=m +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_DUMMY=m +CONFIG_SND_ALOOP=m +CONFIG_SND_VIRMIDI=m +CONFIG_SND_MTPAV=m +CONFIG_SND_MTS64=m +CONFIG_SND_SERIAL_U16550=m +CONFIG_SND_SERIAL_GENERIC=m +CONFIG_SND_MPU401=m +CONFIG_SND_PORTMAN2X4=m +CONFIG_SND_AC97_POWER_SAVE=y +CONFIG_SND_AD1889=m +CONFIG_SND_ATIIXP=m +CONFIG_SND_ATIIXP_MODEM=m +CONFIG_SND_AU8810=m +CONFIG_SND_AU8820=m +CONFIG_SND_AU8830=m +CONFIG_SND_AW2=m +CONFIG_SND_BT87X=m +CONFIG_SND_CA0106=m +CONFIG_SND_CMIPCI=m +CONFIG_SND_OXYGEN=m +CONFIG_SND_CS4281=m +CONFIG_SND_CS46XX=m +CONFIG_SND_CTXFI=m +CONFIG_SND_DARLA20=m +CONFIG_SND_GINA20=m +CONFIG_SND_LAYLA20=m +CONFIG_SND_DARLA24=m +CONFIG_SND_GINA24=m +CONFIG_SND_LAYLA24=m +CONFIG_SND_MONA=m +CONFIG_SND_MIA=m +CONFIG_SND_ECHO3G=m +CONFIG_SND_INDIGO=m +CONFIG_SND_INDIGOIO=m +CONFIG_SND_INDIGODJ=m +CONFIG_SND_INDIGOIOX=m +CONFIG_SND_INDIGODJX=m +CONFIG_SND_ENS1370=m +CONFIG_SND_ENS1371=m +CONFIG_SND_FM801=m +CONFIG_SND_FM801_TEA575X_BOOL=y +CONFIG_SND_HDSP=m +CONFIG_SND_HDSPM=m +CONFIG_SND_ICE1724=m +CONFIG_SND_INTEL8X0=m +CONFIG_SND_INTEL8X0M=m +CONFIG_SND_KORG1212=m +CONFIG_SND_LOLA=m +CONFIG_SND_LX6464ES=m +CONFIG_SND_MIXART=m +CONFIG_SND_NM256=m +CONFIG_SND_PCXHR=m +CONFIG_SND_RIPTIDE=m +CONFIG_SND_RME32=m +CONFIG_SND_RME96=m +CONFIG_SND_RME9652=m +CONFIG_SND_VIA82XX=m +CONFIG_SND_VIA82XX_MODEM=m +CONFIG_SND_VIRTUOSO=m +CONFIG_SND_VX222=m +CONFIG_SND_YMFPCI=m +CONFIG_SND_HDA_INTEL=m +CONFIG_SND_HDA_HWDEP=y +CONFIG_SND_HDA_INPUT_BEEP=y +CONFIG_SND_HDA_INPUT_BEEP_MODE=0 +CONFIG_SND_HDA_PATCH_LOADER=y +CONFIG_SND_HDA_CODEC_REALTEK=m +CONFIG_SND_HDA_CODEC_ANALOG=m +CONFIG_SND_HDA_CODEC_SIGMATEL=m +CONFIG_SND_HDA_CODEC_VIA=m +CONFIG_SND_HDA_CODEC_HDMI=m +CONFIG_SND_HDA_CODEC_CIRRUS=m +CONFIG_SND_HDA_CODEC_CS8409=m +CONFIG_SND_HDA_CODEC_CONEXANT=m +CONFIG_SND_HDA_CODEC_CA0110=m +CONFIG_SND_HDA_CODEC_CA0132=m +CONFIG_SND_HDA_CODEC_CMEDIA=m +CONFIG_SND_HDA_CODEC_SI3054=m +CONFIG_SND_USB_AUDIO=m +CONFIG_SND_USB_UA101=m +CONFIG_SND_USB_CAIAQ=m +CONFIG_SND_USB_CAIAQ_INPUT=y +CONFIG_SND_USB_6FIRE=m +CONFIG_SND_USB_HIFACE=m +CONFIG_SND_BCD2000=m +CONFIG_SND_USB_POD=m +CONFIG_SND_USB_PODHD=m +CONFIG_SND_USB_TONEPORT=m +CONFIG_SND_USB_VARIAX=m +CONFIG_SND_DICE=m +CONFIG_SND_OXFW=m +CONFIG_SND_ISIGHT=m +CONFIG_SND_FIREWORKS=m +CONFIG_SND_BEBOB=m +CONFIG_SND_FIREWIRE_DIGI00X=m +CONFIG_SND_FIREWIRE_TASCAM=m +CONFIG_SND_FIREWIRE_MOTU=m +CONFIG_SND_FIREFACE=m +CONFIG_SND_SOC=m +CONFIG_SND_SOC_ADI=m +CONFIG_SND_SOC_ADI_AXI_I2S=m +CONFIG_SND_SOC_ADI_AXI_SPDIF=m +CONFIG_SND_SOC_AMD_ACP=m +CONFIG_SND_SOC_AMD_CZ_RT5645_MACH=m +CONFIG_SND_AMD_ACP_CONFIG=m +CONFIG_SND_ATMEL_SOC=m +CONFIG_SND_SOC_MIKROE_PROTO=m +CONFIG_SND_BCM63XX_I2S_WHISTLER=m +CONFIG_SND_DESIGNWARE_I2S=m +CONFIG_SND_DESIGNWARE_PCM=y +CONFIG_SND_SOC_FSL_ASRC=m +CONFIG_SND_SOC_FSL_SAI=m +CONFIG_SND_SOC_FSL_MQS=m +CONFIG_SND_SOC_FSL_AUDMIX=m +CONFIG_SND_SOC_FSL_SSI=m +CONFIG_SND_SOC_FSL_SPDIF=m +CONFIG_SND_SOC_FSL_ESAI=m +CONFIG_SND_SOC_FSL_MICFIL=m +CONFIG_SND_SOC_FSL_EASRC=m +CONFIG_SND_SOC_FSL_XCVR=m +CONFIG_SND_SOC_FSL_RPMSG=m +CONFIG_SND_SOC_IMX_AUDMUX=m +CONFIG_SND_I2S_HI6210_I2S=m +CONFIG_SND_SOC_IMG=y +CONFIG_SND_SOC_IMG_I2S_IN=m +CONFIG_SND_SOC_IMG_I2S_OUT=m +CONFIG_SND_SOC_IMG_PARALLEL_OUT=m +CONFIG_SND_SOC_IMG_SPDIF_IN=m +CONFIG_SND_SOC_IMG_SPDIF_OUT=m +CONFIG_SND_SOC_IMG_PISTACHIO_INTERNAL_DAC=m +CONFIG_SND_SOC_MTK_BTCVSD=m +CONFIG_SND_SOC_SOF_TOPLEVEL=y +CONFIG_SND_SOC_SOF_PCI=m +CONFIG_SND_SOC_SOF_OF=m +CONFIG_SND_SOC_XILINX_I2S=m +CONFIG_SND_SOC_XILINX_AUDIO_FORMATTER=m +CONFIG_SND_SOC_XILINX_SPDIF=m +CONFIG_SND_SOC_XTFPGA_I2S=m +CONFIG_SND_SOC_AC97_CODEC=m +CONFIG_SND_SOC_ADAU1372_I2C=m +CONFIG_SND_SOC_ADAU1372_SPI=m +CONFIG_SND_SOC_ADAU1701=m +CONFIG_SND_SOC_ADAU1761_I2C=m +CONFIG_SND_SOC_ADAU1761_SPI=m +CONFIG_SND_SOC_ADAU7002=m +CONFIG_SND_SOC_ADAU7118_HW=m +CONFIG_SND_SOC_ADAU7118_I2C=m +CONFIG_SND_SOC_AK4104=m +CONFIG_SND_SOC_AK4118=m +CONFIG_SND_SOC_AK4375=m +CONFIG_SND_SOC_AK4458=m +CONFIG_SND_SOC_AK4554=m +CONFIG_SND_SOC_AK4613=m +CONFIG_SND_SOC_AK4642=m +CONFIG_SND_SOC_AK5386=m +CONFIG_SND_SOC_AK5558=m +CONFIG_SND_SOC_ALC5623=m +CONFIG_SND_SOC_AW8738=m +CONFIG_SND_SOC_BD28623=m +CONFIG_SND_SOC_BT_SCO=m +CONFIG_SND_SOC_CPCAP=m +CONFIG_SND_SOC_CS35L32=m +CONFIG_SND_SOC_CS35L33=m +CONFIG_SND_SOC_CS35L34=m +CONFIG_SND_SOC_CS35L35=m +CONFIG_SND_SOC_CS35L36=m +CONFIG_SND_SOC_CS35L41_SPI=m +CONFIG_SND_SOC_CS35L41_I2C=m +CONFIG_SND_SOC_CS35L45_SPI=m +CONFIG_SND_SOC_CS35L45_I2C=m +CONFIG_SND_SOC_CS42L42=m +CONFIG_SND_SOC_CS42L51_I2C=m +CONFIG_SND_SOC_CS42L52=m +CONFIG_SND_SOC_CS42L56=m +CONFIG_SND_SOC_CS42L73=m +CONFIG_SND_SOC_CS4234=m +CONFIG_SND_SOC_CS4265=m +CONFIG_SND_SOC_CS4270=m +CONFIG_SND_SOC_CS4271_I2C=m +CONFIG_SND_SOC_CS4271_SPI=m +CONFIG_SND_SOC_CS42XX8_I2C=m +CONFIG_SND_SOC_CS43130=m +CONFIG_SND_SOC_CS4341=m +CONFIG_SND_SOC_CS4349=m +CONFIG_SND_SOC_CS53L30=m +CONFIG_SND_SOC_CX2072X=m +CONFIG_SND_SOC_DA7213=m +CONFIG_SND_SOC_DMIC=m +CONFIG_SND_SOC_ES7134=m +CONFIG_SND_SOC_ES7241=m +CONFIG_SND_SOC_ES8316=m +CONFIG_SND_SOC_ES8328_I2C=m +CONFIG_SND_SOC_ES8328_SPI=m +CONFIG_SND_SOC_GTM601=m +CONFIG_SND_SOC_ICS43432=m +CONFIG_SND_SOC_INNO_RK3036=m +CONFIG_SND_SOC_LOCHNAGAR_SC=m +CONFIG_SND_SOC_MAX98088=m +CONFIG_SND_SOC_MAX98357A=m +CONFIG_SND_SOC_MAX98504=m +CONFIG_SND_SOC_MAX9867=m +CONFIG_SND_SOC_MAX98927=m +CONFIG_SND_SOC_MAX98520=m +CONFIG_SND_SOC_MAX98373_I2C=m +CONFIG_SND_SOC_MAX98373_SDW=m +CONFIG_SND_SOC_MAX98390=m +CONFIG_SND_SOC_MAX98396=m +CONFIG_SND_SOC_MAX9860=m +CONFIG_SND_SOC_MSM8916_WCD_ANALOG=m +CONFIG_SND_SOC_MSM8916_WCD_DIGITAL=m +CONFIG_SND_SOC_PCM1681=m +CONFIG_SND_SOC_PCM1789_I2C=m +CONFIG_SND_SOC_PCM179X_I2C=m +CONFIG_SND_SOC_PCM179X_SPI=m +CONFIG_SND_SOC_PCM186X_I2C=m +CONFIG_SND_SOC_PCM186X_SPI=m +CONFIG_SND_SOC_PCM3060_I2C=m +CONFIG_SND_SOC_PCM3060_SPI=m +CONFIG_SND_SOC_PCM3168A_I2C=m +CONFIG_SND_SOC_PCM3168A_SPI=m +CONFIG_SND_SOC_PCM5102A=m +CONFIG_SND_SOC_PCM512x_I2C=m +CONFIG_SND_SOC_PCM512x_SPI=m +CONFIG_SND_SOC_RK3328=m +CONFIG_SND_SOC_RK817=m +CONFIG_SND_SOC_RT1308_SDW=m +CONFIG_SND_SOC_RT1316_SDW=m +CONFIG_SND_SOC_RT5616=m +CONFIG_SND_SOC_RT5631=m +CONFIG_SND_SOC_RT5640=m +CONFIG_SND_SOC_RT5659=m +CONFIG_SND_SOC_RT5682_SDW=m +CONFIG_SND_SOC_RT700_SDW=m +CONFIG_SND_SOC_RT711_SDW=m +CONFIG_SND_SOC_RT711_SDCA_SDW=m +CONFIG_SND_SOC_RT715_SDW=m +CONFIG_SND_SOC_RT715_SDCA_SDW=m +CONFIG_SND_SOC_RT9120=m +CONFIG_SND_SOC_SDW_MOCKUP=m +CONFIG_SND_SOC_SGTL5000=m +CONFIG_SND_SOC_SIMPLE_AMPLIFIER=m +CONFIG_SND_SOC_SIMPLE_MUX=m +CONFIG_SND_SOC_SPDIF=m +CONFIG_SND_SOC_SSM2305=m +CONFIG_SND_SOC_SSM2518=m +CONFIG_SND_SOC_SSM2602_SPI=m +CONFIG_SND_SOC_SSM2602_I2C=m +CONFIG_SND_SOC_SSM4567=m +CONFIG_SND_SOC_STA32X=m +CONFIG_SND_SOC_STA350=m +CONFIG_SND_SOC_STI_SAS=m +CONFIG_SND_SOC_TAS2552=m +CONFIG_SND_SOC_TAS2562=m +CONFIG_SND_SOC_TAS2764=m +CONFIG_SND_SOC_TAS2770=m +CONFIG_SND_SOC_TAS5086=m +CONFIG_SND_SOC_TAS571X=m +CONFIG_SND_SOC_TAS5720=m +CONFIG_SND_SOC_TAS5805M=m +CONFIG_SND_SOC_TAS6424=m +CONFIG_SND_SOC_TDA7419=m +CONFIG_SND_SOC_TFA9879=m +CONFIG_SND_SOC_TFA989X=m +CONFIG_SND_SOC_TLV320ADC3XXX=m +CONFIG_SND_SOC_TLV320AIC23_I2C=m +CONFIG_SND_SOC_TLV320AIC23_SPI=m +CONFIG_SND_SOC_TLV320AIC31XX=m +CONFIG_SND_SOC_TLV320AIC32X4_I2C=m +CONFIG_SND_SOC_TLV320AIC32X4_SPI=m +CONFIG_SND_SOC_TLV320AIC3X_I2C=m +CONFIG_SND_SOC_TLV320AIC3X_SPI=m +CONFIG_SND_SOC_TLV320ADCX140=m +CONFIG_SND_SOC_TS3A227E=m +CONFIG_SND_SOC_TSCS42XX=m +CONFIG_SND_SOC_TSCS454=m +CONFIG_SND_SOC_UDA1334=m +CONFIG_SND_SOC_WCD9335=m +CONFIG_SND_SOC_WCD934X=m +CONFIG_SND_SOC_WCD938X_SDW=m +CONFIG_SND_SOC_WM8510=m +CONFIG_SND_SOC_WM8523=m +CONFIG_SND_SOC_WM8524=m +CONFIG_SND_SOC_WM8580=m +CONFIG_SND_SOC_WM8711=m +CONFIG_SND_SOC_WM8728=m +CONFIG_SND_SOC_WM8731_I2C=m +CONFIG_SND_SOC_WM8731_SPI=m +CONFIG_SND_SOC_WM8737=m +CONFIG_SND_SOC_WM8741=m +CONFIG_SND_SOC_WM8750=m +CONFIG_SND_SOC_WM8753=m +CONFIG_SND_SOC_WM8770=m +CONFIG_SND_SOC_WM8776=m +CONFIG_SND_SOC_WM8782=m +CONFIG_SND_SOC_WM8804_I2C=m +CONFIG_SND_SOC_WM8804_SPI=m +CONFIG_SND_SOC_WM8903=m +CONFIG_SND_SOC_WM8904=m +CONFIG_SND_SOC_WM8940=m +CONFIG_SND_SOC_WM8960=m +CONFIG_SND_SOC_WM8962=m +CONFIG_SND_SOC_WM8974=m +CONFIG_SND_SOC_WM8978=m +CONFIG_SND_SOC_WM8985=m +CONFIG_SND_SOC_WSA881X=m +CONFIG_SND_SOC_ZL38060=m +CONFIG_SND_SOC_MAX9759=m +CONFIG_SND_SOC_MT6351=m +CONFIG_SND_SOC_MT6358=m +CONFIG_SND_SOC_MT6660=m +CONFIG_SND_SOC_NAU8315=m +CONFIG_SND_SOC_NAU8540=m +CONFIG_SND_SOC_NAU8810=m +CONFIG_SND_SOC_NAU8821=m +CONFIG_SND_SOC_NAU8822=m +CONFIG_SND_SOC_NAU8824=m +CONFIG_SND_SOC_TPA6130A2=m +CONFIG_SND_SOC_LPASS_WSA_MACRO=m +CONFIG_SND_SOC_LPASS_VA_MACRO=m +CONFIG_SND_SOC_LPASS_RX_MACRO=m +CONFIG_SND_SOC_LPASS_TX_MACRO=m +CONFIG_SND_SIMPLE_CARD=m +CONFIG_SND_AUDIO_GRAPH_CARD=m +CONFIG_SND_AUDIO_GRAPH_CARD2=m +CONFIG_SND_AUDIO_GRAPH_CARD2_CUSTOM_SAMPLE=m +CONFIG_SND_TEST_COMPONENT=m +CONFIG_SND_VIRTIO=m +CONFIG_HID=m +CONFIG_HID_BATTERY_STRENGTH=y +CONFIG_HIDRAW=y +CONFIG_UHID=m +CONFIG_HID_A4TECH=m +CONFIG_HID_ACCUTOUCH=m +CONFIG_HID_ACRUX=m +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_APPLE=m +CONFIG_HID_APPLEIR=m +CONFIG_HID_ASUS=m +CONFIG_HID_AUREAL=m +CONFIG_HID_BELKIN=m +CONFIG_HID_BETOP_FF=m +CONFIG_HID_BIGBEN_FF=m +CONFIG_HID_CHERRY=m +CONFIG_HID_CHICONY=m +CONFIG_HID_CORSAIR=m +CONFIG_HID_COUGAR=m +CONFIG_HID_MACALLY=m +CONFIG_HID_PRODIKEYS=m +CONFIG_HID_CMEDIA=m +CONFIG_HID_CP2112=m +CONFIG_HID_CREATIVE_SB0540=m +CONFIG_HID_CYPRESS=m +CONFIG_HID_DRAGONRISE=m +CONFIG_DRAGONRISE_FF=y +CONFIG_HID_EMS_FF=m +CONFIG_HID_ELAN=m +CONFIG_HID_ELECOM=m +CONFIG_HID_ELO=m +CONFIG_HID_EZKEY=m +CONFIG_HID_FT260=m +CONFIG_HID_GEMBIRD=m +CONFIG_HID_GFRM=m +CONFIG_HID_GLORIOUS=m +CONFIG_HID_HOLTEK=m +CONFIG_HOLTEK_FF=y +CONFIG_HID_VIVALDI=m +CONFIG_HID_GT683R=m +CONFIG_HID_KEYTOUCH=m +CONFIG_HID_KYE=m +CONFIG_HID_UCLOGIC=m +CONFIG_HID_WALTOP=m +CONFIG_HID_VIEWSONIC=m +CONFIG_HID_XIAOMI=m +CONFIG_HID_GYRATION=m +CONFIG_HID_ICADE=m +CONFIG_HID_ITE=m +CONFIG_HID_JABRA=m +CONFIG_HID_TWINHAN=m +CONFIG_HID_KENSINGTON=m +CONFIG_HID_LCPOWER=m +CONFIG_HID_LENOVO=m +CONFIG_HID_LETSKETCH=m +CONFIG_HID_LOGITECH=m +CONFIG_HID_LOGITECH_DJ=m +CONFIG_LOGITECH_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGIG940_FF=y +CONFIG_HID_MAGICMOUSE=m +CONFIG_HID_MALTRON=m +CONFIG_HID_MAYFLASH=m +CONFIG_HID_MEGAWORLD_FF=m +CONFIG_HID_REDRAGON=m +CONFIG_HID_MICROSOFT=m +CONFIG_HID_MONTEREY=m +CONFIG_HID_MULTITOUCH=m +CONFIG_HID_NINTENDO=m +CONFIG_NINTENDO_FF=y +CONFIG_HID_NTI=m +CONFIG_HID_NTRIG=m +CONFIG_HID_ORTEK=m +CONFIG_HID_PANTHERLORD=m +CONFIG_PANTHERLORD_FF=y +CONFIG_HID_PENMOUNT=m +CONFIG_HID_PETALYNX=m +CONFIG_HID_PICOLCD=m +CONFIG_HID_PICOLCD_FB=y +CONFIG_HID_PICOLCD_BACKLIGHT=y +CONFIG_HID_PICOLCD_LCD=y +CONFIG_HID_PICOLCD_LEDS=y +CONFIG_HID_PICOLCD_CIR=y +CONFIG_HID_PLANTRONICS=m +CONFIG_HID_PLAYSTATION=m +CONFIG_PLAYSTATION_FF=y +CONFIG_HID_RAZER=m +CONFIG_HID_PRIMAX=m +CONFIG_HID_RETRODE=m +CONFIG_HID_ROCCAT=m +CONFIG_HID_SAITEK=m +CONFIG_HID_SAMSUNG=m +CONFIG_HID_SEMITEK=m +CONFIG_HID_SIGMAMICRO=m +CONFIG_HID_SONY=m +CONFIG_SONY_FF=y +CONFIG_HID_SPEEDLINK=m +CONFIG_HID_STEAM=m +CONFIG_HID_STEELSERIES=m +CONFIG_HID_SUNPLUS=m +CONFIG_HID_RMI=m +CONFIG_HID_GREENASIA=m +CONFIG_GREENASIA_FF=y +CONFIG_HID_SMARTJOYPLUS=m +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_HID_TIVO=m +CONFIG_HID_TOPSEED=m +CONFIG_HID_THINGM=m +CONFIG_HID_THRUSTMASTER=m +CONFIG_THRUSTMASTER_FF=y +CONFIG_HID_UDRAW_PS3=m +CONFIG_HID_U2FZERO=m +CONFIG_HID_WACOM=m +CONFIG_HID_WIIMOTE=m +CONFIG_HID_XINMO=m +CONFIG_HID_ZEROPLUS=m +CONFIG_ZEROPLUS_FF=y +CONFIG_HID_ZYDACRON=m +CONFIG_HID_SENSOR_HUB=m +CONFIG_HID_SENSOR_CUSTOM_SENSOR=m +CONFIG_HID_ALPS=m +CONFIG_HID_MCP2221=m +CONFIG_USB_HID=m +CONFIG_HID_PID=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_KBD=m +CONFIG_USB_MOUSE=m +CONFIG_I2C_HID_OF=m +CONFIG_I2C_HID_OF_GOODIX=m +CONFIG_USB_LED_TRIG=y +CONFIG_USB_CONN_GPIO=m +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_DYNAMIC_MINORS=y +CONFIG_USB_LEDS_TRIGGER_USBPORT=m +CONFIG_USB_MON=m +CONFIG_USB_C67X00_HCD=m +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_DBGCAP=y +CONFIG_USB_XHCI_PCI_RENESAS=m +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_FSL=m +CONFIG_USB_OXU210HP_HCD=m +CONFIG_USB_ISP116X_HCD=m +CONFIG_USB_MAX3421_HCD=m +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_UHCI_HCD=y +CONFIG_USB_U132_HCD=m +CONFIG_USB_SL811_HCD=m +CONFIG_USB_SL811_HCD_ISO=y +CONFIG_USB_R8A66597_HCD=m +CONFIG_USB_HCD_BCMA=m +CONFIG_USB_HCD_SSB=m +CONFIG_USB_PRINTER=m +CONFIG_USB_TMC=m +CONFIG_USB_STORAGE=m +CONFIG_USB_STORAGE_REALTEK=m +CONFIG_USB_STORAGE_DATAFAB=m +CONFIG_USB_STORAGE_FREECOM=m +CONFIG_USB_STORAGE_ISD200=m +CONFIG_USB_STORAGE_USBAT=m +CONFIG_USB_STORAGE_SDDR09=m +CONFIG_USB_STORAGE_SDDR55=m +CONFIG_USB_STORAGE_JUMPSHOT=m +CONFIG_USB_STORAGE_ALAUDA=m +CONFIG_USB_STORAGE_ONETOUCH=m +CONFIG_USB_STORAGE_KARMA=m +CONFIG_USB_STORAGE_CYPRESS_ATACB=m +CONFIG_USB_STORAGE_ENE_UB6250=m +CONFIG_USB_UAS=m +CONFIG_USB_MDC800=m +CONFIG_USB_MICROTEK=m +CONFIG_USBIP_CORE=m +CONFIG_USBIP_VHCI_HCD=m +CONFIG_USBIP_HOST=m +CONFIG_USBIP_VUDC=m +CONFIG_USB_CDNS_SUPPORT=m +CONFIG_USB_CDNS3=m +CONFIG_USB_CDNS3_GADGET=y +CONFIG_USB_CDNS3_HOST=y +CONFIG_USB_MUSB_HDRC=m +CONFIG_USB_MUSB_POLARFIRE_SOC=m +CONFIG_MUSB_PIO_ONLY=y +CONFIG_USB_DWC3=m +CONFIG_USB_DWC3_ULPI=y +CONFIG_USB_DWC2=y +CONFIG_USB_DWC2_PCI=m +CONFIG_USB_CHIPIDEA=m +CONFIG_USB_CHIPIDEA_UDC=y +CONFIG_USB_CHIPIDEA_HOST=y +CONFIG_USB_ISP1760=m +CONFIG_USB_USS720=m +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_SIMPLE=m +CONFIG_USB_SERIAL_AIRCABLE=m +CONFIG_USB_SERIAL_ARK3116=m +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_CH341=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_CP210X=m +CONFIG_USB_SERIAL_CYPRESS_M8=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IR=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_F81232=m +CONFIG_USB_SERIAL_F8153X=m +CONFIG_USB_SERIAL_GARMIN=m +CONFIG_USB_SERIAL_IPW=m +CONFIG_USB_SERIAL_IUU=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_METRO=m +CONFIG_USB_SERIAL_MOS7720=m +CONFIG_USB_SERIAL_MOS7715_PARPORT=y +CONFIG_USB_SERIAL_MOS7840=m +CONFIG_USB_SERIAL_MXUPORT=m +CONFIG_USB_SERIAL_NAVMAN=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_OTI6858=m +CONFIG_USB_SERIAL_QCAUX=m +CONFIG_USB_SERIAL_QUALCOMM=m +CONFIG_USB_SERIAL_SPCP8X5=m +CONFIG_USB_SERIAL_SAFE=m +CONFIG_USB_SERIAL_SIERRAWIRELESS=m +CONFIG_USB_SERIAL_SYMBOL=m +CONFIG_USB_SERIAL_TI=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_OPTION=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_SERIAL_OPTICON=m +CONFIG_USB_SERIAL_XSENS_MT=m +CONFIG_USB_SERIAL_WISHBONE=m +CONFIG_USB_SERIAL_SSU100=m +CONFIG_USB_SERIAL_QT2=m +CONFIG_USB_SERIAL_UPD78F0730=m +CONFIG_USB_SERIAL_XR=m +CONFIG_USB_SERIAL_DEBUG=m +CONFIG_USB_EMI62=m +CONFIG_USB_EMI26=m +CONFIG_USB_ADUTUX=m +CONFIG_USB_SEVSEG=m +CONFIG_USB_LEGOTOWER=m +CONFIG_USB_LCD=m +CONFIG_USB_CYPRESS_CY7C63=m +CONFIG_USB_CYTHERM=m +CONFIG_USB_IDMOUSE=m +CONFIG_USB_FTDI_ELAN=m +CONFIG_USB_APPLEDISPLAY=m +CONFIG_APPLE_MFI_FASTCHARGE=m +CONFIG_USB_SISUSBVGA=m +CONFIG_USB_LD=m +CONFIG_USB_TRANCEVIBRATOR=m +CONFIG_USB_IOWARRIOR=m +CONFIG_USB_TEST=m +CONFIG_USB_EHSET_TEST_FIXTURE=m +CONFIG_USB_ISIGHTFW=m +CONFIG_USB_YUREX=m +CONFIG_USB_HUB_USB251XB=m +CONFIG_USB_HSIC_USB3503=m +CONFIG_USB_HSIC_USB4604=m +CONFIG_USB_LINK_LAYER_TEST=m +CONFIG_USB_CHAOSKEY=m +CONFIG_USB_ATM=m +CONFIG_USB_SPEEDTOUCH=m +CONFIG_USB_CXACRU=m +CONFIG_USB_UEAGLEATM=m +CONFIG_USB_XUSBATM=m +CONFIG_USB_GPIO_VBUS=m +CONFIG_TAHVO_USB=m +CONFIG_TAHVO_USB_HOST_BY_DEFAULT=y +CONFIG_USB_ISP1301=m +CONFIG_USB_GADGET=m +CONFIG_U_SERIAL_CONSOLE=y +CONFIG_USB_GR_UDC=m +CONFIG_USB_R8A66597=m +CONFIG_USB_PXA27X=m +CONFIG_USB_MV_UDC=m +CONFIG_USB_MV_U3D=m +CONFIG_USB_SNP_UDC_PLAT=m +CONFIG_USB_BDC_UDC=m +CONFIG_USB_AMD5536UDC=m +CONFIG_USB_NET2272=m +CONFIG_USB_NET2272_DMA=y +CONFIG_USB_NET2280=m +CONFIG_USB_GOKU=m +CONFIG_USB_EG20T=m +CONFIG_USB_GADGET_XILINX=m +CONFIG_USB_MAX3420_UDC=m +CONFIG_USB_CONFIGFS=m +CONFIG_USB_CONFIGFS_SERIAL=y +CONFIG_USB_CONFIGFS_ACM=y +CONFIG_USB_CONFIGFS_OBEX=y +CONFIG_USB_CONFIGFS_NCM=y +CONFIG_USB_CONFIGFS_ECM=y +CONFIG_USB_CONFIGFS_ECM_SUBSET=y +CONFIG_USB_CONFIGFS_RNDIS=y +CONFIG_USB_CONFIGFS_EEM=y +CONFIG_USB_CONFIGFS_PHONET=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_LB_SS=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_UAC1=y +CONFIG_USB_CONFIGFS_F_UAC1_LEGACY=y +CONFIG_USB_CONFIGFS_F_UAC2=y +CONFIG_USB_CONFIGFS_F_MIDI=y +CONFIG_USB_CONFIGFS_F_HID=y +CONFIG_USB_CONFIGFS_F_UVC=y +CONFIG_USB_CONFIGFS_F_PRINTER=y +CONFIG_USB_CONFIGFS_F_TCM=y +CONFIG_USB_ZERO=m +CONFIG_USB_AUDIO=m +CONFIG_GADGET_UAC1=y +CONFIG_USB_ETH=m +CONFIG_USB_ETH_EEM=y +CONFIG_USB_G_NCM=m +CONFIG_USB_GADGETFS=m +CONFIG_USB_FUNCTIONFS=m +CONFIG_USB_FUNCTIONFS_ETH=y +CONFIG_USB_FUNCTIONFS_RNDIS=y +CONFIG_USB_FUNCTIONFS_GENERIC=y +CONFIG_USB_MASS_STORAGE=m +CONFIG_USB_GADGET_TARGET=m +CONFIG_USB_G_SERIAL=m +CONFIG_USB_MIDI_GADGET=m +CONFIG_USB_G_PRINTER=m +CONFIG_USB_CDC_COMPOSITE=m +CONFIG_USB_G_NOKIA=m +CONFIG_USB_G_ACM_MS=m +CONFIG_USB_G_HID=m +CONFIG_USB_G_DBGP=m +CONFIG_USB_G_WEBCAM=m +CONFIG_USB_RAW_GADGET=m +CONFIG_TYPEC=m +CONFIG_TYPEC_TCPM=m +CONFIG_TYPEC_TCPCI=m +CONFIG_TYPEC_RT1711H=m +CONFIG_TYPEC_MT6360=m +CONFIG_TYPEC_TCPCI_MAXIM=m +CONFIG_TYPEC_FUSB302=m +CONFIG_TYPEC_UCSI=m +CONFIG_UCSI_CCG=m +CONFIG_TYPEC_TPS6598X=m +CONFIG_TYPEC_RT1719=m +CONFIG_TYPEC_HD3SS3220=m +CONFIG_TYPEC_STUSB160X=m +CONFIG_TYPEC_WUSB3801=m +CONFIG_TYPEC_MUX_FSA4480=m +CONFIG_TYPEC_MUX_PI3USB30532=m +CONFIG_TYPEC_DP_ALTMODE=m +CONFIG_TYPEC_NVIDIA_ALTMODE=m +CONFIG_MMC=y +CONFIG_PWRSEQ_EMMC=m +CONFIG_PWRSEQ_SD8787=m +CONFIG_PWRSEQ_SIMPLE=m +CONFIG_SDIO_UART=m +CONFIG_MMC_CRYPTO=y +CONFIG_MMC_SDHCI=m +CONFIG_MMC_SDHCI_PCI=m +CONFIG_MMC_SDHCI_PLTFM=m +CONFIG_MMC_SDHCI_OF_ARASAN=m +CONFIG_MMC_SDHCI_OF_AT91=m +CONFIG_MMC_SDHCI_OF_DWCMSHC=m +CONFIG_MMC_SDHCI_CADENCE=m +CONFIG_MMC_SDHCI_F_SDH30=m +CONFIG_MMC_SDHCI_MILBEAUT=m +CONFIG_MMC_ALCOR=m +CONFIG_MMC_TIFM_SD=m +CONFIG_MMC_SPI=y +CONFIG_MMC_CB710=m +CONFIG_MMC_VIA_SDMMC=m +CONFIG_MMC_DW=m +CONFIG_MMC_DW_BLUEFIELD=m +CONFIG_MMC_DW_EXYNOS=m +CONFIG_MMC_DW_HI3798CV200=m +CONFIG_MMC_DW_K3=m +CONFIG_MMC_DW_PCI=m +CONFIG_MMC_VUB300=m +CONFIG_MMC_USHC=m +CONFIG_MMC_USDHI6ROL0=m +CONFIG_MMC_REALTEK_PCI=m +CONFIG_MMC_REALTEK_USB=m +CONFIG_MMC_HSQ=m +CONFIG_MMC_TOSHIBA_PCI=m +CONFIG_MMC_MTK=m +CONFIG_MMC_SDHCI_XENON=m +CONFIG_MMC_SDHCI_OMAP=m +CONFIG_MMC_SDHCI_AM654=m +CONFIG_MMC_LITEX=m +CONFIG_SCSI_UFSHCD=m +CONFIG_SCSI_UFS_BSG=y +CONFIG_SCSI_UFS_CRYPTO=y +CONFIG_SCSI_UFS_HPB=y +CONFIG_SCSI_UFSHCD_PCI=m +CONFIG_SCSI_UFS_DWC_TC_PCI=m +CONFIG_SCSI_UFSHCD_PLATFORM=m +CONFIG_SCSI_UFS_CDNS_PLATFORM=m +CONFIG_SCSI_UFS_DWC_TC_PLATFORM=m +CONFIG_MEMSTICK=m +CONFIG_MSPRO_BLOCK=m +CONFIG_MS_BLOCK=m +CONFIG_MEMSTICK_TIFM_MS=m +CONFIG_MEMSTICK_JMICRON_38X=m +CONFIG_MEMSTICK_R592=m +CONFIG_MEMSTICK_REALTEK_PCI=m +CONFIG_MEMSTICK_REALTEK_USB=m +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_CLASS_FLASH=m +CONFIG_LEDS_CLASS_MULTICOLOR=m +CONFIG_LEDS_BRIGHTNESS_HW_CHANGED=y +CONFIG_LEDS_88PM860X=m +CONFIG_LEDS_AN30259A=m +CONFIG_LEDS_AW2013=m +CONFIG_LEDS_BCM6328=m +CONFIG_LEDS_BCM6358=m +CONFIG_LEDS_CPCAP=m +CONFIG_LEDS_CR0014114=m +CONFIG_LEDS_EL15203000=m +CONFIG_LEDS_LM3530=m +CONFIG_LEDS_LM3532=m +CONFIG_LEDS_LM3533=m +CONFIG_LEDS_LM3642=m +CONFIG_LEDS_LM3692X=m +CONFIG_LEDS_MT6323=m +CONFIG_LEDS_PCA9532=m +CONFIG_LEDS_PCA9532_GPIO=y +CONFIG_LEDS_GPIO=m +CONFIG_LEDS_LP3944=m +CONFIG_LEDS_LP3952=m +CONFIG_LEDS_LP50XX=m +CONFIG_LEDS_LP55XX_COMMON=m +CONFIG_LEDS_LP5521=m +CONFIG_LEDS_LP5523=m +CONFIG_LEDS_LP5562=m +CONFIG_LEDS_LP8501=m +CONFIG_LEDS_LP8788=m +CONFIG_LEDS_LP8860=m +CONFIG_LEDS_PCA955X=m +CONFIG_LEDS_PCA955X_GPIO=y +CONFIG_LEDS_PCA963X=m +CONFIG_LEDS_WM831X_STATUS=m +CONFIG_LEDS_WM8350=m +CONFIG_LEDS_DA903X=m +CONFIG_LEDS_DA9052=m +CONFIG_LEDS_DAC124S085=m +CONFIG_LEDS_PWM=m +CONFIG_LEDS_REGULATOR=m +CONFIG_LEDS_BD2802=m +CONFIG_LEDS_LT3593=m +CONFIG_LEDS_ADP5520=m +CONFIG_LEDS_MC13783=m +CONFIG_LEDS_TCA6507=m +CONFIG_LEDS_TLC591XX=m +CONFIG_LEDS_MAX77650=m +CONFIG_LEDS_MAX8997=m +CONFIG_LEDS_LM355x=m +CONFIG_LEDS_MENF21BMC=m +CONFIG_LEDS_IS31FL319X=m +CONFIG_LEDS_IS31FL32XX=m +CONFIG_LEDS_BLINKM=m +CONFIG_LEDS_SYSCON=y +CONFIG_LEDS_MLXREG=m +CONFIG_LEDS_USER=m +CONFIG_LEDS_SPI_BYTE=m +CONFIG_LEDS_TI_LMU_COMMON=m +CONFIG_LEDS_LM3697=m +CONFIG_LEDS_LM36274=m +CONFIG_LEDS_AAT1290=m +CONFIG_LEDS_AS3645A=m +CONFIG_LEDS_KTD2692=m +CONFIG_LEDS_LM3601X=m +CONFIG_LEDS_MAX77693=m +CONFIG_LEDS_MT6360=m +CONFIG_LEDS_RT4505=m +CONFIG_LEDS_RT8515=m +CONFIG_LEDS_SGM3140=m +CONFIG_LEDS_PWM_MULTICOLOR=m +CONFIG_LEDS_QCOM_LPG=m +CONFIG_LEDS_TRIGGER_TIMER=m +CONFIG_LEDS_TRIGGER_ONESHOT=m +CONFIG_LEDS_TRIGGER_DISK=y +CONFIG_LEDS_TRIGGER_MTD=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=m +CONFIG_LEDS_TRIGGER_BACKLIGHT=m +CONFIG_LEDS_TRIGGER_CPU=y +CONFIG_LEDS_TRIGGER_ACTIVITY=m +CONFIG_LEDS_TRIGGER_GPIO=m +CONFIG_LEDS_TRIGGER_DEFAULT_ON=m +CONFIG_LEDS_TRIGGER_TRANSIENT=m +CONFIG_LEDS_TRIGGER_CAMERA=m +CONFIG_LEDS_TRIGGER_PANIC=y +CONFIG_LEDS_TRIGGER_NETDEV=m +CONFIG_LEDS_TRIGGER_PATTERN=m +CONFIG_LEDS_TRIGGER_TTY=m +CONFIG_INFINIBAND=m +CONFIG_INFINIBAND_USER_MAD=m +CONFIG_INFINIBAND_USER_ACCESS=m +CONFIG_INFINIBAND_BNXT_RE=m +CONFIG_INFINIBAND_CXGB4=m +CONFIG_INFINIBAND_EFA=m +CONFIG_INFINIBAND_IRDMA=m +CONFIG_MLX4_INFINIBAND=m +CONFIG_MLX5_INFINIBAND=m +CONFIG_INFINIBAND_MTHCA=m +# CONFIG_INFINIBAND_MTHCA_DEBUG is not set +CONFIG_INFINIBAND_OCRDMA=m +CONFIG_INFINIBAND_QEDR=m +CONFIG_INFINIBAND_VMWARE_PVRDMA=m +CONFIG_RDMA_RXE=m +CONFIG_RDMA_SIW=m +CONFIG_INFINIBAND_IPOIB=m +CONFIG_INFINIBAND_IPOIB_CM=y +# CONFIG_INFINIBAND_IPOIB_DEBUG is not set +CONFIG_INFINIBAND_SRP=m +CONFIG_INFINIBAND_SRPT=m +CONFIG_INFINIBAND_ISER=m +CONFIG_INFINIBAND_ISERT=m +CONFIG_INFINIBAND_RTRS_CLIENT=m +CONFIG_INFINIBAND_RTRS_SERVER=m +CONFIG_EDAC=y +# CONFIG_EDAC_LEGACY_SYSFS is not set +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_88PM860X=m +CONFIG_RTC_DRV_88PM80X=m +CONFIG_RTC_DRV_ABB5ZES3=m +CONFIG_RTC_DRV_ABEOZ9=m +CONFIG_RTC_DRV_ABX80X=m +CONFIG_RTC_DRV_AS3722=m +CONFIG_RTC_DRV_DS1307=m +CONFIG_RTC_DRV_DS1307_CENTURY=y +CONFIG_RTC_DRV_DS1374=m +CONFIG_RTC_DRV_DS1374_WDT=y +CONFIG_RTC_DRV_DS1672=m +CONFIG_RTC_DRV_HYM8563=m +CONFIG_RTC_DRV_LP8788=m +CONFIG_RTC_DRV_MAX6900=m +CONFIG_RTC_DRV_MAX8907=m +CONFIG_RTC_DRV_MAX8925=m +CONFIG_RTC_DRV_MAX8998=m +CONFIG_RTC_DRV_MAX8997=m +CONFIG_RTC_DRV_MAX77686=m +CONFIG_RTC_DRV_RK808=m +CONFIG_RTC_DRV_RS5C372=m +CONFIG_RTC_DRV_ISL1208=m +CONFIG_RTC_DRV_ISL12022=m +CONFIG_RTC_DRV_ISL12026=m +CONFIG_RTC_DRV_X1205=m +CONFIG_RTC_DRV_PCF8523=m +CONFIG_RTC_DRV_PCF85063=m +CONFIG_RTC_DRV_PCF85363=m +CONFIG_RTC_DRV_PCF8563=m +CONFIG_RTC_DRV_PCF8583=m +CONFIG_RTC_DRV_M41T80=m +CONFIG_RTC_DRV_M41T80_WDT=y +CONFIG_RTC_DRV_BD70528=m +CONFIG_RTC_DRV_BQ32K=m +CONFIG_RTC_DRV_TWL4030=m +CONFIG_RTC_DRV_PALMAS=m +CONFIG_RTC_DRV_TPS6586X=m +CONFIG_RTC_DRV_TPS65910=m +CONFIG_RTC_DRV_RC5T583=m +CONFIG_RTC_DRV_RC5T619=m +CONFIG_RTC_DRV_S35390A=m +CONFIG_RTC_DRV_FM3130=m +CONFIG_RTC_DRV_RX8010=m +CONFIG_RTC_DRV_RX8581=m +CONFIG_RTC_DRV_RX8025=m +CONFIG_RTC_DRV_EM3027=m +CONFIG_RTC_DRV_RV3028=m +CONFIG_RTC_DRV_RV3032=m +CONFIG_RTC_DRV_RV8803=m +CONFIG_RTC_DRV_S5M=m +CONFIG_RTC_DRV_SD3078=m +CONFIG_RTC_DRV_M41T93=m +CONFIG_RTC_DRV_M41T94=m +CONFIG_RTC_DRV_DS1302=m +CONFIG_RTC_DRV_DS1305=m +CONFIG_RTC_DRV_DS1343=m +CONFIG_RTC_DRV_DS1347=m +CONFIG_RTC_DRV_DS1390=m +CONFIG_RTC_DRV_MAX6916=m +CONFIG_RTC_DRV_R9701=m +CONFIG_RTC_DRV_RX4581=m +CONFIG_RTC_DRV_RS5C348=m +CONFIG_RTC_DRV_MAX6902=m +CONFIG_RTC_DRV_PCF2123=m +CONFIG_RTC_DRV_MCP795=m +CONFIG_RTC_DRV_DS3232=m +CONFIG_RTC_DRV_PCF2127=m +CONFIG_RTC_DRV_RV3029C2=m +CONFIG_RTC_DRV_RX6110=m +CONFIG_RTC_DRV_DS1286=m +CONFIG_RTC_DRV_DS1511=m +CONFIG_RTC_DRV_DS1553=m +CONFIG_RTC_DRV_DS1685_FAMILY=m +CONFIG_RTC_DRV_DS1742=m +CONFIG_RTC_DRV_DS2404=m +CONFIG_RTC_DRV_DA9052=m +CONFIG_RTC_DRV_DA9055=m +CONFIG_RTC_DRV_DA9063=m +CONFIG_RTC_DRV_EFI=m +CONFIG_RTC_DRV_STK17TA8=m +CONFIG_RTC_DRV_M48T86=m +CONFIG_RTC_DRV_M48T35=m +CONFIG_RTC_DRV_M48T59=m +CONFIG_RTC_DRV_MSM6242=m +CONFIG_RTC_DRV_BQ4802=m +CONFIG_RTC_DRV_RP5C01=m +CONFIG_RTC_DRV_WM831X=m +CONFIG_RTC_DRV_WM8350=m +CONFIG_RTC_DRV_PCF50633=m +CONFIG_RTC_DRV_ZYNQMP=m +CONFIG_RTC_DRV_NTXEC=m +CONFIG_RTC_DRV_CADENCE=m +CONFIG_RTC_DRV_FTRTC010=m +CONFIG_RTC_DRV_PCAP=m +CONFIG_RTC_DRV_MC13XXX=m +CONFIG_RTC_DRV_MT6397=m +CONFIG_RTC_DRV_R7301=m +CONFIG_RTC_DRV_CPCAP=m +CONFIG_RTC_DRV_HID_SENSOR_TIME=m +CONFIG_DMADEVICES=y +CONFIG_ALTERA_MSGDMA=m +CONFIG_DW_AXI_DMAC=m +CONFIG_FSL_EDMA=m +CONFIG_INTEL_IDMA64=m +CONFIG_PLX_DMA=m +CONFIG_XILINX_ZYNQMP_DPDMA=m +CONFIG_QCOM_HIDMA_MGMT=m +CONFIG_QCOM_HIDMA=m +CONFIG_DW_DMAC=m +CONFIG_DW_DMAC_PCI=m +CONFIG_DW_EDMA=m +CONFIG_DW_EDMA_PCIE=m +CONFIG_SF_PDMA=m +CONFIG_ASYNC_TX_DMA=y +CONFIG_SW_SYNC=y +CONFIG_UDMABUF=y +CONFIG_DMABUF_HEAPS=y +CONFIG_DMABUF_HEAPS_SYSTEM=y +CONFIG_DMABUF_HEAPS_CMA=y +CONFIG_HD44780=m +CONFIG_KS0108=m +CONFIG_IMG_ASCII_LCD=m +CONFIG_HT16K33=m +CONFIG_LCD2S=m +CONFIG_PANEL=m +CONFIG_UIO_CIF=m +CONFIG_UIO_PDRV_GENIRQ=m +CONFIG_UIO_DMEM_GENIRQ=m +CONFIG_UIO_AEC=m +CONFIG_UIO_SERCOS3=m +CONFIG_UIO_PCI_GENERIC=m +CONFIG_UIO_NETX=m +CONFIG_UIO_PRUSS=m +CONFIG_UIO_MF624=m +CONFIG_UIO_DFL=m +CONFIG_VFIO=m +CONFIG_VFIO_NOIOMMU=y +CONFIG_VFIO_PCI=m +CONFIG_MLX5_VFIO_PCI=m +CONFIG_VIRT_DRIVERS=y +CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO_VDPA=m +CONFIG_VIRTIO_PMEM=m +CONFIG_VIRTIO_BALLOON=y +CONFIG_VIRTIO_INPUT=m +CONFIG_VIRTIO_MMIO=y +CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y +CONFIG_VDPA=m +CONFIG_VDPA_SIM=m +CONFIG_VDPA_SIM_NET=m +CONFIG_VDPA_SIM_BLOCK=m +CONFIG_VDPA_USER=m +CONFIG_IFCVF=m +CONFIG_MLX5_VDPA_NET=m +CONFIG_VP_VDPA=m +CONFIG_VHOST_NET=m +CONFIG_VHOST_SCSI=m +CONFIG_VHOST_VSOCK=m +CONFIG_VHOST_VDPA=m +CONFIG_COMEDI=m +CONFIG_COMEDI_MISC_DRIVERS=y +CONFIG_COMEDI_BOND=m +CONFIG_COMEDI_TEST=m +CONFIG_COMEDI_PARPORT=m +CONFIG_COMEDI_ISA_DRIVERS=y +CONFIG_COMEDI_PCL711=m +CONFIG_COMEDI_PCL724=m +CONFIG_COMEDI_PCL726=m +CONFIG_COMEDI_PCL730=m +CONFIG_COMEDI_PCL812=m +CONFIG_COMEDI_PCL816=m +CONFIG_COMEDI_PCL818=m +CONFIG_COMEDI_PCM3724=m +CONFIG_COMEDI_AMPLC_DIO200_ISA=m +CONFIG_COMEDI_AMPLC_PC236_ISA=m +CONFIG_COMEDI_AMPLC_PC263_ISA=m +CONFIG_COMEDI_RTI800=m +CONFIG_COMEDI_RTI802=m +CONFIG_COMEDI_DAC02=m +CONFIG_COMEDI_DAS16M1=m +CONFIG_COMEDI_DAS08_ISA=m +CONFIG_COMEDI_DAS16=m +CONFIG_COMEDI_DAS800=m +CONFIG_COMEDI_DAS1800=m +CONFIG_COMEDI_DAS6402=m +CONFIG_COMEDI_DT2801=m +CONFIG_COMEDI_DT2811=m +CONFIG_COMEDI_DT2814=m +CONFIG_COMEDI_DT2815=m +CONFIG_COMEDI_DT2817=m +CONFIG_COMEDI_DT282X=m +CONFIG_COMEDI_DMM32AT=m +CONFIG_COMEDI_FL512=m +CONFIG_COMEDI_AIO_AIO12_8=m +CONFIG_COMEDI_AIO_IIRO_16=m +CONFIG_COMEDI_II_PCI20KC=m +CONFIG_COMEDI_C6XDIGIO=m +CONFIG_COMEDI_MPC624=m +CONFIG_COMEDI_ADQ12B=m +CONFIG_COMEDI_NI_AT_A2150=m +CONFIG_COMEDI_NI_AT_AO=m +CONFIG_COMEDI_NI_ATMIO=m +CONFIG_COMEDI_NI_ATMIO16D=m +CONFIG_COMEDI_NI_LABPC_ISA=m +CONFIG_COMEDI_PCMAD=m +CONFIG_COMEDI_PCMDA12=m +CONFIG_COMEDI_PCMMIO=m +CONFIG_COMEDI_PCMUIO=m +CONFIG_COMEDI_MULTIQ3=m +CONFIG_COMEDI_S526=m +CONFIG_COMEDI_PCI_DRIVERS=m +CONFIG_COMEDI_8255_PCI=m +CONFIG_COMEDI_ADDI_APCI_1032=m +CONFIG_COMEDI_ADDI_APCI_1500=m +CONFIG_COMEDI_ADDI_APCI_1516=m +CONFIG_COMEDI_ADDI_APCI_1564=m +CONFIG_COMEDI_ADDI_APCI_16XX=m +CONFIG_COMEDI_ADDI_APCI_2032=m +CONFIG_COMEDI_ADDI_APCI_2200=m +CONFIG_COMEDI_ADDI_APCI_3120=m +CONFIG_COMEDI_ADDI_APCI_3501=m +CONFIG_COMEDI_ADDI_APCI_3XXX=m +CONFIG_COMEDI_ADL_PCI6208=m +CONFIG_COMEDI_ADL_PCI7X3X=m +CONFIG_COMEDI_ADL_PCI8164=m +CONFIG_COMEDI_ADL_PCI9111=m +CONFIG_COMEDI_ADL_PCI9118=m +CONFIG_COMEDI_ADV_PCI1710=m +CONFIG_COMEDI_ADV_PCI1720=m +CONFIG_COMEDI_ADV_PCI1723=m +CONFIG_COMEDI_ADV_PCI1724=m +CONFIG_COMEDI_ADV_PCI1760=m +CONFIG_COMEDI_ADV_PCI_DIO=m +CONFIG_COMEDI_AMPLC_DIO200_PCI=m +CONFIG_COMEDI_AMPLC_PC236_PCI=m +CONFIG_COMEDI_AMPLC_PC263_PCI=m +CONFIG_COMEDI_AMPLC_PCI224=m +CONFIG_COMEDI_AMPLC_PCI230=m +CONFIG_COMEDI_CONTEC_PCI_DIO=m +CONFIG_COMEDI_DAS08_PCI=m +CONFIG_COMEDI_DT3000=m +CONFIG_COMEDI_DYNA_PCI10XX=m +CONFIG_COMEDI_GSC_HPDI=m +CONFIG_COMEDI_MF6X4=m +CONFIG_COMEDI_ICP_MULTI=m +CONFIG_COMEDI_DAQBOARD2000=m +CONFIG_COMEDI_JR3_PCI=m +CONFIG_COMEDI_KE_COUNTER=m +CONFIG_COMEDI_CB_PCIDAS64=m +CONFIG_COMEDI_CB_PCIDAS=m +CONFIG_COMEDI_CB_PCIDDA=m +CONFIG_COMEDI_CB_PCIMDAS=m +CONFIG_COMEDI_CB_PCIMDDA=m +CONFIG_COMEDI_ME4000=m +CONFIG_COMEDI_ME_DAQ=m +CONFIG_COMEDI_NI_6527=m +CONFIG_COMEDI_NI_65XX=m +CONFIG_COMEDI_NI_660X=m +CONFIG_COMEDI_NI_670X=m +CONFIG_COMEDI_NI_LABPC_PCI=m +CONFIG_COMEDI_NI_PCIDIO=m +CONFIG_COMEDI_NI_PCIMIO=m +CONFIG_COMEDI_RTD520=m +CONFIG_COMEDI_S626=m +CONFIG_COMEDI_USB_DRIVERS=m +CONFIG_COMEDI_DT9812=m +CONFIG_COMEDI_NI_USB6501=m +CONFIG_COMEDI_USBDUX=m +CONFIG_COMEDI_USBDUXFAST=m +CONFIG_COMEDI_USBDUXSIGMA=m +CONFIG_COMEDI_VMK80XX=m +CONFIG_COMEDI_8255_SA=m +CONFIG_COMEDI_TESTS=m +CONFIG_COMEDI_TESTS_EXAMPLE=m +CONFIG_COMEDI_TESTS_NI_ROUTES=m +CONFIG_STAGING=y +CONFIG_PRISM2_USB=m +CONFIG_RTL8192U=m +CONFIG_RTLLIB=m +CONFIG_RTL8192E=m +CONFIG_RTL8723BS=m +CONFIG_R8712U=m +CONFIG_R8188EU=m +CONFIG_RTS5208=m +CONFIG_VT6655=m +CONFIG_VT6656=m +CONFIG_ADIS16203=m +CONFIG_ADIS16240=m +CONFIG_AD7816=m +CONFIG_ADT7316=m +CONFIG_ADT7316_I2C=m +CONFIG_AD9832=m +CONFIG_AD9834=m +CONFIG_AD5933=m +CONFIG_ADE7854=m +CONFIG_AD2S1210=m +CONFIG_FB_SM750=m +CONFIG_STAGING_MEDIA=y +CONFIG_VIDEO_MAX96712=m +CONFIG_LTE_GDM724X=m +CONFIG_FB_TFT=m +CONFIG_FB_TFT_AGM1264K_FL=m +CONFIG_FB_TFT_BD663474=m +CONFIG_FB_TFT_HX8340BN=m +CONFIG_FB_TFT_HX8347D=m +CONFIG_FB_TFT_HX8353D=m +CONFIG_FB_TFT_HX8357D=m +CONFIG_FB_TFT_ILI9163=m +CONFIG_FB_TFT_ILI9320=m +CONFIG_FB_TFT_ILI9325=m +CONFIG_FB_TFT_ILI9340=m +CONFIG_FB_TFT_ILI9341=m +CONFIG_FB_TFT_ILI9481=m +CONFIG_FB_TFT_ILI9486=m +CONFIG_FB_TFT_PCD8544=m +CONFIG_FB_TFT_RA8875=m +CONFIG_FB_TFT_S6D02A1=m +CONFIG_FB_TFT_S6D1121=m +CONFIG_FB_TFT_SEPS525=m +CONFIG_FB_TFT_SH1106=m +CONFIG_FB_TFT_SSD1289=m +CONFIG_FB_TFT_SSD1305=m +CONFIG_FB_TFT_SSD1306=m +CONFIG_FB_TFT_SSD1331=m +CONFIG_FB_TFT_SSD1351=m +CONFIG_FB_TFT_ST7735R=m +CONFIG_FB_TFT_ST7789V=m +CONFIG_FB_TFT_TINYLCD=m +CONFIG_FB_TFT_TLS8204=m +CONFIG_FB_TFT_UC1611=m +CONFIG_FB_TFT_UC1701=m +CONFIG_FB_TFT_UPD161704=m +CONFIG_MOST_COMPONENTS=m +CONFIG_MOST_NET=m +CONFIG_MOST_VIDEO=m +CONFIG_MOST_DIM2=m +CONFIG_MOST_I2C=m +CONFIG_KS7010=m +CONFIG_PI433=m +CONFIG_XIL_AXIS_FIFO=m +CONFIG_FIELDBUS_DEV=m +CONFIG_HMS_ANYBUSS_BUS=m +CONFIG_ARCX_ANYBUS_CONTROLLER=m +CONFIG_HMS_PROFINET=m +CONFIG_QLGE=m +CONFIG_VME_BUS=y +CONFIG_VME_TSI148=m +CONFIG_VME_FAKE=m +CONFIG_VME_USER=m +CONFIG_GOLDFISH_PIPE=m +CONFIG_COMMON_CLK_WM831X=m +CONFIG_LMK04832=m +CONFIG_COMMON_CLK_MAX77686=m +CONFIG_COMMON_CLK_MAX9485=m +CONFIG_COMMON_CLK_RK808=m +CONFIG_COMMON_CLK_SI5341=m +CONFIG_COMMON_CLK_SI5351=m +CONFIG_COMMON_CLK_SI514=m +CONFIG_COMMON_CLK_SI544=m +CONFIG_COMMON_CLK_SI570=m +CONFIG_COMMON_CLK_CDCE706=m +CONFIG_COMMON_CLK_CDCE925=m +CONFIG_COMMON_CLK_CS2000_CP=m +CONFIG_COMMON_CLK_S2MPS11=m +CONFIG_CLK_TWL6040=m +CONFIG_COMMON_CLK_AXI_CLKGEN=m +CONFIG_COMMON_CLK_LOCHNAGAR=m +CONFIG_COMMON_CLK_PALMAS=m +CONFIG_COMMON_CLK_PWM=m +CONFIG_COMMON_CLK_RS9_PCIE=m +CONFIG_COMMON_CLK_VC5=m +CONFIG_COMMON_CLK_BD718XX=m +CONFIG_COMMON_CLK_FIXED_MMIO=y +CONFIG_XILINX_VCU=m +CONFIG_HWSPINLOCK=y +CONFIG_MAILBOX=y +CONFIG_PLATFORM_MHU=m +CONFIG_ALTERA_MBOX=m +CONFIG_MAILBOX_TEST=m +CONFIG_POLARFIRE_SOC_MAILBOX=m +CONFIG_RPMSG_CHAR=m +CONFIG_RPMSG_CTRL=m +CONFIG_RPMSG_QCOM_GLINK_RPM=m +CONFIG_RPMSG_VIRTIO=m +CONFIG_SOUNDWIRE=m +CONFIG_SOUNDWIRE_QCOM=m +CONFIG_LITEX_SOC_CONTROLLER=m +CONFIG_POLARFIRE_SOC_SYS_CTRL=m +CONFIG_SOC_TI=y +CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y +CONFIG_DEVFREQ_GOV_PERFORMANCE=y +CONFIG_DEVFREQ_GOV_POWERSAVE=y +CONFIG_DEVFREQ_GOV_USERSPACE=y +CONFIG_DEVFREQ_GOV_PASSIVE=y +CONFIG_PM_DEVFREQ_EVENT=y +CONFIG_EXTCON_ADC_JACK=m +CONFIG_EXTCON_FSA9480=m +CONFIG_EXTCON_GPIO=m +CONFIG_EXTCON_MAX14577=m +CONFIG_EXTCON_MAX3355=m +CONFIG_EXTCON_MAX77693=m +CONFIG_EXTCON_MAX77843=m +CONFIG_EXTCON_MAX8997=m +CONFIG_EXTCON_PALMAS=m +CONFIG_EXTCON_PTN5150=m +CONFIG_EXTCON_RT8973A=m +CONFIG_EXTCON_SM5502=m +CONFIG_EXTCON_USB_GPIO=m +CONFIG_EXTCON_USBC_TUSB320=m +CONFIG_MEMORY=y +CONFIG_FPGA_DFL_EMIF=m +CONFIG_IIO_SW_DEVICE=m +CONFIG_IIO_SW_TRIGGER=m +CONFIG_ADIS16201=m +CONFIG_ADIS16209=m +CONFIG_ADXL313_I2C=m +CONFIG_ADXL313_SPI=m +CONFIG_ADXL355_I2C=m +CONFIG_ADXL355_SPI=m +CONFIG_ADXL367_SPI=m +CONFIG_ADXL367_I2C=m +CONFIG_ADXL372_SPI=m +CONFIG_ADXL372_I2C=m +CONFIG_BMA220=m +CONFIG_BMA400=m +CONFIG_BMC150_ACCEL=m +CONFIG_BMI088_ACCEL=m +CONFIG_DA280=m +CONFIG_DA311=m +CONFIG_DMARD06=m +CONFIG_DMARD09=m +CONFIG_DMARD10=m +CONFIG_FXLS8962AF_I2C=m +CONFIG_FXLS8962AF_SPI=m +CONFIG_HID_SENSOR_ACCEL_3D=m +CONFIG_KXSD9=m +CONFIG_KXCJK1013=m +CONFIG_MC3230=m +CONFIG_MMA7455_I2C=m +CONFIG_MMA7455_SPI=m +CONFIG_MMA7660=m +CONFIG_MMA8452=m +CONFIG_MMA9551=m +CONFIG_MMA9553=m +CONFIG_MXC4005=m +CONFIG_MXC6255=m +CONFIG_SCA3000=m +CONFIG_SCA3300=m +CONFIG_STK8312=m +CONFIG_STK8BA50=m +CONFIG_AD7091R5=m +CONFIG_AD7124=m +CONFIG_AD7192=m +CONFIG_AD7266=m +CONFIG_AD7280=m +CONFIG_AD7291=m +CONFIG_AD7292=m +CONFIG_AD7298=m +CONFIG_AD7476=m +CONFIG_AD7606_IFACE_PARALLEL=m +CONFIG_AD7606_IFACE_SPI=m +CONFIG_AD7766=m +CONFIG_AD7768_1=m +CONFIG_AD7780=m +CONFIG_AD7791=m +CONFIG_AD7793=m +CONFIG_AD7887=m +CONFIG_AD7923=m +CONFIG_AD7949=m +CONFIG_AD799X=m +CONFIG_AD9467=m +CONFIG_ADI_AXI_ADC=m +CONFIG_AXP20X_ADC=m +CONFIG_AXP288_ADC=m +CONFIG_CC10001_ADC=m +CONFIG_CPCAP_ADC=m +CONFIG_DA9150_GPADC=m +CONFIG_DLN2_ADC=m +CONFIG_ENVELOPE_DETECTOR=m +CONFIG_HI8435=m +CONFIG_HX711=m +CONFIG_INA2XX_ADC=m +CONFIG_LP8788_ADC=m +CONFIG_LTC2471=m +CONFIG_LTC2485=m +CONFIG_LTC2496=m +CONFIG_LTC2497=m +CONFIG_MAX1027=m +CONFIG_MAX11100=m +CONFIG_MAX1118=m +CONFIG_MAX1241=m +CONFIG_MAX1363=m +CONFIG_MAX9611=m +CONFIG_MCP320X=m +CONFIG_MCP3422=m +CONFIG_MCP3911=m +CONFIG_MEDIATEK_MT6360_ADC=m +CONFIG_MEN_Z188_ADC=m +CONFIG_MP2629_ADC=m +CONFIG_NAU7802=m +CONFIG_PALMAS_GPADC=m +CONFIG_QCOM_SPMI_IADC=m +CONFIG_QCOM_SPMI_VADC=m +CONFIG_QCOM_SPMI_ADC5=m +CONFIG_RN5T618_ADC=m +CONFIG_SD_ADC_MODULATOR=m +CONFIG_STMPE_ADC=m +CONFIG_TI_ADC081C=m +CONFIG_TI_ADC0832=m +CONFIG_TI_ADC084S021=m +CONFIG_TI_ADC12138=m +CONFIG_TI_ADC108S102=m +CONFIG_TI_ADC128S052=m +CONFIG_TI_ADC161S626=m +CONFIG_TI_ADS1015=m +CONFIG_TI_ADS7950=m +CONFIG_TI_ADS8344=m +CONFIG_TI_ADS8688=m +CONFIG_TI_ADS124S08=m +CONFIG_TI_ADS131E08=m +CONFIG_TI_AM335X_ADC=m +CONFIG_TI_TLC4541=m +CONFIG_TI_TSC2046=m +CONFIG_TWL4030_MADC=m +CONFIG_TWL6030_GPADC=m +CONFIG_VF610_ADC=m +CONFIG_VIPERBOARD_ADC=m +CONFIG_XILINX_XADC=m +CONFIG_AD74413R=m +CONFIG_IIO_RESCALE=m +CONFIG_AD8366=m +CONFIG_ADA4250=m +CONFIG_HMC425=m +CONFIG_AD7150=m +CONFIG_AD7746=m +CONFIG_ATLAS_PH_SENSOR=m +CONFIG_ATLAS_EZO_SENSOR=m +CONFIG_BME680=m +CONFIG_CCS811=m +CONFIG_IAQCORE=m +CONFIG_PMS7003=m +CONFIG_SCD30_CORE=m +CONFIG_SCD30_I2C=m +CONFIG_SCD30_SERIAL=m +CONFIG_SCD4X=m +CONFIG_SENSIRION_SGP30=m +CONFIG_SENSIRION_SGP40=m +CONFIG_SPS30_I2C=m +CONFIG_SPS30_SERIAL=m +CONFIG_SENSEAIR_SUNRISE_CO2=m +CONFIG_VZ89X=m +CONFIG_IIO_SSP_SENSORS_COMMONS=m +CONFIG_IIO_SSP_SENSORHUB=m +CONFIG_AD3552R=m +CONFIG_AD5064=m +CONFIG_AD5360=m +CONFIG_AD5380=m +CONFIG_AD5421=m +CONFIG_AD5446=m +CONFIG_AD5449=m +CONFIG_AD5592R=m +CONFIG_AD5593R=m +CONFIG_AD5504=m +CONFIG_AD5624R_SPI=m +CONFIG_LTC2688=m +CONFIG_AD5686_SPI=m +CONFIG_AD5696_I2C=m +CONFIG_AD5755=m +CONFIG_AD5758=m +CONFIG_AD5761=m +CONFIG_AD5764=m +CONFIG_AD5766=m +CONFIG_AD5770R=m +CONFIG_AD5791=m +CONFIG_AD7293=m +CONFIG_AD7303=m +CONFIG_AD8801=m +CONFIG_DPOT_DAC=m +CONFIG_DS4424=m +CONFIG_LTC1660=m +CONFIG_LTC2632=m +CONFIG_M62332=m +CONFIG_MAX517=m +CONFIG_MAX5821=m +CONFIG_MCP4725=m +CONFIG_MCP4922=m +CONFIG_TI_DAC082S085=m +CONFIG_TI_DAC5571=m +CONFIG_TI_DAC7311=m +CONFIG_TI_DAC7612=m +CONFIG_VF610_DAC=m +CONFIG_IIO_SIMPLE_DUMMY=m +CONFIG_ADMV8818=m +CONFIG_AD9523=m +CONFIG_ADF4350=m +CONFIG_ADF4371=m +CONFIG_ADMV1013=m +CONFIG_ADMV1014=m +CONFIG_ADMV4420=m +CONFIG_ADRF6780=m +CONFIG_ADIS16080=m +CONFIG_ADIS16130=m +CONFIG_ADIS16136=m +CONFIG_ADIS16260=m +CONFIG_ADXRS290=m +CONFIG_ADXRS450=m +CONFIG_BMG160=m +CONFIG_FXAS21002C=m +CONFIG_HID_SENSOR_GYRO_3D=m +CONFIG_MPU3050_I2C=m +CONFIG_IIO_ST_GYRO_3AXIS=m +CONFIG_ITG3200=m +CONFIG_AFE4403=m +CONFIG_AFE4404=m +CONFIG_MAX30100=m +CONFIG_MAX30102=m +CONFIG_AM2315=m +CONFIG_DHT11=m +CONFIG_HDC100X=m +CONFIG_HDC2010=m +CONFIG_HID_SENSOR_HUMIDITY=m +CONFIG_HTS221=m +CONFIG_HTU21=m +CONFIG_SI7005=m +CONFIG_SI7020=m +CONFIG_ADIS16400=m +CONFIG_ADIS16460=m +CONFIG_ADIS16475=m +CONFIG_ADIS16480=m +CONFIG_BMI160_I2C=m +CONFIG_BMI160_SPI=m +CONFIG_FXOS8700_I2C=m +CONFIG_FXOS8700_SPI=m +CONFIG_KMX61=m +CONFIG_INV_ICM42600_I2C=m +CONFIG_INV_ICM42600_SPI=m +CONFIG_INV_MPU6050_I2C=m +CONFIG_INV_MPU6050_SPI=m +CONFIG_IIO_ST_LSM6DSX=m +CONFIG_IIO_ST_LSM9DS0=m +CONFIG_ADJD_S311=m +CONFIG_ADUX1020=m +CONFIG_AL3010=m +CONFIG_AL3320A=m +CONFIG_APDS9300=m +CONFIG_APDS9960=m +CONFIG_AS73211=m +CONFIG_BH1750=m +CONFIG_BH1780=m +CONFIG_CM32181=m +CONFIG_CM3232=m +CONFIG_CM3323=m +CONFIG_CM3605=m +CONFIG_CM36651=m +CONFIG_GP2AP002=m +CONFIG_GP2AP020A00F=m +CONFIG_IQS621_ALS=m +CONFIG_SENSORS_ISL29018=m +CONFIG_SENSORS_ISL29028=m +CONFIG_ISL29125=m +CONFIG_HID_SENSOR_ALS=m +CONFIG_HID_SENSOR_PROX=m +CONFIG_JSA1212=m +CONFIG_RPR0521=m +CONFIG_SENSORS_LM3533=m +CONFIG_LTR501=m +CONFIG_LV0104CS=m +CONFIG_MAX44000=m +CONFIG_MAX44009=m +CONFIG_NOA1305=m +CONFIG_OPT3001=m +CONFIG_PA12203001=m +CONFIG_SI1133=m +CONFIG_SI1145=m +CONFIG_STK3310=m +CONFIG_ST_UVIS25=m +CONFIG_TCS3414=m +CONFIG_TCS3472=m +CONFIG_SENSORS_TSL2563=m +CONFIG_TSL2583=m +CONFIG_TSL2591=m +CONFIG_TSL2772=m +CONFIG_TSL4531=m +CONFIG_US5182D=m +CONFIG_VCNL4000=m +CONFIG_VCNL4035=m +CONFIG_VEML6030=m +CONFIG_VEML6070=m +CONFIG_VL6180=m +CONFIG_ZOPT2201=m +CONFIG_AK8974=m +CONFIG_AK09911=m +CONFIG_BMC150_MAGN_I2C=m +CONFIG_BMC150_MAGN_SPI=m +CONFIG_MAG3110=m +CONFIG_HID_SENSOR_MAGNETOMETER_3D=m +CONFIG_MMC35240=m +CONFIG_SENSORS_HMC5843_I2C=m +CONFIG_SENSORS_HMC5843_SPI=m +CONFIG_SENSORS_RM3100_I2C=m +CONFIG_SENSORS_RM3100_SPI=m +CONFIG_YAMAHA_YAS530=m +CONFIG_IIO_MUX=m +CONFIG_HID_SENSOR_INCLINOMETER_3D=m +CONFIG_HID_SENSOR_DEVICE_ROTATION=m +CONFIG_IIO_HRTIMER_TRIGGER=m +CONFIG_IIO_INTERRUPT_TRIGGER=m +CONFIG_IIO_TIGHTLOOP_TRIGGER=m +CONFIG_IIO_SYSFS_TRIGGER=m +CONFIG_IQS624_POS=m +CONFIG_HID_SENSOR_CUSTOM_INTEL_HINGE=m +CONFIG_AD5110=m +CONFIG_AD5272=m +CONFIG_DS1803=m +CONFIG_MAX5432=m +CONFIG_MAX5481=m +CONFIG_MAX5487=m +CONFIG_MCP4018=m +CONFIG_MCP4131=m +CONFIG_MCP4531=m +CONFIG_MCP41010=m +CONFIG_TPL0102=m +CONFIG_LMP91000=m +CONFIG_ABP060MG=m +CONFIG_BMP280=m +CONFIG_DLHL60D=m +CONFIG_DPS310=m +CONFIG_HID_SENSOR_PRESS=m +CONFIG_HP03=m +CONFIG_ICP10100=m +CONFIG_MPL115_I2C=m +CONFIG_MPL115_SPI=m +CONFIG_MPL3115=m +CONFIG_MS5611=m +CONFIG_MS5611_I2C=m +CONFIG_MS5611_SPI=m +CONFIG_MS5637=m +CONFIG_IIO_ST_PRESS=m +CONFIG_T5403=m +CONFIG_HP206C=m +CONFIG_ZPA2326=m +CONFIG_AS3935=m +CONFIG_ISL29501=m +CONFIG_LIDAR_LITE_V2=m +CONFIG_MB1232=m +CONFIG_PING=m +CONFIG_RFD77402=m +CONFIG_SRF04=m +CONFIG_SX9310=m +CONFIG_SX9324=m +CONFIG_SX9360=m +CONFIG_SX9500=m +CONFIG_SRF08=m +CONFIG_VCNL3020=m +CONFIG_VL53L0X_I2C=m +CONFIG_AD2S90=m +CONFIG_AD2S1200=m +CONFIG_IQS620AT_TEMP=m +CONFIG_LTC2983=m +CONFIG_MAXIM_THERMOCOUPLE=m +CONFIG_HID_SENSOR_TEMP=m +CONFIG_MLX90614=m +CONFIG_MLX90632=m +CONFIG_TMP006=m +CONFIG_TMP007=m +CONFIG_TMP117=m +CONFIG_TSYS01=m +CONFIG_TSYS02D=m +CONFIG_MAX31856=m +CONFIG_MAX31865=m +CONFIG_NTB=m +CONFIG_NTB_MSI=y +CONFIG_NTB_IDT=m +CONFIG_NTB_EPF=m +CONFIG_NTB_SWITCHTEC=m +CONFIG_NTB_PINGPONG=m +CONFIG_NTB_TOOL=m +CONFIG_NTB_PERF=m +CONFIG_NTB_TRANSPORT=m +CONFIG_PWM=y +CONFIG_PWM_ATMEL_HLCDC_PWM=m +CONFIG_PWM_ATMEL_TCB=m +CONFIG_PWM_DWC=m +CONFIG_PWM_FSL_FTM=m +CONFIG_PWM_IQS620A=m +CONFIG_PWM_LP3943=m +CONFIG_PWM_NTXEC=m +CONFIG_PWM_PCA9685=m +CONFIG_PWM_SIFIVE=m +CONFIG_PWM_STMPE=y +CONFIG_PWM_TWL=m +CONFIG_PWM_TWL_LED=m +CONFIG_PWM_XILINX=m +CONFIG_AL_FIC=y +CONFIG_XILINX_INTC=y +CONFIG_IPACK_BUS=m +CONFIG_BOARD_TPCI200=m +CONFIG_SERIAL_IPOCTAL=m +CONFIG_RESET_TI_SYSCON=m +CONFIG_PHY_CAN_TRANSCEIVER=m +CONFIG_BCM_KONA_USB2_PHY=m +CONFIG_PHY_CADENCE_TORRENT=m +CONFIG_PHY_CADENCE_DPHY=m +CONFIG_PHY_CADENCE_DPHY_RX=m +CONFIG_PHY_CADENCE_SIERRA=m +CONFIG_PHY_CADENCE_SALVO=m +CONFIG_PHY_PXA_28NM_HSIC=m +CONFIG_PHY_PXA_28NM_USB2=m +CONFIG_PHY_LAN966X_SERDES=m +CONFIG_PHY_CPCAP_USB=m +CONFIG_PHY_MAPPHONE_MDM6600=m +CONFIG_PHY_OCELOT_SERDES=m +CONFIG_PHY_QCOM_USB_HS=m +CONFIG_PHY_QCOM_USB_HSIC=m +CONFIG_PHY_SAMSUNG_USB2=m +CONFIG_PHY_TUSB1210=m +CONFIG_POWERCAP=y +CONFIG_IDLE_INJECT=y +CONFIG_DTPM=y +CONFIG_MCB=m +CONFIG_MCB_PCI=m +CONFIG_MCB_LPC=m +CONFIG_USB4=m +CONFIG_LIBNVDIMM=y +CONFIG_BLK_DEV_PMEM=m +CONFIG_OF_PMEM=m +CONFIG_DAX=y +CONFIG_DEV_DAX=m +CONFIG_NVMEM_RMEM=m +CONFIG_NVMEM_SPMI_SDAM=m +CONFIG_STM=m +CONFIG_STM_PROTO_BASIC=m +CONFIG_STM_PROTO_SYS_T=m +CONFIG_STM_DUMMY=m +CONFIG_STM_SOURCE_CONSOLE=m +CONFIG_STM_SOURCE_HEARTBEAT=m +CONFIG_STM_SOURCE_FTRACE=m +CONFIG_INTEL_TH=m +CONFIG_INTEL_TH_PCI=m +CONFIG_INTEL_TH_GTH=m +CONFIG_INTEL_TH_STH=m +CONFIG_INTEL_TH_MSU=m +CONFIG_INTEL_TH_PTI=m +CONFIG_FPGA=m +CONFIG_ALTERA_PR_IP_CORE=m +CONFIG_ALTERA_PR_IP_CORE_PLAT=m +CONFIG_FPGA_MGR_ALTERA_PS_SPI=m +CONFIG_FPGA_MGR_ALTERA_CVP=m +CONFIG_FPGA_MGR_XILINX_SPI=m +CONFIG_FPGA_MGR_ICE40_SPI=m +CONFIG_FPGA_MGR_MACHXO2_SPI=m +CONFIG_ALTERA_FREEZE_BRIDGE=m +CONFIG_XILINX_PR_DECOUPLER=m +CONFIG_OF_FPGA_REGION=m +CONFIG_FPGA_DFL=m +CONFIG_FPGA_DFL_FME=m +CONFIG_FPGA_DFL_FME_MGR=m +CONFIG_FPGA_DFL_FME_BRIDGE=m +CONFIG_FPGA_DFL_FME_REGION=m +CONFIG_FPGA_DFL_AFU=m +CONFIG_FPGA_DFL_NIOS_INTEL_PAC_N3000=m +CONFIG_FPGA_DFL_PCI=m +CONFIG_FSI=m +CONFIG_FSI_MASTER_GPIO=m +CONFIG_FSI_MASTER_HUB=m +CONFIG_FSI_MASTER_ASPEED=m +CONFIG_FSI_SCOM=m +CONFIG_FSI_SBEFIFO=m +CONFIG_FSI_OCC=m +CONFIG_MUX_ADG792A=m +CONFIG_MUX_ADGS1408=m +CONFIG_MUX_GPIO=m +CONFIG_MUX_MMIO=m +CONFIG_SIOX=m +CONFIG_SIOX_BUS_GPIO=m +CONFIG_SLIM_QCOM_CTRL=m +CONFIG_INTERCONNECT=y +CONFIG_MOST=m +CONFIG_MOST_USB_HDM=m +CONFIG_MOST_CDEV=m +CONFIG_MOST_SND=m +CONFIG_PECI=m +CONFIG_VALIDATE_FS_PARSER=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_REISERFS_FS=m +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +CONFIG_JFS_FS=m +CONFIG_JFS_POSIX_ACL=y +CONFIG_JFS_SECURITY=y +CONFIG_JFS_STATISTICS=y +CONFIG_XFS_FS=y +CONFIG_XFS_QUOTA=y +CONFIG_XFS_POSIX_ACL=y +CONFIG_XFS_RT=y +CONFIG_GFS2_FS=m +CONFIG_GFS2_FS_LOCKING_DLM=y +CONFIG_OCFS2_FS=m +CONFIG_BTRFS_FS=y +CONFIG_BTRFS_FS_POSIX_ACL=y +CONFIG_NILFS2_FS=m +CONFIG_F2FS_FS=y +CONFIG_F2FS_FS_SECURITY=y +CONFIG_F2FS_FS_COMPRESSION=y +# CONFIG_F2FS_IOSTAT is not set +CONFIG_F2FS_UNFAIR_RWSEM=y +CONFIG_ZONEFS_FS=m +CONFIG_FS_ENCRYPTION=y +CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y +CONFIG_FS_VERITY=y +CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y +CONFIG_FANOTIFY=y +CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +# CONFIG_PRINT_QUOTA_WARNING is not set +CONFIG_QFMT_V1=m +CONFIG_QFMT_V2=y +CONFIG_AUTOFS4_FS=m +CONFIG_FUSE_FS=y +CONFIG_CUSE=m +CONFIG_VIRTIO_FS=m +CONFIG_OVERLAY_FS=m +CONFIG_OVERLAY_FS_XINO_AUTO=y +CONFIG_FSCACHE=m +CONFIG_FSCACHE_STATS=y +CONFIG_CACHEFILES=m +CONFIG_CACHEFILES_ERROR_INJECTION=y +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=y +CONFIG_EXFAT_FS=m +CONFIG_NTFS_FS=m +CONFIG_NTFS3_FS=m +CONFIG_NTFS3_LZX_XPRESS=y +CONFIG_NTFS3_FS_POSIX_ACL=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_VMCORE_DEVICE_DUMP=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS_INODE64=y +CONFIG_HUGETLBFS=y +CONFIG_EFIVAR_FS=y +CONFIG_ORANGEFS_FS=m +CONFIG_ADFS_FS=m +CONFIG_AFFS_FS=m +CONFIG_ECRYPT_FS=y +CONFIG_ECRYPT_FS_MESSAGING=y +CONFIG_HFS_FS=m +CONFIG_HFSPLUS_FS=m +CONFIG_BEFS_FS=m +CONFIG_BFS_FS=m +CONFIG_EFS_FS=m +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_XATTR=y +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_CMODE_FAVOURLZO=y +CONFIG_UBIFS_FS=m +CONFIG_UBIFS_FS_AUTHENTICATION=y +CONFIG_CRAMFS=m +CONFIG_CRAMFS_MTD=y +CONFIG_SQUASHFS=y +CONFIG_SQUASHFS_FILE_DIRECT=y +CONFIG_SQUASHFS_XATTR=y +CONFIG_SQUASHFS_LZ4=y +CONFIG_SQUASHFS_LZO=y +CONFIG_SQUASHFS_XZ=y +CONFIG_SQUASHFS_ZSTD=y +CONFIG_VXFS_FS=m +CONFIG_MINIX_FS=m +CONFIG_OMFS_FS=m +CONFIG_HPFS_FS=m +CONFIG_QNX4FS_FS=m +CONFIG_QNX6FS_FS=m +CONFIG_ROMFS_FS=m +CONFIG_PSTORE=y +CONFIG_PSTORE_RAM=m +CONFIG_PSTORE_BLK=m +CONFIG_SYSV_FS=m +CONFIG_UFS_FS=m +CONFIG_EROFS_FS=m +CONFIG_NFS_FS=m +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=m +CONFIG_NFS_SWAP=y +CONFIG_NFS_V4_1=y +CONFIG_NFS_V4_2=y +CONFIG_NFS_V4_1_MIGRATION=y +CONFIG_NFS_FSCACHE=y +CONFIG_NFSD=m +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y +CONFIG_NFSD_BLOCKLAYOUT=y +CONFIG_NFSD_SCSILAYOUT=y +CONFIG_NFSD_FLEXFILELAYOUT=y +CONFIG_NFSD_V4_2_INTER_SSC=y +CONFIG_NFSD_V4_SECURITY_LABEL=y +CONFIG_SUNRPC_DEBUG=y +CONFIG_CEPH_FS=m +CONFIG_CEPH_FSCACHE=y +CONFIG_CEPH_FS_POSIX_ACL=y +CONFIG_CEPH_FS_SECURITY_LABEL=y +CONFIG_CIFS=m +# CONFIG_CIFS_STATS2 is not set +CONFIG_CIFS_UPCALL=y +CONFIG_CIFS_XATTR=y +CONFIG_CIFS_POSIX=y +CONFIG_CIFS_DFS_UPCALL=y +CONFIG_CIFS_SWN_UPCALL=y +CONFIG_CIFS_FSCACHE=y +CONFIG_SMB_SERVER=m +CONFIG_SMB_SERVER_SMBDIRECT=y +CONFIG_SMB_SERVER_KERBEROS5=y +CONFIG_CODA_FS=m +CONFIG_AFS_FS=m +CONFIG_AFS_FSCACHE=y +CONFIG_9P_FS=y +CONFIG_9P_FSCACHE=y +CONFIG_9P_FS_POSIX_ACL=y +CONFIG_9P_FS_SECURITY=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_MAC_ROMAN=m +CONFIG_NLS_MAC_CELTIC=m +CONFIG_NLS_MAC_CENTEURO=m +CONFIG_NLS_MAC_CROATIAN=m +CONFIG_NLS_MAC_CYRILLIC=m +CONFIG_NLS_MAC_GAELIC=m +CONFIG_NLS_MAC_GREEK=m +CONFIG_NLS_MAC_ICELAND=m +CONFIG_NLS_MAC_INUIT=m +CONFIG_NLS_MAC_ROMANIAN=m +CONFIG_NLS_MAC_TURKISH=m +CONFIG_DLM=m +CONFIG_UNICODE=y +CONFIG_KEYS_REQUEST_CACHE=y +CONFIG_PERSISTENT_KEYRINGS=y +CONFIG_TRUSTED_KEYS=y +CONFIG_USER_DECRYPTED_DATA=y +CONFIG_KEY_DH_OPERATIONS=y +CONFIG_KEY_NOTIFICATIONS=y +CONFIG_SECURITY_DMESG_RESTRICT=y +CONFIG_SECURITY=y +CONFIG_SECURITY_INFINIBAND=y +CONFIG_SECURITY_NETWORK_XFRM=y +CONFIG_LSM_MMAP_MIN_ADDR=0 +CONFIG_HARDENED_USERCOPY=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +CONFIG_SECURITY_SMACK=y +CONFIG_SECURITY_SMACK_NETFILTER=y +CONFIG_SECURITY_SMACK_APPEND_SIGNALS=y +CONFIG_SECURITY_TOMOYO=y +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_YAMA=y +CONFIG_SECURITY_SAFESETID=y +CONFIG_SECURITY_LOCKDOWN_LSM=y +CONFIG_SECURITY_LOCKDOWN_LSM_EARLY=y +CONFIG_SECURITY_LANDLOCK=y +CONFIG_INTEGRITY_SIGNATURE=y +CONFIG_INTEGRITY_ASYMMETRIC_KEYS=y +CONFIG_INTEGRITY_PLATFORM_KEYRING=y +CONFIG_INTEGRITY_MACHINE_KEYRING=y +CONFIG_IMA=y +CONFIG_IMA_KEXEC=y +CONFIG_IMA_APPRAISE=y +CONFIG_IMA_ARCH_POLICY=y +CONFIG_IMA_APPRAISE_MODSIG=y +CONFIG_EVM=y +CONFIG_EVM_EXTRA_SMACK_XATTRS=y +CONFIG_EVM_ADD_XATTRS=y +CONFIG_DEFAULT_SECURITY_APPARMOR=y +CONFIG_LSM="landlock,lockdown,yama,integrity,apparmor" +CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y +CONFIG_CRYPTO_USER=m +CONFIG_CRYPTO_PCRYPT=m +CONFIG_CRYPTO_CRYPTD=m +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_DH_RFC7919_GROUPS=y +CONFIG_CRYPTO_ECDSA=m +CONFIG_CRYPTO_ECRDSA=m +CONFIG_CRYPTO_SM2=m +CONFIG_CRYPTO_CURVE25519=m +CONFIG_CRYPTO_AES_TI=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_ADIANTUM=m +CONFIG_CRYPTO_CFB=m +CONFIG_CRYPTO_KEYWRAP=m +CONFIG_CRYPTO_LRW=m +CONFIG_CRYPTO_OFB=m +CONFIG_CRYPTO_AEGIS128=m +CONFIG_CRYPTO_CHACHA20POLY1305=m +CONFIG_CRYPTO_GCM=y +CONFIG_CRYPTO_SEQIV=y +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_RMD160=m +CONFIG_CRYPTO_SHA3=m +CONFIG_CRYPTO_VMAC=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_XCBC=m +CONFIG_CRYPTO_842=m +CONFIG_CRYPTO_LZ4=m +CONFIG_CRYPTO_LZ4HC=m +CONFIG_CRYPTO_ANSI_CPRNG=m +CONFIG_CRYPTO_DRBG_HASH=y +CONFIG_CRYPTO_DRBG_CTR=y +CONFIG_CRYPTO_USER_API_HASH=m +CONFIG_CRYPTO_USER_API_SKCIPHER=m +CONFIG_CRYPTO_USER_API_RNG=m +CONFIG_CRYPTO_USER_API_AEAD=m +# CONFIG_CRYPTO_USER_API_ENABLE_OBSOLETE is not set +CONFIG_CRYPTO_STATS=y +CONFIG_CRYPTO_DEV_NITROX_CNN55XX=m +CONFIG_CRYPTO_DEV_CHELSIO=m +CONFIG_CRYPTO_DEV_VIRTIO=m +CONFIG_CRYPTO_DEV_CCREE=m +CONFIG_CRYPTO_DEV_AMLOGIC_GXL=m +CONFIG_PKCS8_PRIVATE_KEY_PARSER=m +CONFIG_PKCS7_TEST_KEY=m +CONFIG_SIGNED_PE_FILE_VERIFICATION=y +CONFIG_SYSTEM_EXTRA_CERTIFICATE=y +CONFIG_SECONDARY_TRUSTED_KEYRING=y +CONFIG_SYSTEM_BLACKLIST_KEYRING=y +CONFIG_SYSTEM_REVOCATION_LIST=y +CONFIG_XZ_DEC_MICROLZMA=y +CONFIG_XZ_DEC_TEST=m +CONFIG_DMA_RESTRICTED_POOL=y +CONFIG_DMA_CMA=y +CONFIG_DMA_PERNUMA_CMA=y +CONFIG_CMA_SIZE_MBYTES=32 +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_ACORN_8x8=y +CONFIG_FONT_6x10=y +CONFIG_FONT_TER16x32=y +CONFIG_PRINTK_TIME=y +CONFIG_BOOT_PRINTK_DELAY=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y +CONFIG_GDB_SCRIPTS=y +CONFIG_FRAME_WARN=1024 +CONFIG_VMLINUX_MAP=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x01b6 +CONFIG_KGDB=y +CONFIG_KGDB_KDB=y +CONFIG_KDB_KEYBOARD=y +CONFIG_PAGE_POISONING=y +CONFIG_DEBUG_WX=y +CONFIG_SCHED_STACK_END_CHECK=y +CONFIG_KFENCE=y +CONFIG_KFENCE_SAMPLE_INTERVAL=0 +CONFIG_SOFTLOCKUP_DETECTOR=y +CONFIG_SCHEDSTATS=y +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_TRACE is not set +CONFIG_BOOTTIME_TRACING=y +CONFIG_FUNCTION_PROFILER=y +CONFIG_STACK_TRACER=y +CONFIG_SCHED_TRACER=y +CONFIG_HWLAT_TRACER=y +CONFIG_FTRACE_SYSCALLS=y +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_BPF_KPROBE_OVERRIDE=y +CONFIG_SYNTH_EVENTS=y +CONFIG_TRACE_EVENT_INJECT=y +CONFIG_SAMPLES=y +CONFIG_SAMPLE_TRACE_PRINTK=m +CONFIG_SAMPLE_TRACE_ARRAY=m +CONFIG_NOTIFIER_ERROR_INJECTION=m +CONFIG_FUNCTION_ERROR_INJECTION=y +CONFIG_TEST_BPF=m +CONFIG_TEST_BLACKHOLE_DEV=m +CONFIG_MEMTEST=y +CONFIG_RELOCATABLE=y +CONFIG_RANDOMIZE_BASE=y +CONFIG_ERRATA_THEAD_MAE=y +CONFIG_ERRATA_THEAD=y +CONFIG_RISCV_USER_CFI=y +# DEBUG configs +CONFIG_DEBUG_ATOMIC_SLEEP=y +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_LOCK_ALLOC=y +CONFIG_DEBUG_RWSEMS=y +CONFIG_DEBUG_LOCKDEP=y +CONFIG_DEBUG_IRQFLAGS=y +CONFIG_DEBUG_VM=y +CONFIG_PROVE_LOCKING=y +CONFIG_SLUB_DEBUG=y +CONFIG_SLUB_DEBUG_ON=y +CONFIG_DEBUG_LIST=y +CONFIG_DEBUG_PAGEALLOC=y +CONFIG_DEBUG_PAGEALLOC_DEFAULT=y +CONFIG_DEBUG_STACK_USAGE=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y diff --git a/.github/scripts/series/kernel_builder.sh b/.github/scripts/series/kernel_builder.sh new file mode 100755 index 00000000000000..98837bf7d76e03 --- /dev/null +++ b/.github/scripts/series/kernel_builder.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2023 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +d=$(dirname "${BASH_SOURCE[0]}") +. $d/utils.sh + +xlen=$1 +config=$2 +fragment=$3 +toolchain=$4 + +tm=$(mktemp -p ${ci_root}) +n=$(gen_kernel_name $xlen $config $fragment $toolchain) +logs=$(get_logs_dir) +rc=0 +log="build_kernel___${n}.log" +\time --quiet -o $tm -f "took %es" \ + $d/build_kernel.sh "${xlen}" "${config}" "${fragment}" "${toolchain}" &> "${logs}/${log}" || rc=$? + +if grep -a ": warning:" "${logs}/${log}" | grep -qv "frame size"; then + # TODO Can't get rid of LLVM "warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]" + if [[ ! "${log}" =~ "nommu" ]]; then + echo "::error::FAIL WARNINGS kernel ${n} \"${log}\" $(cat $tm)" + fi +elif (( $rc )); then + echo "::error::FAIL Build kernel ${n} \"${log}\" $(cat $tm)" +else + echo "::notice::OK Build kernel ${n} $(cat $tm)" +fi +rm $tm +exit $rc diff --git a/.github/scripts/series/kernel_tester.sh b/.github/scripts/series/kernel_tester.sh new file mode 100755 index 00000000000000..a1912ddb74e1cf --- /dev/null +++ b/.github/scripts/series/kernel_tester.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2023 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +d=$(dirname "${BASH_SOURCE[0]}") +. $d/utils.sh +. $d/qemu_test_utils.sh + +xlen=$1 +config=$2 +fragment=$3 +toolchain=$4 +rootfs=$5 + +generate_qemu_subtests $xlen $config $fragment $toolchain $rootfs + +tm=$(mktemp -p ${ci_root}) +n=$(gen_kernel_name $xlen $config $fragment $toolchain) +logs=$(get_logs_dir) +tot=${#qemu_subtests[@]} +allrc=0 +for i in $(seq $tot); do + rc=0 + tstn=$(get_qemu_test_name ${qemu_subtests[$(($i - 1))]}) + tst=${qemu_subtests[$(($i - 1))]} + + log="test_kernel___${n}___${rootfs}___${tstn}.log" + \time --quiet -o $tm -f "took %es" \ + $d/test_kernel.sh "${xlen}" "${config}" "${fragment}" "${toolchain}" "${rootfs}" \ + $tst &> "${logs}/${log}" || rc=$? + if (( $rc )); then + allrc=1 + echo "::error::FAIL Test kernel ${n} ${rootfs} ${tst} $i/$tot \"${log}\" $(cat $tm)" + else + echo "::notice::OK Test kernel ${n} ${rootfs} ${tst} $i/$tot $(cat $tm)" + fi +done +rm $tm +exit $allrc diff --git a/.github/scripts/series/kselftest_prep.sh b/.github/scripts/series/kselftest_prep.sh new file mode 100644 index 00000000000000..5f6a5adf1a68ca --- /dev/null +++ b/.github/scripts/series/kselftest_prep.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# Please source me! + +git config --global user.email "you@example.com" +git config --global user.name "Your Name" + +export PATH=$(echo $PATH | tr : "\n"| grep -v ^/opt | tr "\n" :) + +export CI_TRIPLE=riscv64-linux-gnu diff --git a/.github/scripts/series/patches/0001-selftests-bpf-Add-RISC-V-specific-config.patch b/.github/scripts/series/patches/0001-selftests-bpf-Add-RISC-V-specific-config.patch new file mode 100644 index 00000000000000..a4aec87eb24532 --- /dev/null +++ b/.github/scripts/series/patches/0001-selftests-bpf-Add-RISC-V-specific-config.patch @@ -0,0 +1,47 @@ +From 611f4103494e5847190d8d8b22c15a496441c075 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= +Date: Tue, 27 Aug 2024 17:21:12 +0000 +Subject: [PATCH 1/6] selftests: bpf: Add RISC-V specific config +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Björn Töpel +--- + tools/testing/selftests/bpf/config.riscv64 | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + create mode 100644 tools/testing/selftests/bpf/config.riscv64 + +diff --git a/tools/testing/selftests/bpf/config.riscv64 b/tools/testing/selftests/bpf/config.riscv64 +new file mode 100644 +index 000000000000..9124d1549a1a +--- /dev/null ++++ b/tools/testing/selftests/bpf/config.riscv64 +@@ -0,0 +1,22 @@ ++CONFIG_DEBUG_CREDENTIALS=y ++CONFIG_DEBUG_INFO_BTF=y ++CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y ++CONFIG_DEBUG_MEMORY_INIT=y ++CONFIG_EXPERT=y ++CONFIG_RUNTIME_TESTING_MENU=y ++CONFIG_TLS=y ++CONFIG_IP_ROUTE_MULTIPATH=y ++CONFIG_MACSEC=y ++CONFIG_CRYPTO_CHACHA20POLY1305=y ++CONFIG_CRYPTO_CHACHA20=y ++CONFIG_CRYPTO_CCM=y ++CONFIG_MACVTAP=y ++CONFIG_L2TP=y ++CONFIG_TEST_FPU=y ++CONFIG_IOMMUFD=y ++CONFIG_IPV6_SEG6_LWTUNNEL=y ++CONFIG_XFRM_SUB_POLICY=y ++CONFIG_XFRM_USER=y ++CONFIG_OPENVSWITCH=y ++CONFIG_NONPORTABLE=y ++CONFIG_RISCV_EFFICIENT_UNALIGNED_ACCESS=y + +base-commit: 8d8d276ba2fb5f9ac4984f5c10ae60858090babc +-- +2.43.0 + diff --git a/.github/scripts/series/patches/0002-selftests-bpf-Rename-fallback.patch b/.github/scripts/series/patches/0002-selftests-bpf-Rename-fallback.patch new file mode 100644 index 00000000000000..2fef6472ad3fa9 --- /dev/null +++ b/.github/scripts/series/patches/0002-selftests-bpf-Rename-fallback.patch @@ -0,0 +1,70 @@ +From af4e24f21714ca1ffdedeba5fd2e587328b35823 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= +Date: Thu, 22 Aug 2024 16:26:22 +0000 +Subject: [PATCH 2/6] selftests: bpf: Rename fallback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +There's a clash: + +arch/riscv/lib/crc32.c +154:typedef u32 (*fallback)(u32 crc, unsigned char const *p, size_t len); + +Signed-off-by: Björn Töpel +--- + tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c | 2 +- + tools/testing/selftests/bpf/progs/bpf_dctcp.c | 8 ++++---- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c b/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c +index 63422f4f3896..860df52717f0 100644 +--- a/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c ++++ b/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c +@@ -285,7 +285,7 @@ static void test_dctcp_fallback(void) + dctcp_skel = bpf_dctcp__open(); + if (!ASSERT_OK_PTR(dctcp_skel, "dctcp_skel")) + return; +- strcpy(dctcp_skel->rodata->fallback, "cubic"); ++ strcpy(dctcp_skel->rodata->fallback_s, "cubic"); + if (!ASSERT_OK(bpf_dctcp__load(dctcp_skel), "bpf_dctcp__load")) + goto done; + +diff --git a/tools/testing/selftests/bpf/progs/bpf_dctcp.c b/tools/testing/selftests/bpf/progs/bpf_dctcp.c +index 02f552e7fd4d..aaa74d5fbd86 100644 +--- a/tools/testing/selftests/bpf/progs/bpf_dctcp.c ++++ b/tools/testing/selftests/bpf/progs/bpf_dctcp.c +@@ -26,7 +26,7 @@ static bool before(__u32 seq1, __u32 seq2) + + char _license[] SEC("license") = "GPL"; + +-volatile const char fallback[TCP_CA_NAME_MAX]; ++volatile const char fallback_s[TCP_CA_NAME_MAX]; + const char bpf_dctcp[] = "bpf_dctcp"; + const char tcp_cdg[] = "cdg"; + char cc_res[TCP_CA_NAME_MAX]; +@@ -71,10 +71,10 @@ void BPF_PROG(bpf_dctcp_init, struct sock *sk) + struct bpf_dctcp *ca = inet_csk_ca(sk); + int *stg; + +- if (!(tp->ecn_flags & TCP_ECN_OK) && fallback[0]) { ++ if (!(tp->ecn_flags & TCP_ECN_OK) && fallback_s[0]) { + /* Switch to fallback */ + if (bpf_setsockopt(sk, SOL_TCP, TCP_CONGESTION, +- (void *)fallback, sizeof(fallback)) == -EBUSY) ++ (void *)fallback_s, sizeof(fallback_s)) == -EBUSY) + ebusy_cnt++; + + /* Switch back to myself and the recurred bpf_dctcp_init() +@@ -87,7 +87,7 @@ void BPF_PROG(bpf_dctcp_init, struct sock *sk) + + /* Switch back to fallback */ + if (bpf_setsockopt(sk, SOL_TCP, TCP_CONGESTION, +- (void *)fallback, sizeof(fallback)) == -EBUSY) ++ (void *)fallback_s, sizeof(fallback_s)) == -EBUSY) + ebusy_cnt++; + + /* Expecting -ENOTSUPP for tcp_cdg_res */ +-- +2.43.0 + diff --git a/.github/scripts/series/patches/0003-selftests-iommu-Add-RISC-V-specific-config.patch b/.github/scripts/series/patches/0003-selftests-iommu-Add-RISC-V-specific-config.patch new file mode 100644 index 00000000000000..f99e2824232452 --- /dev/null +++ b/.github/scripts/series/patches/0003-selftests-iommu-Add-RISC-V-specific-config.patch @@ -0,0 +1,30 @@ +From 06586b3f06e5f16504967407126684b5d78aed60 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= +Date: Tue, 27 Aug 2024 17:27:18 +0000 +Subject: [PATCH 3/6] selftests: iommu: Add RISC-V specific config +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Björn Töpel +--- + tools/testing/selftests/iommu/config.riscv64 | 7 +++++++ + 1 file changed, 7 insertions(+) + create mode 100644 tools/testing/selftests/iommu/config.riscv64 + +diff --git a/tools/testing/selftests/iommu/config.riscv64 b/tools/testing/selftests/iommu/config.riscv64 +new file mode 100644 +index 000000000000..d218811ccadf +--- /dev/null ++++ b/tools/testing/selftests/iommu/config.riscv64 +@@ -0,0 +1,7 @@ ++# IOMMUFD ++CONFIG_IOMMUFD=y ++CONFIG_VFIO=y ++CONFIG_VFIO_CONTAINER=n ++CONFIG_IOMMUFD_VFIO_CONTAINER=y ++CONFIG_FAULT_INJECTION=y ++CONFIG_IOMMUFD_TEST=y +-- +2.43.0 + diff --git a/.github/scripts/series/patches/0004-selftests-exec-Remove-static-pie.patch b/.github/scripts/series/patches/0004-selftests-exec-Remove-static-pie.patch new file mode 100644 index 00000000000000..58bfa6065b5077 --- /dev/null +++ b/.github/scripts/series/patches/0004-selftests-exec-Remove-static-pie.patch @@ -0,0 +1,40 @@ +From 0e22720f7f4c1cbed83c032ca4b8bc50d2f7aeb5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= +Date: Thu, 22 Aug 2024 16:27:16 +0000 +Subject: [PATCH 4/6] selftests: exec: Remove static-pie +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +static-pie is broken on RV pre libc6-dev 2.40 + +WIP: Fix patch + +Signed-off-by: Björn Töpel +--- + tools/testing/selftests/exec/Makefile | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/tools/testing/selftests/exec/Makefile b/tools/testing/selftests/exec/Makefile +index ba012bc5aab9..fcf2db80cc40 100644 +--- a/tools/testing/selftests/exec/Makefile ++++ b/tools/testing/selftests/exec/Makefile +@@ -5,7 +5,7 @@ CFLAGS += -Wno-nonnull + ALIGNS := 0x1000 0x200000 0x1000000 + ALIGN_PIES := $(patsubst %,load_address.%,$(ALIGNS)) + ALIGN_STATIC_PIES := $(patsubst %,load_address.static.%,$(ALIGNS)) +-ALIGNMENT_TESTS := $(ALIGN_PIES) $(ALIGN_STATIC_PIES) ++ALIGNMENT_TESTS := $(ALIGN_PIES) + + TEST_PROGS := binfmt_script.py + TEST_GEN_PROGS := execveat non-regular $(ALIGNMENT_TESTS) +@@ -35,6 +35,3 @@ $(OUTPUT)/execveat.denatured: $(OUTPUT)/execveat + $(OUTPUT)/load_address.0x%: load_address.c + $(CC) $(CFLAGS) $(LDFLAGS) -Wl,-z,max-page-size=$(lastword $(subst ., ,$@)) \ + -fPIE -pie $< -o $@ +-$(OUTPUT)/load_address.static.0x%: load_address.c +- $(CC) $(CFLAGS) $(LDFLAGS) -Wl,-z,max-page-size=$(lastword $(subst ., ,$@)) \ +- -fPIE -static-pie $< -o $@ +-- +2.43.0 + diff --git a/.github/scripts/series/patches/0005-selftests-hid-Fix-broken-build.patch b/.github/scripts/series/patches/0005-selftests-hid-Fix-broken-build.patch new file mode 100644 index 00000000000000..d8c1ec966ac76b --- /dev/null +++ b/.github/scripts/series/patches/0005-selftests-hid-Fix-broken-build.patch @@ -0,0 +1,30 @@ +From 350c424f2379572fcdc9e6470a02e61e2da5441a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= +Date: Thu, 22 Aug 2024 16:28:10 +0000 +Subject: [PATCH 5/6] selftests: hid: Fix broken build +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +kexec prototypes are messed up in vmlinux.h w/o the define + +Signed-off-by: Björn Töpel +--- + tools/testing/selftests/hid/progs/hid_bpf_helpers.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tools/testing/selftests/hid/progs/hid_bpf_helpers.h b/tools/testing/selftests/hid/progs/hid_bpf_helpers.h +index e5db897586bb..76e06cab1b9d 100644 +--- a/tools/testing/selftests/hid/progs/hid_bpf_helpers.h ++++ b/tools/testing/selftests/hid/progs/hid_bpf_helpers.h +@@ -22,6 +22,7 @@ + #define HID_REQ_SET_IDLE HID_REQ_SET_IDLE___not_used + #define HID_REQ_SET_PROTOCOL HID_REQ_SET_PROTOCOL___not_used + ++#define BPF_NO_KFUNC_PROTOTYPES + #include "vmlinux.h" + + #undef hid_bpf_ctx +-- +2.43.0 + diff --git a/.github/scripts/series/patches/0006-Add-missing-net-lib-kselftest-target.patch b/.github/scripts/series/patches/0006-Add-missing-net-lib-kselftest-target.patch new file mode 100644 index 00000000000000..41011c5b9a466f --- /dev/null +++ b/.github/scripts/series/patches/0006-Add-missing-net-lib-kselftest-target.patch @@ -0,0 +1,28 @@ +From a28da2534fd8273eab88228749786ddfdd463184 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= +Date: Wed, 11 Sep 2024 09:53:21 +0200 +Subject: [PATCH 6/6] Add missing net/lib kselftest target +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Björn Töpel +--- + tools/testing/selftests/Makefile | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile +index bc8fe9e8f7f2..cf166c64a5d3 100644 +--- a/tools/testing/selftests/Makefile ++++ b/tools/testing/selftests/Makefile +@@ -64,6 +64,7 @@ TARGETS += net + TARGETS += net/af_unix + TARGETS += net/forwarding + TARGETS += net/hsr ++TARGETS += net/lib + TARGETS += net/mptcp + TARGETS += net/openvswitch + TARGETS += net/tcp_ao +-- +2.43.0 + diff --git a/.github/scripts/series/patches/0007-BPF-kselftest-fix.patch b/.github/scripts/series/patches/0007-BPF-kselftest-fix.patch new file mode 100644 index 00000000000000..5298f4916b916c --- /dev/null +++ b/.github/scripts/series/patches/0007-BPF-kselftest-fix.patch @@ -0,0 +1,32 @@ +From 597d0700c8c55ef6a627ff6ecbc2d3c51185d570 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= +Date: Sat, 14 Sep 2024 09:49:14 +0200 +Subject: [PATCH 1/2] BPF kselftest fix +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Remove dead script + +Signed-off-by: Björn Töpel +--- + tools/testing/selftests/bpf/Makefile | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile +index f04af11df8eb..df75f1beb731 100644 +--- a/tools/testing/selftests/bpf/Makefile ++++ b/tools/testing/selftests/bpf/Makefile +@@ -132,7 +132,6 @@ TEST_PROGS := test_kmod.sh \ + test_tunnel.sh \ + test_lwt_seg6local.sh \ + test_lirc_mode2.sh \ +- test_skb_cgroup_id.sh \ + test_flow_dissector.sh \ + test_xdp_vlan_mode_generic.sh \ + test_xdp_vlan_mode_native.sh \ + +base-commit: 5277d130947ba8c0d54c16eed89eb97f0b6d2e5a +-- +2.43.0 + diff --git a/.github/scripts/series/patches/0008-BPF-selftest-install.patch b/.github/scripts/series/patches/0008-BPF-selftest-install.patch new file mode 100644 index 00000000000000..c10f52e25bc8b4 --- /dev/null +++ b/.github/scripts/series/patches/0008-BPF-selftest-install.patch @@ -0,0 +1,35 @@ +From 5fd0e251ba091bddb302fd56436007dbf50f450f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= +Date: Sun, 15 Sep 2024 16:58:21 +0200 +Subject: [PATCH 2/2] BPF selftest install +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fix deps Makefile + +Signed-off-by: Björn Töpel +--- + tools/testing/selftests/bpf/Makefile | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile +index df75f1beb731..f6e38b9d07f6 100644 +--- a/tools/testing/selftests/bpf/Makefile ++++ b/tools/testing/selftests/bpf/Makefile +@@ -627,6 +627,12 @@ $(TRUNNER_BPF_SKELS_LINKED): $(TRUNNER_OUTPUT)/%: $$$$(%-deps) $(BPFTOOL) | $(TR + $(notdir %.skel.h): $(TRUNNER_OUTPUT)/%.skel.h + @true + ++$(notdir %.lskel.h): $(TRUNNER_OUTPUT)/%.lskel.h ++ @true ++ ++$(notdir %.subskel.h): $(TRUNNER_OUTPUT)/%.subskel.h ++ @true ++ + endif + + # ensure we set up tests.h header generation rule just once +-- +2.43.0 + diff --git a/.github/scripts/series/patches/0009-selftests-clone3-Avoid-fragile-struct-poking.patch b/.github/scripts/series/patches/0009-selftests-clone3-Avoid-fragile-struct-poking.patch new file mode 100644 index 00000000000000..d4c5d315f13dac --- /dev/null +++ b/.github/scripts/series/patches/0009-selftests-clone3-Avoid-fragile-struct-poking.patch @@ -0,0 +1,66 @@ +From c70c39b2ee707075b40c91e5047cf33406f30f30 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= +Date: Thu, 12 Sep 2024 19:20:34 +0000 +Subject: [PATCH] selftests: clone3: Avoid fragile struct poking +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit +To: Adrian Reber , + Christian Brauner , + Shuah Khan , + linux-kselftest@vger.kernel.org +Cc: linux-kernel@vger.kernel.org + +The struct libcap in the selftest, and the what libcap is actually +using doesn't match, so the test fail. Libcap internals have changed, +but the selftest hasn't. + +Fix by avoid poking the libcap internals. + +Signed-off-by: Björn Töpel +--- + .../clone3/clone3_cap_checkpoint_restore.c | 17 +++-------------- + 1 file changed, 3 insertions(+), 14 deletions(-) + +diff --git a/tools/testing/selftests/clone3/clone3_cap_checkpoint_restore.c b/tools/testing/selftests/clone3/clone3_cap_checkpoint_restore.c +index 31b56d625655..9e6ee8c5316e 100644 +--- a/tools/testing/selftests/clone3/clone3_cap_checkpoint_restore.c ++++ b/tools/testing/selftests/clone3/clone3_cap_checkpoint_restore.c +@@ -89,14 +89,9 @@ static int test_clone3_set_tid(struct __test_metadata *_metadata, + return ret; + } + +-struct libcap { +- struct __user_cap_header_struct hdr; +- struct __user_cap_data_struct data[2]; +-}; +- + static int set_capability(void) + { +- cap_value_t cap_values[] = { CAP_SETUID, CAP_SETGID }; ++ cap_value_t cap_values[] = { CAP_SETUID, CAP_SETGID, CAP_CHECKPOINT_RESTORE }; + struct libcap *cap; + int ret = -1; + cap_t caps; +@@ -113,14 +108,8 @@ static int set_capability(void) + goto out; + } + +- cap_set_flag(caps, CAP_EFFECTIVE, 2, cap_values, CAP_SET); +- cap_set_flag(caps, CAP_PERMITTED, 2, cap_values, CAP_SET); +- +- cap = (struct libcap *) caps; +- +- /* 40 -> CAP_CHECKPOINT_RESTORE */ +- cap->data[1].effective |= 1 << (40 - 32); +- cap->data[1].permitted |= 1 << (40 - 32); ++ cap_set_flag(caps, CAP_EFFECTIVE, 3, cap_values, CAP_SET); ++ cap_set_flag(caps, CAP_PERMITTED, 3, cap_values, CAP_SET); + + if (cap_set_proc(caps)) { + perror("cap_set_proc"); + +base-commit: 075dbe9f6e3c21596c5245826a4ee1f1c1676eb8 +-- +2.43.0 + diff --git a/.github/scripts/series/patches/0010-selftests-clone3-Avoid-fragile-struct-poking.patch b/.github/scripts/series/patches/0010-selftests-clone3-Avoid-fragile-struct-poking.patch new file mode 100644 index 00000000000000..4800187f5ec109 --- /dev/null +++ b/.github/scripts/series/patches/0010-selftests-clone3-Avoid-fragile-struct-poking.patch @@ -0,0 +1,48 @@ +From dd9191caeafccf7fd4b282aa8a516e594b2cc4fe Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= +Date: Fri, 27 Sep 2024 15:01:25 +0200 +Subject: [PATCH bpf-next 1/2] libbpf: Add missing per-arch include path +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit +To: Andrii Nakryiko , + Eduard Zingerman , + Mykola Lysenko , + bpf@vger.kernel.org, + netdev@vger.kernel.org +Cc: linux-kselftest@vger.kernel.org, + linux-kernel@vger.kernel.org, + linux-riscv@lists.infradead.org, + Charlie Jenkins + +libbpf does not include the per-arch tools include path, e.g. +tools/arch/riscv/include. Some architectures depend those files to +build properly. + +Include tools/arch/$(SUBARCH)/include in the libbpf build. + +Fixes: 6d74d178fe6e ("tools: Add riscv barrier implementation") +Signed-off-by: Björn Töpel +--- + tools/lib/bpf/Makefile | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile +index 1b22f0f37288..857a5f7b413d 100644 +--- a/tools/lib/bpf/Makefile ++++ b/tools/lib/bpf/Makefile +@@ -61,7 +61,8 @@ ifndef VERBOSE + endif + + INCLUDES = -I$(or $(OUTPUT),.) \ +- -I$(srctree)/tools/include -I$(srctree)/tools/include/uapi ++ -I$(srctree)/tools/include -I$(srctree)/tools/include/uapi \ ++ -I$(srctree)/tools/arch/$(SRCARCH)/include + + export prefix libdir src obj + + +base-commit: db5ca265e3334b48c4e3fa07eef79e8bc578c430 +-- +2.43.0 + diff --git a/.github/scripts/series/patches/0011-selftests-bpf-Add-missing-per-arch-include-path.patch b/.github/scripts/series/patches/0011-selftests-bpf-Add-missing-per-arch-include-path.patch new file mode 100644 index 00000000000000..8430c2762afe76 --- /dev/null +++ b/.github/scripts/series/patches/0011-selftests-bpf-Add-missing-per-arch-include-path.patch @@ -0,0 +1,54 @@ +From 14733cc5a0896de29d8f4f25d80bb74793659bb1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= +Date: Fri, 27 Sep 2024 15:05:32 +0200 +Subject: [PATCH bpf-next 2/2] selftests: bpf: Add missing per-arch include + path +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit +To: Andrii Nakryiko , + Eduard Zingerman , + Mykola Lysenko , + bpf@vger.kernel.org, + netdev@vger.kernel.org +Cc: linux-kselftest@vger.kernel.org, + linux-kernel@vger.kernel.org, + linux-riscv@lists.infradead.org, + Charlie Jenkins + +The prog_tests programs do not include the per-arch tools include +path, e.g. tools/arch/riscv/include. Some architectures depend those +files to build properly. + +Include tools/arch/$(SUBARCH)/include in the selftests bpf build. + +Fixes: 6d74d178fe6e ("tools: Add riscv barrier implementation") +Signed-off-by: Björn Töpel +--- + tools/testing/selftests/bpf/Makefile | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile +index 365740f24d2e..d6a53afa449f 100644 +--- a/tools/testing/selftests/bpf/Makefile ++++ b/tools/testing/selftests/bpf/Makefile +@@ -10,6 +10,7 @@ TOOLSDIR := $(abspath ../../..) + LIBDIR := $(TOOLSDIR)/lib + BPFDIR := $(LIBDIR)/bpf + TOOLSINCDIR := $(TOOLSDIR)/include ++TOOLSARCHINCDIR := $(TOOLSDIR)/arch/$(SRCARCH)/include + BPFTOOLDIR := $(TOOLSDIR)/bpf/bpftool + APIDIR := $(TOOLSINCDIR)/uapi + ifneq ($(O),) +@@ -44,7 +45,7 @@ CFLAGS += -g $(OPT_FLAGS) -rdynamic \ + -Wall -Werror -fno-omit-frame-pointer \ + $(GENFLAGS) $(SAN_CFLAGS) $(LIBELF_CFLAGS) \ + -I$(CURDIR) -I$(INCLUDE_DIR) -I$(GENDIR) -I$(LIBDIR) \ +- -I$(TOOLSINCDIR) -I$(APIDIR) -I$(OUTPUT) ++ -I$(TOOLSINCDIR) -I$(TOOLSARCHINCDIR) -I$(APIDIR) -I$(OUTPUT) + LDFLAGS += $(SAN_LDFLAGS) + LDLIBS += $(LIBELF_LIBS) -lz -lrt -lpthread + +-- +2.43.0 + diff --git a/.github/scripts/series/patches/0012-Missing-iommu-config.patch b/.github/scripts/series/patches/0012-Missing-iommu-config.patch new file mode 100644 index 00000000000000..aeb956c38564a7 --- /dev/null +++ b/.github/scripts/series/patches/0012-Missing-iommu-config.patch @@ -0,0 +1,29 @@ +From cf68142d04abb6d1c848930bf4b19097497cd924 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B6rn=20T=C3=B6pel?= +Date: Mon, 30 Sep 2024 09:47:56 +0200 +Subject: [PATCH] Missing iommu config +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Björn Töpel +--- + tools/testing/selftests/iommu/config.riscv64 | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tools/testing/selftests/iommu/config.riscv64 b/tools/testing/selftests/iommu/config.riscv64 +index d218811ccadf..efd7fe60553f 100644 +--- a/tools/testing/selftests/iommu/config.riscv64 ++++ b/tools/testing/selftests/iommu/config.riscv64 +@@ -1,4 +1,5 @@ + # IOMMUFD ++CONFIG_RUNTIME_TESTING_MENU=y + CONFIG_IOMMUFD=y + CONFIG_VFIO=y + CONFIG_VFIO_CONTAINER=n + +base-commit: e32cde8d2bd7d251a8f9b434143977ddf13dcec6 +prerequisite-patch-id: 0b6c42032915388333abd2e1fa71082780e474d1 +-- +2.43.0 + diff --git a/.github/scripts/series/post_to_squad.py b/.github/scripts/series/post_to_squad.py new file mode 100755 index 00000000000000..bde975ed0f260a --- /dev/null +++ b/.github/scripts/series/post_to_squad.py @@ -0,0 +1,296 @@ +#!/usr/bin/env python3 + +# SPDX-FileCopyrightText: 2024 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +# +# Pulls build/run results from the kselftest kernel logs, and +# publishes them to SQUAD. +# + +import argparse +import json +import os +import os.path +import pathlib +import pprint +import re +import requests +import sys +import tempfile + +from pathlib import Path +from tap import parser + +SQUAD_TOKEN = os.getenv('SQUAD_TOKEN') +SQUAD_URL = "https://mazarinen.tail1c623.ts.net/api/submit" +SQUAD_GROUP = "riscv-linux" +SQUAD_PROJECT = "linux-all" +SQUAD_CI_ENV = "qemu" + +def parse_bpf_kselftest(kselftest_file, results): + bpf_start_pat = re.compile(r'^#\s+selftests:\s+([a-z_\-/]+):\s+([a-z_\-/]+)') + bpf_end_pat = re.compile(r'^(not ok|ok)\s+([0-9]+)\s+selftests:\s+([a-z_\-/]+):\s+([a-z_\-/]+)') + bpf_test_pat = re.compile(r'^#\s+#([0-9]+)\s+([a-z_\-/]+):(OK|FAIL)') + + curr_start = None + curr_end = None + for i in kselftest_file: + if (m := bpf_start_pat.match(i)): + group = m.group(1) + test = m.group(2) + if curr_start and not curr_end: + print(f"PREMATURE START: group: {group} test: {test}", file=sys.stderr) + curr_start = m + curr_end = None + continue + + if (m := bpf_end_pat.match(i)): + group = "kselftest-" + m.group(3) + test = group + "/" + m.group(4) + "__allsubtests" + res = False if m.group(1) == "not ok" else True + if not curr_start or curr_start.group(1) != m.group(3): + print(f"PREMATURE END: group end: {group} test: {test}", file=sys.stderr) + res = False + curr_end = m + + if group not in results: + results[group] = {} + if "tests" not in results[group]: + results[group]["tests"] = {} + if test not in results[group]["tests"]: + results[group]["tests"][test] = {} + + results[group]["tests"][test]["result"] = "pass" if res else "fail" + results[group]["log"] = kselftest_file.name + continue + + if (m := bpf_test_pat.match(i)): + sub_test_id = m.group(1) + sub_test_name = m.group(2) + sub_res = False if m.group(3) == "FAIL" else True + if not curr_start: + print(f"PREMATURE TEST: test: {sub_test_name}", file=sys.stderr) + continue + + group = "kselftest-" + curr_start.group(1) + test = group + "/" + curr_start.group(2) + "__" + sub_test_name + + if "tests" not in results[group]: + results[group]["tests"] = {} + if test not in results[group]["tests"]: + results[group]["tests"][test] = {} + + results[group]["tests"][test]["result"] = "pass" if sub_res else "fail" + results[group]["log"] = kselftest_file.name + + if curr_start and not curr_end: + group = "kselftest-" + curr_start.group(1) + test = group + "/" + curr_start.group(2) + "__allsubtests" + print(f"END MISSING: group end: {group} test: {test}", file=sys.stderr) + if test not in results[group]["tests"]: + results[group]["tests"][test] = {} + results[group]["tests"][test]["result"] = "fail" + + return results + +def parse_kselftest(kselftest_file, results): + description_pat = re.compile(r"selftests:\s+(\S+)\s+(\S+)") + + p = parser.Parser() + for l in p.parse(kselftest_file): + if l.category == "test": + description = description_pat.match(l.description) + if not description: + print(f"BAD SELFTEST STRING: {l.description}", file=sys.stderr) + continue + + group = "kselftest-" + description.group(1)[:-1] + test = group + "/" + description.group(2) + + if group not in results: + results[group] = {} + if "tests" not in results[group]: + results[group]["tests"] = {} + if test not in results[group]["tests"]: + results[group]["tests"][test] = {} + + # XXX Use l.directive.skip? + + results[group]["tests"][test]["result"] = "pass" if l.ok else "fail" + results[group]["log"] = kselftest_file.name + + return results + +# +# The toplevel file needs special handling, when submitting the +# results to SQUAD. The SQUAD REST API only allows for *one* full log +# per POST, but the toplevel log is a collection of builds/tests. This +# means that each test in the toplevel, that has a log needs a POST of +# its own. +# +def parse_toplevel(top_file, results): + build_fail_pat = re.compile(r"^::error::FAIL Build (kernel|selftest) (\S+) \"(\S+)\"") + build_ok_pat = re.compile(r"^::notice::OK Build (kernel|selftest) (\S+)") + test_fail_pat = re.compile(r"^::error::FAIL Test kernel (\S+) (\S+) (\S+) (\S+) (\S+) (\S+) \S+ \"(\S+)\"") + test_ok_pat = re.compile(r"^::notice::OK Test kernel (\S+) (\S+) (\S+) (\S+) (\S+) (\S+)") + build_name_pat = re.compile(r"^build_name (\S+)") + + for i in top_file: + group = None + test = None + log = None + res = False + + if (m := build_name_pat.match(i)): + results["build_name"] = m.group(1) + continue + + if (m := build_fail_pat.match(i)): + group = m.group(2) + test = group + "/" + "build_" + m.group(1) + log = m.group(3) + res = False + + if (m := build_ok_pat.match(i)): + group = m.group(2) + test = group + "/" + "build_" + m.group(1) + res = True + + if (m := test_fail_pat.match(i)): + group = m.group(1) + test = group + "/" + m.group(2) + "__" + m.group(3) + "__" + m.group(4)\ + + "__" + m.group(5) + "__" + m.group(6) + log = m.group(7) + res = False + + if (m := test_ok_pat.match(i)): + group = m.group(1) + test = group + "/" + m.group(2) + "__" + m.group(3) + "__" + m.group(4)\ + + "__" + m.group(5) + "__" + m.group(6) + res = True + + if group and test: + if group not in results: + results[group] = {} + + results[group]["log_per_test"] = True + + if "tests" not in results[group]: + results[group]["tests"] = {} + if "tests-log" not in results[group]: + results[group]["tests-log"] = {} + if test not in results[group]["tests"]: + results[group]["tests"][test] = {} + + results[group]["tests"][test]["result"] = "pass" if res else "fail" + if log: + if "tests-log" not in results[group]: + results[group]["tests-log"] = {} + + l = os.path.dirname(top_file.name) + "/" + log + results[group]["tests-log"][test] = l + + return results + +def parse_args(): + parser = argparse.ArgumentParser(description = 'Output Squad json from kselftest runs') + + parser.add_argument("--fake-curl", action="store_true", help = 'Dry run showing curl equivalent') + parser.add_argument("--branch", default="please_set_me", help = 'Git branch ref') + parser.add_argument("--job-url", default="http://example.com/notset", help = 'Job URL') + parser.add_argument("--selftest-bpf-log", help = 'BPF kselftest log file') + parser.add_argument("--selftest-log-dir", default=None, help = 'Kselftest log files directory') + parser.add_argument("--toplevel-log", required=True, help = 'Toplevel "kselftest.log" file') + + return parser.parse_args() + +def submit_fake_curl(testsuite, tests_dict, log, job_url, branch, build_name, o_path): + metadata_json = o_path / (testsuite.replace("/", "_") + "--metadata.json") + jstr = json.dumps({"job_url" : job_url, + "branch" : branch + }, indent=4) + metadata_json.write_text(jstr) + print(f"metadata: {jstr}") + + tests_json = o_path / (testsuite.replace("/", "_") + "--tests.json") + jstr = json.dumps(tests_dict, indent=4) + tests_json.write_text(jstr) + print(f"tests: {jstr}") + + print(f'curl --header "Authorization: token {SQUAD_TOKEN}" \\') + print(f' --form tests=@{str(o_path.absolute()) + "/" + tests_json.name} \\') + print(f' --form metadata=@{str(o_path.absolute()) + "/" + metadata_json.name} \\') + if log: + print(f' --form log=@{log} \\') + print(f' {SQUAD_URL}/{SQUAD_GROUP}/{SQUAD_PROJECT}/{build_name}/{SQUAD_CI_ENV}') + +def submit_squad(testsuite, tests_dict, log, job_url, branch, build_name, o_path): + full_url = f"{SQUAD_URL}/{SQUAD_GROUP}/{SQUAD_PROJECT}/{build_name}/{SQUAD_CI_ENV}" + + metadata_json = o_path / (testsuite.replace("/", "_") + "--metadata.json") + jstr = json.dumps({"job_url" : job_url, + "branch" : branch + }, indent=4) + metadata_json.write_text(jstr) + # print(f"metadata: {jstr}") + + tests_json = o_path / (testsuite.replace("/", "_") + "--tests.json") + jstr = json.dumps(tests_dict, indent=4) + tests_json.write_text(jstr) + # print(f"tests: {jstr}") + + headers = { + "Authorization": f"token {SQUAD_TOKEN}" + } + + files = { + "tests": tests_json.open(mode='rb'), + "metadata": metadata_json.open(mode='rb') + } + + if log: + files["log"] = open(f"{log}", 'rb') + + response = requests.post(full_url, headers=headers, files=files) + print(f"Request completed with status code: {response.status_code} text: {response.text}") + +if __name__ == "__main__": + args = parse_args() + + results = {} + + t = os.path.expanduser(args.toplevel_log) + with open(t, 'r') as top: + results = parse_toplevel(top, results) + + if args.selftest_log_dir: + for f in Path(args.selftest_log_dir).glob("test_kernel__*.log"): + a = os.path.expanduser(f) + with open(a, 'r') as all: + results = parse_kselftest(all, results) + + if args.selftest_bpf_log: + b = os.path.expanduser(args.selftest_bpf_log) + with open(b, 'r') as bpf: + results = parse_bpf_kselftest(bpf, results) + + submit = submit_fake_curl if args.fake_curl else submit_squad + + with tempfile.TemporaryDirectory() as temp_dir: + o_path = Path(temp_dir) + + for testsuite in results: + if testsuite == "build_name": + continue + + if results[testsuite].get("log_per_test", False): + for test in results[testsuite]["tests"]: + log = results[testsuite]["tests-log"].get(test, None) + submit(testsuite, {test : results[testsuite]["tests"][test] },\ + log, args.job_url, args.branch, results["build_name"], o_path) + else: + log = results[testsuite].get("log", None) + submit(testsuite, results[testsuite]["tests"], log, args.job_url,\ + args.branch, results["build_name"], o_path) diff --git a/.github/scripts/series/prepare_rootfs.sh b/.github/scripts/series/prepare_rootfs.sh new file mode 100755 index 00000000000000..e77699ea752442 --- /dev/null +++ b/.github/scripts/series/prepare_rootfs.sh @@ -0,0 +1,111 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2023 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +# Prepares a VM image, from a kernel tar-ball and a rootfs. + +set -x +set -euo pipefail + +d=$(dirname "${BASH_SOURCE[0]}") +. $d/utils.sh +. $d/qemu_test_utils.sh + +kernelpath=$1 +rootfs=$2 +tst=$3 +imagename=$4 + +cleanup() { + rm -rf "$tmp" +} + +tmp=$(mktemp -d -p ${ci_root}) +trap cleanup EXIT + +unzstd --keep --stdout $rootfs > $tmp/$(basename $rootfs .zst) + +rootfs="$tmp/$(basename $rootfs .zst)" +modpath=$(find $kernelpath -wholename '*/lib/modules') +vmlinuz=$(find $kernelpath -name '*vmlinu[zx]*') + +kselftestpath=${kernelpath}_build/kselftest/kselftest_install + +imsz=0 +if [[ $tst =~ kselftest ]]; then + sz=$(du -B 1G -s "$kselftestpath" | awk '{print $1}') + imsz=$(( ${imsz} + $sz )) +fi + +if [[ -n $modpath ]]; then + sz=$(du -B 1G -s "$modpath" | awk '{print $1}') + imsz=$(( ${imsz} + $sz )) +fi +imsz=$(( ${imsz} + 2 )) + +# aarch64 export LIBGUESTFS_BACKEND_SETTINGS=force_tcg +eval "$(guestfish --listen)" + +rm -rf $imagename +guestfish --remote -- \ + disk-create "$imagename" raw ${imsz}G : \ + add-drive "$imagename" format:raw : \ + launch : \ + part-init /dev/sda gpt : \ + part-add /dev/sda primary 2048 526336 : \ + part-add /dev/sda primary 526337 -34 : \ + part-set-gpt-type /dev/sda 1 C12A7328-F81F-11D2-BA4B-00A0C93EC93B : \ + mkfs ext4 /dev/sda2 : \ + mount /dev/sda2 / : \ + mkdir /boot : \ + mkdir /boot/efi : \ + mkfs vfat /dev/sda1 : \ + mount /dev/sda1 /boot/efi : \ + tar-in $rootfs / : \ + copy-in $vmlinuz /boot/efi/ : \ + mv /boot/efi/$(basename $vmlinuz) /boot/efi/Image + + +if [[ -n $modpath ]]; then + guestfish --remote -- copy-in $modpath /lib/ +fi + +if [[ $tst =~ kselftest ]]; then + guestfish --remote -- \ + copy-in $kselftestpath / + + subtest=$(echo ${tst} | cut -f2- -d'-') + + if [[ "$subtest" =~ bpf ]]; then + timeout=9000 + else + timeout=3600 + fi + + touch $tmp/dotest + chmod +x $tmp/dotest + cat >$tmp/dotest <Hello kselftest" > /dev/kmsg +cd /kselftest_install +export PATH=${PATH}:/kselftest_install/bpf/tools/sbin + +echo "TEST ${subtest}" +./run_kselftest.sh -o ${timeout} -c ${subtest} +EOF + + echo "dotest:" + cat $tmp/dotest + echo "dotest end" + guestfish --remote -- \ + copy-in $tmp/dotest / +fi + +guestfish --remote -- \ + sync : \ + umount /boot/efi : \ + umount / : \ + exit diff --git a/.github/scripts/series/qemu_test_utils.sh b/.github/scripts/series/qemu_test_utils.sh new file mode 100644 index 00000000000000..5bc13b74e3c87c --- /dev/null +++ b/.github/scripts/series/qemu_test_utils.sh @@ -0,0 +1,95 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2024 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +qemu_subtests=() + +generate_qemu_subtests() { + local xlen=$1 + local config=$2 + local fragment=$3 + local toolchain=$4 + local rootfs=$5 + + local n=$(gen_kernel_name $xlen $config $fragment $toolchain) + local cpu_sifive=0 + local fw_uefi=0 + local hw_acpi=0 + local kernel_config=$(find ${ci_root}/${n} -name 'config-*' 2>/dev/null || echo "/dev/null") + + qemu_subtests=() + + if [[ $xlen == "rv64" ]]; then + if ls ${kernel_config} &> /dev/null; then + if grep -q 'CONFIG_RISCV_ALTERNATIVE_EARLY=y' ${kernel_config}; then + cpu_sifive=1 + fi + if grep -q 'CONFIG_EFI=y' ${kernel_config}; then + fw_uefi=1 + fi + if grep -q 'CONFIG_ACPI=y' ${kernel_config}; then + hw_acpi=1 + fi + fi + + for cpu in default64 server64 max64 sifive; do + if [[ $cpu =~ sifive ]]; then + if ! (( ${cpu_sifive} )); then + continue + fi + fi + + for fw in no_uefi uboot_uefi; do + if ! [[ $fw == no_uefi ]]; then + if ! (( ${fw_uefi} )); then + continue + fi + + if [[ $fw == edk2_uefi ]]; then + continue + fi + fi + + # For now, we're only doing selftest on DT. + if [[ $config =~ ^kselftest ]]; then + if [[ $cpu == server64 && $fw == uboot_uefi && $rootfs == ubuntu ]]; then + if (( ${ci_test_selftests} )); then + qemu_subtests+=( "$cpu $fw dt $config" ) + fi + fi + continue + fi + + for hw in dt acpi; do + if [[ $hw == acpi ]]; then + if [[ $fw == no_uefi ]]; then + continue + fi + + if ! (( ${hw_acpi} )); then + continue + fi + fi + + qemu_subtests+=( "$cpu $fw $hw boot" ) + + done + done + done + else + qemu_subtests+=( "default32 no_uefi dt boot" ) + fi + return 0 +} + +get_qemu_test_name() { + local cpu=$1 + local fw=$2 + local hw=$3 + local tst=$4 + + echo "${cpu}__${fw}__${hw}__${tst}" +} diff --git a/.github/scripts/series/selftest_builder.sh b/.github/scripts/series/selftest_builder.sh new file mode 100755 index 00000000000000..51b0ac69fcb9a6 --- /dev/null +++ b/.github/scripts/series/selftest_builder.sh @@ -0,0 +1,24 @@ +set -euo pipefail + +d=$(dirname "${BASH_SOURCE[0]}") +. $d/utils.sh + +xlen=$1 +config=$2 +fragment=$3 +toolchain=$4 + +tm=$(mktemp -p ${ci_root}) +n=$(gen_kernel_name $xlen $config $fragment $toolchain) +logs=$(get_logs_dir) +rc=0 +log="build_selftest___${n}.log" +\time --quiet -o $tm -f "took %es" \ + $d/build_selftest.sh "${xlen}" "${config}" "${fragment}" "${toolchain}" &> "${logs}/${log}" || rc=$? +if (( $rc )); then + echo "::error::FAIL Build selftest ${n} \"${log}\" $(cat $tm)" +else + echo "::notice::OK Build selftest ${n} $(cat $tm)" +fi +rm $tm +exit $rc diff --git a/.github/scripts/series/test_all.sh b/.github/scripts/series/test_all.sh new file mode 100755 index 00000000000000..b9329e55cffead --- /dev/null +++ b/.github/scripts/series/test_all.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2023 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +d=$(dirname "${BASH_SOURCE[0]}") +. $d/utils.sh + +$d/unpack_fw.sh + +parallel_log=$(mktemp -p ${ci_root}) +parallel -j $(($(nproc)/4)) --colsep ' ' --joblog ${parallel_log} \ + ${d}/kernel_tester.sh {1} {2} {3} {4} {5} :::: <($d/generate_test_runs.sh) || true +cat ${parallel_log} +rm ${parallel_log} diff --git a/.github/scripts/series/test_kernel.sh b/.github/scripts/series/test_kernel.sh new file mode 100755 index 00000000000000..f1e163c3116a58 --- /dev/null +++ b/.github/scripts/series/test_kernel.sh @@ -0,0 +1,212 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2023 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +# Executes the VMs, and report. + +set -x +set -euo pipefail + +d=$(dirname "${BASH_SOURCE[0]}") +. $d/utils.sh +. $d/qemu_test_utils.sh + +xlen=$1 +config=$2 +fragment=$3 +toolchain=$4 +rootfs=$5 + +cpu=$6 +fw=$7 +hw=$8 +tst=$9 + +cpu_to_qemu() { + local cpu=$1 + + case "$cpu" in + "default32") + echo "rv32" + ;; + "default64") + echo "rv64" + ;; + "server64") + echo "rv64,v=true,vlen=256,elen=64,h=true,zbkb=on,zbkc=on,zbkx=on,zkr=on,zkt=on,svinval=on,svnapot=on,svpbmt=on,zabha=on,zacas=on" + ;; + "max64") + echo "max" + ;; + "sifive") + echo "sifive-u54" + ;; + *) + echo "BADCPU" + ;; + esac +} + +fw_to_qemu() { + local hw=$1 + local fw=$2 + local vmlinuz=$3 + + case "$fw" in + "no_uefi") + echo "$vmlinuz" + ;; + "uboot_uefi") + if [[ ${hw} == "acpi" ]]; then + echo "${ci_root}/firmware/rv64/rv64-u-boot-acpi.bin" + else + echo "${ci_root}/firmware/rv64/rv64-u-boot.bin" + fi + ;; + *) + echo "BADFW" + ;; + esac +} + +qemu_kernel_append="root=/dev/vda2 rw earlycon console=tty0 console=ttyS0 panic=-1 oops=panic sysctl.vm.panic_on_oom=1" + +qemu_rv64 () { + local qemu_to=$1 + local qemu_log=$2 + local qemu_bios=$3 + local qemu_kernel=$4 + local qemu_cpu=$5 + local qemu_acpi=$6 + local qemu_aia=$7 + local qemu_image=$8 + + timeout --foreground ${qemu_to}s qemu-system-riscv64 \ + -no-reboot \ + -nodefaults \ + -nographic \ + -machine virt,acpi=${qemu_acpi},aia=${qemu_aia} \ + -smp 4 \ + -bios ${qemu_bios} \ + -cpu ${qemu_cpu} \ + -kernel ${qemu_kernel} \ + -append "${qemu_kernel_append}" \ + -m 8G \ + -object rng-random,filename=/dev/urandom,id=rng0 \ + -device virtio-rng-device,rng=rng0 \ + -chardev stdio,id=char0,mux=on,signal=off,logfile="${qemu_log}" \ + -serial chardev:char0 \ + -drive if=none,file=${qemu_image},format=raw,id=hd0 \ + -device virtio-blk-pci,drive=hd0 +} + +qemu_rv32 () { + local qemu_to=$1 + local qemu_log=$2 + local qemu_bios=$3 + local qemu_kernel=$4 + local qemu_cpu=$5 + local qemu_acpi=$6 + local qemu_aia=$7 + local qemu_image=$8 + + timeout --foreground ${qemu_to}s qemu-system-riscv32 \ + -no-reboot \ + -nodefaults \ + -nographic \ + -machine virt \ + -cpu rv32 \ + -smp 4 \ + -bios ${qemu_bios} \ + -kernel ${qemu_kernel} \ + -append "${qemu_kernel_append}" \ + -m 1G \ + -object rng-random,filename=/dev/urandom,id=rng0 \ + -device virtio-rng-device,rng=rng0 \ + -chardev stdio,id=char0,mux=on,signal=off,logfile="${qemu_log}" \ + -serial chardev:char0 \ + -drive if=none,file=${qemu_image},format=raw,id=hd0 \ + -device virtio-blk-pci,drive=hd0 +} + +check_shutdown () { + local image=$1 + local kernel_name=$2 + local rc=0 + local report_warn_bug="$(get_logs_dir)/series_report_warn_bug" + + shutdown="$(guestfish --ro -a "$image" -i cat /shutdown-status 2>/dev/null)" + if [[ $shutdown == "clean" ]]; then + f=$(mktemp -p ${tmp}) + guestfish --rw -a "$image" -i download /dmesg $f + fail_str=( "\-+\\[ cut here \\]-+\\s+(.*\\s+-+\\[ end trace (\\w*) \\]-+)" "(Unhandled fault.*)\\r\\n" "Kernel panic - (.*) end Kernel panic" "Stack:\\s+(.*\\s+-+\\[ end trace (\\w*) \\]-+)" "^[^\\n]+WARNING:.*?$" "^[^\\n]+Oops(?: -|:).*?$" "^[^\\n]+BUG:.*?$" ) + for fail in "${fail_str[@]}"; do + ret=`grep -E "$fail" $f` + if [[ "$?" == "0" ]]; then + echo "***" >> $report_warn_bug + echo "$kernel_name" >> $report_warn_bug + echo "$ret" >> $report_warn_bug + rc=1 + fi + done + else + rc=1 + fi + + return $rc +} + +tmp=$(mktemp -d -p "${ci_root}") +trap 'rm -rf "$tmp"' EXIT + +kernelpath=${ci_root}/$(gen_kernel_name $xlen $config $fragment $toolchain) +vmlinuz=$(find $kernelpath -name '*vmlinu[zx]*') +rootfs_tar=$(echo ${ci_rootfs_root}/rootfs_${xlen}_${rootfs}_*.tar.zst) +qemu_image=$tmp/rootfs.img + +rc=0 +\time --quiet -f "took prepare_rootfs %e" \ + $d/prepare_rootfs.sh $kernelpath $rootfs_tar $tst $qemu_image || rc=$? +if (( $rc )); then + echo "Failed preparing rootfs image" + exit 1 +fi + +qemu_to=120 +if [[ $rootfs == "ubuntu" ]]; then + qemu_to=$(( $qemu_to * 3 )) + if [[ $fragment =~ nosmp || $fragment =~ lockdep || $fragment =~ kasan || $fragment =~ kfence ]]; then + qemu_to=$(( $qemu_to * 10 )) + fi +else + if [[ $fragment =~ lockdep ]]; then + qemu_to=$(( $qemu_to * 10 )) + fi +fi + +if [[ $config =~ kselftest ]]; then + qemu_to=$((2 * 24 * 3600)) # 40h +fi + +qemu_log=${tmp}/qemu.log +qemu_bios=${ci_root}/firmware/${xlen}/fw_dynamic.bin +qemu_kernel=$(fw_to_qemu $hw $fw $vmlinuz) +qemu_cpu=$(cpu_to_qemu $cpu) + +qemu_acpi=off +if [[ ${hw} == "acpi" ]]; then + qemu_acpi=on + qemu_kernel_append="${qemu_kernel_append} acpi=force" +fi +qemu_aia=none +if [[ ${cpu} == "server64" || ${cpu} == "max64" ]]; then + qemu_aia="aplic-imsic" +fi + +export TIMEFORMAT="took qemu %0R" +time qemu_${xlen} ${qemu_to} ${qemu_log} ${qemu_bios} ${qemu_kernel} ${qemu_cpu} ${qemu_acpi} ${qemu_aia} ${qemu_image} + +export TIMEFORMAT="took check_shutdown %0R" +time check_shutdown $qemu_image $(gen_kernel_name $xlen $config $fragment $toolchain) || rc=$? +exit $rc diff --git a/.github/scripts/series/test_only_defconfig.sh b/.github/scripts/series/test_only_defconfig.sh new file mode 100755 index 00000000000000..b7551995268bef --- /dev/null +++ b/.github/scripts/series/test_only_defconfig.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2024 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +d=$(dirname "${BASH_SOURCE[0]}") +. $d/utils.sh + +$d/unpack_fw.sh + +rc=0 +${d}/kernel_tester.sh rv64 defconfig plain gcc ubuntu || rc=1 +exit $rc diff --git a/.github/scripts/series/test_only_kselftest.sh b/.github/scripts/series/test_only_kselftest.sh new file mode 100755 index 00000000000000..1e29586ba2b5af --- /dev/null +++ b/.github/scripts/series/test_only_kselftest.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2023 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +d=$(dirname "${BASH_SOURCE[0]}") +. $d/utils.sh +. $d/kselftest_prep.sh + +$d/unpack_fw.sh +rc=0 + +kselftest_subtests=("kselftest-bpf" "kselftest-net" "kselftest-ftrace" "kselftest-acct" "kselftest-cachestat" "kselftest-capabilities" "kselftest-cgroup" "kselftest-clone3" "kselftest-connector" "kselftest-core" "kselftest-cpu-hotplug" "kselftest-cpufreq" "kselftest-damon" "kselftest-devices" "kselftest-drivers-dma-buf" "kselftest-dt" "kselftest-efivarfs" "kselftest-exec" "kselftest-fchmodat2" "kselftest-filesystems" "kselftest-filesystems-binderfs" "kselftest-firmware" "kselftest-fpu" "kselftest-futex" "kselftest-gpio" "kselftest-hid" "kselftest-ipc" "kselftest-ir" "kselftest-iommu" "kselftest-kcmp" "kselftest-kexec" "kselftest-kvm" "kselftest-landlock" "kselftest-lib" "kselftest-livepatch" "kselftest-lsm" "kselftest-membarrier" "kselftest-memfd" "kselftest-memory-hotplug" "kselftest-mincore" "kselftest-mount" "kselftest-mqueue" "kselftest-nci" "kselftest-nsfs" "kselftest-openat2" "kselftest-pid_namespace" "kselftest-pidfd" "kselftest-proc" "kselftest-pstore" "kselftest-ptrace" "kselftest-resctrl" "kselftest-riscv" "kselftest-rlimits" "kselftest-rseq" "kselftest-rtc" "kselftest-rust" "kselftest-seccomp" "kselftest-sigaltstack" "kselftest-signal" "kselftest-size" "kselftest-splice" "kselftest-static_keys" "kselftest-sync" "kselftest-sysctl" "kselftest-tc-testing" "kselftest-tdx" "kselftest-timens" "kselftest-timers" "kselftest-tmpfs" "kselftest-tpm2" "kselftest-tty" "kselftest-uevent" "kselftest-user" "kselftest-zram") + +parallel_log=$(mktemp -p ${ci_root}) + +for subtest in "${kselftest_subtests[@]}"; do + echo "${d}/kernel_tester.sh rv64 ${subtest} plain gcc ubuntu" +done | parallel -j$(($(nproc)/8)) --colsep ' ' --joblog ${parallel_log} || true + +cat ${parallel_log} +rm ${parallel_log} diff --git a/.github/scripts/series/tuxrun_to_squad_json.py b/.github/scripts/series/tuxrun_to_squad_json.py new file mode 100644 index 00000000000000..434c5ed78d3bc4 --- /dev/null +++ b/.github/scripts/series/tuxrun_to_squad_json.py @@ -0,0 +1,54 @@ +import argparse +import json + +""" +Turn +{ + "testsuiteA": { + "test1": {} + }, + "testsuiteB": { + "test1": {} + } +} + +into + +{ + "testsuiteA/test1": {} + "testsuiteB/test1": {} +} + +which is what is expected by Squad. +""" + +def parse_args(): + parser = argparse.ArgumentParser(description = 'Output Squad tests results for tuxrun LTP') + parser.add_argument("--result-path", default = "", + help = 'Path to the tuxrun JSON result file') + parser.add_argument("--testsuite", default = "", + help = 'Testsuite name') + + return parser.parse_args() + +def generate_squad_json(result_path, testsuite): + dict_results = {} + + with open(result_path, "r") as f: + dict_initial = json.loads(f.read()) + + # Search only the first dimension for keys starting with "ltp-" + for k, v in dict_initial.items(): + if k.startswith(testsuite): + for ltp_key, ltp_value in v.items(): + dict_results[k + "/" + ltp_key] = ltp_value + + print(dict_results) + + with open(result_path.replace(".json", ".squad.json"), "w") as f: + json.dump(dict_results, f) + +if __name__ == "__main__": + args = parse_args() + generate_squad_json(args.result_path, args.testsuite) + diff --git a/.github/scripts/series/unpack_fw.sh b/.github/scripts/series/unpack_fw.sh new file mode 100755 index 00000000000000..6a6114ad556ba0 --- /dev/null +++ b/.github/scripts/series/unpack_fw.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2023 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail +shopt -s extglob + +d=$(dirname "${BASH_SOURCE[0]}") +. $d/utils.sh + +firmware_dir=${ci_root}/firmware + +fw_rv32_opensbi=$(echo ${ci_fw_root}/firmware_rv32_opensbi_+([a-f0-9]).tar.zst) +fw_rv64_opensbi=$(echo ${ci_fw_root}/firmware_rv64_opensbi_+([a-f0-9]).tar.zst) +fw_rv64_uboot=$(echo ${ci_fw_root}/firmware_rv64_uboot_+([a-f0-9]).tar.zst) +fw_rv64_uboot_acpi=$(echo ${ci_fw_root}/firmware_rv64_uboot_acpi_+([a-f0-9]).tar.zst) + +mkdir -p ${firmware_dir}/rv32 +mkdir -p ${firmware_dir}/rv64 + +tar -C ${firmware_dir}/rv32 -xf $fw_rv32_opensbi +tar -C ${firmware_dir}/rv64 -xf $fw_rv64_opensbi +tar -C ${firmware_dir}/rv64 -xf $fw_rv64_uboot +tar -C ${firmware_dir}/rv64 -xf $fw_rv64_uboot_acpi diff --git a/.github/scripts/series/utils.sh b/.github/scripts/series/utils.sh new file mode 100644 index 00000000000000..55b5e008fcef30 --- /dev/null +++ b/.github/scripts/series/utils.sh @@ -0,0 +1,48 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2024 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +ci_root=${CI_ROOT:-"/build"} +ci_triple=${CI_TRIPLE:-"riscv64-linux"} +ci_patches=${CI_PATCHES:-"$d/patches"} +ci_fw_root=${CI_FW_ROOT:-"/firmware"} +ci_rootfs_root=${CI_ROOTFS_ROOT:-"/rootfs"} + +ci_test_selftests=1 + +apply_patches() { + if [[ -d ${ci_patches} ]]; then + if ls ${ci_patches}/*.patch &> /dev/null; then + for i in ${ci_patches}/*.patch; do + if git apply --check -q $i; then + git apply --index -q $i + fi + done + fi + fi + git commit --allow-empty -m "OOT" +} + +unapply_patches() { + git reset --hard HEAD^ +} + +gen_kernel_name() { + local xlen=$1 + local config=$2 + local fragment=$3 + local toolchain=$4 + + if [[ "$config" =~ ^kselftest ]]; then + config="kselftest" + fi + + echo "${xlen}__${config}__$(basename $fragment)__${toolchain}" +} + +get_logs_dir() { + logs=${ci_root}/logs + mkdir -p ${logs} + echo ${logs} +} diff --git a/.github/scripts/sync.sh b/.github/scripts/sync.sh new file mode 100755 index 00000000000000..6a92064f85134c --- /dev/null +++ b/.github/scripts/sync.sh @@ -0,0 +1,122 @@ +#!/bin/bash + +set -euo pipefail + +# Assumptions: +# Run from git source tree, e.g. /build/linux +# +# This script syncs remote "upstream" branches to the local git repo. +# The script will create a $ORIGIN_BRANCH, which is a clone of of the +# upstream $UPSTREAM_BRANCH, and a $WORKFLOW_BRANCH which is the +# upstream with the latest CI applied as on commit on top. +# +# Subsequent jobs will use these branches, e.g. to run Patchwork CI. + +echo "Environment Variables:" +echo " Workflow: ${GITHUB_WORKFLOW:-notset}" +echo " Action: ${GITHUB_ACTION:-notset}" +echo " Actor: ${GITHUB_ACTOR:-notset}" +echo " Repository: ${GITHUB_REPOSITORY:-notset}" +echo " Event-name: ${GITHUB_EVENT_NAME:-notset}" +echo " Event-path: ${GITHUB_EVENT_PATH:-notset}" +echo " Workspace: ${GITHUB_WORKSPACE:-notset}" +echo " SHA: ${GITHUB_SHA:-notset}" +echo " REF: ${GITHUB_REF:-notset}" +echo " HEAD-REF: ${GITHUB_HEAD_REF:-notset}" +echo " BASE-REF: ${GITHUB_BASE_REF:-notset}" +echo " PWD: $(pwd)" +echo " Repo: ${GITHUB_REPOSITORY:-notset}" + +tmpdir=$(mktemp -d -p /build) + +cleanup() { + git remote remove upstream + echo "bye $tmpdir" + rm -rf $tmpdir +} + +trap cleanup EXIT + +# e.g. "git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git" +UPSTREAM_REPO=$1 +# e.g. "master" +UPSTREAM_BRANCH=$2 +# e.g. "master" +ORIGIN_BRANCH=$3 +# e.g. workflow +WORKFLOW_BRANCH=$4 +#e.g. https://github.com/linux-riscv/github-ci.git +CI_REPO=$5 + +echo ">>> Setup repo" +echo "$ git remote set-url origin $GITHUB_REPOSITORY" +git remote set-url origin "https://$GITHUB_ACTOR:$ACTION_TOKEN@github.com/$GITHUB_REPOSITORY" +echo "$ git remote add upstream $UPSTREAM_REPO" +git remote add upstream "$UPSTREAM_REPO" +echo "$ git fetch upstream $UPSTREAM_BRANCH" +git fetch upstream --tags $UPSTREAM_BRANCH + +echo ">>> Check Origin and Upstream" +if git rev-parse --verify --quiet origin/$ORIGIN_BRANCH &>/dev/null; then + ORIGIN_HEAD=$(git log -1 --format=%H origin/$ORIGIN_BRANCH) +else + ORIGIN_HEAD=noneexisting +fi +echo "ORIGIN_HEAD: $ORIGIN_HEAD" +UPSTREAM_HEAD=$(git log -1 --format=%H upstream/$UPSTREAM_BRANCH) +echo "UPSTREAM_HEAD: $UPSTREAM_HEAD" + +if [[ "$ORIGIN_HEAD" != "$UPSTREAM_HEAD" ]]; then + echo "Repos are NOT synced. Need to merge..." + echo ">>> Sync origin with upstream" + echo "$ git remote set-branches origin *" + git remote set-branches origin '*' + echo "$ git fetch origin" + git fetch origin + echo "$ git push -f origin refs/remotes/upstream/$UPSTREAM_BRANCH:refs/heads/$ORIGIN_BRANCH" + git push -f origin "refs/remotes/upstream/$UPSTREAM_BRANCH:refs/heads/$ORIGIN_BRANCH" + echo "$ git push -f origin refs/tags/*" + git push -f origin "refs/tags/*" +fi + +echo ">>> Prepare CI repo for workflow" +echo "$ git clone $CI_REPO $tmpdir/ci" +git clone $CI_REPO $tmpdir/ci + +if ! git rev-parse --verify --quiet origin/$WORKFLOW_BRANCH &>/dev/null; then + echo "$ git checkout -B $ORIGIN_BRANCH origin/$ORIGIN_BRANCH" + git checkout -B $ORIGIN_BRANCH origin/$ORIGIN_BRANCH +else + echo "$ git checkout -B $WORKFLOW_BRANCH origin/$WORKFLOW_BRANCH" + git checkout -B $WORKFLOW_BRANCH origin/$WORKFLOW_BRANCH +fi + +update() { + echo "$ git checkout -B $WORKFLOW_BRANCH origin/$ORIGIN_BRANCH" + git checkout -B $WORKFLOW_BRANCH origin/$ORIGIN_BRANCH + echo "$ cp -R $tmpdir/ci/.github ." + cp -R $tmpdir/ci/.github . + echo "$ git add --all --force .github" + git add --all --force .github + echo "$ git commit --all --message \"Adding CI files\"" + git commit --all --message "Adding CI files" + echo "$ git branch" + git branch + echo "$ git push -f origin $WORKFLOW_BRANCH" + git push -f origin $WORKFLOW_BRANCH +} + +if ! git diff --no-index .github -- $tmpdir/ci/.github &> /dev/null; then + echo ">>> Workflow has changed, pulling in" + update +fi + +master_commit=$(git log -1 --format=%H origin/$ORIGIN_BRANCH) +workflow_commit=$(git log -1 --format=%H origin/${WORKFLOW_BRANCH}^) +echo ">>> Assert master/workflow commits are same: $master_commit $workflow_commit" +if [[ "$master_commit" != "$workflow_commit" ]]; then + echo ">>> Updating workflow" + update +fi + +echo ">>> Done Exit" diff --git a/.github/scripts/sync_patchwork.py b/.github/scripts/sync_patchwork.py new file mode 100755 index 00000000000000..cc8c5d34f4dfd3 --- /dev/null +++ b/.github/scripts/sync_patchwork.py @@ -0,0 +1,452 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +import os +import sys +import json +import re +import argparse +import tempfile + +from github import Github + +from libs import init_logger, log_debug, log_error, log_info, pr_get_sid +from libs import Patchwork, GithubTool, RepoTool, EmailTool, Context + +def patch_get_new_file_list(patch): + """ + Parse patch to get the file that is newly added + """ + + file_list = [] + + # If patch has no contents, return empty file + if patch == None: + log_error("WARNING: No file found in patch") + return file_list + + # split patch(in string) to list of string by newline + lines = patch.split('\n') + iter_lines = iter(lines) + for line in iter_lines: + try: + if re.search(r'^\-\-\- ', line): + if line.find('dev/null') >= 0: + # Detect new file. Read next line to get the filename + line2 = next(iter_lines) + file_list.append(line2[line2.find('/')+1:]) + except StopIteration: + # End of iteration or no next line. Nothing to do. Just pass + pass + + log_debug(f"New file in the patch: {file_list}") + + return file_list + +def patch_get_file_list(patch): + """ + Parse patch to get the file list + """ + + file_list = [] + + # If patch has no contents, return empty file + if patch == None: + log_error("WARNING: No file found in patch") + return file_list + + # split patch(in string) to list of string by newline + lines = patch.split('\n') + for line in lines: + # Use --- (before) instead of +++ (after). + # If new file is added, --- is /dev/null and can be ignored + # If file is removed, file in --- still exists in the tree + # The corner case is if the patch adds new files. Even in this case + # even if new files are ignored, Makefile should be changed as well + # so it still can be checked. + if re.search(r'^\-\-\- ', line): + # For new file, it should be dev/null. Ignore the file. + if line.find('dev/null') >= 0: + log_debug("New file is added. Ignore in the file list") + continue + + # Trim the '--- /' + file_list.append(line[line.find('/')+1:]) + + log_debug(f"files found in the patch: {file_list}") + + return file_list + +def series_get_file_list(ci_data, series, ignore_new_file=False): + """ + Get the list of files from the patches in the series. + """ + + file_list = [] + new_file_list = [] + + for patch in series['patches']: + full_patch = ci_data.pw.get_patch(patch['id']) + file_list += patch_get_file_list(full_patch['diff']) + if ignore_new_file: + new_file_list += patch_get_new_file_list(full_patch['diff']) + + if ignore_new_file == False or len(new_file_list) == 0: + return file_list + + log_debug("Check if new file is in the file list") + new_list = [] + for filename in file_list: + if filename in new_file_list: + log_debug(f"file:{filename} is in new_file_list. Don't count.") + continue + new_list.append(filename) + + return new_list + +def filter_repo_space(ci_data, space_details, series, src_dir): + """ + Check if the series belong to this repository + + if the series[name] has exclude string + return False + if the series[name] has include string + return True + get file list from the patch in series + if the file exist + return True + else + return False + """ + + log_debug(f"Check repo space for this series[{series['id']}]") + + # Check Exclude string + for str in space_details['exclude']: + if re.search(str, series['name'], re.IGNORECASE): + log_debug(f"Found EXCLUDE string: {str}") + return False + + # Check Include string + for str in space_details['include']: + if re.search(str, series['name'], re.IGNORECASE): + log_debug(f"Found INCLUDE string: {str}") + return True + + # Skip the rest of the test for now + return True + + # Get file list from the patches in the series + file_list = series_get_file_list(ci_data, series, ignore_new_file=True) + if len(file_list) == 0: + # Something is not right. + log_error("ERROR: No files found in the series/patch") + return False + log_debug(f"Files in series={file_list}") + + # File exist in source tree? + for filename in file_list: + file_path = os.path.join(src_dir, filename) + if not os.path.exists(file_path): + log_error(f"File not found: {filename}") + return False + + # Files exist in the source tree + log_info("Files exist in the source tree.") + return True + +EMAIL_MESSAGE = '''This is an automated email and please do not reply to this email. + +Dear Submitter, + +Thank you for submitting the patches to the Linux RISC-V mailing list. + +While preparing the CI tests, the patches you submitted couldn't be +applied to any of the current repository workflow branches. + +----- Output ----- +{content} + +Please resolve the issue and submit the patches again. + +--- +Regards, +Linux RISC-V bot + +''' + +def is_maintainers_only(email_config): + if 'only-maintainers' in email_config and email_config['only-maintainers']: + return True + return False + +def get_receivers(email_config, submitter): + log_debug("Get the list of email receivers") + + receivers = [] + if is_maintainers_only(email_config): + # Send only to the maintainers + receivers.extend(email_config['maintainers']) + else: + # Send to default-to and submitter + receivers.append(email_config['default-to']) + receivers.append(submitter) + + return receivers + +def send_email(ci_data, series, content): + + headers = {} + email_config = ci_data.config['email'] + + body = EMAIL_MESSAGE.format(content=content) + + patch_1 = series['patches'][0] + headers['In-Reply-To'] = patch_1['msgid'] + headers['References'] = patch_1['msgid'] + + if not is_maintainers_only(email_config): + headers['Reply-To'] = email_config['default-to'] + + receivers = get_receivers(email_config, + series['submitter']['email']) + ci_data.email.set_receivers(receivers) + + ci_data.email.compose(f"Re: {series['name']}", body, headers) + + if ci_data.config['dry_run']: + log_info("Dry-Run: Skip sending email") + return + + log_info("Sending Email...") + ci_data.email.send() + +PR_BODY = '''PR for series {sid} applied to {branch} + +Name: {name} +URL: {url} +Version: {version} +''' + +def series_check_patches(ci_data, series): + + series_dir = os.path.join(ci_data.config['temp_root'], f"{series['id']}") + if not os.path.exists(series_dir): + os.makedirs(series_dir) + + series_mbox = ci_data.pw.get_series_mbox(series['id']) + series_mbox_file = os.path.join(series_dir, "series.mbox") + with open(series_mbox_file, "w") as f: + f.write(series_mbox) + + already_checked = False + patch_1 = ci_data.pw.get_patch(series['patches'][0]['id']) + if patch_1['check'] != 'pending': + already_checked = True + log_info("This series is already checked") + + applied_branch = None + content = "" + for branch in ci_data.config['branch']: + ci_data.src_repo.git_checkout(branch); + ci_data.src_repo.git_checkout(f"pw{series['id']}", create_branch=True) + if ci_data.src_repo.git_am(series_mbox_file): + log_info(f"Failed to apply series {series['id']} to {branch}") + content += f"Failed to apply series {series['id']} to {branch}:\n\n" + content += ci_data.src_repo.stdout + content += ci_data.src_repo.stderr + content += "\n---\n" + ci_data.src_repo.git_am(abort=True) + continue + + log_info(f"Applied series {series['id']} to {branch}") + applied_branch = branch + # git am success + break + + if not applied_branch: + if ci_data.config['dry_run'] or already_checked: + log_info(f"Skip submitting the result to PW") + else: + url = ci_data.gh.create_gist(f"pw{series['id']}", "pre-ci_am-FAILED", content) + for patch in series['patches']: + ci_data.pw.post_check(patch, "pre-ci_am", 3, "Failed to apply series", + url=url) + + log_info("PRE-CI AM failed. Notify the submitter") + if ci_data.config['dry_run'] or already_checked: + log_info(f"Skip sending email: {content}") + return False + + send_email(ci_data, series, content) + return False + + if ci_data.config['disable_pr']: + log_info("Disable PR: Skip creating PR") + return True + + # Create Pull Request + if ci_data.src_repo.git_push(f"pw{series['id']}"): + log_error("Failed to push the source to Github") + return False + + title = f"[PW_SID:{series['id']}] {series['name']}" + + pr_body = PR_BODY.format(sid=series['id'], branch=applied_branch, name=series['name'], + url=series['web_url'], version=series['version']) + log_info(f"Creating PR: {title}") + if (pr := ci_data.gh.create_pr(title, pr_body, applied_branch, f"pw{series['id']}")): + if ci_data.config['dry_run'] or already_checked: + log_info("Skip submitting the result to PW: Success") + else: + for patch in series['patches']: + ci_data.pw.post_check(patch, "pre-ci_am", 1, "Success", url=pr.html_url) + + return True + + return False + +def run_series(ci_data, new_series): + + log_debug("##### Processing Series #####") + + space_details = ci_data.config['space_details'][ci_data.config['space']] + + # Process the series + for series in new_series: + log_info(f"\n### Process Series: {series['id']} ###") + + # If the series subject doesn't have the key-str, ignore it. + # Sometimes, the name have null value. If that's the case, use the + # name from the first patch and update to series name + if series['name'] == None: + patch_1 = series['patches'][0] + series['name'] = patch_1['name'] + log_debug(f"updated series name: {series['name']}") + + if not series['received_all']: + log_info(f"Series is NOT fully received") + continue + + # Filter the series by include/exclude string + if not filter_repo_space(ci_data, space_details, series, + ci_data.src_dir): + log_info(f"Series is NOT for this repo") + continue + + # Check if PR already exist + if ci_data.gh.pr_exist_title(f"PW_SID:{series['id']}"): + log_info("PR exists already") + continue + + # This series is ready to create PR + series_check_patches(ci_data, series) + + log_debug("##### processing Series Done #####") + +def sid_in_series_list(sid, series_list): + + log_debug(f"Search PW SID({sid} in the series list") + for series in series_list: + if int(sid) == series['id']: + log_debug("Found matching PW_SID in series list") + return series + + log_debug("No found matching PW_SID in series list") + + return None + +def cleanup_pullrequest(ci_data, new_series): + + log_debug("##### Clean Up Pull Request #####") + + prs = ci_data.gh.get_prs(force=True) + log_debug(f"Current PR: {prs}") + for pr in prs: + log_debug(f"PR: {pr}") + pw_sid = pr_get_sid(pr.title) + if not pw_sid: + log_debug(f"Not a valid PR title: {pr.title}. Skip PR") + continue + + log_debug(f"PW_SID: {pw_sid}") + + if sid_in_series_list(pw_sid, new_series): + log_debug(f"PW_SID:{pw_sid} found in PR list. Keep PR") + continue + + log_debug(f"PW_SID:{pw_sid} not found in PR list. Close PR") + + ci_data.gh.close_pr(pr.number) + + log_debug("##### Clean Up Pull Request Done #####") + +def check_args(args): + + if not os.path.exists(os.path.abspath(args.config)): + log_error(f"Invalid parameter(config) {args.config}") + return False + + if not os.path.exists(os.path.abspath(args.src_dir)): + log_error(f"Invalid parameter(src_dir) {args.src_dir}") + return False + + args.branch = args.branch or ["workflow"] + return True + +def parse_args(): + ap = argparse.ArgumentParser(description= + "Manage patch series in Patchwork and create PR") + ap.add_argument('-c', '--config', default='./config.json', + help='Configuration file to use') + ap.add_argument("-b", "--branch", default=None, action="append", + help="Name of branch in base_repo where the PR is pushed. " + "Use format. i.e. workflow") + ap.add_argument('-s', '--src-dir', required=True, + help='Source directory') + ap.add_argument('-d', '--dry-run', action='store_true', default=False, + help='Run it without uploading the result') + ap.add_argument('-p', '--disable-pr', action='store_true', default=False, + help='Disable creating pull request') + + ap.add_argument("repo", + help="Name of Github repository. i.e. linux-riscv/linux-riscv") + return ap.parse_args() + +def main(): + + init_logger("SyncPatchwork", verbose=True) + + args = parse_args() + if not check_args(args): + sys.exit(1) + + # Set temp workspace + temp_root = tempfile.TemporaryDirectory().name + log_info(f"Temp Root Dir: {temp_root}") + + ci_data = Context(config_file=os.path.abspath(args.config), + github_repo=args.repo, + src_dir=args.src_dir, + branch=args.branch, + space='kernel', + dry_run=args.dry_run, + disable_pr=args.disable_pr, + temp_root=temp_root) + + + # Process the series, state 1 = NEW + new_series = ci_data.pw.get_series_by_state(1, days_lookback=7) + if len(new_series) == 0: + log_info("No new patches/series found. Done. Exit") + return + + # Process Series + run_series(ci_data, new_series) + + # Cleanup PR + cleanup_pullrequest(ci_data, new_series) + + log_debug("----- DONE -----") + +if __name__ == "__main__": + main() diff --git a/.github/scripts/xfstests.sh b/.github/scripts/xfstests.sh new file mode 100755 index 00000000000000..f08f051d61cd99 --- /dev/null +++ b/.github/scripts/xfstests.sh @@ -0,0 +1,46 @@ +#!/bin/bash +# SPDX-FileCopyrightText: 2025 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +set -euox pipefail +d=$(dirname "${BASH_SOURCE[0]}") +. $d/series/utils.sh + +logs=$(get_logs_dir) +f=${logs}/xfstests.log + +KERNEL_PATH=$(find "$1" -name '*vmlinu[zx]*') +mv $KERNEL_PATH $KERNEL_PATH.gz +gunzip $KERNEL_PATH.gz + +ROOTFS_PATH=$(find /rootfs/ -name 'rootfs_rv64_ubuntu*.ext4') +# Resize the fs +truncate -s +20G $ROOTFS_PATH +resize2fs $ROOTFS_PATH + +build_name=$(cat "$1/kernel_version") + +# The Docker image comes with a prebuilt python environment with all tuxrun +# dependencies +source /build/.env/bin/activate + +xfs_tests=( "xfstests-ext4" "xfstests-btrfs" "xfstests-f2fs" "xfstests-xfs" ) + +mkdir -p /build/squad_json/ +parallel_log=$(mktemp -p ${ci_root}) + +for xfs_test in ${xfs_tests[@]}; do + echo "/build/tuxrun/run --runtime null --device qemu-riscv64 --kernel $KERNEL_PATH --tests ${xfs_test} --results /build/squad_json/${xfs_test}.json --log-file-text /build/squad_json/${xfs_test}.log --timeouts ${xfs_test}=480 --overlay /build/xfstests.tar.xz --rootfs $ROOTFS_PATH --boot-args \"rw\" || true" +done | parallel -j $(($(nproc)/4)) --colsep ' ' --joblog ${parallel_log} + +cat ${parallel_log} +rm ${parallel_log} + +for xfs_test in ${xfs_tests[@]}; do + # Convert JSON to squad datamodel + python3 /build/my-linux/.github/scripts/series/tuxrun_to_squad_json.py --result-path /build/squad_json/${xfs_test}.json --testsuite ${xfs_test} + python3 /build/my-linux/.github/scripts/series/generate_metadata.py --logs-path /build/squad_json/ --job-url ${GITHUB_JOB_URL} --branch ${GITHUB_BRANCH_NAME} + + curl --header "Authorization: token $SQUAD_TOKEN" --form tests=@/build/squad_json/${xfs_test}.squad.json --form log=@/build/squad_json/${xfs_test}.log --form metadata=@/build/squad_json/metadata.json https://mazarinen.tail1c623.ts.net/api/submit/riscv-linux/linux-all/${build_name}/qemu +done diff --git a/.github/workflows/kselftest.yml b/.github/workflows/kselftest.yml new file mode 100644 index 00000000000000..cf71d6d410b4fe --- /dev/null +++ b/.github/workflows/kselftest.yml @@ -0,0 +1,59 @@ +# SPDX-FileCopyrightText: 2024 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +name: linux-riscv-ci-kselftest + +defaults: + run: + shell: bash -leo pipefail {0} + +on: pull_request + +concurrency: + group: ci-test-${{ github.workflow }}-${{ github.ref_name }} + cancel-in-progress: true + +jobs: + build-series: + if: ${{ startsWith(github.head_ref, 'linus') || endsWith(github.head_ref, '_manual') }} + runs-on: self-hosted + timeout-minutes: 50400 # 35 days + container: + image: ghcr.io/linux-riscv/pw-builder:latest + volumes: + - /home/github/ramdisk/build:/build + - /home/github/ccache:/build/ccache + - /home/github/gitref:/build/gitref + steps: + - name: Configure git + run: | + git config --global --add safe.directory '*' + - name: Checkout git + run: | + mkdir -p /build/my-linux + cd /build/my-linux + git clone --filter=tree:0 --reference /build/gitref https://github.com/${{ github.repository }} . + git fetch origin ${{ github.event.pull_request.head.sha }} + git reset --hard ${{ github.event.pull_request.head.sha }} + git log -1 + - name: Run checks + continue-on-error: true + run: | + cd /build/my-linux && bash .github/scripts/kselftest.sh + - name: Collect logs + uses: actions/upload-artifact@v4 + with: + name: test-logs + path: /build/logs/* + - name: Publish to SQUAD + env: + SQUAD_TOKEN: ${{ secrets.SQUAD_TOKEN }} + GITHUB_JOB_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + run: | + /build/my-linux/.github/scripts/series/post_to_squad.py \ + --toplevel-log=/build/logs/kselftest.log \ + --selftest-bpf-log=/build/logs/test_kernel___rv64__kselftest__plain__gcc___ubuntu___server64__uboot_uefi__dt__kselftest-bpf.log \ + --selftest-log-dir=/build/logs/ \ + --job-url="${GITHUB_JOB_URL}" \ + --branch="${{ github.head_ref || github.ref_name }}" diff --git a/.github/workflows/libhugetlbfs.yml b/.github/workflows/libhugetlbfs.yml new file mode 100644 index 00000000000000..04bf3047741bbd --- /dev/null +++ b/.github/workflows/libhugetlbfs.yml @@ -0,0 +1,59 @@ +# SPDX-FileCopyrightText: 2024 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +name: linux-riscv-ci-libhugetlbfs + +defaults: + run: + shell: bash -leo pipefail {0} + +on: pull_request + +concurrency: + group: ci-test-${{ github.workflow }}-${{ github.ref_name }} + cancel-in-progress: true + +jobs: + build-series: + if: ${{ startsWith(github.head_ref, 'dev/alex/fixes_v6.12_test') }} + runs-on: self-hosted + timeout-minutes: 50400 # 35 days + container: + image: ghcr.io/linux-riscv/linaro-tuxrun-dispatcher-riscv64:latest + volumes: + - /home/github/ramdisk/build:/build + - /home/github/ccache:/build/ccache + - /home/github/gitref:/build/gitref + - /tmp:/tmp + - /boot:/boot + - /lib/modules:/lib/modules + options: --device /dev/kvm + steps: + - name: Configure git + run: | + git config --global --add safe.directory '*' + - name: Checkout git + run: | + mkdir -p /build/my-linux + cd /build/my-linux + git clone --filter=tree:0 --reference /build/gitref https://github.com/${{ github.repository }} . + git fetch origin ${{ github.event.pull_request.head.sha }} + git reset --hard ${{ github.event.pull_request.head.sha }} + git log -1 + - name: Run checks + env: + SQUAD_TOKEN: ${{ secrets.SQUAD_TOKEN_ALEX }} + GITHUB_JOB_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + continue-on-error: true + run: | + mkdir -p /build/logs/ + cd /build/my-linux && bash .github/scripts/libhugetlbfs.sh | tee -i /build/logs/all.log + - name: Collect logs and json squad + uses: actions/upload-artifact@v4 + with: + name: test-logs + path: | + /build/logs/* + /build/squad_json/* + diff --git a/.github/workflows/patchwork.yml b/.github/workflows/patchwork.yml new file mode 100644 index 00000000000000..593de064624f8d --- /dev/null +++ b/.github/workflows/patchwork.yml @@ -0,0 +1,64 @@ +# SPDX-FileCopyrightText: 2023 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +name: patchwork + +defaults: + run: + shell: bash -leo pipefail {0} + +on: pull_request + +concurrency: + group: ci-test-${{ github.workflow }}-${{ github.ref_name }} + cancel-in-progress: true + +jobs: + patchwork_ci: + if: ${{ startsWith(github.head_ref, 'pw') }} + runs-on: self-hosted + timeout-minutes: 50400 # 35 days + container: + image: ghcr.io/linux-riscv/pw-builder:latest + volumes: + - /home/github/ramdisk/build:/build + - /home/github/ccache:/build/ccache + - /home/github/gitref:/build/gitref + steps: + - name: Configure git + run: | + git config --global --add safe.directory '*' + git config --global user.name "Linux RISC-V bot" + git config --global user.email "linux.riscv.bot@gmail.com" + + - name: Checkout git + run: | + mkdir -p /build/linux + cd /build/linux + git clone --filter=tree:0 --reference /build/gitref https://github.com/${{ github.repository }} . + git fetch origin ${{ github.event.pull_request.head.sha }} + git reset --hard ${{ github.event.pull_request.head.sha }} + git log -1 + + - name: Create and activate virtual environment + run: | + python -m venv venv + source venv/bin/activate + echo "PATH=$PATH" >> $GITHUB_ENV + + - name: Install dependencies + run: | + pip install -r /build/linux/.github/scripts/requirements.txt + + - name: Run checks + env: + GITHUB_TOKEN: ${{ secrets.ACTION_TOKEN }} + GIST_TOKEN: ${{ secrets.GIST_TOKEN }} + PATCHWORK_TOKEN: ${{ secrets.PATCHWORK_TOKEN }} + PATCHWORK_USER: "" + EMAIL_TOKEN: ${{ secrets.EMAIL_TOKEN }} + run: | + cd /build/linux + ./.github/scripts/pw_ci.py -c ./.github/scripts/config.json -s /build/linux linux-riscv/linux + diff --git a/.github/workflows/series.yml b/.github/workflows/series.yml new file mode 100644 index 00000000000000..ba62596b47a899 --- /dev/null +++ b/.github/workflows/series.yml @@ -0,0 +1,52 @@ +# SPDX-FileCopyrightText: 2023 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +name: linux-riscv-ci-series + +defaults: + run: + shell: bash -leo pipefail {0} + +on: pull_request + +concurrency: + group: ci-test-${{ github.workflow }}-${{ github.ref_name }} + cancel-in-progress: true + +jobs: + build-series: + if: ${{ endsWith(github.head_ref, '_test') || endsWith(github.head_ref, '_manual') }} + runs-on: self-hosted + timeout-minutes: 50400 # 35 days + container: + image: ghcr.io/linux-riscv/pw-builder:latest + volumes: + - /home/github/ramdisk/build:/build + - /home/github/ccache:/build/ccache + - /home/github/gitref:/build/gitref + steps: + - name: Configure git + run: | + git config --global --add safe.directory '*' + - name: Checkout git + run: | + mkdir -p /build/my-linux + cd /build/my-linux + git clone --filter=tree:0 --reference /build/gitref https://github.com/${{ github.repository }} . + git fetch origin ${{ github.event.pull_request.head.sha }} + git reset --hard ${{ github.event.pull_request.head.sha }} + git log -1 + - name: Run checks + env: + SQUAD_TOKEN: ${{ secrets.SQUAD_TOKEN }} + GITHUB_JOB_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + GITHUB_BRANCH_NAME: ${{ github.head_ref || github.ref_name }} + continue-on-error: true + run: | + cd /build/my-linux && bash .github/scripts/series.sh + - name: Collect logs + uses: actions/upload-artifact@v4 + with: + name: test-logs + path: /build/logs/* diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml new file mode 100644 index 00000000000000..f787f02e3a866c --- /dev/null +++ b/.github/workflows/sync.yml @@ -0,0 +1,82 @@ +name: sync + +defaults: + run: + shell: bash -leo pipefail {0} + +on: + schedule: + - cron: "*/30 * * * *" + workflow_dispatch: + +concurrency: + group: ci-test-${{ github.workflow }}-${{ github.ref_name }} + +jobs: + sync_repo: + runs-on: ubuntu-latest + container: + image: ghcr.io/linux-riscv/pw-builder:latest + volumes: + - /home/github/ramdisk/build:/build + - /home/github/ccache:/build/ccache + - /home/github/gitref:/build/gitref + steps: + - name: Configure git + run: | + git config --global --add safe.directory '*' + git config --global user.name "Linux RISC-V bot" + git config --global user.email "linux.riscv.bot@gmail.com" + - name: Checkout git + run: | + mkdir -p /build/linux + cd /build/linux + git clone https://github.com/${{ github.repository }} . + git log --oneline -4 + - name: Sync Linus master + env: + ACTION_TOKEN: ${{ secrets.ACTION_TOKEN }} + run: | + cd /build/linux + ./.github/scripts/sync.sh "git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git" master master workflow "https://github.com/linux-riscv/github-ci.git" + - name: Sync RISC-V for-next + env: + ACTION_TOKEN: ${{ secrets.ACTION_TOKEN }} + run: | + cd /build/linux + ./.github/scripts/sync.sh "git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux.git" for-next master__riscv__for-next workflow__riscv__for-next "https://github.com/linux-riscv/github-ci.git" + - name: Sync RISC-V fixes + env: + ACTION_TOKEN: ${{ secrets.ACTION_TOKEN }} + run: | + cd /build/linux + ./.github/scripts/sync.sh "git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux.git" fixes master__riscv__fixes workflow__riscv__fixes "https://github.com/linux-riscv/github-ci.git" + + - name: Create and activate virtual environment + run: | + python -m venv venv + source venv/bin/activate + echo "PATH=$PATH" >> $GITHUB_ENV + + - name: Install dependencies + run: | + pip install -r /build/linux/.github/scripts/requirements.txt + + - name: Sync Patchwork + env: + GITHUB_TOKEN: ${{ secrets.ACTION_TOKEN }} + GIST_TOKEN: ${{ secrets.GIST_TOKEN }} + PATCHWORK_TOKEN: ${{ secrets.PATCHWORK_TOKEN }} + PATCHWORK_USER: "" + EMAIL_TOKEN: ${{ secrets.EMAIL_TOKEN }} + run: | + cd /build/linux + ./.github/scripts/sync_patchwork.py -c ./.github/scripts/config.json -s /build/linux -b workflow__riscv__fixes -b workflow__riscv__for-next -b workflow linux-riscv/linux + + - name: Clean PRs + env: + GITHUB_TOKEN: ${{ secrets.ACTION_TOKEN }} + GIST_TOKEN: ${{ secrets.GIST_TOKEN }} + run: | + cd /build/linux + ./.github/scripts/cleanup_pr.py linux-riscv/linux diff --git a/.github/workflows/testsuites.yml b/.github/workflows/testsuites.yml new file mode 100644 index 00000000000000..5b3de862d647a1 --- /dev/null +++ b/.github/workflows/testsuites.yml @@ -0,0 +1,212 @@ +# SPDX-FileCopyrightText: 2024 Rivos Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +name: linux-riscv-ci-testsuites + +defaults: + run: + shell: bash -leo pipefail {0} + +on: pull_request + +concurrency: + group: ci-test-${{ github.workflow }}-${{ github.ref_name }} + cancel-in-progress: true + +jobs: + build-kernel: + if: ${{ endsWith(github.head_ref, '_manual') }} + runs-on: self-hosted + timeout-minutes: 50400 # 35 days + container: + image: ghcr.io/linux-riscv/linaro-tuxrun-dispatcher-riscv64:latest + volumes: + - /home/github/ccache:/build/ccache + - /home/github/gitref:/build/gitref + steps: + - name: Configure git + run: | + git config --global --add safe.directory '*' + - name: Checkout git + run: | + mkdir -p /build/my-linux + cd /build/my-linux + git clone --filter=tree:0 --reference /build/gitref https://github.com/${{ github.repository }} . + git fetch origin ${{ github.event.pull_request.head.sha }} + git reset --hard ${{ github.event.pull_request.head.sha }} + git log -1 + - name: Build kernel + continue-on-error: true + run: | + mkdir -p /build/logs/ + cd /build/my-linux && bash .github/scripts/build_ubuntu_defconfig.sh + - name: Collect build log + uses: actions/upload-artifact@v4 + with: + name: test-logs + path: /build/logs/* + - name: Publish kernel + uses: actions/upload-artifact@v4 + # TODO create modules directory and kernel separately + with: + name: test-kernel + path: /build/rv64__testsuites__plain__gcc/* + - name: Publish CI files + uses: actions/upload-artifact@v4 + with: + include-hidden-files: true + name: ci-files + path: /build/my-linux/.github/* + + run-ltp: + needs: build-kernel + if: ${{ endsWith(github.head_ref, '_manual') }} + runs-on: self-hosted + timeout-minutes: 50400 # 35 days + container: + image: ghcr.io/linux-riscv/linaro-tuxrun-dispatcher-riscv64:latest + volumes: + - /home/github/ccache:/build/ccache + - /home/github/gitref:/build/gitref + - /tmp:/tmp + steps: + - name: Download pre-built kernel + uses: actions/download-artifact@v4 + with: + name: test-kernel + path: /build/test-kernel + - name: Download CI files + uses: actions/download-artifact@v4 + with: + name: ci-files + path: /build/my-linux/.github + - name: Run checks + env: + SQUAD_TOKEN: ${{ secrets.SQUAD_TOKEN }} + GITHUB_JOB_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + GITHUB_BRANCH_NAME: ${{ github.head_ref || github.ref_name }} + run: | + mkdir -p /build/logs/ + cd /build/my-linux && bash .github/scripts/ltp.sh /build/test-kernel | tee -i /build/logs/all.log + - name: Collect logs and json squad + uses: actions/upload-artifact@v4 + with: + name: test-logs-ltp + path: | + /build/logs/* + /build/squad_json/* + + run-libhugetlbfs: + needs: build-kernel + if: ${{ endsWith(github.head_ref, '_manual') }} + runs-on: self-hosted + timeout-minutes: 50400 # 35 days + container: + image: ghcr.io/linux-riscv/linaro-tuxrun-dispatcher-riscv64:latest + volumes: + - /home/github/ccache:/build/ccache + - /home/github/gitref:/build/gitref + - /tmp:/tmp + steps: + - name: Download pre-built kernel + uses: actions/download-artifact@v4 + with: + name: test-kernel + path: /build/test-kernel + - name: Download CI files + uses: actions/download-artifact@v4 + with: + name: ci-files + path: /build/my-linux/.github + - name: Run checks + env: + SQUAD_TOKEN: ${{ secrets.SQUAD_TOKEN }} + GITHUB_JOB_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + GITHUB_BRANCH_NAME: ${{ github.head_ref || github.ref_name }} + run: | + mkdir -p /build/logs/ + cd /build/my-linux && bash .github/scripts/libhugetlbfs.sh /build/test-kernel | tee -i /build/logs/all.log + - name: Collect logs and json squad + uses: actions/upload-artifact@v4 + with: + name: test-logs-libhugetlbfs + path: | + /build/logs/* + /build/squad_json/* + + run-xfstests: + needs: build-kernel + if: ${{ endsWith(github.head_ref, '_manual') }} + runs-on: self-hosted + timeout-minutes: 50400 # 35 days + container: + image: ghcr.io/linux-riscv/linaro-tuxrun-dispatcher-riscv64:latest + volumes: + - /home/github/ccache:/build/ccache + - /home/github/gitref:/build/gitref + - /tmp:/tmp + steps: + - name: Download pre-built kernel + uses: actions/download-artifact@v4 + with: + name: test-kernel + path: /build/test-kernel + - name: Download CI files + uses: actions/download-artifact@v4 + with: + name: ci-files + path: /build/my-linux/.github + - name: Run checks + env: + SQUAD_TOKEN: ${{ secrets.SQUAD_TOKEN }} + GITHUB_JOB_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + GITHUB_BRANCH_NAME: ${{ github.head_ref || github.ref_name }} + run: | + mkdir -p /build/logs/ + cd /build/my-linux && bash .github/scripts/xfstests.sh /build/test-kernel | tee -i /build/logs/all.log + - name: Collect logs and json squad + uses: actions/upload-artifact@v4 + with: + name: test-logs-xfstests + path: | + /build/logs/* + /build/squad_json/* + + run-isolated-tests: + needs: build-kernel + if: ${{ endsWith(github.head_ref, '_manual') }} + runs-on: self-hosted + timeout-minutes: 50400 # 35 days + container: + image: ghcr.io/linux-riscv/linaro-tuxrun-dispatcher-riscv64:latest + volumes: + - /home/github/ccache:/build/ccache + - /home/github/gitref:/build/gitref + - /tmp:/tmp + steps: + - name: Download pre-built kernel + uses: actions/download-artifact@v4 + with: + name: test-kernel + path: /build/test-kernel + - name: Download CI files + uses: actions/download-artifact@v4 + with: + name: ci-files + path: /build/my-linux/.github + - name: Run checks + env: + SQUAD_TOKEN: ${{ secrets.SQUAD_TOKEN }} + GITHUB_JOB_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + GITHUB_BRANCH_NAME: ${{ github.head_ref || github.ref_name }} + run: | + mkdir -p /build/logs/ + cd /build/my-linux && bash .github/scripts/isolated_tests.sh /build/test-kernel | tee -i /build/logs/all.log + - name: Collect logs and json squad + uses: actions/upload-artifact@v4 + with: + name: test-logs-isolated-tests + path: | + /build/logs/* + /build/squad_json/*