aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoruser <user@clank>2026-07-16 00:37:09 +0200
committeruser <user@clank>2026-07-16 00:37:09 +0200
commit2538b138946128cc5ff473e14ba9bde564aef2e9 (patch)
tree26b9680b11c2c22b05154ed5166923d0e3fa8d97
parentwip: sys_read + serial console shell (read-store bug under investigation) (diff)
downloadgbos-2538b138946128cc5ff473e14ba9bde564aef2e9.tar.gz
gbos-2538b138946128cc5ff473e14ba9bde564aef2e9.tar.xz
gbos-2538b138946128cc5ff473e14ba9bde564aef2e9.zip
shell working: fix syscall ABI (trap clobbers HL) + document
- root cause of the read/echo corruption: SyscallTrap uses HL to index the dispatch table, so HL is clobbered across a syscall; the shell then wrote its buffer pointer's garbage into the $0000-$7FFF MBC register region, corrupting the mapper. fix: userland saves HL around sys_read (push/pop). - shell now runs commands end to end: $ hello -> hello world!, $ worker -> worker!, $ foo -> ? - README: document that syscalls clobber BC/DE/HL (return in A, B for wait); add read + shell to the syscall table.
Diffstat (limited to '')
-rw-r--r--README.md24
-rw-r--r--src/programs.asm6
2 files changed, 27 insertions, 3 deletions
diff --git a/README.md b/README.md
index 929cafe..a0b8338 100644
--- a/README.md
+++ b/README.md
@@ -41,7 +41,10 @@ $FFEF-$FFF2 HRAM bank shadows + switch target
## Syscall ABI
-User loads `C` = syscall number, args in `DE`/`B`, then `rst $30`. Return in `A`.
+User loads `C` = syscall number, args in `DE`/`B`/`HL`, then `rst $30`.
+Return in `A` (and `B` for `wait`). **The trap clobbers `BC`/`DE`/`HL`** (it uses
+`HL` to index the dispatch table), so userland must save any pointer it needs
+across a syscall (`push hl` / `pop hl`). Libc syscall stubs handle this for C.
| # | name | status |
|---|---------|--------|
@@ -52,7 +55,24 @@ User loads `C` = syscall number, args in `DE`/`B`, then `rst $30`. Return in `A`
| 7 | wait | ✅ blocks; reaps a zombie child → `A`=pid `B`=code |
| 8 | getpid | ✅ |
| 11| yield | ✅ cooperative switch |
-| 2,4,5,9,10 | read/open/close/kill/brk | ⛔ `ENOSYS` |
+| 2 | read | ✅ blocking console input (1 byte) via external-clock serial |
+| 4,5,9,10 | open/close/kill/brk | ⛔ `ENOSYS` |
+
+### The shell (PROG_SH)
+
+init `exec`s a tiny shell: **prompt → read a line (with echo) → match a command
+→ `fork`+`exec`+`wait`**. Commands live in a table (`worker`, `hello`). Runs
+entirely over the headless serial console:
+
+```
+$ hello
+hello world!
+$ worker
+worker!
+$ foo
+?
+$
+```
### Process lifecycle (exit / wait / reaping)
diff --git a/src/programs.asm b/src/programs.asm
index df2b98d..d4ae89f 100644
--- a/src/programs.asm
+++ b/src/programs.asm
@@ -59,8 +59,10 @@ ProgSh:
; read a line into SH_LINEBUF, echoing as we go
ld hl, SH_LINEBUF
.rd
+ push hl ; syscalls clobber HL (trap uses it to dispatch)
ld c, SYS_READ
rst $30 ; A = input byte
+ pop hl
cp $0D
jr z, .eol
cp $0A
@@ -70,7 +72,9 @@ ProgSh:
ld [$FF01], a ; echo the char straight to serial
ld a, $81
ld [$FF02], a
- jr .rd
+ ld a, l
+ cp LOW(SH_LINEBUF) + SH_MAXLINE - 1
+ jr c, .rd ; keep reading unless the buffer is full
.eol
ld [hl], 0 ; NUL-terminate