diff --git a/lib/std/Thread.zig b/lib/std/Thread.zig index 49161035b49d8d447efa5cd97c58529a0e9729fc..a6ce01442dafb2edb1c23bafd8e4599c6749ddf9 100644 --- a/lib/std/Thread.zig +++ b/lib/std/Thread.zig @@ -1376,7 +1376,7 @@ const LinuxThreadImpl = struct { \\ mov %%g1, %%o0 // ptr \\ mov %%g2, %%o1 // len \\ mov 73, %%g1 // SYS_munmap - \\ t 0x3 # ST_FLUSH_WINDOWS + \\ t 0x3 // ST_FLUSH_WINDOWS \\ t 0x10 \\ mov 1, %%g1 // SYS_exit \\ mov 0, %%o0 diff --git a/lib/std/os.zig b/lib/std/os.zig index fa811ef0601f0c3b150600db8c2a09238beda085..200d4f2e0f9a58e721768ef100dc114380bc9422 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -15,8 +15,6 @@ pub fn targetRequiresLibC(target: *const std.Target) bool { if (target.requiresLibC()) return true; return switch (target.os.tag) { .linux => switch (target.cpu.arch) { - // https://codeberg.org/ziglang/zig/issues/30942 - .csky, // https://codeberg.org/ziglang/zig/issues/30943 .hppa, .hppa64, @@ -26,8 +24,6 @@ pub fn targetRequiresLibC(target: *const std.Target) bool { // https://codeberg.org/ziglang/zig/issues/30946 .sh, .sheb, - // https://codeberg.org/ziglang/zig/issues/30945 - .sparc, => true, else => false, }, diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 8326b406b652defa174a6190f553513e15ca0009..d168d7f5047c0da56ec5626c92bed6b32aa8970a 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -51,6 +51,7 @@ const arch_bits = switch (native_arch) { .riscv32 => @import("linux/riscv32.zig"), .riscv64 => @import("linux/riscv64.zig"), .s390x => @import("linux/s390x.zig"), + .sparc => @import("linux/sparc.zig"), .sparc64 => @import("linux/sparc64.zig"), .x86 => @import("linux/x86.zig"), .x86_64 => switch (builtin.abi) { @@ -223,7 +224,7 @@ pub const MAP = switch (native_arch) { UNINITIALIZED: bool = false, _: u5 = 0, }, - .sparc64 => packed struct(u32) { + .sparc, .sparc64 => packed struct(u32) { TYPE: MAP_TYPE, FIXED: bool = false, ANONYMOUS: bool = false, @@ -444,7 +445,7 @@ pub const O = switch (native_arch) { TMPFILE: bool = false, _23: u9 = 0, }, - .sparc64 => packed struct(u32) { + .sparc, .sparc64 => packed struct(u32) { ACCMODE: ACCMODE = .RDONLY, _2: u1 = 0, APPEND: bool = false, @@ -1994,7 +1995,7 @@ pub const F = struct { const SETLKW = 7; }, }, - .alpha, .sparc64 => struct { + .alpha, .sparc, .sparc64 => struct { const GETLK = 7; const SETLK = 8; const SETLKW = 9; @@ -6585,7 +6586,7 @@ const TFD_TIMER = packed struct(u32) { }; pub const TFD = switch (native_arch) { - .sparc64 => packed struct(u32) { + .sparc, .sparc64 => packed struct(u32) { _0: u14 = 0, NONBLOCK: bool = false, _15: u7 = 0, diff --git a/lib/std/os/linux/sparc.zig b/lib/std/os/linux/sparc.zig new file mode 100644 index 0000000000000000000000000000000000000000..55a3a22596261612a05b3907e11fe9d82228c3f4 --- /dev/null +++ b/lib/std/os/linux/sparc.zig @@ -0,0 +1,277 @@ +const builtin = @import("builtin"); +const std = @import("../../std.zig"); +const SYS = std.os.linux.SYS; + +pub const syscall_arg_t = u32; + +pub fn syscall0( + number: SYS, +) u32 { + return asm volatile ( + \\ t 0x10 + \\ bcc 1f + \\ nop + \\ neg %%o0 + \\1: + : [ret] "={o0}" (-> u32), + : [number] "{g1}" (@intFromEnum(number)), + : .{ .memory = true, .xcc = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true }); +} + +pub fn syscall1( + number: SYS, + arg1: syscall_arg_t, +) u32 { + return asm volatile ( + \\ t 0x10 + \\ bcc 1f + \\ nop + \\ neg %%o0 + \\1: + : [ret] "={o0}" (-> u32), + : [number] "{g1}" (@intFromEnum(number)), + [arg1] "{o0}" (arg1), + : .{ .memory = true, .xcc = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true }); +} + +pub fn syscall2( + number: SYS, + arg1: syscall_arg_t, + arg2: syscall_arg_t, +) u32 { + return asm volatile ( + \\ t 0x10 + \\ bcc 1f + \\ nop + \\ neg %%o0 + \\1: + : [ret] "={o0}" (-> u32), + : [number] "{g1}" (@intFromEnum(number)), + [arg1] "{o0}" (arg1), + [arg2] "{o1}" (arg2), + : .{ .memory = true, .xcc = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true }); +} + +pub fn syscall3( + number: SYS, + arg1: syscall_arg_t, + arg2: syscall_arg_t, + arg3: syscall_arg_t, +) u32 { + return asm volatile ( + \\ t 0x10 + \\ bcc 1f + \\ nop + \\ neg %%o0 + \\1: + : [ret] "={o0}" (-> u32), + : [number] "{g1}" (@intFromEnum(number)), + [arg1] "{o0}" (arg1), + [arg2] "{o1}" (arg2), + [arg3] "{o2}" (arg3), + : .{ .memory = true, .xcc = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true }); +} + +pub fn syscall4( + number: SYS, + arg1: syscall_arg_t, + arg2: syscall_arg_t, + arg3: syscall_arg_t, + arg4: syscall_arg_t, +) u32 { + return asm volatile ( + \\ t 0x10 + \\ bcc 1f + \\ nop + \\ neg %%o0 + \\1: + : [ret] "={o0}" (-> u32), + : [number] "{g1}" (@intFromEnum(number)), + [arg1] "{o0}" (arg1), + [arg2] "{o1}" (arg2), + [arg3] "{o2}" (arg3), + [arg4] "{o3}" (arg4), + : .{ .memory = true, .xcc = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true }); +} + +pub fn syscall5( + number: SYS, + arg1: syscall_arg_t, + arg2: syscall_arg_t, + arg3: syscall_arg_t, + arg4: syscall_arg_t, + arg5: syscall_arg_t, +) u32 { + return asm volatile ( + \\ t 0x10 + \\ bcc 1f + \\ nop + \\ neg %%o0 + \\1: + : [ret] "={o0}" (-> u32), + : [number] "{g1}" (@intFromEnum(number)), + [arg1] "{o0}" (arg1), + [arg2] "{o1}" (arg2), + [arg3] "{o2}" (arg3), + [arg4] "{o3}" (arg4), + [arg5] "{o4}" (arg5), + : .{ .memory = true, .xcc = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true }); +} + +pub fn syscall6( + number: SYS, + arg1: syscall_arg_t, + arg2: syscall_arg_t, + arg3: syscall_arg_t, + arg4: syscall_arg_t, + arg5: syscall_arg_t, + arg6: syscall_arg_t, +) u32 { + return asm volatile ( + \\ t 0x10 + \\ bcc 1f + \\ nop + \\ neg %%o0 + \\1: + : [ret] "={o0}" (-> u32), + : [number] "{g1}" (@intFromEnum(number)), + [arg1] "{o0}" (arg1), + [arg2] "{o1}" (arg2), + [arg3] "{o2}" (arg3), + [arg4] "{o3}" (arg4), + [arg5] "{o4}" (arg5), + [arg6] "{o5}" (arg6), + : .{ .memory = true, .xcc = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true }); +} + +pub fn syscall_pipe( + fd: *[2]std.os.linux.fd_t, +) u32 { + return asm volatile ( + \\ mov %[arg], %%g3 + \\ t 0x10 + \\ bcc 1f + \\ nop + \\ # Return the error code + \\ ba 2f + \\ neg %%o0 + \\1: + \\ st %%o0, [%%g3+0] + \\ st %%o1, [%%g3+4] + \\ clr %%o0 + \\2: + : [ret] "={o0}" (-> u32), + : [number] "{g1}" (@intFromEnum(SYS.pipe)), + [arg] "r" (fd), + : .{ .memory = true, .g3 = true }); +} + +pub fn syscall_fork() u32 { + // Linux/sparc fork() returns two values in %o0 and %o1: + // - On the parent's side, %o0 is the child's PID and %o1 is 0. + // - On the child's side, %o0 is the parent's PID and %o1 is 1. + // We need to clear the child's %o0 so that the return values + // conform to the libc convention. + return asm volatile ( + \\ t 0x10 + \\ bcc 1f + \\ nop + \\ ba 2f + \\ neg %%o0 + \\1: + \\ # Clear the child's %%o0 + \\ dec %%o1 + \\ and %%o1, %%o0, %%o0 + \\2: + : [ret] "={o0}" (-> u32), + : [number] "{g1}" (@intFromEnum(SYS.fork)), + : .{ .memory = true, .xcc = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true }); +} + +pub fn clone() callconv(.naked) u32 { + // __clone(func, stack, flags, arg, ptid, tls, ctid) + // i0, i1, i2, i3, i4, i5, sp + // + // syscall(SYS_clone, flags, stack, ptid, tls, ctid) + // g1 o0, o1, o2, o3, o4 + asm volatile ( + \\ save %%sp, -96, %%sp + \\ + \\ // clone() on SPARC can fail with EFAULT if %%sp points to uncommitted memory, so flush + \\ // all register windows up to this point to ensure that the kernel has enough committed + \\ // memory for its stack frame. + \\ save %%sp, -96, %%sp + \\ t 0x3 + \\ restore + \\ + \\ # Save the func pointer and the arg pointer + \\ mov %%i0, %%g2 + \\ mov %%i3, %%g3 + \\ + \\ # Shuffle the arguments + \\ mov 217, %%g1 // SYS_clone + \\ mov %%i2, %%o0 + \\ + \\ # Align, and add some extra space for the initial frame + \\ and %%i1, -8, %%i1 + \\ sub %%i1, 96 + 2047, %%o1 + \\ + \\ mov %%i4, %%o2 + \\ mov %%i5, %%o3 + \\ ld [%%fp + 92 + 2047], %%o4 + \\ t 0x10 + \\ bcs 1f + \\ nop + \\ # The child pid is returned in o0 while o1 tells if this + \\ # process is the child (=1) or the parent (=0). + \\ tst %%o1 + \\ bne 2f + \\ nop + \\ + \\ # Parent process, return the child pid + \\ mov %%o0, %%i0 + \\ ret + \\ restore + \\ + \\1: + \\ # The syscall failed + \\ sub %%g0, %%o0, %%i0 + \\ ret + \\ restore + \\ + \\2: + \\ # Child process + ); + if (builtin.unwind_tables != .none or !builtin.strip_debug_info) asm volatile ( + \\ .cfi_undefined %%i7 + ); + asm volatile ( + \\ mov %%g0, %%fp + \\ mov %%g0, %%i7 + \\ + \\ # call func(arg) + \\ call %%g2 + \\ mov %%g3, %%o0 + \\ # Exit + \\ mov 1, %%g1 // SYS_exit + \\ t 0x10 + ); +} + +pub const restore = restore_rt; + +// Need to use C ABI here instead of naked +// to prevent an infinite loop when calling rt_sigreturn. +pub fn restore_rt() callconv(.c) void { + return asm volatile ("t 0x10" + : + : [number] "{g1}" (@intFromEnum(SYS.rt_sigreturn)), + : .{ .memory = true, .xcc = true, .o0 = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true }); +} + +pub const VDSO = struct { + pub const CGT_SYM = "__vdso_clock_gettime"; + pub const CGT_VER = "LINUX_2.6"; +}; + +pub const time_t = i32; diff --git a/lib/std/os/linux/sparc64.zig b/lib/std/os/linux/sparc64.zig index dfd7f6c660c12b0178d8a565efffafb331f152d7..fa23ebdb76ce4484f11c0fe5d572b7ffcb9a51be 100644 --- a/lib/std/os/linux/sparc64.zig +++ b/lib/std/os/linux/sparc64.zig @@ -10,9 +10,9 @@ pub fn syscall0( return asm volatile ( \\ t 0x6d \\ bcc,pt %%xcc, 1f - \\ nop + \\ nop \\ neg %%o0 - \\ 1: + \\1: : [ret] "={o0}" (-> u64), : [number] "{g1}" (@intFromEnum(number)), : .{ .memory = true, .xcc = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true }); @@ -25,9 +25,9 @@ pub fn syscall1( return asm volatile ( \\ t 0x6d \\ bcc,pt %%xcc, 1f - \\ nop + \\ nop \\ neg %%o0 - \\ 1: + \\1: : [ret] "={o0}" (-> u64), : [number] "{g1}" (@intFromEnum(number)), [arg1] "{o0}" (arg1), @@ -42,9 +42,9 @@ pub fn syscall2( return asm volatile ( \\ t 0x6d \\ bcc,pt %%xcc, 1f - \\ nop + \\ nop \\ neg %%o0 - \\ 1: + \\1: : [ret] "={o0}" (-> u64), : [number] "{g1}" (@intFromEnum(number)), [arg1] "{o0}" (arg1), @@ -61,9 +61,9 @@ pub fn syscall3( return asm volatile ( \\ t 0x6d \\ bcc,pt %%xcc, 1f - \\ nop + \\ nop \\ neg %%o0 - \\ 1: + \\1: : [ret] "={o0}" (-> u64), : [number] "{g1}" (@intFromEnum(number)), [arg1] "{o0}" (arg1), @@ -82,9 +82,9 @@ pub fn syscall4( return asm volatile ( \\ t 0x6d \\ bcc,pt %%xcc, 1f - \\ nop + \\ nop \\ neg %%o0 - \\ 1: + \\1: : [ret] "={o0}" (-> u64), : [number] "{g1}" (@intFromEnum(number)), [arg1] "{o0}" (arg1), @@ -105,9 +105,9 @@ pub fn syscall5( return asm volatile ( \\ t 0x6d \\ bcc,pt %%xcc, 1f - \\ nop + \\ nop \\ neg %%o0 - \\ 1: + \\1: : [ret] "={o0}" (-> u64), : [number] "{g1}" (@intFromEnum(number)), [arg1] "{o0}" (arg1), @@ -130,9 +130,9 @@ pub fn syscall6( return asm volatile ( \\ t 0x6d \\ bcc,pt %%xcc, 1f - \\ nop + \\ nop \\ neg %%o0 - \\ 1: + \\1: : [ret] "={o0}" (-> u64), : [number] "{g1}" (@intFromEnum(number)), [arg1] "{o0}" (arg1), @@ -151,10 +151,10 @@ pub fn syscall_pipe( \\ mov %[arg], %%g3 \\ t 0x6d \\ bcc,pt %%xcc, 1f - \\ nop + \\ nop \\ # Return the error code \\ ba 2f - \\ neg %%o0 + \\ neg %%o0 \\1: \\ st %%o0, [%%g3+0] \\ st %%o1, [%%g3+4] @@ -175,14 +175,14 @@ pub fn syscall_fork() u64 { return asm volatile ( \\ t 0x6d \\ bcc,pt %%xcc, 1f - \\ nop + \\ nop \\ ba 2f - \\ neg %%o0 - \\ 1: + \\ neg %%o0 + \\1: \\ # Clear the child's %%o0 \\ dec %%o1 \\ and %%o1, %%o0, %%o0 - \\ 2: + \\2: : [ret] "={o0}" (-> u64), : [number] "{g1}" (@intFromEnum(SYS.fork)), : .{ .memory = true, .xcc = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true }); @@ -196,33 +196,48 @@ pub fn clone() callconv(.naked) u64 { // g1 o0, o1, o2, o3, o4 asm volatile ( \\ save %%sp, -192, %%sp + \\ + \\ // clone() on SPARC can fail with EFAULT if %%sp points to uncommitted memory, so flush + \\ // all register windows up to this point to ensure that the kernel has enough committed + \\ // memory for its stack frame. + \\ save %%sp, -192, %%sp + \\ flushw + \\ restore + \\ \\ # Save the func pointer and the arg pointer \\ mov %%i0, %%g2 \\ mov %%i3, %%g3 + \\ \\ # Shuffle the arguments \\ mov 217, %%g1 // SYS_clone \\ mov %%i2, %%o0 - \\ # Add some extra space for the initial frame - \\ sub %%i1, 176 + 2047, %%o1 + \\ + \\ # Align, and add some extra space for the initial frame + \\ and %%i1, -16, %%i1 + \\ sub %%i1, 192 + 2047, %%o1 + \\ \\ mov %%i4, %%o2 \\ mov %%i5, %%o3 - \\ ldx [%%fp + 0x8af], %%o4 + \\ ldx [%%fp + 176 + 2047], %%o4 \\ t 0x6d \\ bcs,pn %%xcc, 1f - \\ nop + \\ nop \\ # The child pid is returned in o0 while o1 tells if this - \\ # process is # the child (=1) or the parent (=0). + \\ # process is the child (=1) or the parent (=0). \\ brnz %%o1, 2f - \\ nop + \\ nop + \\ \\ # Parent process, return the child pid \\ mov %%o0, %%i0 \\ ret - \\ restore + \\ restore + \\ \\1: \\ # The syscall failed \\ sub %%g0, %%o0, %%i0 \\ ret - \\ restore + \\ restore + \\ \\2: \\ # Child process ); @@ -234,9 +249,8 @@ pub fn clone() callconv(.naked) u64 { \\ mov %%g0, %%i7 \\ \\ # call func(arg) - \\ mov %%g0, %%fp \\ call %%g2 - \\ mov %%g3, %%o0 + \\ mov %%g3, %%o0 \\ # Exit \\ mov 1, %%g1 // SYS_exit \\ t 0x6d diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig index 00baeb24e19ed38ac8d0ff5ae7a7e356f4a69ed6..c2ad638832ea8e5944324e98adcd65ec65b6322e 100644 --- a/lib/std/zig/system.zig +++ b/lib/std/zig/system.zig @@ -152,7 +152,7 @@ pub fn getExternalExecutor(io: Io, candidate: *const std.Target, options: GetExt // TODO: Actually check the SuperH version. .sh => "qemu-sh4", .sheb => "qemu-sh4eb", - .sparc => if (candidate.cpu.has(.sparc, .v8plus)) "qemu-sparc32plus" else "qemu-sparc", + .sparc => "qemu-sparc32plus", .thumb => "qemu-arm", .thumbeb => "qemu-armeb", else => "qemu-" ++ @tagName(t),