1 #define Unknown win_Unknown
2 #define UNICODE
3 #include <windows.h>
4 #include <winbase.h>
5 #include <winsock.h>
6 #undef Unknown
7 #include <excpt.h>
8 #include "dat.h"
9 #include "fns.h"
10 #include "error.h"
11 #include "r16.h"
12 #include "ieplugin.h"
13
14 extern int SYS_SLEEP = 2;
15 extern int SOCK_SELECT = 3;
16 #define MAXSLEEPERS 1500
17
18 extern Plugin* plugin;
19 extern void newiop();
20 extern int sendiop();
21
22 DWORD PlatformId;
23 static char* path;
24 static HANDLE kbdh = INVALID_HANDLE_VALUE;
25 static HANDLE conh = INVALID_HANDLE_VALUE;
26 static int sleepers;
27
28 static ulong erendezvous(void*, ulong);
29
30 __declspec(thread) Proc *up;
31
32 HANDLE ntfd2h(int);
33 int nth2fd(HANDLE);
34 char *hosttype = "Nt";
35
36 static void
pfree(Proc * p)37 pfree(Proc *p)
38 {
39 Osenv *e;
40
41 lock(&procs.l);
42 if(p->prev)
43 p->prev->next = p->next;
44 else
45 procs.head = p->next;
46
47 if(p->next)
48 p->next->prev = p->prev;
49 else
50 procs.tail = p->prev;
51 unlock(&procs.l);
52
53 e = p->env;
54 if(e != nil) {
55 closefgrp(e->fgrp);
56 closepgrp(e->pgrp);
57 closeegrp(e->egrp);
58 closesigs(e->sigs);
59 }
60 free(e->user);
61 free(p->prog);
62 free(p);
63 }
64
65 void
osblock(void)66 osblock(void)
67 {
68 erendezvous(up, 0);
69 }
70
71 void
osready(Proc * p)72 osready(Proc *p)
73 {
74 erendezvous(p, 0);
75 }
76
77
78 void
pexit(char * msg,int t)79 pexit(char *msg, int t)
80 {
81 pfree(up);
82 ExitThread(0);
83 }
84
85 LONG TrapHandler(LPEXCEPTION_POINTERS ureg);
86
87 __cdecl
Exhandler(EXCEPTION_RECORD * rec,void * frame,CONTEXT * context,void * dcon)88 Exhandler(EXCEPTION_RECORD *rec, void *frame, CONTEXT *context, void *dcon)
89 {
90 EXCEPTION_POINTERS ep;
91 ep.ExceptionRecord = rec;
92 ep.ContextRecord = context;
93 TrapHandler(&ep);
94 return ExceptionContinueExecution;
95 }
96
97 DWORD WINAPI
tramp(LPVOID p)98 tramp(LPVOID p)
99 {
100 // install our own exception handler
101 // replacing all others installed on this thread
102 DWORD handler = (DWORD)Exhandler;
103 _asm {
104 mov eax,handler
105 push eax
106 mov eax,-1
107 push eax
108 mov fs:[0],esp
109 }
110
111 up = p;
112 up->func(up->arg);
113 pexit("", 0);
114 // should never get here but tidy up anyway
115 _asm {
116 mov fs:[0],-1
117 add esp, 8
118 }
119 return 0;
120 }
121
122 void
kproc(char * name,void (* func)(void *),void * arg,int flags)123 kproc(char *name, void (*func)(void*), void *arg, int flags)
124 {
125 DWORD h;
126 Proc *p;
127 Pgrp *pg;
128 Fgrp *fg;
129 Egrp *eg;
130
131 p = newproc();
132 if(p == nil)
133 panic("out of kernel processes");
134
135 if(flags & KPDUPPG) {
136 pg = up->env->pgrp;
137 incref(&pg->r);
138 p->env->pgrp = pg;
139 }
140 if(flags & KPDUPFDG) {
141 fg = up->env->fgrp;
142 incref(&fg->r);
143 p->env->fgrp = fg;
144 }
145 if(flags & KPDUPENVG) {
146 eg = up->env->egrp;
147 incref(&eg->r);
148 p->env->egrp = eg;
149 }
150
151 p->env->ui = up->env->ui;
152 kstrdup(&p->env->user, up->env->user);
153 strcpy(p->text, name);
154
155 p->func = func;
156 p->arg = arg;
157
158 lock(&procs.l);
159 if(procs.tail != nil) {
160 p->prev = procs.tail;
161 procs.tail->next = p;
162 }
163 else {
164 procs.head = p;
165 p->prev = nil;
166 }
167 procs.tail = p;
168 unlock(&procs.l);
169
170 p->pid = (int)CreateThread(0, 16384, tramp, p, 0, &h);
171 if(p->pid <= 0)
172 panic("ran out of kernel processes");
173 }
174
175 #if(_WIN32_WINNT >= 0x0400)
sleepintr(DWORD param)176 void APIENTRY sleepintr(DWORD param)
177 {
178 }
179 #endif
180
181 void
oshostintr(Proc * p)182 oshostintr(Proc *p)
183 {
184 if (p->syscall == SOCK_SELECT)
185 return;
186 p->intwait = 0;
187 #if(_WIN32_WINNT >= 0x0400)
188 if(p->syscall == SYS_SLEEP) {
189 QueueUserAPC(sleepintr, (HANDLE) p->pid, (DWORD) p->pid);
190 }
191 #endif
192 }
193
194 void
oslongjmp(void * regs,osjmpbuf env,int val)195 oslongjmp(void *regs, osjmpbuf env, int val)
196 {
197 USED(regs);
198 longjmp(env, val);
199 }
200
201 int
readkbd(void)202 readkbd(void)
203 {
204 DWORD r;
205 char buf[1];
206
207 if(ReadFile(plugin->conin, buf, sizeof(buf), &r, 0) == FALSE)
208 panic("keyboard fail");
209 if (r == 0)
210 panic("keyboard EOF");
211
212 if(buf[0] == '\r')
213 buf[0] = '\n';
214 return buf[0];
215 }
216
217 void
cleanexit(int x)218 cleanexit(int x)
219 {
220 newiop();
221 IOP.op = Iquit;
222 sendiop();
223 ExitProcess(x);
224 }
225
226 struct ecodes {
227 DWORD code;
228 char* name;
229 } ecodes[] = {
230 EXCEPTION_ACCESS_VIOLATION, "Segmentation violation",
231 EXCEPTION_DATATYPE_MISALIGNMENT, "Data Alignment",
232 EXCEPTION_BREAKPOINT, "Breakpoint",
233 EXCEPTION_SINGLE_STEP, "SingleStep",
234 EXCEPTION_ARRAY_BOUNDS_EXCEEDED, "Array Bounds Check",
235 EXCEPTION_FLT_DENORMAL_OPERAND, "Denormalized Float",
236 EXCEPTION_FLT_DIVIDE_BY_ZERO, "Floating Point Divide by Zero",
237 EXCEPTION_FLT_INEXACT_RESULT, "Inexact Floating Point",
238 EXCEPTION_FLT_INVALID_OPERATION, "Invalid Floating Operation",
239 EXCEPTION_FLT_OVERFLOW, "Floating Point Result Overflow",
240 EXCEPTION_FLT_STACK_CHECK, "Floating Point Stack Check",
241 EXCEPTION_FLT_UNDERFLOW, "Floating Point Result Underflow",
242 EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by Zero",
243 EXCEPTION_INT_OVERFLOW, "Integer Overflow",
244 EXCEPTION_PRIV_INSTRUCTION, "Privileged Instruction",
245 EXCEPTION_IN_PAGE_ERROR, "Page-in Error",
246 EXCEPTION_ILLEGAL_INSTRUCTION, "Illegal Instruction",
247 EXCEPTION_NONCONTINUABLE_EXCEPTION, "Non-Continuable Exception",
248 EXCEPTION_STACK_OVERFLOW, "Stack Overflow",
249 EXCEPTION_INVALID_DISPOSITION, "Invalid Disposition",
250 EXCEPTION_GUARD_PAGE, "Guard Page Violation",
251 0, nil
252 };
253
254 void
dodisfault(void)255 dodisfault(void)
256 {
257 disfault(nil, up->env->errstr);
258 }
259
260 typedef struct Ereg Ereg;
261 struct Ereg {
262 Ereg *prev;
263 FARPROC handler;
264 };
265
266 void
dumpex()267 dumpex()
268 {
269 Ereg *er;
270 int i;
271 _asm { mov eax,fs:[0] };
272 _asm { mov [er],eax };
273
274 i = 0;
275 while ((unsigned)er != ~0) {
276 print("handler %ux\n", er->handler);
277 i++;
278 er = er->prev;
279 }
280 print("EXCEPTION CHAIN LENGTH = %d\n", i);
281 }
282
283 LONG
TrapHandler(LPEXCEPTION_POINTERS ureg)284 TrapHandler(LPEXCEPTION_POINTERS ureg)
285 {
286 int i;
287 char *name;
288 DWORD code;
289 // WORD pc;
290 char buf[ERRMAX];
291
292 code = ureg->ExceptionRecord->ExceptionCode;
293 // pc = ureg->ContextRecord->Eip;
294
295 name = nil;
296 for(i = 0; i < nelem(ecodes); i++) {
297 if(ecodes[i].code == code) {
298 name = ecodes[i].name;
299 break;
300 }
301 }
302
303 if(name == nil) {
304 snprint(buf, sizeof(buf), "Unrecognized Machine Trap (%.8lux)\n", code);
305 name = buf;
306 }
307 /*
308 if(pc != 0) {
309 snprint(buf, sizeof(buf), "%s: pc=0x%lux", name, pc);
310 name = buf;
311 }
312 */
313 /* YUCK! */
314 strncpy(up->env->errstr, name, ERRMAX);
315 switch (code) {
316 case EXCEPTION_FLT_DENORMAL_OPERAND:
317 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
318 case EXCEPTION_FLT_INEXACT_RESULT:
319 case EXCEPTION_FLT_INVALID_OPERATION:
320 case EXCEPTION_FLT_OVERFLOW:
321 case EXCEPTION_FLT_STACK_CHECK:
322 case EXCEPTION_FLT_UNDERFLOW:
323 /* clear exception flags and register stack */
324 _asm { fnclex };
325 ureg->ContextRecord->FloatSave.StatusWord = 0x0000;
326 ureg->ContextRecord->FloatSave.TagWord = 0xffff;
327 }
328 ureg->ContextRecord->Eip = (DWORD)dodisfault;
329 return EXCEPTION_CONTINUE_EXECUTION;
330 }
331
332 static int rebootok = 0; /* is shutdown -r supported? */
333
334 void
osreboot(char * file,char ** argv)335 osreboot(char *file, char **argv)
336 {
337 if(rebootok){
338 execvp(file, argv);
339 panic("reboot failure");
340 }else
341 error("reboot option not supported on this system");
342 }
343
344 void
libinit(char * imod)345 libinit(char *imod)
346 {
347 WSADATA wasdat;
348 // DWORD lasterror, namelen;
349 OSVERSIONINFO os;
350 // char sys[64];
351
352 os.dwOSVersionInfoSize = sizeof(os);
353 if(!GetVersionEx(&os))
354 panic("can't get os version");
355 PlatformId = os.dwPlatformId;
356 if (PlatformId == VER_PLATFORM_WIN32_NT) { /* true for NT and 2000 */
357 rebootok = 1;
358 } else {
359 rebootok = 0;
360 }
361
362 if((int)INVALID_HANDLE_VALUE != -1 || sizeof(HANDLE) != sizeof(int))
363 panic("invalid handle value or size");
364
365 if(WSAStartup(MAKEWORD(1, 1), &wasdat) != 0)
366 panic("no winsock.dll");
367
368 // gethostname(sys, sizeof(sys));
369 // kstrdup(&ossysname, sys);
370 kstrdup(&ossysname, "plugin");
371
372 // if(sflag == 0)
373 // SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)TrapHandler);
374
375 path = getenv("PATH");
376 if(path == nil)
377 path = ".";
378
379 up = newproc();
380 if(up == nil)
381 panic("cannot create kernel process");
382
383 kstrdup(&eve, "system");
384 emuinit(imod);
385 }
386
387 enum
388 {
389 NHLOG = 7,
390 NHASH = (1<<NHLOG)
391 };
392
393 typedef struct Tag Tag;
394 struct Tag
395 {
396 void* tag;
397 ulong val;
398 HANDLE pid;
399 Tag* next;
400 };
401
402 static Tag* ht[NHASH];
403 static Tag* ft;
404 static Lock hlock;
405 static int nsema;
406
407 ulong
erendezvous(void * tag,ulong value)408 erendezvous(void *tag, ulong value)
409 {
410 int h;
411 ulong rval;
412 Tag *t, **l, *f;
413
414
415 h = (ulong)tag & (NHASH-1);
416
417 lock(&hlock);
418 l = &ht[h];
419 for(t = ht[h]; t; t = t->next) {
420 if(t->tag == tag) {
421 rval = t->val;
422 t->val = value;
423 t->tag = 0;
424 unlock(&hlock);
425 if(SetEvent(t->pid) == FALSE)
426 panic("Release failed\n");
427 return rval;
428 }
429 }
430
431 t = ft;
432 if(t == 0) {
433 t = malloc(sizeof(Tag));
434 if(t == nil)
435 panic("rendezvous: no memory");
436 t->pid = CreateEvent(0, 0, 0, 0);
437 }
438 else
439 ft = t->next;
440
441 t->tag = tag;
442 t->val = value;
443 t->next = *l;
444 *l = t;
445 unlock(&hlock);
446
447 if(WaitForSingleObject(t->pid, INFINITE) != WAIT_OBJECT_0)
448 panic("WaitForSingleObject failed\n");
449
450 lock(&hlock);
451 rval = t->val;
452 for(f = *l; f; f = f->next) {
453 if(f == t) {
454 *l = f->next;
455 break;
456 }
457 l = &f->next;
458 }
459 t->next = ft;
460 ft = t;
461 unlock(&hlock);
462
463 return rval;
464 }
465
466 void
FPsave(void * fptr)467 FPsave(void *fptr)
468 {
469 _asm {
470 mov eax, fptr
471 fstenv [eax]
472 }
473 }
474
475 void
FPrestore(void * fptr)476 FPrestore(void *fptr)
477 {
478 _asm {
479 mov eax, fptr
480 fldenv [eax]
481 }
482 }
483
484 ulong
umult(ulong a,ulong b,ulong * high)485 umult(ulong a, ulong b, ulong *high)
486 {
487 ulong lo, hi;
488
489 _asm {
490 mov eax, a
491 mov ecx, b
492 MUL ecx
493 mov lo, eax
494 mov hi, edx
495 }
496 *high = hi;
497 return lo;
498 }
499
500 int
close(int fd)501 close(int fd)
502 {
503 if(fd != -1)
504 CloseHandle(ntfd2h(fd));
505 return 0;
506 }
507
508 int
read(int fd,void * buf,uint n)509 read(int fd, void *buf, uint n)
510 {
511 if(!ReadFile(ntfd2h(fd), buf, n, &n, NULL))
512 return -1;
513 return n;
514 }
515
516 int
write(int fd,void * buf,uint n)517 write(int fd, void *buf, uint n)
518 {
519 if(fd == 1 || fd == 2){
520 int w;
521 if (plugin->conout == NULL)
522 return n;
523 if (!WriteFile(plugin->conout, buf, n, &w, NULL) || n != w)
524 abort();
525 return n;
526 }
527 if(!WriteFile(ntfd2h(fd), buf, n, &n, NULL))
528 return -1;
529 return n;
530 }
531
532 /*
533 * map handles and fds.
534 * this code assumes sizeof(HANDLE) == sizeof(int),
535 * that INVALID_HANDLE_VALUE is -1, and assumes
536 * that all tests of invalid fds check only for -1, not < 0
537 */
538 int
nth2fd(HANDLE h)539 nth2fd(HANDLE h)
540 {
541 return (int)h;
542 }
543
544 HANDLE
ntfd2h(int fd)545 ntfd2h(int fd)
546 {
547 return (HANDLE)fd;
548 }
549
550 void
oslopri(void)551 oslopri(void)
552 {
553 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
554 }
555
556 /* Resolve system header name conflict */
557 #undef Sleep
558 void
sleep(int secs)559 sleep(int secs)
560 {
561 Sleep(secs*1000);
562 }
563
564 void*
sbrk(int size)565 sbrk(int size)
566 {
567 void *brk;
568
569 brk = VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
570 if(brk == 0)
571 return (void*)-1;
572
573 return brk;
574 }
575
576 ulong
getcallerpc(void * arg)577 getcallerpc(void *arg)
578 {
579 ulong cpc;
580 _asm {
581 mov eax, dword ptr [ebp]
582 mov eax, dword ptr [eax+4]
583 mov dword ptr cpc, eax
584 }
585 return cpc;
586 }
587
588 /*
589 ulong
590 getpc(void *arg, ulong *narg)
591 {
592 ulong *a = arg, *fp, pc;
593
594 if(a == nil){
595 *narg = 0;
596 return 0;
597 }
598 fp = a-2;
599 pc = fp[1];
600 fp = *(ulong**)fp;
601 if(fp == nil)
602 *narg = 0;
603 else
604 *narg = (ulong)(fp+2);
605 return pc;
606 }
607 */
608
609 /*
610 * Return an abitrary millisecond clock time
611 */
612 long
osmillisec(void)613 osmillisec(void)
614 {
615 return GetTickCount();
616 }
617
618 #define SEC2MIN 60L
619 #define SEC2HOUR (60L*SEC2MIN)
620 #define SEC2DAY (24L*SEC2HOUR)
621
622 /*
623 * days per month plus days/year
624 */
625 static int dmsize[] =
626 {
627 365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
628 };
629 static int ldmsize[] =
630 {
631 366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
632 };
633
634 /*
635 * return the days/month for the given year
636 */
637 static int*
yrsize(int yr)638 yrsize(int yr)
639 {
640 /* a leap year is a multiple of 4, excluding centuries
641 * that are not multiples of 400 */
642 if( (yr % 4 == 0) && (yr % 100 != 0 || yr % 400 == 0) )
643 return ldmsize;
644 else
645 return dmsize;
646 }
647
648 static long
tm2sec(SYSTEMTIME * tm)649 tm2sec(SYSTEMTIME *tm)
650 {
651 long secs;
652 int i, *d2m;
653
654 secs = 0;
655
656 /*
657 * seconds per year
658 */
659 for(i = 1970; i < tm->wYear; i++){
660 d2m = yrsize(i);
661 secs += d2m[0] * SEC2DAY;
662 }
663
664 /*
665 * seconds per month
666 */
667 d2m = yrsize(tm->wYear);
668 for(i = 1; i < tm->wMonth; i++)
669 secs += d2m[i] * SEC2DAY;
670
671 /*
672 * secs in last month
673 */
674 secs += (tm->wDay-1) * SEC2DAY;
675
676 /*
677 * hours, minutes, seconds
678 */
679 secs += tm->wHour * SEC2HOUR;
680 secs += tm->wMinute * SEC2MIN;
681 secs += tm->wSecond;
682
683 return secs;
684 }
685
686 /*
687 * Return the time since the epoch in microseconds
688 * The epoch is defined at 1 Jan 1970
689 */
690 vlong
osusectime(void)691 osusectime(void)
692 {
693 SYSTEMTIME tm;
694 vlong secs;
695
696 GetSystemTime(&tm);
697 secs = tm2sec(&tm);
698 return secs * 1000000 + tm.wMilliseconds * 1000;
699 }
700
701 vlong
osnsec(void)702 osnsec(void)
703 {
704 return osusectime()*1000; /* TO DO better */
705 }
706
707 int
osmillisleep(ulong milsec)708 osmillisleep(ulong milsec)
709 {
710 up->syscall = 1;
711 SleepEx(milsec, FALSE);
712 up->syscall = 0;
713 return 0;
714 }
715
716 int
limbosleep(ulong milsec)717 limbosleep(ulong milsec)
718 {
719 if (sleepers > MAXSLEEPERS)
720 return -1;
721 sleepers++;
722 up->syscall = SYS_SLEEP;
723 SleepEx(milsec, TRUE);
724 up->syscall = 0;
725 sleepers--;
726 return 0;
727 }
728
729 void
osyield(void)730 osyield(void)
731 {
732 sleep(0);
733 }
734
735 void
ospause(void)736 ospause(void)
737 {
738 for(;;)
739 sleep(1000000);
740 }
741
742 /*
743 * these should never be called, and are included
744 * as stubs since we are linking against a library which defines them
745 */
746 int
open(const char * path,int how,...)747 open(const char *path, int how, ...)
748 {
749 panic("open");
750 return -1;
751 }
752
753 int
creat(const char * path,int how)754 creat(const char *path, int how)
755 {
756 panic("creat");
757 return -1;
758 }
759
760 int
stat(const char * path,struct stat * sp)761 stat(const char *path, struct stat *sp)
762 {
763 panic("stat");
764 return -1;
765 }
766
767 int
chown(const char * path,int uid,int gid)768 chown(const char *path, int uid, int gid)
769 {
770 panic("chown");
771 return -1;
772 }
773
774 int
chmod(const char * path,int mode)775 chmod(const char *path, int mode)
776 {
777 panic("chmod");
778 return -1;
779 }
780
781 void
link(char * path,char * next)782 link(char *path, char *next)
783 {
784 panic("link");
785 }
786
787 int
segflush(void * a,ulong n)788 segflush(void *a, ulong n)
789 {
790 return 0;
791 }
792