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