]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: add support for openbsd/mips64
authorJoel Sing <joel@sing.id.au>
Tue, 25 Aug 2020 08:04:47 +0000 (18:04 +1000)
committerJoel Sing <joel@sing.id.au>
Thu, 29 Oct 2020 08:07:46 +0000 (08:07 +0000)
Update #40995

Change-Id: Ie028dfd87ef8731804567a0501f1f7758e8dd203
Reviewed-on: https://go-review.googlesource.com/c/go/+/250580
Trust: Joel Sing <joel@sing.id.au>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Joel Sing <joel@sing.id.au>

src/runtime/os_openbsd.go
src/runtime/os_openbsd_mips64.go [new file with mode: 0644]
src/runtime/rt0_openbsd_mips64.s [new file with mode: 0644]
src/runtime/signal_mips64x.go
src/runtime/signal_openbsd_mips64.go [new file with mode: 0644]
src/runtime/sys_openbsd_mips64.s [new file with mode: 0644]

index cd3565df5b4b04a313fe8dbce50333ef3b187ec5..d7960f4c91c9580aa9185d190bb67967609b3361 100644 (file)
@@ -236,7 +236,11 @@ func goenvs() {
 // Called to initialize a new m (including the bootstrap m).
 // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
 func mpreinit(mp *m) {
-       mp.gsignal = malg(32 * 1024)
+       gsignalSize := int32(32 * 1024)
+       if GOARCH == "mips64" {
+               gsignalSize = int32(64 * 1024)
+       }
+       mp.gsignal = malg(gsignalSize)
        mp.gsignal.m = mp
 }
 
diff --git a/src/runtime/os_openbsd_mips64.go b/src/runtime/os_openbsd_mips64.go
new file mode 100644 (file)
index 0000000..ae220cd
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+//go:nosplit
+func cputicks() int64 {
+       // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand().
+       // runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
+       return nanotime()
+}
diff --git a/src/runtime/rt0_openbsd_mips64.s b/src/runtime/rt0_openbsd_mips64.s
new file mode 100644 (file)
index 0000000..82a8dfa
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+TEXT _rt0_mips64_openbsd(SB),NOSPLIT,$0
+       JMP     _main<>(SB)
+
+TEXT _rt0_mips64le_openbsd(SB),NOSPLIT,$0
+       JMP     _main<>(SB)
+
+TEXT _main<>(SB),NOSPLIT|NOFRAME,$0
+       // In a statically linked binary, the stack contains argc,
+       // argv as argc string pointers followed by a NULL, envv as a
+       // sequence of string pointers followed by a NULL, and auxv.
+       // There is no TLS base pointer.
+#ifdef GOARCH_mips64
+       MOVW    4(R29), R4 // argc, big-endian ABI places int32 at offset 4
+#else
+       MOVW    0(R29), R4 // argc
+#endif
+       ADDV    $8, R29, R5 // argv
+       JMP     main(SB)
+
+TEXT main(SB),NOSPLIT|NOFRAME,$0
+       // in external linking, glibc jumps to main with argc in R4
+       // and argv in R5
+
+       // initialize REGSB = PC&0xffffffff00000000
+       BGEZAL  R0, 1(PC)
+       SRLV    $32, R31, RSB
+       SLLV    $32, RSB
+
+       MOVV    $runtime·rt0_go(SB), R1
+       JMP     (R1)
index 040c959f0423eb2c1f4ea99c3fbc709c0d997a52..2a347ff4cb8bd6ce6ba871344f0767e32e3cbe73 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build linux
+// +build linux openbsd
 // +build mips64 mips64le
 
 package runtime
diff --git a/src/runtime/signal_openbsd_mips64.go b/src/runtime/signal_openbsd_mips64.go
new file mode 100644 (file)
index 0000000..54ed523
--- /dev/null
@@ -0,0 +1,78 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import (
+       "unsafe"
+)
+
+type sigctxt struct {
+       info *siginfo
+       ctxt unsafe.Pointer
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) regs() *sigcontext {
+       return (*sigcontext)(c.ctxt)
+}
+
+func (c *sigctxt) r0() uint64  { return c.regs().sc_regs[0] }
+func (c *sigctxt) r1() uint64  { return c.regs().sc_regs[1] }
+func (c *sigctxt) r2() uint64  { return c.regs().sc_regs[2] }
+func (c *sigctxt) r3() uint64  { return c.regs().sc_regs[3] }
+func (c *sigctxt) r4() uint64  { return c.regs().sc_regs[4] }
+func (c *sigctxt) r5() uint64  { return c.regs().sc_regs[5] }
+func (c *sigctxt) r6() uint64  { return c.regs().sc_regs[6] }
+func (c *sigctxt) r7() uint64  { return c.regs().sc_regs[7] }
+func (c *sigctxt) r8() uint64  { return c.regs().sc_regs[8] }
+func (c *sigctxt) r9() uint64  { return c.regs().sc_regs[9] }
+func (c *sigctxt) r10() uint64 { return c.regs().sc_regs[10] }
+func (c *sigctxt) r11() uint64 { return c.regs().sc_regs[11] }
+func (c *sigctxt) r12() uint64 { return c.regs().sc_regs[12] }
+func (c *sigctxt) r13() uint64 { return c.regs().sc_regs[13] }
+func (c *sigctxt) r14() uint64 { return c.regs().sc_regs[14] }
+func (c *sigctxt) r15() uint64 { return c.regs().sc_regs[15] }
+func (c *sigctxt) r16() uint64 { return c.regs().sc_regs[16] }
+func (c *sigctxt) r17() uint64 { return c.regs().sc_regs[17] }
+func (c *sigctxt) r18() uint64 { return c.regs().sc_regs[18] }
+func (c *sigctxt) r19() uint64 { return c.regs().sc_regs[19] }
+func (c *sigctxt) r20() uint64 { return c.regs().sc_regs[20] }
+func (c *sigctxt) r21() uint64 { return c.regs().sc_regs[21] }
+func (c *sigctxt) r22() uint64 { return c.regs().sc_regs[22] }
+func (c *sigctxt) r23() uint64 { return c.regs().sc_regs[23] }
+func (c *sigctxt) r24() uint64 { return c.regs().sc_regs[24] }
+func (c *sigctxt) r25() uint64 { return c.regs().sc_regs[25] }
+func (c *sigctxt) r26() uint64 { return c.regs().sc_regs[26] }
+func (c *sigctxt) r27() uint64 { return c.regs().sc_regs[27] }
+func (c *sigctxt) r28() uint64 { return c.regs().sc_regs[28] }
+func (c *sigctxt) r29() uint64 { return c.regs().sc_regs[29] }
+func (c *sigctxt) r30() uint64 { return c.regs().sc_regs[30] }
+func (c *sigctxt) r31() uint64 { return c.regs().sc_regs[31] }
+func (c *sigctxt) sp() uint64  { return c.regs().sc_regs[29] }
+
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) pc() uint64 { return c.regs().sc_pc }
+
+func (c *sigctxt) link() uint64 { return c.regs().sc_regs[31] }
+func (c *sigctxt) lo() uint64   { return c.regs().mullo }
+func (c *sigctxt) hi() uint64   { return c.regs().mulhi }
+
+func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
+func (c *sigctxt) sigaddr() uint64 {
+       return *(*uint64)(add(unsafe.Pointer(c.info), 16))
+}
+
+func (c *sigctxt) set_r28(x uint64)  { c.regs().sc_regs[28] = x }
+func (c *sigctxt) set_r30(x uint64)  { c.regs().sc_regs[30] = x }
+func (c *sigctxt) set_pc(x uint64)   { c.regs().sc_pc = x }
+func (c *sigctxt) set_sp(x uint64)   { c.regs().sc_regs[29] = x }
+func (c *sigctxt) set_link(x uint64) { c.regs().sc_regs[31] = x }
+
+func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) }
+func (c *sigctxt) set_sigaddr(x uint64) {
+       *(*uint64)(add(unsafe.Pointer(c.info), 16)) = x
+}
diff --git a/src/runtime/sys_openbsd_mips64.s b/src/runtime/sys_openbsd_mips64.s
new file mode 100644 (file)
index 0000000..57a5dbd
--- /dev/null
@@ -0,0 +1,400 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//
+// System calls and other sys.stuff for mips64, OpenBSD
+// /usr/src/sys/kern/syscalls.master for syscall numbers.
+//
+
+#include "go_asm.h"
+#include "go_tls.h"
+#include "textflag.h"
+
+#define CLOCK_REALTIME $0
+#define        CLOCK_MONOTONIC $3
+
+// Exit the entire program (like C exit)
+TEXT runtime·exit(SB),NOSPLIT|NOFRAME,$0
+       MOVW    code+0(FP), R4          // arg 1 - status
+       MOVV    $1, R2                  // sys_exit
+       SYSCALL
+       BEQ     R7, 3(PC)
+       MOVV    $0, R2                  // crash on syscall failure
+       MOVV    R2, (R2)
+       RET
+
+// func exitThread(wait *uint32)
+TEXT runtime·exitThread(SB),NOSPLIT,$0
+       MOVV    wait+0(FP), R4          // arg 1 - notdead
+       MOVV    $302, R2                // sys___threxit
+       SYSCALL
+       MOVV    $0, R2                  // crash on syscall failure
+       MOVV    R2, (R2)
+       JMP     0(PC)
+
+TEXT runtime·open(SB),NOSPLIT|NOFRAME,$0
+       MOVV    name+0(FP), R4          // arg 1 - path
+       MOVW    mode+8(FP), R5          // arg 2 - mode
+       MOVW    perm+12(FP), R6         // arg 3 - perm
+       MOVV    $5, R2                  // sys_open
+       SYSCALL
+       BEQ     R7, 2(PC)
+       MOVW    $-1, R2
+       MOVW    R2, ret+16(FP)
+       RET
+
+TEXT runtime·closefd(SB),NOSPLIT|NOFRAME,$0
+       MOVW    fd+0(FP), R4            // arg 1 - fd
+       MOVV    $6, R2                  // sys_close
+       SYSCALL
+       BEQ     R7, 2(PC)
+       MOVW    $-1, R2
+       MOVW    R2, ret+8(FP)
+       RET
+
+TEXT runtime·read(SB),NOSPLIT|NOFRAME,$0
+       MOVW    fd+0(FP), R4            // arg 1 - fd
+       MOVV    p+8(FP), R5             // arg 2 - buf
+       MOVW    n+16(FP), R6            // arg 3 - nbyte
+       MOVV    $3, R2                  // sys_read
+       SYSCALL
+       BEQ     R7, 2(PC)
+       SUBVU   R2, R0, R2      // caller expects negative errno
+       MOVW    R2, ret+24(FP)
+       RET
+
+// func pipe() (r, w int32, errno int32)
+TEXT runtime·pipe(SB),NOSPLIT|NOFRAME,$0-12
+       MOVV    $r+0(FP), R4
+       MOVW    $0, R5
+       MOVV    $101, R2                // sys_pipe2
+       SYSCALL
+       BEQ     R7, 2(PC)
+       SUBVU   R2, R0, R2      // caller expects negative errno
+       MOVW    R2, errno+8(FP)
+       RET
+
+// func pipe2(flags int32) (r, w int32, errno int32)
+TEXT runtime·pipe2(SB),NOSPLIT|NOFRAME,$0-20
+       MOVV    $r+8(FP), R4
+       MOVW    flags+0(FP), R5
+       MOVV    $101, R2                // sys_pipe2
+       SYSCALL
+       BEQ     R7, 2(PC)
+       SUBVU   R2, R0, R2      // caller expects negative errno
+       MOVW    R2, errno+16(FP)
+       RET
+
+TEXT runtime·write1(SB),NOSPLIT|NOFRAME,$0
+       MOVV    fd+0(FP), R4            // arg 1 - fd
+       MOVV    p+8(FP), R5             // arg 2 - buf
+       MOVW    n+16(FP), R6            // arg 3 - nbyte
+       MOVV    $4, R2                  // sys_write
+       SYSCALL
+       BEQ     R7, 2(PC)
+       SUBVU   R2, R0, R2      // caller expects negative errno
+       MOVW    R2, ret+24(FP)
+       RET
+
+TEXT runtime·usleep(SB),NOSPLIT,$24-4
+       MOVWU   usec+0(FP), R3
+       MOVV    R3, R5
+       MOVW    $1000000, R4
+       DIVVU   R4, R3
+       MOVV    LO, R3
+       MOVV    R3, 8(R29)              // tv_sec
+       MOVW    $1000, R4
+       MULVU   R3, R4
+       MOVV    LO, R4
+       SUBVU   R4, R5
+       MOVV    R5, 16(R29)             // tv_nsec
+
+       ADDV    $8, R29, R4             // arg 1 - rqtp
+       MOVV    $0, R5                  // arg 2 - rmtp
+       MOVV    $91, R2                 // sys_nanosleep
+       SYSCALL
+       RET
+
+TEXT runtime·getthrid(SB),NOSPLIT,$0-4
+       MOVV    $299, R2                // sys_getthrid
+       SYSCALL
+       MOVW    R2, ret+0(FP)
+       RET
+
+TEXT runtime·thrkill(SB),NOSPLIT,$0-16
+       MOVW    tid+0(FP), R4           // arg 1 - tid
+       MOVV    sig+8(FP), R5           // arg 2 - signum
+       MOVW    $0, R6                  // arg 3 - tcb
+       MOVV    $119, R2                // sys_thrkill
+       SYSCALL
+       RET
+
+TEXT runtime·raiseproc(SB),NOSPLIT,$0
+       MOVV    $20, R4                 // sys_getpid
+       SYSCALL
+       MOVV    R2, R4                  // arg 1 - pid
+       MOVW    sig+0(FP), R5           // arg 2 - signum
+       MOVV    $122, R2                // sys_kill
+       SYSCALL
+       RET
+
+TEXT runtime·mmap(SB),NOSPLIT,$0
+       MOVV    addr+0(FP), R4          // arg 1 - addr
+       MOVV    n+8(FP), R5             // arg 2 - len
+       MOVW    prot+16(FP), R6         // arg 3 - prot
+       MOVW    flags+20(FP), R7        // arg 4 - flags
+       MOVW    fd+24(FP), R8           // arg 5 - fd
+       MOVW    $0, R9                  // arg 6 - pad
+       MOVW    off+28(FP), R10         // arg 7 - offset
+       MOVV    $197, R2                // sys_mmap
+       SYSCALL
+       MOVV    $0, R4
+       BEQ     R7, 3(PC)
+       MOVV    R2, R4                  // if error, move to R4
+       MOVV    $0, R2
+       MOVV    R2, p+32(FP)
+       MOVV    R4, err+40(FP)
+       RET
+
+TEXT runtime·munmap(SB),NOSPLIT,$0
+       MOVV    addr+0(FP), R4          // arg 1 - addr
+       MOVV    n+8(FP), R5             // arg 2 - len
+       MOVV    $73, R2                 // sys_munmap
+       SYSCALL
+       BEQ     R7, 3(PC)
+       MOVV    $0, R2                  // crash on syscall failure
+       MOVV    R2, (R2)
+       RET
+
+TEXT runtime·madvise(SB),NOSPLIT,$0
+       MOVV    addr+0(FP), R4          // arg 1 - addr
+       MOVV    n+8(FP), R5             // arg 2 - len
+       MOVW    flags+16(FP), R6        // arg 2 - flags
+       MOVV    $75, R2                 // sys_madvise
+       SYSCALL
+       BEQ     R7, 2(PC)
+       MOVW    $-1, R2
+       MOVW    R2, ret+24(FP)
+       RET
+
+TEXT runtime·setitimer(SB),NOSPLIT,$0
+       MOVW    mode+0(FP), R4          // arg 1 - mode
+       MOVV    new+8(FP), R5           // arg 2 - new value
+       MOVV    old+16(FP), R6          // arg 3 - old value
+       MOVV    $69, R2                 // sys_setitimer
+       SYSCALL
+       RET
+
+// func walltime1() (sec int64, nsec int32)
+TEXT runtime·walltime1(SB), NOSPLIT, $32
+       MOVW    CLOCK_REALTIME, R4      // arg 1 - clock_id
+       MOVV    $8(R29), R5             // arg 2 - tp
+       MOVV    $87, R2                 // sys_clock_gettime
+       SYSCALL
+
+       MOVV    8(R29), R4              // sec
+       MOVV    16(R29), R5             // nsec
+       MOVV    R4, sec+0(FP)
+       MOVW    R5, nsec+8(FP)
+
+       RET
+
+// int64 nanotime1(void) so really
+// void nanotime1(int64 *nsec)
+TEXT runtime·nanotime1(SB),NOSPLIT,$32
+       MOVW    CLOCK_MONOTONIC, R4     // arg 1 - clock_id
+       MOVV    $8(R29), R5             // arg 2 - tp
+       MOVV    $87, R2                 // sys_clock_gettime
+       SYSCALL
+
+       MOVV    8(R29), R3              // sec
+       MOVV    16(R29), R5             // nsec
+
+       MOVV    $1000000000, R4
+       MULVU   R4, R3
+       MOVV    LO, R3
+       ADDVU   R5, R3
+       MOVV    R3, ret+0(FP)
+       RET
+
+TEXT runtime·sigaction(SB),NOSPLIT,$0
+       MOVW    sig+0(FP), R4           // arg 1 - signum
+       MOVV    new+8(FP), R5           // arg 2 - new sigaction
+       MOVV    old+16(FP), R6          // arg 3 - old sigaction
+       MOVV    $46, R2                 // sys_sigaction
+       SYSCALL
+       BEQ     R7, 3(PC)
+       MOVV    $3, R2                  // crash on syscall failure
+       MOVV    R2, (R2)
+       RET
+
+TEXT runtime·obsdsigprocmask(SB),NOSPLIT,$0
+       MOVW    how+0(FP), R4           // arg 1 - mode
+       MOVW    new+4(FP), R5           // arg 2 - new
+       MOVV    $48, R2                 // sys_sigprocmask
+       SYSCALL
+       BEQ     R7, 3(PC)
+       MOVV    $3, R2                  // crash on syscall failure
+       MOVV    R2, (R2)
+       MOVW    R2, ret+8(FP)
+       RET
+
+TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
+       MOVW    sig+8(FP), R4
+       MOVV    info+16(FP), R5
+       MOVV    ctx+24(FP), R6
+       MOVV    fn+0(FP), R7
+       CALL    (R7)                    // Alignment for ELF ABI?
+       RET
+
+TEXT runtime·sigtramp(SB),NOSPLIT,$192
+       // initialize REGSB = PC&0xffffffff00000000
+       BGEZAL  R0, 1(PC)
+       SRLV    $32, R31, RSB
+       SLLV    $32, RSB
+
+       // this might be called in external code context,
+       // where g is not set.
+       MOVB    runtime·iscgo(SB), R1
+       BEQ     R1, 2(PC)
+       JAL     runtime·load_g(SB)
+
+       MOVW    R4, 8(R29)
+       MOVV    R5, 16(R29)
+       MOVV    R6, 24(R29)
+       MOVV    $runtime·sigtrampgo(SB), R1
+       JAL     (R1)
+       RET
+
+// int32 tfork(void *param, uintptr psize, M *mp, G *gp, void (*fn)(void));
+TEXT runtime·tfork(SB),NOSPLIT,$0
+
+       // Copy mp, gp and fn off parent stack for use by child.
+       MOVV    mm+16(FP), R16
+       MOVV    gg+24(FP), R17
+       MOVV    fn+32(FP), R18
+
+       MOVV    param+0(FP), R4         // arg 1 - param
+       MOVV    psize+8(FP), R5         // arg 2 - psize
+       MOVV    $8, R2                  // sys___tfork
+       SYSCALL
+
+       // Return if syscall failed.
+       BEQ     R7, 4(PC)
+       SUBVU   R2, R0, R2              // caller expects negative errno
+       MOVW    R2, ret+40(FP)
+       RET
+
+       // In parent, return.
+       BEQ     R2, 3(PC)
+       MOVW    R2, ret+40(FP)
+       RET
+
+       // Initialise m, g.
+       MOVV    R17, g
+       MOVV    R16, g_m(g)
+
+       // Call fn.
+       CALL    (R18)
+
+       // fn should never return.
+       MOVV    $2, R8                  // crash if reached
+       MOVV    R8, (R8)
+       RET
+
+TEXT runtime·sigaltstack(SB),NOSPLIT,$0
+       MOVV    new+0(FP), R4           // arg 1 - new sigaltstack
+       MOVV    old+8(FP), R5           // arg 2 - old sigaltstack
+       MOVV    $288, R2                // sys_sigaltstack
+       SYSCALL
+       BEQ     R7, 3(PC)
+       MOVV    $0, R8                  // crash on syscall failure
+       MOVV    R8, (R8)
+       RET
+
+TEXT runtime·osyield(SB),NOSPLIT,$0
+       MOVV    $298, R2                // sys_sched_yield
+       SYSCALL
+       RET
+
+TEXT runtime·thrsleep(SB),NOSPLIT,$0
+       MOVV    ident+0(FP), R4         // arg 1 - ident
+       MOVW    clock_id+8(FP), R5      // arg 2 - clock_id
+       MOVV    tsp+16(FP), R6          // arg 3 - tsp
+       MOVV    lock+24(FP), R7         // arg 4 - lock
+       MOVV    abort+32(FP), R8        // arg 5 - abort
+       MOVV    $94, R2                 // sys___thrsleep
+       SYSCALL
+       MOVW    R2, ret+40(FP)
+       RET
+
+TEXT runtime·thrwakeup(SB),NOSPLIT,$0
+       MOVV    ident+0(FP), R4         // arg 1 - ident
+       MOVW    n+8(FP), R5             // arg 2 - n
+       MOVV    $301, R2                // sys___thrwakeup
+       SYSCALL
+       MOVW    R2, ret+16(FP)
+       RET
+
+TEXT runtime·sysctl(SB),NOSPLIT,$0
+       MOVV    mib+0(FP), R4           // arg 1 - mib
+       MOVW    miblen+8(FP), R5        // arg 2 - miblen
+       MOVV    out+16(FP), R6          // arg 3 - out
+       MOVV    size+24(FP), R7         // arg 4 - size
+       MOVV    dst+32(FP), R8          // arg 5 - dest
+       MOVV    ndst+40(FP), R9         // arg 6 - newlen
+       MOVV    $202, R2                // sys___sysctl
+       SYSCALL
+       BEQ     R7, 2(PC)
+       SUBVU   R2, R0, R2      // caller expects negative errno
+       MOVW    R2, ret+48(FP)
+       RET
+
+// int32 runtime·kqueue(void);
+TEXT runtime·kqueue(SB),NOSPLIT,$0
+       MOVV    $269, R2                // sys_kqueue
+       SYSCALL
+       BEQ     R7, 2(PC)
+       SUBVU   R2, R0, R2      // caller expects negative errno
+       MOVW    R2, ret+0(FP)
+       RET
+
+// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int nevents, Timespec *timeout);
+TEXT runtime·kevent(SB),NOSPLIT,$0
+       MOVW    kq+0(FP), R4            // arg 1 - kq
+       MOVV    ch+8(FP), R5            // arg 2 - changelist
+       MOVW    nch+16(FP), R6          // arg 3 - nchanges
+       MOVV    ev+24(FP), R7           // arg 4 - eventlist
+       MOVW    nev+32(FP), R8          // arg 5 - nevents
+       MOVV    ts+40(FP), R9           // arg 6 - timeout
+       MOVV    $72, R2                 // sys_kevent
+       SYSCALL
+       BEQ     R7, 2(PC)
+       SUBVU   R2, R0, R2      // caller expects negative errno
+       MOVW    R2, ret+48(FP)
+       RET
+
+// func closeonexec(fd int32)
+TEXT runtime·closeonexec(SB),NOSPLIT,$0
+       MOVW    fd+0(FP), R4            // arg 1 - fd
+       MOVV    $2, R5                  // arg 2 - cmd (F_SETFD)
+       MOVV    $1, R6                  // arg 3 - arg (FD_CLOEXEC)
+       MOVV    $92, R2                 // sys_fcntl
+       SYSCALL
+       RET
+
+// func runtime·setNonblock(int32 fd)
+TEXT runtime·setNonblock(SB),NOSPLIT|NOFRAME,$0-4
+       MOVW    fd+0(FP), R4            // arg 1 - fd
+       MOVV    $3, R5                  // arg 2 - cmd (F_GETFL)
+       MOVV    $0, R6                  // arg 3
+       MOVV    $92, R2                 // sys_fcntl
+       SYSCALL
+       MOVV    $4, R6                  // O_NONBLOCK
+       OR      R2, R6                  // arg 3 - flags
+       MOVW    fd+0(FP), R4            // arg 1 - fd
+       MOVV    $4, R5                  // arg 2 - cmd (F_SETFL)
+       MOVV    $92, R2                 // sys_fcntl
+       SYSCALL
+       RET