boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs | README

commit 6ec738c133517a886e87ecdbc76c0322a8c60d7f
parent 52fb5121119dd0b223fa0ab022ba05ee2ee5d275
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Tue,  5 May 2026 17:44:08 -0700

docs/OS-TODO: trim landed tcc3-self-host items

The seven assembler blockers and three codegen blockers all landed
in 52fb512; describing them again here is just commit-message
duplication. Keep the file to what's actually open: the
`-T kernel.lds` gap (tcc-built kernel still uses gcc's ld for the
final link), the toplevel-asm `.globl` ordering quirk worked
around in user/*.c, and two unrelated polish items.

Diffstat:
Mdocs/OS-TODO.md | 172++++++++++---------------------------------------------------------------------
1 file changed, 20 insertions(+), 152 deletions(-)

diff --git a/docs/OS-TODO.md b/docs/OS-TODO.md @@ -11,172 +11,40 @@ ELF, dispatches the eight Tier-1 syscalls plus atomic `sys_spawn` acceptance; `boot{0..5}.sh DRIVER=seed` is byte-identical to the podman path. HVF acceleration enabled. -This file tracks remaining polish. - -## tcc3 self-host of `seed-kernel/` - -The C side compiles cleanly under -[`build/aarch64/boot4/tcc3`](../scripts/boot4.sh) — `kernel.c` and -`user/{forktest,child,hello}.c` have no inline asm, all sysreg / barrier -/ cache / TLB / PSCI ops route through the C-callable thunks at the -bottom of [`kernel.S`](../seed-kernel/kernel.S), and per-syscall -wrappers delegate to a single `syscall6` toplevel-asm thunk. -[`kernel.S`](../seed-kernel/kernel.S) was refactored to drop the -features the doc previously listed as "tcc-side fixable": - -- All `adrp/add :lo12:` and `adr` label loads rewritten to `ldr Xn, - =sym`, which already lowers to the same MOVW_UABS_G{0..3} chain - `arm64-gen.c` uses for compiler-emitted symbol loads. No tcc work - needed for label addressing. -- The 16 `.macro VENTRY` invocations unrolled. -- `.macro SAVE_TF / RESTORE_TF` unrolled at all three trap entries. - -### `kernel.S` blockers — assembler — DONE - -`tcc3 -c kernel.S` now succeeds. The seven items below all landed -together (assembler + linker patches in `scripts/simple-patches/ -tcc-0.9.26/`, dispatched out of `arm64-asm.c` / `arm64-link.c` / -`tccasm.c`): - -1. **`.quad sym1 - sym2`.** `.quad` is now routed through - `asm_data` (the same path `.long` uses) for both X86_64 and - ARM64. `arm64-asm.c` defines `gen_expr64` / `gen_expr32` that - emit `R_AARCH64_PREL64` / `R_AARCH64_PREL32` for symbol - differences (the asm-expr-sum pcrel branch leaves the addend - biased by +4 in the x86 PC32 convention; the emitters - compensate so it matches gas's reloc). -2. **Named MSR / MRS sysregs + MSR-immediate.** `arm64-tok.h` - declares `mrs`/`msr` plus `daifset`/`daifclr`. `arm64-asm.c` - carries a small `sysregs[]` table covering the kernel's set - (`mair_el1`, `tcr_el1`, `ttbr0_el1`, `sctlr_el1`, `cpacr_el1`, - `sp_el0`, `sp_el1`, `esr_el1`, `far_el1`, `vbar_el1`, - `elr_el1`, `spsr_el1`, `hcr_el2`, `spsr_el2`, `elr_el2`, - `currentel`); name lookup is case-insensitive so `CurrentEL` - matches. -3. **`eret`** maps to a fixed `0xd69f03e0` emit. -4. **`ic`/`tlbi` SYS-instruction aliases.** A generic - `emit_sys_alias` helper plus per-mnemonic name tables - (`ic_aliases[]`, `tlbi_aliases[]`) covers `ic iallu`/ - `ic ialluis`/`ic ivau` and `tlbi vmalle1`/`vmalle1is`/ - `alle1`/`alle1is`. -5. **Named `dsb`/`dmb` scope tokens.** `arm64-tok.h` declares - `sy`/`ish`/`ishst`/`ishld`/`nsh`/`nshst`/`nshld`/ - `osh`/`oshst`/`oshld`; `do_barrier` accepts either the named - form or the prior `#imm` numeric form. -6. **Forward `b.cond` to in-section labels.** `arm64-link.c` - gained `R_AARCH64_CONDBR19` (and `R_AARCH64_TSTBR14` for tbz); - the new `sec_branch_offset_or_reloc` falls back to a reloc - when the target sym is forward / extern, and the linker - resolves it. -7. **Forward `cbz`/`cbnz`** ride the same CONDBR19 reloc path. - -Verification: `tcc -c seed-kernel/kernel.S` produces an .o that -links cleanly against a gcc-compiled `kernel.c` and `seed-kernel/ -kernel.lds`; the resulting `Image` differs from the gas baseline -only by `.balign` fill (zero vs `nop`) and a couple of byte-shift -choices that the linker resolves to identical run-time semantics -(vector-table padding is never executed; `ldr Xn, =sym` lowers to -a 4-instruction MOVW chain instead of a literal pool, giving a -slightly larger but identical-function `.head.text`). - -The `.macro`/`.endm` and `adrp`/`:lo12:` items from earlier -drafts are gone: the first by unrolling, the second by switching -to `ldr Xn, =sym`. Both are pure-`kernel.S` choices that made the -assembler's job substantially smaller. +A kernel built end-to-end with the patched +[`build/aarch64/boot4/tcc3`](../scripts/boot4.sh) (`tcc3 -c +kernel.{S,c}` + `tcc3 -c tcc-cc/mem.c` → `ld -T kernel.lds`) boots +under qemu-system-aarch64 and produces console output identical to +the gcc-built kernel through `[seed] user exit_group(0)`. -### `kernel.S` blockers — runtime / codegen — DONE - -8. **`mem*` symbols.** `kernel.c` no longer defines `memset` / - `memcpy` inline; they (plus `memmove`, which tcc emits for some - struct copies and gcc inlines) come from `tcc-cc/mem.c`, which - the seed-kernel `Makefile` and the tcc-build script both - compile + link alongside `kasm.o` / `kernel.o`. Same bytes - under both compilers. - -### `kernel.c` codegen blockers — DONE - -9. **`-mgeneral-regs-only` has no tcc equivalent.** tcc saves - the callee-saved SIMD registers (`q0..q7`) in every C - function prologue; with default `CPACR_EL1.FPEN = 00` those - stp/ldp instructions trap to EL1 with EC=0x07. The fix is - in `kernel.S`: enable FP/SIMD (`CPACR_EL1.FPEN = 0b11`) - immediately after `vbar_el1` is set, before the first - `bl kmain`. gcc-built kernels are unaffected because gcc - honours `-mgeneral-regs-only` and never emits SIMD. - -10. **`(volatile T *)CONST` truncation.** Stock `arm64-gen.c` - in tcc 0.9.26 starts both `load()` and `store()` with - `uint64_t svcul = (uint32_t)sv->c.i;` followed by a - sign-extend, dropping the top 32 bits of any pointer-sized - constant address. Fine for struct-field offsets, fatal for - the seed-kernel writing through `(volatile u32 *) - 0x109000018` (the device alias for the PL011 UART under our - `setup_mmu` layout). Patches `arm64-svcul-no-truncate{,-store}` - in `scripts/simple-patches/tcc-0.9.26/` keep the full 64-bit - constant; signed 9-bit ldur/stur offsets fit regardless so - the prior sign-extend was a no-op for legitimate offsets. +This file tracks remaining polish. -End-to-end: a kernel built entirely with the patched tcc3 -(`tcc3 -c kernel.{S,c}` + `tcc3 -c tcc-cc/mem.c` → `ld -T -kernel.lds`) boots under qemu-system-aarch64 and produces -identical console output to the gcc-built kernel through -`[seed] user exit_group(0)`. +## tcc3 link with `kernel.lds` -### `kernel.lds` blockers — linker +`tcc -Wl,-T,kernel.lds` errors with `unsupported linker option`; +tcc3's `-Wl,` accepts only `-Ttext=` / `-image-base=` / +`-section-alignment=`. The seed kernel's layout needs: -9. **No `-T script` in tcc3.** `tcc -Wl,-T,kernel.lds` errors out: - `unsupported linker option`. Tcc3's `-Wl,` accepts `-Ttext=`, - `-image-base=`, `-section-alignment=` only. The seed kernel's - layout needs: - - `KEEP(*(.head.text))` first (boot header at `0x40080000`). - - Link-time symbol assignments: `__bss_start`, `__bss_end`, - `kstack_top`, `_end`, `_image_end`. - - A custom `.stack` section sized to 64 KB. +- `KEEP(*(.head.text))` first (boot header at `0x40080000`). +- Link-time symbol assignments: `__bss_start`, `__bss_end`, + `kstack_top`, `_end`, `_image_end`. +- A custom `.stack` section sized to 64 KB. -10. **Linker-script symbols undefined** (`kstack_top`, - `__bss_start`, `__bss_end`). Confirmed by the link error above - when the script is dropped — the Image-header `image_size` - expression and the entry stub's BSS-zeroing loop both reference - these. +Two paths: -Two paths for the layout problem (#9 + #10): - **Inline.** Define the symbols and reserve a 64 KB stack inside `kernel.S` using `.skip` / `.balign`. Brackets the kernel's `.bss` by putting `__bss_start:` in a `.bss.0_start` section and `__bss_end:` in `.bss.9_end` — but tcc/ld won't merge these into the main `.bss` without a script, so each becomes its own output - section. Workable if BSS is replaced with explicit storage in - `kernel.S`; brittle if we keep relying on the C compiler's `.bss` - emission. + section. Workable only if BSS is replaced with explicit storage in + `kernel.S`; brittle otherwise. - **Tcc gains a small ld-script subset.** `KEEP(*(...))`, simple symbol assignment (`sym = .;`), and a single explicit-storage section block. ~150 LoC, reusable across kernel-style targets, doesn't restructure `kernel.S` further. -The post-refactor balance probably tips toward the script subset — -the inline-bracket trick for BSS is the wart the previous draft of -this doc called out as "brittle," and the cost gap to a small ld -implementation has narrowed now that everything else is solved. - -### Toplevel `asm()` `.globl` ordering — worked around - -tcc 0.9.26's toplevel-asm parser leaves a symbol marked `UND` if -`.globl name` precedes `name:`; the reverse order registers it as -defined (gcc accepts both). Worked around in `user/{forktest, -child,hello}.c` with `label:` first and `.globl label` immediately -after, with a sourcecode comment noting the constraint. A tcc-side -fix would let the comments go. - -## Open polish - -- **NULL-page hardening.** Slot 0 is unmapped so a NULL deref faults - to the kernel as a user sync; the kernel currently panics rather - than delivering a SIGSEGV-equivalent. Acceptable per OS.md - (default-action termination is sufficient) but a minor polish - opportunity. +The post-refactor balance tips toward the script subset. -- **Cache parsed prelude in kernel.** Each spawn re-parses the - 24 KB `prelude.scm` from scratch. Hashing it once and reusing the - AST across spawns would shave a fraction of per-spawn overhead. - Not load-bearing now that sys_spawn removed the big copy; would - matter again if a future driver crosses ~10k spawns. +Until either lands, the tcc-built seed kernel still uses gcc's +`ld -T kernel.lds` for the final link step.