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:
| M | docs/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.