|  | // Copyright 2013 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 ARM, NetBSD | 
|  | // /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 | 
|  | #define FD_CLOEXEC		1 | 
|  | #define F_SETFD			2 | 
|  |  | 
|  | #define SWI_OS_NETBSD			0xa00000 | 
|  | #define SYS_exit			SWI_OS_NETBSD | 1 | 
|  | #define SYS_read			SWI_OS_NETBSD | 3 | 
|  | #define SYS_write			SWI_OS_NETBSD | 4 | 
|  | #define SYS_open			SWI_OS_NETBSD | 5 | 
|  | #define SYS_close			SWI_OS_NETBSD | 6 | 
|  | #define SYS_getpid			SWI_OS_NETBSD | 20 | 
|  | #define SYS_kill			SWI_OS_NETBSD | 37 | 
|  | #define SYS_munmap			SWI_OS_NETBSD | 73 | 
|  | #define SYS_madvise			SWI_OS_NETBSD | 75 | 
|  | #define SYS_fcntl			SWI_OS_NETBSD | 92 | 
|  | #define SYS_mmap			SWI_OS_NETBSD | 197 | 
|  | #define SYS___sysctl			SWI_OS_NETBSD | 202 | 
|  | #define SYS___sigaltstack14		SWI_OS_NETBSD | 281 | 
|  | #define SYS___sigprocmask14		SWI_OS_NETBSD | 293 | 
|  | #define SYS_getcontext			SWI_OS_NETBSD | 307 | 
|  | #define SYS_setcontext			SWI_OS_NETBSD | 308 | 
|  | #define SYS__lwp_create			SWI_OS_NETBSD | 309 | 
|  | #define SYS__lwp_exit			SWI_OS_NETBSD | 310 | 
|  | #define SYS__lwp_self			SWI_OS_NETBSD | 311 | 
|  | #define SYS__lwp_getprivate		SWI_OS_NETBSD | 316 | 
|  | #define SYS__lwp_setprivate		SWI_OS_NETBSD | 317 | 
|  | #define SYS__lwp_kill			SWI_OS_NETBSD | 318 | 
|  | #define SYS__lwp_unpark			SWI_OS_NETBSD | 321 | 
|  | #define SYS___sigaction_sigtramp	SWI_OS_NETBSD | 340 | 
|  | #define SYS_kqueue			SWI_OS_NETBSD | 344 | 
|  | #define SYS_sched_yield			SWI_OS_NETBSD | 350 | 
|  | #define SYS___setitimer50		SWI_OS_NETBSD | 425 | 
|  | #define SYS___clock_gettime50		SWI_OS_NETBSD | 427 | 
|  | #define SYS___nanosleep50		SWI_OS_NETBSD | 430 | 
|  | #define SYS___kevent50			SWI_OS_NETBSD | 435 | 
|  | #define SYS____lwp_park60		SWI_OS_NETBSD | 478 | 
|  |  | 
|  | // Exit the entire program (like C exit) | 
|  | TEXT runtime·exit(SB),NOSPLIT|NOFRAME,$0 | 
|  | MOVW code+0(FP), R0	// arg 1 exit status | 
|  | SWI $SYS_exit | 
|  | MOVW.CS $0, R8	// crash on syscall failure | 
|  | MOVW.CS R8, (R8) | 
|  | RET | 
|  |  | 
|  | // func exitThread(wait *uint32) | 
|  | TEXT runtime·exitThread(SB),NOSPLIT,$0-4 | 
|  | MOVW wait+0(FP), R0 | 
|  | // We're done using the stack. | 
|  | MOVW $0, R2 | 
|  | storeloop: | 
|  | LDREX (R0), R4          // loads R4 | 
|  | STREX R2, (R0), R1      // stores R2 | 
|  | CMP $0, R1 | 
|  | BNE storeloop | 
|  | SWI $SYS__lwp_exit | 
|  | MOVW $1, R8	// crash | 
|  | MOVW R8, (R8) | 
|  | JMP 0(PC) | 
|  |  | 
|  | TEXT runtime·open(SB),NOSPLIT|NOFRAME,$0 | 
|  | MOVW name+0(FP), R0 | 
|  | MOVW mode+4(FP), R1 | 
|  | MOVW perm+8(FP), R2 | 
|  | SWI $SYS_open | 
|  | MOVW.CS	$-1, R0 | 
|  | MOVW	R0, ret+12(FP) | 
|  | RET | 
|  |  | 
|  | TEXT runtime·closefd(SB),NOSPLIT|NOFRAME,$0 | 
|  | MOVW fd+0(FP), R0 | 
|  | SWI $SYS_close | 
|  | MOVW.CS	$-1, R0 | 
|  | MOVW	R0, ret+4(FP) | 
|  | RET | 
|  |  | 
|  | TEXT runtime·read(SB),NOSPLIT|NOFRAME,$0 | 
|  | MOVW fd+0(FP), R0 | 
|  | MOVW p+4(FP), R1 | 
|  | MOVW n+8(FP), R2 | 
|  | SWI $SYS_read | 
|  | RSB.CS	$0, R0		// caller expects negative errno | 
|  | MOVW	R0, ret+12(FP) | 
|  | RET | 
|  |  | 
|  | // func pipe() (r, w int32, errno int32) | 
|  | TEXT runtime·pipe(SB),NOSPLIT,$0-12 | 
|  | SWI $0xa0002a | 
|  | BCC pipeok | 
|  | MOVW $-1,R2 | 
|  | MOVW R2, r+0(FP) | 
|  | MOVW R2, w+4(FP) | 
|  | MOVW R0, errno+8(FP) | 
|  | RET | 
|  | pipeok: | 
|  | MOVW $0, R2 | 
|  | MOVW R0, r+0(FP) | 
|  | MOVW R1, w+4(FP) | 
|  | MOVW R2, errno+8(FP) | 
|  | RET | 
|  |  | 
|  | // func pipe2(flags int32) (r, w int32, errno int32) | 
|  | TEXT runtime·pipe2(SB),NOSPLIT,$0-16 | 
|  | MOVW $r+4(FP), R0 | 
|  | MOVW flags+0(FP), R1 | 
|  | SWI $0xa001c5 | 
|  | MOVW R0, errno+12(FP) | 
|  | RET | 
|  |  | 
|  | TEXT runtime·write1(SB),NOSPLIT|NOFRAME,$0 | 
|  | MOVW	fd+0(FP), R0	// arg 1 - fd | 
|  | MOVW	p+4(FP), R1	// arg 2 - buf | 
|  | MOVW	n+8(FP), R2	// arg 3 - nbyte | 
|  | SWI $SYS_write | 
|  | RSB.CS	$0, R0		// caller expects negative errno | 
|  | MOVW	R0, ret+12(FP) | 
|  | RET | 
|  |  | 
|  | // int32 lwp_create(void *context, uintptr flags, void *lwpid) | 
|  | TEXT runtime·lwp_create(SB),NOSPLIT,$0 | 
|  | MOVW ctxt+0(FP), R0 | 
|  | MOVW flags+4(FP), R1 | 
|  | MOVW lwpid+8(FP), R2 | 
|  | SWI $SYS__lwp_create | 
|  | MOVW	R0, ret+12(FP) | 
|  | RET | 
|  |  | 
|  | TEXT runtime·osyield(SB),NOSPLIT,$0 | 
|  | SWI $SYS_sched_yield | 
|  | RET | 
|  |  | 
|  | TEXT runtime·lwp_park(SB),NOSPLIT,$8 | 
|  | MOVW clockid+0(FP), R0		// arg 1 - clock_id | 
|  | MOVW flags+4(FP), R1		// arg 2 - flags | 
|  | MOVW ts+8(FP), R2		// arg 3 - ts | 
|  | MOVW unpark+12(FP), R3		// arg 4 - unpark | 
|  | MOVW hint+16(FP), R4		// arg 5 - hint | 
|  | MOVW R4, 4(R13) | 
|  | MOVW unparkhint+20(FP), R5	// arg 6 - unparkhint | 
|  | MOVW R5, 8(R13) | 
|  | SWI $SYS____lwp_park60 | 
|  | MOVW	R0, ret+24(FP) | 
|  | RET | 
|  |  | 
|  | TEXT runtime·lwp_unpark(SB),NOSPLIT,$0 | 
|  | MOVW	lwp+0(FP), R0	// arg 1 - lwp | 
|  | MOVW	hint+4(FP), R1	// arg 2 - hint | 
|  | SWI	$SYS__lwp_unpark | 
|  | MOVW	R0, ret+8(FP) | 
|  | RET | 
|  |  | 
|  | TEXT runtime·lwp_self(SB),NOSPLIT,$0 | 
|  | SWI	$SYS__lwp_self | 
|  | MOVW	R0, ret+0(FP) | 
|  | RET | 
|  |  | 
|  | TEXT runtime·lwp_tramp(SB),NOSPLIT,$0 | 
|  | MOVW R0, g_m(R1) | 
|  | MOVW R1, g | 
|  |  | 
|  | BL runtime·emptyfunc(SB) // fault if stack check is wrong | 
|  | BL (R2) | 
|  | MOVW $2, R8  // crash (not reached) | 
|  | MOVW R8, (R8) | 
|  | RET | 
|  |  | 
|  | TEXT runtime·usleep(SB),NOSPLIT,$16 | 
|  | MOVW usec+0(FP), R0 | 
|  | CALL runtime·usplitR0(SB) | 
|  | // 0(R13) is the saved LR, don't use it | 
|  | MOVW R0, 4(R13) // tv_sec.low | 
|  | MOVW $0, R0 | 
|  | MOVW R0, 8(R13) // tv_sec.high | 
|  | MOVW $1000, R2 | 
|  | MUL R1, R2 | 
|  | MOVW R2, 12(R13) // tv_nsec | 
|  |  | 
|  | MOVW $4(R13), R0 // arg 1 - rqtp | 
|  | MOVW $0, R1      // arg 2 - rmtp | 
|  | SWI $SYS___nanosleep50 | 
|  | RET | 
|  |  | 
|  | TEXT runtime·lwp_kill(SB),NOSPLIT,$0-8 | 
|  | MOVW	tid+0(FP), R0	// arg 1 - tid | 
|  | MOVW	sig+4(FP), R1	// arg 2 - signal | 
|  | SWI	$SYS__lwp_kill | 
|  | RET | 
|  |  | 
|  | TEXT runtime·raiseproc(SB),NOSPLIT,$16 | 
|  | SWI	$SYS_getpid	// the returned R0 is arg 1 | 
|  | MOVW	sig+0(FP), R1	// arg 2 - signal | 
|  | SWI	$SYS_kill | 
|  | RET | 
|  |  | 
|  | TEXT runtime·setitimer(SB),NOSPLIT|NOFRAME,$0 | 
|  | MOVW mode+0(FP), R0	// arg 1 - which | 
|  | MOVW new+4(FP), R1	// arg 2 - itv | 
|  | MOVW old+8(FP), R2	// arg 3 - oitv | 
|  | SWI $SYS___setitimer50 | 
|  | RET | 
|  |  | 
|  | // func walltime1() (sec int64, nsec int32) | 
|  | TEXT runtime·walltime1(SB), NOSPLIT, $32 | 
|  | MOVW $0, R0	// CLOCK_REALTIME | 
|  | MOVW $8(R13), R1 | 
|  | SWI $SYS___clock_gettime50 | 
|  |  | 
|  | MOVW 8(R13), R0	// sec.low | 
|  | MOVW 12(R13), R1 // sec.high | 
|  | MOVW 16(R13), R2 // nsec | 
|  |  | 
|  | MOVW R0, sec_lo+0(FP) | 
|  | MOVW R1, sec_hi+4(FP) | 
|  | MOVW R2, nsec+8(FP) | 
|  | RET | 
|  |  | 
|  | // int64 nanotime1(void) so really | 
|  | // void nanotime1(int64 *nsec) | 
|  | TEXT runtime·nanotime1(SB), NOSPLIT, $32 | 
|  | MOVW $3, R0 // CLOCK_MONOTONIC | 
|  | MOVW $8(R13), R1 | 
|  | SWI $SYS___clock_gettime50 | 
|  |  | 
|  | MOVW 8(R13), R0 // sec.low | 
|  | MOVW 12(R13), R4 // sec.high | 
|  | MOVW 16(R13), R2 // nsec | 
|  |  | 
|  | MOVW $1000000000, R3 | 
|  | MULLU R0, R3, (R1, R0) | 
|  | MUL R3, R4 | 
|  | ADD.S R2, R0 | 
|  | ADC R4, R1 | 
|  |  | 
|  | MOVW R0, ret_lo+0(FP) | 
|  | MOVW R1, ret_hi+4(FP) | 
|  | RET | 
|  |  | 
|  | TEXT runtime·getcontext(SB),NOSPLIT|NOFRAME,$0 | 
|  | MOVW ctxt+0(FP), R0	// arg 1 - context | 
|  | SWI $SYS_getcontext | 
|  | MOVW.CS $0, R8	// crash on syscall failure | 
|  | MOVW.CS R8, (R8) | 
|  | RET | 
|  |  | 
|  | TEXT runtime·sigprocmask(SB),NOSPLIT,$0 | 
|  | MOVW how+0(FP), R0	// arg 1 - how | 
|  | MOVW new+4(FP), R1	// arg 2 - set | 
|  | MOVW old+8(FP), R2	// arg 3 - oset | 
|  | SWI $SYS___sigprocmask14 | 
|  | MOVW.CS $0, R8	// crash on syscall failure | 
|  | MOVW.CS R8, (R8) | 
|  | RET | 
|  |  | 
|  | TEXT sigreturn_tramp<>(SB),NOSPLIT|NOFRAME,$0 | 
|  | // on entry, SP points to siginfo, we add sizeof(ucontext) | 
|  | // to SP to get a pointer to ucontext. | 
|  | ADD $0x80, R13, R0 // 0x80 == sizeof(UcontextT) | 
|  | SWI $SYS_setcontext | 
|  | // something failed, we have to exit | 
|  | MOVW $0x4242, R0 // magic return number | 
|  | SWI $SYS_exit | 
|  | B -2(PC)	// continue exit | 
|  |  | 
|  | TEXT runtime·sigaction(SB),NOSPLIT,$4 | 
|  | MOVW sig+0(FP), R0	// arg 1 - signum | 
|  | MOVW new+4(FP), R1	// arg 2 - nsa | 
|  | MOVW old+8(FP), R2	// arg 3 - osa | 
|  | MOVW $sigreturn_tramp<>(SB), R3	// arg 4 - tramp | 
|  | MOVW $2, R4	// arg 5 - vers | 
|  | MOVW R4, 4(R13) | 
|  | ADD $4, R13	// pass arg 5 on stack | 
|  | SWI $SYS___sigaction_sigtramp | 
|  | SUB $4, R13 | 
|  | MOVW.CS $3, R8	// crash on syscall failure | 
|  | MOVW.CS R8, (R8) | 
|  | RET | 
|  |  | 
|  | TEXT runtime·sigfwd(SB),NOSPLIT,$0-16 | 
|  | MOVW	sig+4(FP), R0 | 
|  | MOVW	info+8(FP), R1 | 
|  | MOVW	ctx+12(FP), R2 | 
|  | MOVW	fn+0(FP), R11 | 
|  | MOVW	R13, R4 | 
|  | SUB	$24, R13 | 
|  | BIC	$0x7, R13 // alignment for ELF ABI | 
|  | BL	(R11) | 
|  | MOVW	R4, R13 | 
|  | RET | 
|  |  | 
|  | TEXT runtime·sigtramp(SB),NOSPLIT,$0 | 
|  | // Reserve space for callee-save registers and arguments. | 
|  | MOVM.DB.W [R4-R11], (R13) | 
|  | SUB	$16, R13 | 
|  |  | 
|  | // this might be called in external code context, | 
|  | // where g is not set. | 
|  | // first save R0, because runtime·load_g will clobber it | 
|  | MOVW	R0, 4(R13) // signum | 
|  | MOVB	runtime·iscgo(SB), R0 | 
|  | CMP 	$0, R0 | 
|  | BL.NE	runtime·load_g(SB) | 
|  |  | 
|  | MOVW	R1, 8(R13) | 
|  | MOVW	R2, 12(R13) | 
|  | BL	runtime·sigtrampgo(SB) | 
|  |  | 
|  | // Restore callee-save registers. | 
|  | ADD	$16, R13 | 
|  | MOVM.IA.W (R13), [R4-R11] | 
|  |  | 
|  | RET | 
|  |  | 
|  | TEXT runtime·mmap(SB),NOSPLIT,$12 | 
|  | MOVW addr+0(FP), R0	// arg 1 - addr | 
|  | MOVW n+4(FP), R1	// arg 2 - len | 
|  | MOVW prot+8(FP), R2	// arg 3 - prot | 
|  | MOVW flags+12(FP), R3	// arg 4 - flags | 
|  | // arg 5 (fid) and arg6 (offset_lo, offset_hi) are passed on stack | 
|  | // note the C runtime only passes the 32-bit offset_lo to us | 
|  | MOVW fd+16(FP), R4		// arg 5 | 
|  | MOVW R4, 4(R13) | 
|  | MOVW off+20(FP), R5		// arg 6 lower 32-bit | 
|  | MOVW R5, 8(R13) | 
|  | MOVW $0, R6 // higher 32-bit for arg 6 | 
|  | MOVW R6, 12(R13) | 
|  | ADD $4, R13 // pass arg 5 and arg 6 on stack | 
|  | SWI $SYS_mmap | 
|  | SUB $4, R13 | 
|  | MOVW	$0, R1 | 
|  | MOVW.CS R0, R1	// if error, move to R1 | 
|  | MOVW.CS $0, R0 | 
|  | MOVW	R0, p+24(FP) | 
|  | MOVW	R1, err+28(FP) | 
|  | RET | 
|  |  | 
|  | TEXT runtime·munmap(SB),NOSPLIT,$0 | 
|  | MOVW addr+0(FP), R0	// arg 1 - addr | 
|  | MOVW n+4(FP), R1	// arg 2 - len | 
|  | SWI $SYS_munmap | 
|  | MOVW.CS $0, R8	// crash on syscall failure | 
|  | MOVW.CS R8, (R8) | 
|  | RET | 
|  |  | 
|  | TEXT runtime·madvise(SB),NOSPLIT,$0 | 
|  | MOVW	addr+0(FP), R0	// arg 1 - addr | 
|  | MOVW	n+4(FP), R1	// arg 2 - len | 
|  | MOVW	flags+8(FP), R2	// arg 3 - behav | 
|  | SWI	$SYS_madvise | 
|  | MOVW.CS	$-1, R0 | 
|  | MOVW	R0, ret+12(FP) | 
|  | RET | 
|  |  | 
|  | TEXT runtime·sigaltstack(SB),NOSPLIT|NOFRAME,$0 | 
|  | MOVW new+0(FP), R0	// arg 1 - nss | 
|  | MOVW old+4(FP), R1	// arg 2 - oss | 
|  | SWI $SYS___sigaltstack14 | 
|  | MOVW.CS $0, R8	// crash on syscall failure | 
|  | MOVW.CS R8, (R8) | 
|  | RET | 
|  |  | 
|  | TEXT runtime·sysctl(SB),NOSPLIT,$8 | 
|  | MOVW mib+0(FP), R0	// arg 1 - name | 
|  | MOVW miblen+4(FP), R1	// arg 2 - namelen | 
|  | MOVW out+8(FP), R2	// arg 3 - oldp | 
|  | MOVW size+12(FP), R3	// arg 4 - oldlenp | 
|  | MOVW dst+16(FP), R4	// arg 5 - newp | 
|  | MOVW R4, 4(R13) | 
|  | MOVW ndst+20(FP), R4	// arg 6 - newlen | 
|  | MOVW R4, 8(R13) | 
|  | ADD $4, R13	// pass arg 5 and 6 on stack | 
|  | SWI $SYS___sysctl | 
|  | SUB $4, R13 | 
|  | MOVW	R0, ret+24(FP) | 
|  | RET | 
|  |  | 
|  | // int32 runtime·kqueue(void) | 
|  | TEXT runtime·kqueue(SB),NOSPLIT,$0 | 
|  | SWI	$SYS_kqueue | 
|  | RSB.CS	$0, R0 | 
|  | MOVW	R0, ret+0(FP) | 
|  | RET | 
|  |  | 
|  | // int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int nevents, Timespec *timeout) | 
|  | TEXT runtime·kevent(SB),NOSPLIT,$8 | 
|  | MOVW kq+0(FP), R0	// kq | 
|  | MOVW ch+4(FP), R1	// changelist | 
|  | MOVW nch+8(FP), R2	// nchanges | 
|  | MOVW ev+12(FP), R3	// eventlist | 
|  | MOVW nev+16(FP), R4	// nevents | 
|  | MOVW R4, 4(R13) | 
|  | MOVW ts+20(FP), R4	// timeout | 
|  | MOVW R4, 8(R13) | 
|  | ADD $4, R13	// pass arg 5 and 6 on stack | 
|  | SWI $SYS___kevent50 | 
|  | RSB.CS $0, R0 | 
|  | SUB $4, R13 | 
|  | MOVW	R0, ret+24(FP) | 
|  | RET | 
|  |  | 
|  | // void runtime·closeonexec(int32 fd) | 
|  | TEXT runtime·closeonexec(SB),NOSPLIT,$0 | 
|  | MOVW fd+0(FP), R0	// fd | 
|  | MOVW $F_SETFD, R1	// F_SETFD | 
|  | MOVW $FD_CLOEXEC, R2	// FD_CLOEXEC | 
|  | SWI $SYS_fcntl | 
|  | RET | 
|  |  | 
|  | // func runtime·setNonblock(fd int32) | 
|  | TEXT runtime·setNonblock(SB),NOSPLIT,$0-4 | 
|  | MOVW fd+0(FP), R0	// fd | 
|  | MOVW $3, R1	// F_GETFL | 
|  | MOVW $0, R2 | 
|  | SWI $0xa0005c	// sys_fcntl | 
|  | ORR $0x4, R0, R2	// O_NONBLOCK | 
|  | MOVW fd+0(FP), R0	// fd | 
|  | MOVW $4, R1	// F_SETFL | 
|  | SWI $0xa0005c	// sys_fcntl | 
|  | RET | 
|  |  | 
|  | // TODO: this is only valid for ARMv7+ | 
|  | TEXT ·publicationBarrier(SB),NOSPLIT|NOFRAME,$0-0 | 
|  | B	runtime·armPublicationBarrier(SB) | 
|  |  | 
|  | TEXT runtime·read_tls_fallback(SB),NOSPLIT|NOFRAME,$0 | 
|  | MOVM.WP [R1, R2, R3, R12], (R13) | 
|  | SWI $SYS__lwp_getprivate | 
|  | MOVM.IAW    (R13), [R1, R2, R3, R12] | 
|  | RET |