s = p->from.sym;
if(s != S && s->dupok) {
if(debug['v'])
- Bprint(&bso, "skipping %s in %s: dupok", s->name, pn);
+ Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
goto loop;
}
if(s != S) {
#include "l.h"
-// see ../../runtime/proc.c:/StackGuard
+// see ../../pkg/runtime/proc.c:/StackGuard
enum
{
StackSmall = 128,
q = p;
}
- p = appendp(p); // load m into DX
+ p = appendp(p); // save frame size in DX
p->as = AMOVL;
- p->from.type = D_INDIR+D_FS;
- p->from.offset = 4;
p->to.type = D_DX;
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
-
- p = appendp(p); // save autoffset in 4(DX)
- p->as = AMOVL;
- p->to.type = D_INDIR+D_DX;
- p->to.offset = 4;
/* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */
p->from.type = D_CONST;
if(autoffset+160 > 4096)
p->from.offset = (autoffset+160) & ~7LL;
- p = appendp(p); // save textarg in 8(DX)
+ p = appendp(p); // save arg size in AX
p->as = AMOVL;
- p->to.type = D_INDIR+D_DX;
- p->to.offset = 8;
+ p->to.type = D_AX;
p->from.type = D_CONST;
p->from.offset = curtext->to.offset2;
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include "386/asm.h"
+
TEXT _rt0_386(SB),7,$0
// copy arguments forward on an even stack
MOVL 0(SP), AX // argc
MOVL AX, 120(SP) // save argc, argv away
MOVL BX, 124(SP)
-/*
- // write "go386\n"
- PUSHL $6
- PUSHL $hello(SB)
- PUSHL $1
- CALL sys·write(SB)
- POPL AX
- POPL AX
- POPL AX
-*/
-
CALL ldt0setup(SB)
// set up %fs to refer to that ldt entry
ok:
// set up m and g "registers"
- // g is 0(FS), m is 4(FS)
LEAL g0(SB), CX
- MOVL CX, 0(FS)
+ MOVL CX, g
LEAL m0(SB), AX
- MOVL AX, 4(FS)
+ MOVL AX, m
// save m->g0 = g0
- MOVL CX, 0(AX)
+ MOVL CX, m_g0(AX)
// create istack out of the OS stack
LEAL (-8192+104)(SP), AX // TODO: 104?
- MOVL AX, 0(CX) // 8(g) is stack limit (w 104b guard)
- MOVL SP, 4(CX) // 12(g) is base
+ MOVL AX, g_stackguard(CX)
+ MOVL SP, g_stackbase(CX)
CALL emptyfunc(SB) // fault if stack check is wrong
// convention is D is always cleared
// create a new goroutine to start program
PUSHL $mainstart(SB) // entry
- PUSHL $8 // arg size
+ PUSHL $0 // arg size
CALL sys·newproc(SB)
POPL AX
POPL AX
BYTE $0xcc
RET
-// go-routine
-TEXT gogo(SB), 7, $0
- MOVL 4(SP), AX // gobuf
- MOVL 0(AX), SP // restore SP
- MOVL 4(AX), AX
- MOVL AX, 0(SP) // put PC on the stack
- MOVL $1, AX
- RET
+/*
+ * go-routine
+ */
+// uintptr gosave(Gobuf*)
+// save state in Gobuf; setjmp
TEXT gosave(SB), 7, $0
- MOVL 4(SP), AX // gobuf
- MOVL SP, 0(AX) // save SP
- MOVL 0(SP), BX
- MOVL BX, 4(AX) // save PC
- MOVL $0, AX // return 0
+ MOVL 4(SP), AX // gobuf
+ LEAL 4(SP), BX // caller's SP
+ MOVL BX, gobuf_sp(AX)
+ MOVL 0(SP), BX // caller's PC
+ MOVL BX, gobuf_pc(AX)
+ MOVL g, BX
+ MOVL BX, gobuf_g(AX)
+ MOVL $0, AX // return 0
RET
-// support for morestack
-
-// return point when leaving new stack.
-// save AX, jmp to lesstack to switch back
-TEXT retfromnewstack(SB),7,$0
- MOVL 4(FS), BX // m
- MOVL AX, 12(BX) // save AX in m->cret
- JMP lessstack(SB)
-
-// gogo, returning 2nd arg instead of 1
-TEXT gogoret(SB), 7, $0
- MOVL 8(SP), AX // return 2nd arg
- MOVL 4(SP), BX // gobuf
- MOVL 0(BX), SP // restore SP
- MOVL 4(BX), BX
- MOVL BX, 0(SP) // put PC on the stack
+// void gogo(Gobuf*, uintptr)
+// restore state from Gobuf; longjmp
+TEXT gogo(SB), 7, $0
+ MOVL 8(SP), AX // return 2nd arg
+ MOVL 4(SP), BX // gobuf
+ MOVL gobuf_g(BX), DX
+ MOVL 0(DX), CX // make sure g != nil
+ MOVL DX, g
+ MOVL gobuf_sp(BX), SP // restore SP
+ MOVL gobuf_pc(BX), BX
+ JMP BX
+
+// void gogocall(Gobuf*, void (*fn)(void))
+// restore state from Gobuf but then call fn.
+// (call fn, returning to state in Gobuf)
+TEXT gogocall(SB), 7, $0
+ MOVL 8(SP), AX // fn
+ MOVL 4(SP), BX // gobuf
+ MOVL gobuf_g(BX), DX
+ MOVL DX, g
+ MOVL 0(DX), CX // make sure g != nil
+ MOVL gobuf_sp(BX), SP // restore SP
+ MOVL gobuf_pc(BX), BX
+ PUSHL BX
+ JMP AX
+ POPL BX // not reached
+
+/*
+ * support for morestack
+ */
+
+// Called during function prolog when more stack is needed.
+TEXT sys·morestack(SB),7,$0
+ // Cannot grow scheduler stack (m->g0).
+ MOVL m, BX
+ MOVL m_g0(BX), SI
+ CMPL g, SI
+ JNE 2(PC)
+ INT $3
+
+ // frame size in DX
+ // arg size in AX
+ // Save in m.
+ MOVL DX, m_moreframe(BX)
+ MOVL AX, m_moreargs(BX)
+
+ // Called from f.
+ // Set m->morebuf to f's caller.
+ MOVL 4(SP), DI // f's caller's PC
+ MOVL DI, (m_morebuf+gobuf_pc)(BX)
+ LEAL 8(SP), CX // f's caller's SP
+ MOVL CX, (m_morebuf+gobuf_sp)(BX)
+ MOVL g, SI
+ MOVL SI, (m_morebuf+gobuf_g)(BX)
+
+ // Set m->morepc to f's PC.
+ MOVL 0(SP), AX
+ MOVL AX, m_morepc(BX)
+
+ // Call newstack on m's scheduling stack.
+ MOVL m_g0(BX), BP
+ MOVL BP, g
+ MOVL (m_sched+gobuf_sp)(BX), SP
+ CALL newstack(SB)
+ MOVL $0, 0x1003 // crash if newstack returns
RET
-TEXT setspgoto(SB), 7, $0
- MOVL 4(SP), AX // SP
- MOVL 8(SP), BX // fn to call
- MOVL 12(SP), CX // fn to return
- MOVL AX, SP
- PUSHL CX
- JMP BX
- POPL AX // not reached
+// Return point when leaving stack.
+TEXT sys·lessstack(SB), 7, $0
+ // Save return value in m->cret
+ MOVL m, BX
+ MOVL AX, m_cret(BX)
+
+ // Call oldstack on m's scheduling stack.
+ MOVL m_g0(BX), DX
+ MOVL DX, g
+ MOVL (m_sched+gobuf_sp)(BX), SP
+ CALL oldstack(SB)
+ MOVL $0, 0x1004 // crash if oldstack returns
RET
+
// bool cas(int32 *val, int32 old, int32 new)
// Atomically:
// if(*val == old){
TEXT abort(SB),7,$0
INT $0x3
-DATA hello+0(SB)/8, $"go386\n\z\z"
-GLOBL hello+0(SB), $8
-
stk = (Stktop*)g->stackbase;
for(n=0; n<100; n++) {
- while(pc == (uintptr)retfromnewstack) {
+ if(pc == (uint64)sys·lessstack) {
+ // printf("--\n");
// pop to earlier stack block
- sp = stk->oldsp;
- stk = (Stktop*)stk->oldbase;
- pc = *(uintptr*)(sp+sizeof(uintptr));
- sp += 2*sizeof(uintptr); // two irrelevant calls on stack: morestack plus its call
+ pc = (uintptr)stk->gobuf.pc;
+ sp = stk->gobuf.sp;
+ stk = (Stktop*)stk->stackbase;
}
f = findfunc(pc);
if(f == nil) {
// dangerous, but poke around to see if it is a closure
p = (byte*)pc;
// ADDL $xxx, SP; RET
- if(p[0] == 0x81 && p[1] == 0xc4 && p[6] == 0xc3) {
+ if(p != 0 && p[0] == 0x81 && p[1] == 0xc4 && p[6] == 0xc3) {
sp += *(uint32*)(p+2) + 8;
pc = *(uintptr*)(sp - 8);
if(pc <= 0x1000)
// now unwind n levels
stk = (Stktop*)g->stackbase;
while(n-- > 0) {
- while(pc == (uintptr)retfromnewstack) {
- sp = stk->oldsp;
- stk = (Stktop*)stk->oldbase;
- pc = *((uintptr*)sp + 1);
- sp += 2*sizeof(uintptr);
+ while(pc == (uintptr)sys·lessstack) {
+ pc = (uintptr)stk->gobuf.pc;
+ sp = stk->gobuf.sp;
+ stk = (Stktop*)stk->stackbase;
}
if(f->frame < sizeof(uintptr)) // assembly functions lie
// 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.
+#include "386/asm.h"
+
TEXT notok(SB),7,$0
MOVL $0xf1, 0xf1
RET
CALL notok(SB)
RET
-TEXT sys·write(SB),7,$0
+TEXT write(SB),7,$0
MOVL $4, AX
INT $0x80
JAE 2(PC)
// 16(FP) siginfo
// 20(FP) context
TEXT sigtramp(SB),7,$40
- MOVL 4(FS), BP // m
- MOVL 28(BP), BP // m->gsignal
- MOVL BP, 0(FS) // g = m->gsignal
+ // g = m->gsignal
+ MOVL m, BP
+ MOVL m_gsignal(BP), BP
+ MOVL BP, g
MOVL handler+4(FP), DI
MOVL signo+12(FP), AX
// 0(SP) is where the caller PC would be; kernel skips it
MOVL func+12(FP), BX
MOVL BX, 4(SP) // func
- MOVL m+4(FP), BX
+ MOVL mm+4(FP), BX
MOVL BX, 8(SP) // arg
MOVL stk+0(FP), BX
MOVL BX, 12(SP) // stack
- MOVL g+8(FP), BX
+ MOVL gg+8(FP), BX
MOVL BX, 16(SP) // pthread
MOVL $0x1000000, 20(SP) // flags = PTHREAD_START_CUSTOM
INT $0x80
// set up ldt 7+id to point at m->tls.
// m->tls is at m+40. newosproc left
// the m->id in tls[0].
- LEAL 40(DX), BP
+ LEAL m_tls(DX), BP
MOVL 0(BP), DI
ADDL $7, DI // m0 is LDT#7. count up.
// setldt(tls#, &tls, sizeof tls)
MOVW DI, FS
// Now segment is established. Initialize m, g.
- MOVL AX, 0(FS) // g
- MOVL DX, 4(FS) // m
- MOVL BX, 20(DX) // m->procid = thread port (for debuggers)
+ MOVL AX, g
+ MOVL DX, m
+ MOVL BX, m_procid(DX) // m->procid = thread port (for debuggers)
CALL CX // fn()
CALL exit1(SB)
RET
void
newosproc(M *m, G *g, void *stk, void (*fn)(void))
{
- // printf("newosproc m=%p g=%p stk=%p fn=%p\n", m, g, stk, fn);
m->tls[0] = m->id; // so 386 asm can find it
+
+ if(0){
+ 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);
+ }
bsdthread_create(stk, m, g, fn);
}
// System calls and other sys.stuff for 386, Linux
//
+#include "386/asm.h"
+
TEXT syscall(SB),7,$0
MOVL 4(SP), AX // syscall number
MOVL 8(SP), BX // arg1
INT $0x80
RET
-TEXT getpid(SB),7,$0
- MOVL $20, AX
- INT $0x80
- RET
-
-TEXT kill(SB),7,$0
- MOVL $37, AX
- MOVL 4(SP), BX
- MOVL 8(SP), CX
- INT $0x80
- RET
-
-TEXT sys·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 rt_sigaction(SB),7,$0
MOVL $174, AX // syscall - rt_sigaction
MOVL 4(SP), BX
RET
TEXT sigtramp(SB),7,$0
- MOVL 4(FS), BP // m
- MOVL 20(BP), AX // m->gsignal
- MOVL AX, 0(FS) // g = m->gsignal
+ MOVL m, BP
+ MOVL m_gsignal(BP), AX
+ MOVL AX, g
JMP sighandler(SB)
TEXT sigignore(SB),7,$0
RET
TEXT sigreturn(SB),7,$0
- MOVL 4(FS), BP // m
- MOVL 32(BP), BP // m->curg
- MOVL BP, 0(FS) // g = m->curg
+ // g = m->curg
+ MOVL m, BP
+ MOVL m_curg(BP), BP
+ MOVL BP, g
MOVL $173, AX // rt_sigreturn
INT $0x80
INT $3 // not reached
INT $3
RET
-// int64 futex(int32 *uaddr, int32 op, int32 val,
+// int32 futex(int32 *uaddr, int32 op, int32 val,
// struct timespec *timeout, int32 *uaddr2, int32 val2);
TEXT futex(SB),7,$0
MOVL $240, AX // futex
INT $0x80
RET
-// int64 clone(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
+// int32 clone(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
TEXT 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 $12, CX
- MOVL m+12(SP), DX
- MOVL DX, 0(CX)
- MOVL g+16(SP), DX
- MOVL DX, 4(CX)
- MOVL fn+20(SP), DX
- MOVL DX, 8(CX)
-
- MOVL $120, AX
+ 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.
JEQ 2(PC)
RET
- // In child, set up new stack, etc.
- MOVL 0(CX), BX // m
- MOVL 12(AX), AX // fs (= m->cret)
- MOVW AX, FS
- MOVL 8(CX), DX // fn
- ADDL $12, CX
- MOVL CX, SP
-
- // fn is now on top of stack.
+ // Paranoia: check that SP is as we expect.
+ MOVL 12(SP), BP
+ CMPL BP, $1234
+ JEQ 2(PC)
+ INT $3
- // initialize m->procid to Linux tid
+ // Initialize AX to Linux tid
MOVL $224, AX
INT $0x80
- MOVL AX, 20(BX)
-
- // call fn
- CALL DX
- // It shouldn't return; if it does, exit.
- MOVL $111, DI
- MOVL $1, AX
- INT $0x80
- JMP -3(PC) // keep exiting
+ // In child on new stack. Reload registers (paranoia).
+ MOVL 0(SP), BX // m
+ MOVL 4(SP), DX // g
+ MOVL 8(SP), CX // fn
+
+ MOVL AX, m_procid(BX) // save tid as m->procid
+
+ // set up ldt 7+id to point at m->tls.
+ // m->tls is at m+40. 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 setldt(SB)
+ POPL AX
+ POPL AX
+ POPL AX
+ POPAL
+ SHLL $3, DI // segment# is ldt*8 + 7 (different 7 than above)
+ ADDL $7, DI
+ MOVW DI, FS
+
+ // Now segment is established. Initialize m, g.
+ MOVL DX, g
+ MOVL BX, m
+
+ MOVL 0(DX), DX // paranoia; check they are not nil
+ MOVL 0(BX), BX
+
+ // more paranoia; check that stack splitting code works
+ PUSHAL
+ CALL emptyfunc(SB)
+ POPAL
+
+ CALL CX // fn()
+ CALL exit1(SB)
+ MOVL $0x1234, 0x1005
+ RET
TEXT sigaltstack(SB),7,$-8
MOVL $186, AX // sigaltstack
INT $3
RET
-// // fake the per-goroutine and per-mach registers
-// LEAL m0(SB),
-
-// TODO(rsc): move to linux.s
// <asm-i386/ldt.h>
// struct user_desc {
// unsigned int entry_number;
// license that can be found in the LICENSE file.
// Linux-specific system calls
-int64 futex(uint32*, int32, uint32, Timespec*, uint32*, uint32);
-int64 clone(int32, void*, M*, G*, void(*)(void));
+int32 futex(uint32*, int32, uint32, Timespec*, uint32*, uint32);
+int32 clone(int32, void*, M*, G*, void(*)(void));
struct Sigaction;
void rt_sigaction(int64, struct Sigaction*, void*, uint64);
static void
futexsleep(uint32 *addr, uint32 val)
{
- int64 ret;
+ int32 ret;
ret = futex(addr, FUTEX_WAIT, val, &longtime, nil, 0);
if(ret >= 0 || ret == -EAGAIN || ret == -EINTR)
void
newosproc(M *m, G *g, void *stk, void (*fn)(void))
{
- int64 ret;
+ int32 ret;
int32 flags;
/*
| CLONE_THREAD /* revisit - okay for now */
;
+ m->tls[0] = m->id; // so 386 asm can find it
if(0){
- prints("newosproc stk=");
- sys·printpointer(stk);
- prints(" m=");
- sys·printpointer(m);
- prints(" g=");
- sys·printpointer(g);
- prints(" fn=");
- sys·printpointer(fn);
- prints(" clone=");
- sys·printpointer(clone);
- prints("\n");
+ printf("newosproc stk=%p m=%p g=%p fn=%p clone=%p id=%d/%d ostk=%p\n",
+ stk, m, g, fn, clone, m->id, m->tls[0], &m);
}
ret = clone(flags, stk, m, g, fn);
+
if(ret < 0)
*(int32*)123 = 123;
}