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