From de725da74db5cba0f9bfd0755269e1683423d87b Mon Sep 17 00:00:00 2001 From: user Date: Wed, 15 Jul 2026 23:44:28 +0200 Subject: 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 --- src/syscall.asm | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 src/syscall.asm (limited to 'src/syscall.asm') 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 -- cgit v1.3.1-sl0p