From 272032d0b245635ca0c5ca4c22e64496174b2ae3 Mon Sep 17 00:00:00 2001 From: Vladimir Stefanovic Date: Tue, 18 Oct 2016 23:51:01 +0200 Subject: [PATCH] runtime: add support files for linux/mips{,le} port Only exe buildmode without cgo supported. Change-Id: Id104a79a99d3285c04db00fd98b8affa94ea3c37 Reviewed-on: https://go-review.googlesource.com/31487 Run-TryBot: Cherry Zhang TryBot-Result: Gobot Gobot Reviewed-by: Cherry Zhang --- src/runtime/asm_mipsx.s | 794 ++++++++++++++++++++++++++++ src/runtime/atomic_mipsx.s | 11 + src/runtime/cputicks.go | 2 + src/runtime/defs_linux_mipsx.go | 188 +++++++ src/runtime/gcinfo_test.go | 2 +- src/runtime/hash32.go | 2 +- src/runtime/lfstack_32bit.go | 2 +- src/runtime/malloc.go | 3 +- src/runtime/memclr_mipsx.s | 71 +++ src/runtime/memmove_mipsx.s | 258 +++++++++ src/runtime/os_linux_generic.go | 2 + src/runtime/os_linux_mips64x.go | 2 +- src/runtime/os_linux_mipsx.go | 62 +++ src/runtime/os_linux_noauxv.go | 2 +- src/runtime/rt0_linux_mipsx.s | 27 + src/runtime/signal_linux_mipsx.go | 65 +++ src/runtime/signal_mipsx.go | 91 ++++ src/runtime/sigtab_linux_generic.go | 2 + src/runtime/sigtab_linux_mips64x.go | 81 --- src/runtime/sigtab_linux_mipsx.go | 145 +++++ src/runtime/stubs32.go | 2 +- src/runtime/sys_linux_mipsx.s | 467 ++++++++++++++++ src/runtime/sys_mipsx.go | 20 + src/runtime/tls_mipsx.s | 21 + src/runtime/unaligned2.go | 2 +- src/runtime/vlrt.go | 7 +- 26 files changed, 2241 insertions(+), 90 deletions(-) create mode 100644 src/runtime/asm_mipsx.s create mode 100644 src/runtime/atomic_mipsx.s create mode 100644 src/runtime/defs_linux_mipsx.go create mode 100644 src/runtime/memclr_mipsx.s create mode 100644 src/runtime/memmove_mipsx.s create mode 100644 src/runtime/os_linux_mipsx.go create mode 100644 src/runtime/rt0_linux_mipsx.s create mode 100644 src/runtime/signal_linux_mipsx.go create mode 100644 src/runtime/signal_mipsx.go delete mode 100644 src/runtime/sigtab_linux_mips64x.go create mode 100644 src/runtime/sigtab_linux_mipsx.go create mode 100644 src/runtime/sys_linux_mipsx.s create mode 100644 src/runtime/sys_mipsx.go create mode 100644 src/runtime/tls_mipsx.s diff --git a/src/runtime/asm_mipsx.s b/src/runtime/asm_mipsx.s new file mode 100644 index 0000000000..cd855c7d34 --- /dev/null +++ b/src/runtime/asm_mipsx.s @@ -0,0 +1,794 @@ +// Copyright 2016 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. + +// +build mips mipsle + +#include "go_asm.h" +#include "go_tls.h" +#include "funcdata.h" +#include "textflag.h" + +#define REGCTXT R22 + +TEXT runtime·rt0_go(SB),NOSPLIT,$0 + // R29 = stack; R1 = argc; R2 = argv + + ADDU $-12, R29 + MOVW R1, 4(R29) // argc + MOVW R2, 8(R29) // argv + + // create istack out of the given (operating system) stack. + // _cgo_init may update stackguard. + MOVW $runtime·g0(SB), g + MOVW $(-64*1024), R23 + ADD R23, R29, R1 + MOVW R1, g_stackguard0(g) + MOVW R1, g_stackguard1(g) + MOVW R1, (g_stack+stack_lo)(g) + MOVW R29, (g_stack+stack_hi)(g) + +// TODO(mips32): cgo + +nocgo: + // update stackguard after _cgo_init + MOVW (g_stack+stack_lo)(g), R1 + ADD $const__StackGuard, R1 + MOVW R1, g_stackguard0(g) + MOVW R1, g_stackguard1(g) + + // set the per-goroutine and per-mach "registers" + MOVW $runtime·m0(SB), R1 + + // save m->g0 = g0 + MOVW g, m_g0(R1) + // save m0 to g0->m + MOVW R1, g_m(g) + + JAL runtime·check(SB) + + // args are already prepared + JAL runtime·args(SB) + JAL runtime·osinit(SB) + JAL runtime·schedinit(SB) + + // create a new goroutine to start program + MOVW $runtime·mainPC(SB), R1 // entry + ADDU $-12, R29 + MOVW R1, 8(R29) + MOVW R0, 4(R29) + MOVW R0, 0(R29) + JAL runtime·newproc(SB) + ADDU $12, R29 + + // start this M + JAL runtime·mstart(SB) + + UNDEF + RET + +DATA runtime·mainPC+0(SB)/4,$runtime·main(SB) +GLOBL runtime·mainPC(SB),RODATA,$4 + +TEXT runtime·breakpoint(SB),NOSPLIT,$0-0 + BREAK + RET + +TEXT runtime·asminit(SB),NOSPLIT,$0-0 + RET + +/* + * go-routine + */ + +// void gosave(Gobuf*) +// save state in Gobuf; setjmp +TEXT runtime·gosave(SB),NOSPLIT,$-4-4 + MOVW buf+0(FP), R1 + MOVW R29, gobuf_sp(R1) + MOVW R31, gobuf_pc(R1) + MOVW g, gobuf_g(R1) + MOVW R0, gobuf_lr(R1) + MOVW R0, gobuf_ret(R1) + // Assert ctxt is zero. See func save. + MOVW gobuf_ctxt(R1), R1 + BEQ R1, 2(PC) + JAL runtime·badctxt(SB) + RET + +// void gogo(Gobuf*) +// restore state from Gobuf; longjmp +TEXT runtime·gogo(SB),NOSPLIT,$8-4 + MOVW buf+0(FP), R3 + + // If ctxt is not nil, invoke deletion barrier before overwriting. + MOVW gobuf_ctxt(R3), R1 + BEQ R1, nilctxt + MOVW $gobuf_ctxt(R3), R1 + MOVW R1, 4(R29) + MOVW R0, 8(R29) + JAL runtime·writebarrierptr_prewrite(SB) + MOVW buf+0(FP), R3 + +nilctxt: + MOVW gobuf_g(R3), g // make sure g is not nil + JAL runtime·save_g(SB) + + MOVW 0(g), R2 + MOVW gobuf_sp(R3), R29 + MOVW gobuf_lr(R3), R31 + MOVW gobuf_ret(R3), R1 + MOVW gobuf_ctxt(R3), REGCTXT + MOVW R0, gobuf_sp(R3) + MOVW R0, gobuf_ret(R3) + MOVW R0, gobuf_lr(R3) + MOVW R0, gobuf_ctxt(R3) + MOVW gobuf_pc(R3), R4 + JMP (R4) + +// void mcall(fn func(*g)) +// Switch to m->g0's stack, call fn(g). +// Fn must never return. It should gogo(&g->sched) +// to keep running g. +TEXT runtime·mcall(SB),NOSPLIT,$-4-4 + // Save caller state in g->sched + MOVW R29, (g_sched+gobuf_sp)(g) + MOVW R31, (g_sched+gobuf_pc)(g) + MOVW R0, (g_sched+gobuf_lr)(g) + MOVW g, (g_sched+gobuf_g)(g) + + // Switch to m->g0 & its stack, call fn. + MOVW g, R1 + MOVW g_m(g), R3 + MOVW m_g0(R3), g + JAL runtime·save_g(SB) + BNE g, R1, 2(PC) + JMP runtime·badmcall(SB) + MOVW fn+0(FP), REGCTXT // context + MOVW 0(REGCTXT), R4 // code pointer + MOVW (g_sched+gobuf_sp)(g), R29 // sp = m->g0->sched.sp + ADDU $-8, R29 // make room for 1 arg and fake LR + MOVW R1, 4(R29) + MOVW R0, 0(R29) + JAL (R4) + JMP runtime·badmcall2(SB) + +// systemstack_switch is a dummy routine that systemstack leaves at the bottom +// of the G stack. We need to distinguish the routine that +// lives at the bottom of the G stack from the one that lives +// at the top of the system stack because the one at the top of +// the system stack terminates the stack walk (see topofstack()). +TEXT runtime·systemstack_switch(SB),NOSPLIT,$0-0 + UNDEF + JAL (R31) // make sure this function is not leaf + RET + +// func systemstack(fn func()) +TEXT runtime·systemstack(SB),NOSPLIT,$0-4 + MOVW fn+0(FP), R1 // R1 = fn + MOVW R1, REGCTXT // context + MOVW g_m(g), R2 // R2 = m + + MOVW m_gsignal(R2), R3 // R3 = gsignal + BEQ g, R3, noswitch + + MOVW m_g0(R2), R3 // R3 = g0 + BEQ g, R3, noswitch + + MOVW m_curg(R2), R4 + BEQ g, R4, switch + + // Bad: g is not gsignal, not g0, not curg. What is it? + // Hide call from linker nosplit analysis. + MOVW $runtime·badsystemstack(SB), R4 + JAL (R4) + +switch: + // save our state in g->sched. Pretend to + // be systemstack_switch if the G stack is scanned. + MOVW $runtime·systemstack_switch(SB), R4 + ADDU $8, R4 // get past prologue + MOVW R4, (g_sched+gobuf_pc)(g) + MOVW R29, (g_sched+gobuf_sp)(g) + MOVW R0, (g_sched+gobuf_lr)(g) + MOVW g, (g_sched+gobuf_g)(g) + + // switch to g0 + MOVW R3, g + JAL runtime·save_g(SB) + MOVW (g_sched+gobuf_sp)(g), R1 + // make it look like mstart called systemstack on g0, to stop traceback + ADDU $-4, R1 + MOVW $runtime·mstart(SB), R2 + MOVW R2, 0(R1) + MOVW R1, R29 + + // call target function + MOVW 0(REGCTXT), R4 // code pointer + JAL (R4) + + // switch back to g + MOVW g_m(g), R1 + MOVW m_curg(R1), g + JAL runtime·save_g(SB) + MOVW (g_sched+gobuf_sp)(g), R29 + MOVW R0, (g_sched+gobuf_sp)(g) + RET + +noswitch: + // already on m stack, just call directly + MOVW 0(REGCTXT), R4 // code pointer + JAL (R4) + RET + +/* + * support for morestack + */ + +// Called during function prolog when more stack is needed. +// Caller has already loaded: +// R1: framesize, R2: argsize, R3: LR +// +// The traceback routines see morestack on a g0 as being +// the top of a stack (for example, morestack calling newstack +// calling the scheduler calling newm calling gc), so we must +// record an argument size. For that purpose, it has no arguments. +TEXT runtime·morestack(SB),NOSPLIT,$-4-0 + // Cannot grow scheduler stack (m->g0). + MOVW g_m(g), R7 + MOVW m_g0(R7), R8 + BNE g, R8, 3(PC) + JAL runtime·badmorestackg0(SB) + JAL runtime·abort(SB) + + // Cannot grow signal stack (m->gsignal). + MOVW m_gsignal(R7), R8 + BNE g, R8, 3(PC) + JAL runtime·badmorestackgsignal(SB) + JAL runtime·abort(SB) + + // Called from f. + // Set g->sched to context in f. + MOVW R29, (g_sched+gobuf_sp)(g) + MOVW R31, (g_sched+gobuf_pc)(g) + MOVW R3, (g_sched+gobuf_lr)(g) + // newstack will fill gobuf.ctxt. + + // Called from f. + // Set m->morebuf to f's caller. + MOVW R3, (m_morebuf+gobuf_pc)(R7) // f's caller's PC + MOVW R29, (m_morebuf+gobuf_sp)(R7) // f's caller's SP + MOVW g, (m_morebuf+gobuf_g)(R7) + + // Call newstack on m->g0's stack. + MOVW m_g0(R7), g + JAL runtime·save_g(SB) + MOVW (g_sched+gobuf_sp)(g), R29 + // Create a stack frame on g0 to call newstack. + MOVW R0, -8(R29) // Zero saved LR in frame + ADDU $-8, R29 + MOVW REGCTXT, 4(R29) // ctxt argument + JAL runtime·newstack(SB) + + // Not reached, but make sure the return PC from the call to newstack + // is still in this function, and not the beginning of the next. + UNDEF + +TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0-0 + MOVW R0, REGCTXT + JMP runtime·morestack(SB) + +TEXT runtime·stackBarrier(SB),NOSPLIT,$0 + // We came here via a RET to an overwritten LR. + // R1 may be live. Other registers are available. + + // Get the original return PC, g.stkbar[g.stkbarPos].savedLRVal. + MOVW (g_stkbar+slice_array)(g), R2 + MOVW g_stkbarPos(g), R3 + MOVW $stkbar__size, R4 + MULU R3, R4 + MOVW LO, R4 + ADDU R2, R4 + MOVW stkbar_savedLRVal(R4), R4 + ADDU $1, R3 + MOVW R3, g_stkbarPos(g) // Record that this stack barrier was hit. + JMP (R4) // Jump to the original return PC. + +// reflectcall: call a function with the given argument list +// func call(argtype *_type, f *FuncVal, arg *byte, argsize, retoffset uint32). +// we don't have variable-sized frames, so we use a small number +// of constant-sized-frame functions to encode a few bits of size in the pc. + +#define DISPATCH(NAME,MAXSIZE) \ + MOVW $MAXSIZE, R23; \ + SGTU R1, R23, R23; \ + BNE R23, 3(PC); \ + MOVW $NAME(SB), R4; \ + JMP (R4) + +TEXT reflect·call(SB),NOSPLIT,$0-20 + JMP ·reflectcall(SB) + +TEXT ·reflectcall(SB),NOSPLIT,$-4-20 + MOVW argsize+12(FP), R1 + + DISPATCH(runtime·call16, 16) + DISPATCH(runtime·call32, 32) + DISPATCH(runtime·call64, 64) + DISPATCH(runtime·call128, 128) + DISPATCH(runtime·call256, 256) + DISPATCH(runtime·call512, 512) + DISPATCH(runtime·call1024, 1024) + DISPATCH(runtime·call2048, 2048) + DISPATCH(runtime·call4096, 4096) + DISPATCH(runtime·call8192, 8192) + DISPATCH(runtime·call16384, 16384) + DISPATCH(runtime·call32768, 32768) + DISPATCH(runtime·call65536, 65536) + DISPATCH(runtime·call131072, 131072) + DISPATCH(runtime·call262144, 262144) + DISPATCH(runtime·call524288, 524288) + DISPATCH(runtime·call1048576, 1048576) + DISPATCH(runtime·call2097152, 2097152) + DISPATCH(runtime·call4194304, 4194304) + DISPATCH(runtime·call8388608, 8388608) + DISPATCH(runtime·call16777216, 16777216) + DISPATCH(runtime·call33554432, 33554432) + DISPATCH(runtime·call67108864, 67108864) + DISPATCH(runtime·call134217728, 134217728) + DISPATCH(runtime·call268435456, 268435456) + DISPATCH(runtime·call536870912, 536870912) + DISPATCH(runtime·call1073741824, 1073741824) + MOVW $runtime·badreflectcall(SB), R4 + JMP (R4) + +#define CALLFN(NAME,MAXSIZE) \ +TEXT NAME(SB),WRAPPER,$MAXSIZE-20; \ + NO_LOCAL_POINTERS; \ + /* copy arguments to stack */ \ + MOVW arg+8(FP), R1; \ + MOVW argsize+12(FP), R2; \ + MOVW R29, R3; \ + ADDU $4, R3; \ + ADDU R3, R2; \ + BEQ R3, R2, 6(PC); \ + MOVBU (R1), R4; \ + ADDU $1, R1; \ + MOVBU R4, (R3); \ + ADDU $1, R3; \ + JMP -5(PC); \ + /* call function */ \ + MOVW f+4(FP), REGCTXT; \ + MOVW (REGCTXT), R4; \ + PCDATA $PCDATA_StackMapIndex, $0; \ + JAL (R4); \ + /* copy return values back */ \ + MOVW argtype+0(FP), R5; \ + MOVW arg+8(FP), R1; \ + MOVW n+12(FP), R2; \ + MOVW retoffset+16(FP), R4; \ + ADDU $4, R29, R3; \ + ADDU R4, R3; \ + ADDU R4, R1; \ + SUBU R4, R2; \ + JAL callRet<>(SB); \ + RET + +// callRet copies return values back at the end of call*. This is a +// separate function so it can allocate stack space for the arguments +// to reflectcallmove. It does not follow the Go ABI; it expects its +// arguments in registers. +TEXT callRet<>(SB), NOSPLIT, $16-0 + MOVW R5, 4(R29) + MOVW R1, 8(R29) + MOVW R3, 12(R29) + MOVW R2, 16(R29) + JAL runtime·reflectcallmove(SB) + RET + +CALLFN(·call16, 16) +CALLFN(·call32, 32) +CALLFN(·call64, 64) +CALLFN(·call128, 128) +CALLFN(·call256, 256) +CALLFN(·call512, 512) +CALLFN(·call1024, 1024) +CALLFN(·call2048, 2048) +CALLFN(·call4096, 4096) +CALLFN(·call8192, 8192) +CALLFN(·call16384, 16384) +CALLFN(·call32768, 32768) +CALLFN(·call65536, 65536) +CALLFN(·call131072, 131072) +CALLFN(·call262144, 262144) +CALLFN(·call524288, 524288) +CALLFN(·call1048576, 1048576) +CALLFN(·call2097152, 2097152) +CALLFN(·call4194304, 4194304) +CALLFN(·call8388608, 8388608) +CALLFN(·call16777216, 16777216) +CALLFN(·call33554432, 33554432) +CALLFN(·call67108864, 67108864) +CALLFN(·call134217728, 134217728) +CALLFN(·call268435456, 268435456) +CALLFN(·call536870912, 536870912) +CALLFN(·call1073741824, 1073741824) + +TEXT runtime·procyield(SB),NOSPLIT,$0-4 + RET + +// void jmpdefer(fv, sp); +// called from deferreturn. +// 1. grab stored LR for caller +// 2. sub 8 bytes to get back to JAL deferreturn +// 3. JMP to fn +TEXT runtime·jmpdefer(SB),NOSPLIT,$0-8 + MOVW 0(R29), R31 + ADDU $-8, R31 + + MOVW fv+0(FP), REGCTXT + MOVW argp+4(FP), R29 + ADDU $-4, R29 + NOR R0, R0 // prevent scheduling + MOVW 0(REGCTXT), R4 + JMP (R4) + +// Save state of caller into g->sched. Smashes R1. +TEXT gosave<>(SB),NOSPLIT,$0 + MOVW R31, (g_sched+gobuf_pc)(g) + MOVW R29, (g_sched+gobuf_sp)(g) + MOVW R0, (g_sched+gobuf_lr)(g) + MOVW R0, (g_sched+gobuf_ret)(g) + // Assert ctxt is zero. See func save. + MOVW (g_sched+gobuf_ctxt)(g), R1 + BEQ R1, 2(PC) + JAL runtime·badctxt(SB) + RET + +// func asmcgocall(fn, arg unsafe.Pointer) int32 +// Call fn(arg) on the scheduler stack, +// aligned appropriately for the gcc ABI. +// See cgocall.go for more details. +// Not implemented. +TEXT ·asmcgocall(SB),NOSPLIT,$0-12 + UNDEF + +// cgocallback(void (*fn)(void*), void *frame, uintptr framesize) +// Turn the fn into a Go func (by taking its address) and call +// cgocallback_gofunc. +// Not implemented. +TEXT runtime·cgocallback(SB),NOSPLIT,$0-16 + UNDEF + +// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize) +// See cgocall.go for more details. +// Not implemented. +TEXT ·cgocallback_gofunc(SB),NOSPLIT,$0-16 + UNDEF + +// void setg(G*); set g. for use by needm. +// This only happens if iscgo, so jump straight to save_g +TEXT runtime·setg(SB),NOSPLIT,$0-4 + MOVW gg+0(FP), g + JAL runtime·save_g(SB) + RET + +// void setg_gcc(G*); set g in C TLS. +// Must obey the gcc calling convention. +// Not implemented. +TEXT setg_gcc<>(SB),NOSPLIT,$0 + UNDEF + +TEXT runtime·getcallerpc(SB),NOSPLIT,$4-8 + MOVW 8(R29), R1 // LR saved by caller + MOVW runtime·stackBarrierPC(SB), R2 + BNE R1, R2, nobar + JAL runtime·nextBarrierPC(SB) // Get original return PC. + MOVW 4(R29), R1 +nobar: + MOVW R1, ret+4(FP) + RET + +TEXT runtime·setcallerpc(SB),NOSPLIT,$4-8 + MOVW pc+4(FP), R1 + MOVW 8(R29), R2 + MOVW runtime·stackBarrierPC(SB), R3 + BEQ R2, R3, setbar + MOVW R1, 8(R29) // set LR in caller + RET +setbar: + MOVW R1, 4(R29) + JAL runtime·setNextBarrierPC(SB) // Set the stack barrier return PC. + RET + +TEXT runtime·abort(SB),NOSPLIT,$0-0 + UNDEF + +// memhash_varlen(p unsafe.Pointer, h seed) uintptr +// redirects to memhash(p, h, size) using the size +// stored in the closure. +TEXT runtime·memhash_varlen(SB),NOSPLIT,$16-12 + GO_ARGS + NO_LOCAL_POINTERS + MOVW p+0(FP), R1 + MOVW h+4(FP), R2 + MOVW 4(REGCTXT), R3 + MOVW R1, 4(R29) + MOVW R2, 8(R29) + MOVW R3, 12(R29) + JAL runtime·memhash(SB) + MOVW 16(R29), R1 + MOVW R1, ret+8(FP) + RET + +// Not implemented. +TEXT runtime·aeshash(SB),NOSPLIT,$0 + UNDEF + +// Not implemented. +TEXT runtime·aeshash32(SB),NOSPLIT,$0 + UNDEF + +// Not implemented. +TEXT runtime·aeshash64(SB),NOSPLIT,$0 + UNDEF + +// Not implemented. +TEXT runtime·aeshashstr(SB),NOSPLIT,$0 + UNDEF + +// memequal(a, b unsafe.Pointer, size uintptr) bool +TEXT runtime·memequal(SB),NOSPLIT,$0-13 + MOVW a+0(FP), R1 + MOVW b+4(FP), R2 + BEQ R1, R2, eq + MOVW size+8(FP), R3 + ADDU R1, R3, R4 +loop: + BNE R1, R4, test + MOVW $1, R1 + MOVB R1, ret+12(FP) + RET +test: + MOVBU (R1), R6 + ADDU $1, R1 + MOVBU (R2), R7 + ADDU $1, R2 + BEQ R6, R7, loop + + MOVB R0, ret+12(FP) + RET +eq: + MOVW $1, R1 + MOVB R1, ret+12(FP) + RET + +// memequal_varlen(a, b unsafe.Pointer) bool +TEXT runtime·memequal_varlen(SB),NOSPLIT,$0-9 + MOVW a+0(FP), R1 + MOVW b+4(FP), R2 + BEQ R1, R2, eq + MOVW 4(REGCTXT), R3 // compiler stores size at offset 4 in the closure + ADDU R1, R3, R4 +loop: + BNE R1, R4, test + MOVW $1, R1 + MOVB R1, ret+8(FP) + RET +test: + MOVBU (R1), R6 + ADDU $1, R1 + MOVBU (R2), R7 + ADDU $1, R2 + BEQ R6, R7, loop + + MOVB R0, ret+8(FP) + RET +eq: + MOVW $1, R1 + MOVB R1, ret+8(FP) + RET + +// eqstring tests whether two strings are equal. +// The compiler guarantees that strings passed +// to eqstring have equal length. +// See runtime_test.go:eqstring_generic for +// equivalent Go code. +TEXT runtime·eqstring(SB),NOSPLIT,$0-17 + MOVW s1_base+0(FP), R1 + MOVW s2_base+8(FP), R2 + MOVW $1, R3 + MOVBU R3, ret+16(FP) + BNE R1, R2, 2(PC) + RET + MOVW s1_len+4(FP), R3 + ADDU R1, R3, R4 +loop: + BNE R1, R4, 2(PC) + RET + MOVBU (R1), R6 + ADDU $1, R1 + MOVBU (R2), R7 + ADDU $1, R2 + BEQ R6, R7, loop + MOVB R0, ret+16(FP) + RET + +TEXT bytes·Equal(SB),NOSPLIT,$0-25 + MOVW a_len+4(FP), R3 + MOVW b_len+16(FP), R4 + BNE R3, R4, noteq // unequal lengths are not equal + + MOVW a+0(FP), R1 + MOVW b+12(FP), R2 + ADDU R1, R3 // end + +loop: + BEQ R1, R3, equal // reached the end + MOVBU (R1), R6 + ADDU $1, R1 + MOVBU (R2), R7 + ADDU $1, R2 + BEQ R6, R7, loop + +noteq: + MOVB R0, ret+24(FP) + RET + +equal: + MOVW $1, R1 + MOVB R1, ret+24(FP) + RET + +TEXT bytes·IndexByte(SB),NOSPLIT,$0-20 + MOVW s+0(FP), R1 + MOVW s_len+4(FP), R2 + MOVBU c+12(FP), R3 // byte to find + ADDU $1, R1, R4 // store base+1 for later + ADDU R1, R2 // end + +loop: + BEQ R1, R2, notfound + MOVBU (R1), R5 + ADDU $1, R1 + BNE R3, R5, loop + + SUBU R4, R1 // R1 will be one beyond the position we want so remove (base+1) + MOVW R1, ret+16(FP) + RET + +notfound: + MOVW $-1, R1 + MOVW R1, ret+16(FP) + RET + +TEXT strings·IndexByte(SB),NOSPLIT,$0-16 + MOVW s_base+0(FP), R1 + MOVW s_len+4(FP), R2 + MOVBU c+8(FP), R3 // byte to find + ADDU $1, R1, R4 // store base+1 for later + ADDU R1, R2 // end + +loop: + BEQ R1, R2, notfound + MOVBU (R1), R5 + ADDU $1, R1 + BNE R3, R5, loop + + SUBU R4, R1 // remove (base+1) + MOVW R1, ret+12(FP) + RET + +notfound: + MOVW $-1, R1 + MOVW R1, ret+12(FP) + RET + +TEXT runtime·cmpstring(SB),NOSPLIT,$0-20 + MOVW s1_base+0(FP), R3 + MOVW s1_len+4(FP), R1 + MOVW s2_base+8(FP), R4 + MOVW s2_len+12(FP), R2 + BEQ R3, R4, samebytes + SGTU R1, R2, R7 + MOVW R1, R8 + CMOVN R7, R2, R8 // R8 is min(R1, R2) + + ADDU R3, R8 // R3 is current byte in s1, R8 is last byte in s1 to compare +loop: + BEQ R3, R8, samebytes // all compared bytes were the same; compare lengths + + MOVBU (R3), R6 + ADDU $1, R3 + MOVBU (R4), R7 + ADDU $1, R4 + BEQ R6, R7 , loop + // bytes differed + SGTU R6, R7, R8 + MOVW $-1, R6 + CMOVZ R8, R6, R8 + JMP cmp_ret +samebytes: + SGTU R1, R2, R6 + SGTU R2, R1, R7 + SUBU R7, R6, R8 +cmp_ret: + MOVW R8, ret+16(FP) + RET + +TEXT bytes·Compare(SB),NOSPLIT,$0-28 + MOVW s1_base+0(FP), R3 + MOVW s2_base+12(FP), R4 + MOVW s1_len+4(FP), R1 + MOVW s2_len+16(FP), R2 + BEQ R3, R4, samebytes + SGTU R1, R2, R7 + MOVW R1, R8 + CMOVN R7, R2, R8 // R8 is min(R1, R2) + + ADDU R3, R8 // R3 is current byte in s1, R8 is last byte in s1 to compare +loop: + BEQ R3, R8, samebytes + + MOVBU (R3), R6 + ADDU $1, R3 + MOVBU (R4), R7 + ADDU $1, R4 + BEQ R6, R7 , loop + + SGTU R6, R7, R8 + MOVW $-1, R6 + CMOVZ R8, R6, R8 + JMP cmp_ret +samebytes: + SGTU R1, R2, R6 + SGTU R2, R1, R7 + SUBU R7, R6, R8 +cmp_ret: + MOVW R8, ret+24(FP) + RET + +TEXT runtime·fastrand(SB),NOSPLIT,$0-4 + MOVW g_m(g), R2 + MOVW m_fastrand(R2), R1 + ADDU R1, R1 + BGEZ R1, 2(PC) + XOR $0x88888eef, R1 + MOVW R1, m_fastrand(R2) + MOVW R1, ret+0(FP) + RET + +TEXT runtime·return0(SB),NOSPLIT,$0 + MOVW $0, R1 + RET + +// Called from cgo wrappers, this function returns g->m->curg.stack.hi. +// Must obey the gcc calling convention. +// Not implemented. +TEXT _cgo_topofstack(SB),NOSPLIT,$-4 + UNDEF + +// The top-most function running on a goroutine +// returns to goexit+PCQuantum. +TEXT runtime·goexit(SB),NOSPLIT,$-4-0 + NOR R0, R0 // NOP + JAL runtime·goexit1(SB) // does not return + // traceback from goexit1 must hit code range of goexit + NOR R0, R0 // NOP + +TEXT runtime·prefetcht0(SB),NOSPLIT,$0-4 + RET + +TEXT runtime·prefetcht1(SB),NOSPLIT,$0-4 + RET + +TEXT runtime·prefetcht2(SB),NOSPLIT,$0-4 + RET + +TEXT runtime·prefetchnta(SB),NOSPLIT,$0-4 + RET + +TEXT ·checkASM(SB),NOSPLIT,$0-1 + MOVW $1, R1 + MOVB R1, ret+0(FP) + RET diff --git a/src/runtime/atomic_mipsx.s b/src/runtime/atomic_mipsx.s new file mode 100644 index 0000000000..ed078a2d8a --- /dev/null +++ b/src/runtime/atomic_mipsx.s @@ -0,0 +1,11 @@ +// Copyright 2016 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. + +// +build mips mipsle + +#include "textflag.h" + +TEXT ·publicationBarrier(SB),NOSPLIT,$0 + SYNC + RET diff --git a/src/runtime/cputicks.go b/src/runtime/cputicks.go index 91627460c3..ccc3947bb2 100644 --- a/src/runtime/cputicks.go +++ b/src/runtime/cputicks.go @@ -6,6 +6,8 @@ // +build !arm64 // +build !mips64 // +build !mips64le +// +build !mips +// +build !mipsle package runtime diff --git a/src/runtime/defs_linux_mipsx.go b/src/runtime/defs_linux_mipsx.go new file mode 100644 index 0000000000..702fbb51c8 --- /dev/null +++ b/src/runtime/defs_linux_mipsx.go @@ -0,0 +1,188 @@ +// Copyright 2016 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. + +// +build mips mipsle +// +build linux + +package runtime + +const ( + _EINTR = 0x4 + _EAGAIN = 0xb + _ENOMEM = 0xc + + _PROT_NONE = 0x0 + _PROT_READ = 0x1 + _PROT_WRITE = 0x2 + _PROT_EXEC = 0x4 + + _MAP_ANON = 0x800 + _MAP_PRIVATE = 0x2 + _MAP_FIXED = 0x10 + + _MADV_DONTNEED = 0x4 + _MADV_HUGEPAGE = 0xe + _MADV_NOHUGEPAGE = 0xf + + _SA_RESTART = 0x10000000 + _SA_ONSTACK = 0x8000000 + _SA_SIGINFO = 0x8 + + _SIGHUP = 0x1 + _SIGINT = 0x2 + _SIGQUIT = 0x3 + _SIGILL = 0x4 + _SIGTRAP = 0x5 + _SIGABRT = 0x6 + _SIGEMT = 0x7 + _SIGFPE = 0x8 + _SIGKILL = 0x9 + _SIGBUS = 0xa + _SIGSEGV = 0xb + _SIGSYS = 0xc + _SIGPIPE = 0xd + _SIGALRM = 0xe + _SIGUSR1 = 0x10 + _SIGUSR2 = 0x11 + _SIGCHLD = 0x12 + _SIGPWR = 0x13 + _SIGWINCH = 0x14 + _SIGURG = 0x15 + _SIGIO = 0x16 + _SIGSTOP = 0x17 + _SIGTSTP = 0x18 + _SIGCONT = 0x19 + _SIGTTIN = 0x1a + _SIGTTOU = 0x1b + _SIGVTALRM = 0x1c + _SIGPROF = 0x1d + _SIGXCPU = 0x1e + _SIGXFSZ = 0x1f + + _FPE_INTDIV = 0x1 + _FPE_INTOVF = 0x2 + _FPE_FLTDIV = 0x3 + _FPE_FLTOVF = 0x4 + _FPE_FLTUND = 0x5 + _FPE_FLTRES = 0x6 + _FPE_FLTINV = 0x7 + _FPE_FLTSUB = 0x8 + + _BUS_ADRALN = 0x1 + _BUS_ADRERR = 0x2 + _BUS_OBJERR = 0x3 + + _SEGV_MAPERR = 0x1 + _SEGV_ACCERR = 0x2 + + _ITIMER_REAL = 0x0 + _ITIMER_VIRTUAL = 0x1 + _ITIMER_PROF = 0x2 + + _EPOLLIN = 0x1 + _EPOLLOUT = 0x4 + _EPOLLERR = 0x8 + _EPOLLHUP = 0x10 + _EPOLLRDHUP = 0x2000 + _EPOLLET = 0x80000000 + _EPOLL_CLOEXEC = 0x80000 + _EPOLL_CTL_ADD = 0x1 + _EPOLL_CTL_DEL = 0x2 + _EPOLL_CTL_MOD = 0x3 +) + +type timespec struct { + tv_sec int32 + tv_nsec int32 +} + +//go:nosplit +func (ts *timespec) set_sec(x int64) { + ts.tv_sec = int32(x) +} + +//go:nosplit +func (ts *timespec) set_nsec(x int32) { + ts.tv_nsec = x +} + +type timeval struct { + tv_sec int32 + tv_usec int32 +} + +//go:nosplit +func (tv *timeval) set_usec(x int32) { + tv.tv_usec = x +} + +type sigactiont struct { + sa_flags uint32 + sa_handler uintptr + sa_mask [4]uint32 + // linux header does not have sa_restorer field, + // but it is used in setsig(). it is no harm to put it here + sa_restorer uintptr +} + +type siginfo struct { + si_signo int32 + si_code int32 + si_errno int32 + // below here is a union; si_addr is the only field we use + si_addr uint32 +} + +type itimerval struct { + it_interval timeval + it_value timeval +} + +type epollevent struct { + events uint32 + pad_cgo_0 [4]byte + data uint64 +} + +const ( + _O_RDONLY = 0x0 + _O_CLOEXEC = 0x80000 + _SA_RESTORER = 0 +) + +type stackt struct { + ss_sp *byte + ss_size uintptr + ss_flags int32 +} + +type sigcontext struct { + sc_regmask uint32 + sc_status uint32 + sc_pc uint64 + sc_regs [32]uint64 + sc_fpregs [32]uint64 + sc_acx uint32 + sc_fpc_csr uint32 + sc_fpc_eir uint32 + sc_used_math uint32 + sc_dsp uint32 + sc_mdhi uint64 + sc_mdlo uint64 + sc_hi1 uint32 + sc_lo1 uint32 + sc_hi2 uint32 + sc_lo2 uint32 + sc_hi3 uint32 + sc_lo3 uint32 +} + +type ucontext struct { + uc_flags uint32 + uc_link *ucontext + uc_stack stackt + Pad_cgo_0 [4]byte + uc_mcontext sigcontext + uc_sigmask [4]uint32 +} diff --git a/src/runtime/gcinfo_test.go b/src/runtime/gcinfo_test.go index 011f005403..14f514f96a 100644 --- a/src/runtime/gcinfo_test.go +++ b/src/runtime/gcinfo_test.go @@ -139,7 +139,7 @@ type BigStruct struct { func infoBigStruct() []byte { switch runtime.GOARCH { - case "386", "arm": + case "386", "arm", "mips", "mipsle": return []byte{ typePointer, // q *int typeScalar, typeScalar, typeScalar, typeScalar, typeScalar, // w byte; e [17]byte diff --git a/src/runtime/hash32.go b/src/runtime/hash32.go index 2b7c5c0c68..be59076635 100644 --- a/src/runtime/hash32.go +++ b/src/runtime/hash32.go @@ -6,7 +6,7 @@ // xxhash: https://code.google.com/p/xxhash/ // cityhash: https://code.google.com/p/cityhash/ -// +build 386 arm +// +build 386 arm mips mipsle package runtime diff --git a/src/runtime/lfstack_32bit.go b/src/runtime/lfstack_32bit.go index 2f59e0212e..d36ca50971 100644 --- a/src/runtime/lfstack_32bit.go +++ b/src/runtime/lfstack_32bit.go @@ -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 386 arm nacl +// +build 386 arm nacl mips mipsle package runtime diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 366fe9608d..1c9efc3432 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -141,10 +141,11 @@ const ( // See https://golang.org/issue/5402 and https://golang.org/issue/5236. // On other 64-bit platforms, we limit the arena to 512GB, or 39 bits. // On 32-bit, we don't bother limiting anything, so we use the full 32-bit address. + // The only exception is mips32 which only has access to low 2GB of virtual memory. // On Darwin/arm64, we cannot reserve more than ~5GB of virtual memory, // but as most devices have less than 4GB of physical memory anyway, we // try to be conservative here, and only ask for a 2GB heap. - _MHeapMap_TotalBits = (_64bit*sys.GoosWindows)*35 + (_64bit*(1-sys.GoosWindows)*(1-sys.GoosDarwin*sys.GoarchArm64))*39 + sys.GoosDarwin*sys.GoarchArm64*31 + (1-_64bit)*32 + _MHeapMap_TotalBits = (_64bit*sys.GoosWindows)*35 + (_64bit*(1-sys.GoosWindows)*(1-sys.GoosDarwin*sys.GoarchArm64))*39 + sys.GoosDarwin*sys.GoarchArm64*31 + (1-_64bit)*(32-(sys.GoarchMips+sys.GoarchMipsle)) _MHeapMap_Bits = _MHeapMap_TotalBits - _PageShift _MaxMem = uintptr(1<<_MHeapMap_TotalBits - 1) diff --git a/src/runtime/memclr_mipsx.s b/src/runtime/memclr_mipsx.s new file mode 100644 index 0000000000..ad013b8421 --- /dev/null +++ b/src/runtime/memclr_mipsx.s @@ -0,0 +1,71 @@ +// Copyright 2016 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. + +// +build mips mipsle + +#include "textflag.h" + +#ifdef GOARCH_mips +#define MOVWHI MOVWL +#define MOVWLO MOVWR +#else +#define MOVWHI MOVWR +#define MOVWLO MOVWL +#endif + +// void runtime·memclrNoHeapPointers(void*, uintptr) +TEXT runtime·memclrNoHeapPointers(SB),NOSPLIT,$0-8 + MOVW n+4(FP), R2 + MOVW ptr+0(FP), R1 + + SGTU $4, R2, R3 + ADDU R2, R1, R4 + BNE R3, small_zero + +ptr_align: + AND $3, R1, R3 + BEQ R3, setup + SUBU R1, R0, R3 + AND $3, R3 // R3 contains number of bytes needed to align ptr + MOVWHI R0, 0(R1) // MOVWHI will write zeros up to next word boundary + SUBU R3, R2 + ADDU R3, R1 + +setup: + AND $31, R2, R6 + AND $3, R2, R5 + SUBU R6, R4, R6 // end pointer for 32-byte chunks + SUBU R5, R4, R5 // end pointer for 4-byte chunks + +large: + BEQ R1, R6, words + MOVW R0, 0(R1) + MOVW R0, 4(R1) + MOVW R0, 8(R1) + MOVW R0, 12(R1) + MOVW R0, 16(R1) + MOVW R0, 20(R1) + MOVW R0, 24(R1) + MOVW R0, 28(R1) + ADDU $32, R1 + JMP large + +words: + BEQ R1, R5, tail + MOVW R0, 0(R1) + ADDU $4, R1 + JMP words + +tail: + BEQ R1, R4, ret + MOVWLO R0, -1(R4) + +ret: + RET + +small_zero: + BEQ R1, R4, ret + MOVB R0, 0(R1) + ADDU $1, R1 + JMP small_zero diff --git a/src/runtime/memmove_mipsx.s b/src/runtime/memmove_mipsx.s new file mode 100644 index 0000000000..e934e4d499 --- /dev/null +++ b/src/runtime/memmove_mipsx.s @@ -0,0 +1,258 @@ +// Copyright 2016 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. + +// +build mips mipsle + +#include "textflag.h" + +#ifdef GOARCH_mips +#define MOVWHI MOVWL +#define MOVWLO MOVWR +#else +#define MOVWHI MOVWR +#define MOVWLO MOVWL +#endif + +// void runtime·memmove(void*, void*, uintptr) +TEXT runtime·memmove(SB),NOSPLIT,$-0-12 + MOVW n+8(FP), R3 + MOVW from+4(FP), R2 + MOVW to+0(FP), R1 + + ADDU R3, R2, R4 // end pointer for source + ADDU R3, R1, R5 // end pointer for destination + + // if destination is ahead of source, start at the end of the buffer and go backward. + SGTU R1, R2, R6 + BNE R6, backward + + // if less than 4 bytes, use byte by byte copying + SGTU $4, R3, R6 + BNE R6, f_small_copy + + // align destination to 4 bytes + AND $3, R1, R6 + BEQ R6, f_dest_aligned + SUBU R1, R0, R6 + AND $3, R6 + MOVWHI 0(R2), R7 + SUBU R6, R3 + MOVWLO 3(R2), R7 + ADDU R6, R2 + MOVWHI R7, 0(R1) + ADDU R6, R1 + +f_dest_aligned: + AND $31, R3, R7 + AND $3, R3, R6 + SUBU R7, R5, R7 // end pointer for 32-byte chunks + SUBU R6, R5, R6 // end pointer for 4-byte chunks + + // if source is not aligned, use unaligned reads + AND $3, R2, R8 + BNE R8, f_large_ua + +f_large: + BEQ R1, R7, f_words + ADDU $32, R1 + MOVW 0(R2), R8 + MOVW 4(R2), R9 + MOVW 8(R2), R10 + MOVW 12(R2), R11 + MOVW 16(R2), R12 + MOVW 20(R2), R13 + MOVW 24(R2), R14 + MOVW 28(R2), R15 + ADDU $32, R2 + MOVW R8, -32(R1) + MOVW R9, -28(R1) + MOVW R10, -24(R1) + MOVW R11, -20(R1) + MOVW R12, -16(R1) + MOVW R13, -12(R1) + MOVW R14, -8(R1) + MOVW R15, -4(R1) + JMP f_large + +f_words: + BEQ R1, R6, f_tail + ADDU $4, R1 + MOVW 0(R2), R8 + ADDU $4, R2 + MOVW R8, -4(R1) + JMP f_words + +f_tail: + BEQ R1, R5, ret + MOVWLO -1(R4), R8 + MOVWLO R8, -1(R5) + +ret: + RET + +f_large_ua: + BEQ R1, R7, f_words_ua + ADDU $32, R1 + MOVWHI 0(R2), R8 + MOVWHI 4(R2), R9 + MOVWHI 8(R2), R10 + MOVWHI 12(R2), R11 + MOVWHI 16(R2), R12 + MOVWHI 20(R2), R13 + MOVWHI 24(R2), R14 + MOVWHI 28(R2), R15 + MOVWLO 3(R2), R8 + MOVWLO 7(R2), R9 + MOVWLO 11(R2), R10 + MOVWLO 15(R2), R11 + MOVWLO 19(R2), R12 + MOVWLO 23(R2), R13 + MOVWLO 27(R2), R14 + MOVWLO 31(R2), R15 + ADDU $32, R2 + MOVW R8, -32(R1) + MOVW R9, -28(R1) + MOVW R10, -24(R1) + MOVW R11, -20(R1) + MOVW R12, -16(R1) + MOVW R13, -12(R1) + MOVW R14, -8(R1) + MOVW R15, -4(R1) + JMP f_large_ua + +f_words_ua: + BEQ R1, R6, f_tail_ua + MOVWHI 0(R2), R8 + ADDU $4, R1 + MOVWLO 3(R2), R8 + ADDU $4, R2 + MOVW R8, -4(R1) + JMP f_words_ua + +f_tail_ua: + BEQ R1, R5, ret + MOVWHI -4(R4), R8 + MOVWLO -1(R4), R8 + MOVWLO R8, -1(R5) + JMP ret + +f_small_copy: + BEQ R1, R5, ret + ADDU $1, R1 + MOVB 0(R2), R6 + ADDU $1, R2 + MOVB R6, -1(R1) + JMP f_small_copy + +backward: + SGTU $4, R3, R6 + BNE R6, b_small_copy + + AND $3, R5, R6 + BEQ R6, b_dest_aligned + MOVWHI -4(R4), R7 + SUBU R6, R3 + MOVWLO -1(R4), R7 + SUBU R6, R4 + MOVWLO R7, -1(R5) + SUBU R6, R5 + +b_dest_aligned: + AND $31, R3, R7 + AND $3, R3, R6 + ADDU R7, R1, R7 + ADDU R6, R1, R6 + + AND $3, R4, R8 + BNE R8, b_large_ua + +b_large: + BEQ R5, R7, b_words + ADDU $-32, R5 + MOVW -4(R4), R8 + MOVW -8(R4), R9 + MOVW -12(R4), R10 + MOVW -16(R4), R11 + MOVW -20(R4), R12 + MOVW -24(R4), R13 + MOVW -28(R4), R14 + MOVW -32(R4), R15 + ADDU $-32, R4 + MOVW R8, 28(R5) + MOVW R9, 24(R5) + MOVW R10, 20(R5) + MOVW R11, 16(R5) + MOVW R12, 12(R5) + MOVW R13, 8(R5) + MOVW R14, 4(R5) + MOVW R15, 0(R5) + JMP b_large + +b_words: + BEQ R5, R6, b_tail + ADDU $-4, R5 + MOVW -4(R4), R8 + ADDU $-4, R4 + MOVW R8, 0(R5) + JMP b_words + +b_tail: + BEQ R5, R1, ret + MOVWHI 0(R2), R8 // R2 and R1 have the same alignment so we don't need to load a whole word + MOVWHI R8, 0(R1) + JMP ret + +b_large_ua: + BEQ R5, R7, b_words_ua + ADDU $-32, R5 + MOVWHI -4(R4), R8 + MOVWHI -8(R4), R9 + MOVWHI -12(R4), R10 + MOVWHI -16(R4), R11 + MOVWHI -20(R4), R12 + MOVWHI -24(R4), R13 + MOVWHI -28(R4), R14 + MOVWHI -32(R4), R15 + MOVWLO -1(R4), R8 + MOVWLO -5(R4), R9 + MOVWLO -9(R4), R10 + MOVWLO -13(R4), R11 + MOVWLO -17(R4), R12 + MOVWLO -21(R4), R13 + MOVWLO -25(R4), R14 + MOVWLO -29(R4), R15 + ADDU $-32, R4 + MOVW R8, 28(R5) + MOVW R9, 24(R5) + MOVW R10, 20(R5) + MOVW R11, 16(R5) + MOVW R12, 12(R5) + MOVW R13, 8(R5) + MOVW R14, 4(R5) + MOVW R15, 0(R5) + JMP b_large_ua + +b_words_ua: + BEQ R5, R6, b_tail_ua + MOVWHI -4(R4), R8 + ADDU $-4, R5 + MOVWLO -1(R4), R8 + ADDU $-4, R4 + MOVW R8, 0(R5) + JMP b_words_ua + +b_tail_ua: + BEQ R5, R1, ret + MOVWHI (R2), R8 + MOVWLO 3(R2), R8 + MOVWHI R8, 0(R1) + JMP ret + +b_small_copy: + BEQ R5, R1, ret + ADDU $-1, R5 + MOVB -1(R4), R6 + ADDU $-1, R4 + MOVB R6, 0(R5) + JMP b_small_copy diff --git a/src/runtime/os_linux_generic.go b/src/runtime/os_linux_generic.go index 43d0093c31..f672162eae 100644 --- a/src/runtime/os_linux_generic.go +++ b/src/runtime/os_linux_generic.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build !mips +// +build !mipsle // +build !mips64 // +build !mips64le // +build !s390x diff --git a/src/runtime/os_linux_mips64x.go b/src/runtime/os_linux_mips64x.go index 1c690fed0a..be2b71911b 100644 --- a/src/runtime/os_linux_mips64x.go +++ b/src/runtime/os_linux_mips64x.go @@ -30,7 +30,7 @@ func cputicks() int64 { const ( _SS_DISABLE = 2 - _NSIG = 65 + _NSIG = 129 _SI_USER = 0 _SIG_BLOCK = 1 _SIG_UNBLOCK = 2 diff --git a/src/runtime/os_linux_mipsx.go b/src/runtime/os_linux_mipsx.go new file mode 100644 index 0000000000..313da1b3b2 --- /dev/null +++ b/src/runtime/os_linux_mipsx.go @@ -0,0 +1,62 @@ +// Copyright 2016 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. + +// +build linux +// +build mips mipsle + +package runtime + +var randomNumber uint32 + +func archauxv(tag, val uintptr) { + switch tag { + case _AT_RANDOM: + // sysargs filled in startupRandomData, but that + // pointer may not be word aligned, so we must treat + // it as a byte array. + randomNumber = uint32(startupRandomData[4]) | uint32(startupRandomData[5])<<8 | + uint32(startupRandomData[6])<<16 | uint32(startupRandomData[7])<<24 + } +} + +//go:nosplit +func cputicks() int64 { + // Currently cputicks() is used in blocking profiler and to seed fastrand(). + // nanotime() is a poor approximation of CPU ticks that is enough for the profiler. + // randomNumber provides better seeding of fastrand1. + return nanotime() + int64(randomNumber) +} + +const ( + _SS_DISABLE = 2 + _NSIG = 128 + 1 + _SI_USER = 0 + _SIG_BLOCK = 1 + _SIG_UNBLOCK = 2 + _SIG_SETMASK = 3 + _RLIMIT_AS = 6 +) + +type sigset [4]uint32 + +type rlimit struct { + rlim_cur uintptr + rlim_max uintptr +} + +var sigset_all = sigset{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)} + +//go:nosplit +//go:nowritebarrierrec +func sigaddset(mask *sigset, i int) { + (*mask)[(i-1)/32] |= 1 << ((uint32(i) - 1) & 31) +} + +func sigdelset(mask *sigset, i int) { + (*mask)[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31) +} + +func sigfillset(mask *[4]uint32) { + (*mask)[0], (*mask)[1], (*mask)[2], (*mask)[3] = ^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0) +} diff --git a/src/runtime/os_linux_noauxv.go b/src/runtime/os_linux_noauxv.go index 3b0e34a337..5e9f03120d 100644 --- a/src/runtime/os_linux_noauxv.go +++ b/src/runtime/os_linux_noauxv.go @@ -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 !amd64,!arm,!arm64,!mips64,!mips64le,!s390x,!ppc64,!ppc64le +// +build !amd64,!arm,!arm64,!mips,!mipsle,!mips64,!mips64le,!s390x,!ppc64,!ppc64le package runtime diff --git a/src/runtime/rt0_linux_mipsx.s b/src/runtime/rt0_linux_mipsx.s new file mode 100644 index 0000000000..5e8c5c3161 --- /dev/null +++ b/src/runtime/rt0_linux_mipsx.s @@ -0,0 +1,27 @@ +// Copyright 2016 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. + +// +build linux +// +build mips mipsle + +#include "textflag.h" + +TEXT _rt0_mips_linux(SB),NOSPLIT,$0 + JMP _main<>(SB) + +TEXT _rt0_mipsle_linux(SB),NOSPLIT,$0 + JMP _main<>(SB) + +TEXT _main<>(SB),NOSPLIT,$-4 + // 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. + MOVW 0(R29), R1 // argc + ADD $4, R29, R2 // argv + JMP main(SB) + +TEXT main(SB),NOSPLIT,$-4 + MOVW $runtime·rt0_go(SB), R4 + JMP (R4) diff --git a/src/runtime/signal_linux_mipsx.go b/src/runtime/signal_linux_mipsx.go new file mode 100644 index 0000000000..c88ac4d521 --- /dev/null +++ b/src/runtime/signal_linux_mipsx.go @@ -0,0 +1,65 @@ +// Copyright 2016 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. + +// +build linux +// +build mips mipsle + +package runtime + +import "unsafe" + +type sigctxt struct { + info *siginfo + ctxt unsafe.Pointer +} + +func (c *sigctxt) regs() *sigcontext { return &(*ucontext)(c.ctxt).uc_mcontext } +func (c *sigctxt) r0() uint32 { return uint32(c.regs().sc_regs[0]) } +func (c *sigctxt) r1() uint32 { return uint32(c.regs().sc_regs[1]) } +func (c *sigctxt) r2() uint32 { return uint32(c.regs().sc_regs[2]) } +func (c *sigctxt) r3() uint32 { return uint32(c.regs().sc_regs[3]) } +func (c *sigctxt) r4() uint32 { return uint32(c.regs().sc_regs[4]) } +func (c *sigctxt) r5() uint32 { return uint32(c.regs().sc_regs[5]) } +func (c *sigctxt) r6() uint32 { return uint32(c.regs().sc_regs[6]) } +func (c *sigctxt) r7() uint32 { return uint32(c.regs().sc_regs[7]) } +func (c *sigctxt) r8() uint32 { return uint32(c.regs().sc_regs[8]) } +func (c *sigctxt) r9() uint32 { return uint32(c.regs().sc_regs[9]) } +func (c *sigctxt) r10() uint32 { return uint32(c.regs().sc_regs[10]) } +func (c *sigctxt) r11() uint32 { return uint32(c.regs().sc_regs[11]) } +func (c *sigctxt) r12() uint32 { return uint32(c.regs().sc_regs[12]) } +func (c *sigctxt) r13() uint32 { return uint32(c.regs().sc_regs[13]) } +func (c *sigctxt) r14() uint32 { return uint32(c.regs().sc_regs[14]) } +func (c *sigctxt) r15() uint32 { return uint32(c.regs().sc_regs[15]) } +func (c *sigctxt) r16() uint32 { return uint32(c.regs().sc_regs[16]) } +func (c *sigctxt) r17() uint32 { return uint32(c.regs().sc_regs[17]) } +func (c *sigctxt) r18() uint32 { return uint32(c.regs().sc_regs[18]) } +func (c *sigctxt) r19() uint32 { return uint32(c.regs().sc_regs[19]) } +func (c *sigctxt) r20() uint32 { return uint32(c.regs().sc_regs[20]) } +func (c *sigctxt) r21() uint32 { return uint32(c.regs().sc_regs[21]) } +func (c *sigctxt) r22() uint32 { return uint32(c.regs().sc_regs[22]) } +func (c *sigctxt) r23() uint32 { return uint32(c.regs().sc_regs[23]) } +func (c *sigctxt) r24() uint32 { return uint32(c.regs().sc_regs[24]) } +func (c *sigctxt) r25() uint32 { return uint32(c.regs().sc_regs[25]) } +func (c *sigctxt) r26() uint32 { return uint32(c.regs().sc_regs[26]) } +func (c *sigctxt) r27() uint32 { return uint32(c.regs().sc_regs[27]) } +func (c *sigctxt) r28() uint32 { return uint32(c.regs().sc_regs[28]) } +func (c *sigctxt) r29() uint32 { return uint32(c.regs().sc_regs[29]) } +func (c *sigctxt) r30() uint32 { return uint32(c.regs().sc_regs[30]) } +func (c *sigctxt) r31() uint32 { return uint32(c.regs().sc_regs[31]) } +func (c *sigctxt) sp() uint32 { return uint32(c.regs().sc_regs[29]) } +func (c *sigctxt) pc() uint32 { return uint32(c.regs().sc_pc) } +func (c *sigctxt) link() uint32 { return uint32(c.regs().sc_regs[31]) } +func (c *sigctxt) lo() uint32 { return uint32(c.regs().sc_mdlo) } +func (c *sigctxt) hi() uint32 { return uint32(c.regs().sc_mdhi) } + +func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) } +func (c *sigctxt) sigaddr() uint32 { return c.info.si_addr } + +func (c *sigctxt) set_r30(x uint32) { c.regs().sc_regs[30] = uint64(x) } +func (c *sigctxt) set_pc(x uint32) { c.regs().sc_pc = uint64(x) } +func (c *sigctxt) set_sp(x uint32) { c.regs().sc_regs[29] = uint64(x) } +func (c *sigctxt) set_link(x uint32) { c.regs().sc_regs[31] = uint64(x) } + +func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) } +func (c *sigctxt) set_sigaddr(x uint32) { c.info.si_addr = x } diff --git a/src/runtime/signal_mipsx.go b/src/runtime/signal_mipsx.go new file mode 100644 index 0000000000..62df79caeb --- /dev/null +++ b/src/runtime/signal_mipsx.go @@ -0,0 +1,91 @@ +// Copyright 2016 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. + +// +build linux +// +build mips mipsle + +package runtime + +import ( + "runtime/internal/sys" + "unsafe" +) + +func dumpregs(c *sigctxt) { + print("r0 ", hex(c.r0()), "\t") + print("r1 ", hex(c.r1()), "\n") + print("r2 ", hex(c.r2()), "\t") + print("r3 ", hex(c.r3()), "\n") + print("r4 ", hex(c.r4()), "\t") + print("r5 ", hex(c.r5()), "\n") + print("r6 ", hex(c.r6()), "\t") + print("r7 ", hex(c.r7()), "\n") + print("r8 ", hex(c.r8()), "\t") + print("r9 ", hex(c.r9()), "\n") + print("r10 ", hex(c.r10()), "\t") + print("r11 ", hex(c.r11()), "\n") + print("r12 ", hex(c.r12()), "\t") + print("r13 ", hex(c.r13()), "\n") + print("r14 ", hex(c.r14()), "\t") + print("r15 ", hex(c.r15()), "\n") + print("r16 ", hex(c.r16()), "\t") + print("r17 ", hex(c.r17()), "\n") + print("r18 ", hex(c.r18()), "\t") + print("r19 ", hex(c.r19()), "\n") + print("r20 ", hex(c.r20()), "\t") + print("r21 ", hex(c.r21()), "\n") + print("r22 ", hex(c.r22()), "\t") + print("r23 ", hex(c.r23()), "\n") + print("r24 ", hex(c.r24()), "\t") + print("r25 ", hex(c.r25()), "\n") + print("r26 ", hex(c.r26()), "\t") + print("r27 ", hex(c.r27()), "\n") + print("r28 ", hex(c.r28()), "\t") + print("r29 ", hex(c.r29()), "\n") + print("r30 ", hex(c.r30()), "\t") + print("r31 ", hex(c.r31()), "\n") + print("pc ", hex(c.pc()), "\t") + print("link ", hex(c.link()), "\n") + print("lo ", hex(c.lo()), "\t") + print("hi ", hex(c.hi()), "\n") +} + +func (c *sigctxt) sigpc() uintptr { return uintptr(c.pc()) } +func (c *sigctxt) sigsp() uintptr { return uintptr(c.sp()) } +func (c *sigctxt) siglr() uintptr { return uintptr(c.link()) } +func (c *sigctxt) fault() uintptr { return uintptr(c.sigaddr()) } + +// preparePanic sets up the stack to look like a call to sigpanic. +func (c *sigctxt) preparePanic(sig uint32, gp *g) { + // We arrange link, and pc to pretend the panicking + // function calls sigpanic directly. + // Always save LINK to stack so that panics in leaf + // functions are correctly handled. This smashes + // the stack frame but we're not going back there + // anyway. + sp := c.sp() - sys.MinFrameSize + c.set_sp(sp) + *(*uint32)(unsafe.Pointer(uintptr(sp))) = c.link() + + pc := gp.sigpc + + // If we don't recognize the PC as code + // but we do recognize the link register as code, + // then assume this was a call to non-code and treat like + // pc == 0, to make unwinding show the context. + if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.link())) != nil { + pc = 0 + } + + // Don't bother saving PC if it's zero, which is + // probably a call to a nil func: the old link register + // is more useful in the stack trace. + if pc != 0 { + c.set_link(uint32(pc)) + } + + // In case we are panicking from external C code + c.set_r30(uint32(uintptr(unsafe.Pointer(gp)))) + c.set_pc(uint32(funcPC(sigpanic))) +} diff --git a/src/runtime/sigtab_linux_generic.go b/src/runtime/sigtab_linux_generic.go index ea36bf3645..874148e1d2 100644 --- a/src/runtime/sigtab_linux_generic.go +++ b/src/runtime/sigtab_linux_generic.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build !mips +// +build !mipsle // +build !mips64 // +build !mips64le // +build linux diff --git a/src/runtime/sigtab_linux_mips64x.go b/src/runtime/sigtab_linux_mips64x.go deleted file mode 100644 index 201fe3deeb..0000000000 --- a/src/runtime/sigtab_linux_mips64x.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2015 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. - -// +build mips64 mips64le -// +build linux - -package runtime - -type sigTabT struct { - flags int32 - name string -} - -var sigtable = [...]sigTabT{ - /* 0 */ {0, "SIGNONE: no trap"}, - /* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"}, - /* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"}, - /* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"}, - /* 4 */ {_SigThrow + _SigUnblock, "SIGILL: illegal instruction"}, - /* 5 */ {_SigThrow + _SigUnblock, "SIGTRAP: trace trap"}, - /* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"}, - /* 7 */ {_SigThrow, "SIGEMT"}, - /* 8 */ {_SigPanic + _SigUnblock, "SIGFPE: floating-point exception"}, - /* 9 */ {0, "SIGKILL: kill"}, - /* 10 */ {_SigPanic + _SigUnblock, "SIGBUS: bus error"}, - /* 11 */ {_SigPanic + _SigUnblock, "SIGSEGV: segmentation violation"}, - /* 12 */ {_SigThrow, "SIGSYS: bad system call"}, - /* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"}, - /* 14 */ {_SigNotify, "SIGALRM: alarm clock"}, - /* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"}, - /* 16 */ {_SigNotify, "SIGUSR1: user-defined signal 1"}, - /* 17 */ {_SigNotify, "SIGUSR2: user-defined signal 2"}, - /* 18 */ {_SigNotify + _SigUnblock, "SIGCHLD: child status has changed"}, - /* 19 */ {_SigNotify, "SIGPWR: power failure restart"}, - /* 20 */ {_SigNotify, "SIGWINCH: window size change"}, - /* 21 */ {_SigNotify, "SIGURG: urgent condition on socket"}, - /* 22 */ {_SigNotify, "SIGIO: i/o now possible"}, - /* 23 */ {0, "SIGSTOP: stop, unblockable"}, - /* 24 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"}, - /* 25 */ {_SigNotify + _SigDefault, "SIGCONT: continue"}, - /* 26 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"}, - /* 27 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"}, - /* 28 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"}, - /* 29 */ {_SigNotify + _SigUnblock, "SIGPROF: profiling alarm clock"}, - /* 30 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"}, - /* 31 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"}, - /* 32 */ {_SigSetStack + _SigUnblock, "signal 32"}, /* SIGCANCEL; see issue 6997 */ - /* 33 */ {_SigSetStack + _SigUnblock, "signal 33"}, /* SIGSETXID; see issues 3871, 9400, 12498 */ - /* 34 */ {_SigNotify, "signal 34"}, - /* 35 */ {_SigNotify, "signal 35"}, - /* 36 */ {_SigNotify, "signal 36"}, - /* 37 */ {_SigNotify, "signal 37"}, - /* 38 */ {_SigNotify, "signal 38"}, - /* 39 */ {_SigNotify, "signal 39"}, - /* 40 */ {_SigNotify, "signal 40"}, - /* 41 */ {_SigNotify, "signal 41"}, - /* 42 */ {_SigNotify, "signal 42"}, - /* 43 */ {_SigNotify, "signal 43"}, - /* 44 */ {_SigNotify, "signal 44"}, - /* 45 */ {_SigNotify, "signal 45"}, - /* 46 */ {_SigNotify, "signal 46"}, - /* 47 */ {_SigNotify, "signal 47"}, - /* 48 */ {_SigNotify, "signal 48"}, - /* 49 */ {_SigNotify, "signal 49"}, - /* 50 */ {_SigNotify, "signal 50"}, - /* 51 */ {_SigNotify, "signal 51"}, - /* 52 */ {_SigNotify, "signal 52"}, - /* 53 */ {_SigNotify, "signal 53"}, - /* 54 */ {_SigNotify, "signal 54"}, - /* 55 */ {_SigNotify, "signal 55"}, - /* 56 */ {_SigNotify, "signal 56"}, - /* 57 */ {_SigNotify, "signal 57"}, - /* 58 */ {_SigNotify, "signal 58"}, - /* 59 */ {_SigNotify, "signal 59"}, - /* 60 */ {_SigNotify, "signal 60"}, - /* 61 */ {_SigNotify, "signal 61"}, - /* 62 */ {_SigNotify, "signal 62"}, - /* 63 */ {_SigNotify, "signal 63"}, - /* 64 */ {_SigNotify, "signal 64"}, -} diff --git a/src/runtime/sigtab_linux_mipsx.go b/src/runtime/sigtab_linux_mipsx.go new file mode 100644 index 0000000000..8d9fb06704 --- /dev/null +++ b/src/runtime/sigtab_linux_mipsx.go @@ -0,0 +1,145 @@ +// Copyright 2015 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. + +// +build mips mipsle mips64 mips64le +// +build linux + +package runtime + +type sigTabT struct { + flags int32 + name string +} + +var sigtable = [...]sigTabT{ + /* 0 */ {0, "SIGNONE: no trap"}, + /* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"}, + /* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"}, + /* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"}, + /* 4 */ {_SigThrow + _SigUnblock, "SIGILL: illegal instruction"}, + /* 5 */ {_SigThrow + _SigUnblock, "SIGTRAP: trace trap"}, + /* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"}, + /* 7 */ {_SigThrow, "SIGEMT"}, + /* 8 */ {_SigPanic + _SigUnblock, "SIGFPE: floating-point exception"}, + /* 9 */ {0, "SIGKILL: kill"}, + /* 10 */ {_SigPanic + _SigUnblock, "SIGBUS: bus error"}, + /* 11 */ {_SigPanic + _SigUnblock, "SIGSEGV: segmentation violation"}, + /* 12 */ {_SigThrow, "SIGSYS: bad system call"}, + /* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"}, + /* 14 */ {_SigNotify, "SIGALRM: alarm clock"}, + /* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"}, + /* 16 */ {_SigNotify, "SIGUSR1: user-defined signal 1"}, + /* 17 */ {_SigNotify, "SIGUSR2: user-defined signal 2"}, + /* 18 */ {_SigNotify + _SigUnblock, "SIGCHLD: child status has changed"}, + /* 19 */ {_SigNotify, "SIGPWR: power failure restart"}, + /* 20 */ {_SigNotify, "SIGWINCH: window size change"}, + /* 21 */ {_SigNotify, "SIGURG: urgent condition on socket"}, + /* 22 */ {_SigNotify, "SIGIO: i/o now possible"}, + /* 23 */ {0, "SIGSTOP: stop, unblockable"}, + /* 24 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"}, + /* 25 */ {_SigNotify + _SigDefault, "SIGCONT: continue"}, + /* 26 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"}, + /* 27 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"}, + /* 28 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"}, + /* 29 */ {_SigNotify + _SigUnblock, "SIGPROF: profiling alarm clock"}, + /* 30 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"}, + /* 31 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"}, + /* 32 */ {_SigSetStack + _SigUnblock, "signal 32"}, /* SIGCANCEL; see issue 6997 */ + /* 33 */ {_SigSetStack + _SigUnblock, "signal 33"}, /* SIGSETXID; see issues 3871, 9400, 12498 */ + /* 34 */ {_SigNotify, "signal 34"}, + /* 35 */ {_SigNotify, "signal 35"}, + /* 36 */ {_SigNotify, "signal 36"}, + /* 37 */ {_SigNotify, "signal 37"}, + /* 38 */ {_SigNotify, "signal 38"}, + /* 39 */ {_SigNotify, "signal 39"}, + /* 40 */ {_SigNotify, "signal 40"}, + /* 41 */ {_SigNotify, "signal 41"}, + /* 42 */ {_SigNotify, "signal 42"}, + /* 43 */ {_SigNotify, "signal 43"}, + /* 44 */ {_SigNotify, "signal 44"}, + /* 45 */ {_SigNotify, "signal 45"}, + /* 46 */ {_SigNotify, "signal 46"}, + /* 47 */ {_SigNotify, "signal 47"}, + /* 48 */ {_SigNotify, "signal 48"}, + /* 49 */ {_SigNotify, "signal 49"}, + /* 50 */ {_SigNotify, "signal 50"}, + /* 51 */ {_SigNotify, "signal 51"}, + /* 52 */ {_SigNotify, "signal 52"}, + /* 53 */ {_SigNotify, "signal 53"}, + /* 54 */ {_SigNotify, "signal 54"}, + /* 55 */ {_SigNotify, "signal 55"}, + /* 56 */ {_SigNotify, "signal 56"}, + /* 57 */ {_SigNotify, "signal 57"}, + /* 58 */ {_SigNotify, "signal 58"}, + /* 59 */ {_SigNotify, "signal 59"}, + /* 60 */ {_SigNotify, "signal 60"}, + /* 61 */ {_SigNotify, "signal 61"}, + /* 62 */ {_SigNotify, "signal 62"}, + /* 63 */ {_SigNotify, "signal 63"}, + /* 64 */ {_SigNotify, "signal 64"}, + /* 65 */ {_SigNotify, "signal 65"}, + /* 66 */ {_SigNotify, "signal 66"}, + /* 67 */ {_SigNotify, "signal 67"}, + /* 68 */ {_SigNotify, "signal 68"}, + /* 69 */ {_SigNotify, "signal 69"}, + /* 70 */ {_SigNotify, "signal 70"}, + /* 71 */ {_SigNotify, "signal 71"}, + /* 72 */ {_SigNotify, "signal 72"}, + /* 73 */ {_SigNotify, "signal 73"}, + /* 74 */ {_SigNotify, "signal 74"}, + /* 75 */ {_SigNotify, "signal 75"}, + /* 76 */ {_SigNotify, "signal 76"}, + /* 77 */ {_SigNotify, "signal 77"}, + /* 78 */ {_SigNotify, "signal 78"}, + /* 79 */ {_SigNotify, "signal 79"}, + /* 80 */ {_SigNotify, "signal 80"}, + /* 81 */ {_SigNotify, "signal 81"}, + /* 82 */ {_SigNotify, "signal 82"}, + /* 83 */ {_SigNotify, "signal 83"}, + /* 84 */ {_SigNotify, "signal 84"}, + /* 85 */ {_SigNotify, "signal 85"}, + /* 86 */ {_SigNotify, "signal 86"}, + /* 87 */ {_SigNotify, "signal 87"}, + /* 88 */ {_SigNotify, "signal 88"}, + /* 89 */ {_SigNotify, "signal 89"}, + /* 90 */ {_SigNotify, "signal 90"}, + /* 91 */ {_SigNotify, "signal 91"}, + /* 92 */ {_SigNotify, "signal 92"}, + /* 93 */ {_SigNotify, "signal 93"}, + /* 94 */ {_SigNotify, "signal 94"}, + /* 95 */ {_SigNotify, "signal 95"}, + /* 96 */ {_SigNotify, "signal 96"}, + /* 97 */ {_SigNotify, "signal 97"}, + /* 98 */ {_SigNotify, "signal 98"}, + /* 99 */ {_SigNotify, "signal 99"}, + /* 100 */ {_SigNotify, "signal 100"}, + /* 101 */ {_SigNotify, "signal 101"}, + /* 102 */ {_SigNotify, "signal 102"}, + /* 103 */ {_SigNotify, "signal 103"}, + /* 104 */ {_SigNotify, "signal 104"}, + /* 105 */ {_SigNotify, "signal 105"}, + /* 106 */ {_SigNotify, "signal 106"}, + /* 107 */ {_SigNotify, "signal 107"}, + /* 108 */ {_SigNotify, "signal 108"}, + /* 109 */ {_SigNotify, "signal 109"}, + /* 110 */ {_SigNotify, "signal 110"}, + /* 111 */ {_SigNotify, "signal 111"}, + /* 112 */ {_SigNotify, "signal 112"}, + /* 113 */ {_SigNotify, "signal 113"}, + /* 114 */ {_SigNotify, "signal 114"}, + /* 115 */ {_SigNotify, "signal 115"}, + /* 116 */ {_SigNotify, "signal 116"}, + /* 117 */ {_SigNotify, "signal 117"}, + /* 118 */ {_SigNotify, "signal 118"}, + /* 119 */ {_SigNotify, "signal 119"}, + /* 120 */ {_SigNotify, "signal 120"}, + /* 121 */ {_SigNotify, "signal 121"}, + /* 122 */ {_SigNotify, "signal 122"}, + /* 123 */ {_SigNotify, "signal 123"}, + /* 124 */ {_SigNotify, "signal 124"}, + /* 125 */ {_SigNotify, "signal 125"}, + /* 126 */ {_SigNotify, "signal 126"}, + /* 127 */ {_SigNotify, "signal 127"}, + /* 128 */ {_SigNotify, "signal 128"}, +} diff --git a/src/runtime/stubs32.go b/src/runtime/stubs32.go index cd442e92dc..149560fd93 100644 --- a/src/runtime/stubs32.go +++ b/src/runtime/stubs32.go @@ -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 386 arm amd64p32 +// +build 386 arm amd64p32 mips mipsle package runtime diff --git a/src/runtime/sys_linux_mipsx.s b/src/runtime/sys_linux_mipsx.s new file mode 100644 index 0000000000..6f089f5932 --- /dev/null +++ b/src/runtime/sys_linux_mipsx.s @@ -0,0 +1,467 @@ +// Copyright 2016 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. + +// +build linux +// +build mips mipsle + +// +// System calls and other sys.stuff for mips, Linux +// + +#include "go_asm.h" +#include "go_tls.h" +#include "textflag.h" + +#define SYS_exit 4001 +#define SYS_read 4003 +#define SYS_write 4004 +#define SYS_open 4005 +#define SYS_close 4006 +#define SYS_getpid 4020 +#define SYS_kill 4037 +#define SYS_fcntl 4055 +#define SYS_gettimeofday 4078 +#define SYS_mmap 4090 +#define SYS_munmap 4091 +#define SYS_setitimer 4104 +#define SYS_clone 4120 +#define SYS_newselect 4142 +#define SYS_sched_yield 4162 +#define SYS_rt_sigreturn 4193 +#define SYS_rt_sigaction 4194 +#define SYS_rt_sigprocmask 4195 +#define SYS_sigaltstack 4206 +#define SYS_getrlimit 4076 +#define SYS_madvise 4218 +#define SYS_mincore 4217 +#define SYS_gettid 4222 +#define SYS_tkill 4236 +#define SYS_futex 4238 +#define SYS_sched_getaffinity 4240 +#define SYS_exit_group 4246 +#define SYS_epoll_create 4248 +#define SYS_epoll_ctl 4249 +#define SYS_epoll_wait 4250 +#define SYS_clock_gettime 4263 +#define SYS_epoll_create1 4326 + +TEXT runtime·exit(SB),NOSPLIT,$0-4 + MOVW code+0(FP), R4 + MOVW $SYS_exit_group, R2 + SYSCALL + UNDEF + RET + +TEXT runtime·exit1(SB),NOSPLIT,$0-4 + MOVW code+0(FP), R4 + MOVW $SYS_exit, R2 + SYSCALL + UNDEF + RET + +TEXT runtime·open(SB),NOSPLIT,$0-16 + MOVW name+0(FP), R4 + MOVW mode+4(FP), R5 + MOVW perm+8(FP), R6 + MOVW $SYS_open, R2 + SYSCALL + BEQ R7, 2(PC) + MOVW $-1, R2 + MOVW R2, ret+12(FP) + RET + +TEXT runtime·closefd(SB),NOSPLIT,$0-8 + MOVW fd+0(FP), R4 + MOVW $SYS_close, R2 + SYSCALL + BEQ R7, 2(PC) + MOVW $-1, R2 + MOVW R2, ret+4(FP) + RET + +TEXT runtime·write(SB),NOSPLIT,$0-16 + MOVW fd+0(FP), R4 + MOVW p+4(FP), R5 + MOVW n+8(FP), R6 + MOVW $SYS_write, R2 + SYSCALL + BEQ R7, 2(PC) + MOVW $-1, R2 + MOVW R2, ret+12(FP) + RET + +TEXT runtime·read(SB),NOSPLIT,$0-16 + MOVW fd+0(FP), R4 + MOVW p+4(FP), R5 + MOVW n+8(FP), R6 + MOVW $SYS_read, R2 + SYSCALL + BEQ R7, 2(PC) + MOVW $-1, R2 + MOVW R2, ret+12(FP) + RET + +TEXT runtime·getrlimit(SB),NOSPLIT,$0-12 + MOVW kind+0(FP), R4 + MOVW limit+4(FP), R5 + MOVW $SYS_getrlimit, R2 + SYSCALL + MOVW R2, ret+8(FP) + RET + +TEXT runtime·usleep(SB),NOSPLIT,$28-4 + MOVW usec+0(FP), R3 + MOVW R3, R5 + MOVW $1000000, R4 + DIVU R4, R3 + MOVW LO, R3 + MOVW R3, 24(R29) + MULU R3, R4 + MOVW LO, R4 + SUBU R4, R5 + MOVW R5, 28(R29) + + // select(0, 0, 0, 0, &tv) + MOVW $0, R4 + MOVW $0, R5 + MOVW $0, R6 + MOVW $0, R7 + ADDU $24, R29, R8 + MOVW R8, 16(R29) + MOVW $SYS_newselect, R2 + SYSCALL + RET + +TEXT runtime·gettid(SB),NOSPLIT,$0-4 + MOVW $SYS_gettid, R2 + SYSCALL + MOVW R2, ret+0(FP) + RET + +TEXT runtime·raise(SB),NOSPLIT,$0-4 + MOVW $SYS_gettid, R2 + SYSCALL + MOVW R2, R4 // arg 1 tid + MOVW sig+0(FP), R5 // arg 2 + MOVW $SYS_tkill, R2 + SYSCALL + RET + +TEXT runtime·raiseproc(SB),NOSPLIT,$0 + MOVW $SYS_getpid, R2 + SYSCALL + MOVW R2, R4 // arg 1 pid + MOVW sig+0(FP), R5 // arg 2 + MOVW $SYS_kill, R2 + SYSCALL + RET + +TEXT runtime·setitimer(SB),NOSPLIT,$0-12 + MOVW mode+0(FP), R4 + MOVW new+4(FP), R5 + MOVW old+8(FP), R6 + MOVW $SYS_setitimer, R2 + SYSCALL + RET + +TEXT runtime·mincore(SB),NOSPLIT,$0-16 + MOVW addr+0(FP), R4 + MOVW n+4(FP), R5 + MOVW dst+8(FP), R6 + MOVW $SYS_mincore, R2 + SYSCALL + SUBU R2, R0, R2 // caller expects negative errno + MOVW R2, ret+12(FP) + RET + +// func now() (sec int64, nsec int32) +TEXT time·now(SB),NOSPLIT,$8-12 + MOVW $0, R4 // CLOCK_REALTIME + MOVW $4(R29), R5 + MOVW $SYS_clock_gettime, R2 + SYSCALL + MOVW 4(R29), R3 // sec + MOVW 8(R29), R5 // nsec +#ifdef GOARCH_mips + MOVW R3, sec_lo+4(FP) + MOVW R0, sec_hi+0(FP) +#else + MOVW R3, sec_lo+0(FP) + MOVW R0, sec_hi+4(FP) +#endif + MOVW R5, nsec+8(FP) + RET + +TEXT runtime·nanotime(SB),NOSPLIT,$8-8 + MOVW $1, R4 // CLOCK_MONOTONIC + MOVW $4(R29), R5 + MOVW $SYS_clock_gettime, R2 + SYSCALL + MOVW 4(R29), R3 // sec + MOVW 8(R29), R5 // nsec + // sec is in R3, nsec in R5 + // return nsec in R3 + MOVW $1000000000, R4 + MULU R4, R3 + MOVW LO, R3 + ADDU R5, R3 + SGTU R5, R3, R4 +#ifdef GOARCH_mips + MOVW R3, ret_lo+4(FP) +#else + MOVW R3, ret_lo+0(FP) +#endif + MOVW HI, R3 + ADDU R4, R3 +#ifdef GOARCH_mips + MOVW R3, ret_hi+0(FP) +#else + MOVW R3, ret_hi+4(FP) +#endif + RET + +TEXT runtime·rtsigprocmask(SB),NOSPLIT,$0-16 + MOVW how+0(FP), R4 + MOVW new+4(FP), R5 + MOVW old+8(FP), R6 + MOVW size+12(FP), R7 + MOVW $SYS_rt_sigprocmask, R2 + SYSCALL + BEQ R7, 2(PC) + UNDEF // crash + RET + +TEXT runtime·rt_sigaction(SB),NOSPLIT,$0-20 + MOVW sig+0(FP), R4 + MOVW new+4(FP), R5 + MOVW old+8(FP), R6 + MOVW size+12(FP), R7 + MOVW $SYS_rt_sigaction, R2 + SYSCALL + MOVW R2, ret+16(FP) + RET + +TEXT runtime·sigfwd(SB),NOSPLIT,$0-16 + MOVW sig+4(FP), R4 + MOVW info+8(FP), R5 + MOVW ctx+12(FP), R6 + MOVW fn+0(FP), R25 + MOVW R29, R22 + SUBU $16, R29 + AND $0x7, R29 // shadow space for 4 args aligned to 8 bytes as per O32 ABI + JAL (R25) + MOVW R22, R29 + RET + +TEXT runtime·sigtramp(SB),NOSPLIT,$12 + // 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, 4(R29) + MOVW R5, 8(R29) + MOVW R6, 12(R29) + MOVW $runtime·sigtrampgo(SB), R1 + JAL (R1) + RET + +TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0 + JMP runtime·sigtramp(SB) + +TEXT runtime·mmap(SB),NOSPLIT,$20-28 + MOVW addr+0(FP), R4 + MOVW n+4(FP), R5 + MOVW prot+8(FP), R6 + MOVW flags+12(FP), R7 + MOVW fd+16(FP), R8 + MOVW off+20(FP), R9 + MOVW R8, 16(R29) + MOVW R9, 20(R29) + + MOVW $SYS_mmap, R2 + SYSCALL + MOVW R2, ret+24(FP) + RET + +TEXT runtime·munmap(SB),NOSPLIT,$0-8 + MOVW addr+0(FP), R4 + MOVW n+4(FP), R5 + MOVW $SYS_munmap, R2 + SYSCALL + BEQ R7, 2(PC) + UNDEF // crash + RET + +TEXT runtime·madvise(SB),NOSPLIT,$0-12 + MOVW addr+0(FP), R4 + MOVW n+4(FP), R5 + MOVW flags+8(FP), R6 + MOVW $SYS_madvise, R2 + SYSCALL + // ignore failure - maybe pages are locked + RET + +// int32 futex(int32 *uaddr, int32 op, int32 val, struct timespec *timeout, int32 *uaddr2, int32 val2); +TEXT runtime·futex(SB),NOSPLIT,$20-28 + MOVW addr+0(FP), R4 + MOVW op+4(FP), R5 + MOVW val+8(FP), R6 + MOVW ts+12(FP), R7 + + MOVW addr2+16(FP), R8 + MOVW val3+20(FP), R9 + + MOVW R8, 16(R29) + MOVW R9, 20(R29) + + MOVW $SYS_futex, R2 + SYSCALL + MOVW R2, ret+24(FP) + RET + + +// int32 clone(int32 flags, void *stk, M *mm, G *gg, void (*fn)(void)); +TEXT runtime·clone(SB),NOSPLIT,$-4-24 + MOVW flags+0(FP), R4 + MOVW stk+4(FP), R5 + MOVW R0, R6 // ptid + MOVW R0, R7 // tls + + // O32 syscall handler unconditionally copies arguments 5-8 from stack, + // even for syscalls with less than 8 arguments. Reserve 32 bytes of new + // stack so that any syscall invoked immediately in the new thread won't fail. + ADD $-32, R5 + + // Copy mm, gg, fn off parent stack for use by child. + MOVW mm+8(FP), R16 + MOVW gg+12(FP), R17 + MOVW fn+16(FP), R18 + + MOVW $1234, R1 + + MOVW R16, 0(R5) + MOVW R17, 4(R5) + MOVW R18, 8(R5) + + MOVW R1, 12(R5) + + MOVW $SYS_clone, R2 + SYSCALL + + // In parent, return. + BEQ R2, 5(PC) + SUBU R2, R0, R3 + CMOVN R7, R3, R2 + MOVW R2, ret+20(FP) + RET + + // In child, on new stack. + // Check that SP is as we expect + MOVW 12(R29), R16 + MOVW $1234, R1 + BEQ R16, R1, 2(PC) + MOVW (R0), R0 + + // Initialize m->procid to Linux tid + MOVW $SYS_gettid, R2 + SYSCALL + + MOVW 0(R29), R16 // m + MOVW 4(R29), R17 // g + MOVW 8(R29), R18 // fn + + BEQ R16, nog + BEQ R17, nog + + MOVW R2, m_procid(R16) + + // In child, set up new stack + MOVW R16, g_m(R17) + MOVW R17, g + +// TODO(mips32): doesn't have runtime·stackcheck(SB) + +nog: + // Call fn + ADDU $32, R29 + JAL (R18) + + // It shouldn't return. If it does, exit that thread. + ADDU $-32, R29 + MOVW $0xf4, R4 + MOVW $SYS_exit, R2 + SYSCALL + UNDEF + +TEXT runtime·sigaltstack(SB),NOSPLIT,$0 + MOVW new+0(FP), R4 + MOVW old+4(FP), R5 + MOVW $SYS_sigaltstack, R2 + SYSCALL + BEQ R7, 2(PC) + UNDEF // crash + RET + +TEXT runtime·osyield(SB),NOSPLIT,$0 + MOVW $SYS_sched_yield, R2 + SYSCALL + RET + +TEXT runtime·sched_getaffinity(SB),NOSPLIT,$0-16 + MOVW pid+0(FP), R4 + MOVW len+4(FP), R5 + MOVW buf+8(FP), R6 + MOVW $SYS_sched_getaffinity, R2 + SYSCALL + MOVW R2, ret+12(FP) + RET + +// int32 runtime·epollcreate(int32 size); +TEXT runtime·epollcreate(SB),NOSPLIT,$0-8 + MOVW size+0(FP), R4 + MOVW $SYS_epoll_create, R2 + SYSCALL + MOVW R2, ret+4(FP) + RET + +// int32 runtime·epollcreate1(int32 flags); +TEXT runtime·epollcreate1(SB),NOSPLIT,$0-8 + MOVW flags+0(FP), R4 + MOVW $SYS_epoll_create1, R2 + SYSCALL + MOVW R2, ret+4(FP) + RET + +// func epollctl(epfd, op, fd int32, ev *epollEvent) int +TEXT runtime·epollctl(SB),NOSPLIT,$0-20 + MOVW epfd+0(FP), R4 + MOVW op+4(FP), R5 + MOVW fd+8(FP), R6 + MOVW ev+12(FP), R7 + MOVW $SYS_epoll_ctl, R2 + SYSCALL + MOVW R2, ret+16(FP) + RET + +// int32 runtime·epollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout); +TEXT runtime·epollwait(SB),NOSPLIT,$0-20 + MOVW epfd+0(FP), R4 + MOVW ev+4(FP), R5 + MOVW nev+8(FP), R6 + MOVW timeout+12(FP), R7 + MOVW $SYS_epoll_wait, R2 + SYSCALL + MOVW R2, ret+16(FP) + RET + +// void runtime·closeonexec(int32 fd); +TEXT runtime·closeonexec(SB),NOSPLIT,$0-4 + MOVW fd+0(FP), R4 // fd + MOVW $2, R5 // F_SETFD + MOVW $1, R6 // FD_CLOEXEC + MOVW $SYS_fcntl, R2 + SYSCALL + RET diff --git a/src/runtime/sys_mipsx.go b/src/runtime/sys_mipsx.go new file mode 100644 index 0000000000..2819218d5f --- /dev/null +++ b/src/runtime/sys_mipsx.go @@ -0,0 +1,20 @@ +// Copyright 2016 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. + +// +build mips mipsle + +package runtime + +import "unsafe" + +// adjust Gobuf as if it executed a call to fn with context ctxt +// and then did an immediate Gosave. +func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) { + if buf.lr != 0 { + throw("invalid use of gostartcall") + } + buf.lr = buf.pc + buf.pc = uintptr(fn) + buf.ctxt = ctxt +} diff --git a/src/runtime/tls_mipsx.s b/src/runtime/tls_mipsx.s new file mode 100644 index 0000000000..95fbc32a7c --- /dev/null +++ b/src/runtime/tls_mipsx.s @@ -0,0 +1,21 @@ +// Copyright 2016 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. + +// +build mips mipsle + +#include "go_asm.h" +#include "go_tls.h" +#include "funcdata.h" +#include "textflag.h" + +// If !iscgo, this is a no-op. +TEXT runtime·save_g(SB),NOSPLIT,$-4-0 + MOVB runtime·iscgo(SB), R23 + BEQ R23, nocgo + UNDEF +nocgo: + RET + +TEXT runtime·load_g(SB),NOSPLIT,$-4-0 + RET diff --git a/src/runtime/unaligned2.go b/src/runtime/unaligned2.go index fed3cca1fd..28b61192c4 100644 --- a/src/runtime/unaligned2.go +++ b/src/runtime/unaligned2.go @@ -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 arm mips64 mips64le +// +build arm mips mipsle mips64 mips64le package runtime diff --git a/src/runtime/vlrt.go b/src/runtime/vlrt.go index f60457d084..d63da9c890 100644 --- a/src/runtime/vlrt.go +++ b/src/runtime/vlrt.go @@ -23,7 +23,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -// +build arm 386 +// +build arm 386 mips mipsle package runtime @@ -198,6 +198,11 @@ func dodiv(n, d uint64) (q, r uint64) { return slowdodiv(n, d) } + if GOARCH == "mips" || GOARCH == "mipsle" { + // No _div64by32 on mips and using only _mul64by32 doesn't bring much benefit + return slowdodiv(n, d) + } + if d > n { return 0, n } -- 2.50.0