2010-01-06 18:58:55 -07: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.
|
|
|
|
|
|
|
|
#include "runtime.h"
|
|
|
|
#include "os.h"
|
|
|
|
|
|
|
|
extern void *get_kernel_module(void);
|
|
|
|
|
|
|
|
// Also referenced by external packages
|
|
|
|
void *CloseHandle;
|
|
|
|
void *ExitProcess;
|
|
|
|
void *GetStdHandle;
|
|
|
|
void *SetEvent;
|
|
|
|
void *WriteFile;
|
2010-01-13 18:50:02 -07:00
|
|
|
void *VirtualAlloc;
|
2010-09-08 20:09:10 -06:00
|
|
|
void *VirtualFree;
|
2010-03-09 16:09:09 -07:00
|
|
|
void *LoadLibraryEx;
|
|
|
|
void *GetProcAddress;
|
|
|
|
void *GetLastError;
|
2010-07-25 18:24:48 -06:00
|
|
|
void *SetLastError;
|
2010-01-06 18:58:55 -07:00
|
|
|
|
|
|
|
static void *CreateEvent;
|
|
|
|
static void *CreateThread;
|
|
|
|
static void *WaitForSingleObject;
|
|
|
|
|
|
|
|
static void*
|
|
|
|
get_proc_addr2(byte *base, byte *name)
|
|
|
|
{
|
|
|
|
byte *pe_header, *exports;
|
|
|
|
uint32 entries, *addr, *names, i;
|
|
|
|
uint16 *ordinals;
|
|
|
|
|
|
|
|
pe_header = base+*(uint32*)(base+0x3c);
|
|
|
|
exports = base+*(uint32*)(pe_header+0x78);
|
|
|
|
entries = *(uint32*)(exports+0x18);
|
|
|
|
addr = (uint32*)(base+*(uint32*)(exports+0x1c));
|
|
|
|
names = (uint32*)(base+*(uint32*)(exports+0x20));
|
|
|
|
ordinals = (uint16*)(base+*(uint32*)(exports+0x24));
|
|
|
|
for(i=0; i<entries; i++) {
|
|
|
|
byte *s = base+names[i];
|
|
|
|
if(!strcmp(name, s))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(i == entries)
|
|
|
|
return 0;
|
|
|
|
return base+addr[ordinals[i]];
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
osinit(void)
|
|
|
|
{
|
|
|
|
void *base;
|
|
|
|
|
|
|
|
base = get_kernel_module();
|
|
|
|
GetProcAddress = get_proc_addr2(base, (byte*)"GetProcAddress");
|
|
|
|
LoadLibraryEx = get_proc_addr2(base, (byte*)"LoadLibraryExA");
|
|
|
|
CloseHandle = get_proc_addr("kernel32.dll", "CloseHandle");
|
|
|
|
CreateEvent = get_proc_addr("kernel32.dll", "CreateEventA");
|
|
|
|
CreateThread = get_proc_addr("kernel32.dll", "CreateThread");
|
|
|
|
ExitProcess = get_proc_addr("kernel32.dll", "ExitProcess");
|
|
|
|
GetStdHandle = get_proc_addr("kernel32.dll", "GetStdHandle");
|
|
|
|
SetEvent = get_proc_addr("kernel32.dll", "SetEvent");
|
|
|
|
VirtualAlloc = get_proc_addr("kernel32.dll", "VirtualAlloc");
|
2010-09-08 20:09:10 -06:00
|
|
|
VirtualFree = get_proc_addr("kernel32.dll", "VirtualFree");
|
2010-01-06 18:58:55 -07:00
|
|
|
WaitForSingleObject = get_proc_addr("kernel32.dll", "WaitForSingleObject");
|
|
|
|
WriteFile = get_proc_addr("kernel32.dll", "WriteFile");
|
2010-03-09 16:09:09 -07:00
|
|
|
GetLastError = get_proc_addr("kernel32.dll", "GetLastError");
|
2010-07-25 18:24:48 -06:00
|
|
|
SetLastError = get_proc_addr("kernel32.dll", "SetLastError");
|
2010-01-06 18:58:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// The arguments are strings.
|
|
|
|
void*
|
|
|
|
get_proc_addr(void *library, void *name)
|
|
|
|
{
|
|
|
|
void *base;
|
|
|
|
|
2010-09-11 19:45:16 -06:00
|
|
|
base = stdcall(LoadLibraryEx, 3, library, 0, 0);
|
|
|
|
return stdcall(GetProcAddress, 2, base, name);
|
2010-01-06 18:58:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-04-30 00:45:14 -06:00
|
|
|
windows_goargs(void)
|
2010-01-06 18:58:55 -07:00
|
|
|
{
|
|
|
|
extern Slice os·Args;
|
|
|
|
extern Slice os·Envs;
|
|
|
|
|
2010-08-08 19:30:33 -06:00
|
|
|
void *gcl, *clta, *ges, *fes;
|
2010-01-06 18:58:55 -07:00
|
|
|
uint16 *cmd, *env, **argv;
|
|
|
|
String *gargv;
|
|
|
|
String *genvv;
|
|
|
|
int32 i, argc, envc;
|
|
|
|
uint16 *envp;
|
|
|
|
|
|
|
|
gcl = get_proc_addr("kernel32.dll", "GetCommandLineW");
|
|
|
|
clta = get_proc_addr("shell32.dll", "CommandLineToArgvW");
|
|
|
|
ges = get_proc_addr("kernel32.dll", "GetEnvironmentStringsW");
|
2010-08-08 19:30:33 -06:00
|
|
|
fes = get_proc_addr("kernel32.dll", "FreeEnvironmentStringsW");
|
2010-01-06 18:58:55 -07:00
|
|
|
|
2010-06-11 02:38:12 -06:00
|
|
|
cmd = stdcall(gcl, 0);
|
|
|
|
env = stdcall(ges, 0);
|
|
|
|
argv = stdcall(clta, 2, cmd, &argc);
|
2010-01-06 18:58:55 -07:00
|
|
|
|
|
|
|
envc = 0;
|
|
|
|
for(envp=env; *envp; envc++)
|
|
|
|
envp += findnullw(envp)+1;
|
|
|
|
|
|
|
|
gargv = malloc(argc*sizeof gargv[0]);
|
|
|
|
genvv = malloc(envc*sizeof genvv[0]);
|
|
|
|
|
|
|
|
for(i=0; i<argc; i++)
|
|
|
|
gargv[i] = gostringw(argv[i]);
|
|
|
|
os·Args.array = (byte*)gargv;
|
|
|
|
os·Args.len = argc;
|
|
|
|
os·Args.cap = argc;
|
|
|
|
|
|
|
|
envp = env;
|
|
|
|
for(i=0; i<envc; i++) {
|
|
|
|
genvv[i] = gostringw(envp);
|
|
|
|
envp += findnullw(envp)+1;
|
|
|
|
}
|
|
|
|
os·Envs.array = (byte*)genvv;
|
|
|
|
os·Envs.len = envc;
|
|
|
|
os·Envs.cap = envc;
|
2010-08-08 19:30:33 -06:00
|
|
|
|
|
|
|
stdcall(fes, 1, env);
|
2010-01-06 18:58:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
exit(int32 code)
|
|
|
|
{
|
2010-06-11 02:38:12 -06:00
|
|
|
stdcall(ExitProcess, 1, code);
|
2010-01-06 18:58:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
int32
|
|
|
|
write(int32 fd, void *buf, int32 n)
|
|
|
|
{
|
|
|
|
void *handle;
|
|
|
|
uint32 written;
|
|
|
|
|
|
|
|
written = 0;
|
|
|
|
switch(fd) {
|
|
|
|
case 1:
|
2010-06-11 02:38:12 -06:00
|
|
|
handle = stdcall(GetStdHandle, 1, -11);
|
2010-01-06 18:58:55 -07:00
|
|
|
break;
|
|
|
|
case 2:
|
2010-06-11 02:38:12 -06:00
|
|
|
handle = stdcall(GetStdHandle, 1, -12);
|
2010-01-06 18:58:55 -07:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
2010-06-11 02:38:12 -06:00
|
|
|
stdcall(WriteFile, 5, handle, buf, n, &written, 0);
|
2010-01-06 18:58:55 -07:00
|
|
|
return written;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Thread-safe allocation of an event.
|
|
|
|
static void
|
|
|
|
initevent(void **pevent)
|
|
|
|
{
|
|
|
|
void *event;
|
|
|
|
|
2010-06-11 02:38:12 -06:00
|
|
|
event = stdcall(CreateEvent, 4, 0, 0, 0, 0);
|
2010-01-06 18:58:55 -07:00
|
|
|
if(!casp(pevent, 0, event)) {
|
|
|
|
// Someone else filled it in. Use theirs.
|
2010-06-11 02:38:12 -06:00
|
|
|
stdcall(CloseHandle, 1, event);
|
2010-01-06 18:58:55 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
eventlock(Lock *l)
|
|
|
|
{
|
|
|
|
// Allocate event if needed.
|
|
|
|
if(l->event == 0)
|
|
|
|
initevent(&l->event);
|
|
|
|
|
|
|
|
if(xadd(&l->key, 1) > 1) // someone else has it; wait
|
2010-06-11 02:38:12 -06:00
|
|
|
stdcall(WaitForSingleObject, 2, l->event, -1);
|
2010-01-06 18:58:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
eventunlock(Lock *l)
|
|
|
|
{
|
|
|
|
if(xadd(&l->key, -1) > 0) // someone else is waiting
|
2010-06-11 02:38:12 -06:00
|
|
|
stdcall(SetEvent, 1, l->event);
|
2010-01-06 18:58:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
lock(Lock *l)
|
|
|
|
{
|
|
|
|
if(m->locks < 0)
|
|
|
|
throw("lock count");
|
|
|
|
m->locks++;
|
|
|
|
eventlock(l);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
unlock(Lock *l)
|
|
|
|
{
|
|
|
|
m->locks--;
|
|
|
|
if(m->locks < 0)
|
|
|
|
throw("lock count");
|
|
|
|
eventunlock(l);
|
|
|
|
}
|
|
|
|
|
2010-03-24 19:03:10 -06:00
|
|
|
void
|
|
|
|
destroylock(Lock *l)
|
|
|
|
{
|
2010-06-11 01:53:54 -06:00
|
|
|
if(l->event != 0)
|
|
|
|
stdcall(CloseHandle, 1, l->event);
|
2010-03-24 19:03:10 -06:00
|
|
|
}
|
|
|
|
|
2010-01-06 18:58:55 -07:00
|
|
|
void
|
|
|
|
noteclear(Note *n)
|
|
|
|
{
|
|
|
|
eventlock(&n->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
notewakeup(Note *n)
|
|
|
|
{
|
|
|
|
eventunlock(&n->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
notesleep(Note *n)
|
|
|
|
{
|
|
|
|
eventlock(&n->lock);
|
|
|
|
eventunlock(&n->lock); // Let other sleepers find out too.
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
newosproc(M *m, G *g, void *stk, void (*fn)(void))
|
|
|
|
{
|
2010-09-11 19:45:16 -06:00
|
|
|
USED(stk);
|
|
|
|
USED(g); // assuming g = m->g0
|
|
|
|
USED(fn); // assuming fn = mstart
|
|
|
|
|
|
|
|
stdcall(CreateThread, 6, 0, 0, tstart_stdcall, m, 0, 0);
|
2010-01-06 18:58:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Called to initialize a new m (including the bootstrap m).
|
|
|
|
void
|
|
|
|
minit(void)
|
|
|
|
{
|
|
|
|
}
|
2010-06-11 02:38:12 -06:00
|
|
|
|
|
|
|
// Calling stdcall on os stack.
|
|
|
|
#pragma textflag 7
|
|
|
|
void *
|
|
|
|
stdcall(void *fn, int32 count, ...)
|
|
|
|
{
|
2010-09-11 19:45:16 -06:00
|
|
|
return stdcall_raw(fn, count, (uintptr*)(&count + 1));
|
2010-06-11 02:38:12 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-09-11 19:45:16 -06:00
|
|
|
syscall(StdcallParams *p)
|
2010-06-11 02:38:12 -06:00
|
|
|
{
|
2010-09-11 19:45:16 -06:00
|
|
|
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();
|
2010-06-11 02:38:12 -06:00
|
|
|
}
|