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 // install our own exception handler 111 // replacing all others installed on this thread 112 DWORD handler = (DWORD)Exhandler; 113 _asm { 114 mov eax,handler 115 push eax 116 mov eax,-1 117 push eax 118 mov fs:[0],esp 119 } 120 121 up = p; 122 up->func(up->arg); 123 pexit("", 0); 124 /* not reached */ 125 for(;;) 126 panic("tramp"); 127 return 0; 128 } 129 130 int 131 kproc(char *name, void (*func)(void*), void *arg, int flags) 132 { 133 DWORD h; 134 Proc *p; 135 Pgrp *pg; 136 Fgrp *fg; 137 Egrp *eg; 138 139 p = newproc(); 140 if(p == nil){ 141 print("out of kernel processes\n"); 142 return -1; 143 } 144 p->os = CreateEvent(NULL, FALSE, FALSE, NULL); 145 if(p->os == NULL){ 146 pfree(p); 147 print("can't allocate os event\n"); 148 return -1; 149 } 150 151 if(flags & KPDUPPG) { 152 pg = up->env->pgrp; 153 incref(&pg->r); 154 p->env->pgrp = pg; 155 } 156 if(flags & KPDUPFDG) { 157 fg = up->env->fgrp; 158 incref(&fg->r); 159 p->env->fgrp = fg; 160 } 161 if(flags & KPDUPENVG) { 162 eg = up->env->egrp; 163 incref(&eg->r); 164 p->env->egrp = eg; 165 } 166 167 p->env->ui = up->env->ui; 168 kstrdup(&p->env->user, up->env->user); 169 strcpy(p->text, name); 170 171 p->func = func; 172 p->arg = arg; 173 174 lock(&procs.l); 175 if(procs.tail != nil) { 176 p->prev = procs.tail; 177 procs.tail->next = p; 178 } 179 else { 180 procs.head = p; 181 p->prev = nil; 182 } 183 procs.tail = p; 184 unlock(&procs.l); 185 186 p->pid = (int)CreateThread(0, 16384, tramp, p, 0, &h); 187 if(p->pid <= 0){ 188 pfree(p); 189 print("ran out of kernel processes\n"); 190 return -1; 191 } 192 return p->pid; 193 } 194 195 #if(_WIN32_WINNT >= 0x0400) 196 void APIENTRY sleepintr(DWORD param) 197 { 198 } 199 #endif 200 201 void 202 oshostintr(Proc *p) 203 { 204 if (p->syscall == SOCK_SELECT) 205 return; 206 p->intwait = 0; 207 #if(_WIN32_WINNT >= 0x0400) 208 if(p->syscall == SYS_SLEEP) { 209 QueueUserAPC(sleepintr, (HANDLE) p->pid, (DWORD) p->pid); 210 } 211 #endif 212 } 213 214 void 215 oslongjmp(void *regs, osjmpbuf env, int val) 216 { 217 USED(regs); 218 longjmp(env, val); 219 } 220 221 int 222 readkbd(void) 223 { 224 DWORD r; 225 char buf[1]; 226 227 if(ReadFile(kbdh, buf, sizeof(buf), &r, 0) == FALSE) 228 panic("keyboard fail"); 229 if (r == 0) 230 panic("keyboard EOF"); 231 232 if (buf[0] == 0x03) { 233 // INTR (CTRL+C) 234 termrestore(); 235 ExitProcess(0); 236 } 237 if(buf[0] == '\r') 238 buf[0] = '\n'; 239 return buf[0]; 240 } 241 242 void 243 cleanexit(int x) 244 { 245 sleep(2); /* give user a chance to see message */ 246 termrestore(); 247 ExitProcess(x); 248 } 249 250 struct ecodes { 251 DWORD code; 252 char* name; 253 } ecodes[] = { 254 EXCEPTION_ACCESS_VIOLATION, "Segmentation violation", 255 EXCEPTION_DATATYPE_MISALIGNMENT, "Data Alignment", 256 EXCEPTION_BREAKPOINT, "Breakpoint", 257 EXCEPTION_SINGLE_STEP, "SingleStep", 258 EXCEPTION_ARRAY_BOUNDS_EXCEEDED, "Array Bounds Check", 259 EXCEPTION_FLT_DENORMAL_OPERAND, "Denormalized Float", 260 EXCEPTION_FLT_DIVIDE_BY_ZERO, "Floating Point Divide by Zero", 261 EXCEPTION_FLT_INEXACT_RESULT, "Inexact Floating Point", 262 EXCEPTION_FLT_INVALID_OPERATION, "Invalid Floating Operation", 263 EXCEPTION_FLT_OVERFLOW, "Floating Point Result Overflow", 264 EXCEPTION_FLT_STACK_CHECK, "Floating Point Stack Check", 265 EXCEPTION_FLT_UNDERFLOW, "Floating Point Result Underflow", 266 EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by Zero", 267 EXCEPTION_INT_OVERFLOW, "Integer Overflow", 268 EXCEPTION_PRIV_INSTRUCTION, "Privileged Instruction", 269 EXCEPTION_IN_PAGE_ERROR, "Page-in Error", 270 EXCEPTION_ILLEGAL_INSTRUCTION, "Illegal Instruction", 271 EXCEPTION_NONCONTINUABLE_EXCEPTION, "Non-Continuable Exception", 272 EXCEPTION_STACK_OVERFLOW, "Stack Overflow", 273 EXCEPTION_INVALID_DISPOSITION, "Invalid Disposition", 274 EXCEPTION_GUARD_PAGE, "Guard Page Violation", 275 0, nil 276 }; 277 278 void 279 dodisfault(void) 280 { 281 disfault(nil, up->env->errstr); 282 } 283 284 typedef struct Ereg Ereg; 285 struct Ereg { 286 Ereg *prev; 287 FARPROC handler; 288 }; 289 290 void 291 dumpex() 292 { 293 Ereg *er; 294 int i; 295 _asm { mov eax,fs:[0] }; 296 _asm { mov [er],eax }; 297 298 i = 0; 299 while ((unsigned)er != ~0) { 300 print("handler %ux\n", er->handler); 301 i++; 302 er = er->prev; 303 } 304 print("EXCEPTION CHAIN LENGTH = %d\n", i); 305 } 306 307 LONG 308 TrapHandler(LPEXCEPTION_POINTERS ureg) 309 { 310 int i; 311 char *name; 312 DWORD code; 313 // WORD pc; 314 char buf[ERRMAX]; 315 316 code = ureg->ExceptionRecord->ExceptionCode; 317 // pc = ureg->ContextRecord->Eip; 318 319 name = nil; 320 for(i = 0; i < nelem(ecodes); i++) { 321 if(ecodes[i].code == code) { 322 name = ecodes[i].name; 323 break; 324 } 325 } 326 327 if(name == nil) { 328 snprint(buf, sizeof(buf), "Unrecognized Machine Trap (%.8lux)\n", code); 329 name = buf; 330 } 331 /* 332 if(pc != 0) { 333 snprint(buf, sizeof(buf), "%s: pc=0x%lux", name, pc); 334 name = buf; 335 } 336 */ 337 /* YUCK! */ 338 strncpy(up->env->errstr, name, ERRMAX); 339 switch (code) { 340 case EXCEPTION_FLT_DENORMAL_OPERAND: 341 case EXCEPTION_FLT_DIVIDE_BY_ZERO: 342 case EXCEPTION_FLT_INEXACT_RESULT: 343 case EXCEPTION_FLT_INVALID_OPERATION: 344 case EXCEPTION_FLT_OVERFLOW: 345 case EXCEPTION_FLT_STACK_CHECK: 346 case EXCEPTION_FLT_UNDERFLOW: 347 /* clear exception flags and register stack */ 348 _asm { fnclex }; 349 ureg->ContextRecord->FloatSave.StatusWord = 0x0000; 350 ureg->ContextRecord->FloatSave.TagWord = 0xffff; 351 } 352 ureg->ContextRecord->Eip = (DWORD)dodisfault; 353 return EXCEPTION_CONTINUE_EXECUTION; 354 } 355 356 static void 357 termset(void) 358 { 359 DWORD flag; 360 361 if(donetermset) 362 return; 363 donetermset = 1; 364 conh = GetStdHandle(STD_OUTPUT_HANDLE); 365 kbdh = GetStdHandle(STD_INPUT_HANDLE); 366 errh = GetStdHandle(STD_ERROR_HANDLE); 367 if(errh == INVALID_HANDLE_VALUE) 368 errh = conh; 369 370 // The following will fail if kbdh not from console (e.g. a pipe) 371 // in which case we don't care 372 GetConsoleMode(kbdh, &consolestate); 373 flag = consolestate; 374 flag = flag & ~(ENABLE_PROCESSED_INPUT|ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT); 375 SetConsoleMode(kbdh, flag); 376 } 377 378 void 379 termrestore(void) 380 { 381 if(kbdh != INVALID_HANDLE_VALUE) 382 SetConsoleMode(kbdh, consolestate); 383 } 384 385 static int rebootok = 0; /* is shutdown -r supported? */ 386 387 void 388 osreboot(char *file, char **argv) 389 { 390 if(rebootok){ 391 termrestore(); 392 execvp(file, argv); 393 panic("reboot failure"); 394 } 395 } 396 397 void 398 libinit(char *imod) 399 { 400 WSADATA wasdat; 401 DWORD lasterror, namelen; 402 OSVERSIONINFO os; 403 char sys[64], uname[64]; 404 wchar_t wuname[64]; 405 char *uns; 406 407 os.dwOSVersionInfoSize = sizeof(os); 408 if(!GetVersionEx(&os)) 409 panic("can't get os version"); 410 PlatformId = os.dwPlatformId; 411 if (PlatformId == VER_PLATFORM_WIN32_NT) { /* true for NT and 2000 */ 412 rebootok = 1; 413 } else { 414 rebootok = 0; 415 } 416 termset(); 417 418 if((int)INVALID_HANDLE_VALUE != -1 || sizeof(HANDLE) != sizeof(int)) 419 panic("invalid handle value or size"); 420 421 if(WSAStartup(MAKEWORD(1, 1), &wasdat) != 0) 422 panic("no winsock.dll"); 423 424 gethostname(sys, sizeof(sys)); 425 kstrdup(&ossysname, sys); 426 // if(sflag == 0) 427 // SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)TrapHandler); 428 429 path = getenv("PATH"); 430 if(path == nil) 431 path = "."; 432 433 up = newproc(); 434 if(up == nil) 435 panic("cannot create kernel process"); 436 437 strcpy(uname, "inferno"); 438 namelen = sizeof(wuname); 439 if(GetUserName(wuname, &namelen) != TRUE) { 440 lasterror = GetLastError(); 441 if(PlatformId == VER_PLATFORM_WIN32_NT || lasterror != ERROR_NOT_LOGGED_ON) 442 print("cannot GetUserName: %d\n", lasterror); 443 }else{ 444 uns = narrowen(wuname); 445 snprint(uname, sizeof(uname), "%s", uns); 446 free(uns); 447 } 448 kstrdup(&eve, uname); 449 450 emuinit(imod); 451 } 452 453 void 454 FPsave(void *fptr) 455 { 456 _asm { 457 mov eax, fptr 458 fstenv [eax] 459 } 460 } 461 462 void 463 FPrestore(void *fptr) 464 { 465 _asm { 466 mov eax, fptr 467 fldenv [eax] 468 } 469 } 470 471 ulong 472 umult(ulong a, ulong b, ulong *high) 473 { 474 ulong lo, hi; 475 476 _asm { 477 mov eax, a 478 mov ecx, b 479 MUL ecx 480 mov lo, eax 481 mov hi, edx 482 } 483 *high = hi; 484 return lo; 485 } 486 487 int 488 close(int fd) 489 { 490 if(fd == -1) 491 return 0; 492 CloseHandle(ntfd2h(fd)); 493 return 0; 494 } 495 496 int 497 read(int fd, void *buf, uint n) 498 { 499 HANDLE h; 500 501 if(fd == 0) 502 h = kbdh; 503 else 504 h = ntfd2h(fd); 505 if(h == INVALID_HANDLE_VALUE) 506 return -1; 507 if(!ReadFile(h, buf, n, &n, NULL)) 508 return -1; 509 return n; 510 } 511 512 int 513 write(int fd, void *buf, uint n) 514 { 515 HANDLE h; 516 517 if(fd == 1 || fd == 2){ 518 if(!donetermset) 519 termset(); 520 if(fd == 1) 521 h = conh; 522 else 523 h = errh; 524 if(h == INVALID_HANDLE_VALUE) 525 return -1; 526 if(!WriteFile(h, buf, n, &n, NULL)) 527 return -1; 528 return n; 529 } 530 if(!WriteFile(ntfd2h(fd), buf, n, &n, NULL)) 531 return -1; 532 return n; 533 } 534 535 /* 536 * map handles and fds. 537 * this code assumes sizeof(HANDLE) == sizeof(int), 538 * that INVALID_HANDLE_VALUE is -1, and assumes 539 * that all tests of invalid fds check only for -1, not < 0 540 */ 541 int 542 nth2fd(HANDLE h) 543 { 544 return (int)h; 545 } 546 547 HANDLE 548 ntfd2h(int fd) 549 { 550 return (HANDLE)fd; 551 } 552 553 void 554 oslopri(void) 555 { 556 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL); 557 } 558 559 /* Resolve system header name conflict */ 560 #undef Sleep 561 void 562 sleep(int secs) 563 { 564 Sleep(secs*1000); 565 } 566 567 void* 568 sbrk(int size) 569 { 570 void *brk; 571 572 brk = VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); 573 if(brk == 0) 574 return (void*)-1; 575 576 return brk; 577 } 578 579 ulong 580 getcallerpc(void *arg) 581 { 582 ulong cpc; 583 _asm { 584 mov eax, dword ptr [ebp] 585 mov eax, dword ptr [eax+4] 586 mov dword ptr cpc, eax 587 } 588 return cpc; 589 } 590 591 /* 592 * Return an abitrary millisecond clock time 593 */ 594 long 595 osmillisec(void) 596 { 597 return GetTickCount(); 598 } 599 600 #define SEC2MIN 60L 601 #define SEC2HOUR (60L*SEC2MIN) 602 #define SEC2DAY (24L*SEC2HOUR) 603 604 /* 605 * days per month plus days/year 606 */ 607 static int dmsize[] = 608 { 609 365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 610 }; 611 static int ldmsize[] = 612 { 613 366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 614 }; 615 616 /* 617 * return the days/month for the given year 618 */ 619 static int* 620 yrsize(int yr) 621 { 622 /* a leap year is a multiple of 4, excluding centuries 623 * that are not multiples of 400 */ 624 if( (yr % 4 == 0) && (yr % 100 != 0 || yr % 400 == 0) ) 625 return ldmsize; 626 else 627 return dmsize; 628 } 629 630 static long 631 tm2sec(SYSTEMTIME *tm) 632 { 633 long secs; 634 int i, *d2m; 635 636 secs = 0; 637 638 /* 639 * seconds per year 640 */ 641 for(i = 1970; i < tm->wYear; i++){ 642 d2m = yrsize(i); 643 secs += d2m[0] * SEC2DAY; 644 } 645 646 /* 647 * seconds per month 648 */ 649 d2m = yrsize(tm->wYear); 650 for(i = 1; i < tm->wMonth; i++) 651 secs += d2m[i] * SEC2DAY; 652 653 /* 654 * secs in last month 655 */ 656 secs += (tm->wDay-1) * SEC2DAY; 657 658 /* 659 * hours, minutes, seconds 660 */ 661 secs += tm->wHour * SEC2HOUR; 662 secs += tm->wMinute * SEC2MIN; 663 secs += tm->wSecond; 664 665 return secs; 666 } 667 668 /* 669 * Return the time since the epoch in microseconds 670 * The epoch is defined at 1 Jan 1970 671 */ 672 vlong 673 osusectime(void) 674 { 675 SYSTEMTIME tm; 676 vlong secs; 677 678 GetSystemTime(&tm); 679 secs = tm2sec(&tm); 680 return secs * 1000000 + tm.wMilliseconds * 1000; 681 } 682 683 vlong 684 osnsec(void) 685 { 686 return osusectime()*1000; /* TO DO better */ 687 } 688 689 int 690 osmillisleep(ulong milsec) 691 { 692 SleepEx(milsec, FALSE); 693 return 0; 694 } 695 696 int 697 limbosleep(ulong milsec) 698 { 699 if (sleepers > MAXSLEEPERS) 700 return -1; 701 sleepers++; 702 up->syscall = SYS_SLEEP; 703 SleepEx(milsec, TRUE); 704 up->syscall = 0; 705 sleepers--; 706 return 0; 707 } 708 709 void 710 osyield(void) 711 { 712 sleep(0); 713 } 714 715 void 716 ospause(void) 717 { 718 for(;;) 719 sleep(1000000); 720 } 721 722 /* 723 * these should never be called, and are included 724 * as stubs since we are linking against a library which defines them 725 */ 726 int 727 open(const char *path, int how, ...) 728 { 729 panic("open"); 730 return -1; 731 } 732 733 int 734 creat(const char *path, int how) 735 { 736 panic("creat"); 737 return -1; 738 } 739 740 int 741 stat(const char *path, struct stat *sp) 742 { 743 panic("stat"); 744 return -1; 745 } 746 747 int 748 chown(const char *path, int uid, int gid) 749 { 750 panic("chown"); 751 return -1; 752 } 753 754 int 755 chmod(const char *path, int mode) 756 { 757 panic("chmod"); 758 return -1; 759 } 760 761 void 762 link(char *path, char *next) 763 { 764 panic("link"); 765 } 766 767 int 768 segflush(void *a, ulong n) 769 { 770 return 0; 771 } 772 773 wchar_t * 774 widen(char *s) 775 { 776 int n; 777 wchar_t *ws; 778 779 n = utflen(s) + 1; 780 ws = smalloc(n*sizeof(wchar_t)); 781 utftorunes(ws, s, n); 782 return ws; 783 } 784 785 786 char * 787 narrowen(wchar_t *ws) 788 { 789 char *s; 790 int n; 791 792 n = widebytes(ws); 793 s = smalloc(n); 794 runestoutf(s, ws, n); 795 return s; 796 } 797 798 799 int 800 widebytes(wchar_t *ws) 801 { 802 int n = 0; 803 804 while (*ws) 805 n += runelen(*ws++); 806 return n+1; 807 } 808