#include <9pm/windows.h>
#include <9pm/u.h>
#include <9pm/libc.h>
#include "dat.h"
#include "fns.h"
#include "syscall.h"
#undef main
static char magic[] = "9pm.3fe6c2dcaeee8517";
Mach *machp0;
char *argv0;
Mach nomach;
static HANDLE idle;
static HWND window;
static LRESULT CALLBACK NewProcProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
static HANDLE me;
static long tlsmach;
static int debug;
void
noidlehands(void)
{
ReleaseSemaphore(idle, 1, nil);
}
void
idlehands(void)
{
WaitForSingleObject(idle, INFINITE);
}
extern WINBASEAPI HWND WINAPI GetConsoleWindow(void);
void
dwriten(char *s, int n)
{
static HANDLE h;
DWORD m;
if(h == INVALID_HANDLE_VALUE || h == NULL){
AllocConsole();
h = GetStdHandle(STD_ERROR_HANDLE);
}
if(h != INVALID_HANDLE_VALUE && h != NULL)
WriteFile(h, s, n, &m, nil);
else
abort();
}
void
dwrite(char *s)
{
dwriten(s, strlen(s));
}
/*
* alarmthread only calls checkalarms,
* so it doesn't need its own Mach structure.
*/
DWORD WINAPI
alarmthread(void *a)
{
USED(a);
setmach(&nomach);
print("alarmthread started\n");
for(;;){
Sleep(100);
machp0->ticks = GetTickCount();
checkalarms();
}
return 0;
}
DWORD WINAPI
kernelthread(void *a)
{
Mach *m;
m = a;
print("kernelthread %d started\n", m->machno);
TlsSetValue(tlsmach, m);
schedinit();
abort();
return 0;
}
Mach*
getmach(void)
{
return TlsGetValue(tlsmach);
}
void
setmach(Mach *m)
{
TlsSetValue(tlsmach, m);
}
static int args(char *argv[], int n, char *p);
int PASCAL
WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR arg, int nshow)
{
int argc, n;
char *p, **argv;
WNDCLASS wc;
HANDLE inst;
MSG msg;
Rune rbuf[256], *r;
/* conservative guess at the number of args */
for(argc=5,p=arg; *p; p++)
if(*p == ' ' || *p == '\t')
argc++;
argv = GlobalAlloc(GMEM_FIXED, argc*sizeof(char*));
argc = args(argv+1, argc, arg);
argv[0] = "plan9";
argc++;
ARGBEGIN{
case 'd':
debug = 1;
break;
}ARGEND
machp0 = GlobalAlloc(GMEM_FIXED, sizeof(Mach));
machp0->ticks = GetTickCount();
memset(machp0, 0, sizeof(Mach));
tlsmach = TlsAlloc();
nomach.machno = -1;
TlsSetValue(tlsmach, &nomach);
screenputs = dwriten;
print("Plan 9 from User Space\n");
SetConsoleTitleA("Plan 9 from User Space");
if(!debug)
ShowWindow(GetConsoleWindow(), SW_HIDE);
inst = GetModuleHandle(nil);
wc.style = 0;
wc.lpfnWndProc = NewProcProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = inst;
wc.hIcon = LoadIcon(inst, nil);
wc.hCursor = LoadCursor(nil, IDC_ARROW);
wc.hbrBackground = GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = 0;
wc.lpszClassName = L"Plan 9 Kernel";
RegisterClass(&wc);
me = GetCurrentProcess();
idle = CreateSemaphore(nil, 0, 1, nil);
window = CreateWindowEx(
WS_EX_TOOLWINDOW,
L"Plan 9 Kernel",
L"Plan 9 Kernel",
WS_OVERLAPPEDWINDOW|
WS_MINIMIZE|WS_DISABLED,
CW_USEDEFAULT,
CW_USEDEFAULT,
100,
100,
NULL,
NULL,
inst,
NULL
);
if(window == nil){
oserror();
panic("can't allocate window: %r");
}
n = nelem(rbuf);
r = rbuf;
if(!GetUserName(r, &n)){
n++;
r = win_malloc(n*sizeof(Rune));
if(!GetUserName(r, &n))
r = L"glenda";
}
eve = win_wstr2utf(r);
adddev(&devroot); /* must be first */
adddev(&devcons);
adddev(&devdup);
adddev(&devenv);
adddev(&devfs);
adddev(&devmnt);
adddev(&devpipe);
adddev(&devproc);
adddev(&devsrv);
adddev(&devssl);
procinit0();
userinit();
up->slash = namec("#/", Atodir, 0, 0);
cnameclose(up->slash->name);
up->slash->name = newcname("/");
up->dot = namec("/", Atodir, 0, 0);
CreateThread(nil, 8192, kernelthread, machp0, 0, nil);
CreateThread(nil, 8192, alarmthread, nil, 0, nil);
while(GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
ExitProcess(0);
}
void
runsyscall(Syscallmem *c)
{
int i;
char *e;
long ret;
if(!waserror()){
if(c->nr < 0 || c->nr >= Nsyscall || systab[c->nr].fn==nil){
print("pid %d bad sys call number %d\n", up->pid, c->nr);
delay(1000);
pprint("bad sys call number %d\n", c->nr);
delay(1000);
postnote(up, 1, "sys: bad sys call", NDebug); /* Ndebug? BUG? */
delay(1000);
error(Ebadarg);
}
validargs(c->arg, &c[1], (uchar*)c+CallMem, systab[c->nr].fmt);
// print("%d calling %s\n", up->pid, systab[c->nr].psstate);
up->psstate = systab[c->nr].psstate;
ret = (*systab[c->nr].fn)(c->arg);
poperror();
// print("%d %s ret = %d\n", up->pid, systab[c->nr].psstate, ret);
}else{
/* failure: save the error buffer for errstr */
print("%d syscall %s failed '%s'\n", up->pid, systab[c->nr].psstate, up->errstr);
e = up->errstr;
up->syserrstr = up->errstr;
up->errstr = e;
ret = -1;
}
if(up->nerrlab){
print("bad errstack [%d]: %d extra\n", c->nr, up->nerrlab);
for(i=0; i<NERR; i++)
print("sp=%lux pc=%lux\n", up->errlab[i].jb[JMPBUFSP], up->errlab[i].jb[JMPBUFPC]);
panic("error stack");
}
up->psstate = nil;
c->ret = ret;
/* BUG notify etc. */
}
void
procdie(Proc *p, char *exitstr)
{
Syscallmem *c;
c = p->sysaux;
if(!c->exitnow){
c->exitnow = 1;
strcpy(c->exitstatus, exitstr);
}
if(c->nr == Sexits)
ReleaseSemaphore(c->hs.hclientsig, 1, nil);
CloseHandle(c->hs.hserversig);
CloseHandle(c->hs.hclientsig);
CloseHandle(c->hs.hmem);
CloseHandle(c->hs.hkillsig);
UnmapViewOfFile(c);
}
void
userproc(void *arg)
{
DWORD status;
char err[ERRMAX];
Hwait w;
Hevent e[2];
Syscallmem *c;
c = arg;
up->sysaux = c;
up->die = procdie;
print("userproc %lud [%d] started\n", up->pid, up->index);
memset(e, 0, sizeof e);
e[0].h = c->hs.hserversig;
e[1].h = c->hs.hclientproc;
w.e = e;
w.ne = 2;
for(;;){
// print("userproc %lud wait\n", up->pid);
handlewait(&w);
// print("userproc %lud wait ended\n", up->pid);
switch(w.alt){
default:
/* interrupted; give up */
print("%lud handlewait interrupted\n", up->pid);
strcpy(up->exitstatus, "handlewait interrupted");
goto End;
case 0:
/* dispatch system call */
// print("%lud syscall %d\n", up->pid, c->nr);
runsyscall(c);
// print("ReleasingSemaphore\n");
ReleaseSemaphore(c->hs.hclientsig, 1, nil);
break;
case 1:
/* process has exited */
print("%lud process exited (handleproc=%p)\n", up->pid, c->hs.hclientproc);
status = 10101010;
if(!GetExitCodeProcess(c->hs.hclientproc, &status)){
osrerrstr(err, sizeof err);
snprint(up->exitstatus, ERRMAX, "GetExitCodeProcess failed: %s", err);
print("%s\n", up->exitstatus);
goto End;
}
if(status == STILL_ACTIVE){
print("GetExitCodeProcess returned STILL_ACTIVE?\n");
strcpy(up->exitstatus, "bad GetExitCodeProcess call");
goto End;
}
if(status != 99)
snprint(up->exitstatus, ERRMAX, "%d", status);
End:
print("userproc %lud is exiting; status=%s\n", up->pid, up->exitstatus);
pexit(up->exitstatus, 1);
abort();
}
}
}
LRESULT CALLBACK
NewProcProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
Handles *h, *x;
Proc *p;
Syscallmem *c;
char err[ERRMAX];
HANDLE hproc, hmem;
print("msg %d\n", msg);
switch(msg){
case WM_USER:
p = findproc(wparam);
if(p == nil){
print("Attach as pid %d failed\n", wparam);
return 1;
}
hproc = OpenProcess(PROCESS_ALL_ACCESS, 0, lparam);
if(hproc == nil){
osrerrstr(err, sizeof err);
print("OpenProcess %d: %s\n", lparam, err);
Err0:
return 0;
}
if(0){
Err1:
CloseHandle(hproc);
goto Err0;
}
hmem = CreateFileMapping(nil, nil, PAGE_READWRITE, 0, CallMem, nil);
if(hmem == nil){
osrerrstr(err, sizeof err);
print("CreateFileMapping for %d: %s\n", lparam, err);
goto Err1;
}
if(0){
Err2:
CloseHandle(hmem);
goto Err1;
}
c = MapViewOfFile(hmem, FILE_MAP_WRITE, 0, 0, 0);
if(c == nil){
osrerrstr(err, sizeof err);
print("MapViewOfFile for %d: %s\n", lparam, err);
goto Err2;
}
if(0){
Err3:
UnmapViewOfFile(c);
goto Err2;
}
h = &c->hs;
memset(h, 0, sizeof(*h));
h->hmem = hmem;
h->hclientproc = hproc;
if((h->hserversig = CreateSemaphore(nil, 0, 1, nil)) == nil){
osrerrstr(err, sizeof err);
print("CreateSemaphore: %s\n", err);
goto Err3;
}
if(0){
Err4:
CloseHandle(h->hserversig);
goto Err3;
}
if((h->hclientsig = CreateSemaphore(nil, 0, 1, nil)) == nil){
osrerrstr(err, sizeof err);
print("CreateSemaphore: %s\n", err);
goto Err4;
}
if(0){
Err5:
CloseHandle(h->hclientsig);
goto Err4;
}
if((h->hkillsig = CreateSemaphore(nil, 0, 1, nil)) == nil){
osrerrstr(err, sizeof err);
print("CreateSemaphore: %s\n", err);
goto Err5;
}
if(0){
Err6:
CloseHandle(h->hclientsig);
goto Err5;
}
x = &c->hc;
memset(x, 0, sizeof(*x));
/*
* We can't close the other guy's handles, so if an error occurs
* we have to just leave them and only clean up after ourselves.
*/
if(!DuplicateHandle(me, h->hserversig, hproc, &x->hserversig, 0, 0, DUPLICATE_SAME_ACCESS)){
osrerrstr(err, sizeof err);
print("DuplicateHandle 0 %p for %d: %s\n", h->hserversig, lparam, err);
goto Err6;
}
if(!DuplicateHandle(me, h->hclientsig, hproc, &x->hclientsig, 0, 0, DUPLICATE_SAME_ACCESS)){
osrerrstr(err, sizeof err);
print("DuplicateHandle 1 %p for %d: %s\n", h->hclientsig, lparam, err);
goto Err6;
}
if(!DuplicateHandle(me, h->hmem, hproc, &x->hmem, 0, 0, DUPLICATE_SAME_ACCESS)){
osrerrstr(err, sizeof err);
print("DuplicateHandle 2 %p for %d: %s\n", h->hmem, lparam, err);
goto Err6;
}
if(!DuplicateHandle(me, h->hkillsig, hproc, &x->hkillsig, 0, 0, DUPLICATE_SAME_ACCESS)){
osrerrstr(err, sizeof err);
print("DuplicateHandle 2 %p for %d: %s\n", h->hkillsig, lparam, err);
goto Err6;
}
c->p = p;
kprocchild(c->p, userproc, c);
ready(c->p);
return (LRESULT)x->hmem;
default:
return DefWindowProc(hwnd, msg, wparam, lparam);
}
}
/*
* Break the command line into arguments
* The rules for this are not documented but appear to be the following
* according to the source for the microsoft C library.
* Words are seperated by space or tab
* Words containing a space or tab can be quoted using "
* 2N backslashes + " ==> N backslashes and end quote
* 2N+1 backslashes + " ==> N backslashes + literal "
* N backslashes not followed by " ==> N backslashes
*/
static int
args(char *argv[], int n, char *p)
{
char *p2;
int i, j, quote, nbs;
for(i=0; *p && i<n-1; i++) {
while(*p == ' ' || *p == '\t')
p++;
quote = 0;
argv[i] = p2 = p;
for(;*p; p++) {
if(!quote && (*p == ' ' || *p == '\t'))
break;
for(nbs=0; *p == '\\'; p++,nbs++)
;
if(*p == '"') {
for(j=0; j<(nbs>>1); j++)
*p2++ = '\\';
if(nbs&1)
*p2++ = *p;
else
quote = !quote;
} else {
for(j=0; j<nbs; j++)
*p2++ = '\\';
*p2++ = *p;
}
}
/* move p up one to avoid pointing to null at end of p2 */
if(*p)
p++;
*p2 = 0;
}
argv[i] = 0;
return i;
}
void
ossched(void)
{
Sleep(0);
}
static int
is9pm(char *s, int ns)
{
char *e;
int len;
len = strlen(magic);
e = s+ns-len;
for(; s<e; s++)
if(memcmp(s, magic, len)==0)
return 1;
return 0;
}
long
sysexec(ulong *arg)
{
int indir, n, m;
char *buf, *p;
Chan *tc;
char *file;
char **args;
Rune *r;
file = (char*)arg[0];
indir = 0;
elem = nil;
if(waserror()){
free(elem);
nexterror();
}
for(;;){
tc = namec(file, Aopen, OEXEC, 0);
if(waserror()){
cclose(tc);
nexterror();
}
if(!indir)
kstrdup(&elem, up->genbuf);
n = devtab[tc->type]->read(tc, &exec, sizeof(Exec), 0);
if(n < 2)
error(Ebadexec);
magic = l2be(exec.magic);
text = l2be(exec.text);
entry = l2be(exec.entry);
if(n==sizeof(Exec) && (magic == AOUT_MAGIC)){
if((text&KZERO) == KZERO
|| entry < UTZERO+sizeof(Exec)
|| entry >= UTZERO+sizeof(Exec)+text)
error(Ebadexec);
break; /* for binary */
}
/*
* Process #! /bin/sh args ...
*/
memmove(line, &exec, sizeof(Exec));
if(indir || line[0]!='#' || line[1]!='!')
error(Ebadexec);
n = shargs(line, n, progarg);
if(n == 0)
error(Ebadexec);
indir = 1;
/*
* First arg becomes complete file name
*/
progarg[n++] = file;
progarg[n] = 0;
validaddr(arg[1], BY2WD, 1);
arg[1] += BY2WD;
file = progarg[0];
if(strlen(elem) >= sizeof progelem)
error(Ebadexec);
strcpy(progelem, elem);
progarg[0] = progelem;
poperror();
cclose(tc);
}
buf = smalloc(2048);
indir = 0;
tc = namec(prog, Aopen, AEXEC, 0);
if(waserror()){
free(buf):
cclose(c);
nexterror();
}
m = 0;
while(m < 2048){
n = devtab[tc->type]->read(tc, buf+m, 2048-m, m);
if(n <= 0)
break;
m += n;
}
if(m[0]=='#' && m[1]=='!'){ /* shell script */
m[2047] = '\0';
p = strchr(m, '\n');
*p = '\0';
prog = m+2;
cclose(tc);
poperror();
}
if(m[0]!='M' || m[1]!='Z')
error(Ebadexec);
if(is9pm(m, 2048))
}
syntax highlighted by Code2HTML, v. 0.9.1