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