xref: /inferno-os/emu/Nt/os.c (revision 9dc22068e29604f4b484e746112a9a4efe6fd57f)
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