1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
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_fork ; 1 FORK
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_exec ; 6 EXEC
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
|