nx_hal_test.nx source
↩ module page · 163 lines · 6856 B
1// nx_hal_test.nx -- smoke for the substrate HAL.
2
3import "nx_syscalls.nx"
4import "nx_hal.nx"
5
6func main() -> i64 {
7 // ----- 1. Sealed-enum gates -----
8 if nx_hal_op_is_valid(NX_HAL_OP_CLOCK_NOW_NS) != 1 { return 1 }
9 if nx_hal_op_is_valid(NX_HAL_OP_ALLOC_PAGES) != 1 { return 2 }
10 if nx_hal_op_is_valid(NX_HAL_OP_RELEASE_PAGES) != 1 { return 3 }
11 if nx_hal_op_is_valid(NX_HAL_OP_CONSOLE_WRITE) != 1 { return 4 }
12 if nx_hal_op_is_valid(NX_HAL_OP_RANDOM_BYTES) != 1 { return 5 }
13 if nx_hal_op_is_valid(NX_HAL_OP_YIELD) != 1 { return 6 }
14 if nx_hal_op_is_valid(NX_HAL_OP_EXIT) != 1 { return 7 }
15 if nx_hal_op_is_valid(-1) != 0 { return 8 }
16 if nx_hal_op_is_valid(NX_HAL_OP_N_KINDS) != 0 { return 9 }
17
18 if nx_hal_shim_is_valid(NX_HAL_SHIM_LINUX) != 1 { return 10 }
19 if nx_hal_shim_is_valid(NX_HAL_SHIM_BARE_METAL) != 1 { return 11 }
20 if nx_hal_shim_is_valid(NX_HAL_SHIM_NISHI_SILICON) != 1 { return 12 }
21 if nx_hal_shim_is_valid(-1) != 0 { return 13 }
22 if nx_hal_shim_is_valid(NX_HAL_SHIM_N_KINDS) != 0 { return 14 }
23
24 if nx_hal_verdict_is_valid(NX_HAL_OK) != 1 { return 15 }
25 if nx_hal_verdict_is_valid(NX_HAL_FAULT) != 1 { return 16 }
26 if nx_hal_verdict_is_valid(-1) != 0 { return 17 }
27 if nx_hal_verdict_is_valid(NX_HAL_N_VERDICTS) != 0 { return 18 }
28
29 // ----- 2. Active shim is Linux today -----
30 if nx_hal_active_shim() != NX_HAL_SHIM_LINUX { return 19 }
31
32 // ----- 3. nx_hal_clock_now_ns -----
33 let t0: i64 = nx_hal_clock_now_ns()
34 if t0 <= 0 { return 20 }
35 // Second call must be >= first (monotonic).
36 let t1: i64 = nx_hal_clock_now_ns()
37 if t1 < t0 { return 21 }
38
39 // ----- 4. nx_hal_alloc_pages -----
40 let p: *u8 = nx_hal_alloc_pages(4096)
41 if (p as i64) == 0 { return 22 }
42 // Zero-initialised.
43 if p[0] != 0 { return 23 }
44 if p[4095] != 0 { return 24 }
45 // Writable.
46 p[0] = 42
47 p[4095] = 99
48 if p[0] != 42 { return 25 }
49 if p[4095] != 99 { return 26 }
50 // Bad inputs.
51 if (nx_hal_alloc_pages(0) as i64) != 0 { return 27 }
52 if (nx_hal_alloc_pages(-1) as i64) != 0 { return 28 }
53
54 // ----- 5. nx_hal_release_pages -- V1 returns NO_BACKING -----
55 let rel_rc: i64 = nx_hal_release_pages(p, 4096)
56 if rel_rc != (0 - NX_HAL_NO_BACKING) { return 29 }
57 // Bad inputs still rejected.
58 let null_p: *u8 = (0 as i64) as *u8
59 if nx_hal_release_pages(null_p, 4096) != (0 - NX_HAL_BAD_INPUT) { return 30 }
60 if nx_hal_release_pages(p, 0) != (0 - NX_HAL_BAD_INPUT) { return 31 }
61 if nx_hal_release_pages(p, -1) != (0 - NX_HAL_BAD_INPUT) { return 32 }
62
63 // ----- 6. nx_hal_console_write -----
64 let msg: *u8 = "[HAL smoke] console write OK\n" as *u8
65 let written: i64 = nx_hal_console_write(msg, 29)
66 if written != 29 { return 33 }
67 // Empty write is a no-op.
68 if nx_hal_console_write(msg, 0) != NX_HAL_OK { return 34 }
69 // Bad inputs.
70 if nx_hal_console_write(null_p, 5) != (0 - NX_HAL_BAD_INPUT) { return 35 }
71 if nx_hal_console_write(msg, -1) != (0 - NX_HAL_BAD_INPUT) { return 36 }
72
73 // ----- 7. nx_hal_random_bytes -----
74 let r: *u8 = nx_hal_alloc_pages(32)
75 if nx_hal_random_bytes(r, 32) != NX_HAL_OK { return 37 }
76 // Bytes are NOT all zero (probabilistic; vanishingly unlikely
77 // for 32 bytes of true entropy).
78 var i: i64 = 0
79 var nonzero_count: i64 = 0
80 while i < 32 {
81 if r[i] != 0 { nonzero_count = nonzero_count + 1 }
82 i = i + 1
83 }
84 if nonzero_count < 8 { return 38 }
85 // Bad inputs.
86 if nx_hal_random_bytes(null_p, 32) != (0 - NX_HAL_BAD_INPUT) { return 39 }
87 if nx_hal_random_bytes(r, -1) != (0 - NX_HAL_BAD_INPUT) { return 40 }
88 if nx_hal_random_bytes(r, 0) != NX_HAL_OK { return 41 }
89
90 // ----- 8. nx_hal_yield -----
91 if nx_hal_yield() != NX_HAL_OK { return 42 }
92
93 // ----- 9. Clock monotonicity over yield -----
94 let t_pre: i64 = nx_hal_clock_now_ns()
95 nx_hal_yield()
96 let t_post: i64 = nx_hal_clock_now_ns()
97 if t_post < t_pre { return 43 }
98
99 // nx_hal_exit deliberately NOT tested (it terminates).
100
101 // ----- 10. nx_hal_spawn + nx_hal_wait: substrate becomes parent -----
102 // /bin/true is a universal Linux binary that exits 0.
103 let true_path: *u8 = "/bin/true" as *u8
104 let argv_true: *i64 = (sys_mmap(16)) as *i64
105 argv_true[0] = true_path as i64
106 argv_true[1] = 0 // null-terminator
107 let null_envp: *i64 = (0 as i64) as *i64
108 let pid: i64 = nx_hal_spawn(true_path, argv_true, null_envp)
109 if pid <= 0 { return 44 }
110
111 let exit_out: *i64 = (sys_mmap(8)) as *i64
112 exit_out[0] = -1
113 let wait_rc: i64 = nx_hal_wait(pid, exit_out)
114 if wait_rc != NX_HAL_OK { return 45 }
115 if exit_out[0] != 0 { return 46 }
116
117 // ----- 11. /bin/false returns non-zero -----
118 let false_path: *u8 = "/bin/false" as *u8
119 let argv_false: *i64 = (sys_mmap(16)) as *i64
120 argv_false[0] = false_path as i64
121 argv_false[1] = 0
122 let pid2: i64 = nx_hal_spawn(false_path, argv_false, null_envp)
123 if pid2 <= 0 { return 47 }
124 exit_out[0] = 0
125 if nx_hal_wait(pid2, exit_out) != NX_HAL_OK { return 48 }
126 if exit_out[0] != 1 { return 49 }
127
128 // ----- 12. Spawn /bin/echo: visible side-effect via stdout -----
129 let echo_path: *u8 = "/bin/echo" as *u8
130 let echo_msg: *u8 = "[substrate spawn] child child child" as *u8
131 let argv_echo: *i64 = (sys_mmap(32)) as *i64
132 argv_echo[0] = echo_path as i64
133 argv_echo[1] = echo_msg as i64
134 argv_echo[2] = 0
135 let pid3: i64 = nx_hal_spawn(echo_path, argv_echo, null_envp)
136 if pid3 <= 0 { return 50 }
137 if nx_hal_wait(pid3, exit_out) != NX_HAL_OK { return 51 }
138 if exit_out[0] != 0 { return 52 }
139
140 // ----- 13. nx_hal_spawn bad-input gates -----
141 let null_u8: *u8 = (0 as i64) as *u8
142 let null_i64: *i64 = (0 as i64) as *i64
143 if nx_hal_spawn(null_u8, argv_true, null_envp) != (0 - NX_HAL_BAD_INPUT) { return 53 }
144 if nx_hal_spawn(true_path, null_i64, null_envp) != (0 - NX_HAL_BAD_INPUT) { return 54 }
145
146 // ----- 14. nx_hal_wait bad-input -----
147 if nx_hal_wait(-1, null_i64) != (0 - NX_HAL_BAD_INPUT) { return 55 }
148
149 // ----- 15. nx_hal_kill bad-input gates -----
150 if nx_hal_kill(0, 15) != (0 - NX_HAL_BAD_INPUT) { return 56 }
151 if nx_hal_kill(-1, 15) != (0 - NX_HAL_BAD_INPUT) { return 57 }
152 if nx_hal_kill(1, 0) != (0 - NX_HAL_BAD_INPUT) { return 58 }
153 if nx_hal_kill(1, -1) != (0 - NX_HAL_BAD_INPUT) { return 59 }
154 if nx_hal_kill(1, 65) != (0 - NX_HAL_BAD_INPUT) { return 60 }
155
156 // ----- 16. New sealed-enum gates -----
157 if nx_hal_op_is_valid(NX_HAL_OP_SPAWN) != 1 { return 61 }
158 if nx_hal_op_is_valid(NX_HAL_OP_WAIT) != 1 { return 62 }
159 if nx_hal_op_is_valid(NX_HAL_OP_KILL) != 1 { return 63 }
160 if nx_hal_op_is_valid(NX_HAL_OP_N_KINDS) != 0 { return 64 }
161
162 return 0
163}