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