riscv: Fix page table traversal for SV39

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 <liang.huang@houmo.ai>
This commit is contained in:
liang.huang 2026-02-03 21:57:01 -08:00 committed by Alan C. Assis
parent 82a218cbf3
commit 1653db7ddc
4 changed files with 120 additions and 19 deletions

View file

@ -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;
}

View file

@ -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)

View file

@ -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

View file

@ -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