ts.fn = mstart;
runcgo(libcgo_thread_start, &ts);
} else {
- m->g0 = malg(8192);
+ if(Windows)
+ // windows will layout sched stack on os stack
+ m->g0 = malg(-1);
+ else
+ m->g0 = malg(8192);
newosproc(m, m->g0, m->g0->stackbase, mstart);
}
}
G* lockedg;
uint64 freg[8]; // Floating point register storage used by ARM software fp routines
#ifdef __WINDOWS__
- void* return_address; // saved return address and stack
- void* stack_pointer; // pointer for Windows stdcall
- void* os_stack_pointer;
+ void* gostack; // bookmark to keep track of go stack during stdcall
#endif
};
struct Stktop
int32 locals; // number of 32-bit locals
};
+#ifdef __WINDOWS__
+enum {
+ Windows = 1
+};
+#else
+enum {
+ Windows = 0
+};
+#endif
+
/*
* defined macros
* you need super-goru privilege
MOVL 0x08(AX), AX // get base of module
RET
-// void *stdcall_raw(void *fn, ...);
-// Call fn with stdcall calling convention.
-// fn parameters are on stack.
-TEXT stdcall_raw(SB),7,$0
- get_tls(CX)
- MOVL m(CX), CX
- POPL m_return_address(CX) // save return address
- POPL AX // first arg is function pointer
- MOVL SP, m_stack_pointer(CX) // save stack pointer
- CALL AX
- get_tls(CX)
- MOVL m(CX), CX
- MOVL m_stack_pointer(CX), SP
- PUSHL AX
- PUSHL m_return_address(CX)
- RET
+// void *stdcall_raw(void *fn, int32 count, uintptr *args)
+TEXT stdcall_raw(SB),7,$4
+ // Copy arguments from stack.
+ MOVL fn+0(FP), AX
+ MOVL count+4(FP), CX // words
+ MOVL args+8(FP), BP
-// void syscall(StdcallParams *p);
-// Call p.fn syscall + GetLastError on os stack.
-TEXT syscall(SB),7,$16
- MOVL p+0(FP), AX
- MOVL SP, CX
-
- // Figure out if we need to switch to m->g0 stack.
+ // Switch to m->g0 if needed.
get_tls(DI)
MOVL m(DI), DX
+ MOVL g(DI), SI
+ MOVL SI, 0(SP) // save g
+ MOVL SP, m_gostack(DX) // save SP
MOVL m_g0(DX), SI
CMPL g(DI), SI
- JEQ 2(PC)
+ JEQ 3(PC)
MOVL (m_sched+gobuf_sp)(DX), SP
-
- // Now on a scheduling stack (an os stack).
- MOVL g(DI), BP
- MOVL BP, 8(SP)
MOVL SI, g(DI)
- MOVL CX, 4(SP)
- MOVL AX, 0(SP)
- CALL call_syscall(SB)
-
- // Back; switch to original g and stack, re-establish
- // "DF is clear" invariant.
+
+ // Copy args to new stack.
+ SUBL $(10*4), SP // padding
+ MOVL CX, BX
+ SALL $2, BX
+ SUBL BX, SP // room for args
+ MOVL SP, DI
+ MOVL BP, SI
CLD
+ REP; MOVSL
+
+ // Call stdcall function.
+ CALL AX
+
+ // Restore original SP, g.
get_tls(DI)
- MOVL 8(SP), SI
+ MOVL m(DI), DX
+ MOVL m_gostack(DX), SP // restore SP
+ MOVL 0(SP), SI // restore g
MOVL SI, g(DI)
- MOVL 4(SP), SP
- RET
-TEXT threadstart(SB),7,$0
- MOVL 4(SP), AX // threadstart param
- MOVL 0(AX), BX // newosproc arg stack
- MOVL 0(BX), CX // m
- MOVL 4(BX), DX // g
+ // Someday the convention will be D is always cleared.
+ CLD
+
+ RET
+
+// void tstart(M *newm);
+TEXT tstart(SB),7,$0
+ MOVL newm+4(SP), CX // m
+ MOVL m_g0(CX), DX // g
- // set up tls
+ MOVL SP, DI // remember stack
+
+ // Layout new m scheduler stack on os stack.
+ MOVL SP, AX
+ SUBL $256, AX // just some space for ourselves
+ MOVL AX, g_stackbase(DX)
+ SUBL $8192, AX // stack size
+ MOVL AX, g_stackguard(DX)
+
+ // Set up tls.
LEAL m_tls(CX), SI
MOVL SI, 0x2c(FS)
MOVL CX, m(SI)
MOVL DX, g(SI)
- MOVL SP, m_os_stack_pointer(CX)
- PUSHL 8(BX) // stk
- PUSHL 12(BX) // fn
- PUSHL 4(AX) // event_handle
+ // Use scheduler stack now.
+ MOVL g_stackbase(DX), SP
+
+ // Someday the convention will be D is always cleared.
+ CLD
- // signal that we're done with thread args
- MOVL SetEvent(SB), BX
- CALL BX // SetEvent(event_handle)
- POPL BX // fn
- POPL SP // stk
+ PUSHL DI // original stack
CALL stackcheck(SB) // clobbers AX,CX
- CALL BX // fn()
-
- // cleanup stack before returning as we are stdcall
- get_tls(CX)
- MOVL m(CX), CX
- MOVL m_os_stack_pointer(CX), SP
- POPL AX // return address
- MOVL AX, (SP)
- XORL AX, AX
+
+ CALL mstart(SB)
+
+ POPL DI // original stack
+ MOVL DI, SP
+
+ RET
+
+// uint32 tstart_stdcall(M *newm);
+TEXT tstart_stdcall(SB),7,$0
+ MOVL newm+4(SP), BX
+
+ PUSHL BX
+ CALL tstart+0(SB)
+ POPL BX
+
+ // Adjust stack for stdcall to return properly.
+ MOVL (SP), AX // save return address
+ ADDL $4, SP // remove single parameter
+ MOVL AX, (SP) // restore return address
+
+ XORL AX, AX // return 0 == success
+
RET
// setldt(int entry, int address, int limit)
// Get start address of symbol data in memory.
void *get_symdat_addr(void);
-// Call a Windows function with stdcall conventions.
-void *stdcall_raw(void *fn, ...);
-
// Call a Windows function with stdcall conventions,
// and switch to os stack during the call.
+void *stdcall_raw(void *fn, int32 count, uintptr *args);
void *stdcall(void *fn, int32 count, ...);
+// Function to be called by windows CreateTread
+// to start new os thread.
+uint32 tstart_stdcall(M *newm);
+
// Call stdcall Windows function StdcallParams.fn
// with params StdcallParams.args,
// followed immediately by GetLastError call.
{
void *fn;
uintptr args[12];
+ int32 n;
uintptr r;
uintptr err;
};
-void call_syscall(void *args);
+
void syscall(StdcallParams *p);
p.args[0] = filename;
p.args[1] = 0;
p.args[2] = 0;
- ·entersyscall();
+ p.n = 3;
syscall(&p);
- ·exitsyscall();
handle = p.r;
}
p.fn = (void*)GetProcAddress;
p.args[0] = handle;
p.args[1] = procname;
- ·entersyscall();
+ p.n = 2;
syscall(&p);
- ·exitsyscall();
proc = p.r;
}
p.args[0] = a1;
p.args[1] = a2;
p.args[2] = a3;
- ·entersyscall();
+ p.n = 3;
syscall(&p);
- ·exitsyscall();
r1 = p.r;
r2 = 0;
err = p.err;
p.args[3] = a4;
p.args[4] = a5;
p.args[5] = a6;
- ·entersyscall();
+ p.n = 6;
syscall(&p);
- ·exitsyscall();
r1 = p.r;
r2 = 0;
err = p.err;
p.args[6] = a7;
p.args[7] = a8;
p.args[8] = a9;
- ·entersyscall();
+ p.n = 9;
syscall(&p);
- ·exitsyscall();
r1 = p.r;
r2 = 0;
lasterr = p.err;
p.args[9] = a10;
p.args[10] = a11;
p.args[11] = a12;
- ·entersyscall();
+ p.n = 12;
syscall(&p);
- ·exitsyscall();
r1 = p.r;
r2 = 0;
lasterr = p.err;
p.args[0] = a1;
p.args[1] = a2;
p.args[2] = a3;
+ p.n = 3;
syscall(&p);
r1 = p.r;
r2 = 0;
{
void *base;
- base = stdcall_raw(LoadLibraryEx, library, 0, 0);
- return stdcall_raw(GetProcAddress, base, name);
+ base = stdcall(LoadLibraryEx, 3, library, 0, 0);
+ return stdcall(GetProcAddress, 2, base, name);
}
void
void
newosproc(M *m, G *g, void *stk, void (*fn)(void))
{
- struct {
- void *args;
- void *event_handle;
- } param = { &m };
- extern uint32 threadstart(void *p);
-
- USED(g, stk, fn);
- param.event_handle = stdcall(CreateEvent, 4, 0, 0, 0, 0);
- stdcall(CreateThread, 6, 0, 0, threadstart, ¶m, 0, 0);
- stdcall(WaitForSingleObject, 2, param.event_handle, -1);
- stdcall(CloseHandle, 1, param.event_handle);
+ USED(stk);
+ USED(g); // assuming g = m->g0
+ USED(fn); // assuming fn = mstart
+
+ stdcall(CreateThread, 6, 0, 0, tstart_stdcall, m, 0, 0);
}
// Called to initialize a new m (including the bootstrap m).
void *
stdcall(void *fn, int32 count, ...)
{
- uintptr *a;
- StdcallParams p;
-
- p.fn = fn;
- a = (uintptr*)(&count + 1);
- while(count > 0) {
- count--;
- p.args[count] = a[count];
- }
- syscall(&p);
- return (void*)(p.r);
+ return stdcall_raw(fn, count, (uintptr*)(&count + 1));
}
void
-call_syscall(void *args)
+syscall(StdcallParams *p)
{
- StdcallParams *p = (StdcallParams*)args;
- stdcall_raw(SetLastError, 0);
- p->r = (uintptr)stdcall_raw((void*)p->fn, p->args[0], p->args[1], p->args[2], p->args[3], p->args[4], p->args[5], p->args[6], p->args[7], p->args[8], p->args[9], p->args[10], p->args[11]);
- p->err = (uintptr)stdcall_raw(GetLastError);
- return;
+ uintptr a;
+
+ ·entersyscall();
+ // TODO(brainman): Move calls to SetLastError and GetLastError
+ // to stdcall_raw to speed up syscall.
+ a = 0;
+ stdcall_raw(SetLastError, 1, &a);
+ p->r = (uintptr)stdcall_raw((void*)p->fn, p->n, p->args);
+ p->err = (uintptr)stdcall_raw(GetLastError, 0, &a);
+ ·exitsyscall();
}