runtime: add runtime support for openbsd 386
Add openbsd 386 runtime support, partially based on the existing
freebsd 386 runtime.
This requires change 4973043.
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/4951043
diff --git a/src/pkg/runtime/openbsd/386/rt0.s b/src/pkg/runtime/openbsd/386/rt0.s
new file mode 100644
index 0000000..e7e0da7
--- /dev/null
+++ b/src/pkg/runtime/openbsd/386/rt0.s
@@ -0,0 +1,6 @@
+// Copyright 2009 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.
+
+TEXT _rt0_386_openbsd(SB),7,$0
+ JMP _rt0_386(SB)
diff --git a/src/pkg/runtime/openbsd/386/signal.c b/src/pkg/runtime/openbsd/386/signal.c
new file mode 100644
index 0000000..8b0d4ac
--- /dev/null
+++ b/src/pkg/runtime/openbsd/386/signal.c
@@ -0,0 +1,189 @@
+// Copyright 2009 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 "runtime.h"
+#include "defs.h"
+#include "signals.h"
+#include "os.h"
+
+extern void runtime·sigtramp(void);
+
+typedef struct sigaction {
+ union {
+ void (*__sa_handler)(int32);
+ void (*__sa_sigaction)(int32, Siginfo*, void *);
+ } __sigaction_u; /* signal handler */
+ uint32 sa_mask; /* signal mask to apply */
+ int32 sa_flags; /* see signal options below */
+} Sigaction;
+
+void
+runtime·dumpregs(Sigcontext *r)
+{
+ runtime·printf("eax %x\n", r->sc_eax);
+ runtime·printf("ebx %x\n", r->sc_ebx);
+ runtime·printf("ecx %x\n", r->sc_ecx);
+ runtime·printf("edx %x\n", r->sc_edx);
+ runtime·printf("edi %x\n", r->sc_edi);
+ runtime·printf("esi %x\n", r->sc_esi);
+ runtime·printf("ebp %x\n", r->sc_ebp);
+ runtime·printf("esp %x\n", r->sc_esp);
+ runtime·printf("eip %x\n", r->sc_eip);
+ runtime·printf("eflags %x\n", r->sc_eflags);
+ runtime·printf("cs %x\n", r->sc_cs);
+ runtime·printf("fs %x\n", r->sc_fs);
+ runtime·printf("gs %x\n", r->sc_gs);
+}
+
+String
+runtime·signame(int32 sig)
+{
+ if(sig < 0 || sig >= NSIG)
+ return runtime·emptystring;
+ return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
+}
+
+void
+runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
+{
+ Sigcontext *r = context;
+ uintptr *sp;
+
+ if(sig == SIGPROF) {
+ runtime·sigprof((uint8*)r->sc_eip, (uint8*)r->sc_esp, nil, gp);
+ return;
+ }
+
+ if(gp != nil && (runtime·sigtab[sig].flags & SigPanic)) {
+ // Make it look like a call to the signal func.
+ // Have to pass arguments out of band since
+ // augmenting the stack frame would break
+ // the unwinding code.
+ gp->sig = sig;
+ gp->sigcode0 = info->si_code;
+ gp->sigcode1 = *(uintptr*)((byte*)info + 12); /* si_addr */
+ gp->sigpc = r->sc_eip;
+
+ // Only push runtime·sigpanic if r->sc_eip != 0.
+ // If r->sc_eip == 0, probably panicked because of a
+ // call to a nil func. Not pushing that onto sp will
+ // make the trace look like a call to runtime·sigpanic instead.
+ // (Otherwise the trace will end at runtime·sigpanic and we
+ // won't get to see who faulted.)
+ if(r->sc_eip != 0) {
+ sp = (uintptr*)r->sc_esp;
+ *--sp = r->sc_eip;
+ r->sc_esp = (uintptr)sp;
+ }
+ r->sc_eip = (uintptr)runtime·sigpanic;
+ return;
+ }
+
+ if(runtime·sigtab[sig].flags & SigQueue) {
+ if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
+ return;
+ runtime·exit(2); // SIGINT, SIGTERM, etc
+ }
+
+ if(runtime·panicking) // traceback already printed
+ runtime·exit(2);
+ runtime·panicking = 1;
+
+ if(sig < 0 || sig >= NSIG)
+ runtime·printf("Signal %d\n", sig);
+ else
+ runtime·printf("%s\n", runtime·sigtab[sig].name);
+
+ runtime·printf("PC=%X\n", r->sc_eip);
+ runtime·printf("\n");
+
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->sc_eip, (void*)r->sc_esp, 0, gp);
+ runtime·tracebackothers(gp);
+ runtime·dumpregs(r);
+ }
+
+ runtime·exit(2);
+}
+
+// Called from kernel on signal stack, so no stack split.
+#pragma textflag 7
+void
+runtime·sigignore(void)
+{
+}
+
+void
+runtime·signalstack(byte *p, int32 n)
+{
+ Sigaltstack st;
+
+ st.ss_sp = (int8*)p;
+ st.ss_size = n;
+ st.ss_flags = 0;
+ runtime·sigaltstack(&st, nil);
+}
+
+static void
+sigaction(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
+{
+ Sigaction sa;
+
+ runtime·memclr((byte*)&sa, sizeof sa);
+ sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
+ if(restart)
+ sa.sa_flags |= SA_RESTART;
+ sa.sa_mask = ~0ULL;
+ if (fn == runtime·sighandler)
+ fn = (void*)runtime·sigtramp;
+ sa.__sigaction_u.__sa_sigaction = (void*)fn;
+ runtime·sigaction(i, &sa, nil);
+}
+
+void
+runtime·initsig(int32 queue)
+{
+ int32 i;
+ void *fn;
+
+ runtime·siginit();
+
+ for(i = 0; i<NSIG; i++) {
+ if(runtime·sigtab[i].flags) {
+ if((runtime·sigtab[i].flags & SigQueue) != queue)
+ continue;
+ if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
+ fn = runtime·sighandler;
+ else
+ fn = runtime·sigignore;
+ sigaction(i, fn, (runtime·sigtab[i].flags & SigRestart) != 0);
+ }
+ }
+}
+
+void
+runtime·resetcpuprofiler(int32 hz)
+{
+ Itimerval it;
+
+ runtime·memclr((byte*)&it, sizeof it);
+ if(hz == 0) {
+ runtime·setitimer(ITIMER_PROF, &it, nil);
+ sigaction(SIGPROF, SIG_IGN, true);
+ } else {
+ sigaction(SIGPROF, runtime·sighandler, true);
+ it.it_interval.tv_sec = 0;
+ it.it_interval.tv_usec = 1000000 / hz;
+ it.it_value = it.it_interval;
+ runtime·setitimer(ITIMER_PROF, &it, nil);
+ }
+ m->profilehz = hz;
+}
+
+void
+os·sigpipe(void)
+{
+ sigaction(SIGPIPE, SIG_DFL, false);
+ runtime·raisesigpipe();
+}
diff --git a/src/pkg/runtime/openbsd/386/sys.s b/src/pkg/runtime/openbsd/386/sys.s
new file mode 100644
index 0000000..d508ce1
--- /dev/null
+++ b/src/pkg/runtime/openbsd/386/sys.s
@@ -0,0 +1,254 @@
+// Copyright 2009 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 386, OpenBSD
+// /usr/src/sys/kern/syscalls.master for syscall numbers.
+//
+
+#include "386/asm.h"
+
+// Exit the entire program (like C exit)
+TEXT runtime·exit(SB),7,$-4
+ MOVL $1, AX
+ INT $0x80
+ CALL runtime·notok(SB)
+ RET
+
+TEXT runtime·exit1(SB),7,$-4
+ MOVL $302, AX // sys_threxit
+ INT $0x80
+ JAE 2(PC)
+ CALL runtime·notok(SB)
+ RET
+
+TEXT runtime·write(SB),7,$-4
+ MOVL $4, AX // sys_write
+ INT $0x80
+ RET
+
+TEXT runtime·raisesigpipe(SB),7,$12
+ MOVL $299, AX // sys_getthrid
+ INT $80
+ MOVL $0, 0(SP)
+ MOVL AX, 4(SP) // arg 1 - pid
+ MOVL $13, 8(SP) // arg 2 - signum == SIGPIPE
+ MOVL $37, AX // sys_kill
+ INT $0x80
+ RET
+
+TEXT runtime·notok(SB),7,$0
+ MOVL $0xf1, 0xf1
+ RET
+
+TEXT runtime·mmap(SB),7,$36
+ LEAL arg0+0(FP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL // arg 1 - addr
+ MOVSL // arg 2 - len
+ MOVSL // arg 3 - prot
+ MOVSL // arg 4 - flags
+ MOVSL // arg 5 - fd
+ MOVL $0, AX
+ STOSL // arg 6 - pad
+ MOVSL // arg 7 - offset
+ MOVL $0, AX // top 64 bits of file offset
+ STOSL
+ MOVL $197, AX // sys_mmap
+ INT $0x80
+ JCC 2(PC)
+ NEGL AX
+ RET
+
+TEXT runtime·munmap(SB),7,$-4
+ MOVL $73, AX // sys_munmap
+ INT $0x80
+ JAE 2(PC)
+ CALL runtime·notok(SB)
+ RET
+
+TEXT runtime·setitimer(SB),7,$-4
+ MOVL $83, AX
+ INT $0x80
+ RET
+
+TEXT runtime·gettime(SB),7,$32
+ MOVL $116, AX
+ LEAL 12(SP), BX
+ MOVL BX, 4(SP)
+ MOVL $0, 8(SP)
+ INT $0x80
+
+ MOVL 12(SP), BX // sec
+ MOVL sec+0(FP), DI
+ MOVL BX, (DI)
+ MOVL $0, 4(DI) // zero extend 32 -> 64 bits
+
+ MOVL 16(SP), BX // usec
+ MOVL usec+4(FP), DI
+ MOVL BX, (DI)
+ RET
+
+TEXT runtime·sigaction(SB),7,$-4
+ MOVL $46, AX // sys_sigaction
+ INT $0x80
+ JAE 2(PC)
+ CALL runtime·notok(SB)
+ RET
+
+TEXT runtime·sigtramp(SB),7,$44
+ get_tls(CX)
+
+ // save g
+ MOVL g(CX), DI
+ MOVL DI, 20(SP)
+
+ // g = m->gsignal
+ MOVL m(CX), BX
+ MOVL m_gsignal(BX), BX
+ MOVL BX, g(CX)
+
+ // copy arguments for call to sighandler
+ MOVL signo+0(FP), BX
+ MOVL BX, 0(SP)
+ MOVL info+4(FP), BX
+ MOVL BX, 4(SP)
+ MOVL context+8(FP), BX
+ MOVL BX, 8(SP)
+ MOVL DI, 12(SP)
+
+ CALL runtime·sighandler(SB)
+
+ // restore g
+ get_tls(CX)
+ MOVL 20(SP), BX
+ MOVL BX, g(CX)
+
+ // call sigreturn
+ MOVL context+8(FP), AX
+ MOVL $0, 0(SP) // syscall gap
+ MOVL AX, 4(SP) // arg 1 - sigcontext
+ MOVL $103, AX // sys_sigreturn
+ INT $0x80
+ CALL runtime·notok(SB)
+ RET
+
+// int32 rfork_thread(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
+TEXT runtime·rfork_thread(SB),7,$8
+ MOVL flags+8(SP), AX
+ MOVL stack+12(SP), CX
+
+ // Copy m, g, fn off parent stack for use by child.
+ SUBL $16, CX
+ MOVL mm+16(SP), SI
+ MOVL SI, 0(CX)
+ MOVL gg+20(SP), SI
+ MOVL SI, 4(CX)
+ MOVL fn+24(SP), SI
+ MOVL SI, 8(CX)
+ MOVL $1234, 12(CX)
+ MOVL CX, SI
+
+ MOVL $0, 0(SP) // syscall gap
+ MOVL AX, 4(SP) // arg 1 - flags
+ MOVL $251, AX // sys_rfork
+ INT $0x80
+
+ // Return if rfork syscall failed
+ JCC 4(PC)
+ NEGL AX
+ MOVL AX, 48(SP)
+ RET
+
+ // In parent, return.
+ CMPL AX, $0
+ JEQ 3(PC)
+ MOVL AX, 48(SP)
+ RET
+
+ // In child, on new stack.
+ MOVL SI, SP
+
+ // Paranoia: check that SP is as we expect.
+ MOVL 12(SP), BP
+ CMPL BP, $1234
+ JEQ 2(PC)
+ INT $3
+
+ // Reload registers
+ MOVL 0(SP), BX // m
+ MOVL 4(SP), DX // g
+ MOVL 8(SP), SI // fn
+
+ // Initialize m->procid to thread ID
+ MOVL $299, AX // sys_getthrid
+ INT $0x80
+ MOVL AX, m_procid(BX)
+
+ // Set FS to point at m->tls
+ LEAL m_tls(BX), BP
+ PUSHAL // save registers
+ PUSHL BP
+ CALL runtime·settls(SB)
+ POPL AX
+ POPAL
+
+ // Now segment is established. Initialize m, g.
+ get_tls(AX)
+ MOVL DX, g(AX)
+ MOVL BX, m(AX)
+
+ CALL runtime·stackcheck(SB) // smashes AX, CX
+ MOVL 0(DX), DX // paranoia; check they are not nil
+ MOVL 0(BX), BX
+
+ // more paranoia; check that stack splitting code works
+ PUSHAL
+ CALL runtime·emptyfunc(SB)
+ POPAL
+
+ // Call fn
+ CALL SI
+
+ CALL runtime·exit1(SB)
+ MOVL $0x1234, 0x1005
+ RET
+
+TEXT runtime·sigaltstack(SB),7,$-8
+ MOVL $288, AX // sys_sigaltstack
+ MOVL new+4(SP), BX
+ MOVL old+8(SP), CX
+ INT $0x80
+ CMPL AX, $0xfffff001
+ JLS 2(PC)
+ INT $3
+ RET
+
+TEXT runtime·setldt(SB),7,$8
+ // Under OpenBSD we set the GS base instead of messing with the LDT.
+ MOVL 16(SP), AX // tls0
+ MOVL AX, 0(SP)
+ CALL runtime·settls(SB)
+ RET
+
+TEXT runtime·settls(SB),7,$16
+ // adjust for ELF: wants to use -8(GS) and -4(GS) for g and m
+ MOVL 20(SP), CX
+ ADDL $8, CX
+ MOVL CX, 0(CX)
+ MOVL $0, 0(SP) // syscall gap
+ MOVL $9, 4(SP) // I386_SET_GSBASE (machine/sysarch.h)
+ MOVL CX, 8(SP) // pointer to base
+ MOVL $165, AX // sys_sysarch
+ INT $0x80
+ JCC 2(PC)
+ CALL runtime·notok(SB)
+ RET
+
+TEXT runtime·osyield(SB),7,$-4
+ MOVL $298, AX // sys_sched_yield
+ INT $0x80
+ RET
+
+GLOBL runtime·tlsoffset(SB),$4
diff --git a/src/pkg/runtime/openbsd/defs.c b/src/pkg/runtime/openbsd/defs.c
index d8adec9..d0e0a19 100644
--- a/src/pkg/runtime/openbsd/defs.c
+++ b/src/pkg/runtime/openbsd/defs.c
@@ -14,7 +14,6 @@
#include <sys/time.h>
#include <sys/unistd.h>
#include <sys/signal.h>
-#include <machine/mcontext.h>
#include <errno.h>
#include <signal.h>
@@ -97,7 +96,8 @@
typedef struct timeval $Timeval;
typedef struct itimerval $Itimerval;
-// This is a hack to avoid pulling in machine/fpu.h and struct fxsave64.
+// This is a hack to avoid pulling in machine/fpu.h.
typedef void $sfxsave64;
+typedef void $usavefpu;
typedef struct sigcontext $Sigcontext;
diff --git a/src/pkg/runtime/openbsd/mem.c b/src/pkg/runtime/openbsd/mem.c
index 07abf2c..46b6b07 100644
--- a/src/pkg/runtime/openbsd/mem.c
+++ b/src/pkg/runtime/openbsd/mem.c
@@ -3,6 +3,11 @@
#include "os.h"
#include "malloc.h"
+enum
+{
+ ENOMEM = 12,
+};
+
void*
runtime·SysAlloc(uintptr n)
{
@@ -33,19 +38,20 @@
void*
runtime·SysReserve(void *v, uintptr n)
{
+ void *p;
+
// On 64-bit, people with ulimit -v set complain if we reserve too
// much address space. Instead, assume that the reservation is okay
// and check the assumption in SysMap.
if(sizeof(void*) == 8)
return v;
-
- return runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
-}
-enum
-{
- ENOMEM = 12,
-};
+ p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if (p == ((void *)-ENOMEM))
+ return nil;
+ else
+ return p;
+}
void
runtime·SysMap(void *v, uintptr n)