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