diff --git a/CMakeLists.txt b/CMakeLists.txt index 6bd5f24a97cf..32f48ba2f005 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -381,6 +381,7 @@ set(ZIG_STAGE2_SOURCES lib/std/Target/avr.zig lib/std/Target/bpf.zig lib/std/Target/hexagon.zig + lib/std/Target/loongarch.zig lib/std/Target/mips.zig lib/std/Target/msp430.zig lib/std/Target/nvptx.zig diff --git a/lib/std/Thread.zig b/lib/std/Thread.zig index 224a3097300b..dadf50e5ad53 100644 --- a/lib/std/Thread.zig +++ b/lib/std/Thread.zig @@ -1224,6 +1224,19 @@ const LinuxThreadImpl = struct { [len] "r" (self.mapped.len), : "memory" ), + .loongarch64 => asm volatile ( + \\ or $a0, $zero, %[ptr] + \\ or $a1, $zero, %[len] + \\ ori $a7, $zero, 215 # SYS_munmap + \\ syscall 0 # call munmap + \\ ori $a0, $zero, 0 + \\ ori $a7, $zero, 93 # SYS_exit + \\ syscall 0 # call exit + : + : [ptr] "r" (@intFromPtr(self.mapped.ptr)), + [len] "r" (self.mapped.len), + : "memory" + ), else => |cpu_arch| @compileError("Unsupported linux arch: " ++ @tagName(cpu_arch)), } unreachable; diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 8f3b6a8eccc3..1061b9f24615 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -42,6 +42,7 @@ const arch_bits = switch (native_arch) { .riscv32 => @import("linux/riscv32.zig"), .riscv64 => @import("linux/riscv64.zig"), .sparc64 => @import("linux/sparc64.zig"), + .loongarch64 => @import("linux/loongarch64.zig"), .mips, .mipsel => @import("linux/mips.zig"), .mips64, .mips64el => @import("linux/mips64.zig"), .powerpc, .powerpcle => @import("linux/powerpc.zig"), @@ -196,7 +197,7 @@ pub const MAP = switch (native_arch) { UNINITIALIZED: bool = false, _: u5 = 0, }, - .riscv32, .riscv64 => packed struct(u32) { + .riscv32, .riscv64, .loongarch64 => packed struct(u32) { TYPE: MAP_TYPE, FIXED: bool = false, ANONYMOUS: bool = false, @@ -301,7 +302,7 @@ pub const O = switch (native_arch) { TMPFILE: bool = false, _: u9 = 0, }, - .x86, .riscv32, .riscv64 => packed struct(u32) { + .x86, .riscv32, .riscv64, .loongarch64 => packed struct(u32) { ACCMODE: ACCMODE = .RDONLY, _2: u4 = 0, CREAT: bool = false, diff --git a/lib/std/os/linux/loongarch64.zig b/lib/std/os/linux/loongarch64.zig new file mode 100644 index 000000000000..83cabcf1d559 --- /dev/null +++ b/lib/std/os/linux/loongarch64.zig @@ -0,0 +1,203 @@ +const std = @import("../../std.zig"); +const linux = std.os.linux; +const SYS = linux.SYS; +const iovec = std.os.iovec; +const uid_t = linux.uid_t; +const gid_t = linux.gid_t; +const stack_t = linux.stack_t; +const sigset_t = linux.sigset_t; + +pub fn syscall0(number: SYS) usize { + return asm volatile ( + \\ syscall 0 + : [ret] "={$r4}" (-> usize), + : [number] "{$r11}" (@intFromEnum(number)), + : "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8", "memory" + ); +} + +pub fn syscall1(number: SYS, arg1: usize) usize { + return asm volatile ( + \\ syscall 0 + : [ret] "={$r4}" (-> usize), + : [number] "{$r11}" (@intFromEnum(number)), + [arg1] "{$r4}" (arg1), + : "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8", "memory" + ); +} + +pub fn syscall2(number: SYS, arg1: usize, arg2: usize) usize { + return asm volatile ( + \\ syscall 0 + : [ret] "={$r4}" (-> usize), + : [number] "{$r11}" (@intFromEnum(number)), + [arg1] "{$r4}" (arg1), + [arg2] "{$r5}" (arg2), + : "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8", "memory" + ); +} + +pub fn syscall3(number: SYS, arg1: usize, arg2: usize, arg3: usize) usize { + return asm volatile ( + \\ syscall 0 + : [ret] "={$r4}" (-> usize), + : [number] "{$r11}" (@intFromEnum(number)), + [arg1] "{$r4}" (arg1), + [arg2] "{$r5}" (arg2), + [arg3] "{$r6}" (arg3), + : "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8", "memory" + ); +} + +pub fn syscall4(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize { + return asm volatile ( + \\ syscall 0 + : [ret] "={$r4}" (-> usize), + : [number] "{$r11}" (@intFromEnum(number)), + [arg1] "{$r4}" (arg1), + [arg2] "{$r5}" (arg2), + [arg3] "{$r6}" (arg3), + [arg4] "{$r7}" (arg4), + : "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8", "memory" + ); +} + +pub fn syscall5(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) usize { + return asm volatile ( + \\ syscall 0 + : [ret] "={$r4}" (-> usize), + : [number] "{$r11}" (@intFromEnum(number)), + [arg1] "{$r4}" (arg1), + [arg2] "{$r5}" (arg2), + [arg3] "{$r6}" (arg3), + [arg4] "{$r7}" (arg4), + [arg5] "{$r8}" (arg5), + : "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8", "memory" + ); +} + +pub fn syscall6( + number: SYS, + arg1: usize, + arg2: usize, + arg3: usize, + arg4: usize, + arg5: usize, + arg6: usize, +) usize { + return asm volatile ( + \\ syscall 0 + : [ret] "={$r4}" (-> usize), + : [number] "{$r11}" (@intFromEnum(number)), + [arg1] "{$r4}" (arg1), + [arg2] "{$r5}" (arg2), + [arg3] "{$r6}" (arg3), + [arg4] "{$r7}" (arg4), + [arg5] "{$r8}" (arg5), + [arg6] "{$r9}" (arg6), + : "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8", "memory" + ); +} + +pub fn clone() callconv(.Naked) usize { + // __clone(func, stack, flags, arg, ptid, tls, ctid) + // a0, a1, a2, a3, a4, a5, a6 + // sys_clone(flags, stack, ptid, ctid, tls) + // a0, a1, a2, a3, a4 + asm volatile ( + \\ bstrins.d $a1, $zero, 3, 0 # stack to 16 align + \\ + \\ # Save function pointer and argument pointer on new thread stack + \\ addi.d $a1, $a1, -16 + \\ st.d $a0, $a1, 0 # save function pointer + \\ st.d $a3, $a1, 8 # save argument pointer + \\ or $a0, $a2, $zero + \\ or $a2, $a4, $zero + \\ or $a3, $a6, $zero + \\ or $a4, $a5, $zero + \\ ori $a7, $zero, 220 # SYS_clone + \\ syscall 0 # call clone + \\ + \\ beqz $a0, 1f # whether child process + \\ jirl $zero, $ra, 0 # parent process return + \\1: + \\ ld.d $t8, $sp, 0 # function pointer + \\ ld.d $a0, $sp, 8 # argument pointer + \\ jirl $ra, $t8, 0 # call the user's function + \\ ori $a7, $zero, 93 # SYS_exit + \\ syscall 0 # child process exit + ); +} + +pub const restore = restore_rt; + +pub fn restore_rt() callconv(.Naked) noreturn { + asm volatile ( + \\ or $a7, $zero, %[number] + \\ syscall 0 + : + : [number] "r" (@intFromEnum(SYS.rt_sigreturn)), + : "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8", "memory" + ); +} + +pub const blksize_t = i32; +pub const nlink_t = u32; +pub const time_t = i64; +pub const mode_t = u32; +pub const off_t = i64; +pub const ino_t = u64; +pub const dev_t = u32; +pub const blkcnt_t = i64; + +pub const timeval = extern struct { + tv_sec: time_t, + tv_usec: i64, +}; + +pub const F = struct { + pub const DUPFD = 0; + pub const GETFD = 1; + pub const SETFD = 2; + pub const GETFL = 3; + pub const SETFL = 4; + pub const GETLK = 5; + pub const SETLK = 6; + pub const SETLKW = 7; + pub const SETOWN = 8; + pub const GETOWN = 9; + pub const SETSIG = 10; + pub const GETSIG = 11; + + pub const RDLCK = 0; + pub const WRLCK = 1; + pub const UNLCK = 2; + + pub const SETOWN_EX = 15; + pub const GETOWN_EX = 16; + + pub const GETOWNER_UIDS = 17; +}; + +pub const VDSO = struct { + pub const CGT_SYM = "__vdso_clock_gettime"; + pub const CGT_VER = "LINUX_5.10"; +}; + +pub const mcontext_t = extern struct { + pc: u64, + regs: [32]u64, + flags: u32, + extcontext: [0]u64 align(16), +}; + +pub const ucontext_t = extern struct { + flags: c_ulong, + link: ?*ucontext_t, + stack: stack_t, + sigmask: sigset_t, + _pad: [1024 / 8 - @sizeOf(sigset_t)]u8, + mcontext: mcontext_t, +}; + +pub const Elf_Symndx = u32;