nx_emu_cortexm.nx source
↩ module page · 167 lines · 8858 B
1// nx_emu_cortexm.nx -- sovereign ARMv7-M / Cortex-M (Thumb-2) interpreter (NX-EMU).
2// Little-endian, MIXED 16/32-bit instructions (32-bit iff hw1[15:11] in {11101,11110,
3// 11111} i.e. hw1>=0xE800), 16 GPRs + C flag. Decodes the subset nxc2's cortex_m
4// backend emits: push/pop, mov(hi), movs, adds/subs/adcs/sbcs, sub-sp, ldr/str (16-bit
5// imm5 + 32-bit T4 neg-offset), blx, movw, umull, mla, subw. Bare-metal: BKPT halts
6// with result=r0 (no OS). NO qemu. license_tier: ORIGINAL
7import "nx_syscalls_x86_64.nx"
8
9const CM_GUEST: i64 = 16777216
10const CM_MASK: i64 = 0xFFFFFFFF
11
12func cm_ld(mem: *u8, va: i64, width: i64) -> i64 { var v: i64 = 0; var i: i64 = 0; while i < width { v = v | ((mem[va + i] & 0xff) << (i * 8)); i = i + 1 } return v }
13func cm_st(mem: *u8, va: i64, width: i64, val: i64) -> i64 { var i: i64 = 0; while i < width { mem[va + i] = (val >> (i * 8)) & 0xff; i = i + 1 } return 0 }
14
15func emu_cortexm_run_mem(mem: *u8, mem_size: i64, entry: i64, sp0: i64) -> i64 {
16 let r: *i64 = sys_mmap(16 * 8) as *i64
17 var i: i64 = 0
18 while i < 16 { r[i] = 0; i = i + 1 }
19 r[13] = sp0
20 var pc: i64 = entry
21 var cf: i64 = 0
22 var result: i64 = 0
23 var halted: i64 = 0
24 var steps: i64 = 0
25 while halted == 0 {
26 if steps > 5000000 { halted = 1 } else {
27 let hw1: i64 = cm_ld(mem, pc, 2)
28 var next: i64 = pc + 2
29 var handled: i64 = 0
30 if (hw1 & 0xF800) >= 0xE800 {
31 // ---- 32-bit Thumb-2 ----
32 let hw2: i64 = cm_ld(mem, pc + 2, 2)
33 next = pc + 4
34 if (hw1 & 0xFBF0) == 0xF240 { // MOVW
35 handled = 1
36 let rd: i64 = (hw2 >> 8) & 0xF
37 let imm: i64 = (((hw1 & 0xF) << 12) | (((hw1 >> 10) & 1) << 11) | (((hw2 >> 12) & 7) << 8) | (hw2 & 0xFF))
38 r[rd] = imm
39 }
40 if (hw1 & 0xFBF0) == 0xF2A0 { // SUBW (T4, plain imm12)
41 handled = 1
42 let rn: i64 = hw1 & 0xF
43 let rd: i64 = (hw2 >> 8) & 0xF
44 let imm: i64 = (((hw1 >> 10) & 1) << 11) | (((hw2 >> 12) & 7) << 8) | (hw2 & 0xFF)
45 r[rd] = (r[rn] - imm) & CM_MASK
46 }
47 if (hw1 & 0xFFF0) == 0xFBA0 { // UMULL
48 handled = 1
49 let rn: i64 = hw1 & 0xF
50 let rdlo: i64 = (hw2 >> 12) & 0xF
51 let rdhi: i64 = (hw2 >> 8) & 0xF
52 let rm: i64 = hw2 & 0xF
53 let p: i64 = (r[rn] & CM_MASK) * (r[rm] & CM_MASK)
54 r[rdlo] = p & CM_MASK
55 r[rdhi] = (p >> 32) & CM_MASK
56 }
57 if (hw1 & 0xFFF0) == 0xFB00 { if (hw2 & 0xF0) == 0x00 { // MLA
58 handled = 1
59 let rn: i64 = hw1 & 0xF
60 let ra: i64 = (hw2 >> 12) & 0xF
61 let rd: i64 = (hw2 >> 8) & 0xF
62 let rm: i64 = hw2 & 0xF
63 r[rd] = (r[rn] * r[rm] + r[ra]) & CM_MASK
64 } }
65 if (hw1 & 0xFFF0) == 0xF850 { // LDR (T4)
66 handled = 1
67 let rn: i64 = hw1 & 0xF
68 let rt: i64 = (hw2 >> 12) & 0xF
69 let U: i64 = (hw2 >> 9) & 1
70 var off: i64 = hw2 & 0xFF
71 if U == 0 { off = 0 - off }
72 r[rt] = cm_ld(mem, (r[rn] + off) & CM_MASK, 4) & CM_MASK
73 }
74 if (hw1 & 0xFFF0) == 0xF840 { // STR (T4)
75 handled = 1
76 let rn: i64 = hw1 & 0xF
77 let rt: i64 = (hw2 >> 12) & 0xF
78 let U: i64 = (hw2 >> 9) & 1
79 var off: i64 = hw2 & 0xFF
80 if U == 0 { off = 0 - off }
81 cm_st(mem, (r[rn] + off) & CM_MASK, 4, r[rt] & CM_MASK)
82 }
83 } else {
84 // ---- 16-bit Thumb ----
85 if (hw1 & 0xFF00) == 0xBE00 { handled = 1; result = r[0] & 0xff; halted = 1 } // BKPT -> halt
86 if (hw1 & 0xFF87) == 0x4780 { handled = 1; let rm: i64 = (hw1 >> 3) & 0xF; r[14] = (pc + 2) | 1; next = r[rm] & (CM_MASK - 1) } // BLX reg
87 if (hw1 & 0xFE00) == 0xB400 { // PUSH
88 handled = 1
89 var list: i64 = hw1 & 0xFF
90 if ((hw1 >> 8) & 1) == 1 { list = list | (1 << 14) } // M -> lr
91 var cnt: i64 = 0; var k: i64 = 0; while k < 16 { if (list & (1<<k)) != 0 { cnt = cnt + 1 } k = k + 1 }
92 var addr: i64 = (r[13] - 4 * cnt) & CM_MASK
93 r[13] = addr
94 k = 0; while k < 16 { if (list & (1<<k)) != 0 { cm_st(mem, addr, 4, r[k] & CM_MASK); addr = addr + 4 } k = k + 1 }
95 }
96 if (hw1 & 0xFE00) == 0xBC00 { // POP
97 handled = 1
98 var list: i64 = hw1 & 0xFF
99 var ppc: i64 = (hw1 >> 8) & 1 // P -> pc
100 var addr: i64 = r[13]
101 var k: i64 = 0; while k < 16 { if (list & (1<<k)) != 0 { r[k] = cm_ld(mem, addr, 4) & CM_MASK; addr = addr + 4 } k = k + 1 }
102 if ppc == 1 { next = cm_ld(mem, addr, 4) & (CM_MASK - 1); addr = addr + 4 }
103 r[13] = addr
104 }
105 if (hw1 & 0xFF00) == 0x4600 { // MOV (hi)
106 handled = 1
107 let rd: i64 = (((hw1 >> 7) & 1) << 3) | (hw1 & 7)
108 let rm: i64 = (hw1 >> 3) & 0xF
109 r[rd] = r[rm] & CM_MASK
110 }
111 if (hw1 & 0xF800) == 0x2000 { // MOVS imm8
112 handled = 1
113 r[(hw1 >> 8) & 7] = hw1 & 0xFF
114 }
115 if (hw1 & 0xFE00) == 0x1800 { // ADDS 3-reg
116 handled = 1
117 let rm: i64 = (hw1 >> 6) & 7; let rn: i64 = (hw1 >> 3) & 7; let rd: i64 = hw1 & 7
118 let s2: i64 = (r[rn] & CM_MASK) + (r[rm] & CM_MASK); cf = (s2 >> 32) & 1; r[rd] = s2 & CM_MASK
119 }
120 if (hw1 & 0xFE00) == 0x1A00 { // SUBS 3-reg
121 handled = 1
122 let rm: i64 = (hw1 >> 6) & 7; let rn: i64 = (hw1 >> 3) & 7; let rd: i64 = hw1 & 7
123 let a: i64 = r[rn] & CM_MASK; let b: i64 = r[rm] & CM_MASK
124 if a < b { cf = 0 } else { cf = 1 }
125 r[rd] = (a - b) & CM_MASK
126 }
127 if (hw1 & 0xFFC0) == 0x4140 { // ADCS rdn,rm
128 handled = 1
129 let rm: i64 = (hw1 >> 3) & 7; let rd: i64 = hw1 & 7
130 let s2: i64 = (r[rd] & CM_MASK) + (r[rm] & CM_MASK) + cf; cf = (s2 >> 32) & 1; r[rd] = s2 & CM_MASK
131 }
132 if (hw1 & 0xFFC0) == 0x4180 { // SBCS rdn,rm
133 handled = 1
134 let rm: i64 = (hw1 >> 3) & 7; let rd: i64 = hw1 & 7
135 let a: i64 = r[rd] & CM_MASK; let b: i64 = r[rm] & CM_MASK
136 r[rd] = (a - b - (1 - cf)) & CM_MASK
137 if a >= (b + (1 - cf)) { cf = 1 } else { cf = 0 }
138 }
139 if (hw1 & 0xF800) == 0x6800 { // LDR imm5
140 handled = 1
141 let imm: i64 = ((hw1 >> 6) & 0x1F) * 4; let rn: i64 = (hw1 >> 3) & 7; let rt: i64 = hw1 & 7
142 r[rt] = cm_ld(mem, (r[rn] + imm) & CM_MASK, 4) & CM_MASK
143 }
144 if (hw1 & 0xF800) == 0x6000 { // STR imm5
145 handled = 1
146 let imm: i64 = ((hw1 >> 6) & 0x1F) * 4; let rn: i64 = (hw1 >> 3) & 7; let rt: i64 = hw1 & 7
147 cm_st(mem, (r[rn] + imm) & CM_MASK, 4, r[rt] & CM_MASK)
148 }
149 if (hw1 & 0xFF80) == 0xB080 { // SUB SP imm7
150 handled = 1
151 r[13] = (r[13] - (hw1 & 0x7F) * 4) & CM_MASK
152 }
153 }
154 if handled == 0 { result = 0 - 1; halted = 1 }
155 pc = next
156 steps = steps + 1
157 }
158 }
159 return result
160}
161
162func emu_cortexm_run(code: *u8, code_len: i64) -> i64 {
163 let mem: *u8 = sys_mmap(CM_GUEST)
164 var i: i64 = 0
165 while i < code_len { mem[i] = code[i]; i = i + 1 }
166 return emu_cortexm_run_mem(mem, CM_GUEST, 0, 0x00800000) // entry at offset 0 (aligned)
167}