code wiki / _hdl_build / nx_syscall_emit.nx
nx_syscall_emit.nx source
↩ module page · 167 lines · 8863 B
1// nx_syscall_emit.nx -- functioning SYSCALL ABI (args + dispatch + return + resume).
2//
3// Completes the user/kernel boundary: a U-mode program makes REAL syscalls (a0 = syscall number,
4// a1 = argument), the M-mode kernel DISPATCHES on a0, SERVICES the call, advances mepc past the
5// ecall, and mret's back so the user RESUMES after the call. Multiple calls prove resumption:
6// user(U): syscall(PUTC,'A'); syscall(PUTC,'B'); syscall(EXIT)
7// kernel(M, mtvec): if a0==EXIT(0) -> finisher (halt); else PUTC(1) -> emit a1 over UART,
8// mepc += 4 (skip the ecall), mret -> resume the user after the call.
9// Success transcript "AB": two PUTC syscalls were serviced AND the user resumed between them (the
10// mepc+4 + mret return path works), then EXIT halted -- a working syscall round-trip.
11// nx_syscall_emit -> runtime/_hdl_build/_syscall_virt.bin + .gold
12// Sovereign, no gcc/.sh. license_tier: ORIGINAL
13import "nx_syscalls.nx"
14const SC_MAGIC_8192: i64 = 8192
15
16const SC_OUT: *u8 = "runtime/_hdl_build/_syscall_virt.bin"
17const SC_GOLD: *u8 = "runtime/_hdl_build/_syscall_virt.bin.gold"
18const SC_LOG: *u8 = "knowledge/status/priv.log"
19
20const SC_UART: i64 = 0x10000000
21const SC_FIN: i64 = 0x100000
22const SC_PASS: i64 = 0x5555
23const SC_MEM_BASE: i64 = 0x80000000
24const SC_CSR_MSTATUS: i64 = 0x300
25const SC_CSR_MTVEC: i64 = 0x305
26const SC_CSR_MEPC: i64 = 0x341
27const SC_MRET: i64 = 0x30200073
28const SC_ECALL: i64 = 0x00000073
29const SC_MPP_U: i64 = 0
30
31const RV_X0: i64 = 0
32const RV_T0: i64 = 5
33const RV_T1: i64 = 6
34const RV_T4: i64 = 29
35const RV_T5: i64 = 30
36const RV_A0: i64 = 10
37const RV_A1: i64 = 11
38
39const SC_CH_A: i64 = 65
40const SC_CH_B: i64 = 66
41
42func sc_lui(rd: i64, imm20: i64) -> i64 { return ((imm20 & 0xFFFFF) << 12) | (rd << 7) | 0x37 }
43func sc_addi(rd: i64, rs1: i64, imm: i64) -> i64 { return ((imm & 0xFFF) << 20) | (rs1 << 15) | (rd << 7) | 0x13 }
44func sc_store(rs2: i64, rs1: i64, f3: i64, imm: i64) -> i64 {
45 let hi: i64 = ((imm >> 5) & 0x7f) << 25
46 let lo: i64 = (imm & 0x1f) << 7
47 return hi | (rs2 << 20) | (rs1 << 15) | (f3 << 12) | lo | 0x23
48}
49func sc_branch(rs1: i64, rs2: i64, f3: i64, imm: i64) -> i64 {
50 let b12: i64 = ((imm >> 12) & 0x1) << 31
51 let b11: i64 = ((imm >> 11) & 0x1) << 7
52 let b10_5: i64 = ((imm >> 5) & 0x3f) << 25
53 let b4_1: i64 = ((imm >> 1) & 0xf) << 8
54 return b12 | b10_5 | (rs2 << 20) | (rs1 << 15) | (f3 << 12) | b4_1 | b11 | 0x63
55}
56func sc_jal(rd: i64, imm: i64) -> i64 {
57 let b20: i64 = ((imm >> 20) & 0x1) << 31
58 let b19_12: i64 = ((imm >> 12) & 0xff) << 12
59 let b11: i64 = ((imm >> 11) & 0x1) << 20
60 let b10_1: i64 = ((imm >> 1) & 0x3ff) << 21
61 return b20 | b10_1 | b11 | b19_12 | (rd << 7) | 0x6f
62}
63func sc_slli(rd: i64, rs1: i64, shamt: i64) -> i64 { return ((shamt & 0x3f) << 20) | (rs1 << 15) | (1 << 12) | (rd << 7) | 0x13 }
64func sc_srli(rd: i64, rs1: i64, shamt: i64) -> i64 { return ((shamt & 0x3f) << 20) | (rs1 << 15) | (5 << 12) | (rd << 7) | 0x13 }
65func sc_csrrw(rd: i64, csr: i64, rs1: i64) -> i64 { return ((csr & 0xfff) << 20) | (rs1 << 15) | (1 << 12) | (rd << 7) | 0x73 }
66func sc_csrrs(rd: i64, csr: i64, rs1: i64) -> i64 { return ((csr & 0xfff) << 20) | (rs1 << 15) | (2 << 12) | (rd << 7) | 0x73 }
67func sc_w32(buf: *u8, off: i64, w: i64) -> i64 { buf[off]=(w&0xff) as u8; buf[off+1]=((w>>8)&0xff) as u8; buf[off+2]=((w>>16)&0xff) as u8; buf[off+3]=((w>>24)&0xff) as u8; return off+4 }
68func sc_li32(buf: *u8, off: i64, rd: i64, val: i64) -> i64 {
69 var hi: i64 = (val >> 12) & 0xFFFFF
70 var lo: i64 = val & 0xFFF
71 if lo >= 0x800 { lo = lo - 0x1000; hi = (hi + 1) & 0xFFFFF }
72 var o: i64 = sc_w32(buf, off, sc_lui(rd, hi))
73 o = sc_w32(buf, o, sc_addi(rd, rd, lo))
74 return o
75}
76func sc_li32u(buf: *u8, off: i64, rd: i64, val: i64) -> i64 {
77 var o: i64 = sc_li32(buf, off, rd, val)
78 o = sc_w32(buf, o, sc_slli(rd, rd, 32))
79 o = sc_w32(buf, o, sc_srli(rd, rd, 32))
80 return o
81}
82func sc_p(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
83func sc_fn(fd: i64, v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m}; let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48;k=1}; while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1}; var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1}; sys_write(fd,bb,k); return 0 }
84
85// pos_out[0]=USER [1]=HANDLER [2]=EXIT
86func sc_emit_image(buf: *u8, user_off: i64, handler_off: i64, exit_off: i64, pos_out: *i64, advance: i64) -> i64 {
87 var o: i64 = 0
88 o = sc_w32(buf, o, sc_lui(RV_T0, SC_UART >> 12))
89 // install mtvec=&handler; mepc=&user; MPP=U; mret -> drop to U-mode
90 o = sc_li32u(buf, o, RV_T1, SC_MEM_BASE + handler_off)
91 o = sc_w32(buf, o, sc_csrrw(RV_X0, SC_CSR_MTVEC, RV_T1))
92 o = sc_li32u(buf, o, RV_T1, SC_MEM_BASE + user_off)
93 o = sc_w32(buf, o, sc_csrrw(RV_X0, SC_CSR_MEPC, RV_T1))
94 o = sc_li32(buf, o, RV_T1, SC_MPP_U)
95 o = sc_w32(buf, o, sc_csrrw(RV_X0, SC_CSR_MSTATUS, RV_T1))
96 o = sc_w32(buf, o, SC_MRET)
97 pos_out[0] = o // USER (U-mode)
98 // syscall(PUTC,'A')
99 o = sc_w32(buf, o, sc_addi(RV_A0, RV_X0, 1)) // a0 = PUTC(1)
100 o = sc_w32(buf, o, sc_addi(RV_A1, RV_X0, SC_CH_A)) // a1 = 'A'
101 o = sc_w32(buf, o, SC_ECALL)
102 // syscall(PUTC,'B') (reached only if the first syscall RETURNED -> proves resume)
103 o = sc_w32(buf, o, sc_addi(RV_A0, RV_X0, 1))
104 o = sc_w32(buf, o, sc_addi(RV_A1, RV_X0, SC_CH_B))
105 o = sc_w32(buf, o, SC_ECALL)
106 // syscall(EXIT)
107 o = sc_w32(buf, o, sc_addi(RV_A0, RV_X0, 0)) // a0 = EXIT(0)
108 o = sc_w32(buf, o, SC_ECALL)
109 o = sc_w32(buf, o, sc_jal(RV_X0, exit_off - o)) // dead safety
110 pos_out[1] = o // HANDLER (mtvec, M-mode)
111 o = sc_w32(buf, o, sc_lui(RV_T0, SC_UART >> 12)) // re-establish UART base
112 o = sc_w32(buf, o, sc_addi(RV_T4, RV_X0, 0)) // t4 = 0 (EXIT)
113 let pcb: i64 = o
114 o = sc_w32(buf, o, sc_branch(RV_A0, RV_T4, 0, exit_off - pcb)) // a0==0 -> EXIT
115 // PUTC: emit a1 (the char) over the UART
116 o = sc_w32(buf, o, sc_store(RV_A1, RV_T0, 0, 0)) // sb a1, 0(t0)
117 // return to user: mepc += 4 (skip the ecall), mret
118 o = sc_w32(buf, o, sc_csrrs(RV_T1, SC_CSR_MEPC, RV_X0)) // t1 = mepc
119 o = sc_w32(buf, o, sc_addi(RV_T1, RV_T1, advance)) // t1 += advance (4=normal; 0=control: re-runs ecall, no resume)
120 o = sc_w32(buf, o, sc_csrrw(RV_X0, SC_CSR_MEPC, RV_T1)) // mepc = t1
121 o = sc_w32(buf, o, SC_MRET) // resume user after the ecall
122 pos_out[2] = o // EXIT (finisher)
123 o = sc_li32(buf, o, RV_T5, SC_FIN)
124 o = sc_li32(buf, o, RV_T1, SC_PASS)
125 o = sc_w32(buf, o, sc_store(RV_T1, RV_T5, 2, 0))
126 o = sc_w32(buf, o, sc_jal(RV_X0, 0))
127 return o
128}
129
130func sc_parse_num(s: *u8) -> i64 {
131 var q: i64 = 0; var val: i64 = 0
132 if s[0] == (48 as u8) { if s[1] == (120 as u8) {
133 q = 2
134 var go: i64 = 1
135 while go == 1 { let c: i64 = s[q] as i64; var d: i64 = 0-1; if c>=48 { if c<=57 { d=c-48 } } if c>=97 { if c<=102 { d=c-87 } } if c>=65 { if c<=70 { d=c-55 } } if d<0 { go=0 } else { val=val*16+d; q=q+1 } }
136 return val
137 }}
138 var go2: i64 = 1
139 while go2 == 1 { let c: i64 = s[q] as i64; if c>=48 { if c<=57 { val=val*10+(c-48); q=q+1 } else { go2=0 } } else { go2=0 } }
140 return val
141}
142
143func main(argc: i64, argv: *i64) -> i64 {
144 var advance: i64 = 4
145 var outp: *u8 = SC_OUT
146 if argc >= 2 { advance = sc_parse_num(argv[1] as *u8) } // control: 0 -> no resume (re-runs ecall, no B)
147 if argc >= 3 { outp = argv[2] as *u8 }
148 let scratch: *u8 = sys_mmap(SC_MAGIC_8192)
149 let pos: *i64 = sys_mmap(32) as *i64
150 sc_emit_image(scratch, 0, 0, 0, pos, advance)
151 let user_off: i64 = pos[0]
152 let handler_off: i64 = pos[1]
153 let exit_off: i64 = pos[2]
154 let buf: *u8 = sys_mmap(SC_MAGIC_8192)
155 let sz: i64 = sc_emit_image(buf, user_off, handler_off, exit_off, pos, advance)
156 let fd: i64 = sys_openat_wr(outp, 420)
157 if fd < 0 { sc_p("SYSCALLEMIT verdict=RED reason=out-unwritable\n" as *u8); return 1 }
158 sys_write(fd, buf, sz); sys_close(fd)
159 let gold: *u8 = sys_mmap(8)
160 gold[0]=65 as u8; gold[1]=66 as u8 // "AB"
161 let gfd: i64 = sys_openat_wr(SC_GOLD, 420)
162 if gfd >= 0 { sys_write(gfd, gold, 2); sys_close(gfd) }
163 sc_p("SYSCALLEMIT name=" as *u8); sc_p(outp); sc_p(" bytes=" as *u8); sc_fn(1, sz); sc_p(" golden=AB (U-mode syscalls PUTC A,B + EXIT; resume between calls)\n" as *u8)
164 let lf: i64 = sys_openat_append(SC_LOG, 420)
165 if lf >= 0 { var n: i64=0; let m: *u8="SYSCALLEMIT authored _syscall_virt.bin golden=AB\n" as *u8; while m[n]!=(0 as u8){n=n+1} sys_write(lf,m,n); sys_close(lf) }
166 return 0
167}