/* * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* * @OSF_COPYRIGHT@ */ /* * Values from http://einstein.et.tudelft.nl/~offerman/chiplist.html * (dated 18 Oct 1995) */ #include #include /* * Generic product array (before CPUID) */ unsigned int cpuid_i386_freq[] = { 12, 16, 20, 25, 33, 0 }; unsigned int cpuid_i486_freq[] = { 20, 25, 33, 50, 0 }; struct cpuid_product cpuid_generic[] = { { 0, CPUID_FAMILY_386, 0, 80, cpuid_i386_freq, "i386" }, { 0, CPUID_FAMILY_486, 0, 240, cpuid_i486_freq, "i486" }, }; /* * INTEL product array */ unsigned int cpuid_i486_dx_freq[] = { 20, 25, 33, 0 }; unsigned int cpuid_i486_dx_s_freq[] = { 50, 0 }; unsigned int cpuid_i486_sx_freq[] = { 16, 20, 25, 33, 0 }; unsigned int cpuid_i486_dx2_freq[] = { 32, 40, 50, 66, 0 }; unsigned int cpuid_i486_sl_freq[] = { 25, 33, 0 }; unsigned int cpuid_i486_sx2_freq[] = { 50, 0 }; unsigned int cpuid_i486_dx2wb_freq[] = { 50, 66, 0 }; unsigned int cpuid_i486_dx4_freq[] = { 90, 100, 0 }; unsigned int cpuid_i486_dx2wb_od_freq[] = { 32, 40, 50, 66, 0 }; unsigned int cpuid_i486_dx4_od_freq[] = { 75, 99, 0 }; unsigned int cpuid_p5_freq[] = { 60, 66, 0 }; unsigned int cpuid_p54_freq[] = { 60, 66, 75, 90, 100, 120, 133, 166, 200, 0 }; unsigned int cpuid_p24t_freq[] = { 25, 33, 0 }; unsigned int cpuid_p24ct_freq[] = { 63, 83, 0 }; unsigned int cpuid_pii_freq[] = { 300, 0 }; struct cpuid_product cpuid_intel[] = { { CPUID_TYPE_OEM, CPUID_FAMILY_486, CPUID_MODEL_I486_DX, 240, cpuid_i486_dx_freq, "Intel 486DX" }, { CPUID_TYPE_OEM, CPUID_FAMILY_486, CPUID_MODEL_I486_DX_S, 240, cpuid_i486_dx_s_freq, "Intel 486DX-S" }, { CPUID_TYPE_OEM, CPUID_FAMILY_486, CPUID_MODEL_I486_SX, 240, cpuid_i486_sx_freq, "Intel 486SX" }, { CPUID_TYPE_OEM, CPUID_FAMILY_486, CPUID_MODEL_I486_DX2, 240, cpuid_i486_dx2_freq, "Intel 486DX2" }, { CPUID_TYPE_OEM, CPUID_FAMILY_486, CPUID_MODEL_I486_SL, 240, cpuid_i486_sl_freq, "Intel 486SL" }, { CPUID_TYPE_OEM, CPUID_FAMILY_486, CPUID_MODEL_I486_SX2, 240, cpuid_i486_sx2_freq, "Intel 486SX2" }, { CPUID_TYPE_OEM, CPUID_FAMILY_486, CPUID_MODEL_I486_DX2WB, 240, cpuid_i486_dx2wb_freq, "Intel 486DX2WB" }, { CPUID_TYPE_OEM, CPUID_FAMILY_486, CPUID_MODEL_I486_DX4, 240, cpuid_i486_dx4_freq, "Intel 486DX4" }, { CPUID_TYPE_OVERDRIVE, CPUID_FAMILY_486, CPUID_MODEL_I486_DX2, 240, cpuid_i486_dx2_freq, "Intel 486DX2 OverDrive" }, { CPUID_TYPE_OVERDRIVE, CPUID_FAMILY_486, CPUID_MODEL_I486_DX2WB, 240, cpuid_i486_dx2wb_od_freq, "Intel 486DX2WB OverDrive" }, { CPUID_TYPE_OVERDRIVE, CPUID_FAMILY_486, CPUID_MODEL_I486_DX4, 240, cpuid_i486_dx4_od_freq, "Intel 486DX4 OverDrive" }, { CPUID_TYPE_OVERDRIVE, CPUID_FAMILY_P5, CPUID_MODEL_P24T, 208, cpuid_p24t_freq, "Intel Pentium P24T OverDrive" }, { CPUID_TYPE_OVERDRIVE, CPUID_FAMILY_P5, CPUID_MODEL_P54, 207, cpuid_p24ct_freq, "Intel Pentium P24CT OverDrive" }, { CPUID_TYPE_OEM, CPUID_FAMILY_P5, CPUID_MODEL_P5A, 207, cpuid_p5_freq, "Intel Pentium P5 rev A" }, { CPUID_TYPE_OEM, CPUID_FAMILY_P5, CPUID_MODEL_P5, 207, cpuid_p5_freq, "Intel Pentium P5" }, { CPUID_TYPE_OEM, CPUID_FAMILY_P5, CPUID_MODEL_P54, 207, cpuid_p54_freq, "Intel Pentium P54" }, { CPUID_TYPE_OEM, CPUID_FAMILY_PPRO, CPUID_MODEL_PII, 480, cpuid_pii_freq, "Intel Pentium II" } }; unsigned int cpuid_intel_size = sizeof (cpuid_intel) / sizeof (cpuid_intel[0]); /* * AMD product arrays */ unsigned int cpuid_am486_dx_freq[] = { 33, 40, 0 }; unsigned int cpuid_am486_dx2_freq[] = { 50, 66, 80, 99, 0 }; unsigned int cpuid_am486_dx4_freq[] = { 99, 120, 133, 0 }; unsigned int cpuid_am486_dx4wb_freq[] = { 99, 120, 133, 0 }; /* * UMC product array */ unsigned int cpuid_u5sd_freq[] = { 25, 33, 40, 0 }; unsigned int cpuid_u5s_freq[] = { 25, 33, 40, 0 }; /* * Vendor ID array */ struct cpuid_name cpuid_name[] = { { CPUID_VID_INTEL, cpuid_intel, sizeof (cpuid_intel) / sizeof (cpuid_intel[0]) }, { CPUID_VID_UMC, (struct cpuid_product *)0, }, { CPUID_VID_AMD, (struct cpuid_product *)0, }, { CPUID_VID_CYRIX, (struct cpuid_product *)0, }, { CPUID_VID_NEXTGEN, (struct cpuid_product *)0 }, { "", cpuid_generic, sizeof (cpuid_generic) / sizeof (cpuid_generic[0]) }, { (char *)0, } }; /* * Feature Flag values */ char *cpuid_flag[] = { "FPU", /* Floating point unit on-chip */ "VME", /* Virtual Mode Extension */ "DE", /* Debugging Extension */ "PSE", /* Page Size Extension */ "TSC", /* Time Stamp Counter */ "MSR", /* Model Specific Registers */ "PAE", /* Physical Address Extension */ "MCE", /* Machine Check Exception */ "CX8", /* CMPXCHG8 Instruction sSupported */ "APIC", /* Local APIC Supported */ "(bit 10)", "(bit 11)", "MTRR", /* Machine Type Range Register */ "PGE", /* Page Global Enable */ "MCA", /* Machine Check Architecture */ "CMOV", /* Conditional Move Instruction Supported */ "(bit 16)", "(bit 17)", "(bit 18)", "(bit 19)", "(bit 20)", "(bit 21)", "(bit 22)", "MMX", /* Supports MMX instructions */ "(bit 24)", "(bit 25)", "(bit 26)", "(bit 27)", "(bit 28)", "(bit 29)", "(bit 30)", "(bit 31)", }; /* * Cache description array */ struct cpuid_cache_desc cpuid_cache_desc[] = { { CPUID_CACHE_ITLB_4K, "Instruction TBL, 4K, pages 4-way set associative, 64 entries" }, { CPUID_CACHE_ITLB_4M, "Instruction TBL, 4M, pages 4-way set associative, 4 entries" }, { CPUID_CACHE_DTLB_4K, "Data TBL, 4K pages, 4-way set associative, 64 entries" }, { CPUID_CACHE_DTLB_4M, "Data TBL, 4M pages, 4-way set associative, 4 entries" }, { CPUID_CACHE_ICACHE_8K, "Instruction L1 cache, 8K, 4-way set associative, 32byte line size" }, { CPUID_CACHE_DCACHE_8K, "Data L1 cache, 8K, 2-way set associative, 32byte line size" }, { CPUID_CACHE_UCACHE_128K, "Unified L2 cache, 128K, 4-way set associative, 32byte line size" }, { CPUID_CACHE_UCACHE_256K, "Unified L2 cache, 256K, 4-way set associative, 32byte line size" }, { CPUID_CACHE_UCACHE_512K, "Unified L2 cache, 512K, 4-way set associative, 32byte line size" }, { CPUID_CACHE_NULL, (char *)0 } }; /* * CPU identification */ unsigned int cpuid_value; unsigned char cpuid_type; unsigned char cpuid_family; unsigned char cpuid_model; unsigned char cpuid_stepping; unsigned int cpuid_feature; char cpuid_vid[CPUID_VID_SIZE + 1]; unsigned char cpuid_cache[CPUID_CACHE_SIZE]; /* * Return correct CPU_TYPE */ /*ARGSUSED*/ cpu_type_t cpuid_cputype( int my_cpu) { #ifndef MACH_BSD /* FIXME - add more family/chip types */ switch (cpuid_family) { case CPUID_FAMILY_PPRO: return (CPU_TYPE_PENTIUMPRO); case CPUID_FAMILY_P5: return (CPU_TYPE_PENTIUM); case CPUID_FAMILY_486: return (CPU_TYPE_I486); default: break; } #endif return (CPU_TYPE_I386); } /* * Display processor signature */ /*ARGSUSED*/ void cpuid_cpu_display( char *header, int my_cpu) { struct cpuid_name *name; unsigned int i; unsigned int *freq; unsigned int mhz; unsigned int feature; char **flag; extern unsigned int delaycount; /* * Identify vendor ID */ for (name = cpuid_name; name->name != (char *)0; name++) { char *p = name->name; char *q = cpuid_vid; while (*p == *q && *p != 0) { p++; q++; } if (*p == '\0' && *q == '\0') break; } if (name->name == (char *)0) { printf("Unrecognized processor vendor id = '%s'\n", cpuid_vid); return; } /* * Identify Product ID */ for (i = 0; i < name->size; i++) if (name->product[i].type == cpuid_type && name->product[i].family == cpuid_family && name->product[i].model == cpuid_model) break; if (i == name->size) { printf("%s processor (type = 0x%x, family = 0x%x, model = 0x%x)\n", "Unrecognized", cpuid_type, cpuid_family, cpuid_model); return; } /* * Look for frequency and adjust it to known values */ mhz = (1000 * delaycount) / name->product[i].delay; for (freq = name->product[i].frequency; *freq != 0; freq++) if (*freq >= mhz) break; if (*freq == 0) mhz = *(freq - 1); else if (freq == name->product[i].frequency) mhz = *freq; else if (*freq - mhz > mhz - *(freq - 1)) mhz = *(freq - 1); else if (*freq != mhz) mhz = *freq; /* * Display product and frequency */ printf("%s: %s at %d MHz (signature = %d/%d/%d/%d)\n", header, name->product[i].name, mhz, cpuid_type, cpuid_family, cpuid_model, cpuid_stepping); /* * Display feature (if any) */ if (cpuid_feature) { i = 0; flag = cpuid_flag; for (feature = cpuid_feature; feature != 0; feature >>= 1) { if (feature & 1) if (i == 0) { printf("%s: %s", header, *flag); i = 1; } else printf(", %s", *flag); flag++; } printf("\n"); } } /* * Display processor configuration information */ /*ARGSUSED*/ void cpuid_cache_display( char *header, int my_cpu) { struct cpuid_cache_desc *desc; unsigned int i; if (cpuid_cache[CPUID_CACHE_VALID] == 1) for (i = 0; i < CPUID_CACHE_SIZE; i++) { if (i != CPUID_CACHE_VALID || cpuid_cache[i] == CPUID_CACHE_NULL) continue; for (desc = cpuid_cache_desc; desc->description != (char *)0; desc++) if (desc->value == cpuid_cache[i]) break; if (desc->description != (char *)0) printf("%s: %s\n", header, desc->description); } }