#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; ierrlab[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>1); j++) *p2++ = '\\'; if(nbs&1) *p2++ = *p; else quote = !quote; } else { for(j=0; jgenbuf); 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)) }