This document explains memmap.ld, the single source of truth for the
physical memory layout shared across every linked image in this project
(currently jny, the bootloader, and emilia, the kernel).
jny.ld and emilia.ld each need to agree on where RAM starts, how big
it is, and where the boot region ends and the kernel region begins. If
each repo hardcoded its own copy of those numbers, they could silently
drift apart, one script gets edited, the other doesn't, and now the
bootloader hands off to an address the kernel script doesn't actually
own. Keeping the numbers in one place and pulling a copy into each
consuming repo (via puller.toml/pulled.toml thanks to pff) means there is exactly
one place to change the memory map, and every image that includes it
picks up the same values.
RAM_SIZE = 128M;
BOOT_ORIGIN = 0x80000000;
BOOT_LENGTH = 16K;
KERNEL_ORIGIN = BOOT_ORIGIN + BOOT_LENGTH;
KERNEL_LENGTH = RAM_SIZE - BOOT_LENGTH;| Constant | Value | Meaning |
|---|---|---|
RAM_SIZE |
128M |
Total usable RAM on the target (matches qemu-system-riscv64 -m 128M) |
BOOT_ORIGIN |
0x80000000 |
Start of DRAM on QEMU's RISC-V virt machine |
BOOT_LENGTH |
16K |
Size of the region reserved for the bootloader image |
KERNEL_ORIGIN |
BOOT_ORIGIN + BOOT_LENGTH |
Start of the region reserved for the kernel image |
KERNEL_LENGTH |
RAM_SIZE - BOOT_LENGTH |
Size of the region reserved for the kernel image |
BOOT_ORIGIN is a QEMU/SiFive convention, not a RISC-V architectural
requirement, virt reserves the low addresses for boot ROM and
memory-mapped devices and leaves 0x80000000 as the start of DRAM. See
jny.ld for the full breakdown
of virt's memory map.
KERNEL_ORIGIN is defined in terms of BOOT_ORIGIN + BOOT_LENGTH rather
than as its own literal, so the boot and kernel regions are always
adjacent and non-overlapping by construction: grow BOOT_LENGTH and
KERNEL_ORIGIN moves with it automatically, there's no second number to
remember to update.
- jny.ld: the bootloader's
linker script. Its
MEMORYblock isORIGIN = BOOT_ORIGIN, LENGTH = BOOT_LENGTH, and it exposes_kstart = KERNEL_ORIGINas the handoff address it jumps to once boot setup is done. - emilia.ld: the kernel's
linker script. Its
MEMORYblock isORIGIN = KERNEL_ORIGIN, LENGTH = KERNEL_LENGTH, picking up exactly where the boot region ends.
- Single flat RAM region. No separate regions for boot ROM, flash, or
MMIO device ranges, only the split between boot and kernel RAM. QEMU's
virtmachine's device ranges below0x80000000don't need describing here since neither consuming script ever places sections there. - No FPGA target yet. These values are QEMU-specific. A real SoC build will need its own memory map (or a variant of this one) once RAM size, origin, and any additional reserved regions are known for the actual board.
These will be revisited as the project grows, this file covers exactly what's needed for the two images that exist today.