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