From b6ea9680f8c101967caf9981c2980b80b818ccbf Mon Sep 17 00:00:00 2001 From: Vivian Wang Date: Mon, 13 Jul 2026 11:29:52 -0600 Subject: [PATCH 1/7] riscv: mm: Make mark_new_valid_map() stuff depend on 64BIT && MMU None of the code relating to mark_new_valid_map() does anything useful without CONFIG_64BIT=y && CONFIG_MMU=y, because the new_valid_map_cpus_check code is only used if CONFIG_64BIT, and the exception codes checked there can only happen with CONFIG_MMU=y. Therefore, make these conditional on CONFIG_64BIT=y && CONFIG_MMU=y to simplify programming, since we do not have to handle CONFIG_MMU=n when changing this code in the future. This also removes some unused code on the entry path for CONFIG_MMU=n. Signed-off-by: Vivian Wang Link: https://patch.msgid.link/20260713-mark-after-vmemmap-populate-v6-1-b945ceba29d4@iscas.ac.cn Signed-off-by: Paul Walmsley --- arch/riscv/include/asm/cacheflush.h | 2 +- arch/riscv/kernel/entry.S | 2 +- arch/riscv/mm/init.c | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/riscv/include/asm/cacheflush.h b/arch/riscv/include/asm/cacheflush.h index 8cfe59483a8f..58e787fad029 100644 --- a/arch/riscv/include/asm/cacheflush.h +++ b/arch/riscv/include/asm/cacheflush.h @@ -40,7 +40,7 @@ do { \ flush_icache_mm(vma->vm_mm, 0); \ } while (0) -#ifdef CONFIG_64BIT +#if defined(CONFIG_64BIT) && defined(CONFIG_MMU) /* This is accessed in assembly code. cpumask_var_t would be too complex. */ extern DECLARE_BITMAP(new_valid_map_cpus, NR_CPUS); extern char _end[]; diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S index 08df724e13b9..d799c4e56f80 100644 --- a/arch/riscv/kernel/entry.S +++ b/arch/riscv/kernel/entry.S @@ -137,7 +137,7 @@ SYM_CODE_START(handle_exception) .Lrestore_kernel_tpsp: csrr tp, CSR_SCRATCH -#ifdef CONFIG_64BIT +#if defined(CONFIG_64BIT) && defined(CONFIG_MMU) /* * The RISC-V kernel does not flush TLBs on all CPUS after each new * vmalloc mapping or kfence_unprotect(), which may result in diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c index 5b1b3c88b4d1..3e450890be07 100644 --- a/arch/riscv/mm/init.c +++ b/arch/riscv/mm/init.c @@ -37,7 +37,9 @@ #include "../kernel/head.h" +#if defined(CONFIG_64BIT) && defined(CONFIG_MMU) DECLARE_BITMAP(new_valid_map_cpus, NR_CPUS); +#endif struct kernel_mapping kernel_map __ro_after_init; EXPORT_SYMBOL(kernel_map); From 4edd70ee6a7d0408a4e3ac921185779e7605f29c Mon Sep 17 00:00:00 2001 From: Vivian Wang Date: Mon, 13 Jul 2026 11:29:52 -0600 Subject: [PATCH 2/7] mm/sparse-vmemmap: flush_cache_vmap() after hotplugging vmemmap section_activate() does not flush TLB after populating new vmemmap pages. On most architectures, this is okay. However it is a problem on RISC-V since there the TLB caching non-present entries is permitted, which causes spurious faults on some hardwares. This seems to be most easily reproduced with DEBUG_VM=y and PAGE_POISONING=y, which causes these newly mapped struct pages to be poisoned i.e. written to immediately after mapping. Extend the RISC-V flush_cache_vmap() to also handle the vmemmap range, and call it after hotplugging vmemmap, which gets the possible spurious fault handled in the exception handler. At least for now, the only other architecture with both SPARSEMEM_VMEMMAP and flush_cache_vmap() is PowerPC, which has a similar problem with newly valid PTEs. But there flush_cache_vmap() is just a ptesync. So it should be safe to do this for generic code while having minimal performance impact. Suggested-by: Muchun Song Signed-off-by: Vivian Wang Reviewed-by: Muchun Song Acked-by: David Hildenbrand (Arm) Link: https://patch.msgid.link/20260713-mark-after-vmemmap-populate-v6-2-b945ceba29d4@iscas.ac.cn Signed-off-by: Paul Walmsley --- arch/riscv/include/asm/cacheflush.h | 3 ++- mm/sparse-vmemmap.c | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/riscv/include/asm/cacheflush.h b/arch/riscv/include/asm/cacheflush.h index 58e787fad029..c2b0a2928f06 100644 --- a/arch/riscv/include/asm/cacheflush.h +++ b/arch/riscv/include/asm/cacheflush.h @@ -56,7 +56,8 @@ static inline void mark_new_valid_map(void) #define flush_cache_vmap flush_cache_vmap static inline void flush_cache_vmap(unsigned long start, unsigned long end) { - if (is_vmalloc_or_module_addr((void *)start)) + if (is_vmalloc_or_module_addr((void *)start) || + (start >= VMEMMAP_START && end <= VMEMMAP_END)) mark_new_valid_map(); } #define flush_cache_vmap_early(start, end) local_flush_tlb_kernel_range(start, end) diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c index 99e2be39671b..ebd3ac997f64 100644 --- a/mm/sparse-vmemmap.c +++ b/mm/sparse-vmemmap.c @@ -564,6 +564,8 @@ struct page * __meminit __populate_section_memmap(unsigned long pfn, if (r < 0) return NULL; + flush_cache_vmap(start, end); + return pfn_to_page(pfn); } From 3a2694bf6ac8e47b3814293e80343f58fc72937f Mon Sep 17 00:00:00 2001 From: Rui Qi Date: Mon, 6 Jul 2026 21:04:14 +0800 Subject: [PATCH 3/7] riscv: Gate FUNCTION_ALIGNMENT_4B on DYNAMIC_FTRACE The FUNCTION_ALIGNMENT_4B select forces the whole kernel to be built with -fmin-function-alignment=4. This alignment is only needed so the patchable-function-entry NOPs, which arch/riscv/Makefile emits under CONFIG_DYNAMIC_FTRACE, can be patched reliably on RISCV_ISA_C=y builds where compressed instructions otherwise allow 2-byte function alignment. The select is currently gated on HAVE_DYNAMIC_FTRACE, a capability bit that is selected whenever the toolchain supports dynamic ftrace, rather than on whether tracing is actually enabled. As a result every RISCV_ISA_C=y build gets 4-byte function alignment across the entire kernel even when function tracing is disabled, needlessly growing the kernel image and wasting instruction cache for a feature that is not in use. Gate the select on DYNAMIC_FTRACE instead, matching the condition under which arch/riscv/Makefile emits -fpatchable-function-entry, so the alignment is only applied when it is actually needed. Fixes: c41bf4326c7b ("riscv: ftrace: align patchable functions to 4 Byte boundary") Signed-off-by: Rui Qi Link: https://patch.msgid.link/20260706130415.463682-1-qirui.001@bytedance.com Signed-off-by: Paul Walmsley --- arch/riscv/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index c0a6992933e4..f7028caaeae0 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -157,7 +157,7 @@ config RISCV select HAVE_DEBUG_KMEMLEAK select HAVE_DMA_CONTIGUOUS if MMU select HAVE_DYNAMIC_FTRACE if MMU && (CLANG_SUPPORTS_DYNAMIC_FTRACE || GCC_SUPPORTS_DYNAMIC_FTRACE) - select FUNCTION_ALIGNMENT_4B if HAVE_DYNAMIC_FTRACE && RISCV_ISA_C + select FUNCTION_ALIGNMENT_4B if DYNAMIC_FTRACE && RISCV_ISA_C 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) select HAVE_DYNAMIC_FTRACE_WITH_ARGS if HAVE_DYNAMIC_FTRACE From 6dc3934152d1cc48b0395264d0061ebb4aed359e Mon Sep 17 00:00:00 2001 From: Yunhui Cui Date: Fri, 3 Jul 2026 20:28:30 +0800 Subject: [PATCH 4/7] riscv: io: avoid null-pointer arithmetic in PIO helpers When port I/O is not supported, exposing the port-string helpers is both unnecessary and can make clang diagnose null-pointer arithmetic from the PCI_IOBASE based address expression. Keep the MMIO string helpers available as before, but only provide the port I/O variants when CONFIG_HAS_IOPORT is enabled. Signed-off-by: Yunhui Cui Reviewed-by: Arnd Bergmann Link: https://patch.msgid.link/20260703122832.15984-2-cuiyunhui@bytedance.com Signed-off-by: Paul Walmsley --- arch/riscv/include/asm/io.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/riscv/include/asm/io.h b/arch/riscv/include/asm/io.h index 09bb5f57a9d3..92d5f831f349 100644 --- a/arch/riscv/include/asm/io.h +++ b/arch/riscv/include/asm/io.h @@ -102,12 +102,14 @@ __io_reads_ins(reads, u32, l, __io_br(), __io_ar(addr)) #define readsw(addr, buffer, count) __readsw(addr, buffer, count) #define readsl(addr, buffer, count) __readsl(addr, buffer, count) +#ifdef CONFIG_HAS_IOPORT __io_reads_ins(ins, u8, b, __io_pbr(), __io_par(addr)) __io_reads_ins(ins, u16, w, __io_pbr(), __io_par(addr)) __io_reads_ins(ins, u32, l, __io_pbr(), __io_par(addr)) #define insb(addr, buffer, count) __insb(PCI_IOBASE + (addr), buffer, count) #define insw(addr, buffer, count) __insw(PCI_IOBASE + (addr), buffer, count) #define insl(addr, buffer, count) __insl(PCI_IOBASE + (addr), buffer, count) +#endif __io_writes_outs(writes, u8, b, __io_bw(), __io_aw()) __io_writes_outs(writes, u16, w, __io_bw(), __io_aw()) @@ -116,26 +118,32 @@ __io_writes_outs(writes, u32, l, __io_bw(), __io_aw()) #define writesw(addr, buffer, count) __writesw(addr, buffer, count) #define writesl(addr, buffer, count) __writesl(addr, buffer, count) +#ifdef CONFIG_HAS_IOPORT __io_writes_outs(outs, u8, b, __io_pbw(), __io_paw()) __io_writes_outs(outs, u16, w, __io_pbw(), __io_paw()) __io_writes_outs(outs, u32, l, __io_pbw(), __io_paw()) #define outsb(addr, buffer, count) __outsb(PCI_IOBASE + (addr), buffer, count) #define outsw(addr, buffer, count) __outsw(PCI_IOBASE + (addr), buffer, count) #define outsl(addr, buffer, count) __outsl(PCI_IOBASE + (addr), buffer, count) +#endif #ifdef CONFIG_64BIT __io_reads_ins(reads, u64, q, __io_br(), __io_ar(addr)) #define readsq(addr, buffer, count) __readsq(addr, buffer, count) +#ifdef CONFIG_HAS_IOPORT __io_reads_ins(ins, u64, q, __io_pbr(), __io_par(addr)) #define insq(addr, buffer, count) __insq(PCI_IOBASE + (addr), buffer, count) +#endif __io_writes_outs(writes, u64, q, __io_bw(), __io_aw()) #define writesq(addr, buffer, count) __writesq(addr, buffer, count) +#ifdef CONFIG_HAS_IOPORT __io_writes_outs(outs, u64, q, __io_pbr(), __io_paw()) #define outsq(addr, buffer, count) __outsq(PCI_IOBASE + (addr), buffer, count) #endif +#endif #include From ad6dcfa023762e37962f77ee48e752b7570e9440 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 1 Jul 2026 11:21:22 +0200 Subject: [PATCH 5/7] riscv: vdso: Do not use LTO for the vDSO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With LTO enabled the compiler assumes that the vDSO functions are not used and optimizes them away completely. Currently this happens to __vdso_clock_getres(), __vdso_clock_gettime(), __vdso_getrandom(), __vdso_gettimeofday() and __vdso_riscv_hwprobe(). Disable LTO for the vDSO, as these functions are hand-optimized anyways. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202606301855.WvkSC4kD-lkp@intel.com/ Fixes: 021d23428bdb ("RISC-V: build: Allow LTO to be selected") Cc: stable@vger.kernel.org Signed-off-by: Thomas Weißschuh Link: https://patch.msgid.link/20260701-riscv-vdso-lto-v1-1-89db0cd82077@linutronix.de Signed-off-by: Paul Walmsley --- arch/riscv/kernel/vdso/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/riscv/kernel/vdso/Makefile b/arch/riscv/kernel/vdso/Makefile index a842dc034571..43ee881f6c6f 100644 --- a/arch/riscv/kernel/vdso/Makefile +++ b/arch/riscv/kernel/vdso/Makefile @@ -69,9 +69,9 @@ CPPFLAGS_$(vdso_lds) += -DHAS_VGETTIMEOFDAY endif # Disable -pg to prevent insert call site -CFLAGS_REMOVE_vgettimeofday.o = $(CC_FLAGS_FTRACE) $(CC_FLAGS_SCS) -CFLAGS_REMOVE_getrandom.o = $(CC_FLAGS_FTRACE) $(CC_FLAGS_SCS) -CFLAGS_REMOVE_hwprobe.o = $(CC_FLAGS_FTRACE) $(CC_FLAGS_SCS) +CFLAGS_REMOVE_vgettimeofday.o = $(CC_FLAGS_FTRACE) $(CC_FLAGS_SCS) $(CC_FLAGS_LTO) +CFLAGS_REMOVE_getrandom.o = $(CC_FLAGS_FTRACE) $(CC_FLAGS_SCS) $(CC_FLAGS_LTO) +CFLAGS_REMOVE_hwprobe.o = $(CC_FLAGS_FTRACE) $(CC_FLAGS_SCS) $(CC_FLAGS_LTO) # Force dependency $(obj)/$(vdso_o): $(obj)/$(vdso_so) From e4bf6eb4c7b61db1cf24487e14e6ae8755e61e3d Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 23 Jun 2026 22:40:57 +0200 Subject: [PATCH 6/7] arch/riscv: vdso: remove CFI landing pad from rt_sigreturn When CONFIG_RISCV_USER_CFI is enabled, the CFI version of the vDSO, has a CFI landing pad instruction at the start of __vdso_rt_sigreturn. This breaks libgcc's unwinding code which matches on the first two instructions. Other unwinders that rely on similar instruction matching may also be affected. Since __vdso_rt_sigreturn is reached as part of signal-return handling rather than via an indirect call/jump from userspace, it does not need a CFI landing pad. Remove it and restore the instruction sequence expected by existing unwinding code. This matches what was done on arm64 in commit 9a964285572b ("arm64: vdso: Don't prefix sigreturn trampoline with a BTI C instruction") for a similar issue. Cc: stable@vger.kernel.org Fixes: 37f57bd3faea ("arch/riscv: compile vdso with landing pad and shadow stack note") Co-authored-by: Joel Stanley Signed-off-by: Aurelien Jarno Signed-off-by: Joel Stanley Link: https://patch.msgid.link/20260623204058.498120-1-aurelien@aurel32.net [pjw@kernel.org: fixed comment style] Signed-off-by: Paul Walmsley --- arch/riscv/kernel/vdso/rt_sigreturn.S | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/riscv/kernel/vdso/rt_sigreturn.S b/arch/riscv/kernel/vdso/rt_sigreturn.S index e82987dc3739..d6f96b1abe40 100644 --- a/arch/riscv/kernel/vdso/rt_sigreturn.S +++ b/arch/riscv/kernel/vdso/rt_sigreturn.S @@ -7,11 +7,19 @@ #include #include +/* + * WARNING: Do NOT add a CFI landing pad at the start of this function. + * Unwinders such as libgcc identify the sigreturn trampoline by matching the + * instruction sequence. Adding a landing pad here would break unwinding from + * signal handlers. + * + * This trampoline is used only for signal return and not via an indirect + * call/jump from userspace, so adding CFI landing pad is unnecessary. + */ .text SYM_FUNC_START(__vdso_rt_sigreturn) .cfi_startproc .cfi_signal_frame - vdso_lpad li a7, __NR_rt_sigreturn ecall .cfi_endproc From 5caae1deee89a6582c761d5dcd4b924b744426cc Mon Sep 17 00:00:00 2001 From: Mark Harris Date: Mon, 13 Jul 2026 17:30:56 -0700 Subject: [PATCH 7/7] riscv: hwprobe: Avoid uninitialized read in hwprobe_get_cpus() When cpusetsize < cpumask_size(), hwprobe_get_cpus() did not fully initialize its copy of the cpu mask, which could cause non-deterministic results from the riscv_hwprobe syscall on a system with more than 8 CPUs when the supplied cpu mask is empty. Address this by fully initializing the cpu mask. Fixes: e178bf146e4b ("RISC-V: hwprobe: Introduce which-cpus flag") Signed-off-by: Mark Harris Reviewed-by: Nam Cao Reviewed-by: Michael Ellerman Link: https://patch.msgid.link/20260714003056.73707-1-mark.hsj@gmail.com Signed-off-by: Paul Walmsley --- arch/riscv/kernel/sys_hwprobe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c index 1659d31fd288..caf6762427c8 100644 --- a/arch/riscv/kernel/sys_hwprobe.c +++ b/arch/riscv/kernel/sys_hwprobe.c @@ -450,6 +450,7 @@ static int hwprobe_get_cpus(struct riscv_hwprobe __user *pairs, if (cpusetsize > cpumask_size()) cpusetsize = cpumask_size(); + cpumask_clear(&cpus); ret = copy_from_user(&cpus, cpus_user, cpusetsize); if (ret) return -EFAULT;