arch/risc-v/eic7700x: Correct the kernel memory map.

Three faults in how the kernel maps itself.

The page pool covered the RAM disk, which the boot loader appends above
the kernel, so the BSS clear destroyed it before anything searched for it.
The pool now covers only pgram, and the RAM disk is mapped on its own
account.

The kernel data region is mapped with 2 MiB pages rather than 4 KiB ones.
Everything in it carries the same permissions, so the finer granularity
bought nothing while costing one L3 slab per 2 MiB from a pool of two.

The linker script and Kconfig describe the page pool separately and both
descriptions are used, so they now agree.  When they disagree, pages
outside the smaller of the two get a virtual address of zero and are
written through, which on this SoC lands on identity mapped low memory
rather than faulting.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
This commit is contained in:
Justin Hammond
2026-08-19 01:40:57 +08:00
committed by Xiang Xiao
parent 6266800dc2
commit c60257bcc2
2 changed files with 44 additions and 1 deletions
+17 -1
View File
@@ -237,8 +237,16 @@ void eic7700x_kernel_mappings(void)
binfo("map kernel text\n");
map_region(KFLASH_START, KFLASH_START, KFLASH_SIZE, MMU_KTEXT_FLAGS);
/* The kernel data region is mapped with 2 MiB pages rather than through
* map_region()'s 4 KiB ones. Everything in it, data, bss, the page
* tables, the idle stacks and the whole kernel heap, carries the same
* permissions, so the finer granularity buys nothing while costing one L3
* slab per 2 MiB from a pool of exactly two.
*/
binfo("map kernel data\n");
map_region(KSRAM_START, KSRAM_START, KSRAM_SIZE, MMU_KDATA_FLAGS);
mmu_ln_map_region(2, PGT_L2_VBASE, KSRAM_START, KSRAM_START,
KSRAM_SIZE, MMU_KDATA_FLAGS);
/* Connect the L1 and L2 page tables for the kernel text and data */
@@ -250,6 +258,14 @@ void eic7700x_kernel_mappings(void)
binfo("map the page pool\n");
mmu_ln_map_region(2, PGT_L2_VBASE, PGPOOL_START, PGPOOL_START,
PGPOOL_SIZE, MMU_KDATA_FLAGS);
/* Map the RAM disk. The page pool no longer covers it, so it needs its
* own mapping or the first read of /dev/ram0 faults.
*/
binfo("map the RAM disk\n");
mmu_ln_map_region(2, PGT_L2_VBASE, RAMDISK_START, RAMDISK_START,
RAMDISK_SIZE, MMU_KDATA_FLAGS);
}
/****************************************************************************
@@ -31,6 +31,21 @@
#include <nuttx/debug.h>
#include <arch/board/board_memorymap.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* The granule allocator behind mm_pgalloc() counts its pages in a uint16_t,
* and gran_initialize() refuses a pool with more than UINT16_MAX of them,
* returning NULL. mm_pginitialize() then asserts, so an oversized pool is a
* board that does not boot rather than a board with less memory than asked
* for. See mm/mm_gran/mm_gran.h and mm/mm_gran/mm_graninit.c.
*/
#if (CONFIG_ARCH_PGPOOL_SIZE / CONFIG_MM_PGSIZE) > 65535
# error "Page pool has more pages than the granule allocator can count"
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
@@ -50,6 +65,18 @@ void up_allocate_pgheap(void **heap_start, size_t *heap_size)
{
DEBUGASSERT(heap_start && heap_size);
/* The linker script and Kconfig describe this pool separately, and both
* descriptions are used: the size below comes from the linker, while
* riscv_pgvaddr() decides whether a page is in the pool using the Kconfig
* values. If they disagree, pages outside the smaller of the two get a
* virtual address of zero and are then written through, which on this SoC
* lands on the identity mapped low memory rather than faulting. Say so
* here instead of finding out that way.
*/
DEBUGASSERT(PGPOOL_START == CONFIG_ARCH_PGPOOL_PBASE);
DEBUGASSERT(PGPOOL_SIZE == CONFIG_ARCH_PGPOOL_SIZE);
*heap_start = (void *)PGPOOL_START;
*heap_size = (size_t)PGPOOL_SIZE;
}