diff options
| author | user <user@clank> | 2026-07-15 23:44:28 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-07-15 23:44:28 +0200 |
| commit | de725da74db5cba0f9bfd0755269e1683423d87b (patch) | |
| tree | dc39eca9fbd290393ed51de31eee5e4bd6af8375 /src/syscall.asm | |
| download | gbos-de725da74db5cba0f9bfd0755269e1683423d87b.tar.gz gbos-de725da74db5cba0f9bfd0755269e1683423d87b.tar.xz gbos-de725da74db5cba0f9bfd0755269e1683423d87b.zip | |
gbos scaffold: working cooperative microkernel (verified ABAB in emulator)
- fix ClearKernelRAM clobbering the kernel stack (only clear $C000-$CBFF)
- fix SyscallTrap clobbering DE (buffer arg) during table dispatch
- README: run via ~/dev/gbc --headless; note bring-up bugs
Diffstat (limited to '')
| -rw-r--r-- | src/syscall.asm | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/src/syscall.asm b/src/syscall.asm new file mode 100644 index 0000000..71e1f2b --- /dev/null +++ b/src/syscall.asm @@ -0,0 +1,117 @@ +; ============================================================================= +; syscall.asm - the trap entry, dispatch table, and handlers. +; +; ABI: user loads C = syscall number, args in DE/B/HL, then `rst $30`. +; return value in A. ($30 vector jp's here - see boot.asm) +; ============================================================================= +INCLUDE "include/gbos.inc" + +SECTION "syscall", ROM0 + +; ----------------------------------------------------------------------------- +SyscallTrap:: + ld a, c + cp SYS_MAX + jr nc, .bad + ; index the table WITHOUT touching DE/B (those are syscall args). + ld hl, SyscallTable + ld a, c + add a ; A = C*2 (word entries; C < SYS_MAX) + add l + ld l, a + jr nc, .nocarry + inc h +.nocarry + ld a, [hl+] + ld h, [hl] + ld l, a + jp hl ; tail-call; handler's `ret` returns to user +.bad + ld a, $FF ; ENOSYS-ish + ret + +; ----------------------------------------------------------------------------- +; Dispatch table (indexed by syscall number) +; ----------------------------------------------------------------------------- +SyscallTable: + dw sys_exit ; 0 + dw sys_nosys ; 1 FORK (TODO) + dw sys_nosys ; 2 READ (TODO) + dw sys_write ; 3 WRITE + dw sys_nosys ; 4 OPEN (TODO) + dw sys_nosys ; 5 CLOSE (TODO) + dw sys_nosys ; 6 EXEC (TODO) + dw sys_nosys ; 7 WAIT (TODO) + dw sys_getpid ; 8 GETPID + dw sys_nosys ; 9 KILL (TODO) + dw sys_nosys ; 10 BRK (TODO) + dw sys_yield ; 11 YIELD + +; ----------------------------------------------------------------------------- +sys_nosys: + ld a, $FF + ret + +; ----------------------------------------------------------------------------- +; sys_write(fd=B, buf=DE, len=B?) -- scaffold: fd ignored, DE=buf, B=len. +; Writes to the serial console. Returns A = bytes written. +; ----------------------------------------------------------------------------- +sys_write: + ld a, b + or a + ret z ; len 0 + ld c, b ; C = remaining +.loop + ld a, [de] + call PutChar + inc de + dec c + jr nz, .loop + ld a, b ; return len + ret + +; ----------------------------------------------------------------------------- +; sys_getpid() -> A = current pid +; ----------------------------------------------------------------------------- +sys_getpid: + ld a, [wCurProc] + add PROC_PID + ld l, a + ld a, [wCurProc+1] + adc 0 + ld h, a + ld a, [hl] + ret + +; ----------------------------------------------------------------------------- +; sys_yield() +; ----------------------------------------------------------------------------- +sys_yield: + call SchedYield + ret + +; ----------------------------------------------------------------------------- +; sys_exit(code=B) -- mark zombie and schedule away forever. +; ----------------------------------------------------------------------------- +sys_exit: + ; mark current PCB as zombie, store exit code + ld a, [wCurProc] + ld l, a + ld a, [wCurProc+1] + ld h, a ; HL = &PCB + ld a, PS_ZOMBIE + ld [hl], a ; PROC_STATE + ; PROC_EXIT is at offset PROC_EXIT + ld a, [wCurProc] + add PROC_EXIT + ld l, a + ld a, [wCurProc+1] + adc 0 + ld h, a + ld a, b + ld [hl], a ; exit code + ; never return to this task + call SchedYield + ; if we somehow come back (no other ready task), spin +.halt + jr .halt |
