2008-06-30 12:50:36 -06:00
|
|
|
// 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, Darwin
|
2008-09-09 12:50:14 -06:00
|
|
|
// See http://fxr.watson.org/fxr/source/bsd/kern/syscalls.c?v=xnu-1228
|
|
|
|
// or /usr/include/sys/syscall.h (on a Mac) for system call numbers.
|
2008-06-30 12:50:36 -06:00
|
|
|
//
|
2010-08-04 18:50:22 -06:00
|
|
|
// The low 24 bits are the system call number.
|
|
|
|
// The high 8 bits specify the kind of system call: 1=Mach, 2=BSD, 3=Machine-Dependent.
|
|
|
|
//
|
2008-06-30 12:50:36 -06:00
|
|
|
|
2009-06-17 16:12:16 -06:00
|
|
|
#include "amd64/asm.h"
|
|
|
|
|
2008-09-09 12:50:14 -06:00
|
|
|
// Exit the entire program (like C exit)
|
2009-12-09 00:34:45 -07:00
|
|
|
TEXT exit(SB),7,$0
|
2008-06-30 12:50:36 -06:00
|
|
|
MOVL 8(SP), DI // arg 1 exit status
|
|
|
|
MOVL $(0x2000000+1), AX // syscall entry
|
|
|
|
SYSCALL
|
|
|
|
CALL notok(SB)
|
|
|
|
RET
|
|
|
|
|
2008-09-09 12:50:14 -06:00
|
|
|
// Exit this OS thread (like pthread_exit, which eventually
|
|
|
|
// calls __bsdthread_terminate).
|
2009-12-09 00:34:45 -07:00
|
|
|
TEXT exit1(SB),7,$0
|
2008-08-04 17:43:49 -06:00
|
|
|
MOVL 8(SP), DI // arg 1 exit status
|
2008-09-09 12:50:14 -06:00
|
|
|
MOVL $(0x2000000+361), AX // syscall entry
|
2008-08-04 17:43:49 -06:00
|
|
|
SYSCALL
|
|
|
|
CALL notok(SB)
|
|
|
|
RET
|
|
|
|
|
2009-12-09 00:34:45 -07:00
|
|
|
TEXT write(SB),7,$0
|
2009-06-17 16:12:16 -06:00
|
|
|
MOVL 8(SP), DI // arg 1 fd
|
2008-06-30 12:50:36 -06:00
|
|
|
MOVQ 16(SP), SI // arg 2 buf
|
|
|
|
MOVL 24(SP), DX // arg 3 count
|
|
|
|
MOVL $(0x2000000+4), AX // syscall entry
|
|
|
|
SYSCALL
|
|
|
|
JCC 2(PC)
|
|
|
|
CALL notok(SB)
|
|
|
|
RET
|
|
|
|
|
2010-02-08 15:32:22 -07:00
|
|
|
// void gettime(int64 *sec, int32 *usec)
|
|
|
|
TEXT gettime(SB), 7, $32
|
|
|
|
MOVQ SP, DI // must be non-nil, unused
|
|
|
|
MOVQ $0, SI
|
|
|
|
MOVQ $(0x2000000+116), AX
|
|
|
|
SYSCALL
|
|
|
|
MOVQ sec+0(FP), DI
|
|
|
|
MOVQ AX, (DI)
|
|
|
|
MOVQ usec+8(FP), DI
|
|
|
|
MOVL DX, (DI)
|
|
|
|
RET
|
|
|
|
|
2009-12-09 00:34:45 -07:00
|
|
|
TEXT sigaction(SB),7,$0
|
2008-06-30 12:50:36 -06:00
|
|
|
MOVL 8(SP), DI // arg 1 sig
|
|
|
|
MOVQ 16(SP), SI // arg 2 act
|
|
|
|
MOVQ 24(SP), DX // arg 3 oact
|
|
|
|
MOVQ 24(SP), CX // arg 3 oact
|
|
|
|
MOVQ 24(SP), R10 // arg 3 oact
|
|
|
|
MOVL $(0x2000000+46), AX // syscall entry
|
|
|
|
SYSCALL
|
|
|
|
JCC 2(PC)
|
|
|
|
CALL notok(SB)
|
|
|
|
RET
|
|
|
|
|
2010-08-04 18:50:22 -06:00
|
|
|
TEXT sigtramp(SB),7,$64
|
|
|
|
get_tls(BX)
|
|
|
|
|
|
|
|
// save g
|
|
|
|
MOVQ g(BX), BP
|
|
|
|
MOVQ BP, 40(SP)
|
|
|
|
|
|
|
|
// g = m->gsignal
|
|
|
|
MOVQ m(BX), BP
|
|
|
|
MOVQ m_gsignal(BP), BP
|
|
|
|
MOVQ BP, g(BX)
|
|
|
|
|
2009-06-17 16:12:16 -06:00
|
|
|
MOVL DX, 0(SP)
|
|
|
|
MOVQ CX, 8(SP)
|
|
|
|
MOVQ R8, 16(SP)
|
2008-12-03 15:21:28 -07:00
|
|
|
MOVQ R8, 24(SP) // save ucontext
|
|
|
|
MOVQ SI, 32(SP) // save infostyle
|
|
|
|
CALL DI
|
2010-08-04 18:50:22 -06:00
|
|
|
|
|
|
|
// restore g
|
|
|
|
get_tls(BX)
|
|
|
|
MOVQ 40(SP), BP
|
|
|
|
MOVQ BP, g(BX)
|
|
|
|
|
2008-12-03 15:21:28 -07:00
|
|
|
MOVL $(0x2000000+184), AX // sigreturn(ucontext, infostyle)
|
|
|
|
MOVQ 24(SP), DI // saved ucontext
|
|
|
|
MOVQ 32(SP), SI // saved infostyle
|
|
|
|
SYSCALL
|
|
|
|
INT $3 // not reached
|
2008-06-30 12:50:36 -06:00
|
|
|
|
2010-01-25 19:52:55 -07:00
|
|
|
TEXT ·mmap(SB),7,$0
|
2008-06-30 12:50:36 -06:00
|
|
|
MOVQ 8(SP), DI // arg 1 addr
|
2010-04-05 18:26:59 -06:00
|
|
|
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
|
2008-06-30 12:50:36 -06:00
|
|
|
MOVL $(0x2000000+197), AX // syscall entry
|
|
|
|
SYSCALL
|
|
|
|
JCC 2(PC)
|
|
|
|
CALL notok(SB)
|
|
|
|
RET
|
|
|
|
|
2009-12-09 00:34:45 -07:00
|
|
|
TEXT notok(SB),7,$0
|
2008-06-30 12:50:36 -06:00
|
|
|
MOVL $0xf1, BP
|
|
|
|
MOVQ BP, (BP)
|
|
|
|
RET
|
|
|
|
|
2009-12-09 00:34:45 -07:00
|
|
|
TEXT sigaltstack(SB),7,$0
|
2008-09-18 16:56:46 -06:00
|
|
|
MOVQ new+8(SP), DI
|
|
|
|
MOVQ old+16(SP), SI
|
|
|
|
MOVQ $(0x2000000+53), AX
|
|
|
|
SYSCALL
|
|
|
|
JCC 2(PC)
|
|
|
|
CALL notok(SB)
|
2008-06-30 12:50:36 -06:00
|
|
|
RET
|
2008-09-09 12:50:14 -06:00
|
|
|
|
|
|
|
// void bsdthread_create(void *stk, M *m, G *g, void (*fn)(void))
|
2009-12-09 00:34:45 -07:00
|
|
|
TEXT bsdthread_create(SB),7,$0
|
2008-09-09 12:50:14 -06:00
|
|
|
// Set up arguments to bsdthread_create system call.
|
|
|
|
// The ones in quotes pass through to the thread callback
|
|
|
|
// uninterpreted, so we can put whatever we want there.
|
|
|
|
MOVQ fn+32(SP), DI // "func"
|
2009-06-17 16:12:16 -06:00
|
|
|
MOVQ mm+16(SP), SI // "arg"
|
2008-09-09 12:50:14 -06:00
|
|
|
MOVQ stk+8(SP), DX // stack
|
2009-06-17 16:12:16 -06:00
|
|
|
MOVQ gg+24(SP), R10 // "pthread"
|
2009-06-04 12:16:03 -06:00
|
|
|
// TODO(rsc): why do we get away with 0 flags here but not on 386?
|
2008-12-15 09:56:32 -07:00
|
|
|
MOVQ $0, R8 // flags
|
runtime: work around kernel bug in Snow Leopard signal handling
Could not take a signal on threads other than the main thread.
If you look at the spinning binary with dtrace, you can see a
fault happening over and over:
$ dtrace -n '
fbt::user_trap:entry /execname=="boot32" && self->count < 10/
{
self->count++;
printf("%s %x %x %x %x", probefunc, arg1, arg2, arg3, arg4);
stack();
tracemem(arg4, 256);
}'
dtrace: description 'fbt::user_trap:entry ' matched 1 probe
CPU ID FUNCTION:NAME
1 17015 user_trap:entry user_trap 0 10 79af0a0 79af0a0
mach_kernel`lo_alltraps+0x12a
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
0: 0e 00 00 00 37 00 00 00 00 00 00 00 1f 00 00 00 ....7...........
10: 1f 00 00 00 a8 33 00 00 00 00 00 01 00 00 00 00 .....3..........
20: 98 ba dc fe 07 09 00 00 00 00 00 00 98 ba dc fe ................
30: 06 00 00 00 0d 00 00 00 34 00 00 00 9e 1c 00 00 ........4.......
40: 17 00 00 00 00 02 00 00 ac 30 00 00 1f 00 00 00 .........0......
50: 00 00 00 00 00 00 00 00 0d 00 00 00 e0 e6 29 00 ..............).
60: 34 00 00 00 00 00 00 00 9e 1c 00 00 00 00 00 00 4...............
70: 17 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 ................
80: ac 30 00 00 00 00 00 00 1f 00 00 00 00 00 00 00 .0..............
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a0: 48 00 00 00 10 00 00 00 85 00 00 00 a0 f2 29 00 H.............).
b0: 69 01 00 02 00 00 00 00 e6 93 04 82 ff 7f 00 00 i...............
c0: 2f 00 00 00 00 00 00 00 06 02 00 00 00 00 00 00 /...............
d0: 78 ee 42 01 01 00 00 00 1f 00 00 00 00 00 00 00 x.B.............
e0: 00 ed 9a 07 00 00 00 00 00 00 00 00 00 00 00 00 ................
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
...
The memory dump shows a 32-bit exception frame:
x86_saved_state32
gs = 0x37
fs = 0
es = 0x1f
ds = 0x1f
edi = 0x33a8
esi = 0x01000000
ebp = 0
cr2 = 0xfedcba98
ebx = 0x0907
edx = 0
ecx = 0xfedcba98
eax = 0x06
trapno = 0x0d
err = 0x34
eip = 0x1c9e
cs = 0x17
efl = 0x0200
uesp = 0x30ac
ss = 0x1f
The cr2 of 0xfedcba98 is the address that the new thread read
to cause the fault, but note that the trap is now a GP fault with
error code 0x34, meaning it's moved past the cr2 problem and on
to an invaild segment selector. The 0x34 is suspiciously similar
to the 0x37 in gs, and sure enough, OS X forces gs to have
that value in the signal handler, and if your thread hasn't set
up that segment (known as USER_CTHREAD), you'll fault on the IRET
into the signal handler and never be able to handle a signal.
The kernel bug is that it forces segment 0x37 without making sure
it is a valid segment. Leopard also forced 0x37 but had the courtesy
to set it up first.
Since OS X requires us to set up that segment (using the
thread_fast_set_cthread_self system call), we might as well
use it instead of the more complicated i386_set_ldt call to
set up our per-OS thread storage.
Also add some more zeros to bsdthread_register for new arguments
in Snow Leopard (apparently unnecessary, but being careful).
Fixes #510.
R=r
CC=golang-dev
https://golang.org/cl/824046
2010-04-08 14:24:37 -06:00
|
|
|
MOVQ $0, R9 // paranoia
|
2008-09-09 12:50:14 -06:00
|
|
|
MOVQ $(0x2000000+360), AX // bsdthread_create
|
|
|
|
SYSCALL
|
2010-04-28 20:36:42 -06:00
|
|
|
JCC 3(PC)
|
|
|
|
MOVL $-1, AX
|
|
|
|
RET
|
|
|
|
MOVL $0, AX
|
2008-09-09 12:50:14 -06:00
|
|
|
RET
|
|
|
|
|
|
|
|
// The thread that bsdthread_create creates starts executing here,
|
|
|
|
// because we registered this function using bsdthread_register
|
|
|
|
// at startup.
|
2009-11-18 19:17:11 -07:00
|
|
|
// DI = "pthread"
|
2008-09-09 12:50:14 -06:00
|
|
|
// SI = mach thread port
|
|
|
|
// DX = "func" (= fn)
|
|
|
|
// CX = "arg" (= m)
|
|
|
|
// R8 = stack
|
|
|
|
// R9 = flags (= 0)
|
|
|
|
// SP = stack - C_64_REDZONE_LEN (= stack - 128)
|
2009-12-09 00:34:45 -07:00
|
|
|
TEXT bsdthread_start(SB),7,$0
|
|
|
|
MOVQ R8, SP // empirically, SP is very wrong but R8 is right
|
2010-08-04 18:50:22 -06:00
|
|
|
|
|
|
|
PUSHQ DX
|
|
|
|
PUSHQ CX
|
|
|
|
PUSHQ SI
|
|
|
|
|
|
|
|
// set up thread local storage pointing at m->tls.
|
|
|
|
LEAQ m_tls(CX), DI
|
|
|
|
CALL settls(SB)
|
|
|
|
|
|
|
|
POPQ SI
|
|
|
|
POPQ CX
|
|
|
|
POPQ DX
|
|
|
|
|
|
|
|
get_tls(BX)
|
|
|
|
MOVQ CX, m(BX)
|
|
|
|
MOVQ SI, m_procid(CX) // thread port is m->procid
|
|
|
|
MOVQ m_g0(CX), AX
|
|
|
|
MOVQ AX, g(BX)
|
|
|
|
CALL stackcheck(SB) // smashes AX, CX
|
2008-09-09 12:50:14 -06:00
|
|
|
CALL DX // fn
|
|
|
|
CALL exit1(SB)
|
|
|
|
RET
|
|
|
|
|
|
|
|
// void bsdthread_register(void)
|
|
|
|
// registers callbacks for threadstart (see bsdthread_create above
|
|
|
|
// and wqthread and pthsize (not used). returns 0 on success.
|
2009-12-09 00:34:45 -07:00
|
|
|
TEXT bsdthread_register(SB),7,$0
|
2008-09-09 12:50:14 -06:00
|
|
|
MOVQ $bsdthread_start(SB), DI // threadstart
|
|
|
|
MOVQ $0, SI // wqthread, not used by us
|
|
|
|
MOVQ $0, DX // pthsize, not used by us
|
runtime: work around kernel bug in Snow Leopard signal handling
Could not take a signal on threads other than the main thread.
If you look at the spinning binary with dtrace, you can see a
fault happening over and over:
$ dtrace -n '
fbt::user_trap:entry /execname=="boot32" && self->count < 10/
{
self->count++;
printf("%s %x %x %x %x", probefunc, arg1, arg2, arg3, arg4);
stack();
tracemem(arg4, 256);
}'
dtrace: description 'fbt::user_trap:entry ' matched 1 probe
CPU ID FUNCTION:NAME
1 17015 user_trap:entry user_trap 0 10 79af0a0 79af0a0
mach_kernel`lo_alltraps+0x12a
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
0: 0e 00 00 00 37 00 00 00 00 00 00 00 1f 00 00 00 ....7...........
10: 1f 00 00 00 a8 33 00 00 00 00 00 01 00 00 00 00 .....3..........
20: 98 ba dc fe 07 09 00 00 00 00 00 00 98 ba dc fe ................
30: 06 00 00 00 0d 00 00 00 34 00 00 00 9e 1c 00 00 ........4.......
40: 17 00 00 00 00 02 00 00 ac 30 00 00 1f 00 00 00 .........0......
50: 00 00 00 00 00 00 00 00 0d 00 00 00 e0 e6 29 00 ..............).
60: 34 00 00 00 00 00 00 00 9e 1c 00 00 00 00 00 00 4...............
70: 17 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 ................
80: ac 30 00 00 00 00 00 00 1f 00 00 00 00 00 00 00 .0..............
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a0: 48 00 00 00 10 00 00 00 85 00 00 00 a0 f2 29 00 H.............).
b0: 69 01 00 02 00 00 00 00 e6 93 04 82 ff 7f 00 00 i...............
c0: 2f 00 00 00 00 00 00 00 06 02 00 00 00 00 00 00 /...............
d0: 78 ee 42 01 01 00 00 00 1f 00 00 00 00 00 00 00 x.B.............
e0: 00 ed 9a 07 00 00 00 00 00 00 00 00 00 00 00 00 ................
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
...
The memory dump shows a 32-bit exception frame:
x86_saved_state32
gs = 0x37
fs = 0
es = 0x1f
ds = 0x1f
edi = 0x33a8
esi = 0x01000000
ebp = 0
cr2 = 0xfedcba98
ebx = 0x0907
edx = 0
ecx = 0xfedcba98
eax = 0x06
trapno = 0x0d
err = 0x34
eip = 0x1c9e
cs = 0x17
efl = 0x0200
uesp = 0x30ac
ss = 0x1f
The cr2 of 0xfedcba98 is the address that the new thread read
to cause the fault, but note that the trap is now a GP fault with
error code 0x34, meaning it's moved past the cr2 problem and on
to an invaild segment selector. The 0x34 is suspiciously similar
to the 0x37 in gs, and sure enough, OS X forces gs to have
that value in the signal handler, and if your thread hasn't set
up that segment (known as USER_CTHREAD), you'll fault on the IRET
into the signal handler and never be able to handle a signal.
The kernel bug is that it forces segment 0x37 without making sure
it is a valid segment. Leopard also forced 0x37 but had the courtesy
to set it up first.
Since OS X requires us to set up that segment (using the
thread_fast_set_cthread_self system call), we might as well
use it instead of the more complicated i386_set_ldt call to
set up our per-OS thread storage.
Also add some more zeros to bsdthread_register for new arguments
in Snow Leopard (apparently unnecessary, but being careful).
Fixes #510.
R=r
CC=golang-dev
https://golang.org/cl/824046
2010-04-08 14:24:37 -06:00
|
|
|
MOVQ $0, R10 // dummy_value [sic]
|
|
|
|
MOVQ $0, R8 // targetconc_ptr
|
|
|
|
MOVQ $0, R9 // dispatchqueue_offset
|
2008-09-09 12:50:14 -06:00
|
|
|
MOVQ $(0x2000000+366), AX // bsdthread_register
|
|
|
|
SYSCALL
|
|
|
|
JCC 2(PC)
|
|
|
|
CALL notok(SB)
|
|
|
|
RET
|
|
|
|
|
|
|
|
// Mach system calls use 0x1000000 instead of the BSD's 0x2000000.
|
|
|
|
|
|
|
|
// uint32 mach_msg_trap(void*, uint32, uint32, uint32, uint32, uint32, uint32)
|
|
|
|
TEXT mach_msg_trap(SB),7,$0
|
|
|
|
MOVQ 8(SP), DI
|
|
|
|
MOVL 16(SP), SI
|
|
|
|
MOVL 20(SP), DX
|
|
|
|
MOVL 24(SP), R10
|
|
|
|
MOVL 28(SP), R8
|
|
|
|
MOVL 32(SP), R9
|
|
|
|
MOVL 36(SP), R11
|
|
|
|
PUSHQ R11 // seventh arg, on stack
|
|
|
|
MOVL $(0x1000000+31), AX // mach_msg_trap
|
|
|
|
SYSCALL
|
|
|
|
POPQ R11
|
|
|
|
RET
|
|
|
|
|
|
|
|
TEXT mach_task_self(SB),7,$0
|
|
|
|
MOVL $(0x1000000+28), AX // task_self_trap
|
|
|
|
SYSCALL
|
|
|
|
RET
|
|
|
|
|
|
|
|
TEXT mach_thread_self(SB),7,$0
|
|
|
|
MOVL $(0x1000000+27), AX // thread_self_trap
|
|
|
|
SYSCALL
|
|
|
|
RET
|
|
|
|
|
|
|
|
TEXT mach_reply_port(SB),7,$0
|
|
|
|
MOVL $(0x1000000+26), AX // mach_reply_port
|
|
|
|
SYSCALL
|
|
|
|
RET
|
|
|
|
|
|
|
|
// Mach provides trap versions of the semaphore ops,
|
|
|
|
// instead of requiring the use of RPC.
|
|
|
|
|
|
|
|
// uint32 mach_semaphore_wait(uint32)
|
|
|
|
TEXT mach_semaphore_wait(SB),7,$0
|
|
|
|
MOVL 8(SP), DI
|
|
|
|
MOVL $(0x1000000+36), AX // semaphore_wait_trap
|
|
|
|
SYSCALL
|
|
|
|
RET
|
|
|
|
|
|
|
|
// uint32 mach_semaphore_timedwait(uint32, uint32, uint32)
|
|
|
|
TEXT mach_semaphore_timedwait(SB),7,$0
|
|
|
|
MOVL 8(SP), DI
|
|
|
|
MOVL 12(SP), SI
|
|
|
|
MOVL 16(SP), DX
|
|
|
|
MOVL $(0x1000000+38), AX // semaphore_timedwait_trap
|
|
|
|
SYSCALL
|
|
|
|
RET
|
|
|
|
|
|
|
|
// uint32 mach_semaphore_signal(uint32)
|
|
|
|
TEXT mach_semaphore_signal(SB),7,$0
|
|
|
|
MOVL 8(SP), DI
|
|
|
|
MOVL $(0x1000000+33), AX // semaphore_signal_trap
|
|
|
|
SYSCALL
|
|
|
|
RET
|
|
|
|
|
|
|
|
// uint32 mach_semaphore_signal_all(uint32)
|
|
|
|
TEXT mach_semaphore_signal_all(SB),7,$0
|
|
|
|
MOVL 8(SP), DI
|
|
|
|
MOVL $(0x1000000+34), AX // semaphore_signal_all_trap
|
|
|
|
SYSCALL
|
|
|
|
RET
|
2010-08-04 18:50:22 -06:00
|
|
|
|
|
|
|
// set tls base to DI
|
|
|
|
TEXT settls(SB),7,$32
|
|
|
|
/*
|
|
|
|
* Same as in ../386/sys.s:/ugliness, different constant.
|
|
|
|
* See ../../../../libcgo/darwin_amd64.c for the derivation
|
|
|
|
* of the constant.
|
|
|
|
*/
|
|
|
|
SUBQ $0x8a0, DI
|
|
|
|
|
|
|
|
MOVL $(0x3000000+3), AX // thread_fast_set_cthread_self - machdep call #3
|
|
|
|
SYSCALL
|
|
|
|
RET
|