authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-08-01 19:12:36+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-08-01 19:12:36+02:00
logdf5bbb5b95137384384a758145f6eedcca51867c
tree37b34ab6785ddd58152da86a2d56f9f37236bd06
parentf212e3716b7f687d552fdad5f15cd1f736039910
parentbcf65eb51085c0fa1a9380172cdea55811d9fe97
signaturebadge-check Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM

Merge branch 'sparc-fixes'


8 files changed, 49 insertions(+), 57 deletions(-)

lib/std/Io/RwLock.zig-2
...@@ -284,8 +284,6 @@ test "concurrent access" {...@@ -284,8 +284,6 @@ test "concurrent access" {
284}284}
285285
286test "lock canceling" {286test "lock canceling" {
287 if (builtin.cpu.arch.isSPARC() and builtin.os.tag == .linux) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/35347
288
289 const io = testing.io;287 const io = testing.io;
290288
291 var rl: Io.RwLock = .init;289 var rl: Io.RwLock = .init;
lib/std/Io/Threaded/test.zig-2
...@@ -149,8 +149,6 @@ test "async with array return type" {...@@ -149,8 +149,6 @@ test "async with array return type" {
149}149}
150150
151test "cancel blocked read from pipe" {151test "cancel blocked read from pipe" {
152 if (builtin.cpu.arch.isSPARC() and builtin.os.tag == .linux) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/35347
153
154 const global = struct {152 const global = struct {
155 fn readFromPipe(io: Io, pipe: Io.File) !void {153 fn readFromPipe(io: Io, pipe: Io.File) !void {
156 var buf: [1]u8 = undefined;154 var buf: [1]u8 = undefined;
lib/std/Io/net/test.zig-2
...@@ -356,8 +356,6 @@ test "decompress compressed DNS name" {...@@ -356,8 +356,6 @@ test "decompress compressed DNS name" {
356}356}
357357
358test "cancel accept" {358test "cancel accept" {
359 if (builtin.cpu.arch.isSPARC() and builtin.os.tag == .linux) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/35347
360
361 const io = testing.io;359 const io = testing.io;
362 const localhost: net.IpAddress = .{ .ip4 = .loopback(0) };360 const localhost: net.IpAddress = .{ .ip4 = .loopback(0) };
363361
lib/std/Io/test.zig-4
...@@ -232,8 +232,6 @@ fn count(a: usize, b: usize, result: *usize) void {...@@ -232,8 +232,6 @@ fn count(a: usize, b: usize, result: *usize) void {
232}232}
233233
234test "Group.cancel" {234test "Group.cancel" {
235 if (builtin.cpu.arch.isSPARC() and builtin.os.tag == .linux) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/35347
236
237 const global = struct {235 const global = struct {
238 fn sleep(io: Io, result: *usize) Io.Cancelable!void {236 fn sleep(io: Io, result: *usize) Io.Cancelable!void {
239 defer result.* = 1;237 defer result.* = 1;
...@@ -326,8 +324,6 @@ test "Group materializes error.Cancel" {...@@ -326,8 +324,6 @@ test "Group materializes error.Cancel" {
326}324}
327325
328test "Group task receives cancelation unknowingly" {326test "Group task receives cancelation unknowingly" {
329 if (builtin.cpu.arch.isSPARC() and builtin.os.tag == .linux) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/35347
330
331 const S = struct {327 const S = struct {
332 io: Io,328 io: Io,
333 err: ?Io.Cancelable!void,329 err: ?Io.Cancelable!void,
lib/std/Thread.zig+32-37
...@@ -1146,6 +1146,13 @@ const LinuxThreadImpl = struct {...@@ -1146,6 +1146,13 @@ const LinuxThreadImpl = struct {
1146 parent_tid: i32 = undefined,1146 parent_tid: i32 = undefined,
1147 mapped: []align(std.heap.page_size_min) u8,1147 mapped: []align(std.heap.page_size_min) u8,
11481148
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 /// Calls `munmap(mapped.ptr, mapped.len)` then `exit(1)` without touching the stack (which lives in `mapped.ptr`).1156 /// Calls `munmap(mapped.ptr, mapped.len)` then `exit(1)` without touching the stack (which lives in `mapped.ptr`).
1150 /// Ported over from musl libc's pthread detached implementation:1157 /// Ported over from musl libc's pthread detached implementation:
1151 /// https://github.com/ifduyue/musl/search?q=__unmapself1158 /// https://github.com/ifduyue/musl/search?q=__unmapself
...@@ -1365,51 +1372,39 @@ const LinuxThreadImpl = struct {...@@ -1365,51 +1372,39 @@ const LinuxThreadImpl = struct {
1365 [len] "{r5}" (self.mapped.len),1372 [len] "{r5}" (self.mapped.len),
1366 ),1373 ),
1367 .sparc => asm volatile (1374 .sparc => asm volatile (
1368 \\ # See sparc64 comments below.1375 \\ // See sparc64 comments below.
1369 \\ 1:1376 \\ t 0x3 // ST_FLUSH_WINDOWS
1370 \\ cmp %%fp, 01377 \\ mov %%g3, %%sp
1371 \\ beq 2f1378 \\ mov %%g1, %%o0
1372 \\ nop1379 \\ mov %%g2, %%o1
1373 \\ ba 1b1380 \\ mov 73, %%g1 // SYS_munmap
1374 \\ restore1381 \\ t 0x10
1375 \\ 2:1382 \\ mov 1, %%g1 // SYS_exit
1376 \\ mov %%g1, %%o0 // ptr1383 \\ mov 0, %%o0
1377 \\ mov %%g2, %%o1 // len1384 \\ t 0x10
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
1384 :1385 :
1385 : [ptr] "{g1}" (@intFromPtr(self.mapped.ptr)),1386 : [ptr] "{g1}" (@intFromPtr(self.mapped.ptr)),
1386 [len] "{g2}" (self.mapped.len),1387 [len] "{g2}" (self.mapped.len),
1388 [stack] "{g3}" (&sparc_exit_stack),
1387 : .{ .memory = true }),1389 : .{ .memory = true }),
1388 .sparc64 => asm volatile (1390 .sparc64 => asm volatile (
1389 \\ # SPARCs really don't like it when active stack frames1391 \\ // Ensure that the kernel only has to flush the current register window.
1390 \\ # is unmapped (it will result in a segfault), so we1392 \\ flushw
1391 \\ # force-deactivate it by running `restore` until1393 \\ // Set up a fake stack for the syscall to restore l/i registers from. Local
1392 \\ # all frames are cleared.1394 \\ // and incoming registers must be treated as effectively garbage past this
1393 \\ 1:1395 \\ // instruction!
1394 \\ cmp %%fp, 01396 \\ sub %%g3, 2047, %%sp
1395 \\ beq 2f1397 \\ mov %%g1, %%o0
1396 \\ nop1398 \\ mov %%g2, %%o1
1397 \\ ba 1b1399 \\ mov 73, %%g1 // SYS_munmap
1398 \\ restore1400 \\ t 0x6d
1399 \\ 2:1401 \\ mov 1, %%g1 // SYS_exit
1400 \\ mov %%g1, %%o0 // ptr1402 \\ mov 0, %%o0
1401 \\ mov %%g2, %%o1 // len1403 \\ t 0x6d
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
1410 :1404 :
1411 : [ptr] "{g1}" (@intFromPtr(self.mapped.ptr)),1405 : [ptr] "{g1}" (@intFromPtr(self.mapped.ptr)),
1412 [len] "{g2}" (self.mapped.len),1406 [len] "{g2}" (self.mapped.len),
1407 [stack] "{g3}" (&sparc_exit_stack),
1413 : .{ .memory = true }),1408 : .{ .memory = true }),
1414 .loongarch32, .loongarch64 => asm volatile (1409 .loongarch32, .loongarch64 => asm volatile (
1415 \\ ori $a7, $zero, 215 # SYS_munmap1410 \\ ori $a7, $zero, 215 # SYS_munmap
lib/std/heap/PageAllocator.zig+1
...@@ -24,6 +24,7 @@ pub const vtable: Allocator.VTable = .{...@@ -24,6 +24,7 @@ pub const vtable: Allocator.VTable = .{
24/// that don't provide a hint (for security reasons, but it serves our needs24/// that don't provide a hint (for security reasons, but it serves our needs
25/// too).25/// too).
26const enable_hints = switch (builtin.target.os.tag) {26const enable_hints = switch (builtin.target.os.tag) {
27 .linux => !builtin.target.cpu.arch.isSPARC(), // https://bugzilla.kernel.org/show_bug.cgi?id=221820
27 .openbsd => false,28 .openbsd => false,
28 else => true,29 else => true,
29};30};
lib/std/os/linux/sparc.zig+8-5
...@@ -260,13 +260,16 @@ pub fn clone() callconv(.naked) u32 {...@@ -260,13 +260,16 @@ pub fn clone() callconv(.naked) u32 {
260260
261pub const restore = restore_rt;261pub const restore = restore_rt;
262262
263// Need to use C ABI here instead of naked263pub fn restore_rt() callconv(.naked) noreturn {
264// to prevent an infinite loop when calling rt_sigreturn.264 asm volatile (
265pub fn restore_rt() callconv(.c) void {265 \\ nop
266 return asm volatile ("t 0x10"266 \\ nop
267 );
268 asm volatile (
269 \\ t 0x10
267 :270 :
268 : [number] "{g1}" (@backingInt(SYS.rt_sigreturn)),271 : [number] "{g1}" (@backingInt(SYS.rt_sigreturn)),
269 : .{ .memory = true, .xcc = true, .o0 = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true });272 );
270}273}
271274
272pub const VDSO = struct {275pub const VDSO = struct {
lib/std/os/linux/sparc64.zig+8-5
...@@ -259,13 +259,16 @@ pub fn clone() callconv(.naked) u64 {...@@ -259,13 +259,16 @@ pub fn clone() callconv(.naked) u64 {
259259
260pub const restore = restore_rt;260pub const restore = restore_rt;
261261
262// Need to use C ABI here instead of naked262pub fn restore_rt() callconv(.naked) noreturn {
263// to prevent an infinite loop when calling rt_sigreturn.263 asm volatile (
264pub fn restore_rt() callconv(.c) void {264 \\ nop
265 return asm volatile ("t 0x6d"265 \\ nop
266 );
267 asm volatile (
268 \\ t 0x6d
266 :269 :
267 : [number] "{g1}" (@backingInt(SYS.rt_sigreturn)),270 : [number] "{g1}" (@backingInt(SYS.rt_sigreturn)),
268 : .{ .memory = true, .xcc = true, .o0 = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true });271 );
269}272}
270273
271pub const VDSO = struct {274pub const VDSO = struct {