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