diff options
author | Ondřej Surý <ondrej@sury.org> | 2011-09-13 13:13:40 +0200 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2011-09-13 13:13:40 +0200 |
commit | 5ff4c17907d5b19510a62e08fd8d3b11e62b431d (patch) | |
tree | c0650497e988f47be9c6f2324fa692a52dea82e1 /src/pkg/runtime/freebsd | |
parent | 80f18fc933cf3f3e829c5455a1023d69f7b86e52 (diff) | |
download | golang-5ff4c17907d5b19510a62e08fd8d3b11e62b431d.tar.gz |
Imported Upstream version 60upstream/60
Diffstat (limited to 'src/pkg/runtime/freebsd')
-rw-r--r-- | src/pkg/runtime/freebsd/386/defs.h | 187 | ||||
-rw-r--r-- | src/pkg/runtime/freebsd/386/rt0.s | 9 | ||||
-rw-r--r-- | src/pkg/runtime/freebsd/386/signal.c | 193 | ||||
-rw-r--r-- | src/pkg/runtime/freebsd/386/sys.s | 239 | ||||
-rw-r--r-- | src/pkg/runtime/freebsd/amd64/defs.h | 198 | ||||
-rw-r--r-- | src/pkg/runtime/freebsd/amd64/rt0.s | 9 | ||||
-rw-r--r-- | src/pkg/runtime/freebsd/amd64/signal.c | 201 | ||||
-rw-r--r-- | src/pkg/runtime/freebsd/amd64/sys.s | 182 | ||||
-rw-r--r-- | src/pkg/runtime/freebsd/defs.c | 108 | ||||
-rw-r--r-- | src/pkg/runtime/freebsd/mem.c | 74 | ||||
-rw-r--r-- | src/pkg/runtime/freebsd/os.h | 12 | ||||
-rw-r--r-- | src/pkg/runtime/freebsd/signals.h | 52 | ||||
-rw-r--r-- | src/pkg/runtime/freebsd/thread.c | 201 |
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*)¶m, 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(¶m, 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); +} |