xref: /inferno-os/emu/Nt/ie-os.c (revision 50b0dbb170df61467e42c7ea4deb0b5692d15f4c)
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
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
66 osblock(void)
67 {
68 	erendezvous(up, 0);
69 }
70 
71 void
72 osready(Proc *p)
73 {
74 	erendezvous(p, 0);
75 }
76 
77 
78 void
79 pexit(char *msg, int t)
80 {
81 	pfree(up);
82 	ExitThread(0);
83 }
84 
85 LONG TrapHandler(LPEXCEPTION_POINTERS ureg);
86 
87 __cdecl
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
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
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)
176 void APIENTRY sleepintr(DWORD param)
177 {
178 }
179 #endif
180 
181 void
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
195 oslongjmp(void *regs, osjmpbuf env, int val)
196 {
197 	USED(regs);
198 	longjmp(env, val);
199 }
200 
201 int
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
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
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
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
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
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
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
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
467 FPsave(void *fptr)
468 {
469 	_asm {
470 		mov	eax, fptr
471 		fstenv	[eax]
472 	}
473 }
474 
475 void
476 FPrestore(void *fptr)
477 {
478 	_asm {
479 		mov	eax, fptr
480 		fldenv	[eax]
481 	}
482 }
483 
484 ulong
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
501 close(int fd)
502 {
503 	if(fd != -1)
504 		CloseHandle(ntfd2h(fd));
505 	return 0;
506 }
507 
508 int
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
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
539 nth2fd(HANDLE h)
540 {
541 	return (int)h;
542 }
543 
544 HANDLE
545 ntfd2h(int fd)
546 {
547 	return (HANDLE)fd;
548 }
549 
550 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
559 sleep(int secs)
560 {
561 	Sleep(secs*1000);
562 }
563 
564 void*
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
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
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*
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
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
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
702 osnsec(void)
703 {
704 	return osusectime()*1000;	/* TO DO better */
705 }
706 
707 int
708 osmillisleep(ulong milsec)
709 {
710 	up->syscall = 1;
711 	SleepEx(milsec, FALSE);
712 	up->syscall = 0;
713 	return 0;
714 }
715 
716 int
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
730 osyield(void)
731 {
732 	sleep(0);
733 }
734 
735 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
747 open(const char *path, int how, ...)
748 {
749 	panic("open");
750 	return -1;
751 }
752 
753 int
754 creat(const char *path, int how)
755 {
756 	panic("creat");
757 	return -1;
758 }
759 
760 int
761 stat(const char *path, struct stat *sp)
762 {
763 	panic("stat");
764 	return -1;
765 }
766 
767 int
768 chown(const char *path, int uid, int gid)
769 {
770 	panic("chown");
771 	return -1;
772 }
773 
774 int
775 chmod(const char *path, int mode)
776 {
777 	panic("chmod");
778 	return -1;
779 }
780 
781 void
782 link(char *path, char *next)
783 {
784 	panic("link");
785 }
786 
787 int
788 segflush(void *a, ulong n)
789 {
790 	return 0;
791 }
792 
793 wchar_t *
794 widen(char *s)
795 {
796 	int n;
797 	wchar_t *ws;
798 
799 	n = utflen(s) + 1;
800 	ws = smalloc(n*sizeof(wchar_t));
801 	utftorunes(ws, s, n);
802 	return ws;
803 }
804 
805 
806 char *
807 narrowen(wchar_t *ws)
808 {
809 	char *s;
810 	int n;
811 
812 	n = widebytes(ws);
813 	s = smalloc(n);
814 	runestoutf(s, ws, n);
815 	return s;
816 }
817 
818 
819 int
820 widebytes(wchar_t *ws)
821 {
822 	int n = 0;
823 
824 	while (*ws)
825 		n += runelen(*ws++);
826 	return n+1;
827 }
828