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