|
| 1 | +/* vim: set sw=2 expandtab tw=80: */ |
| 2 | + |
| 3 | +// Allow _start to go undeclared |
| 4 | +#pragma GCC diagnostic ignored "-Wmissing-declarations" |
| 5 | +#pragma GCC diagnostic ignored "-Wmissing-prototypes" |
| 6 | + |
| 7 | +__attribute__ ((section(".start"), used)) |
| 8 | +__attribute__ ((naked)) |
| 9 | +__attribute__ ((noreturn)) |
| 10 | +void _start(void* app_start __attribute__((unused)), |
| 11 | + void* mem_start __attribute__((unused)), |
| 12 | + void* memory_len __attribute__((unused)), |
| 13 | + void* app_heap_break __attribute__((unused))) { |
| 14 | + __asm__ volatile ( |
| 15 | + // This minimal test evaluates whether memory protection is configured |
| 16 | + // as-expected. It uses the low-level debug (LLD) mechanism to print |
| 17 | + // incremental numbers as it progresses, but provides no other output as it is |
| 18 | + // all assembly to precisely control behavior (and never sets up a stack |
| 19 | + // beyond the minimal one provided by the kernel). |
| 20 | + |
| 21 | + // First, save all the variables in hardware-stacked, callee-save registers |
| 22 | +#if defined(__thumb__) |
| 23 | + "movs r4, r0\n" // r4 = app_start |
| 24 | + "movs r5, r1\n" // r5 = mem_start |
| 25 | + "movs r6, r2\n" // r6 = memory_len |
| 26 | + "movs r7, r3\n" // r7 = app_heap_break |
| 27 | + "mov r8, sp\n" // r8 = stack pointer |
| 28 | +#elif defined(__riscv) |
| 29 | + "mv s0, a0\n" // s0 = app_start |
| 30 | + "mv s1, a1\n" // s1 = mem_start |
| 31 | + "mv s2, a2\n" // s2 = memory_len |
| 32 | + "mv s3, a3\n" // s3 = app_heap_break |
| 33 | + "mv s4, sp\n" // s4 = stack pointer |
| 34 | +#else |
| 35 | +#error Unknown arch. Note: Subsequent code assumes only two archs. |
| 36 | +#endif |
| 37 | + |
| 38 | + |
| 39 | + // Note that the test has commenced |
| 40 | +#if defined(__thumb__) |
| 41 | + "movs r2, #0\n" // LLD Command 2, Arg 1: Number to print (0) |
| 42 | + "bl lld_print_r2\n" |
| 43 | +#else |
| 44 | + "li a2, 0\n" |
| 45 | + "jal ra, lld_print_a2\n" |
| 46 | +#endif |
| 47 | + |
| 48 | + |
| 49 | + // Print all of the interesting starting values |
| 50 | + // 1. app_start: where app starts in flash |
| 51 | + // 2. mem_start: where app-accesible RAM starts |
| 52 | + // 3. memory_len: *total* length of app allocation (incl grant) |
| 53 | + // 4. app_heap_break: max app-accesible address |
| 54 | + // 5. the initial stack pointer when process was created |
| 55 | + // 6. the current stack pointer (should be same as 5) |
| 56 | +#if defined(__thumb__) |
| 57 | + "movs r2, #1\n" |
| 58 | + "movs r3, r4\n" |
| 59 | + "bl lld_print_r2r3\n" |
| 60 | + "movs r2, #2\n" |
| 61 | + "movs r3, r5\n" |
| 62 | + "bl lld_print_r2r3\n" |
| 63 | + "movs r2, #3\n" |
| 64 | + "movs r3, r6\n" |
| 65 | + "bl lld_print_r2r3\n" |
| 66 | + "movs r2, #4\n" |
| 67 | + "movs r3, r7\n" |
| 68 | + "bl lld_print_r2r3\n" |
| 69 | + "movs r2, #5\n" |
| 70 | + "movs r3, r8\n" |
| 71 | + "bl lld_print_r2r3\n" |
| 72 | + "movs r2, #6\n" |
| 73 | + "mov r3, sp\n" |
| 74 | +#else |
| 75 | + "li a2, 1\n" |
| 76 | + "mv a3, s0\n" |
| 77 | + "jal ra, lld_print_a2a3\n" |
| 78 | + "li a2, 2\n" |
| 79 | + "mv a3, s1\n" |
| 80 | + "jal ra, lld_print_a2a3\n" |
| 81 | + "li a2, 3\n" |
| 82 | + "mv a3, s2\n" |
| 83 | + "jal ra, lld_print_a2a3\n" |
| 84 | + "li a2, 4\n" |
| 85 | + "mv a3, s3\n" |
| 86 | + "jal ra, lld_print_a2a3\n" |
| 87 | + "li a2, 5\n" |
| 88 | + "mv a3, s4\n" |
| 89 | + "jal ra, lld_print_a2a3\n" |
| 90 | + "li a2, 6\n" |
| 91 | + "mv a3, sp\n" |
| 92 | + "jal ra, lld_print_a2a3\n" |
| 93 | +#endif |
| 94 | + |
| 95 | + |
| 96 | + // 7. Read all app-accessible memory: [mem_start , app_heap_break) |
| 97 | + // Assumed invariant: app_heap_break >= [mem_start + 4] |
| 98 | +#if defined(__thumb__) |
| 99 | + "movs r2, #7\n" |
| 100 | + "bl lld_print_r2\n" |
| 101 | + |
| 102 | + "movs r3, r5\n" // r3 (loop var) = mem_start |
| 103 | + "test_7_loop:\n" |
| 104 | + "ldr r2, [r3]\n" // read *r3 |
| 105 | + "add r3, r3, #4\n" // increment r3=r3+4 |
| 106 | + "cmp r3, r7\n" |
| 107 | + "ble test_7_loop\n" // if r3 < app_heap_break[r7], loop |
| 108 | +#else |
| 109 | + "li a2, 7\n" |
| 110 | + "jal ra, lld_print_a2\n" |
| 111 | + |
| 112 | + "mv t1, s1\n" |
| 113 | + "test_7_loop:\n" |
| 114 | + "lw t0, 0(t1)\n" |
| 115 | + "addi t1, t1, 4\n" |
| 116 | + "blt t1, s3, test_7_loop\n" |
| 117 | +#endif |
| 118 | + |
| 119 | + |
| 120 | + // 8. Write all app-accessible memory: [mem_start , app_heap_break) |
| 121 | + // Assumed invariant: app_heap_break >= [mem_start + 4] |
| 122 | +#if defined(__thumb__) |
| 123 | + "movs r2, #8\n" |
| 124 | + "bl lld_print_r2\n" |
| 125 | + |
| 126 | + "movs r3, r5\n" // r3 (loop var) = mem_start |
| 127 | + "test_8_loop:\n" |
| 128 | + "str r2, [r3]\n" // read *r3 |
| 129 | + "add r3, r3, #4\n" // increment r3=r3+4 |
| 130 | + "cmp r3, r7\n" |
| 131 | + "ble test_8_loop\n" // if r3 < app_heap_break[r7], loop |
| 132 | +#else |
| 133 | + "li a2, 8\n" |
| 134 | + "jal ra, lld_print_a2\n" |
| 135 | + |
| 136 | + "mv t1, s1\n" |
| 137 | + "test_8_loop:\n" |
| 138 | + "sw t0, 0(t1)\n" |
| 139 | + "addi t1, t1, 4\n" |
| 140 | + "blt t1, s3, test_8_loop\n" |
| 141 | +#endif |
| 142 | + |
| 143 | + |
| 144 | + // 9. Read all app-accessible flash: [app_start , memop(6)) |
| 145 | + // Flash length is not a startup argument, so we must use |
| 146 | + // memop(6) to get the end of app flash first. |
| 147 | +#if defined(__thumb__) |
| 148 | + "movs r2, #9\n" |
| 149 | + "bl lld_print_r2\n" |
| 150 | + |
| 151 | + "movs r0, #6\n" |
| 152 | + "movs r1, #0\n" |
| 153 | + "svc 5\n" |
| 154 | + "movs r11, r1\n" |
| 155 | + |
| 156 | + "movs r2, #9\n" |
| 157 | + "movs r3, r11\n" |
| 158 | + "bl lld_print_r2r3\n" |
| 159 | + |
| 160 | + "movs r3, r4\n" // r3 (loop var) = app_start |
| 161 | + "test_9_loop:\n" |
| 162 | + "ldr r2, [r3]\n" // read *r3 |
| 163 | + "add r3, r3, #4\n" // increment r3=r3+4 |
| 164 | + "cmp r3, r11\n" |
| 165 | + "ble test_9_loop\n" // if r3 < memop(6)[r11], loop |
| 166 | +#else |
| 167 | + "li a2, 9\n" |
| 168 | + "jal ra, lld_print_a2\n" |
| 169 | + |
| 170 | + "li a0, 6\n" |
| 171 | + "li a1, 0\n" |
| 172 | + "li a4, 5\n" |
| 173 | + "ecall\n" |
| 174 | + "mv t2, a1\n" |
| 175 | + |
| 176 | + "li a2, 9\n" |
| 177 | + "mv a3, t2\n" |
| 178 | + "jal ra, lld_print_a2a3\n" |
| 179 | + |
| 180 | + "mv t1, s0\n" |
| 181 | + "test_9_loop:\n" |
| 182 | + "lw t0, 0(t1)\n" |
| 183 | + "addi t1, t1, 4\n" |
| 184 | + "blt t1, t2, test_9_loop\n" |
| 185 | +#endif |
| 186 | + |
| 187 | + |
| 188 | + // 10. Return success |
| 189 | + // Indicate all tests are done and exit. |
| 190 | +#if defined(__thumb__) |
| 191 | + "movs r2, #10\n" |
| 192 | + "bl lld_print_r2\n" |
| 193 | + |
| 194 | + "movs r0, #0\n" // exit-terminate |
| 195 | + "movs r1, #0\n" // completion: sucess |
| 196 | + "svc 6\n" // Exit syscall |
| 197 | +#else |
| 198 | + "li a2, 10\n" |
| 199 | + "jal ra, lld_print_a2\n" |
| 200 | + |
| 201 | + "li a0, 0\n" |
| 202 | + "li a1, 0\n" |
| 203 | + "li a4, 6\n" |
| 204 | + "ecall\n" |
| 205 | +#endif |
| 206 | + |
| 207 | + |
| 208 | + // -1. Unreachable/error |
| 209 | +#if defined(__thumb__) |
| 210 | + "loop_error:\n" |
| 211 | + "movs r2, #0\n" |
| 212 | + "sub r2, r2, #1\n" |
| 213 | + "bl lld_print_r2\n" |
| 214 | + "b loop_error\n" |
| 215 | +#else |
| 216 | + "loop_error:\n" |
| 217 | + "li a2, -1\n" |
| 218 | + "jal ra, lld_print_a2\n" |
| 219 | + "j loop_error\n" |
| 220 | +#endif |
| 221 | + |
| 222 | + |
| 223 | + |
| 224 | + // Function to invoke LLD print of one number |
| 225 | + // r2/a2 must be set to desired number |
| 226 | + // may clobber any caller-save b/c of syscall rules |
| 227 | +#if defined(__thumb__) |
| 228 | + "lld_print_r2:\n" |
| 229 | + "movs r0, #8\n" // LLD is driver number 8 |
| 230 | + "movs r1, #2\n" // LLD Command 2: Print one number |
| 231 | + "svc 2\n" // Invoke Command syscall |
| 232 | + "bx lr\n" // Return. |
| 233 | +#else |
| 234 | + "lld_print_a2:\n" |
| 235 | + "li a0, 8\n" // LLD is driver number 8 |
| 236 | + "li a1, 2\n" // LLD Command 2: Print one number |
| 237 | + "li a4, 2\n" // Command is syscall 2 |
| 238 | + "ecall\n" // Invoke Command syscall |
| 239 | + "jr ra\n" // Return. |
| 240 | +#endif |
| 241 | + |
| 242 | + // Function to invoke LLD print of two numbers |
| 243 | + // r2,r3/a2,a3 must be set to desired number |
| 244 | + // may clobber any caller-save b/c of syscall rules |
| 245 | +#if defined(__thumb__) |
| 246 | + "lld_print_r2r3:\n" |
| 247 | + "movs r0, #8\n" // LLD is driver number 8 |
| 248 | + "movs r1, #3\n" // LLD Command 3: Print one number |
| 249 | + "svc 2\n" // Invoke Command syscall |
| 250 | + "bx lr\n" // Return. |
| 251 | +#else |
| 252 | + "lld_print_a2a3:\n" |
| 253 | + "li a0, 8\n" // LLD is driver number 8 |
| 254 | + "li a1, 3\n" // LLD Command 3: Print one number |
| 255 | + "li a4, 2\n" // Command is syscall 2 |
| 256 | + "ecall\n" // Invoke Command syscall |
| 257 | + "jr ra\n" // Return. |
| 258 | +#endif |
| 259 | + ); |
| 260 | +} |
0 commit comments