Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
b5917a7
loader(aarch64): pass PTs to enable MMU assembler
midnightveil May 6, 2026
75b307c
loader(aarch64): dynamically allocate PTs
midnightveil May 18, 2026
e8ee048
loader(riscv64): apply the aarch64 treatment
midnightveil May 18, 2026
3aba572
[WIP] ram
midnightveil May 22, 2026
5417be0
loader: gc-sections
midnightveil Jul 28, 2026
0557f16
move the stuff to runtime (but it breaks it!! need fix!!)
midnightveil Jul 29, 2026
30cc89e
fixes
midnightveil Jul 29, 2026
aaaa69a
back to old style
midnightveil Jul 29, 2026
807aa03
FIX
midnightveil Jul 29, 2026
8a87d9d
minor makefile touchups
midnightveil Jul 31, 2026
0890270
tests + return struct
midnightveil Aug 18, 2026
62651ed
work again for qemu
midnightveil Aug 18, 2026
2ccf7c2
make it easier
midnightveil Aug 18, 2026
5577520
tests part of build
midnightveil Aug 18, 2026
ac001d0
clippy
midnightveil Aug 18, 2026
61604b1
clippy
midnightveil Aug 18, 2026
9716d32
rustfmt + cleanup make
midnightveil Aug 18, 2026
70fea7e
don't create large temporaries on the stack
midnightveil Aug 18, 2026
1fbf199
fix stack overflow
midnightveil Aug 18, 2026
9bb64fb
fix style
midnightveil Aug 18, 2026
9a1f22b
fix warnings
midnightveil Aug 18, 2026
396232e
add safety comment
midnightveil Aug 18, 2026
bae0a5e
test walker
midnightveil Aug 18, 2026
2a0a57b
almost working clean
midnightveil Aug 20, 2026
0018db9
truly works impl
midnightveil Aug 20, 2026
0799991
cleanup
midnightveil Aug 20, 2026
871db3a
reomve prints
midnightveil Aug 20, 2026
cc6be77
more helper fns
midnightveil Aug 20, 2026
a0bbb47
attempt (badly) to make risv64 also work
midnightveil Aug 20, 2026
856d8db
pass mmu loader information in the tool
midnightveil Aug 25, 2026
e6e4b03
print is_ram instead of raw has not been initialised in union
midnightveil Aug 25, 2026
75d91f0
fix linker script I broke
midnightveil Aug 25, 2026
5ca9762
fix riscv64 boot
midnightveil Aug 25, 2026
861669c
fix bug in merge_regions impl
midnightveil Aug 25, 2026
e7dbbf2
try enabling the mmu before copying regions, works for maaxboard. how…
midnightveil Aug 25, 2026
2e1dbd0
use MT_NORMAL in page tables : now a 100MiB image is instant. probabl…
midnightveil Aug 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,17 @@ jobs:
- name: Run Clippy
# Make sure CI fails on all warnings, including Clippy lints
run: nix develop --ignore-environment -c bash -c "cd tool/microkit && cargo-clippy --all-targets --all-features -- -D warnings -Wclippy::get_unwrap"
- name: Run Clippy (loader)
run: nix develop --ignore-environment -c bash -c 'make -C loader clippy CLIPPY_FLAGS="-D warnings -Wclippy::get_unwrap" BUILD_DIR=$(mktemp -d) RUST_ONLY=True'

rustfmt_check:
runs-on: [self-hosted, macos, ARM64]
steps:
- uses: actions/checkout@v4
- name: Run rustfmt
run: nix develop --ignore-environment -c bash -c "cd tool/microkit && cargo-fmt --check"
- name: Run rustfmt (loader)
run: nix develop --ignore-environment -c bash -c 'make -C loader rustfmt-check BUILD_DIR=$(mktemp -d) RUST_ONLY=True'

code:
name: Freeze Code
Expand Down
22 changes: 22 additions & 0 deletions build_sdk.py
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,26 @@ def build_sel4(
json_dst.chmod(0o744)


def test_loader(build_dir: Path) -> None:
build_dir = build_dir / "loader"
build_dir.mkdir(exist_ok=True, parents=True)

make_args = f"BUILD_DIR={build_dir.absolute()} RUST_ONLY=True"

r = system(
f"make -C loader tests {make_args}"
)
if r != 0:
raise Exception(f"Tests failed: loader")

# We don't pass CLIPPYARGS, so this is warning-only
r = system(
f"make -C loader clippy {make_args}"
)
if r != 0:
raise Exception(f"Clippy failed: loader")


def build_elf_component(
component_name: str,
sdk_dir: Path,
Expand Down Expand Up @@ -1094,6 +1114,8 @@ def main() -> None:

if not args.skip_run_time:
build_dir = Path("build")
test_loader(build_dir)

for (board, configs) in build_goals:
for config in configs:
if not args.skip_sel4:
Expand Down
2 changes: 1 addition & 1 deletion example/hello/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ ifeq ($(ARCH),aarch64)
TARGET_TRIPLE := aarch64-none-elf
CFLAGS_ARCH := -mstrict-align
else ifeq ($(ARCH),riscv64)
TARGET_TRIPLE := riscv64-unknown-elf
TARGET_TRIPLE := riscv64-none-elf
CFLAGS_ARCH := -march=rv64imafdc_zicsr_zifencei -mabi=lp64d
else ifeq ($(ARCH),x86_64)
TARGET_TRIPLE := x86_64-linux-gnu
Expand Down
2 changes: 2 additions & 0 deletions example/hello/hello.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include <stdint.h>
#include <microkit.h>

char xxxxxxxxxxx[100000000] = { 1 };

void init(void)
{
microkit_dbg_puts("hello, world\n");
Expand Down
79 changes: 74 additions & 5 deletions loader/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@
#
# SPDX-License-Identifier: BSD-2-Clause
#

ifneq ($(strip $(RUST_ONLY)),)
ARCH := dummy
BOARD := dummy
LINK_ADDRESS := dummy
TARGET_TRIPLE := dummy
SEL4_SDK := dummy
endif

ifeq ($(strip $(BUILD_DIR)),)
$(error BUILD_DIR must be specified)
endif
Expand Down Expand Up @@ -35,34 +44,46 @@ else
LD = $(TARGET_TRIPLE)-ld
endif

RUSTC := rustc
CLIPPY := clippy-driver
RUSTFMT := rustfmt

ifeq ($(ARCH),aarch64)
CFLAGS_AARCH64 := -mcpu=$(GCC_CPU) -mgeneral-regs-only -mstrict-align -mno-outline-atomics
CFLAGS_ARCH := $(CFLAGS_AARCH64) -DARCH_aarch64
ASM_FLAGS_ARCH := -mcpu=$(GCC_CPU)
ARCH_DIR := aarch64
RUST_TARGET_TRIPLE := aarch64-unknown-none
else ifeq ($(ARCH),riscv64)
CFLAGS_RISCV64 := -mcmodel=medany -march=rv64imac_zicsr_zifencei -mabi=lp64
CFLAGS_RISCV64 := -mcmodel=medany -march=rv64gc -mabi=lp64d
CFLAGS_ARCH := $(CFLAGS_RISCV64) -DARCH_riscv64
ASM_FLAGS_ARCH := -march=rv64imac_zicsr_zifencei -mabi=lp64
ASM_FLAGS_ARCH := -march=rv64gc -mabi=lp64d
RUST_TARGET_TRIPLE := riscv64gc-unknown-none-elf
ARCH_DIR := riscv
endif

CFLAGS := -std=gnu11 -g -O3 -nostdlib -ffreestanding \
-MP -MD $(CFLAGS_ARCH) -DBOARD_$(BOARD) -I$(SEL4_SDK)/include \
-Wall -Werror -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations \
-Wundef -Wno-nonnull -Wnested-externs
-Wundef -Wno-nonnull -Wnested-externs -ffunction-sections -fdata-sections

ASM_FLAGS := $(ASM_FLAGS_ARCH) -g -MP -MD -I$(SEL4_SDK)/include

RUST_EDITION := 2024
RUSTFLAGS := --edition $(RUST_EDITION) -g -C opt-level=2
CLIPPY_FLAGS ?=

PROGS := loader.elf
OBJECTS := loader.o crt0.o uart.o cutil.o
OBJECTS := loader.o crt0.o uart.o cutil.o libpage_tables.a

ifeq ($(ARCH),aarch64)
OBJECTS += util64.o el.o exceptions.o init.o mmu.o cpus.o
else ifeq ($(ARCH),riscv64)
OBJECTS += exceptions.o init.o mmu.o cpus.o sbi.o
endif

RUST_CRATES := page_tables

LINKSCRIPT_INPUT := $(ARCH).ld
LINKSCRIPT := $(BUILD_DIR)/link.ld

Expand All @@ -80,6 +101,18 @@ $(BUILD_DIR)/%.o : src/$(ARCH_DIR)/%.c
$(BUILD_DIR)/%.o : src/%.c
$(CC) -c $(CFLAGS) $< -o $@

# Note: having multiple libs with staticlib will give duplicate linker symbol
# issues. Use "--crate-type rlib" instead, but then we need to link a single
# copy of the rust corelibs. For now this is fine.
$(BUILD_DIR)/lib%.a : src/%.rs
$(RUSTC) $(RUSTFLAGS) \
--emit dep-info,metadata,link \
--out-dir $(BUILD_DIR) -L dependency=$(BUILD_DIR) \
--target $(RUST_TARGET_TRIPLE) \
--crate-type staticlib \
--crate-name $(patsubst lib%.a,%,$(notdir $@)) \
$<

-include $(BUILD_DIR)/*.d

OBJPROG = $(addprefix $(BUILD_DIR)/, $(PROGS))
Expand All @@ -89,5 +122,41 @@ all: $(OBJPROG)
$(LINKSCRIPT): $(LINKSCRIPT_INPUT)
$(CPP) -DLINK_ADDRESS=$(LINK_ADDRESS) $< | grep -v "^#" > $@

LDFLAGS := -T$(LINKSCRIPT)

$(OBJPROG): $(addprefix $(BUILD_DIR)/, $(OBJECTS)) $(LINKSCRIPT)
$(LD) -T$(LINKSCRIPT) $(addprefix $(BUILD_DIR)/, $(OBJECTS)) -o $@
$(LD) $(LDFLAGS) --start-group $(addprefix $(BUILD_DIR)/, $(OBJECTS)) --end-group -o $@

rusttest_%: src/%.rs
$(RUSTC) $(RUSTFLAGS) \
--emit dep-info,metadata,link \
--out-dir $(BUILD_DIR) -L dependency=$(BUILD_DIR) \
-Awarnings \
--test \
--crate-name "$@" \
$<

tests: $(addprefix rusttest_, $(RUST_CRATES))
$(BUILD_DIR)/rusttest_page_tables

rustclippy_%: src/%.rs
$(CLIPPY) $(RUSTFLAGS) \
--emit dep-info,metadata,link \
--out-dir $(BUILD_DIR) -L dependency=$(BUILD_DIR) \
$(CLIPPYFLAGS) \
-Cpanic=abort \
--crate-type staticlib \
--crate-name "$@" \
$<

clippy: $(addprefix rustclippy_, $(RUST_CRATES))

rustfmt_%: src/%.rs
$(RUSTFMT) $(RUSTFMT_FLAGS) \
--edition $(RUST_EDITION) \
$<

rustfmt: $(addprefix rustfmt_, $(RUST_CRATES))

rustfmt-check: RUSTFMT_FLAGS += --check
rustfmt-check: rustfmt
25 changes: 21 additions & 4 deletions loader/aarch64.ld
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ PHDRS
all PT_LOAD AT (LINK_ADDRESS);
}


// text PT_LOAD FLAGS(5); /* RX */
// rodata PT_LOAD FLAGS(4); /* RO */
// data PT_LOAD FLAGS(6); /* RW */
// bss PT_LOAD FLAGS(6); /* RW */

SECTIONS
{
. = LINK_ADDRESS;
Expand All @@ -17,23 +23,34 @@ SECTIONS
.text :
{
_text = .;
*(.text.start)
*(.text*)
*(.rodata)

KEEP(*(.text.start))
*(.text .text.*)

_text_end = .;
} :all

.rodata :
{
*(.rodata .rodata.* .rodata..Lanon.*)
} :all

.data :
{
_data = .;
*(.data)
*(.data .data.*)
*(.data.*)

KEEP(*(.data.uart_addr))

_data_end = .;
} :all

.bss :
{
_bss = .;
*(.bss)
*(.bss.*)
*(COMMON)
. = ALIGN(4);
_bss_end = .;
Expand Down
28 changes: 19 additions & 9 deletions loader/riscv64.ld
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,37 @@ SECTIONS
.text :
{
_text = .;
*(.text.start)
*(.text*)
*(.rodata)

KEEP(*(.text.start))
*(.text .text.*)

_text_end = .;
} :all

.rodata :
{
*(.rodata .rodata.* .rodata..Lanon.*)
} :all

.data :
{
_data = .;
*(.data)
*(.data .data.*)
*(.data.*)
__global_pointer$ = . + 0x800;
*(.srodata)
*(.sdata)
_data_end = .;
*(.srodata .srodata.*)
*(.sdata .sdata.*)

KEEP(*(.data.uart_addr))

_data_end = .;
} :all

.bss :
{
_bss = .;
*(.sbss)
*(.bss)
*(.sbss .sbss.*)
*(.bss .bss.*)
*(COMMON)
. = ALIGN(4);
_bss_end = .;
Expand Down
9 changes: 9 additions & 0 deletions loader/src/aarch64/cpus.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <stdint.h>

#include "smc.h"
#include "../arch.h"
#include "../cpus.h"
#include "../cutil.h"
#include "../loader.h"
Expand Down Expand Up @@ -101,6 +102,14 @@ void arm_secondary_cpu_entry(int logical_cpu, uint64_t mpidr_el1)
puthex64(mpidr_el1);
puts("\n");

int r = arch_mmu_enable(logical_cpu);
if (r != 0) {
LDR_PRINT("ERROR", logical_cpu, "failed to enable MMU: ");
puthex32(r);
puts("\n");
for (;;) {}
}

if (logical_cpu == 0) {
LDR_PRINT("ERROR", logical_cpu, "secondary CPU should not have logical id 0!!!\n");
goto fail;
Expand Down
30 changes: 0 additions & 30 deletions loader/src/aarch64/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,36 +80,6 @@ void arch_init(void)
configure_gicv2();
#endif

/* Drop to correct EL before disabling MMU */
int r = ensure_correct_el(0);
if (r != 0) {
puts("LDR|ERROR: failed to ensure correct EL\n");
fail();
}

/* Disable the MMU, as U-Boot will start in virtual memory on some platforms
* (https://docs.u-boot.org/en/latest/arch/arm64.html), which means that
* certain physical memory addresses contain page table information which
* the loader doesn't know about and would need to be careful not to
* overwrite.
*
* This also means that we would need to worry about caching.
* TODO: should we do that instead?
* note the issues where it forces us to flush any shared addresses all the
* way to cache as we might have mixed non-cached/cached access.
*/
puts("LDR|INFO: disabling MMU (if it was enabled)\n");
enum el el = current_el();

if (el == EL1) {
el1_mmu_disable();
} else if (el == EL2) {
el2_mmu_disable();
} else {
puts("LDR|ERROR: unknown EL level for MMU disable\n");
fail();
}

#if !defined(ARM_PSCI_UNAVAILABLE)
uint32_t ret = arm_smc32_call(PSCI_FUNCTION_VERSION, /* unused */ 0, 0, 0);
/* the return value has no error codes, but if we get it wrong this is what we will get */
Expand Down
Loading
Loading