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;