From 1653db7ddcc493fb625c168b020fe3d925787abc Mon Sep 17 00:00:00 2001 From: "liang.huang" Date: Tue, 3 Feb 2026 21:57:01 -0800 Subject: [PATCH] riscv: Fix page table traversal for SV39 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With CONFIG_PAGING enabled and the RISC-V SV39 MMU active, the page fault handler incorrectly tracked page table levels: `ptprev` pointed to the L1 page table while `ptlevel` indicated L2. This inconsistency caused faulty virtual address resolution. This commit fixes the traversal logic to ensure consistent level tracking across all three page table levels (L1–L3), enabling reliable page fault handling and on-demand paging. Additional changes: - Set PGT_L3_SIZE to 2048 to enable mapping up to 8MB of address space. - Update knsh_paging config to avoid crashes caused by excessive memory alignment requirements. - Add knsh64_paging config to verify this commit works as expected. Signed-off-by: liang.huang --- arch/risc-v/src/common/riscv_exception.c | 38 +++---- arch/risc-v/src/qemu-rv/qemu_rv_mm_init.c | 2 +- .../rv-virt/configs/knsh64_paging/defconfig | 98 +++++++++++++++++++ .../rv-virt/configs/knsh_paging/defconfig | 1 - 4 files changed, 120 insertions(+), 19 deletions(-) create mode 100644 boards/risc-v/qemu-rv/rv-virt/configs/knsh64_paging/defconfig diff --git a/arch/risc-v/src/common/riscv_exception.c b/arch/risc-v/src/common/riscv_exception.c index 05f433f4d03..ee798506767 100644 --- a/arch/risc-v/src/common/riscv_exception.c +++ b/arch/risc-v/src/common/riscv_exception.c @@ -207,26 +207,30 @@ int riscv_fillpage(int mcause, void *regs, void *args) } satp = READ_CSR(CSR_SATP); - ptprev = riscv_pgvaddr(mmu_satp_to_paddr(satp)); - ptlevel = ARCH_SPGTS; - paddr = mmu_pte_to_paddr(mmu_ln_getentry(ptlevel, ptprev, vaddr)); - if (!paddr) - { - /* Nothing yet, allocate one page for final level page table */ + paddr = mmu_satp_to_paddr(satp); - paddr = mm_pgalloc(1); + for (ptlevel = 1; ptlevel <= ARCH_SPGTS; ptlevel++) + { + ptprev = riscv_pgvaddr(paddr); + paddr = mmu_pte_to_paddr(mmu_ln_getentry(ptlevel, ptprev, vaddr)); if (!paddr) { - return -ENOMEM; + /* Nothing yet, allocate one page for next level page table */ + + paddr = mm_pgalloc(1); + if (!paddr) + { + return -ENOMEM; + } + + /* Map the page table to the prior level */ + + mmu_ln_setentry(ptlevel, ptprev, paddr, vaddr, MMU_UPGT_FLAGS); + + /* This is then used to map the next level */ + + riscv_pgwipe(paddr); } - - /* Map the page table to the prior level */ - - mmu_ln_setentry(ptlevel, ptprev, paddr, vaddr, MMU_UPGT_FLAGS); - - /* This is then used to map the final level */ - - riscv_pgwipe(paddr); } ptlast = riscv_pgvaddr(paddr); @@ -242,7 +246,7 @@ int riscv_fillpage(int mcause, void *regs, void *args) /* Then map the virtual address to the physical address */ - mmu_ln_setentry(ptlevel + 1, ptlast, paddr, vaddr, mmuflags); + mmu_ln_setentry(ARCH_PGT_MAX_LEVELS, ptlast, paddr, vaddr, mmuflags); return 0; } diff --git a/arch/risc-v/src/qemu-rv/qemu_rv_mm_init.c b/arch/risc-v/src/qemu-rv/qemu_rv_mm_init.c index bc3ab73d512..e553b40d0fa 100644 --- a/arch/risc-v/src/qemu-rv/qemu_rv_mm_init.c +++ b/arch/risc-v/src/qemu-rv/qemu_rv_mm_init.c @@ -82,7 +82,7 @@ #define PGT_L1_SIZE (512) /* Enough to map 512 GiB */ #define PGT_L2_SIZE (512) /* Enough to map 1 GiB */ -#define PGT_L3_SIZE (1024) /* Enough to map 4 MiB (2MiB x 2) */ +#define PGT_L3_SIZE (2048) /* Enough to map 8 MiB (2MiB x 4) */ #define SLAB_COUNT (sizeof(m_l3_pgtable) / RV_MMU_PAGE_SIZE) diff --git a/boards/risc-v/qemu-rv/rv-virt/configs/knsh64_paging/defconfig b/boards/risc-v/qemu-rv/rv-virt/configs/knsh64_paging/defconfig new file mode 100644 index 00000000000..1fca77a6dc4 --- /dev/null +++ b/boards/risc-v/qemu-rv/rv-virt/configs/knsh64_paging/defconfig @@ -0,0 +1,98 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ASSERTIONS_FILENAME is not set +# CONFIG_DISABLE_OS_API is not set +# CONFIG_NDEBUG is not set +# CONFIG_NSH_DISABLE_LOSMART is not set +CONFIG_16550_ADDRWIDTH=0 +CONFIG_16550_UART0=y +CONFIG_16550_UART0_BASE=0x10000000 +CONFIG_16550_UART0_CLOCK=3686400 +CONFIG_16550_UART0_IRQ=35 +CONFIG_16550_UART0_SERIAL_CONSOLE=y +CONFIG_16550_UART=y +CONFIG_ARCH="risc-v" +CONFIG_ARCH_ADDRENV=y +CONFIG_ARCH_BOARD="rv-virt" +CONFIG_ARCH_BOARD_QEMU_RV_VIRT=y +CONFIG_ARCH_CHIP="qemu-rv" +CONFIG_ARCH_CHIP_QEMU_RV64=y +CONFIG_ARCH_CHIP_QEMU_RV=y +CONFIG_ARCH_CHIP_QEMU_RV_ISA_A=y +CONFIG_ARCH_CHIP_QEMU_RV_ISA_C=y +CONFIG_ARCH_CHIP_QEMU_RV_ISA_M=y +CONFIG_ARCH_DATA_NPAGES=128 +CONFIG_ARCH_DATA_VBASE=0xC0100000 +CONFIG_ARCH_HEAP_NPAGES=2048 +CONFIG_ARCH_HEAP_VBASE=0xC0800000 +CONFIG_ARCH_INTERRUPTSTACK=2048 +CONFIG_ARCH_KERNEL_STACKSIZE=3072 +CONFIG_ARCH_PGPOOL_MAPPING=y +CONFIG_ARCH_PGPOOL_PBASE=0x80a00000 +CONFIG_ARCH_PGPOOL_SIZE=4194304 +CONFIG_ARCH_PGPOOL_VBASE=0x80a00000 +CONFIG_ARCH_RISCV=y +CONFIG_ARCH_RV_EXT_SSTC=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARCH_TEXT_NPAGES=128 +CONFIG_ARCH_TEXT_VBASE=0xC0000000 +CONFIG_ARCH_USE_MMU=y +CONFIG_ARCH_USE_MPU=y +CONFIG_ARCH_USE_S_MODE=y +CONFIG_BINFMT_ELF_EXECUTABLE=y +CONFIG_BOARD_INITTHREAD_STACKSIZE=3072 +CONFIG_BOARD_LATE_INITIALIZE=y +CONFIG_BOARD_LOOPSPERMSEC=6366 +CONFIG_BUILD_KERNEL=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_ELF=y +CONFIG_EXAMPLES_HELLO=m +CONFIG_EXAMPLES_HELLO_STACKSIZE=8192 +CONFIG_FS_PROCFS=y +CONFIG_FS_ROMFS=y +CONFIG_GRAN_INTR=y +CONFIG_IDLETHREAD_STACKSIZE=3072 +CONFIG_INIT_FILEPATH="/system/bin/init" +CONFIG_INIT_MOUNT=y +CONFIG_INIT_MOUNT_FLAGS=0x1 +CONFIG_INIT_MOUNT_TARGET="/system/bin" +CONFIG_INIT_STACKSIZE=3072 +CONFIG_INTELHEX_BINARY=y +CONFIG_LIBC_ENVPATH=y +CONFIG_LIBC_EXECFUNCS=y +CONFIG_LIBC_PERROR_STDOUT=y +CONFIG_LIBC_STRERROR=y +CONFIG_LIBM=y +CONFIG_MM_PGALLOC=y +CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6 +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_FILE_APPS=y +CONFIG_NSH_READLINE=y +CONFIG_PAGING=y +CONFIG_PATH_INITIAL="/system/bin" +CONFIG_POSIX_SPAWN_DEFAULT_STACKSIZE=1048576 +CONFIG_RAM_SIZE=4194304 +CONFIG_RAM_START=0x80600000 +CONFIG_READLINE_CMD_HISTORY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_HAVE_PARENT=y +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_SERIAL_UART_ARCH_MMIO=y +CONFIG_SIG_DEFAULT=y +CONFIG_START_MONTH=12 +CONFIG_START_YEAR=2021 +CONFIG_SYMTAB_ORDEREDBYNAME=y +CONFIG_SYSLOG_TIMESTAMP=y +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_NSH_PROGNAME="init" +CONFIG_TESTING_GETPRIME=y +CONFIG_TESTING_OSTEST=y +CONFIG_USEC_PER_TICK=1000 diff --git a/boards/risc-v/qemu-rv/rv-virt/configs/knsh_paging/defconfig b/boards/risc-v/qemu-rv/rv-virt/configs/knsh_paging/defconfig index 4d1c9bf9040..bbe83b1a908 100644 --- a/boards/risc-v/qemu-rv/rv-virt/configs/knsh_paging/defconfig +++ b/boards/risc-v/qemu-rv/rv-virt/configs/knsh_paging/defconfig @@ -94,5 +94,4 @@ CONFIG_SYSTEM_NSH=y CONFIG_SYSTEM_NSH_PROGNAME="init" CONFIG_TESTING_GETPRIME=y CONFIG_TESTING_OSTEST=y -CONFIG_TLS_LOG2_MAXSTACK=20 CONFIG_USEC_PER_TICK=1000