summaryrefslogtreecommitdiff
path: root/src/pkg/runtime/freebsd
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2011-09-13 13:13:40 +0200
committerOndřej Surý <ondrej@sury.org>2011-09-13 13:13:40 +0200
commit5ff4c17907d5b19510a62e08fd8d3b11e62b431d (patch)
treec0650497e988f47be9c6f2324fa692a52dea82e1 /src/pkg/runtime/freebsd
parent80f18fc933cf3f3e829c5455a1023d69f7b86e52 (diff)
downloadgolang-5ff4c17907d5b19510a62e08fd8d3b11e62b431d.tar.gz
Imported Upstream version 60upstream/60
Diffstat (limited to 'src/pkg/runtime/freebsd')
-rw-r--r--src/pkg/runtime/freebsd/386/defs.h187
-rw-r--r--src/pkg/runtime/freebsd/386/rt0.s9
-rw-r--r--src/pkg/runtime/freebsd/386/signal.c193
-rw-r--r--src/pkg/runtime/freebsd/386/sys.s239
-rw-r--r--src/pkg/runtime/freebsd/amd64/defs.h198
-rw-r--r--src/pkg/runtime/freebsd/amd64/rt0.s9
-rw-r--r--src/pkg/runtime/freebsd/amd64/signal.c201
-rw-r--r--src/pkg/runtime/freebsd/amd64/sys.s182
-rw-r--r--src/pkg/runtime/freebsd/defs.c108
-rw-r--r--src/pkg/runtime/freebsd/mem.c74
-rw-r--r--src/pkg/runtime/freebsd/os.h12
-rw-r--r--src/pkg/runtime/freebsd/signals.h52
-rw-r--r--src/pkg/runtime/freebsd/thread.c201
13 files changed, 1665 insertions, 0 deletions
diff --git a/src/pkg/runtime/freebsd/386/defs.h b/src/pkg/runtime/freebsd/386/defs.h
new file mode 100644
index 000000000..ae12b2019
--- /dev/null
+++ b/src/pkg/runtime/freebsd/386/defs.h
@@ -0,0 +1,187 @@
+// godefs -f -m32 defs.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+// Constants
+enum {
+ PROT_NONE = 0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+ MAP_ANON = 0x1000,
+ MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
+ SA_SIGINFO = 0x40,
+ SA_RESTART = 0x2,
+ SA_ONSTACK = 0x1,
+ UMTX_OP_WAIT = 0x2,
+ UMTX_OP_WAKE = 0x3,
+ EINTR = 0x4,
+ 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,
+ SIGTERM = 0xf,
+ SIGURG = 0x10,
+ SIGSTOP = 0x11,
+ SIGTSTP = 0x12,
+ SIGCONT = 0x13,
+ SIGCHLD = 0x14,
+ SIGTTIN = 0x15,
+ SIGTTOU = 0x16,
+ SIGIO = 0x17,
+ SIGXCPU = 0x18,
+ SIGXFSZ = 0x19,
+ SIGVTALRM = 0x1a,
+ SIGPROF = 0x1b,
+ SIGWINCH = 0x1c,
+ SIGINFO = 0x1d,
+ SIGUSR1 = 0x1e,
+ SIGUSR2 = 0x1f,
+ FPE_INTDIV = 0x2,
+ FPE_INTOVF = 0x1,
+ 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 = 0,
+ ITIMER_VIRTUAL = 0x1,
+ ITIMER_PROF = 0x2,
+};
+
+// Types
+#pragma pack on
+
+typedef struct Rtprio Rtprio;
+struct Rtprio {
+ uint16 type;
+ uint16 prio;
+};
+
+typedef struct ThrParam ThrParam;
+struct ThrParam {
+ void *start_func;
+ void *arg;
+ int8 *stack_base;
+ uint32 stack_size;
+ int8 *tls_base;
+ uint32 tls_size;
+ int32 *child_tid;
+ int32 *parent_tid;
+ int32 flags;
+ Rtprio *rtp;
+ void* spare[3];
+};
+
+typedef struct Sigaltstack Sigaltstack;
+struct Sigaltstack {
+ int8 *ss_sp;
+ uint32 ss_size;
+ int32 ss_flags;
+};
+
+typedef struct Sigset Sigset;
+struct Sigset {
+ uint32 __bits[4];
+};
+
+typedef union Sigval Sigval;
+union Sigval {
+ int32 sival_int;
+ void *sival_ptr;
+ int32 sigval_int;
+ void *sigval_ptr;
+};
+
+typedef struct StackT StackT;
+struct StackT {
+ int8 *ss_sp;
+ uint32 ss_size;
+ int32 ss_flags;
+};
+
+typedef struct Siginfo Siginfo;
+struct Siginfo {
+ int32 si_signo;
+ int32 si_errno;
+ int32 si_code;
+ int32 si_pid;
+ uint32 si_uid;
+ int32 si_status;
+ void *si_addr;
+ Sigval si_value;
+ byte _reason[32];
+};
+
+typedef struct Mcontext Mcontext;
+struct Mcontext {
+ int32 mc_onstack;
+ int32 mc_gs;
+ int32 mc_fs;
+ int32 mc_es;
+ int32 mc_ds;
+ int32 mc_edi;
+ int32 mc_esi;
+ int32 mc_ebp;
+ int32 mc_isp;
+ int32 mc_ebx;
+ int32 mc_edx;
+ int32 mc_ecx;
+ int32 mc_eax;
+ int32 mc_trapno;
+ int32 mc_err;
+ int32 mc_eip;
+ int32 mc_cs;
+ int32 mc_eflags;
+ int32 mc_esp;
+ int32 mc_ss;
+ int32 mc_len;
+ int32 mc_fpformat;
+ int32 mc_ownedfp;
+ int32 mc_spare1[1];
+ int32 mc_fpstate[128];
+ int32 mc_fsbase;
+ int32 mc_gsbase;
+ int32 mc_spare2[6];
+};
+
+typedef struct Ucontext Ucontext;
+struct Ucontext {
+ Sigset uc_sigmask;
+ Mcontext uc_mcontext;
+ Ucontext *uc_link;
+ StackT uc_stack;
+ int32 uc_flags;
+ int32 __spare__[4];
+ byte pad_godefs_0[12];
+};
+
+typedef struct Timeval Timeval;
+struct Timeval {
+ int32 tv_sec;
+ int32 tv_usec;
+};
+
+typedef struct Itimerval Itimerval;
+struct Itimerval {
+ Timeval it_interval;
+ Timeval it_value;
+};
+#pragma pack off
diff --git a/src/pkg/runtime/freebsd/386/rt0.s b/src/pkg/runtime/freebsd/386/rt0.s
new file mode 100644
index 000000000..3ca981b3a
--- /dev/null
+++ b/src/pkg/runtime/freebsd/386/rt0.s
@@ -0,0 +1,9 @@
+// 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.
+
+// Darwin and Linux use the same linkage to main
+
+TEXT _rt0_386_freebsd(SB),7,$0
+ JMP _rt0_386(SB)
+
diff --git a/src/pkg/runtime/freebsd/386/signal.c b/src/pkg/runtime/freebsd/386/signal.c
new file mode 100644
index 000000000..2fe7ecd70
--- /dev/null
+++ b/src/pkg/runtime/freebsd/386/signal.c
@@ -0,0 +1,193 @@
+// 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 */
+ int32 sa_flags; /* see signal options below */
+ int64 sa_mask; /* signal mask to apply */
+} Sigaction;
+
+void
+runtime·dumpregs(Mcontext *r)
+{
+ runtime·printf("eax %x\n", r->mc_eax);
+ runtime·printf("ebx %x\n", r->mc_ebx);
+ runtime·printf("ecx %x\n", r->mc_ecx);
+ runtime·printf("edx %x\n", r->mc_edx);
+ runtime·printf("edi %x\n", r->mc_edi);
+ runtime·printf("esi %x\n", r->mc_esi);
+ runtime·printf("ebp %x\n", r->mc_ebp);
+ runtime·printf("esp %x\n", r->mc_esp);
+ runtime·printf("eip %x\n", r->mc_eip);
+ runtime·printf("eflags %x\n", r->mc_eflags);
+ runtime·printf("cs %x\n", r->mc_cs);
+ runtime·printf("fs %x\n", r->mc_fs);
+ runtime·printf("gs %x\n", r->mc_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)
+{
+ Ucontext *uc;
+ Mcontext *r;
+ uintptr *sp;
+
+ uc = context;
+ r = &uc->uc_mcontext;
+
+ if(sig == SIGPROF) {
+ runtime·sigprof((uint8*)r->mc_eip, (uint8*)r->mc_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)info->si_addr;
+ gp->sigpc = r->mc_eip;
+
+ // Only push runtime·sigpanic if r->mc_eip != 0.
+ // If r->mc_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->mc_eip != 0) {
+ sp = (uintptr*)r->mc_esp;
+ *--sp = r->mc_eip;
+ r->mc_esp = (uintptr)sp;
+ }
+ r->mc_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->mc_eip);
+ runtime·printf("\n");
+
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->mc_eip, (void*)r->mc_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/freebsd/386/sys.s b/src/pkg/runtime/freebsd/386/sys.s
new file mode 100644
index 000000000..765e2fcc4
--- /dev/null
+++ b/src/pkg/runtime/freebsd/386/sys.s
@@ -0,0 +1,239 @@
+// 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, FreeBSD
+// /usr/src/sys/kern/syscalls.master for syscall numbers.
+//
+
+#include "386/asm.h"
+
+TEXT runtime·sys_umtx_op(SB),7,$-4
+ MOVL $454, AX
+ INT $0x80
+ RET
+
+TEXT runtime·thr_new(SB),7,$-4
+ MOVL $455, AX
+ INT $0x80
+ RET
+
+TEXT runtime·thr_start(SB),7,$0
+ MOVL mm+0(FP), AX
+ MOVL m_g0(AX), BX
+ LEAL m_tls(AX), BP
+ MOVL 0(BP), DI
+ ADDL $7, DI
+ PUSHAL
+ PUSHL $32
+ PUSHL BP
+ PUSHL DI
+ CALL runtime·setldt(SB)
+ POPL AX
+ POPL AX
+ POPL AX
+ POPAL
+ get_tls(CX)
+ MOVL BX, g(CX)
+
+ MOVL AX, m(CX)
+ CALL runtime·stackcheck(SB) // smashes AX
+ CALL runtime·mstart(SB)
+ MOVL 0, AX // crash (not reached)
+
+// 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 $431, AX
+ INT $0x80
+ JAE 2(PC)
+ CALL runtime·notok(SB)
+ RET
+
+TEXT runtime·write(SB),7,$-4
+ MOVL $4, AX
+ INT $0x80
+ RET
+
+TEXT runtime·raisesigpipe(SB),7,$12
+ // thr_self(&8(SP))
+ LEAL 8(SP), AX
+ MOVL AX, 0(SP)
+ MOVL $432, AX
+ INT $0x80
+ // thr_kill(self, SIGPIPE)
+ MOVL 8(SP), AX
+ MOVL AX, 0(SP)
+ MOVL $13, 4(SP)
+ MOVL $433, AX
+ INT $0x80
+ RET
+
+TEXT runtime·notok(SB),7,$0
+ MOVL $0xf1, 0xf1
+ RET
+
+TEXT runtime·mmap(SB),7,$32
+ LEAL arg0+0(FP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVL $0, AX // top 64 bits of file offset
+ STOSL
+ MOVL $477, AX
+ INT $0x80
+ RET
+
+TEXT runtime·munmap(SB),7,$-4
+ MOVL $73, AX
+ 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 $416, AX
+ 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)
+ MOVL $417, AX // sigreturn(ucontext)
+ INT $0x80
+ CALL runtime·notok(SB)
+ RET
+
+TEXT runtime·sigaltstack(SB),7,$0
+ MOVL $53, AX
+ INT $0x80
+ JAE 2(PC)
+ CALL runtime·notok(SB)
+ RET
+
+/*
+descriptor entry format for system call
+is the native machine format, ugly as it is:
+
+ 2-byte limit
+ 3-byte base
+ 1-byte: 0x80=present, 0x60=dpl<<5, 0x1F=type
+ 1-byte: 0x80=limit is *4k, 0x40=32-bit operand size,
+ 0x0F=4 more bits of limit
+ 1 byte: 8 more bits of base
+
+int i386_get_ldt(int, union ldt_entry *, int);
+int i386_set_ldt(int, const union ldt_entry *, int);
+
+*/
+
+// setldt(int entry, int address, int limit)
+TEXT runtime·setldt(SB),7,$32
+ MOVL address+4(FP), BX // aka base
+ // see comment in linux/386/sys.s; freebsd is similar
+ ADDL $0x8, BX
+
+ // set up data_desc
+ LEAL 16(SP), AX // struct data_desc
+ MOVL $0, 0(AX)
+ MOVL $0, 4(AX)
+
+ MOVW BX, 2(AX)
+ SHRL $16, BX
+ MOVB BX, 4(AX)
+ SHRL $8, BX
+ MOVB BX, 7(AX)
+
+ MOVW $0xffff, 0(AX)
+ MOVB $0xCF, 6(AX) // 32-bit operand, 4k limit unit, 4 more bits of limit
+
+ MOVB $0xF2, 5(AX) // r/w data descriptor, dpl=3, present
+
+ // call i386_set_ldt(entry, desc, 1)
+ MOVL $0xffffffff, 0(SP) // auto-allocate entry and return in AX
+ MOVL AX, 4(SP)
+ MOVL $1, 8(SP)
+ CALL runtime·i386_set_ldt(SB)
+
+ // compute segment selector - (entry*8+7)
+ SHLL $3, AX
+ ADDL $7, AX
+ MOVW AX, GS
+ RET
+
+TEXT runtime·i386_set_ldt(SB),7,$16
+ LEAL args+0(FP), AX // 0(FP) == 4(SP) before SP got moved
+ MOVL $0, 0(SP) // syscall gap
+ MOVL $1, 4(SP)
+ MOVL AX, 8(SP)
+ MOVL $165, AX
+ INT $0x80
+ CMPL AX, $0xfffff001
+ JLS 2(PC)
+ INT $3
+ RET
+
+GLOBL runtime·tlsoffset(SB),$4
diff --git a/src/pkg/runtime/freebsd/amd64/defs.h b/src/pkg/runtime/freebsd/amd64/defs.h
new file mode 100644
index 000000000..b101b1932
--- /dev/null
+++ b/src/pkg/runtime/freebsd/amd64/defs.h
@@ -0,0 +1,198 @@
+// godefs -f -m64 defs.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+// Constants
+enum {
+ PROT_NONE = 0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+ MAP_ANON = 0x1000,
+ MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
+ SA_SIGINFO = 0x40,
+ SA_RESTART = 0x2,
+ SA_ONSTACK = 0x1,
+ UMTX_OP_WAIT = 0x2,
+ UMTX_OP_WAKE = 0x3,
+ EINTR = 0x4,
+ 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,
+ SIGTERM = 0xf,
+ SIGURG = 0x10,
+ SIGSTOP = 0x11,
+ SIGTSTP = 0x12,
+ SIGCONT = 0x13,
+ SIGCHLD = 0x14,
+ SIGTTIN = 0x15,
+ SIGTTOU = 0x16,
+ SIGIO = 0x17,
+ SIGXCPU = 0x18,
+ SIGXFSZ = 0x19,
+ SIGVTALRM = 0x1a,
+ SIGPROF = 0x1b,
+ SIGWINCH = 0x1c,
+ SIGINFO = 0x1d,
+ SIGUSR1 = 0x1e,
+ SIGUSR2 = 0x1f,
+ FPE_INTDIV = 0x2,
+ FPE_INTOVF = 0x1,
+ 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 = 0,
+ ITIMER_VIRTUAL = 0x1,
+ ITIMER_PROF = 0x2,
+};
+
+// Types
+#pragma pack on
+
+typedef struct Rtprio Rtprio;
+struct Rtprio {
+ uint16 type;
+ uint16 prio;
+};
+
+typedef struct ThrParam ThrParam;
+struct ThrParam {
+ void *start_func;
+ void *arg;
+ int8 *stack_base;
+ uint64 stack_size;
+ int8 *tls_base;
+ uint64 tls_size;
+ int64 *child_tid;
+ int64 *parent_tid;
+ int32 flags;
+ byte pad_godefs_0[4];
+ Rtprio *rtp;
+ void* spare[3];
+};
+
+typedef struct Sigaltstack Sigaltstack;
+struct Sigaltstack {
+ int8 *ss_sp;
+ uint64 ss_size;
+ int32 ss_flags;
+ byte pad_godefs_0[4];
+};
+
+typedef struct Sigset Sigset;
+struct Sigset {
+ uint32 __bits[4];
+};
+
+typedef union Sigval Sigval;
+union Sigval {
+ int32 sival_int;
+ void *sival_ptr;
+ int32 sigval_int;
+ void *sigval_ptr;
+};
+
+typedef struct StackT StackT;
+struct StackT {
+ int8 *ss_sp;
+ uint64 ss_size;
+ int32 ss_flags;
+ byte pad_godefs_0[4];
+};
+
+typedef struct Siginfo Siginfo;
+struct Siginfo {
+ int32 si_signo;
+ int32 si_errno;
+ int32 si_code;
+ int32 si_pid;
+ uint32 si_uid;
+ int32 si_status;
+ void *si_addr;
+ Sigval si_value;
+ byte _reason[40];
+};
+
+typedef struct Mcontext Mcontext;
+struct Mcontext {
+ int64 mc_onstack;
+ int64 mc_rdi;
+ int64 mc_rsi;
+ int64 mc_rdx;
+ int64 mc_rcx;
+ int64 mc_r8;
+ int64 mc_r9;
+ int64 mc_rax;
+ int64 mc_rbx;
+ int64 mc_rbp;
+ int64 mc_r10;
+ int64 mc_r11;
+ int64 mc_r12;
+ int64 mc_r13;
+ int64 mc_r14;
+ int64 mc_r15;
+ uint32 mc_trapno;
+ uint16 mc_fs;
+ uint16 mc_gs;
+ int64 mc_addr;
+ uint32 mc_flags;
+ uint16 mc_es;
+ uint16 mc_ds;
+ int64 mc_err;
+ int64 mc_rip;
+ int64 mc_cs;
+ int64 mc_rflags;
+ int64 mc_rsp;
+ int64 mc_ss;
+ int64 mc_len;
+ int64 mc_fpformat;
+ int64 mc_ownedfp;
+ int64 mc_fpstate[64];
+ int64 mc_fsbase;
+ int64 mc_gsbase;
+ int64 mc_spare[6];
+};
+
+typedef struct Ucontext Ucontext;
+struct Ucontext {
+ Sigset uc_sigmask;
+ Mcontext uc_mcontext;
+ Ucontext *uc_link;
+ StackT uc_stack;
+ int32 uc_flags;
+ int32 __spare__[4];
+ byte pad_godefs_0[12];
+};
+
+typedef struct Timeval Timeval;
+struct Timeval {
+ int64 tv_sec;
+ int64 tv_usec;
+};
+
+typedef struct Itimerval Itimerval;
+struct Itimerval {
+ Timeval it_interval;
+ Timeval it_value;
+};
+#pragma pack off
diff --git a/src/pkg/runtime/freebsd/amd64/rt0.s b/src/pkg/runtime/freebsd/amd64/rt0.s
new file mode 100644
index 000000000..5d2eeeeff
--- /dev/null
+++ b/src/pkg/runtime/freebsd/amd64/rt0.s
@@ -0,0 +1,9 @@
+// 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.
+
+// Darwin and Linux use the same linkage to main
+
+TEXT _rt0_amd64_freebsd(SB),7,$-8
+ MOVQ $_rt0_amd64(SB), DX
+ JMP DX
diff --git a/src/pkg/runtime/freebsd/amd64/signal.c b/src/pkg/runtime/freebsd/amd64/signal.c
new file mode 100644
index 000000000..8015e366e
--- /dev/null
+++ b/src/pkg/runtime/freebsd/amd64/signal.c
@@ -0,0 +1,201 @@
+// 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 */
+ int32 sa_flags; /* see signal options below */
+ int64 sa_mask; /* signal mask to apply */
+} Sigaction;
+
+void
+runtime·dumpregs(Mcontext *r)
+{
+ runtime·printf("rax %X\n", r->mc_rax);
+ runtime·printf("rbx %X\n", r->mc_rbx);
+ runtime·printf("rcx %X\n", r->mc_rcx);
+ runtime·printf("rdx %X\n", r->mc_rdx);
+ runtime·printf("rdi %X\n", r->mc_rdi);
+ runtime·printf("rsi %X\n", r->mc_rsi);
+ runtime·printf("rbp %X\n", r->mc_rbp);
+ runtime·printf("rsp %X\n", r->mc_rsp);
+ runtime·printf("r8 %X\n", r->mc_r8 );
+ runtime·printf("r9 %X\n", r->mc_r9 );
+ runtime·printf("r10 %X\n", r->mc_r10);
+ runtime·printf("r11 %X\n", r->mc_r11);
+ runtime·printf("r12 %X\n", r->mc_r12);
+ runtime·printf("r13 %X\n", r->mc_r13);
+ runtime·printf("r14 %X\n", r->mc_r14);
+ runtime·printf("r15 %X\n", r->mc_r15);
+ runtime·printf("rip %X\n", r->mc_rip);
+ runtime·printf("rflags %X\n", r->mc_flags);
+ runtime·printf("cs %X\n", r->mc_cs);
+ runtime·printf("fs %X\n", r->mc_fs);
+ runtime·printf("gs %X\n", r->mc_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)
+{
+ Ucontext *uc;
+ Mcontext *r;
+ uintptr *sp;
+
+ uc = context;
+ r = &uc->uc_mcontext;
+
+ if(sig == SIGPROF) {
+ runtime·sigprof((uint8*)r->mc_rip, (uint8*)r->mc_rsp, 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)info->si_addr;
+ gp->sigpc = r->mc_rip;
+
+ // Only push runtime·sigpanic if r->mc_rip != 0.
+ // If r->mc_rip == 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->mc_rip != 0) {
+ sp = (uintptr*)r->mc_rsp;
+ *--sp = r->mc_rip;
+ r->mc_rsp = (uintptr)sp;
+ }
+ r->mc_rip = (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->mc_rip);
+ runtime·printf("\n");
+
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->mc_rip, (void*)r->mc_rsp, 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/freebsd/amd64/sys.s b/src/pkg/runtime/freebsd/amd64/sys.s
new file mode 100644
index 000000000..c5cc082e4
--- /dev/null
+++ b/src/pkg/runtime/freebsd/amd64/sys.s
@@ -0,0 +1,182 @@
+// 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 AMD64, FreeBSD
+// /usr/src/sys/kern/syscalls.master for syscall numbers.
+//
+
+#include "amd64/asm.h"
+
+TEXT runtime·sys_umtx_op(SB),7,$0
+ MOVQ 8(SP), DI
+ MOVL 16(SP), SI
+ MOVL 20(SP), DX
+ MOVQ 24(SP), R10
+ MOVQ 32(SP), R8
+ MOVL $454, AX
+ SYSCALL
+ RET
+
+TEXT runtime·thr_new(SB),7,$0
+ MOVQ 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVL $455, AX
+ SYSCALL
+ RET
+
+TEXT runtime·thr_start(SB),7,$0
+ MOVQ DI, R13 // m
+
+ // set up FS to point at m->tls
+ LEAQ m_tls(R13), DI
+ CALL runtime·settls(SB) // smashes DI
+
+ // set up m, g
+ get_tls(CX)
+ MOVQ R13, m(CX)
+ MOVQ m_g0(R13), DI
+ MOVQ DI, g(CX)
+
+ CALL runtime·stackcheck(SB)
+ CALL runtime·mstart(SB)
+ MOVQ 0, AX // crash (not reached)
+
+// Exit the entire program (like C exit)
+TEXT runtime·exit(SB),7,$-8
+ MOVL 8(SP), DI // arg 1 exit status
+ MOVL $1, AX
+ SYSCALL
+ CALL runtime·notok(SB)
+ RET
+
+TEXT runtime·exit1(SB),7,$-8
+ MOVQ 8(SP), DI // arg 1 exit status
+ MOVL $431, AX
+ SYSCALL
+ CALL runtime·notok(SB)
+ RET
+
+TEXT runtime·write(SB),7,$-8
+ MOVL 8(SP), DI // arg 1 fd
+ MOVQ 16(SP), SI // arg 2 buf
+ MOVL 24(SP), DX // arg 3 count
+ MOVL $4, AX
+ SYSCALL
+ RET
+
+TEXT runtime·raisesigpipe(SB),7,$16
+ // thr_self(&8(SP))
+ LEAQ 8(SP), DI // arg 1 &8(SP)
+ MOVL $432, AX
+ SYSCALL
+ // thr_kill(self, SIGPIPE)
+ MOVQ 8(SP), DI // arg 1 id
+ MOVQ $13, SI // arg 2 SIGPIPE
+ MOVL $433, AX
+ SYSCALL
+ RET
+
+TEXT runtime·setitimer(SB), 7, $-8
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVQ 24(SP), DX
+ MOVL $83, AX
+ SYSCALL
+ RET
+
+TEXT runtime·gettime(SB), 7, $32
+ MOVL $116, AX
+ LEAQ 8(SP), DI
+ MOVQ $0, SI
+ SYSCALL
+
+ MOVQ 8(SP), BX // sec
+ MOVQ sec+0(FP), DI
+ MOVQ BX, (DI)
+
+ MOVL 16(SP), BX // usec
+ MOVQ usec+8(FP), DI
+ MOVL BX, (DI)
+ RET
+
+TEXT runtime·sigaction(SB),7,$-8
+ MOVL 8(SP), DI // arg 1 sig
+ MOVQ 16(SP), SI // arg 2 act
+ MOVQ 24(SP), DX // arg 3 oact
+ MOVL $416, AX
+ SYSCALL
+ JCC 2(PC)
+ CALL runtime·notok(SB)
+ RET
+
+TEXT runtime·sigtramp(SB),7,$64
+ get_tls(BX)
+
+ // save g
+ MOVQ g(BX), R10
+ MOVQ R10, 40(SP)
+
+ // g = m->signal
+ MOVQ m(BX), BP
+ MOVQ m_gsignal(BP), BP
+ MOVQ BP, g(BX)
+
+ MOVQ DI, 0(SP)
+ MOVQ SI, 8(SP)
+ MOVQ DX, 16(SP)
+ MOVQ R10, 24(SP)
+
+ CALL runtime·sighandler(SB)
+
+ // restore g
+ get_tls(BX)
+ MOVQ 40(SP), R10
+ MOVQ R10, g(BX)
+ RET
+
+TEXT runtime·mmap(SB),7,$0
+ MOVQ 8(SP), DI // arg 1 addr
+ MOVQ 16(SP), SI // arg 2 len
+ MOVL 24(SP), DX // arg 3 prot
+ MOVL 28(SP), R10 // arg 4 flags
+ MOVL 32(SP), R8 // arg 5 fid
+ MOVL 36(SP), R9 // arg 6 offset
+ MOVL $477, AX
+ SYSCALL
+ RET
+
+TEXT runtime·munmap(SB),7,$0
+ MOVQ 8(SP), DI // arg 1 addr
+ MOVQ 16(SP), SI // arg 2 len
+ MOVL $73, AX
+ SYSCALL
+ JCC 2(PC)
+ CALL runtime·notok(SB)
+ RET
+
+TEXT runtime·notok(SB),7,$-8
+ MOVL $0xf1, BP
+ MOVQ BP, (BP)
+ RET
+
+TEXT runtime·sigaltstack(SB),7,$-8
+ MOVQ new+8(SP), DI
+ MOVQ old+16(SP), SI
+ MOVQ $53, AX
+ SYSCALL
+ JCC 2(PC)
+ CALL runtime·notok(SB)
+ RET
+
+// set tls base to DI
+TEXT runtime·settls(SB),7,$8
+ ADDQ $16, DI // adjust for ELF: wants to use -16(FS) and -8(FS) for g and m
+ MOVQ DI, 0(SP)
+ MOVQ SP, SI
+ MOVQ $129, DI // AMD64_SET_FSBASE
+ MOVQ $165, AX // sysarch
+ SYSCALL
+ JCC 2(PC)
+ CALL runtime·notok(SB)
+ RET
diff --git a/src/pkg/runtime/freebsd/defs.c b/src/pkg/runtime/freebsd/defs.c
new file mode 100644
index 000000000..2ce4fdc51
--- /dev/null
+++ b/src/pkg/runtime/freebsd/defs.c
@@ -0,0 +1,108 @@
+// 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.
+
+/*
+ * Input to godefs.
+ *
+ godefs -f -m64 defs.c >amd64/defs.h
+ godefs -f -m32 defs.c >386/defs.h
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/ucontext.h>
+#include <sys/umtx.h>
+#include <sys/rtprio.h>
+#include <sys/thr.h>
+#include <sys/_sigset.h>
+#include <sys/unistd.h>
+
+enum {
+ $PROT_NONE = PROT_NONE,
+ $PROT_READ = PROT_READ,
+ $PROT_WRITE = PROT_WRITE,
+ $PROT_EXEC = PROT_EXEC,
+
+ $MAP_ANON = MAP_ANON,
+ $MAP_PRIVATE = MAP_PRIVATE,
+ $MAP_FIXED = MAP_FIXED,
+
+ $SA_SIGINFO = SA_SIGINFO,
+ $SA_RESTART = SA_RESTART,
+ $SA_ONSTACK = SA_ONSTACK,
+
+ $UMTX_OP_WAIT = UMTX_OP_WAIT,
+ $UMTX_OP_WAKE = UMTX_OP_WAKE,
+
+ $EINTR = EINTR,
+
+ $SIGHUP = SIGHUP,
+ $SIGINT = SIGINT,
+ $SIGQUIT = SIGQUIT,
+ $SIGILL = SIGILL,
+ $SIGTRAP = SIGTRAP,
+ $SIGABRT = SIGABRT,
+ $SIGEMT = SIGEMT,
+ $SIGFPE = SIGFPE,
+ $SIGKILL = SIGKILL,
+ $SIGBUS = SIGBUS,
+ $SIGSEGV = SIGSEGV,
+ $SIGSYS = SIGSYS,
+ $SIGPIPE = SIGPIPE,
+ $SIGALRM = SIGALRM,
+ $SIGTERM = SIGTERM,
+ $SIGURG = SIGURG,
+ $SIGSTOP = SIGSTOP,
+ $SIGTSTP = SIGTSTP,
+ $SIGCONT = SIGCONT,
+ $SIGCHLD = SIGCHLD,
+ $SIGTTIN = SIGTTIN,
+ $SIGTTOU = SIGTTOU,
+ $SIGIO = SIGIO,
+ $SIGXCPU = SIGXCPU,
+ $SIGXFSZ = SIGXFSZ,
+ $SIGVTALRM = SIGVTALRM,
+ $SIGPROF = SIGPROF,
+ $SIGWINCH = SIGWINCH,
+ $SIGINFO = SIGINFO,
+ $SIGUSR1 = SIGUSR1,
+ $SIGUSR2 = SIGUSR2,
+
+ $FPE_INTDIV = FPE_INTDIV,
+ $FPE_INTOVF = FPE_INTOVF,
+ $FPE_FLTDIV = FPE_FLTDIV,
+ $FPE_FLTOVF = FPE_FLTOVF,
+ $FPE_FLTUND = FPE_FLTUND,
+ $FPE_FLTRES = FPE_FLTRES,
+ $FPE_FLTINV = FPE_FLTINV,
+ $FPE_FLTSUB = FPE_FLTSUB,
+
+ $BUS_ADRALN = BUS_ADRALN,
+ $BUS_ADRERR = BUS_ADRERR,
+ $BUS_OBJERR = BUS_OBJERR,
+
+ $SEGV_MAPERR = SEGV_MAPERR,
+ $SEGV_ACCERR = SEGV_ACCERR,
+
+ $ITIMER_REAL = ITIMER_REAL,
+ $ITIMER_VIRTUAL = ITIMER_VIRTUAL,
+ $ITIMER_PROF = ITIMER_PROF,
+};
+
+typedef struct rtprio $Rtprio;
+typedef struct thr_param $ThrParam;
+typedef struct sigaltstack $Sigaltstack;
+typedef struct __sigset $Sigset;
+typedef union sigval $Sigval;
+typedef stack_t $StackT;
+
+typedef siginfo_t $Siginfo;
+
+typedef mcontext_t $Mcontext;
+typedef ucontext_t $Ucontext;
+typedef struct timeval $Timeval;
+typedef struct itimerval $Itimerval;
diff --git a/src/pkg/runtime/freebsd/mem.c b/src/pkg/runtime/freebsd/mem.c
new file mode 100644
index 000000000..07abf2cfe
--- /dev/null
+++ b/src/pkg/runtime/freebsd/mem.c
@@ -0,0 +1,74 @@
+#include "runtime.h"
+#include "defs.h"
+#include "os.h"
+#include "malloc.h"
+
+void*
+runtime·SysAlloc(uintptr n)
+{
+ void *v;
+
+ mstats.sys += n;
+ v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(v < (void*)4096)
+ return nil;
+ return v;
+}
+
+void
+runtime·SysUnused(void *v, uintptr n)
+{
+ USED(v);
+ USED(n);
+ // TODO(rsc): call madvise MADV_DONTNEED
+}
+
+void
+runtime·SysFree(void *v, uintptr n)
+{
+ mstats.sys -= n;
+ runtime·munmap(v, n);
+}
+
+void*
+runtime·SysReserve(void *v, uintptr n)
+{
+ // 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,
+};
+
+void
+runtime·SysMap(void *v, uintptr n)
+{
+ void *p;
+
+ mstats.sys += n;
+
+ // On 64-bit, we don't actually have v reserved, so tread carefully.
+ if(sizeof(void*) == 8) {
+ p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(p == (void*)-ENOMEM)
+ runtime·throw("runtime: out of memory");
+ if(p != v) {
+ runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
+ runtime·throw("runtime: address space conflict");
+ }
+ return;
+ }
+
+ p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
+ if(p == (void*)-ENOMEM)
+ runtime·throw("runtime: out of memory");
+ if(p != v)
+ runtime·throw("runtime: cannot map pages in arena address space");
+}
diff --git a/src/pkg/runtime/freebsd/os.h b/src/pkg/runtime/freebsd/os.h
new file mode 100644
index 000000000..007856c6b
--- /dev/null
+++ b/src/pkg/runtime/freebsd/os.h
@@ -0,0 +1,12 @@
+#define SIG_DFL ((void*)0)
+#define SIG_IGN ((void*)1)
+
+int32 runtime·thr_new(ThrParam*, int32);
+void runtime·sigpanic(void);
+void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
+struct sigaction;
+void runtime·sigaction(int32, struct sigaction*, struct sigaction*);
+void runtiem·setitimerval(int32, Itimerval*, Itimerval*);
+void runtime·setitimer(int32, Itimerval*, Itimerval*);
+
+void runtime·raisesigpipe(void);
diff --git a/src/pkg/runtime/freebsd/signals.h b/src/pkg/runtime/freebsd/signals.h
new file mode 100644
index 000000000..63a84671d
--- /dev/null
+++ b/src/pkg/runtime/freebsd/signals.h
@@ -0,0 +1,52 @@
+// 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.
+
+#define C SigCatch
+#define I SigIgnore
+#define R SigRestart
+#define Q SigQueue
+#define P SigPanic
+
+SigTab runtime·sigtab[] = {
+ /* 0 */ 0, "SIGNONE: no trap",
+ /* 1 */ Q+R, "SIGHUP: terminal line hangup",
+ /* 2 */ Q+R, "SIGINT: interrupt",
+ /* 3 */ C, "SIGQUIT: quit",
+ /* 4 */ C, "SIGILL: illegal instruction",
+ /* 5 */ C, "SIGTRAP: trace trap",
+ /* 6 */ C, "SIGABRT: abort",
+ /* 7 */ C, "SIGEMT: EMT instruction",
+ /* 8 */ C+P, "SIGFPE: floating-point exception",
+ /* 9 */ 0, "SIGKILL: kill",
+ /* 10 */ C+P, "SIGBUS: bus error",
+ /* 11 */ C+P, "SIGSEGV: segmentation violation",
+ /* 12 */ C, "SIGSYS: bad system call",
+ /* 13 */ I, "SIGPIPE: write to broken pipe",
+ /* 14 */ Q+I+R, "SIGALRM: alarm clock",
+ /* 15 */ Q+R, "SIGTERM: termination",
+ /* 16 */ Q+I+R, "SIGURG: urgent condition on socket",
+ /* 17 */ 0, "SIGSTOP: stop, unblockable",
+ /* 18 */ Q+I+R, "SIGTSTP: stop from tty",
+ /* 19 */ 0, "SIGCONT: continue",
+ /* 20 */ Q+I+R, "SIGCHLD: child status has changed",
+ /* 21 */ Q+I+R, "SIGTTIN: background read from tty",
+ /* 22 */ Q+I+R, "SIGTTOU: background write to tty",
+ /* 23 */ Q+I+R, "SIGIO: i/o now possible",
+ /* 24 */ Q+I+R, "SIGXCPU: cpu limit exceeded",
+ /* 25 */ Q+I+R, "SIGXFSZ: file size limit exceeded",
+ /* 26 */ Q+I+R, "SIGVTALRM: virtual alarm clock",
+ /* 27 */ Q+I+R, "SIGPROF: profiling alarm clock",
+ /* 28 */ Q+I+R, "SIGWINCH: window size change",
+ /* 29 */ Q+I+R, "SIGINFO: information request",
+ /* 30 */ Q+I+R, "SIGUSR1: user-defined signal 1",
+ /* 31 */ Q+I+R, "SIGUSR2: user-defined signal 2",
+ /* 32 */ Q+I+R, "SIGTHR: reserved",
+};
+#undef C
+#undef I
+#undef R
+#undef Q
+#undef P
+
+#define NSIG 33
diff --git a/src/pkg/runtime/freebsd/thread.c b/src/pkg/runtime/freebsd/thread.c
new file mode 100644
index 000000000..f8c550f57
--- /dev/null
+++ b/src/pkg/runtime/freebsd/thread.c
@@ -0,0 +1,201 @@
+// Use of this source file is governed by a BSD-style
+// license that can be found in the LICENSE file.`
+
+#include "runtime.h"
+#include "defs.h"
+#include "os.h"
+#include "stack.h"
+
+extern SigTab runtime·sigtab[];
+extern int32 runtime·sys_umtx_op(uint32*, int32, uint32, void*, void*);
+
+// FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and
+// thus the code is largely similar. See linux/thread.c for comments.
+
+static void
+umtx_wait(uint32 *addr, uint32 val)
+{
+ int32 ret;
+
+ ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT, val, nil, nil);
+ if(ret >= 0 || ret == -EINTR)
+ return;
+
+ runtime·printf("umtx_wait addr=%p val=%d ret=%d\n", addr, val, ret);
+ *(int32*)0x1005 = 0x1005;
+}
+
+static void
+umtx_wake(uint32 *addr)
+{
+ int32 ret;
+
+ ret = runtime·sys_umtx_op(addr, UMTX_OP_WAKE, 1, nil, nil);
+ if(ret >= 0)
+ return;
+
+ runtime·printf("umtx_wake addr=%p ret=%d\n", addr, ret);
+ *(int32*)0x1006 = 0x1006;
+}
+
+// See linux/thread.c for comments about the algorithm.
+static void
+umtx_lock(Lock *l)
+{
+ uint32 v;
+
+again:
+ v = l->key;
+ if((v&1) == 0){
+ if(runtime·cas(&l->key, v, v|1))
+ return;
+ goto again;
+ }
+
+ if(!runtime·cas(&l->key, v, v+2))
+ goto again;
+
+ umtx_wait(&l->key, v+2);
+
+ for(;;){
+ v = l->key;
+ if(v < 2)
+ runtime·throw("bad lock key");
+ if(runtime·cas(&l->key, v, v-2))
+ break;
+ }
+
+ goto again;
+}
+
+static void
+umtx_unlock(Lock *l)
+{
+ uint32 v;
+
+again:
+ v = l->key;
+ if((v&1) == 0)
+ runtime·throw("unlock of unlocked lock");
+ if(!runtime·cas(&l->key, v, v&~1))
+ goto again;
+
+ if(v&~1)
+ umtx_wake(&l->key);
+}
+
+void
+runtime·lock(Lock *l)
+{
+ if(m->locks < 0)
+ runtime·throw("lock count");
+ m->locks++;
+ umtx_lock(l);
+}
+
+void
+runtime·unlock(Lock *l)
+{
+ m->locks--;
+ if(m->locks < 0)
+ runtime·throw("lock count");
+ umtx_unlock(l);
+}
+
+// Event notifications.
+void
+runtime·noteclear(Note *n)
+{
+ n->lock.key = 0;
+ umtx_lock(&n->lock);
+}
+
+void
+runtime·notesleep(Note *n)
+{
+ umtx_lock(&n->lock);
+ umtx_unlock(&n->lock);
+}
+
+void
+runtime·notewakeup(Note *n)
+{
+ umtx_unlock(&n->lock);
+}
+
+void runtime·thr_start(void*);
+
+void
+runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
+{
+ ThrParam param;
+
+ USED(fn); // thr_start assumes fn == mstart
+ USED(g); // thr_start assumes g == m->g0
+
+ if(0){
+ runtime·printf("newosproc stk=%p m=%p g=%p fn=%p id=%d/%d ostk=%p\n",
+ stk, m, g, fn, m->id, m->tls[0], &m);
+ }
+
+ runtime·memclr((byte*)&param, sizeof param);
+
+ param.start_func = runtime·thr_start;
+ param.arg = m;
+ param.stack_base = (int8*)g->stackbase;
+ param.stack_size = (byte*)stk - (byte*)g->stackbase;
+ param.child_tid = (intptr*)&m->procid;
+ param.parent_tid = nil;
+ param.tls_base = (int8*)&m->tls[0];
+ param.tls_size = sizeof m->tls;
+
+ m->tls[0] = m->id; // so 386 asm can find it
+
+ runtime·thr_new(&param, sizeof param);
+}
+
+void
+runtime·osinit(void)
+{
+}
+
+void
+runtime·goenvs(void)
+{
+ runtime·goenvs_unix();
+}
+
+// Called to initialize a new m (including the bootstrap m).
+void
+runtime·minit(void)
+{
+ // Initialize signal handling
+ m->gsignal = runtime·malg(32*1024);
+ runtime·signalstack(m->gsignal->stackguard - StackGuard, 32*1024);
+}
+
+void
+runtime·sigpanic(void)
+{
+ switch(g->sig) {
+ case SIGBUS:
+ if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000)
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
+ runtime·throw("fault");
+ case SIGSEGV:
+ if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000)
+ runtime·panicstring("invalid memory address or nil pointer dereference");
+ runtime·printf("unexpected fault address %p\n", g->sigcode1);
+ runtime·throw("fault");
+ case SIGFPE:
+ switch(g->sigcode0) {
+ case FPE_INTDIV:
+ runtime·panicstring("integer divide by zero");
+ case FPE_INTOVF:
+ runtime·panicstring("integer overflow");
+ }
+ runtime·panicstring("floating point error");
+ }
+ runtime·panicstring(runtime·sigtab[g->sig].name);
+}