diff options
Diffstat (limited to 'src/pkg/runtime/linux')
-rw-r--r-- | src/pkg/runtime/linux/386/defs.h | 191 | ||||
-rw-r--r-- | src/pkg/runtime/linux/386/rt0.s | 9 | ||||
-rw-r--r-- | src/pkg/runtime/linux/386/signal.c | 184 | ||||
-rw-r--r-- | src/pkg/runtime/linux/386/sys.s | 344 | ||||
-rw-r--r-- | src/pkg/runtime/linux/amd64/defs.h | 236 | ||||
-rw-r--r-- | src/pkg/runtime/linux/amd64/rt0.s | 10 | ||||
-rw-r--r-- | src/pkg/runtime/linux/amd64/signal.c | 194 | ||||
-rw-r--r-- | src/pkg/runtime/linux/amd64/sys.s | 252 | ||||
-rw-r--r-- | src/pkg/runtime/linux/arm/defs.h | 149 | ||||
-rw-r--r-- | src/pkg/runtime/linux/arm/rt0.s | 6 | ||||
-rw-r--r-- | src/pkg/runtime/linux/arm/signal.c | 189 | ||||
-rw-r--r-- | src/pkg/runtime/linux/arm/sys.s | 319 | ||||
-rw-r--r-- | src/pkg/runtime/linux/defs.c | 95 | ||||
-rw-r--r-- | src/pkg/runtime/linux/defs1.c | 24 | ||||
-rw-r--r-- | src/pkg/runtime/linux/defs2.c | 120 | ||||
-rw-r--r-- | src/pkg/runtime/linux/defs_arm.c | 122 | ||||
-rw-r--r-- | src/pkg/runtime/linux/mem.c | 113 | ||||
-rw-r--r-- | src/pkg/runtime/linux/os.h | 19 | ||||
-rw-r--r-- | src/pkg/runtime/linux/signals.h | 51 | ||||
-rw-r--r-- | src/pkg/runtime/linux/thread.c | 320 |
20 files changed, 2947 insertions, 0 deletions
diff --git a/src/pkg/runtime/linux/386/defs.h b/src/pkg/runtime/linux/386/defs.h new file mode 100644 index 000000000..73fe23ef9 --- /dev/null +++ b/src/pkg/runtime/linux/386/defs.h @@ -0,0 +1,191 @@ +// godefs -f -m32 -f -I/home/rsc/pub/linux-2.6/arch/x86/include -f -I/home/rsc/pub/linux-2.6/include -f -D_LOOSE_KERNEL_NAMES -f -D__ARCH_SI_UID_T=__kernel_uid32_t defs2.c + +// MACHINE GENERATED - DO NOT EDIT. + +// Constants +enum { + PROT_NONE = 0, + PROT_READ = 0x1, + PROT_WRITE = 0x2, + PROT_EXEC = 0x4, + MAP_ANON = 0x20, + MAP_PRIVATE = 0x2, + MAP_FIXED = 0x10, + SA_RESTART = 0x10000000, + SA_ONSTACK = 0x8000000, + SA_RESTORER = 0x4000000, + SA_SIGINFO = 0x4, + SIGHUP = 0x1, + SIGINT = 0x2, + SIGQUIT = 0x3, + SIGILL = 0x4, + SIGTRAP = 0x5, + SIGABRT = 0x6, + SIGBUS = 0x7, + SIGFPE = 0x8, + SIGKILL = 0x9, + SIGUSR1 = 0xa, + SIGSEGV = 0xb, + SIGUSR2 = 0xc, + SIGPIPE = 0xd, + SIGALRM = 0xe, + SIGSTKFLT = 0x10, + SIGCHLD = 0x11, + SIGCONT = 0x12, + SIGSTOP = 0x13, + SIGTSTP = 0x14, + SIGTTIN = 0x15, + SIGTTOU = 0x16, + SIGURG = 0x17, + SIGXCPU = 0x18, + SIGXFSZ = 0x19, + SIGVTALRM = 0x1a, + SIGPROF = 0x1b, + SIGWINCH = 0x1c, + SIGIO = 0x1d, + SIGPWR = 0x1e, + SIGSYS = 0x1f, + FPE_INTDIV = 0x1, + FPE_INTOVF = 0x2, + FPE_FLTDIV = 0x3, + FPE_FLTOVF = 0x4, + FPE_FLTUND = 0x5, + FPE_FLTRES = 0x6, + FPE_FLTINV = 0x7, + FPE_FLTSUB = 0x8, + BUS_ADRALN = 0x1, + BUS_ADRERR = 0x2, + BUS_OBJERR = 0x3, + SEGV_MAPERR = 0x1, + SEGV_ACCERR = 0x2, + ITIMER_REAL = 0, + ITIMER_VIRTUAL = 0x1, + ITIMER_PROF = 0x2, + O_RDONLY = 0, + O_CLOEXEC = 02000000, +}; + +// Types +#pragma pack on + +typedef struct Fpreg Fpreg; +struct Fpreg { + uint16 significand[4]; + uint16 exponent; +}; + +typedef struct Fpxreg Fpxreg; +struct Fpxreg { + uint16 significand[4]; + uint16 exponent; + uint16 padding[3]; +}; + +typedef struct Xmmreg Xmmreg; +struct Xmmreg { + uint32 element[4]; +}; + +typedef struct Fpstate Fpstate; +struct Fpstate { + uint32 cw; + uint32 sw; + uint32 tag; + uint32 ipoff; + uint32 cssel; + uint32 dataoff; + uint32 datasel; + Fpreg _st[8]; + uint16 status; + uint16 magic; + uint32 _fxsr_env[6]; + uint32 mxcsr; + uint32 reserved; + Fpxreg _fxsr_st[8]; + Xmmreg _xmm[8]; + uint32 padding1[44]; + byte Pad_godefs_0[48]; +}; + +typedef struct Timespec Timespec; +struct Timespec { + int32 tv_sec; + int32 tv_nsec; +}; + +typedef struct Timeval Timeval; +struct Timeval { + int32 tv_sec; + int32 tv_usec; +}; + +typedef struct Sigaction Sigaction; +struct Sigaction { + void *k_sa_handler; + uint32 sa_flags; + void *sa_restorer; + uint32 sa_mask; +}; + +typedef struct Siginfo Siginfo; +struct Siginfo { + int32 si_signo; + int32 si_errno; + int32 si_code; + byte _sifields[116]; +}; + +typedef struct Sigaltstack Sigaltstack; +struct Sigaltstack { + void *ss_sp; + int32 ss_flags; + uint32 ss_size; +}; + +typedef struct Sigcontext Sigcontext; +struct Sigcontext { + uint16 gs; + uint16 __gsh; + uint16 fs; + uint16 __fsh; + uint16 es; + uint16 __esh; + uint16 ds; + uint16 __dsh; + uint32 edi; + uint32 esi; + uint32 ebp; + uint32 esp; + uint32 ebx; + uint32 edx; + uint32 ecx; + uint32 eax; + uint32 trapno; + uint32 err; + uint32 eip; + uint16 cs; + uint16 __csh; + uint32 eflags; + uint32 esp_at_signal; + uint16 ss; + uint16 __ssh; + Fpstate *fpstate; + uint32 oldmask; + uint32 cr2; +}; + +typedef struct Ucontext Ucontext; +struct Ucontext { + uint32 uc_flags; + Ucontext *uc_link; + Sigaltstack uc_stack; + Sigcontext uc_mcontext; + uint32 uc_sigmask; +}; + +typedef struct Itimerval Itimerval; +struct Itimerval { + Timeval it_interval; + Timeval it_value; +}; +#pragma pack off diff --git a/src/pkg/runtime/linux/386/rt0.s b/src/pkg/runtime/linux/386/rt0.s new file mode 100644 index 000000000..223e6d2ea --- /dev/null +++ b/src/pkg/runtime/linux/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_linux(SB),7,$0 + JMP _rt0_386(SB) + diff --git a/src/pkg/runtime/linux/386/signal.c b/src/pkg/runtime/linux/386/signal.c new file mode 100644 index 000000000..8916e10bd --- /dev/null +++ b/src/pkg/runtime/linux/386/signal.c @@ -0,0 +1,184 @@ +// 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" + +void +runtime·dumpregs(Sigcontext *r) +{ + runtime·printf("eax %x\n", r->eax); + runtime·printf("ebx %x\n", r->ebx); + runtime·printf("ecx %x\n", r->ecx); + runtime·printf("edx %x\n", r->edx); + runtime·printf("edi %x\n", r->edi); + runtime·printf("esi %x\n", r->esi); + runtime·printf("ebp %x\n", r->ebp); + runtime·printf("esp %x\n", r->esp); + runtime·printf("eip %x\n", r->eip); + runtime·printf("eflags %x\n", r->eflags); + runtime·printf("cs %x\n", r->cs); + runtime·printf("fs %x\n", r->fs); + runtime·printf("gs %x\n", r->gs); +} + +/* + * This assembler routine takes the args from registers, puts them on the stack, + * and calls sighandler(). + */ +extern void runtime·sigtramp(void); +extern void runtime·sigignore(void); // just returns +extern void runtime·sigreturn(void); // calls runtime·sigreturn + +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; + Sigcontext *r; + uintptr *sp; + + uc = context; + r = &uc->uc_mcontext; + + if(sig == SIGPROF) { + runtime·sigprof((uint8*)r->eip, (uint8*)r->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)[3]; + gp->sigpc = r->eip; + + // Only push runtime·sigpanic if r->eip != 0. + // If r->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->eip != 0) { + sp = (uintptr*)r->esp; + *--sp = r->eip; + r->esp = (uintptr)sp; + } + r->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->eip); + runtime·printf("\n"); + + if(runtime·gotraceback()){ + runtime·traceback((void*)r->eip, (void*)r->esp, 0, gp); + runtime·tracebackothers(gp); + runtime·dumpregs(r); + } + + runtime·exit(2); +} + +void +runtime·signalstack(byte *p, int32 n) +{ + Sigaltstack st; + + st.ss_sp = 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_ONSTACK | SA_SIGINFO | SA_RESTORER; + if(restart) + sa.sa_flags |= SA_RESTART; + sa.sa_mask = ~0ULL; + sa.sa_restorer = (void*)runtime·sigreturn; + if(fn == runtime·sighandler) + fn = (void*)runtime·sigtramp; + sa.k_sa_handler = fn; + runtime·rt_sigaction(i, &sa, nil, 8); +} + +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/linux/386/sys.s b/src/pkg/runtime/linux/386/sys.s new file mode 100644 index 000000000..0b4a34986 --- /dev/null +++ b/src/pkg/runtime/linux/386/sys.s @@ -0,0 +1,344 @@ +// 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, Linux +// + +#include "386/asm.h" + +TEXT runtime·exit(SB),7,$0 + MOVL $252, AX // syscall number + MOVL 4(SP), BX + INT $0x80 + INT $3 // not reached + RET + +TEXT runtime·exit1(SB),7,$0 + MOVL $1, AX // exit - exit the current os thread + MOVL 4(SP), BX + INT $0x80 + INT $3 // not reached + RET + +TEXT runtime·open(SB),7,$0 + MOVL $5, AX // syscall - open + MOVL 4(SP), BX + MOVL 8(SP), CX + MOVL 12(SP), DX + INT $0x80 + RET + +TEXT runtime·close(SB),7,$0 + MOVL $6, AX // syscall - close + MOVL 4(SP), BX + INT $0x80 + RET + +TEXT runtime·write(SB),7,$0 + MOVL $4, AX // syscall - write + MOVL 4(SP), BX + MOVL 8(SP), CX + MOVL 12(SP), DX + INT $0x80 + RET + +TEXT runtime·read(SB),7,$0 + MOVL $3, AX // syscall - read + MOVL 4(SP), BX + MOVL 8(SP), CX + MOVL 12(SP), DX + INT $0x80 + RET + +TEXT runtime·raisesigpipe(SB),7,$12 + MOVL $224, AX // syscall - gettid + INT $0x80 + MOVL AX, 0(SP) // arg 1 tid + MOVL $13, 4(SP) // arg 2 SIGPIPE + MOVL $238, AX // syscall - tkill + INT $0x80 + RET + +TEXT runtime·setitimer(SB),7,$0-24 + MOVL $104, AX // syscall - setitimer + MOVL 4(SP), BX + MOVL 8(SP), CX + MOVL 12(SP), DX + INT $0x80 + RET + +TEXT runtime·mincore(SB),7,$0-24 + MOVL $218, AX // syscall - mincore + MOVL 4(SP), BX + MOVL 8(SP), CX + MOVL 12(SP), DX + INT $0x80 + RET + +TEXT runtime·gettime(SB), 7, $32 + MOVL $78, AX // syscall - gettimeofday + LEAL 8(SP), BX + MOVL $0, CX + MOVL $0, DX + INT $0x80 + + MOVL 8(SP), BX // sec + MOVL sec+0(FP), DI + MOVL BX, (DI) + MOVL $0, 4(DI) // zero extend 32 -> 64 bits + + MOVL 12(SP), BX // usec + MOVL usec+4(FP), DI + MOVL BX, (DI) + RET + +TEXT runtime·rt_sigaction(SB),7,$0 + MOVL $174, AX // syscall - rt_sigaction + MOVL 4(SP), BX + MOVL 8(SP), CX + MOVL 12(SP), DX + MOVL 16(SP), SI + INT $0x80 + 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 sig+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) + + RET + +TEXT runtime·sigignore(SB),7,$0 + RET + +TEXT runtime·sigreturn(SB),7,$0 + MOVL $173, AX // rt_sigreturn + INT $0x80 + INT $3 // not reached + RET + +TEXT runtime·mmap(SB),7,$0 + MOVL $192, AX // mmap2 + MOVL 4(SP), BX + MOVL 8(SP), CX + MOVL 12(SP), DX + MOVL 16(SP), SI + MOVL 20(SP), DI + MOVL 24(SP), BP + SHRL $12, BP + INT $0x80 + CMPL AX, $0xfffff001 + JLS 3(PC) + NOTL AX + INCL AX + RET + +TEXT runtime·munmap(SB),7,$0 + MOVL $91, AX // munmap + MOVL 4(SP), BX + MOVL 8(SP), CX + INT $0x80 + CMPL AX, $0xfffff001 + JLS 2(PC) + INT $3 + RET + +// int32 futex(int32 *uaddr, int32 op, int32 val, +// struct timespec *timeout, int32 *uaddr2, int32 val2); +TEXT runtime·futex(SB),7,$0 + MOVL $240, AX // futex + MOVL 4(SP), BX + MOVL 8(SP), CX + MOVL 12(SP), DX + MOVL 16(SP), SI + MOVL 20(SP), DI + MOVL 24(SP), BP + INT $0x80 + RET + +// int32 clone(int32 flags, void *stack, M *m, G *g, void (*fn)(void)); +TEXT runtime·clone(SB),7,$0 + MOVL $120, AX // clone + MOVL flags+4(SP), BX + MOVL stack+8(SP), CX + MOVL $0, DX // parent tid ptr + MOVL $0, DI // child tid ptr + + // Copy m, g, fn off parent stack for use by child. + SUBL $16, CX + MOVL mm+12(SP), SI + MOVL SI, 0(CX) + MOVL gg+16(SP), SI + MOVL SI, 4(CX) + MOVL fn+20(SP), SI + MOVL SI, 8(CX) + MOVL $1234, 12(CX) + + INT $0x80 + + // In parent, return. + CMPL AX, $0 + JEQ 2(PC) + RET + + // Paranoia: check that SP is as we expect. + MOVL 12(SP), BP + CMPL BP, $1234 + JEQ 2(PC) + INT $3 + + // Initialize AX to Linux tid + MOVL $224, AX + INT $0x80 + + // In child on new stack. Reload registers (paranoia). + MOVL 0(SP), BX // m + MOVL 4(SP), DX // g + MOVL 8(SP), SI // fn + + MOVL AX, m_procid(BX) // save tid as m->procid + + // set up ldt 7+id to point at m->tls. + // newosproc left the id in tls[0]. + LEAL m_tls(BX), BP + MOVL 0(BP), DI + ADDL $7, DI // m0 is LDT#7. count up. + // setldt(tls#, &tls, sizeof tls) + PUSHAL // save registers + PUSHL $32 // sizeof tls + PUSHL BP // &tls + PUSHL DI // tls # + CALL runtime·setldt(SB) + POPL AX + POPL AX + 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 SI // fn() + CALL runtime·exit1(SB) + MOVL $0x1234, 0x1005 + RET + +TEXT runtime·sigaltstack(SB),7,$-8 + MOVL $186, AX // sigaltstack + MOVL new+4(SP), BX + MOVL old+8(SP), CX + INT $0x80 + CMPL AX, $0xfffff001 + JLS 2(PC) + INT $3 + RET + +// <asm-i386/ldt.h> +// struct user_desc { +// unsigned int entry_number; +// unsigned long base_addr; +// unsigned int limit; +// unsigned int seg_32bit:1; +// unsigned int contents:2; +// unsigned int read_exec_only:1; +// unsigned int limit_in_pages:1; +// unsigned int seg_not_present:1; +// unsigned int useable:1; +// }; +#define SEG_32BIT 0x01 +// contents are the 2 bits 0x02 and 0x04. +#define CONTENTS_DATA 0x00 +#define CONTENTS_STACK 0x02 +#define CONTENTS_CODE 0x04 +#define READ_EXEC_ONLY 0x08 +#define LIMIT_IN_PAGES 0x10 +#define SEG_NOT_PRESENT 0x20 +#define USEABLE 0x40 + +// setldt(int entry, int address, int limit) +TEXT runtime·setldt(SB),7,$32 + MOVL entry+0(FP), BX // entry + MOVL address+4(FP), CX // base address + + /* + * When linking against the system libraries, + * we use its pthread_create and let it set up %gs + * for us. When we do that, the private storage + * we get is not at 0(GS), 4(GS), but -8(GS), -4(GS). + * To insulate the rest of the tool chain from this + * ugliness, 8l rewrites 0(GS) into -8(GS) for us. + * To accommodate that rewrite, we translate + * the address here and bump the limit to 0xffffffff (no limit) + * so that -8(GS) maps to 0(address). + * Also, the final 0(GS) (current 8(CX)) has to point + * to itself, to mimic ELF. + */ + ADDL $0x8, CX // address + MOVL CX, 0(CX) + + // set up user_desc + LEAL 16(SP), AX // struct user_desc + MOVL BX, 0(AX) + MOVL CX, 4(AX) + MOVL $0xfffff, 8(AX) + MOVL $(SEG_32BIT|LIMIT_IN_PAGES|USEABLE|CONTENTS_DATA), 12(AX) // flag bits + + // call modify_ldt + MOVL $1, BX // func = 1 (write) + MOVL AX, CX // user_desc + MOVL $16, DX // sizeof(user_desc) + MOVL $123, AX // syscall - modify_ldt + INT $0x80 + + // breakpoint on error + CMPL AX, $0xfffff001 + JLS 2(PC) + INT $3 + + // compute segment selector - (entry*8+7) + MOVL entry+0(FP), AX + SHLL $3, AX + ADDL $7, AX + MOVW AX, GS + + RET + +TEXT runtime·osyield(SB),7,$0 + MOVL $158, AX + INT $0x80 + RET diff --git a/src/pkg/runtime/linux/amd64/defs.h b/src/pkg/runtime/linux/amd64/defs.h new file mode 100644 index 000000000..8053dd16f --- /dev/null +++ b/src/pkg/runtime/linux/amd64/defs.h @@ -0,0 +1,236 @@ +// 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 = 0x20, + MAP_PRIVATE = 0x2, + MAP_FIXED = 0x10, + SA_RESTART = 0x10000000, + SA_ONSTACK = 0x8000000, + SA_RESTORER = 0x4000000, + SA_SIGINFO = 0x4, + SIGHUP = 0x1, + SIGINT = 0x2, + SIGQUIT = 0x3, + SIGILL = 0x4, + SIGTRAP = 0x5, + SIGABRT = 0x6, + SIGBUS = 0x7, + SIGFPE = 0x8, + SIGKILL = 0x9, + SIGUSR1 = 0xa, + SIGSEGV = 0xb, + SIGUSR2 = 0xc, + SIGPIPE = 0xd, + SIGALRM = 0xe, + SIGSTKFLT = 0x10, + SIGCHLD = 0x11, + SIGCONT = 0x12, + SIGSTOP = 0x13, + SIGTSTP = 0x14, + SIGTTIN = 0x15, + SIGTTOU = 0x16, + SIGURG = 0x17, + SIGXCPU = 0x18, + SIGXFSZ = 0x19, + SIGVTALRM = 0x1a, + SIGPROF = 0x1b, + SIGWINCH = 0x1c, + SIGIO = 0x1d, + SIGPWR = 0x1e, + SIGSYS = 0x1f, + FPE_INTDIV = 0x1, + FPE_INTOVF = 0x2, + FPE_FLTDIV = 0x3, + FPE_FLTOVF = 0x4, + FPE_FLTUND = 0x5, + FPE_FLTRES = 0x6, + FPE_FLTINV = 0x7, + FPE_FLTSUB = 0x8, + BUS_ADRALN = 0x1, + BUS_ADRERR = 0x2, + BUS_OBJERR = 0x3, + SEGV_MAPERR = 0x1, + SEGV_ACCERR = 0x2, + ITIMER_REAL = 0, + ITIMER_VIRTUAL = 0x1, + ITIMER_PROF = 0x2, + O_RDONLY = 0, + O_CLOEXEC = 02000000, +}; + +// Types +#pragma pack on + +typedef struct Timespec Timespec; +struct Timespec { + int64 tv_sec; + int64 tv_nsec; +}; + +typedef struct Timeval Timeval; +struct Timeval { + int64 tv_sec; + int64 tv_usec; +}; + +typedef struct Sigaction Sigaction; +struct Sigaction { + void *sa_handler; + uint64 sa_flags; + void *sa_restorer; + uint64 sa_mask; +}; + +typedef struct Siginfo Siginfo; +struct Siginfo { + int32 si_signo; + int32 si_errno; + int32 si_code; + byte pad_godefs_0[4]; + byte _sifields[112]; +}; + +typedef struct Itimerval Itimerval; +struct Itimerval { + Timeval it_interval; + Timeval it_value; +}; +#pragma pack off +// godefs -f -m64 defs1.c + +// MACHINE GENERATED - DO NOT EDIT. + +// Constants + +// Types +#pragma pack on + +typedef struct Usigset Usigset; +struct Usigset { + uint64 __val[16]; +}; + +typedef struct Fpxreg Fpxreg; +struct Fpxreg { + uint16 significand[4]; + uint16 exponent; + uint16 padding[3]; +}; + +typedef struct Xmmreg Xmmreg; +struct Xmmreg { + uint32 element[4]; +}; + +typedef struct Fpstate Fpstate; +struct Fpstate { + uint16 cwd; + uint16 swd; + uint16 ftw; + uint16 fop; + uint64 rip; + uint64 rdp; + uint32 mxcsr; + uint32 mxcr_mask; + Fpxreg _st[8]; + Xmmreg _xmm[16]; + uint32 padding[24]; +}; + +typedef struct Fpxreg1 Fpxreg1; +struct Fpxreg1 { + uint16 significand[4]; + uint16 exponent; + uint16 padding[3]; +}; + +typedef struct Xmmreg1 Xmmreg1; +struct Xmmreg1 { + uint32 element[4]; +}; + +typedef struct Fpstate1 Fpstate1; +struct Fpstate1 { + uint16 cwd; + uint16 swd; + uint16 ftw; + uint16 fop; + uint64 rip; + uint64 rdp; + uint32 mxcsr; + uint32 mxcr_mask; + Fpxreg1 _st[8]; + Xmmreg1 _xmm[16]; + uint32 padding[24]; +}; + +typedef struct Fpreg1 Fpreg1; +struct Fpreg1 { + uint16 significand[4]; + uint16 exponent; +}; + +typedef struct Sigaltstack Sigaltstack; +struct Sigaltstack { + void *ss_sp; + int32 ss_flags; + byte pad_godefs_0[4]; + uint64 ss_size; +}; + +typedef struct Mcontext Mcontext; +struct Mcontext { + int64 gregs[23]; + Fpstate *fpregs; + uint64 __reserved1[8]; +}; + +typedef struct Ucontext Ucontext; +struct Ucontext { + uint64 uc_flags; + Ucontext *uc_link; + Sigaltstack uc_stack; + Mcontext uc_mcontext; + Usigset uc_sigmask; + Fpstate __fpregs_mem; +}; + +typedef struct Sigcontext Sigcontext; +struct Sigcontext { + uint64 r8; + uint64 r9; + uint64 r10; + uint64 r11; + uint64 r12; + uint64 r13; + uint64 r14; + uint64 r15; + uint64 rdi; + uint64 rsi; + uint64 rbp; + uint64 rbx; + uint64 rdx; + uint64 rax; + uint64 rcx; + uint64 rsp; + uint64 rip; + uint64 eflags; + uint16 cs; + uint16 gs; + uint16 fs; + uint16 __pad0; + uint64 err; + uint64 trapno; + uint64 oldmask; + uint64 cr2; + Fpstate1 *fpstate; + uint64 __reserved1[8]; +}; +#pragma pack off diff --git a/src/pkg/runtime/linux/amd64/rt0.s b/src/pkg/runtime/linux/amd64/rt0.s new file mode 100644 index 000000000..dac9ae181 --- /dev/null +++ b/src/pkg/runtime/linux/amd64/rt0.s @@ -0,0 +1,10 @@ +// 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_linux(SB),7,$-8 + MOVQ $_rt0_amd64(SB), AX + MOVQ SP, DI + JMP AX diff --git a/src/pkg/runtime/linux/amd64/signal.c b/src/pkg/runtime/linux/amd64/signal.c new file mode 100644 index 000000000..ee90271ed --- /dev/null +++ b/src/pkg/runtime/linux/amd64/signal.c @@ -0,0 +1,194 @@ +// 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" + +void +runtime·dumpregs(Sigcontext *r) +{ + runtime·printf("rax %X\n", r->rax); + runtime·printf("rbx %X\n", r->rbx); + runtime·printf("rcx %X\n", r->rcx); + runtime·printf("rdx %X\n", r->rdx); + runtime·printf("rdi %X\n", r->rdi); + runtime·printf("rsi %X\n", r->rsi); + runtime·printf("rbp %X\n", r->rbp); + runtime·printf("rsp %X\n", r->rsp); + runtime·printf("r8 %X\n", r->r8 ); + runtime·printf("r9 %X\n", r->r9 ); + runtime·printf("r10 %X\n", r->r10); + runtime·printf("r11 %X\n", r->r11); + runtime·printf("r12 %X\n", r->r12); + runtime·printf("r13 %X\n", r->r13); + runtime·printf("r14 %X\n", r->r14); + runtime·printf("r15 %X\n", r->r15); + runtime·printf("rip %X\n", r->rip); + runtime·printf("rflags %X\n", r->eflags); + runtime·printf("cs %X\n", (uint64)r->cs); + runtime·printf("fs %X\n", (uint64)r->fs); + runtime·printf("gs %X\n", (uint64)r->gs); +} + +/* + * This assembler routine takes the args from registers, puts them on the stack, + * and calls sighandler(). + */ +extern void runtime·sigtramp(void); +extern void runtime·sigignore(void); // just returns +extern void runtime·sigreturn(void); // calls runtime·sigreturn + +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 *mc; + Sigcontext *r; + uintptr *sp; + + uc = context; + mc = &uc->uc_mcontext; + r = (Sigcontext*)mc; // same layout, more conveient names + + if(sig == SIGPROF) { + runtime·sigprof((uint8*)r->rip, (uint8*)r->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)[2]; + gp->sigpc = r->rip; + + // Only push runtime·sigpanic if r->rip != 0. + // If r->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->rip != 0) { + sp = (uintptr*)r->rsp; + *--sp = r->rip; + r->rsp = (uintptr)sp; + } + r->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->rip); + runtime·printf("\n"); + + if(runtime·gotraceback()){ + runtime·traceback((void*)r->rip, (void*)r->rsp, 0, gp); + runtime·tracebackothers(gp); + runtime·dumpregs(r); + } + + runtime·exit(2); +} + +void +runtime·signalstack(byte *p, int32 n) +{ + Sigaltstack st; + + st.ss_sp = 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_ONSTACK | SA_SIGINFO | SA_RESTORER; + if(restart) + sa.sa_flags |= SA_RESTART; + sa.sa_mask = ~0ULL; + sa.sa_restorer = (void*)runtime·sigreturn; + if(fn == runtime·sighandler) + fn = (void*)runtime·sigtramp; + sa.sa_handler = fn; + runtime·rt_sigaction(i, &sa, nil, 8); +} + +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/linux/amd64/sys.s b/src/pkg/runtime/linux/amd64/sys.s new file mode 100644 index 000000000..8b4dcd921 --- /dev/null +++ b/src/pkg/runtime/linux/amd64/sys.s @@ -0,0 +1,252 @@ +// 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, Linux +// + +#include "amd64/asm.h" + +TEXT runtime·exit(SB),7,$0-8 + MOVL 8(SP), DI + MOVL $231, AX // exitgroup - force all os threads to exit + SYSCALL + RET + +TEXT runtime·exit1(SB),7,$0-8 + MOVL 8(SP), DI + MOVL $60, AX // exit - exit the current os thread + SYSCALL + RET + +TEXT runtime·open(SB),7,$0-16 + MOVQ 8(SP), DI + MOVL 16(SP), SI + MOVL 20(SP), DX + MOVL $2, AX // syscall entry + SYSCALL + RET + +TEXT runtime·close(SB),7,$0-16 + MOVL 8(SP), DI + MOVL $3, AX // syscall entry + SYSCALL + RET + +TEXT runtime·write(SB),7,$0-24 + MOVL 8(SP), DI + MOVQ 16(SP), SI + MOVL 24(SP), DX + MOVL $1, AX // syscall entry + SYSCALL + RET + +TEXT runtime·read(SB),7,$0-24 + MOVL 8(SP), DI + MOVQ 16(SP), SI + MOVL 24(SP), DX + MOVL $0, AX // syscall entry + SYSCALL + RET + +TEXT runtime·raisesigpipe(SB),7,$12 + MOVL $186, AX // syscall - gettid + SYSCALL + MOVL AX, DI // arg 1 tid + MOVL $13, SI // arg 2 SIGPIPE + MOVL $200, AX // syscall - tkill + SYSCALL + RET + +TEXT runtime·setitimer(SB),7,$0-24 + MOVL 8(SP), DI + MOVQ 16(SP), SI + MOVQ 24(SP), DX + MOVL $38, AX // syscall entry + SYSCALL + RET + +TEXT runtime·mincore(SB),7,$0-24 + MOVQ 8(SP), DI + MOVQ 16(SP), SI + MOVQ 24(SP), DX + MOVL $27, AX // syscall entry + SYSCALL + RET + +TEXT runtime·gettime(SB), 7, $32 + LEAQ 8(SP), DI + MOVQ $0, SI + MOVQ $0xffffffffff600000, AX + CALL AX + + 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·rt_sigaction(SB),7,$0-32 + MOVL 8(SP), DI + MOVQ 16(SP), SI + MOVQ 24(SP), DX + MOVQ 32(SP), R10 + MOVL $13, AX // syscall entry + SYSCALL + RET + +TEXT runtime·sigtramp(SB),7,$64 + get_tls(BX) + + // save g + MOVQ g(BX), R10 + MOVQ R10, 40(SP) + + // g = m->gsignal + 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·sigignore(SB),7,$0 + RET + +TEXT runtime·sigreturn(SB),7,$0 + MOVL $15, AX // rt_sigreturn + SYSCALL + INT $3 // not reached + +TEXT runtime·mmap(SB),7,$0 + MOVQ 8(SP), DI + MOVQ $0, SI + MOVQ 16(SP), SI + MOVL 24(SP), DX + MOVL 28(SP), R10 + MOVL 32(SP), R8 + MOVL 36(SP), R9 + + MOVL $9, AX // mmap + SYSCALL + CMPQ AX, $0xfffffffffffff001 + JLS 3(PC) + NOTQ AX + INCQ AX + RET + +TEXT runtime·munmap(SB),7,$0 + MOVQ 8(SP), DI + MOVQ 16(SP), SI + MOVQ $11, AX // munmap + SYSCALL + CMPQ AX, $0xfffffffffffff001 + JLS 2(PC) + CALL runtime·notok(SB) + RET + +TEXT runtime·notok(SB),7,$0 + MOVQ $0xf1, BP + MOVQ BP, (BP) + RET + +// int64 futex(int32 *uaddr, int32 op, int32 val, +// struct timespec *timeout, int32 *uaddr2, int32 val2); +TEXT runtime·futex(SB),7,$0 + MOVQ 8(SP), DI + MOVL 16(SP), SI + MOVL 20(SP), DX + MOVQ 24(SP), R10 + MOVQ 32(SP), R8 + MOVL 40(SP), R9 + MOVL $202, AX + SYSCALL + RET + +// int64 clone(int32 flags, void *stack, M *m, G *g, void (*fn)(void)); +TEXT runtime·clone(SB),7,$0 + MOVL flags+8(SP), DI + MOVQ stack+16(SP), SI + + // Copy m, g, fn off parent stack for use by child. + // Careful: Linux system call clobbers CX and R11. + MOVQ mm+24(SP), R8 + MOVQ gg+32(SP), R9 + MOVQ fn+40(SP), R12 + + MOVL $56, AX + SYSCALL + + // In parent, return. + CMPQ AX, $0 + JEQ 2(PC) + RET + + // In child, on new stack. + MOVQ SI, SP + + // Initialize m->procid to Linux tid + MOVL $186, AX // gettid + SYSCALL + MOVQ AX, m_procid(R8) + + // Set FS to point at m->tls. + LEAQ m_tls(R8), DI + CALL runtime·settls(SB) + + // In child, set up new stack + get_tls(CX) + MOVQ R8, m(CX) + MOVQ R9, g(CX) + CALL runtime·stackcheck(SB) + + // Call fn + CALL R12 + + // It shouldn't return. If it does, exit + MOVL $111, DI + MOVL $60, AX + SYSCALL + JMP -3(PC) // keep exiting + +TEXT runtime·sigaltstack(SB),7,$-8 + MOVQ new+8(SP), DI + MOVQ old+16(SP), SI + MOVQ $131, AX + SYSCALL + CMPQ AX, $0xfffffffffffff001 + JLS 2(PC) + CALL runtime·notok(SB) + RET + +// set tls base to DI +TEXT runtime·settls(SB),7,$32 + ADDQ $16, DI // ELF wants to use -16(FS), -8(FS) + + MOVQ DI, SI + MOVQ $0x1002, DI // ARCH_SET_FS + MOVQ $158, AX // arch_prctl + SYSCALL + CMPQ AX, $0xfffffffffffff001 + JLS 2(PC) + CALL runtime·notok(SB) + RET + +TEXT runtime·osyield(SB),7,$0 + MOVL $24, AX + SYSCALL + RET diff --git a/src/pkg/runtime/linux/arm/defs.h b/src/pkg/runtime/linux/arm/defs.h new file mode 100644 index 000000000..09b558ed0 --- /dev/null +++ b/src/pkg/runtime/linux/arm/defs.h @@ -0,0 +1,149 @@ +// godefs -f-I/usr/src/linux-headers-2.6.26-2-versatile/include defs_arm.c + +// MACHINE GENERATED - DO NOT EDIT. + +// Constants +enum { + PROT_NONE = 0, + PROT_READ = 0x1, + PROT_WRITE = 0x2, + PROT_EXEC = 0x4, + MAP_ANON = 0x20, + MAP_PRIVATE = 0x2, + MAP_FIXED = 0x10, + SA_RESTART = 0x10000000, + SA_ONSTACK = 0x8000000, + SA_RESTORER = 0x4000000, + SA_SIGINFO = 0x4, + SIGHUP = 0x1, + SIGINT = 0x2, + SIGQUIT = 0x3, + SIGILL = 0x4, + SIGTRAP = 0x5, + SIGABRT = 0x6, + SIGBUS = 0x7, + SIGFPE = 0x8, + SIGKILL = 0x9, + SIGUSR1 = 0xa, + SIGSEGV = 0xb, + SIGUSR2 = 0xc, + SIGPIPE = 0xd, + SIGALRM = 0xe, + SIGSTKFLT = 0x10, + SIGCHLD = 0x11, + SIGCONT = 0x12, + SIGSTOP = 0x13, + SIGTSTP = 0x14, + SIGTTIN = 0x15, + SIGTTOU = 0x16, + SIGURG = 0x17, + SIGXCPU = 0x18, + SIGXFSZ = 0x19, + SIGVTALRM = 0x1a, + SIGPROF = 0x1b, + SIGWINCH = 0x1c, + SIGIO = 0x1d, + SIGPWR = 0x1e, + SIGSYS = 0x1f, + FPE_INTDIV = 0x1, + FPE_INTOVF = 0x2, + FPE_FLTDIV = 0x3, + FPE_FLTOVF = 0x4, + FPE_FLTUND = 0x5, + FPE_FLTRES = 0x6, + FPE_FLTINV = 0x7, + FPE_FLTSUB = 0x8, + BUS_ADRALN = 0x1, + BUS_ADRERR = 0x2, + BUS_OBJERR = 0x3, + SEGV_MAPERR = 0x1, + SEGV_ACCERR = 0x2, + ITIMER_REAL = 0, + ITIMER_PROF = 0x2, + ITIMER_VIRTUAL = 0x1, + O_RDONLY = 0, + O_CLOEXEC = 02000000, +}; + +// Types +#pragma pack on + +typedef uint32 Sigset; + +typedef struct Timespec Timespec; +struct Timespec { + int32 tv_sec; + int32 tv_nsec; +}; + +typedef struct Sigaltstack Sigaltstack; +struct Sigaltstack { + void *ss_sp; + int32 ss_flags; + uint32 ss_size; +}; + +typedef struct Sigcontext Sigcontext; +struct Sigcontext { + uint32 trap_no; + uint32 error_code; + uint32 oldmask; + uint32 arm_r0; + uint32 arm_r1; + uint32 arm_r2; + uint32 arm_r3; + uint32 arm_r4; + uint32 arm_r5; + uint32 arm_r6; + uint32 arm_r7; + uint32 arm_r8; + uint32 arm_r9; + uint32 arm_r10; + uint32 arm_fp; + uint32 arm_ip; + uint32 arm_sp; + uint32 arm_lr; + uint32 arm_pc; + uint32 arm_cpsr; + uint32 fault_address; +}; + +typedef struct Ucontext Ucontext; +struct Ucontext { + uint32 uc_flags; + Ucontext *uc_link; + Sigaltstack uc_stack; + Sigcontext uc_mcontext; + uint32 uc_sigmask; + int32 __unused[31]; + uint32 uc_regspace[128]; +}; + +typedef struct Timeval Timeval; +struct Timeval { + int32 tv_sec; + int32 tv_usec; +}; + +typedef struct Itimerval Itimerval; +struct Itimerval { + Timeval it_interval; + Timeval it_value; +}; + +typedef struct Siginfo Siginfo; +struct Siginfo { + int32 si_signo; + int32 si_errno; + int32 si_code; + uint8 _sifields[4]; +}; + +typedef struct Sigaction Sigaction; +struct Sigaction { + void *sa_handler; + uint32 sa_flags; + void *sa_restorer; + uint32 sa_mask; +}; +#pragma pack off diff --git a/src/pkg/runtime/linux/arm/rt0.s b/src/pkg/runtime/linux/arm/rt0.s new file mode 100644 index 000000000..8838b4891 --- /dev/null +++ b/src/pkg/runtime/linux/arm/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_arm_linux(SB),7,$0 + B _rt0_arm(SB) diff --git a/src/pkg/runtime/linux/arm/signal.c b/src/pkg/runtime/linux/arm/signal.c new file mode 100644 index 000000000..88a84d112 --- /dev/null +++ b/src/pkg/runtime/linux/arm/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" + +void +runtime·dumpregs(Sigcontext *r) +{ + runtime·printf("trap %x\n", r->trap_no); + runtime·printf("error %x\n", r->error_code); + runtime·printf("oldmask %x\n", r->oldmask); + runtime·printf("r0 %x\n", r->arm_r0); + runtime·printf("r1 %x\n", r->arm_r1); + runtime·printf("r2 %x\n", r->arm_r2); + runtime·printf("r3 %x\n", r->arm_r3); + runtime·printf("r4 %x\n", r->arm_r4); + runtime·printf("r5 %x\n", r->arm_r5); + runtime·printf("r6 %x\n", r->arm_r6); + runtime·printf("r7 %x\n", r->arm_r7); + runtime·printf("r8 %x\n", r->arm_r8); + runtime·printf("r9 %x\n", r->arm_r9); + runtime·printf("r10 %x\n", r->arm_r10); + runtime·printf("fp %x\n", r->arm_fp); + runtime·printf("ip %x\n", r->arm_ip); + runtime·printf("sp %x\n", r->arm_sp); + runtime·printf("lr %x\n", r->arm_lr); + runtime·printf("pc %x\n", r->arm_pc); + runtime·printf("cpsr %x\n", r->arm_cpsr); + runtime·printf("fault %x\n", r->fault_address); +} + +/* + * This assembler routine takes the args from registers, puts them on the stack, + * and calls sighandler(). + */ +extern void runtime·sigtramp(void); +extern void runtime·sigignore(void); // just returns +extern void runtime·sigreturn(void); // calls runtime·sigreturn + +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; + Sigcontext *r; + + uc = context; + r = &uc->uc_mcontext; + + if(sig == SIGPROF) { + runtime·sigprof((uint8*)r->arm_pc, (uint8*)r->arm_sp, (uint8*)r->arm_lr, 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 = r->fault_address; + gp->sigpc = r->arm_pc; + + // If this is a leaf function, we do smash LR, + // but we're not going back there anyway. + // Don't bother smashing if r->arm_pc is 0, + // which is probably a call to a nil func: the + // old link register is more useful in the stack trace. + if(r->arm_pc != 0) + r->arm_lr = r->arm_pc; + r->arm_pc = (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->arm_pc); + runtime·printf("\n"); + + if(runtime·gotraceback()){ + runtime·traceback((void*)r->arm_pc, (void*)r->arm_sp, (void*)r->arm_lr, gp); + runtime·tracebackothers(gp); + runtime·printf("\n"); + runtime·dumpregs(r); + } + +// breakpoint(); + runtime·exit(2); +} + +void +runtime·signalstack(byte *p, int32 n) +{ + Sigaltstack st; + + st.ss_sp = 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_ONSTACK | SA_SIGINFO | SA_RESTORER; + if(restart) + sa.sa_flags |= SA_RESTART; + sa.sa_mask = ~0ULL; + sa.sa_restorer = (void*)runtime·sigreturn; + if(fn == runtime·sighandler) + fn = (void*)runtime·sigtramp; + sa.sa_handler = fn; + runtime·rt_sigaction(i, &sa, nil, 8); +} + +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/linux/arm/sys.s b/src/pkg/runtime/linux/arm/sys.s new file mode 100644 index 000000000..8619f0945 --- /dev/null +++ b/src/pkg/runtime/linux/arm/sys.s @@ -0,0 +1,319 @@ +// 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 arm, Linux +// + +#include "arm/asm.h" + +// OABI +//#define SYS_BASE 0x00900000 + +// EABI +#define SYS_BASE 0x0 + +#define SYS_exit (SYS_BASE + 1) +#define SYS_read (SYS_BASE + 3) +#define SYS_write (SYS_BASE + 4) +#define SYS_open (SYS_BASE + 5) +#define SYS_close (SYS_BASE + 6) +#define SYS_gettimeofday (SYS_BASE + 78) +#define SYS_clone (SYS_BASE + 120) +#define SYS_rt_sigreturn (SYS_BASE + 173) +#define SYS_rt_sigaction (SYS_BASE + 174) +#define SYS_sigaltstack (SYS_BASE + 186) +#define SYS_mmap2 (SYS_BASE + 192) +#define SYS_futex (SYS_BASE + 240) +#define SYS_exit_group (SYS_BASE + 248) +#define SYS_munmap (SYS_BASE + 91) +#define SYS_setitimer (SYS_BASE + 104) +#define SYS_mincore (SYS_BASE + 219) +#define SYS_gettid (SYS_BASE + 224) +#define SYS_tkill (SYS_BASE + 238) +#define SYS_sched_yield (SYS_BASE + 158) + +#define ARM_BASE (SYS_BASE + 0x0f0000) +#define SYS_ARM_cacheflush (ARM_BASE + 2) + +TEXT runtime·open(SB),7,$0 + MOVW 0(FP), R0 + MOVW 4(FP), R1 + MOVW 8(FP), R2 + MOVW $SYS_open, R7 + SWI $0 + RET + +TEXT runtime·close(SB),7,$0 + MOVW 0(FP), R0 + MOVW $SYS_close, R7 + SWI $0 + RET + +TEXT runtime·write(SB),7,$0 + MOVW 0(FP), R0 + MOVW 4(FP), R1 + MOVW 8(FP), R2 + MOVW $SYS_write, R7 + SWI $0 + RET + +TEXT runtime·read(SB),7,$0 + MOVW 0(FP), R0 + MOVW 4(FP), R1 + MOVW 8(FP), R2 + MOVW $SYS_read, R7 + SWI $0 + RET + +TEXT runtime·exit(SB),7,$-4 + MOVW 0(FP), R0 + MOVW $SYS_exit_group, R7 + SWI $0 + MOVW $1234, R0 + MOVW $1002, R1 + MOVW R0, (R1) // fail hard + +TEXT runtime·exit1(SB),7,$-4 + MOVW 0(FP), R0 + MOVW $SYS_exit, R7 + SWI $0 + MOVW $1234, R0 + MOVW $1003, R1 + MOVW R0, (R1) // fail hard + +TEXT runtime·raisesigpipe(SB),7,$-4 + MOVW $SYS_gettid, R7 + SWI $0 + // arg 1 tid already in R0 from gettid + MOVW $13, R1 // arg 2 SIGPIPE + MOVW $SYS_tkill, R7 + SWI $0 + RET + +TEXT runtime·mmap(SB),7,$0 + MOVW 0(FP), R0 + MOVW 4(FP), R1 + MOVW 8(FP), R2 + MOVW 12(FP), R3 + MOVW 16(FP), R4 + MOVW 20(FP), R5 + MOVW $SYS_mmap2, R7 + SWI $0 + RET + +TEXT runtime·munmap(SB),7,$0 + MOVW 0(FP), R0 + MOVW 4(FP), R1 + MOVW $SYS_munmap, R7 + SWI $0 + RET + +TEXT runtime·setitimer(SB),7,$0 + MOVW 0(FP), R0 + MOVW 4(FP), R1 + MOVW 8(FP), R2 + MOVW $SYS_setitimer, R7 + SWI $0 + RET + +TEXT runtime·mincore(SB),7,$0 + MOVW 0(FP), R0 + MOVW 4(FP), R1 + MOVW 8(FP), R2 + MOVW $SYS_mincore, R7 + SWI $0 + RET + +TEXT runtime·gettime(SB),7,$32 + /* dummy version - return 0,0 */ + MOVW $0, R1 + MOVW 0(FP), R0 + MOVW R1, 0(R0) + MOVW R1, 4(R0) + MOVW 4(FP), R0 + MOVW R1, 0(R0) + +/* + attempt at real version - seg faults + + MOVW $8(SP), R0 + MOVW $0, R1 + MOVW $SYS_gettimeofday, R7 + SWI $0 + + MOVW 0(FP), R0 // sec + MOVW 8(SP), R1 + MOVW R1, 0(R0) + + MOVW 4(FP), R0 // usec + MOVW 12(SP), R1 + MOVW R1, 0(R0) +*/ + RET + +// int32 futex(int32 *uaddr, int32 op, int32 val, +// struct timespec *timeout, int32 *uaddr2, int32 val2); +TEXT runtime·futex(SB),7,$0 + MOVW 4(SP), R0 + MOVW 8(SP), R1 + MOVW 12(SP), R2 + MOVW 16(SP), R3 + MOVW 20(SP), R4 + MOVW 24(SP), R5 + MOVW $SYS_futex, R7 + SWI $0 + RET + + +// int32 clone(int32 flags, void *stack, M *m, G *g, void (*fn)(void)); +TEXT runtime·clone(SB),7,$0 + MOVW flags+0(FP), R0 + MOVW stack+4(FP), R1 + MOVW $0, R2 // parent tid ptr + MOVW $0, R3 // tls_val + MOVW $0, R4 // child tid ptr + MOVW $0, R5 + + // Copy m, g, fn off parent stack for use by child. + // TODO(kaib): figure out which registers are clobbered by clone and avoid stack copying + MOVW $-16(R1), R1 + MOVW mm+8(FP), R6 + MOVW R6, 0(R1) + MOVW gg+12(FP), R6 + MOVW R6, 4(R1) + MOVW fn+16(FP), R6 + MOVW R6, 8(R1) + MOVW $1234, R6 + MOVW R6, 12(R1) + + MOVW $SYS_clone, R7 + SWI $0 + + // In parent, return. + CMP $0, R0 + BEQ 2(PC) + RET + + // Paranoia: check that SP is as we expect. Use R13 to avoid linker 'fixup' + MOVW 12(R13), R0 + MOVW $1234, R1 + CMP R0, R1 + BEQ 2(PC) + BL runtime·abort(SB) + + MOVW 0(R13), m + MOVW 4(R13), g + + // paranoia; check they are not nil + MOVW 0(m), R0 + MOVW 0(g), R0 + + BL runtime·emptyfunc(SB) // fault if stack check is wrong + + // Initialize m->procid to Linux tid + MOVW $SYS_gettid, R7 + SWI $0 + MOVW R0, m_procid(m) + + // Call fn + MOVW 8(R13), R0 + MOVW $16(R13), R13 + BL (R0) + + MOVW $0, R0 + MOVW R0, 4(R13) + BL runtime·exit1(SB) + + // It shouldn't return + MOVW $1234, R0 + MOVW $1005, R1 + MOVW R0, (R1) + + +TEXT runtime·cacheflush(SB),7,$0 + MOVW 0(FP), R0 + MOVW 4(FP), R1 + MOVW $0, R2 + MOVW $SYS_ARM_cacheflush, R7 + SWI $0 + RET + +TEXT runtime·sigaltstack(SB),7,$0 + MOVW 0(FP), R0 + MOVW 4(FP), R1 + MOVW $SYS_sigaltstack, R7 + SWI $0 + RET + +TEXT runtime·sigignore(SB),7,$0 + RET + +TEXT runtime·sigtramp(SB),7,$24 + // save g + MOVW g, R3 + MOVW g, 20(R13) + + // g = m->gsignal + MOVW m_gsignal(m), g + + // copy arguments for call to sighandler + MOVW R0, 4(R13) + MOVW R1, 8(R13) + MOVW R2, 12(R13) + MOVW R3, 16(R13) + + BL runtime·sighandler(SB) + + // restore g + MOVW 20(R13), g + + RET + +TEXT runtime·rt_sigaction(SB),7,$0 + MOVW 0(FP), R0 + MOVW 4(FP), R1 + MOVW 8(FP), R2 + MOVW 12(FP), R3 + MOVW $SYS_rt_sigaction, R7 + SWI $0 + RET + +TEXT runtime·sigreturn(SB),7,$0 + MOVW $SYS_rt_sigreturn, R7 + SWI $0 + RET + +// Use kernel version instead of native armcas in ../../arm.s. +// See ../../../sync/atomic/asm_linux_arm.s for details. +TEXT cas<>(SB),7,$0 + MOVW $0xffff0fc0, PC + +TEXT runtime·cas(SB),7,$0 + MOVW valptr+0(FP), R2 + MOVW old+4(FP), R0 +casagain: + MOVW new+8(FP), R1 + BL cas<>(SB) + BCC cascheck + MOVW $1, R0 + RET +cascheck: + // Kernel lies; double-check. + MOVW valptr+0(FP), R2 + MOVW old+4(FP), R0 + MOVW 0(R2), R3 + CMP R0, R3 + BEQ casagain + MOVW $0, R0 + RET + + +TEXT runtime·casp(SB),7,$0 + B runtime·cas(SB) + +TEXT runtime·osyield(SB),7,$0 + MOVW $SYS_sched_yield, R7 + SWI $0 + RET diff --git a/src/pkg/runtime/linux/defs.c b/src/pkg/runtime/linux/defs.c new file mode 100644 index 000000000..5dda78789 --- /dev/null +++ b/src/pkg/runtime/linux/defs.c @@ -0,0 +1,95 @@ +// 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 -m64 defs1.c >>amd64/defs.h + */ + +// Linux glibc and Linux kernel define different and conflicting +// definitions for struct sigaction, struct timespec, etc. +// We want the kernel ones, which are in the asm/* headers. +// But then we'd get conflicts when we include the system +// headers for things like ucontext_t, so that happens in +// a separate file, defs1.c. + +#include <asm/posix_types.h> +#define size_t __kernel_size_t +#include <asm/signal.h> +#include <asm/siginfo.h> +#include <asm/mman.h> + +enum { + $PROT_NONE = PROT_NONE, + $PROT_READ = PROT_READ, + $PROT_WRITE = PROT_WRITE, + $PROT_EXEC = PROT_EXEC, + + $MAP_ANON = MAP_ANONYMOUS, + $MAP_PRIVATE = MAP_PRIVATE, + $MAP_FIXED = MAP_FIXED, + + $SA_RESTART = SA_RESTART, + $SA_ONSTACK = SA_ONSTACK, + $SA_RESTORER = SA_RESTORER, + $SA_SIGINFO = SA_SIGINFO, + + $SIGHUP = SIGHUP, + $SIGINT = SIGINT, + $SIGQUIT = SIGQUIT, + $SIGILL = SIGILL, + $SIGTRAP = SIGTRAP, + $SIGABRT = SIGABRT, + $SIGBUS = SIGBUS, + $SIGFPE = SIGFPE, + $SIGKILL = SIGKILL, + $SIGUSR1 = SIGUSR1, + $SIGSEGV = SIGSEGV, + $SIGUSR2 = SIGUSR2, + $SIGPIPE = SIGPIPE, + $SIGALRM = SIGALRM, + $SIGSTKFLT = SIGSTKFLT, + $SIGCHLD = SIGCHLD, + $SIGCONT = SIGCONT, + $SIGSTOP = SIGSTOP, + $SIGTSTP = SIGTSTP, + $SIGTTIN = SIGTTIN, + $SIGTTOU = SIGTTOU, + $SIGURG = SIGURG, + $SIGXCPU = SIGXCPU, + $SIGXFSZ = SIGXFSZ, + $SIGVTALRM = SIGVTALRM, + $SIGPROF = SIGPROF, + $SIGWINCH = SIGWINCH, + $SIGIO = SIGIO, + $SIGPWR = SIGPWR, + $SIGSYS = SIGSYS, + + $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 timespec $Timespec; +typedef struct timeval $Timeval; +typedef struct sigaction $Sigaction; +typedef siginfo_t $Siginfo; +typedef struct itimerval $Itimerval; diff --git a/src/pkg/runtime/linux/defs1.c b/src/pkg/runtime/linux/defs1.c new file mode 100644 index 000000000..e737f8e9e --- /dev/null +++ b/src/pkg/runtime/linux/defs1.c @@ -0,0 +1,24 @@ +// 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 -m64 defs1.c >>amd64/defs.h + */ + +#include <ucontext.h> + +typedef __sigset_t $Usigset; +typedef struct _libc_fpxreg $Fpxreg; +typedef struct _libc_xmmreg $Xmmreg; +typedef struct _libc_fpstate $Fpstate; +typedef struct _fpxreg $Fpxreg1; +typedef struct _xmmreg $Xmmreg1; +typedef struct _fpstate $Fpstate1; +typedef struct _fpreg $Fpreg1; +typedef struct sigaltstack $Sigaltstack; +typedef mcontext_t $Mcontext; +typedef ucontext_t $Ucontext; +typedef struct sigcontext $Sigcontext; diff --git a/src/pkg/runtime/linux/defs2.c b/src/pkg/runtime/linux/defs2.c new file mode 100644 index 000000000..ff641fff2 --- /dev/null +++ b/src/pkg/runtime/linux/defs2.c @@ -0,0 +1,120 @@ +// 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 -m32 \ + -f -I/home/rsc/pub/linux-2.6/arch/x86/include \ + -f -I/home/rsc/pub/linux-2.6/include \ + -f -D_LOOSE_KERNEL_NAMES \ + -f -D__ARCH_SI_UID_T'='__kernel_uid32_t \ + defs2.c >386/defs.h + + * The asm header tricks we have to use for Linux on amd64 + * (see defs.c and defs1.c) don't work here, so this is yet another + * file. Sigh. + */ + +#include <asm/signal.h> +#include <asm/mman.h> +#include <asm/sigcontext.h> +#include <asm/ucontext.h> +#include <asm/siginfo.h> + +/* +#include <sys/signal.h> +#include <sys/mman.h> +#include <ucontext.h> +*/ + +/* This is the sigaction structure from the Linux 2.1.68 kernel which + is used with the rt_sigaction system call. For 386 this is not + defined in any public header file. */ + +struct kernel_sigaction { + __sighandler_t k_sa_handler; + unsigned long sa_flags; + void (*sa_restorer) (void); + sigset_t sa_mask; +}; + +enum { + $PROT_NONE = PROT_NONE, + $PROT_READ = PROT_READ, + $PROT_WRITE = PROT_WRITE, + $PROT_EXEC = PROT_EXEC, + + $MAP_ANON = MAP_ANONYMOUS, + $MAP_PRIVATE = MAP_PRIVATE, + $MAP_FIXED = MAP_FIXED, + + $SA_RESTART = SA_RESTART, + $SA_ONSTACK = SA_ONSTACK, + $SA_RESTORER = SA_RESTORER, + $SA_SIGINFO = SA_SIGINFO, + + $SIGHUP = SIGHUP, + $SIGINT = SIGINT, + $SIGQUIT = SIGQUIT, + $SIGILL = SIGILL, + $SIGTRAP = SIGTRAP, + $SIGABRT = SIGABRT, + $SIGBUS = SIGBUS, + $SIGFPE = SIGFPE, + $SIGKILL = SIGKILL, + $SIGUSR1 = SIGUSR1, + $SIGSEGV = SIGSEGV, + $SIGUSR2 = SIGUSR2, + $SIGPIPE = SIGPIPE, + $SIGALRM = SIGALRM, + $SIGSTKFLT = SIGSTKFLT, + $SIGCHLD = SIGCHLD, + $SIGCONT = SIGCONT, + $SIGSTOP = SIGSTOP, + $SIGTSTP = SIGTSTP, + $SIGTTIN = SIGTTIN, + $SIGTTOU = SIGTTOU, + $SIGURG = SIGURG, + $SIGXCPU = SIGXCPU, + $SIGXFSZ = SIGXFSZ, + $SIGVTALRM = SIGVTALRM, + $SIGPROF = SIGPROF, + $SIGWINCH = SIGWINCH, + $SIGIO = SIGIO, + $SIGPWR = SIGPWR, + $SIGSYS = SIGSYS, + + $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 _fpreg $Fpreg; +typedef struct _fpxreg $Fpxreg; +typedef struct _xmmreg $Xmmreg; +typedef struct _fpstate $Fpstate; +typedef struct timespec $Timespec; +typedef struct timeval $Timeval; +typedef struct kernel_sigaction $Sigaction; +typedef siginfo_t $Siginfo; +typedef struct sigaltstack $Sigaltstack; +typedef struct sigcontext $Sigcontext; +typedef struct ucontext $Ucontext; +typedef struct itimerval $Itimerval; diff --git a/src/pkg/runtime/linux/defs_arm.c b/src/pkg/runtime/linux/defs_arm.c new file mode 100644 index 000000000..1f935046e --- /dev/null +++ b/src/pkg/runtime/linux/defs_arm.c @@ -0,0 +1,122 @@ +// 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 + * On a Debian Lenny arm linux distribution: + godefs -f-I/usr/src/linux-headers-2.6.26-2-versatile/include defs_arm.c + */ + +#define __ARCH_SI_UID_T int + +#include <asm/signal.h> +#include <asm/mman.h> +#include <asm/sigcontext.h> +#include <asm/ucontext.h> +#include <asm/siginfo.h> +#include <linux/time.h> + +/* +#include <sys/signal.h> +#include <sys/mman.h> +#include <ucontext.h> +*/ + +enum { + $PROT_NONE = PROT_NONE, + $PROT_READ = PROT_READ, + $PROT_WRITE = PROT_WRITE, + $PROT_EXEC = PROT_EXEC, + + $MAP_ANON = MAP_ANONYMOUS, + $MAP_PRIVATE = MAP_PRIVATE, + $MAP_FIXED = MAP_FIXED, + + $SA_RESTART = SA_RESTART, + $SA_ONSTACK = SA_ONSTACK, + $SA_RESTORER = SA_RESTORER, + $SA_SIGINFO = SA_SIGINFO, + + $SIGHUP = SIGHUP, + $SIGINT = SIGINT, + $SIGQUIT = SIGQUIT, + $SIGILL = SIGILL, + $SIGTRAP = SIGTRAP, + $SIGABRT = SIGABRT, + $SIGBUS = SIGBUS, + $SIGFPE = SIGFPE, + $SIGKILL = SIGKILL, + $SIGUSR1 = SIGUSR1, + $SIGSEGV = SIGSEGV, + $SIGUSR2 = SIGUSR2, + $SIGPIPE = SIGPIPE, + $SIGALRM = SIGALRM, + $SIGSTKFLT = SIGSTKFLT, + $SIGCHLD = SIGCHLD, + $SIGCONT = SIGCONT, + $SIGSTOP = SIGSTOP, + $SIGTSTP = SIGTSTP, + $SIGTTIN = SIGTTIN, + $SIGTTOU = SIGTTOU, + $SIGURG = SIGURG, + $SIGXCPU = SIGXCPU, + $SIGXFSZ = SIGXFSZ, + $SIGVTALRM = SIGVTALRM, + $SIGPROF = SIGPROF, + $SIGWINCH = SIGWINCH, + $SIGIO = SIGIO, + $SIGPWR = SIGPWR, + $SIGSYS = SIGSYS, + + $FPE_INTDIV = FPE_INTDIV & 0xFFFF, + $FPE_INTOVF = FPE_INTOVF & 0xFFFF, + $FPE_FLTDIV = FPE_FLTDIV & 0xFFFF, + $FPE_FLTOVF = FPE_FLTOVF & 0xFFFF, + $FPE_FLTUND = FPE_FLTUND & 0xFFFF, + $FPE_FLTRES = FPE_FLTRES & 0xFFFF, + $FPE_FLTINV = FPE_FLTINV & 0xFFFF, + $FPE_FLTSUB = FPE_FLTSUB & 0xFFFF, + + $BUS_ADRALN = BUS_ADRALN & 0xFFFF, + $BUS_ADRERR = BUS_ADRERR & 0xFFFF, + $BUS_OBJERR = BUS_OBJERR & 0xFFFF, + + $SEGV_MAPERR = SEGV_MAPERR & 0xFFFF, + $SEGV_ACCERR = SEGV_ACCERR & 0xFFFF, + + $ITIMER_REAL = ITIMER_REAL, + $ITIMER_PROF = ITIMER_PROF, + $ITIMER_VIRTUAL = ITIMER_VIRTUAL, +}; + +typedef sigset_t $Sigset; +typedef struct timespec $Timespec; +typedef struct sigaltstack $Sigaltstack; +typedef struct sigcontext $Sigcontext; +typedef struct ucontext $Ucontext; +typedef struct timeval $Timeval; +typedef struct itimerval $Itimerval; + +struct xsiginfo { + int si_signo; + int si_errno; + int si_code; + char _sifields[4]; +}; + +typedef struct xsiginfo $Siginfo; + +#undef sa_handler +#undef sa_flags +#undef sa_restorer +#undef sa_mask + +struct xsigaction { + void (*sa_handler)(void); + unsigned long sa_flags; + void (*sa_restorer)(void); + unsigned int sa_mask; /* mask last for extensibility */ +}; + +typedef struct xsigaction $Sigaction; diff --git a/src/pkg/runtime/linux/mem.c b/src/pkg/runtime/linux/mem.c new file mode 100644 index 000000000..ad0fac6d3 --- /dev/null +++ b/src/pkg/runtime/linux/mem.c @@ -0,0 +1,113 @@ +#include "runtime.h" +#include "defs.h" +#include "os.h" +#include "malloc.h" + +enum +{ + ENOMEM = 12, +}; + +static int32 +addrspace_free(void *v, uintptr n) +{ + uintptr page_size = 4096; + uintptr off; + int8 one_byte; + + for(off = 0; off < n; off += page_size) { + int32 errval = runtime·mincore((int8 *)v + off, page_size, (void *)&one_byte); + // errval is 0 if success, or -(error_code) if error. + if (errval == 0 || errval != -ENOMEM) + return 0; + } + USED(v); + USED(n); + return 1; +} + + +void* +runtime·SysAlloc(uintptr n) +{ + void *p; + + mstats.sys += n; + p = runtime·mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0); + if(p < (void*)4096) { + if(p == (void*)EACCES) { + runtime·printf("runtime: mmap: access denied\n"); + runtime·printf("if you're running SELinux, enable execmem for this process.\n"); + runtime·exit(2); + } + return nil; + } + return p; +} + +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) +{ + 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; + + p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0); + if(p < (void*)4096) { + return nil; + } + return p; +} + +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 != v && addrspace_free(v, n)) { + // On some systems, mmap ignores v without + // MAP_FIXED, so retry if the address space is free. + if(p > (void*)4096) { + runtime·munmap(p, n); + } + 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·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/linux/os.h b/src/pkg/runtime/linux/os.h new file mode 100644 index 000000000..0bb8d0339 --- /dev/null +++ b/src/pkg/runtime/linux/os.h @@ -0,0 +1,19 @@ +// 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 SIG_DFL ((void*)0) +#define SIG_IGN ((void*)1) + +// Linux-specific system calls +int32 runtime·futex(uint32*, int32, uint32, Timespec*, uint32*, uint32); +int32 runtime·clone(int32, void*, M*, G*, void(*)(void)); + +struct Sigaction; +void runtime·rt_sigaction(uintptr, struct Sigaction*, void*, uintptr); + +void runtime·sigaltstack(Sigaltstack*, Sigaltstack*); +void runtime·sigpanic(void); +void runtime·setitimer(int32, Itimerval*, Itimerval*); + +void runtime·raisesigpipe(void); diff --git a/src/pkg/runtime/linux/signals.h b/src/pkg/runtime/linux/signals.h new file mode 100644 index 000000000..919b80ea2 --- /dev/null +++ b/src/pkg/runtime/linux/signals.h @@ -0,0 +1,51 @@ +// 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+P, "SIGILL: illegal instruction", + /* 5 */ C, "SIGTRAP: trace trap", + /* 6 */ C, "SIGABRT: abort", + /* 7 */ C+P, "SIGBUS: bus error", + /* 8 */ C+P, "SIGFPE: floating-point exception", + /* 9 */ 0, "SIGKILL: kill", + /* 10 */ Q+I+R, "SIGUSR1: user-defined signal 1", + /* 11 */ C+P, "SIGSEGV: segmentation violation", + /* 12 */ Q+I+R, "SIGUSR2: user-defined signal 2", + /* 13 */ I, "SIGPIPE: write to broken pipe", + /* 14 */ Q+I+R, "SIGALRM: alarm clock", + /* 15 */ Q+R, "SIGTERM: termination", + /* 16 */ C, "SIGSTKFLT: stack fault", + /* 17 */ Q+I+R, "SIGCHLD: child status has changed", + /* 18 */ 0, "SIGCONT: continue", + /* 19 */ 0, "SIGSTOP: stop, unblockable", + /* 20 */ Q+I+R, "SIGTSTP: keyboard stop", + /* 21 */ Q+I+R, "SIGTTIN: background read from tty", + /* 22 */ Q+I+R, "SIGTTOU: background write to tty", + /* 23 */ Q+I+R, "SIGURG: urgent condition on socket", + /* 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, "SIGIO: i/o now possible", + /* 30 */ Q+I+R, "SIGPWR: power failure restart", + /* 31 */ C, "SIGSYS: bad system call", +}; +#undef C +#undef I +#undef R +#undef Q +#undef P + +#define NSIG 32 diff --git a/src/pkg/runtime/linux/thread.c b/src/pkg/runtime/linux/thread.c new file mode 100644 index 000000000..4878a00f2 --- /dev/null +++ b/src/pkg/runtime/linux/thread.c @@ -0,0 +1,320 @@ +// 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 "os.h" +#include "stack.h" + +extern SigTab runtime·sigtab[]; +static int32 proccount; + +int32 runtime·open(uint8*, int32, int32); +int32 runtime·close(int32); +int32 runtime·read(int32, void*, int32); + +// Linux futex. +// +// futexsleep(uint32 *addr, uint32 val) +// futexwakeup(uint32 *addr) +// +// Futexsleep atomically checks if *addr == val and if so, sleeps on addr. +// Futexwakeup wakes up threads sleeping on addr. +// Futexsleep is allowed to wake up spuriously. + +enum +{ + MUTEX_UNLOCKED = 0, + MUTEX_LOCKED = 1, + MUTEX_SLEEPING = 2, + + ACTIVE_SPIN = 4, + ACTIVE_SPIN_CNT = 30, + PASSIVE_SPIN = 1, + + FUTEX_WAIT = 0, + FUTEX_WAKE = 1, + + EINTR = 4, + EAGAIN = 11, +}; + +// TODO(rsc): I tried using 1<<40 here but futex woke up (-ETIMEDOUT). +// I wonder if the timespec that gets to the kernel +// actually has two 32-bit numbers in it, so that +// a 64-bit 1<<40 ends up being 0 seconds, +// 1<<8 nanoseconds. +static Timespec longtime = +{ + 1<<30, // 34 years + 0 +}; + +// Atomically, +// if(*addr == val) sleep +// Might be woken up spuriously; that's allowed. +static void +futexsleep(uint32 *addr, uint32 val) +{ + // Some Linux kernels have a bug where futex of + // FUTEX_WAIT returns an internal error code + // as an errno. Libpthread ignores the return value + // here, and so can we: as it says a few lines up, + // spurious wakeups are allowed. + runtime·futex(addr, FUTEX_WAIT, val, &longtime, nil, 0); +} + +// If any procs are sleeping on addr, wake up at most cnt. +static void +futexwakeup(uint32 *addr, uint32 cnt) +{ + int64 ret; + + ret = runtime·futex(addr, FUTEX_WAKE, cnt, nil, nil, 0); + + if(ret >= 0) + return; + + // I don't know that futex wakeup can return + // EAGAIN or EINTR, but if it does, it would be + // safe to loop and call futex again. + runtime·printf("futexwakeup addr=%p returned %D\n", addr, ret); + *(int32*)0x1006 = 0x1006; +} + +static int32 +getproccount(void) +{ + int32 fd, rd, cnt, cpustrlen; + byte *cpustr, *pos, *bufpos; + byte buf[256]; + + fd = runtime·open((byte*)"/proc/stat", O_RDONLY|O_CLOEXEC, 0); + if(fd == -1) + return 1; + cnt = 0; + bufpos = buf; + cpustr = (byte*)"\ncpu"; + cpustrlen = runtime·findnull(cpustr); + for(;;) { + rd = runtime·read(fd, bufpos, sizeof(buf)-cpustrlen); + if(rd == -1) + break; + bufpos[rd] = 0; + for(pos=buf; pos=runtime·strstr(pos, cpustr); cnt++, pos++) { + } + if(rd < cpustrlen) + break; + runtime·memmove(buf, bufpos+rd-cpustrlen+1, cpustrlen-1); + bufpos = buf+cpustrlen-1; + } + runtime·close(fd); + return cnt ? cnt : 1; +} + +// Possible lock states are MUTEX_UNLOCKED, MUTEX_LOCKED and MUTEX_SLEEPING. +// MUTEX_SLEEPING means that there is presumably at least one sleeping thread. +// Note that there can be spinning threads during all states - they do not +// affect mutex's state. +static void +futexlock(Lock *l) +{ + uint32 i, v, wait, spin; + + // Speculative grab for lock. + v = runtime·xchg(&l->key, MUTEX_LOCKED); + if(v == MUTEX_UNLOCKED) + return; + + // wait is either MUTEX_LOCKED or MUTEX_SLEEPING + // depending on whether there is a thread sleeping + // on this mutex. If we ever change l->key from + // MUTEX_SLEEPING to some other value, we must be + // careful to change it back to MUTEX_SLEEPING before + // returning, to ensure that the sleeping thread gets + // its wakeup call. + wait = v; + + if(proccount == 0) + proccount = getproccount(); + + // On uniprocessor's, no point spinning. + // On multiprocessors, spin for ACTIVE_SPIN attempts. + spin = 0; + if(proccount > 1) + spin = ACTIVE_SPIN; + + for(;;) { + // Try for lock, spinning. + for(i = 0; i < spin; i++) { + while(l->key == MUTEX_UNLOCKED) + if(runtime·cas(&l->key, MUTEX_UNLOCKED, wait)) + return; + runtime·procyield(ACTIVE_SPIN_CNT); + } + + // Try for lock, rescheduling. + for(i=0; i < PASSIVE_SPIN; i++) { + while(l->key == MUTEX_UNLOCKED) + if(runtime·cas(&l->key, MUTEX_UNLOCKED, wait)) + return; + runtime·osyield(); + } + + // Sleep. + v = runtime·xchg(&l->key, MUTEX_SLEEPING); + if(v == MUTEX_UNLOCKED) + return; + wait = MUTEX_SLEEPING; + futexsleep(&l->key, MUTEX_SLEEPING); + } +} + +static void +futexunlock(Lock *l) +{ + uint32 v; + + v = runtime·xchg(&l->key, MUTEX_UNLOCKED); + if(v == MUTEX_UNLOCKED) + runtime·throw("unlock of unlocked lock"); + if(v == MUTEX_SLEEPING) + futexwakeup(&l->key, 1); +} + +void +runtime·lock(Lock *l) +{ + if(m->locks++ < 0) + runtime·throw("runtime·lock: lock count"); + futexlock(l); +} + +void +runtime·unlock(Lock *l) +{ + if(--m->locks < 0) + runtime·throw("runtime·unlock: lock count"); + futexunlock(l); +} + + +// One-time notifications. +void +runtime·noteclear(Note *n) +{ + n->state = 0; +} + +void +runtime·notewakeup(Note *n) +{ + runtime·xchg(&n->state, 1); + futexwakeup(&n->state, 1<<30); +} + +void +runtime·notesleep(Note *n) +{ + while(runtime·atomicload(&n->state) == 0) + futexsleep(&n->state, 0); +} + + +// Clone, the Linux rfork. +enum +{ + CLONE_VM = 0x100, + CLONE_FS = 0x200, + CLONE_FILES = 0x400, + CLONE_SIGHAND = 0x800, + CLONE_PTRACE = 0x2000, + CLONE_VFORK = 0x4000, + CLONE_PARENT = 0x8000, + CLONE_THREAD = 0x10000, + CLONE_NEWNS = 0x20000, + CLONE_SYSVSEM = 0x40000, + CLONE_SETTLS = 0x80000, + CLONE_PARENT_SETTID = 0x100000, + CLONE_CHILD_CLEARTID = 0x200000, + CLONE_UNTRACED = 0x800000, + CLONE_CHILD_SETTID = 0x1000000, + CLONE_STOPPED = 0x2000000, + CLONE_NEWUTS = 0x4000000, + CLONE_NEWIPC = 0x8000000, +}; + +void +runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void)) +{ + int32 ret; + int32 flags; + + /* + * note: strace gets confused if we use CLONE_PTRACE here. + */ + flags = CLONE_VM /* share memory */ + | CLONE_FS /* share cwd, etc */ + | CLONE_FILES /* share fd table */ + | CLONE_SIGHAND /* share sig handler table */ + | CLONE_THREAD /* revisit - okay for now */ + ; + + m->tls[0] = m->id; // so 386 asm can find it + if(0){ + runtime·printf("newosproc stk=%p m=%p g=%p fn=%p clone=%p id=%d/%d ostk=%p\n", + stk, m, g, fn, runtime·clone, m->id, m->tls[0], &m); + } + + if((ret = runtime·clone(flags, stk, m, g, fn)) < 0) { + runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), -ret); + runtime·throw("runtime.newosproc"); + } +} + +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); // OS X wants >=8K, Linux >=2K + 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); +} |