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