aboutsummaryrefslogtreecommitdiffstats
path: root/README.md
diff options
context:
space:
mode:
authoruser <user@clank>2026-07-15 23:54:13 +0200
committeruser <user@clank>2026-07-15 23:54:13 +0200
commitab3ebbe227c72b745a46f9233fbfbb27477586b8 (patch)
treed71f87605d17c5653f34ebcdef3941f898cd5b91 /README.md
parentgbos scaffold: working cooperative microkernel (verified ABAB in emulator) (diff)
downloadgbos-ab3ebbe227c72b745a46f9233fbfbb27477586b8.tar.gz
gbos-ab3ebbe227c72b745a46f9233fbfbb27477586b8.tar.xz
gbos-ab3ebbe227c72b745a46f9233fbfbb27477586b8.zip
kernel: implement fork()
- sys_fork: switch to a kernel stack, bump-allocate a cart-RAM bank, copy the parent's 8 KiB bank via a WRAM bounce buffer, plant a switch-in frame so the child returns 0 to the post-fork PC, fill the child PCB (shared ROM text) - add AllocRamBank (bump allocator) + FindFreeSlot helpers - demo: init forks; parent prints P, child prints C (PCPC...); nested fork gives three distinct pids (123...) - README: document the fork mechanism, mark syscall status
Diffstat (limited to '')
-rw-r--r--README.md24
1 files changed, 22 insertions, 2 deletions
diff --git a/README.md b/README.md
index bd6c5cf..2d2946c 100644
--- a/README.md
+++ b/README.md
@@ -46,10 +46,30 @@ User loads `C` = syscall number, args in `DE`/`B`, then `rst $30`. Return in `A`
| # | name | status |
|---|---------|--------|
| 0 | exit | ✅ marks zombie, reschedules |
+| 1 | fork | ✅ copies the 8 KiB bank, child returns 0 |
| 3 | write | ✅ `DE`=buf `B`=len → serial console |
| 8 | getpid | ✅ |
| 11| yield | ✅ cooperative switch |
-| 1,2,4,5,6,7,9,10 | fork/read/open/close/exec/wait/kill/brk | ⛔ `ENOSYS` |
+| 2,4,5,6,7,9,10 | read/open/close/exec/wait/kill/brk | ⛔ `ENOSYS` |
+
+### fork (`sys_fork`, src/proc.asm)
+
+The interesting syscall. It enters on the parent's user stack (which lives in
+the `$A000-$BFFF` cart-RAM window), so before it can swap that window it
+**switches to a kernel stack in WRAM0**. Then it:
+
+1. allocates a free PCB slot + a fresh cart-RAM bank (bump allocator),
+2. copies the parent's whole 8 KiB bank → the child bank, 256 bytes at a time
+ through a WRAM bounce buffer (only one cart-RAM bank is visible at once),
+3. plants a **switch-in frame** in the child at `Uafter-8` (`Uafter` = parent
+ SP at entry): the copied return address is already there, so it just zeroes
+ the saved `hl/de/bc/af` slots — the child resumes at the post-`fork` PC with
+ `A=0`,
+4. fills the child PCB (shared ROM text bank, new RAM bank, parent as PPID),
+5. restores the parent stack and returns the child pid.
+
+Verified: `init` forks a child (P/C alternate on serial); nested forks yield
+three independent processes with distinct pids (`123123...`).
## The context switch (`src/hram.asm`)
@@ -91,7 +111,7 @@ A real gbos would render to VRAM; serial is the zero-VRAM debug channel.
## Roadmap
-- [ ] `fork`: copy parent's 8 KiB RAM bank → free bank, dup u-area, child returns 0
+- [x] `fork`: copy parent's 8 KiB RAM bank → free bank, child returns 0
- [ ] `exec`: point `PROC_ROMB` at a flashed program, reset RAM-bank layout
- [ ] Preemptive scheduling: real context save in `TimerISR` → `hSwitchTo`
- [ ] Use the `$D000-$DFFF` u-area (SVBK) for per-process kernel state / kstack