1.9 KiB
1.9 KiB
Phase 11 - Tiny Kernel + Command Shell
Context
This phase builds an OS-shaped firmware payload before the project moves into traps, interrupts, privilege, DRAM, and Linux.
Goals
- Load a separate GCC-built kernel ELF from the BIOS.
- Provide a kernel-owned command shell.
- Run tiny trusted ELF programs through a simple service table.
New Concepts
- Kernel: central program that owns machine services. Before traps, this is still trusted bare-machine firmware, not an isolated privileged OS.
- Service table: function-pointer ABI for console I/O, exit, and simple utilities.
- Bump allocator: simple allocator that hands out memory linearly.
- Program table: small kernel data structure tracking loaded payloads.
How To Think About It
The goal is a complete loop, not a Unix clone: compile a tiny program on the host, send it over UART, load it as ELF, run it on the CPU, and return to the shell.
Learning Tasks
- Decide whether kernel console I/O calls the BIOS or drives UART directly.
- Define the tiny-program ABI: entry registers, stack, service table, and return path.
- Implement the smallest useful allocator.
- Add shell commands that expose real machine state, not decorative output.
Pitfalls
- Pretending trusted payloads are isolated before traps and privilege modes exist.
- Growing the kernel into a second large project too early.
- Hiding loader or ABI bugs behind ad hoc special cases.
Tooling And Testing
- Keep kernel and user-payload linker scripts separate.
- Build a tiny test suite of loaded programs: hello, echo, memory copy, return status.
- Run the same payloads after Phase 12 trap handling lands to catch ABI regressions.
References
- OSDev kernel structure notes: https://wiki.osdev.org/Kernel
- RISC-V calling convention: https://github.com/riscv-non-isa/riscv-elf-psabi-doc
- Embedded Artistry first-fit allocator background: https://embeddedartistry.com/blog/2017/02/15/implementing-malloc-first-fit-free-list/