From efacd971904a8521c911ccbee2bd31354601c7be Mon Sep 17 00:00:00 2001 From: bernard Date: Sun, 18 Oct 2026 19:33:57 +0800 Subject: [PATCH 1/2] [libcpu][riscv] fix MMU and user fault handling for Smart - add XuanTie architecture selection and the SVPBMT option - translate early page table pointers with the kernel physical offset - allow the MPR range to extend below the linked kernel base - clean early page tables and clear user entries for each hart - terminate only the current LWP on unhandled user faults - keep interrupts enabled while reporting user context --- libcpu/Kconfig | 12 ++++++++++++ libcpu/risc-v/common/mmu.c | 31 ++++++++++++++++++++++++++++--- libcpu/risc-v/common/trap.c | 19 ++++++++++++++++--- libcpu/risc-v/common64/mmu.c | 35 +++++++++++++++++++++++++++++++++-- 4 files changed, 89 insertions(+), 8 deletions(-) diff --git a/libcpu/Kconfig b/libcpu/Kconfig index 7f3dfca11f1f..3b1edab25084 100644 --- a/libcpu/Kconfig +++ b/libcpu/Kconfig @@ -288,6 +288,10 @@ config ARCH_RISCV64 select ARCH_CPU_64BIT bool +config ARCH_RISCV_XUANTIE + select ARCH_RISCV + bool + if ARCH_RISCV orsource "./risc-v/Kconfig" endif @@ -304,6 +308,14 @@ if ARCH_RISCV64 select ARCH_USING_NEW_CTX_SWITCH help Using the common64 implementation under ./libcpu/risc-v + +if RT_USING_SMART + config CONFIG_XUANTIE_SVPBMT + int + depends on ARCH_RISCV_XUANTIE + default 1 +endif + endif config ARCH_REMAP_KERNEL diff --git a/libcpu/risc-v/common/mmu.c b/libcpu/risc-v/common/mmu.c index 8a15c24f2d86..8acd2cbc0cbe 100644 --- a/libcpu/risc-v/common/mmu.c +++ b/libcpu/risc-v/common/mmu.c @@ -136,6 +136,7 @@ static int mmu_map_early(rt_ubase_t *tbl, rt_uint8_t max_level, rt_ubase_t va, rt_ubase_t pa, rt_ubase_t attr, rt_bool_t flush) { rt_ubase_t page, *table, off, level_shift; + rt_ubase_t pv_off = flush ? rt_kmem_pvoff() : 0; attr = mmu_attr_fixup(attr); @@ -168,7 +169,7 @@ static int mmu_map_early(rt_ubase_t *tbl, rt_uint8_t max_level, return MMU_MAP_ERROR_NOPAGE; } - rt_memset((void *)page, 0, ARCH_PAGE_SIZE); + rt_memset((void *)(page - pv_off), 0, ARCH_PAGE_SIZE); table[off] = ((page >> ARCH_PAGE_SHIFT) << PTE_BITS) | PTE_V; if (flush) @@ -185,7 +186,7 @@ static int mmu_map_early(rt_ubase_t *tbl, rt_uint8_t max_level, /* Step into the next level page table */ page = (table[off] >> PTE_BITS) << ARCH_PAGE_SHIFT; - table = (rt_ubase_t *)page; + table = (rt_ubase_t *)(page - pv_off); level_shift -= VPN_BITS; } @@ -934,6 +935,12 @@ int rt_hw_mmu_map_init(rt_aspace_t aspace, void *v_address, rt_ubase_t size, #if __riscv_xlen == 32 && !defined(RT_USING_SMART) /* The RV32 ioremap and MPR regions are placed below the kernel image. */ aspace_start = (rt_ubase_t)v_address - rt_mpr_size; +#elif defined(RT_USING_SMART) + /* The runtime-sized MPR can extend below the linked kernel base. */ + if ((rt_ubase_t)v_address - rt_mpr_size < aspace_start) + { + aspace_start = (rt_ubase_t)v_address - rt_mpr_size; + } #endif rt_aspace_init(aspace, (void *)aspace_start, 0UL - aspace_start, vtable); @@ -1395,10 +1402,28 @@ void *rt_hw_mmu_pgtbl_create(void) (void *)rt_kernel_space.page_table + i * ARCH_PAGE_SIZE, ARCH_PAGE_SIZE); } +#else + rt_memcpy(mmu_table, rt_kernel_space.page_table, ARCH_PAGE_SIZE); +#endif + +#ifdef RT_USING_SMART + /* Do not share early identity mappings with the user address space. */ + rt_size_t user_start = get_top_vpn(USER_VADDR_START, satp_level_4k); + rt_size_t user_end = get_top_vpn(USER_VADDR_TOP - 1, satp_level_4k); + + for (int i = 0; i < (1UL << alloc_bits); ++i) + { + rt_ubase_t *table = (void *)mmu_table + i * ARCH_PAGE_SIZE; + + rt_memset(table + user_start, 0, + (user_end - user_start + 1) * sizeof(*table)); + } +#endif + +#ifdef MMU_PERCPU rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_table, RT_CPUS_NR * ARCH_PAGE_SIZE); #else - rt_memcpy(mmu_table, rt_kernel_space.page_table, ARCH_PAGE_SIZE); rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_table, ARCH_PAGE_SIZE); #endif diff --git a/libcpu/risc-v/common/trap.c b/libcpu/risc-v/common/trap.c index 64074399fc7b..d459118da0ce 100644 --- a/libcpu/risc-v/common/trap.c +++ b/libcpu/risc-v/common/trap.c @@ -46,10 +46,14 @@ static void _check_fault(struct rt_hw_stack_frame *regs, uint32_t pc_adj, char * { rt_thread_t th; rt_bool_t is_user_fault = !(regs->xstatus & SR_PP); + rt_base_t saved_stat = 0; if (is_user_fault) { + /* User backtrace and process teardown can acquire sleeping locks. */ + saved_stat = csr_read_set(CSR_STATUS, SR_IE); rt_kprintf("%s! pc = %p\n", info, regs->epc - pc_adj); + rt_hw_show_register(regs); } /* User stack backtrace */ @@ -65,6 +69,7 @@ static void _check_fault(struct rt_hw_stack_frame *regs, uint32_t pc_adj, char * lwp_core_dump(regs, pc_adj); #endif sys_exit_group(-1); + csr_write(CSR_STATUS, saved_stat); } } @@ -296,6 +301,7 @@ void rt_hw_trap(struct rt_hw_stack_frame *regs) { rt_ubase_t xcause = regs->xcause; rt_ubase_t tval = csr_read_clear(CSR_TVAL, 0); + rt_bool_t is_user_fault = !(regs->xstatus & SR_PP); /* IRQ */ if (xcause & CAUSE_IRQ_FLAG) @@ -364,16 +370,23 @@ void rt_hw_trap(struct rt_hw_stack_frame *regs) case EXC_INST_PAGE_FAULT: case EXC_LOAD_PAGE_FAULT: case EXC_STORE_PAGE_FAULT: - #ifdef RT_USING_SMART - if (!(regs->xstatus & SR_PP) || +#ifdef RT_USING_SMART + if (is_user_fault || (tval >= USER_VADDR_START && tval < USER_VADDR_TOP)) { if (user_fault_fixable(regs, xcause, tval)) { return; } + + /* A failed user mapping must terminate only the LWP. */ + if (is_user_fault && rt_thread_self()) + { + _check_fault(regs, 0, "user fault"); + return; + } } - #endif /* RT_USING_SMART */ +#endif /* RT_USING_SMART */ default: LOG_E("Unhandle Execption: (%d) %s, TVAL = %p", xcause, diff --git a/libcpu/risc-v/common64/mmu.c b/libcpu/risc-v/common64/mmu.c index f09100c3d4f0..d834a722b05f 100644 --- a/libcpu/risc-v/common64/mmu.c +++ b/libcpu/risc-v/common64/mmu.c @@ -12,6 +12,7 @@ */ #include +#include #include #include @@ -85,6 +86,20 @@ void rt_hw_aspace_switch(rt_aspace_t aspace) uint32_t hartid = rt_hw_cpu_id(); uintptr_t ptr = (uintptr_t)aspace->page_table + (uintptr_t)(hartid * ARCH_PAGE_SIZE); uintptr_t page_table = (uintptr_t)rt_kmem_v2p((void *)ptr); + + if (page_table == (uintptr_t)ARCH_MAP_FAILED) + { + /* + * During early K230 bring-up the kernel still runs with low physical + * pointers after relocation, including MMUTable. The formal kernel + * aspace does not translate that low pointer yet, but SATP needs the + * physical page-table address, so use the low address directly. + */ + if (ptr < KERNEL_VADDR_START) + { + page_table = ptr; + } + } #ifndef RT_USING_SMP current_mmu_table = aspace->page_table; #else @@ -632,14 +647,14 @@ static inline void _init_region(void *vaddr, size_t size) { rt_ioremap_start = vaddr; rt_ioremap_size = size; - rt_mpr_start = rt_ioremap_start - rt_mpr_size; + rt_mpr_start = (void *)((rt_ubase_t)rt_ioremap_start - rt_mpr_size); LOG_D("rt_ioremap_start: %p, rt_mpr_start: %p", rt_ioremap_start, rt_mpr_start); } #else static inline void _init_region(void *vaddr, size_t size) { - rt_mpr_start = vaddr - rt_mpr_size; + rt_mpr_start = (void *)((rt_ubase_t)vaddr - rt_mpr_size); } #endif @@ -1057,6 +1072,9 @@ void rt_hw_mem_setup_early(void *pgtbl, rt_uint64_t hartid) vs += EARLY_MAP_PAGE_SIZE_2M; } #endif + /* flush page table entries from data cache before enabling MMU */ + rt_hw_cpu_dcache_clean(early_pgtbl, ARCH_PAGE_SIZE); + /* apply new mapping */ asm volatile("sfence.vma x0, x0"); write_csr(satp, SATP_BASE | ((size_t)early_pgtbl >> PAGE_OFFSET_BIT)); @@ -1121,6 +1139,19 @@ void *rt_hw_mmu_pgtbl_create(void) return RT_NULL; } rt_memcpy(mmu_table, rt_kernel_space.page_table, ARCH_PAGE_SIZE); + +#ifdef RT_USING_SMART + { + int i; + int start_idx = USER_VADDR_START >> VPN2_SHIFT; + int end_idx = USER_VADDR_TOP >> VPN2_SHIFT; + for (i = start_idx; i <= end_idx; i++) + { + mmu_table[i] = 0; + } + } +#endif + rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_table, ARCH_PAGE_SIZE); #endif From 88463e20eb17115bc341b94b1cfc8b8798122fb2 Mon Sep 17 00:00:00 2001 From: bernard Date: Sun, 18 Oct 2026 20:43:51 +0800 Subject: [PATCH 2/2] [libcpu][riscv] declare rt_hw_show_register before use - add a forward declaration for the user fault register dump - fix the implicit declaration error on RISC-V builds --- libcpu/risc-v/common/trap.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libcpu/risc-v/common/trap.c b/libcpu/risc-v/common/trap.c index d459118da0ce..84bc9c7c0be6 100644 --- a/libcpu/risc-v/common/trap.c +++ b/libcpu/risc-v/common/trap.c @@ -33,6 +33,8 @@ extern long list_thread(void); #endif +void rt_hw_show_register(struct rt_hw_stack_frame *regs); + #ifdef RT_USING_LWP #include #include