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}