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/osfmk/i386/cpuid.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) 2000 Apple Computer, Inc. All rights reserved.
    3  *
    4  * @APPLE_LICENSE_HEADER_START@
    5  * 
    6  * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
    7  * 
    8  * This file contains Original Code and/or Modifications of Original Code
    9  * as defined in and that are subject to the Apple Public Source License
   10  * Version 2.0 (the 'License'). You may not use this file except in
   11  * compliance with the License. Please obtain a copy of the License at
   12  * http://www.opensource.apple.com/apsl/ and read it before using this
   13  * file.
   14  * 
   15  * The Original Code and all software distributed under the License are
   16  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   17  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   18  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   19  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   20  * Please see the License for the specific language governing rights and
   21  * limitations under the License.
   22  * 
   23  * @APPLE_LICENSE_HEADER_END@
   24  */
   25 /*
   26  * @OSF_COPYRIGHT@
   27  */
   28 
   29 #include "cpuid.h"
   30 
   31 #define min(a,b) ((a) < (b) ? (a) : (b))
   32 
   33 /*
   34  * CPU identification routines.
   35  *
   36  * Note that this code assumes a processor that supports the
   37  * 'cpuid' instruction.
   38  */
   39 
   40 static unsigned int     cpuid_maxcpuid;
   41 
   42 static i386_cpu_info_t  cpuid_cpu_info;
   43 
   44 uint32_t                cpuid_feature;          /* XXX obsolescent for compat */
   45 
   46 /*
   47  * We only identify Intel CPUs here.  Adding support
   48  * for others would be straightforward.
   49  */
   50 static void     set_cpu_intel(i386_cpu_info_t *);
   51 static void     set_cpu_unknown(i386_cpu_info_t *);
   52 
   53 struct {
   54         char    *vendor;
   55         void    (* func)(i386_cpu_info_t *);
   56 } cpu_vendors[] = {
   57         {CPUID_VID_INTEL,       set_cpu_intel},
   58         {0,                     set_cpu_unknown}
   59 };
   60 
   61 void
   62 cpuid_get_info(i386_cpu_info_t *info_p)
   63 {
   64         uint32_t        cpuid_result[4];
   65         int             i;
   66 
   67         bzero((void *)info_p, sizeof(i386_cpu_info_t));
   68 
   69         /* do cpuid 0 to get vendor */
   70         do_cpuid(0, cpuid_result);
   71         cpuid_maxcpuid = cpuid_result[0];
   72         bcopy((char *)&cpuid_result[1], &info_p->cpuid_vendor[0], 4); /* ugh */
   73         bcopy((char *)&cpuid_result[2], &info_p->cpuid_vendor[8], 4);
   74         bcopy((char *)&cpuid_result[3], &info_p->cpuid_vendor[4], 4);
   75         info_p->cpuid_vendor[12] = 0;
   76 
   77         /* look up vendor */
   78         for (i = 0; ; i++) {
   79                 if ((cpu_vendors[i].vendor == 0) ||
   80                     (!strcmp(cpu_vendors[i].vendor, info_p->cpuid_vendor))) {
   81                         cpu_vendors[i].func(info_p);
   82                         break;
   83                 }
   84         }
   85 }
   86 
   87 /*
   88  * A useful model name string takes some decoding.
   89  */
   90 char *
   91 cpuid_intel_get_model_name(
   92         uint8_t         brand,
   93         uint8_t         family,
   94         uint8_t         model,
   95         uint32_t        signature)
   96 {
   97         /* check for brand id */
   98         switch(brand) {
   99             case 0:
  100                 /* brand ID not supported; use alternate method. */
  101                 switch(family) {
  102                     case CPUID_FAMILY_486:
  103                         return "486";
  104                     case CPUID_FAMILY_P5:
  105                         return "Pentium";
  106                     case CPUID_FAMILY_PPRO:
  107                         switch(model) {
  108                             case CPUID_MODEL_P6:
  109                                 return "Pentium Pro";
  110                             case CPUID_MODEL_PII:
  111                                 return "Pentium II";
  112                             case CPUID_MODEL_P65:
  113                             case CPUID_MODEL_P66:
  114                                 return "Celeron";
  115                             case CPUID_MODEL_P67:
  116                             case CPUID_MODEL_P68:
  117                             case CPUID_MODEL_P6A:
  118                             case CPUID_MODEL_P6B:
  119                                 return "Pentium III";
  120                             default:
  121                                 return "Unknown P6 Family";
  122                         }
  123                     case CPUID_FAMILY_PENTIUM4:
  124                         return "Pentium 4";
  125                     default:
  126                         return "Unknown Family";
  127                 }
  128             case 0x01:
  129                 return "Celeron";
  130             case 0x02:
  131             case 0x04:
  132                 return "Pentium III";
  133             case 0x03:
  134                 if (signature == 0x6B1)
  135                         return "Celeron";
  136                 else
  137                         return "Pentium III Xeon";
  138             case 0x06:
  139                 return "Mobile Pentium III";
  140             case 0x07:
  141                 return "Mobile Celeron";
  142             case 0x08:
  143                 if (signature >= 0xF20)
  144                         return "Genuine Intel";
  145                 else
  146                         return "Pentium 4";
  147             case 0x09:
  148                 return "Pentium 4";
  149             case 0x0b:
  150                 return "Xeon";
  151             case 0x0e:
  152             case 0x0f:
  153                 return "Mobile Pentium 4";
  154             default:
  155                 return "Unknown Pentium";
  156         }
  157 }
  158 
  159 /*
  160  * Cache descriptor table. Each row has the form:
  161  *         (descriptor_value,           cache,  size,           linesize,
  162  *                              description)
  163  * Note: the CACHE_DESC macro does not expand description text in the kernel.
  164  */
  165 static cpuid_cache_desc_t cpuid_cache_desc_tab[] = {
  166 CACHE_DESC(CPUID_CACHE_ITLB_4K,         Lnone,  0,              0, \
  167         "Instruction TLB, 4K, pages 4-way set associative, 64 entries"),
  168 CACHE_DESC(CPUID_CACHE_ITLB_4M,         Lnone,  0,              0, \
  169         "Instruction TLB, 4M, pages 4-way set associative, 4 entries"),
  170 CACHE_DESC(CPUID_CACHE_DTLB_4K,         Lnone,  0,              0, \
  171         "Data TLB, 4K pages, 4-way set associative, 64 entries"),
  172 CACHE_DESC(CPUID_CACHE_DTLB_4M,         Lnone,  0,              0, \
  173         "Data TLB, 4M pages, 4-way set associative, 4 entries"),
  174 CACHE_DESC(CPUID_CACHE_ITLB_64,         Lnone,  0,              0, \
  175         "Instruction TLB, 4K and 2M or 4M pages, 64 entries"),
  176 CACHE_DESC(CPUID_CACHE_ITLB_128,        Lnone,  0,              0, \
  177         "Instruction TLB, 4K and 2M or 4M pages, 128 entries"),
  178 CACHE_DESC(CPUID_CACHE_ITLB_256,        Lnone,  0,              0, \
  179         "Instruction TLB, 4K and 2M or 4M pages, 256 entries"),
  180 CACHE_DESC(CPUID_CACHE_DTLB_64,         Lnone,  0,              0, \
  181         "Data TLB, 4K and 4M pages, 64 entries"),
  182 CACHE_DESC(CPUID_CACHE_DTLB_128,        Lnone,  0,              0, \
  183         "Data TLB, 4K and 4M pages, 128 entries"),
  184 CACHE_DESC(CPUID_CACHE_DTLB_256,        Lnone,  0,              0, \
  185         "Data TLB, 4K and 4M pages, 256 entries"),
  186 CACHE_DESC(CPUID_CACHE_ICACHE_8K,       L1I,    8*1024,         32, \
  187         "Instruction L1 cache, 8K, 4-way set associative, 32byte line size"),
  188 CACHE_DESC(CPUID_CACHE_DCACHE_8K,       L1D,    8*1024,         32, \
  189         "Data L1 cache, 8K, 2-way set associative, 32byte line size"),
  190 CACHE_DESC(CPUID_CACHE_ICACHE_16K,      L1I,    16*1024,         32, \
  191         "Instruction L1 cache, 16K, 4-way set associative, 32byte line size"),
  192 CACHE_DESC(CPUID_CACHE_DCACHE_16K,      L1D,    16*1024,        32, \
  193         "Data L1 cache, 16K, 4-way set associative, 32byte line size"),
  194 CACHE_DESC(CPUID_CACHE_DCACHE_8K_64,    L1D,    8*1024,         64, \
  195         "Data L1 cache, 8K, 4-way set associative, 64byte line size"),
  196 CACHE_DESC(CPUID_CACHE_DCACHE_16K_64,   L1D,    16*1024,        64, \
  197         "Data L1 cache, 16K, 4-way set associative, 64byte line size"),
  198 CACHE_DESC(CPUID_CACHE_DCACHE_32K_64,   L1D,    32*1024,        64, \
  199         "Data L1 cache, 32K, 4-way set associative, 64byte line size"),
  200 CACHE_DESC(CPUID_CACHE_TRACE_12K,       L1I,    12*1024,        64, \
  201         "Trace cache, 12K-uop, 8-way set associative"),
  202 CACHE_DESC(CPUID_CACHE_TRACE_12K,       L1I,    16*1024,        64, \
  203         "Trace cache, 16K-uop, 8-way set associative"),
  204 CACHE_DESC(CPUID_CACHE_TRACE_12K,       L1I,    32*1024,        64, \
  205         "Trace cache, 32K-uop, 8-way set associative"),
  206 CACHE_DESC(CPUID_CACHE_UCACHE_128K,     L2U,    128*1024,       32, \
  207         "Unified L2 cache, 128K, 4-way set associative, 32byte line size"),
  208 CACHE_DESC(CPUID_CACHE_UCACHE_256K,     L2U,    128*1024,       32, \
  209         "Unified L2 cache, 256K, 4-way set associative, 32byte line size"),
  210 CACHE_DESC(CPUID_CACHE_UCACHE_512K,     L2U,    512*1024,       32, \
  211         "Unified L2 cache, 512K, 4-way set associative, 32byte line size"),
  212 CACHE_DESC(CPUID_CACHE_UCACHE_1M,       L2U,    1*1024*1024,    32, \
  213         "Unified L2 cache, 1M, 4-way set associative, 32byte line size"),
  214 CACHE_DESC(CPUID_CACHE_UCACHE_2M,       L2U,    2*1024*1024,    32, \
  215         "Unified L2 cache, 2M, 4-way set associative, 32byte line size"),
  216 CACHE_DESC(CPUID_CACHE_UCACHE_128K_64,  L2U,    128*1024,       64, \
  217         "Unified L2 cache, 128K, 8-way set associative, 64byte line size"),
  218 CACHE_DESC(CPUID_CACHE_UCACHE_256K_64,  L2U,    256*1024,       64, \
  219         "Unified L2 cache, 256K, 8-way set associative, 64byte line size"),
  220 CACHE_DESC(CPUID_CACHE_UCACHE_512K_64,  L2U,    512*1024,       64, \
  221         "Unified L2 cache, 512K, 8-way set associative, 64byte line size"),
  222 CACHE_DESC(CPUID_CACHE_UCACHE_1M_64,    L2U,    1*1024*1024,    64, \
  223         "Unified L2 cache, 1M, 8-way set associative, 64byte line size"),
  224 CACHE_DESC(CPUID_CACHE_UCACHE_256K_32,  L2U,    256*1024,       32, \
  225         "Unified L2 cache, 256K, 8-way set associative, 32byte line size"),
  226 CACHE_DESC(CPUID_CACHE_UCACHE_512K_32,  L2U,    512*1024,       32, \
  227         "Unified L2 cache, 512K, 8-way set associative, 32byte line size"),
  228 CACHE_DESC(CPUID_CACHE_UCACHE_1M_32,    L2U,    1*1024*1024,    32, \
  229         "Unified L2 cache, 1M, 8-way set associative, 32byte line size"),
  230 CACHE_DESC(CPUID_CACHE_UCACHE_2M_32,    L2U,    2*1024*1024,    32, \
  231         "Unified L2 cache, 2M, 8-way set associative, 32byte line size"),
  232 CACHE_DESC(CPUID_CACHE_NULL, Lnone, 0, 0, \
  233         (char *)0),
  234 };
  235 
  236 static void
  237 set_cpu_intel(i386_cpu_info_t *info_p)
  238 {
  239         uint32_t        cpuid_result[4];
  240         uint32_t        max_extid;
  241         char            str[128], *p;
  242         char            *model;
  243         int             i;
  244         int             j;
  245 
  246         /* get extended cpuid results */
  247         do_cpuid(0x80000000, cpuid_result);
  248         max_extid = cpuid_result[0];
  249 
  250         /* check to see if we can get brand string */
  251         if (max_extid > 0x80000000) {
  252                 /*
  253                  * The brand string 48 bytes (max), guaranteed to
  254                  * be NUL terminated.
  255                  */
  256                 do_cpuid(0x80000002, cpuid_result);
  257                 bcopy((char *)cpuid_result, &str[0], 16);
  258                 do_cpuid(0x80000003, cpuid_result);
  259                 bcopy((char *)cpuid_result, &str[16], 16);
  260                 do_cpuid(0x80000004, cpuid_result);
  261                 bcopy((char *)cpuid_result, &str[32], 16);
  262                 for (p = str; *p != '\0'; p++) {
  263                         if (*p != ' ') break;
  264                 }
  265                 strncpy(info_p->cpuid_brand_string,
  266                         p, sizeof(info_p->cpuid_brand_string)-1);
  267                 info_p->cpuid_brand_string[sizeof(info_p->cpuid_brand_string)-1] = '\0';
  268         }
  269     
  270         /* get processor signature and decode */
  271         do_cpuid(1, cpuid_result);
  272         info_p->cpuid_signature =  cpuid_result[0];
  273         info_p->cpuid_stepping  =  cpuid_result[0]        & 0x0f;
  274         info_p->cpuid_model     = (cpuid_result[0] >> 4)  & 0x0f;
  275         info_p->cpuid_family    = (cpuid_result[0] >> 8)  & 0x0f;
  276         info_p->cpuid_type      = (cpuid_result[0] >> 12) & 0x03;
  277         info_p->cpuid_extmodel  = (cpuid_result[0] >> 16) & 0x0f;
  278         info_p->cpuid_extfamily = (cpuid_result[0] >> 20) & 0xff;
  279         info_p->cpuid_brand     =  cpuid_result[1]        & 0xff;
  280         info_p->cpuid_features  =  cpuid_result[3];
  281 
  282         /* decode family/model/type */
  283         switch (info_p->cpuid_type) {
  284             case CPUID_TYPE_OVERDRIVE:
  285                 strcat(info_p->model_string, "Overdrive ");
  286                 break;
  287             case CPUID_TYPE_DUAL:
  288                 strcat(info_p->model_string, "Dual ");
  289                 break;
  290         }
  291         strcat(info_p->model_string,
  292                cpuid_intel_get_model_name(info_p->cpuid_brand,
  293                                           info_p->cpuid_family,
  294                                           info_p->cpuid_model,
  295                                           info_p->cpuid_signature));
  296         info_p->model_string[sizeof(info_p->model_string)-1] = '\0';
  297 
  298         /* get processor cache descriptor info */
  299         do_cpuid(2, cpuid_result);
  300         for (j = 0; j < 4; j++) {
  301                 if ((cpuid_result[j] >> 31) == 1)       /* bit31 is validity */
  302                         continue;
  303                 ((uint32_t *) info_p->cache_info)[j] = cpuid_result[j];
  304         }
  305         /* first byte gives number of cpuid calls to get all descriptors */
  306         for (i = 1; i < info_p->cache_info[0]; i++) {
  307                 if (i*16 > sizeof(info_p->cache_info))
  308                         break;
  309                 do_cpuid(2, cpuid_result);
  310                 for (j = 0; j < 4; j++) {
  311                         if ((cpuid_result[j] >> 31) == 1) 
  312                                 continue;
  313                         ((uint32_t *) info_p->cache_info)[4*i+j] =
  314                                 cpuid_result[j];
  315                 }
  316         }
  317 
  318         /* decode the descriptors looking for L1/L2/L3 size info */
  319         for (i = 1; i < sizeof(info_p->cache_info); i++) {
  320                 cpuid_cache_desc_t      *descp;
  321                 uint8_t                 desc = info_p->cache_info[i];
  322 
  323                 if (desc == CPUID_CACHE_NULL)
  324                         continue;
  325                 for (descp = cpuid_cache_desc_tab;
  326                         descp->value != CPUID_CACHE_NULL; descp++) {
  327                         if (descp->value != desc)
  328                                 continue;
  329                         info_p->cache_size[descp->type] = descp->size;
  330                         if (descp->type == L2U)
  331                                 info_p->cache_linesize = descp->linesize;
  332                         break;
  333                 }
  334         }
  335         /* For P-IIIs, L2 could be 256k or 512k but we can't tell */ 
  336         if (info_p->cache_size[L2U] == 0 &&
  337             info_p->cpuid_family == 0x6 && info_p->cpuid_model == 0xb) {
  338                 info_p->cache_size[L2U] = 256*1024;
  339                 info_p->cache_linesize = 32;
  340         }
  341 
  342         return;
  343 }
  344 
  345 static void
  346 set_cpu_unknown(i386_cpu_info_t *info_p)
  347 {
  348         strcat(info_p->model_string, "Unknown");
  349 }
  350 
  351 
  352 static struct {
  353         uint32_t        mask;
  354         char            *name;
  355 } feature_names[] = {
  356         {CPUID_FEATURE_FPU,   "FPU",},
  357         {CPUID_FEATURE_VME,   "VME",},
  358         {CPUID_FEATURE_DE,    "DE",},
  359         {CPUID_FEATURE_PSE,   "PSE",},
  360         {CPUID_FEATURE_TSC,   "TSC",},
  361         {CPUID_FEATURE_MSR,   "MSR",},
  362         {CPUID_FEATURE_PAE,   "PAE",},
  363         {CPUID_FEATURE_MCE,   "MCE",},
  364         {CPUID_FEATURE_CX8,   "CX8",},
  365         {CPUID_FEATURE_APIC,  "APIC",},
  366         {CPUID_FEATURE_SEP,   "SEP",},
  367         {CPUID_FEATURE_MTRR,  "MTRR",},
  368         {CPUID_FEATURE_PGE,   "PGE",},
  369         {CPUID_FEATURE_MCA,   "MCA",},
  370         {CPUID_FEATURE_CMOV,  "CMOV",},
  371         {CPUID_FEATURE_PAT,   "PAT",},
  372         {CPUID_FEATURE_PSE36, "PSE36",},
  373         {CPUID_FEATURE_PSN,   "PSN",},
  374         {CPUID_FEATURE_CLFSH, "CLFSH",},
  375         {CPUID_FEATURE_DS,    "DS",},
  376         {CPUID_FEATURE_ACPI,  "ACPI",},
  377         {CPUID_FEATURE_MMX,   "MMX",},
  378         {CPUID_FEATURE_FXSR,  "FXSR",},
  379         {CPUID_FEATURE_SSE,   "SSE",},
  380         {CPUID_FEATURE_SSE2,  "SSE2",},
  381         {CPUID_FEATURE_SS,    "SS",},
  382         {CPUID_FEATURE_HTT,   "HTT",},
  383         {CPUID_FEATURE_TM,    "TM",},
  384         {0, 0}
  385 };
  386 
  387 char *
  388 cpuid_get_feature_names(uint32_t feature, char *buf, unsigned buf_len)
  389 {
  390         int     i;
  391         int     len;
  392         char    *p = buf;
  393 
  394         for (i = 0; feature_names[i].mask != 0; i++) {
  395                 if ((feature & feature_names[i].mask) == 0)
  396                         continue;
  397                 if (i > 0)
  398                         *p++ = ' ';
  399                 len = min(strlen(feature_names[i].name), (buf_len-1) - (p-buf));
  400                 if (len == 0)
  401                         break;
  402                 bcopy(feature_names[i].name, p, len);
  403                 p += len;
  404         }
  405         *p = '\0';
  406         return buf;
  407 }
  408 
  409 void
  410 cpuid_feature_display(
  411         char    *header,
  412         int     my_cpu)
  413 {
  414         char    buf[256];
  415 
  416         printf("%s: %s\n", header,
  417                   cpuid_get_feature_names(cpuid_features(), buf, sizeof(buf)));
  418 }
  419 
  420 void
  421 cpuid_cpu_display(
  422         char    *header,
  423         int     my_cpu)
  424 {
  425         printf("%s: %s\n", header,
  426                 (cpuid_cpu_info.cpuid_brand_string[0] != '\0') ?
  427                         cpuid_cpu_info.cpuid_brand_string :
  428                         cpuid_cpu_info.model_string);
  429 }
  430 
  431 unsigned int
  432 cpuid_family(void)
  433 {
  434         return cpuid_cpu_info.cpuid_family;
  435 }
  436 
  437 unsigned int
  438 cpuid_features(void)
  439 {
  440         return cpuid_cpu_info.cpuid_features;
  441 }
  442 
  443 i386_cpu_info_t *
  444 cpuid_info(void)
  445 {
  446         return &cpuid_cpu_info;
  447 }
  448 
  449 /* XXX for temporary compatibility */
  450 void
  451 set_cpu_model(void)
  452 {
  453         cpuid_get_info(&cpuid_cpu_info);
  454         cpuid_feature = cpuid_cpu_info.cpuid_features;  /* XXX compat */
  455 }
  456 

Cache object: 203a0df102ffd3b1d31bae1efec60c1c


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