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