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)