1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "io.h" 7 #include "ureg.h" 8 #include "init.h" 9 #include <ctype.h> 10 11 12 uchar *sp; /* stack pointer for /boot */ 13 14 extern PCArch nsx20, generic, ncr3170; 15 16 PCArch *arch; 17 PCArch *knownarch[] = 18 { 19 &nsx20, 20 &ncr3170, 21 &generic, 22 }; 23 24 /* where b.com leaves configuration info */ 25 #define BOOTARGS ((char*)(KZERO|1024)) 26 #define BOOTARGSLEN 1024 27 #define MAXCONF 32 28 29 char bootdisk[NAMELEN]; 30 char *confname[MAXCONF]; 31 char *confval[MAXCONF]; 32 int nconf; 33 34 /* memory map */ 35 #define MAXMEG 64 36 char mmap[MAXMEG+2]; 37 38 void 39 main(void) 40 { 41 ident(); 42 i8042a20(); /* enable address lines 20 and up */ 43 machinit(); 44 active.exiting = 0; 45 active.machs = 1; 46 confinit(); 47 xinit(); 48 dmainit(); 49 screeninit(); 50 printinit(); 51 mmuinit(); 52 pageinit(); 53 trapinit(); 54 mathinit(); 55 clockinit(); 56 printcpufreq(); 57 faultinit(); 58 kbdinit(); 59 procinit0(); 60 initseg(); 61 streaminit(); 62 chandevreset(); 63 swapinit(); 64 userinit(); 65 schedinit(); 66 } 67 68 /* 69 * This tries to capture architecture dependencies since things 70 * like power management/reseting/mouse are outside the hardware 71 * model. 72 */ 73 void 74 ident(void) 75 { 76 char *id = (char*)(ROMBIOS + 0xFF40); 77 PCArch **p; 78 79 for(p = knownarch; *p != &generic; p++) 80 if(strncmp((*p)->id, id, strlen((*p)->id)) == 0) 81 break; 82 arch = *p; 83 } 84 85 void 86 machinit(void) 87 { 88 int n; 89 90 n = m->machno; 91 memset(m, 0, sizeof(Mach)); 92 m->machno = n; 93 m->mmask = 1<<m->machno; 94 } 95 96 ulong garbage; 97 98 void 99 init0(void) 100 { 101 int i; 102 char tstr[32]; 103 104 u->nerrlab = 0; 105 m->proc = u->p; 106 u->p->state = Running; 107 u->p->mach = m; 108 109 spllo(); 110 111 /* 112 * These are o.k. because rootinit is null. 113 * Then early kproc's will have a root and dot. 114 */ 115 u->slash = (*devtab[0].attach)(0); 116 u->dot = clone(u->slash, 0); 117 118 kproc("alarm", alarmkproc, 0); 119 chandevinit(); 120 121 if(!waserror()){ 122 strcpy(tstr, arch->id); 123 strcat(tstr, " %s"); 124 ksetterm(tstr); 125 ksetenv("cputype", "386"); 126 for(i = 0; i < nconf; i++) 127 if(confname[i]) 128 ksetenv(confname[i], confval[i]); 129 poperror(); 130 } 131 touser(sp); 132 } 133 134 void 135 userinit(void) 136 { 137 Proc *p; 138 Segment *s; 139 User *up; 140 KMap *k; 141 Page *pg; 142 143 p = newproc(); 144 p->pgrp = newpgrp(); 145 p->egrp = smalloc(sizeof(Egrp)); 146 p->egrp->ref = 1; 147 p->fgrp = smalloc(sizeof(Fgrp)); 148 p->fgrp->ref = 1; 149 p->procmode = 0640; 150 151 strcpy(p->text, "*init*"); 152 strcpy(p->user, eve); 153 p->fpstate = FPinit; 154 fpoff(); 155 156 /* 157 * Kernel Stack 158 * 159 * N.B. The -12 for the stack pointer is important. 160 * 4 bytes for gotolabel's return PC 161 */ 162 p->sched.pc = (ulong)init0; 163 p->sched.sp = USERADDR + BY2PG - 4; 164 p->upage = newpage(1, 0, USERADDR|(p->pid&0xFFFF)); 165 166 /* 167 * User 168 */ 169 k = kmap(p->upage); 170 up = (User*)VA(k); 171 up->p = p; 172 kunmap(k); 173 174 /* 175 * User Stack 176 */ 177 s = newseg(SG_STACK, USTKTOP-BY2PG, 1); 178 p->seg[SSEG] = s; 179 pg = newpage(1, 0, USTKTOP-BY2PG); 180 segpage(s, pg); 181 k = kmap(pg); 182 bootargs(VA(k)); 183 kunmap(k); 184 185 /* 186 * Text 187 */ 188 s = newseg(SG_TEXT, UTZERO, 1); 189 p->seg[TSEG] = s; 190 segpage(s, newpage(1, 0, UTZERO)); 191 k = kmap(s->map[0]->pages[0]); 192 memmove((ulong*)VA(k), initcode, sizeof initcode); 193 kunmap(k); 194 195 ready(p); 196 } 197 198 uchar * 199 pusharg(char *p) 200 { 201 int n; 202 203 n = strlen(p)+1; 204 sp -= n; 205 memmove(sp, p, n); 206 return sp; 207 } 208 209 void 210 bootargs(ulong base) 211 { 212 int i, ac; 213 uchar *av[32]; 214 uchar **lsp; 215 char *cp = BOOTLINE; 216 char buf[64]; 217 218 sp = (uchar*)base + BY2PG - MAXSYSARG*BY2WD; 219 220 ac = 0; 221 av[ac++] = pusharg("/386/9pc"); 222 cp[64] = 0; 223 buf[0] = 0; 224 225 /* 226 * decode the b.com bootline and convert to 227 * a disk device name to pass to the boot 228 */ 229 if(strncmp(cp, "fd!", 3) == 0){ 230 sprint(buf, "local!#f/fd%ddisk", atoi(cp+3)); 231 av[ac++] = pusharg(buf); 232 } else if(strncmp(cp, "h!", 2) == 0){ 233 sprint(buf, "local!#H/hd%dfs", atoi(cp+2)); 234 av[ac++] = pusharg(buf); 235 } else if(strncmp(cp, "hd!", 3) == 0){ 236 sprint(buf, "local!#H/hd%ddisk", atoi(cp+3)); 237 av[ac++] = pusharg(buf); 238 } else if(strncmp(cp, "s!", 2) == 0){ 239 sprint(buf, "local!#w%d/sd%dfs", atoi(cp+2), atoi(cp+2)); 240 av[ac++] = pusharg(buf); 241 } else if(strncmp(cp, "sd!", 3) == 0){ 242 sprint(buf, "local!#w%d/sd%ddisk", atoi(cp+3), atoi(cp+3)); 243 av[ac++] = pusharg(buf); 244 } else if(getconf("bootdisk") == 0){ 245 if(conf.nhard){ 246 sprint(buf, "local!#H/hd0disk"); 247 av[ac++] = pusharg(buf); 248 } else{ 249 sprint(buf, "local!#w/sd0disk"); 250 av[ac++] = pusharg(buf); 251 } 252 } 253 if(buf[0]){ 254 cp = strchr(buf, '!'); 255 if(cp){ 256 strcpy(bootdisk, cp+1); 257 addconf("bootdisk", bootdisk); 258 } 259 } 260 261 /* 4 byte word align stack */ 262 sp = (uchar*)((ulong)sp & ~3); 263 264 /* build argc, argv on stack */ 265 sp -= (ac+1)*sizeof(sp); 266 lsp = (uchar**)sp; 267 for(i = 0; i < ac; i++) 268 *lsp++ = av[i] + ((USTKTOP - BY2PG) - base); 269 *lsp = 0; 270 sp += (USTKTOP - BY2PG) - base - sizeof(ulong); 271 } 272 273 Conf conf; 274 275 void 276 addconf(char *name, char *val) 277 { 278 if(nconf >= MAXCONF) 279 return; 280 confname[nconf] = name; 281 confval[nconf] = val; 282 nconf++; 283 } 284 285 char* 286 getconf(char *name) 287 { 288 int i; 289 290 for(i = 0; i < nconf; i++) 291 if(strcmp(confname[i], name) == 0) 292 return confval[i]; 293 return 0; 294 } 295 296 /* 297 * look for unused address space in 0xC8000 to 1 meg 298 */ 299 void 300 romscan(void) 301 { 302 uchar *p; 303 304 p = (uchar*)(KZERO+0xC8000); 305 while(p < (uchar*)(KZERO+0xE0000)){ 306 p[0] = 0x55; 307 p[1] = 0xAA; 308 p[2] = 4; 309 if(p[0] != 0x55 || p[1] != 0xAA){ 310 putisa(PADDR(p), 2048); 311 p += 2048; 312 continue; 313 } 314 p += p[2]*512; 315 } 316 317 p = (uchar*)(KZERO+0xE0000); 318 if(p[0] != 0x55 || p[1] != 0xAA) 319 putisa(PADDR(p), 64*1024); 320 } 321 322 323 void 324 confinit(void) 325 { 326 long x, i, j, n; 327 int pcnt; 328 ulong ktop; 329 char *cp; 330 char *line[MAXCONF]; 331 332 pcnt = 0; 333 334 /* 335 * parse configuration args from dos file p9rc 336 */ 337 cp = BOOTARGS; /* where b.com leaves plan9.ini */ 338 cp[BOOTARGSLEN-1] = 0; 339 n = getfields(cp, line, MAXCONF, "\n"); 340 for(j = 0; j < n; j++){ 341 cp = strchr(line[j], '\r'); 342 if(cp) 343 *cp = 0; 344 cp = strchr(line[j], '='); 345 if(cp == 0) 346 continue; 347 *cp++ = 0; 348 if(cp - line[j] >= NAMELEN+1) 349 *(line[j]+NAMELEN-1) = 0; 350 confname[nconf] = line[j]; 351 confval[nconf] = cp; 352 if(strcmp(confname[nconf], "kernelpercent") == 0) 353 pcnt = 100 - atoi(confval[nconf]); 354 nconf++; 355 } 356 /* 357 * size memory above 1 meg. Kernel sits at 1 meg. We 358 * only recognize MB size chunks. 359 */ 360 memset(mmap, ' ', sizeof(mmap)); 361 x = 0x12345678; 362 for(i = 1; i <= MAXMEG; i++){ 363 /* 364 * write the first & last word in a megabyte of memory 365 */ 366 *mapaddr(KZERO|(i*MB)) = x; 367 *mapaddr(KZERO|((i+1)*MB-BY2WD)) = x; 368 369 /* 370 * write the first and last word in all previous megs to 371 * handle address wrap around 372 */ 373 for(j = 1; j < i; j++){ 374 *mapaddr(KZERO|(j*MB)) = ~x; 375 *mapaddr(KZERO|((j+1)*MB-BY2WD)) = ~x; 376 } 377 378 /* 379 * check for correct value 380 */ 381 if(*mapaddr(KZERO|(i*MB)) == x && *mapaddr(KZERO|((i+1)*MB-BY2WD)) == x){ 382 mmap[i] = 'x'; 383 /* 384 * zero memory to set ECC but skip over the kernel 385 */ 386 if(i != 1) 387 for(j = 0; j < MB/BY2PG; j += BY2PG) 388 memset(mapaddr(KZERO|(i*MB+j)), 0, BY2PG); 389 } 390 x += 0x3141526; 391 } 392 /* 393 * bank0 usually goes from the end of kernel bss to the end of memory 394 */ 395 ktop = PGROUND((ulong)end); 396 ktop = PADDR(ktop); 397 conf.base0 = ktop; 398 for(i = 1; mmap[i] == 'x'; i++) 399 ; 400 conf.npage0 = (i*MB - ktop)/BY2PG; 401 conf.topofmem = i*MB; 402 403 /* 404 * bank1 usually goes from the end of BOOTARGS to 640k 405 */ 406 conf.base1 = (ulong)(BOOTARGS+BOOTARGSLEN); 407 conf.base1 = PGROUND(conf.base1); 408 conf.base1 = PADDR(conf.base1); 409 conf.npage1 = (640*1024-conf.base1)/BY2PG; 410 411 /* 412 * if there is a hole in memory (due to a shadow BIOS) make the 413 * memory after the hole be bank 1. The memory from 0 to 640k 414 * is lost. 415 */ 416 for(; i <= MAXMEG; i++) 417 if(mmap[i] == 'x'){ 418 conf.base1 = i*MB; 419 for(j = i+1; mmap[j] == 'x'; j++) 420 ; 421 conf.npage1 = (j - i)*MB/BY2PG; 422 conf.topofmem = j*MB; 423 break; 424 } 425 426 /* 427 * add address space holes holes under 16 meg to available 428 * isa space. 429 */ 430 romscan(); 431 if(conf.topofmem < 16*MB) 432 putisa(conf.topofmem, 16*MB - conf.topofmem); 433 434 conf.npage = conf.npage0 + conf.npage1; 435 conf.ldepth = 0; 436 if(pcnt < 10) 437 pcnt = 70; 438 conf.upages = (conf.npage*pcnt)/100; 439 440 conf.nproc = 30 + ((conf.npage*BY2PG)/MB)*8; 441 conf.monitor = 1; 442 conf.nswap = conf.nproc*80; 443 conf.nimage = 50; 444 switch(x86()){ 445 case 3: 446 conf.copymode = 1; /* copy on reference */ 447 break; 448 default: 449 conf.copymode = 0; /* copy on write */ 450 break; 451 } 452 conf.nfloppy = 2; 453 conf.nhard = 2; 454 conf.nmach = 1; 455 } 456 457 char *mathmsg[] = 458 { 459 "invalid", 460 "denormalized", 461 "div-by-zero", 462 "overflow", 463 "underflow", 464 "precision", 465 "stack", 466 "error", 467 }; 468 469 /* 470 * math coprocessor error 471 */ 472 void 473 matherror(Ureg *ur, void *a) 474 { 475 ulong status; 476 int i; 477 char *msg; 478 char note[ERRLEN]; 479 480 USED(a); 481 482 /* 483 * a write cycle to port 0xF0 clears the interrupt latch attached 484 * to the error# line from the 387 485 */ 486 outb(0xF0, 0xFF); 487 488 /* 489 * save floating point state to check out error 490 */ 491 fpenv(&u->fpsave); 492 status = u->fpsave.status; 493 494 msg = 0; 495 for(i = 0; i < 8; i++) 496 if((1<<i) & status){ 497 msg = mathmsg[i]; 498 sprint(note, "sys: fp: %s fppc=0x%lux", msg, u->fpsave.pc); 499 postnote(u->p, 1, note, NDebug); 500 break; 501 } 502 if(msg == 0){ 503 sprint(note, "sys: fp: unknown fppc=0x%lux", u->fpsave.pc); 504 postnote(u->p, 1, note, NDebug); 505 } 506 if(ur->pc & KZERO) 507 panic("fp: status %lux fppc=0x%lux pc=0x%lux", status, 508 u->fpsave.pc, ur->pc); 509 } 510 511 /* 512 * math coprocessor emulation fault 513 */ 514 void 515 mathemu(Ureg *ur, void *a) 516 { 517 USED(ur, a); 518 519 switch(u->p->fpstate){ 520 case FPinit: 521 fpinit(); 522 u->p->fpstate = FPactive; 523 break; 524 case FPinactive: 525 fprestore(&u->fpsave); 526 u->p->fpstate = FPactive; 527 break; 528 case FPactive: 529 panic("math emu", 0); 530 break; 531 } 532 } 533 534 /* 535 * math coprocessor segment overrun 536 */ 537 void 538 mathover(Ureg *ur, void *a) 539 { 540 USED(ur, a); 541 542 print("sys: fp: math overrun pc 0x%lux pid %d\n", ur->pc, u->p->pid); 543 pexit("math overrun", 0); 544 } 545 546 void 547 mathinit(void) 548 { 549 setvec(Matherr1vec, matherror, 0); 550 setvec(Matherr2vec, matherror, 0); 551 setvec(Mathemuvec, mathemu, 0); 552 setvec(Mathovervec, mathover, 0); 553 } 554 555 /* 556 * set up floating point for a new process 557 */ 558 void 559 procsetup(Proc *p) 560 { 561 p->fpstate = FPinit; 562 fpoff(); 563 } 564 565 /* 566 * Save the mach dependent part of the process state. 567 */ 568 void 569 procsave(Proc *p) 570 { 571 if(p->fpstate == FPactive){ 572 if(p->state == Moribund) 573 fpoff(); 574 else 575 fpsave(&u->fpsave); 576 p->fpstate = FPinactive; 577 } 578 } 579 580 /* 581 * Restore what procsave() saves 582 */ 583 void 584 procrestore(Proc *p) 585 { 586 USED(p); 587 } 588 589 590 /* 591 * the following functions all are slightly different from 592 * PC to PC. 593 */ 594 595 /* 596 * reset the i387 chip 597 */ 598 void 599 exit(int ispanic) 600 { 601 u = 0; 602 wipekeys(); 603 print("exiting\n"); 604 if(ispanic){ 605 if(cpuserver) 606 delay(10000); 607 else 608 for(;;); 609 } 610 611 (*arch->reset)(); 612 } 613 614 /* 615 * set cpu speed 616 * 0 == low speed 617 * 1 == high speed 618 */ 619 int 620 cpuspeed(int speed) 621 { 622 if(arch->cpuspeed) 623 return (*arch->cpuspeed)(speed); 624 else 625 return 0; 626 } 627 628 /* 629 * f == frequency (Hz) 630 * d == duration (ms) 631 */ 632 void 633 buzz(int f, int d) 634 { 635 if(arch->buzz) 636 (*arch->buzz)(f, d); 637 } 638 639 /* 640 * each bit in val stands for a light 641 */ 642 void 643 lights(int val) 644 { 645 if(arch->lights) 646 (*arch->lights)(val); 647 } 648 649 /* 650 * power to serial port 651 * onoff == 1 means on 652 * onoff == 0 means off 653 */ 654 int 655 serial(int onoff) 656 { 657 if(arch->serialpower) 658 return (*arch->serialpower)(onoff); 659 else 660 return 0; 661 } 662 663 /* 664 * power to modem 665 * onoff == 1 means on 666 * onoff == 0 means off 667 */ 668 int 669 modem(int onoff) 670 { 671 if(arch->modempower) 672 return (*arch->modempower)(onoff); 673 else 674 return 0; 675 } 676 677 int 678 parseether(uchar *to, char *from) 679 { 680 char nip[4]; 681 char *p; 682 int i; 683 684 p = from; 685 while(*p == ' ') 686 ++p; 687 for(i = 0; i < 6; i++){ 688 if(*p == 0) 689 return -1; 690 nip[0] = *p++; 691 if(*p == 0) 692 return -1; 693 nip[1] = *p++; 694 nip[2] = 0; 695 to[i] = strtoul(nip, 0, 16); 696 if(*p == ':') 697 p++; 698 } 699 return 0; 700 } 701 702 int 703 isaconfig(char *class, int ctlrno, ISAConf *isa) 704 { 705 char cc[NAMELEN], *p, *q; 706 int n; 707 708 sprint(cc, "%s%d", class, ctlrno); 709 for(n = 0; n < nconf; n++){ 710 if(strncmp(confname[n], cc, NAMELEN)) 711 continue; 712 p = confval[n]; 713 while(*p){ 714 while(*p == ' ' || *p == '\t') 715 p++; 716 if(*p == '\0') 717 break; 718 if(strncmp(p, "type=", 5) == 0){ 719 p += 5; 720 for(q = isa->type; q < &isa->type[NAMELEN-1]; q++){ 721 if(*p == '\0' || *p == ' ' || *p == '\t') 722 break; 723 *q = *p++; 724 } 725 *q = '\0'; 726 } 727 else if(strncmp(p, "port=", 5) == 0) 728 isa->port = strtoul(p+5, &p, 0); 729 else if(strncmp(p, "irq=", 4) == 0) 730 isa->irq = strtoul(p+4, &p, 0); 731 else if(strncmp(p, "mem=", 4) == 0) 732 isa->mem = strtoul(p+4, &p, 0); 733 else if(strncmp(p, "size=", 5) == 0) 734 isa->size = strtoul(p+5, &p, 0); 735 else if(strncmp(p, "dma=", 4) == 0) 736 isa->dma = strtoul(p+4, &p, 0); 737 else if(strncmp(p, "ea=", 3) == 0){ 738 if(parseether(isa->ea, p+3) == -1) 739 memset(isa->ea, 0, 6); 740 } 741 while(*p && *p != ' ' && *p != '\t') 742 p++; 743 } 744 return 1; 745 } 746 return 0; 747 } 748 749 static void 750 pcfloppyintr(Ureg *ur, void *a) 751 { 752 USED(a); 753 754 floppyintr(ur); 755 } 756 757 void 758 floppysetup0(FController *fl) 759 { 760 USED(fl); 761 } 762 763 void 764 floppysetup1(FController *fl) 765 { 766 uchar equip; 767 768 /* 769 * read nvram for types of floppies 0 & 1 770 */ 771 equip = nvramread(0x10); 772 if(conf.nfloppy > 0){ 773 fl->d[0].dt = (equip >> 4) & 0xf; 774 floppysetdef(&fl->d[0]); 775 } 776 if(conf.nfloppy > 1){ 777 fl->d[1].dt = equip & 0xf; 778 floppysetdef(&fl->d[1]); 779 } 780 781 setvec(Floppyvec, pcfloppyintr, 0); 782 } 783 784 /* 785 * eject disk ( unknown on safari ) 786 */ 787 void 788 floppyeject(FDrive *dp) 789 { 790 floppyon(dp); 791 dp->vers++; 792 floppyoff(dp); 793 } 794 795 int 796 floppyexec(char *a, long b, int c) 797 { 798 USED(a, b, c); 799 return b; 800 } 801 802 int 803 cistrcmp(char *a, char *b) 804 { 805 int ac, bc; 806 807 for(;;){ 808 ac = *a++; 809 bc = *b++; 810 811 if(ac >= 'A' && ac <= 'Z') 812 ac = 'a' + (ac - 'A'); 813 if(bc >= 'A' && bc <= 'Z') 814 bc = 'a' + (bc - 'A'); 815 ac -= bc; 816 if(ac) 817 return ac; 818 if(bc == 0) 819 break; 820 } 821 return 0; 822 } 823