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