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 "../port/error.h" 9 10 typedef struct IOMap IOMap; 11 struct IOMap 12 { 13 IOMap *next; 14 int reserved; 15 char tag[13]; 16 ulong start; 17 ulong end; 18 }; 19 20 static struct 21 { 22 Lock; 23 IOMap *m; 24 IOMap *free; 25 IOMap maps[32]; // some initial free maps 26 27 QLock ql; // lock for reading map 28 } iomap; 29 30 enum { 31 Qdir = 0, 32 Qioalloc = 1, 33 Qiob, 34 Qiow, 35 Qiol, 36 Qbase, 37 38 Qmax = 16, 39 }; 40 41 typedef long Rdwrfn(Chan*, void*, long, vlong); 42 43 static Rdwrfn *readfn[Qmax]; 44 static Rdwrfn *writefn[Qmax]; 45 46 static Dirtab archdir[Qmax] = { 47 ".", { Qdir, 0, QTDIR }, 0, 0555, 48 "ioalloc", { Qioalloc, 0 }, 0, 0444, 49 "iob", { Qiob, 0 }, 0, 0660, 50 "iow", { Qiow, 0 }, 0, 0660, 51 "iol", { Qiol, 0 }, 0, 0660, 52 }; 53 Lock archwlock; /* the lock is only for changing archdir */ 54 int narchdir = Qbase; 55 int (*_pcmspecial)(char*, ISAConf*); 56 void (*_pcmspecialclose)(int); 57 58 static int doi8253set = 1; 59 60 /* 61 * Add a file to the #P listing. Once added, you can't delete it. 62 * You can't add a file with the same name as one already there, 63 * and you get a pointer to the Dirtab entry so you can do things 64 * like change the Qid version. Changing the Qid path is disallowed. 65 */ 66 Dirtab* 67 addarchfile(char *name, int perm, Rdwrfn *rdfn, Rdwrfn *wrfn) 68 { 69 int i; 70 Dirtab d; 71 Dirtab *dp; 72 73 memset(&d, 0, sizeof d); 74 strcpy(d.name, name); 75 d.perm = perm; 76 77 lock(&archwlock); 78 if(narchdir >= Qmax){ 79 unlock(&archwlock); 80 return nil; 81 } 82 83 for(i=0; i<narchdir; i++) 84 if(strcmp(archdir[i].name, name) == 0){ 85 unlock(&archwlock); 86 return nil; 87 } 88 89 d.qid.path = narchdir; 90 archdir[narchdir] = d; 91 readfn[narchdir] = rdfn; 92 writefn[narchdir] = wrfn; 93 dp = &archdir[narchdir++]; 94 unlock(&archwlock); 95 96 return dp; 97 } 98 99 void 100 ioinit(void) 101 { 102 char *excluded; 103 int i; 104 105 for(i = 0; i < nelem(iomap.maps)-1; i++) 106 iomap.maps[i].next = &iomap.maps[i+1]; 107 iomap.maps[i].next = nil; 108 iomap.free = iomap.maps; 109 110 /* 111 * This is necessary to make the IBM X20 boot. 112 * Have not tracked down the reason. 113 */ 114 ioalloc(0x0fff, 1, 0, "dummy"); // i82557 is at 0x1000, the dummy 115 // entry is needed for swappable devs. 116 117 if ((excluded = getconf("ioexclude")) != nil) { 118 char *s; 119 120 s = excluded; 121 while (s && *s != '\0' && *s != '\n') { 122 char *ends; 123 int io_s, io_e; 124 125 io_s = (int)strtol(s, &ends, 0); 126 if (ends == nil || ends == s || *ends != '-') { 127 print("ioinit: cannot parse option string\n"); 128 break; 129 } 130 s = ++ends; 131 132 io_e = (int)strtol(s, &ends, 0); 133 if (ends && *ends == ',') 134 *ends++ = '\0'; 135 s = ends; 136 137 ioalloc(io_s, io_e - io_s + 1, 0, "pre-allocated"); 138 } 139 } 140 141 } 142 143 // Reserve a range to be ioalloced later. 144 // This is in particular useful for exchangable cards, such 145 // as pcmcia and cardbus cards. 146 int 147 ioreserve(int port, int size, int align, char *tag) 148 { 149 IOMap *m, **l; 150 int i; 151 152 lock(&iomap); 153 // find a free port above 0x400 and below 0x1000 154 port = 0x400; 155 for(l = &iomap.m; *l; l = &(*l)->next){ 156 m = *l; 157 if (m->start < 0x400) continue; 158 i = m->start - port; 159 if(i > size) 160 break; 161 if(align > 0) 162 port = ((port+align-1)/align)*align; 163 else 164 port = m->end; 165 } 166 if(*l == nil){ 167 unlock(&iomap); 168 return -1; 169 } 170 m = iomap.free; 171 if(m == nil){ 172 print("ioalloc: out of maps"); 173 unlock(&iomap); 174 return port; 175 } 176 iomap.free = m->next; 177 m->next = *l; 178 m->start = port; 179 m->end = port + size; 180 m->reserved = 1; 181 strncpy(m->tag, tag, sizeof(m->tag)); 182 m->tag[sizeof(m->tag)-1] = 0; 183 *l = m; 184 185 archdir[0].qid.vers++; 186 187 unlock(&iomap); 188 return m->start; 189 } 190 191 // 192 // alloc some io port space and remember who it was 193 // alloced to. if port < 0, find a free region. 194 // 195 int 196 ioalloc(int port, int size, int align, char *tag) 197 { 198 IOMap *m, **l; 199 int i; 200 201 lock(&iomap); 202 if(port < 0){ 203 // find a free port above 0x400 and below 0x1000 204 port = 0x400; 205 for(l = &iomap.m; *l; l = &(*l)->next){ 206 m = *l; 207 if (m->start < 0x400) continue; 208 i = m->start - port; 209 if(i > size) 210 break; 211 if(align > 0) 212 port = ((port+align-1)/align)*align; 213 else 214 port = m->end; 215 } 216 if(*l == nil){ 217 unlock(&iomap); 218 return -1; 219 } 220 } else { 221 // Only 64KB I/O space on the x86. 222 if((port+size) > 0x10000){ 223 unlock(&iomap); 224 return -1; 225 } 226 // see if the space clashes with previously allocated ports 227 for(l = &iomap.m; *l; l = &(*l)->next){ 228 m = *l; 229 if(m->end <= port) 230 continue; 231 if(m->reserved && m->start == port && m->end == port + size) { 232 m->reserved = 0; 233 unlock(&iomap); 234 return m->start; 235 } 236 if(m->start >= port+size) 237 break; 238 unlock(&iomap); 239 return -1; 240 } 241 } 242 m = iomap.free; 243 if(m == nil){ 244 print("ioalloc: out of maps"); 245 unlock(&iomap); 246 return port; 247 } 248 iomap.free = m->next; 249 m->next = *l; 250 m->start = port; 251 m->end = port + size; 252 strncpy(m->tag, tag, sizeof(m->tag)); 253 m->tag[sizeof(m->tag)-1] = 0; 254 *l = m; 255 256 archdir[0].qid.vers++; 257 258 unlock(&iomap); 259 return m->start; 260 } 261 262 void 263 iofree(int port) 264 { 265 IOMap *m, **l; 266 267 lock(&iomap); 268 for(l = &iomap.m; *l; l = &(*l)->next){ 269 if((*l)->start == port){ 270 m = *l; 271 *l = m->next; 272 m->next = iomap.free; 273 iomap.free = m; 274 break; 275 } 276 if((*l)->start > port) 277 break; 278 } 279 archdir[0].qid.vers++; 280 unlock(&iomap); 281 } 282 283 int 284 iounused(int start, int end) 285 { 286 IOMap *m; 287 288 for(m = iomap.m; m; m = m->next){ 289 if(start >= m->start && start < m->end 290 || start <= m->start && end > m->start) 291 return 0; 292 } 293 return 1; 294 } 295 296 static void 297 checkport(int start, int end) 298 { 299 /* standard vga regs are OK */ 300 if(start >= 0x2b0 && end <= 0x2df+1) 301 return; 302 if(start >= 0x3c0 && end <= 0x3da+1) 303 return; 304 305 if(iounused(start, end)) 306 return; 307 error(Eperm); 308 } 309 310 static Chan* 311 archattach(char* spec) 312 { 313 return devattach('P', spec); 314 } 315 316 Walkqid* 317 archwalk(Chan* c, Chan *nc, char** name, int nname) 318 { 319 return devwalk(c, nc, name, nname, archdir, narchdir, devgen); 320 } 321 322 static int 323 archstat(Chan* c, uchar* dp, int n) 324 { 325 return devstat(c, dp, n, archdir, narchdir, devgen); 326 } 327 328 static Chan* 329 archopen(Chan* c, int omode) 330 { 331 return devopen(c, omode, archdir, narchdir, devgen); 332 } 333 334 static void 335 archclose(Chan*) 336 { 337 } 338 339 enum 340 { 341 Linelen= 31, 342 }; 343 344 static long 345 archread(Chan *c, void *a, long n, vlong offset) 346 { 347 char *buf, *p; 348 int port; 349 ushort *sp; 350 ulong *lp; 351 IOMap *m; 352 Rdwrfn *fn; 353 354 switch((ulong)c->qid.path){ 355 356 case Qdir: 357 return devdirread(c, a, n, archdir, narchdir, devgen); 358 359 case Qiob: 360 port = offset; 361 checkport(offset, offset+n); 362 for(p = a; port < offset+n; port++) 363 *p++ = inb(port); 364 return n; 365 366 case Qiow: 367 if(n & 1) 368 error(Ebadarg); 369 checkport(offset, offset+n); 370 sp = a; 371 for(port = offset; port < offset+n; port += 2) 372 *sp++ = ins(port); 373 return n; 374 375 case Qiol: 376 if(n & 3) 377 error(Ebadarg); 378 checkport(offset, offset+n); 379 lp = a; 380 for(port = offset; port < offset+n; port += 4) 381 *lp++ = inl(port); 382 return n; 383 384 case Qioalloc: 385 break; 386 387 default: 388 if(c->qid.path < narchdir && (fn = readfn[c->qid.path])) 389 return fn(c, a, n, offset); 390 error(Eperm); 391 break; 392 } 393 394 if((buf = malloc(n)) == nil) 395 error(Enomem); 396 p = buf; 397 n = n/Linelen; 398 offset = offset/Linelen; 399 400 lock(&iomap); 401 for(m = iomap.m; n > 0 && m != nil; m = m->next){ 402 if(offset-- > 0) 403 continue; 404 sprint(p, "%8lux %8lux %-12.12s\n", m->start, m->end-1, m->tag); 405 p += Linelen; 406 n--; 407 } 408 unlock(&iomap); 409 410 n = p - buf; 411 memmove(a, buf, n); 412 free(buf); 413 414 return n; 415 } 416 417 static long 418 archwrite(Chan *c, void *a, long n, vlong offset) 419 { 420 char *p; 421 int port; 422 ushort *sp; 423 ulong *lp; 424 Rdwrfn *fn; 425 426 switch((ulong)c->qid.path){ 427 428 case Qiob: 429 p = a; 430 checkport(offset, offset+n); 431 for(port = offset; port < offset+n; port++) 432 outb(port, *p++); 433 return n; 434 435 case Qiow: 436 if(n & 1) 437 error(Ebadarg); 438 checkport(offset, offset+n); 439 sp = a; 440 for(port = offset; port < offset+n; port += 2) 441 outs(port, *sp++); 442 return n; 443 444 case Qiol: 445 if(n & 3) 446 error(Ebadarg); 447 checkport(offset, offset+n); 448 lp = a; 449 for(port = offset; port < offset+n; port += 4) 450 outl(port, *lp++); 451 return n; 452 453 default: 454 if(c->qid.path < narchdir && (fn = writefn[c->qid.path])) 455 return fn(c, a, n, offset); 456 error(Eperm); 457 break; 458 } 459 return 0; 460 } 461 462 Dev archdevtab = { 463 'P', 464 "arch", 465 466 devreset, 467 devinit, 468 devshutdown, 469 archattach, 470 archwalk, 471 archstat, 472 archopen, 473 devcreate, 474 archclose, 475 archread, 476 devbread, 477 archwrite, 478 devbwrite, 479 devremove, 480 devwstat, 481 }; 482 483 /* 484 * the following is a generic version of the 485 * architecture specific stuff 486 */ 487 488 static int 489 unimplemented(int) 490 { 491 return 0; 492 } 493 494 static void 495 nop(void) 496 { 497 } 498 499 /* 500 * On a uniprocessor, you'd think that coherence could be nop, 501 * but it can't. We still need a barrier when using coherence() in 502 * device drivers. 503 * 504 * On VMware, it's safe (and a huge win) to set this to nop. 505 * Aux/vmware does this via the #P/archctl file. 506 */ 507 void (*coherence)(void) = nop; 508 509 PCArch* arch; 510 extern PCArch* knownarch[]; 511 512 PCArch archgeneric = { 513 .id= "generic", 514 .ident= 0, 515 .reset= i8042reset, 516 .serialpower= unimplemented, 517 .modempower= unimplemented, 518 519 .intrinit= i8259init, 520 .intrenable= i8259enable, 521 .intrvecno= i8259vecno, 522 .intrdisable= i8259disable, 523 524 .clockenable= i8253enable, 525 .fastclock= i8253read, 526 .timerset= i8253timerset, 527 }; 528 529 typedef struct X86type X86type; 530 struct X86type { 531 int family; 532 int model; 533 int aalcycles; 534 char* name; 535 }; 536 537 static X86type x86intel[] = 538 { 539 { 4, 0, 22, "486DX", }, /* known chips */ 540 { 4, 1, 22, "486DX50", }, 541 { 4, 2, 22, "486SX", }, 542 { 4, 3, 22, "486DX2", }, 543 { 4, 4, 22, "486SL", }, 544 { 4, 5, 22, "486SX2", }, 545 { 4, 7, 22, "DX2WB", }, /* P24D */ 546 { 4, 8, 22, "DX4", }, /* P24C */ 547 { 4, 9, 22, "DX4WB", }, /* P24CT */ 548 { 5, 0, 23, "P5", }, 549 { 5, 1, 23, "P5", }, 550 { 5, 2, 23, "P54C", }, 551 { 5, 3, 23, "P24T", }, 552 { 5, 4, 23, "P55C MMX", }, 553 { 5, 7, 23, "P54C VRT", }, 554 { 6, 1, 16, "PentiumPro", },/* trial and error */ 555 { 6, 3, 16, "PentiumII", }, 556 { 6, 5, 16, "PentiumII/Xeon", }, 557 { 6, 6, 16, "Celeron", }, 558 { 6, 7, 16, "PentiumIII/Xeon", }, 559 { 6, 8, 16, "PentiumIII/Xeon", }, 560 { 6, 0xB, 16, "PentiumIII/Xeon", }, 561 { 0xF, 1, 16, "P4", }, /* P4 */ 562 { 0xF, 2, 16, "PentiumIV/Xeon", }, 563 564 { 3, -1, 32, "386", }, /* family defaults */ 565 { 4, -1, 22, "486", }, 566 { 5, -1, 23, "P5", }, 567 { 6, -1, 16, "P6", }, 568 { 0xF, -1, 16, "P4", }, /* P4 */ 569 570 { -1, -1, 16, "unknown", }, /* total default */ 571 }; 572 573 /* 574 * The AMD processors all implement the CPUID instruction. 575 * The later ones also return the processor name via functions 576 * 0x80000002, 0x80000003 and 0x80000004 in registers AX, BX, CX 577 * and DX: 578 * K5 "AMD-K5(tm) Processor" 579 * K6 "AMD-K6tm w/ multimedia extensions" 580 * K6 3D "AMD-K6(tm) 3D processor" 581 * K6 3D+ ? 582 */ 583 static X86type x86amd[] = 584 { 585 { 5, 0, 23, "AMD-K5", }, /* guesswork */ 586 { 5, 1, 23, "AMD-K5", }, /* guesswork */ 587 { 5, 2, 23, "AMD-K5", }, /* guesswork */ 588 { 5, 3, 23, "AMD-K5", }, /* guesswork */ 589 { 5, 6, 11, "AMD-K6", }, /* trial and error */ 590 { 5, 7, 11, "AMD-K6", }, /* trial and error */ 591 { 5, 8, 11, "AMD-K6-2", }, /* trial and error */ 592 { 5, 9, 11, "AMD-K6-III", },/* trial and error */ 593 594 { 6, 1, 11, "AMD-Athlon", },/* trial and error */ 595 { 6, 2, 11, "AMD-Athlon", },/* trial and error */ 596 597 { 4, -1, 22, "Am486", }, /* guesswork */ 598 { 5, -1, 23, "AMD-K5/K6", }, /* guesswork */ 599 { 6, -1, 11, "AMD-Athlon", },/* guesswork */ 600 { 0xF, -1, 11, "AMD64", }, /* guesswork */ 601 602 { -1, -1, 11, "unknown", }, /* total default */ 603 }; 604 605 /* 606 * WinChip 240MHz 607 */ 608 static X86type x86winchip[] = 609 { 610 {5, 4, 23, "Winchip",}, /* guesswork */ 611 {6, 7, 23, "Via C3 Samuel 2 or Ezra",}, 612 {6, 8, 23, "Via C3 Ezra-T",}, 613 { -1, -1, 23, "unknown", }, /* total default */ 614 }; 615 616 /* 617 * SiS 55x 618 */ 619 static X86type x86sis[] = 620 { 621 {5, 0, 23, "SiS 55x",}, /* guesswork */ 622 { -1, -1, 23, "unknown", }, /* total default */ 623 }; 624 625 static X86type *cputype; 626 627 static void simplecycles(uvlong*); 628 void (*cycles)(uvlong*) = simplecycles; 629 void _cycles(uvlong*); /* in l.s */ 630 631 static void 632 simplecycles(uvlong*x) 633 { 634 *x = m->ticks; 635 } 636 637 void 638 cpuidprint(void) 639 { 640 int i; 641 char buf[128]; 642 643 i = sprint(buf, "cpu%d: %dMHz ", m->machno, m->cpumhz); 644 if(m->cpuidid[0]) 645 i += sprint(buf+i, "%12.12s ", m->cpuidid); 646 sprint(buf+i, "%s (cpuid: AX 0x%4.4uX DX 0x%4.4uX)\n", 647 m->cpuidtype, m->cpuidax, m->cpuiddx); 648 print(buf); 649 } 650 651 /* 652 * figure out: 653 * - cpu type 654 * - whether or not we have a TSC (cycle counter) 655 * - whether or not it supports page size extensions 656 * (if so turn it on) 657 * - whether or not it supports machine check exceptions 658 * (if so turn it on) 659 * - whether or not it supports the page global flag 660 * (if so turn it on) 661 */ 662 int 663 cpuidentify(void) 664 { 665 char *p; 666 int family, model, nomce; 667 X86type *t, *tab; 668 ulong cr4; 669 vlong mca, mct; 670 671 cpuid(m->cpuidid, &m->cpuidax, &m->cpuiddx); 672 if(strncmp(m->cpuidid, "AuthenticAMD", 12) == 0) 673 tab = x86amd; 674 else if(strncmp(m->cpuidid, "CentaurHauls", 12) == 0) 675 tab = x86winchip; 676 else if(strncmp(m->cpuidid, "SiS SiS SiS ", 12) == 0) 677 tab = x86sis; 678 else 679 tab = x86intel; 680 681 family = X86FAMILY(m->cpuidax); 682 model = X86MODEL(m->cpuidax); 683 for(t=tab; t->name; t++) 684 if((t->family == family && t->model == model) 685 || (t->family == family && t->model == -1) 686 || (t->family == -1)) 687 break; 688 689 m->cpuidtype = t->name; 690 691 /* 692 * if there is one, set tsc to a known value 693 */ 694 if(m->cpuiddx & 0x10){ 695 m->havetsc = 1; 696 cycles = _cycles; 697 if(m->cpuiddx & 0x20) 698 wrmsr(0x10, 0); 699 } 700 701 /* 702 * use i8253 to guess our cpu speed 703 */ 704 guesscpuhz(t->aalcycles); 705 706 /* 707 * If machine check exception, page size extensions or page global bit 708 * are supported enable them in CR4 and clear any other set extensions. 709 * If machine check was enabled clear out any lingering status. 710 */ 711 if(m->cpuiddx & 0x2088){ 712 cr4 = 0; 713 if(m->cpuiddx & 0x08) 714 cr4 |= 0x10; /* page size extensions */ 715 if(p = getconf("*nomce")) 716 nomce = strtoul(p, 0, 0); 717 else 718 nomce = 0; 719 if((m->cpuiddx & 0x80) && !nomce){ 720 cr4 |= 0x40; /* machine check enable */ 721 if(family == 5){ 722 rdmsr(0x00, &mca); 723 rdmsr(0x01, &mct); 724 } 725 } 726 727 /* 728 * Detect whether the chip supports the global bit 729 * in page directory and page table entries. When set 730 * in a particular entry, it means ``don't bother removing 731 * this from the TLB when CR3 changes.'' 732 * 733 * We flag all kernel pages with this bit. Doing so lessens the 734 * overhead of switching processes on bare hardware, 735 * even more so on VMware. See mmu.c:/^memglobal. 736 * 737 * For future reference, should we ever need to do a 738 * full TLB flush, it can be accomplished by clearing 739 * the PGE bit in CR4, writing to CR3, and then 740 * restoring the PGE bit. 741 */ 742 if(m->cpuiddx & 0x2000){ 743 cr4 |= 0x80; /* page global enable bit */ 744 m->havepge = 1; 745 } 746 747 putcr4(cr4); 748 if(m->cpuiddx & 0x80) 749 rdmsr(0x01, &mct); 750 } 751 752 cputype = t; 753 return t->family; 754 } 755 756 static long 757 cputyperead(Chan*, void *a, long n, vlong offset) 758 { 759 char str[32]; 760 ulong mhz; 761 762 mhz = (m->cpuhz+999999)/1000000; 763 764 snprint(str, sizeof(str), "%s %lud\n", cputype->name, mhz); 765 return readstr(offset, a, n, str); 766 } 767 768 static long 769 archctlread(Chan*, void *a, long nn, vlong offset) 770 { 771 char buf[256]; 772 int n; 773 774 n = snprint(buf, sizeof buf, "cpu %s %lud%s\n", 775 cputype->name, (ulong)(m->cpuhz+999999)/1000000, 776 m->havepge ? " pge" : ""); 777 n += snprint(buf+n, sizeof buf-n, "pge %s\n", getcr4()&0x80 ? "on" : "off"); 778 n += snprint(buf+n, sizeof buf-n, "coherence "); 779 if(coherence == mb386) 780 n += snprint(buf+n, sizeof buf-n, "mb386\n"); 781 else if(coherence == mb586) 782 n += snprint(buf+n, sizeof buf-n, "mb586\n"); 783 else if(coherence == nop) 784 n += snprint(buf+n, sizeof buf-n, "nop\n"); 785 else 786 n += snprint(buf+n, sizeof buf-n, "0x%p\n", coherence); 787 n += snprint(buf+n, sizeof buf-n, "i8253set %s\n", doi8253set ? "on" : "off"); 788 buf[n] = 0; 789 return readstr(offset, a, nn, buf); 790 } 791 792 enum 793 { 794 CMpge, 795 CMcoherence, 796 CMi8253set, 797 }; 798 799 static Cmdtab archctlmsg[] = 800 { 801 CMpge, "pge", 2, 802 CMcoherence, "coherence", 2, 803 CMi8253set, "i8253set", 2, 804 }; 805 806 static long 807 archctlwrite(Chan*, void *a, long n, vlong) 808 { 809 Cmdbuf *cb; 810 Cmdtab *ct; 811 812 cb = parsecmd(a, n); 813 if(waserror()){ 814 free(cb); 815 nexterror(); 816 } 817 ct = lookupcmd(cb, archctlmsg, nelem(archctlmsg)); 818 switch(ct->index){ 819 case CMpge: 820 if(!m->havepge) 821 error("processor does not support pge"); 822 if(strcmp(cb->f[1], "on") == 0) 823 putcr4(getcr4() | 0x80); 824 else if(strcmp(cb->f[1], "off") == 0) 825 putcr4(getcr4() & ~0x80); 826 else 827 cmderror(cb, "invalid pge ctl"); 828 break; 829 case CMcoherence: 830 if(strcmp(cb->f[1], "mb386") == 0) 831 coherence = mb386; 832 else if(strcmp(cb->f[1], "mb586") == 0){ 833 if(X86FAMILY(m->cpuidax) < 5) 834 error("invalid coherence ctl on this cpu family"); 835 coherence = mb586; 836 } 837 else if(strcmp(cb->f[1], "nop") == 0){ 838 /* only safe on vmware */ 839 if(conf.nmach > 1) 840 error("cannot disable coherence on a multiprocessor"); 841 coherence = nop; 842 }else 843 cmderror(cb, "invalid coherence ctl"); 844 break; 845 case CMi8253set: 846 if(strcmp(cb->f[1], "on") == 0) 847 doi8253set = 1; 848 else if(strcmp(cb->f[1], "off") == 0){ 849 doi8253set = 0; 850 (*arch->timerset)(0); 851 }else 852 cmderror(cb, "invalid i2853set ctl"); 853 break; 854 } 855 free(cb); 856 poperror(); 857 return n; 858 } 859 860 void 861 archinit(void) 862 { 863 PCArch **p; 864 865 arch = 0; 866 for(p = knownarch; *p; p++){ 867 if((*p)->ident && (*p)->ident() == 0){ 868 arch = *p; 869 break; 870 } 871 } 872 if(arch == 0) 873 arch = &archgeneric; 874 else{ 875 if(arch->id == 0) 876 arch->id = archgeneric.id; 877 if(arch->reset == 0) 878 arch->reset = archgeneric.reset; 879 if(arch->serialpower == 0) 880 arch->serialpower = archgeneric.serialpower; 881 if(arch->modempower == 0) 882 arch->modempower = archgeneric.modempower; 883 if(arch->intrinit == 0) 884 arch->intrinit = archgeneric.intrinit; 885 if(arch->intrenable == 0) 886 arch->intrenable = archgeneric.intrenable; 887 } 888 889 /* 890 * Decide whether to use copy-on-reference (386 and mp). 891 * We get another chance to set it in mpinit() for a 892 * multiprocessor. 893 */ 894 if(X86FAMILY(m->cpuidax) == 3) 895 conf.copymode = 1; 896 897 if(X86FAMILY(m->cpuidax) >= 5) 898 coherence = mb586; 899 900 addarchfile("cputype", 0444, cputyperead, nil); 901 addarchfile("archctl", 0664, archctlread, archctlwrite); 902 } 903 904 /* 905 * call either the pcmcia or pccard device setup 906 */ 907 int 908 pcmspecial(char *idstr, ISAConf *isa) 909 { 910 return (_pcmspecial != nil)? _pcmspecial(idstr, isa): -1; 911 } 912 913 /* 914 * call either the pcmcia or pccard device teardown 915 */ 916 void 917 pcmspecialclose(int a) 918 { 919 if (_pcmspecialclose != nil) 920 _pcmspecialclose(a); 921 } 922 923 /* 924 * return value and speed of timer set in arch->clockenable 925 */ 926 uvlong 927 fastticks(uvlong *hz) 928 { 929 return (*arch->fastclock)(hz); 930 } 931 932 /* 933 * set next timer interrupt 934 */ 935 void 936 timerset(uvlong x) 937 { 938 if(doi8253set) 939 (*arch->timerset)(x); 940 } 941