The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/pc/devarch.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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,   &regs[1], BY2WD); /* bx */
  735         memmove(m->cpuidid+4, &regs[3], BY2WD); /* dx */
  736         memmove(m->cpuidid+8, &regs[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         char buf[256];
  844         int n;
  845 
  846         n = snprint(buf, sizeof buf, "cpu %s %lud%s\n",
  847                 cputype->name, (ulong)(m->cpuhz+999999)/1000000,
  848                 m->havepge ? " pge" : "");
  849         n += snprint(buf+n, sizeof buf-n, "pge %s\n", getcr4()&0x80 ? "on" : "off");
  850         n += snprint(buf+n, sizeof buf-n, "coherence ");
  851         if(coherence == mb386)
  852                 n += snprint(buf+n, sizeof buf-n, "mb386\n");
  853         else if(coherence == mb586)
  854                 n += snprint(buf+n, sizeof buf-n, "mb586\n");
  855         else if(coherence == mfence)
  856                 n += snprint(buf+n, sizeof buf-n, "mfence\n");
  857         else if(coherence == nop)
  858                 n += snprint(buf+n, sizeof buf-n, "nop\n");
  859         else
  860                 n += snprint(buf+n, sizeof buf-n, "0x%p\n", coherence);
  861         n += snprint(buf+n, sizeof buf-n, "cmpswap ");
  862         if(cmpswap == cmpswap386)
  863                 n += snprint(buf+n, sizeof buf-n, "cmpswap386\n");
  864         else if(cmpswap == cmpswap486)
  865                 n += snprint(buf+n, sizeof buf-n, "cmpswap486\n");
  866         else
  867                 n += snprint(buf+n, sizeof buf-n, "0x%p\n", cmpswap);
  868         n += snprint(buf+n, sizeof buf-n, "i8253set %s\n", doi8253set ? "on" : "off");
  869         n += mtrrprint(buf+n, sizeof buf-n);
  870         buf[n] = 0;
  871         return readstr(offset, a, nn, buf);
  872 }
  873 
  874 enum
  875 {
  876         CMpge,
  877         CMcoherence,
  878         CMi8253set,
  879         CMcache,
  880 };
  881 
  882 static Cmdtab archctlmsg[] =
  883 {
  884         CMpge,          "pge",          2,
  885         CMcoherence,    "coherence",    2,
  886         CMi8253set,     "i8253set",     2,
  887         CMcache,                "cache",                4,
  888 };
  889 
  890 static long
  891 archctlwrite(Chan*, void *a, long n, vlong)
  892 {
  893         Cmdbuf *cb;
  894         Cmdtab *ct;
  895         uintptr base;
  896         ulong size;
  897         char *ep;
  898 
  899         cb = parsecmd(a, n);
  900         if(waserror()){
  901                 free(cb);
  902                 nexterror();
  903         }
  904         ct = lookupcmd(cb, archctlmsg, nelem(archctlmsg));
  905         switch(ct->index){
  906         case CMpge:
  907                 if(!m->havepge)
  908                         error("processor does not support pge");
  909                 if(strcmp(cb->f[1], "on") == 0)
  910                         putcr4(getcr4() | 0x80);
  911                 else if(strcmp(cb->f[1], "off") == 0)
  912                         putcr4(getcr4() & ~0x80);
  913                 else
  914                         cmderror(cb, "invalid pge ctl");
  915                 break;
  916         case CMcoherence:
  917                 if(strcmp(cb->f[1], "mb386") == 0)
  918                         coherence = mb386;
  919                 else if(strcmp(cb->f[1], "mb586") == 0){
  920                         if(X86FAMILY(m->cpuidax) < 5)
  921                                 error("invalid coherence ctl on this cpu family");
  922                         coherence = mb586;
  923                 }else if(strcmp(cb->f[1], "mfence") == 0){
  924                         if((m->cpuiddx & Sse2) == 0)
  925                                 error("invalid coherence ctl on this cpu family");
  926                         coherence = mfence;
  927                 }else if(strcmp(cb->f[1], "nop") == 0){
  928                         /* only safe on vmware */
  929                         if(conf.nmach > 1)
  930                                 error("cannot disable coherence on a multiprocessor");
  931                         coherence = nop;
  932                 }else
  933                         cmderror(cb, "invalid coherence ctl");
  934                 break;
  935         case CMi8253set:
  936                 if(strcmp(cb->f[1], "on") == 0)
  937                         doi8253set = 1;
  938                 else if(strcmp(cb->f[1], "off") == 0){
  939                         doi8253set = 0;
  940                         (*arch->timerset)(0);
  941                 }else
  942                         cmderror(cb, "invalid i2853set ctl");
  943                 break;
  944         case CMcache:
  945                 base = strtoul(cb->f[1], &ep, 0);
  946                 if(*ep)
  947                         error("cache: parse error: base not a number?");
  948                 size = strtoul(cb->f[2], &ep, 0);
  949                 if(*ep)
  950                         error("cache: parse error: size not a number?");
  951                 mtrr(base, size, cb->f[3]);
  952                 break;
  953         }
  954         free(cb);
  955         poperror();
  956         return n;
  957 }
  958 
  959 void
  960 archinit(void)
  961 {
  962         PCArch **p;
  963 
  964         arch = 0;
  965         for(p = knownarch; *p; p++){
  966                 if((*p)->ident && (*p)->ident() == 0){
  967                         arch = *p;
  968                         break;
  969                 }
  970         }
  971         if(arch == 0)
  972                 arch = &archgeneric;
  973         else{
  974                 if(arch->id == 0)
  975                         arch->id = archgeneric.id;
  976                 if(arch->reset == 0)
  977                         arch->reset = archgeneric.reset;
  978                 if(arch->serialpower == 0)
  979                         arch->serialpower = archgeneric.serialpower;
  980                 if(arch->modempower == 0)
  981                         arch->modempower = archgeneric.modempower;
  982                 if(arch->intrinit == 0)
  983                         arch->intrinit = archgeneric.intrinit;
  984                 if(arch->intrenable == 0)
  985                         arch->intrenable = archgeneric.intrenable;
  986         }
  987 
  988         /*
  989          *  Decide whether to use copy-on-reference (386 and mp).
  990          *  We get another chance to set it in mpinit() for a
  991          *  multiprocessor.
  992          */
  993         if(X86FAMILY(m->cpuidax) == 3)
  994                 conf.copymode = 1;
  995 
  996         if(X86FAMILY(m->cpuidax) >= 4)
  997                 cmpswap = cmpswap486;
  998 
  999         if(X86FAMILY(m->cpuidax) >= 5)
 1000                 coherence = mb586;
 1001 
 1002         if(m->cpuiddx & Sse2)
 1003                 coherence = mfence;
 1004 
 1005         addarchfile("cputype", 0444, cputyperead, nil);
 1006         addarchfile("archctl", 0664, archctlread, archctlwrite);
 1007 }
 1008 
 1009 /*
 1010  *  call either the pcmcia or pccard device setup
 1011  */
 1012 int
 1013 pcmspecial(char *idstr, ISAConf *isa)
 1014 {
 1015         return (_pcmspecial != nil)? _pcmspecial(idstr, isa): -1;
 1016 }
 1017 
 1018 /*
 1019  *  call either the pcmcia or pccard device teardown
 1020  */
 1021 void
 1022 pcmspecialclose(int a)
 1023 {
 1024         if (_pcmspecialclose != nil)
 1025                 _pcmspecialclose(a);
 1026 }
 1027 
 1028 /*
 1029  *  return value and speed of timer set in arch->clockenable
 1030  */
 1031 uvlong
 1032 fastticks(uvlong *hz)
 1033 {
 1034         return (*arch->fastclock)(hz);
 1035 }
 1036 
 1037 ulong
 1038 ยตs(void)
 1039 {
 1040         return fastticks2us((*arch->fastclock)(nil));
 1041 }
 1042 
 1043 /*
 1044  *  set next timer interrupt
 1045  */
 1046 void
 1047 timerset(Tval x)
 1048 {
 1049         if(doi8253set)
 1050                 (*arch->timerset)(x);
 1051 }

Cache object: 591a62aa571f284887a97a5ee9429d2f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.