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/i386/i386/identcpu.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 /*
    2  * Copyright (c) 1992 Terrence R. Lambert.
    3  * Copyright (c) 1982, 1987, 1990 The Regents of the University of California.
    4  * Copyright (c) 1997 KATO Takenori.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to Berkeley by
    8  * William Jolitz.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *      This product includes software developed by the University of
   21  *      California, Berkeley and its contributors.
   22  * 4. Neither the name of the University nor the names of its contributors
   23  *    may be used to endorse or promote products derived from this software
   24  *    without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   36  * SUCH DAMAGE.
   37  *
   38  *      from: Id: machdep.c,v 1.193 1996/06/18 01:22:04 bde Exp
   39  * $FreeBSD: src/sys/i386/i386/identcpu.c,v 1.7.2.19 1999/09/05 08:11:07 peter Exp $
   40  */
   41 
   42 #include "opt_cpu.h"
   43 
   44 #include <sys/param.h>
   45 #include <sys/systm.h>
   46 #include <sys/kernel.h>
   47 #include <sys/sysctl.h>
   48 
   49 #include <machine/asmacros.h>
   50 #include <machine/cpu.h>
   51 #include <machine/clock.h>
   52 #include <machine/cputypes.h>
   53 #include <machine/segments.h>
   54 #include <machine/specialreg.h>
   55 #include <machine/md_var.h>
   56 
   57 #include <i386/isa/isa_device.h>
   58 
   59 #define IDENTBLUE_CYRIX486      0
   60 #define IDENTBLUE_IBMCPU        1
   61 #define IDENTBLUE_CYRIXM2       2
   62 
   63 /* XXX - should be in header file */
   64 void    i486_bzero __P((void *buf, size_t len));
   65 
   66 void printcpuinfo(void);        /* XXX should be in different header file */
   67 void finishidentcpu(void);
   68 void earlysetcpuclass(void);
   69 void panicifcpuunsupported(void);
   70 static void identifycyrix(void);
   71 static void print_AMD_info(void);
   72 static void print_AMD_assoc(int i);
   73 static void do_cpuid(u_long ax, u_long *p);
   74 
   75 u_long  cyrix_did;              /* Device ID of Cyrix CPU */
   76 int cpu_class = CPUCLASS_386;   /* least common denominator */
   77 char machine[] = "i386";
   78 SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, "");
   79 
   80 static char cpu_model[128];
   81 SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, cpu_model, 0, "");
   82 
   83 static struct cpu_nameclass i386_cpus[] = {
   84         { "Intel 80286",        CPUCLASS_286 },         /* CPU_286   */
   85         { "i386SX",             CPUCLASS_386 },         /* CPU_386SX */
   86         { "i386DX",             CPUCLASS_386 },         /* CPU_386   */
   87         { "i486SX",             CPUCLASS_486 },         /* CPU_486SX */
   88         { "i486DX",             CPUCLASS_486 },         /* CPU_486   */
   89         { "Pentium",            CPUCLASS_586 },         /* CPU_586   */
   90         { "Cyrix 486",          CPUCLASS_486 },         /* CPU_486DLC */
   91         { "Pentium Pro",        CPUCLASS_686 },         /* CPU_686 */
   92         { "Cyrix 5x86",         CPUCLASS_486 },         /* CPU_M1SC */
   93         { "Cyrix 6x86",         CPUCLASS_486 },         /* CPU_M1 */
   94         { "Blue Lightning",     CPUCLASS_486 },         /* CPU_BLUE */
   95         { "Cyrix 6x86MX",       CPUCLASS_686 },         /* CPU_M2 */
   96         { "NexGen 586",         CPUCLASS_386 },         /* CPU_NX586 (XXX) */
   97         { "Cyrix 486S/DX",      CPUCLASS_486 },         /* CPU_CY486DX */
   98         { "Pentium II",         CPUCLASS_686 },         /* CPU_PII */
   99 };
  100 
  101 static void
  102 do_cpuid(u_long ax, u_long *p)
  103 {
  104         __asm __volatile(
  105         ".byte  0x0f, 0xa2;"
  106         "movl   %%eax, (%%esi);"
  107         "movl   %%ebx, (4)(%%esi);"
  108         "movl   %%ecx, (8)(%%esi);"
  109         "movl   %%edx, (12)(%%esi);"
  110         :
  111         : "a" (ax), "S" (p)
  112         : "ax", "bx", "cx", "dx"
  113         );
  114 }
  115 
  116 #if defined(I586_CPU) && !defined(NO_F00F_HACK)
  117 int has_f00f_bug = 0;
  118 #endif
  119 
  120 void
  121 printcpuinfo(void)
  122 {
  123 
  124         u_long regs[4], nreg;
  125         cpu_class = i386_cpus[cpu].cpu_class;
  126         printf("CPU: ");
  127         strncpy(cpu_model, i386_cpus[cpu].cpu_name, sizeof cpu_model);
  128 
  129 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
  130         if (strcmp(cpu_vendor,"GenuineIntel") == 0) {
  131                 if ((cpu_id & 0xf00) > 3) {
  132                         cpu_model[0] = '\0';
  133 
  134                         switch (cpu_id & 0x3000) {
  135                         case 0x1000:
  136                                 strcpy(cpu_model, "Overdrive ");
  137                                 break;
  138                         case 0x2000:
  139                                 strcpy(cpu_model, "Dual ");
  140                                 break;
  141                         }
  142 
  143                         switch (cpu_id & 0xf00) {
  144                         case 0x400:
  145                                 strcat(cpu_model, "i486 ");
  146                                 break;
  147                         case 0x500:
  148                                 /* Check the particular flavor of 586 */
  149                                 strcat(cpu_model, "Pentium");
  150                                 switch (cpu_id & 0xf0) {
  151                                 case 0x00:
  152                                         strcat(cpu_model, " A-step");
  153                                         break;
  154                                 case 0x10:
  155                                         strcat(cpu_model, "/P5");
  156                                         break;
  157                                 case 0x20:
  158                                         strcat(cpu_model, "/P54C");
  159                                         break;
  160                                 case 0x30:
  161                                         strcat(cpu_model, "/P54T Overdrive");
  162                                         break;
  163                                 case 0x40:
  164                                         strcat(cpu_model, "/P55C");
  165                                         break;
  166                                 case 0x70:
  167                                         strcat(cpu_model, "/P54C");
  168                                         break;
  169                                 case 0x80:
  170                                         strcat(cpu_model, "/P55C (quarter-micron)");
  171                                         break;
  172                                 default:
  173                                         /* nothing */
  174                                         break;
  175                                 }
  176 #if defined(I586_CPU) && !defined(NO_F00F_HACK)
  177                                 /*
  178                                  * XXX - If/when Intel fixes the bug, this
  179                                  * should also check the version of the
  180                                  * CPU, not just that it's a Pentium.
  181                                  */
  182                                 has_f00f_bug = 1;
  183 #endif
  184                                 break;
  185                         case 0x600:
  186                                 /* Check the particular flavor of 686 */
  187                                 switch (cpu_id & 0xf0) {
  188                                 case 0x00:
  189                                         strcat(cpu_model, "Pentium Pro A-step");
  190                                         break;
  191                                 case 0x10:
  192                                         strcat(cpu_model, "Pentium Pro");
  193                                         break;
  194                                 case 0x30:
  195                                         strcat(cpu_model, "Pentium II");
  196                                         cpu = CPU_PII;
  197                                         break;
  198                                 case 0x50:
  199                                         strcat(cpu_model, "Pentium II (quarter-micron)");
  200                                         cpu = CPU_PII;
  201                                         break;
  202                                 default:
  203                                         strcat(cpu_model, "Unknown 80686");
  204                                         break;
  205                                 }
  206                                 break;
  207                         default:
  208                                 strcat(cpu_model, "unknown");
  209                                 break;
  210                         }
  211 
  212                         switch (cpu_id & 0xff0) {
  213                         case 0x400:
  214                                 strcat(cpu_model, "DX"); break;
  215                         case 0x410:
  216                                 strcat(cpu_model, "DX"); break;
  217                         case 0x420:
  218                                 strcat(cpu_model, "SX"); break;
  219                         case 0x430:
  220                                 strcat(cpu_model, "DX2"); break;
  221                         case 0x440:
  222                                 strcat(cpu_model, "SL"); break;
  223                         case 0x450:
  224                                 strcat(cpu_model, "SX2"); break;
  225                         case 0x470:
  226                                 strcat(cpu_model, "DX2 Write-Back Enhanced");
  227                                 break;
  228                         case 0x480:
  229                                 strcat(cpu_model, "DX4"); break;
  230                                 break;
  231                         }
  232                 }
  233         } else if (strcmp(cpu_vendor,"AuthenticAMD") == 0) {
  234                 /*
  235                  * Values taken from AMD Processor Recognition
  236                  * http://www.amd.com/K6/k6docs/pdf/20734g.pdf
  237                  * (also describes ``Features'' encodings.
  238                  */
  239                 strcpy(cpu_model, "AMD ");
  240                 switch (cpu_id & 0xFF0) {
  241                 case 0x410:
  242                         strcat(cpu_model, "Standard Am486DX");
  243                         break;
  244                 case 0x430:
  245                         strcat(cpu_model, "Am486DX2/4 Write-Through");
  246                         break;
  247                 case 0x470:
  248                         strcat(cpu_model, "Enhanced Am486DX4 Write-Back");
  249                         break;
  250                 case 0x480:
  251                         strcat(cpu_model, "Enhanced Am486DX4 Write-Through");
  252                         break;
  253                 case 0x490:
  254                         strcat(cpu_model, "Enhanced Am486DX4 Write-Back");
  255                         break;
  256                 case 0x4E0:
  257                         strcat(cpu_model, "Am5x86 Write-Through");
  258                         break;
  259                 case 0x4F0:
  260                         strcat(cpu_model, "Am5x86 Write-Back");
  261                         break;
  262                 case 0x500:
  263                         strcat(cpu_model, "K5 model 0");
  264                         break;
  265                 case 0x510:
  266                         strcat(cpu_model, "K5 model 1");
  267                         break;
  268                 case 0x520:
  269                         strcat(cpu_model, "K5 PR166 (model 2)");
  270                         break;
  271                 case 0x530:
  272                         strcat(cpu_model, "K5 PR200 (model 3)");
  273                         break;
  274                 case 0x560:
  275                         strcat(cpu_model, "K6");
  276                         break;
  277                 default:
  278                         strcat(cpu_model, "Unknown");
  279                         break;
  280                 }
  281                 do_cpuid(0x80000000, regs);
  282                 nreg = regs[0];
  283                 /* Probe to see if we can improve on the model string. */
  284                 if (nreg >= 0x80000004) {
  285                         do_cpuid(0x80000002, regs);
  286                         memcpy(cpu_model, regs, sizeof regs);
  287                         do_cpuid(0x80000003, regs);
  288                         memcpy(cpu_model+16, regs, sizeof regs);
  289                         do_cpuid(0x80000004, regs);
  290                         memcpy(cpu_model+32, regs, sizeof regs);
  291                 }
  292         } else if (strcmp(cpu_vendor,"CyrixInstead") == 0) {
  293                 strcpy(cpu_model, "Cyrix ");
  294                 switch (cpu_id & 0xff0) {
  295                 case 0x440:
  296                         strcat(cpu_model, "MediaGX");
  297                         break;
  298                 case 0x520:
  299                         strcat(cpu_model, "6x86");
  300                         break;
  301                 case 0x540:
  302                         cpu_class = CPUCLASS_586;
  303                         strcat(cpu_model, "GXm");
  304                         break;
  305                 case 0x600:
  306                         strcat(cpu_model, "6x86MX");
  307                         break;
  308                 default:
  309                         /*
  310                          * Even though CPU supports the cpuid
  311                          * instruction, it can be disabled.
  312                          * Therefore, this routine supports all Cyrix
  313                          * CPUs.
  314                          */
  315                         switch (cyrix_did & 0xf0) {
  316                         case 0x00:
  317                                 switch (cyrix_did & 0x0f) {
  318                                 case 0x00:
  319                                         strcat(cpu_model, "486SLC");
  320                                         break;
  321                                 case 0x01:
  322                                         strcat(cpu_model, "486DLC");
  323                                         break;
  324                                 case 0x02:
  325                                         strcat(cpu_model, "486SLC2");
  326                                         break;
  327                                 case 0x03:
  328                                         strcat(cpu_model, "486DLC2");
  329                                         break;
  330                                 case 0x04:
  331                                         strcat(cpu_model, "486SRx");
  332                                         break;
  333                                 case 0x05:
  334                                         strcat(cpu_model, "486DRx");
  335                                         break;
  336                                 case 0x06:
  337                                         strcat(cpu_model, "486SRx2");
  338                                         break;
  339                                 case 0x07:
  340                                         strcat(cpu_model, "486DRx2");
  341                                         break;
  342                                 case 0x08:
  343                                         strcat(cpu_model, "486SRu");
  344                                         break;
  345                                 case 0x09:
  346                                         strcat(cpu_model, "486DRu");
  347                                         break;
  348                                 case 0x0a:
  349                                         strcat(cpu_model, "486SRu2");
  350                                         break;
  351                                 case 0x0b:
  352                                         strcat(cpu_model, "486DRu2");
  353                                         break;
  354                                 default:
  355                                         strcat(cpu_model, "Unknown");
  356                                         break;
  357                                 }
  358                                 break;
  359                         case 0x10:
  360                                 switch (cyrix_did & 0x0f) {
  361                                 case 0x00:
  362                                         strcat(cpu_model, "486S");
  363                                         break;
  364                                 case 0x01:
  365                                         strcat(cpu_model, "486S2");
  366                                         break;
  367                                 case 0x02:
  368                                         strcat(cpu_model, "486Se");
  369                                         break;
  370                                 case 0x03:
  371                                         strcat(cpu_model, "486S2e");
  372                                         break;
  373                                 case 0x0a:
  374                                         strcat(cpu_model, "486DX");
  375                                         break;
  376                                 case 0x0b:
  377                                         strcat(cpu_model, "486DX2");
  378                                         break;
  379                                 case 0x0f:
  380                                         strcat(cpu_model, "486DX4");
  381                                         break;
  382                                 default:
  383                                         strcat(cpu_model, "Unknown");
  384                                         break;
  385                                 }
  386                                 break;
  387                         case 0x20:
  388                                 if ((cyrix_did & 0x0f) < 8)
  389                                         strcat(cpu_model, "6x86");      /* Where did you get it? */
  390                                 else
  391                                         strcat(cpu_model, "5x86");
  392                                 break;
  393                         case 0x30:
  394                                 strcat(cpu_model, "6x86");
  395                                 break;
  396                         case 0x40:
  397                                 if ((cyrix_did & 0xf000) == 0x3000) {
  398                                         cpu_class = CPUCLASS_586;
  399                                         strcat(cpu_model, "GXm");
  400                                 } else
  401                                         strcat(cpu_model, "MediaGX");
  402                                 break;
  403                         case 0x50:
  404                                 strcat(cpu_model, "6x86MX");
  405                                 break;
  406                         case 0xf0:
  407                                 switch (cyrix_did & 0x0f) {
  408                                 case 0x0d:
  409                                         strcat(cpu_model, "Overdrive CPU");
  410                                 case 0x0e:
  411                                         strcpy(cpu_model, "Texas Instruments 486SXL");
  412                                         break;
  413                                 case 0x0f:
  414                                         strcat(cpu_model, "486SLC/DLC");
  415                                         break;
  416                                 default:
  417                                         strcat(cpu_model, "Unknown");
  418                                         break;
  419                                 }
  420                                 break;
  421                         default:
  422                                 strcat(cpu_model, "Unknown");
  423                                 break;
  424                         }
  425                         break;
  426                 }
  427         } else if (strcmp(cpu_vendor,"IBM") == 0)
  428                 strcpy(cpu_model, "Blue Lightning CPU");
  429 #endif
  430 
  431         printf("%s (", cpu_model);
  432         switch(cpu_class) {
  433         case CPUCLASS_286:
  434                 printf("286");
  435                 break;
  436 #if defined(I386_CPU)
  437         case CPUCLASS_386:
  438                 printf("386");
  439                 break;
  440 #endif
  441 #if defined(I486_CPU)
  442         case CPUCLASS_486:
  443                 printf("486");
  444                 bzero = i486_bzero;
  445                 break;
  446 #endif
  447 #if defined(I586_CPU)
  448         case CPUCLASS_586:
  449                 printf("%d.%02d-MHz ",
  450                        (i586_ctr_freq + 4999) / 1000000,
  451                        ((i586_ctr_freq + 4999) / 10000) % 100);
  452                 printf("586");
  453                 break;
  454 #endif
  455 #if defined(I686_CPU)
  456         case CPUCLASS_686:
  457                 printf("%d.%02d-MHz ",
  458                        (i586_ctr_freq + 4999) / 1000000,
  459                        ((i586_ctr_freq + 4999) / 10000) % 100);
  460                 printf("686");
  461                 break;
  462 #endif
  463         default:
  464                 printf("unknown");      /* will panic below... */
  465         }
  466         printf("-class CPU)\n");
  467 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
  468         if(*cpu_vendor)
  469                 printf("  Origin = \"%s\"",cpu_vendor);
  470         if(cpu_id)
  471                 printf("  Id = 0x%lx",cpu_id);
  472 
  473         if (strcmp(cpu_vendor, "GenuineIntel") == 0 ||
  474             strcmp(cpu_vendor, "AuthenticAMD") == 0 ||
  475                 ((strcmp(cpu_vendor, "CyrixInstead") == 0) &&
  476                  (cpu_id & 0xf00 > 5))) {
  477                 printf("  Stepping=%ld", cpu_id & 0xf);
  478                 if (cpu_high > 0) {
  479                         /*
  480                          * Here we should probably set up flags indicating
  481                          * whether or not various features are available.
  482                          * The interesting ones are probably VME, PSE, PAE,
  483                          * and PGE.  The code already assumes without bothering
  484                          * to check that all CPUs >= Pentium have a TSC and
  485                          * MSRs.
  486                          */
  487                         printf("\n  Features=0x%b", cpu_feature, 
  488                         "\020"
  489                         "\001FPU"
  490                         "\002VME"
  491                         "\003DE"
  492                         "\004PSE"
  493                         "\005TSC"
  494                         "\006MSR"
  495                         "\007PAE"
  496                         "\010MCE"
  497                         "\011CX8"
  498                         "\012APIC"
  499                         "\013oldMTRR"
  500                         "\014SEP"
  501                         "\015MTRR"
  502                         "\016PGE"
  503                         "\017MCA"
  504                         "\020CMOV"
  505                         "\021<b16>"
  506                         "\022<b17>"
  507                         "\023<b18>"
  508                         "\024<b19>"
  509                         "\025<b20>"
  510                         "\026<b21>"
  511                         "\027<b22>"
  512                         "\030MMX"
  513                         "\031<b24>"
  514                         "\032<b25>"
  515                         "\033<b26>"
  516                         "\034<b27>"
  517                         "\035<b28>"
  518                         "\036<b29>"
  519                         "\037<b30>"
  520                         "\040<b31>"
  521                         );
  522                 }
  523         } else if (strcmp(cpu_vendor, "CyrixInstead") == 0) {
  524                 printf("  DIR=0x%lx", cyrix_did);
  525                 printf("  Stepping=%ld", (cyrix_did & 0xf000) >> 12);
  526                 printf("  Revision=%ld", (cyrix_did & 0x0fff) >> 8);
  527 #ifndef CYRIX_CACHE_REALLY_WORKS
  528                 if (cpu == CPU_M1 && (cyrix_did & 0xff00) < 0x1700)
  529                         printf("\n  CPU cache: write-through mode");
  530 #endif
  531         }
  532         /* Avoid ugly blank lines: only print newline when we have to. */
  533         if (*cpu_vendor || cpu_id)
  534                 printf("\n");
  535 
  536 #endif
  537         if (!bootverbose)
  538                 return;
  539 
  540         if (strcmp(cpu_vendor, "AuthenticAMD") == 0)
  541                 print_AMD_info();
  542 #ifdef I686_CPU
  543         /*
  544          * XXX - Do PPro CPUID level=2 stuff here?
  545          *
  546          * No, but maybe in a print_Intel_info() function called from here.
  547          */
  548 #endif
  549 }
  550 
  551 void
  552 panicifcpuunsupported(void)
  553 {
  554 
  555         /*
  556          * Now that we have told the user what they have,
  557          * let them know if that machine type isn't configured.
  558          */
  559         switch (cpu_class) {
  560         case CPUCLASS_286:      /* a 286 should not make it this far, anyway */
  561 #if !defined(I386_CPU) && !defined(I486_CPU) && !defined(I586_CPU) && !defined(I686_CPU)
  562 #error This kernel is not configured for one of the supported CPUs
  563 #endif
  564 #if !defined(I386_CPU)
  565         case CPUCLASS_386:
  566 #endif
  567 #if !defined(I486_CPU)
  568         case CPUCLASS_486:
  569 #endif
  570 #if !defined(I586_CPU)
  571         case CPUCLASS_586:
  572 #endif
  573 #if !defined(I686_CPU)
  574         case CPUCLASS_686:
  575 #endif
  576                 panic("CPU class not configured");
  577         default:
  578                 break;
  579         }
  580 }
  581 
  582 
  583 static  volatile u_int trap_by_rdmsr;
  584 
  585 /*
  586  * Special exception 6 handler.
  587  * The rdmsr instruction generates invalid opcodes fault on 486-class
  588  * Cyrix CPU.  Stacked eip register points the rdmsr instruction in the
  589  * function identblue() when this handler is called.  Stacked eip should
  590  * be advanced.
  591  */
  592 inthand_t       bluetrap6;
  593 __asm
  594 ("
  595         .text
  596         .p2align 2,0x90
  597 " __XSTRING(CNAME(bluetrap6)) ":
  598         ss
  599         movl    $0xa8c1d," __XSTRING(CNAME(trap_by_rdmsr)) "
  600         addl    $2, (%esp)                # I know rdmsr is a 2-bytes instruction.
  601         iret
  602 ");
  603 
  604 /*
  605  * Special exception 13 handler.
  606  * Accessing non-existent MSR generates general protection fault.
  607  */
  608 inthand_t       bluetrap13;
  609 __asm
  610 ("
  611         .text
  612         .p2align 2,0x90
  613 " __XSTRING(CNAME(bluetrap13)) ":
  614         ss
  615         movl    $0xa89c4," __XSTRING(CNAME(trap_by_rdmsr)) "
  616         popl    %eax                            # discard errorcode.
  617         addl    $2, (%esp)                      # I know rdmsr is a 2-bytes instruction.
  618         iret
  619 ");
  620 
  621 /*
  622  * Distinguish IBM Blue Lightning CPU from Cyrix CPUs that does not
  623  * support cpuid instruction.  This function should be called after
  624  * loading interrupt descriptor table register.
  625  *
  626  * I don't like this method that handles fault, but I couldn't get
  627  * information for any other methods.  Does blue giant know?
  628  */
  629 static int
  630 identblue(void)
  631 {
  632 
  633         trap_by_rdmsr = 0;
  634 
  635         /* 
  636          * Cyrix 486-class CPU does not support rdmsr instruction.
  637          * The rdmsr instruction generates invalid opcode fault, and exception
  638          * will be trapped by bluetrap6() on Cyrix 486-class CPU.  The
  639          * bluetrap6() set the magic number to trap_by_rdmsr.
  640          */
  641         setidt(6, bluetrap6, SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
  642 
  643         /*
  644          * Certain BIOS disables cpuid instructnion of Cyrix 6x86MX CPU.
  645          * In this case, rdmsr generates general protection fault, and
  646          * exception will be trapped by bluetrap13().
  647          */
  648         setidt(13, bluetrap13, SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
  649 
  650         rdmsr(0x1002);          /* Cyrix CPU generates fault. */
  651 
  652         if (trap_by_rdmsr == 0xa8c1d)
  653                 return IDENTBLUE_CYRIX486;
  654         else if (trap_by_rdmsr == 0xa89c4)
  655                 return IDENTBLUE_CYRIXM2;
  656         return IDENTBLUE_IBMCPU;
  657 }
  658 
  659 
  660 /*
  661  * identifycyrix() set lower 16 bits of cyrix_did as follows:
  662  *
  663  *  F E D C B A 9 8 7 6 5 4 3 2 1 0
  664  * +-------+-------+---------------+
  665  * |  SID  |  RID  |   Device ID   |
  666  * |    (DIR 1)    |    (DIR 0)    |
  667  * +-------+-------+---------------+
  668  */
  669 static void
  670 identifycyrix(void)
  671 {
  672         u_long  eflags;
  673         int     ccr2_test = 0, dir_test = 0;
  674         u_char  ccr2, ccr3;
  675 
  676         eflags = read_eflags();
  677         disable_intr();
  678 
  679         ccr2 = read_cyrix_reg(CCR2);
  680         write_cyrix_reg(CCR2, ccr2 ^ CCR2_LOCK_NW);
  681         read_cyrix_reg(CCR2);
  682         if (read_cyrix_reg(CCR2) != ccr2)
  683                 ccr2_test = 1;
  684         write_cyrix_reg(CCR2, ccr2);
  685 
  686         ccr3 = read_cyrix_reg(CCR3);
  687         write_cyrix_reg(CCR3, ccr3 ^ CCR3_MAPEN3);
  688         read_cyrix_reg(CCR3);
  689         if (read_cyrix_reg(CCR3) != ccr3)
  690                 dir_test = 1;                                   /* CPU supports DIRs. */
  691         write_cyrix_reg(CCR3, ccr3);
  692 
  693         if (dir_test) {
  694                 /* Device ID registers are available. */
  695                 cyrix_did = read_cyrix_reg(DIR1) << 8;
  696                 cyrix_did += read_cyrix_reg(DIR0);
  697         } else if (ccr2_test)
  698                 cyrix_did = 0x0010;             /* 486S A-step */
  699         else
  700                 cyrix_did = 0x00ff;             /* Old 486SLC/DLC and TI486SXLC/SXL */
  701 
  702         write_eflags(eflags);
  703 }
  704 
  705 /*
  706  * Final stage of CPU identification. -- Should I check TI?
  707  */
  708 void
  709 finishidentcpu(void)
  710 {
  711         int     isblue = 0;
  712         u_char  ccr3;
  713         u_long  regs[4];
  714 
  715         if (strcmp(cpu_vendor, "CyrixInstead") == 0) {
  716                 if (cpu == CPU_486) {
  717                         /*
  718                          * These conditions are equivalent to:
  719                          *     - CPU does not support cpuid instruction.
  720                          *     - Cyrix/IBM CPU is detected.
  721                          */
  722                         isblue = identblue();
  723                         if (isblue == IDENTBLUE_IBMCPU) {
  724                                 strcpy(cpu_vendor, "IBM");
  725                                 cpu = CPU_BLUE;
  726                                 return;
  727                         }
  728                 }
  729                 switch (cpu_id & 0xf00) {
  730                 case 0x600:
  731                         /*
  732                          * Cyrix's datasheet does not describe DIRs.
  733                          * Therefor, I assume it does not have them
  734                          * and use the result of the cpuid instruction.
  735                          */
  736                         identifycyrix();
  737                         cpu = CPU_M2;
  738                         break;
  739                 default:
  740                         identifycyrix();
  741                         /*
  742                          * This routine contains a trick.
  743                          * Don't check (cpu_id & 0x00f0) == 0x50 to detect M2, now.
  744                          */
  745                         switch (cyrix_did & 0x00f0) {
  746                         case 0x00:
  747                         case 0xf0:
  748                                 cpu = CPU_486DLC;
  749                                 break;
  750                         case 0x10:
  751                                 cpu = CPU_CY486DX;
  752                                 break;
  753                         case 0x20:
  754                                 if ((cyrix_did & 0x000f) < 8)
  755                                         cpu = CPU_M1;
  756                                 else
  757                                         cpu = CPU_M1SC;
  758                                 break;
  759                         case 0x30:
  760                                 cpu = CPU_M1;
  761                                 break;
  762                         case 0x40:
  763                                 /* MediaGX CPU */
  764                                 cpu = CPU_M1SC;
  765                                 break;
  766                         default:
  767                                 /* M2 and later CPUs are treated as M2. */
  768                                 cpu = CPU_M2;
  769 
  770                                 /*
  771                                  * enable cpuid instruction.
  772                                  */
  773                                 ccr3 = read_cyrix_reg(CCR3);
  774                                 write_cyrix_reg(CCR3, CCR3_MAPEN0);
  775                                 write_cyrix_reg(CCR4, read_cyrix_reg(CCR4) | CCR4_CPUID);
  776                                 write_cyrix_reg(CCR3, ccr3);
  777 
  778                                 do_cpuid(1, regs);
  779                                 cpu_id = regs[0];       /* eax */
  780                                 cpu_feature = regs[3];  /* edx */
  781                                 break;
  782                         }
  783                 }
  784         }
  785 }
  786 
  787 /*
  788  * This routine is called specifically to set up cpu_class before 
  789  * startrtclock() uses it.  Probably this should be rearranged so that
  790  * startrtclock() doesn't need to run until after identifycpu() has been
  791  * called.  Another alternative formulation would be for this routine
  792  * to do all the identification work, and make identifycpu() into a
  793  * printing-only routine.
  794  */
  795 void
  796 earlysetcpuclass(void)
  797 {
  798 
  799         cpu_class = i386_cpus[cpu].cpu_class;
  800 }
  801 
  802 static void
  803 print_AMD_assoc(int i)
  804 {
  805         if (i == 255)
  806                 printf(", fully associative\n");
  807         else
  808                 printf(", %d-way associative\n", i);
  809 }
  810 
  811 static void
  812 print_AMD_info(void) 
  813 {
  814         u_long regs[4];
  815 
  816         do_cpuid(0x80000000, regs);
  817         if (regs[0] >= 0x80000005) {
  818                 do_cpuid(0x80000005, regs);
  819                 printf("Data TLB: %d entries", (regs[1] >> 16) & 0xff);
  820                 print_AMD_assoc(regs[1] >> 24);
  821                 printf("Instruction TLB: %d entries", regs[1] & 0xff);
  822                 print_AMD_assoc((regs[1] >> 8) & 0xff);
  823                 printf("L1 data cache: %d kbytes", regs[2] >> 24);
  824                 printf(", %d bytes/line", regs[2] & 0xff);
  825                 printf(", %d lines/tag", (regs[2] >> 8) & 0xff);
  826                 print_AMD_assoc((regs[2] >> 16) & 0xff);
  827                 printf("L1 instruction cache: %d kbytes", regs[3] >> 24);
  828                 printf(", %d bytes/line", regs[3] & 0xff);
  829                 printf(", %d lines/tag", (regs[3] >> 8) & 0xff);
  830                 print_AMD_assoc((regs[3] >> 16) & 0xff);
  831         }
  832 }

Cache object: 2c60f65d83ec7ce92ce13035c0b2dac9


[ 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.