| ... | ... | @@ -1146,6 +1146,13 @@ const LinuxThreadImpl = struct { |
| 1146 | 1146 | parent_tid: i32 = undefined, |
| 1147 | 1147 | mapped: []align(std.heap.page_size_min) u8, |
| 1148 | 1148 | |
| 1149 | // On SPARC, the kernel needs to be able to restore the current register window from the |
| 1150 | // stack when returning from a syscall. That presents a bit of a problem in `freeAndExit` |
| 1151 | // since we're deallocating the stack! The good news is that, since we do not care about |
| 1152 | // the contents of the incoming and local registers at that point, we can just tell the |
| 1153 | // kernel that our stack is this undefined global buffer. |
| 1154 | var sparc_exit_stack: [192]u8 align(16) = undefined; |
| 1155 | |
| 1149 | 1156 | /// Calls `munmap(mapped.ptr, mapped.len)` then `exit(1)` without touching the stack (which lives in `mapped.ptr`). |
| 1150 | 1157 | /// Ported over from musl libc's pthread detached implementation: |
| 1151 | 1158 | /// https://github.com/ifduyue/musl/search?q=__unmapself |
| ... | ... | @@ -1365,51 +1372,39 @@ const LinuxThreadImpl = struct { |
| 1365 | 1372 | [len] "{r5}" (self.mapped.len), |
| 1366 | 1373 | ), |
| 1367 | 1374 | .sparc => asm volatile ( |
| 1368 | | \\ # See sparc64 comments below. |
| 1369 | | \\ 1: |
| 1370 | | \\ cmp %%fp, 0 |
| 1371 | | \\ beq 2f |
| 1372 | | \\ nop |
| 1373 | | \\ ba 1b |
| 1374 | | \\ restore |
| 1375 | | \\ 2: |
| 1376 | | \\ mov %%g1, %%o0 // ptr |
| 1377 | | \\ mov %%g2, %%o1 // len |
| 1378 | | \\ mov 73, %%g1 // SYS_munmap |
| 1379 | | \\ t 0x3 // ST_FLUSH_WINDOWS |
| 1380 | | \\ t 0x10 |
| 1381 | | \\ mov 1, %%g1 // SYS_exit |
| 1382 | | \\ mov 0, %%o0 |
| 1383 | | \\ t 0x10 |
| 1375 | \\ // See sparc64 comments below. |
| 1376 | \\ t 0x3 // ST_FLUSH_WINDOWS |
| 1377 | \\ mov %%g3, %%sp |
| 1378 | \\ mov %%g1, %%o0 |
| 1379 | \\ mov %%g2, %%o1 |
| 1380 | \\ mov 73, %%g1 // SYS_munmap |
| 1381 | \\ t 0x10 |
| 1382 | \\ mov 1, %%g1 // SYS_exit |
| 1383 | \\ mov 0, %%o0 |
| 1384 | \\ t 0x10 |
| 1384 | 1385 | : |
| 1385 | 1386 | : [ptr] "{g1}" (@intFromPtr(self.mapped.ptr)), |
| 1386 | 1387 | [len] "{g2}" (self.mapped.len), |
| 1388 | [stack] "{g3}" (&sparc_exit_stack), |
| 1387 | 1389 | : .{ .memory = true }), |
| 1388 | 1390 | .sparc64 => asm volatile ( |
| 1389 | | \\ # SPARCs really don't like it when active stack frames |
| 1390 | | \\ # is unmapped (it will result in a segfault), so we |
| 1391 | | \\ # force-deactivate it by running `restore` until |
| 1392 | | \\ # all frames are cleared. |
| 1393 | | \\ 1: |
| 1394 | | \\ cmp %%fp, 0 |
| 1395 | | \\ beq 2f |
| 1396 | | \\ nop |
| 1397 | | \\ ba 1b |
| 1398 | | \\ restore |
| 1399 | | \\ 2: |
| 1400 | | \\ mov %%g1, %%o0 // ptr |
| 1401 | | \\ mov %%g2, %%o1 // len |
| 1402 | | \\ mov 73, %%g1 // SYS_munmap |
| 1403 | | \\ # Flush register window contents to prevent background |
| 1404 | | \\ # memory access before unmapping the stack. |
| 1405 | | \\ flushw |
| 1406 | | \\ t 0x6d |
| 1407 | | \\ mov 1, %%g1 // SYS_exit |
| 1408 | | \\ mov 0, %%o0 |
| 1409 | | \\ t 0x6d |
| 1391 | \\ // Ensure that the kernel only has to flush the current register window. |
| 1392 | \\ flushw |
| 1393 | \\ // Set up a fake stack for the syscall to restore l/i registers from. Local |
| 1394 | \\ // and incoming registers must be treated as effectively garbage past this |
| 1395 | \\ // instruction! |
| 1396 | \\ sub %%g3, 2047, %%sp |
| 1397 | \\ mov %%g1, %%o0 |
| 1398 | \\ mov %%g2, %%o1 |
| 1399 | \\ mov 73, %%g1 // SYS_munmap |
| 1400 | \\ t 0x6d |
| 1401 | \\ mov 1, %%g1 // SYS_exit |
| 1402 | \\ mov 0, %%o0 |
| 1403 | \\ t 0x6d |
| 1410 | 1404 | : |
| 1411 | 1405 | : [ptr] "{g1}" (@intFromPtr(self.mapped.ptr)), |
| 1412 | 1406 | [len] "{g2}" (self.mapped.len), |
| 1407 | [stack] "{g3}" (&sparc_exit_stack), |
| 1413 | 1408 | : .{ .memory = true }), |
| 1414 | 1409 | .loongarch32, .loongarch64 => asm volatile ( |
| 1415 | 1410 | \\ ori $a7, $zero, 215 # SYS_munmap |