code wiki / _hdl_build / nx_strap_emit.nx
nx_strap_emit.nx source
↩ module page · 176 lines · 9901 B
1// nx_strap_emit.nx -- S-MODE TRAP DELEGATION + sret (X-PAGE-STRAP-001). The real-OS trap path: instead
2// of every trap going to the M-mode monitor, an exception is DELEGATED (medeleg) to the S-mode kernel,
3// which handles it at stvec and returns with sret. Sequence: M-mode installs mtvec(=M handler) +
4// stvec(=S handler) + medeleg + drops to U-mode (mret, MPP=U); the U program ecalls; with the ecall-from-U
5// bit set in medeleg the trap vectors to the S-MODE handler (stvec), which confirms scause==8, prints
6// "STRAP", advances sepc+4, and sret's back to U; the U program then halts (finisher) -- reaching the
7// finisher PROVES sret returned. With medeleg=0 (the gate's control) the trap goes to the M-mode handler
8// instead -> "MTRAP", no STRAP.
9// medeleg (argv[1]) -- default 0x100 (delegate ecall-from-U, cause 8). out-path (argv[2]).
10// Sovereign, no gcc/.sh. license_tier: ORIGINAL
11import "nx_syscalls.nx"
12const ST_MAGIC_8192: i64 = 8192
13
14const ST_OUT: *u8 = "runtime/_hdl_build/_strap_virt.bin"
15const ST_GOLD: *u8 = "runtime/_hdl_build/_strap_virt.bin.gold"
16const ST_LOG: *u8 = "knowledge/status/priv.log"
17
18const ST_UART: i64 = 0x10000000
19const ST_FIN: i64 = 0x100000
20const ST_PASS: i64 = 0x5555
21const ST_MEM_BASE: i64 = 0x80000000
22const ST_CSR_MSTATUS: i64 = 0x300
23const ST_CSR_MTVEC: i64 = 0x305
24const ST_CSR_MEPC: i64 = 0x341
25const ST_CSR_STVEC: i64 = 0x105
26const ST_CSR_SEPC: i64 = 0x141
27const ST_CSR_SCAUSE: i64 = 0x142
28const ST_CSR_MEDELEG: i64 = 0x302
29const ST_MRET: i64 = 0x30200073
30const ST_SRET: i64 = 0x10200073
31const ST_ECALL: i64 = 0x00000073
32const ST_MPP_U: i64 = 0
33const ST_ECALL_U_CAUSE: i64 = 8
34
35const RV_X0: i64 = 0
36const RV_T0: i64 = 5
37const RV_T1: i64 = 6
38const RV_T3: i64 = 28
39const RV_T4: i64 = 29
40const RV_T5: i64 = 30
41
42func st_lui(rd: i64, imm20: i64) -> i64 { return ((imm20 & 0xFFFFF) << 12) | (rd << 7) | 0x37 }
43func st_addi(rd: i64, rs1: i64, imm: i64) -> i64 { return ((imm & 0xFFF) << 20) | (rs1 << 15) | (rd << 7) | 0x13 }
44func st_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 st_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 st_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 st_slli(rd: i64, rs1: i64, shamt: i64) -> i64 { return ((shamt & 0x3f) << 20) | (rs1 << 15) | (1 << 12) | (rd << 7) | 0x13 }
64func st_srli(rd: i64, rs1: i64, shamt: i64) -> i64 { return ((shamt & 0x3f) << 20) | (rs1 << 15) | (5 << 12) | (rd << 7) | 0x13 }
65func st_csrrw(rd: i64, csr: i64, rs1: i64) -> i64 { return ((csr & 0xfff) << 20) | (rs1 << 15) | (1 << 12) | (rd << 7) | 0x73 }
66func st_csrrs(rd: i64, csr: i64, rs1: i64) -> i64 { return ((csr & 0xfff) << 20) | (rs1 << 15) | (2 << 12) | (rd << 7) | 0x73 }
67func st_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 st_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 = st_w32(buf, off, st_lui(rd, hi))
73 o = st_w32(buf, o, st_addi(rd, rd, lo))
74 return o
75}
76func st_li32u(buf: *u8, off: i64, rd: i64, val: i64) -> i64 {
77 var o: i64 = st_li32(buf, off, rd, val)
78 o = st_w32(buf, o, st_slli(rd, rd, 32))
79 o = st_w32(buf, o, st_srli(rd, rd, 32))
80 return o
81}
82func st_emit_str(buf: *u8, off: i64, s: *u8, n: i64) -> i64 {
83 var o: i64 = off
84 var i: i64 = 0
85 while i < n { o = st_w32(buf, o, st_addi(RV_T1, RV_X0, s[i] as i64)); o = st_w32(buf, o, st_store(RV_T1, RV_T0, 0, 0)); i = i + 1 }
86 return o
87}
88func st_fin(buf: *u8, off: i64) -> i64 { // li FIN; li PASS; sw; (caller adds jal)
89 var o: i64 = st_li32(buf, off, RV_T5, ST_FIN)
90 o = st_li32(buf, o, RV_T1, ST_PASS)
91 o = st_w32(buf, o, st_store(RV_T1, RV_T5, 2, 0))
92 return o
93}
94func st_p(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
95func st_fn(fd: i64, v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(fd,"-" as *u8,1)}; 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 }
96
97// pos_out[0]=USER [1]=SHANDLER [2]=NOTS [3]=MHANDLER [4]=HALT
98func st_emit_image(buf: *u8, user_off: i64, sh_off: i64, nots_off: i64, mh_off: i64, halt_off: i64, pos_out: *i64, medeleg: i64) -> i64 {
99 var o: i64 = 0
100 o = st_w32(buf, o, st_lui(RV_T0, ST_UART >> 12)) // t0 = UART
101 o = st_li32u(buf, o, RV_T1, ST_MEM_BASE + mh_off) // mtvec = &m_handler
102 o = st_w32(buf, o, st_csrrw(RV_X0, ST_CSR_MTVEC, RV_T1))
103 o = st_li32u(buf, o, RV_T1, ST_MEM_BASE + sh_off) // stvec = &s_handler
104 o = st_w32(buf, o, st_csrrw(RV_X0, ST_CSR_STVEC, RV_T1))
105 o = st_li32(buf, o, RV_T1, medeleg) // medeleg (delegate ecall-from-U?)
106 o = st_w32(buf, o, st_csrrw(RV_X0, ST_CSR_MEDELEG, RV_T1))
107 o = st_li32u(buf, o, RV_T1, ST_MEM_BASE + user_off) // mepc = &user
108 o = st_w32(buf, o, st_csrrw(RV_X0, ST_CSR_MEPC, RV_T1))
109 o = st_li32(buf, o, RV_T1, ST_MPP_U) // mstatus = MPP=U
110 o = st_w32(buf, o, st_csrrw(RV_X0, ST_CSR_MSTATUS, RV_T1))
111 o = st_w32(buf, o, ST_MRET)
112 pos_out[0] = o // USER (U-mode)
113 o = st_w32(buf, o, ST_ECALL) // syscall -> delegated (S) or not (M)
114 o = st_w32(buf, o, st_jal(RV_X0, halt_off - o)) // on sret-return, fall to HALT (proves sret)
115 pos_out[1] = o // S_HANDLER (stvec, S-mode)
116 o = st_w32(buf, o, st_csrrs(RV_T3, ST_CSR_SCAUSE, RV_X0)) // t3 = scause
117 o = st_li32(buf, o, RV_T4, ST_ECALL_U_CAUSE) // t4 = 8
118 let pcb: i64 = o
119 o = st_w32(buf, o, st_branch(RV_T3, RV_T4, 1, nots_off - pcb)) // bne -> NOTS
120 o = st_emit_str(buf, o, "STRAP" as *u8, 5) // an ecall-from-U handled in S-MODE
121 o = st_w32(buf, o, st_csrrs(RV_T1, ST_CSR_SEPC, RV_X0)) // sepc += 4 (skip past the ecall)
122 o = st_w32(buf, o, st_addi(RV_T1, RV_T1, 4))
123 o = st_w32(buf, o, st_csrrw(RV_X0, ST_CSR_SEPC, RV_T1))
124 o = st_w32(buf, o, ST_SRET) // return to U-mode
125 pos_out[2] = o // NOTS
126 o = st_emit_str(buf, o, "SX" as *u8, 2)
127 o = st_w32(buf, o, st_jal(RV_X0, halt_off - o))
128 pos_out[3] = o // M_HANDLER (mtvec, M-mode: not delegated)
129 o = st_emit_str(buf, o, "MTRAP" as *u8, 5)
130 o = st_w32(buf, o, st_jal(RV_X0, halt_off - o))
131 pos_out[4] = o // HALT
132 o = st_fin(buf, o)
133 o = st_w32(buf, o, st_jal(RV_X0, 0))
134 return o
135}
136
137func st_parse_num(s: *u8) -> i64 {
138 var q: i64 = 0; var val: i64 = 0
139 if s[0] == (48 as u8) { if s[1] == (120 as u8) {
140 q = 2
141 var go: i64 = 1
142 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 } }
143 return val
144 }}
145 var go2: i64 = 1
146 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 } }
147 return val
148}
149
150func main(argc: i64, argv: *i64) -> i64 {
151 var medeleg: i64 = 0x100 // default: delegate ecall-from-U (cause 8) to S-mode
152 var outp: *u8 = ST_OUT
153 if argc >= 2 { medeleg = st_parse_num(argv[1] as *u8) }
154 if argc >= 3 { outp = argv[2] as *u8 }
155 let scratch: *u8 = sys_mmap(ST_MAGIC_8192)
156 let pos: *i64 = sys_mmap(40) as *i64
157 st_emit_image(scratch, 0, 0, 0, 0, 0, pos, medeleg)
158 let user_off: i64 = pos[0]
159 let sh_off: i64 = pos[1]
160 let nots_off: i64 = pos[2]
161 let mh_off: i64 = pos[3]
162 let halt_off: i64 = pos[4]
163 let buf: *u8 = sys_mmap(ST_MAGIC_8192)
164 let sz: i64 = st_emit_image(buf, user_off, sh_off, nots_off, mh_off, halt_off, pos, medeleg)
165 let fd: i64 = sys_openat_wr(outp, MODE_0644)
166 if fd < 0 { st_p("STRAPEMIT verdict=RED reason=out-unwritable\n" as *u8); return 1 }
167 sys_write(fd, buf, sz); sys_close(fd)
168 let gold: *u8 = sys_mmap(8)
169 gold[0]=83 as u8; gold[1]=84 as u8; gold[2]=82 as u8; gold[3]=65 as u8; gold[4]=80 as u8 // "STRAP"
170 let gfd: i64 = sys_openat_wr(ST_GOLD, 420)
171 if gfd >= 0 { sys_write(gfd, gold, 5); sys_close(gfd) }
172 st_p("STRAPEMIT name=" as *u8); st_p(outp); st_p(" bytes=" as *u8); st_fn(1, sz); st_p(" (S-mode trap delegation + sret)\n" as *u8)
173 let lf: i64 = sys_openat_append(ST_LOG, 420)
174 if lf >= 0 { var n: i64=0; let m: *u8="STRAPEMIT authored _strap_virt.bin golden=STRAP\n" as *u8; while m[n]!=(0 as u8){n=n+1} sys_write(lf,m,n); sys_close(lf) }
175 return 0
176}