17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5ee88d2b9Skchow * Common Development and Distribution License (the "License"). 6ee88d2b9Skchow * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 226e5580c9SFrank Van Der Linden * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 23cfe84b82SMatt Amdur * Copyright (c) 2011 by Delphix. All rights reserved. 247c478bd9Sstevel@tonic-gate */ 25cef70d2cSBill Holler /* 2641afdfa7SKrishnendu Sadhukhan - Sun Microsystems * Copyright (c) 2010, Intel Corporation. 27cef70d2cSBill Holler * All rights reserved. 28cef70d2cSBill Holler */ 298031591dSSrihari Venkatesan /* 308031591dSSrihari Venkatesan * Portions Copyright 2009 Advanced Micro Devices, Inc. 318031591dSSrihari Venkatesan */ 32faa20166SBryan Cantrill /* 33*f3390f39SRobert Mustacchi * Copyright (c) 2012, Joyent, Inc. All rights reserved. 34faa20166SBryan Cantrill */ 357c478bd9Sstevel@tonic-gate /* 367c478bd9Sstevel@tonic-gate * Various routines to handle identification 377c478bd9Sstevel@tonic-gate * and classification of x86 processors. 387c478bd9Sstevel@tonic-gate */ 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate #include <sys/types.h> 417c478bd9Sstevel@tonic-gate #include <sys/archsystm.h> 427c478bd9Sstevel@tonic-gate #include <sys/x86_archext.h> 437c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 447c478bd9Sstevel@tonic-gate #include <sys/systm.h> 457c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 467c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 477c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 487c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 497c478bd9Sstevel@tonic-gate #include <sys/processor.h> 505b8a6efeSbholler #include <sys/sysmacros.h> 51fb2f18f8Sesaxe #include <sys/pg.h> 527c478bd9Sstevel@tonic-gate #include <sys/fp.h> 537c478bd9Sstevel@tonic-gate #include <sys/controlregs.h> 547c478bd9Sstevel@tonic-gate #include <sys/bitmap.h> 55dfea898aSKuriakose Kuruvilla #include <sys/auxv_386.h> 567c478bd9Sstevel@tonic-gate #include <sys/memnode.h> 578031591dSSrihari Venkatesan #include <sys/pci_cfgspace.h> 587c478bd9Sstevel@tonic-gate 59e4b86885SCheng Sean Ye #ifdef __xpv 60e4b86885SCheng Sean Ye #include <sys/hypervisor.h> 61e774b42bSBill Holler #else 62e774b42bSBill Holler #include <sys/ontrap.h> 63e4b86885SCheng Sean Ye #endif 64e4b86885SCheng Sean Ye 657c478bd9Sstevel@tonic-gate /* 667c478bd9Sstevel@tonic-gate * Pass 0 of cpuid feature analysis happens in locore. It contains special code 677c478bd9Sstevel@tonic-gate * to recognize Cyrix processors that are not cpuid-compliant, and to deal with 687c478bd9Sstevel@tonic-gate * them accordingly. For most modern processors, feature detection occurs here 697c478bd9Sstevel@tonic-gate * in pass 1. 707c478bd9Sstevel@tonic-gate * 717c478bd9Sstevel@tonic-gate * Pass 1 of cpuid feature analysis happens just at the beginning of mlsetup() 727c478bd9Sstevel@tonic-gate * for the boot CPU and does the basic analysis that the early kernel needs. 737417cfdeSKuriakose Kuruvilla * x86_featureset is set based on the return value of cpuid_pass1() of the boot 747c478bd9Sstevel@tonic-gate * CPU. 757c478bd9Sstevel@tonic-gate * 767c478bd9Sstevel@tonic-gate * Pass 1 includes: 777c478bd9Sstevel@tonic-gate * 787c478bd9Sstevel@tonic-gate * o Determining vendor/model/family/stepping and setting x86_type and 797c478bd9Sstevel@tonic-gate * x86_vendor accordingly. 807c478bd9Sstevel@tonic-gate * o Processing the feature flags returned by the cpuid instruction while 817c478bd9Sstevel@tonic-gate * applying any workarounds or tricks for the specific processor. 827c478bd9Sstevel@tonic-gate * o Mapping the feature flags into Solaris feature bits (X86_*). 837c478bd9Sstevel@tonic-gate * o Processing extended feature flags if supported by the processor, 847c478bd9Sstevel@tonic-gate * again while applying specific processor knowledge. 857c478bd9Sstevel@tonic-gate * o Determining the CMT characteristics of the system. 867c478bd9Sstevel@tonic-gate * 877c478bd9Sstevel@tonic-gate * Pass 1 is done on non-boot CPUs during their initialization and the results 887c478bd9Sstevel@tonic-gate * are used only as a meager attempt at ensuring that all processors within the 897c478bd9Sstevel@tonic-gate * system support the same features. 907c478bd9Sstevel@tonic-gate * 917c478bd9Sstevel@tonic-gate * Pass 2 of cpuid feature analysis happens just at the beginning 927c478bd9Sstevel@tonic-gate * of startup(). It just copies in and corrects the remainder 937c478bd9Sstevel@tonic-gate * of the cpuid data we depend on: standard cpuid functions that we didn't 947c478bd9Sstevel@tonic-gate * need for pass1 feature analysis, and extended cpuid functions beyond the 957c478bd9Sstevel@tonic-gate * simple feature processing done in pass1. 967c478bd9Sstevel@tonic-gate * 977c478bd9Sstevel@tonic-gate * Pass 3 of cpuid analysis is invoked after basic kernel services; in 987c478bd9Sstevel@tonic-gate * particular kernel memory allocation has been made available. It creates a 997c478bd9Sstevel@tonic-gate * readable brand string based on the data collected in the first two passes. 1007c478bd9Sstevel@tonic-gate * 1017c478bd9Sstevel@tonic-gate * Pass 4 of cpuid analysis is invoked after post_startup() when all 1027c478bd9Sstevel@tonic-gate * the support infrastructure for various hardware features has been 1037c478bd9Sstevel@tonic-gate * initialized. It determines which processor features will be reported 1047c478bd9Sstevel@tonic-gate * to userland via the aux vector. 1057c478bd9Sstevel@tonic-gate * 1067c478bd9Sstevel@tonic-gate * All passes are executed on all CPUs, but only the boot CPU determines what 1077c478bd9Sstevel@tonic-gate * features the kernel will use. 1087c478bd9Sstevel@tonic-gate * 1097c478bd9Sstevel@tonic-gate * Much of the worst junk in this file is for the support of processors 1107c478bd9Sstevel@tonic-gate * that didn't really implement the cpuid instruction properly. 1117c478bd9Sstevel@tonic-gate * 1127c478bd9Sstevel@tonic-gate * NOTE: The accessor functions (cpuid_get*) are aware of, and ASSERT upon, 1137c478bd9Sstevel@tonic-gate * the pass numbers. Accordingly, changes to the pass code may require changes 1147c478bd9Sstevel@tonic-gate * to the accessor code. 1157c478bd9Sstevel@tonic-gate */ 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate uint_t x86_vendor = X86_VENDOR_IntelClone; 1187c478bd9Sstevel@tonic-gate uint_t x86_type = X86_TYPE_OTHER; 11986c1f4dcSVikram Hegde uint_t x86_clflush_size = 0; 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate uint_t pentiumpro_bug4046376; 1227c478bd9Sstevel@tonic-gate uint_t pentiumpro_bug4064495; 1237c478bd9Sstevel@tonic-gate 124dfea898aSKuriakose Kuruvilla uchar_t x86_featureset[BT_SIZEOFMAP(NUM_X86_FEATURES)]; 1257417cfdeSKuriakose Kuruvilla 126dfea898aSKuriakose Kuruvilla static char *x86_feature_names[NUM_X86_FEATURES] = { 1277417cfdeSKuriakose Kuruvilla "lgpg", 1287417cfdeSKuriakose Kuruvilla "tsc", 1297417cfdeSKuriakose Kuruvilla "msr", 1307417cfdeSKuriakose Kuruvilla "mtrr", 1317417cfdeSKuriakose Kuruvilla "pge", 1327417cfdeSKuriakose Kuruvilla "de", 1337417cfdeSKuriakose Kuruvilla "cmov", 1347417cfdeSKuriakose Kuruvilla "mmx", 1357417cfdeSKuriakose Kuruvilla "mca", 1367417cfdeSKuriakose Kuruvilla "pae", 1377417cfdeSKuriakose Kuruvilla "cv8", 1387417cfdeSKuriakose Kuruvilla "pat", 1397417cfdeSKuriakose Kuruvilla "sep", 1407417cfdeSKuriakose Kuruvilla "sse", 1417417cfdeSKuriakose Kuruvilla "sse2", 1427417cfdeSKuriakose Kuruvilla "htt", 1437417cfdeSKuriakose Kuruvilla "asysc", 1447417cfdeSKuriakose Kuruvilla "nx", 1457417cfdeSKuriakose Kuruvilla "sse3", 1467417cfdeSKuriakose Kuruvilla "cx16", 1477417cfdeSKuriakose Kuruvilla "cmp", 1487417cfdeSKuriakose Kuruvilla "tscp", 1497417cfdeSKuriakose Kuruvilla "mwait", 1507417cfdeSKuriakose Kuruvilla "sse4a", 1517417cfdeSKuriakose Kuruvilla "cpuid", 1527417cfdeSKuriakose Kuruvilla "ssse3", 1537417cfdeSKuriakose Kuruvilla "sse4_1", 1547417cfdeSKuriakose Kuruvilla "sse4_2", 1557417cfdeSKuriakose Kuruvilla "1gpg", 1567417cfdeSKuriakose Kuruvilla "clfsh", 1577417cfdeSKuriakose Kuruvilla "64", 1587417cfdeSKuriakose Kuruvilla "aes", 1597af88ac7SKuriakose Kuruvilla "pclmulqdq", 1607af88ac7SKuriakose Kuruvilla "xsave", 161faa20166SBryan Cantrill "avx", 162faa20166SBryan Cantrill "vmx", 163faa20166SBryan Cantrill "svm" 164faa20166SBryan Cantrill }; 1657417cfdeSKuriakose Kuruvilla 1667417cfdeSKuriakose Kuruvilla boolean_t 1677417cfdeSKuriakose Kuruvilla is_x86_feature(void *featureset, uint_t feature) 1687417cfdeSKuriakose Kuruvilla { 1697417cfdeSKuriakose Kuruvilla ASSERT(feature < NUM_X86_FEATURES); 1707417cfdeSKuriakose Kuruvilla return (BT_TEST((ulong_t *)featureset, feature)); 1717417cfdeSKuriakose Kuruvilla } 1727417cfdeSKuriakose Kuruvilla 1737417cfdeSKuriakose Kuruvilla void 1747417cfdeSKuriakose Kuruvilla add_x86_feature(void *featureset, uint_t feature) 1757417cfdeSKuriakose Kuruvilla { 1767417cfdeSKuriakose Kuruvilla ASSERT(feature < NUM_X86_FEATURES); 1777417cfdeSKuriakose Kuruvilla BT_SET((ulong_t *)featureset, feature); 1787417cfdeSKuriakose Kuruvilla } 1797417cfdeSKuriakose Kuruvilla 1807417cfdeSKuriakose Kuruvilla void 1817417cfdeSKuriakose Kuruvilla remove_x86_feature(void *featureset, uint_t feature) 1827417cfdeSKuriakose Kuruvilla { 1837417cfdeSKuriakose Kuruvilla ASSERT(feature < NUM_X86_FEATURES); 1847417cfdeSKuriakose Kuruvilla BT_CLEAR((ulong_t *)featureset, feature); 1857417cfdeSKuriakose Kuruvilla } 1867417cfdeSKuriakose Kuruvilla 1877417cfdeSKuriakose Kuruvilla boolean_t 1887417cfdeSKuriakose Kuruvilla compare_x86_featureset(void *setA, void *setB) 1897417cfdeSKuriakose Kuruvilla { 1907417cfdeSKuriakose Kuruvilla /* 1917417cfdeSKuriakose Kuruvilla * We assume that the unused bits of the bitmap are always zero. 1927417cfdeSKuriakose Kuruvilla */ 1937417cfdeSKuriakose Kuruvilla if (memcmp(setA, setB, BT_SIZEOFMAP(NUM_X86_FEATURES)) == 0) { 1947417cfdeSKuriakose Kuruvilla return (B_TRUE); 1957417cfdeSKuriakose Kuruvilla } else { 1967417cfdeSKuriakose Kuruvilla return (B_FALSE); 1977417cfdeSKuriakose Kuruvilla } 1987417cfdeSKuriakose Kuruvilla } 1997417cfdeSKuriakose Kuruvilla 2007417cfdeSKuriakose Kuruvilla void 2017417cfdeSKuriakose Kuruvilla print_x86_featureset(void *featureset) 2027417cfdeSKuriakose Kuruvilla { 2037417cfdeSKuriakose Kuruvilla uint_t i; 2047417cfdeSKuriakose Kuruvilla 2057417cfdeSKuriakose Kuruvilla for (i = 0; i < NUM_X86_FEATURES; i++) { 2067417cfdeSKuriakose Kuruvilla if (is_x86_feature(featureset, i)) { 2077417cfdeSKuriakose Kuruvilla cmn_err(CE_CONT, "?x86_feature: %s\n", 2087417cfdeSKuriakose Kuruvilla x86_feature_names[i]); 2097417cfdeSKuriakose Kuruvilla } 2107417cfdeSKuriakose Kuruvilla } 2117417cfdeSKuriakose Kuruvilla } 2127417cfdeSKuriakose Kuruvilla 2137c478bd9Sstevel@tonic-gate uint_t enable486; 2147af88ac7SKuriakose Kuruvilla 2157af88ac7SKuriakose Kuruvilla static size_t xsave_state_size = 0; 2167af88ac7SKuriakose Kuruvilla uint64_t xsave_bv_all = (XFEATURE_LEGACY_FP | XFEATURE_SSE); 2177af88ac7SKuriakose Kuruvilla boolean_t xsave_force_disable = B_FALSE; 2187af88ac7SKuriakose Kuruvilla 2197997e108SSurya Prakki /* 220b9bfdccdSStuart Maybee * This is set to platform type Solaris is running on. 2217997e108SSurya Prakki */ 222349b53ddSStuart Maybee static int platform_type = -1; 223349b53ddSStuart Maybee 224349b53ddSStuart Maybee #if !defined(__xpv) 225349b53ddSStuart Maybee /* 226349b53ddSStuart Maybee * Variable to patch if hypervisor platform detection needs to be 227349b53ddSStuart Maybee * disabled (e.g. platform_type will always be HW_NATIVE if this is 0). 228349b53ddSStuart Maybee */ 229349b53ddSStuart Maybee int enable_platform_detection = 1; 230349b53ddSStuart Maybee #endif 2317c478bd9Sstevel@tonic-gate 2327c478bd9Sstevel@tonic-gate /* 233f98fbcecSbholler * monitor/mwait info. 2345b8a6efeSbholler * 2355b8a6efeSbholler * size_actual and buf_actual are the real address and size allocated to get 2365b8a6efeSbholler * proper mwait_buf alignement. buf_actual and size_actual should be passed 2375b8a6efeSbholler * to kmem_free(). Currently kmem_alloc() and mwait happen to both use 2385b8a6efeSbholler * processor cache-line alignment, but this is not guarantied in the furture. 239f98fbcecSbholler */ 240f98fbcecSbholler struct mwait_info { 241f98fbcecSbholler size_t mon_min; /* min size to avoid missed wakeups */ 242f98fbcecSbholler size_t mon_max; /* size to avoid false wakeups */ 2435b8a6efeSbholler size_t size_actual; /* size actually allocated */ 2445b8a6efeSbholler void *buf_actual; /* memory actually allocated */ 245f98fbcecSbholler uint32_t support; /* processor support of monitor/mwait */ 246f98fbcecSbholler }; 247f98fbcecSbholler 248f98fbcecSbholler /* 2497af88ac7SKuriakose Kuruvilla * xsave/xrestor info. 2507af88ac7SKuriakose Kuruvilla * 2517af88ac7SKuriakose Kuruvilla * This structure contains HW feature bits and size of the xsave save area. 2527af88ac7SKuriakose Kuruvilla * Note: the kernel will use the maximum size required for all hardware 2537af88ac7SKuriakose Kuruvilla * features. It is not optimize for potential memory savings if features at 2547af88ac7SKuriakose Kuruvilla * the end of the save area are not enabled. 2557af88ac7SKuriakose Kuruvilla */ 2567af88ac7SKuriakose Kuruvilla struct xsave_info { 2577af88ac7SKuriakose Kuruvilla uint32_t xsav_hw_features_low; /* Supported HW features */ 2587af88ac7SKuriakose Kuruvilla uint32_t xsav_hw_features_high; /* Supported HW features */ 2597af88ac7SKuriakose Kuruvilla size_t xsav_max_size; /* max size save area for HW features */ 2607af88ac7SKuriakose Kuruvilla size_t ymm_size; /* AVX: size of ymm save area */ 2617af88ac7SKuriakose Kuruvilla size_t ymm_offset; /* AVX: offset for ymm save area */ 2627af88ac7SKuriakose Kuruvilla }; 2637af88ac7SKuriakose Kuruvilla 2647af88ac7SKuriakose Kuruvilla 2657af88ac7SKuriakose Kuruvilla /* 2667c478bd9Sstevel@tonic-gate * These constants determine how many of the elements of the 2677c478bd9Sstevel@tonic-gate * cpuid we cache in the cpuid_info data structure; the 2687c478bd9Sstevel@tonic-gate * remaining elements are accessible via the cpuid instruction. 2697c478bd9Sstevel@tonic-gate */ 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate #define NMAX_CPI_STD 6 /* eax = 0 .. 5 */ 2728031591dSSrihari Venkatesan #define NMAX_CPI_EXTD 0x1c /* eax = 0x80000000 .. 0x8000001b */ 2738031591dSSrihari Venkatesan 2748031591dSSrihari Venkatesan /* 2758031591dSSrihari Venkatesan * Some terminology needs to be explained: 2768031591dSSrihari Venkatesan * - Socket: Something that can be plugged into a motherboard. 2778031591dSSrihari Venkatesan * - Package: Same as socket 2788031591dSSrihari Venkatesan * - Chip: Same as socket. Note that AMD's documentation uses term "chip" 2798031591dSSrihari Venkatesan * differently: there, chip is the same as processor node (below) 2808031591dSSrihari Venkatesan * - Processor node: Some AMD processors have more than one 2818031591dSSrihari Venkatesan * "subprocessor" embedded in a package. These subprocessors (nodes) 2828031591dSSrihari Venkatesan * are fully-functional processors themselves with cores, caches, 2838031591dSSrihari Venkatesan * memory controllers, PCI configuration spaces. They are connected 2848031591dSSrihari Venkatesan * inside the package with Hypertransport links. On single-node 2858031591dSSrihari Venkatesan * processors, processor node is equivalent to chip/socket/package. 2868031591dSSrihari Venkatesan */ 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate struct cpuid_info { 2897c478bd9Sstevel@tonic-gate uint_t cpi_pass; /* last pass completed */ 2907c478bd9Sstevel@tonic-gate /* 2917c478bd9Sstevel@tonic-gate * standard function information 2927c478bd9Sstevel@tonic-gate */ 2937c478bd9Sstevel@tonic-gate uint_t cpi_maxeax; /* fn 0: %eax */ 2947c478bd9Sstevel@tonic-gate char cpi_vendorstr[13]; /* fn 0: %ebx:%ecx:%edx */ 2957c478bd9Sstevel@tonic-gate uint_t cpi_vendor; /* enum of cpi_vendorstr */ 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate uint_t cpi_family; /* fn 1: extended family */ 2987c478bd9Sstevel@tonic-gate uint_t cpi_model; /* fn 1: extended model */ 2997c478bd9Sstevel@tonic-gate uint_t cpi_step; /* fn 1: stepping */ 3008031591dSSrihari Venkatesan chipid_t cpi_chipid; /* fn 1: %ebx: Intel: chip # */ 3018031591dSSrihari Venkatesan /* AMD: package/socket # */ 3027c478bd9Sstevel@tonic-gate uint_t cpi_brandid; /* fn 1: %ebx: brand ID */ 3037c478bd9Sstevel@tonic-gate int cpi_clogid; /* fn 1: %ebx: thread # */ 3048949bcd6Sandrei uint_t cpi_ncpu_per_chip; /* fn 1: %ebx: logical cpu count */ 3057c478bd9Sstevel@tonic-gate uint8_t cpi_cacheinfo[16]; /* fn 2: intel-style cache desc */ 3067c478bd9Sstevel@tonic-gate uint_t cpi_ncache; /* fn 2: number of elements */ 307d129bde2Sesaxe uint_t cpi_ncpu_shr_last_cache; /* fn 4: %eax: ncpus sharing cache */ 308d129bde2Sesaxe id_t cpi_last_lvl_cacheid; /* fn 4: %eax: derived cache id */ 309d129bde2Sesaxe uint_t cpi_std_4_size; /* fn 4: number of fn 4 elements */ 310d129bde2Sesaxe struct cpuid_regs **cpi_std_4; /* fn 4: %ecx == 0 .. fn4_size */ 3118949bcd6Sandrei struct cpuid_regs cpi_std[NMAX_CPI_STD]; /* 0 .. 5 */ 3127c478bd9Sstevel@tonic-gate /* 3137c478bd9Sstevel@tonic-gate * extended function information 3147c478bd9Sstevel@tonic-gate */ 3157c478bd9Sstevel@tonic-gate uint_t cpi_xmaxeax; /* fn 0x80000000: %eax */ 3167c478bd9Sstevel@tonic-gate char cpi_brandstr[49]; /* fn 0x8000000[234] */ 3177c478bd9Sstevel@tonic-gate uint8_t cpi_pabits; /* fn 0x80000006: %eax */ 3187c478bd9Sstevel@tonic-gate uint8_t cpi_vabits; /* fn 0x80000006: %eax */ 3198031591dSSrihari Venkatesan struct cpuid_regs cpi_extd[NMAX_CPI_EXTD]; /* 0x800000XX */ 3208031591dSSrihari Venkatesan 32110569901Sgavinm id_t cpi_coreid; /* same coreid => strands share core */ 32210569901Sgavinm int cpi_pkgcoreid; /* core number within single package */ 3238949bcd6Sandrei uint_t cpi_ncore_per_chip; /* AMD: fn 0x80000008: %ecx[7-0] */ 3248949bcd6Sandrei /* Intel: fn 4: %eax[31-26] */ 3257c478bd9Sstevel@tonic-gate /* 3267c478bd9Sstevel@tonic-gate * supported feature information 3277c478bd9Sstevel@tonic-gate */ 328ae115bc7Smrj uint32_t cpi_support[5]; 3297c478bd9Sstevel@tonic-gate #define STD_EDX_FEATURES 0 3307c478bd9Sstevel@tonic-gate #define AMD_EDX_FEATURES 1 3317c478bd9Sstevel@tonic-gate #define TM_EDX_FEATURES 2 3327c478bd9Sstevel@tonic-gate #define STD_ECX_FEATURES 3 333ae115bc7Smrj #define AMD_ECX_FEATURES 4 3348a40a695Sgavinm /* 3358a40a695Sgavinm * Synthesized information, where known. 3368a40a695Sgavinm */ 3378a40a695Sgavinm uint32_t cpi_chiprev; /* See X86_CHIPREV_* in x86_archext.h */ 3388a40a695Sgavinm const char *cpi_chiprevstr; /* May be NULL if chiprev unknown */ 3398a40a695Sgavinm uint32_t cpi_socket; /* Chip package/socket type */ 340f98fbcecSbholler 341f98fbcecSbholler struct mwait_info cpi_mwait; /* fn 5: monitor/mwait info */ 342b6917abeSmishra uint32_t cpi_apicid; 3438031591dSSrihari Venkatesan uint_t cpi_procnodeid; /* AMD: nodeID on HT, Intel: chipid */ 3448031591dSSrihari Venkatesan uint_t cpi_procnodes_per_pkg; /* AMD: # of nodes in the package */ 3458031591dSSrihari Venkatesan /* Intel: 1 */ 3467af88ac7SKuriakose Kuruvilla 3477af88ac7SKuriakose Kuruvilla struct xsave_info cpi_xsave; /* fn D: xsave/xrestor info */ 3487c478bd9Sstevel@tonic-gate }; 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate static struct cpuid_info cpuid_info0; 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate /* 3547c478bd9Sstevel@tonic-gate * These bit fields are defined by the Intel Application Note AP-485 3557c478bd9Sstevel@tonic-gate * "Intel Processor Identification and the CPUID Instruction" 3567c478bd9Sstevel@tonic-gate */ 3577c478bd9Sstevel@tonic-gate #define CPI_FAMILY_XTD(cpi) BITX((cpi)->cpi_std[1].cp_eax, 27, 20) 3587c478bd9Sstevel@tonic-gate #define CPI_MODEL_XTD(cpi) BITX((cpi)->cpi_std[1].cp_eax, 19, 16) 3597c478bd9Sstevel@tonic-gate #define CPI_TYPE(cpi) BITX((cpi)->cpi_std[1].cp_eax, 13, 12) 3607c478bd9Sstevel@tonic-gate #define CPI_FAMILY(cpi) BITX((cpi)->cpi_std[1].cp_eax, 11, 8) 3617c478bd9Sstevel@tonic-gate #define CPI_STEP(cpi) BITX((cpi)->cpi_std[1].cp_eax, 3, 0) 3627c478bd9Sstevel@tonic-gate #define CPI_MODEL(cpi) BITX((cpi)->cpi_std[1].cp_eax, 7, 4) 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate #define CPI_FEATURES_EDX(cpi) ((cpi)->cpi_std[1].cp_edx) 3657c478bd9Sstevel@tonic-gate #define CPI_FEATURES_ECX(cpi) ((cpi)->cpi_std[1].cp_ecx) 3667c478bd9Sstevel@tonic-gate #define CPI_FEATURES_XTD_EDX(cpi) ((cpi)->cpi_extd[1].cp_edx) 3677c478bd9Sstevel@tonic-gate #define CPI_FEATURES_XTD_ECX(cpi) ((cpi)->cpi_extd[1].cp_ecx) 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate #define CPI_BRANDID(cpi) BITX((cpi)->cpi_std[1].cp_ebx, 7, 0) 3707c478bd9Sstevel@tonic-gate #define CPI_CHUNKS(cpi) BITX((cpi)->cpi_std[1].cp_ebx, 15, 7) 3717c478bd9Sstevel@tonic-gate #define CPI_CPU_COUNT(cpi) BITX((cpi)->cpi_std[1].cp_ebx, 23, 16) 3727c478bd9Sstevel@tonic-gate #define CPI_APIC_ID(cpi) BITX((cpi)->cpi_std[1].cp_ebx, 31, 24) 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate #define CPI_MAXEAX_MAX 0x100 /* sanity control */ 3757c478bd9Sstevel@tonic-gate #define CPI_XMAXEAX_MAX 0x80000100 376d129bde2Sesaxe #define CPI_FN4_ECX_MAX 0x20 /* sanity: max fn 4 levels */ 377b6917abeSmishra #define CPI_FNB_ECX_MAX 0x20 /* sanity: max fn B levels */ 378d129bde2Sesaxe 379d129bde2Sesaxe /* 380d129bde2Sesaxe * Function 4 (Deterministic Cache Parameters) macros 381d129bde2Sesaxe * Defined by Intel Application Note AP-485 382d129bde2Sesaxe */ 383d129bde2Sesaxe #define CPI_NUM_CORES(regs) BITX((regs)->cp_eax, 31, 26) 384d129bde2Sesaxe #define CPI_NTHR_SHR_CACHE(regs) BITX((regs)->cp_eax, 25, 14) 385d129bde2Sesaxe #define CPI_FULL_ASSOC_CACHE(regs) BITX((regs)->cp_eax, 9, 9) 386d129bde2Sesaxe #define CPI_SELF_INIT_CACHE(regs) BITX((regs)->cp_eax, 8, 8) 387d129bde2Sesaxe #define CPI_CACHE_LVL(regs) BITX((regs)->cp_eax, 7, 5) 388d129bde2Sesaxe #define CPI_CACHE_TYPE(regs) BITX((regs)->cp_eax, 4, 0) 389b6917abeSmishra #define CPI_CPU_LEVEL_TYPE(regs) BITX((regs)->cp_ecx, 15, 8) 390d129bde2Sesaxe 391d129bde2Sesaxe #define CPI_CACHE_WAYS(regs) BITX((regs)->cp_ebx, 31, 22) 392d129bde2Sesaxe #define CPI_CACHE_PARTS(regs) BITX((regs)->cp_ebx, 21, 12) 393d129bde2Sesaxe #define CPI_CACHE_COH_LN_SZ(regs) BITX((regs)->cp_ebx, 11, 0) 394d129bde2Sesaxe 395d129bde2Sesaxe #define CPI_CACHE_SETS(regs) BITX((regs)->cp_ecx, 31, 0) 396d129bde2Sesaxe 397d129bde2Sesaxe #define CPI_PREFCH_STRIDE(regs) BITX((regs)->cp_edx, 9, 0) 398d129bde2Sesaxe 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate /* 4015ff02082Sdmick * A couple of shorthand macros to identify "later" P6-family chips 4025ff02082Sdmick * like the Pentium M and Core. First, the "older" P6-based stuff 4035ff02082Sdmick * (loosely defined as "pre-Pentium-4"): 4045ff02082Sdmick * P6, PII, Mobile PII, PII Xeon, PIII, Mobile PIII, PIII Xeon 4055ff02082Sdmick */ 4065ff02082Sdmick 4075ff02082Sdmick #define IS_LEGACY_P6(cpi) ( \ 4085ff02082Sdmick cpi->cpi_family == 6 && \ 4095ff02082Sdmick (cpi->cpi_model == 1 || \ 4105ff02082Sdmick cpi->cpi_model == 3 || \ 4115ff02082Sdmick cpi->cpi_model == 5 || \ 4125ff02082Sdmick cpi->cpi_model == 6 || \ 4135ff02082Sdmick cpi->cpi_model == 7 || \ 4145ff02082Sdmick cpi->cpi_model == 8 || \ 4155ff02082Sdmick cpi->cpi_model == 0xA || \ 4165ff02082Sdmick cpi->cpi_model == 0xB) \ 4175ff02082Sdmick ) 4185ff02082Sdmick 4195ff02082Sdmick /* A "new F6" is everything with family 6 that's not the above */ 4205ff02082Sdmick #define IS_NEW_F6(cpi) ((cpi->cpi_family == 6) && !IS_LEGACY_P6(cpi)) 4215ff02082Sdmick 422bf91205bSksadhukh /* Extended family/model support */ 423bf91205bSksadhukh #define IS_EXTENDED_MODEL_INTEL(cpi) (cpi->cpi_family == 0x6 || \ 424bf91205bSksadhukh cpi->cpi_family >= 0xf) 425bf91205bSksadhukh 4265ff02082Sdmick /* 427f98fbcecSbholler * Info for monitor/mwait idle loop. 428f98fbcecSbholler * 429f98fbcecSbholler * See cpuid section of "Intel 64 and IA-32 Architectures Software Developer's 430f98fbcecSbholler * Manual Volume 2A: Instruction Set Reference, A-M" #25366-022US, November 431f98fbcecSbholler * 2006. 432f98fbcecSbholler * See MONITOR/MWAIT section of "AMD64 Architecture Programmer's Manual 433f98fbcecSbholler * Documentation Updates" #33633, Rev 2.05, December 2006. 434f98fbcecSbholler */ 435f98fbcecSbholler #define MWAIT_SUPPORT (0x00000001) /* mwait supported */ 436f98fbcecSbholler #define MWAIT_EXTENSIONS (0x00000002) /* extenstion supported */ 437f98fbcecSbholler #define MWAIT_ECX_INT_ENABLE (0x00000004) /* ecx 1 extension supported */ 438f98fbcecSbholler #define MWAIT_SUPPORTED(cpi) ((cpi)->cpi_std[1].cp_ecx & CPUID_INTC_ECX_MON) 439f98fbcecSbholler #define MWAIT_INT_ENABLE(cpi) ((cpi)->cpi_std[5].cp_ecx & 0x2) 440f98fbcecSbholler #define MWAIT_EXTENSION(cpi) ((cpi)->cpi_std[5].cp_ecx & 0x1) 441f98fbcecSbholler #define MWAIT_SIZE_MIN(cpi) BITX((cpi)->cpi_std[5].cp_eax, 15, 0) 442f98fbcecSbholler #define MWAIT_SIZE_MAX(cpi) BITX((cpi)->cpi_std[5].cp_ebx, 15, 0) 443f98fbcecSbholler /* 444f98fbcecSbholler * Number of sub-cstates for a given c-state. 445f98fbcecSbholler */ 446f98fbcecSbholler #define MWAIT_NUM_SUBC_STATES(cpi, c_state) \ 447f98fbcecSbholler BITX((cpi)->cpi_std[5].cp_edx, c_state + 3, c_state) 448f98fbcecSbholler 4498a40a695Sgavinm /* 4507af88ac7SKuriakose Kuruvilla * XSAVE leaf 0xD enumeration 4517af88ac7SKuriakose Kuruvilla */ 4527af88ac7SKuriakose Kuruvilla #define CPUID_LEAFD_2_YMM_OFFSET 576 4537af88ac7SKuriakose Kuruvilla #define CPUID_LEAFD_2_YMM_SIZE 256 4547af88ac7SKuriakose Kuruvilla 4557af88ac7SKuriakose Kuruvilla /* 456e4b86885SCheng Sean Ye * Functions we consune from cpuid_subr.c; don't publish these in a header 457e4b86885SCheng Sean Ye * file to try and keep people using the expected cpuid_* interfaces. 4588a40a695Sgavinm */ 459e4b86885SCheng Sean Ye extern uint32_t _cpuid_skt(uint_t, uint_t, uint_t, uint_t); 46089e921d5SKuriakose Kuruvilla extern const char *_cpuid_sktstr(uint_t, uint_t, uint_t, uint_t); 461e4b86885SCheng Sean Ye extern uint32_t _cpuid_chiprev(uint_t, uint_t, uint_t, uint_t); 462e4b86885SCheng Sean Ye extern const char *_cpuid_chiprevstr(uint_t, uint_t, uint_t, uint_t); 463e4b86885SCheng Sean Ye extern uint_t _cpuid_vendorstr_to_vendorcode(char *); 4648a40a695Sgavinm 4658a40a695Sgavinm /* 466ae115bc7Smrj * Apply up various platform-dependent restrictions where the 467ae115bc7Smrj * underlying platform restrictions mean the CPU can be marked 468ae115bc7Smrj * as less capable than its cpuid instruction would imply. 469ae115bc7Smrj */ 470843e1988Sjohnlev #if defined(__xpv) 471843e1988Sjohnlev static void 472843e1988Sjohnlev platform_cpuid_mangle(uint_t vendor, uint32_t eax, struct cpuid_regs *cp) 473843e1988Sjohnlev { 474843e1988Sjohnlev switch (eax) { 475e4b86885SCheng Sean Ye case 1: { 476e4b86885SCheng Sean Ye uint32_t mcamask = DOMAIN_IS_INITDOMAIN(xen_info) ? 477e4b86885SCheng Sean Ye 0 : CPUID_INTC_EDX_MCA; 478843e1988Sjohnlev cp->cp_edx &= 479e4b86885SCheng Sean Ye ~(mcamask | 480e4b86885SCheng Sean Ye CPUID_INTC_EDX_PSE | 481843e1988Sjohnlev CPUID_INTC_EDX_VME | CPUID_INTC_EDX_DE | 482843e1988Sjohnlev CPUID_INTC_EDX_SEP | CPUID_INTC_EDX_MTRR | 483843e1988Sjohnlev CPUID_INTC_EDX_PGE | CPUID_INTC_EDX_PAT | 484843e1988Sjohnlev CPUID_AMD_EDX_SYSC | CPUID_INTC_EDX_SEP | 485843e1988Sjohnlev CPUID_INTC_EDX_PSE36 | CPUID_INTC_EDX_HTT); 486843e1988Sjohnlev break; 487e4b86885SCheng Sean Ye } 488ae115bc7Smrj 489843e1988Sjohnlev case 0x80000001: 490843e1988Sjohnlev cp->cp_edx &= 491843e1988Sjohnlev ~(CPUID_AMD_EDX_PSE | 492843e1988Sjohnlev CPUID_INTC_EDX_VME | CPUID_INTC_EDX_DE | 493843e1988Sjohnlev CPUID_AMD_EDX_MTRR | CPUID_AMD_EDX_PGE | 494843e1988Sjohnlev CPUID_AMD_EDX_PAT | CPUID_AMD_EDX_PSE36 | 495843e1988Sjohnlev CPUID_AMD_EDX_SYSC | CPUID_INTC_EDX_SEP | 496843e1988Sjohnlev CPUID_AMD_EDX_TSCP); 497843e1988Sjohnlev cp->cp_ecx &= ~CPUID_AMD_ECX_CMP_LGCY; 498843e1988Sjohnlev break; 499843e1988Sjohnlev default: 500843e1988Sjohnlev break; 501843e1988Sjohnlev } 502843e1988Sjohnlev 503843e1988Sjohnlev switch (vendor) { 504843e1988Sjohnlev case X86_VENDOR_Intel: 505843e1988Sjohnlev switch (eax) { 506843e1988Sjohnlev case 4: 507843e1988Sjohnlev /* 508843e1988Sjohnlev * Zero out the (ncores-per-chip - 1) field 509843e1988Sjohnlev */ 510843e1988Sjohnlev cp->cp_eax &= 0x03fffffff; 511843e1988Sjohnlev break; 512843e1988Sjohnlev default: 513843e1988Sjohnlev break; 514843e1988Sjohnlev } 515843e1988Sjohnlev break; 516843e1988Sjohnlev case X86_VENDOR_AMD: 517843e1988Sjohnlev switch (eax) { 5182ef50f01SJoe Bonasera 5192ef50f01SJoe Bonasera case 0x80000001: 5202ef50f01SJoe Bonasera cp->cp_ecx &= ~CPUID_AMD_ECX_CR8D; 5212ef50f01SJoe Bonasera break; 5222ef50f01SJoe Bonasera 523843e1988Sjohnlev case 0x80000008: 524843e1988Sjohnlev /* 525843e1988Sjohnlev * Zero out the (ncores-per-chip - 1) field 526843e1988Sjohnlev */ 527843e1988Sjohnlev cp->cp_ecx &= 0xffffff00; 528843e1988Sjohnlev break; 529843e1988Sjohnlev default: 530843e1988Sjohnlev break; 531843e1988Sjohnlev } 532843e1988Sjohnlev break; 533843e1988Sjohnlev default: 534843e1988Sjohnlev break; 535843e1988Sjohnlev } 536843e1988Sjohnlev } 537843e1988Sjohnlev #else 538ae115bc7Smrj #define platform_cpuid_mangle(vendor, eax, cp) /* nothing */ 539843e1988Sjohnlev #endif 540ae115bc7Smrj 541ae115bc7Smrj /* 5427c478bd9Sstevel@tonic-gate * Some undocumented ways of patching the results of the cpuid 5437c478bd9Sstevel@tonic-gate * instruction to permit running Solaris 10 on future cpus that 5447c478bd9Sstevel@tonic-gate * we don't currently support. Could be set to non-zero values 5457c478bd9Sstevel@tonic-gate * via settings in eeprom. 5467c478bd9Sstevel@tonic-gate */ 5477c478bd9Sstevel@tonic-gate 5487c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_ecx_include; 5497c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_ecx_exclude; 5507c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_edx_include; 5517c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_edx_exclude; 5527c478bd9Sstevel@tonic-gate 553a3114836SGerry Liu /* 554a3114836SGerry Liu * Allocate space for mcpu_cpi in the machcpu structure for all non-boot CPUs. 555a3114836SGerry Liu */ 556ae115bc7Smrj void 557ae115bc7Smrj cpuid_alloc_space(cpu_t *cpu) 558ae115bc7Smrj { 559ae115bc7Smrj /* 560ae115bc7Smrj * By convention, cpu0 is the boot cpu, which is set up 561ae115bc7Smrj * before memory allocation is available. All other cpus get 562ae115bc7Smrj * their cpuid_info struct allocated here. 563ae115bc7Smrj */ 564ae115bc7Smrj ASSERT(cpu->cpu_id != 0); 565a3114836SGerry Liu ASSERT(cpu->cpu_m.mcpu_cpi == NULL); 566ae115bc7Smrj cpu->cpu_m.mcpu_cpi = 567ae115bc7Smrj kmem_zalloc(sizeof (*cpu->cpu_m.mcpu_cpi), KM_SLEEP); 568ae115bc7Smrj } 569ae115bc7Smrj 570ae115bc7Smrj void 571ae115bc7Smrj cpuid_free_space(cpu_t *cpu) 572ae115bc7Smrj { 573d129bde2Sesaxe struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi; 574d129bde2Sesaxe int i; 575d129bde2Sesaxe 576a3114836SGerry Liu ASSERT(cpi != NULL); 577a3114836SGerry Liu ASSERT(cpi != &cpuid_info0); 578d129bde2Sesaxe 579d129bde2Sesaxe /* 580d129bde2Sesaxe * Free up any function 4 related dynamic storage 581d129bde2Sesaxe */ 582d129bde2Sesaxe for (i = 1; i < cpi->cpi_std_4_size; i++) 583d129bde2Sesaxe kmem_free(cpi->cpi_std_4[i], sizeof (struct cpuid_regs)); 584d129bde2Sesaxe if (cpi->cpi_std_4_size > 0) 585d129bde2Sesaxe kmem_free(cpi->cpi_std_4, 586d129bde2Sesaxe cpi->cpi_std_4_size * sizeof (struct cpuid_regs *)); 587d129bde2Sesaxe 588a3114836SGerry Liu kmem_free(cpi, sizeof (*cpi)); 589a3114836SGerry Liu cpu->cpu_m.mcpu_cpi = NULL; 590ae115bc7Smrj } 591ae115bc7Smrj 592551bc2a6Smrj #if !defined(__xpv) 593551bc2a6Smrj 594cfe84b82SMatt Amdur /* 595cfe84b82SMatt Amdur * Determine the type of the underlying platform. This is used to customize 596cfe84b82SMatt Amdur * initialization of various subsystems (e.g. TSC). determine_platform() must 597cfe84b82SMatt Amdur * only ever be called once to prevent two processors from seeing different 598cfe84b82SMatt Amdur * values of platform_type, it must be called before cpuid_pass1(), the 599cfe84b82SMatt Amdur * earliest consumer to execute. 600cfe84b82SMatt Amdur */ 601cfe84b82SMatt Amdur void 602cfe84b82SMatt Amdur determine_platform(void) 603551bc2a6Smrj { 604551bc2a6Smrj struct cpuid_regs cp; 605551bc2a6Smrj char *xen_str; 6066e5580c9SFrank Van Der Linden uint32_t xen_signature[4], base; 607551bc2a6Smrj 608cfe84b82SMatt Amdur ASSERT(platform_type == -1); 609cfe84b82SMatt Amdur 610349b53ddSStuart Maybee platform_type = HW_NATIVE; 611349b53ddSStuart Maybee 612349b53ddSStuart Maybee if (!enable_platform_detection) 613349b53ddSStuart Maybee return; 614349b53ddSStuart Maybee 615551bc2a6Smrj /* 616551bc2a6Smrj * In a fully virtualized domain, Xen's pseudo-cpuid function 6176e5580c9SFrank Van Der Linden * returns a string representing the Xen signature in %ebx, %ecx, 6186e5580c9SFrank Van Der Linden * and %edx. %eax contains the maximum supported cpuid function. 6196e5580c9SFrank Van Der Linden * We need at least a (base + 2) leaf value to do what we want 6206e5580c9SFrank Van Der Linden * to do. Try different base values, since the hypervisor might 6216e5580c9SFrank Van Der Linden * use a different one depending on whether hyper-v emulation 6226e5580c9SFrank Van Der Linden * is switched on by default or not. 623551bc2a6Smrj */ 6246e5580c9SFrank Van Der Linden for (base = 0x40000000; base < 0x40010000; base += 0x100) { 6256e5580c9SFrank Van Der Linden cp.cp_eax = base; 626551bc2a6Smrj (void) __cpuid_insn(&cp); 627551bc2a6Smrj xen_signature[0] = cp.cp_ebx; 628551bc2a6Smrj xen_signature[1] = cp.cp_ecx; 629551bc2a6Smrj xen_signature[2] = cp.cp_edx; 630551bc2a6Smrj xen_signature[3] = 0; 631551bc2a6Smrj xen_str = (char *)xen_signature; 6326e5580c9SFrank Van Der Linden if (strcmp("XenVMMXenVMM", xen_str) == 0 && 6336e5580c9SFrank Van Der Linden cp.cp_eax >= (base + 2)) { 634b9bfdccdSStuart Maybee platform_type = HW_XEN_HVM; 6356e5580c9SFrank Van Der Linden return; 636551bc2a6Smrj } 637b9bfdccdSStuart Maybee } 638b9bfdccdSStuart Maybee 6396e5580c9SFrank Van Der Linden if (vmware_platform()) /* running under vmware hypervisor? */ 6406e5580c9SFrank Van Der Linden platform_type = HW_VMWARE; 6416e5580c9SFrank Van Der Linden } 6426e5580c9SFrank Van Der Linden 643b9bfdccdSStuart Maybee int 644b9bfdccdSStuart Maybee get_hwenv(void) 645b9bfdccdSStuart Maybee { 646cfe84b82SMatt Amdur ASSERT(platform_type != -1); 647b9bfdccdSStuart Maybee return (platform_type); 648b9bfdccdSStuart Maybee } 649b9bfdccdSStuart Maybee 650b9bfdccdSStuart Maybee int 651b9bfdccdSStuart Maybee is_controldom(void) 652b9bfdccdSStuart Maybee { 653b9bfdccdSStuart Maybee return (0); 654b9bfdccdSStuart Maybee } 655b9bfdccdSStuart Maybee 656b9bfdccdSStuart Maybee #else 657b9bfdccdSStuart Maybee 658b9bfdccdSStuart Maybee int 659b9bfdccdSStuart Maybee get_hwenv(void) 660b9bfdccdSStuart Maybee { 661b9bfdccdSStuart Maybee return (HW_XEN_PV); 662b9bfdccdSStuart Maybee } 663b9bfdccdSStuart Maybee 664b9bfdccdSStuart Maybee int 665b9bfdccdSStuart Maybee is_controldom(void) 666b9bfdccdSStuart Maybee { 667b9bfdccdSStuart Maybee return (DOMAIN_IS_INITDOMAIN(xen_info)); 668b9bfdccdSStuart Maybee } 669b9bfdccdSStuart Maybee 670551bc2a6Smrj #endif /* __xpv */ 671551bc2a6Smrj 6728031591dSSrihari Venkatesan static void 6737417cfdeSKuriakose Kuruvilla cpuid_intel_getids(cpu_t *cpu, void *feature) 6748031591dSSrihari Venkatesan { 6758031591dSSrihari Venkatesan uint_t i; 6768031591dSSrihari Venkatesan uint_t chipid_shift = 0; 6778031591dSSrihari Venkatesan uint_t coreid_shift = 0; 6788031591dSSrihari Venkatesan struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi; 6798031591dSSrihari Venkatesan 6808031591dSSrihari Venkatesan for (i = 1; i < cpi->cpi_ncpu_per_chip; i <<= 1) 6818031591dSSrihari Venkatesan chipid_shift++; 6828031591dSSrihari Venkatesan 6838031591dSSrihari Venkatesan cpi->cpi_chipid = cpi->cpi_apicid >> chipid_shift; 6848031591dSSrihari Venkatesan cpi->cpi_clogid = cpi->cpi_apicid & ((1 << chipid_shift) - 1); 6858031591dSSrihari Venkatesan 6867417cfdeSKuriakose Kuruvilla if (is_x86_feature(feature, X86FSET_CMP)) { 6878031591dSSrihari Venkatesan /* 6888031591dSSrihari Venkatesan * Multi-core (and possibly multi-threaded) 6898031591dSSrihari Venkatesan * processors. 6908031591dSSrihari Venkatesan */ 6918031591dSSrihari Venkatesan uint_t ncpu_per_core; 6928031591dSSrihari Venkatesan if (cpi->cpi_ncore_per_chip == 1) 6938031591dSSrihari Venkatesan ncpu_per_core = cpi->cpi_ncpu_per_chip; 6948031591dSSrihari Venkatesan else if (cpi->cpi_ncore_per_chip > 1) 6958031591dSSrihari Venkatesan ncpu_per_core = cpi->cpi_ncpu_per_chip / 6968031591dSSrihari Venkatesan cpi->cpi_ncore_per_chip; 6978031591dSSrihari Venkatesan /* 6988031591dSSrihari Venkatesan * 8bit APIC IDs on dual core Pentiums 6998031591dSSrihari Venkatesan * look like this: 7008031591dSSrihari Venkatesan * 7018031591dSSrihari Venkatesan * +-----------------------+------+------+ 7028031591dSSrihari Venkatesan * | Physical Package ID | MC | HT | 7038031591dSSrihari Venkatesan * +-----------------------+------+------+ 7048031591dSSrihari Venkatesan * <------- chipid --------> 7058031591dSSrihari Venkatesan * <------- coreid ---------------> 7068031591dSSrihari Venkatesan * <--- clogid --> 7078031591dSSrihari Venkatesan * <------> 7088031591dSSrihari Venkatesan * pkgcoreid 7098031591dSSrihari Venkatesan * 7108031591dSSrihari Venkatesan * Where the number of bits necessary to 7118031591dSSrihari Venkatesan * represent MC and HT fields together equals 7128031591dSSrihari Venkatesan * to the minimum number of bits necessary to 7138031591dSSrihari Venkatesan * store the value of cpi->cpi_ncpu_per_chip. 7148031591dSSrihari Venkatesan * Of those bits, the MC part uses the number 7158031591dSSrihari Venkatesan * of bits necessary to store the value of 7168031591dSSrihari Venkatesan * cpi->cpi_ncore_per_chip. 7178031591dSSrihari Venkatesan */ 7188031591dSSrihari Venkatesan for (i = 1; i < ncpu_per_core; i <<= 1) 7198031591dSSrihari Venkatesan coreid_shift++; 7208031591dSSrihari Venkatesan cpi->cpi_coreid = cpi->cpi_apicid >> coreid_shift; 7218031591dSSrihari Venkatesan cpi->cpi_pkgcoreid = cpi->cpi_clogid >> coreid_shift; 7227417cfdeSKuriakose Kuruvilla } else if (is_x86_feature(feature, X86FSET_HTT)) { 7238031591dSSrihari Venkatesan /* 7248031591dSSrihari Venkatesan * Single-core multi-threaded processors. 7258031591dSSrihari Venkatesan */ 7268031591dSSrihari Venkatesan cpi->cpi_coreid = cpi->cpi_chipid; 7278031591dSSrihari Venkatesan cpi->cpi_pkgcoreid = 0; 7288031591dSSrihari Venkatesan } 7298031591dSSrihari Venkatesan cpi->cpi_procnodeid = cpi->cpi_chipid; 7308031591dSSrihari Venkatesan } 7318031591dSSrihari Venkatesan 7328031591dSSrihari Venkatesan static void 7338031591dSSrihari Venkatesan cpuid_amd_getids(cpu_t *cpu) 7348031591dSSrihari Venkatesan { 7351fbe4a4fSSrihari Venkatesan int i, first_half, coreidsz; 7368031591dSSrihari Venkatesan uint32_t nb_caps_reg; 7378031591dSSrihari Venkatesan uint_t node2_1; 7388031591dSSrihari Venkatesan struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi; 7398031591dSSrihari Venkatesan 7408031591dSSrihari Venkatesan /* 7418031591dSSrihari Venkatesan * AMD CMP chips currently have a single thread per core. 7428031591dSSrihari Venkatesan * 7438031591dSSrihari Venkatesan * Since no two cpus share a core we must assign a distinct coreid 7448031591dSSrihari Venkatesan * per cpu, and we do this by using the cpu_id. This scheme does not, 7458031591dSSrihari Venkatesan * however, guarantee that sibling cores of a chip will have sequential 7468031591dSSrihari Venkatesan * coreids starting at a multiple of the number of cores per chip - 7478031591dSSrihari Venkatesan * that is usually the case, but if the ACPI MADT table is presented 7488031591dSSrihari Venkatesan * in a different order then we need to perform a few more gymnastics 7498031591dSSrihari Venkatesan * for the pkgcoreid. 7508031591dSSrihari Venkatesan * 7518031591dSSrihari Venkatesan * All processors in the system have the same number of enabled 7528031591dSSrihari Venkatesan * cores. Cores within a processor are always numbered sequentially 7538031591dSSrihari Venkatesan * from 0 regardless of how many or which are disabled, and there 7548031591dSSrihari Venkatesan * is no way for operating system to discover the real core id when some 7558031591dSSrihari Venkatesan * are disabled. 7568031591dSSrihari Venkatesan */ 7578031591dSSrihari Venkatesan 7588031591dSSrihari Venkatesan cpi->cpi_coreid = cpu->cpu_id; 7598031591dSSrihari Venkatesan 7608031591dSSrihari Venkatesan if (cpi->cpi_xmaxeax >= 0x80000008) { 7618031591dSSrihari Venkatesan 7628031591dSSrihari Venkatesan coreidsz = BITX((cpi)->cpi_extd[8].cp_ecx, 15, 12); 7638031591dSSrihari Venkatesan 7648031591dSSrihari Venkatesan /* 7658031591dSSrihari Venkatesan * In AMD parlance chip is really a node while Solaris 7668031591dSSrihari Venkatesan * sees chip as equivalent to socket/package. 7678031591dSSrihari Venkatesan */ 7688031591dSSrihari Venkatesan cpi->cpi_ncore_per_chip = 7698031591dSSrihari Venkatesan BITX((cpi)->cpi_extd[8].cp_ecx, 7, 0) + 1; 7701fbe4a4fSSrihari Venkatesan if (coreidsz == 0) { 7718031591dSSrihari Venkatesan /* Use legacy method */ 7721fbe4a4fSSrihari Venkatesan for (i = 1; i < cpi->cpi_ncore_per_chip; i <<= 1) 7731fbe4a4fSSrihari Venkatesan coreidsz++; 7741fbe4a4fSSrihari Venkatesan if (coreidsz == 0) 7751fbe4a4fSSrihari Venkatesan coreidsz = 1; 7761fbe4a4fSSrihari Venkatesan } 7778031591dSSrihari Venkatesan } else { 7788031591dSSrihari Venkatesan /* Assume single-core part */ 7791fbe4a4fSSrihari Venkatesan cpi->cpi_ncore_per_chip = 1; 78072b70389SJakub Jermar coreidsz = 1; 7818031591dSSrihari Venkatesan } 7828031591dSSrihari Venkatesan 7831fbe4a4fSSrihari Venkatesan cpi->cpi_clogid = cpi->cpi_pkgcoreid = 7841fbe4a4fSSrihari Venkatesan cpi->cpi_apicid & ((1<<coreidsz) - 1); 7858031591dSSrihari Venkatesan cpi->cpi_ncpu_per_chip = cpi->cpi_ncore_per_chip; 7868031591dSSrihari Venkatesan 7878031591dSSrihari Venkatesan /* Get nodeID */ 7888031591dSSrihari Venkatesan if (cpi->cpi_family == 0xf) { 7891fbe4a4fSSrihari Venkatesan cpi->cpi_procnodeid = (cpi->cpi_apicid >> coreidsz) & 7; 7908031591dSSrihari Venkatesan cpi->cpi_chipid = cpi->cpi_procnodeid; 7918031591dSSrihari Venkatesan } else if (cpi->cpi_family == 0x10) { 7928031591dSSrihari Venkatesan /* 7938031591dSSrihari Venkatesan * See if we are a multi-node processor. 7948031591dSSrihari Venkatesan * All processors in the system have the same number of nodes 7958031591dSSrihari Venkatesan */ 7968031591dSSrihari Venkatesan nb_caps_reg = pci_getl_func(0, 24, 3, 0xe8); 7978031591dSSrihari Venkatesan if ((cpi->cpi_model < 8) || BITX(nb_caps_reg, 29, 29) == 0) { 7988031591dSSrihari Venkatesan /* Single-node */ 7991fbe4a4fSSrihari Venkatesan cpi->cpi_procnodeid = BITX(cpi->cpi_apicid, 5, 8001fbe4a4fSSrihari Venkatesan coreidsz); 8018031591dSSrihari Venkatesan cpi->cpi_chipid = cpi->cpi_procnodeid; 8028031591dSSrihari Venkatesan } else { 8038031591dSSrihari Venkatesan 8048031591dSSrihari Venkatesan /* 8058031591dSSrihari Venkatesan * Multi-node revision D (2 nodes per package 8068031591dSSrihari Venkatesan * are supported) 8078031591dSSrihari Venkatesan */ 8088031591dSSrihari Venkatesan cpi->cpi_procnodes_per_pkg = 2; 8098031591dSSrihari Venkatesan 8108031591dSSrihari Venkatesan first_half = (cpi->cpi_pkgcoreid <= 8118031591dSSrihari Venkatesan (cpi->cpi_ncore_per_chip/2 - 1)); 8128031591dSSrihari Venkatesan 8138031591dSSrihari Venkatesan if (cpi->cpi_apicid == cpi->cpi_pkgcoreid) { 8148031591dSSrihari Venkatesan /* We are BSP */ 8158031591dSSrihari Venkatesan cpi->cpi_procnodeid = (first_half ? 0 : 1); 8168031591dSSrihari Venkatesan cpi->cpi_chipid = cpi->cpi_procnodeid >> 1; 8178031591dSSrihari Venkatesan } else { 8188031591dSSrihari Venkatesan 8198031591dSSrihari Venkatesan /* We are AP */ 8208031591dSSrihari Venkatesan /* NodeId[2:1] bits to use for reading F3xe8 */ 8218031591dSSrihari Venkatesan node2_1 = BITX(cpi->cpi_apicid, 5, 4) << 1; 8228031591dSSrihari Venkatesan 8238031591dSSrihari Venkatesan nb_caps_reg = 8248031591dSSrihari Venkatesan pci_getl_func(0, 24 + node2_1, 3, 0xe8); 8258031591dSSrihari Venkatesan 8268031591dSSrihari Venkatesan /* 8278031591dSSrihari Venkatesan * Check IntNodeNum bit (31:30, but bit 31 is 8288031591dSSrihari Venkatesan * always 0 on dual-node processors) 8298031591dSSrihari Venkatesan */ 8308031591dSSrihari Venkatesan if (BITX(nb_caps_reg, 30, 30) == 0) 8318031591dSSrihari Venkatesan cpi->cpi_procnodeid = node2_1 + 8328031591dSSrihari Venkatesan !first_half; 8338031591dSSrihari Venkatesan else 8348031591dSSrihari Venkatesan cpi->cpi_procnodeid = node2_1 + 8358031591dSSrihari Venkatesan first_half; 8368031591dSSrihari Venkatesan 8378031591dSSrihari Venkatesan cpi->cpi_chipid = cpi->cpi_procnodeid >> 1; 8388031591dSSrihari Venkatesan } 8398031591dSSrihari Venkatesan } 8408031591dSSrihari Venkatesan } else if (cpi->cpi_family >= 0x11) { 8418031591dSSrihari Venkatesan cpi->cpi_procnodeid = (cpi->cpi_apicid >> coreidsz) & 7; 8428031591dSSrihari Venkatesan cpi->cpi_chipid = cpi->cpi_procnodeid; 8438031591dSSrihari Venkatesan } else { 8448031591dSSrihari Venkatesan cpi->cpi_procnodeid = 0; 8458031591dSSrihari Venkatesan cpi->cpi_chipid = cpi->cpi_procnodeid; 8468031591dSSrihari Venkatesan } 8478031591dSSrihari Venkatesan } 8488031591dSSrihari Venkatesan 8497af88ac7SKuriakose Kuruvilla /* 8507af88ac7SKuriakose Kuruvilla * Setup XFeature_Enabled_Mask register. Required by xsave feature. 8517af88ac7SKuriakose Kuruvilla */ 8527af88ac7SKuriakose Kuruvilla void 8537af88ac7SKuriakose Kuruvilla setup_xfem(void) 8547af88ac7SKuriakose Kuruvilla { 8557af88ac7SKuriakose Kuruvilla uint64_t flags = XFEATURE_LEGACY_FP; 8567af88ac7SKuriakose Kuruvilla 8577af88ac7SKuriakose Kuruvilla ASSERT(is_x86_feature(x86_featureset, X86FSET_XSAVE)); 8587af88ac7SKuriakose Kuruvilla 8597af88ac7SKuriakose Kuruvilla if (is_x86_feature(x86_featureset, X86FSET_SSE)) 8607af88ac7SKuriakose Kuruvilla flags |= XFEATURE_SSE; 8617af88ac7SKuriakose Kuruvilla 8627af88ac7SKuriakose Kuruvilla if (is_x86_feature(x86_featureset, X86FSET_AVX)) 8637af88ac7SKuriakose Kuruvilla flags |= XFEATURE_AVX; 8647af88ac7SKuriakose Kuruvilla 8657af88ac7SKuriakose Kuruvilla set_xcr(XFEATURE_ENABLED_MASK, flags); 8667af88ac7SKuriakose Kuruvilla 8677af88ac7SKuriakose Kuruvilla xsave_bv_all = flags; 8687af88ac7SKuriakose Kuruvilla } 8697af88ac7SKuriakose Kuruvilla 870dfea898aSKuriakose Kuruvilla void 871dfea898aSKuriakose Kuruvilla cpuid_pass1(cpu_t *cpu, uchar_t *featureset) 8727c478bd9Sstevel@tonic-gate { 8737c478bd9Sstevel@tonic-gate uint32_t mask_ecx, mask_edx; 8747c478bd9Sstevel@tonic-gate struct cpuid_info *cpi; 8758949bcd6Sandrei struct cpuid_regs *cp; 8767c478bd9Sstevel@tonic-gate int xcpuid; 877843e1988Sjohnlev #if !defined(__xpv) 8785b8a6efeSbholler extern int idle_cpu_prefer_mwait; 879843e1988Sjohnlev #endif 880ae115bc7Smrj 8817c478bd9Sstevel@tonic-gate /* 882a3114836SGerry Liu * Space statically allocated for BSP, ensure pointer is set 8837c478bd9Sstevel@tonic-gate */ 8847417cfdeSKuriakose Kuruvilla if (cpu->cpu_id == 0) { 8857417cfdeSKuriakose Kuruvilla if (cpu->cpu_m.mcpu_cpi == NULL) 886ae115bc7Smrj cpu->cpu_m.mcpu_cpi = &cpuid_info0; 8877417cfdeSKuriakose Kuruvilla } 8887417cfdeSKuriakose Kuruvilla 8897417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_CPUID); 8907417cfdeSKuriakose Kuruvilla 891ae115bc7Smrj cpi = cpu->cpu_m.mcpu_cpi; 892ae115bc7Smrj ASSERT(cpi != NULL); 8937c478bd9Sstevel@tonic-gate cp = &cpi->cpi_std[0]; 8948949bcd6Sandrei cp->cp_eax = 0; 8958949bcd6Sandrei cpi->cpi_maxeax = __cpuid_insn(cp); 8967c478bd9Sstevel@tonic-gate { 8977c478bd9Sstevel@tonic-gate uint32_t *iptr = (uint32_t *)cpi->cpi_vendorstr; 8987c478bd9Sstevel@tonic-gate *iptr++ = cp->cp_ebx; 8997c478bd9Sstevel@tonic-gate *iptr++ = cp->cp_edx; 9007c478bd9Sstevel@tonic-gate *iptr++ = cp->cp_ecx; 9017c478bd9Sstevel@tonic-gate *(char *)&cpi->cpi_vendorstr[12] = '\0'; 9027c478bd9Sstevel@tonic-gate } 9037c478bd9Sstevel@tonic-gate 904e4b86885SCheng Sean Ye cpi->cpi_vendor = _cpuid_vendorstr_to_vendorcode(cpi->cpi_vendorstr); 9057c478bd9Sstevel@tonic-gate x86_vendor = cpi->cpi_vendor; /* for compatibility */ 9067c478bd9Sstevel@tonic-gate 9077c478bd9Sstevel@tonic-gate /* 9087c478bd9Sstevel@tonic-gate * Limit the range in case of weird hardware 9097c478bd9Sstevel@tonic-gate */ 9107c478bd9Sstevel@tonic-gate if (cpi->cpi_maxeax > CPI_MAXEAX_MAX) 9117c478bd9Sstevel@tonic-gate cpi->cpi_maxeax = CPI_MAXEAX_MAX; 9127c478bd9Sstevel@tonic-gate if (cpi->cpi_maxeax < 1) 9137c478bd9Sstevel@tonic-gate goto pass1_done; 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate cp = &cpi->cpi_std[1]; 9168949bcd6Sandrei cp->cp_eax = 1; 9178949bcd6Sandrei (void) __cpuid_insn(cp); 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate /* 9207c478bd9Sstevel@tonic-gate * Extract identifying constants for easy access. 9217c478bd9Sstevel@tonic-gate */ 9227c478bd9Sstevel@tonic-gate cpi->cpi_model = CPI_MODEL(cpi); 9237c478bd9Sstevel@tonic-gate cpi->cpi_family = CPI_FAMILY(cpi); 9247c478bd9Sstevel@tonic-gate 9255ff02082Sdmick if (cpi->cpi_family == 0xf) 9267c478bd9Sstevel@tonic-gate cpi->cpi_family += CPI_FAMILY_XTD(cpi); 9275ff02082Sdmick 92868c91426Sdmick /* 929875b116eSkchow * Beware: AMD uses "extended model" iff base *FAMILY* == 0xf. 93068c91426Sdmick * Intel, and presumably everyone else, uses model == 0xf, as 93168c91426Sdmick * one would expect (max value means possible overflow). Sigh. 93268c91426Sdmick */ 93368c91426Sdmick 93468c91426Sdmick switch (cpi->cpi_vendor) { 935bf91205bSksadhukh case X86_VENDOR_Intel: 936bf91205bSksadhukh if (IS_EXTENDED_MODEL_INTEL(cpi)) 937bf91205bSksadhukh cpi->cpi_model += CPI_MODEL_XTD(cpi) << 4; 938447af253Sksadhukh break; 93968c91426Sdmick case X86_VENDOR_AMD: 940875b116eSkchow if (CPI_FAMILY(cpi) == 0xf) 94168c91426Sdmick cpi->cpi_model += CPI_MODEL_XTD(cpi) << 4; 94268c91426Sdmick break; 94368c91426Sdmick default: 9445ff02082Sdmick if (cpi->cpi_model == 0xf) 9457c478bd9Sstevel@tonic-gate cpi->cpi_model += CPI_MODEL_XTD(cpi) << 4; 94668c91426Sdmick break; 94768c91426Sdmick } 9487c478bd9Sstevel@tonic-gate 9497c478bd9Sstevel@tonic-gate cpi->cpi_step = CPI_STEP(cpi); 9507c478bd9Sstevel@tonic-gate cpi->cpi_brandid = CPI_BRANDID(cpi); 9517c478bd9Sstevel@tonic-gate 9527c478bd9Sstevel@tonic-gate /* 9537c478bd9Sstevel@tonic-gate * *default* assumptions: 9547c478bd9Sstevel@tonic-gate * - believe %edx feature word 9557c478bd9Sstevel@tonic-gate * - ignore %ecx feature word 9567c478bd9Sstevel@tonic-gate * - 32-bit virtual and physical addressing 9577c478bd9Sstevel@tonic-gate */ 9587c478bd9Sstevel@tonic-gate mask_edx = 0xffffffff; 9597c478bd9Sstevel@tonic-gate mask_ecx = 0; 9607c478bd9Sstevel@tonic-gate 9617c478bd9Sstevel@tonic-gate cpi->cpi_pabits = cpi->cpi_vabits = 32; 9627c478bd9Sstevel@tonic-gate 9637c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 9647c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 9657c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 5) 9667c478bd9Sstevel@tonic-gate x86_type = X86_TYPE_P5; 9675ff02082Sdmick else if (IS_LEGACY_P6(cpi)) { 9687c478bd9Sstevel@tonic-gate x86_type = X86_TYPE_P6; 9697c478bd9Sstevel@tonic-gate pentiumpro_bug4046376 = 1; 9707c478bd9Sstevel@tonic-gate pentiumpro_bug4064495 = 1; 9717c478bd9Sstevel@tonic-gate /* 9727c478bd9Sstevel@tonic-gate * Clear the SEP bit when it was set erroneously 9737c478bd9Sstevel@tonic-gate */ 9747c478bd9Sstevel@tonic-gate if (cpi->cpi_model < 3 && cpi->cpi_step < 3) 9757c478bd9Sstevel@tonic-gate cp->cp_edx &= ~CPUID_INTC_EDX_SEP; 9765ff02082Sdmick } else if (IS_NEW_F6(cpi) || cpi->cpi_family == 0xf) { 9777c478bd9Sstevel@tonic-gate x86_type = X86_TYPE_P4; 9787c478bd9Sstevel@tonic-gate /* 9797c478bd9Sstevel@tonic-gate * We don't currently depend on any of the %ecx 9807c478bd9Sstevel@tonic-gate * features until Prescott, so we'll only check 9817c478bd9Sstevel@tonic-gate * this from P4 onwards. We might want to revisit 9827c478bd9Sstevel@tonic-gate * that idea later. 9837c478bd9Sstevel@tonic-gate */ 9847c478bd9Sstevel@tonic-gate mask_ecx = 0xffffffff; 9857c478bd9Sstevel@tonic-gate } else if (cpi->cpi_family > 0xf) 9867c478bd9Sstevel@tonic-gate mask_ecx = 0xffffffff; 9877c622d23Sbholler /* 9887c622d23Sbholler * We don't support MONITOR/MWAIT if leaf 5 is not available 9897c622d23Sbholler * to obtain the monitor linesize. 9907c622d23Sbholler */ 9917c622d23Sbholler if (cpi->cpi_maxeax < 5) 9927c622d23Sbholler mask_ecx &= ~CPUID_INTC_ECX_MON; 9937c478bd9Sstevel@tonic-gate break; 9947c478bd9Sstevel@tonic-gate case X86_VENDOR_IntelClone: 9957c478bd9Sstevel@tonic-gate default: 9967c478bd9Sstevel@tonic-gate break; 9977c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 9987c478bd9Sstevel@tonic-gate #if defined(OPTERON_ERRATUM_108) 9997c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 0xf && cpi->cpi_model == 0xe) { 10007c478bd9Sstevel@tonic-gate cp->cp_eax = (0xf0f & cp->cp_eax) | 0xc0; 10017c478bd9Sstevel@tonic-gate cpi->cpi_model = 0xc; 10027c478bd9Sstevel@tonic-gate } else 10037c478bd9Sstevel@tonic-gate #endif 10047c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 5) { 10057c478bd9Sstevel@tonic-gate /* 10067c478bd9Sstevel@tonic-gate * AMD K5 and K6 10077c478bd9Sstevel@tonic-gate * 10087c478bd9Sstevel@tonic-gate * These CPUs have an incomplete implementation 10097c478bd9Sstevel@tonic-gate * of MCA/MCE which we mask away. 10107c478bd9Sstevel@tonic-gate */ 10118949bcd6Sandrei mask_edx &= ~(CPUID_INTC_EDX_MCE | CPUID_INTC_EDX_MCA); 10128949bcd6Sandrei 10137c478bd9Sstevel@tonic-gate /* 10147c478bd9Sstevel@tonic-gate * Model 0 uses the wrong (APIC) bit 10157c478bd9Sstevel@tonic-gate * to indicate PGE. Fix it here. 10167c478bd9Sstevel@tonic-gate */ 10178949bcd6Sandrei if (cpi->cpi_model == 0) { 10187c478bd9Sstevel@tonic-gate if (cp->cp_edx & 0x200) { 10197c478bd9Sstevel@tonic-gate cp->cp_edx &= ~0x200; 10207c478bd9Sstevel@tonic-gate cp->cp_edx |= CPUID_INTC_EDX_PGE; 10217c478bd9Sstevel@tonic-gate } 10227c478bd9Sstevel@tonic-gate } 10238949bcd6Sandrei 10248949bcd6Sandrei /* 10258949bcd6Sandrei * Early models had problems w/ MMX; disable. 10268949bcd6Sandrei */ 10278949bcd6Sandrei if (cpi->cpi_model < 6) 10288949bcd6Sandrei mask_edx &= ~CPUID_INTC_EDX_MMX; 10298949bcd6Sandrei } 10308949bcd6Sandrei 10318949bcd6Sandrei /* 10328949bcd6Sandrei * For newer families, SSE3 and CX16, at least, are valid; 10338949bcd6Sandrei * enable all 10348949bcd6Sandrei */ 10358949bcd6Sandrei if (cpi->cpi_family >= 0xf) 10368949bcd6Sandrei mask_ecx = 0xffffffff; 10377c622d23Sbholler /* 10387c622d23Sbholler * We don't support MONITOR/MWAIT if leaf 5 is not available 10397c622d23Sbholler * to obtain the monitor linesize. 10407c622d23Sbholler */ 10417c622d23Sbholler if (cpi->cpi_maxeax < 5) 10427c622d23Sbholler mask_ecx &= ~CPUID_INTC_ECX_MON; 10435b8a6efeSbholler 1044843e1988Sjohnlev #if !defined(__xpv) 10455b8a6efeSbholler /* 10465b8a6efeSbholler * Do not use MONITOR/MWAIT to halt in the idle loop on any AMD 10475b8a6efeSbholler * processors. AMD does not intend MWAIT to be used in the cpu 10485b8a6efeSbholler * idle loop on current and future processors. 10h and future 10495b8a6efeSbholler * AMD processors use more power in MWAIT than HLT. 10505b8a6efeSbholler * Pre-family-10h Opterons do not have the MWAIT instruction. 10515b8a6efeSbholler */ 10525b8a6efeSbholler idle_cpu_prefer_mwait = 0; 1053843e1988Sjohnlev #endif 10545b8a6efeSbholler 10557c478bd9Sstevel@tonic-gate break; 10567c478bd9Sstevel@tonic-gate case X86_VENDOR_TM: 10577c478bd9Sstevel@tonic-gate /* 10587c478bd9Sstevel@tonic-gate * workaround the NT workaround in CMS 4.1 10597c478bd9Sstevel@tonic-gate */ 10607c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 5 && cpi->cpi_model == 4 && 10617c478bd9Sstevel@tonic-gate (cpi->cpi_step == 2 || cpi->cpi_step == 3)) 10627c478bd9Sstevel@tonic-gate cp->cp_edx |= CPUID_INTC_EDX_CX8; 10637c478bd9Sstevel@tonic-gate break; 10647c478bd9Sstevel@tonic-gate case X86_VENDOR_Centaur: 10657c478bd9Sstevel@tonic-gate /* 10667c478bd9Sstevel@tonic-gate * workaround the NT workarounds again 10677c478bd9Sstevel@tonic-gate */ 10687c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 6) 10697c478bd9Sstevel@tonic-gate cp->cp_edx |= CPUID_INTC_EDX_CX8; 10707c478bd9Sstevel@tonic-gate break; 10717c478bd9Sstevel@tonic-gate case X86_VENDOR_Cyrix: 10727c478bd9Sstevel@tonic-gate /* 10737c478bd9Sstevel@tonic-gate * We rely heavily on the probing in locore 10747c478bd9Sstevel@tonic-gate * to actually figure out what parts, if any, 10757c478bd9Sstevel@tonic-gate * of the Cyrix cpuid instruction to believe. 10767c478bd9Sstevel@tonic-gate */ 10777c478bd9Sstevel@tonic-gate switch (x86_type) { 10787c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_486: 10797c478bd9Sstevel@tonic-gate mask_edx = 0; 10807c478bd9Sstevel@tonic-gate break; 10817c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_6x86: 10827c478bd9Sstevel@tonic-gate mask_edx = 0; 10837c478bd9Sstevel@tonic-gate break; 10847c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_6x86L: 10857c478bd9Sstevel@tonic-gate mask_edx = 10867c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_DE | 10877c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_CX8; 10887c478bd9Sstevel@tonic-gate break; 10897c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_6x86MX: 10907c478bd9Sstevel@tonic-gate mask_edx = 10917c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_DE | 10927c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_MSR | 10937c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_CX8 | 10947c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_PGE | 10957c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_CMOV | 10967c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_MMX; 10977c478bd9Sstevel@tonic-gate break; 10987c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_GXm: 10997c478bd9Sstevel@tonic-gate mask_edx = 11007c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_MSR | 11017c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_CX8 | 11027c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_CMOV | 11037c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_MMX; 11047c478bd9Sstevel@tonic-gate break; 11057c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_MediaGX: 11067c478bd9Sstevel@tonic-gate break; 11077c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_MII: 11087c478bd9Sstevel@tonic-gate case X86_TYPE_VIA_CYRIX_III: 11097c478bd9Sstevel@tonic-gate mask_edx = 11107c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_DE | 11117c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_TSC | 11127c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_MSR | 11137c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_CX8 | 11147c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_PGE | 11157c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_CMOV | 11167c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_MMX; 11177c478bd9Sstevel@tonic-gate break; 11187c478bd9Sstevel@tonic-gate default: 11197c478bd9Sstevel@tonic-gate break; 11207c478bd9Sstevel@tonic-gate } 11217c478bd9Sstevel@tonic-gate break; 11227c478bd9Sstevel@tonic-gate } 11237c478bd9Sstevel@tonic-gate 1124843e1988Sjohnlev #if defined(__xpv) 1125843e1988Sjohnlev /* 1126843e1988Sjohnlev * Do not support MONITOR/MWAIT under a hypervisor 1127843e1988Sjohnlev */ 1128843e1988Sjohnlev mask_ecx &= ~CPUID_INTC_ECX_MON; 11297af88ac7SKuriakose Kuruvilla /* 11307af88ac7SKuriakose Kuruvilla * Do not support XSAVE under a hypervisor for now 11317af88ac7SKuriakose Kuruvilla */ 11327af88ac7SKuriakose Kuruvilla xsave_force_disable = B_TRUE; 11337af88ac7SKuriakose Kuruvilla 1134843e1988Sjohnlev #endif /* __xpv */ 1135843e1988Sjohnlev 11367af88ac7SKuriakose Kuruvilla if (xsave_force_disable) { 11377af88ac7SKuriakose Kuruvilla mask_ecx &= ~CPUID_INTC_ECX_XSAVE; 11387af88ac7SKuriakose Kuruvilla mask_ecx &= ~CPUID_INTC_ECX_AVX; 11397af88ac7SKuriakose Kuruvilla } 11407af88ac7SKuriakose Kuruvilla 11417c478bd9Sstevel@tonic-gate /* 11427c478bd9Sstevel@tonic-gate * Now we've figured out the masks that determine 11437c478bd9Sstevel@tonic-gate * which bits we choose to believe, apply the masks 11447c478bd9Sstevel@tonic-gate * to the feature words, then map the kernel's view 11457c478bd9Sstevel@tonic-gate * of these feature words into its feature word. 11467c478bd9Sstevel@tonic-gate */ 11477c478bd9Sstevel@tonic-gate cp->cp_edx &= mask_edx; 11487c478bd9Sstevel@tonic-gate cp->cp_ecx &= mask_ecx; 11497c478bd9Sstevel@tonic-gate 11507c478bd9Sstevel@tonic-gate /* 1151ae115bc7Smrj * apply any platform restrictions (we don't call this 1152ae115bc7Smrj * immediately after __cpuid_insn here, because we need the 1153ae115bc7Smrj * workarounds applied above first) 11547c478bd9Sstevel@tonic-gate */ 1155ae115bc7Smrj platform_cpuid_mangle(cpi->cpi_vendor, 1, cp); 11567c478bd9Sstevel@tonic-gate 1157ae115bc7Smrj /* 1158ae115bc7Smrj * fold in overrides from the "eeprom" mechanism 1159ae115bc7Smrj */ 11607c478bd9Sstevel@tonic-gate cp->cp_edx |= cpuid_feature_edx_include; 11617c478bd9Sstevel@tonic-gate cp->cp_edx &= ~cpuid_feature_edx_exclude; 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate cp->cp_ecx |= cpuid_feature_ecx_include; 11647c478bd9Sstevel@tonic-gate cp->cp_ecx &= ~cpuid_feature_ecx_exclude; 11657c478bd9Sstevel@tonic-gate 11667417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_PSE) { 11677417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_LARGEPAGE); 11687417cfdeSKuriakose Kuruvilla } 11697417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_TSC) { 11707417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_TSC); 11717417cfdeSKuriakose Kuruvilla } 11727417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_MSR) { 11737417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_MSR); 11747417cfdeSKuriakose Kuruvilla } 11757417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_MTRR) { 11767417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_MTRR); 11777417cfdeSKuriakose Kuruvilla } 11787417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_PGE) { 11797417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_PGE); 11807417cfdeSKuriakose Kuruvilla } 11817417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_CMOV) { 11827417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_CMOV); 11837417cfdeSKuriakose Kuruvilla } 11847417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_MMX) { 11857417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_MMX); 11867417cfdeSKuriakose Kuruvilla } 11877c478bd9Sstevel@tonic-gate if ((cp->cp_edx & CPUID_INTC_EDX_MCE) != 0 && 11887417cfdeSKuriakose Kuruvilla (cp->cp_edx & CPUID_INTC_EDX_MCA) != 0) { 11897417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_MCA); 11907417cfdeSKuriakose Kuruvilla } 11917417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_PAE) { 11927417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_PAE); 11937417cfdeSKuriakose Kuruvilla } 11947417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_CX8) { 11957417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_CX8); 11967417cfdeSKuriakose Kuruvilla } 11977417cfdeSKuriakose Kuruvilla if (cp->cp_ecx & CPUID_INTC_ECX_CX16) { 11987417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_CX16); 11997417cfdeSKuriakose Kuruvilla } 12007417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_PAT) { 12017417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_PAT); 12027417cfdeSKuriakose Kuruvilla } 12037417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_SEP) { 12047417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_SEP); 12057417cfdeSKuriakose Kuruvilla } 12067c478bd9Sstevel@tonic-gate if (cp->cp_edx & CPUID_INTC_EDX_FXSR) { 12077c478bd9Sstevel@tonic-gate /* 12087c478bd9Sstevel@tonic-gate * In our implementation, fxsave/fxrstor 12097c478bd9Sstevel@tonic-gate * are prerequisites before we'll even 12107c478bd9Sstevel@tonic-gate * try and do SSE things. 12117c478bd9Sstevel@tonic-gate */ 12127417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_SSE) { 12137417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_SSE); 12147417cfdeSKuriakose Kuruvilla } 12157417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_SSE2) { 12167417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_SSE2); 12177417cfdeSKuriakose Kuruvilla } 12187417cfdeSKuriakose Kuruvilla if (cp->cp_ecx & CPUID_INTC_ECX_SSE3) { 12197417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_SSE3); 12207417cfdeSKuriakose Kuruvilla } 12217417cfdeSKuriakose Kuruvilla if (cp->cp_ecx & CPUID_INTC_ECX_SSSE3) { 12227417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_SSSE3); 12237417cfdeSKuriakose Kuruvilla } 12247417cfdeSKuriakose Kuruvilla if (cp->cp_ecx & CPUID_INTC_ECX_SSE4_1) { 12257417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_SSE4_1); 12267417cfdeSKuriakose Kuruvilla } 12277417cfdeSKuriakose Kuruvilla if (cp->cp_ecx & CPUID_INTC_ECX_SSE4_2) { 12287417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_SSE4_2); 12297417cfdeSKuriakose Kuruvilla } 12307417cfdeSKuriakose Kuruvilla if (cp->cp_ecx & CPUID_INTC_ECX_AES) { 12317417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_AES); 12327417cfdeSKuriakose Kuruvilla } 12337417cfdeSKuriakose Kuruvilla if (cp->cp_ecx & CPUID_INTC_ECX_PCLMULQDQ) { 12347417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_PCLMULQDQ); 1235d0f8ff6eSkk208521 } 12367af88ac7SKuriakose Kuruvilla 12377af88ac7SKuriakose Kuruvilla if (cp->cp_ecx & CPUID_INTC_ECX_XSAVE) { 12387af88ac7SKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_XSAVE); 12397af88ac7SKuriakose Kuruvilla /* We only test AVX when there is XSAVE */ 12407af88ac7SKuriakose Kuruvilla if (cp->cp_ecx & CPUID_INTC_ECX_AVX) { 12417af88ac7SKuriakose Kuruvilla add_x86_feature(featureset, 12427af88ac7SKuriakose Kuruvilla X86FSET_AVX); 12437af88ac7SKuriakose Kuruvilla } 12447af88ac7SKuriakose Kuruvilla } 12457c478bd9Sstevel@tonic-gate } 12467417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_DE) { 12477417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_DE); 12487417cfdeSKuriakose Kuruvilla } 12491d1a3942SBill Holler #if !defined(__xpv) 1250f98fbcecSbholler if (cp->cp_ecx & CPUID_INTC_ECX_MON) { 12511d1a3942SBill Holler 12521d1a3942SBill Holler /* 12531d1a3942SBill Holler * We require the CLFLUSH instruction for erratum workaround 12541d1a3942SBill Holler * to use MONITOR/MWAIT. 12551d1a3942SBill Holler */ 12561d1a3942SBill Holler if (cp->cp_edx & CPUID_INTC_EDX_CLFSH) { 1257f98fbcecSbholler cpi->cpi_mwait.support |= MWAIT_SUPPORT; 12587417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_MWAIT); 12591d1a3942SBill Holler } else { 12601d1a3942SBill Holler extern int idle_cpu_assert_cflush_monitor; 12611d1a3942SBill Holler 12621d1a3942SBill Holler /* 12631d1a3942SBill Holler * All processors we are aware of which have 12641d1a3942SBill Holler * MONITOR/MWAIT also have CLFLUSH. 12651d1a3942SBill Holler */ 12661d1a3942SBill Holler if (idle_cpu_assert_cflush_monitor) { 12671d1a3942SBill Holler ASSERT((cp->cp_ecx & CPUID_INTC_ECX_MON) && 12681d1a3942SBill Holler (cp->cp_edx & CPUID_INTC_EDX_CLFSH)); 1269f98fbcecSbholler } 12701d1a3942SBill Holler } 12711d1a3942SBill Holler } 12721d1a3942SBill Holler #endif /* __xpv */ 12737c478bd9Sstevel@tonic-gate 1274faa20166SBryan Cantrill if (cp->cp_ecx & CPUID_INTC_ECX_VMX) { 1275faa20166SBryan Cantrill add_x86_feature(featureset, X86FSET_VMX); 1276faa20166SBryan Cantrill } 1277faa20166SBryan Cantrill 127886c1f4dcSVikram Hegde /* 1279faa20166SBryan Cantrill * Only need it first time, rest of the cpus would follow suit. 128086c1f4dcSVikram Hegde * we only capture this for the bootcpu. 128186c1f4dcSVikram Hegde */ 128286c1f4dcSVikram Hegde if (cp->cp_edx & CPUID_INTC_EDX_CLFSH) { 12837417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_CLFSH); 128486c1f4dcSVikram Hegde x86_clflush_size = (BITX(cp->cp_ebx, 15, 8) * 8); 128586c1f4dcSVikram Hegde } 12867417cfdeSKuriakose Kuruvilla if (is_x86_feature(featureset, X86FSET_PAE)) 12877c478bd9Sstevel@tonic-gate cpi->cpi_pabits = 36; 12887c478bd9Sstevel@tonic-gate 12897c478bd9Sstevel@tonic-gate /* 12907c478bd9Sstevel@tonic-gate * Hyperthreading configuration is slightly tricky on Intel 12917c478bd9Sstevel@tonic-gate * and pure clones, and even trickier on AMD. 12927c478bd9Sstevel@tonic-gate * 12937c478bd9Sstevel@tonic-gate * (AMD chose to set the HTT bit on their CMP processors, 12947c478bd9Sstevel@tonic-gate * even though they're not actually hyperthreaded. Thus it 12957c478bd9Sstevel@tonic-gate * takes a bit more work to figure out what's really going 1296ae115bc7Smrj * on ... see the handling of the CMP_LGCY bit below) 12977c478bd9Sstevel@tonic-gate */ 12987c478bd9Sstevel@tonic-gate if (cp->cp_edx & CPUID_INTC_EDX_HTT) { 12997c478bd9Sstevel@tonic-gate cpi->cpi_ncpu_per_chip = CPI_CPU_COUNT(cpi); 13007c478bd9Sstevel@tonic-gate if (cpi->cpi_ncpu_per_chip > 1) 13017417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_HTT); 13028949bcd6Sandrei } else { 13038949bcd6Sandrei cpi->cpi_ncpu_per_chip = 1; 13047c478bd9Sstevel@tonic-gate } 13057c478bd9Sstevel@tonic-gate 13067c478bd9Sstevel@tonic-gate /* 13077c478bd9Sstevel@tonic-gate * Work on the "extended" feature information, doing 13087c478bd9Sstevel@tonic-gate * some basic initialization for cpuid_pass2() 13097c478bd9Sstevel@tonic-gate */ 13107c478bd9Sstevel@tonic-gate xcpuid = 0; 13117c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 13127c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 13135ff02082Sdmick if (IS_NEW_F6(cpi) || cpi->cpi_family >= 0xf) 13147c478bd9Sstevel@tonic-gate xcpuid++; 13157c478bd9Sstevel@tonic-gate break; 13167c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 13177c478bd9Sstevel@tonic-gate if (cpi->cpi_family > 5 || 13187c478bd9Sstevel@tonic-gate (cpi->cpi_family == 5 && cpi->cpi_model >= 1)) 13197c478bd9Sstevel@tonic-gate xcpuid++; 13207c478bd9Sstevel@tonic-gate break; 13217c478bd9Sstevel@tonic-gate case X86_VENDOR_Cyrix: 13227c478bd9Sstevel@tonic-gate /* 13237c478bd9Sstevel@tonic-gate * Only these Cyrix CPUs are -known- to support 13247c478bd9Sstevel@tonic-gate * extended cpuid operations. 13257c478bd9Sstevel@tonic-gate */ 13267c478bd9Sstevel@tonic-gate if (x86_type == X86_TYPE_VIA_CYRIX_III || 13277c478bd9Sstevel@tonic-gate x86_type == X86_TYPE_CYRIX_GXm) 13287c478bd9Sstevel@tonic-gate xcpuid++; 13297c478bd9Sstevel@tonic-gate break; 13307c478bd9Sstevel@tonic-gate case X86_VENDOR_Centaur: 13317c478bd9Sstevel@tonic-gate case X86_VENDOR_TM: 13327c478bd9Sstevel@tonic-gate default: 13337c478bd9Sstevel@tonic-gate xcpuid++; 13347c478bd9Sstevel@tonic-gate break; 13357c478bd9Sstevel@tonic-gate } 13367c478bd9Sstevel@tonic-gate 13377c478bd9Sstevel@tonic-gate if (xcpuid) { 13387c478bd9Sstevel@tonic-gate cp = &cpi->cpi_extd[0]; 13398949bcd6Sandrei cp->cp_eax = 0x80000000; 13408949bcd6Sandrei cpi->cpi_xmaxeax = __cpuid_insn(cp); 13417c478bd9Sstevel@tonic-gate } 13427c478bd9Sstevel@tonic-gate 13437c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax & 0x80000000) { 13447c478bd9Sstevel@tonic-gate 13457c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax > CPI_XMAXEAX_MAX) 13467c478bd9Sstevel@tonic-gate cpi->cpi_xmaxeax = CPI_XMAXEAX_MAX; 13477c478bd9Sstevel@tonic-gate 13487c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 13497c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 13507c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 13517c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax < 0x80000001) 13527c478bd9Sstevel@tonic-gate break; 13537c478bd9Sstevel@tonic-gate cp = &cpi->cpi_extd[1]; 13548949bcd6Sandrei cp->cp_eax = 0x80000001; 13558949bcd6Sandrei (void) __cpuid_insn(cp); 1356ae115bc7Smrj 13577c478bd9Sstevel@tonic-gate if (cpi->cpi_vendor == X86_VENDOR_AMD && 13587c478bd9Sstevel@tonic-gate cpi->cpi_family == 5 && 13597c478bd9Sstevel@tonic-gate cpi->cpi_model == 6 && 13607c478bd9Sstevel@tonic-gate cpi->cpi_step == 6) { 13617c478bd9Sstevel@tonic-gate /* 13627c478bd9Sstevel@tonic-gate * K6 model 6 uses bit 10 to indicate SYSC 13637c478bd9Sstevel@tonic-gate * Later models use bit 11. Fix it here. 13647c478bd9Sstevel@tonic-gate */ 13657c478bd9Sstevel@tonic-gate if (cp->cp_edx & 0x400) { 13667c478bd9Sstevel@tonic-gate cp->cp_edx &= ~0x400; 13677c478bd9Sstevel@tonic-gate cp->cp_edx |= CPUID_AMD_EDX_SYSC; 13687c478bd9Sstevel@tonic-gate } 13697c478bd9Sstevel@tonic-gate } 13707c478bd9Sstevel@tonic-gate 1371ae115bc7Smrj platform_cpuid_mangle(cpi->cpi_vendor, 0x80000001, cp); 1372ae115bc7Smrj 13737c478bd9Sstevel@tonic-gate /* 13747c478bd9Sstevel@tonic-gate * Compute the additions to the kernel's feature word. 13757c478bd9Sstevel@tonic-gate */ 13767417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_AMD_EDX_NX) { 13777417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_NX); 13787417cfdeSKuriakose Kuruvilla } 13797c478bd9Sstevel@tonic-gate 138019397407SSherry Moore /* 138119397407SSherry Moore * Regardless whether or not we boot 64-bit, 138219397407SSherry Moore * we should have a way to identify whether 138319397407SSherry Moore * the CPU is capable of running 64-bit. 138419397407SSherry Moore */ 13857417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_AMD_EDX_LM) { 13867417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_64); 13877417cfdeSKuriakose Kuruvilla } 138819397407SSherry Moore 138902bc52beSkchow #if defined(__amd64) 139002bc52beSkchow /* 1 GB large page - enable only for 64 bit kernel */ 13917417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_AMD_EDX_1GPG) { 13927417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_1GPG); 13937417cfdeSKuriakose Kuruvilla } 139402bc52beSkchow #endif 139502bc52beSkchow 1396f8801251Skk208521 if ((cpi->cpi_vendor == X86_VENDOR_AMD) && 1397f8801251Skk208521 (cpi->cpi_std[1].cp_edx & CPUID_INTC_EDX_FXSR) && 13987417cfdeSKuriakose Kuruvilla (cp->cp_ecx & CPUID_AMD_ECX_SSE4A)) { 13997417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_SSE4A); 14007417cfdeSKuriakose Kuruvilla } 1401f8801251Skk208521 14027c478bd9Sstevel@tonic-gate /* 1403ae115bc7Smrj * If both the HTT and CMP_LGCY bits are set, 14048949bcd6Sandrei * then we're not actually HyperThreaded. Read 14058949bcd6Sandrei * "AMD CPUID Specification" for more details. 14067c478bd9Sstevel@tonic-gate */ 14077c478bd9Sstevel@tonic-gate if (cpi->cpi_vendor == X86_VENDOR_AMD && 14087417cfdeSKuriakose Kuruvilla is_x86_feature(featureset, X86FSET_HTT) && 1409ae115bc7Smrj (cp->cp_ecx & CPUID_AMD_ECX_CMP_LGCY)) { 14107417cfdeSKuriakose Kuruvilla remove_x86_feature(featureset, X86FSET_HTT); 14117417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_CMP); 14128949bcd6Sandrei } 1413ae115bc7Smrj #if defined(__amd64) 14147c478bd9Sstevel@tonic-gate /* 14157c478bd9Sstevel@tonic-gate * It's really tricky to support syscall/sysret in 14167c478bd9Sstevel@tonic-gate * the i386 kernel; we rely on sysenter/sysexit 14177c478bd9Sstevel@tonic-gate * instead. In the amd64 kernel, things are -way- 14187c478bd9Sstevel@tonic-gate * better. 14197c478bd9Sstevel@tonic-gate */ 14207417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_AMD_EDX_SYSC) { 14217417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_ASYSC); 14227417cfdeSKuriakose Kuruvilla } 14237c478bd9Sstevel@tonic-gate 14247c478bd9Sstevel@tonic-gate /* 14257c478bd9Sstevel@tonic-gate * While we're thinking about system calls, note 14267c478bd9Sstevel@tonic-gate * that AMD processors don't support sysenter 14277c478bd9Sstevel@tonic-gate * in long mode at all, so don't try to program them. 14287c478bd9Sstevel@tonic-gate */ 14297417cfdeSKuriakose Kuruvilla if (x86_vendor == X86_VENDOR_AMD) { 14307417cfdeSKuriakose Kuruvilla remove_x86_feature(featureset, X86FSET_SEP); 14317417cfdeSKuriakose Kuruvilla } 14327c478bd9Sstevel@tonic-gate #endif 14337417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_AMD_EDX_TSCP) { 14347417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_TSCP); 14357417cfdeSKuriakose Kuruvilla } 1436faa20166SBryan Cantrill 1437faa20166SBryan Cantrill if (cp->cp_ecx & CPUID_AMD_ECX_SVM) { 1438faa20166SBryan Cantrill add_x86_feature(featureset, X86FSET_SVM); 1439faa20166SBryan Cantrill } 14407c478bd9Sstevel@tonic-gate break; 14417c478bd9Sstevel@tonic-gate default: 14427c478bd9Sstevel@tonic-gate break; 14437c478bd9Sstevel@tonic-gate } 14447c478bd9Sstevel@tonic-gate 14458949bcd6Sandrei /* 14468949bcd6Sandrei * Get CPUID data about processor cores and hyperthreads. 14478949bcd6Sandrei */ 14487c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 14497c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 14508949bcd6Sandrei if (cpi->cpi_maxeax >= 4) { 14518949bcd6Sandrei cp = &cpi->cpi_std[4]; 14528949bcd6Sandrei cp->cp_eax = 4; 14538949bcd6Sandrei cp->cp_ecx = 0; 14548949bcd6Sandrei (void) __cpuid_insn(cp); 1455ae115bc7Smrj platform_cpuid_mangle(cpi->cpi_vendor, 4, cp); 14568949bcd6Sandrei } 14578949bcd6Sandrei /*FALLTHROUGH*/ 14587c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 14597c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax < 0x80000008) 14607c478bd9Sstevel@tonic-gate break; 14617c478bd9Sstevel@tonic-gate cp = &cpi->cpi_extd[8]; 14628949bcd6Sandrei cp->cp_eax = 0x80000008; 14638949bcd6Sandrei (void) __cpuid_insn(cp); 1464ae115bc7Smrj platform_cpuid_mangle(cpi->cpi_vendor, 0x80000008, cp); 1465ae115bc7Smrj 14667c478bd9Sstevel@tonic-gate /* 14677c478bd9Sstevel@tonic-gate * Virtual and physical address limits from 14687c478bd9Sstevel@tonic-gate * cpuid override previously guessed values. 14697c478bd9Sstevel@tonic-gate */ 14707c478bd9Sstevel@tonic-gate cpi->cpi_pabits = BITX(cp->cp_eax, 7, 0); 14717c478bd9Sstevel@tonic-gate cpi->cpi_vabits = BITX(cp->cp_eax, 15, 8); 14727c478bd9Sstevel@tonic-gate break; 14737c478bd9Sstevel@tonic-gate default: 14747c478bd9Sstevel@tonic-gate break; 14757c478bd9Sstevel@tonic-gate } 14768949bcd6Sandrei 1477d129bde2Sesaxe /* 1478d129bde2Sesaxe * Derive the number of cores per chip 1479d129bde2Sesaxe */ 14808949bcd6Sandrei switch (cpi->cpi_vendor) { 14818949bcd6Sandrei case X86_VENDOR_Intel: 14828949bcd6Sandrei if (cpi->cpi_maxeax < 4) { 14838949bcd6Sandrei cpi->cpi_ncore_per_chip = 1; 14848949bcd6Sandrei break; 14858949bcd6Sandrei } else { 14868949bcd6Sandrei cpi->cpi_ncore_per_chip = 14878949bcd6Sandrei BITX((cpi)->cpi_std[4].cp_eax, 31, 26) + 1; 14888949bcd6Sandrei } 14898949bcd6Sandrei break; 14908949bcd6Sandrei case X86_VENDOR_AMD: 14918949bcd6Sandrei if (cpi->cpi_xmaxeax < 0x80000008) { 14928949bcd6Sandrei cpi->cpi_ncore_per_chip = 1; 14938949bcd6Sandrei break; 14948949bcd6Sandrei } else { 149510569901Sgavinm /* 149610569901Sgavinm * On family 0xf cpuid fn 2 ECX[7:0] "NC" is 149710569901Sgavinm * 1 less than the number of physical cores on 149810569901Sgavinm * the chip. In family 0x10 this value can 149910569901Sgavinm * be affected by "downcoring" - it reflects 150010569901Sgavinm * 1 less than the number of cores actually 150110569901Sgavinm * enabled on this node. 150210569901Sgavinm */ 15038949bcd6Sandrei cpi->cpi_ncore_per_chip = 15048949bcd6Sandrei BITX((cpi)->cpi_extd[8].cp_ecx, 7, 0) + 1; 15058949bcd6Sandrei } 15068949bcd6Sandrei break; 15078949bcd6Sandrei default: 15088949bcd6Sandrei cpi->cpi_ncore_per_chip = 1; 15098949bcd6Sandrei break; 15107c478bd9Sstevel@tonic-gate } 15110e751525SEric Saxe 15120e751525SEric Saxe /* 15130e751525SEric Saxe * Get CPUID data about TSC Invariance in Deep C-State. 15140e751525SEric Saxe */ 15150e751525SEric Saxe switch (cpi->cpi_vendor) { 15160e751525SEric Saxe case X86_VENDOR_Intel: 15170e751525SEric Saxe if (cpi->cpi_maxeax >= 7) { 15180e751525SEric Saxe cp = &cpi->cpi_extd[7]; 15190e751525SEric Saxe cp->cp_eax = 0x80000007; 15200e751525SEric Saxe cp->cp_ecx = 0; 15210e751525SEric Saxe (void) __cpuid_insn(cp); 15220e751525SEric Saxe } 15230e751525SEric Saxe break; 15240e751525SEric Saxe default: 15250e751525SEric Saxe break; 15260e751525SEric Saxe } 1527fa2e767eSgavinm } else { 1528fa2e767eSgavinm cpi->cpi_ncore_per_chip = 1; 15298949bcd6Sandrei } 15308949bcd6Sandrei 15318949bcd6Sandrei /* 15328949bcd6Sandrei * If more than one core, then this processor is CMP. 15338949bcd6Sandrei */ 15347417cfdeSKuriakose Kuruvilla if (cpi->cpi_ncore_per_chip > 1) { 15357417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_CMP); 15367417cfdeSKuriakose Kuruvilla } 1537ae115bc7Smrj 15388949bcd6Sandrei /* 15398949bcd6Sandrei * If the number of cores is the same as the number 15408949bcd6Sandrei * of CPUs, then we cannot have HyperThreading. 15418949bcd6Sandrei */ 15427417cfdeSKuriakose Kuruvilla if (cpi->cpi_ncpu_per_chip == cpi->cpi_ncore_per_chip) { 15437417cfdeSKuriakose Kuruvilla remove_x86_feature(featureset, X86FSET_HTT); 15447417cfdeSKuriakose Kuruvilla } 15458949bcd6Sandrei 15468031591dSSrihari Venkatesan cpi->cpi_apicid = CPI_APIC_ID(cpi); 15478031591dSSrihari Venkatesan cpi->cpi_procnodes_per_pkg = 1; 15487417cfdeSKuriakose Kuruvilla if (is_x86_feature(featureset, X86FSET_HTT) == B_FALSE && 15497417cfdeSKuriakose Kuruvilla is_x86_feature(featureset, X86FSET_CMP) == B_FALSE) { 15508949bcd6Sandrei /* 15518949bcd6Sandrei * Single-core single-threaded processors. 15528949bcd6Sandrei */ 15537c478bd9Sstevel@tonic-gate cpi->cpi_chipid = -1; 15547c478bd9Sstevel@tonic-gate cpi->cpi_clogid = 0; 15558949bcd6Sandrei cpi->cpi_coreid = cpu->cpu_id; 155610569901Sgavinm cpi->cpi_pkgcoreid = 0; 15578031591dSSrihari Venkatesan if (cpi->cpi_vendor == X86_VENDOR_AMD) 15588031591dSSrihari Venkatesan cpi->cpi_procnodeid = BITX(cpi->cpi_apicid, 3, 0); 15598031591dSSrihari Venkatesan else 15608031591dSSrihari Venkatesan cpi->cpi_procnodeid = cpi->cpi_chipid; 15617c478bd9Sstevel@tonic-gate } else if (cpi->cpi_ncpu_per_chip > 1) { 15628031591dSSrihari Venkatesan if (cpi->cpi_vendor == X86_VENDOR_Intel) 15637417cfdeSKuriakose Kuruvilla cpuid_intel_getids(cpu, featureset); 15648031591dSSrihari Venkatesan else if (cpi->cpi_vendor == X86_VENDOR_AMD) 15658031591dSSrihari Venkatesan cpuid_amd_getids(cpu); 15668031591dSSrihari Venkatesan else { 15678949bcd6Sandrei /* 15688949bcd6Sandrei * All other processors are currently 15698949bcd6Sandrei * assumed to have single cores. 15708949bcd6Sandrei */ 15718949bcd6Sandrei cpi->cpi_coreid = cpi->cpi_chipid; 157210569901Sgavinm cpi->cpi_pkgcoreid = 0; 15738031591dSSrihari Venkatesan cpi->cpi_procnodeid = cpi->cpi_chipid; 15748949bcd6Sandrei } 15757c478bd9Sstevel@tonic-gate } 15767c478bd9Sstevel@tonic-gate 15778a40a695Sgavinm /* 15788a40a695Sgavinm * Synthesize chip "revision" and socket type 15798a40a695Sgavinm */ 1580e4b86885SCheng Sean Ye cpi->cpi_chiprev = _cpuid_chiprev(cpi->cpi_vendor, cpi->cpi_family, 1581e4b86885SCheng Sean Ye cpi->cpi_model, cpi->cpi_step); 1582e4b86885SCheng Sean Ye cpi->cpi_chiprevstr = _cpuid_chiprevstr(cpi->cpi_vendor, 1583e4b86885SCheng Sean Ye cpi->cpi_family, cpi->cpi_model, cpi->cpi_step); 1584e4b86885SCheng Sean Ye cpi->cpi_socket = _cpuid_skt(cpi->cpi_vendor, cpi->cpi_family, 1585e4b86885SCheng Sean Ye cpi->cpi_model, cpi->cpi_step); 15868a40a695Sgavinm 15877c478bd9Sstevel@tonic-gate pass1_done: 15887c478bd9Sstevel@tonic-gate cpi->cpi_pass = 1; 15897c478bd9Sstevel@tonic-gate } 15907c478bd9Sstevel@tonic-gate 15917c478bd9Sstevel@tonic-gate /* 15927c478bd9Sstevel@tonic-gate * Make copies of the cpuid table entries we depend on, in 15937c478bd9Sstevel@tonic-gate * part for ease of parsing now, in part so that we have only 15947c478bd9Sstevel@tonic-gate * one place to correct any of it, in part for ease of 15957c478bd9Sstevel@tonic-gate * later export to userland, and in part so we can look at 15967c478bd9Sstevel@tonic-gate * this stuff in a crash dump. 15977c478bd9Sstevel@tonic-gate */ 15987c478bd9Sstevel@tonic-gate 15997c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 16007c478bd9Sstevel@tonic-gate void 16017c478bd9Sstevel@tonic-gate cpuid_pass2(cpu_t *cpu) 16027c478bd9Sstevel@tonic-gate { 16037c478bd9Sstevel@tonic-gate uint_t n, nmax; 16047c478bd9Sstevel@tonic-gate int i; 16058949bcd6Sandrei struct cpuid_regs *cp; 16067c478bd9Sstevel@tonic-gate uint8_t *dp; 16077c478bd9Sstevel@tonic-gate uint32_t *iptr; 16087c478bd9Sstevel@tonic-gate struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi; 16097c478bd9Sstevel@tonic-gate 16107c478bd9Sstevel@tonic-gate ASSERT(cpi->cpi_pass == 1); 16117c478bd9Sstevel@tonic-gate 16127c478bd9Sstevel@tonic-gate if (cpi->cpi_maxeax < 1) 16137c478bd9Sstevel@tonic-gate goto pass2_done; 16147c478bd9Sstevel@tonic-gate 16157c478bd9Sstevel@tonic-gate if ((nmax = cpi->cpi_maxeax + 1) > NMAX_CPI_STD) 16167c478bd9Sstevel@tonic-gate nmax = NMAX_CPI_STD; 16177c478bd9Sstevel@tonic-gate /* 16187c478bd9Sstevel@tonic-gate * (We already handled n == 0 and n == 1 in pass 1) 16197c478bd9Sstevel@tonic-gate */ 16207c478bd9Sstevel@tonic-gate for (n = 2, cp = &cpi->cpi_std[2]; n < nmax; n++, cp++) { 16218949bcd6Sandrei cp->cp_eax = n; 1622d129bde2Sesaxe 1623d129bde2Sesaxe /* 1624d129bde2Sesaxe * CPUID function 4 expects %ecx to be initialized 1625d129bde2Sesaxe * with an index which indicates which cache to return 1626d129bde2Sesaxe * information about. The OS is expected to call function 4 1627d129bde2Sesaxe * with %ecx set to 0, 1, 2, ... until it returns with 1628d129bde2Sesaxe * EAX[4:0] set to 0, which indicates there are no more 1629d129bde2Sesaxe * caches. 1630d129bde2Sesaxe * 1631d129bde2Sesaxe * Here, populate cpi_std[4] with the information returned by 1632d129bde2Sesaxe * function 4 when %ecx == 0, and do the rest in cpuid_pass3() 1633d129bde2Sesaxe * when dynamic memory allocation becomes available. 1634d129bde2Sesaxe * 1635d129bde2Sesaxe * Note: we need to explicitly initialize %ecx here, since 1636d129bde2Sesaxe * function 4 may have been previously invoked. 1637d129bde2Sesaxe */ 1638d129bde2Sesaxe if (n == 4) 1639d129bde2Sesaxe cp->cp_ecx = 0; 1640d129bde2Sesaxe 16418949bcd6Sandrei (void) __cpuid_insn(cp); 1642ae115bc7Smrj platform_cpuid_mangle(cpi->cpi_vendor, n, cp); 16437c478bd9Sstevel@tonic-gate switch (n) { 16447c478bd9Sstevel@tonic-gate case 2: 16457c478bd9Sstevel@tonic-gate /* 16467c478bd9Sstevel@tonic-gate * "the lower 8 bits of the %eax register 16477c478bd9Sstevel@tonic-gate * contain a value that identifies the number 16487c478bd9Sstevel@tonic-gate * of times the cpuid [instruction] has to be 16497c478bd9Sstevel@tonic-gate * executed to obtain a complete image of the 16507c478bd9Sstevel@tonic-gate * processor's caching systems." 16517c478bd9Sstevel@tonic-gate * 16527c478bd9Sstevel@tonic-gate * How *do* they make this stuff up? 16537c478bd9Sstevel@tonic-gate */ 16547c478bd9Sstevel@tonic-gate cpi->cpi_ncache = sizeof (*cp) * 16557c478bd9Sstevel@tonic-gate BITX(cp->cp_eax, 7, 0); 16567c478bd9Sstevel@tonic-gate if (cpi->cpi_ncache == 0) 16577c478bd9Sstevel@tonic-gate break; 16587c478bd9Sstevel@tonic-gate cpi->cpi_ncache--; /* skip count byte */ 16597c478bd9Sstevel@tonic-gate 16607c478bd9Sstevel@tonic-gate /* 16617c478bd9Sstevel@tonic-gate * Well, for now, rather than attempt to implement 16627c478bd9Sstevel@tonic-gate * this slightly dubious algorithm, we just look 16637c478bd9Sstevel@tonic-gate * at the first 15 .. 16647c478bd9Sstevel@tonic-gate */ 16657c478bd9Sstevel@tonic-gate if (cpi->cpi_ncache > (sizeof (*cp) - 1)) 16667c478bd9Sstevel@tonic-gate cpi->cpi_ncache = sizeof (*cp) - 1; 16677c478bd9Sstevel@tonic-gate 16687c478bd9Sstevel@tonic-gate dp = cpi->cpi_cacheinfo; 16697c478bd9Sstevel@tonic-gate if (BITX(cp->cp_eax, 31, 31) == 0) { 16707c478bd9Sstevel@tonic-gate uint8_t *p = (void *)&cp->cp_eax; 167163d3f7dfSkk208521 for (i = 1; i < 4; i++) 16727c478bd9Sstevel@tonic-gate if (p[i] != 0) 16737c478bd9Sstevel@tonic-gate *dp++ = p[i]; 16747c478bd9Sstevel@tonic-gate } 16757c478bd9Sstevel@tonic-gate if (BITX(cp->cp_ebx, 31, 31) == 0) { 16767c478bd9Sstevel@tonic-gate uint8_t *p = (void *)&cp->cp_ebx; 16777c478bd9Sstevel@tonic-gate for (i = 0; i < 4; i++) 16787c478bd9Sstevel@tonic-gate if (p[i] != 0) 16797c478bd9Sstevel@tonic-gate *dp++ = p[i]; 16807c478bd9Sstevel@tonic-gate } 16817c478bd9Sstevel@tonic-gate if (BITX(cp->cp_ecx, 31, 31) == 0) { 16827c478bd9Sstevel@tonic-gate uint8_t *p = (void *)&cp->cp_ecx; 16837c478bd9Sstevel@tonic-gate for (i = 0; i < 4; i++) 16847c478bd9Sstevel@tonic-gate if (p[i] != 0) 16857c478bd9Sstevel@tonic-gate *dp++ = p[i]; 16867c478bd9Sstevel@tonic-gate } 16877c478bd9Sstevel@tonic-gate if (BITX(cp->cp_edx, 31, 31) == 0) { 16887c478bd9Sstevel@tonic-gate uint8_t *p = (void *)&cp->cp_edx; 16897c478bd9Sstevel@tonic-gate for (i = 0; i < 4; i++) 16907c478bd9Sstevel@tonic-gate if (p[i] != 0) 16917c478bd9Sstevel@tonic-gate *dp++ = p[i]; 16927c478bd9Sstevel@tonic-gate } 16937c478bd9Sstevel@tonic-gate break; 1694f98fbcecSbholler 16957c478bd9Sstevel@tonic-gate case 3: /* Processor serial number, if PSN supported */ 1696f98fbcecSbholler break; 1697f98fbcecSbholler 16987c478bd9Sstevel@tonic-gate case 4: /* Deterministic cache parameters */ 1699f98fbcecSbholler break; 1700f98fbcecSbholler 17017c478bd9Sstevel@tonic-gate case 5: /* Monitor/Mwait parameters */ 17025b8a6efeSbholler { 17035b8a6efeSbholler size_t mwait_size; 1704f98fbcecSbholler 1705f98fbcecSbholler /* 1706f98fbcecSbholler * check cpi_mwait.support which was set in cpuid_pass1 1707f98fbcecSbholler */ 1708f98fbcecSbholler if (!(cpi->cpi_mwait.support & MWAIT_SUPPORT)) 1709f98fbcecSbholler break; 1710f98fbcecSbholler 17115b8a6efeSbholler /* 17125b8a6efeSbholler * Protect ourself from insane mwait line size. 17135b8a6efeSbholler * Workaround for incomplete hardware emulator(s). 17145b8a6efeSbholler */ 17155b8a6efeSbholler mwait_size = (size_t)MWAIT_SIZE_MAX(cpi); 17165b8a6efeSbholler if (mwait_size < sizeof (uint32_t) || 17175b8a6efeSbholler !ISP2(mwait_size)) { 17185b8a6efeSbholler #if DEBUG 17195b8a6efeSbholler cmn_err(CE_NOTE, "Cannot handle cpu %d mwait " 17205d8efbbcSSaurabh Misra "size %ld", cpu->cpu_id, (long)mwait_size); 17215b8a6efeSbholler #endif 17225b8a6efeSbholler break; 17235b8a6efeSbholler } 17245b8a6efeSbholler 1725f98fbcecSbholler cpi->cpi_mwait.mon_min = (size_t)MWAIT_SIZE_MIN(cpi); 17265b8a6efeSbholler cpi->cpi_mwait.mon_max = mwait_size; 1727f98fbcecSbholler if (MWAIT_EXTENSION(cpi)) { 1728f98fbcecSbholler cpi->cpi_mwait.support |= MWAIT_EXTENSIONS; 1729f98fbcecSbholler if (MWAIT_INT_ENABLE(cpi)) 1730f98fbcecSbholler cpi->cpi_mwait.support |= 1731f98fbcecSbholler MWAIT_ECX_INT_ENABLE; 1732f98fbcecSbholler } 1733f98fbcecSbholler break; 17345b8a6efeSbholler } 17357c478bd9Sstevel@tonic-gate default: 17367c478bd9Sstevel@tonic-gate break; 17377c478bd9Sstevel@tonic-gate } 17387c478bd9Sstevel@tonic-gate } 17397c478bd9Sstevel@tonic-gate 1740b6917abeSmishra if (cpi->cpi_maxeax >= 0xB && cpi->cpi_vendor == X86_VENDOR_Intel) { 17415d8efbbcSSaurabh Misra struct cpuid_regs regs; 17425d8efbbcSSaurabh Misra 17435d8efbbcSSaurabh Misra cp = ®s; 1744b6917abeSmishra cp->cp_eax = 0xB; 17455d8efbbcSSaurabh Misra cp->cp_edx = cp->cp_ebx = cp->cp_ecx = 0; 1746b6917abeSmishra 1747b6917abeSmishra (void) __cpuid_insn(cp); 1748b6917abeSmishra 1749b6917abeSmishra /* 1750b6917abeSmishra * Check CPUID.EAX=0BH, ECX=0H:EBX is non-zero, which 1751b6917abeSmishra * indicates that the extended topology enumeration leaf is 1752b6917abeSmishra * available. 1753b6917abeSmishra */ 1754b6917abeSmishra if (cp->cp_ebx) { 1755b6917abeSmishra uint32_t x2apic_id; 1756b6917abeSmishra uint_t coreid_shift = 0; 1757b6917abeSmishra uint_t ncpu_per_core = 1; 1758b6917abeSmishra uint_t chipid_shift = 0; 1759b6917abeSmishra uint_t ncpu_per_chip = 1; 1760b6917abeSmishra uint_t i; 1761b6917abeSmishra uint_t level; 1762b6917abeSmishra 1763b6917abeSmishra for (i = 0; i < CPI_FNB_ECX_MAX; i++) { 1764b6917abeSmishra cp->cp_eax = 0xB; 1765b6917abeSmishra cp->cp_ecx = i; 1766b6917abeSmishra 1767b6917abeSmishra (void) __cpuid_insn(cp); 1768b6917abeSmishra level = CPI_CPU_LEVEL_TYPE(cp); 1769b6917abeSmishra 1770b6917abeSmishra if (level == 1) { 1771b6917abeSmishra x2apic_id = cp->cp_edx; 1772b6917abeSmishra coreid_shift = BITX(cp->cp_eax, 4, 0); 1773b6917abeSmishra ncpu_per_core = BITX(cp->cp_ebx, 15, 0); 1774b6917abeSmishra } else if (level == 2) { 1775b6917abeSmishra x2apic_id = cp->cp_edx; 1776b6917abeSmishra chipid_shift = BITX(cp->cp_eax, 4, 0); 1777b6917abeSmishra ncpu_per_chip = BITX(cp->cp_ebx, 15, 0); 1778b6917abeSmishra } 1779b6917abeSmishra } 1780b6917abeSmishra 1781b6917abeSmishra cpi->cpi_apicid = x2apic_id; 1782b6917abeSmishra cpi->cpi_ncpu_per_chip = ncpu_per_chip; 1783b6917abeSmishra cpi->cpi_ncore_per_chip = ncpu_per_chip / 1784b6917abeSmishra ncpu_per_core; 1785b6917abeSmishra cpi->cpi_chipid = x2apic_id >> chipid_shift; 1786b6917abeSmishra cpi->cpi_clogid = x2apic_id & ((1 << chipid_shift) - 1); 1787b6917abeSmishra cpi->cpi_coreid = x2apic_id >> coreid_shift; 1788b6917abeSmishra cpi->cpi_pkgcoreid = cpi->cpi_clogid >> coreid_shift; 1789b6917abeSmishra } 17905d8efbbcSSaurabh Misra 17915d8efbbcSSaurabh Misra /* Make cp NULL so that we don't stumble on others */ 17925d8efbbcSSaurabh Misra cp = NULL; 1793b6917abeSmishra } 1794b6917abeSmishra 17957af88ac7SKuriakose Kuruvilla /* 17967af88ac7SKuriakose Kuruvilla * XSAVE enumeration 17977af88ac7SKuriakose Kuruvilla */ 179863408480SHans Rosenfeld if (cpi->cpi_maxeax >= 0xD) { 17997af88ac7SKuriakose Kuruvilla struct cpuid_regs regs; 18007af88ac7SKuriakose Kuruvilla boolean_t cpuid_d_valid = B_TRUE; 18017af88ac7SKuriakose Kuruvilla 18027af88ac7SKuriakose Kuruvilla cp = ®s; 18037af88ac7SKuriakose Kuruvilla cp->cp_eax = 0xD; 18047af88ac7SKuriakose Kuruvilla cp->cp_edx = cp->cp_ebx = cp->cp_ecx = 0; 18057af88ac7SKuriakose Kuruvilla 18067af88ac7SKuriakose Kuruvilla (void) __cpuid_insn(cp); 18077af88ac7SKuriakose Kuruvilla 18087af88ac7SKuriakose Kuruvilla /* 18097af88ac7SKuriakose Kuruvilla * Sanity checks for debug 18107af88ac7SKuriakose Kuruvilla */ 18117af88ac7SKuriakose Kuruvilla if ((cp->cp_eax & XFEATURE_LEGACY_FP) == 0 || 18127af88ac7SKuriakose Kuruvilla (cp->cp_eax & XFEATURE_SSE) == 0) { 18137af88ac7SKuriakose Kuruvilla cpuid_d_valid = B_FALSE; 18147af88ac7SKuriakose Kuruvilla } 18157af88ac7SKuriakose Kuruvilla 18167af88ac7SKuriakose Kuruvilla cpi->cpi_xsave.xsav_hw_features_low = cp->cp_eax; 18177af88ac7SKuriakose Kuruvilla cpi->cpi_xsave.xsav_hw_features_high = cp->cp_edx; 18187af88ac7SKuriakose Kuruvilla cpi->cpi_xsave.xsav_max_size = cp->cp_ecx; 18197af88ac7SKuriakose Kuruvilla 18207af88ac7SKuriakose Kuruvilla /* 18217af88ac7SKuriakose Kuruvilla * If the hw supports AVX, get the size and offset in the save 18227af88ac7SKuriakose Kuruvilla * area for the ymm state. 18237af88ac7SKuriakose Kuruvilla */ 18247af88ac7SKuriakose Kuruvilla if (cpi->cpi_xsave.xsav_hw_features_low & XFEATURE_AVX) { 18257af88ac7SKuriakose Kuruvilla cp->cp_eax = 0xD; 18267af88ac7SKuriakose Kuruvilla cp->cp_ecx = 2; 18277af88ac7SKuriakose Kuruvilla cp->cp_edx = cp->cp_ebx = 0; 18287af88ac7SKuriakose Kuruvilla 18297af88ac7SKuriakose Kuruvilla (void) __cpuid_insn(cp); 18307af88ac7SKuriakose Kuruvilla 18317af88ac7SKuriakose Kuruvilla if (cp->cp_ebx != CPUID_LEAFD_2_YMM_OFFSET || 18327af88ac7SKuriakose Kuruvilla cp->cp_eax != CPUID_LEAFD_2_YMM_SIZE) { 18337af88ac7SKuriakose Kuruvilla cpuid_d_valid = B_FALSE; 18347af88ac7SKuriakose Kuruvilla } 18357af88ac7SKuriakose Kuruvilla 18367af88ac7SKuriakose Kuruvilla cpi->cpi_xsave.ymm_size = cp->cp_eax; 18377af88ac7SKuriakose Kuruvilla cpi->cpi_xsave.ymm_offset = cp->cp_ebx; 18387af88ac7SKuriakose Kuruvilla } 18397af88ac7SKuriakose Kuruvilla 18407af88ac7SKuriakose Kuruvilla if (is_x86_feature(x86_featureset, X86FSET_XSAVE)) { 18417af88ac7SKuriakose Kuruvilla xsave_state_size = 0; 18427af88ac7SKuriakose Kuruvilla } else if (cpuid_d_valid) { 18437af88ac7SKuriakose Kuruvilla xsave_state_size = cpi->cpi_xsave.xsav_max_size; 18447af88ac7SKuriakose Kuruvilla } else { 18457af88ac7SKuriakose Kuruvilla /* Broken CPUID 0xD, probably in HVM */ 18467af88ac7SKuriakose Kuruvilla cmn_err(CE_WARN, "cpu%d: CPUID.0xD returns invalid " 18477af88ac7SKuriakose Kuruvilla "value: hw_low = %d, hw_high = %d, xsave_size = %d" 18487af88ac7SKuriakose Kuruvilla ", ymm_size = %d, ymm_offset = %d\n", 18497af88ac7SKuriakose Kuruvilla cpu->cpu_id, cpi->cpi_xsave.xsav_hw_features_low, 18507af88ac7SKuriakose Kuruvilla cpi->cpi_xsave.xsav_hw_features_high, 18517af88ac7SKuriakose Kuruvilla (int)cpi->cpi_xsave.xsav_max_size, 18527af88ac7SKuriakose Kuruvilla (int)cpi->cpi_xsave.ymm_size, 18537af88ac7SKuriakose Kuruvilla (int)cpi->cpi_xsave.ymm_offset); 18547af88ac7SKuriakose Kuruvilla 18557af88ac7SKuriakose Kuruvilla if (xsave_state_size != 0) { 18567af88ac7SKuriakose Kuruvilla /* 18577af88ac7SKuriakose Kuruvilla * This must be a non-boot CPU. We cannot 18587af88ac7SKuriakose Kuruvilla * continue, because boot cpu has already 18597af88ac7SKuriakose Kuruvilla * enabled XSAVE. 18607af88ac7SKuriakose Kuruvilla */ 18617af88ac7SKuriakose Kuruvilla ASSERT(cpu->cpu_id != 0); 18627af88ac7SKuriakose Kuruvilla cmn_err(CE_PANIC, "cpu%d: we have already " 18637af88ac7SKuriakose Kuruvilla "enabled XSAVE on boot cpu, cannot " 18647af88ac7SKuriakose Kuruvilla "continue.", cpu->cpu_id); 18657af88ac7SKuriakose Kuruvilla } else { 18667af88ac7SKuriakose Kuruvilla /* 18677af88ac7SKuriakose Kuruvilla * Must be from boot CPU, OK to disable XSAVE. 18687af88ac7SKuriakose Kuruvilla */ 18697af88ac7SKuriakose Kuruvilla ASSERT(cpu->cpu_id == 0); 18707af88ac7SKuriakose Kuruvilla remove_x86_feature(x86_featureset, 18717af88ac7SKuriakose Kuruvilla X86FSET_XSAVE); 18727af88ac7SKuriakose Kuruvilla remove_x86_feature(x86_featureset, X86FSET_AVX); 18737af88ac7SKuriakose Kuruvilla CPI_FEATURES_ECX(cpi) &= ~CPUID_INTC_ECX_XSAVE; 18747af88ac7SKuriakose Kuruvilla CPI_FEATURES_ECX(cpi) &= ~CPUID_INTC_ECX_AVX; 18757af88ac7SKuriakose Kuruvilla xsave_force_disable = B_TRUE; 18767af88ac7SKuriakose Kuruvilla } 18777af88ac7SKuriakose Kuruvilla } 18787af88ac7SKuriakose Kuruvilla } 18797af88ac7SKuriakose Kuruvilla 18807af88ac7SKuriakose Kuruvilla 18817c478bd9Sstevel@tonic-gate if ((cpi->cpi_xmaxeax & 0x80000000) == 0) 18827c478bd9Sstevel@tonic-gate goto pass2_done; 18837c478bd9Sstevel@tonic-gate 18847c478bd9Sstevel@tonic-gate if ((nmax = cpi->cpi_xmaxeax - 0x80000000 + 1) > NMAX_CPI_EXTD) 18857c478bd9Sstevel@tonic-gate nmax = NMAX_CPI_EXTD; 18867c478bd9Sstevel@tonic-gate /* 18877c478bd9Sstevel@tonic-gate * Copy the extended properties, fixing them as we go. 18887c478bd9Sstevel@tonic-gate * (We already handled n == 0 and n == 1 in pass 1) 18897c478bd9Sstevel@tonic-gate */ 18907c478bd9Sstevel@tonic-gate iptr = (void *)cpi->cpi_brandstr; 18917c478bd9Sstevel@tonic-gate for (n = 2, cp = &cpi->cpi_extd[2]; n < nmax; cp++, n++) { 18928949bcd6Sandrei cp->cp_eax = 0x80000000 + n; 18938949bcd6Sandrei (void) __cpuid_insn(cp); 1894ae115bc7Smrj platform_cpuid_mangle(cpi->cpi_vendor, 0x80000000 + n, cp); 18957c478bd9Sstevel@tonic-gate switch (n) { 18967c478bd9Sstevel@tonic-gate case 2: 18977c478bd9Sstevel@tonic-gate case 3: 18987c478bd9Sstevel@tonic-gate case 4: 18997c478bd9Sstevel@tonic-gate /* 19007c478bd9Sstevel@tonic-gate * Extract the brand string 19017c478bd9Sstevel@tonic-gate */ 19027c478bd9Sstevel@tonic-gate *iptr++ = cp->cp_eax; 19037c478bd9Sstevel@tonic-gate *iptr++ = cp->cp_ebx; 19047c478bd9Sstevel@tonic-gate *iptr++ = cp->cp_ecx; 19057c478bd9Sstevel@tonic-gate *iptr++ = cp->cp_edx; 19067c478bd9Sstevel@tonic-gate break; 19077c478bd9Sstevel@tonic-gate case 5: 19087c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 19097c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 19107c478bd9Sstevel@tonic-gate /* 19117c478bd9Sstevel@tonic-gate * The Athlon and Duron were the first 19127c478bd9Sstevel@tonic-gate * parts to report the sizes of the 19137c478bd9Sstevel@tonic-gate * TLB for large pages. Before then, 19147c478bd9Sstevel@tonic-gate * we don't trust the data. 19157c478bd9Sstevel@tonic-gate */ 19167c478bd9Sstevel@tonic-gate if (cpi->cpi_family < 6 || 19177c478bd9Sstevel@tonic-gate (cpi->cpi_family == 6 && 19187c478bd9Sstevel@tonic-gate cpi->cpi_model < 1)) 19197c478bd9Sstevel@tonic-gate cp->cp_eax = 0; 19207c478bd9Sstevel@tonic-gate break; 19217c478bd9Sstevel@tonic-gate default: 19227c478bd9Sstevel@tonic-gate break; 19237c478bd9Sstevel@tonic-gate } 19247c478bd9Sstevel@tonic-gate break; 19257c478bd9Sstevel@tonic-gate case 6: 19267c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 19277c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 19287c478bd9Sstevel@tonic-gate /* 19297c478bd9Sstevel@tonic-gate * The Athlon and Duron were the first 19307c478bd9Sstevel@tonic-gate * AMD parts with L2 TLB's. 19317c478bd9Sstevel@tonic-gate * Before then, don't trust the data. 19327c478bd9Sstevel@tonic-gate */ 19337c478bd9Sstevel@tonic-gate if (cpi->cpi_family < 6 || 19347c478bd9Sstevel@tonic-gate cpi->cpi_family == 6 && 19357c478bd9Sstevel@tonic-gate cpi->cpi_model < 1) 19367c478bd9Sstevel@tonic-gate cp->cp_eax = cp->cp_ebx = 0; 19377c478bd9Sstevel@tonic-gate /* 19387c478bd9Sstevel@tonic-gate * AMD Duron rev A0 reports L2 19397c478bd9Sstevel@tonic-gate * cache size incorrectly as 1K 19407c478bd9Sstevel@tonic-gate * when it is really 64K 19417c478bd9Sstevel@tonic-gate */ 19427c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 6 && 19437c478bd9Sstevel@tonic-gate cpi->cpi_model == 3 && 19447c478bd9Sstevel@tonic-gate cpi->cpi_step == 0) { 19457c478bd9Sstevel@tonic-gate cp->cp_ecx &= 0xffff; 19467c478bd9Sstevel@tonic-gate cp->cp_ecx |= 0x400000; 19477c478bd9Sstevel@tonic-gate } 19487c478bd9Sstevel@tonic-gate break; 19497c478bd9Sstevel@tonic-gate case X86_VENDOR_Cyrix: /* VIA C3 */ 19507c478bd9Sstevel@tonic-gate /* 19517c478bd9Sstevel@tonic-gate * VIA C3 processors are a bit messed 19527c478bd9Sstevel@tonic-gate * up w.r.t. encoding cache sizes in %ecx 19537c478bd9Sstevel@tonic-gate */ 19547c478bd9Sstevel@tonic-gate if (cpi->cpi_family != 6) 19557c478bd9Sstevel@tonic-gate break; 19567c478bd9Sstevel@tonic-gate /* 19577c478bd9Sstevel@tonic-gate * model 7 and 8 were incorrectly encoded 19587c478bd9Sstevel@tonic-gate * 19597c478bd9Sstevel@tonic-gate * xxx is model 8 really broken? 19607c478bd9Sstevel@tonic-gate */ 19617c478bd9Sstevel@tonic-gate if (cpi->cpi_model == 7 || 19627c478bd9Sstevel@tonic-gate cpi->cpi_model == 8) 19637c478bd9Sstevel@tonic-gate cp->cp_ecx = 19647c478bd9Sstevel@tonic-gate BITX(cp->cp_ecx, 31, 24) << 16 | 19657c478bd9Sstevel@tonic-gate BITX(cp->cp_ecx, 23, 16) << 12 | 19667c478bd9Sstevel@tonic-gate BITX(cp->cp_ecx, 15, 8) << 8 | 19677c478bd9Sstevel@tonic-gate BITX(cp->cp_ecx, 7, 0); 19687c478bd9Sstevel@tonic-gate /* 19697c478bd9Sstevel@tonic-gate * model 9 stepping 1 has wrong associativity 19707c478bd9Sstevel@tonic-gate */ 19717c478bd9Sstevel@tonic-gate if (cpi->cpi_model == 9 && cpi->cpi_step == 1) 19727c478bd9Sstevel@tonic-gate cp->cp_ecx |= 8 << 12; 19737c478bd9Sstevel@tonic-gate break; 19747c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 19757c478bd9Sstevel@tonic-gate /* 19767c478bd9Sstevel@tonic-gate * Extended L2 Cache features function. 19777c478bd9Sstevel@tonic-gate * First appeared on Prescott. 19787c478bd9Sstevel@tonic-gate */ 19797c478bd9Sstevel@tonic-gate default: 19807c478bd9Sstevel@tonic-gate break; 19817c478bd9Sstevel@tonic-gate } 19827c478bd9Sstevel@tonic-gate break; 19837c478bd9Sstevel@tonic-gate default: 19847c478bd9Sstevel@tonic-gate break; 19857c478bd9Sstevel@tonic-gate } 19867c478bd9Sstevel@tonic-gate } 19877c478bd9Sstevel@tonic-gate 19887c478bd9Sstevel@tonic-gate pass2_done: 19897c478bd9Sstevel@tonic-gate cpi->cpi_pass = 2; 19907c478bd9Sstevel@tonic-gate } 19917c478bd9Sstevel@tonic-gate 19927c478bd9Sstevel@tonic-gate static const char * 19937c478bd9Sstevel@tonic-gate intel_cpubrand(const struct cpuid_info *cpi) 19947c478bd9Sstevel@tonic-gate { 19957c478bd9Sstevel@tonic-gate int i; 19967c478bd9Sstevel@tonic-gate 19977417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_CPUID) || 19987c478bd9Sstevel@tonic-gate cpi->cpi_maxeax < 1 || cpi->cpi_family < 5) 19997c478bd9Sstevel@tonic-gate return ("i486"); 20007c478bd9Sstevel@tonic-gate 20017c478bd9Sstevel@tonic-gate switch (cpi->cpi_family) { 20027c478bd9Sstevel@tonic-gate case 5: 20037c478bd9Sstevel@tonic-gate return ("Intel Pentium(r)"); 20047c478bd9Sstevel@tonic-gate case 6: 20057c478bd9Sstevel@tonic-gate switch (cpi->cpi_model) { 20067c478bd9Sstevel@tonic-gate uint_t celeron, xeon; 20078949bcd6Sandrei const struct cpuid_regs *cp; 20087c478bd9Sstevel@tonic-gate case 0: 20097c478bd9Sstevel@tonic-gate case 1: 20107c478bd9Sstevel@tonic-gate case 2: 20117c478bd9Sstevel@tonic-gate return ("Intel Pentium(r) Pro"); 20127c478bd9Sstevel@tonic-gate case 3: 20137c478bd9Sstevel@tonic-gate case 4: 20147c478bd9Sstevel@tonic-gate return ("Intel Pentium(r) II"); 20157c478bd9Sstevel@tonic-gate case 6: 20167c478bd9Sstevel@tonic-gate return ("Intel Celeron(r)"); 20177c478bd9Sstevel@tonic-gate case 5: 20187c478bd9Sstevel@tonic-gate case 7: 20197c478bd9Sstevel@tonic-gate celeron = xeon = 0; 20207c478bd9Sstevel@tonic-gate cp = &cpi->cpi_std[2]; /* cache info */ 20217c478bd9Sstevel@tonic-gate 202263d3f7dfSkk208521 for (i = 1; i < 4; i++) { 20237c478bd9Sstevel@tonic-gate uint_t tmp; 20247c478bd9Sstevel@tonic-gate 20257c478bd9Sstevel@tonic-gate tmp = (cp->cp_eax >> (8 * i)) & 0xff; 20267c478bd9Sstevel@tonic-gate if (tmp == 0x40) 20277c478bd9Sstevel@tonic-gate celeron++; 20287c478bd9Sstevel@tonic-gate if (tmp >= 0x44 && tmp <= 0x45) 20297c478bd9Sstevel@tonic-gate xeon++; 20307c478bd9Sstevel@tonic-gate } 20317c478bd9Sstevel@tonic-gate 20327c478bd9Sstevel@tonic-gate for (i = 0; i < 2; i++) { 20337c478bd9Sstevel@tonic-gate uint_t tmp; 20347c478bd9Sstevel@tonic-gate 20357c478bd9Sstevel@tonic-gate tmp = (cp->cp_ebx >> (8 * i)) & 0xff; 20367c478bd9Sstevel@tonic-gate if (tmp == 0x40) 20377c478bd9Sstevel@tonic-gate celeron++; 20387c478bd9Sstevel@tonic-gate else if (tmp >= 0x44 && tmp <= 0x45) 20397c478bd9Sstevel@tonic-gate xeon++; 20407c478bd9Sstevel@tonic-gate } 20417c478bd9Sstevel@tonic-gate 20427c478bd9Sstevel@tonic-gate for (i = 0; i < 4; i++) { 20437c478bd9Sstevel@tonic-gate uint_t tmp; 20447c478bd9Sstevel@tonic-gate 20457c478bd9Sstevel@tonic-gate tmp = (cp->cp_ecx >> (8 * i)) & 0xff; 20467c478bd9Sstevel@tonic-gate if (tmp == 0x40) 20477c478bd9Sstevel@tonic-gate celeron++; 20487c478bd9Sstevel@tonic-gate else if (tmp >= 0x44 && tmp <= 0x45) 20497c478bd9Sstevel@tonic-gate xeon++; 20507c478bd9Sstevel@tonic-gate } 20517c478bd9Sstevel@tonic-gate 20527c478bd9Sstevel@tonic-gate for (i = 0; i < 4; i++) { 20537c478bd9Sstevel@tonic-gate uint_t tmp; 20547c478bd9Sstevel@tonic-gate 20557c478bd9Sstevel@tonic-gate tmp = (cp->cp_edx >> (8 * i)) & 0xff; 20567c478bd9Sstevel@tonic-gate if (tmp == 0x40) 20577c478bd9Sstevel@tonic-gate celeron++; 20587c478bd9Sstevel@tonic-gate else if (tmp >= 0x44 && tmp <= 0x45) 20597c478bd9Sstevel@tonic-gate xeon++; 20607c478bd9Sstevel@tonic-gate } 20617c478bd9Sstevel@tonic-gate 20627c478bd9Sstevel@tonic-gate if (celeron) 20637c478bd9Sstevel@tonic-gate return ("Intel Celeron(r)"); 20647c478bd9Sstevel@tonic-gate if (xeon) 20657c478bd9Sstevel@tonic-gate return (cpi->cpi_model == 5 ? 20667c478bd9Sstevel@tonic-gate "Intel Pentium(r) II Xeon(tm)" : 20677c478bd9Sstevel@tonic-gate "Intel Pentium(r) III Xeon(tm)"); 20687c478bd9Sstevel@tonic-gate return (cpi->cpi_model == 5 ? 20697c478bd9Sstevel@tonic-gate "Intel Pentium(r) II or Pentium(r) II Xeon(tm)" : 20707c478bd9Sstevel@tonic-gate "Intel Pentium(r) III or Pentium(r) III Xeon(tm)"); 20717c478bd9Sstevel@tonic-gate default: 20727c478bd9Sstevel@tonic-gate break; 20737c478bd9Sstevel@tonic-gate } 20747c478bd9Sstevel@tonic-gate default: 20757c478bd9Sstevel@tonic-gate break; 20767c478bd9Sstevel@tonic-gate } 20777c478bd9Sstevel@tonic-gate 20785ff02082Sdmick /* BrandID is present if the field is nonzero */ 20795ff02082Sdmick if (cpi->cpi_brandid != 0) { 20807c478bd9Sstevel@tonic-gate static const struct { 20817c478bd9Sstevel@tonic-gate uint_t bt_bid; 20827c478bd9Sstevel@tonic-gate const char *bt_str; 20837c478bd9Sstevel@tonic-gate } brand_tbl[] = { 20847c478bd9Sstevel@tonic-gate { 0x1, "Intel(r) Celeron(r)" }, 20857c478bd9Sstevel@tonic-gate { 0x2, "Intel(r) Pentium(r) III" }, 20867c478bd9Sstevel@tonic-gate { 0x3, "Intel(r) Pentium(r) III Xeon(tm)" }, 20877c478bd9Sstevel@tonic-gate { 0x4, "Intel(r) Pentium(r) III" }, 20887c478bd9Sstevel@tonic-gate { 0x6, "Mobile Intel(r) Pentium(r) III" }, 20897c478bd9Sstevel@tonic-gate { 0x7, "Mobile Intel(r) Celeron(r)" }, 20907c478bd9Sstevel@tonic-gate { 0x8, "Intel(r) Pentium(r) 4" }, 20917c478bd9Sstevel@tonic-gate { 0x9, "Intel(r) Pentium(r) 4" }, 20927c478bd9Sstevel@tonic-gate { 0xa, "Intel(r) Celeron(r)" }, 20937c478bd9Sstevel@tonic-gate { 0xb, "Intel(r) Xeon(tm)" }, 20947c478bd9Sstevel@tonic-gate { 0xc, "Intel(r) Xeon(tm) MP" }, 20957c478bd9Sstevel@tonic-gate { 0xe, "Mobile Intel(r) Pentium(r) 4" }, 20965ff02082Sdmick { 0xf, "Mobile Intel(r) Celeron(r)" }, 20975ff02082Sdmick { 0x11, "Mobile Genuine Intel(r)" }, 20985ff02082Sdmick { 0x12, "Intel(r) Celeron(r) M" }, 20995ff02082Sdmick { 0x13, "Mobile Intel(r) Celeron(r)" }, 21005ff02082Sdmick { 0x14, "Intel(r) Celeron(r)" }, 21015ff02082Sdmick { 0x15, "Mobile Genuine Intel(r)" }, 21025ff02082Sdmick { 0x16, "Intel(r) Pentium(r) M" }, 21035ff02082Sdmick { 0x17, "Mobile Intel(r) Celeron(r)" } 21047c478bd9Sstevel@tonic-gate }; 21057c478bd9Sstevel@tonic-gate uint_t btblmax = sizeof (brand_tbl) / sizeof (brand_tbl[0]); 21067c478bd9Sstevel@tonic-gate uint_t sgn; 21077c478bd9Sstevel@tonic-gate 21087c478bd9Sstevel@tonic-gate sgn = (cpi->cpi_family << 8) | 21097c478bd9Sstevel@tonic-gate (cpi->cpi_model << 4) | cpi->cpi_step; 21107c478bd9Sstevel@tonic-gate 21117c478bd9Sstevel@tonic-gate for (i = 0; i < btblmax; i++) 21127c478bd9Sstevel@tonic-gate if (brand_tbl[i].bt_bid == cpi->cpi_brandid) 21137c478bd9Sstevel@tonic-gate break; 21147c478bd9Sstevel@tonic-gate if (i < btblmax) { 21157c478bd9Sstevel@tonic-gate if (sgn == 0x6b1 && cpi->cpi_brandid == 3) 21167c478bd9Sstevel@tonic-gate return ("Intel(r) Celeron(r)"); 21177c478bd9Sstevel@tonic-gate if (sgn < 0xf13 && cpi->cpi_brandid == 0xb) 21187c478bd9Sstevel@tonic-gate return ("Intel(r) Xeon(tm) MP"); 21197c478bd9Sstevel@tonic-gate if (sgn < 0xf13 && cpi->cpi_brandid == 0xe) 21207c478bd9Sstevel@tonic-gate return ("Intel(r) Xeon(tm)"); 21217c478bd9Sstevel@tonic-gate return (brand_tbl[i].bt_str); 21227c478bd9Sstevel@tonic-gate } 21237c478bd9Sstevel@tonic-gate } 21247c478bd9Sstevel@tonic-gate 21257c478bd9Sstevel@tonic-gate return (NULL); 21267c478bd9Sstevel@tonic-gate } 21277c478bd9Sstevel@tonic-gate 21287c478bd9Sstevel@tonic-gate static const char * 21297c478bd9Sstevel@tonic-gate amd_cpubrand(const struct cpuid_info *cpi) 21307c478bd9Sstevel@tonic-gate { 21317417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_CPUID) || 21327c478bd9Sstevel@tonic-gate cpi->cpi_maxeax < 1 || cpi->cpi_family < 5) 21337c478bd9Sstevel@tonic-gate return ("i486 compatible"); 21347c478bd9Sstevel@tonic-gate 21357c478bd9Sstevel@tonic-gate switch (cpi->cpi_family) { 21367c478bd9Sstevel@tonic-gate case 5: 21377c478bd9Sstevel@tonic-gate switch (cpi->cpi_model) { 21387c478bd9Sstevel@tonic-gate case 0: 21397c478bd9Sstevel@tonic-gate case 1: 21407c478bd9Sstevel@tonic-gate case 2: 21417c478bd9Sstevel@tonic-gate case 3: 21427c478bd9Sstevel@tonic-gate case 4: 21437c478bd9Sstevel@tonic-gate case 5: 21447c478bd9Sstevel@tonic-gate return ("AMD-K5(r)"); 21457c478bd9Sstevel@tonic-gate case 6: 21467c478bd9Sstevel@tonic-gate case 7: 21477c478bd9Sstevel@tonic-gate return ("AMD-K6(r)"); 21487c478bd9Sstevel@tonic-gate case 8: 21497c478bd9Sstevel@tonic-gate return ("AMD-K6(r)-2"); 21507c478bd9Sstevel@tonic-gate case 9: 21517c478bd9Sstevel@tonic-gate return ("AMD-K6(r)-III"); 21527c478bd9Sstevel@tonic-gate default: 21537c478bd9Sstevel@tonic-gate return ("AMD (family 5)"); 21547c478bd9Sstevel@tonic-gate } 21557c478bd9Sstevel@tonic-gate case 6: 21567c478bd9Sstevel@tonic-gate switch (cpi->cpi_model) { 21577c478bd9Sstevel@tonic-gate case 1: 21587c478bd9Sstevel@tonic-gate return ("AMD-K7(tm)"); 21597c478bd9Sstevel@tonic-gate case 0: 21607c478bd9Sstevel@tonic-gate case 2: 21617c478bd9Sstevel@tonic-gate case 4: 21627c478bd9Sstevel@tonic-gate return ("AMD Athlon(tm)"); 21637c478bd9Sstevel@tonic-gate case 3: 21647c478bd9Sstevel@tonic-gate case 7: 21657c478bd9Sstevel@tonic-gate return ("AMD Duron(tm)"); 21667c478bd9Sstevel@tonic-gate case 6: 21677c478bd9Sstevel@tonic-gate case 8: 21687c478bd9Sstevel@tonic-gate case 10: 21697c478bd9Sstevel@tonic-gate /* 21707c478bd9Sstevel@tonic-gate * Use the L2 cache size to distinguish 21717c478bd9Sstevel@tonic-gate */ 21727c478bd9Sstevel@tonic-gate return ((cpi->cpi_extd[6].cp_ecx >> 16) >= 256 ? 21737c478bd9Sstevel@tonic-gate "AMD Athlon(tm)" : "AMD Duron(tm)"); 21747c478bd9Sstevel@tonic-gate default: 21757c478bd9Sstevel@tonic-gate return ("AMD (family 6)"); 21767c478bd9Sstevel@tonic-gate } 21777c478bd9Sstevel@tonic-gate default: 21787c478bd9Sstevel@tonic-gate break; 21797c478bd9Sstevel@tonic-gate } 21807c478bd9Sstevel@tonic-gate 21817c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 0xf && cpi->cpi_model == 5 && 21827c478bd9Sstevel@tonic-gate cpi->cpi_brandid != 0) { 21837c478bd9Sstevel@tonic-gate switch (BITX(cpi->cpi_brandid, 7, 5)) { 21847c478bd9Sstevel@tonic-gate case 3: 21857c478bd9Sstevel@tonic-gate return ("AMD Opteron(tm) UP 1xx"); 21867c478bd9Sstevel@tonic-gate case 4: 21877c478bd9Sstevel@tonic-gate return ("AMD Opteron(tm) DP 2xx"); 21887c478bd9Sstevel@tonic-gate case 5: 21897c478bd9Sstevel@tonic-gate return ("AMD Opteron(tm) MP 8xx"); 21907c478bd9Sstevel@tonic-gate default: 21917c478bd9Sstevel@tonic-gate return ("AMD Opteron(tm)"); 21927c478bd9Sstevel@tonic-gate } 21937c478bd9Sstevel@tonic-gate } 21947c478bd9Sstevel@tonic-gate 21957c478bd9Sstevel@tonic-gate return (NULL); 21967c478bd9Sstevel@tonic-gate } 21977c478bd9Sstevel@tonic-gate 21987c478bd9Sstevel@tonic-gate static const char * 21997c478bd9Sstevel@tonic-gate cyrix_cpubrand(struct cpuid_info *cpi, uint_t type) 22007c478bd9Sstevel@tonic-gate { 22017417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_CPUID) || 22027c478bd9Sstevel@tonic-gate cpi->cpi_maxeax < 1 || cpi->cpi_family < 5 || 22037c478bd9Sstevel@tonic-gate type == X86_TYPE_CYRIX_486) 22047c478bd9Sstevel@tonic-gate return ("i486 compatible"); 22057c478bd9Sstevel@tonic-gate 22067c478bd9Sstevel@tonic-gate switch (type) { 22077c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_6x86: 22087c478bd9Sstevel@tonic-gate return ("Cyrix 6x86"); 22097c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_6x86L: 22107c478bd9Sstevel@tonic-gate return ("Cyrix 6x86L"); 22117c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_6x86MX: 22127c478bd9Sstevel@tonic-gate return ("Cyrix 6x86MX"); 22137c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_GXm: 22147c478bd9Sstevel@tonic-gate return ("Cyrix GXm"); 22157c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_MediaGX: 22167c478bd9Sstevel@tonic-gate return ("Cyrix MediaGX"); 22177c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_MII: 22187c478bd9Sstevel@tonic-gate return ("Cyrix M2"); 22197c478bd9Sstevel@tonic-gate case X86_TYPE_VIA_CYRIX_III: 22207c478bd9Sstevel@tonic-gate return ("VIA Cyrix M3"); 22217c478bd9Sstevel@tonic-gate default: 22227c478bd9Sstevel@tonic-gate /* 22237c478bd9Sstevel@tonic-gate * Have another wild guess .. 22247c478bd9Sstevel@tonic-gate */ 22257c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 4 && cpi->cpi_model == 9) 22267c478bd9Sstevel@tonic-gate return ("Cyrix 5x86"); 22277c478bd9Sstevel@tonic-gate else if (cpi->cpi_family == 5) { 22287c478bd9Sstevel@tonic-gate switch (cpi->cpi_model) { 22297c478bd9Sstevel@tonic-gate case 2: 22307c478bd9Sstevel@tonic-gate return ("Cyrix 6x86"); /* Cyrix M1 */ 22317c478bd9Sstevel@tonic-gate case 4: 22327c478bd9Sstevel@tonic-gate return ("Cyrix MediaGX"); 22337c478bd9Sstevel@tonic-gate default: 22347c478bd9Sstevel@tonic-gate break; 22357c478bd9Sstevel@tonic-gate } 22367c478bd9Sstevel@tonic-gate } else if (cpi->cpi_family == 6) { 22377c478bd9Sstevel@tonic-gate switch (cpi->cpi_model) { 22387c478bd9Sstevel@tonic-gate case 0: 22397c478bd9Sstevel@tonic-gate return ("Cyrix 6x86MX"); /* Cyrix M2? */ 22407c478bd9Sstevel@tonic-gate case 5: 22417c478bd9Sstevel@tonic-gate case 6: 22427c478bd9Sstevel@tonic-gate case 7: 22437c478bd9Sstevel@tonic-gate case 8: 22447c478bd9Sstevel@tonic-gate case 9: 22457c478bd9Sstevel@tonic-gate return ("VIA C3"); 22467c478bd9Sstevel@tonic-gate default: 22477c478bd9Sstevel@tonic-gate break; 22487c478bd9Sstevel@tonic-gate } 22497c478bd9Sstevel@tonic-gate } 22507c478bd9Sstevel@tonic-gate break; 22517c478bd9Sstevel@tonic-gate } 22527c478bd9Sstevel@tonic-gate return (NULL); 22537c478bd9Sstevel@tonic-gate } 22547c478bd9Sstevel@tonic-gate 22557c478bd9Sstevel@tonic-gate /* 22567c478bd9Sstevel@tonic-gate * This only gets called in the case that the CPU extended 22577c478bd9Sstevel@tonic-gate * feature brand string (0x80000002, 0x80000003, 0x80000004) 22587c478bd9Sstevel@tonic-gate * aren't available, or contain null bytes for some reason. 22597c478bd9Sstevel@tonic-gate */ 22607c478bd9Sstevel@tonic-gate static void 22617c478bd9Sstevel@tonic-gate fabricate_brandstr(struct cpuid_info *cpi) 22627c478bd9Sstevel@tonic-gate { 22637c478bd9Sstevel@tonic-gate const char *brand = NULL; 22647c478bd9Sstevel@tonic-gate 22657c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 22667c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 22677c478bd9Sstevel@tonic-gate brand = intel_cpubrand(cpi); 22687c478bd9Sstevel@tonic-gate break; 22697c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 22707c478bd9Sstevel@tonic-gate brand = amd_cpubrand(cpi); 22717c478bd9Sstevel@tonic-gate break; 22727c478bd9Sstevel@tonic-gate case X86_VENDOR_Cyrix: 22737c478bd9Sstevel@tonic-gate brand = cyrix_cpubrand(cpi, x86_type); 22747c478bd9Sstevel@tonic-gate break; 22757c478bd9Sstevel@tonic-gate case X86_VENDOR_NexGen: 22767c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 5 && cpi->cpi_model == 0) 22777c478bd9Sstevel@tonic-gate brand = "NexGen Nx586"; 22787c478bd9Sstevel@tonic-gate break; 22797c478bd9Sstevel@tonic-gate case X86_VENDOR_Centaur: 22807c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 5) 22817c478bd9Sstevel@tonic-gate switch (cpi->cpi_model) { 22827c478bd9Sstevel@tonic-gate case 4: 22837c478bd9Sstevel@tonic-gate brand = "Centaur C6"; 22847c478bd9Sstevel@tonic-gate break; 22857c478bd9Sstevel@tonic-gate case 8: 22867c478bd9Sstevel@tonic-gate brand = "Centaur C2"; 22877c478bd9Sstevel@tonic-gate break; 22887c478bd9Sstevel@tonic-gate case 9: 22897c478bd9Sstevel@tonic-gate brand = "Centaur C3"; 22907c478bd9Sstevel@tonic-gate break; 22917c478bd9Sstevel@tonic-gate default: 22927c478bd9Sstevel@tonic-gate break; 22937c478bd9Sstevel@tonic-gate } 22947c478bd9Sstevel@tonic-gate break; 22957c478bd9Sstevel@tonic-gate case X86_VENDOR_Rise: 22967c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 5 && 22977c478bd9Sstevel@tonic-gate (cpi->cpi_model == 0 || cpi->cpi_model == 2)) 22987c478bd9Sstevel@tonic-gate brand = "Rise mP6"; 22997c478bd9Sstevel@tonic-gate break; 23007c478bd9Sstevel@tonic-gate case X86_VENDOR_SiS: 23017c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 5 && cpi->cpi_model == 0) 23027c478bd9Sstevel@tonic-gate brand = "SiS 55x"; 23037c478bd9Sstevel@tonic-gate break; 23047c478bd9Sstevel@tonic-gate case X86_VENDOR_TM: 23057c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 5 && cpi->cpi_model == 4) 23067c478bd9Sstevel@tonic-gate brand = "Transmeta Crusoe TM3x00 or TM5x00"; 23077c478bd9Sstevel@tonic-gate break; 23087c478bd9Sstevel@tonic-gate case X86_VENDOR_NSC: 23097c478bd9Sstevel@tonic-gate case X86_VENDOR_UMC: 23107c478bd9Sstevel@tonic-gate default: 23117c478bd9Sstevel@tonic-gate break; 23127c478bd9Sstevel@tonic-gate } 23137c478bd9Sstevel@tonic-gate if (brand) { 23147c478bd9Sstevel@tonic-gate (void) strcpy((char *)cpi->cpi_brandstr, brand); 23157c478bd9Sstevel@tonic-gate return; 23167c478bd9Sstevel@tonic-gate } 23177c478bd9Sstevel@tonic-gate 23187c478bd9Sstevel@tonic-gate /* 23197c478bd9Sstevel@tonic-gate * If all else fails ... 23207c478bd9Sstevel@tonic-gate */ 23217c478bd9Sstevel@tonic-gate (void) snprintf(cpi->cpi_brandstr, sizeof (cpi->cpi_brandstr), 23227c478bd9Sstevel@tonic-gate "%s %d.%d.%d", cpi->cpi_vendorstr, cpi->cpi_family, 23237c478bd9Sstevel@tonic-gate cpi->cpi_model, cpi->cpi_step); 23247c478bd9Sstevel@tonic-gate } 23257c478bd9Sstevel@tonic-gate 23267c478bd9Sstevel@tonic-gate /* 23277c478bd9Sstevel@tonic-gate * This routine is called just after kernel memory allocation 23287c478bd9Sstevel@tonic-gate * becomes available on cpu0, and as part of mp_startup() on 23297c478bd9Sstevel@tonic-gate * the other cpus. 23307c478bd9Sstevel@tonic-gate * 2331d129bde2Sesaxe * Fixup the brand string, and collect any information from cpuid 2332d129bde2Sesaxe * that requires dynamicically allocated storage to represent. 23337c478bd9Sstevel@tonic-gate */ 23347c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 23357c478bd9Sstevel@tonic-gate void 23367c478bd9Sstevel@tonic-gate cpuid_pass3(cpu_t *cpu) 23377c478bd9Sstevel@tonic-gate { 2338d129bde2Sesaxe int i, max, shft, level, size; 2339d129bde2Sesaxe struct cpuid_regs regs; 2340d129bde2Sesaxe struct cpuid_regs *cp; 23417c478bd9Sstevel@tonic-gate struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi; 23427c478bd9Sstevel@tonic-gate 23437c478bd9Sstevel@tonic-gate ASSERT(cpi->cpi_pass == 2); 23447c478bd9Sstevel@tonic-gate 2345d129bde2Sesaxe /* 2346d129bde2Sesaxe * Function 4: Deterministic cache parameters 2347d129bde2Sesaxe * 2348d129bde2Sesaxe * Take this opportunity to detect the number of threads 2349d129bde2Sesaxe * sharing the last level cache, and construct a corresponding 2350d129bde2Sesaxe * cache id. The respective cpuid_info members are initialized 2351d129bde2Sesaxe * to the default case of "no last level cache sharing". 2352d129bde2Sesaxe */ 2353d129bde2Sesaxe cpi->cpi_ncpu_shr_last_cache = 1; 2354d129bde2Sesaxe cpi->cpi_last_lvl_cacheid = cpu->cpu_id; 2355d129bde2Sesaxe 2356d129bde2Sesaxe if (cpi->cpi_maxeax >= 4 && cpi->cpi_vendor == X86_VENDOR_Intel) { 2357d129bde2Sesaxe 2358d129bde2Sesaxe /* 2359d129bde2Sesaxe * Find the # of elements (size) returned by fn 4, and along 2360d129bde2Sesaxe * the way detect last level cache sharing details. 2361d129bde2Sesaxe */ 2362d129bde2Sesaxe bzero(®s, sizeof (regs)); 2363d129bde2Sesaxe cp = ®s; 2364d129bde2Sesaxe for (i = 0, max = 0; i < CPI_FN4_ECX_MAX; i++) { 2365d129bde2Sesaxe cp->cp_eax = 4; 2366d129bde2Sesaxe cp->cp_ecx = i; 2367d129bde2Sesaxe 2368d129bde2Sesaxe (void) __cpuid_insn(cp); 2369d129bde2Sesaxe 2370d129bde2Sesaxe if (CPI_CACHE_TYPE(cp) == 0) 2371d129bde2Sesaxe break; 2372d129bde2Sesaxe level = CPI_CACHE_LVL(cp); 2373d129bde2Sesaxe if (level > max) { 2374d129bde2Sesaxe max = level; 2375d129bde2Sesaxe cpi->cpi_ncpu_shr_last_cache = 2376d129bde2Sesaxe CPI_NTHR_SHR_CACHE(cp) + 1; 2377d129bde2Sesaxe } 2378d129bde2Sesaxe } 2379d129bde2Sesaxe cpi->cpi_std_4_size = size = i; 2380d129bde2Sesaxe 2381d129bde2Sesaxe /* 2382d129bde2Sesaxe * Allocate the cpi_std_4 array. The first element 2383d129bde2Sesaxe * references the regs for fn 4, %ecx == 0, which 2384d129bde2Sesaxe * cpuid_pass2() stashed in cpi->cpi_std[4]. 2385d129bde2Sesaxe */ 2386d129bde2Sesaxe if (size > 0) { 2387d129bde2Sesaxe cpi->cpi_std_4 = 2388d129bde2Sesaxe kmem_alloc(size * sizeof (cp), KM_SLEEP); 2389d129bde2Sesaxe cpi->cpi_std_4[0] = &cpi->cpi_std[4]; 2390d129bde2Sesaxe 2391d129bde2Sesaxe /* 2392d129bde2Sesaxe * Allocate storage to hold the additional regs 2393d129bde2Sesaxe * for function 4, %ecx == 1 .. cpi_std_4_size. 2394d129bde2Sesaxe * 2395d129bde2Sesaxe * The regs for fn 4, %ecx == 0 has already 2396d129bde2Sesaxe * been allocated as indicated above. 2397d129bde2Sesaxe */ 2398d129bde2Sesaxe for (i = 1; i < size; i++) { 2399d129bde2Sesaxe cp = cpi->cpi_std_4[i] = 2400d129bde2Sesaxe kmem_zalloc(sizeof (regs), KM_SLEEP); 2401d129bde2Sesaxe cp->cp_eax = 4; 2402d129bde2Sesaxe cp->cp_ecx = i; 2403d129bde2Sesaxe 2404d129bde2Sesaxe (void) __cpuid_insn(cp); 2405d129bde2Sesaxe } 2406d129bde2Sesaxe } 2407d129bde2Sesaxe /* 2408d129bde2Sesaxe * Determine the number of bits needed to represent 2409d129bde2Sesaxe * the number of CPUs sharing the last level cache. 2410d129bde2Sesaxe * 2411d129bde2Sesaxe * Shift off that number of bits from the APIC id to 2412d129bde2Sesaxe * derive the cache id. 2413d129bde2Sesaxe */ 2414d129bde2Sesaxe shft = 0; 2415d129bde2Sesaxe for (i = 1; i < cpi->cpi_ncpu_shr_last_cache; i <<= 1) 2416d129bde2Sesaxe shft++; 2417b6917abeSmishra cpi->cpi_last_lvl_cacheid = cpi->cpi_apicid >> shft; 2418d129bde2Sesaxe } 2419d129bde2Sesaxe 2420d129bde2Sesaxe /* 2421d129bde2Sesaxe * Now fixup the brand string 2422d129bde2Sesaxe */ 24237c478bd9Sstevel@tonic-gate if ((cpi->cpi_xmaxeax & 0x80000000) == 0) { 24247c478bd9Sstevel@tonic-gate fabricate_brandstr(cpi); 2425d129bde2Sesaxe } else { 24267c478bd9Sstevel@tonic-gate 24277c478bd9Sstevel@tonic-gate /* 24287c478bd9Sstevel@tonic-gate * If we successfully extracted a brand string from the cpuid 24297c478bd9Sstevel@tonic-gate * instruction, clean it up by removing leading spaces and 24307c478bd9Sstevel@tonic-gate * similar junk. 24317c478bd9Sstevel@tonic-gate */ 24327c478bd9Sstevel@tonic-gate if (cpi->cpi_brandstr[0]) { 24337c478bd9Sstevel@tonic-gate size_t maxlen = sizeof (cpi->cpi_brandstr); 24347c478bd9Sstevel@tonic-gate char *src, *dst; 24357c478bd9Sstevel@tonic-gate 24367c478bd9Sstevel@tonic-gate dst = src = (char *)cpi->cpi_brandstr; 24377c478bd9Sstevel@tonic-gate src[maxlen - 1] = '\0'; 24387c478bd9Sstevel@tonic-gate /* 24397c478bd9Sstevel@tonic-gate * strip leading spaces 24407c478bd9Sstevel@tonic-gate */ 24417c478bd9Sstevel@tonic-gate while (*src == ' ') 24427c478bd9Sstevel@tonic-gate src++; 24437c478bd9Sstevel@tonic-gate /* 24447c478bd9Sstevel@tonic-gate * Remove any 'Genuine' or "Authentic" prefixes 24457c478bd9Sstevel@tonic-gate */ 24467c478bd9Sstevel@tonic-gate if (strncmp(src, "Genuine ", 8) == 0) 24477c478bd9Sstevel@tonic-gate src += 8; 24487c478bd9Sstevel@tonic-gate if (strncmp(src, "Authentic ", 10) == 0) 24497c478bd9Sstevel@tonic-gate src += 10; 24507c478bd9Sstevel@tonic-gate 24517c478bd9Sstevel@tonic-gate /* 24527c478bd9Sstevel@tonic-gate * Now do an in-place copy. 24537c478bd9Sstevel@tonic-gate * Map (R) to (r) and (TM) to (tm). 24547c478bd9Sstevel@tonic-gate * The era of teletypes is long gone, and there's 24557c478bd9Sstevel@tonic-gate * -really- no need to shout. 24567c478bd9Sstevel@tonic-gate */ 24577c478bd9Sstevel@tonic-gate while (*src != '\0') { 24587c478bd9Sstevel@tonic-gate if (src[0] == '(') { 24597c478bd9Sstevel@tonic-gate if (strncmp(src + 1, "R)", 2) == 0) { 24607c478bd9Sstevel@tonic-gate (void) strncpy(dst, "(r)", 3); 24617c478bd9Sstevel@tonic-gate src += 3; 24627c478bd9Sstevel@tonic-gate dst += 3; 24637c478bd9Sstevel@tonic-gate continue; 24647c478bd9Sstevel@tonic-gate } 24657c478bd9Sstevel@tonic-gate if (strncmp(src + 1, "TM)", 3) == 0) { 24667c478bd9Sstevel@tonic-gate (void) strncpy(dst, "(tm)", 4); 24677c478bd9Sstevel@tonic-gate src += 4; 24687c478bd9Sstevel@tonic-gate dst += 4; 24697c478bd9Sstevel@tonic-gate continue; 24707c478bd9Sstevel@tonic-gate } 24717c478bd9Sstevel@tonic-gate } 24727c478bd9Sstevel@tonic-gate *dst++ = *src++; 24737c478bd9Sstevel@tonic-gate } 24747c478bd9Sstevel@tonic-gate *dst = '\0'; 24757c478bd9Sstevel@tonic-gate 24767c478bd9Sstevel@tonic-gate /* 24777c478bd9Sstevel@tonic-gate * Finally, remove any trailing spaces 24787c478bd9Sstevel@tonic-gate */ 24797c478bd9Sstevel@tonic-gate while (--dst > cpi->cpi_brandstr) 24807c478bd9Sstevel@tonic-gate if (*dst == ' ') 24817c478bd9Sstevel@tonic-gate *dst = '\0'; 24827c478bd9Sstevel@tonic-gate else 24837c478bd9Sstevel@tonic-gate break; 24847c478bd9Sstevel@tonic-gate } else 24857c478bd9Sstevel@tonic-gate fabricate_brandstr(cpi); 2486d129bde2Sesaxe } 24877c478bd9Sstevel@tonic-gate cpi->cpi_pass = 3; 24887c478bd9Sstevel@tonic-gate } 24897c478bd9Sstevel@tonic-gate 24907c478bd9Sstevel@tonic-gate /* 24917c478bd9Sstevel@tonic-gate * This routine is called out of bind_hwcap() much later in the life 24927c478bd9Sstevel@tonic-gate * of the kernel (post_startup()). The job of this routine is to resolve 24937c478bd9Sstevel@tonic-gate * the hardware feature support and kernel support for those features into 24947c478bd9Sstevel@tonic-gate * what we're actually going to tell applications via the aux vector. 24957c478bd9Sstevel@tonic-gate */ 24967c478bd9Sstevel@tonic-gate uint_t 24977c478bd9Sstevel@tonic-gate cpuid_pass4(cpu_t *cpu) 24987c478bd9Sstevel@tonic-gate { 24997c478bd9Sstevel@tonic-gate struct cpuid_info *cpi; 25007c478bd9Sstevel@tonic-gate uint_t hwcap_flags = 0; 25017c478bd9Sstevel@tonic-gate 25027c478bd9Sstevel@tonic-gate if (cpu == NULL) 25037c478bd9Sstevel@tonic-gate cpu = CPU; 25047c478bd9Sstevel@tonic-gate cpi = cpu->cpu_m.mcpu_cpi; 25057c478bd9Sstevel@tonic-gate 25067c478bd9Sstevel@tonic-gate ASSERT(cpi->cpi_pass == 3); 25077c478bd9Sstevel@tonic-gate 25087c478bd9Sstevel@tonic-gate if (cpi->cpi_maxeax >= 1) { 25097c478bd9Sstevel@tonic-gate uint32_t *edx = &cpi->cpi_support[STD_EDX_FEATURES]; 25107c478bd9Sstevel@tonic-gate uint32_t *ecx = &cpi->cpi_support[STD_ECX_FEATURES]; 25117c478bd9Sstevel@tonic-gate 25127c478bd9Sstevel@tonic-gate *edx = CPI_FEATURES_EDX(cpi); 25137c478bd9Sstevel@tonic-gate *ecx = CPI_FEATURES_ECX(cpi); 25147c478bd9Sstevel@tonic-gate 25157c478bd9Sstevel@tonic-gate /* 25167c478bd9Sstevel@tonic-gate * [these require explicit kernel support] 25177c478bd9Sstevel@tonic-gate */ 25187417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_SEP)) 25197c478bd9Sstevel@tonic-gate *edx &= ~CPUID_INTC_EDX_SEP; 25207c478bd9Sstevel@tonic-gate 25217417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_SSE)) 25227c478bd9Sstevel@tonic-gate *edx &= ~(CPUID_INTC_EDX_FXSR|CPUID_INTC_EDX_SSE); 25237417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_SSE2)) 25247c478bd9Sstevel@tonic-gate *edx &= ~CPUID_INTC_EDX_SSE2; 25257c478bd9Sstevel@tonic-gate 25267417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_HTT)) 25277c478bd9Sstevel@tonic-gate *edx &= ~CPUID_INTC_EDX_HTT; 25287c478bd9Sstevel@tonic-gate 25297417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_SSE3)) 25307c478bd9Sstevel@tonic-gate *ecx &= ~CPUID_INTC_ECX_SSE3; 25317c478bd9Sstevel@tonic-gate 25327417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_SSSE3)) 2533d0f8ff6eSkk208521 *ecx &= ~CPUID_INTC_ECX_SSSE3; 25347417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_SSE4_1)) 2535d0f8ff6eSkk208521 *ecx &= ~CPUID_INTC_ECX_SSE4_1; 25367417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_SSE4_2)) 2537d0f8ff6eSkk208521 *ecx &= ~CPUID_INTC_ECX_SSE4_2; 25387417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_AES)) 2539a50a8b93SKuriakose Kuruvilla *ecx &= ~CPUID_INTC_ECX_AES; 25407417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_PCLMULQDQ)) 25417417cfdeSKuriakose Kuruvilla *ecx &= ~CPUID_INTC_ECX_PCLMULQDQ; 25427af88ac7SKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_XSAVE)) 25437af88ac7SKuriakose Kuruvilla *ecx &= ~(CPUID_INTC_ECX_XSAVE | 25447af88ac7SKuriakose Kuruvilla CPUID_INTC_ECX_OSXSAVE); 25457af88ac7SKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_AVX)) 25467af88ac7SKuriakose Kuruvilla *ecx &= ~CPUID_INTC_ECX_AVX; 2547d0f8ff6eSkk208521 25487c478bd9Sstevel@tonic-gate /* 25497c478bd9Sstevel@tonic-gate * [no explicit support required beyond x87 fp context] 25507c478bd9Sstevel@tonic-gate */ 25517c478bd9Sstevel@tonic-gate if (!fpu_exists) 25527c478bd9Sstevel@tonic-gate *edx &= ~(CPUID_INTC_EDX_FPU | CPUID_INTC_EDX_MMX); 25537c478bd9Sstevel@tonic-gate 25547c478bd9Sstevel@tonic-gate /* 25557c478bd9Sstevel@tonic-gate * Now map the supported feature vector to things that we 25567c478bd9Sstevel@tonic-gate * think userland will care about. 25577c478bd9Sstevel@tonic-gate */ 25587c478bd9Sstevel@tonic-gate if (*edx & CPUID_INTC_EDX_SEP) 25597c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_SEP; 25607c478bd9Sstevel@tonic-gate if (*edx & CPUID_INTC_EDX_SSE) 25617c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_FXSR | AV_386_SSE; 25627c478bd9Sstevel@tonic-gate if (*edx & CPUID_INTC_EDX_SSE2) 25637c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_SSE2; 25647c478bd9Sstevel@tonic-gate if (*ecx & CPUID_INTC_ECX_SSE3) 25657c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_SSE3; 2566d0f8ff6eSkk208521 if (*ecx & CPUID_INTC_ECX_SSSE3) 2567d0f8ff6eSkk208521 hwcap_flags |= AV_386_SSSE3; 2568d0f8ff6eSkk208521 if (*ecx & CPUID_INTC_ECX_SSE4_1) 2569d0f8ff6eSkk208521 hwcap_flags |= AV_386_SSE4_1; 2570d0f8ff6eSkk208521 if (*ecx & CPUID_INTC_ECX_SSE4_2) 2571d0f8ff6eSkk208521 hwcap_flags |= AV_386_SSE4_2; 25725087e485SKrishnendu Sadhukhan - Sun Microsystems if (*ecx & CPUID_INTC_ECX_MOVBE) 25735087e485SKrishnendu Sadhukhan - Sun Microsystems hwcap_flags |= AV_386_MOVBE; 2574a50a8b93SKuriakose Kuruvilla if (*ecx & CPUID_INTC_ECX_AES) 2575a50a8b93SKuriakose Kuruvilla hwcap_flags |= AV_386_AES; 2576a50a8b93SKuriakose Kuruvilla if (*ecx & CPUID_INTC_ECX_PCLMULQDQ) 2577a50a8b93SKuriakose Kuruvilla hwcap_flags |= AV_386_PCLMULQDQ; 25787af88ac7SKuriakose Kuruvilla if ((*ecx & CPUID_INTC_ECX_XSAVE) && 2579*f3390f39SRobert Mustacchi (*ecx & CPUID_INTC_ECX_OSXSAVE)) { 25807af88ac7SKuriakose Kuruvilla hwcap_flags |= AV_386_XSAVE; 2581*f3390f39SRobert Mustacchi 2582*f3390f39SRobert Mustacchi if (*ecx & CPUID_INTC_ECX_AVX) 2583*f3390f39SRobert Mustacchi hwcap_flags |= AV_386_AVX; 2584*f3390f39SRobert Mustacchi } 2585faa20166SBryan Cantrill if (*ecx & CPUID_INTC_ECX_VMX) 2586faa20166SBryan Cantrill hwcap_flags |= AV_386_VMX; 2587f8801251Skk208521 if (*ecx & CPUID_INTC_ECX_POPCNT) 2588f8801251Skk208521 hwcap_flags |= AV_386_POPCNT; 25897c478bd9Sstevel@tonic-gate if (*edx & CPUID_INTC_EDX_FPU) 25907c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_FPU; 25917c478bd9Sstevel@tonic-gate if (*edx & CPUID_INTC_EDX_MMX) 25927c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_MMX; 25937c478bd9Sstevel@tonic-gate 25947c478bd9Sstevel@tonic-gate if (*edx & CPUID_INTC_EDX_TSC) 25957c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_TSC; 25967c478bd9Sstevel@tonic-gate if (*edx & CPUID_INTC_EDX_CX8) 25977c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_CX8; 25987c478bd9Sstevel@tonic-gate if (*edx & CPUID_INTC_EDX_CMOV) 25997c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_CMOV; 26007c478bd9Sstevel@tonic-gate if (*ecx & CPUID_INTC_ECX_CX16) 26017c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_CX16; 26027c478bd9Sstevel@tonic-gate } 26037c478bd9Sstevel@tonic-gate 26047c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax < 0x80000001) 26057c478bd9Sstevel@tonic-gate goto pass4_done; 26067c478bd9Sstevel@tonic-gate 26077c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 26088949bcd6Sandrei struct cpuid_regs cp; 2609ae115bc7Smrj uint32_t *edx, *ecx; 26107c478bd9Sstevel@tonic-gate 2611ae115bc7Smrj case X86_VENDOR_Intel: 2612ae115bc7Smrj /* 2613ae115bc7Smrj * Seems like Intel duplicated what we necessary 2614ae115bc7Smrj * here to make the initial crop of 64-bit OS's work. 2615ae115bc7Smrj * Hopefully, those are the only "extended" bits 2616ae115bc7Smrj * they'll add. 2617ae115bc7Smrj */ 2618ae115bc7Smrj /*FALLTHROUGH*/ 2619ae115bc7Smrj 26207c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 26217c478bd9Sstevel@tonic-gate edx = &cpi->cpi_support[AMD_EDX_FEATURES]; 2622ae115bc7Smrj ecx = &cpi->cpi_support[AMD_ECX_FEATURES]; 26237c478bd9Sstevel@tonic-gate 26247c478bd9Sstevel@tonic-gate *edx = CPI_FEATURES_XTD_EDX(cpi); 2625ae115bc7Smrj *ecx = CPI_FEATURES_XTD_ECX(cpi); 2626ae115bc7Smrj 2627ae115bc7Smrj /* 2628ae115bc7Smrj * [these features require explicit kernel support] 2629ae115bc7Smrj */ 2630ae115bc7Smrj switch (cpi->cpi_vendor) { 2631ae115bc7Smrj case X86_VENDOR_Intel: 26327417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_TSCP)) 2633d36ea5d8Ssudheer *edx &= ~CPUID_AMD_EDX_TSCP; 2634ae115bc7Smrj break; 2635ae115bc7Smrj 2636ae115bc7Smrj case X86_VENDOR_AMD: 26377417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_TSCP)) 2638ae115bc7Smrj *edx &= ~CPUID_AMD_EDX_TSCP; 26397417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_SSE4A)) 2640f8801251Skk208521 *ecx &= ~CPUID_AMD_ECX_SSE4A; 2641ae115bc7Smrj break; 2642ae115bc7Smrj 2643ae115bc7Smrj default: 2644ae115bc7Smrj break; 2645ae115bc7Smrj } 26467c478bd9Sstevel@tonic-gate 26477c478bd9Sstevel@tonic-gate /* 26487c478bd9Sstevel@tonic-gate * [no explicit support required beyond 26497c478bd9Sstevel@tonic-gate * x87 fp context and exception handlers] 26507c478bd9Sstevel@tonic-gate */ 26517c478bd9Sstevel@tonic-gate if (!fpu_exists) 26527c478bd9Sstevel@tonic-gate *edx &= ~(CPUID_AMD_EDX_MMXamd | 26537c478bd9Sstevel@tonic-gate CPUID_AMD_EDX_3DNow | CPUID_AMD_EDX_3DNowx); 26547c478bd9Sstevel@tonic-gate 26557417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_NX)) 26567c478bd9Sstevel@tonic-gate *edx &= ~CPUID_AMD_EDX_NX; 2657ae115bc7Smrj #if !defined(__amd64) 26587c478bd9Sstevel@tonic-gate *edx &= ~CPUID_AMD_EDX_LM; 26597c478bd9Sstevel@tonic-gate #endif 26607c478bd9Sstevel@tonic-gate /* 26617c478bd9Sstevel@tonic-gate * Now map the supported feature vector to 26627c478bd9Sstevel@tonic-gate * things that we think userland will care about. 26637c478bd9Sstevel@tonic-gate */ 2664ae115bc7Smrj #if defined(__amd64) 26657c478bd9Sstevel@tonic-gate if (*edx & CPUID_AMD_EDX_SYSC) 26667c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_AMD_SYSC; 2667ae115bc7Smrj #endif 26687c478bd9Sstevel@tonic-gate if (*edx & CPUID_AMD_EDX_MMXamd) 26697c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_AMD_MMX; 26707c478bd9Sstevel@tonic-gate if (*edx & CPUID_AMD_EDX_3DNow) 26717c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_AMD_3DNow; 26727c478bd9Sstevel@tonic-gate if (*edx & CPUID_AMD_EDX_3DNowx) 26737c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_AMD_3DNowx; 2674faa20166SBryan Cantrill if (*ecx & CPUID_AMD_ECX_SVM) 2675faa20166SBryan Cantrill hwcap_flags |= AV_386_AMD_SVM; 2676ae115bc7Smrj 2677ae115bc7Smrj switch (cpi->cpi_vendor) { 2678ae115bc7Smrj case X86_VENDOR_AMD: 2679ae115bc7Smrj if (*edx & CPUID_AMD_EDX_TSCP) 2680ae115bc7Smrj hwcap_flags |= AV_386_TSCP; 2681ae115bc7Smrj if (*ecx & CPUID_AMD_ECX_AHF64) 2682ae115bc7Smrj hwcap_flags |= AV_386_AHF; 2683f8801251Skk208521 if (*ecx & CPUID_AMD_ECX_SSE4A) 2684f8801251Skk208521 hwcap_flags |= AV_386_AMD_SSE4A; 2685f8801251Skk208521 if (*ecx & CPUID_AMD_ECX_LZCNT) 2686f8801251Skk208521 hwcap_flags |= AV_386_AMD_LZCNT; 2687ae115bc7Smrj break; 2688ae115bc7Smrj 2689ae115bc7Smrj case X86_VENDOR_Intel: 2690d36ea5d8Ssudheer if (*edx & CPUID_AMD_EDX_TSCP) 2691d36ea5d8Ssudheer hwcap_flags |= AV_386_TSCP; 2692ae115bc7Smrj /* 2693ae115bc7Smrj * Aarrgh. 2694ae115bc7Smrj * Intel uses a different bit in the same word. 2695ae115bc7Smrj */ 2696ae115bc7Smrj if (*ecx & CPUID_INTC_ECX_AHF64) 2697ae115bc7Smrj hwcap_flags |= AV_386_AHF; 2698ae115bc7Smrj break; 2699ae115bc7Smrj 2700ae115bc7Smrj default: 2701ae115bc7Smrj break; 2702ae115bc7Smrj } 27037c478bd9Sstevel@tonic-gate break; 27047c478bd9Sstevel@tonic-gate 27057c478bd9Sstevel@tonic-gate case X86_VENDOR_TM: 27068949bcd6Sandrei cp.cp_eax = 0x80860001; 27078949bcd6Sandrei (void) __cpuid_insn(&cp); 27088949bcd6Sandrei cpi->cpi_support[TM_EDX_FEATURES] = cp.cp_edx; 27097c478bd9Sstevel@tonic-gate break; 27107c478bd9Sstevel@tonic-gate 27117c478bd9Sstevel@tonic-gate default: 27127c478bd9Sstevel@tonic-gate break; 27137c478bd9Sstevel@tonic-gate } 27147c478bd9Sstevel@tonic-gate 27157c478bd9Sstevel@tonic-gate pass4_done: 27167c478bd9Sstevel@tonic-gate cpi->cpi_pass = 4; 27177c478bd9Sstevel@tonic-gate return (hwcap_flags); 27187c478bd9Sstevel@tonic-gate } 27197c478bd9Sstevel@tonic-gate 27207c478bd9Sstevel@tonic-gate 27217c478bd9Sstevel@tonic-gate /* 27227c478bd9Sstevel@tonic-gate * Simulate the cpuid instruction using the data we previously 27237c478bd9Sstevel@tonic-gate * captured about this CPU. We try our best to return the truth 27247c478bd9Sstevel@tonic-gate * about the hardware, independently of kernel support. 27257c478bd9Sstevel@tonic-gate */ 27267c478bd9Sstevel@tonic-gate uint32_t 27278949bcd6Sandrei cpuid_insn(cpu_t *cpu, struct cpuid_regs *cp) 27287c478bd9Sstevel@tonic-gate { 27297c478bd9Sstevel@tonic-gate struct cpuid_info *cpi; 27308949bcd6Sandrei struct cpuid_regs *xcp; 27317c478bd9Sstevel@tonic-gate 27327c478bd9Sstevel@tonic-gate if (cpu == NULL) 27337c478bd9Sstevel@tonic-gate cpu = CPU; 27347c478bd9Sstevel@tonic-gate cpi = cpu->cpu_m.mcpu_cpi; 27357c478bd9Sstevel@tonic-gate 27367c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 3)); 27377c478bd9Sstevel@tonic-gate 27387c478bd9Sstevel@tonic-gate /* 27397c478bd9Sstevel@tonic-gate * CPUID data is cached in two separate places: cpi_std for standard 27407c478bd9Sstevel@tonic-gate * CPUID functions, and cpi_extd for extended CPUID functions. 27417c478bd9Sstevel@tonic-gate */ 27428949bcd6Sandrei if (cp->cp_eax <= cpi->cpi_maxeax && cp->cp_eax < NMAX_CPI_STD) 27438949bcd6Sandrei xcp = &cpi->cpi_std[cp->cp_eax]; 27448949bcd6Sandrei else if (cp->cp_eax >= 0x80000000 && cp->cp_eax <= cpi->cpi_xmaxeax && 27458949bcd6Sandrei cp->cp_eax < 0x80000000 + NMAX_CPI_EXTD) 27468949bcd6Sandrei xcp = &cpi->cpi_extd[cp->cp_eax - 0x80000000]; 27477c478bd9Sstevel@tonic-gate else 27487c478bd9Sstevel@tonic-gate /* 27497c478bd9Sstevel@tonic-gate * The caller is asking for data from an input parameter which 27507c478bd9Sstevel@tonic-gate * the kernel has not cached. In this case we go fetch from 27517c478bd9Sstevel@tonic-gate * the hardware and return the data directly to the user. 27527c478bd9Sstevel@tonic-gate */ 27538949bcd6Sandrei return (__cpuid_insn(cp)); 27548949bcd6Sandrei 27558949bcd6Sandrei cp->cp_eax = xcp->cp_eax; 27568949bcd6Sandrei cp->cp_ebx = xcp->cp_ebx; 27578949bcd6Sandrei cp->cp_ecx = xcp->cp_ecx; 27588949bcd6Sandrei cp->cp_edx = xcp->cp_edx; 27597c478bd9Sstevel@tonic-gate return (cp->cp_eax); 27607c478bd9Sstevel@tonic-gate } 27617c478bd9Sstevel@tonic-gate 27627c478bd9Sstevel@tonic-gate int 27637c478bd9Sstevel@tonic-gate cpuid_checkpass(cpu_t *cpu, int pass) 27647c478bd9Sstevel@tonic-gate { 27657c478bd9Sstevel@tonic-gate return (cpu != NULL && cpu->cpu_m.mcpu_cpi != NULL && 27667c478bd9Sstevel@tonic-gate cpu->cpu_m.mcpu_cpi->cpi_pass >= pass); 27677c478bd9Sstevel@tonic-gate } 27687c478bd9Sstevel@tonic-gate 27697c478bd9Sstevel@tonic-gate int 27707c478bd9Sstevel@tonic-gate cpuid_getbrandstr(cpu_t *cpu, char *s, size_t n) 27717c478bd9Sstevel@tonic-gate { 27727c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 3)); 27737c478bd9Sstevel@tonic-gate 27747c478bd9Sstevel@tonic-gate return (snprintf(s, n, "%s", cpu->cpu_m.mcpu_cpi->cpi_brandstr)); 27757c478bd9Sstevel@tonic-gate } 27767c478bd9Sstevel@tonic-gate 27777c478bd9Sstevel@tonic-gate int 27788949bcd6Sandrei cpuid_is_cmt(cpu_t *cpu) 27797c478bd9Sstevel@tonic-gate { 27807c478bd9Sstevel@tonic-gate if (cpu == NULL) 27817c478bd9Sstevel@tonic-gate cpu = CPU; 27827c478bd9Sstevel@tonic-gate 27837c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 27847c478bd9Sstevel@tonic-gate 27857c478bd9Sstevel@tonic-gate return (cpu->cpu_m.mcpu_cpi->cpi_chipid >= 0); 27867c478bd9Sstevel@tonic-gate } 27877c478bd9Sstevel@tonic-gate 27887c478bd9Sstevel@tonic-gate /* 27897c478bd9Sstevel@tonic-gate * AMD and Intel both implement the 64-bit variant of the syscall 27907c478bd9Sstevel@tonic-gate * instruction (syscallq), so if there's -any- support for syscall, 27917c478bd9Sstevel@tonic-gate * cpuid currently says "yes, we support this". 27927c478bd9Sstevel@tonic-gate * 27937c478bd9Sstevel@tonic-gate * However, Intel decided to -not- implement the 32-bit variant of the 27947c478bd9Sstevel@tonic-gate * syscall instruction, so we provide a predicate to allow our caller 27957c478bd9Sstevel@tonic-gate * to test that subtlety here. 2796843e1988Sjohnlev * 2797843e1988Sjohnlev * XXPV Currently, 32-bit syscall instructions don't work via the hypervisor, 2798843e1988Sjohnlev * even in the case where the hardware would in fact support it. 27997c478bd9Sstevel@tonic-gate */ 28007c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 28017c478bd9Sstevel@tonic-gate int 28027c478bd9Sstevel@tonic-gate cpuid_syscall32_insn(cpu_t *cpu) 28037c478bd9Sstevel@tonic-gate { 28047c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass((cpu == NULL ? CPU : cpu), 1)); 28057c478bd9Sstevel@tonic-gate 2806843e1988Sjohnlev #if !defined(__xpv) 2807ae115bc7Smrj if (cpu == NULL) 2808ae115bc7Smrj cpu = CPU; 2809ae115bc7Smrj 2810ae115bc7Smrj /*CSTYLED*/ 2811ae115bc7Smrj { 2812ae115bc7Smrj struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi; 2813ae115bc7Smrj 2814ae115bc7Smrj if (cpi->cpi_vendor == X86_VENDOR_AMD && 2815ae115bc7Smrj cpi->cpi_xmaxeax >= 0x80000001 && 2816ae115bc7Smrj (CPI_FEATURES_XTD_EDX(cpi) & CPUID_AMD_EDX_SYSC)) 2817ae115bc7Smrj return (1); 2818ae115bc7Smrj } 2819843e1988Sjohnlev #endif 28207c478bd9Sstevel@tonic-gate return (0); 28217c478bd9Sstevel@tonic-gate } 28227c478bd9Sstevel@tonic-gate 28237c478bd9Sstevel@tonic-gate int 28247c478bd9Sstevel@tonic-gate cpuid_getidstr(cpu_t *cpu, char *s, size_t n) 28257c478bd9Sstevel@tonic-gate { 28267c478bd9Sstevel@tonic-gate struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi; 28277c478bd9Sstevel@tonic-gate 28287c478bd9Sstevel@tonic-gate static const char fmt[] = 2829ecfa43a5Sdmick "x86 (%s %X family %d model %d step %d clock %d MHz)"; 28307c478bd9Sstevel@tonic-gate static const char fmt_ht[] = 2831ecfa43a5Sdmick "x86 (chipid 0x%x %s %X family %d model %d step %d clock %d MHz)"; 28327c478bd9Sstevel@tonic-gate 28337c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 28347c478bd9Sstevel@tonic-gate 28358949bcd6Sandrei if (cpuid_is_cmt(cpu)) 28367c478bd9Sstevel@tonic-gate return (snprintf(s, n, fmt_ht, cpi->cpi_chipid, 2837ecfa43a5Sdmick cpi->cpi_vendorstr, cpi->cpi_std[1].cp_eax, 2838ecfa43a5Sdmick cpi->cpi_family, cpi->cpi_model, 28397c478bd9Sstevel@tonic-gate cpi->cpi_step, cpu->cpu_type_info.pi_clock)); 28407c478bd9Sstevel@tonic-gate return (snprintf(s, n, fmt, 2841ecfa43a5Sdmick cpi->cpi_vendorstr, cpi->cpi_std[1].cp_eax, 2842ecfa43a5Sdmick cpi->cpi_family, cpi->cpi_model, 28437c478bd9Sstevel@tonic-gate cpi->cpi_step, cpu->cpu_type_info.pi_clock)); 28447c478bd9Sstevel@tonic-gate } 28457c478bd9Sstevel@tonic-gate 28467c478bd9Sstevel@tonic-gate const char * 28477c478bd9Sstevel@tonic-gate cpuid_getvendorstr(cpu_t *cpu) 28487c478bd9Sstevel@tonic-gate { 28497c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 28507c478bd9Sstevel@tonic-gate return ((const char *)cpu->cpu_m.mcpu_cpi->cpi_vendorstr); 28517c478bd9Sstevel@tonic-gate } 28527c478bd9Sstevel@tonic-gate 28537c478bd9Sstevel@tonic-gate uint_t 28547c478bd9Sstevel@tonic-gate cpuid_getvendor(cpu_t *cpu) 28557c478bd9Sstevel@tonic-gate { 28567c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 28577c478bd9Sstevel@tonic-gate return (cpu->cpu_m.mcpu_cpi->cpi_vendor); 28587c478bd9Sstevel@tonic-gate } 28597c478bd9Sstevel@tonic-gate 28607c478bd9Sstevel@tonic-gate uint_t 28617c478bd9Sstevel@tonic-gate cpuid_getfamily(cpu_t *cpu) 28627c478bd9Sstevel@tonic-gate { 28637c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 28647c478bd9Sstevel@tonic-gate return (cpu->cpu_m.mcpu_cpi->cpi_family); 28657c478bd9Sstevel@tonic-gate } 28667c478bd9Sstevel@tonic-gate 28677c478bd9Sstevel@tonic-gate uint_t 28687c478bd9Sstevel@tonic-gate cpuid_getmodel(cpu_t *cpu) 28697c478bd9Sstevel@tonic-gate { 28707c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 28717c478bd9Sstevel@tonic-gate return (cpu->cpu_m.mcpu_cpi->cpi_model); 28727c478bd9Sstevel@tonic-gate } 28737c478bd9Sstevel@tonic-gate 28747c478bd9Sstevel@tonic-gate uint_t 28757c478bd9Sstevel@tonic-gate cpuid_get_ncpu_per_chip(cpu_t *cpu) 28767c478bd9Sstevel@tonic-gate { 28777c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 28787c478bd9Sstevel@tonic-gate return (cpu->cpu_m.mcpu_cpi->cpi_ncpu_per_chip); 28797c478bd9Sstevel@tonic-gate } 28807c478bd9Sstevel@tonic-gate 28817c478bd9Sstevel@tonic-gate uint_t 28828949bcd6Sandrei cpuid_get_ncore_per_chip(cpu_t *cpu) 28838949bcd6Sandrei { 28848949bcd6Sandrei ASSERT(cpuid_checkpass(cpu, 1)); 28858949bcd6Sandrei return (cpu->cpu_m.mcpu_cpi->cpi_ncore_per_chip); 28868949bcd6Sandrei } 28878949bcd6Sandrei 28888949bcd6Sandrei uint_t 2889d129bde2Sesaxe cpuid_get_ncpu_sharing_last_cache(cpu_t *cpu) 2890d129bde2Sesaxe { 2891d129bde2Sesaxe ASSERT(cpuid_checkpass(cpu, 2)); 2892d129bde2Sesaxe return (cpu->cpu_m.mcpu_cpi->cpi_ncpu_shr_last_cache); 2893d129bde2Sesaxe } 2894d129bde2Sesaxe 2895d129bde2Sesaxe id_t 2896d129bde2Sesaxe cpuid_get_last_lvl_cacheid(cpu_t *cpu) 2897d129bde2Sesaxe { 2898d129bde2Sesaxe ASSERT(cpuid_checkpass(cpu, 2)); 2899d129bde2Sesaxe return (cpu->cpu_m.mcpu_cpi->cpi_last_lvl_cacheid); 2900d129bde2Sesaxe } 2901d129bde2Sesaxe 2902d129bde2Sesaxe uint_t 29037c478bd9Sstevel@tonic-gate cpuid_getstep(cpu_t *cpu) 29047c478bd9Sstevel@tonic-gate { 29057c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 29067c478bd9Sstevel@tonic-gate return (cpu->cpu_m.mcpu_cpi->cpi_step); 29077c478bd9Sstevel@tonic-gate } 29087c478bd9Sstevel@tonic-gate 29092449e17fSsherrym uint_t 29102449e17fSsherrym cpuid_getsig(struct cpu *cpu) 29112449e17fSsherrym { 29122449e17fSsherrym ASSERT(cpuid_checkpass(cpu, 1)); 29132449e17fSsherrym return (cpu->cpu_m.mcpu_cpi->cpi_std[1].cp_eax); 29142449e17fSsherrym } 29152449e17fSsherrym 29168a40a695Sgavinm uint32_t 29178a40a695Sgavinm cpuid_getchiprev(struct cpu *cpu) 29188a40a695Sgavinm { 29198a40a695Sgavinm ASSERT(cpuid_checkpass(cpu, 1)); 29208a40a695Sgavinm return (cpu->cpu_m.mcpu_cpi->cpi_chiprev); 29218a40a695Sgavinm } 29228a40a695Sgavinm 29238a40a695Sgavinm const char * 29248a40a695Sgavinm cpuid_getchiprevstr(struct cpu *cpu) 29258a40a695Sgavinm { 29268a40a695Sgavinm ASSERT(cpuid_checkpass(cpu, 1)); 29278a40a695Sgavinm return (cpu->cpu_m.mcpu_cpi->cpi_chiprevstr); 29288a40a695Sgavinm } 29298a40a695Sgavinm 29308a40a695Sgavinm uint32_t 29318a40a695Sgavinm cpuid_getsockettype(struct cpu *cpu) 29328a40a695Sgavinm { 29338a40a695Sgavinm ASSERT(cpuid_checkpass(cpu, 1)); 29348a40a695Sgavinm return (cpu->cpu_m.mcpu_cpi->cpi_socket); 29358a40a695Sgavinm } 29368a40a695Sgavinm 293789e921d5SKuriakose Kuruvilla const char * 293889e921d5SKuriakose Kuruvilla cpuid_getsocketstr(cpu_t *cpu) 293989e921d5SKuriakose Kuruvilla { 294089e921d5SKuriakose Kuruvilla static const char *socketstr = NULL; 294189e921d5SKuriakose Kuruvilla struct cpuid_info *cpi; 294289e921d5SKuriakose Kuruvilla 294389e921d5SKuriakose Kuruvilla ASSERT(cpuid_checkpass(cpu, 1)); 294489e921d5SKuriakose Kuruvilla cpi = cpu->cpu_m.mcpu_cpi; 294589e921d5SKuriakose Kuruvilla 294689e921d5SKuriakose Kuruvilla /* Assume that socket types are the same across the system */ 294789e921d5SKuriakose Kuruvilla if (socketstr == NULL) 294889e921d5SKuriakose Kuruvilla socketstr = _cpuid_sktstr(cpi->cpi_vendor, cpi->cpi_family, 294989e921d5SKuriakose Kuruvilla cpi->cpi_model, cpi->cpi_step); 295089e921d5SKuriakose Kuruvilla 295189e921d5SKuriakose Kuruvilla 295289e921d5SKuriakose Kuruvilla return (socketstr); 295389e921d5SKuriakose Kuruvilla } 295489e921d5SKuriakose Kuruvilla 2955fb2f18f8Sesaxe int 2956fb2f18f8Sesaxe cpuid_get_chipid(cpu_t *cpu) 29577c478bd9Sstevel@tonic-gate { 29587c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 29597c478bd9Sstevel@tonic-gate 29608949bcd6Sandrei if (cpuid_is_cmt(cpu)) 29617c478bd9Sstevel@tonic-gate return (cpu->cpu_m.mcpu_cpi->cpi_chipid); 29627c478bd9Sstevel@tonic-gate return (cpu->cpu_id); 29637c478bd9Sstevel@tonic-gate } 29647c478bd9Sstevel@tonic-gate 29658949bcd6Sandrei id_t 2966fb2f18f8Sesaxe cpuid_get_coreid(cpu_t *cpu) 29678949bcd6Sandrei { 29688949bcd6Sandrei ASSERT(cpuid_checkpass(cpu, 1)); 29698949bcd6Sandrei return (cpu->cpu_m.mcpu_cpi->cpi_coreid); 29708949bcd6Sandrei } 29718949bcd6Sandrei 29727c478bd9Sstevel@tonic-gate int 297310569901Sgavinm cpuid_get_pkgcoreid(cpu_t *cpu) 297410569901Sgavinm { 297510569901Sgavinm ASSERT(cpuid_checkpass(cpu, 1)); 297610569901Sgavinm return (cpu->cpu_m.mcpu_cpi->cpi_pkgcoreid); 297710569901Sgavinm } 297810569901Sgavinm 297910569901Sgavinm int 2980fb2f18f8Sesaxe cpuid_get_clogid(cpu_t *cpu) 29817c478bd9Sstevel@tonic-gate { 29827c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 29837c478bd9Sstevel@tonic-gate return (cpu->cpu_m.mcpu_cpi->cpi_clogid); 29847c478bd9Sstevel@tonic-gate } 29857c478bd9Sstevel@tonic-gate 2986b885580bSAlexander Kolbasov int 2987b885580bSAlexander Kolbasov cpuid_get_cacheid(cpu_t *cpu) 2988b885580bSAlexander Kolbasov { 2989b885580bSAlexander Kolbasov ASSERT(cpuid_checkpass(cpu, 1)); 2990b885580bSAlexander Kolbasov return (cpu->cpu_m.mcpu_cpi->cpi_last_lvl_cacheid); 2991b885580bSAlexander Kolbasov } 2992b885580bSAlexander Kolbasov 29938031591dSSrihari Venkatesan uint_t 29948031591dSSrihari Venkatesan cpuid_get_procnodeid(cpu_t *cpu) 29958031591dSSrihari Venkatesan { 29968031591dSSrihari Venkatesan ASSERT(cpuid_checkpass(cpu, 1)); 29978031591dSSrihari Venkatesan return (cpu->cpu_m.mcpu_cpi->cpi_procnodeid); 29988031591dSSrihari Venkatesan } 29998031591dSSrihari Venkatesan 30008031591dSSrihari Venkatesan uint_t 30018031591dSSrihari Venkatesan cpuid_get_procnodes_per_pkg(cpu_t *cpu) 30028031591dSSrihari Venkatesan { 30038031591dSSrihari Venkatesan ASSERT(cpuid_checkpass(cpu, 1)); 30048031591dSSrihari Venkatesan return (cpu->cpu_m.mcpu_cpi->cpi_procnodes_per_pkg); 30058031591dSSrihari Venkatesan } 30068031591dSSrihari Venkatesan 30072ef50f01SJoe Bonasera /*ARGSUSED*/ 30082ef50f01SJoe Bonasera int 30092ef50f01SJoe Bonasera cpuid_have_cr8access(cpu_t *cpu) 30102ef50f01SJoe Bonasera { 30112ef50f01SJoe Bonasera #if defined(__amd64) 30122ef50f01SJoe Bonasera return (1); 30132ef50f01SJoe Bonasera #else 30142ef50f01SJoe Bonasera struct cpuid_info *cpi; 30152ef50f01SJoe Bonasera 30162ef50f01SJoe Bonasera ASSERT(cpu != NULL); 30172ef50f01SJoe Bonasera cpi = cpu->cpu_m.mcpu_cpi; 30182ef50f01SJoe Bonasera if (cpi->cpi_vendor == X86_VENDOR_AMD && cpi->cpi_maxeax >= 1 && 30192ef50f01SJoe Bonasera (CPI_FEATURES_XTD_ECX(cpi) & CPUID_AMD_ECX_CR8D) != 0) 30202ef50f01SJoe Bonasera return (1); 30212ef50f01SJoe Bonasera return (0); 30222ef50f01SJoe Bonasera #endif 30232ef50f01SJoe Bonasera } 30242ef50f01SJoe Bonasera 3025fa96bd91SMichael Corcoran uint32_t 3026fa96bd91SMichael Corcoran cpuid_get_apicid(cpu_t *cpu) 3027fa96bd91SMichael Corcoran { 3028fa96bd91SMichael Corcoran ASSERT(cpuid_checkpass(cpu, 1)); 3029fa96bd91SMichael Corcoran if (cpu->cpu_m.mcpu_cpi->cpi_maxeax < 1) { 3030fa96bd91SMichael Corcoran return (UINT32_MAX); 3031fa96bd91SMichael Corcoran } else { 3032fa96bd91SMichael Corcoran return (cpu->cpu_m.mcpu_cpi->cpi_apicid); 3033fa96bd91SMichael Corcoran } 3034fa96bd91SMichael Corcoran } 3035fa96bd91SMichael Corcoran 30367c478bd9Sstevel@tonic-gate void 30377c478bd9Sstevel@tonic-gate cpuid_get_addrsize(cpu_t *cpu, uint_t *pabits, uint_t *vabits) 30387c478bd9Sstevel@tonic-gate { 30397c478bd9Sstevel@tonic-gate struct cpuid_info *cpi; 30407c478bd9Sstevel@tonic-gate 30417c478bd9Sstevel@tonic-gate if (cpu == NULL) 30427c478bd9Sstevel@tonic-gate cpu = CPU; 30437c478bd9Sstevel@tonic-gate cpi = cpu->cpu_m.mcpu_cpi; 30447c478bd9Sstevel@tonic-gate 30457c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 30467c478bd9Sstevel@tonic-gate 30477c478bd9Sstevel@tonic-gate if (pabits) 30487c478bd9Sstevel@tonic-gate *pabits = cpi->cpi_pabits; 30497c478bd9Sstevel@tonic-gate if (vabits) 30507c478bd9Sstevel@tonic-gate *vabits = cpi->cpi_vabits; 30517c478bd9Sstevel@tonic-gate } 30527c478bd9Sstevel@tonic-gate 30537c478bd9Sstevel@tonic-gate /* 30547c478bd9Sstevel@tonic-gate * Returns the number of data TLB entries for a corresponding 30557c478bd9Sstevel@tonic-gate * pagesize. If it can't be computed, or isn't known, the 30567c478bd9Sstevel@tonic-gate * routine returns zero. If you ask about an architecturally 30577c478bd9Sstevel@tonic-gate * impossible pagesize, the routine will panic (so that the 30587c478bd9Sstevel@tonic-gate * hat implementor knows that things are inconsistent.) 30597c478bd9Sstevel@tonic-gate */ 30607c478bd9Sstevel@tonic-gate uint_t 30617c478bd9Sstevel@tonic-gate cpuid_get_dtlb_nent(cpu_t *cpu, size_t pagesize) 30627c478bd9Sstevel@tonic-gate { 30637c478bd9Sstevel@tonic-gate struct cpuid_info *cpi; 30647c478bd9Sstevel@tonic-gate uint_t dtlb_nent = 0; 30657c478bd9Sstevel@tonic-gate 30667c478bd9Sstevel@tonic-gate if (cpu == NULL) 30677c478bd9Sstevel@tonic-gate cpu = CPU; 30687c478bd9Sstevel@tonic-gate cpi = cpu->cpu_m.mcpu_cpi; 30697c478bd9Sstevel@tonic-gate 30707c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 30717c478bd9Sstevel@tonic-gate 30727c478bd9Sstevel@tonic-gate /* 30737c478bd9Sstevel@tonic-gate * Check the L2 TLB info 30747c478bd9Sstevel@tonic-gate */ 30757c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax >= 0x80000006) { 30768949bcd6Sandrei struct cpuid_regs *cp = &cpi->cpi_extd[6]; 30777c478bd9Sstevel@tonic-gate 30787c478bd9Sstevel@tonic-gate switch (pagesize) { 30797c478bd9Sstevel@tonic-gate 30807c478bd9Sstevel@tonic-gate case 4 * 1024: 30817c478bd9Sstevel@tonic-gate /* 30827c478bd9Sstevel@tonic-gate * All zero in the top 16 bits of the register 30837c478bd9Sstevel@tonic-gate * indicates a unified TLB. Size is in low 16 bits. 30847c478bd9Sstevel@tonic-gate */ 30857c478bd9Sstevel@tonic-gate if ((cp->cp_ebx & 0xffff0000) == 0) 30867c478bd9Sstevel@tonic-gate dtlb_nent = cp->cp_ebx & 0x0000ffff; 30877c478bd9Sstevel@tonic-gate else 30887c478bd9Sstevel@tonic-gate dtlb_nent = BITX(cp->cp_ebx, 27, 16); 30897c478bd9Sstevel@tonic-gate break; 30907c478bd9Sstevel@tonic-gate 30917c478bd9Sstevel@tonic-gate case 2 * 1024 * 1024: 30927c478bd9Sstevel@tonic-gate if ((cp->cp_eax & 0xffff0000) == 0) 30937c478bd9Sstevel@tonic-gate dtlb_nent = cp->cp_eax & 0x0000ffff; 30947c478bd9Sstevel@tonic-gate else 30957c478bd9Sstevel@tonic-gate dtlb_nent = BITX(cp->cp_eax, 27, 16); 30967c478bd9Sstevel@tonic-gate break; 30977c478bd9Sstevel@tonic-gate 30987c478bd9Sstevel@tonic-gate default: 30997c478bd9Sstevel@tonic-gate panic("unknown L2 pagesize"); 31007c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 31017c478bd9Sstevel@tonic-gate } 31027c478bd9Sstevel@tonic-gate } 31037c478bd9Sstevel@tonic-gate 31047c478bd9Sstevel@tonic-gate if (dtlb_nent != 0) 31057c478bd9Sstevel@tonic-gate return (dtlb_nent); 31067c478bd9Sstevel@tonic-gate 31077c478bd9Sstevel@tonic-gate /* 31087c478bd9Sstevel@tonic-gate * No L2 TLB support for this size, try L1. 31097c478bd9Sstevel@tonic-gate */ 31107c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax >= 0x80000005) { 31118949bcd6Sandrei struct cpuid_regs *cp = &cpi->cpi_extd[5]; 31127c478bd9Sstevel@tonic-gate 31137c478bd9Sstevel@tonic-gate switch (pagesize) { 31147c478bd9Sstevel@tonic-gate case 4 * 1024: 31157c478bd9Sstevel@tonic-gate dtlb_nent = BITX(cp->cp_ebx, 23, 16); 31167c478bd9Sstevel@tonic-gate break; 31177c478bd9Sstevel@tonic-gate case 2 * 1024 * 1024: 31187c478bd9Sstevel@tonic-gate dtlb_nent = BITX(cp->cp_eax, 23, 16); 31197c478bd9Sstevel@tonic-gate break; 31207c478bd9Sstevel@tonic-gate default: 31217c478bd9Sstevel@tonic-gate panic("unknown L1 d-TLB pagesize"); 31227c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 31237c478bd9Sstevel@tonic-gate } 31247c478bd9Sstevel@tonic-gate } 31257c478bd9Sstevel@tonic-gate 31267c478bd9Sstevel@tonic-gate return (dtlb_nent); 31277c478bd9Sstevel@tonic-gate } 31287c478bd9Sstevel@tonic-gate 31297c478bd9Sstevel@tonic-gate /* 31307c478bd9Sstevel@tonic-gate * Return 0 if the erratum is not present or not applicable, positive 31317c478bd9Sstevel@tonic-gate * if it is, and negative if the status of the erratum is unknown. 31327c478bd9Sstevel@tonic-gate * 31337c478bd9Sstevel@tonic-gate * See "Revision Guide for AMD Athlon(tm) 64 and AMD Opteron(tm) 31342201b277Skucharsk * Processors" #25759, Rev 3.57, August 2005 31357c478bd9Sstevel@tonic-gate */ 31367c478bd9Sstevel@tonic-gate int 31377c478bd9Sstevel@tonic-gate cpuid_opteron_erratum(cpu_t *cpu, uint_t erratum) 31387c478bd9Sstevel@tonic-gate { 31397c478bd9Sstevel@tonic-gate struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi; 31408949bcd6Sandrei uint_t eax; 31417c478bd9Sstevel@tonic-gate 3142ea99987eSsethg /* 3143ea99987eSsethg * Bail out if this CPU isn't an AMD CPU, or if it's 3144ea99987eSsethg * a legacy (32-bit) AMD CPU. 3145ea99987eSsethg */ 3146ea99987eSsethg if (cpi->cpi_vendor != X86_VENDOR_AMD || 3147875b116eSkchow cpi->cpi_family == 4 || cpi->cpi_family == 5 || 3148875b116eSkchow cpi->cpi_family == 6) 31498a40a695Sgavinm 31507c478bd9Sstevel@tonic-gate return (0); 31517c478bd9Sstevel@tonic-gate 31527c478bd9Sstevel@tonic-gate eax = cpi->cpi_std[1].cp_eax; 31537c478bd9Sstevel@tonic-gate 31547c478bd9Sstevel@tonic-gate #define SH_B0(eax) (eax == 0xf40 || eax == 0xf50) 31557c478bd9Sstevel@tonic-gate #define SH_B3(eax) (eax == 0xf51) 3156ee88d2b9Skchow #define B(eax) (SH_B0(eax) || SH_B3(eax)) 31577c478bd9Sstevel@tonic-gate 31587c478bd9Sstevel@tonic-gate #define SH_C0(eax) (eax == 0xf48 || eax == 0xf58) 31597c478bd9Sstevel@tonic-gate 31607c478bd9Sstevel@tonic-gate #define SH_CG(eax) (eax == 0xf4a || eax == 0xf5a || eax == 0xf7a) 31617c478bd9Sstevel@tonic-gate #define DH_CG(eax) (eax == 0xfc0 || eax == 0xfe0 || eax == 0xff0) 31627c478bd9Sstevel@tonic-gate #define CH_CG(eax) (eax == 0xf82 || eax == 0xfb2) 3163ee88d2b9Skchow #define CG(eax) (SH_CG(eax) || DH_CG(eax) || CH_CG(eax)) 31647c478bd9Sstevel@tonic-gate 31657c478bd9Sstevel@tonic-gate #define SH_D0(eax) (eax == 0x10f40 || eax == 0x10f50 || eax == 0x10f70) 31667c478bd9Sstevel@tonic-gate #define DH_D0(eax) (eax == 0x10fc0 || eax == 0x10ff0) 31677c478bd9Sstevel@tonic-gate #define CH_D0(eax) (eax == 0x10f80 || eax == 0x10fb0) 3168ee88d2b9Skchow #define D0(eax) (SH_D0(eax) || DH_D0(eax) || CH_D0(eax)) 31697c478bd9Sstevel@tonic-gate 31707c478bd9Sstevel@tonic-gate #define SH_E0(eax) (eax == 0x20f50 || eax == 0x20f40 || eax == 0x20f70) 31717c478bd9Sstevel@tonic-gate #define JH_E1(eax) (eax == 0x20f10) /* JH8_E0 had 0x20f30 */ 31727c478bd9Sstevel@tonic-gate #define DH_E3(eax) (eax == 0x20fc0 || eax == 0x20ff0) 31737c478bd9Sstevel@tonic-gate #define SH_E4(eax) (eax == 0x20f51 || eax == 0x20f71) 31747c478bd9Sstevel@tonic-gate #define BH_E4(eax) (eax == 0x20fb1) 31757c478bd9Sstevel@tonic-gate #define SH_E5(eax) (eax == 0x20f42) 31767c478bd9Sstevel@tonic-gate #define DH_E6(eax) (eax == 0x20ff2 || eax == 0x20fc2) 31777c478bd9Sstevel@tonic-gate #define JH_E6(eax) (eax == 0x20f12 || eax == 0x20f32) 3178ee88d2b9Skchow #define EX(eax) (SH_E0(eax) || JH_E1(eax) || DH_E3(eax) || \ 3179ee88d2b9Skchow SH_E4(eax) || BH_E4(eax) || SH_E5(eax) || \ 3180ee88d2b9Skchow DH_E6(eax) || JH_E6(eax)) 31817c478bd9Sstevel@tonic-gate 3182512cf780Skchow #define DR_AX(eax) (eax == 0x100f00 || eax == 0x100f01 || eax == 0x100f02) 3183512cf780Skchow #define DR_B0(eax) (eax == 0x100f20) 3184512cf780Skchow #define DR_B1(eax) (eax == 0x100f21) 3185512cf780Skchow #define DR_BA(eax) (eax == 0x100f2a) 3186512cf780Skchow #define DR_B2(eax) (eax == 0x100f22) 3187512cf780Skchow #define DR_B3(eax) (eax == 0x100f23) 3188512cf780Skchow #define RB_C0(eax) (eax == 0x100f40) 3189512cf780Skchow 31907c478bd9Sstevel@tonic-gate switch (erratum) { 31917c478bd9Sstevel@tonic-gate case 1: 3192875b116eSkchow return (cpi->cpi_family < 0x10); 31937c478bd9Sstevel@tonic-gate case 51: /* what does the asterisk mean? */ 31947c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax)); 31957c478bd9Sstevel@tonic-gate case 52: 31967c478bd9Sstevel@tonic-gate return (B(eax)); 31977c478bd9Sstevel@tonic-gate case 57: 3198512cf780Skchow return (cpi->cpi_family <= 0x11); 31997c478bd9Sstevel@tonic-gate case 58: 32007c478bd9Sstevel@tonic-gate return (B(eax)); 32017c478bd9Sstevel@tonic-gate case 60: 3202512cf780Skchow return (cpi->cpi_family <= 0x11); 32037c478bd9Sstevel@tonic-gate case 61: 32047c478bd9Sstevel@tonic-gate case 62: 32057c478bd9Sstevel@tonic-gate case 63: 32067c478bd9Sstevel@tonic-gate case 64: 32077c478bd9Sstevel@tonic-gate case 65: 32087c478bd9Sstevel@tonic-gate case 66: 32097c478bd9Sstevel@tonic-gate case 68: 32107c478bd9Sstevel@tonic-gate case 69: 32117c478bd9Sstevel@tonic-gate case 70: 32127c478bd9Sstevel@tonic-gate case 71: 32137c478bd9Sstevel@tonic-gate return (B(eax)); 32147c478bd9Sstevel@tonic-gate case 72: 32157c478bd9Sstevel@tonic-gate return (SH_B0(eax)); 32167c478bd9Sstevel@tonic-gate case 74: 32177c478bd9Sstevel@tonic-gate return (B(eax)); 32187c478bd9Sstevel@tonic-gate case 75: 3219875b116eSkchow return (cpi->cpi_family < 0x10); 32207c478bd9Sstevel@tonic-gate case 76: 32217c478bd9Sstevel@tonic-gate return (B(eax)); 32227c478bd9Sstevel@tonic-gate case 77: 3223512cf780Skchow return (cpi->cpi_family <= 0x11); 32247c478bd9Sstevel@tonic-gate case 78: 32257c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax)); 32267c478bd9Sstevel@tonic-gate case 79: 32277c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax) || EX(eax)); 32287c478bd9Sstevel@tonic-gate case 80: 32297c478bd9Sstevel@tonic-gate case 81: 32307c478bd9Sstevel@tonic-gate case 82: 32317c478bd9Sstevel@tonic-gate return (B(eax)); 32327c478bd9Sstevel@tonic-gate case 83: 32337c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax)); 32347c478bd9Sstevel@tonic-gate case 85: 3235875b116eSkchow return (cpi->cpi_family < 0x10); 32367c478bd9Sstevel@tonic-gate case 86: 32377c478bd9Sstevel@tonic-gate return (SH_C0(eax) || CG(eax)); 32387c478bd9Sstevel@tonic-gate case 88: 32397c478bd9Sstevel@tonic-gate #if !defined(__amd64) 32407c478bd9Sstevel@tonic-gate return (0); 32417c478bd9Sstevel@tonic-gate #else 32427c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax)); 32437c478bd9Sstevel@tonic-gate #endif 32447c478bd9Sstevel@tonic-gate case 89: 3245875b116eSkchow return (cpi->cpi_family < 0x10); 32467c478bd9Sstevel@tonic-gate case 90: 32477c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax)); 32487c478bd9Sstevel@tonic-gate case 91: 32497c478bd9Sstevel@tonic-gate case 92: 32507c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax)); 32517c478bd9Sstevel@tonic-gate case 93: 32527c478bd9Sstevel@tonic-gate return (SH_C0(eax)); 32537c478bd9Sstevel@tonic-gate case 94: 32547c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax)); 32557c478bd9Sstevel@tonic-gate case 95: 32567c478bd9Sstevel@tonic-gate #if !defined(__amd64) 32577c478bd9Sstevel@tonic-gate return (0); 32587c478bd9Sstevel@tonic-gate #else 32597c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax)); 32607c478bd9Sstevel@tonic-gate #endif 32617c478bd9Sstevel@tonic-gate case 96: 32627c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax)); 32637c478bd9Sstevel@tonic-gate case 97: 32647c478bd9Sstevel@tonic-gate case 98: 32657c478bd9Sstevel@tonic-gate return (SH_C0(eax) || CG(eax)); 32667c478bd9Sstevel@tonic-gate case 99: 32677c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax)); 32687c478bd9Sstevel@tonic-gate case 100: 32697c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax)); 32707c478bd9Sstevel@tonic-gate case 101: 32717c478bd9Sstevel@tonic-gate case 103: 32727c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax)); 32737c478bd9Sstevel@tonic-gate case 104: 32747c478bd9Sstevel@tonic-gate return (SH_C0(eax) || CG(eax) || D0(eax)); 32757c478bd9Sstevel@tonic-gate case 105: 32767c478bd9Sstevel@tonic-gate case 106: 32777c478bd9Sstevel@tonic-gate case 107: 32787c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax)); 32797c478bd9Sstevel@tonic-gate case 108: 32807c478bd9Sstevel@tonic-gate return (DH_CG(eax)); 32817c478bd9Sstevel@tonic-gate case 109: 32827c478bd9Sstevel@tonic-gate return (SH_C0(eax) || CG(eax) || D0(eax)); 32837c478bd9Sstevel@tonic-gate case 110: 32847c478bd9Sstevel@tonic-gate return (D0(eax) || EX(eax)); 32857c478bd9Sstevel@tonic-gate case 111: 32867c478bd9Sstevel@tonic-gate return (CG(eax)); 32877c478bd9Sstevel@tonic-gate case 112: 32887c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax) || EX(eax)); 32897c478bd9Sstevel@tonic-gate case 113: 32907c478bd9Sstevel@tonic-gate return (eax == 0x20fc0); 32917c478bd9Sstevel@tonic-gate case 114: 32927c478bd9Sstevel@tonic-gate return (SH_E0(eax) || JH_E1(eax) || DH_E3(eax)); 32937c478bd9Sstevel@tonic-gate case 115: 32947c478bd9Sstevel@tonic-gate return (SH_E0(eax) || JH_E1(eax)); 32957c478bd9Sstevel@tonic-gate case 116: 32967c478bd9Sstevel@tonic-gate return (SH_E0(eax) || JH_E1(eax) || DH_E3(eax)); 32977c478bd9Sstevel@tonic-gate case 117: 32987c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax)); 32997c478bd9Sstevel@tonic-gate case 118: 33007c478bd9Sstevel@tonic-gate return (SH_E0(eax) || JH_E1(eax) || SH_E4(eax) || BH_E4(eax) || 33017c478bd9Sstevel@tonic-gate JH_E6(eax)); 33027c478bd9Sstevel@tonic-gate case 121: 33037c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax) || EX(eax)); 33047c478bd9Sstevel@tonic-gate case 122: 3305512cf780Skchow return (cpi->cpi_family < 0x10 || cpi->cpi_family == 0x11); 33067c478bd9Sstevel@tonic-gate case 123: 33077c478bd9Sstevel@tonic-gate return (JH_E1(eax) || BH_E4(eax) || JH_E6(eax)); 33082201b277Skucharsk case 131: 3309875b116eSkchow return (cpi->cpi_family < 0x10); 3310ef50d8c0Sesaxe case 6336786: 3311ef50d8c0Sesaxe /* 3312ef50d8c0Sesaxe * Test for AdvPowerMgmtInfo.TscPStateInvariant 3313875b116eSkchow * if this is a K8 family or newer processor 3314ef50d8c0Sesaxe */ 3315ef50d8c0Sesaxe if (CPI_FAMILY(cpi) == 0xf) { 33168949bcd6Sandrei struct cpuid_regs regs; 33178949bcd6Sandrei regs.cp_eax = 0x80000007; 33188949bcd6Sandrei (void) __cpuid_insn(®s); 33198949bcd6Sandrei return (!(regs.cp_edx & 0x100)); 3320ef50d8c0Sesaxe } 3321ef50d8c0Sesaxe return (0); 3322ee88d2b9Skchow case 6323525: 3323ee88d2b9Skchow return (((((eax >> 12) & 0xff00) + (eax & 0xf00)) | 3324ee88d2b9Skchow (((eax >> 4) & 0xf) | ((eax >> 12) & 0xf0))) < 0xf40); 3325ee88d2b9Skchow 3326512cf780Skchow case 6671130: 3327512cf780Skchow /* 3328512cf780Skchow * check for processors (pre-Shanghai) that do not provide 3329512cf780Skchow * optimal management of 1gb ptes in its tlb. 3330512cf780Skchow */ 3331512cf780Skchow return (cpi->cpi_family == 0x10 && cpi->cpi_model < 4); 3332512cf780Skchow 3333512cf780Skchow case 298: 3334512cf780Skchow return (DR_AX(eax) || DR_B0(eax) || DR_B1(eax) || DR_BA(eax) || 3335512cf780Skchow DR_B2(eax) || RB_C0(eax)); 3336512cf780Skchow 33375e54b56dSHans Rosenfeld case 721: 33385e54b56dSHans Rosenfeld #if defined(__amd64) 33395e54b56dSHans Rosenfeld return (cpi->cpi_family == 0x10 || cpi->cpi_family == 0x12); 33405e54b56dSHans Rosenfeld #else 33415e54b56dSHans Rosenfeld return (0); 33425e54b56dSHans Rosenfeld #endif 33435e54b56dSHans Rosenfeld 3344512cf780Skchow default: 3345512cf780Skchow return (-1); 3346512cf780Skchow 3347512cf780Skchow } 3348512cf780Skchow } 3349512cf780Skchow 3350512cf780Skchow /* 3351512cf780Skchow * Determine if specified erratum is present via OSVW (OS Visible Workaround). 3352512cf780Skchow * Return 1 if erratum is present, 0 if not present and -1 if indeterminate. 3353512cf780Skchow */ 3354512cf780Skchow int 3355512cf780Skchow osvw_opteron_erratum(cpu_t *cpu, uint_t erratum) 3356512cf780Skchow { 3357512cf780Skchow struct cpuid_info *cpi; 3358512cf780Skchow uint_t osvwid; 3359512cf780Skchow static int osvwfeature = -1; 3360512cf780Skchow uint64_t osvwlength; 3361512cf780Skchow 3362512cf780Skchow 3363512cf780Skchow cpi = cpu->cpu_m.mcpu_cpi; 3364512cf780Skchow 3365512cf780Skchow /* confirm OSVW supported */ 3366512cf780Skchow if (osvwfeature == -1) { 3367512cf780Skchow osvwfeature = cpi->cpi_extd[1].cp_ecx & CPUID_AMD_ECX_OSVW; 3368512cf780Skchow } else { 3369512cf780Skchow /* assert that osvw feature setting is consistent on all cpus */ 3370512cf780Skchow ASSERT(osvwfeature == 3371512cf780Skchow (cpi->cpi_extd[1].cp_ecx & CPUID_AMD_ECX_OSVW)); 3372512cf780Skchow } 3373512cf780Skchow if (!osvwfeature) 3374512cf780Skchow return (-1); 3375512cf780Skchow 3376512cf780Skchow osvwlength = rdmsr(MSR_AMD_OSVW_ID_LEN) & OSVW_ID_LEN_MASK; 3377512cf780Skchow 3378512cf780Skchow switch (erratum) { 3379512cf780Skchow case 298: /* osvwid is 0 */ 3380512cf780Skchow osvwid = 0; 3381512cf780Skchow if (osvwlength <= (uint64_t)osvwid) { 3382512cf780Skchow /* osvwid 0 is unknown */ 3383512cf780Skchow return (-1); 3384512cf780Skchow } 3385512cf780Skchow 3386512cf780Skchow /* 3387512cf780Skchow * Check the OSVW STATUS MSR to determine the state 3388512cf780Skchow * of the erratum where: 3389512cf780Skchow * 0 - fixed by HW 3390512cf780Skchow * 1 - BIOS has applied the workaround when BIOS 3391512cf780Skchow * workaround is available. (Or for other errata, 3392512cf780Skchow * OS workaround is required.) 3393512cf780Skchow * For a value of 1, caller will confirm that the 3394512cf780Skchow * erratum 298 workaround has indeed been applied by BIOS. 3395512cf780Skchow * 3396512cf780Skchow * A 1 may be set in cpus that have a HW fix 3397512cf780Skchow * in a mixed cpu system. Regarding erratum 298: 3398512cf780Skchow * In a multiprocessor platform, the workaround above 3399512cf780Skchow * should be applied to all processors regardless of 3400512cf780Skchow * silicon revision when an affected processor is 3401512cf780Skchow * present. 3402512cf780Skchow */ 3403512cf780Skchow 3404512cf780Skchow return (rdmsr(MSR_AMD_OSVW_STATUS + 3405512cf780Skchow (osvwid / OSVW_ID_CNT_PER_MSR)) & 3406512cf780Skchow (1ULL << (osvwid % OSVW_ID_CNT_PER_MSR))); 3407512cf780Skchow 34087c478bd9Sstevel@tonic-gate default: 34097c478bd9Sstevel@tonic-gate return (-1); 34107c478bd9Sstevel@tonic-gate } 34117c478bd9Sstevel@tonic-gate } 34127c478bd9Sstevel@tonic-gate 34137c478bd9Sstevel@tonic-gate static const char assoc_str[] = "associativity"; 34147c478bd9Sstevel@tonic-gate static const char line_str[] = "line-size"; 34157c478bd9Sstevel@tonic-gate static const char size_str[] = "size"; 34167c478bd9Sstevel@tonic-gate 34177c478bd9Sstevel@tonic-gate static void 34187c478bd9Sstevel@tonic-gate add_cache_prop(dev_info_t *devi, const char *label, const char *type, 34197c478bd9Sstevel@tonic-gate uint32_t val) 34207c478bd9Sstevel@tonic-gate { 34217c478bd9Sstevel@tonic-gate char buf[128]; 34227c478bd9Sstevel@tonic-gate 34237c478bd9Sstevel@tonic-gate /* 34247c478bd9Sstevel@tonic-gate * ndi_prop_update_int() is used because it is desirable for 34257c478bd9Sstevel@tonic-gate * DDI_PROP_HW_DEF and DDI_PROP_DONTSLEEP to be set. 34267c478bd9Sstevel@tonic-gate */ 34277c478bd9Sstevel@tonic-gate if (snprintf(buf, sizeof (buf), "%s-%s", label, type) < sizeof (buf)) 34287c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, devi, buf, val); 34297c478bd9Sstevel@tonic-gate } 34307c478bd9Sstevel@tonic-gate 34317c478bd9Sstevel@tonic-gate /* 34327c478bd9Sstevel@tonic-gate * Intel-style cache/tlb description 34337c478bd9Sstevel@tonic-gate * 34347c478bd9Sstevel@tonic-gate * Standard cpuid level 2 gives a randomly ordered 34357c478bd9Sstevel@tonic-gate * selection of tags that index into a table that describes 34367c478bd9Sstevel@tonic-gate * cache and tlb properties. 34377c478bd9Sstevel@tonic-gate */ 34387c478bd9Sstevel@tonic-gate 34397c478bd9Sstevel@tonic-gate static const char l1_icache_str[] = "l1-icache"; 34407c478bd9Sstevel@tonic-gate static const char l1_dcache_str[] = "l1-dcache"; 34417c478bd9Sstevel@tonic-gate static const char l2_cache_str[] = "l2-cache"; 3442ae115bc7Smrj static const char l3_cache_str[] = "l3-cache"; 34437c478bd9Sstevel@tonic-gate static const char itlb4k_str[] = "itlb-4K"; 34447c478bd9Sstevel@tonic-gate static const char dtlb4k_str[] = "dtlb-4K"; 3445824e4fecSvd224797 static const char itlb2M_str[] = "itlb-2M"; 34467c478bd9Sstevel@tonic-gate static const char itlb4M_str[] = "itlb-4M"; 34477c478bd9Sstevel@tonic-gate static const char dtlb4M_str[] = "dtlb-4M"; 344825dfb062Sksadhukh static const char dtlb24_str[] = "dtlb0-2M-4M"; 34497c478bd9Sstevel@tonic-gate static const char itlb424_str[] = "itlb-4K-2M-4M"; 345025dfb062Sksadhukh static const char itlb24_str[] = "itlb-2M-4M"; 34517c478bd9Sstevel@tonic-gate static const char dtlb44_str[] = "dtlb-4K-4M"; 34527c478bd9Sstevel@tonic-gate static const char sl1_dcache_str[] = "sectored-l1-dcache"; 34537c478bd9Sstevel@tonic-gate static const char sl2_cache_str[] = "sectored-l2-cache"; 34547c478bd9Sstevel@tonic-gate static const char itrace_str[] = "itrace-cache"; 34557c478bd9Sstevel@tonic-gate static const char sl3_cache_str[] = "sectored-l3-cache"; 345625dfb062Sksadhukh static const char sh_l2_tlb4k_str[] = "shared-l2-tlb-4k"; 34577c478bd9Sstevel@tonic-gate 34587c478bd9Sstevel@tonic-gate static const struct cachetab { 34597c478bd9Sstevel@tonic-gate uint8_t ct_code; 34607c478bd9Sstevel@tonic-gate uint8_t ct_assoc; 34617c478bd9Sstevel@tonic-gate uint16_t ct_line_size; 34627c478bd9Sstevel@tonic-gate size_t ct_size; 34637c478bd9Sstevel@tonic-gate const char *ct_label; 34647c478bd9Sstevel@tonic-gate } intel_ctab[] = { 3465824e4fecSvd224797 /* 3466824e4fecSvd224797 * maintain descending order! 3467824e4fecSvd224797 * 3468824e4fecSvd224797 * Codes ignored - Reason 3469824e4fecSvd224797 * ---------------------- 3470824e4fecSvd224797 * 40H - intel_cpuid_4_cache_info() disambiguates l2/l3 cache 3471824e4fecSvd224797 * f0H/f1H - Currently we do not interpret prefetch size by design 3472824e4fecSvd224797 */ 347325dfb062Sksadhukh { 0xe4, 16, 64, 8*1024*1024, l3_cache_str}, 347425dfb062Sksadhukh { 0xe3, 16, 64, 4*1024*1024, l3_cache_str}, 347525dfb062Sksadhukh { 0xe2, 16, 64, 2*1024*1024, l3_cache_str}, 347625dfb062Sksadhukh { 0xde, 12, 64, 6*1024*1024, l3_cache_str}, 347725dfb062Sksadhukh { 0xdd, 12, 64, 3*1024*1024, l3_cache_str}, 347825dfb062Sksadhukh { 0xdc, 12, 64, ((1*1024*1024)+(512*1024)), l3_cache_str}, 347925dfb062Sksadhukh { 0xd8, 8, 64, 4*1024*1024, l3_cache_str}, 348025dfb062Sksadhukh { 0xd7, 8, 64, 2*1024*1024, l3_cache_str}, 348125dfb062Sksadhukh { 0xd6, 8, 64, 1*1024*1024, l3_cache_str}, 348225dfb062Sksadhukh { 0xd2, 4, 64, 2*1024*1024, l3_cache_str}, 348325dfb062Sksadhukh { 0xd1, 4, 64, 1*1024*1024, l3_cache_str}, 348425dfb062Sksadhukh { 0xd0, 4, 64, 512*1024, l3_cache_str}, 348525dfb062Sksadhukh { 0xca, 4, 0, 512, sh_l2_tlb4k_str}, 3486824e4fecSvd224797 { 0xc0, 4, 0, 8, dtlb44_str }, 3487824e4fecSvd224797 { 0xba, 4, 0, 64, dtlb4k_str }, 3488ae115bc7Smrj { 0xb4, 4, 0, 256, dtlb4k_str }, 34897c478bd9Sstevel@tonic-gate { 0xb3, 4, 0, 128, dtlb4k_str }, 349025dfb062Sksadhukh { 0xb2, 4, 0, 64, itlb4k_str }, 34917c478bd9Sstevel@tonic-gate { 0xb0, 4, 0, 128, itlb4k_str }, 34927c478bd9Sstevel@tonic-gate { 0x87, 8, 64, 1024*1024, l2_cache_str}, 34937c478bd9Sstevel@tonic-gate { 0x86, 4, 64, 512*1024, l2_cache_str}, 34947c478bd9Sstevel@tonic-gate { 0x85, 8, 32, 2*1024*1024, l2_cache_str}, 34957c478bd9Sstevel@tonic-gate { 0x84, 8, 32, 1024*1024, l2_cache_str}, 34967c478bd9Sstevel@tonic-gate { 0x83, 8, 32, 512*1024, l2_cache_str}, 34977c478bd9Sstevel@tonic-gate { 0x82, 8, 32, 256*1024, l2_cache_str}, 3498824e4fecSvd224797 { 0x80, 8, 64, 512*1024, l2_cache_str}, 34997c478bd9Sstevel@tonic-gate { 0x7f, 2, 64, 512*1024, l2_cache_str}, 35007c478bd9Sstevel@tonic-gate { 0x7d, 8, 64, 2*1024*1024, sl2_cache_str}, 35017c478bd9Sstevel@tonic-gate { 0x7c, 8, 64, 1024*1024, sl2_cache_str}, 35027c478bd9Sstevel@tonic-gate { 0x7b, 8, 64, 512*1024, sl2_cache_str}, 35037c478bd9Sstevel@tonic-gate { 0x7a, 8, 64, 256*1024, sl2_cache_str}, 35047c478bd9Sstevel@tonic-gate { 0x79, 8, 64, 128*1024, sl2_cache_str}, 35057c478bd9Sstevel@tonic-gate { 0x78, 8, 64, 1024*1024, l2_cache_str}, 3506ae115bc7Smrj { 0x73, 8, 0, 64*1024, itrace_str}, 35077c478bd9Sstevel@tonic-gate { 0x72, 8, 0, 32*1024, itrace_str}, 35087c478bd9Sstevel@tonic-gate { 0x71, 8, 0, 16*1024, itrace_str}, 35097c478bd9Sstevel@tonic-gate { 0x70, 8, 0, 12*1024, itrace_str}, 35107c478bd9Sstevel@tonic-gate { 0x68, 4, 64, 32*1024, sl1_dcache_str}, 35117c478bd9Sstevel@tonic-gate { 0x67, 4, 64, 16*1024, sl1_dcache_str}, 35127c478bd9Sstevel@tonic-gate { 0x66, 4, 64, 8*1024, sl1_dcache_str}, 35137c478bd9Sstevel@tonic-gate { 0x60, 8, 64, 16*1024, sl1_dcache_str}, 35147c478bd9Sstevel@tonic-gate { 0x5d, 0, 0, 256, dtlb44_str}, 35157c478bd9Sstevel@tonic-gate { 0x5c, 0, 0, 128, dtlb44_str}, 35167c478bd9Sstevel@tonic-gate { 0x5b, 0, 0, 64, dtlb44_str}, 351725dfb062Sksadhukh { 0x5a, 4, 0, 32, dtlb24_str}, 3518824e4fecSvd224797 { 0x59, 0, 0, 16, dtlb4k_str}, 3519824e4fecSvd224797 { 0x57, 4, 0, 16, dtlb4k_str}, 3520824e4fecSvd224797 { 0x56, 4, 0, 16, dtlb4M_str}, 352125dfb062Sksadhukh { 0x55, 0, 0, 7, itlb24_str}, 35227c478bd9Sstevel@tonic-gate { 0x52, 0, 0, 256, itlb424_str}, 35237c478bd9Sstevel@tonic-gate { 0x51, 0, 0, 128, itlb424_str}, 35247c478bd9Sstevel@tonic-gate { 0x50, 0, 0, 64, itlb424_str}, 3525824e4fecSvd224797 { 0x4f, 0, 0, 32, itlb4k_str}, 3526824e4fecSvd224797 { 0x4e, 24, 64, 6*1024*1024, l2_cache_str}, 3527ae115bc7Smrj { 0x4d, 16, 64, 16*1024*1024, l3_cache_str}, 3528ae115bc7Smrj { 0x4c, 12, 64, 12*1024*1024, l3_cache_str}, 3529ae115bc7Smrj { 0x4b, 16, 64, 8*1024*1024, l3_cache_str}, 3530ae115bc7Smrj { 0x4a, 12, 64, 6*1024*1024, l3_cache_str}, 3531ae115bc7Smrj { 0x49, 16, 64, 4*1024*1024, l3_cache_str}, 3532824e4fecSvd224797 { 0x48, 12, 64, 3*1024*1024, l2_cache_str}, 3533ae115bc7Smrj { 0x47, 8, 64, 8*1024*1024, l3_cache_str}, 3534ae115bc7Smrj { 0x46, 4, 64, 4*1024*1024, l3_cache_str}, 35357c478bd9Sstevel@tonic-gate { 0x45, 4, 32, 2*1024*1024, l2_cache_str}, 35367c478bd9Sstevel@tonic-gate { 0x44, 4, 32, 1024*1024, l2_cache_str}, 35377c478bd9Sstevel@tonic-gate { 0x43, 4, 32, 512*1024, l2_cache_str}, 35387c478bd9Sstevel@tonic-gate { 0x42, 4, 32, 256*1024, l2_cache_str}, 35397c478bd9Sstevel@tonic-gate { 0x41, 4, 32, 128*1024, l2_cache_str}, 3540ae115bc7Smrj { 0x3e, 4, 64, 512*1024, sl2_cache_str}, 3541ae115bc7Smrj { 0x3d, 6, 64, 384*1024, sl2_cache_str}, 35427c478bd9Sstevel@tonic-gate { 0x3c, 4, 64, 256*1024, sl2_cache_str}, 35437c478bd9Sstevel@tonic-gate { 0x3b, 2, 64, 128*1024, sl2_cache_str}, 3544ae115bc7Smrj { 0x3a, 6, 64, 192*1024, sl2_cache_str}, 35457c478bd9Sstevel@tonic-gate { 0x39, 4, 64, 128*1024, sl2_cache_str}, 35467c478bd9Sstevel@tonic-gate { 0x30, 8, 64, 32*1024, l1_icache_str}, 35477c478bd9Sstevel@tonic-gate { 0x2c, 8, 64, 32*1024, l1_dcache_str}, 35487c478bd9Sstevel@tonic-gate { 0x29, 8, 64, 4096*1024, sl3_cache_str}, 35497c478bd9Sstevel@tonic-gate { 0x25, 8, 64, 2048*1024, sl3_cache_str}, 35507c478bd9Sstevel@tonic-gate { 0x23, 8, 64, 1024*1024, sl3_cache_str}, 35517c478bd9Sstevel@tonic-gate { 0x22, 4, 64, 512*1024, sl3_cache_str}, 3552824e4fecSvd224797 { 0x0e, 6, 64, 24*1024, l1_dcache_str}, 355325dfb062Sksadhukh { 0x0d, 4, 32, 16*1024, l1_dcache_str}, 35547c478bd9Sstevel@tonic-gate { 0x0c, 4, 32, 16*1024, l1_dcache_str}, 3555ae115bc7Smrj { 0x0b, 4, 0, 4, itlb4M_str}, 35567c478bd9Sstevel@tonic-gate { 0x0a, 2, 32, 8*1024, l1_dcache_str}, 35577c478bd9Sstevel@tonic-gate { 0x08, 4, 32, 16*1024, l1_icache_str}, 35587c478bd9Sstevel@tonic-gate { 0x06, 4, 32, 8*1024, l1_icache_str}, 3559824e4fecSvd224797 { 0x05, 4, 0, 32, dtlb4M_str}, 35607c478bd9Sstevel@tonic-gate { 0x04, 4, 0, 8, dtlb4M_str}, 35617c478bd9Sstevel@tonic-gate { 0x03, 4, 0, 64, dtlb4k_str}, 35627c478bd9Sstevel@tonic-gate { 0x02, 4, 0, 2, itlb4M_str}, 35637c478bd9Sstevel@tonic-gate { 0x01, 4, 0, 32, itlb4k_str}, 35647c478bd9Sstevel@tonic-gate { 0 } 35657c478bd9Sstevel@tonic-gate }; 35667c478bd9Sstevel@tonic-gate 35677c478bd9Sstevel@tonic-gate static const struct cachetab cyrix_ctab[] = { 35687c478bd9Sstevel@tonic-gate { 0x70, 4, 0, 32, "tlb-4K" }, 35697c478bd9Sstevel@tonic-gate { 0x80, 4, 16, 16*1024, "l1-cache" }, 35707c478bd9Sstevel@tonic-gate { 0 } 35717c478bd9Sstevel@tonic-gate }; 35727c478bd9Sstevel@tonic-gate 35737c478bd9Sstevel@tonic-gate /* 35747c478bd9Sstevel@tonic-gate * Search a cache table for a matching entry 35757c478bd9Sstevel@tonic-gate */ 35767c478bd9Sstevel@tonic-gate static const struct cachetab * 35777c478bd9Sstevel@tonic-gate find_cacheent(const struct cachetab *ct, uint_t code) 35787c478bd9Sstevel@tonic-gate { 35797c478bd9Sstevel@tonic-gate if (code != 0) { 35807c478bd9Sstevel@tonic-gate for (; ct->ct_code != 0; ct++) 35817c478bd9Sstevel@tonic-gate if (ct->ct_code <= code) 35827c478bd9Sstevel@tonic-gate break; 35837c478bd9Sstevel@tonic-gate if (ct->ct_code == code) 35847c478bd9Sstevel@tonic-gate return (ct); 35857c478bd9Sstevel@tonic-gate } 35867c478bd9Sstevel@tonic-gate return (NULL); 35877c478bd9Sstevel@tonic-gate } 35887c478bd9Sstevel@tonic-gate 35897c478bd9Sstevel@tonic-gate /* 35907dee861bSksadhukh * Populate cachetab entry with L2 or L3 cache-information using 35917dee861bSksadhukh * cpuid function 4. This function is called from intel_walk_cacheinfo() 35927dee861bSksadhukh * when descriptor 0x49 is encountered. It returns 0 if no such cache 35937dee861bSksadhukh * information is found. 35947dee861bSksadhukh */ 35957dee861bSksadhukh static int 35967dee861bSksadhukh intel_cpuid_4_cache_info(struct cachetab *ct, struct cpuid_info *cpi) 35977dee861bSksadhukh { 35987dee861bSksadhukh uint32_t level, i; 35997dee861bSksadhukh int ret = 0; 36007dee861bSksadhukh 36017dee861bSksadhukh for (i = 0; i < cpi->cpi_std_4_size; i++) { 36027dee861bSksadhukh level = CPI_CACHE_LVL(cpi->cpi_std_4[i]); 36037dee861bSksadhukh 36047dee861bSksadhukh if (level == 2 || level == 3) { 36057dee861bSksadhukh ct->ct_assoc = CPI_CACHE_WAYS(cpi->cpi_std_4[i]) + 1; 36067dee861bSksadhukh ct->ct_line_size = 36077dee861bSksadhukh CPI_CACHE_COH_LN_SZ(cpi->cpi_std_4[i]) + 1; 36087dee861bSksadhukh ct->ct_size = ct->ct_assoc * 36097dee861bSksadhukh (CPI_CACHE_PARTS(cpi->cpi_std_4[i]) + 1) * 36107dee861bSksadhukh ct->ct_line_size * 36117dee861bSksadhukh (cpi->cpi_std_4[i]->cp_ecx + 1); 36127dee861bSksadhukh 36137dee861bSksadhukh if (level == 2) { 36147dee861bSksadhukh ct->ct_label = l2_cache_str; 36157dee861bSksadhukh } else if (level == 3) { 36167dee861bSksadhukh ct->ct_label = l3_cache_str; 36177dee861bSksadhukh } 36187dee861bSksadhukh ret = 1; 36197dee861bSksadhukh } 36207dee861bSksadhukh } 36217dee861bSksadhukh 36227dee861bSksadhukh return (ret); 36237dee861bSksadhukh } 36247dee861bSksadhukh 36257dee861bSksadhukh /* 36267c478bd9Sstevel@tonic-gate * Walk the cacheinfo descriptor, applying 'func' to every valid element 36277c478bd9Sstevel@tonic-gate * The walk is terminated if the walker returns non-zero. 36287c478bd9Sstevel@tonic-gate */ 36297c478bd9Sstevel@tonic-gate static void 36307c478bd9Sstevel@tonic-gate intel_walk_cacheinfo(struct cpuid_info *cpi, 36317c478bd9Sstevel@tonic-gate void *arg, int (*func)(void *, const struct cachetab *)) 36327c478bd9Sstevel@tonic-gate { 36337c478bd9Sstevel@tonic-gate const struct cachetab *ct; 3634824e4fecSvd224797 struct cachetab des_49_ct, des_b1_ct; 36357c478bd9Sstevel@tonic-gate uint8_t *dp; 36367c478bd9Sstevel@tonic-gate int i; 36377c478bd9Sstevel@tonic-gate 36387c478bd9Sstevel@tonic-gate if ((dp = cpi->cpi_cacheinfo) == NULL) 36397c478bd9Sstevel@tonic-gate return; 3640f1d742a9Sksadhukh for (i = 0; i < cpi->cpi_ncache; i++, dp++) { 3641f1d742a9Sksadhukh /* 3642f1d742a9Sksadhukh * For overloaded descriptor 0x49 we use cpuid function 4 36437dee861bSksadhukh * if supported by the current processor, to create 3644f1d742a9Sksadhukh * cache information. 3645824e4fecSvd224797 * For overloaded descriptor 0xb1 we use X86_PAE flag 3646824e4fecSvd224797 * to disambiguate the cache information. 3647f1d742a9Sksadhukh */ 36487dee861bSksadhukh if (*dp == 0x49 && cpi->cpi_maxeax >= 0x4 && 36497dee861bSksadhukh intel_cpuid_4_cache_info(&des_49_ct, cpi) == 1) { 36507dee861bSksadhukh ct = &des_49_ct; 3651824e4fecSvd224797 } else if (*dp == 0xb1) { 3652824e4fecSvd224797 des_b1_ct.ct_code = 0xb1; 3653824e4fecSvd224797 des_b1_ct.ct_assoc = 4; 3654824e4fecSvd224797 des_b1_ct.ct_line_size = 0; 36557417cfdeSKuriakose Kuruvilla if (is_x86_feature(x86_featureset, X86FSET_PAE)) { 3656824e4fecSvd224797 des_b1_ct.ct_size = 8; 3657824e4fecSvd224797 des_b1_ct.ct_label = itlb2M_str; 3658824e4fecSvd224797 } else { 3659824e4fecSvd224797 des_b1_ct.ct_size = 4; 3660824e4fecSvd224797 des_b1_ct.ct_label = itlb4M_str; 3661824e4fecSvd224797 } 3662824e4fecSvd224797 ct = &des_b1_ct; 36637dee861bSksadhukh } else { 36647dee861bSksadhukh if ((ct = find_cacheent(intel_ctab, *dp)) == NULL) { 3665f1d742a9Sksadhukh continue; 3666f1d742a9Sksadhukh } 36677dee861bSksadhukh } 3668f1d742a9Sksadhukh 36697dee861bSksadhukh if (func(arg, ct) != 0) { 36707c478bd9Sstevel@tonic-gate break; 36717c478bd9Sstevel@tonic-gate } 36727c478bd9Sstevel@tonic-gate } 3673f1d742a9Sksadhukh } 36747c478bd9Sstevel@tonic-gate 36757c478bd9Sstevel@tonic-gate /* 36767c478bd9Sstevel@tonic-gate * (Like the Intel one, except for Cyrix CPUs) 36777c478bd9Sstevel@tonic-gate */ 36787c478bd9Sstevel@tonic-gate static void 36797c478bd9Sstevel@tonic-gate cyrix_walk_cacheinfo(struct cpuid_info *cpi, 36807c478bd9Sstevel@tonic-gate void *arg, int (*func)(void *, const struct cachetab *)) 36817c478bd9Sstevel@tonic-gate { 36827c478bd9Sstevel@tonic-gate const struct cachetab *ct; 36837c478bd9Sstevel@tonic-gate uint8_t *dp; 36847c478bd9Sstevel@tonic-gate int i; 36857c478bd9Sstevel@tonic-gate 36867c478bd9Sstevel@tonic-gate if ((dp = cpi->cpi_cacheinfo) == NULL) 36877c478bd9Sstevel@tonic-gate return; 36887c478bd9Sstevel@tonic-gate for (i = 0; i < cpi->cpi_ncache; i++, dp++) { 36897c478bd9Sstevel@tonic-gate /* 36907c478bd9Sstevel@tonic-gate * Search Cyrix-specific descriptor table first .. 36917c478bd9Sstevel@tonic-gate */ 36927c478bd9Sstevel@tonic-gate if ((ct = find_cacheent(cyrix_ctab, *dp)) != NULL) { 36937c478bd9Sstevel@tonic-gate if (func(arg, ct) != 0) 36947c478bd9Sstevel@tonic-gate break; 36957c478bd9Sstevel@tonic-gate continue; 36967c478bd9Sstevel@tonic-gate } 36977c478bd9Sstevel@tonic-gate /* 36987c478bd9Sstevel@tonic-gate * .. else fall back to the Intel one 36997c478bd9Sstevel@tonic-gate */ 37007c478bd9Sstevel@tonic-gate if ((ct = find_cacheent(intel_ctab, *dp)) != NULL) { 37017c478bd9Sstevel@tonic-gate if (func(arg, ct) != 0) 37027c478bd9Sstevel@tonic-gate break; 37037c478bd9Sstevel@tonic-gate continue; 37047c478bd9Sstevel@tonic-gate } 37057c478bd9Sstevel@tonic-gate } 37067c478bd9Sstevel@tonic-gate } 37077c478bd9Sstevel@tonic-gate 37087c478bd9Sstevel@tonic-gate /* 37097c478bd9Sstevel@tonic-gate * A cacheinfo walker that adds associativity, line-size, and size properties 37107c478bd9Sstevel@tonic-gate * to the devinfo node it is passed as an argument. 37117c478bd9Sstevel@tonic-gate */ 37127c478bd9Sstevel@tonic-gate static int 37137c478bd9Sstevel@tonic-gate add_cacheent_props(void *arg, const struct cachetab *ct) 37147c478bd9Sstevel@tonic-gate { 37157c478bd9Sstevel@tonic-gate dev_info_t *devi = arg; 37167c478bd9Sstevel@tonic-gate 37177c478bd9Sstevel@tonic-gate add_cache_prop(devi, ct->ct_label, assoc_str, ct->ct_assoc); 37187c478bd9Sstevel@tonic-gate if (ct->ct_line_size != 0) 37197c478bd9Sstevel@tonic-gate add_cache_prop(devi, ct->ct_label, line_str, 37207c478bd9Sstevel@tonic-gate ct->ct_line_size); 37217c478bd9Sstevel@tonic-gate add_cache_prop(devi, ct->ct_label, size_str, ct->ct_size); 37227c478bd9Sstevel@tonic-gate return (0); 37237c478bd9Sstevel@tonic-gate } 37247c478bd9Sstevel@tonic-gate 3725f1d742a9Sksadhukh 37267c478bd9Sstevel@tonic-gate static const char fully_assoc[] = "fully-associative?"; 37277c478bd9Sstevel@tonic-gate 37287c478bd9Sstevel@tonic-gate /* 37297c478bd9Sstevel@tonic-gate * AMD style cache/tlb description 37307c478bd9Sstevel@tonic-gate * 37317c478bd9Sstevel@tonic-gate * Extended functions 5 and 6 directly describe properties of 37327c478bd9Sstevel@tonic-gate * tlbs and various cache levels. 37337c478bd9Sstevel@tonic-gate */ 37347c478bd9Sstevel@tonic-gate static void 37357c478bd9Sstevel@tonic-gate add_amd_assoc(dev_info_t *devi, const char *label, uint_t assoc) 37367c478bd9Sstevel@tonic-gate { 37377c478bd9Sstevel@tonic-gate switch (assoc) { 37387c478bd9Sstevel@tonic-gate case 0: /* reserved; ignore */ 37397c478bd9Sstevel@tonic-gate break; 37407c478bd9Sstevel@tonic-gate default: 37417c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, assoc_str, assoc); 37427c478bd9Sstevel@tonic-gate break; 37437c478bd9Sstevel@tonic-gate case 0xff: 37447c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, fully_assoc, 1); 37457c478bd9Sstevel@tonic-gate break; 37467c478bd9Sstevel@tonic-gate } 37477c478bd9Sstevel@tonic-gate } 37487c478bd9Sstevel@tonic-gate 37497c478bd9Sstevel@tonic-gate static void 37507c478bd9Sstevel@tonic-gate add_amd_tlb(dev_info_t *devi, const char *label, uint_t assoc, uint_t size) 37517c478bd9Sstevel@tonic-gate { 37527c478bd9Sstevel@tonic-gate if (size == 0) 37537c478bd9Sstevel@tonic-gate return; 37547c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, size_str, size); 37557c478bd9Sstevel@tonic-gate add_amd_assoc(devi, label, assoc); 37567c478bd9Sstevel@tonic-gate } 37577c478bd9Sstevel@tonic-gate 37587c478bd9Sstevel@tonic-gate static void 37597c478bd9Sstevel@tonic-gate add_amd_cache(dev_info_t *devi, const char *label, 37607c478bd9Sstevel@tonic-gate uint_t size, uint_t assoc, uint_t lines_per_tag, uint_t line_size) 37617c478bd9Sstevel@tonic-gate { 37627c478bd9Sstevel@tonic-gate if (size == 0 || line_size == 0) 37637c478bd9Sstevel@tonic-gate return; 37647c478bd9Sstevel@tonic-gate add_amd_assoc(devi, label, assoc); 37657c478bd9Sstevel@tonic-gate /* 37667c478bd9Sstevel@tonic-gate * Most AMD parts have a sectored cache. Multiple cache lines are 37677c478bd9Sstevel@tonic-gate * associated with each tag. A sector consists of all cache lines 37687c478bd9Sstevel@tonic-gate * associated with a tag. For example, the AMD K6-III has a sector 37697c478bd9Sstevel@tonic-gate * size of 2 cache lines per tag. 37707c478bd9Sstevel@tonic-gate */ 37717c478bd9Sstevel@tonic-gate if (lines_per_tag != 0) 37727c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, "lines-per-tag", lines_per_tag); 37737c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, line_str, line_size); 37747c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, size_str, size * 1024); 37757c478bd9Sstevel@tonic-gate } 37767c478bd9Sstevel@tonic-gate 37777c478bd9Sstevel@tonic-gate static void 37787c478bd9Sstevel@tonic-gate add_amd_l2_assoc(dev_info_t *devi, const char *label, uint_t assoc) 37797c478bd9Sstevel@tonic-gate { 37807c478bd9Sstevel@tonic-gate switch (assoc) { 37817c478bd9Sstevel@tonic-gate case 0: /* off */ 37827c478bd9Sstevel@tonic-gate break; 37837c478bd9Sstevel@tonic-gate case 1: 37847c478bd9Sstevel@tonic-gate case 2: 37857c478bd9Sstevel@tonic-gate case 4: 37867c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, assoc_str, assoc); 37877c478bd9Sstevel@tonic-gate break; 37887c478bd9Sstevel@tonic-gate case 6: 37897c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, assoc_str, 8); 37907c478bd9Sstevel@tonic-gate break; 37917c478bd9Sstevel@tonic-gate case 8: 37927c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, assoc_str, 16); 37937c478bd9Sstevel@tonic-gate break; 37947c478bd9Sstevel@tonic-gate case 0xf: 37957c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, fully_assoc, 1); 37967c478bd9Sstevel@tonic-gate break; 37977c478bd9Sstevel@tonic-gate default: /* reserved; ignore */ 37987c478bd9Sstevel@tonic-gate break; 37997c478bd9Sstevel@tonic-gate } 38007c478bd9Sstevel@tonic-gate } 38017c478bd9Sstevel@tonic-gate 38027c478bd9Sstevel@tonic-gate static void 38037c478bd9Sstevel@tonic-gate add_amd_l2_tlb(dev_info_t *devi, const char *label, uint_t assoc, uint_t size) 38047c478bd9Sstevel@tonic-gate { 38057c478bd9Sstevel@tonic-gate if (size == 0 || assoc == 0) 38067c478bd9Sstevel@tonic-gate return; 38077c478bd9Sstevel@tonic-gate add_amd_l2_assoc(devi, label, assoc); 38087c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, size_str, size); 38097c478bd9Sstevel@tonic-gate } 38107c478bd9Sstevel@tonic-gate 38117c478bd9Sstevel@tonic-gate static void 38127c478bd9Sstevel@tonic-gate add_amd_l2_cache(dev_info_t *devi, const char *label, 38137c478bd9Sstevel@tonic-gate uint_t size, uint_t assoc, uint_t lines_per_tag, uint_t line_size) 38147c478bd9Sstevel@tonic-gate { 38157c478bd9Sstevel@tonic-gate if (size == 0 || assoc == 0 || line_size == 0) 38167c478bd9Sstevel@tonic-gate return; 38177c478bd9Sstevel@tonic-gate add_amd_l2_assoc(devi, label, assoc); 38187c478bd9Sstevel@tonic-gate if (lines_per_tag != 0) 38197c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, "lines-per-tag", lines_per_tag); 38207c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, line_str, line_size); 38217c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, size_str, size * 1024); 38227c478bd9Sstevel@tonic-gate } 38237c478bd9Sstevel@tonic-gate 38247c478bd9Sstevel@tonic-gate static void 38257c478bd9Sstevel@tonic-gate amd_cache_info(struct cpuid_info *cpi, dev_info_t *devi) 38267c478bd9Sstevel@tonic-gate { 38278949bcd6Sandrei struct cpuid_regs *cp; 38287c478bd9Sstevel@tonic-gate 38297c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax < 0x80000005) 38307c478bd9Sstevel@tonic-gate return; 38317c478bd9Sstevel@tonic-gate cp = &cpi->cpi_extd[5]; 38327c478bd9Sstevel@tonic-gate 38337c478bd9Sstevel@tonic-gate /* 38347c478bd9Sstevel@tonic-gate * 4M/2M L1 TLB configuration 38357c478bd9Sstevel@tonic-gate * 38367c478bd9Sstevel@tonic-gate * We report the size for 2M pages because AMD uses two 38377c478bd9Sstevel@tonic-gate * TLB entries for one 4M page. 38387c478bd9Sstevel@tonic-gate */ 38397c478bd9Sstevel@tonic-gate add_amd_tlb(devi, "dtlb-2M", 38407c478bd9Sstevel@tonic-gate BITX(cp->cp_eax, 31, 24), BITX(cp->cp_eax, 23, 16)); 38417c478bd9Sstevel@tonic-gate add_amd_tlb(devi, "itlb-2M", 38427c478bd9Sstevel@tonic-gate BITX(cp->cp_eax, 15, 8), BITX(cp->cp_eax, 7, 0)); 38437c478bd9Sstevel@tonic-gate 38447c478bd9Sstevel@tonic-gate /* 38457c478bd9Sstevel@tonic-gate * 4K L1 TLB configuration 38467c478bd9Sstevel@tonic-gate */ 38477c478bd9Sstevel@tonic-gate 38487c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 38497c478bd9Sstevel@tonic-gate uint_t nentries; 38507c478bd9Sstevel@tonic-gate case X86_VENDOR_TM: 38517c478bd9Sstevel@tonic-gate if (cpi->cpi_family >= 5) { 38527c478bd9Sstevel@tonic-gate /* 38537c478bd9Sstevel@tonic-gate * Crusoe processors have 256 TLB entries, but 38547c478bd9Sstevel@tonic-gate * cpuid data format constrains them to only 38557c478bd9Sstevel@tonic-gate * reporting 255 of them. 38567c478bd9Sstevel@tonic-gate */ 38577c478bd9Sstevel@tonic-gate if ((nentries = BITX(cp->cp_ebx, 23, 16)) == 255) 38587c478bd9Sstevel@tonic-gate nentries = 256; 38597c478bd9Sstevel@tonic-gate /* 38607c478bd9Sstevel@tonic-gate * Crusoe processors also have a unified TLB 38617c478bd9Sstevel@tonic-gate */ 38627c478bd9Sstevel@tonic-gate add_amd_tlb(devi, "tlb-4K", BITX(cp->cp_ebx, 31, 24), 38637c478bd9Sstevel@tonic-gate nentries); 38647c478bd9Sstevel@tonic-gate break; 38657c478bd9Sstevel@tonic-gate } 38667c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 38677c478bd9Sstevel@tonic-gate default: 38687c478bd9Sstevel@tonic-gate add_amd_tlb(devi, itlb4k_str, 38697c478bd9Sstevel@tonic-gate BITX(cp->cp_ebx, 31, 24), BITX(cp->cp_ebx, 23, 16)); 38707c478bd9Sstevel@tonic-gate add_amd_tlb(devi, dtlb4k_str, 38717c478bd9Sstevel@tonic-gate BITX(cp->cp_ebx, 15, 8), BITX(cp->cp_ebx, 7, 0)); 38727c478bd9Sstevel@tonic-gate break; 38737c478bd9Sstevel@tonic-gate } 38747c478bd9Sstevel@tonic-gate 38757c478bd9Sstevel@tonic-gate /* 38767c478bd9Sstevel@tonic-gate * data L1 cache configuration 38777c478bd9Sstevel@tonic-gate */ 38787c478bd9Sstevel@tonic-gate 38797c478bd9Sstevel@tonic-gate add_amd_cache(devi, l1_dcache_str, 38807c478bd9Sstevel@tonic-gate BITX(cp->cp_ecx, 31, 24), BITX(cp->cp_ecx, 23, 16), 38817c478bd9Sstevel@tonic-gate BITX(cp->cp_ecx, 15, 8), BITX(cp->cp_ecx, 7, 0)); 38827c478bd9Sstevel@tonic-gate 38837c478bd9Sstevel@tonic-gate /* 38847c478bd9Sstevel@tonic-gate * code L1 cache configuration 38857c478bd9Sstevel@tonic-gate */ 38867c478bd9Sstevel@tonic-gate 38877c478bd9Sstevel@tonic-gate add_amd_cache(devi, l1_icache_str, 38887c478bd9Sstevel@tonic-gate BITX(cp->cp_edx, 31, 24), BITX(cp->cp_edx, 23, 16), 38897c478bd9Sstevel@tonic-gate BITX(cp->cp_edx, 15, 8), BITX(cp->cp_edx, 7, 0)); 38907c478bd9Sstevel@tonic-gate 38917c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax < 0x80000006) 38927c478bd9Sstevel@tonic-gate return; 38937c478bd9Sstevel@tonic-gate cp = &cpi->cpi_extd[6]; 38947c478bd9Sstevel@tonic-gate 38957c478bd9Sstevel@tonic-gate /* Check for a unified L2 TLB for large pages */ 38967c478bd9Sstevel@tonic-gate 38977c478bd9Sstevel@tonic-gate if (BITX(cp->cp_eax, 31, 16) == 0) 38987c478bd9Sstevel@tonic-gate add_amd_l2_tlb(devi, "l2-tlb-2M", 38997c478bd9Sstevel@tonic-gate BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0)); 39007c478bd9Sstevel@tonic-gate else { 39017c478bd9Sstevel@tonic-gate add_amd_l2_tlb(devi, "l2-dtlb-2M", 39027c478bd9Sstevel@tonic-gate BITX(cp->cp_eax, 31, 28), BITX(cp->cp_eax, 27, 16)); 39037c478bd9Sstevel@tonic-gate add_amd_l2_tlb(devi, "l2-itlb-2M", 39047c478bd9Sstevel@tonic-gate BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0)); 39057c478bd9Sstevel@tonic-gate } 39067c478bd9Sstevel@tonic-gate 39077c478bd9Sstevel@tonic-gate /* Check for a unified L2 TLB for 4K pages */ 39087c478bd9Sstevel@tonic-gate 39097c478bd9Sstevel@tonic-gate if (BITX(cp->cp_ebx, 31, 16) == 0) { 39107c478bd9Sstevel@tonic-gate add_amd_l2_tlb(devi, "l2-tlb-4K", 39117c478bd9Sstevel@tonic-gate BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0)); 39127c478bd9Sstevel@tonic-gate } else { 39137c478bd9Sstevel@tonic-gate add_amd_l2_tlb(devi, "l2-dtlb-4K", 39147c478bd9Sstevel@tonic-gate BITX(cp->cp_eax, 31, 28), BITX(cp->cp_eax, 27, 16)); 39157c478bd9Sstevel@tonic-gate add_amd_l2_tlb(devi, "l2-itlb-4K", 39167c478bd9Sstevel@tonic-gate BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0)); 39177c478bd9Sstevel@tonic-gate } 39187c478bd9Sstevel@tonic-gate 39197c478bd9Sstevel@tonic-gate add_amd_l2_cache(devi, l2_cache_str, 39207c478bd9Sstevel@tonic-gate BITX(cp->cp_ecx, 31, 16), BITX(cp->cp_ecx, 15, 12), 39217c478bd9Sstevel@tonic-gate BITX(cp->cp_ecx, 11, 8), BITX(cp->cp_ecx, 7, 0)); 39227c478bd9Sstevel@tonic-gate } 39237c478bd9Sstevel@tonic-gate 39247c478bd9Sstevel@tonic-gate /* 39257c478bd9Sstevel@tonic-gate * There are two basic ways that the x86 world describes it cache 39267c478bd9Sstevel@tonic-gate * and tlb architecture - Intel's way and AMD's way. 39277c478bd9Sstevel@tonic-gate * 39287c478bd9Sstevel@tonic-gate * Return which flavor of cache architecture we should use 39297c478bd9Sstevel@tonic-gate */ 39307c478bd9Sstevel@tonic-gate static int 39317c478bd9Sstevel@tonic-gate x86_which_cacheinfo(struct cpuid_info *cpi) 39327c478bd9Sstevel@tonic-gate { 39337c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 39347c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 39357c478bd9Sstevel@tonic-gate if (cpi->cpi_maxeax >= 2) 39367c478bd9Sstevel@tonic-gate return (X86_VENDOR_Intel); 39377c478bd9Sstevel@tonic-gate break; 39387c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 39397c478bd9Sstevel@tonic-gate /* 39407c478bd9Sstevel@tonic-gate * The K5 model 1 was the first part from AMD that reported 39417c478bd9Sstevel@tonic-gate * cache sizes via extended cpuid functions. 39427c478bd9Sstevel@tonic-gate */ 39437c478bd9Sstevel@tonic-gate if (cpi->cpi_family > 5 || 39447c478bd9Sstevel@tonic-gate (cpi->cpi_family == 5 && cpi->cpi_model >= 1)) 39457c478bd9Sstevel@tonic-gate return (X86_VENDOR_AMD); 39467c478bd9Sstevel@tonic-gate break; 39477c478bd9Sstevel@tonic-gate case X86_VENDOR_TM: 39487c478bd9Sstevel@tonic-gate if (cpi->cpi_family >= 5) 39497c478bd9Sstevel@tonic-gate return (X86_VENDOR_AMD); 39507c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 39517c478bd9Sstevel@tonic-gate default: 39527c478bd9Sstevel@tonic-gate /* 39537c478bd9Sstevel@tonic-gate * If they have extended CPU data for 0x80000005 39547c478bd9Sstevel@tonic-gate * then we assume they have AMD-format cache 39557c478bd9Sstevel@tonic-gate * information. 39567c478bd9Sstevel@tonic-gate * 39577c478bd9Sstevel@tonic-gate * If not, and the vendor happens to be Cyrix, 39587c478bd9Sstevel@tonic-gate * then try our-Cyrix specific handler. 39597c478bd9Sstevel@tonic-gate * 39607c478bd9Sstevel@tonic-gate * If we're not Cyrix, then assume we're using Intel's 39617c478bd9Sstevel@tonic-gate * table-driven format instead. 39627c478bd9Sstevel@tonic-gate */ 39637c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax >= 0x80000005) 39647c478bd9Sstevel@tonic-gate return (X86_VENDOR_AMD); 39657c478bd9Sstevel@tonic-gate else if (cpi->cpi_vendor == X86_VENDOR_Cyrix) 39667c478bd9Sstevel@tonic-gate return (X86_VENDOR_Cyrix); 39677c478bd9Sstevel@tonic-gate else if (cpi->cpi_maxeax >= 2) 39687c478bd9Sstevel@tonic-gate return (X86_VENDOR_Intel); 39697c478bd9Sstevel@tonic-gate break; 39707c478bd9Sstevel@tonic-gate } 39717c478bd9Sstevel@tonic-gate return (-1); 39727c478bd9Sstevel@tonic-gate } 39737c478bd9Sstevel@tonic-gate 39747c478bd9Sstevel@tonic-gate void 3975fa96bd91SMichael Corcoran cpuid_set_cpu_properties(void *dip, processorid_t cpu_id, 3976fa96bd91SMichael Corcoran struct cpuid_info *cpi) 39777c478bd9Sstevel@tonic-gate { 39787c478bd9Sstevel@tonic-gate dev_info_t *cpu_devi; 39797c478bd9Sstevel@tonic-gate int create; 39807c478bd9Sstevel@tonic-gate 3981fa96bd91SMichael Corcoran cpu_devi = (dev_info_t *)dip; 39827c478bd9Sstevel@tonic-gate 39837c478bd9Sstevel@tonic-gate /* device_type */ 39847c478bd9Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, cpu_devi, 39857c478bd9Sstevel@tonic-gate "device_type", "cpu"); 39867c478bd9Sstevel@tonic-gate 39877c478bd9Sstevel@tonic-gate /* reg */ 39887c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 39897c478bd9Sstevel@tonic-gate "reg", cpu_id); 39907c478bd9Sstevel@tonic-gate 39917c478bd9Sstevel@tonic-gate /* cpu-mhz, and clock-frequency */ 39927c478bd9Sstevel@tonic-gate if (cpu_freq > 0) { 39937c478bd9Sstevel@tonic-gate long long mul; 39947c478bd9Sstevel@tonic-gate 39957c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 39967c478bd9Sstevel@tonic-gate "cpu-mhz", cpu_freq); 39977c478bd9Sstevel@tonic-gate if ((mul = cpu_freq * 1000000LL) <= INT_MAX) 39987c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 39997c478bd9Sstevel@tonic-gate "clock-frequency", (int)mul); 40007c478bd9Sstevel@tonic-gate } 40017c478bd9Sstevel@tonic-gate 40027417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_CPUID)) { 40037c478bd9Sstevel@tonic-gate return; 40047c478bd9Sstevel@tonic-gate } 40057c478bd9Sstevel@tonic-gate 40067c478bd9Sstevel@tonic-gate /* vendor-id */ 40077c478bd9Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, cpu_devi, 40087c478bd9Sstevel@tonic-gate "vendor-id", cpi->cpi_vendorstr); 40097c478bd9Sstevel@tonic-gate 40107c478bd9Sstevel@tonic-gate if (cpi->cpi_maxeax == 0) { 40117c478bd9Sstevel@tonic-gate return; 40127c478bd9Sstevel@tonic-gate } 40137c478bd9Sstevel@tonic-gate 40147c478bd9Sstevel@tonic-gate /* 40157c478bd9Sstevel@tonic-gate * family, model, and step 40167c478bd9Sstevel@tonic-gate */ 40177c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 40187c478bd9Sstevel@tonic-gate "family", CPI_FAMILY(cpi)); 40197c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 40207c478bd9Sstevel@tonic-gate "cpu-model", CPI_MODEL(cpi)); 40217c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 40227c478bd9Sstevel@tonic-gate "stepping-id", CPI_STEP(cpi)); 40237c478bd9Sstevel@tonic-gate 40247c478bd9Sstevel@tonic-gate /* type */ 40257c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 40267c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 40277c478bd9Sstevel@tonic-gate create = 1; 40287c478bd9Sstevel@tonic-gate break; 40297c478bd9Sstevel@tonic-gate default: 40307c478bd9Sstevel@tonic-gate create = 0; 40317c478bd9Sstevel@tonic-gate break; 40327c478bd9Sstevel@tonic-gate } 40337c478bd9Sstevel@tonic-gate if (create) 40347c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 40357c478bd9Sstevel@tonic-gate "type", CPI_TYPE(cpi)); 40367c478bd9Sstevel@tonic-gate 40377c478bd9Sstevel@tonic-gate /* ext-family */ 40387c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 40397c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 40407c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 40417c478bd9Sstevel@tonic-gate create = cpi->cpi_family >= 0xf; 40427c478bd9Sstevel@tonic-gate break; 40437c478bd9Sstevel@tonic-gate default: 40447c478bd9Sstevel@tonic-gate create = 0; 40457c478bd9Sstevel@tonic-gate break; 40467c478bd9Sstevel@tonic-gate } 40477c478bd9Sstevel@tonic-gate if (create) 40487c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 40497c478bd9Sstevel@tonic-gate "ext-family", CPI_FAMILY_XTD(cpi)); 40507c478bd9Sstevel@tonic-gate 40517c478bd9Sstevel@tonic-gate /* ext-model */ 40527c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 40537c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 405463d3f7dfSkk208521 create = IS_EXTENDED_MODEL_INTEL(cpi); 405568c91426Sdmick break; 40567c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 4057ee88d2b9Skchow create = CPI_FAMILY(cpi) == 0xf; 40587c478bd9Sstevel@tonic-gate break; 40597c478bd9Sstevel@tonic-gate default: 40607c478bd9Sstevel@tonic-gate create = 0; 40617c478bd9Sstevel@tonic-gate break; 40627c478bd9Sstevel@tonic-gate } 40637c478bd9Sstevel@tonic-gate if (create) 40647c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 40657c478bd9Sstevel@tonic-gate "ext-model", CPI_MODEL_XTD(cpi)); 40667c478bd9Sstevel@tonic-gate 40677c478bd9Sstevel@tonic-gate /* generation */ 40687c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 40697c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 40707c478bd9Sstevel@tonic-gate /* 40717c478bd9Sstevel@tonic-gate * AMD K5 model 1 was the first part to support this 40727c478bd9Sstevel@tonic-gate */ 40737c478bd9Sstevel@tonic-gate create = cpi->cpi_xmaxeax >= 0x80000001; 40747c478bd9Sstevel@tonic-gate break; 40757c478bd9Sstevel@tonic-gate default: 40767c478bd9Sstevel@tonic-gate create = 0; 40777c478bd9Sstevel@tonic-gate break; 40787c478bd9Sstevel@tonic-gate } 40797c478bd9Sstevel@tonic-gate if (create) 40807c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 40817c478bd9Sstevel@tonic-gate "generation", BITX((cpi)->cpi_extd[1].cp_eax, 11, 8)); 40827c478bd9Sstevel@tonic-gate 40837c478bd9Sstevel@tonic-gate /* brand-id */ 40847c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 40857c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 40867c478bd9Sstevel@tonic-gate /* 40877c478bd9Sstevel@tonic-gate * brand id first appeared on Pentium III Xeon model 8, 40887c478bd9Sstevel@tonic-gate * and Celeron model 8 processors and Opteron 40897c478bd9Sstevel@tonic-gate */ 40907c478bd9Sstevel@tonic-gate create = cpi->cpi_family > 6 || 40917c478bd9Sstevel@tonic-gate (cpi->cpi_family == 6 && cpi->cpi_model >= 8); 40927c478bd9Sstevel@tonic-gate break; 40937c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 40947c478bd9Sstevel@tonic-gate create = cpi->cpi_family >= 0xf; 40957c478bd9Sstevel@tonic-gate break; 40967c478bd9Sstevel@tonic-gate default: 40977c478bd9Sstevel@tonic-gate create = 0; 40987c478bd9Sstevel@tonic-gate break; 40997c478bd9Sstevel@tonic-gate } 41007c478bd9Sstevel@tonic-gate if (create && cpi->cpi_brandid != 0) { 41017c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 41027c478bd9Sstevel@tonic-gate "brand-id", cpi->cpi_brandid); 41037c478bd9Sstevel@tonic-gate } 41047c478bd9Sstevel@tonic-gate 41057c478bd9Sstevel@tonic-gate /* chunks, and apic-id */ 41067c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 41077c478bd9Sstevel@tonic-gate /* 41087c478bd9Sstevel@tonic-gate * first available on Pentium IV and Opteron (K8) 41097c478bd9Sstevel@tonic-gate */ 41105ff02082Sdmick case X86_VENDOR_Intel: 41115ff02082Sdmick create = IS_NEW_F6(cpi) || cpi->cpi_family >= 0xf; 41125ff02082Sdmick break; 41135ff02082Sdmick case X86_VENDOR_AMD: 41147c478bd9Sstevel@tonic-gate create = cpi->cpi_family >= 0xf; 41157c478bd9Sstevel@tonic-gate break; 41167c478bd9Sstevel@tonic-gate default: 41177c478bd9Sstevel@tonic-gate create = 0; 41187c478bd9Sstevel@tonic-gate break; 41197c478bd9Sstevel@tonic-gate } 41207c478bd9Sstevel@tonic-gate if (create) { 41217c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 41227c478bd9Sstevel@tonic-gate "chunks", CPI_CHUNKS(cpi)); 41237c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 4124b6917abeSmishra "apic-id", cpi->cpi_apicid); 41257aec1d6eScindi if (cpi->cpi_chipid >= 0) { 41267c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 41277c478bd9Sstevel@tonic-gate "chip#", cpi->cpi_chipid); 41287aec1d6eScindi (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 41297aec1d6eScindi "clog#", cpi->cpi_clogid); 41307aec1d6eScindi } 41317c478bd9Sstevel@tonic-gate } 41327c478bd9Sstevel@tonic-gate 41337c478bd9Sstevel@tonic-gate /* cpuid-features */ 41347c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 41357c478bd9Sstevel@tonic-gate "cpuid-features", CPI_FEATURES_EDX(cpi)); 41367c478bd9Sstevel@tonic-gate 41377c478bd9Sstevel@tonic-gate 41387c478bd9Sstevel@tonic-gate /* cpuid-features-ecx */ 41397c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 41407c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 41415ff02082Sdmick create = IS_NEW_F6(cpi) || cpi->cpi_family >= 0xf; 41427c478bd9Sstevel@tonic-gate break; 414363408480SHans Rosenfeld case X86_VENDOR_AMD: 414463408480SHans Rosenfeld create = cpi->cpi_family >= 0xf; 414563408480SHans Rosenfeld break; 41467c478bd9Sstevel@tonic-gate default: 41477c478bd9Sstevel@tonic-gate create = 0; 41487c478bd9Sstevel@tonic-gate break; 41497c478bd9Sstevel@tonic-gate } 41507c478bd9Sstevel@tonic-gate if (create) 41517c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 41527c478bd9Sstevel@tonic-gate "cpuid-features-ecx", CPI_FEATURES_ECX(cpi)); 41537c478bd9Sstevel@tonic-gate 41547c478bd9Sstevel@tonic-gate /* ext-cpuid-features */ 41557c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 41565ff02082Sdmick case X86_VENDOR_Intel: 41577c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 41587c478bd9Sstevel@tonic-gate case X86_VENDOR_Cyrix: 41597c478bd9Sstevel@tonic-gate case X86_VENDOR_TM: 41607c478bd9Sstevel@tonic-gate case X86_VENDOR_Centaur: 41617c478bd9Sstevel@tonic-gate create = cpi->cpi_xmaxeax >= 0x80000001; 41627c478bd9Sstevel@tonic-gate break; 41637c478bd9Sstevel@tonic-gate default: 41647c478bd9Sstevel@tonic-gate create = 0; 41657c478bd9Sstevel@tonic-gate break; 41667c478bd9Sstevel@tonic-gate } 41675ff02082Sdmick if (create) { 41687c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 41697c478bd9Sstevel@tonic-gate "ext-cpuid-features", CPI_FEATURES_XTD_EDX(cpi)); 41705ff02082Sdmick (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 41715ff02082Sdmick "ext-cpuid-features-ecx", CPI_FEATURES_XTD_ECX(cpi)); 41725ff02082Sdmick } 41737c478bd9Sstevel@tonic-gate 41747c478bd9Sstevel@tonic-gate /* 41757c478bd9Sstevel@tonic-gate * Brand String first appeared in Intel Pentium IV, AMD K5 41767c478bd9Sstevel@tonic-gate * model 1, and Cyrix GXm. On earlier models we try and 41777c478bd9Sstevel@tonic-gate * simulate something similar .. so this string should always 41787c478bd9Sstevel@tonic-gate * same -something- about the processor, however lame. 41797c478bd9Sstevel@tonic-gate */ 41807c478bd9Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, cpu_devi, 41817c478bd9Sstevel@tonic-gate "brand-string", cpi->cpi_brandstr); 41827c478bd9Sstevel@tonic-gate 41837c478bd9Sstevel@tonic-gate /* 41847c478bd9Sstevel@tonic-gate * Finally, cache and tlb information 41857c478bd9Sstevel@tonic-gate */ 41867c478bd9Sstevel@tonic-gate switch (x86_which_cacheinfo(cpi)) { 41877c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 41887c478bd9Sstevel@tonic-gate intel_walk_cacheinfo(cpi, cpu_devi, add_cacheent_props); 41897c478bd9Sstevel@tonic-gate break; 41907c478bd9Sstevel@tonic-gate case X86_VENDOR_Cyrix: 41917c478bd9Sstevel@tonic-gate cyrix_walk_cacheinfo(cpi, cpu_devi, add_cacheent_props); 41927c478bd9Sstevel@tonic-gate break; 41937c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 41947c478bd9Sstevel@tonic-gate amd_cache_info(cpi, cpu_devi); 41957c478bd9Sstevel@tonic-gate break; 41967c478bd9Sstevel@tonic-gate default: 41977c478bd9Sstevel@tonic-gate break; 41987c478bd9Sstevel@tonic-gate } 41997c478bd9Sstevel@tonic-gate } 42007c478bd9Sstevel@tonic-gate 42017c478bd9Sstevel@tonic-gate struct l2info { 42027c478bd9Sstevel@tonic-gate int *l2i_csz; 42037c478bd9Sstevel@tonic-gate int *l2i_lsz; 42047c478bd9Sstevel@tonic-gate int *l2i_assoc; 42057c478bd9Sstevel@tonic-gate int l2i_ret; 42067c478bd9Sstevel@tonic-gate }; 42077c478bd9Sstevel@tonic-gate 42087c478bd9Sstevel@tonic-gate /* 42097c478bd9Sstevel@tonic-gate * A cacheinfo walker that fetches the size, line-size and associativity 42107c478bd9Sstevel@tonic-gate * of the L2 cache 42117c478bd9Sstevel@tonic-gate */ 42127c478bd9Sstevel@tonic-gate static int 42137c478bd9Sstevel@tonic-gate intel_l2cinfo(void *arg, const struct cachetab *ct) 42147c478bd9Sstevel@tonic-gate { 42157c478bd9Sstevel@tonic-gate struct l2info *l2i = arg; 42167c478bd9Sstevel@tonic-gate int *ip; 42177c478bd9Sstevel@tonic-gate 42187c478bd9Sstevel@tonic-gate if (ct->ct_label != l2_cache_str && 42197c478bd9Sstevel@tonic-gate ct->ct_label != sl2_cache_str) 42207c478bd9Sstevel@tonic-gate return (0); /* not an L2 -- keep walking */ 42217c478bd9Sstevel@tonic-gate 42227c478bd9Sstevel@tonic-gate if ((ip = l2i->l2i_csz) != NULL) 42237c478bd9Sstevel@tonic-gate *ip = ct->ct_size; 42247c478bd9Sstevel@tonic-gate if ((ip = l2i->l2i_lsz) != NULL) 42257c478bd9Sstevel@tonic-gate *ip = ct->ct_line_size; 42267c478bd9Sstevel@tonic-gate if ((ip = l2i->l2i_assoc) != NULL) 42277c478bd9Sstevel@tonic-gate *ip = ct->ct_assoc; 42287c478bd9Sstevel@tonic-gate l2i->l2i_ret = ct->ct_size; 42297c478bd9Sstevel@tonic-gate return (1); /* was an L2 -- terminate walk */ 42307c478bd9Sstevel@tonic-gate } 42317c478bd9Sstevel@tonic-gate 4232606303c9Skchow /* 4233606303c9Skchow * AMD L2/L3 Cache and TLB Associativity Field Definition: 4234606303c9Skchow * 4235606303c9Skchow * Unlike the associativity for the L1 cache and tlb where the 8 bit 4236606303c9Skchow * value is the associativity, the associativity for the L2 cache and 4237606303c9Skchow * tlb is encoded in the following table. The 4 bit L2 value serves as 4238606303c9Skchow * an index into the amd_afd[] array to determine the associativity. 4239606303c9Skchow * -1 is undefined. 0 is fully associative. 4240606303c9Skchow */ 4241606303c9Skchow 4242606303c9Skchow static int amd_afd[] = 4243606303c9Skchow {-1, 1, 2, -1, 4, -1, 8, -1, 16, -1, 32, 48, 64, 96, 128, 0}; 4244606303c9Skchow 42457c478bd9Sstevel@tonic-gate static void 42467c478bd9Sstevel@tonic-gate amd_l2cacheinfo(struct cpuid_info *cpi, struct l2info *l2i) 42477c478bd9Sstevel@tonic-gate { 42488949bcd6Sandrei struct cpuid_regs *cp; 42497c478bd9Sstevel@tonic-gate uint_t size, assoc; 4250606303c9Skchow int i; 42517c478bd9Sstevel@tonic-gate int *ip; 42527c478bd9Sstevel@tonic-gate 42537c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax < 0x80000006) 42547c478bd9Sstevel@tonic-gate return; 42557c478bd9Sstevel@tonic-gate cp = &cpi->cpi_extd[6]; 42567c478bd9Sstevel@tonic-gate 4257606303c9Skchow if ((i = BITX(cp->cp_ecx, 15, 12)) != 0 && 42587c478bd9Sstevel@tonic-gate (size = BITX(cp->cp_ecx, 31, 16)) != 0) { 42597c478bd9Sstevel@tonic-gate uint_t cachesz = size * 1024; 4260606303c9Skchow assoc = amd_afd[i]; 42617c478bd9Sstevel@tonic-gate 4262606303c9Skchow ASSERT(assoc != -1); 42637c478bd9Sstevel@tonic-gate 42647c478bd9Sstevel@tonic-gate if ((ip = l2i->l2i_csz) != NULL) 42657c478bd9Sstevel@tonic-gate *ip = cachesz; 42667c478bd9Sstevel@tonic-gate if ((ip = l2i->l2i_lsz) != NULL) 42677c478bd9Sstevel@tonic-gate *ip = BITX(cp->cp_ecx, 7, 0); 42687c478bd9Sstevel@tonic-gate if ((ip = l2i->l2i_assoc) != NULL) 42697c478bd9Sstevel@tonic-gate *ip = assoc; 42707c478bd9Sstevel@tonic-gate l2i->l2i_ret = cachesz; 42717c478bd9Sstevel@tonic-gate } 42727c478bd9Sstevel@tonic-gate } 42737c478bd9Sstevel@tonic-gate 42747c478bd9Sstevel@tonic-gate int 42757c478bd9Sstevel@tonic-gate getl2cacheinfo(cpu_t *cpu, int *csz, int *lsz, int *assoc) 42767c478bd9Sstevel@tonic-gate { 42777c478bd9Sstevel@tonic-gate struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi; 42787c478bd9Sstevel@tonic-gate struct l2info __l2info, *l2i = &__l2info; 42797c478bd9Sstevel@tonic-gate 42807c478bd9Sstevel@tonic-gate l2i->l2i_csz = csz; 42817c478bd9Sstevel@tonic-gate l2i->l2i_lsz = lsz; 42827c478bd9Sstevel@tonic-gate l2i->l2i_assoc = assoc; 42837c478bd9Sstevel@tonic-gate l2i->l2i_ret = -1; 42847c478bd9Sstevel@tonic-gate 42857c478bd9Sstevel@tonic-gate switch (x86_which_cacheinfo(cpi)) { 42867c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 42877c478bd9Sstevel@tonic-gate intel_walk_cacheinfo(cpi, l2i, intel_l2cinfo); 42887c478bd9Sstevel@tonic-gate break; 42897c478bd9Sstevel@tonic-gate case X86_VENDOR_Cyrix: 42907c478bd9Sstevel@tonic-gate cyrix_walk_cacheinfo(cpi, l2i, intel_l2cinfo); 42917c478bd9Sstevel@tonic-gate break; 42927c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 42937c478bd9Sstevel@tonic-gate amd_l2cacheinfo(cpi, l2i); 42947c478bd9Sstevel@tonic-gate break; 42957c478bd9Sstevel@tonic-gate default: 42967c478bd9Sstevel@tonic-gate break; 42977c478bd9Sstevel@tonic-gate } 42987c478bd9Sstevel@tonic-gate return (l2i->l2i_ret); 42997c478bd9Sstevel@tonic-gate } 4300f98fbcecSbholler 4301843e1988Sjohnlev #if !defined(__xpv) 4302843e1988Sjohnlev 43035b8a6efeSbholler uint32_t * 43045b8a6efeSbholler cpuid_mwait_alloc(cpu_t *cpu) 43055b8a6efeSbholler { 43065b8a6efeSbholler uint32_t *ret; 43075b8a6efeSbholler size_t mwait_size; 43085b8a6efeSbholler 4309a3114836SGerry Liu ASSERT(cpuid_checkpass(CPU, 2)); 43105b8a6efeSbholler 4311a3114836SGerry Liu mwait_size = CPU->cpu_m.mcpu_cpi->cpi_mwait.mon_max; 43125b8a6efeSbholler if (mwait_size == 0) 43135b8a6efeSbholler return (NULL); 43145b8a6efeSbholler 43155b8a6efeSbholler /* 43165b8a6efeSbholler * kmem_alloc() returns cache line size aligned data for mwait_size 43175b8a6efeSbholler * allocations. mwait_size is currently cache line sized. Neither 43185b8a6efeSbholler * of these implementation details are guarantied to be true in the 43195b8a6efeSbholler * future. 43205b8a6efeSbholler * 43215b8a6efeSbholler * First try allocating mwait_size as kmem_alloc() currently returns 43225b8a6efeSbholler * correctly aligned memory. If kmem_alloc() does not return 43235b8a6efeSbholler * mwait_size aligned memory, then use mwait_size ROUNDUP. 43245b8a6efeSbholler * 43255b8a6efeSbholler * Set cpi_mwait.buf_actual and cpi_mwait.size_actual in case we 43265b8a6efeSbholler * decide to free this memory. 43275b8a6efeSbholler */ 43285b8a6efeSbholler ret = kmem_zalloc(mwait_size, KM_SLEEP); 43295b8a6efeSbholler if (ret == (uint32_t *)P2ROUNDUP((uintptr_t)ret, mwait_size)) { 43305b8a6efeSbholler cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual = ret; 43315b8a6efeSbholler cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual = mwait_size; 43325b8a6efeSbholler *ret = MWAIT_RUNNING; 43335b8a6efeSbholler return (ret); 43345b8a6efeSbholler } else { 43355b8a6efeSbholler kmem_free(ret, mwait_size); 43365b8a6efeSbholler ret = kmem_zalloc(mwait_size * 2, KM_SLEEP); 43375b8a6efeSbholler cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual = ret; 43385b8a6efeSbholler cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual = mwait_size * 2; 43395b8a6efeSbholler ret = (uint32_t *)P2ROUNDUP((uintptr_t)ret, mwait_size); 43405b8a6efeSbholler *ret = MWAIT_RUNNING; 43415b8a6efeSbholler return (ret); 43425b8a6efeSbholler } 43435b8a6efeSbholler } 43445b8a6efeSbholler 43455b8a6efeSbholler void 43465b8a6efeSbholler cpuid_mwait_free(cpu_t *cpu) 4347f98fbcecSbholler { 4348a3114836SGerry Liu if (cpu->cpu_m.mcpu_cpi == NULL) { 4349a3114836SGerry Liu return; 4350a3114836SGerry Liu } 43515b8a6efeSbholler 43525b8a6efeSbholler if (cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual != NULL && 43535b8a6efeSbholler cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual > 0) { 43545b8a6efeSbholler kmem_free(cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual, 43555b8a6efeSbholler cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual); 43565b8a6efeSbholler } 43575b8a6efeSbholler 43585b8a6efeSbholler cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual = NULL; 43595b8a6efeSbholler cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual = 0; 4360f98fbcecSbholler } 4361843e1988Sjohnlev 4362247dbb3dSsudheer void 4363247dbb3dSsudheer patch_tsc_read(int flag) 4364247dbb3dSsudheer { 4365247dbb3dSsudheer size_t cnt; 4366e4b86885SCheng Sean Ye 4367247dbb3dSsudheer switch (flag) { 4368247dbb3dSsudheer case X86_NO_TSC: 4369247dbb3dSsudheer cnt = &_no_rdtsc_end - &_no_rdtsc_start; 43702b0bcb26Ssudheer (void) memcpy((void *)tsc_read, (void *)&_no_rdtsc_start, cnt); 4371247dbb3dSsudheer break; 4372247dbb3dSsudheer case X86_HAVE_TSCP: 4373247dbb3dSsudheer cnt = &_tscp_end - &_tscp_start; 43742b0bcb26Ssudheer (void) memcpy((void *)tsc_read, (void *)&_tscp_start, cnt); 4375247dbb3dSsudheer break; 4376247dbb3dSsudheer case X86_TSC_MFENCE: 4377247dbb3dSsudheer cnt = &_tsc_mfence_end - &_tsc_mfence_start; 43782b0bcb26Ssudheer (void) memcpy((void *)tsc_read, 43792b0bcb26Ssudheer (void *)&_tsc_mfence_start, cnt); 4380247dbb3dSsudheer break; 438115363b27Ssudheer case X86_TSC_LFENCE: 438215363b27Ssudheer cnt = &_tsc_lfence_end - &_tsc_lfence_start; 438315363b27Ssudheer (void) memcpy((void *)tsc_read, 438415363b27Ssudheer (void *)&_tsc_lfence_start, cnt); 438515363b27Ssudheer break; 4386247dbb3dSsudheer default: 4387247dbb3dSsudheer break; 4388247dbb3dSsudheer } 4389247dbb3dSsudheer } 4390247dbb3dSsudheer 43910e751525SEric Saxe int 43920e751525SEric Saxe cpuid_deep_cstates_supported(void) 43930e751525SEric Saxe { 43940e751525SEric Saxe struct cpuid_info *cpi; 43950e751525SEric Saxe struct cpuid_regs regs; 43960e751525SEric Saxe 43970e751525SEric Saxe ASSERT(cpuid_checkpass(CPU, 1)); 43980e751525SEric Saxe 43990e751525SEric Saxe cpi = CPU->cpu_m.mcpu_cpi; 44000e751525SEric Saxe 44017417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_CPUID)) 44020e751525SEric Saxe return (0); 44030e751525SEric Saxe 44040e751525SEric Saxe switch (cpi->cpi_vendor) { 44050e751525SEric Saxe case X86_VENDOR_Intel: 44060e751525SEric Saxe if (cpi->cpi_xmaxeax < 0x80000007) 44070e751525SEric Saxe return (0); 44080e751525SEric Saxe 44090e751525SEric Saxe /* 44100e751525SEric Saxe * TSC run at a constant rate in all ACPI C-states? 44110e751525SEric Saxe */ 44120e751525SEric Saxe regs.cp_eax = 0x80000007; 44130e751525SEric Saxe (void) __cpuid_insn(®s); 44140e751525SEric Saxe return (regs.cp_edx & CPUID_TSC_CSTATE_INVARIANCE); 44150e751525SEric Saxe 44160e751525SEric Saxe default: 44170e751525SEric Saxe return (0); 44180e751525SEric Saxe } 44190e751525SEric Saxe } 44200e751525SEric Saxe 4421e774b42bSBill Holler #endif /* !__xpv */ 4422e774b42bSBill Holler 4423e774b42bSBill Holler void 4424e774b42bSBill Holler post_startup_cpu_fixups(void) 4425e774b42bSBill Holler { 4426e774b42bSBill Holler #ifndef __xpv 4427e774b42bSBill Holler /* 4428e774b42bSBill Holler * Some AMD processors support C1E state. Entering this state will 4429e774b42bSBill Holler * cause the local APIC timer to stop, which we can't deal with at 4430e774b42bSBill Holler * this time. 4431e774b42bSBill Holler */ 4432e774b42bSBill Holler if (cpuid_getvendor(CPU) == X86_VENDOR_AMD) { 4433e774b42bSBill Holler on_trap_data_t otd; 4434e774b42bSBill Holler uint64_t reg; 4435e774b42bSBill Holler 4436e774b42bSBill Holler if (!on_trap(&otd, OT_DATA_ACCESS)) { 4437e774b42bSBill Holler reg = rdmsr(MSR_AMD_INT_PENDING_CMP_HALT); 4438e774b42bSBill Holler /* Disable C1E state if it is enabled by BIOS */ 4439e774b42bSBill Holler if ((reg >> AMD_ACTONCMPHALT_SHIFT) & 4440e774b42bSBill Holler AMD_ACTONCMPHALT_MASK) { 4441e774b42bSBill Holler reg &= ~(AMD_ACTONCMPHALT_MASK << 4442e774b42bSBill Holler AMD_ACTONCMPHALT_SHIFT); 4443e774b42bSBill Holler wrmsr(MSR_AMD_INT_PENDING_CMP_HALT, reg); 4444e774b42bSBill Holler } 4445e774b42bSBill Holler } 4446e774b42bSBill Holler no_trap(); 4447e774b42bSBill Holler } 4448e774b42bSBill Holler #endif /* !__xpv */ 4449e774b42bSBill Holler } 4450e774b42bSBill Holler 4451cef70d2cSBill Holler /* 44527af88ac7SKuriakose Kuruvilla * Setup necessary registers to enable XSAVE feature on this processor. 44537af88ac7SKuriakose Kuruvilla * This function needs to be called early enough, so that no xsave/xrstor 44547af88ac7SKuriakose Kuruvilla * ops will execute on the processor before the MSRs are properly set up. 44557af88ac7SKuriakose Kuruvilla * 44567af88ac7SKuriakose Kuruvilla * Current implementation has the following assumption: 44577af88ac7SKuriakose Kuruvilla * - cpuid_pass1() is done, so that X86 features are known. 44587af88ac7SKuriakose Kuruvilla * - fpu_probe() is done, so that fp_save_mech is chosen. 44597af88ac7SKuriakose Kuruvilla */ 44607af88ac7SKuriakose Kuruvilla void 44617af88ac7SKuriakose Kuruvilla xsave_setup_msr(cpu_t *cpu) 44627af88ac7SKuriakose Kuruvilla { 44637af88ac7SKuriakose Kuruvilla ASSERT(fp_save_mech == FP_XSAVE); 44647af88ac7SKuriakose Kuruvilla ASSERT(is_x86_feature(x86_featureset, X86FSET_XSAVE)); 44657af88ac7SKuriakose Kuruvilla 44667af88ac7SKuriakose Kuruvilla /* Enable OSXSAVE in CR4. */ 44677af88ac7SKuriakose Kuruvilla setcr4(getcr4() | CR4_OSXSAVE); 44687af88ac7SKuriakose Kuruvilla /* 44697af88ac7SKuriakose Kuruvilla * Update SW copy of ECX, so that /dev/cpu/self/cpuid will report 44707af88ac7SKuriakose Kuruvilla * correct value. 44717af88ac7SKuriakose Kuruvilla */ 44727af88ac7SKuriakose Kuruvilla cpu->cpu_m.mcpu_cpi->cpi_std[1].cp_ecx |= CPUID_INTC_ECX_OSXSAVE; 44737af88ac7SKuriakose Kuruvilla setup_xfem(); 44747af88ac7SKuriakose Kuruvilla } 44757af88ac7SKuriakose Kuruvilla 44767af88ac7SKuriakose Kuruvilla /* 4477cef70d2cSBill Holler * Starting with the Westmere processor the local 4478cef70d2cSBill Holler * APIC timer will continue running in all C-states, 4479cef70d2cSBill Holler * including the deepest C-states. 4480cef70d2cSBill Holler */ 4481cef70d2cSBill Holler int 4482cef70d2cSBill Holler cpuid_arat_supported(void) 4483cef70d2cSBill Holler { 4484cef70d2cSBill Holler struct cpuid_info *cpi; 4485cef70d2cSBill Holler struct cpuid_regs regs; 4486cef70d2cSBill Holler 4487cef70d2cSBill Holler ASSERT(cpuid_checkpass(CPU, 1)); 44887417cfdeSKuriakose Kuruvilla ASSERT(is_x86_feature(x86_featureset, X86FSET_CPUID)); 4489cef70d2cSBill Holler 4490cef70d2cSBill Holler cpi = CPU->cpu_m.mcpu_cpi; 4491cef70d2cSBill Holler 4492cef70d2cSBill Holler switch (cpi->cpi_vendor) { 4493cef70d2cSBill Holler case X86_VENDOR_Intel: 4494cef70d2cSBill Holler /* 4495cef70d2cSBill Holler * Always-running Local APIC Timer is 4496cef70d2cSBill Holler * indicated by CPUID.6.EAX[2]. 4497cef70d2cSBill Holler */ 4498cef70d2cSBill Holler if (cpi->cpi_maxeax >= 6) { 4499cef70d2cSBill Holler regs.cp_eax = 6; 4500cef70d2cSBill Holler (void) cpuid_insn(NULL, ®s); 4501cef70d2cSBill Holler return (regs.cp_eax & CPUID_CSTATE_ARAT); 4502cef70d2cSBill Holler } else { 4503cef70d2cSBill Holler return (0); 4504cef70d2cSBill Holler } 4505cef70d2cSBill Holler default: 4506cef70d2cSBill Holler return (0); 4507cef70d2cSBill Holler } 4508cef70d2cSBill Holler } 4509cef70d2cSBill Holler 4510f21ed392Saubrey.li@intel.com /* 4511f21ed392Saubrey.li@intel.com * Check support for Intel ENERGY_PERF_BIAS feature 4512f21ed392Saubrey.li@intel.com */ 4513f21ed392Saubrey.li@intel.com int 4514f21ed392Saubrey.li@intel.com cpuid_iepb_supported(struct cpu *cp) 4515f21ed392Saubrey.li@intel.com { 4516f21ed392Saubrey.li@intel.com struct cpuid_info *cpi = cp->cpu_m.mcpu_cpi; 4517f21ed392Saubrey.li@intel.com struct cpuid_regs regs; 4518f21ed392Saubrey.li@intel.com 4519f21ed392Saubrey.li@intel.com ASSERT(cpuid_checkpass(cp, 1)); 4520f21ed392Saubrey.li@intel.com 45217417cfdeSKuriakose Kuruvilla if (!(is_x86_feature(x86_featureset, X86FSET_CPUID)) || 45227417cfdeSKuriakose Kuruvilla !(is_x86_feature(x86_featureset, X86FSET_MSR))) { 4523f21ed392Saubrey.li@intel.com return (0); 4524f21ed392Saubrey.li@intel.com } 4525f21ed392Saubrey.li@intel.com 4526f21ed392Saubrey.li@intel.com /* 4527f21ed392Saubrey.li@intel.com * Intel ENERGY_PERF_BIAS MSR is indicated by 4528f21ed392Saubrey.li@intel.com * capability bit CPUID.6.ECX.3 4529f21ed392Saubrey.li@intel.com */ 4530f21ed392Saubrey.li@intel.com if ((cpi->cpi_vendor != X86_VENDOR_Intel) || (cpi->cpi_maxeax < 6)) 4531f21ed392Saubrey.li@intel.com return (0); 4532f21ed392Saubrey.li@intel.com 4533f21ed392Saubrey.li@intel.com regs.cp_eax = 0x6; 4534f21ed392Saubrey.li@intel.com (void) cpuid_insn(NULL, ®s); 4535f21ed392Saubrey.li@intel.com return (regs.cp_ecx & CPUID_EPB_SUPPORT); 4536f21ed392Saubrey.li@intel.com } 4537f21ed392Saubrey.li@intel.com 453841afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* 453941afdfa7SKrishnendu Sadhukhan - Sun Microsystems * Check support for TSC deadline timer 454041afdfa7SKrishnendu Sadhukhan - Sun Microsystems * 454141afdfa7SKrishnendu Sadhukhan - Sun Microsystems * TSC deadline timer provides a superior software programming 454241afdfa7SKrishnendu Sadhukhan - Sun Microsystems * model over local APIC timer that eliminates "time drifts". 454341afdfa7SKrishnendu Sadhukhan - Sun Microsystems * Instead of specifying a relative time, software specifies an 454441afdfa7SKrishnendu Sadhukhan - Sun Microsystems * absolute time as the target at which the processor should 454541afdfa7SKrishnendu Sadhukhan - Sun Microsystems * generate a timer event. 454641afdfa7SKrishnendu Sadhukhan - Sun Microsystems */ 454741afdfa7SKrishnendu Sadhukhan - Sun Microsystems int 454841afdfa7SKrishnendu Sadhukhan - Sun Microsystems cpuid_deadline_tsc_supported(void) 454941afdfa7SKrishnendu Sadhukhan - Sun Microsystems { 455041afdfa7SKrishnendu Sadhukhan - Sun Microsystems struct cpuid_info *cpi = CPU->cpu_m.mcpu_cpi; 455141afdfa7SKrishnendu Sadhukhan - Sun Microsystems struct cpuid_regs regs; 455241afdfa7SKrishnendu Sadhukhan - Sun Microsystems 455341afdfa7SKrishnendu Sadhukhan - Sun Microsystems ASSERT(cpuid_checkpass(CPU, 1)); 455441afdfa7SKrishnendu Sadhukhan - Sun Microsystems ASSERT(is_x86_feature(x86_featureset, X86FSET_CPUID)); 455541afdfa7SKrishnendu Sadhukhan - Sun Microsystems 455641afdfa7SKrishnendu Sadhukhan - Sun Microsystems switch (cpi->cpi_vendor) { 455741afdfa7SKrishnendu Sadhukhan - Sun Microsystems case X86_VENDOR_Intel: 455841afdfa7SKrishnendu Sadhukhan - Sun Microsystems if (cpi->cpi_maxeax >= 1) { 455941afdfa7SKrishnendu Sadhukhan - Sun Microsystems regs.cp_eax = 1; 456041afdfa7SKrishnendu Sadhukhan - Sun Microsystems (void) cpuid_insn(NULL, ®s); 456141afdfa7SKrishnendu Sadhukhan - Sun Microsystems return (regs.cp_ecx & CPUID_DEADLINE_TSC); 456241afdfa7SKrishnendu Sadhukhan - Sun Microsystems } else { 456341afdfa7SKrishnendu Sadhukhan - Sun Microsystems return (0); 456441afdfa7SKrishnendu Sadhukhan - Sun Microsystems } 456541afdfa7SKrishnendu Sadhukhan - Sun Microsystems default: 456641afdfa7SKrishnendu Sadhukhan - Sun Microsystems return (0); 456741afdfa7SKrishnendu Sadhukhan - Sun Microsystems } 456841afdfa7SKrishnendu Sadhukhan - Sun Microsystems } 456941afdfa7SKrishnendu Sadhukhan - Sun Microsystems 457022cc0e45SBill Holler #if defined(__amd64) && !defined(__xpv) 457122cc0e45SBill Holler /* 457222cc0e45SBill Holler * Patch in versions of bcopy for high performance Intel Nhm processors 457322cc0e45SBill Holler * and later... 457422cc0e45SBill Holler */ 457522cc0e45SBill Holler void 457622cc0e45SBill Holler patch_memops(uint_t vendor) 457722cc0e45SBill Holler { 457822cc0e45SBill Holler size_t cnt, i; 457922cc0e45SBill Holler caddr_t to, from; 458022cc0e45SBill Holler 45817417cfdeSKuriakose Kuruvilla if ((vendor == X86_VENDOR_Intel) && 45827417cfdeSKuriakose Kuruvilla is_x86_feature(x86_featureset, X86FSET_SSE4_2)) { 458322cc0e45SBill Holler cnt = &bcopy_patch_end - &bcopy_patch_start; 458422cc0e45SBill Holler to = &bcopy_ck_size; 458522cc0e45SBill Holler from = &bcopy_patch_start; 458622cc0e45SBill Holler for (i = 0; i < cnt; i++) { 458722cc0e45SBill Holler *to++ = *from++; 458822cc0e45SBill Holler } 458922cc0e45SBill Holler } 459022cc0e45SBill Holler } 459122cc0e45SBill Holler #endif /* __amd64 && !__xpv */ 45922d2efdc6SVuong Nguyen 45932d2efdc6SVuong Nguyen /* 45942d2efdc6SVuong Nguyen * This function finds the number of bits to represent the number of cores per 45952d2efdc6SVuong Nguyen * chip and the number of strands per core for the Intel platforms. 45962d2efdc6SVuong Nguyen * It re-uses the x2APIC cpuid code of the cpuid_pass2(). 45972d2efdc6SVuong Nguyen */ 45982d2efdc6SVuong Nguyen void 45992d2efdc6SVuong Nguyen cpuid_get_ext_topo(uint_t vendor, uint_t *core_nbits, uint_t *strand_nbits) 46002d2efdc6SVuong Nguyen { 46012d2efdc6SVuong Nguyen struct cpuid_regs regs; 46022d2efdc6SVuong Nguyen struct cpuid_regs *cp = ®s; 46032d2efdc6SVuong Nguyen 46042d2efdc6SVuong Nguyen if (vendor != X86_VENDOR_Intel) { 46052d2efdc6SVuong Nguyen return; 46062d2efdc6SVuong Nguyen } 46072d2efdc6SVuong Nguyen 46082d2efdc6SVuong Nguyen /* if the cpuid level is 0xB, extended topo is available. */ 46092d2efdc6SVuong Nguyen cp->cp_eax = 0; 46102d2efdc6SVuong Nguyen if (__cpuid_insn(cp) >= 0xB) { 46112d2efdc6SVuong Nguyen 46122d2efdc6SVuong Nguyen cp->cp_eax = 0xB; 46132d2efdc6SVuong Nguyen cp->cp_edx = cp->cp_ebx = cp->cp_ecx = 0; 46142d2efdc6SVuong Nguyen (void) __cpuid_insn(cp); 46152d2efdc6SVuong Nguyen 46162d2efdc6SVuong Nguyen /* 46172d2efdc6SVuong Nguyen * Check CPUID.EAX=0BH, ECX=0H:EBX is non-zero, which 46182d2efdc6SVuong Nguyen * indicates that the extended topology enumeration leaf is 46192d2efdc6SVuong Nguyen * available. 46202d2efdc6SVuong Nguyen */ 46212d2efdc6SVuong Nguyen if (cp->cp_ebx) { 46222d2efdc6SVuong Nguyen uint_t coreid_shift = 0; 46232d2efdc6SVuong Nguyen uint_t chipid_shift = 0; 46242d2efdc6SVuong Nguyen uint_t i; 46252d2efdc6SVuong Nguyen uint_t level; 46262d2efdc6SVuong Nguyen 46272d2efdc6SVuong Nguyen for (i = 0; i < CPI_FNB_ECX_MAX; i++) { 46282d2efdc6SVuong Nguyen cp->cp_eax = 0xB; 46292d2efdc6SVuong Nguyen cp->cp_ecx = i; 46302d2efdc6SVuong Nguyen 46312d2efdc6SVuong Nguyen (void) __cpuid_insn(cp); 46322d2efdc6SVuong Nguyen level = CPI_CPU_LEVEL_TYPE(cp); 46332d2efdc6SVuong Nguyen 46342d2efdc6SVuong Nguyen if (level == 1) { 46352d2efdc6SVuong Nguyen /* 46362d2efdc6SVuong Nguyen * Thread level processor topology 46372d2efdc6SVuong Nguyen * Number of bits shift right APIC ID 46382d2efdc6SVuong Nguyen * to get the coreid. 46392d2efdc6SVuong Nguyen */ 46402d2efdc6SVuong Nguyen coreid_shift = BITX(cp->cp_eax, 4, 0); 46412d2efdc6SVuong Nguyen } else if (level == 2) { 46422d2efdc6SVuong Nguyen /* 46432d2efdc6SVuong Nguyen * Core level processor topology 46442d2efdc6SVuong Nguyen * Number of bits shift right APIC ID 46452d2efdc6SVuong Nguyen * to get the chipid. 46462d2efdc6SVuong Nguyen */ 46472d2efdc6SVuong Nguyen chipid_shift = BITX(cp->cp_eax, 4, 0); 46482d2efdc6SVuong Nguyen } 46492d2efdc6SVuong Nguyen } 46502d2efdc6SVuong Nguyen 46512d2efdc6SVuong Nguyen if (coreid_shift > 0 && chipid_shift > coreid_shift) { 46522d2efdc6SVuong Nguyen *strand_nbits = coreid_shift; 46532d2efdc6SVuong Nguyen *core_nbits = chipid_shift - coreid_shift; 46542d2efdc6SVuong Nguyen } 46552d2efdc6SVuong Nguyen } 46562d2efdc6SVuong Nguyen } 46572d2efdc6SVuong Nguyen } 4658