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. 2479ec9da8SYuri Pankov * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 256eedf6a5SJosef 'Jeff' Sipek * Copyright 2014 Josef "Jeff" Sipek <jeffpc@josefsipek.net> 267c478bd9Sstevel@tonic-gate */ 27cef70d2cSBill Holler /* 2841afdfa7SKrishnendu Sadhukhan - Sun Microsystems * Copyright (c) 2010, Intel Corporation. 29cef70d2cSBill Holler * All rights reserved. 30cef70d2cSBill Holler */ 318031591dSSrihari Venkatesan /* 328031591dSSrihari Venkatesan * Portions Copyright 2009 Advanced Micro Devices, Inc. 338031591dSSrihari Venkatesan */ 34faa20166SBryan Cantrill /* 35263f549eSPatrick Mooney * Copyright 2016 Joyent, Inc. 36faa20166SBryan Cantrill */ 377c478bd9Sstevel@tonic-gate /* 387c478bd9Sstevel@tonic-gate * Various routines to handle identification 397c478bd9Sstevel@tonic-gate * and classification of x86 processors. 407c478bd9Sstevel@tonic-gate */ 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #include <sys/types.h> 437c478bd9Sstevel@tonic-gate #include <sys/archsystm.h> 447c478bd9Sstevel@tonic-gate #include <sys/x86_archext.h> 457c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 467c478bd9Sstevel@tonic-gate #include <sys/systm.h> 477c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 487c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 497c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 507c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 517c478bd9Sstevel@tonic-gate #include <sys/processor.h> 525b8a6efeSbholler #include <sys/sysmacros.h> 53fb2f18f8Sesaxe #include <sys/pg.h> 547c478bd9Sstevel@tonic-gate #include <sys/fp.h> 557c478bd9Sstevel@tonic-gate #include <sys/controlregs.h> 567c478bd9Sstevel@tonic-gate #include <sys/bitmap.h> 57dfea898aSKuriakose Kuruvilla #include <sys/auxv_386.h> 587c478bd9Sstevel@tonic-gate #include <sys/memnode.h> 598031591dSSrihari Venkatesan #include <sys/pci_cfgspace.h> 60263f549eSPatrick Mooney #include <sys/comm_page.h> 61263f549eSPatrick Mooney #include <sys/tsc.h> 627c478bd9Sstevel@tonic-gate 63e4b86885SCheng Sean Ye #ifdef __xpv 64e4b86885SCheng Sean Ye #include <sys/hypervisor.h> 65e774b42bSBill Holler #else 66e774b42bSBill Holler #include <sys/ontrap.h> 67e4b86885SCheng Sean Ye #endif 68e4b86885SCheng Sean Ye 697c478bd9Sstevel@tonic-gate /* 707c478bd9Sstevel@tonic-gate * Pass 0 of cpuid feature analysis happens in locore. It contains special code 717c478bd9Sstevel@tonic-gate * to recognize Cyrix processors that are not cpuid-compliant, and to deal with 727c478bd9Sstevel@tonic-gate * them accordingly. For most modern processors, feature detection occurs here 737c478bd9Sstevel@tonic-gate * in pass 1. 747c478bd9Sstevel@tonic-gate * 757c478bd9Sstevel@tonic-gate * Pass 1 of cpuid feature analysis happens just at the beginning of mlsetup() 767c478bd9Sstevel@tonic-gate * for the boot CPU and does the basic analysis that the early kernel needs. 777417cfdeSKuriakose Kuruvilla * x86_featureset is set based on the return value of cpuid_pass1() of the boot 787c478bd9Sstevel@tonic-gate * CPU. 797c478bd9Sstevel@tonic-gate * 807c478bd9Sstevel@tonic-gate * Pass 1 includes: 817c478bd9Sstevel@tonic-gate * 827c478bd9Sstevel@tonic-gate * o Determining vendor/model/family/stepping and setting x86_type and 837c478bd9Sstevel@tonic-gate * x86_vendor accordingly. 847c478bd9Sstevel@tonic-gate * o Processing the feature flags returned by the cpuid instruction while 857c478bd9Sstevel@tonic-gate * applying any workarounds or tricks for the specific processor. 867c478bd9Sstevel@tonic-gate * o Mapping the feature flags into Solaris feature bits (X86_*). 877c478bd9Sstevel@tonic-gate * o Processing extended feature flags if supported by the processor, 887c478bd9Sstevel@tonic-gate * again while applying specific processor knowledge. 897c478bd9Sstevel@tonic-gate * o Determining the CMT characteristics of the system. 907c478bd9Sstevel@tonic-gate * 917c478bd9Sstevel@tonic-gate * Pass 1 is done on non-boot CPUs during their initialization and the results 927c478bd9Sstevel@tonic-gate * are used only as a meager attempt at ensuring that all processors within the 937c478bd9Sstevel@tonic-gate * system support the same features. 947c478bd9Sstevel@tonic-gate * 957c478bd9Sstevel@tonic-gate * Pass 2 of cpuid feature analysis happens just at the beginning 967c478bd9Sstevel@tonic-gate * of startup(). It just copies in and corrects the remainder 977c478bd9Sstevel@tonic-gate * of the cpuid data we depend on: standard cpuid functions that we didn't 987c478bd9Sstevel@tonic-gate * need for pass1 feature analysis, and extended cpuid functions beyond the 997c478bd9Sstevel@tonic-gate * simple feature processing done in pass1. 1007c478bd9Sstevel@tonic-gate * 1017c478bd9Sstevel@tonic-gate * Pass 3 of cpuid analysis is invoked after basic kernel services; in 1027c478bd9Sstevel@tonic-gate * particular kernel memory allocation has been made available. It creates a 1037c478bd9Sstevel@tonic-gate * readable brand string based on the data collected in the first two passes. 1047c478bd9Sstevel@tonic-gate * 1057c478bd9Sstevel@tonic-gate * Pass 4 of cpuid analysis is invoked after post_startup() when all 1067c478bd9Sstevel@tonic-gate * the support infrastructure for various hardware features has been 1077c478bd9Sstevel@tonic-gate * initialized. It determines which processor features will be reported 1087c478bd9Sstevel@tonic-gate * to userland via the aux vector. 1097c478bd9Sstevel@tonic-gate * 1107c478bd9Sstevel@tonic-gate * All passes are executed on all CPUs, but only the boot CPU determines what 1117c478bd9Sstevel@tonic-gate * features the kernel will use. 1127c478bd9Sstevel@tonic-gate * 1137c478bd9Sstevel@tonic-gate * Much of the worst junk in this file is for the support of processors 1147c478bd9Sstevel@tonic-gate * that didn't really implement the cpuid instruction properly. 1157c478bd9Sstevel@tonic-gate * 1167c478bd9Sstevel@tonic-gate * NOTE: The accessor functions (cpuid_get*) are aware of, and ASSERT upon, 1177c478bd9Sstevel@tonic-gate * the pass numbers. Accordingly, changes to the pass code may require changes 1187c478bd9Sstevel@tonic-gate * to the accessor code. 1197c478bd9Sstevel@tonic-gate */ 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate uint_t x86_vendor = X86_VENDOR_IntelClone; 1227c478bd9Sstevel@tonic-gate uint_t x86_type = X86_TYPE_OTHER; 12386c1f4dcSVikram Hegde uint_t x86_clflush_size = 0; 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate uint_t pentiumpro_bug4046376; 1267c478bd9Sstevel@tonic-gate 127dfea898aSKuriakose Kuruvilla uchar_t x86_featureset[BT_SIZEOFMAP(NUM_X86_FEATURES)]; 1287417cfdeSKuriakose Kuruvilla 129dfea898aSKuriakose Kuruvilla static char *x86_feature_names[NUM_X86_FEATURES] = { 1307417cfdeSKuriakose Kuruvilla "lgpg", 1317417cfdeSKuriakose Kuruvilla "tsc", 1327417cfdeSKuriakose Kuruvilla "msr", 1337417cfdeSKuriakose Kuruvilla "mtrr", 1347417cfdeSKuriakose Kuruvilla "pge", 1357417cfdeSKuriakose Kuruvilla "de", 1367417cfdeSKuriakose Kuruvilla "cmov", 1377417cfdeSKuriakose Kuruvilla "mmx", 1387417cfdeSKuriakose Kuruvilla "mca", 1397417cfdeSKuriakose Kuruvilla "pae", 1407417cfdeSKuriakose Kuruvilla "cv8", 1417417cfdeSKuriakose Kuruvilla "pat", 1427417cfdeSKuriakose Kuruvilla "sep", 1437417cfdeSKuriakose Kuruvilla "sse", 1447417cfdeSKuriakose Kuruvilla "sse2", 1457417cfdeSKuriakose Kuruvilla "htt", 1467417cfdeSKuriakose Kuruvilla "asysc", 1477417cfdeSKuriakose Kuruvilla "nx", 1487417cfdeSKuriakose Kuruvilla "sse3", 1497417cfdeSKuriakose Kuruvilla "cx16", 1507417cfdeSKuriakose Kuruvilla "cmp", 1517417cfdeSKuriakose Kuruvilla "tscp", 1527417cfdeSKuriakose Kuruvilla "mwait", 1537417cfdeSKuriakose Kuruvilla "sse4a", 1547417cfdeSKuriakose Kuruvilla "cpuid", 1557417cfdeSKuriakose Kuruvilla "ssse3", 1567417cfdeSKuriakose Kuruvilla "sse4_1", 1577417cfdeSKuriakose Kuruvilla "sse4_2", 1587417cfdeSKuriakose Kuruvilla "1gpg", 1597417cfdeSKuriakose Kuruvilla "clfsh", 1607417cfdeSKuriakose Kuruvilla "64", 1617417cfdeSKuriakose Kuruvilla "aes", 1627af88ac7SKuriakose Kuruvilla "pclmulqdq", 1637af88ac7SKuriakose Kuruvilla "xsave", 164faa20166SBryan Cantrill "avx", 165faa20166SBryan Cantrill "vmx", 1667660e73fSHans Rosenfeld "svm", 167ebb8ac07SRobert Mustacchi "topoext", 168ebb8ac07SRobert Mustacchi "f16c", 1696eedf6a5SJosef 'Jeff' Sipek "rdrand", 1706eedf6a5SJosef 'Jeff' Sipek "x2apic", 171245ac945SRobert Mustacchi "avx2", 172245ac945SRobert Mustacchi "bmi1", 173245ac945SRobert Mustacchi "bmi2", 174799823bbSRobert Mustacchi "fma", 175a3623a38SRobert Mustacchi "smep", 176a3623a38SRobert Mustacchi "adx", 177a3623a38SRobert Mustacchi "rdseed" 178faa20166SBryan Cantrill }; 1797417cfdeSKuriakose Kuruvilla 1807417cfdeSKuriakose Kuruvilla boolean_t 1817417cfdeSKuriakose Kuruvilla is_x86_feature(void *featureset, uint_t feature) 1827417cfdeSKuriakose Kuruvilla { 1837417cfdeSKuriakose Kuruvilla ASSERT(feature < NUM_X86_FEATURES); 1847417cfdeSKuriakose Kuruvilla return (BT_TEST((ulong_t *)featureset, feature)); 1857417cfdeSKuriakose Kuruvilla } 1867417cfdeSKuriakose Kuruvilla 1877417cfdeSKuriakose Kuruvilla void 1887417cfdeSKuriakose Kuruvilla add_x86_feature(void *featureset, uint_t feature) 1897417cfdeSKuriakose Kuruvilla { 1907417cfdeSKuriakose Kuruvilla ASSERT(feature < NUM_X86_FEATURES); 1917417cfdeSKuriakose Kuruvilla BT_SET((ulong_t *)featureset, feature); 1927417cfdeSKuriakose Kuruvilla } 1937417cfdeSKuriakose Kuruvilla 1947417cfdeSKuriakose Kuruvilla void 1957417cfdeSKuriakose Kuruvilla remove_x86_feature(void *featureset, uint_t feature) 1967417cfdeSKuriakose Kuruvilla { 1977417cfdeSKuriakose Kuruvilla ASSERT(feature < NUM_X86_FEATURES); 1987417cfdeSKuriakose Kuruvilla BT_CLEAR((ulong_t *)featureset, feature); 1997417cfdeSKuriakose Kuruvilla } 2007417cfdeSKuriakose Kuruvilla 2017417cfdeSKuriakose Kuruvilla boolean_t 2027417cfdeSKuriakose Kuruvilla compare_x86_featureset(void *setA, void *setB) 2037417cfdeSKuriakose Kuruvilla { 2047417cfdeSKuriakose Kuruvilla /* 2057417cfdeSKuriakose Kuruvilla * We assume that the unused bits of the bitmap are always zero. 2067417cfdeSKuriakose Kuruvilla */ 2077417cfdeSKuriakose Kuruvilla if (memcmp(setA, setB, BT_SIZEOFMAP(NUM_X86_FEATURES)) == 0) { 2087417cfdeSKuriakose Kuruvilla return (B_TRUE); 2097417cfdeSKuriakose Kuruvilla } else { 2107417cfdeSKuriakose Kuruvilla return (B_FALSE); 2117417cfdeSKuriakose Kuruvilla } 2127417cfdeSKuriakose Kuruvilla } 2137417cfdeSKuriakose Kuruvilla 2147417cfdeSKuriakose Kuruvilla void 2157417cfdeSKuriakose Kuruvilla print_x86_featureset(void *featureset) 2167417cfdeSKuriakose Kuruvilla { 2177417cfdeSKuriakose Kuruvilla uint_t i; 2187417cfdeSKuriakose Kuruvilla 2197417cfdeSKuriakose Kuruvilla for (i = 0; i < NUM_X86_FEATURES; i++) { 2207417cfdeSKuriakose Kuruvilla if (is_x86_feature(featureset, i)) { 2217417cfdeSKuriakose Kuruvilla cmn_err(CE_CONT, "?x86_feature: %s\n", 2227417cfdeSKuriakose Kuruvilla x86_feature_names[i]); 2237417cfdeSKuriakose Kuruvilla } 2247417cfdeSKuriakose Kuruvilla } 2257417cfdeSKuriakose Kuruvilla } 2267417cfdeSKuriakose Kuruvilla 2277af88ac7SKuriakose Kuruvilla static size_t xsave_state_size = 0; 2287af88ac7SKuriakose Kuruvilla uint64_t xsave_bv_all = (XFEATURE_LEGACY_FP | XFEATURE_SSE); 2297af88ac7SKuriakose Kuruvilla boolean_t xsave_force_disable = B_FALSE; 2307af88ac7SKuriakose Kuruvilla 2317997e108SSurya Prakki /* 23279ec9da8SYuri Pankov * This is set to platform type we are running on. 2337997e108SSurya Prakki */ 234349b53ddSStuart Maybee static int platform_type = -1; 235349b53ddSStuart Maybee 236349b53ddSStuart Maybee #if !defined(__xpv) 237349b53ddSStuart Maybee /* 238349b53ddSStuart Maybee * Variable to patch if hypervisor platform detection needs to be 239349b53ddSStuart Maybee * disabled (e.g. platform_type will always be HW_NATIVE if this is 0). 240349b53ddSStuart Maybee */ 241349b53ddSStuart Maybee int enable_platform_detection = 1; 242349b53ddSStuart Maybee #endif 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate /* 245f98fbcecSbholler * monitor/mwait info. 2465b8a6efeSbholler * 2475b8a6efeSbholler * size_actual and buf_actual are the real address and size allocated to get 2485b8a6efeSbholler * proper mwait_buf alignement. buf_actual and size_actual should be passed 2495b8a6efeSbholler * to kmem_free(). Currently kmem_alloc() and mwait happen to both use 2505b8a6efeSbholler * processor cache-line alignment, but this is not guarantied in the furture. 251f98fbcecSbholler */ 252f98fbcecSbholler struct mwait_info { 253f98fbcecSbholler size_t mon_min; /* min size to avoid missed wakeups */ 254f98fbcecSbholler size_t mon_max; /* size to avoid false wakeups */ 2555b8a6efeSbholler size_t size_actual; /* size actually allocated */ 2565b8a6efeSbholler void *buf_actual; /* memory actually allocated */ 257f98fbcecSbholler uint32_t support; /* processor support of monitor/mwait */ 258f98fbcecSbholler }; 259f98fbcecSbholler 260f98fbcecSbholler /* 2617af88ac7SKuriakose Kuruvilla * xsave/xrestor info. 2627af88ac7SKuriakose Kuruvilla * 2637af88ac7SKuriakose Kuruvilla * This structure contains HW feature bits and size of the xsave save area. 2647af88ac7SKuriakose Kuruvilla * Note: the kernel will use the maximum size required for all hardware 2657af88ac7SKuriakose Kuruvilla * features. It is not optimize for potential memory savings if features at 2667af88ac7SKuriakose Kuruvilla * the end of the save area are not enabled. 2677af88ac7SKuriakose Kuruvilla */ 2687af88ac7SKuriakose Kuruvilla struct xsave_info { 2697af88ac7SKuriakose Kuruvilla uint32_t xsav_hw_features_low; /* Supported HW features */ 2707af88ac7SKuriakose Kuruvilla uint32_t xsav_hw_features_high; /* Supported HW features */ 2717af88ac7SKuriakose Kuruvilla size_t xsav_max_size; /* max size save area for HW features */ 2727af88ac7SKuriakose Kuruvilla size_t ymm_size; /* AVX: size of ymm save area */ 2737af88ac7SKuriakose Kuruvilla size_t ymm_offset; /* AVX: offset for ymm save area */ 2747af88ac7SKuriakose Kuruvilla }; 2757af88ac7SKuriakose Kuruvilla 2767af88ac7SKuriakose Kuruvilla 2777af88ac7SKuriakose Kuruvilla /* 2787c478bd9Sstevel@tonic-gate * These constants determine how many of the elements of the 2797c478bd9Sstevel@tonic-gate * cpuid we cache in the cpuid_info data structure; the 2807c478bd9Sstevel@tonic-gate * remaining elements are accessible via the cpuid instruction. 2817c478bd9Sstevel@tonic-gate */ 2827c478bd9Sstevel@tonic-gate 283245ac945SRobert Mustacchi #define NMAX_CPI_STD 8 /* eax = 0 .. 7 */ 2847660e73fSHans Rosenfeld #define NMAX_CPI_EXTD 0x1f /* eax = 0x80000000 .. 0x8000001e */ 2858031591dSSrihari Venkatesan 2868031591dSSrihari Venkatesan /* 2878031591dSSrihari Venkatesan * Some terminology needs to be explained: 2888031591dSSrihari Venkatesan * - Socket: Something that can be plugged into a motherboard. 2898031591dSSrihari Venkatesan * - Package: Same as socket 2908031591dSSrihari Venkatesan * - Chip: Same as socket. Note that AMD's documentation uses term "chip" 2918031591dSSrihari Venkatesan * differently: there, chip is the same as processor node (below) 2928031591dSSrihari Venkatesan * - Processor node: Some AMD processors have more than one 2938031591dSSrihari Venkatesan * "subprocessor" embedded in a package. These subprocessors (nodes) 2948031591dSSrihari Venkatesan * are fully-functional processors themselves with cores, caches, 2958031591dSSrihari Venkatesan * memory controllers, PCI configuration spaces. They are connected 2968031591dSSrihari Venkatesan * inside the package with Hypertransport links. On single-node 2978031591dSSrihari Venkatesan * processors, processor node is equivalent to chip/socket/package. 2987660e73fSHans Rosenfeld * - Compute Unit: Some AMD processors pair cores in "compute units" that 2997660e73fSHans Rosenfeld * share the FPU and the I$ and L2 caches. 3008031591dSSrihari Venkatesan */ 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate struct cpuid_info { 3037c478bd9Sstevel@tonic-gate uint_t cpi_pass; /* last pass completed */ 3047c478bd9Sstevel@tonic-gate /* 3057c478bd9Sstevel@tonic-gate * standard function information 3067c478bd9Sstevel@tonic-gate */ 3077c478bd9Sstevel@tonic-gate uint_t cpi_maxeax; /* fn 0: %eax */ 3087c478bd9Sstevel@tonic-gate char cpi_vendorstr[13]; /* fn 0: %ebx:%ecx:%edx */ 3097c478bd9Sstevel@tonic-gate uint_t cpi_vendor; /* enum of cpi_vendorstr */ 3107c478bd9Sstevel@tonic-gate 3117c478bd9Sstevel@tonic-gate uint_t cpi_family; /* fn 1: extended family */ 3127c478bd9Sstevel@tonic-gate uint_t cpi_model; /* fn 1: extended model */ 3137c478bd9Sstevel@tonic-gate uint_t cpi_step; /* fn 1: stepping */ 3148031591dSSrihari Venkatesan chipid_t cpi_chipid; /* fn 1: %ebx: Intel: chip # */ 3158031591dSSrihari Venkatesan /* AMD: package/socket # */ 3167c478bd9Sstevel@tonic-gate uint_t cpi_brandid; /* fn 1: %ebx: brand ID */ 3177c478bd9Sstevel@tonic-gate int cpi_clogid; /* fn 1: %ebx: thread # */ 3188949bcd6Sandrei uint_t cpi_ncpu_per_chip; /* fn 1: %ebx: logical cpu count */ 3197c478bd9Sstevel@tonic-gate uint8_t cpi_cacheinfo[16]; /* fn 2: intel-style cache desc */ 3207c478bd9Sstevel@tonic-gate uint_t cpi_ncache; /* fn 2: number of elements */ 321d129bde2Sesaxe uint_t cpi_ncpu_shr_last_cache; /* fn 4: %eax: ncpus sharing cache */ 322d129bde2Sesaxe id_t cpi_last_lvl_cacheid; /* fn 4: %eax: derived cache id */ 323d129bde2Sesaxe uint_t cpi_std_4_size; /* fn 4: number of fn 4 elements */ 324d129bde2Sesaxe struct cpuid_regs **cpi_std_4; /* fn 4: %ecx == 0 .. fn4_size */ 325245ac945SRobert Mustacchi struct cpuid_regs cpi_std[NMAX_CPI_STD]; /* 0 .. 7 */ 3267c478bd9Sstevel@tonic-gate /* 3277c478bd9Sstevel@tonic-gate * extended function information 3287c478bd9Sstevel@tonic-gate */ 3297c478bd9Sstevel@tonic-gate uint_t cpi_xmaxeax; /* fn 0x80000000: %eax */ 3307c478bd9Sstevel@tonic-gate char cpi_brandstr[49]; /* fn 0x8000000[234] */ 3317c478bd9Sstevel@tonic-gate uint8_t cpi_pabits; /* fn 0x80000006: %eax */ 3327c478bd9Sstevel@tonic-gate uint8_t cpi_vabits; /* fn 0x80000006: %eax */ 3338031591dSSrihari Venkatesan struct cpuid_regs cpi_extd[NMAX_CPI_EXTD]; /* 0x800000XX */ 3348031591dSSrihari Venkatesan 33510569901Sgavinm id_t cpi_coreid; /* same coreid => strands share core */ 33610569901Sgavinm int cpi_pkgcoreid; /* core number within single package */ 3378949bcd6Sandrei uint_t cpi_ncore_per_chip; /* AMD: fn 0x80000008: %ecx[7-0] */ 3388949bcd6Sandrei /* Intel: fn 4: %eax[31-26] */ 3397c478bd9Sstevel@tonic-gate /* 3407c478bd9Sstevel@tonic-gate * supported feature information 3417c478bd9Sstevel@tonic-gate */ 342245ac945SRobert Mustacchi uint32_t cpi_support[6]; 3437c478bd9Sstevel@tonic-gate #define STD_EDX_FEATURES 0 3447c478bd9Sstevel@tonic-gate #define AMD_EDX_FEATURES 1 3457c478bd9Sstevel@tonic-gate #define TM_EDX_FEATURES 2 3467c478bd9Sstevel@tonic-gate #define STD_ECX_FEATURES 3 347ae115bc7Smrj #define AMD_ECX_FEATURES 4 348245ac945SRobert Mustacchi #define STD_EBX_FEATURES 5 3498a40a695Sgavinm /* 3508a40a695Sgavinm * Synthesized information, where known. 3518a40a695Sgavinm */ 3528a40a695Sgavinm uint32_t cpi_chiprev; /* See X86_CHIPREV_* in x86_archext.h */ 3538a40a695Sgavinm const char *cpi_chiprevstr; /* May be NULL if chiprev unknown */ 3548a40a695Sgavinm uint32_t cpi_socket; /* Chip package/socket type */ 355f98fbcecSbholler 356f98fbcecSbholler struct mwait_info cpi_mwait; /* fn 5: monitor/mwait info */ 357b6917abeSmishra uint32_t cpi_apicid; 3588031591dSSrihari Venkatesan uint_t cpi_procnodeid; /* AMD: nodeID on HT, Intel: chipid */ 3598031591dSSrihari Venkatesan uint_t cpi_procnodes_per_pkg; /* AMD: # of nodes in the package */ 3608031591dSSrihari Venkatesan /* Intel: 1 */ 3617660e73fSHans Rosenfeld uint_t cpi_compunitid; /* AMD: ComputeUnit ID, Intel: coreid */ 3627660e73fSHans Rosenfeld uint_t cpi_cores_per_compunit; /* AMD: # of cores in the ComputeUnit */ 3637af88ac7SKuriakose Kuruvilla 3647af88ac7SKuriakose Kuruvilla struct xsave_info cpi_xsave; /* fn D: xsave/xrestor info */ 3657c478bd9Sstevel@tonic-gate }; 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate static struct cpuid_info cpuid_info0; 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate /* 3717c478bd9Sstevel@tonic-gate * These bit fields are defined by the Intel Application Note AP-485 3727c478bd9Sstevel@tonic-gate * "Intel Processor Identification and the CPUID Instruction" 3737c478bd9Sstevel@tonic-gate */ 3747c478bd9Sstevel@tonic-gate #define CPI_FAMILY_XTD(cpi) BITX((cpi)->cpi_std[1].cp_eax, 27, 20) 3757c478bd9Sstevel@tonic-gate #define CPI_MODEL_XTD(cpi) BITX((cpi)->cpi_std[1].cp_eax, 19, 16) 3767c478bd9Sstevel@tonic-gate #define CPI_TYPE(cpi) BITX((cpi)->cpi_std[1].cp_eax, 13, 12) 3777c478bd9Sstevel@tonic-gate #define CPI_FAMILY(cpi) BITX((cpi)->cpi_std[1].cp_eax, 11, 8) 3787c478bd9Sstevel@tonic-gate #define CPI_STEP(cpi) BITX((cpi)->cpi_std[1].cp_eax, 3, 0) 3797c478bd9Sstevel@tonic-gate #define CPI_MODEL(cpi) BITX((cpi)->cpi_std[1].cp_eax, 7, 4) 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate #define CPI_FEATURES_EDX(cpi) ((cpi)->cpi_std[1].cp_edx) 3827c478bd9Sstevel@tonic-gate #define CPI_FEATURES_ECX(cpi) ((cpi)->cpi_std[1].cp_ecx) 3837c478bd9Sstevel@tonic-gate #define CPI_FEATURES_XTD_EDX(cpi) ((cpi)->cpi_extd[1].cp_edx) 3847c478bd9Sstevel@tonic-gate #define CPI_FEATURES_XTD_ECX(cpi) ((cpi)->cpi_extd[1].cp_ecx) 385245ac945SRobert Mustacchi #define CPI_FEATURES_7_0_EBX(cpi) ((cpi)->cpi_std[7].cp_ebx) 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate #define CPI_BRANDID(cpi) BITX((cpi)->cpi_std[1].cp_ebx, 7, 0) 3887c478bd9Sstevel@tonic-gate #define CPI_CHUNKS(cpi) BITX((cpi)->cpi_std[1].cp_ebx, 15, 7) 3897c478bd9Sstevel@tonic-gate #define CPI_CPU_COUNT(cpi) BITX((cpi)->cpi_std[1].cp_ebx, 23, 16) 3907c478bd9Sstevel@tonic-gate #define CPI_APIC_ID(cpi) BITX((cpi)->cpi_std[1].cp_ebx, 31, 24) 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate #define CPI_MAXEAX_MAX 0x100 /* sanity control */ 3937c478bd9Sstevel@tonic-gate #define CPI_XMAXEAX_MAX 0x80000100 394d129bde2Sesaxe #define CPI_FN4_ECX_MAX 0x20 /* sanity: max fn 4 levels */ 395b6917abeSmishra #define CPI_FNB_ECX_MAX 0x20 /* sanity: max fn B levels */ 396d129bde2Sesaxe 397d129bde2Sesaxe /* 398d129bde2Sesaxe * Function 4 (Deterministic Cache Parameters) macros 399d129bde2Sesaxe * Defined by Intel Application Note AP-485 400d129bde2Sesaxe */ 401d129bde2Sesaxe #define CPI_NUM_CORES(regs) BITX((regs)->cp_eax, 31, 26) 402d129bde2Sesaxe #define CPI_NTHR_SHR_CACHE(regs) BITX((regs)->cp_eax, 25, 14) 403d129bde2Sesaxe #define CPI_FULL_ASSOC_CACHE(regs) BITX((regs)->cp_eax, 9, 9) 404d129bde2Sesaxe #define CPI_SELF_INIT_CACHE(regs) BITX((regs)->cp_eax, 8, 8) 405d129bde2Sesaxe #define CPI_CACHE_LVL(regs) BITX((regs)->cp_eax, 7, 5) 406d129bde2Sesaxe #define CPI_CACHE_TYPE(regs) BITX((regs)->cp_eax, 4, 0) 407b6917abeSmishra #define CPI_CPU_LEVEL_TYPE(regs) BITX((regs)->cp_ecx, 15, 8) 408d129bde2Sesaxe 409d129bde2Sesaxe #define CPI_CACHE_WAYS(regs) BITX((regs)->cp_ebx, 31, 22) 410d129bde2Sesaxe #define CPI_CACHE_PARTS(regs) BITX((regs)->cp_ebx, 21, 12) 411d129bde2Sesaxe #define CPI_CACHE_COH_LN_SZ(regs) BITX((regs)->cp_ebx, 11, 0) 412d129bde2Sesaxe 413d129bde2Sesaxe #define CPI_CACHE_SETS(regs) BITX((regs)->cp_ecx, 31, 0) 414d129bde2Sesaxe 415d129bde2Sesaxe #define CPI_PREFCH_STRIDE(regs) BITX((regs)->cp_edx, 9, 0) 416d129bde2Sesaxe 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate /* 4195ff02082Sdmick * A couple of shorthand macros to identify "later" P6-family chips 4205ff02082Sdmick * like the Pentium M and Core. First, the "older" P6-based stuff 4215ff02082Sdmick * (loosely defined as "pre-Pentium-4"): 4225ff02082Sdmick * P6, PII, Mobile PII, PII Xeon, PIII, Mobile PIII, PIII Xeon 4235ff02082Sdmick */ 4245ff02082Sdmick 4255ff02082Sdmick #define IS_LEGACY_P6(cpi) ( \ 4265ff02082Sdmick cpi->cpi_family == 6 && \ 4275ff02082Sdmick (cpi->cpi_model == 1 || \ 4285ff02082Sdmick cpi->cpi_model == 3 || \ 4295ff02082Sdmick cpi->cpi_model == 5 || \ 4305ff02082Sdmick cpi->cpi_model == 6 || \ 4315ff02082Sdmick cpi->cpi_model == 7 || \ 4325ff02082Sdmick cpi->cpi_model == 8 || \ 4335ff02082Sdmick cpi->cpi_model == 0xA || \ 4345ff02082Sdmick cpi->cpi_model == 0xB) \ 4355ff02082Sdmick ) 4365ff02082Sdmick 4375ff02082Sdmick /* A "new F6" is everything with family 6 that's not the above */ 4385ff02082Sdmick #define IS_NEW_F6(cpi) ((cpi->cpi_family == 6) && !IS_LEGACY_P6(cpi)) 4395ff02082Sdmick 440bf91205bSksadhukh /* Extended family/model support */ 441bf91205bSksadhukh #define IS_EXTENDED_MODEL_INTEL(cpi) (cpi->cpi_family == 0x6 || \ 442bf91205bSksadhukh cpi->cpi_family >= 0xf) 443bf91205bSksadhukh 4445ff02082Sdmick /* 445f98fbcecSbholler * Info for monitor/mwait idle loop. 446f98fbcecSbholler * 447f98fbcecSbholler * See cpuid section of "Intel 64 and IA-32 Architectures Software Developer's 448f98fbcecSbholler * Manual Volume 2A: Instruction Set Reference, A-M" #25366-022US, November 449f98fbcecSbholler * 2006. 450f98fbcecSbholler * See MONITOR/MWAIT section of "AMD64 Architecture Programmer's Manual 451f98fbcecSbholler * Documentation Updates" #33633, Rev 2.05, December 2006. 452f98fbcecSbholler */ 453f98fbcecSbholler #define MWAIT_SUPPORT (0x00000001) /* mwait supported */ 454f98fbcecSbholler #define MWAIT_EXTENSIONS (0x00000002) /* extenstion supported */ 455f98fbcecSbholler #define MWAIT_ECX_INT_ENABLE (0x00000004) /* ecx 1 extension supported */ 456f98fbcecSbholler #define MWAIT_SUPPORTED(cpi) ((cpi)->cpi_std[1].cp_ecx & CPUID_INTC_ECX_MON) 457f98fbcecSbholler #define MWAIT_INT_ENABLE(cpi) ((cpi)->cpi_std[5].cp_ecx & 0x2) 458f98fbcecSbholler #define MWAIT_EXTENSION(cpi) ((cpi)->cpi_std[5].cp_ecx & 0x1) 459f98fbcecSbholler #define MWAIT_SIZE_MIN(cpi) BITX((cpi)->cpi_std[5].cp_eax, 15, 0) 460f98fbcecSbholler #define MWAIT_SIZE_MAX(cpi) BITX((cpi)->cpi_std[5].cp_ebx, 15, 0) 461f98fbcecSbholler /* 462f98fbcecSbholler * Number of sub-cstates for a given c-state. 463f98fbcecSbholler */ 464f98fbcecSbholler #define MWAIT_NUM_SUBC_STATES(cpi, c_state) \ 465f98fbcecSbholler BITX((cpi)->cpi_std[5].cp_edx, c_state + 3, c_state) 466f98fbcecSbholler 4678a40a695Sgavinm /* 4687af88ac7SKuriakose Kuruvilla * XSAVE leaf 0xD enumeration 4697af88ac7SKuriakose Kuruvilla */ 4707af88ac7SKuriakose Kuruvilla #define CPUID_LEAFD_2_YMM_OFFSET 576 4717af88ac7SKuriakose Kuruvilla #define CPUID_LEAFD_2_YMM_SIZE 256 4727af88ac7SKuriakose Kuruvilla 4737af88ac7SKuriakose Kuruvilla /* 474e4b86885SCheng Sean Ye * Functions we consune from cpuid_subr.c; don't publish these in a header 475e4b86885SCheng Sean Ye * file to try and keep people using the expected cpuid_* interfaces. 4768a40a695Sgavinm */ 477e4b86885SCheng Sean Ye extern uint32_t _cpuid_skt(uint_t, uint_t, uint_t, uint_t); 47889e921d5SKuriakose Kuruvilla extern const char *_cpuid_sktstr(uint_t, uint_t, uint_t, uint_t); 479e4b86885SCheng Sean Ye extern uint32_t _cpuid_chiprev(uint_t, uint_t, uint_t, uint_t); 480e4b86885SCheng Sean Ye extern const char *_cpuid_chiprevstr(uint_t, uint_t, uint_t, uint_t); 481e4b86885SCheng Sean Ye extern uint_t _cpuid_vendorstr_to_vendorcode(char *); 4828a40a695Sgavinm 4838a40a695Sgavinm /* 484ae115bc7Smrj * Apply up various platform-dependent restrictions where the 485ae115bc7Smrj * underlying platform restrictions mean the CPU can be marked 486ae115bc7Smrj * as less capable than its cpuid instruction would imply. 487ae115bc7Smrj */ 488843e1988Sjohnlev #if defined(__xpv) 489843e1988Sjohnlev static void 490843e1988Sjohnlev platform_cpuid_mangle(uint_t vendor, uint32_t eax, struct cpuid_regs *cp) 491843e1988Sjohnlev { 492843e1988Sjohnlev switch (eax) { 493e4b86885SCheng Sean Ye case 1: { 494e4b86885SCheng Sean Ye uint32_t mcamask = DOMAIN_IS_INITDOMAIN(xen_info) ? 495e4b86885SCheng Sean Ye 0 : CPUID_INTC_EDX_MCA; 496843e1988Sjohnlev cp->cp_edx &= 497e4b86885SCheng Sean Ye ~(mcamask | 498e4b86885SCheng Sean Ye CPUID_INTC_EDX_PSE | 499843e1988Sjohnlev CPUID_INTC_EDX_VME | CPUID_INTC_EDX_DE | 500843e1988Sjohnlev CPUID_INTC_EDX_SEP | CPUID_INTC_EDX_MTRR | 501843e1988Sjohnlev CPUID_INTC_EDX_PGE | CPUID_INTC_EDX_PAT | 502843e1988Sjohnlev CPUID_AMD_EDX_SYSC | CPUID_INTC_EDX_SEP | 503843e1988Sjohnlev CPUID_INTC_EDX_PSE36 | CPUID_INTC_EDX_HTT); 504843e1988Sjohnlev break; 505e4b86885SCheng Sean Ye } 506ae115bc7Smrj 507843e1988Sjohnlev case 0x80000001: 508843e1988Sjohnlev cp->cp_edx &= 509843e1988Sjohnlev ~(CPUID_AMD_EDX_PSE | 510843e1988Sjohnlev CPUID_INTC_EDX_VME | CPUID_INTC_EDX_DE | 511843e1988Sjohnlev CPUID_AMD_EDX_MTRR | CPUID_AMD_EDX_PGE | 512843e1988Sjohnlev CPUID_AMD_EDX_PAT | CPUID_AMD_EDX_PSE36 | 513843e1988Sjohnlev CPUID_AMD_EDX_SYSC | CPUID_INTC_EDX_SEP | 514843e1988Sjohnlev CPUID_AMD_EDX_TSCP); 515843e1988Sjohnlev cp->cp_ecx &= ~CPUID_AMD_ECX_CMP_LGCY; 516843e1988Sjohnlev break; 517843e1988Sjohnlev default: 518843e1988Sjohnlev break; 519843e1988Sjohnlev } 520843e1988Sjohnlev 521843e1988Sjohnlev switch (vendor) { 522843e1988Sjohnlev case X86_VENDOR_Intel: 523843e1988Sjohnlev switch (eax) { 524843e1988Sjohnlev case 4: 525843e1988Sjohnlev /* 526843e1988Sjohnlev * Zero out the (ncores-per-chip - 1) field 527843e1988Sjohnlev */ 528843e1988Sjohnlev cp->cp_eax &= 0x03fffffff; 529843e1988Sjohnlev break; 530843e1988Sjohnlev default: 531843e1988Sjohnlev break; 532843e1988Sjohnlev } 533843e1988Sjohnlev break; 534843e1988Sjohnlev case X86_VENDOR_AMD: 535843e1988Sjohnlev switch (eax) { 5362ef50f01SJoe Bonasera 5372ef50f01SJoe Bonasera case 0x80000001: 5382ef50f01SJoe Bonasera cp->cp_ecx &= ~CPUID_AMD_ECX_CR8D; 5392ef50f01SJoe Bonasera break; 5402ef50f01SJoe Bonasera 541843e1988Sjohnlev case 0x80000008: 542843e1988Sjohnlev /* 543843e1988Sjohnlev * Zero out the (ncores-per-chip - 1) field 544843e1988Sjohnlev */ 545843e1988Sjohnlev cp->cp_ecx &= 0xffffff00; 546843e1988Sjohnlev break; 547843e1988Sjohnlev default: 548843e1988Sjohnlev break; 549843e1988Sjohnlev } 550843e1988Sjohnlev break; 551843e1988Sjohnlev default: 552843e1988Sjohnlev break; 553843e1988Sjohnlev } 554843e1988Sjohnlev } 555843e1988Sjohnlev #else 556ae115bc7Smrj #define platform_cpuid_mangle(vendor, eax, cp) /* nothing */ 557843e1988Sjohnlev #endif 558ae115bc7Smrj 559ae115bc7Smrj /* 5607c478bd9Sstevel@tonic-gate * Some undocumented ways of patching the results of the cpuid 5617c478bd9Sstevel@tonic-gate * instruction to permit running Solaris 10 on future cpus that 5627c478bd9Sstevel@tonic-gate * we don't currently support. Could be set to non-zero values 5637c478bd9Sstevel@tonic-gate * via settings in eeprom. 5647c478bd9Sstevel@tonic-gate */ 5657c478bd9Sstevel@tonic-gate 5667c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_ecx_include; 5677c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_ecx_exclude; 5687c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_edx_include; 5697c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_edx_exclude; 5707c478bd9Sstevel@tonic-gate 571a3114836SGerry Liu /* 572a3114836SGerry Liu * Allocate space for mcpu_cpi in the machcpu structure for all non-boot CPUs. 573a3114836SGerry Liu */ 574ae115bc7Smrj void 575ae115bc7Smrj cpuid_alloc_space(cpu_t *cpu) 576ae115bc7Smrj { 577ae115bc7Smrj /* 578ae115bc7Smrj * By convention, cpu0 is the boot cpu, which is set up 579ae115bc7Smrj * before memory allocation is available. All other cpus get 580ae115bc7Smrj * their cpuid_info struct allocated here. 581ae115bc7Smrj */ 582ae115bc7Smrj ASSERT(cpu->cpu_id != 0); 583a3114836SGerry Liu ASSERT(cpu->cpu_m.mcpu_cpi == NULL); 584ae115bc7Smrj cpu->cpu_m.mcpu_cpi = 585ae115bc7Smrj kmem_zalloc(sizeof (*cpu->cpu_m.mcpu_cpi), KM_SLEEP); 586ae115bc7Smrj } 587ae115bc7Smrj 588ae115bc7Smrj void 589ae115bc7Smrj cpuid_free_space(cpu_t *cpu) 590ae115bc7Smrj { 591d129bde2Sesaxe struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi; 592d129bde2Sesaxe int i; 593d129bde2Sesaxe 594a3114836SGerry Liu ASSERT(cpi != NULL); 595a3114836SGerry Liu ASSERT(cpi != &cpuid_info0); 596d129bde2Sesaxe 597d129bde2Sesaxe /* 598d129bde2Sesaxe * Free up any function 4 related dynamic storage 599d129bde2Sesaxe */ 600d129bde2Sesaxe for (i = 1; i < cpi->cpi_std_4_size; i++) 601d129bde2Sesaxe kmem_free(cpi->cpi_std_4[i], sizeof (struct cpuid_regs)); 602d129bde2Sesaxe if (cpi->cpi_std_4_size > 0) 603d129bde2Sesaxe kmem_free(cpi->cpi_std_4, 604d129bde2Sesaxe cpi->cpi_std_4_size * sizeof (struct cpuid_regs *)); 605d129bde2Sesaxe 606a3114836SGerry Liu kmem_free(cpi, sizeof (*cpi)); 607a3114836SGerry Liu cpu->cpu_m.mcpu_cpi = NULL; 608ae115bc7Smrj } 609ae115bc7Smrj 610551bc2a6Smrj #if !defined(__xpv) 611cfe84b82SMatt Amdur /* 612cfe84b82SMatt Amdur * Determine the type of the underlying platform. This is used to customize 613cfe84b82SMatt Amdur * initialization of various subsystems (e.g. TSC). determine_platform() must 614cfe84b82SMatt Amdur * only ever be called once to prevent two processors from seeing different 61579ec9da8SYuri Pankov * values of platform_type. Must be called before cpuid_pass1(), the earliest 61679ec9da8SYuri Pankov * consumer to execute (uses _cpuid_chiprev --> synth_amd_info --> get_hwenv). 617cfe84b82SMatt Amdur */ 618cfe84b82SMatt Amdur void 619cfe84b82SMatt Amdur determine_platform(void) 620551bc2a6Smrj { 621551bc2a6Smrj struct cpuid_regs cp; 62279ec9da8SYuri Pankov uint32_t base; 62379ec9da8SYuri Pankov uint32_t regs[4]; 62479ec9da8SYuri Pankov char *hvstr = (char *)regs; 625551bc2a6Smrj 626cfe84b82SMatt Amdur ASSERT(platform_type == -1); 627cfe84b82SMatt Amdur 628349b53ddSStuart Maybee platform_type = HW_NATIVE; 629349b53ddSStuart Maybee 630349b53ddSStuart Maybee if (!enable_platform_detection) 631349b53ddSStuart Maybee return; 632349b53ddSStuart Maybee 633551bc2a6Smrj /* 63479ec9da8SYuri Pankov * If Hypervisor CPUID bit is set, try to determine hypervisor 63579ec9da8SYuri Pankov * vendor signature, and set platform type accordingly. 63679ec9da8SYuri Pankov * 63779ec9da8SYuri Pankov * References: 63879ec9da8SYuri Pankov * http://lkml.org/lkml/2008/10/1/246 63979ec9da8SYuri Pankov * http://kb.vmware.com/kb/1009458 640551bc2a6Smrj */ 64179ec9da8SYuri Pankov cp.cp_eax = 0x1; 642551bc2a6Smrj (void) __cpuid_insn(&cp); 64379ec9da8SYuri Pankov if ((cp.cp_ecx & CPUID_INTC_ECX_HV) != 0) { 64479ec9da8SYuri Pankov cp.cp_eax = 0x40000000; 64579ec9da8SYuri Pankov (void) __cpuid_insn(&cp); 64679ec9da8SYuri Pankov regs[0] = cp.cp_ebx; 64779ec9da8SYuri Pankov regs[1] = cp.cp_ecx; 64879ec9da8SYuri Pankov regs[2] = cp.cp_edx; 64979ec9da8SYuri Pankov regs[3] = 0; 65079ec9da8SYuri Pankov if (strcmp(hvstr, HVSIG_XEN_HVM) == 0) { 651b9bfdccdSStuart Maybee platform_type = HW_XEN_HVM; 6526e5580c9SFrank Van Der Linden return; 653551bc2a6Smrj } 65479ec9da8SYuri Pankov if (strcmp(hvstr, HVSIG_VMWARE) == 0) { 65579ec9da8SYuri Pankov platform_type = HW_VMWARE; 65679ec9da8SYuri Pankov return; 65779ec9da8SYuri Pankov } 65879ec9da8SYuri Pankov if (strcmp(hvstr, HVSIG_KVM) == 0) { 65979ec9da8SYuri Pankov platform_type = HW_KVM; 66079ec9da8SYuri Pankov return; 66179ec9da8SYuri Pankov } 66279ec9da8SYuri Pankov if (strcmp(hvstr, HVSIG_MICROSOFT) == 0) 66379ec9da8SYuri Pankov platform_type = HW_MICROSOFT; 66479ec9da8SYuri Pankov } else { 66579ec9da8SYuri Pankov /* 66679ec9da8SYuri Pankov * Check older VMware hardware versions. VMware hypervisor is 66779ec9da8SYuri Pankov * detected by performing an IN operation to VMware hypervisor 66879ec9da8SYuri Pankov * port and checking that value returned in %ebx is VMware 66979ec9da8SYuri Pankov * hypervisor magic value. 67079ec9da8SYuri Pankov * 67179ec9da8SYuri Pankov * References: http://kb.vmware.com/kb/1009458 67279ec9da8SYuri Pankov */ 67379ec9da8SYuri Pankov vmware_port(VMWARE_HVCMD_GETVERSION, regs); 67479ec9da8SYuri Pankov if (regs[1] == VMWARE_HVMAGIC) { 67579ec9da8SYuri Pankov platform_type = HW_VMWARE; 67679ec9da8SYuri Pankov return; 67779ec9da8SYuri Pankov } 678b9bfdccdSStuart Maybee } 679b9bfdccdSStuart Maybee 68079ec9da8SYuri Pankov /* 68179ec9da8SYuri Pankov * Check Xen hypervisor. In a fully virtualized domain, 68279ec9da8SYuri Pankov * Xen's pseudo-cpuid function returns a string representing the 68379ec9da8SYuri Pankov * Xen signature in %ebx, %ecx, and %edx. %eax contains the maximum 68479ec9da8SYuri Pankov * supported cpuid function. We need at least a (base + 2) leaf value 68579ec9da8SYuri Pankov * to do what we want to do. Try different base values, since the 68679ec9da8SYuri Pankov * hypervisor might use a different one depending on whether Hyper-V 68779ec9da8SYuri Pankov * emulation is switched on by default or not. 68879ec9da8SYuri Pankov */ 68979ec9da8SYuri Pankov for (base = 0x40000000; base < 0x40010000; base += 0x100) { 69079ec9da8SYuri Pankov cp.cp_eax = base; 69179ec9da8SYuri Pankov (void) __cpuid_insn(&cp); 69279ec9da8SYuri Pankov regs[0] = cp.cp_ebx; 69379ec9da8SYuri Pankov regs[1] = cp.cp_ecx; 69479ec9da8SYuri Pankov regs[2] = cp.cp_edx; 69579ec9da8SYuri Pankov regs[3] = 0; 69679ec9da8SYuri Pankov if (strcmp(hvstr, HVSIG_XEN_HVM) == 0 && 69779ec9da8SYuri Pankov cp.cp_eax >= (base + 2)) { 69879ec9da8SYuri Pankov platform_type &= ~HW_NATIVE; 69979ec9da8SYuri Pankov platform_type |= HW_XEN_HVM; 70079ec9da8SYuri Pankov return; 70179ec9da8SYuri Pankov } 70279ec9da8SYuri Pankov } 7036e5580c9SFrank Van Der Linden } 7046e5580c9SFrank Van Der Linden 705b9bfdccdSStuart Maybee int 706b9bfdccdSStuart Maybee get_hwenv(void) 707b9bfdccdSStuart Maybee { 708cfe84b82SMatt Amdur ASSERT(platform_type != -1); 709b9bfdccdSStuart Maybee return (platform_type); 710b9bfdccdSStuart Maybee } 711b9bfdccdSStuart Maybee 712b9bfdccdSStuart Maybee int 713b9bfdccdSStuart Maybee is_controldom(void) 714b9bfdccdSStuart Maybee { 715b9bfdccdSStuart Maybee return (0); 716b9bfdccdSStuart Maybee } 717b9bfdccdSStuart Maybee 718b9bfdccdSStuart Maybee #else 719b9bfdccdSStuart Maybee 720b9bfdccdSStuart Maybee int 721b9bfdccdSStuart Maybee get_hwenv(void) 722b9bfdccdSStuart Maybee { 723b9bfdccdSStuart Maybee return (HW_XEN_PV); 724b9bfdccdSStuart Maybee } 725b9bfdccdSStuart Maybee 726b9bfdccdSStuart Maybee int 727b9bfdccdSStuart Maybee is_controldom(void) 728b9bfdccdSStuart Maybee { 729b9bfdccdSStuart Maybee return (DOMAIN_IS_INITDOMAIN(xen_info)); 730b9bfdccdSStuart Maybee } 731b9bfdccdSStuart Maybee 732551bc2a6Smrj #endif /* __xpv */ 733551bc2a6Smrj 7348031591dSSrihari Venkatesan static void 7357417cfdeSKuriakose Kuruvilla cpuid_intel_getids(cpu_t *cpu, void *feature) 7368031591dSSrihari Venkatesan { 7378031591dSSrihari Venkatesan uint_t i; 7388031591dSSrihari Venkatesan uint_t chipid_shift = 0; 7398031591dSSrihari Venkatesan uint_t coreid_shift = 0; 7408031591dSSrihari Venkatesan struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi; 7418031591dSSrihari Venkatesan 7428031591dSSrihari Venkatesan for (i = 1; i < cpi->cpi_ncpu_per_chip; i <<= 1) 7438031591dSSrihari Venkatesan chipid_shift++; 7448031591dSSrihari Venkatesan 7458031591dSSrihari Venkatesan cpi->cpi_chipid = cpi->cpi_apicid >> chipid_shift; 7468031591dSSrihari Venkatesan cpi->cpi_clogid = cpi->cpi_apicid & ((1 << chipid_shift) - 1); 7478031591dSSrihari Venkatesan 7487417cfdeSKuriakose Kuruvilla if (is_x86_feature(feature, X86FSET_CMP)) { 7498031591dSSrihari Venkatesan /* 7508031591dSSrihari Venkatesan * Multi-core (and possibly multi-threaded) 7518031591dSSrihari Venkatesan * processors. 7528031591dSSrihari Venkatesan */ 7538031591dSSrihari Venkatesan uint_t ncpu_per_core; 7548031591dSSrihari Venkatesan if (cpi->cpi_ncore_per_chip == 1) 7558031591dSSrihari Venkatesan ncpu_per_core = cpi->cpi_ncpu_per_chip; 7568031591dSSrihari Venkatesan else if (cpi->cpi_ncore_per_chip > 1) 7578031591dSSrihari Venkatesan ncpu_per_core = cpi->cpi_ncpu_per_chip / 7588031591dSSrihari Venkatesan cpi->cpi_ncore_per_chip; 7598031591dSSrihari Venkatesan /* 7608031591dSSrihari Venkatesan * 8bit APIC IDs on dual core Pentiums 7618031591dSSrihari Venkatesan * look like this: 7628031591dSSrihari Venkatesan * 7638031591dSSrihari Venkatesan * +-----------------------+------+------+ 7648031591dSSrihari Venkatesan * | Physical Package ID | MC | HT | 7658031591dSSrihari Venkatesan * +-----------------------+------+------+ 7668031591dSSrihari Venkatesan * <------- chipid --------> 7678031591dSSrihari Venkatesan * <------- coreid ---------------> 7688031591dSSrihari Venkatesan * <--- clogid --> 7698031591dSSrihari Venkatesan * <------> 7708031591dSSrihari Venkatesan * pkgcoreid 7718031591dSSrihari Venkatesan * 7728031591dSSrihari Venkatesan * Where the number of bits necessary to 7738031591dSSrihari Venkatesan * represent MC and HT fields together equals 7748031591dSSrihari Venkatesan * to the minimum number of bits necessary to 7758031591dSSrihari Venkatesan * store the value of cpi->cpi_ncpu_per_chip. 7768031591dSSrihari Venkatesan * Of those bits, the MC part uses the number 7778031591dSSrihari Venkatesan * of bits necessary to store the value of 7788031591dSSrihari Venkatesan * cpi->cpi_ncore_per_chip. 7798031591dSSrihari Venkatesan */ 7808031591dSSrihari Venkatesan for (i = 1; i < ncpu_per_core; i <<= 1) 7818031591dSSrihari Venkatesan coreid_shift++; 7828031591dSSrihari Venkatesan cpi->cpi_coreid = cpi->cpi_apicid >> coreid_shift; 7838031591dSSrihari Venkatesan cpi->cpi_pkgcoreid = cpi->cpi_clogid >> coreid_shift; 7847417cfdeSKuriakose Kuruvilla } else if (is_x86_feature(feature, X86FSET_HTT)) { 7858031591dSSrihari Venkatesan /* 7868031591dSSrihari Venkatesan * Single-core multi-threaded processors. 7878031591dSSrihari Venkatesan */ 7888031591dSSrihari Venkatesan cpi->cpi_coreid = cpi->cpi_chipid; 7898031591dSSrihari Venkatesan cpi->cpi_pkgcoreid = 0; 7908031591dSSrihari Venkatesan } 7918031591dSSrihari Venkatesan cpi->cpi_procnodeid = cpi->cpi_chipid; 7927660e73fSHans Rosenfeld cpi->cpi_compunitid = cpi->cpi_coreid; 7938031591dSSrihari Venkatesan } 7948031591dSSrihari Venkatesan 7958031591dSSrihari Venkatesan static void 7968031591dSSrihari Venkatesan cpuid_amd_getids(cpu_t *cpu) 7978031591dSSrihari Venkatesan { 7981fbe4a4fSSrihari Venkatesan int i, first_half, coreidsz; 7998031591dSSrihari Venkatesan uint32_t nb_caps_reg; 8008031591dSSrihari Venkatesan uint_t node2_1; 8018031591dSSrihari Venkatesan struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi; 8027660e73fSHans Rosenfeld struct cpuid_regs *cp; 8038031591dSSrihari Venkatesan 8048031591dSSrihari Venkatesan /* 8058031591dSSrihari Venkatesan * AMD CMP chips currently have a single thread per core. 8068031591dSSrihari Venkatesan * 8078031591dSSrihari Venkatesan * Since no two cpus share a core we must assign a distinct coreid 8088031591dSSrihari Venkatesan * per cpu, and we do this by using the cpu_id. This scheme does not, 8098031591dSSrihari Venkatesan * however, guarantee that sibling cores of a chip will have sequential 8108031591dSSrihari Venkatesan * coreids starting at a multiple of the number of cores per chip - 8118031591dSSrihari Venkatesan * that is usually the case, but if the ACPI MADT table is presented 8128031591dSSrihari Venkatesan * in a different order then we need to perform a few more gymnastics 8138031591dSSrihari Venkatesan * for the pkgcoreid. 8148031591dSSrihari Venkatesan * 8158031591dSSrihari Venkatesan * All processors in the system have the same number of enabled 8168031591dSSrihari Venkatesan * cores. Cores within a processor are always numbered sequentially 8178031591dSSrihari Venkatesan * from 0 regardless of how many or which are disabled, and there 8188031591dSSrihari Venkatesan * is no way for operating system to discover the real core id when some 8198031591dSSrihari Venkatesan * are disabled. 8207660e73fSHans Rosenfeld * 8217660e73fSHans Rosenfeld * In family 0x15, the cores come in pairs called compute units. They 8227660e73fSHans Rosenfeld * share I$ and L2 caches and the FPU. Enumeration of this feature is 8237660e73fSHans Rosenfeld * simplified by the new topology extensions CPUID leaf, indicated by 8247660e73fSHans Rosenfeld * the X86 feature X86FSET_TOPOEXT. 8258031591dSSrihari Venkatesan */ 8268031591dSSrihari Venkatesan 8278031591dSSrihari Venkatesan cpi->cpi_coreid = cpu->cpu_id; 8287660e73fSHans Rosenfeld cpi->cpi_compunitid = cpu->cpu_id; 8298031591dSSrihari Venkatesan 8308031591dSSrihari Venkatesan if (cpi->cpi_xmaxeax >= 0x80000008) { 8318031591dSSrihari Venkatesan 8328031591dSSrihari Venkatesan coreidsz = BITX((cpi)->cpi_extd[8].cp_ecx, 15, 12); 8338031591dSSrihari Venkatesan 8348031591dSSrihari Venkatesan /* 8358031591dSSrihari Venkatesan * In AMD parlance chip is really a node while Solaris 8368031591dSSrihari Venkatesan * sees chip as equivalent to socket/package. 8378031591dSSrihari Venkatesan */ 8388031591dSSrihari Venkatesan cpi->cpi_ncore_per_chip = 8398031591dSSrihari Venkatesan BITX((cpi)->cpi_extd[8].cp_ecx, 7, 0) + 1; 8401fbe4a4fSSrihari Venkatesan if (coreidsz == 0) { 8418031591dSSrihari Venkatesan /* Use legacy method */ 8421fbe4a4fSSrihari Venkatesan for (i = 1; i < cpi->cpi_ncore_per_chip; i <<= 1) 8431fbe4a4fSSrihari Venkatesan coreidsz++; 8441fbe4a4fSSrihari Venkatesan if (coreidsz == 0) 8451fbe4a4fSSrihari Venkatesan coreidsz = 1; 8461fbe4a4fSSrihari Venkatesan } 8478031591dSSrihari Venkatesan } else { 8488031591dSSrihari Venkatesan /* Assume single-core part */ 8491fbe4a4fSSrihari Venkatesan cpi->cpi_ncore_per_chip = 1; 85072b70389SJakub Jermar coreidsz = 1; 8518031591dSSrihari Venkatesan } 8528031591dSSrihari Venkatesan 8531fbe4a4fSSrihari Venkatesan cpi->cpi_clogid = cpi->cpi_pkgcoreid = 8541fbe4a4fSSrihari Venkatesan cpi->cpi_apicid & ((1<<coreidsz) - 1); 8558031591dSSrihari Venkatesan cpi->cpi_ncpu_per_chip = cpi->cpi_ncore_per_chip; 8568031591dSSrihari Venkatesan 8577660e73fSHans Rosenfeld /* Get node ID, compute unit ID */ 8587660e73fSHans Rosenfeld if (is_x86_feature(x86_featureset, X86FSET_TOPOEXT) && 8597660e73fSHans Rosenfeld cpi->cpi_xmaxeax >= 0x8000001e) { 8607660e73fSHans Rosenfeld cp = &cpi->cpi_extd[0x1e]; 8617660e73fSHans Rosenfeld cp->cp_eax = 0x8000001e; 8627660e73fSHans Rosenfeld (void) __cpuid_insn(cp); 8637660e73fSHans Rosenfeld 8647660e73fSHans Rosenfeld cpi->cpi_procnodes_per_pkg = BITX(cp->cp_ecx, 10, 8) + 1; 8657660e73fSHans Rosenfeld cpi->cpi_procnodeid = BITX(cp->cp_ecx, 7, 0); 8667660e73fSHans Rosenfeld cpi->cpi_cores_per_compunit = BITX(cp->cp_ebx, 15, 8) + 1; 8677660e73fSHans Rosenfeld cpi->cpi_compunitid = BITX(cp->cp_ebx, 7, 0) 8687660e73fSHans Rosenfeld + (cpi->cpi_ncore_per_chip / cpi->cpi_cores_per_compunit) 8697660e73fSHans Rosenfeld * (cpi->cpi_procnodeid / cpi->cpi_procnodes_per_pkg); 8707660e73fSHans Rosenfeld } else if (cpi->cpi_family == 0xf || cpi->cpi_family >= 0x11) { 8711fbe4a4fSSrihari Venkatesan cpi->cpi_procnodeid = (cpi->cpi_apicid >> coreidsz) & 7; 8728031591dSSrihari Venkatesan } else if (cpi->cpi_family == 0x10) { 8738031591dSSrihari Venkatesan /* 8748031591dSSrihari Venkatesan * See if we are a multi-node processor. 8758031591dSSrihari Venkatesan * All processors in the system have the same number of nodes 8768031591dSSrihari Venkatesan */ 8778031591dSSrihari Venkatesan nb_caps_reg = pci_getl_func(0, 24, 3, 0xe8); 8788031591dSSrihari Venkatesan if ((cpi->cpi_model < 8) || BITX(nb_caps_reg, 29, 29) == 0) { 8798031591dSSrihari Venkatesan /* Single-node */ 8801fbe4a4fSSrihari Venkatesan cpi->cpi_procnodeid = BITX(cpi->cpi_apicid, 5, 8811fbe4a4fSSrihari Venkatesan coreidsz); 8828031591dSSrihari Venkatesan } else { 8838031591dSSrihari Venkatesan 8848031591dSSrihari Venkatesan /* 8858031591dSSrihari Venkatesan * Multi-node revision D (2 nodes per package 8868031591dSSrihari Venkatesan * are supported) 8878031591dSSrihari Venkatesan */ 8888031591dSSrihari Venkatesan cpi->cpi_procnodes_per_pkg = 2; 8898031591dSSrihari Venkatesan 8908031591dSSrihari Venkatesan first_half = (cpi->cpi_pkgcoreid <= 8918031591dSSrihari Venkatesan (cpi->cpi_ncore_per_chip/2 - 1)); 8928031591dSSrihari Venkatesan 8938031591dSSrihari Venkatesan if (cpi->cpi_apicid == cpi->cpi_pkgcoreid) { 8948031591dSSrihari Venkatesan /* We are BSP */ 8958031591dSSrihari Venkatesan cpi->cpi_procnodeid = (first_half ? 0 : 1); 8968031591dSSrihari Venkatesan } else { 8978031591dSSrihari Venkatesan 8988031591dSSrihari Venkatesan /* We are AP */ 8998031591dSSrihari Venkatesan /* NodeId[2:1] bits to use for reading F3xe8 */ 9008031591dSSrihari Venkatesan node2_1 = BITX(cpi->cpi_apicid, 5, 4) << 1; 9018031591dSSrihari Venkatesan 9028031591dSSrihari Venkatesan nb_caps_reg = 9038031591dSSrihari Venkatesan pci_getl_func(0, 24 + node2_1, 3, 0xe8); 9048031591dSSrihari Venkatesan 9058031591dSSrihari Venkatesan /* 9068031591dSSrihari Venkatesan * Check IntNodeNum bit (31:30, but bit 31 is 9078031591dSSrihari Venkatesan * always 0 on dual-node processors) 9088031591dSSrihari Venkatesan */ 9098031591dSSrihari Venkatesan if (BITX(nb_caps_reg, 30, 30) == 0) 9108031591dSSrihari Venkatesan cpi->cpi_procnodeid = node2_1 + 9118031591dSSrihari Venkatesan !first_half; 9128031591dSSrihari Venkatesan else 9138031591dSSrihari Venkatesan cpi->cpi_procnodeid = node2_1 + 9148031591dSSrihari Venkatesan first_half; 9158031591dSSrihari Venkatesan } 9168031591dSSrihari Venkatesan } 9178031591dSSrihari Venkatesan } else { 9188031591dSSrihari Venkatesan cpi->cpi_procnodeid = 0; 9198031591dSSrihari Venkatesan } 9207660e73fSHans Rosenfeld 9217660e73fSHans Rosenfeld cpi->cpi_chipid = 9227660e73fSHans Rosenfeld cpi->cpi_procnodeid / cpi->cpi_procnodes_per_pkg; 9238031591dSSrihari Venkatesan } 9248031591dSSrihari Venkatesan 9257af88ac7SKuriakose Kuruvilla /* 9267af88ac7SKuriakose Kuruvilla * Setup XFeature_Enabled_Mask register. Required by xsave feature. 9277af88ac7SKuriakose Kuruvilla */ 9287af88ac7SKuriakose Kuruvilla void 9297af88ac7SKuriakose Kuruvilla setup_xfem(void) 9307af88ac7SKuriakose Kuruvilla { 9317af88ac7SKuriakose Kuruvilla uint64_t flags = XFEATURE_LEGACY_FP; 9327af88ac7SKuriakose Kuruvilla 9337af88ac7SKuriakose Kuruvilla ASSERT(is_x86_feature(x86_featureset, X86FSET_XSAVE)); 9347af88ac7SKuriakose Kuruvilla 9357af88ac7SKuriakose Kuruvilla if (is_x86_feature(x86_featureset, X86FSET_SSE)) 9367af88ac7SKuriakose Kuruvilla flags |= XFEATURE_SSE; 9377af88ac7SKuriakose Kuruvilla 9387af88ac7SKuriakose Kuruvilla if (is_x86_feature(x86_featureset, X86FSET_AVX)) 9397af88ac7SKuriakose Kuruvilla flags |= XFEATURE_AVX; 9407af88ac7SKuriakose Kuruvilla 9417af88ac7SKuriakose Kuruvilla set_xcr(XFEATURE_ENABLED_MASK, flags); 9427af88ac7SKuriakose Kuruvilla 9437af88ac7SKuriakose Kuruvilla xsave_bv_all = flags; 9447af88ac7SKuriakose Kuruvilla } 9457af88ac7SKuriakose Kuruvilla 946dfea898aSKuriakose Kuruvilla void 947dfea898aSKuriakose Kuruvilla cpuid_pass1(cpu_t *cpu, uchar_t *featureset) 9487c478bd9Sstevel@tonic-gate { 9497c478bd9Sstevel@tonic-gate uint32_t mask_ecx, mask_edx; 9507c478bd9Sstevel@tonic-gate struct cpuid_info *cpi; 9518949bcd6Sandrei struct cpuid_regs *cp; 9527c478bd9Sstevel@tonic-gate int xcpuid; 953843e1988Sjohnlev #if !defined(__xpv) 9545b8a6efeSbholler extern int idle_cpu_prefer_mwait; 955843e1988Sjohnlev #endif 956ae115bc7Smrj 9577c478bd9Sstevel@tonic-gate /* 958a3114836SGerry Liu * Space statically allocated for BSP, ensure pointer is set 9597c478bd9Sstevel@tonic-gate */ 9607417cfdeSKuriakose Kuruvilla if (cpu->cpu_id == 0) { 9617417cfdeSKuriakose Kuruvilla if (cpu->cpu_m.mcpu_cpi == NULL) 962ae115bc7Smrj cpu->cpu_m.mcpu_cpi = &cpuid_info0; 9637417cfdeSKuriakose Kuruvilla } 9647417cfdeSKuriakose Kuruvilla 9657417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_CPUID); 9667417cfdeSKuriakose Kuruvilla 967ae115bc7Smrj cpi = cpu->cpu_m.mcpu_cpi; 968ae115bc7Smrj ASSERT(cpi != NULL); 9697c478bd9Sstevel@tonic-gate cp = &cpi->cpi_std[0]; 9708949bcd6Sandrei cp->cp_eax = 0; 9718949bcd6Sandrei cpi->cpi_maxeax = __cpuid_insn(cp); 9727c478bd9Sstevel@tonic-gate { 9737c478bd9Sstevel@tonic-gate uint32_t *iptr = (uint32_t *)cpi->cpi_vendorstr; 9747c478bd9Sstevel@tonic-gate *iptr++ = cp->cp_ebx; 9757c478bd9Sstevel@tonic-gate *iptr++ = cp->cp_edx; 9767c478bd9Sstevel@tonic-gate *iptr++ = cp->cp_ecx; 9777c478bd9Sstevel@tonic-gate *(char *)&cpi->cpi_vendorstr[12] = '\0'; 9787c478bd9Sstevel@tonic-gate } 9797c478bd9Sstevel@tonic-gate 980e4b86885SCheng Sean Ye cpi->cpi_vendor = _cpuid_vendorstr_to_vendorcode(cpi->cpi_vendorstr); 9817c478bd9Sstevel@tonic-gate x86_vendor = cpi->cpi_vendor; /* for compatibility */ 9827c478bd9Sstevel@tonic-gate 9837c478bd9Sstevel@tonic-gate /* 9847c478bd9Sstevel@tonic-gate * Limit the range in case of weird hardware 9857c478bd9Sstevel@tonic-gate */ 9867c478bd9Sstevel@tonic-gate if (cpi->cpi_maxeax > CPI_MAXEAX_MAX) 9877c478bd9Sstevel@tonic-gate cpi->cpi_maxeax = CPI_MAXEAX_MAX; 9887c478bd9Sstevel@tonic-gate if (cpi->cpi_maxeax < 1) 9897c478bd9Sstevel@tonic-gate goto pass1_done; 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate cp = &cpi->cpi_std[1]; 9928949bcd6Sandrei cp->cp_eax = 1; 9938949bcd6Sandrei (void) __cpuid_insn(cp); 9947c478bd9Sstevel@tonic-gate 9957c478bd9Sstevel@tonic-gate /* 9967c478bd9Sstevel@tonic-gate * Extract identifying constants for easy access. 9977c478bd9Sstevel@tonic-gate */ 9987c478bd9Sstevel@tonic-gate cpi->cpi_model = CPI_MODEL(cpi); 9997c478bd9Sstevel@tonic-gate cpi->cpi_family = CPI_FAMILY(cpi); 10007c478bd9Sstevel@tonic-gate 10015ff02082Sdmick if (cpi->cpi_family == 0xf) 10027c478bd9Sstevel@tonic-gate cpi->cpi_family += CPI_FAMILY_XTD(cpi); 10035ff02082Sdmick 100468c91426Sdmick /* 1005875b116eSkchow * Beware: AMD uses "extended model" iff base *FAMILY* == 0xf. 100668c91426Sdmick * Intel, and presumably everyone else, uses model == 0xf, as 100768c91426Sdmick * one would expect (max value means possible overflow). Sigh. 100868c91426Sdmick */ 100968c91426Sdmick 101068c91426Sdmick switch (cpi->cpi_vendor) { 1011bf91205bSksadhukh case X86_VENDOR_Intel: 1012bf91205bSksadhukh if (IS_EXTENDED_MODEL_INTEL(cpi)) 1013bf91205bSksadhukh cpi->cpi_model += CPI_MODEL_XTD(cpi) << 4; 1014447af253Sksadhukh break; 101568c91426Sdmick case X86_VENDOR_AMD: 1016875b116eSkchow if (CPI_FAMILY(cpi) == 0xf) 101768c91426Sdmick cpi->cpi_model += CPI_MODEL_XTD(cpi) << 4; 101868c91426Sdmick break; 101968c91426Sdmick default: 10205ff02082Sdmick if (cpi->cpi_model == 0xf) 10217c478bd9Sstevel@tonic-gate cpi->cpi_model += CPI_MODEL_XTD(cpi) << 4; 102268c91426Sdmick break; 102368c91426Sdmick } 10247c478bd9Sstevel@tonic-gate 10257c478bd9Sstevel@tonic-gate cpi->cpi_step = CPI_STEP(cpi); 10267c478bd9Sstevel@tonic-gate cpi->cpi_brandid = CPI_BRANDID(cpi); 10277c478bd9Sstevel@tonic-gate 10287c478bd9Sstevel@tonic-gate /* 10297c478bd9Sstevel@tonic-gate * *default* assumptions: 10307c478bd9Sstevel@tonic-gate * - believe %edx feature word 10317c478bd9Sstevel@tonic-gate * - ignore %ecx feature word 10327c478bd9Sstevel@tonic-gate * - 32-bit virtual and physical addressing 10337c478bd9Sstevel@tonic-gate */ 10347c478bd9Sstevel@tonic-gate mask_edx = 0xffffffff; 10357c478bd9Sstevel@tonic-gate mask_ecx = 0; 10367c478bd9Sstevel@tonic-gate 10377c478bd9Sstevel@tonic-gate cpi->cpi_pabits = cpi->cpi_vabits = 32; 10387c478bd9Sstevel@tonic-gate 10397c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 10407c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 10417c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 5) 10427c478bd9Sstevel@tonic-gate x86_type = X86_TYPE_P5; 10435ff02082Sdmick else if (IS_LEGACY_P6(cpi)) { 10447c478bd9Sstevel@tonic-gate x86_type = X86_TYPE_P6; 10457c478bd9Sstevel@tonic-gate pentiumpro_bug4046376 = 1; 10467c478bd9Sstevel@tonic-gate /* 10477c478bd9Sstevel@tonic-gate * Clear the SEP bit when it was set erroneously 10487c478bd9Sstevel@tonic-gate */ 10497c478bd9Sstevel@tonic-gate if (cpi->cpi_model < 3 && cpi->cpi_step < 3) 10507c478bd9Sstevel@tonic-gate cp->cp_edx &= ~CPUID_INTC_EDX_SEP; 10515ff02082Sdmick } else if (IS_NEW_F6(cpi) || cpi->cpi_family == 0xf) { 10527c478bd9Sstevel@tonic-gate x86_type = X86_TYPE_P4; 10537c478bd9Sstevel@tonic-gate /* 10547c478bd9Sstevel@tonic-gate * We don't currently depend on any of the %ecx 10557c478bd9Sstevel@tonic-gate * features until Prescott, so we'll only check 10567c478bd9Sstevel@tonic-gate * this from P4 onwards. We might want to revisit 10577c478bd9Sstevel@tonic-gate * that idea later. 10587c478bd9Sstevel@tonic-gate */ 10597c478bd9Sstevel@tonic-gate mask_ecx = 0xffffffff; 10607c478bd9Sstevel@tonic-gate } else if (cpi->cpi_family > 0xf) 10617c478bd9Sstevel@tonic-gate mask_ecx = 0xffffffff; 10627c622d23Sbholler /* 10637c622d23Sbholler * We don't support MONITOR/MWAIT if leaf 5 is not available 10647c622d23Sbholler * to obtain the monitor linesize. 10657c622d23Sbholler */ 10667c622d23Sbholler if (cpi->cpi_maxeax < 5) 10677c622d23Sbholler mask_ecx &= ~CPUID_INTC_ECX_MON; 10687c478bd9Sstevel@tonic-gate break; 10697c478bd9Sstevel@tonic-gate case X86_VENDOR_IntelClone: 10707c478bd9Sstevel@tonic-gate default: 10717c478bd9Sstevel@tonic-gate break; 10727c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 10737c478bd9Sstevel@tonic-gate #if defined(OPTERON_ERRATUM_108) 10747c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 0xf && cpi->cpi_model == 0xe) { 10757c478bd9Sstevel@tonic-gate cp->cp_eax = (0xf0f & cp->cp_eax) | 0xc0; 10767c478bd9Sstevel@tonic-gate cpi->cpi_model = 0xc; 10777c478bd9Sstevel@tonic-gate } else 10787c478bd9Sstevel@tonic-gate #endif 10797c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 5) { 10807c478bd9Sstevel@tonic-gate /* 10817c478bd9Sstevel@tonic-gate * AMD K5 and K6 10827c478bd9Sstevel@tonic-gate * 10837c478bd9Sstevel@tonic-gate * These CPUs have an incomplete implementation 10847c478bd9Sstevel@tonic-gate * of MCA/MCE which we mask away. 10857c478bd9Sstevel@tonic-gate */ 10868949bcd6Sandrei mask_edx &= ~(CPUID_INTC_EDX_MCE | CPUID_INTC_EDX_MCA); 10878949bcd6Sandrei 10887c478bd9Sstevel@tonic-gate /* 10897c478bd9Sstevel@tonic-gate * Model 0 uses the wrong (APIC) bit 10907c478bd9Sstevel@tonic-gate * to indicate PGE. Fix it here. 10917c478bd9Sstevel@tonic-gate */ 10928949bcd6Sandrei if (cpi->cpi_model == 0) { 10937c478bd9Sstevel@tonic-gate if (cp->cp_edx & 0x200) { 10947c478bd9Sstevel@tonic-gate cp->cp_edx &= ~0x200; 10957c478bd9Sstevel@tonic-gate cp->cp_edx |= CPUID_INTC_EDX_PGE; 10967c478bd9Sstevel@tonic-gate } 10977c478bd9Sstevel@tonic-gate } 10988949bcd6Sandrei 10998949bcd6Sandrei /* 11008949bcd6Sandrei * Early models had problems w/ MMX; disable. 11018949bcd6Sandrei */ 11028949bcd6Sandrei if (cpi->cpi_model < 6) 11038949bcd6Sandrei mask_edx &= ~CPUID_INTC_EDX_MMX; 11048949bcd6Sandrei } 11058949bcd6Sandrei 11068949bcd6Sandrei /* 11078949bcd6Sandrei * For newer families, SSE3 and CX16, at least, are valid; 11088949bcd6Sandrei * enable all 11098949bcd6Sandrei */ 11108949bcd6Sandrei if (cpi->cpi_family >= 0xf) 11118949bcd6Sandrei mask_ecx = 0xffffffff; 11127c622d23Sbholler /* 11137c622d23Sbholler * We don't support MONITOR/MWAIT if leaf 5 is not available 11147c622d23Sbholler * to obtain the monitor linesize. 11157c622d23Sbholler */ 11167c622d23Sbholler if (cpi->cpi_maxeax < 5) 11177c622d23Sbholler mask_ecx &= ~CPUID_INTC_ECX_MON; 11185b8a6efeSbholler 1119843e1988Sjohnlev #if !defined(__xpv) 11205b8a6efeSbholler /* 11215b8a6efeSbholler * Do not use MONITOR/MWAIT to halt in the idle loop on any AMD 11225b8a6efeSbholler * processors. AMD does not intend MWAIT to be used in the cpu 11235b8a6efeSbholler * idle loop on current and future processors. 10h and future 11245b8a6efeSbholler * AMD processors use more power in MWAIT than HLT. 11255b8a6efeSbholler * Pre-family-10h Opterons do not have the MWAIT instruction. 11265b8a6efeSbholler */ 11275b8a6efeSbholler idle_cpu_prefer_mwait = 0; 1128843e1988Sjohnlev #endif 11295b8a6efeSbholler 11307c478bd9Sstevel@tonic-gate break; 11317c478bd9Sstevel@tonic-gate case X86_VENDOR_TM: 11327c478bd9Sstevel@tonic-gate /* 11337c478bd9Sstevel@tonic-gate * workaround the NT workaround in CMS 4.1 11347c478bd9Sstevel@tonic-gate */ 11357c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 5 && cpi->cpi_model == 4 && 11367c478bd9Sstevel@tonic-gate (cpi->cpi_step == 2 || cpi->cpi_step == 3)) 11377c478bd9Sstevel@tonic-gate cp->cp_edx |= CPUID_INTC_EDX_CX8; 11387c478bd9Sstevel@tonic-gate break; 11397c478bd9Sstevel@tonic-gate case X86_VENDOR_Centaur: 11407c478bd9Sstevel@tonic-gate /* 11417c478bd9Sstevel@tonic-gate * workaround the NT workarounds again 11427c478bd9Sstevel@tonic-gate */ 11437c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 6) 11447c478bd9Sstevel@tonic-gate cp->cp_edx |= CPUID_INTC_EDX_CX8; 11457c478bd9Sstevel@tonic-gate break; 11467c478bd9Sstevel@tonic-gate case X86_VENDOR_Cyrix: 11477c478bd9Sstevel@tonic-gate /* 11487c478bd9Sstevel@tonic-gate * We rely heavily on the probing in locore 11497c478bd9Sstevel@tonic-gate * to actually figure out what parts, if any, 11507c478bd9Sstevel@tonic-gate * of the Cyrix cpuid instruction to believe. 11517c478bd9Sstevel@tonic-gate */ 11527c478bd9Sstevel@tonic-gate switch (x86_type) { 11537c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_486: 11547c478bd9Sstevel@tonic-gate mask_edx = 0; 11557c478bd9Sstevel@tonic-gate break; 11567c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_6x86: 11577c478bd9Sstevel@tonic-gate mask_edx = 0; 11587c478bd9Sstevel@tonic-gate break; 11597c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_6x86L: 11607c478bd9Sstevel@tonic-gate mask_edx = 11617c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_DE | 11627c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_CX8; 11637c478bd9Sstevel@tonic-gate break; 11647c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_6x86MX: 11657c478bd9Sstevel@tonic-gate mask_edx = 11667c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_DE | 11677c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_MSR | 11687c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_CX8 | 11697c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_PGE | 11707c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_CMOV | 11717c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_MMX; 11727c478bd9Sstevel@tonic-gate break; 11737c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_GXm: 11747c478bd9Sstevel@tonic-gate mask_edx = 11757c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_MSR | 11767c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_CX8 | 11777c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_CMOV | 11787c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_MMX; 11797c478bd9Sstevel@tonic-gate break; 11807c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_MediaGX: 11817c478bd9Sstevel@tonic-gate break; 11827c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_MII: 11837c478bd9Sstevel@tonic-gate case X86_TYPE_VIA_CYRIX_III: 11847c478bd9Sstevel@tonic-gate mask_edx = 11857c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_DE | 11867c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_TSC | 11877c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_MSR | 11887c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_CX8 | 11897c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_PGE | 11907c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_CMOV | 11917c478bd9Sstevel@tonic-gate CPUID_INTC_EDX_MMX; 11927c478bd9Sstevel@tonic-gate break; 11937c478bd9Sstevel@tonic-gate default: 11947c478bd9Sstevel@tonic-gate break; 11957c478bd9Sstevel@tonic-gate } 11967c478bd9Sstevel@tonic-gate break; 11977c478bd9Sstevel@tonic-gate } 11987c478bd9Sstevel@tonic-gate 1199843e1988Sjohnlev #if defined(__xpv) 1200843e1988Sjohnlev /* 1201843e1988Sjohnlev * Do not support MONITOR/MWAIT under a hypervisor 1202843e1988Sjohnlev */ 1203843e1988Sjohnlev mask_ecx &= ~CPUID_INTC_ECX_MON; 12047af88ac7SKuriakose Kuruvilla /* 12057af88ac7SKuriakose Kuruvilla * Do not support XSAVE under a hypervisor for now 12067af88ac7SKuriakose Kuruvilla */ 12077af88ac7SKuriakose Kuruvilla xsave_force_disable = B_TRUE; 12087af88ac7SKuriakose Kuruvilla 1209843e1988Sjohnlev #endif /* __xpv */ 1210843e1988Sjohnlev 12117af88ac7SKuriakose Kuruvilla if (xsave_force_disable) { 12127af88ac7SKuriakose Kuruvilla mask_ecx &= ~CPUID_INTC_ECX_XSAVE; 12137af88ac7SKuriakose Kuruvilla mask_ecx &= ~CPUID_INTC_ECX_AVX; 1214ebb8ac07SRobert Mustacchi mask_ecx &= ~CPUID_INTC_ECX_F16C; 1215245ac945SRobert Mustacchi mask_ecx &= ~CPUID_INTC_ECX_FMA; 12167af88ac7SKuriakose Kuruvilla } 12177af88ac7SKuriakose Kuruvilla 12187c478bd9Sstevel@tonic-gate /* 12197c478bd9Sstevel@tonic-gate * Now we've figured out the masks that determine 12207c478bd9Sstevel@tonic-gate * which bits we choose to believe, apply the masks 12217c478bd9Sstevel@tonic-gate * to the feature words, then map the kernel's view 12227c478bd9Sstevel@tonic-gate * of these feature words into its feature word. 12237c478bd9Sstevel@tonic-gate */ 12247c478bd9Sstevel@tonic-gate cp->cp_edx &= mask_edx; 12257c478bd9Sstevel@tonic-gate cp->cp_ecx &= mask_ecx; 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate /* 1228ae115bc7Smrj * apply any platform restrictions (we don't call this 1229ae115bc7Smrj * immediately after __cpuid_insn here, because we need the 1230ae115bc7Smrj * workarounds applied above first) 12317c478bd9Sstevel@tonic-gate */ 1232ae115bc7Smrj platform_cpuid_mangle(cpi->cpi_vendor, 1, cp); 12337c478bd9Sstevel@tonic-gate 1234ae115bc7Smrj /* 1235245ac945SRobert Mustacchi * In addition to ecx and edx, Intel is storing a bunch of instruction 1236245ac945SRobert Mustacchi * set extensions in leaf 7's ebx. 1237245ac945SRobert Mustacchi */ 1238245ac945SRobert Mustacchi if (cpi->cpi_vendor == X86_VENDOR_Intel && cpi->cpi_maxeax >= 7) { 1239245ac945SRobert Mustacchi struct cpuid_regs *ecp; 1240245ac945SRobert Mustacchi ecp = &cpi->cpi_std[7]; 1241245ac945SRobert Mustacchi ecp->cp_eax = 7; 1242245ac945SRobert Mustacchi ecp->cp_ecx = 0; 1243245ac945SRobert Mustacchi (void) __cpuid_insn(ecp); 1244245ac945SRobert Mustacchi /* 1245245ac945SRobert Mustacchi * If XSAVE has been disabled, just ignore all of the AVX 1246245ac945SRobert Mustacchi * dependent flags here. 1247245ac945SRobert Mustacchi */ 1248245ac945SRobert Mustacchi if (xsave_force_disable) { 1249245ac945SRobert Mustacchi ecp->cp_ebx &= ~CPUID_INTC_EBX_7_0_BMI1; 1250245ac945SRobert Mustacchi ecp->cp_ebx &= ~CPUID_INTC_EBX_7_0_BMI2; 1251245ac945SRobert Mustacchi ecp->cp_ebx &= ~CPUID_INTC_EBX_7_0_AVX2; 1252245ac945SRobert Mustacchi } 1253799823bbSRobert Mustacchi 1254799823bbSRobert Mustacchi if (ecp->cp_ebx & CPUID_INTC_EBX_7_0_SMEP) 1255799823bbSRobert Mustacchi add_x86_feature(featureset, X86FSET_SMEP); 1256a3623a38SRobert Mustacchi 1257a3623a38SRobert Mustacchi if (ecp->cp_ebx & CPUID_INTC_EBX_7_0_RDSEED) 1258a3623a38SRobert Mustacchi add_x86_feature(featureset, X86FSET_RDSEED); 1259a3623a38SRobert Mustacchi 1260a3623a38SRobert Mustacchi if (ecp->cp_ebx & CPUID_INTC_EBX_7_0_ADX) 1261a3623a38SRobert Mustacchi add_x86_feature(featureset, X86FSET_ADX); 1262245ac945SRobert Mustacchi } 1263245ac945SRobert Mustacchi 1264245ac945SRobert Mustacchi /* 1265ae115bc7Smrj * fold in overrides from the "eeprom" mechanism 1266ae115bc7Smrj */ 12677c478bd9Sstevel@tonic-gate cp->cp_edx |= cpuid_feature_edx_include; 12687c478bd9Sstevel@tonic-gate cp->cp_edx &= ~cpuid_feature_edx_exclude; 12697c478bd9Sstevel@tonic-gate 12707c478bd9Sstevel@tonic-gate cp->cp_ecx |= cpuid_feature_ecx_include; 12717c478bd9Sstevel@tonic-gate cp->cp_ecx &= ~cpuid_feature_ecx_exclude; 12727c478bd9Sstevel@tonic-gate 12737417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_PSE) { 12747417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_LARGEPAGE); 12757417cfdeSKuriakose Kuruvilla } 12767417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_TSC) { 12777417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_TSC); 12787417cfdeSKuriakose Kuruvilla } 12797417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_MSR) { 12807417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_MSR); 12817417cfdeSKuriakose Kuruvilla } 12827417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_MTRR) { 12837417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_MTRR); 12847417cfdeSKuriakose Kuruvilla } 12857417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_PGE) { 12867417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_PGE); 12877417cfdeSKuriakose Kuruvilla } 12887417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_CMOV) { 12897417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_CMOV); 12907417cfdeSKuriakose Kuruvilla } 12917417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_MMX) { 12927417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_MMX); 12937417cfdeSKuriakose Kuruvilla } 12947c478bd9Sstevel@tonic-gate if ((cp->cp_edx & CPUID_INTC_EDX_MCE) != 0 && 12957417cfdeSKuriakose Kuruvilla (cp->cp_edx & CPUID_INTC_EDX_MCA) != 0) { 12967417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_MCA); 12977417cfdeSKuriakose Kuruvilla } 12987417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_PAE) { 12997417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_PAE); 13007417cfdeSKuriakose Kuruvilla } 13017417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_CX8) { 13027417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_CX8); 13037417cfdeSKuriakose Kuruvilla } 13047417cfdeSKuriakose Kuruvilla if (cp->cp_ecx & CPUID_INTC_ECX_CX16) { 13057417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_CX16); 13067417cfdeSKuriakose Kuruvilla } 13077417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_PAT) { 13087417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_PAT); 13097417cfdeSKuriakose Kuruvilla } 13107417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_SEP) { 13117417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_SEP); 13127417cfdeSKuriakose Kuruvilla } 13137c478bd9Sstevel@tonic-gate if (cp->cp_edx & CPUID_INTC_EDX_FXSR) { 13147c478bd9Sstevel@tonic-gate /* 13157c478bd9Sstevel@tonic-gate * In our implementation, fxsave/fxrstor 13167c478bd9Sstevel@tonic-gate * are prerequisites before we'll even 13177c478bd9Sstevel@tonic-gate * try and do SSE things. 13187c478bd9Sstevel@tonic-gate */ 13197417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_SSE) { 13207417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_SSE); 13217417cfdeSKuriakose Kuruvilla } 13227417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_SSE2) { 13237417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_SSE2); 13247417cfdeSKuriakose Kuruvilla } 13257417cfdeSKuriakose Kuruvilla if (cp->cp_ecx & CPUID_INTC_ECX_SSE3) { 13267417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_SSE3); 13277417cfdeSKuriakose Kuruvilla } 13287417cfdeSKuriakose Kuruvilla if (cp->cp_ecx & CPUID_INTC_ECX_SSSE3) { 13297417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_SSSE3); 13307417cfdeSKuriakose Kuruvilla } 13317417cfdeSKuriakose Kuruvilla if (cp->cp_ecx & CPUID_INTC_ECX_SSE4_1) { 13327417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_SSE4_1); 13337417cfdeSKuriakose Kuruvilla } 13347417cfdeSKuriakose Kuruvilla if (cp->cp_ecx & CPUID_INTC_ECX_SSE4_2) { 13357417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_SSE4_2); 13367417cfdeSKuriakose Kuruvilla } 13377417cfdeSKuriakose Kuruvilla if (cp->cp_ecx & CPUID_INTC_ECX_AES) { 13387417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_AES); 13397417cfdeSKuriakose Kuruvilla } 13407417cfdeSKuriakose Kuruvilla if (cp->cp_ecx & CPUID_INTC_ECX_PCLMULQDQ) { 13417417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_PCLMULQDQ); 1342d0f8ff6eSkk208521 } 13437af88ac7SKuriakose Kuruvilla 13447af88ac7SKuriakose Kuruvilla if (cp->cp_ecx & CPUID_INTC_ECX_XSAVE) { 13457af88ac7SKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_XSAVE); 1346ebb8ac07SRobert Mustacchi 13477af88ac7SKuriakose Kuruvilla /* We only test AVX when there is XSAVE */ 13487af88ac7SKuriakose Kuruvilla if (cp->cp_ecx & CPUID_INTC_ECX_AVX) { 13497af88ac7SKuriakose Kuruvilla add_x86_feature(featureset, 13507af88ac7SKuriakose Kuruvilla X86FSET_AVX); 1351ebb8ac07SRobert Mustacchi 1352245ac945SRobert Mustacchi /* 1353245ac945SRobert Mustacchi * Intel says we can't check these without also 1354245ac945SRobert Mustacchi * checking AVX. 1355245ac945SRobert Mustacchi */ 1356ebb8ac07SRobert Mustacchi if (cp->cp_ecx & CPUID_INTC_ECX_F16C) 1357ebb8ac07SRobert Mustacchi add_x86_feature(featureset, 1358ebb8ac07SRobert Mustacchi X86FSET_F16C); 1359245ac945SRobert Mustacchi 1360245ac945SRobert Mustacchi if (cp->cp_ecx & CPUID_INTC_ECX_FMA) 1361245ac945SRobert Mustacchi add_x86_feature(featureset, 1362245ac945SRobert Mustacchi X86FSET_FMA); 1363245ac945SRobert Mustacchi 1364245ac945SRobert Mustacchi if (cpi->cpi_std[7].cp_ebx & 1365245ac945SRobert Mustacchi CPUID_INTC_EBX_7_0_BMI1) 1366245ac945SRobert Mustacchi add_x86_feature(featureset, 1367245ac945SRobert Mustacchi X86FSET_BMI1); 1368245ac945SRobert Mustacchi 1369245ac945SRobert Mustacchi if (cpi->cpi_std[7].cp_ebx & 1370245ac945SRobert Mustacchi CPUID_INTC_EBX_7_0_BMI2) 1371245ac945SRobert Mustacchi add_x86_feature(featureset, 1372245ac945SRobert Mustacchi X86FSET_BMI2); 1373245ac945SRobert Mustacchi 1374245ac945SRobert Mustacchi if (cpi->cpi_std[7].cp_ebx & 1375245ac945SRobert Mustacchi CPUID_INTC_EBX_7_0_AVX2) 1376245ac945SRobert Mustacchi add_x86_feature(featureset, 1377245ac945SRobert Mustacchi X86FSET_AVX2); 13787af88ac7SKuriakose Kuruvilla } 13797af88ac7SKuriakose Kuruvilla } 13807c478bd9Sstevel@tonic-gate } 13816eedf6a5SJosef 'Jeff' Sipek if (cp->cp_ecx & CPUID_INTC_ECX_X2APIC) { 13826eedf6a5SJosef 'Jeff' Sipek add_x86_feature(featureset, X86FSET_X2APIC); 13836eedf6a5SJosef 'Jeff' Sipek } 13847417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_INTC_EDX_DE) { 13857417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_DE); 13867417cfdeSKuriakose Kuruvilla } 13871d1a3942SBill Holler #if !defined(__xpv) 1388f98fbcecSbholler if (cp->cp_ecx & CPUID_INTC_ECX_MON) { 13891d1a3942SBill Holler 13901d1a3942SBill Holler /* 13911d1a3942SBill Holler * We require the CLFLUSH instruction for erratum workaround 13921d1a3942SBill Holler * to use MONITOR/MWAIT. 13931d1a3942SBill Holler */ 13941d1a3942SBill Holler if (cp->cp_edx & CPUID_INTC_EDX_CLFSH) { 1395f98fbcecSbholler cpi->cpi_mwait.support |= MWAIT_SUPPORT; 13967417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_MWAIT); 13971d1a3942SBill Holler } else { 13981d1a3942SBill Holler extern int idle_cpu_assert_cflush_monitor; 13991d1a3942SBill Holler 14001d1a3942SBill Holler /* 14011d1a3942SBill Holler * All processors we are aware of which have 14021d1a3942SBill Holler * MONITOR/MWAIT also have CLFLUSH. 14031d1a3942SBill Holler */ 14041d1a3942SBill Holler if (idle_cpu_assert_cflush_monitor) { 14051d1a3942SBill Holler ASSERT((cp->cp_ecx & CPUID_INTC_ECX_MON) && 14061d1a3942SBill Holler (cp->cp_edx & CPUID_INTC_EDX_CLFSH)); 1407f98fbcecSbholler } 14081d1a3942SBill Holler } 14091d1a3942SBill Holler } 14101d1a3942SBill Holler #endif /* __xpv */ 14117c478bd9Sstevel@tonic-gate 1412faa20166SBryan Cantrill if (cp->cp_ecx & CPUID_INTC_ECX_VMX) { 1413faa20166SBryan Cantrill add_x86_feature(featureset, X86FSET_VMX); 1414faa20166SBryan Cantrill } 1415faa20166SBryan Cantrill 1416ebb8ac07SRobert Mustacchi if (cp->cp_ecx & CPUID_INTC_ECX_RDRAND) 1417ebb8ac07SRobert Mustacchi add_x86_feature(featureset, X86FSET_RDRAND); 1418ebb8ac07SRobert Mustacchi 141986c1f4dcSVikram Hegde /* 1420faa20166SBryan Cantrill * Only need it first time, rest of the cpus would follow suit. 142186c1f4dcSVikram Hegde * we only capture this for the bootcpu. 142286c1f4dcSVikram Hegde */ 142386c1f4dcSVikram Hegde if (cp->cp_edx & CPUID_INTC_EDX_CLFSH) { 14247417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_CLFSH); 142586c1f4dcSVikram Hegde x86_clflush_size = (BITX(cp->cp_ebx, 15, 8) * 8); 142686c1f4dcSVikram Hegde } 14277417cfdeSKuriakose Kuruvilla if (is_x86_feature(featureset, X86FSET_PAE)) 14287c478bd9Sstevel@tonic-gate cpi->cpi_pabits = 36; 14297c478bd9Sstevel@tonic-gate 14307c478bd9Sstevel@tonic-gate /* 14317c478bd9Sstevel@tonic-gate * Hyperthreading configuration is slightly tricky on Intel 14327c478bd9Sstevel@tonic-gate * and pure clones, and even trickier on AMD. 14337c478bd9Sstevel@tonic-gate * 14347c478bd9Sstevel@tonic-gate * (AMD chose to set the HTT bit on their CMP processors, 14357c478bd9Sstevel@tonic-gate * even though they're not actually hyperthreaded. Thus it 14367c478bd9Sstevel@tonic-gate * takes a bit more work to figure out what's really going 1437ae115bc7Smrj * on ... see the handling of the CMP_LGCY bit below) 14387c478bd9Sstevel@tonic-gate */ 14397c478bd9Sstevel@tonic-gate if (cp->cp_edx & CPUID_INTC_EDX_HTT) { 14407c478bd9Sstevel@tonic-gate cpi->cpi_ncpu_per_chip = CPI_CPU_COUNT(cpi); 14417c478bd9Sstevel@tonic-gate if (cpi->cpi_ncpu_per_chip > 1) 14427417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_HTT); 14438949bcd6Sandrei } else { 14448949bcd6Sandrei cpi->cpi_ncpu_per_chip = 1; 14457c478bd9Sstevel@tonic-gate } 14467c478bd9Sstevel@tonic-gate 14477c478bd9Sstevel@tonic-gate /* 14487c478bd9Sstevel@tonic-gate * Work on the "extended" feature information, doing 14497c478bd9Sstevel@tonic-gate * some basic initialization for cpuid_pass2() 14507c478bd9Sstevel@tonic-gate */ 14517c478bd9Sstevel@tonic-gate xcpuid = 0; 14527c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 14537c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 14545ff02082Sdmick if (IS_NEW_F6(cpi) || cpi->cpi_family >= 0xf) 14557c478bd9Sstevel@tonic-gate xcpuid++; 14567c478bd9Sstevel@tonic-gate break; 14577c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 14587c478bd9Sstevel@tonic-gate if (cpi->cpi_family > 5 || 14597c478bd9Sstevel@tonic-gate (cpi->cpi_family == 5 && cpi->cpi_model >= 1)) 14607c478bd9Sstevel@tonic-gate xcpuid++; 14617c478bd9Sstevel@tonic-gate break; 14627c478bd9Sstevel@tonic-gate case X86_VENDOR_Cyrix: 14637c478bd9Sstevel@tonic-gate /* 14647c478bd9Sstevel@tonic-gate * Only these Cyrix CPUs are -known- to support 14657c478bd9Sstevel@tonic-gate * extended cpuid operations. 14667c478bd9Sstevel@tonic-gate */ 14677c478bd9Sstevel@tonic-gate if (x86_type == X86_TYPE_VIA_CYRIX_III || 14687c478bd9Sstevel@tonic-gate x86_type == X86_TYPE_CYRIX_GXm) 14697c478bd9Sstevel@tonic-gate xcpuid++; 14707c478bd9Sstevel@tonic-gate break; 14717c478bd9Sstevel@tonic-gate case X86_VENDOR_Centaur: 14727c478bd9Sstevel@tonic-gate case X86_VENDOR_TM: 14737c478bd9Sstevel@tonic-gate default: 14747c478bd9Sstevel@tonic-gate xcpuid++; 14757c478bd9Sstevel@tonic-gate break; 14767c478bd9Sstevel@tonic-gate } 14777c478bd9Sstevel@tonic-gate 14787c478bd9Sstevel@tonic-gate if (xcpuid) { 14797c478bd9Sstevel@tonic-gate cp = &cpi->cpi_extd[0]; 14808949bcd6Sandrei cp->cp_eax = 0x80000000; 14818949bcd6Sandrei cpi->cpi_xmaxeax = __cpuid_insn(cp); 14827c478bd9Sstevel@tonic-gate } 14837c478bd9Sstevel@tonic-gate 14847c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax & 0x80000000) { 14857c478bd9Sstevel@tonic-gate 14867c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax > CPI_XMAXEAX_MAX) 14877c478bd9Sstevel@tonic-gate cpi->cpi_xmaxeax = CPI_XMAXEAX_MAX; 14887c478bd9Sstevel@tonic-gate 14897c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 14907c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 14917c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 14927c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax < 0x80000001) 14937c478bd9Sstevel@tonic-gate break; 14947c478bd9Sstevel@tonic-gate cp = &cpi->cpi_extd[1]; 14958949bcd6Sandrei cp->cp_eax = 0x80000001; 14968949bcd6Sandrei (void) __cpuid_insn(cp); 1497ae115bc7Smrj 14987c478bd9Sstevel@tonic-gate if (cpi->cpi_vendor == X86_VENDOR_AMD && 14997c478bd9Sstevel@tonic-gate cpi->cpi_family == 5 && 15007c478bd9Sstevel@tonic-gate cpi->cpi_model == 6 && 15017c478bd9Sstevel@tonic-gate cpi->cpi_step == 6) { 15027c478bd9Sstevel@tonic-gate /* 15037c478bd9Sstevel@tonic-gate * K6 model 6 uses bit 10 to indicate SYSC 15047c478bd9Sstevel@tonic-gate * Later models use bit 11. Fix it here. 15057c478bd9Sstevel@tonic-gate */ 15067c478bd9Sstevel@tonic-gate if (cp->cp_edx & 0x400) { 15077c478bd9Sstevel@tonic-gate cp->cp_edx &= ~0x400; 15087c478bd9Sstevel@tonic-gate cp->cp_edx |= CPUID_AMD_EDX_SYSC; 15097c478bd9Sstevel@tonic-gate } 15107c478bd9Sstevel@tonic-gate } 15117c478bd9Sstevel@tonic-gate 1512ae115bc7Smrj platform_cpuid_mangle(cpi->cpi_vendor, 0x80000001, cp); 1513ae115bc7Smrj 15147c478bd9Sstevel@tonic-gate /* 15157c478bd9Sstevel@tonic-gate * Compute the additions to the kernel's feature word. 15167c478bd9Sstevel@tonic-gate */ 15177417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_AMD_EDX_NX) { 15187417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_NX); 15197417cfdeSKuriakose Kuruvilla } 15207c478bd9Sstevel@tonic-gate 152119397407SSherry Moore /* 152219397407SSherry Moore * Regardless whether or not we boot 64-bit, 152319397407SSherry Moore * we should have a way to identify whether 152419397407SSherry Moore * the CPU is capable of running 64-bit. 152519397407SSherry Moore */ 15267417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_AMD_EDX_LM) { 15277417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_64); 15287417cfdeSKuriakose Kuruvilla } 152919397407SSherry Moore 153002bc52beSkchow #if defined(__amd64) 153102bc52beSkchow /* 1 GB large page - enable only for 64 bit kernel */ 15327417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_AMD_EDX_1GPG) { 15337417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_1GPG); 15347417cfdeSKuriakose Kuruvilla } 153502bc52beSkchow #endif 153602bc52beSkchow 1537f8801251Skk208521 if ((cpi->cpi_vendor == X86_VENDOR_AMD) && 1538f8801251Skk208521 (cpi->cpi_std[1].cp_edx & CPUID_INTC_EDX_FXSR) && 15397417cfdeSKuriakose Kuruvilla (cp->cp_ecx & CPUID_AMD_ECX_SSE4A)) { 15407417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_SSE4A); 15417417cfdeSKuriakose Kuruvilla } 1542f8801251Skk208521 15437c478bd9Sstevel@tonic-gate /* 1544ae115bc7Smrj * If both the HTT and CMP_LGCY bits are set, 15458949bcd6Sandrei * then we're not actually HyperThreaded. Read 15468949bcd6Sandrei * "AMD CPUID Specification" for more details. 15477c478bd9Sstevel@tonic-gate */ 15487c478bd9Sstevel@tonic-gate if (cpi->cpi_vendor == X86_VENDOR_AMD && 15497417cfdeSKuriakose Kuruvilla is_x86_feature(featureset, X86FSET_HTT) && 1550ae115bc7Smrj (cp->cp_ecx & CPUID_AMD_ECX_CMP_LGCY)) { 15517417cfdeSKuriakose Kuruvilla remove_x86_feature(featureset, X86FSET_HTT); 15527417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_CMP); 15538949bcd6Sandrei } 1554ae115bc7Smrj #if defined(__amd64) 15557c478bd9Sstevel@tonic-gate /* 15567c478bd9Sstevel@tonic-gate * It's really tricky to support syscall/sysret in 15577c478bd9Sstevel@tonic-gate * the i386 kernel; we rely on sysenter/sysexit 15587c478bd9Sstevel@tonic-gate * instead. In the amd64 kernel, things are -way- 15597c478bd9Sstevel@tonic-gate * better. 15607c478bd9Sstevel@tonic-gate */ 15617417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_AMD_EDX_SYSC) { 15627417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_ASYSC); 15637417cfdeSKuriakose Kuruvilla } 15647c478bd9Sstevel@tonic-gate 15657c478bd9Sstevel@tonic-gate /* 15667c478bd9Sstevel@tonic-gate * While we're thinking about system calls, note 15677c478bd9Sstevel@tonic-gate * that AMD processors don't support sysenter 15687c478bd9Sstevel@tonic-gate * in long mode at all, so don't try to program them. 15697c478bd9Sstevel@tonic-gate */ 15707417cfdeSKuriakose Kuruvilla if (x86_vendor == X86_VENDOR_AMD) { 15717417cfdeSKuriakose Kuruvilla remove_x86_feature(featureset, X86FSET_SEP); 15727417cfdeSKuriakose Kuruvilla } 15737c478bd9Sstevel@tonic-gate #endif 15747417cfdeSKuriakose Kuruvilla if (cp->cp_edx & CPUID_AMD_EDX_TSCP) { 15757417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_TSCP); 15767417cfdeSKuriakose Kuruvilla } 1577faa20166SBryan Cantrill 1578faa20166SBryan Cantrill if (cp->cp_ecx & CPUID_AMD_ECX_SVM) { 1579faa20166SBryan Cantrill add_x86_feature(featureset, X86FSET_SVM); 1580faa20166SBryan Cantrill } 15817660e73fSHans Rosenfeld 15827660e73fSHans Rosenfeld if (cp->cp_ecx & CPUID_AMD_ECX_TOPOEXT) { 15837660e73fSHans Rosenfeld add_x86_feature(featureset, X86FSET_TOPOEXT); 15847660e73fSHans Rosenfeld } 15857c478bd9Sstevel@tonic-gate break; 15867c478bd9Sstevel@tonic-gate default: 15877c478bd9Sstevel@tonic-gate break; 15887c478bd9Sstevel@tonic-gate } 15897c478bd9Sstevel@tonic-gate 15908949bcd6Sandrei /* 15918949bcd6Sandrei * Get CPUID data about processor cores and hyperthreads. 15928949bcd6Sandrei */ 15937c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 15947c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 15958949bcd6Sandrei if (cpi->cpi_maxeax >= 4) { 15968949bcd6Sandrei cp = &cpi->cpi_std[4]; 15978949bcd6Sandrei cp->cp_eax = 4; 15988949bcd6Sandrei cp->cp_ecx = 0; 15998949bcd6Sandrei (void) __cpuid_insn(cp); 1600ae115bc7Smrj platform_cpuid_mangle(cpi->cpi_vendor, 4, cp); 16018949bcd6Sandrei } 16028949bcd6Sandrei /*FALLTHROUGH*/ 16037c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 16047c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax < 0x80000008) 16057c478bd9Sstevel@tonic-gate break; 16067c478bd9Sstevel@tonic-gate cp = &cpi->cpi_extd[8]; 16078949bcd6Sandrei cp->cp_eax = 0x80000008; 16088949bcd6Sandrei (void) __cpuid_insn(cp); 1609ae115bc7Smrj platform_cpuid_mangle(cpi->cpi_vendor, 0x80000008, cp); 1610ae115bc7Smrj 16117c478bd9Sstevel@tonic-gate /* 16127c478bd9Sstevel@tonic-gate * Virtual and physical address limits from 16137c478bd9Sstevel@tonic-gate * cpuid override previously guessed values. 16147c478bd9Sstevel@tonic-gate */ 16157c478bd9Sstevel@tonic-gate cpi->cpi_pabits = BITX(cp->cp_eax, 7, 0); 16167c478bd9Sstevel@tonic-gate cpi->cpi_vabits = BITX(cp->cp_eax, 15, 8); 16177c478bd9Sstevel@tonic-gate break; 16187c478bd9Sstevel@tonic-gate default: 16197c478bd9Sstevel@tonic-gate break; 16207c478bd9Sstevel@tonic-gate } 16218949bcd6Sandrei 1622d129bde2Sesaxe /* 1623d129bde2Sesaxe * Derive the number of cores per chip 1624d129bde2Sesaxe */ 16258949bcd6Sandrei switch (cpi->cpi_vendor) { 16268949bcd6Sandrei case X86_VENDOR_Intel: 16278949bcd6Sandrei if (cpi->cpi_maxeax < 4) { 16288949bcd6Sandrei cpi->cpi_ncore_per_chip = 1; 16298949bcd6Sandrei break; 16308949bcd6Sandrei } else { 16318949bcd6Sandrei cpi->cpi_ncore_per_chip = 16328949bcd6Sandrei BITX((cpi)->cpi_std[4].cp_eax, 31, 26) + 1; 16338949bcd6Sandrei } 16348949bcd6Sandrei break; 16358949bcd6Sandrei case X86_VENDOR_AMD: 16368949bcd6Sandrei if (cpi->cpi_xmaxeax < 0x80000008) { 16378949bcd6Sandrei cpi->cpi_ncore_per_chip = 1; 16388949bcd6Sandrei break; 16398949bcd6Sandrei } else { 164010569901Sgavinm /* 164110569901Sgavinm * On family 0xf cpuid fn 2 ECX[7:0] "NC" is 164210569901Sgavinm * 1 less than the number of physical cores on 164310569901Sgavinm * the chip. In family 0x10 this value can 164410569901Sgavinm * be affected by "downcoring" - it reflects 164510569901Sgavinm * 1 less than the number of cores actually 164610569901Sgavinm * enabled on this node. 164710569901Sgavinm */ 16488949bcd6Sandrei cpi->cpi_ncore_per_chip = 16498949bcd6Sandrei BITX((cpi)->cpi_extd[8].cp_ecx, 7, 0) + 1; 16508949bcd6Sandrei } 16518949bcd6Sandrei break; 16528949bcd6Sandrei default: 16538949bcd6Sandrei cpi->cpi_ncore_per_chip = 1; 16548949bcd6Sandrei break; 16557c478bd9Sstevel@tonic-gate } 16560e751525SEric Saxe 16570e751525SEric Saxe /* 16580e751525SEric Saxe * Get CPUID data about TSC Invariance in Deep C-State. 16590e751525SEric Saxe */ 16600e751525SEric Saxe switch (cpi->cpi_vendor) { 16610e751525SEric Saxe case X86_VENDOR_Intel: 16620e751525SEric Saxe if (cpi->cpi_maxeax >= 7) { 16630e751525SEric Saxe cp = &cpi->cpi_extd[7]; 16640e751525SEric Saxe cp->cp_eax = 0x80000007; 16650e751525SEric Saxe cp->cp_ecx = 0; 16660e751525SEric Saxe (void) __cpuid_insn(cp); 16670e751525SEric Saxe } 16680e751525SEric Saxe break; 16690e751525SEric Saxe default: 16700e751525SEric Saxe break; 16710e751525SEric Saxe } 1672fa2e767eSgavinm } else { 1673fa2e767eSgavinm cpi->cpi_ncore_per_chip = 1; 16748949bcd6Sandrei } 16758949bcd6Sandrei 16768949bcd6Sandrei /* 16778949bcd6Sandrei * If more than one core, then this processor is CMP. 16788949bcd6Sandrei */ 16797417cfdeSKuriakose Kuruvilla if (cpi->cpi_ncore_per_chip > 1) { 16807417cfdeSKuriakose Kuruvilla add_x86_feature(featureset, X86FSET_CMP); 16817417cfdeSKuriakose Kuruvilla } 1682ae115bc7Smrj 16838949bcd6Sandrei /* 16848949bcd6Sandrei * If the number of cores is the same as the number 16858949bcd6Sandrei * of CPUs, then we cannot have HyperThreading. 16868949bcd6Sandrei */ 16877417cfdeSKuriakose Kuruvilla if (cpi->cpi_ncpu_per_chip == cpi->cpi_ncore_per_chip) { 16887417cfdeSKuriakose Kuruvilla remove_x86_feature(featureset, X86FSET_HTT); 16897417cfdeSKuriakose Kuruvilla } 16908949bcd6Sandrei 16918031591dSSrihari Venkatesan cpi->cpi_apicid = CPI_APIC_ID(cpi); 16928031591dSSrihari Venkatesan cpi->cpi_procnodes_per_pkg = 1; 16937660e73fSHans Rosenfeld cpi->cpi_cores_per_compunit = 1; 16947417cfdeSKuriakose Kuruvilla if (is_x86_feature(featureset, X86FSET_HTT) == B_FALSE && 16957417cfdeSKuriakose Kuruvilla is_x86_feature(featureset, X86FSET_CMP) == B_FALSE) { 16968949bcd6Sandrei /* 16978949bcd6Sandrei * Single-core single-threaded processors. 16988949bcd6Sandrei */ 16997c478bd9Sstevel@tonic-gate cpi->cpi_chipid = -1; 17007c478bd9Sstevel@tonic-gate cpi->cpi_clogid = 0; 17018949bcd6Sandrei cpi->cpi_coreid = cpu->cpu_id; 170210569901Sgavinm cpi->cpi_pkgcoreid = 0; 17038031591dSSrihari Venkatesan if (cpi->cpi_vendor == X86_VENDOR_AMD) 17048031591dSSrihari Venkatesan cpi->cpi_procnodeid = BITX(cpi->cpi_apicid, 3, 0); 17058031591dSSrihari Venkatesan else 17068031591dSSrihari Venkatesan cpi->cpi_procnodeid = cpi->cpi_chipid; 17077c478bd9Sstevel@tonic-gate } else if (cpi->cpi_ncpu_per_chip > 1) { 17088031591dSSrihari Venkatesan if (cpi->cpi_vendor == X86_VENDOR_Intel) 17097417cfdeSKuriakose Kuruvilla cpuid_intel_getids(cpu, featureset); 17108031591dSSrihari Venkatesan else if (cpi->cpi_vendor == X86_VENDOR_AMD) 17118031591dSSrihari Venkatesan cpuid_amd_getids(cpu); 17128031591dSSrihari Venkatesan else { 17138949bcd6Sandrei /* 17148949bcd6Sandrei * All other processors are currently 17158949bcd6Sandrei * assumed to have single cores. 17168949bcd6Sandrei */ 17178949bcd6Sandrei cpi->cpi_coreid = cpi->cpi_chipid; 171810569901Sgavinm cpi->cpi_pkgcoreid = 0; 17198031591dSSrihari Venkatesan cpi->cpi_procnodeid = cpi->cpi_chipid; 17207660e73fSHans Rosenfeld cpi->cpi_compunitid = cpi->cpi_chipid; 17218949bcd6Sandrei } 17227c478bd9Sstevel@tonic-gate } 17237c478bd9Sstevel@tonic-gate 17248a40a695Sgavinm /* 17258a40a695Sgavinm * Synthesize chip "revision" and socket type 17268a40a695Sgavinm */ 1727e4b86885SCheng Sean Ye cpi->cpi_chiprev = _cpuid_chiprev(cpi->cpi_vendor, cpi->cpi_family, 1728e4b86885SCheng Sean Ye cpi->cpi_model, cpi->cpi_step); 1729e4b86885SCheng Sean Ye cpi->cpi_chiprevstr = _cpuid_chiprevstr(cpi->cpi_vendor, 1730e4b86885SCheng Sean Ye cpi->cpi_family, cpi->cpi_model, cpi->cpi_step); 1731e4b86885SCheng Sean Ye cpi->cpi_socket = _cpuid_skt(cpi->cpi_vendor, cpi->cpi_family, 1732e4b86885SCheng Sean Ye cpi->cpi_model, cpi->cpi_step); 17338a40a695Sgavinm 17347c478bd9Sstevel@tonic-gate pass1_done: 17357c478bd9Sstevel@tonic-gate cpi->cpi_pass = 1; 17367c478bd9Sstevel@tonic-gate } 17377c478bd9Sstevel@tonic-gate 17387c478bd9Sstevel@tonic-gate /* 17397c478bd9Sstevel@tonic-gate * Make copies of the cpuid table entries we depend on, in 17407c478bd9Sstevel@tonic-gate * part for ease of parsing now, in part so that we have only 17417c478bd9Sstevel@tonic-gate * one place to correct any of it, in part for ease of 17427c478bd9Sstevel@tonic-gate * later export to userland, and in part so we can look at 17437c478bd9Sstevel@tonic-gate * this stuff in a crash dump. 17447c478bd9Sstevel@tonic-gate */ 17457c478bd9Sstevel@tonic-gate 17467c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 17477c478bd9Sstevel@tonic-gate void 17487c478bd9Sstevel@tonic-gate cpuid_pass2(cpu_t *cpu) 17497c478bd9Sstevel@tonic-gate { 17507c478bd9Sstevel@tonic-gate uint_t n, nmax; 17517c478bd9Sstevel@tonic-gate int i; 17528949bcd6Sandrei struct cpuid_regs *cp; 17537c478bd9Sstevel@tonic-gate uint8_t *dp; 17547c478bd9Sstevel@tonic-gate uint32_t *iptr; 17557c478bd9Sstevel@tonic-gate struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi; 17567c478bd9Sstevel@tonic-gate 17577c478bd9Sstevel@tonic-gate ASSERT(cpi->cpi_pass == 1); 17587c478bd9Sstevel@tonic-gate 17597c478bd9Sstevel@tonic-gate if (cpi->cpi_maxeax < 1) 17607c478bd9Sstevel@tonic-gate goto pass2_done; 17617c478bd9Sstevel@tonic-gate 17627c478bd9Sstevel@tonic-gate if ((nmax = cpi->cpi_maxeax + 1) > NMAX_CPI_STD) 17637c478bd9Sstevel@tonic-gate nmax = NMAX_CPI_STD; 17647c478bd9Sstevel@tonic-gate /* 17657c478bd9Sstevel@tonic-gate * (We already handled n == 0 and n == 1 in pass 1) 17667c478bd9Sstevel@tonic-gate */ 17677c478bd9Sstevel@tonic-gate for (n = 2, cp = &cpi->cpi_std[2]; n < nmax; n++, cp++) { 17688949bcd6Sandrei cp->cp_eax = n; 1769d129bde2Sesaxe 1770d129bde2Sesaxe /* 1771d129bde2Sesaxe * CPUID function 4 expects %ecx to be initialized 1772d129bde2Sesaxe * with an index which indicates which cache to return 1773d129bde2Sesaxe * information about. The OS is expected to call function 4 1774d129bde2Sesaxe * with %ecx set to 0, 1, 2, ... until it returns with 1775d129bde2Sesaxe * EAX[4:0] set to 0, which indicates there are no more 1776d129bde2Sesaxe * caches. 1777d129bde2Sesaxe * 1778d129bde2Sesaxe * Here, populate cpi_std[4] with the information returned by 1779d129bde2Sesaxe * function 4 when %ecx == 0, and do the rest in cpuid_pass3() 1780d129bde2Sesaxe * when dynamic memory allocation becomes available. 1781d129bde2Sesaxe * 1782d129bde2Sesaxe * Note: we need to explicitly initialize %ecx here, since 1783d129bde2Sesaxe * function 4 may have been previously invoked. 1784d129bde2Sesaxe */ 1785d129bde2Sesaxe if (n == 4) 1786d129bde2Sesaxe cp->cp_ecx = 0; 1787d129bde2Sesaxe 17888949bcd6Sandrei (void) __cpuid_insn(cp); 1789ae115bc7Smrj platform_cpuid_mangle(cpi->cpi_vendor, n, cp); 17907c478bd9Sstevel@tonic-gate switch (n) { 17917c478bd9Sstevel@tonic-gate case 2: 17927c478bd9Sstevel@tonic-gate /* 17937c478bd9Sstevel@tonic-gate * "the lower 8 bits of the %eax register 17947c478bd9Sstevel@tonic-gate * contain a value that identifies the number 17957c478bd9Sstevel@tonic-gate * of times the cpuid [instruction] has to be 17967c478bd9Sstevel@tonic-gate * executed to obtain a complete image of the 17977c478bd9Sstevel@tonic-gate * processor's caching systems." 17987c478bd9Sstevel@tonic-gate * 17997c478bd9Sstevel@tonic-gate * How *do* they make this stuff up? 18007c478bd9Sstevel@tonic-gate */ 18017c478bd9Sstevel@tonic-gate cpi->cpi_ncache = sizeof (*cp) * 18027c478bd9Sstevel@tonic-gate BITX(cp->cp_eax, 7, 0); 18037c478bd9Sstevel@tonic-gate if (cpi->cpi_ncache == 0) 18047c478bd9Sstevel@tonic-gate break; 18057c478bd9Sstevel@tonic-gate cpi->cpi_ncache--; /* skip count byte */ 18067c478bd9Sstevel@tonic-gate 18077c478bd9Sstevel@tonic-gate /* 18087c478bd9Sstevel@tonic-gate * Well, for now, rather than attempt to implement 18097c478bd9Sstevel@tonic-gate * this slightly dubious algorithm, we just look 18107c478bd9Sstevel@tonic-gate * at the first 15 .. 18117c478bd9Sstevel@tonic-gate */ 18127c478bd9Sstevel@tonic-gate if (cpi->cpi_ncache > (sizeof (*cp) - 1)) 18137c478bd9Sstevel@tonic-gate cpi->cpi_ncache = sizeof (*cp) - 1; 18147c478bd9Sstevel@tonic-gate 18157c478bd9Sstevel@tonic-gate dp = cpi->cpi_cacheinfo; 18167c478bd9Sstevel@tonic-gate if (BITX(cp->cp_eax, 31, 31) == 0) { 18177c478bd9Sstevel@tonic-gate uint8_t *p = (void *)&cp->cp_eax; 181863d3f7dfSkk208521 for (i = 1; i < 4; i++) 18197c478bd9Sstevel@tonic-gate if (p[i] != 0) 18207c478bd9Sstevel@tonic-gate *dp++ = p[i]; 18217c478bd9Sstevel@tonic-gate } 18227c478bd9Sstevel@tonic-gate if (BITX(cp->cp_ebx, 31, 31) == 0) { 18237c478bd9Sstevel@tonic-gate uint8_t *p = (void *)&cp->cp_ebx; 18247c478bd9Sstevel@tonic-gate for (i = 0; i < 4; i++) 18257c478bd9Sstevel@tonic-gate if (p[i] != 0) 18267c478bd9Sstevel@tonic-gate *dp++ = p[i]; 18277c478bd9Sstevel@tonic-gate } 18287c478bd9Sstevel@tonic-gate if (BITX(cp->cp_ecx, 31, 31) == 0) { 18297c478bd9Sstevel@tonic-gate uint8_t *p = (void *)&cp->cp_ecx; 18307c478bd9Sstevel@tonic-gate for (i = 0; i < 4; i++) 18317c478bd9Sstevel@tonic-gate if (p[i] != 0) 18327c478bd9Sstevel@tonic-gate *dp++ = p[i]; 18337c478bd9Sstevel@tonic-gate } 18347c478bd9Sstevel@tonic-gate if (BITX(cp->cp_edx, 31, 31) == 0) { 18357c478bd9Sstevel@tonic-gate uint8_t *p = (void *)&cp->cp_edx; 18367c478bd9Sstevel@tonic-gate for (i = 0; i < 4; i++) 18377c478bd9Sstevel@tonic-gate if (p[i] != 0) 18387c478bd9Sstevel@tonic-gate *dp++ = p[i]; 18397c478bd9Sstevel@tonic-gate } 18407c478bd9Sstevel@tonic-gate break; 1841f98fbcecSbholler 18427c478bd9Sstevel@tonic-gate case 3: /* Processor serial number, if PSN supported */ 1843f98fbcecSbholler break; 1844f98fbcecSbholler 18457c478bd9Sstevel@tonic-gate case 4: /* Deterministic cache parameters */ 1846f98fbcecSbholler break; 1847f98fbcecSbholler 18487c478bd9Sstevel@tonic-gate case 5: /* Monitor/Mwait parameters */ 18495b8a6efeSbholler { 18505b8a6efeSbholler size_t mwait_size; 1851f98fbcecSbholler 1852f98fbcecSbholler /* 1853f98fbcecSbholler * check cpi_mwait.support which was set in cpuid_pass1 1854f98fbcecSbholler */ 1855f98fbcecSbholler if (!(cpi->cpi_mwait.support & MWAIT_SUPPORT)) 1856f98fbcecSbholler break; 1857f98fbcecSbholler 18585b8a6efeSbholler /* 18595b8a6efeSbholler * Protect ourself from insane mwait line size. 18605b8a6efeSbholler * Workaround for incomplete hardware emulator(s). 18615b8a6efeSbholler */ 18625b8a6efeSbholler mwait_size = (size_t)MWAIT_SIZE_MAX(cpi); 18635b8a6efeSbholler if (mwait_size < sizeof (uint32_t) || 18645b8a6efeSbholler !ISP2(mwait_size)) { 18655b8a6efeSbholler #if DEBUG 18665b8a6efeSbholler cmn_err(CE_NOTE, "Cannot handle cpu %d mwait " 18675d8efbbcSSaurabh Misra "size %ld", cpu->cpu_id, (long)mwait_size); 18685b8a6efeSbholler #endif 18695b8a6efeSbholler break; 18705b8a6efeSbholler } 18715b8a6efeSbholler 1872f98fbcecSbholler cpi->cpi_mwait.mon_min = (size_t)MWAIT_SIZE_MIN(cpi); 18735b8a6efeSbholler cpi->cpi_mwait.mon_max = mwait_size; 1874f98fbcecSbholler if (MWAIT_EXTENSION(cpi)) { 1875f98fbcecSbholler cpi->cpi_mwait.support |= MWAIT_EXTENSIONS; 1876f98fbcecSbholler if (MWAIT_INT_ENABLE(cpi)) 1877f98fbcecSbholler cpi->cpi_mwait.support |= 1878f98fbcecSbholler MWAIT_ECX_INT_ENABLE; 1879f98fbcecSbholler } 1880f98fbcecSbholler break; 18815b8a6efeSbholler } 18827c478bd9Sstevel@tonic-gate default: 18837c478bd9Sstevel@tonic-gate break; 18847c478bd9Sstevel@tonic-gate } 18857c478bd9Sstevel@tonic-gate } 18867c478bd9Sstevel@tonic-gate 1887b6917abeSmishra if (cpi->cpi_maxeax >= 0xB && cpi->cpi_vendor == X86_VENDOR_Intel) { 18885d8efbbcSSaurabh Misra struct cpuid_regs regs; 18895d8efbbcSSaurabh Misra 18905d8efbbcSSaurabh Misra cp = ®s; 1891b6917abeSmishra cp->cp_eax = 0xB; 18925d8efbbcSSaurabh Misra cp->cp_edx = cp->cp_ebx = cp->cp_ecx = 0; 1893b6917abeSmishra 1894b6917abeSmishra (void) __cpuid_insn(cp); 1895b6917abeSmishra 1896b6917abeSmishra /* 1897b6917abeSmishra * Check CPUID.EAX=0BH, ECX=0H:EBX is non-zero, which 1898b6917abeSmishra * indicates that the extended topology enumeration leaf is 1899b6917abeSmishra * available. 1900b6917abeSmishra */ 1901b6917abeSmishra if (cp->cp_ebx) { 1902b6917abeSmishra uint32_t x2apic_id; 1903b6917abeSmishra uint_t coreid_shift = 0; 1904b6917abeSmishra uint_t ncpu_per_core = 1; 1905b6917abeSmishra uint_t chipid_shift = 0; 1906b6917abeSmishra uint_t ncpu_per_chip = 1; 1907b6917abeSmishra uint_t i; 1908b6917abeSmishra uint_t level; 1909b6917abeSmishra 1910b6917abeSmishra for (i = 0; i < CPI_FNB_ECX_MAX; i++) { 1911b6917abeSmishra cp->cp_eax = 0xB; 1912b6917abeSmishra cp->cp_ecx = i; 1913b6917abeSmishra 1914b6917abeSmishra (void) __cpuid_insn(cp); 1915b6917abeSmishra level = CPI_CPU_LEVEL_TYPE(cp); 1916b6917abeSmishra 1917b6917abeSmishra if (level == 1) { 1918b6917abeSmishra x2apic_id = cp->cp_edx; 1919b6917abeSmishra coreid_shift = BITX(cp->cp_eax, 4, 0); 1920b6917abeSmishra ncpu_per_core = BITX(cp->cp_ebx, 15, 0); 1921b6917abeSmishra } else if (level == 2) { 1922b6917abeSmishra x2apic_id = cp->cp_edx; 1923b6917abeSmishra chipid_shift = BITX(cp->cp_eax, 4, 0); 1924b6917abeSmishra ncpu_per_chip = BITX(cp->cp_ebx, 15, 0); 1925b6917abeSmishra } 1926b6917abeSmishra } 1927b6917abeSmishra 1928b6917abeSmishra cpi->cpi_apicid = x2apic_id; 1929b6917abeSmishra cpi->cpi_ncpu_per_chip = ncpu_per_chip; 1930b6917abeSmishra cpi->cpi_ncore_per_chip = ncpu_per_chip / 1931b6917abeSmishra ncpu_per_core; 1932b6917abeSmishra cpi->cpi_chipid = x2apic_id >> chipid_shift; 1933b6917abeSmishra cpi->cpi_clogid = x2apic_id & ((1 << chipid_shift) - 1); 1934b6917abeSmishra cpi->cpi_coreid = x2apic_id >> coreid_shift; 1935b6917abeSmishra cpi->cpi_pkgcoreid = cpi->cpi_clogid >> coreid_shift; 1936b6917abeSmishra } 19375d8efbbcSSaurabh Misra 19385d8efbbcSSaurabh Misra /* Make cp NULL so that we don't stumble on others */ 19395d8efbbcSSaurabh Misra cp = NULL; 1940b6917abeSmishra } 1941b6917abeSmishra 19427af88ac7SKuriakose Kuruvilla /* 19437af88ac7SKuriakose Kuruvilla * XSAVE enumeration 19447af88ac7SKuriakose Kuruvilla */ 194563408480SHans Rosenfeld if (cpi->cpi_maxeax >= 0xD) { 19467af88ac7SKuriakose Kuruvilla struct cpuid_regs regs; 19477af88ac7SKuriakose Kuruvilla boolean_t cpuid_d_valid = B_TRUE; 19487af88ac7SKuriakose Kuruvilla 19497af88ac7SKuriakose Kuruvilla cp = ®s; 19507af88ac7SKuriakose Kuruvilla cp->cp_eax = 0xD; 19517af88ac7SKuriakose Kuruvilla cp->cp_edx = cp->cp_ebx = cp->cp_ecx = 0; 19527af88ac7SKuriakose Kuruvilla 19537af88ac7SKuriakose Kuruvilla (void) __cpuid_insn(cp); 19547af88ac7SKuriakose Kuruvilla 19557af88ac7SKuriakose Kuruvilla /* 19567af88ac7SKuriakose Kuruvilla * Sanity checks for debug 19577af88ac7SKuriakose Kuruvilla */ 19587af88ac7SKuriakose Kuruvilla if ((cp->cp_eax & XFEATURE_LEGACY_FP) == 0 || 19597af88ac7SKuriakose Kuruvilla (cp->cp_eax & XFEATURE_SSE) == 0) { 19607af88ac7SKuriakose Kuruvilla cpuid_d_valid = B_FALSE; 19617af88ac7SKuriakose Kuruvilla } 19627af88ac7SKuriakose Kuruvilla 19637af88ac7SKuriakose Kuruvilla cpi->cpi_xsave.xsav_hw_features_low = cp->cp_eax; 19647af88ac7SKuriakose Kuruvilla cpi->cpi_xsave.xsav_hw_features_high = cp->cp_edx; 19657af88ac7SKuriakose Kuruvilla cpi->cpi_xsave.xsav_max_size = cp->cp_ecx; 19667af88ac7SKuriakose Kuruvilla 19677af88ac7SKuriakose Kuruvilla /* 19687af88ac7SKuriakose Kuruvilla * If the hw supports AVX, get the size and offset in the save 19697af88ac7SKuriakose Kuruvilla * area for the ymm state. 19707af88ac7SKuriakose Kuruvilla */ 19717af88ac7SKuriakose Kuruvilla if (cpi->cpi_xsave.xsav_hw_features_low & XFEATURE_AVX) { 19727af88ac7SKuriakose Kuruvilla cp->cp_eax = 0xD; 19737af88ac7SKuriakose Kuruvilla cp->cp_ecx = 2; 19747af88ac7SKuriakose Kuruvilla cp->cp_edx = cp->cp_ebx = 0; 19757af88ac7SKuriakose Kuruvilla 19767af88ac7SKuriakose Kuruvilla (void) __cpuid_insn(cp); 19777af88ac7SKuriakose Kuruvilla 19787af88ac7SKuriakose Kuruvilla if (cp->cp_ebx != CPUID_LEAFD_2_YMM_OFFSET || 19797af88ac7SKuriakose Kuruvilla cp->cp_eax != CPUID_LEAFD_2_YMM_SIZE) { 19807af88ac7SKuriakose Kuruvilla cpuid_d_valid = B_FALSE; 19817af88ac7SKuriakose Kuruvilla } 19827af88ac7SKuriakose Kuruvilla 19837af88ac7SKuriakose Kuruvilla cpi->cpi_xsave.ymm_size = cp->cp_eax; 19847af88ac7SKuriakose Kuruvilla cpi->cpi_xsave.ymm_offset = cp->cp_ebx; 19857af88ac7SKuriakose Kuruvilla } 19867af88ac7SKuriakose Kuruvilla 19877af88ac7SKuriakose Kuruvilla if (is_x86_feature(x86_featureset, X86FSET_XSAVE)) { 19887af88ac7SKuriakose Kuruvilla xsave_state_size = 0; 19897af88ac7SKuriakose Kuruvilla } else if (cpuid_d_valid) { 19907af88ac7SKuriakose Kuruvilla xsave_state_size = cpi->cpi_xsave.xsav_max_size; 19917af88ac7SKuriakose Kuruvilla } else { 19927af88ac7SKuriakose Kuruvilla /* Broken CPUID 0xD, probably in HVM */ 19937af88ac7SKuriakose Kuruvilla cmn_err(CE_WARN, "cpu%d: CPUID.0xD returns invalid " 19947af88ac7SKuriakose Kuruvilla "value: hw_low = %d, hw_high = %d, xsave_size = %d" 19957af88ac7SKuriakose Kuruvilla ", ymm_size = %d, ymm_offset = %d\n", 19967af88ac7SKuriakose Kuruvilla cpu->cpu_id, cpi->cpi_xsave.xsav_hw_features_low, 19977af88ac7SKuriakose Kuruvilla cpi->cpi_xsave.xsav_hw_features_high, 19987af88ac7SKuriakose Kuruvilla (int)cpi->cpi_xsave.xsav_max_size, 19997af88ac7SKuriakose Kuruvilla (int)cpi->cpi_xsave.ymm_size, 20007af88ac7SKuriakose Kuruvilla (int)cpi->cpi_xsave.ymm_offset); 20017af88ac7SKuriakose Kuruvilla 20027af88ac7SKuriakose Kuruvilla if (xsave_state_size != 0) { 20037af88ac7SKuriakose Kuruvilla /* 20047af88ac7SKuriakose Kuruvilla * This must be a non-boot CPU. We cannot 20057af88ac7SKuriakose Kuruvilla * continue, because boot cpu has already 20067af88ac7SKuriakose Kuruvilla * enabled XSAVE. 20077af88ac7SKuriakose Kuruvilla */ 20087af88ac7SKuriakose Kuruvilla ASSERT(cpu->cpu_id != 0); 20097af88ac7SKuriakose Kuruvilla cmn_err(CE_PANIC, "cpu%d: we have already " 20107af88ac7SKuriakose Kuruvilla "enabled XSAVE on boot cpu, cannot " 20117af88ac7SKuriakose Kuruvilla "continue.", cpu->cpu_id); 20127af88ac7SKuriakose Kuruvilla } else { 20137af88ac7SKuriakose Kuruvilla /* 2014dcf050afSRobert Mustacchi * If we reached here on the boot CPU, it's also 2015dcf050afSRobert Mustacchi * almost certain that we'll reach here on the 2016dcf050afSRobert Mustacchi * non-boot CPUs. When we're here on a boot CPU 2017dcf050afSRobert Mustacchi * we should disable the feature, on a non-boot 2018dcf050afSRobert Mustacchi * CPU we need to confirm that we have. 20197af88ac7SKuriakose Kuruvilla */ 2020dcf050afSRobert Mustacchi if (cpu->cpu_id == 0) { 20217af88ac7SKuriakose Kuruvilla remove_x86_feature(x86_featureset, 20227af88ac7SKuriakose Kuruvilla X86FSET_XSAVE); 2023dcf050afSRobert Mustacchi remove_x86_feature(x86_featureset, 2024dcf050afSRobert Mustacchi X86FSET_AVX); 2025245ac945SRobert Mustacchi remove_x86_feature(x86_featureset, 2026245ac945SRobert Mustacchi X86FSET_F16C); 2027245ac945SRobert Mustacchi remove_x86_feature(x86_featureset, 2028245ac945SRobert Mustacchi X86FSET_BMI1); 2029245ac945SRobert Mustacchi remove_x86_feature(x86_featureset, 2030245ac945SRobert Mustacchi X86FSET_BMI2); 2031245ac945SRobert Mustacchi remove_x86_feature(x86_featureset, 2032245ac945SRobert Mustacchi X86FSET_FMA); 2033245ac945SRobert Mustacchi remove_x86_feature(x86_featureset, 2034245ac945SRobert Mustacchi X86FSET_AVX2); 2035dcf050afSRobert Mustacchi CPI_FEATURES_ECX(cpi) &= 2036dcf050afSRobert Mustacchi ~CPUID_INTC_ECX_XSAVE; 2037dcf050afSRobert Mustacchi CPI_FEATURES_ECX(cpi) &= 2038dcf050afSRobert Mustacchi ~CPUID_INTC_ECX_AVX; 2039dcf050afSRobert Mustacchi CPI_FEATURES_ECX(cpi) &= 2040dcf050afSRobert Mustacchi ~CPUID_INTC_ECX_F16C; 2041245ac945SRobert Mustacchi CPI_FEATURES_ECX(cpi) &= 2042245ac945SRobert Mustacchi ~CPUID_INTC_ECX_FMA; 2043245ac945SRobert Mustacchi CPI_FEATURES_7_0_EBX(cpi) &= 2044245ac945SRobert Mustacchi ~CPUID_INTC_EBX_7_0_BMI1; 2045245ac945SRobert Mustacchi CPI_FEATURES_7_0_EBX(cpi) &= 2046245ac945SRobert Mustacchi ~CPUID_INTC_EBX_7_0_BMI2; 2047245ac945SRobert Mustacchi CPI_FEATURES_7_0_EBX(cpi) &= 2048245ac945SRobert Mustacchi ~CPUID_INTC_EBX_7_0_AVX2; 20497af88ac7SKuriakose Kuruvilla xsave_force_disable = B_TRUE; 2050dcf050afSRobert Mustacchi } else { 2051dcf050afSRobert Mustacchi VERIFY(is_x86_feature(x86_featureset, 2052dcf050afSRobert Mustacchi X86FSET_XSAVE) == B_FALSE); 2053dcf050afSRobert Mustacchi } 20547af88ac7SKuriakose Kuruvilla } 20557af88ac7SKuriakose Kuruvilla } 20567af88ac7SKuriakose Kuruvilla } 20577af88ac7SKuriakose Kuruvilla 20587af88ac7SKuriakose Kuruvilla 20597c478bd9Sstevel@tonic-gate if ((cpi->cpi_xmaxeax & 0x80000000) == 0) 20607c478bd9Sstevel@tonic-gate goto pass2_done; 20617c478bd9Sstevel@tonic-gate 20627c478bd9Sstevel@tonic-gate if ((nmax = cpi->cpi_xmaxeax - 0x80000000 + 1) > NMAX_CPI_EXTD) 20637c478bd9Sstevel@tonic-gate nmax = NMAX_CPI_EXTD; 20647c478bd9Sstevel@tonic-gate /* 20657c478bd9Sstevel@tonic-gate * Copy the extended properties, fixing them as we go. 20667c478bd9Sstevel@tonic-gate * (We already handled n == 0 and n == 1 in pass 1) 20677c478bd9Sstevel@tonic-gate */ 20687c478bd9Sstevel@tonic-gate iptr = (void *)cpi->cpi_brandstr; 20697c478bd9Sstevel@tonic-gate for (n = 2, cp = &cpi->cpi_extd[2]; n < nmax; cp++, n++) { 20708949bcd6Sandrei cp->cp_eax = 0x80000000 + n; 20718949bcd6Sandrei (void) __cpuid_insn(cp); 2072ae115bc7Smrj platform_cpuid_mangle(cpi->cpi_vendor, 0x80000000 + n, cp); 20737c478bd9Sstevel@tonic-gate switch (n) { 20747c478bd9Sstevel@tonic-gate case 2: 20757c478bd9Sstevel@tonic-gate case 3: 20767c478bd9Sstevel@tonic-gate case 4: 20777c478bd9Sstevel@tonic-gate /* 20787c478bd9Sstevel@tonic-gate * Extract the brand string 20797c478bd9Sstevel@tonic-gate */ 20807c478bd9Sstevel@tonic-gate *iptr++ = cp->cp_eax; 20817c478bd9Sstevel@tonic-gate *iptr++ = cp->cp_ebx; 20827c478bd9Sstevel@tonic-gate *iptr++ = cp->cp_ecx; 20837c478bd9Sstevel@tonic-gate *iptr++ = cp->cp_edx; 20847c478bd9Sstevel@tonic-gate break; 20857c478bd9Sstevel@tonic-gate case 5: 20867c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 20877c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 20887c478bd9Sstevel@tonic-gate /* 20897c478bd9Sstevel@tonic-gate * The Athlon and Duron were the first 20907c478bd9Sstevel@tonic-gate * parts to report the sizes of the 20917c478bd9Sstevel@tonic-gate * TLB for large pages. Before then, 20927c478bd9Sstevel@tonic-gate * we don't trust the data. 20937c478bd9Sstevel@tonic-gate */ 20947c478bd9Sstevel@tonic-gate if (cpi->cpi_family < 6 || 20957c478bd9Sstevel@tonic-gate (cpi->cpi_family == 6 && 20967c478bd9Sstevel@tonic-gate cpi->cpi_model < 1)) 20977c478bd9Sstevel@tonic-gate cp->cp_eax = 0; 20987c478bd9Sstevel@tonic-gate break; 20997c478bd9Sstevel@tonic-gate default: 21007c478bd9Sstevel@tonic-gate break; 21017c478bd9Sstevel@tonic-gate } 21027c478bd9Sstevel@tonic-gate break; 21037c478bd9Sstevel@tonic-gate case 6: 21047c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 21057c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 21067c478bd9Sstevel@tonic-gate /* 21077c478bd9Sstevel@tonic-gate * The Athlon and Duron were the first 21087c478bd9Sstevel@tonic-gate * AMD parts with L2 TLB's. 21097c478bd9Sstevel@tonic-gate * Before then, don't trust the data. 21107c478bd9Sstevel@tonic-gate */ 21117c478bd9Sstevel@tonic-gate if (cpi->cpi_family < 6 || 21127c478bd9Sstevel@tonic-gate cpi->cpi_family == 6 && 21137c478bd9Sstevel@tonic-gate cpi->cpi_model < 1) 21147c478bd9Sstevel@tonic-gate cp->cp_eax = cp->cp_ebx = 0; 21157c478bd9Sstevel@tonic-gate /* 21167c478bd9Sstevel@tonic-gate * AMD Duron rev A0 reports L2 21177c478bd9Sstevel@tonic-gate * cache size incorrectly as 1K 21187c478bd9Sstevel@tonic-gate * when it is really 64K 21197c478bd9Sstevel@tonic-gate */ 21207c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 6 && 21217c478bd9Sstevel@tonic-gate cpi->cpi_model == 3 && 21227c478bd9Sstevel@tonic-gate cpi->cpi_step == 0) { 21237c478bd9Sstevel@tonic-gate cp->cp_ecx &= 0xffff; 21247c478bd9Sstevel@tonic-gate cp->cp_ecx |= 0x400000; 21257c478bd9Sstevel@tonic-gate } 21267c478bd9Sstevel@tonic-gate break; 21277c478bd9Sstevel@tonic-gate case X86_VENDOR_Cyrix: /* VIA C3 */ 21287c478bd9Sstevel@tonic-gate /* 21297c478bd9Sstevel@tonic-gate * VIA C3 processors are a bit messed 21307c478bd9Sstevel@tonic-gate * up w.r.t. encoding cache sizes in %ecx 21317c478bd9Sstevel@tonic-gate */ 21327c478bd9Sstevel@tonic-gate if (cpi->cpi_family != 6) 21337c478bd9Sstevel@tonic-gate break; 21347c478bd9Sstevel@tonic-gate /* 21357c478bd9Sstevel@tonic-gate * model 7 and 8 were incorrectly encoded 21367c478bd9Sstevel@tonic-gate * 21377c478bd9Sstevel@tonic-gate * xxx is model 8 really broken? 21387c478bd9Sstevel@tonic-gate */ 21397c478bd9Sstevel@tonic-gate if (cpi->cpi_model == 7 || 21407c478bd9Sstevel@tonic-gate cpi->cpi_model == 8) 21417c478bd9Sstevel@tonic-gate cp->cp_ecx = 21427c478bd9Sstevel@tonic-gate BITX(cp->cp_ecx, 31, 24) << 16 | 21437c478bd9Sstevel@tonic-gate BITX(cp->cp_ecx, 23, 16) << 12 | 21447c478bd9Sstevel@tonic-gate BITX(cp->cp_ecx, 15, 8) << 8 | 21457c478bd9Sstevel@tonic-gate BITX(cp->cp_ecx, 7, 0); 21467c478bd9Sstevel@tonic-gate /* 21477c478bd9Sstevel@tonic-gate * model 9 stepping 1 has wrong associativity 21487c478bd9Sstevel@tonic-gate */ 21497c478bd9Sstevel@tonic-gate if (cpi->cpi_model == 9 && cpi->cpi_step == 1) 21507c478bd9Sstevel@tonic-gate cp->cp_ecx |= 8 << 12; 21517c478bd9Sstevel@tonic-gate break; 21527c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 21537c478bd9Sstevel@tonic-gate /* 21547c478bd9Sstevel@tonic-gate * Extended L2 Cache features function. 21557c478bd9Sstevel@tonic-gate * First appeared on Prescott. 21567c478bd9Sstevel@tonic-gate */ 21577c478bd9Sstevel@tonic-gate default: 21587c478bd9Sstevel@tonic-gate break; 21597c478bd9Sstevel@tonic-gate } 21607c478bd9Sstevel@tonic-gate break; 21617c478bd9Sstevel@tonic-gate default: 21627c478bd9Sstevel@tonic-gate break; 21637c478bd9Sstevel@tonic-gate } 21647c478bd9Sstevel@tonic-gate } 21657c478bd9Sstevel@tonic-gate 21667c478bd9Sstevel@tonic-gate pass2_done: 21677c478bd9Sstevel@tonic-gate cpi->cpi_pass = 2; 21687c478bd9Sstevel@tonic-gate } 21697c478bd9Sstevel@tonic-gate 21707c478bd9Sstevel@tonic-gate static const char * 21717c478bd9Sstevel@tonic-gate intel_cpubrand(const struct cpuid_info *cpi) 21727c478bd9Sstevel@tonic-gate { 21737c478bd9Sstevel@tonic-gate int i; 21747c478bd9Sstevel@tonic-gate 21757417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_CPUID) || 21767c478bd9Sstevel@tonic-gate cpi->cpi_maxeax < 1 || cpi->cpi_family < 5) 21777c478bd9Sstevel@tonic-gate return ("i486"); 21787c478bd9Sstevel@tonic-gate 21797c478bd9Sstevel@tonic-gate switch (cpi->cpi_family) { 21807c478bd9Sstevel@tonic-gate case 5: 21817c478bd9Sstevel@tonic-gate return ("Intel Pentium(r)"); 21827c478bd9Sstevel@tonic-gate case 6: 21837c478bd9Sstevel@tonic-gate switch (cpi->cpi_model) { 21847c478bd9Sstevel@tonic-gate uint_t celeron, xeon; 21858949bcd6Sandrei const struct cpuid_regs *cp; 21867c478bd9Sstevel@tonic-gate case 0: 21877c478bd9Sstevel@tonic-gate case 1: 21887c478bd9Sstevel@tonic-gate case 2: 21897c478bd9Sstevel@tonic-gate return ("Intel Pentium(r) Pro"); 21907c478bd9Sstevel@tonic-gate case 3: 21917c478bd9Sstevel@tonic-gate case 4: 21927c478bd9Sstevel@tonic-gate return ("Intel Pentium(r) II"); 21937c478bd9Sstevel@tonic-gate case 6: 21947c478bd9Sstevel@tonic-gate return ("Intel Celeron(r)"); 21957c478bd9Sstevel@tonic-gate case 5: 21967c478bd9Sstevel@tonic-gate case 7: 21977c478bd9Sstevel@tonic-gate celeron = xeon = 0; 21987c478bd9Sstevel@tonic-gate cp = &cpi->cpi_std[2]; /* cache info */ 21997c478bd9Sstevel@tonic-gate 220063d3f7dfSkk208521 for (i = 1; i < 4; i++) { 22017c478bd9Sstevel@tonic-gate uint_t tmp; 22027c478bd9Sstevel@tonic-gate 22037c478bd9Sstevel@tonic-gate tmp = (cp->cp_eax >> (8 * i)) & 0xff; 22047c478bd9Sstevel@tonic-gate if (tmp == 0x40) 22057c478bd9Sstevel@tonic-gate celeron++; 22067c478bd9Sstevel@tonic-gate if (tmp >= 0x44 && tmp <= 0x45) 22077c478bd9Sstevel@tonic-gate xeon++; 22087c478bd9Sstevel@tonic-gate } 22097c478bd9Sstevel@tonic-gate 22107c478bd9Sstevel@tonic-gate for (i = 0; i < 2; i++) { 22117c478bd9Sstevel@tonic-gate uint_t tmp; 22127c478bd9Sstevel@tonic-gate 22137c478bd9Sstevel@tonic-gate tmp = (cp->cp_ebx >> (8 * i)) & 0xff; 22147c478bd9Sstevel@tonic-gate if (tmp == 0x40) 22157c478bd9Sstevel@tonic-gate celeron++; 22167c478bd9Sstevel@tonic-gate else if (tmp >= 0x44 && tmp <= 0x45) 22177c478bd9Sstevel@tonic-gate xeon++; 22187c478bd9Sstevel@tonic-gate } 22197c478bd9Sstevel@tonic-gate 22207c478bd9Sstevel@tonic-gate for (i = 0; i < 4; i++) { 22217c478bd9Sstevel@tonic-gate uint_t tmp; 22227c478bd9Sstevel@tonic-gate 22237c478bd9Sstevel@tonic-gate tmp = (cp->cp_ecx >> (8 * i)) & 0xff; 22247c478bd9Sstevel@tonic-gate if (tmp == 0x40) 22257c478bd9Sstevel@tonic-gate celeron++; 22267c478bd9Sstevel@tonic-gate else if (tmp >= 0x44 && tmp <= 0x45) 22277c478bd9Sstevel@tonic-gate xeon++; 22287c478bd9Sstevel@tonic-gate } 22297c478bd9Sstevel@tonic-gate 22307c478bd9Sstevel@tonic-gate for (i = 0; i < 4; i++) { 22317c478bd9Sstevel@tonic-gate uint_t tmp; 22327c478bd9Sstevel@tonic-gate 22337c478bd9Sstevel@tonic-gate tmp = (cp->cp_edx >> (8 * i)) & 0xff; 22347c478bd9Sstevel@tonic-gate if (tmp == 0x40) 22357c478bd9Sstevel@tonic-gate celeron++; 22367c478bd9Sstevel@tonic-gate else if (tmp >= 0x44 && tmp <= 0x45) 22377c478bd9Sstevel@tonic-gate xeon++; 22387c478bd9Sstevel@tonic-gate } 22397c478bd9Sstevel@tonic-gate 22407c478bd9Sstevel@tonic-gate if (celeron) 22417c478bd9Sstevel@tonic-gate return ("Intel Celeron(r)"); 22427c478bd9Sstevel@tonic-gate if (xeon) 22437c478bd9Sstevel@tonic-gate return (cpi->cpi_model == 5 ? 22447c478bd9Sstevel@tonic-gate "Intel Pentium(r) II Xeon(tm)" : 22457c478bd9Sstevel@tonic-gate "Intel Pentium(r) III Xeon(tm)"); 22467c478bd9Sstevel@tonic-gate return (cpi->cpi_model == 5 ? 22477c478bd9Sstevel@tonic-gate "Intel Pentium(r) II or Pentium(r) II Xeon(tm)" : 22487c478bd9Sstevel@tonic-gate "Intel Pentium(r) III or Pentium(r) III Xeon(tm)"); 22497c478bd9Sstevel@tonic-gate default: 22507c478bd9Sstevel@tonic-gate break; 22517c478bd9Sstevel@tonic-gate } 22527c478bd9Sstevel@tonic-gate default: 22537c478bd9Sstevel@tonic-gate break; 22547c478bd9Sstevel@tonic-gate } 22557c478bd9Sstevel@tonic-gate 22565ff02082Sdmick /* BrandID is present if the field is nonzero */ 22575ff02082Sdmick if (cpi->cpi_brandid != 0) { 22587c478bd9Sstevel@tonic-gate static const struct { 22597c478bd9Sstevel@tonic-gate uint_t bt_bid; 22607c478bd9Sstevel@tonic-gate const char *bt_str; 22617c478bd9Sstevel@tonic-gate } brand_tbl[] = { 22627c478bd9Sstevel@tonic-gate { 0x1, "Intel(r) Celeron(r)" }, 22637c478bd9Sstevel@tonic-gate { 0x2, "Intel(r) Pentium(r) III" }, 22647c478bd9Sstevel@tonic-gate { 0x3, "Intel(r) Pentium(r) III Xeon(tm)" }, 22657c478bd9Sstevel@tonic-gate { 0x4, "Intel(r) Pentium(r) III" }, 22667c478bd9Sstevel@tonic-gate { 0x6, "Mobile Intel(r) Pentium(r) III" }, 22677c478bd9Sstevel@tonic-gate { 0x7, "Mobile Intel(r) Celeron(r)" }, 22687c478bd9Sstevel@tonic-gate { 0x8, "Intel(r) Pentium(r) 4" }, 22697c478bd9Sstevel@tonic-gate { 0x9, "Intel(r) Pentium(r) 4" }, 22707c478bd9Sstevel@tonic-gate { 0xa, "Intel(r) Celeron(r)" }, 22717c478bd9Sstevel@tonic-gate { 0xb, "Intel(r) Xeon(tm)" }, 22727c478bd9Sstevel@tonic-gate { 0xc, "Intel(r) Xeon(tm) MP" }, 22737c478bd9Sstevel@tonic-gate { 0xe, "Mobile Intel(r) Pentium(r) 4" }, 22745ff02082Sdmick { 0xf, "Mobile Intel(r) Celeron(r)" }, 22755ff02082Sdmick { 0x11, "Mobile Genuine Intel(r)" }, 22765ff02082Sdmick { 0x12, "Intel(r) Celeron(r) M" }, 22775ff02082Sdmick { 0x13, "Mobile Intel(r) Celeron(r)" }, 22785ff02082Sdmick { 0x14, "Intel(r) Celeron(r)" }, 22795ff02082Sdmick { 0x15, "Mobile Genuine Intel(r)" }, 22805ff02082Sdmick { 0x16, "Intel(r) Pentium(r) M" }, 22815ff02082Sdmick { 0x17, "Mobile Intel(r) Celeron(r)" } 22827c478bd9Sstevel@tonic-gate }; 22837c478bd9Sstevel@tonic-gate uint_t btblmax = sizeof (brand_tbl) / sizeof (brand_tbl[0]); 22847c478bd9Sstevel@tonic-gate uint_t sgn; 22857c478bd9Sstevel@tonic-gate 22867c478bd9Sstevel@tonic-gate sgn = (cpi->cpi_family << 8) | 22877c478bd9Sstevel@tonic-gate (cpi->cpi_model << 4) | cpi->cpi_step; 22887c478bd9Sstevel@tonic-gate 22897c478bd9Sstevel@tonic-gate for (i = 0; i < btblmax; i++) 22907c478bd9Sstevel@tonic-gate if (brand_tbl[i].bt_bid == cpi->cpi_brandid) 22917c478bd9Sstevel@tonic-gate break; 22927c478bd9Sstevel@tonic-gate if (i < btblmax) { 22937c478bd9Sstevel@tonic-gate if (sgn == 0x6b1 && cpi->cpi_brandid == 3) 22947c478bd9Sstevel@tonic-gate return ("Intel(r) Celeron(r)"); 22957c478bd9Sstevel@tonic-gate if (sgn < 0xf13 && cpi->cpi_brandid == 0xb) 22967c478bd9Sstevel@tonic-gate return ("Intel(r) Xeon(tm) MP"); 22977c478bd9Sstevel@tonic-gate if (sgn < 0xf13 && cpi->cpi_brandid == 0xe) 22987c478bd9Sstevel@tonic-gate return ("Intel(r) Xeon(tm)"); 22997c478bd9Sstevel@tonic-gate return (brand_tbl[i].bt_str); 23007c478bd9Sstevel@tonic-gate } 23017c478bd9Sstevel@tonic-gate } 23027c478bd9Sstevel@tonic-gate 23037c478bd9Sstevel@tonic-gate return (NULL); 23047c478bd9Sstevel@tonic-gate } 23057c478bd9Sstevel@tonic-gate 23067c478bd9Sstevel@tonic-gate static const char * 23077c478bd9Sstevel@tonic-gate amd_cpubrand(const struct cpuid_info *cpi) 23087c478bd9Sstevel@tonic-gate { 23097417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_CPUID) || 23107c478bd9Sstevel@tonic-gate cpi->cpi_maxeax < 1 || cpi->cpi_family < 5) 23117c478bd9Sstevel@tonic-gate return ("i486 compatible"); 23127c478bd9Sstevel@tonic-gate 23137c478bd9Sstevel@tonic-gate switch (cpi->cpi_family) { 23147c478bd9Sstevel@tonic-gate case 5: 23157c478bd9Sstevel@tonic-gate switch (cpi->cpi_model) { 23167c478bd9Sstevel@tonic-gate case 0: 23177c478bd9Sstevel@tonic-gate case 1: 23187c478bd9Sstevel@tonic-gate case 2: 23197c478bd9Sstevel@tonic-gate case 3: 23207c478bd9Sstevel@tonic-gate case 4: 23217c478bd9Sstevel@tonic-gate case 5: 23227c478bd9Sstevel@tonic-gate return ("AMD-K5(r)"); 23237c478bd9Sstevel@tonic-gate case 6: 23247c478bd9Sstevel@tonic-gate case 7: 23257c478bd9Sstevel@tonic-gate return ("AMD-K6(r)"); 23267c478bd9Sstevel@tonic-gate case 8: 23277c478bd9Sstevel@tonic-gate return ("AMD-K6(r)-2"); 23287c478bd9Sstevel@tonic-gate case 9: 23297c478bd9Sstevel@tonic-gate return ("AMD-K6(r)-III"); 23307c478bd9Sstevel@tonic-gate default: 23317c478bd9Sstevel@tonic-gate return ("AMD (family 5)"); 23327c478bd9Sstevel@tonic-gate } 23337c478bd9Sstevel@tonic-gate case 6: 23347c478bd9Sstevel@tonic-gate switch (cpi->cpi_model) { 23357c478bd9Sstevel@tonic-gate case 1: 23367c478bd9Sstevel@tonic-gate return ("AMD-K7(tm)"); 23377c478bd9Sstevel@tonic-gate case 0: 23387c478bd9Sstevel@tonic-gate case 2: 23397c478bd9Sstevel@tonic-gate case 4: 23407c478bd9Sstevel@tonic-gate return ("AMD Athlon(tm)"); 23417c478bd9Sstevel@tonic-gate case 3: 23427c478bd9Sstevel@tonic-gate case 7: 23437c478bd9Sstevel@tonic-gate return ("AMD Duron(tm)"); 23447c478bd9Sstevel@tonic-gate case 6: 23457c478bd9Sstevel@tonic-gate case 8: 23467c478bd9Sstevel@tonic-gate case 10: 23477c478bd9Sstevel@tonic-gate /* 23487c478bd9Sstevel@tonic-gate * Use the L2 cache size to distinguish 23497c478bd9Sstevel@tonic-gate */ 23507c478bd9Sstevel@tonic-gate return ((cpi->cpi_extd[6].cp_ecx >> 16) >= 256 ? 23517c478bd9Sstevel@tonic-gate "AMD Athlon(tm)" : "AMD Duron(tm)"); 23527c478bd9Sstevel@tonic-gate default: 23537c478bd9Sstevel@tonic-gate return ("AMD (family 6)"); 23547c478bd9Sstevel@tonic-gate } 23557c478bd9Sstevel@tonic-gate default: 23567c478bd9Sstevel@tonic-gate break; 23577c478bd9Sstevel@tonic-gate } 23587c478bd9Sstevel@tonic-gate 23597c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 0xf && cpi->cpi_model == 5 && 23607c478bd9Sstevel@tonic-gate cpi->cpi_brandid != 0) { 23617c478bd9Sstevel@tonic-gate switch (BITX(cpi->cpi_brandid, 7, 5)) { 23627c478bd9Sstevel@tonic-gate case 3: 23637c478bd9Sstevel@tonic-gate return ("AMD Opteron(tm) UP 1xx"); 23647c478bd9Sstevel@tonic-gate case 4: 23657c478bd9Sstevel@tonic-gate return ("AMD Opteron(tm) DP 2xx"); 23667c478bd9Sstevel@tonic-gate case 5: 23677c478bd9Sstevel@tonic-gate return ("AMD Opteron(tm) MP 8xx"); 23687c478bd9Sstevel@tonic-gate default: 23697c478bd9Sstevel@tonic-gate return ("AMD Opteron(tm)"); 23707c478bd9Sstevel@tonic-gate } 23717c478bd9Sstevel@tonic-gate } 23727c478bd9Sstevel@tonic-gate 23737c478bd9Sstevel@tonic-gate return (NULL); 23747c478bd9Sstevel@tonic-gate } 23757c478bd9Sstevel@tonic-gate 23767c478bd9Sstevel@tonic-gate static const char * 23777c478bd9Sstevel@tonic-gate cyrix_cpubrand(struct cpuid_info *cpi, uint_t type) 23787c478bd9Sstevel@tonic-gate { 23797417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_CPUID) || 23807c478bd9Sstevel@tonic-gate cpi->cpi_maxeax < 1 || cpi->cpi_family < 5 || 23817c478bd9Sstevel@tonic-gate type == X86_TYPE_CYRIX_486) 23827c478bd9Sstevel@tonic-gate return ("i486 compatible"); 23837c478bd9Sstevel@tonic-gate 23847c478bd9Sstevel@tonic-gate switch (type) { 23857c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_6x86: 23867c478bd9Sstevel@tonic-gate return ("Cyrix 6x86"); 23877c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_6x86L: 23887c478bd9Sstevel@tonic-gate return ("Cyrix 6x86L"); 23897c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_6x86MX: 23907c478bd9Sstevel@tonic-gate return ("Cyrix 6x86MX"); 23917c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_GXm: 23927c478bd9Sstevel@tonic-gate return ("Cyrix GXm"); 23937c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_MediaGX: 23947c478bd9Sstevel@tonic-gate return ("Cyrix MediaGX"); 23957c478bd9Sstevel@tonic-gate case X86_TYPE_CYRIX_MII: 23967c478bd9Sstevel@tonic-gate return ("Cyrix M2"); 23977c478bd9Sstevel@tonic-gate case X86_TYPE_VIA_CYRIX_III: 23987c478bd9Sstevel@tonic-gate return ("VIA Cyrix M3"); 23997c478bd9Sstevel@tonic-gate default: 24007c478bd9Sstevel@tonic-gate /* 24017c478bd9Sstevel@tonic-gate * Have another wild guess .. 24027c478bd9Sstevel@tonic-gate */ 24037c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 4 && cpi->cpi_model == 9) 24047c478bd9Sstevel@tonic-gate return ("Cyrix 5x86"); 24057c478bd9Sstevel@tonic-gate else if (cpi->cpi_family == 5) { 24067c478bd9Sstevel@tonic-gate switch (cpi->cpi_model) { 24077c478bd9Sstevel@tonic-gate case 2: 24087c478bd9Sstevel@tonic-gate return ("Cyrix 6x86"); /* Cyrix M1 */ 24097c478bd9Sstevel@tonic-gate case 4: 24107c478bd9Sstevel@tonic-gate return ("Cyrix MediaGX"); 24117c478bd9Sstevel@tonic-gate default: 24127c478bd9Sstevel@tonic-gate break; 24137c478bd9Sstevel@tonic-gate } 24147c478bd9Sstevel@tonic-gate } else if (cpi->cpi_family == 6) { 24157c478bd9Sstevel@tonic-gate switch (cpi->cpi_model) { 24167c478bd9Sstevel@tonic-gate case 0: 24177c478bd9Sstevel@tonic-gate return ("Cyrix 6x86MX"); /* Cyrix M2? */ 24187c478bd9Sstevel@tonic-gate case 5: 24197c478bd9Sstevel@tonic-gate case 6: 24207c478bd9Sstevel@tonic-gate case 7: 24217c478bd9Sstevel@tonic-gate case 8: 24227c478bd9Sstevel@tonic-gate case 9: 24237c478bd9Sstevel@tonic-gate return ("VIA C3"); 24247c478bd9Sstevel@tonic-gate default: 24257c478bd9Sstevel@tonic-gate break; 24267c478bd9Sstevel@tonic-gate } 24277c478bd9Sstevel@tonic-gate } 24287c478bd9Sstevel@tonic-gate break; 24297c478bd9Sstevel@tonic-gate } 24307c478bd9Sstevel@tonic-gate return (NULL); 24317c478bd9Sstevel@tonic-gate } 24327c478bd9Sstevel@tonic-gate 24337c478bd9Sstevel@tonic-gate /* 24347c478bd9Sstevel@tonic-gate * This only gets called in the case that the CPU extended 24357c478bd9Sstevel@tonic-gate * feature brand string (0x80000002, 0x80000003, 0x80000004) 24367c478bd9Sstevel@tonic-gate * aren't available, or contain null bytes for some reason. 24377c478bd9Sstevel@tonic-gate */ 24387c478bd9Sstevel@tonic-gate static void 24397c478bd9Sstevel@tonic-gate fabricate_brandstr(struct cpuid_info *cpi) 24407c478bd9Sstevel@tonic-gate { 24417c478bd9Sstevel@tonic-gate const char *brand = NULL; 24427c478bd9Sstevel@tonic-gate 24437c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 24447c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 24457c478bd9Sstevel@tonic-gate brand = intel_cpubrand(cpi); 24467c478bd9Sstevel@tonic-gate break; 24477c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 24487c478bd9Sstevel@tonic-gate brand = amd_cpubrand(cpi); 24497c478bd9Sstevel@tonic-gate break; 24507c478bd9Sstevel@tonic-gate case X86_VENDOR_Cyrix: 24517c478bd9Sstevel@tonic-gate brand = cyrix_cpubrand(cpi, x86_type); 24527c478bd9Sstevel@tonic-gate break; 24537c478bd9Sstevel@tonic-gate case X86_VENDOR_NexGen: 24547c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 5 && cpi->cpi_model == 0) 24557c478bd9Sstevel@tonic-gate brand = "NexGen Nx586"; 24567c478bd9Sstevel@tonic-gate break; 24577c478bd9Sstevel@tonic-gate case X86_VENDOR_Centaur: 24587c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 5) 24597c478bd9Sstevel@tonic-gate switch (cpi->cpi_model) { 24607c478bd9Sstevel@tonic-gate case 4: 24617c478bd9Sstevel@tonic-gate brand = "Centaur C6"; 24627c478bd9Sstevel@tonic-gate break; 24637c478bd9Sstevel@tonic-gate case 8: 24647c478bd9Sstevel@tonic-gate brand = "Centaur C2"; 24657c478bd9Sstevel@tonic-gate break; 24667c478bd9Sstevel@tonic-gate case 9: 24677c478bd9Sstevel@tonic-gate brand = "Centaur C3"; 24687c478bd9Sstevel@tonic-gate break; 24697c478bd9Sstevel@tonic-gate default: 24707c478bd9Sstevel@tonic-gate break; 24717c478bd9Sstevel@tonic-gate } 24727c478bd9Sstevel@tonic-gate break; 24737c478bd9Sstevel@tonic-gate case X86_VENDOR_Rise: 24747c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 5 && 24757c478bd9Sstevel@tonic-gate (cpi->cpi_model == 0 || cpi->cpi_model == 2)) 24767c478bd9Sstevel@tonic-gate brand = "Rise mP6"; 24777c478bd9Sstevel@tonic-gate break; 24787c478bd9Sstevel@tonic-gate case X86_VENDOR_SiS: 24797c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 5 && cpi->cpi_model == 0) 24807c478bd9Sstevel@tonic-gate brand = "SiS 55x"; 24817c478bd9Sstevel@tonic-gate break; 24827c478bd9Sstevel@tonic-gate case X86_VENDOR_TM: 24837c478bd9Sstevel@tonic-gate if (cpi->cpi_family == 5 && cpi->cpi_model == 4) 24847c478bd9Sstevel@tonic-gate brand = "Transmeta Crusoe TM3x00 or TM5x00"; 24857c478bd9Sstevel@tonic-gate break; 24867c478bd9Sstevel@tonic-gate case X86_VENDOR_NSC: 24877c478bd9Sstevel@tonic-gate case X86_VENDOR_UMC: 24887c478bd9Sstevel@tonic-gate default: 24897c478bd9Sstevel@tonic-gate break; 24907c478bd9Sstevel@tonic-gate } 24917c478bd9Sstevel@tonic-gate if (brand) { 24927c478bd9Sstevel@tonic-gate (void) strcpy((char *)cpi->cpi_brandstr, brand); 24937c478bd9Sstevel@tonic-gate return; 24947c478bd9Sstevel@tonic-gate } 24957c478bd9Sstevel@tonic-gate 24967c478bd9Sstevel@tonic-gate /* 24977c478bd9Sstevel@tonic-gate * If all else fails ... 24987c478bd9Sstevel@tonic-gate */ 24997c478bd9Sstevel@tonic-gate (void) snprintf(cpi->cpi_brandstr, sizeof (cpi->cpi_brandstr), 25007c478bd9Sstevel@tonic-gate "%s %d.%d.%d", cpi->cpi_vendorstr, cpi->cpi_family, 25017c478bd9Sstevel@tonic-gate cpi->cpi_model, cpi->cpi_step); 25027c478bd9Sstevel@tonic-gate } 25037c478bd9Sstevel@tonic-gate 25047c478bd9Sstevel@tonic-gate /* 25057c478bd9Sstevel@tonic-gate * This routine is called just after kernel memory allocation 25067c478bd9Sstevel@tonic-gate * becomes available on cpu0, and as part of mp_startup() on 25077c478bd9Sstevel@tonic-gate * the other cpus. 25087c478bd9Sstevel@tonic-gate * 2509d129bde2Sesaxe * Fixup the brand string, and collect any information from cpuid 251079ec9da8SYuri Pankov * that requires dynamically allocated storage to represent. 25117c478bd9Sstevel@tonic-gate */ 25127c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 25137c478bd9Sstevel@tonic-gate void 25147c478bd9Sstevel@tonic-gate cpuid_pass3(cpu_t *cpu) 25157c478bd9Sstevel@tonic-gate { 2516d129bde2Sesaxe int i, max, shft, level, size; 2517d129bde2Sesaxe struct cpuid_regs regs; 2518d129bde2Sesaxe struct cpuid_regs *cp; 25197c478bd9Sstevel@tonic-gate struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi; 25207c478bd9Sstevel@tonic-gate 25217c478bd9Sstevel@tonic-gate ASSERT(cpi->cpi_pass == 2); 25227c478bd9Sstevel@tonic-gate 2523d129bde2Sesaxe /* 2524d129bde2Sesaxe * Function 4: Deterministic cache parameters 2525d129bde2Sesaxe * 2526d129bde2Sesaxe * Take this opportunity to detect the number of threads 2527d129bde2Sesaxe * sharing the last level cache, and construct a corresponding 2528d129bde2Sesaxe * cache id. The respective cpuid_info members are initialized 2529d129bde2Sesaxe * to the default case of "no last level cache sharing". 2530d129bde2Sesaxe */ 2531d129bde2Sesaxe cpi->cpi_ncpu_shr_last_cache = 1; 2532d129bde2Sesaxe cpi->cpi_last_lvl_cacheid = cpu->cpu_id; 2533d129bde2Sesaxe 2534d129bde2Sesaxe if (cpi->cpi_maxeax >= 4 && cpi->cpi_vendor == X86_VENDOR_Intel) { 2535d129bde2Sesaxe 2536d129bde2Sesaxe /* 2537d129bde2Sesaxe * Find the # of elements (size) returned by fn 4, and along 2538d129bde2Sesaxe * the way detect last level cache sharing details. 2539d129bde2Sesaxe */ 2540d129bde2Sesaxe bzero(®s, sizeof (regs)); 2541d129bde2Sesaxe cp = ®s; 2542d129bde2Sesaxe for (i = 0, max = 0; i < CPI_FN4_ECX_MAX; i++) { 2543d129bde2Sesaxe cp->cp_eax = 4; 2544d129bde2Sesaxe cp->cp_ecx = i; 2545d129bde2Sesaxe 2546d129bde2Sesaxe (void) __cpuid_insn(cp); 2547d129bde2Sesaxe 2548d129bde2Sesaxe if (CPI_CACHE_TYPE(cp) == 0) 2549d129bde2Sesaxe break; 2550d129bde2Sesaxe level = CPI_CACHE_LVL(cp); 2551d129bde2Sesaxe if (level > max) { 2552d129bde2Sesaxe max = level; 2553d129bde2Sesaxe cpi->cpi_ncpu_shr_last_cache = 2554d129bde2Sesaxe CPI_NTHR_SHR_CACHE(cp) + 1; 2555d129bde2Sesaxe } 2556d129bde2Sesaxe } 2557d129bde2Sesaxe cpi->cpi_std_4_size = size = i; 2558d129bde2Sesaxe 2559d129bde2Sesaxe /* 2560d129bde2Sesaxe * Allocate the cpi_std_4 array. The first element 2561d129bde2Sesaxe * references the regs for fn 4, %ecx == 0, which 2562d129bde2Sesaxe * cpuid_pass2() stashed in cpi->cpi_std[4]. 2563d129bde2Sesaxe */ 2564d129bde2Sesaxe if (size > 0) { 2565d129bde2Sesaxe cpi->cpi_std_4 = 2566d129bde2Sesaxe kmem_alloc(size * sizeof (cp), KM_SLEEP); 2567d129bde2Sesaxe cpi->cpi_std_4[0] = &cpi->cpi_std[4]; 2568d129bde2Sesaxe 2569d129bde2Sesaxe /* 2570d129bde2Sesaxe * Allocate storage to hold the additional regs 2571d129bde2Sesaxe * for function 4, %ecx == 1 .. cpi_std_4_size. 2572d129bde2Sesaxe * 2573d129bde2Sesaxe * The regs for fn 4, %ecx == 0 has already 2574d129bde2Sesaxe * been allocated as indicated above. 2575d129bde2Sesaxe */ 2576d129bde2Sesaxe for (i = 1; i < size; i++) { 2577d129bde2Sesaxe cp = cpi->cpi_std_4[i] = 2578d129bde2Sesaxe kmem_zalloc(sizeof (regs), KM_SLEEP); 2579d129bde2Sesaxe cp->cp_eax = 4; 2580d129bde2Sesaxe cp->cp_ecx = i; 2581d129bde2Sesaxe 2582d129bde2Sesaxe (void) __cpuid_insn(cp); 2583d129bde2Sesaxe } 2584d129bde2Sesaxe } 2585d129bde2Sesaxe /* 2586d129bde2Sesaxe * Determine the number of bits needed to represent 2587d129bde2Sesaxe * the number of CPUs sharing the last level cache. 2588d129bde2Sesaxe * 2589d129bde2Sesaxe * Shift off that number of bits from the APIC id to 2590d129bde2Sesaxe * derive the cache id. 2591d129bde2Sesaxe */ 2592d129bde2Sesaxe shft = 0; 2593d129bde2Sesaxe for (i = 1; i < cpi->cpi_ncpu_shr_last_cache; i <<= 1) 2594d129bde2Sesaxe shft++; 2595b6917abeSmishra cpi->cpi_last_lvl_cacheid = cpi->cpi_apicid >> shft; 2596d129bde2Sesaxe } 2597d129bde2Sesaxe 2598d129bde2Sesaxe /* 2599d129bde2Sesaxe * Now fixup the brand string 2600d129bde2Sesaxe */ 26017c478bd9Sstevel@tonic-gate if ((cpi->cpi_xmaxeax & 0x80000000) == 0) { 26027c478bd9Sstevel@tonic-gate fabricate_brandstr(cpi); 2603d129bde2Sesaxe } else { 26047c478bd9Sstevel@tonic-gate 26057c478bd9Sstevel@tonic-gate /* 26067c478bd9Sstevel@tonic-gate * If we successfully extracted a brand string from the cpuid 26077c478bd9Sstevel@tonic-gate * instruction, clean it up by removing leading spaces and 26087c478bd9Sstevel@tonic-gate * similar junk. 26097c478bd9Sstevel@tonic-gate */ 26107c478bd9Sstevel@tonic-gate if (cpi->cpi_brandstr[0]) { 26117c478bd9Sstevel@tonic-gate size_t maxlen = sizeof (cpi->cpi_brandstr); 26127c478bd9Sstevel@tonic-gate char *src, *dst; 26137c478bd9Sstevel@tonic-gate 26147c478bd9Sstevel@tonic-gate dst = src = (char *)cpi->cpi_brandstr; 26157c478bd9Sstevel@tonic-gate src[maxlen - 1] = '\0'; 26167c478bd9Sstevel@tonic-gate /* 26177c478bd9Sstevel@tonic-gate * strip leading spaces 26187c478bd9Sstevel@tonic-gate */ 26197c478bd9Sstevel@tonic-gate while (*src == ' ') 26207c478bd9Sstevel@tonic-gate src++; 26217c478bd9Sstevel@tonic-gate /* 26227c478bd9Sstevel@tonic-gate * Remove any 'Genuine' or "Authentic" prefixes 26237c478bd9Sstevel@tonic-gate */ 26247c478bd9Sstevel@tonic-gate if (strncmp(src, "Genuine ", 8) == 0) 26257c478bd9Sstevel@tonic-gate src += 8; 26267c478bd9Sstevel@tonic-gate if (strncmp(src, "Authentic ", 10) == 0) 26277c478bd9Sstevel@tonic-gate src += 10; 26287c478bd9Sstevel@tonic-gate 26297c478bd9Sstevel@tonic-gate /* 26307c478bd9Sstevel@tonic-gate * Now do an in-place copy. 26317c478bd9Sstevel@tonic-gate * Map (R) to (r) and (TM) to (tm). 26327c478bd9Sstevel@tonic-gate * The era of teletypes is long gone, and there's 26337c478bd9Sstevel@tonic-gate * -really- no need to shout. 26347c478bd9Sstevel@tonic-gate */ 26357c478bd9Sstevel@tonic-gate while (*src != '\0') { 26367c478bd9Sstevel@tonic-gate if (src[0] == '(') { 26377c478bd9Sstevel@tonic-gate if (strncmp(src + 1, "R)", 2) == 0) { 26387c478bd9Sstevel@tonic-gate (void) strncpy(dst, "(r)", 3); 26397c478bd9Sstevel@tonic-gate src += 3; 26407c478bd9Sstevel@tonic-gate dst += 3; 26417c478bd9Sstevel@tonic-gate continue; 26427c478bd9Sstevel@tonic-gate } 26437c478bd9Sstevel@tonic-gate if (strncmp(src + 1, "TM)", 3) == 0) { 26447c478bd9Sstevel@tonic-gate (void) strncpy(dst, "(tm)", 4); 26457c478bd9Sstevel@tonic-gate src += 4; 26467c478bd9Sstevel@tonic-gate dst += 4; 26477c478bd9Sstevel@tonic-gate continue; 26487c478bd9Sstevel@tonic-gate } 26497c478bd9Sstevel@tonic-gate } 26507c478bd9Sstevel@tonic-gate *dst++ = *src++; 26517c478bd9Sstevel@tonic-gate } 26527c478bd9Sstevel@tonic-gate *dst = '\0'; 26537c478bd9Sstevel@tonic-gate 26547c478bd9Sstevel@tonic-gate /* 26557c478bd9Sstevel@tonic-gate * Finally, remove any trailing spaces 26567c478bd9Sstevel@tonic-gate */ 26577c478bd9Sstevel@tonic-gate while (--dst > cpi->cpi_brandstr) 26587c478bd9Sstevel@tonic-gate if (*dst == ' ') 26597c478bd9Sstevel@tonic-gate *dst = '\0'; 26607c478bd9Sstevel@tonic-gate else 26617c478bd9Sstevel@tonic-gate break; 26627c478bd9Sstevel@tonic-gate } else 26637c478bd9Sstevel@tonic-gate fabricate_brandstr(cpi); 2664d129bde2Sesaxe } 26657c478bd9Sstevel@tonic-gate cpi->cpi_pass = 3; 26667c478bd9Sstevel@tonic-gate } 26677c478bd9Sstevel@tonic-gate 26687c478bd9Sstevel@tonic-gate /* 26697c478bd9Sstevel@tonic-gate * This routine is called out of bind_hwcap() much later in the life 26707c478bd9Sstevel@tonic-gate * of the kernel (post_startup()). The job of this routine is to resolve 26717c478bd9Sstevel@tonic-gate * the hardware feature support and kernel support for those features into 26727c478bd9Sstevel@tonic-gate * what we're actually going to tell applications via the aux vector. 26737c478bd9Sstevel@tonic-gate */ 2674ebb8ac07SRobert Mustacchi void 2675ebb8ac07SRobert Mustacchi cpuid_pass4(cpu_t *cpu, uint_t *hwcap_out) 26767c478bd9Sstevel@tonic-gate { 26777c478bd9Sstevel@tonic-gate struct cpuid_info *cpi; 2678ebb8ac07SRobert Mustacchi uint_t hwcap_flags = 0, hwcap_flags_2 = 0; 26797c478bd9Sstevel@tonic-gate 26807c478bd9Sstevel@tonic-gate if (cpu == NULL) 26817c478bd9Sstevel@tonic-gate cpu = CPU; 26827c478bd9Sstevel@tonic-gate cpi = cpu->cpu_m.mcpu_cpi; 26837c478bd9Sstevel@tonic-gate 26847c478bd9Sstevel@tonic-gate ASSERT(cpi->cpi_pass == 3); 26857c478bd9Sstevel@tonic-gate 26867c478bd9Sstevel@tonic-gate if (cpi->cpi_maxeax >= 1) { 26877c478bd9Sstevel@tonic-gate uint32_t *edx = &cpi->cpi_support[STD_EDX_FEATURES]; 26887c478bd9Sstevel@tonic-gate uint32_t *ecx = &cpi->cpi_support[STD_ECX_FEATURES]; 2689245ac945SRobert Mustacchi uint32_t *ebx = &cpi->cpi_support[STD_EBX_FEATURES]; 26907c478bd9Sstevel@tonic-gate 26917c478bd9Sstevel@tonic-gate *edx = CPI_FEATURES_EDX(cpi); 26927c478bd9Sstevel@tonic-gate *ecx = CPI_FEATURES_ECX(cpi); 2693245ac945SRobert Mustacchi *ebx = CPI_FEATURES_7_0_EBX(cpi); 26947c478bd9Sstevel@tonic-gate 26957c478bd9Sstevel@tonic-gate /* 26967c478bd9Sstevel@tonic-gate * [these require explicit kernel support] 26977c478bd9Sstevel@tonic-gate */ 26987417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_SEP)) 26997c478bd9Sstevel@tonic-gate *edx &= ~CPUID_INTC_EDX_SEP; 27007c478bd9Sstevel@tonic-gate 27017417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_SSE)) 27027c478bd9Sstevel@tonic-gate *edx &= ~(CPUID_INTC_EDX_FXSR|CPUID_INTC_EDX_SSE); 27037417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_SSE2)) 27047c478bd9Sstevel@tonic-gate *edx &= ~CPUID_INTC_EDX_SSE2; 27057c478bd9Sstevel@tonic-gate 27067417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_HTT)) 27077c478bd9Sstevel@tonic-gate *edx &= ~CPUID_INTC_EDX_HTT; 27087c478bd9Sstevel@tonic-gate 27097417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_SSE3)) 27107c478bd9Sstevel@tonic-gate *ecx &= ~CPUID_INTC_ECX_SSE3; 27117c478bd9Sstevel@tonic-gate 27127417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_SSSE3)) 2713d0f8ff6eSkk208521 *ecx &= ~CPUID_INTC_ECX_SSSE3; 27147417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_SSE4_1)) 2715d0f8ff6eSkk208521 *ecx &= ~CPUID_INTC_ECX_SSE4_1; 27167417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_SSE4_2)) 2717d0f8ff6eSkk208521 *ecx &= ~CPUID_INTC_ECX_SSE4_2; 27187417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_AES)) 2719a50a8b93SKuriakose Kuruvilla *ecx &= ~CPUID_INTC_ECX_AES; 27207417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_PCLMULQDQ)) 27217417cfdeSKuriakose Kuruvilla *ecx &= ~CPUID_INTC_ECX_PCLMULQDQ; 27227af88ac7SKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_XSAVE)) 27237af88ac7SKuriakose Kuruvilla *ecx &= ~(CPUID_INTC_ECX_XSAVE | 27247af88ac7SKuriakose Kuruvilla CPUID_INTC_ECX_OSXSAVE); 27257af88ac7SKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_AVX)) 27267af88ac7SKuriakose Kuruvilla *ecx &= ~CPUID_INTC_ECX_AVX; 2727ebb8ac07SRobert Mustacchi if (!is_x86_feature(x86_featureset, X86FSET_F16C)) 2728ebb8ac07SRobert Mustacchi *ecx &= ~CPUID_INTC_ECX_F16C; 2729245ac945SRobert Mustacchi if (!is_x86_feature(x86_featureset, X86FSET_FMA)) 2730245ac945SRobert Mustacchi *ecx &= ~CPUID_INTC_ECX_FMA; 2731245ac945SRobert Mustacchi if (!is_x86_feature(x86_featureset, X86FSET_BMI1)) 2732245ac945SRobert Mustacchi *ebx &= ~CPUID_INTC_EBX_7_0_BMI1; 2733245ac945SRobert Mustacchi if (!is_x86_feature(x86_featureset, X86FSET_BMI2)) 2734245ac945SRobert Mustacchi *ebx &= ~CPUID_INTC_EBX_7_0_BMI2; 2735245ac945SRobert Mustacchi if (!is_x86_feature(x86_featureset, X86FSET_AVX2)) 2736245ac945SRobert Mustacchi *ebx &= ~CPUID_INTC_EBX_7_0_AVX2; 2737a3623a38SRobert Mustacchi if (!is_x86_feature(x86_featureset, X86FSET_RDSEED)) 2738a3623a38SRobert Mustacchi *ebx &= ~CPUID_INTC_EBX_7_0_RDSEED; 2739a3623a38SRobert Mustacchi if (!is_x86_feature(x86_featureset, X86FSET_ADX)) 2740a3623a38SRobert Mustacchi *ebx &= ~CPUID_INTC_EBX_7_0_ADX; 2741d0f8ff6eSkk208521 27427c478bd9Sstevel@tonic-gate /* 27437c478bd9Sstevel@tonic-gate * [no explicit support required beyond x87 fp context] 27447c478bd9Sstevel@tonic-gate */ 27457c478bd9Sstevel@tonic-gate if (!fpu_exists) 27467c478bd9Sstevel@tonic-gate *edx &= ~(CPUID_INTC_EDX_FPU | CPUID_INTC_EDX_MMX); 27477c478bd9Sstevel@tonic-gate 27487c478bd9Sstevel@tonic-gate /* 27497c478bd9Sstevel@tonic-gate * Now map the supported feature vector to things that we 27507c478bd9Sstevel@tonic-gate * think userland will care about. 27517c478bd9Sstevel@tonic-gate */ 27527c478bd9Sstevel@tonic-gate if (*edx & CPUID_INTC_EDX_SEP) 27537c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_SEP; 27547c478bd9Sstevel@tonic-gate if (*edx & CPUID_INTC_EDX_SSE) 27557c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_FXSR | AV_386_SSE; 27567c478bd9Sstevel@tonic-gate if (*edx & CPUID_INTC_EDX_SSE2) 27577c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_SSE2; 27587c478bd9Sstevel@tonic-gate if (*ecx & CPUID_INTC_ECX_SSE3) 27597c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_SSE3; 2760d0f8ff6eSkk208521 if (*ecx & CPUID_INTC_ECX_SSSE3) 2761d0f8ff6eSkk208521 hwcap_flags |= AV_386_SSSE3; 2762d0f8ff6eSkk208521 if (*ecx & CPUID_INTC_ECX_SSE4_1) 2763d0f8ff6eSkk208521 hwcap_flags |= AV_386_SSE4_1; 2764d0f8ff6eSkk208521 if (*ecx & CPUID_INTC_ECX_SSE4_2) 2765d0f8ff6eSkk208521 hwcap_flags |= AV_386_SSE4_2; 27665087e485SKrishnendu Sadhukhan - Sun Microsystems if (*ecx & CPUID_INTC_ECX_MOVBE) 27675087e485SKrishnendu Sadhukhan - Sun Microsystems hwcap_flags |= AV_386_MOVBE; 2768a50a8b93SKuriakose Kuruvilla if (*ecx & CPUID_INTC_ECX_AES) 2769a50a8b93SKuriakose Kuruvilla hwcap_flags |= AV_386_AES; 2770a50a8b93SKuriakose Kuruvilla if (*ecx & CPUID_INTC_ECX_PCLMULQDQ) 2771a50a8b93SKuriakose Kuruvilla hwcap_flags |= AV_386_PCLMULQDQ; 27727af88ac7SKuriakose Kuruvilla if ((*ecx & CPUID_INTC_ECX_XSAVE) && 2773f3390f39SRobert Mustacchi (*ecx & CPUID_INTC_ECX_OSXSAVE)) { 27747af88ac7SKuriakose Kuruvilla hwcap_flags |= AV_386_XSAVE; 2775f3390f39SRobert Mustacchi 2776ebb8ac07SRobert Mustacchi if (*ecx & CPUID_INTC_ECX_AVX) { 2777f3390f39SRobert Mustacchi hwcap_flags |= AV_386_AVX; 2778ebb8ac07SRobert Mustacchi if (*ecx & CPUID_INTC_ECX_F16C) 2779ebb8ac07SRobert Mustacchi hwcap_flags_2 |= AV_386_2_F16C; 2780245ac945SRobert Mustacchi if (*ecx & CPUID_INTC_ECX_FMA) 2781245ac945SRobert Mustacchi hwcap_flags_2 |= AV_386_2_FMA; 2782245ac945SRobert Mustacchi if (*ebx & CPUID_INTC_EBX_7_0_BMI1) 2783245ac945SRobert Mustacchi hwcap_flags_2 |= AV_386_2_BMI1; 2784245ac945SRobert Mustacchi if (*ebx & CPUID_INTC_EBX_7_0_BMI2) 2785245ac945SRobert Mustacchi hwcap_flags_2 |= AV_386_2_BMI2; 2786245ac945SRobert Mustacchi if (*ebx & CPUID_INTC_EBX_7_0_AVX2) 2787245ac945SRobert Mustacchi hwcap_flags_2 |= AV_386_2_AVX2; 2788ebb8ac07SRobert Mustacchi } 2789f3390f39SRobert Mustacchi } 2790faa20166SBryan Cantrill if (*ecx & CPUID_INTC_ECX_VMX) 2791faa20166SBryan Cantrill hwcap_flags |= AV_386_VMX; 2792f8801251Skk208521 if (*ecx & CPUID_INTC_ECX_POPCNT) 2793f8801251Skk208521 hwcap_flags |= AV_386_POPCNT; 27947c478bd9Sstevel@tonic-gate if (*edx & CPUID_INTC_EDX_FPU) 27957c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_FPU; 27967c478bd9Sstevel@tonic-gate if (*edx & CPUID_INTC_EDX_MMX) 27977c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_MMX; 27987c478bd9Sstevel@tonic-gate 27997c478bd9Sstevel@tonic-gate if (*edx & CPUID_INTC_EDX_TSC) 28007c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_TSC; 28017c478bd9Sstevel@tonic-gate if (*edx & CPUID_INTC_EDX_CX8) 28027c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_CX8; 28037c478bd9Sstevel@tonic-gate if (*edx & CPUID_INTC_EDX_CMOV) 28047c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_CMOV; 28057c478bd9Sstevel@tonic-gate if (*ecx & CPUID_INTC_ECX_CX16) 28067c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_CX16; 2807ebb8ac07SRobert Mustacchi 2808ebb8ac07SRobert Mustacchi if (*ecx & CPUID_INTC_ECX_RDRAND) 2809ebb8ac07SRobert Mustacchi hwcap_flags_2 |= AV_386_2_RDRAND; 2810a3623a38SRobert Mustacchi if (*ebx & CPUID_INTC_EBX_7_0_ADX) 2811a3623a38SRobert Mustacchi hwcap_flags_2 |= AV_386_2_ADX; 2812a3623a38SRobert Mustacchi if (*ebx & CPUID_INTC_EBX_7_0_RDSEED) 2813a3623a38SRobert Mustacchi hwcap_flags_2 |= AV_386_2_RDSEED; 2814*b8f64308SRobert Mustacchi if (*ebx & CPUID_INTC_EBX_7_0_SHA) 2815*b8f64308SRobert Mustacchi hwcap_flags_2 |= AV_386_2_SHA; 2816a3623a38SRobert Mustacchi 28177c478bd9Sstevel@tonic-gate } 28187c478bd9Sstevel@tonic-gate 28197c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax < 0x80000001) 28207c478bd9Sstevel@tonic-gate goto pass4_done; 28217c478bd9Sstevel@tonic-gate 28227c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 28238949bcd6Sandrei struct cpuid_regs cp; 2824ae115bc7Smrj uint32_t *edx, *ecx; 28257c478bd9Sstevel@tonic-gate 2826ae115bc7Smrj case X86_VENDOR_Intel: 2827ae115bc7Smrj /* 2828ae115bc7Smrj * Seems like Intel duplicated what we necessary 2829ae115bc7Smrj * here to make the initial crop of 64-bit OS's work. 2830ae115bc7Smrj * Hopefully, those are the only "extended" bits 2831ae115bc7Smrj * they'll add. 2832ae115bc7Smrj */ 2833ae115bc7Smrj /*FALLTHROUGH*/ 2834ae115bc7Smrj 28357c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 28367c478bd9Sstevel@tonic-gate edx = &cpi->cpi_support[AMD_EDX_FEATURES]; 2837ae115bc7Smrj ecx = &cpi->cpi_support[AMD_ECX_FEATURES]; 28387c478bd9Sstevel@tonic-gate 28397c478bd9Sstevel@tonic-gate *edx = CPI_FEATURES_XTD_EDX(cpi); 2840ae115bc7Smrj *ecx = CPI_FEATURES_XTD_ECX(cpi); 2841ae115bc7Smrj 2842ae115bc7Smrj /* 2843ae115bc7Smrj * [these features require explicit kernel support] 2844ae115bc7Smrj */ 2845ae115bc7Smrj switch (cpi->cpi_vendor) { 2846ae115bc7Smrj case X86_VENDOR_Intel: 28477417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_TSCP)) 2848d36ea5d8Ssudheer *edx &= ~CPUID_AMD_EDX_TSCP; 2849ae115bc7Smrj break; 2850ae115bc7Smrj 2851ae115bc7Smrj case X86_VENDOR_AMD: 28527417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_TSCP)) 2853ae115bc7Smrj *edx &= ~CPUID_AMD_EDX_TSCP; 28547417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_SSE4A)) 2855f8801251Skk208521 *ecx &= ~CPUID_AMD_ECX_SSE4A; 2856ae115bc7Smrj break; 2857ae115bc7Smrj 2858ae115bc7Smrj default: 2859ae115bc7Smrj break; 2860ae115bc7Smrj } 28617c478bd9Sstevel@tonic-gate 28627c478bd9Sstevel@tonic-gate /* 28637c478bd9Sstevel@tonic-gate * [no explicit support required beyond 28647c478bd9Sstevel@tonic-gate * x87 fp context and exception handlers] 28657c478bd9Sstevel@tonic-gate */ 28667c478bd9Sstevel@tonic-gate if (!fpu_exists) 28677c478bd9Sstevel@tonic-gate *edx &= ~(CPUID_AMD_EDX_MMXamd | 28687c478bd9Sstevel@tonic-gate CPUID_AMD_EDX_3DNow | CPUID_AMD_EDX_3DNowx); 28697c478bd9Sstevel@tonic-gate 28707417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_NX)) 28717c478bd9Sstevel@tonic-gate *edx &= ~CPUID_AMD_EDX_NX; 2872ae115bc7Smrj #if !defined(__amd64) 28737c478bd9Sstevel@tonic-gate *edx &= ~CPUID_AMD_EDX_LM; 28747c478bd9Sstevel@tonic-gate #endif 28757c478bd9Sstevel@tonic-gate /* 28767c478bd9Sstevel@tonic-gate * Now map the supported feature vector to 28777c478bd9Sstevel@tonic-gate * things that we think userland will care about. 28787c478bd9Sstevel@tonic-gate */ 2879ae115bc7Smrj #if defined(__amd64) 28807c478bd9Sstevel@tonic-gate if (*edx & CPUID_AMD_EDX_SYSC) 28817c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_AMD_SYSC; 2882ae115bc7Smrj #endif 28837c478bd9Sstevel@tonic-gate if (*edx & CPUID_AMD_EDX_MMXamd) 28847c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_AMD_MMX; 28857c478bd9Sstevel@tonic-gate if (*edx & CPUID_AMD_EDX_3DNow) 28867c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_AMD_3DNow; 28877c478bd9Sstevel@tonic-gate if (*edx & CPUID_AMD_EDX_3DNowx) 28887c478bd9Sstevel@tonic-gate hwcap_flags |= AV_386_AMD_3DNowx; 2889faa20166SBryan Cantrill if (*ecx & CPUID_AMD_ECX_SVM) 2890faa20166SBryan Cantrill hwcap_flags |= AV_386_AMD_SVM; 2891ae115bc7Smrj 2892ae115bc7Smrj switch (cpi->cpi_vendor) { 2893ae115bc7Smrj case X86_VENDOR_AMD: 2894ae115bc7Smrj if (*edx & CPUID_AMD_EDX_TSCP) 2895ae115bc7Smrj hwcap_flags |= AV_386_TSCP; 2896ae115bc7Smrj if (*ecx & CPUID_AMD_ECX_AHF64) 2897ae115bc7Smrj hwcap_flags |= AV_386_AHF; 2898f8801251Skk208521 if (*ecx & CPUID_AMD_ECX_SSE4A) 2899f8801251Skk208521 hwcap_flags |= AV_386_AMD_SSE4A; 2900f8801251Skk208521 if (*ecx & CPUID_AMD_ECX_LZCNT) 2901f8801251Skk208521 hwcap_flags |= AV_386_AMD_LZCNT; 2902ae115bc7Smrj break; 2903ae115bc7Smrj 2904ae115bc7Smrj case X86_VENDOR_Intel: 2905d36ea5d8Ssudheer if (*edx & CPUID_AMD_EDX_TSCP) 2906d36ea5d8Ssudheer hwcap_flags |= AV_386_TSCP; 2907ae115bc7Smrj /* 2908ae115bc7Smrj * Aarrgh. 2909ae115bc7Smrj * Intel uses a different bit in the same word. 2910ae115bc7Smrj */ 2911ae115bc7Smrj if (*ecx & CPUID_INTC_ECX_AHF64) 2912ae115bc7Smrj hwcap_flags |= AV_386_AHF; 2913ae115bc7Smrj break; 2914ae115bc7Smrj 2915ae115bc7Smrj default: 2916ae115bc7Smrj break; 2917ae115bc7Smrj } 29187c478bd9Sstevel@tonic-gate break; 29197c478bd9Sstevel@tonic-gate 29207c478bd9Sstevel@tonic-gate case X86_VENDOR_TM: 29218949bcd6Sandrei cp.cp_eax = 0x80860001; 29228949bcd6Sandrei (void) __cpuid_insn(&cp); 29238949bcd6Sandrei cpi->cpi_support[TM_EDX_FEATURES] = cp.cp_edx; 29247c478bd9Sstevel@tonic-gate break; 29257c478bd9Sstevel@tonic-gate 29267c478bd9Sstevel@tonic-gate default: 29277c478bd9Sstevel@tonic-gate break; 29287c478bd9Sstevel@tonic-gate } 29297c478bd9Sstevel@tonic-gate 29307c478bd9Sstevel@tonic-gate pass4_done: 29317c478bd9Sstevel@tonic-gate cpi->cpi_pass = 4; 2932ebb8ac07SRobert Mustacchi if (hwcap_out != NULL) { 2933ebb8ac07SRobert Mustacchi hwcap_out[0] = hwcap_flags; 2934ebb8ac07SRobert Mustacchi hwcap_out[1] = hwcap_flags_2; 2935ebb8ac07SRobert Mustacchi } 29367c478bd9Sstevel@tonic-gate } 29377c478bd9Sstevel@tonic-gate 29387c478bd9Sstevel@tonic-gate 29397c478bd9Sstevel@tonic-gate /* 29407c478bd9Sstevel@tonic-gate * Simulate the cpuid instruction using the data we previously 29417c478bd9Sstevel@tonic-gate * captured about this CPU. We try our best to return the truth 29427c478bd9Sstevel@tonic-gate * about the hardware, independently of kernel support. 29437c478bd9Sstevel@tonic-gate */ 29447c478bd9Sstevel@tonic-gate uint32_t 29458949bcd6Sandrei cpuid_insn(cpu_t *cpu, struct cpuid_regs *cp) 29467c478bd9Sstevel@tonic-gate { 29477c478bd9Sstevel@tonic-gate struct cpuid_info *cpi; 29488949bcd6Sandrei struct cpuid_regs *xcp; 29497c478bd9Sstevel@tonic-gate 29507c478bd9Sstevel@tonic-gate if (cpu == NULL) 29517c478bd9Sstevel@tonic-gate cpu = CPU; 29527c478bd9Sstevel@tonic-gate cpi = cpu->cpu_m.mcpu_cpi; 29537c478bd9Sstevel@tonic-gate 29547c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 3)); 29557c478bd9Sstevel@tonic-gate 29567c478bd9Sstevel@tonic-gate /* 29577c478bd9Sstevel@tonic-gate * CPUID data is cached in two separate places: cpi_std for standard 29587c478bd9Sstevel@tonic-gate * CPUID functions, and cpi_extd for extended CPUID functions. 29597c478bd9Sstevel@tonic-gate */ 29608949bcd6Sandrei if (cp->cp_eax <= cpi->cpi_maxeax && cp->cp_eax < NMAX_CPI_STD) 29618949bcd6Sandrei xcp = &cpi->cpi_std[cp->cp_eax]; 29628949bcd6Sandrei else if (cp->cp_eax >= 0x80000000 && cp->cp_eax <= cpi->cpi_xmaxeax && 29638949bcd6Sandrei cp->cp_eax < 0x80000000 + NMAX_CPI_EXTD) 29648949bcd6Sandrei xcp = &cpi->cpi_extd[cp->cp_eax - 0x80000000]; 29657c478bd9Sstevel@tonic-gate else 29667c478bd9Sstevel@tonic-gate /* 29677c478bd9Sstevel@tonic-gate * The caller is asking for data from an input parameter which 29687c478bd9Sstevel@tonic-gate * the kernel has not cached. In this case we go fetch from 29697c478bd9Sstevel@tonic-gate * the hardware and return the data directly to the user. 29707c478bd9Sstevel@tonic-gate */ 29718949bcd6Sandrei return (__cpuid_insn(cp)); 29728949bcd6Sandrei 29738949bcd6Sandrei cp->cp_eax = xcp->cp_eax; 29748949bcd6Sandrei cp->cp_ebx = xcp->cp_ebx; 29758949bcd6Sandrei cp->cp_ecx = xcp->cp_ecx; 29768949bcd6Sandrei cp->cp_edx = xcp->cp_edx; 29777c478bd9Sstevel@tonic-gate return (cp->cp_eax); 29787c478bd9Sstevel@tonic-gate } 29797c478bd9Sstevel@tonic-gate 29807c478bd9Sstevel@tonic-gate int 29817c478bd9Sstevel@tonic-gate cpuid_checkpass(cpu_t *cpu, int pass) 29827c478bd9Sstevel@tonic-gate { 29837c478bd9Sstevel@tonic-gate return (cpu != NULL && cpu->cpu_m.mcpu_cpi != NULL && 29847c478bd9Sstevel@tonic-gate cpu->cpu_m.mcpu_cpi->cpi_pass >= pass); 29857c478bd9Sstevel@tonic-gate } 29867c478bd9Sstevel@tonic-gate 29877c478bd9Sstevel@tonic-gate int 29887c478bd9Sstevel@tonic-gate cpuid_getbrandstr(cpu_t *cpu, char *s, size_t n) 29897c478bd9Sstevel@tonic-gate { 29907c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 3)); 29917c478bd9Sstevel@tonic-gate 29927c478bd9Sstevel@tonic-gate return (snprintf(s, n, "%s", cpu->cpu_m.mcpu_cpi->cpi_brandstr)); 29937c478bd9Sstevel@tonic-gate } 29947c478bd9Sstevel@tonic-gate 29957c478bd9Sstevel@tonic-gate int 29968949bcd6Sandrei cpuid_is_cmt(cpu_t *cpu) 29977c478bd9Sstevel@tonic-gate { 29987c478bd9Sstevel@tonic-gate if (cpu == NULL) 29997c478bd9Sstevel@tonic-gate cpu = CPU; 30007c478bd9Sstevel@tonic-gate 30017c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 30027c478bd9Sstevel@tonic-gate 30037c478bd9Sstevel@tonic-gate return (cpu->cpu_m.mcpu_cpi->cpi_chipid >= 0); 30047c478bd9Sstevel@tonic-gate } 30057c478bd9Sstevel@tonic-gate 30067c478bd9Sstevel@tonic-gate /* 30077c478bd9Sstevel@tonic-gate * AMD and Intel both implement the 64-bit variant of the syscall 30087c478bd9Sstevel@tonic-gate * instruction (syscallq), so if there's -any- support for syscall, 30097c478bd9Sstevel@tonic-gate * cpuid currently says "yes, we support this". 30107c478bd9Sstevel@tonic-gate * 30117c478bd9Sstevel@tonic-gate * However, Intel decided to -not- implement the 32-bit variant of the 30127c478bd9Sstevel@tonic-gate * syscall instruction, so we provide a predicate to allow our caller 30137c478bd9Sstevel@tonic-gate * to test that subtlety here. 3014843e1988Sjohnlev * 3015843e1988Sjohnlev * XXPV Currently, 32-bit syscall instructions don't work via the hypervisor, 3016843e1988Sjohnlev * even in the case where the hardware would in fact support it. 30177c478bd9Sstevel@tonic-gate */ 30187c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 30197c478bd9Sstevel@tonic-gate int 30207c478bd9Sstevel@tonic-gate cpuid_syscall32_insn(cpu_t *cpu) 30217c478bd9Sstevel@tonic-gate { 30227c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass((cpu == NULL ? CPU : cpu), 1)); 30237c478bd9Sstevel@tonic-gate 3024843e1988Sjohnlev #if !defined(__xpv) 3025ae115bc7Smrj if (cpu == NULL) 3026ae115bc7Smrj cpu = CPU; 3027ae115bc7Smrj 3028ae115bc7Smrj /*CSTYLED*/ 3029ae115bc7Smrj { 3030ae115bc7Smrj struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi; 3031ae115bc7Smrj 3032ae115bc7Smrj if (cpi->cpi_vendor == X86_VENDOR_AMD && 3033ae115bc7Smrj cpi->cpi_xmaxeax >= 0x80000001 && 3034ae115bc7Smrj (CPI_FEATURES_XTD_EDX(cpi) & CPUID_AMD_EDX_SYSC)) 3035ae115bc7Smrj return (1); 3036ae115bc7Smrj } 3037843e1988Sjohnlev #endif 30387c478bd9Sstevel@tonic-gate return (0); 30397c478bd9Sstevel@tonic-gate } 30407c478bd9Sstevel@tonic-gate 30417c478bd9Sstevel@tonic-gate int 30427c478bd9Sstevel@tonic-gate cpuid_getidstr(cpu_t *cpu, char *s, size_t n) 30437c478bd9Sstevel@tonic-gate { 30447c478bd9Sstevel@tonic-gate struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi; 30457c478bd9Sstevel@tonic-gate 30467c478bd9Sstevel@tonic-gate static const char fmt[] = 3047ecfa43a5Sdmick "x86 (%s %X family %d model %d step %d clock %d MHz)"; 30487c478bd9Sstevel@tonic-gate static const char fmt_ht[] = 3049ecfa43a5Sdmick "x86 (chipid 0x%x %s %X family %d model %d step %d clock %d MHz)"; 30507c478bd9Sstevel@tonic-gate 30517c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 30527c478bd9Sstevel@tonic-gate 30538949bcd6Sandrei if (cpuid_is_cmt(cpu)) 30547c478bd9Sstevel@tonic-gate return (snprintf(s, n, fmt_ht, cpi->cpi_chipid, 3055ecfa43a5Sdmick cpi->cpi_vendorstr, cpi->cpi_std[1].cp_eax, 3056ecfa43a5Sdmick cpi->cpi_family, cpi->cpi_model, 30577c478bd9Sstevel@tonic-gate cpi->cpi_step, cpu->cpu_type_info.pi_clock)); 30587c478bd9Sstevel@tonic-gate return (snprintf(s, n, fmt, 3059ecfa43a5Sdmick cpi->cpi_vendorstr, cpi->cpi_std[1].cp_eax, 3060ecfa43a5Sdmick cpi->cpi_family, cpi->cpi_model, 30617c478bd9Sstevel@tonic-gate cpi->cpi_step, cpu->cpu_type_info.pi_clock)); 30627c478bd9Sstevel@tonic-gate } 30637c478bd9Sstevel@tonic-gate 30647c478bd9Sstevel@tonic-gate const char * 30657c478bd9Sstevel@tonic-gate cpuid_getvendorstr(cpu_t *cpu) 30667c478bd9Sstevel@tonic-gate { 30677c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 30687c478bd9Sstevel@tonic-gate return ((const char *)cpu->cpu_m.mcpu_cpi->cpi_vendorstr); 30697c478bd9Sstevel@tonic-gate } 30707c478bd9Sstevel@tonic-gate 30717c478bd9Sstevel@tonic-gate uint_t 30727c478bd9Sstevel@tonic-gate cpuid_getvendor(cpu_t *cpu) 30737c478bd9Sstevel@tonic-gate { 30747c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 30757c478bd9Sstevel@tonic-gate return (cpu->cpu_m.mcpu_cpi->cpi_vendor); 30767c478bd9Sstevel@tonic-gate } 30777c478bd9Sstevel@tonic-gate 30787c478bd9Sstevel@tonic-gate uint_t 30797c478bd9Sstevel@tonic-gate cpuid_getfamily(cpu_t *cpu) 30807c478bd9Sstevel@tonic-gate { 30817c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 30827c478bd9Sstevel@tonic-gate return (cpu->cpu_m.mcpu_cpi->cpi_family); 30837c478bd9Sstevel@tonic-gate } 30847c478bd9Sstevel@tonic-gate 30857c478bd9Sstevel@tonic-gate uint_t 30867c478bd9Sstevel@tonic-gate cpuid_getmodel(cpu_t *cpu) 30877c478bd9Sstevel@tonic-gate { 30887c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 30897c478bd9Sstevel@tonic-gate return (cpu->cpu_m.mcpu_cpi->cpi_model); 30907c478bd9Sstevel@tonic-gate } 30917c478bd9Sstevel@tonic-gate 30927c478bd9Sstevel@tonic-gate uint_t 30937c478bd9Sstevel@tonic-gate cpuid_get_ncpu_per_chip(cpu_t *cpu) 30947c478bd9Sstevel@tonic-gate { 30957c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 30967c478bd9Sstevel@tonic-gate return (cpu->cpu_m.mcpu_cpi->cpi_ncpu_per_chip); 30977c478bd9Sstevel@tonic-gate } 30987c478bd9Sstevel@tonic-gate 30997c478bd9Sstevel@tonic-gate uint_t 31008949bcd6Sandrei cpuid_get_ncore_per_chip(cpu_t *cpu) 31018949bcd6Sandrei { 31028949bcd6Sandrei ASSERT(cpuid_checkpass(cpu, 1)); 31038949bcd6Sandrei return (cpu->cpu_m.mcpu_cpi->cpi_ncore_per_chip); 31048949bcd6Sandrei } 31058949bcd6Sandrei 31068949bcd6Sandrei uint_t 3107d129bde2Sesaxe cpuid_get_ncpu_sharing_last_cache(cpu_t *cpu) 3108d129bde2Sesaxe { 3109d129bde2Sesaxe ASSERT(cpuid_checkpass(cpu, 2)); 3110d129bde2Sesaxe return (cpu->cpu_m.mcpu_cpi->cpi_ncpu_shr_last_cache); 3111d129bde2Sesaxe } 3112d129bde2Sesaxe 3113d129bde2Sesaxe id_t 3114d129bde2Sesaxe cpuid_get_last_lvl_cacheid(cpu_t *cpu) 3115d129bde2Sesaxe { 3116d129bde2Sesaxe ASSERT(cpuid_checkpass(cpu, 2)); 3117d129bde2Sesaxe return (cpu->cpu_m.mcpu_cpi->cpi_last_lvl_cacheid); 3118d129bde2Sesaxe } 3119d129bde2Sesaxe 3120d129bde2Sesaxe uint_t 31217c478bd9Sstevel@tonic-gate cpuid_getstep(cpu_t *cpu) 31227c478bd9Sstevel@tonic-gate { 31237c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 31247c478bd9Sstevel@tonic-gate return (cpu->cpu_m.mcpu_cpi->cpi_step); 31257c478bd9Sstevel@tonic-gate } 31267c478bd9Sstevel@tonic-gate 31272449e17fSsherrym uint_t 31282449e17fSsherrym cpuid_getsig(struct cpu *cpu) 31292449e17fSsherrym { 31302449e17fSsherrym ASSERT(cpuid_checkpass(cpu, 1)); 31312449e17fSsherrym return (cpu->cpu_m.mcpu_cpi->cpi_std[1].cp_eax); 31322449e17fSsherrym } 31332449e17fSsherrym 31348a40a695Sgavinm uint32_t 31358a40a695Sgavinm cpuid_getchiprev(struct cpu *cpu) 31368a40a695Sgavinm { 31378a40a695Sgavinm ASSERT(cpuid_checkpass(cpu, 1)); 31388a40a695Sgavinm return (cpu->cpu_m.mcpu_cpi->cpi_chiprev); 31398a40a695Sgavinm } 31408a40a695Sgavinm 31418a40a695Sgavinm const char * 31428a40a695Sgavinm cpuid_getchiprevstr(struct cpu *cpu) 31438a40a695Sgavinm { 31448a40a695Sgavinm ASSERT(cpuid_checkpass(cpu, 1)); 31458a40a695Sgavinm return (cpu->cpu_m.mcpu_cpi->cpi_chiprevstr); 31468a40a695Sgavinm } 31478a40a695Sgavinm 31488a40a695Sgavinm uint32_t 31498a40a695Sgavinm cpuid_getsockettype(struct cpu *cpu) 31508a40a695Sgavinm { 31518a40a695Sgavinm ASSERT(cpuid_checkpass(cpu, 1)); 31528a40a695Sgavinm return (cpu->cpu_m.mcpu_cpi->cpi_socket); 31538a40a695Sgavinm } 31548a40a695Sgavinm 315589e921d5SKuriakose Kuruvilla const char * 315689e921d5SKuriakose Kuruvilla cpuid_getsocketstr(cpu_t *cpu) 315789e921d5SKuriakose Kuruvilla { 315889e921d5SKuriakose Kuruvilla static const char *socketstr = NULL; 315989e921d5SKuriakose Kuruvilla struct cpuid_info *cpi; 316089e921d5SKuriakose Kuruvilla 316189e921d5SKuriakose Kuruvilla ASSERT(cpuid_checkpass(cpu, 1)); 316289e921d5SKuriakose Kuruvilla cpi = cpu->cpu_m.mcpu_cpi; 316389e921d5SKuriakose Kuruvilla 316489e921d5SKuriakose Kuruvilla /* Assume that socket types are the same across the system */ 316589e921d5SKuriakose Kuruvilla if (socketstr == NULL) 316689e921d5SKuriakose Kuruvilla socketstr = _cpuid_sktstr(cpi->cpi_vendor, cpi->cpi_family, 316789e921d5SKuriakose Kuruvilla cpi->cpi_model, cpi->cpi_step); 316889e921d5SKuriakose Kuruvilla 316989e921d5SKuriakose Kuruvilla 317089e921d5SKuriakose Kuruvilla return (socketstr); 317189e921d5SKuriakose Kuruvilla } 317289e921d5SKuriakose Kuruvilla 3173fb2f18f8Sesaxe int 3174fb2f18f8Sesaxe cpuid_get_chipid(cpu_t *cpu) 31757c478bd9Sstevel@tonic-gate { 31767c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 31777c478bd9Sstevel@tonic-gate 31788949bcd6Sandrei if (cpuid_is_cmt(cpu)) 31797c478bd9Sstevel@tonic-gate return (cpu->cpu_m.mcpu_cpi->cpi_chipid); 31807c478bd9Sstevel@tonic-gate return (cpu->cpu_id); 31817c478bd9Sstevel@tonic-gate } 31827c478bd9Sstevel@tonic-gate 31838949bcd6Sandrei id_t 3184fb2f18f8Sesaxe cpuid_get_coreid(cpu_t *cpu) 31858949bcd6Sandrei { 31868949bcd6Sandrei ASSERT(cpuid_checkpass(cpu, 1)); 31878949bcd6Sandrei return (cpu->cpu_m.mcpu_cpi->cpi_coreid); 31888949bcd6Sandrei } 31898949bcd6Sandrei 31907c478bd9Sstevel@tonic-gate int 319110569901Sgavinm cpuid_get_pkgcoreid(cpu_t *cpu) 319210569901Sgavinm { 319310569901Sgavinm ASSERT(cpuid_checkpass(cpu, 1)); 319410569901Sgavinm return (cpu->cpu_m.mcpu_cpi->cpi_pkgcoreid); 319510569901Sgavinm } 319610569901Sgavinm 319710569901Sgavinm int 3198fb2f18f8Sesaxe cpuid_get_clogid(cpu_t *cpu) 31997c478bd9Sstevel@tonic-gate { 32007c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 32017c478bd9Sstevel@tonic-gate return (cpu->cpu_m.mcpu_cpi->cpi_clogid); 32027c478bd9Sstevel@tonic-gate } 32037c478bd9Sstevel@tonic-gate 3204b885580bSAlexander Kolbasov int 3205b885580bSAlexander Kolbasov cpuid_get_cacheid(cpu_t *cpu) 3206b885580bSAlexander Kolbasov { 3207b885580bSAlexander Kolbasov ASSERT(cpuid_checkpass(cpu, 1)); 3208b885580bSAlexander Kolbasov return (cpu->cpu_m.mcpu_cpi->cpi_last_lvl_cacheid); 3209b885580bSAlexander Kolbasov } 3210b885580bSAlexander Kolbasov 32118031591dSSrihari Venkatesan uint_t 32128031591dSSrihari Venkatesan cpuid_get_procnodeid(cpu_t *cpu) 32138031591dSSrihari Venkatesan { 32148031591dSSrihari Venkatesan ASSERT(cpuid_checkpass(cpu, 1)); 32158031591dSSrihari Venkatesan return (cpu->cpu_m.mcpu_cpi->cpi_procnodeid); 32168031591dSSrihari Venkatesan } 32178031591dSSrihari Venkatesan 32188031591dSSrihari Venkatesan uint_t 32198031591dSSrihari Venkatesan cpuid_get_procnodes_per_pkg(cpu_t *cpu) 32208031591dSSrihari Venkatesan { 32218031591dSSrihari Venkatesan ASSERT(cpuid_checkpass(cpu, 1)); 32228031591dSSrihari Venkatesan return (cpu->cpu_m.mcpu_cpi->cpi_procnodes_per_pkg); 32238031591dSSrihari Venkatesan } 32248031591dSSrihari Venkatesan 32257660e73fSHans Rosenfeld uint_t 32267660e73fSHans Rosenfeld cpuid_get_compunitid(cpu_t *cpu) 32277660e73fSHans Rosenfeld { 32287660e73fSHans Rosenfeld ASSERT(cpuid_checkpass(cpu, 1)); 32297660e73fSHans Rosenfeld return (cpu->cpu_m.mcpu_cpi->cpi_compunitid); 32307660e73fSHans Rosenfeld } 32317660e73fSHans Rosenfeld 32327660e73fSHans Rosenfeld uint_t 32337660e73fSHans Rosenfeld cpuid_get_cores_per_compunit(cpu_t *cpu) 32347660e73fSHans Rosenfeld { 32357660e73fSHans Rosenfeld ASSERT(cpuid_checkpass(cpu, 1)); 32367660e73fSHans Rosenfeld return (cpu->cpu_m.mcpu_cpi->cpi_cores_per_compunit); 32377660e73fSHans Rosenfeld } 32387660e73fSHans Rosenfeld 32392ef50f01SJoe Bonasera /*ARGSUSED*/ 32402ef50f01SJoe Bonasera int 32412ef50f01SJoe Bonasera cpuid_have_cr8access(cpu_t *cpu) 32422ef50f01SJoe Bonasera { 32432ef50f01SJoe Bonasera #if defined(__amd64) 32442ef50f01SJoe Bonasera return (1); 32452ef50f01SJoe Bonasera #else 32462ef50f01SJoe Bonasera struct cpuid_info *cpi; 32472ef50f01SJoe Bonasera 32482ef50f01SJoe Bonasera ASSERT(cpu != NULL); 32492ef50f01SJoe Bonasera cpi = cpu->cpu_m.mcpu_cpi; 32502ef50f01SJoe Bonasera if (cpi->cpi_vendor == X86_VENDOR_AMD && cpi->cpi_maxeax >= 1 && 32512ef50f01SJoe Bonasera (CPI_FEATURES_XTD_ECX(cpi) & CPUID_AMD_ECX_CR8D) != 0) 32522ef50f01SJoe Bonasera return (1); 32532ef50f01SJoe Bonasera return (0); 32542ef50f01SJoe Bonasera #endif 32552ef50f01SJoe Bonasera } 32562ef50f01SJoe Bonasera 3257fa96bd91SMichael Corcoran uint32_t 3258fa96bd91SMichael Corcoran cpuid_get_apicid(cpu_t *cpu) 3259fa96bd91SMichael Corcoran { 3260fa96bd91SMichael Corcoran ASSERT(cpuid_checkpass(cpu, 1)); 3261fa96bd91SMichael Corcoran if (cpu->cpu_m.mcpu_cpi->cpi_maxeax < 1) { 3262fa96bd91SMichael Corcoran return (UINT32_MAX); 3263fa96bd91SMichael Corcoran } else { 3264fa96bd91SMichael Corcoran return (cpu->cpu_m.mcpu_cpi->cpi_apicid); 3265fa96bd91SMichael Corcoran } 3266fa96bd91SMichael Corcoran } 3267fa96bd91SMichael Corcoran 32687c478bd9Sstevel@tonic-gate void 32697c478bd9Sstevel@tonic-gate cpuid_get_addrsize(cpu_t *cpu, uint_t *pabits, uint_t *vabits) 32707c478bd9Sstevel@tonic-gate { 32717c478bd9Sstevel@tonic-gate struct cpuid_info *cpi; 32727c478bd9Sstevel@tonic-gate 32737c478bd9Sstevel@tonic-gate if (cpu == NULL) 32747c478bd9Sstevel@tonic-gate cpu = CPU; 32757c478bd9Sstevel@tonic-gate cpi = cpu->cpu_m.mcpu_cpi; 32767c478bd9Sstevel@tonic-gate 32777c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 32787c478bd9Sstevel@tonic-gate 32797c478bd9Sstevel@tonic-gate if (pabits) 32807c478bd9Sstevel@tonic-gate *pabits = cpi->cpi_pabits; 32817c478bd9Sstevel@tonic-gate if (vabits) 32827c478bd9Sstevel@tonic-gate *vabits = cpi->cpi_vabits; 32837c478bd9Sstevel@tonic-gate } 32847c478bd9Sstevel@tonic-gate 32857c478bd9Sstevel@tonic-gate /* 32867c478bd9Sstevel@tonic-gate * Returns the number of data TLB entries for a corresponding 32877c478bd9Sstevel@tonic-gate * pagesize. If it can't be computed, or isn't known, the 32887c478bd9Sstevel@tonic-gate * routine returns zero. If you ask about an architecturally 32897c478bd9Sstevel@tonic-gate * impossible pagesize, the routine will panic (so that the 32907c478bd9Sstevel@tonic-gate * hat implementor knows that things are inconsistent.) 32917c478bd9Sstevel@tonic-gate */ 32927c478bd9Sstevel@tonic-gate uint_t 32937c478bd9Sstevel@tonic-gate cpuid_get_dtlb_nent(cpu_t *cpu, size_t pagesize) 32947c478bd9Sstevel@tonic-gate { 32957c478bd9Sstevel@tonic-gate struct cpuid_info *cpi; 32967c478bd9Sstevel@tonic-gate uint_t dtlb_nent = 0; 32977c478bd9Sstevel@tonic-gate 32987c478bd9Sstevel@tonic-gate if (cpu == NULL) 32997c478bd9Sstevel@tonic-gate cpu = CPU; 33007c478bd9Sstevel@tonic-gate cpi = cpu->cpu_m.mcpu_cpi; 33017c478bd9Sstevel@tonic-gate 33027c478bd9Sstevel@tonic-gate ASSERT(cpuid_checkpass(cpu, 1)); 33037c478bd9Sstevel@tonic-gate 33047c478bd9Sstevel@tonic-gate /* 33057c478bd9Sstevel@tonic-gate * Check the L2 TLB info 33067c478bd9Sstevel@tonic-gate */ 33077c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax >= 0x80000006) { 33088949bcd6Sandrei struct cpuid_regs *cp = &cpi->cpi_extd[6]; 33097c478bd9Sstevel@tonic-gate 33107c478bd9Sstevel@tonic-gate switch (pagesize) { 33117c478bd9Sstevel@tonic-gate 33127c478bd9Sstevel@tonic-gate case 4 * 1024: 33137c478bd9Sstevel@tonic-gate /* 33147c478bd9Sstevel@tonic-gate * All zero in the top 16 bits of the register 33157c478bd9Sstevel@tonic-gate * indicates a unified TLB. Size is in low 16 bits. 33167c478bd9Sstevel@tonic-gate */ 33177c478bd9Sstevel@tonic-gate if ((cp->cp_ebx & 0xffff0000) == 0) 33187c478bd9Sstevel@tonic-gate dtlb_nent = cp->cp_ebx & 0x0000ffff; 33197c478bd9Sstevel@tonic-gate else 33207c478bd9Sstevel@tonic-gate dtlb_nent = BITX(cp->cp_ebx, 27, 16); 33217c478bd9Sstevel@tonic-gate break; 33227c478bd9Sstevel@tonic-gate 33237c478bd9Sstevel@tonic-gate case 2 * 1024 * 1024: 33247c478bd9Sstevel@tonic-gate if ((cp->cp_eax & 0xffff0000) == 0) 33257c478bd9Sstevel@tonic-gate dtlb_nent = cp->cp_eax & 0x0000ffff; 33267c478bd9Sstevel@tonic-gate else 33277c478bd9Sstevel@tonic-gate dtlb_nent = BITX(cp->cp_eax, 27, 16); 33287c478bd9Sstevel@tonic-gate break; 33297c478bd9Sstevel@tonic-gate 33307c478bd9Sstevel@tonic-gate default: 33317c478bd9Sstevel@tonic-gate panic("unknown L2 pagesize"); 33327c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 33337c478bd9Sstevel@tonic-gate } 33347c478bd9Sstevel@tonic-gate } 33357c478bd9Sstevel@tonic-gate 33367c478bd9Sstevel@tonic-gate if (dtlb_nent != 0) 33377c478bd9Sstevel@tonic-gate return (dtlb_nent); 33387c478bd9Sstevel@tonic-gate 33397c478bd9Sstevel@tonic-gate /* 33407c478bd9Sstevel@tonic-gate * No L2 TLB support for this size, try L1. 33417c478bd9Sstevel@tonic-gate */ 33427c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax >= 0x80000005) { 33438949bcd6Sandrei struct cpuid_regs *cp = &cpi->cpi_extd[5]; 33447c478bd9Sstevel@tonic-gate 33457c478bd9Sstevel@tonic-gate switch (pagesize) { 33467c478bd9Sstevel@tonic-gate case 4 * 1024: 33477c478bd9Sstevel@tonic-gate dtlb_nent = BITX(cp->cp_ebx, 23, 16); 33487c478bd9Sstevel@tonic-gate break; 33497c478bd9Sstevel@tonic-gate case 2 * 1024 * 1024: 33507c478bd9Sstevel@tonic-gate dtlb_nent = BITX(cp->cp_eax, 23, 16); 33517c478bd9Sstevel@tonic-gate break; 33527c478bd9Sstevel@tonic-gate default: 33537c478bd9Sstevel@tonic-gate panic("unknown L1 d-TLB pagesize"); 33547c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 33557c478bd9Sstevel@tonic-gate } 33567c478bd9Sstevel@tonic-gate } 33577c478bd9Sstevel@tonic-gate 33587c478bd9Sstevel@tonic-gate return (dtlb_nent); 33597c478bd9Sstevel@tonic-gate } 33607c478bd9Sstevel@tonic-gate 33617c478bd9Sstevel@tonic-gate /* 33627c478bd9Sstevel@tonic-gate * Return 0 if the erratum is not present or not applicable, positive 33637c478bd9Sstevel@tonic-gate * if it is, and negative if the status of the erratum is unknown. 33647c478bd9Sstevel@tonic-gate * 33657c478bd9Sstevel@tonic-gate * See "Revision Guide for AMD Athlon(tm) 64 and AMD Opteron(tm) 33662201b277Skucharsk * Processors" #25759, Rev 3.57, August 2005 33677c478bd9Sstevel@tonic-gate */ 33687c478bd9Sstevel@tonic-gate int 33697c478bd9Sstevel@tonic-gate cpuid_opteron_erratum(cpu_t *cpu, uint_t erratum) 33707c478bd9Sstevel@tonic-gate { 33717c478bd9Sstevel@tonic-gate struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi; 33728949bcd6Sandrei uint_t eax; 33737c478bd9Sstevel@tonic-gate 3374ea99987eSsethg /* 3375ea99987eSsethg * Bail out if this CPU isn't an AMD CPU, or if it's 3376ea99987eSsethg * a legacy (32-bit) AMD CPU. 3377ea99987eSsethg */ 3378ea99987eSsethg if (cpi->cpi_vendor != X86_VENDOR_AMD || 3379875b116eSkchow cpi->cpi_family == 4 || cpi->cpi_family == 5 || 3380875b116eSkchow cpi->cpi_family == 6) 33818a40a695Sgavinm 33827c478bd9Sstevel@tonic-gate return (0); 33837c478bd9Sstevel@tonic-gate 33847c478bd9Sstevel@tonic-gate eax = cpi->cpi_std[1].cp_eax; 33857c478bd9Sstevel@tonic-gate 33867c478bd9Sstevel@tonic-gate #define SH_B0(eax) (eax == 0xf40 || eax == 0xf50) 33877c478bd9Sstevel@tonic-gate #define SH_B3(eax) (eax == 0xf51) 3388ee88d2b9Skchow #define B(eax) (SH_B0(eax) || SH_B3(eax)) 33897c478bd9Sstevel@tonic-gate 33907c478bd9Sstevel@tonic-gate #define SH_C0(eax) (eax == 0xf48 || eax == 0xf58) 33917c478bd9Sstevel@tonic-gate 33927c478bd9Sstevel@tonic-gate #define SH_CG(eax) (eax == 0xf4a || eax == 0xf5a || eax == 0xf7a) 33937c478bd9Sstevel@tonic-gate #define DH_CG(eax) (eax == 0xfc0 || eax == 0xfe0 || eax == 0xff0) 33947c478bd9Sstevel@tonic-gate #define CH_CG(eax) (eax == 0xf82 || eax == 0xfb2) 3395ee88d2b9Skchow #define CG(eax) (SH_CG(eax) || DH_CG(eax) || CH_CG(eax)) 33967c478bd9Sstevel@tonic-gate 33977c478bd9Sstevel@tonic-gate #define SH_D0(eax) (eax == 0x10f40 || eax == 0x10f50 || eax == 0x10f70) 33987c478bd9Sstevel@tonic-gate #define DH_D0(eax) (eax == 0x10fc0 || eax == 0x10ff0) 33997c478bd9Sstevel@tonic-gate #define CH_D0(eax) (eax == 0x10f80 || eax == 0x10fb0) 3400ee88d2b9Skchow #define D0(eax) (SH_D0(eax) || DH_D0(eax) || CH_D0(eax)) 34017c478bd9Sstevel@tonic-gate 34027c478bd9Sstevel@tonic-gate #define SH_E0(eax) (eax == 0x20f50 || eax == 0x20f40 || eax == 0x20f70) 34037c478bd9Sstevel@tonic-gate #define JH_E1(eax) (eax == 0x20f10) /* JH8_E0 had 0x20f30 */ 34047c478bd9Sstevel@tonic-gate #define DH_E3(eax) (eax == 0x20fc0 || eax == 0x20ff0) 34057c478bd9Sstevel@tonic-gate #define SH_E4(eax) (eax == 0x20f51 || eax == 0x20f71) 34067c478bd9Sstevel@tonic-gate #define BH_E4(eax) (eax == 0x20fb1) 34077c478bd9Sstevel@tonic-gate #define SH_E5(eax) (eax == 0x20f42) 34087c478bd9Sstevel@tonic-gate #define DH_E6(eax) (eax == 0x20ff2 || eax == 0x20fc2) 34097c478bd9Sstevel@tonic-gate #define JH_E6(eax) (eax == 0x20f12 || eax == 0x20f32) 3410ee88d2b9Skchow #define EX(eax) (SH_E0(eax) || JH_E1(eax) || DH_E3(eax) || \ 3411ee88d2b9Skchow SH_E4(eax) || BH_E4(eax) || SH_E5(eax) || \ 3412ee88d2b9Skchow DH_E6(eax) || JH_E6(eax)) 34137c478bd9Sstevel@tonic-gate 3414512cf780Skchow #define DR_AX(eax) (eax == 0x100f00 || eax == 0x100f01 || eax == 0x100f02) 3415512cf780Skchow #define DR_B0(eax) (eax == 0x100f20) 3416512cf780Skchow #define DR_B1(eax) (eax == 0x100f21) 3417512cf780Skchow #define DR_BA(eax) (eax == 0x100f2a) 3418512cf780Skchow #define DR_B2(eax) (eax == 0x100f22) 3419512cf780Skchow #define DR_B3(eax) (eax == 0x100f23) 3420512cf780Skchow #define RB_C0(eax) (eax == 0x100f40) 3421512cf780Skchow 34227c478bd9Sstevel@tonic-gate switch (erratum) { 34237c478bd9Sstevel@tonic-gate case 1: 3424875b116eSkchow return (cpi->cpi_family < 0x10); 34257c478bd9Sstevel@tonic-gate case 51: /* what does the asterisk mean? */ 34267c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax)); 34277c478bd9Sstevel@tonic-gate case 52: 34287c478bd9Sstevel@tonic-gate return (B(eax)); 34297c478bd9Sstevel@tonic-gate case 57: 3430512cf780Skchow return (cpi->cpi_family <= 0x11); 34317c478bd9Sstevel@tonic-gate case 58: 34327c478bd9Sstevel@tonic-gate return (B(eax)); 34337c478bd9Sstevel@tonic-gate case 60: 3434512cf780Skchow return (cpi->cpi_family <= 0x11); 34357c478bd9Sstevel@tonic-gate case 61: 34367c478bd9Sstevel@tonic-gate case 62: 34377c478bd9Sstevel@tonic-gate case 63: 34387c478bd9Sstevel@tonic-gate case 64: 34397c478bd9Sstevel@tonic-gate case 65: 34407c478bd9Sstevel@tonic-gate case 66: 34417c478bd9Sstevel@tonic-gate case 68: 34427c478bd9Sstevel@tonic-gate case 69: 34437c478bd9Sstevel@tonic-gate case 70: 34447c478bd9Sstevel@tonic-gate case 71: 34457c478bd9Sstevel@tonic-gate return (B(eax)); 34467c478bd9Sstevel@tonic-gate case 72: 34477c478bd9Sstevel@tonic-gate return (SH_B0(eax)); 34487c478bd9Sstevel@tonic-gate case 74: 34497c478bd9Sstevel@tonic-gate return (B(eax)); 34507c478bd9Sstevel@tonic-gate case 75: 3451875b116eSkchow return (cpi->cpi_family < 0x10); 34527c478bd9Sstevel@tonic-gate case 76: 34537c478bd9Sstevel@tonic-gate return (B(eax)); 34547c478bd9Sstevel@tonic-gate case 77: 3455512cf780Skchow return (cpi->cpi_family <= 0x11); 34567c478bd9Sstevel@tonic-gate case 78: 34577c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax)); 34587c478bd9Sstevel@tonic-gate case 79: 34597c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax) || EX(eax)); 34607c478bd9Sstevel@tonic-gate case 80: 34617c478bd9Sstevel@tonic-gate case 81: 34627c478bd9Sstevel@tonic-gate case 82: 34637c478bd9Sstevel@tonic-gate return (B(eax)); 34647c478bd9Sstevel@tonic-gate case 83: 34657c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax)); 34667c478bd9Sstevel@tonic-gate case 85: 3467875b116eSkchow return (cpi->cpi_family < 0x10); 34687c478bd9Sstevel@tonic-gate case 86: 34697c478bd9Sstevel@tonic-gate return (SH_C0(eax) || CG(eax)); 34707c478bd9Sstevel@tonic-gate case 88: 34717c478bd9Sstevel@tonic-gate #if !defined(__amd64) 34727c478bd9Sstevel@tonic-gate return (0); 34737c478bd9Sstevel@tonic-gate #else 34747c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax)); 34757c478bd9Sstevel@tonic-gate #endif 34767c478bd9Sstevel@tonic-gate case 89: 3477875b116eSkchow return (cpi->cpi_family < 0x10); 34787c478bd9Sstevel@tonic-gate case 90: 34797c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax)); 34807c478bd9Sstevel@tonic-gate case 91: 34817c478bd9Sstevel@tonic-gate case 92: 34827c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax)); 34837c478bd9Sstevel@tonic-gate case 93: 34847c478bd9Sstevel@tonic-gate return (SH_C0(eax)); 34857c478bd9Sstevel@tonic-gate case 94: 34867c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax)); 34877c478bd9Sstevel@tonic-gate case 95: 34887c478bd9Sstevel@tonic-gate #if !defined(__amd64) 34897c478bd9Sstevel@tonic-gate return (0); 34907c478bd9Sstevel@tonic-gate #else 34917c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax)); 34927c478bd9Sstevel@tonic-gate #endif 34937c478bd9Sstevel@tonic-gate case 96: 34947c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax)); 34957c478bd9Sstevel@tonic-gate case 97: 34967c478bd9Sstevel@tonic-gate case 98: 34977c478bd9Sstevel@tonic-gate return (SH_C0(eax) || CG(eax)); 34987c478bd9Sstevel@tonic-gate case 99: 34997c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax)); 35007c478bd9Sstevel@tonic-gate case 100: 35017c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax)); 35027c478bd9Sstevel@tonic-gate case 101: 35037c478bd9Sstevel@tonic-gate case 103: 35047c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax)); 35057c478bd9Sstevel@tonic-gate case 104: 35067c478bd9Sstevel@tonic-gate return (SH_C0(eax) || CG(eax) || D0(eax)); 35077c478bd9Sstevel@tonic-gate case 105: 35087c478bd9Sstevel@tonic-gate case 106: 35097c478bd9Sstevel@tonic-gate case 107: 35107c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax)); 35117c478bd9Sstevel@tonic-gate case 108: 35127c478bd9Sstevel@tonic-gate return (DH_CG(eax)); 35137c478bd9Sstevel@tonic-gate case 109: 35147c478bd9Sstevel@tonic-gate return (SH_C0(eax) || CG(eax) || D0(eax)); 35157c478bd9Sstevel@tonic-gate case 110: 35167c478bd9Sstevel@tonic-gate return (D0(eax) || EX(eax)); 35177c478bd9Sstevel@tonic-gate case 111: 35187c478bd9Sstevel@tonic-gate return (CG(eax)); 35197c478bd9Sstevel@tonic-gate case 112: 35207c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax) || EX(eax)); 35217c478bd9Sstevel@tonic-gate case 113: 35227c478bd9Sstevel@tonic-gate return (eax == 0x20fc0); 35237c478bd9Sstevel@tonic-gate case 114: 35247c478bd9Sstevel@tonic-gate return (SH_E0(eax) || JH_E1(eax) || DH_E3(eax)); 35257c478bd9Sstevel@tonic-gate case 115: 35267c478bd9Sstevel@tonic-gate return (SH_E0(eax) || JH_E1(eax)); 35277c478bd9Sstevel@tonic-gate case 116: 35287c478bd9Sstevel@tonic-gate return (SH_E0(eax) || JH_E1(eax) || DH_E3(eax)); 35297c478bd9Sstevel@tonic-gate case 117: 35307c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax)); 35317c478bd9Sstevel@tonic-gate case 118: 35327c478bd9Sstevel@tonic-gate return (SH_E0(eax) || JH_E1(eax) || SH_E4(eax) || BH_E4(eax) || 35337c478bd9Sstevel@tonic-gate JH_E6(eax)); 35347c478bd9Sstevel@tonic-gate case 121: 35357c478bd9Sstevel@tonic-gate return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax) || EX(eax)); 35367c478bd9Sstevel@tonic-gate case 122: 3537512cf780Skchow return (cpi->cpi_family < 0x10 || cpi->cpi_family == 0x11); 35387c478bd9Sstevel@tonic-gate case 123: 35397c478bd9Sstevel@tonic-gate return (JH_E1(eax) || BH_E4(eax) || JH_E6(eax)); 35402201b277Skucharsk case 131: 3541875b116eSkchow return (cpi->cpi_family < 0x10); 3542ef50d8c0Sesaxe case 6336786: 3543ef50d8c0Sesaxe /* 3544ef50d8c0Sesaxe * Test for AdvPowerMgmtInfo.TscPStateInvariant 3545875b116eSkchow * if this is a K8 family or newer processor 3546ef50d8c0Sesaxe */ 3547ef50d8c0Sesaxe if (CPI_FAMILY(cpi) == 0xf) { 35488949bcd6Sandrei struct cpuid_regs regs; 35498949bcd6Sandrei regs.cp_eax = 0x80000007; 35508949bcd6Sandrei (void) __cpuid_insn(®s); 35518949bcd6Sandrei return (!(regs.cp_edx & 0x100)); 3552ef50d8c0Sesaxe } 3553ef50d8c0Sesaxe return (0); 3554ee88d2b9Skchow case 6323525: 3555ee88d2b9Skchow return (((((eax >> 12) & 0xff00) + (eax & 0xf00)) | 3556ee88d2b9Skchow (((eax >> 4) & 0xf) | ((eax >> 12) & 0xf0))) < 0xf40); 3557ee88d2b9Skchow 3558512cf780Skchow case 6671130: 3559512cf780Skchow /* 3560512cf780Skchow * check for processors (pre-Shanghai) that do not provide 3561512cf780Skchow * optimal management of 1gb ptes in its tlb. 3562512cf780Skchow */ 3563512cf780Skchow return (cpi->cpi_family == 0x10 && cpi->cpi_model < 4); 3564512cf780Skchow 3565512cf780Skchow case 298: 3566512cf780Skchow return (DR_AX(eax) || DR_B0(eax) || DR_B1(eax) || DR_BA(eax) || 3567512cf780Skchow DR_B2(eax) || RB_C0(eax)); 3568512cf780Skchow 35695e54b56dSHans Rosenfeld case 721: 35705e54b56dSHans Rosenfeld #if defined(__amd64) 35715e54b56dSHans Rosenfeld return (cpi->cpi_family == 0x10 || cpi->cpi_family == 0x12); 35725e54b56dSHans Rosenfeld #else 35735e54b56dSHans Rosenfeld return (0); 35745e54b56dSHans Rosenfeld #endif 35755e54b56dSHans Rosenfeld 3576512cf780Skchow default: 3577512cf780Skchow return (-1); 3578512cf780Skchow 3579512cf780Skchow } 3580512cf780Skchow } 3581512cf780Skchow 3582512cf780Skchow /* 3583512cf780Skchow * Determine if specified erratum is present via OSVW (OS Visible Workaround). 3584512cf780Skchow * Return 1 if erratum is present, 0 if not present and -1 if indeterminate. 3585512cf780Skchow */ 3586512cf780Skchow int 3587512cf780Skchow osvw_opteron_erratum(cpu_t *cpu, uint_t erratum) 3588512cf780Skchow { 3589512cf780Skchow struct cpuid_info *cpi; 3590512cf780Skchow uint_t osvwid; 3591512cf780Skchow static int osvwfeature = -1; 3592512cf780Skchow uint64_t osvwlength; 3593512cf780Skchow 3594512cf780Skchow 3595512cf780Skchow cpi = cpu->cpu_m.mcpu_cpi; 3596512cf780Skchow 3597512cf780Skchow /* confirm OSVW supported */ 3598512cf780Skchow if (osvwfeature == -1) { 3599512cf780Skchow osvwfeature = cpi->cpi_extd[1].cp_ecx & CPUID_AMD_ECX_OSVW; 3600512cf780Skchow } else { 3601512cf780Skchow /* assert that osvw feature setting is consistent on all cpus */ 3602512cf780Skchow ASSERT(osvwfeature == 3603512cf780Skchow (cpi->cpi_extd[1].cp_ecx & CPUID_AMD_ECX_OSVW)); 3604512cf780Skchow } 3605512cf780Skchow if (!osvwfeature) 3606512cf780Skchow return (-1); 3607512cf780Skchow 3608512cf780Skchow osvwlength = rdmsr(MSR_AMD_OSVW_ID_LEN) & OSVW_ID_LEN_MASK; 3609512cf780Skchow 3610512cf780Skchow switch (erratum) { 3611512cf780Skchow case 298: /* osvwid is 0 */ 3612512cf780Skchow osvwid = 0; 3613512cf780Skchow if (osvwlength <= (uint64_t)osvwid) { 3614512cf780Skchow /* osvwid 0 is unknown */ 3615512cf780Skchow return (-1); 3616512cf780Skchow } 3617512cf780Skchow 3618512cf780Skchow /* 3619512cf780Skchow * Check the OSVW STATUS MSR to determine the state 3620512cf780Skchow * of the erratum where: 3621512cf780Skchow * 0 - fixed by HW 3622512cf780Skchow * 1 - BIOS has applied the workaround when BIOS 3623512cf780Skchow * workaround is available. (Or for other errata, 3624512cf780Skchow * OS workaround is required.) 3625512cf780Skchow * For a value of 1, caller will confirm that the 3626512cf780Skchow * erratum 298 workaround has indeed been applied by BIOS. 3627512cf780Skchow * 3628512cf780Skchow * A 1 may be set in cpus that have a HW fix 3629512cf780Skchow * in a mixed cpu system. Regarding erratum 298: 3630512cf780Skchow * In a multiprocessor platform, the workaround above 3631512cf780Skchow * should be applied to all processors regardless of 3632512cf780Skchow * silicon revision when an affected processor is 3633512cf780Skchow * present. 3634512cf780Skchow */ 3635512cf780Skchow 3636512cf780Skchow return (rdmsr(MSR_AMD_OSVW_STATUS + 3637512cf780Skchow (osvwid / OSVW_ID_CNT_PER_MSR)) & 3638512cf780Skchow (1ULL << (osvwid % OSVW_ID_CNT_PER_MSR))); 3639512cf780Skchow 36407c478bd9Sstevel@tonic-gate default: 36417c478bd9Sstevel@tonic-gate return (-1); 36427c478bd9Sstevel@tonic-gate } 36437c478bd9Sstevel@tonic-gate } 36447c478bd9Sstevel@tonic-gate 36457c478bd9Sstevel@tonic-gate static const char assoc_str[] = "associativity"; 36467c478bd9Sstevel@tonic-gate static const char line_str[] = "line-size"; 36477c478bd9Sstevel@tonic-gate static const char size_str[] = "size"; 36487c478bd9Sstevel@tonic-gate 36497c478bd9Sstevel@tonic-gate static void 36507c478bd9Sstevel@tonic-gate add_cache_prop(dev_info_t *devi, const char *label, const char *type, 36517c478bd9Sstevel@tonic-gate uint32_t val) 36527c478bd9Sstevel@tonic-gate { 36537c478bd9Sstevel@tonic-gate char buf[128]; 36547c478bd9Sstevel@tonic-gate 36557c478bd9Sstevel@tonic-gate /* 36567c478bd9Sstevel@tonic-gate * ndi_prop_update_int() is used because it is desirable for 36577c478bd9Sstevel@tonic-gate * DDI_PROP_HW_DEF and DDI_PROP_DONTSLEEP to be set. 36587c478bd9Sstevel@tonic-gate */ 36597c478bd9Sstevel@tonic-gate if (snprintf(buf, sizeof (buf), "%s-%s", label, type) < sizeof (buf)) 36607c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, devi, buf, val); 36617c478bd9Sstevel@tonic-gate } 36627c478bd9Sstevel@tonic-gate 36637c478bd9Sstevel@tonic-gate /* 36647c478bd9Sstevel@tonic-gate * Intel-style cache/tlb description 36657c478bd9Sstevel@tonic-gate * 36667c478bd9Sstevel@tonic-gate * Standard cpuid level 2 gives a randomly ordered 36677c478bd9Sstevel@tonic-gate * selection of tags that index into a table that describes 36687c478bd9Sstevel@tonic-gate * cache and tlb properties. 36697c478bd9Sstevel@tonic-gate */ 36707c478bd9Sstevel@tonic-gate 36717c478bd9Sstevel@tonic-gate static const char l1_icache_str[] = "l1-icache"; 36727c478bd9Sstevel@tonic-gate static const char l1_dcache_str[] = "l1-dcache"; 36737c478bd9Sstevel@tonic-gate static const char l2_cache_str[] = "l2-cache"; 3674ae115bc7Smrj static const char l3_cache_str[] = "l3-cache"; 36757c478bd9Sstevel@tonic-gate static const char itlb4k_str[] = "itlb-4K"; 36767c478bd9Sstevel@tonic-gate static const char dtlb4k_str[] = "dtlb-4K"; 3677824e4fecSvd224797 static const char itlb2M_str[] = "itlb-2M"; 36787c478bd9Sstevel@tonic-gate static const char itlb4M_str[] = "itlb-4M"; 36797c478bd9Sstevel@tonic-gate static const char dtlb4M_str[] = "dtlb-4M"; 368025dfb062Sksadhukh static const char dtlb24_str[] = "dtlb0-2M-4M"; 36817c478bd9Sstevel@tonic-gate static const char itlb424_str[] = "itlb-4K-2M-4M"; 368225dfb062Sksadhukh static const char itlb24_str[] = "itlb-2M-4M"; 36837c478bd9Sstevel@tonic-gate static const char dtlb44_str[] = "dtlb-4K-4M"; 36847c478bd9Sstevel@tonic-gate static const char sl1_dcache_str[] = "sectored-l1-dcache"; 36857c478bd9Sstevel@tonic-gate static const char sl2_cache_str[] = "sectored-l2-cache"; 36867c478bd9Sstevel@tonic-gate static const char itrace_str[] = "itrace-cache"; 36877c478bd9Sstevel@tonic-gate static const char sl3_cache_str[] = "sectored-l3-cache"; 368825dfb062Sksadhukh static const char sh_l2_tlb4k_str[] = "shared-l2-tlb-4k"; 36897c478bd9Sstevel@tonic-gate 36907c478bd9Sstevel@tonic-gate static const struct cachetab { 36917c478bd9Sstevel@tonic-gate uint8_t ct_code; 36927c478bd9Sstevel@tonic-gate uint8_t ct_assoc; 36937c478bd9Sstevel@tonic-gate uint16_t ct_line_size; 36947c478bd9Sstevel@tonic-gate size_t ct_size; 36957c478bd9Sstevel@tonic-gate const char *ct_label; 36967c478bd9Sstevel@tonic-gate } intel_ctab[] = { 3697824e4fecSvd224797 /* 3698824e4fecSvd224797 * maintain descending order! 3699824e4fecSvd224797 * 3700824e4fecSvd224797 * Codes ignored - Reason 3701824e4fecSvd224797 * ---------------------- 3702824e4fecSvd224797 * 40H - intel_cpuid_4_cache_info() disambiguates l2/l3 cache 3703824e4fecSvd224797 * f0H/f1H - Currently we do not interpret prefetch size by design 3704824e4fecSvd224797 */ 370525dfb062Sksadhukh { 0xe4, 16, 64, 8*1024*1024, l3_cache_str}, 370625dfb062Sksadhukh { 0xe3, 16, 64, 4*1024*1024, l3_cache_str}, 370725dfb062Sksadhukh { 0xe2, 16, 64, 2*1024*1024, l3_cache_str}, 370825dfb062Sksadhukh { 0xde, 12, 64, 6*1024*1024, l3_cache_str}, 370925dfb062Sksadhukh { 0xdd, 12, 64, 3*1024*1024, l3_cache_str}, 371025dfb062Sksadhukh { 0xdc, 12, 64, ((1*1024*1024)+(512*1024)), l3_cache_str}, 371125dfb062Sksadhukh { 0xd8, 8, 64, 4*1024*1024, l3_cache_str}, 371225dfb062Sksadhukh { 0xd7, 8, 64, 2*1024*1024, l3_cache_str}, 371325dfb062Sksadhukh { 0xd6, 8, 64, 1*1024*1024, l3_cache_str}, 371425dfb062Sksadhukh { 0xd2, 4, 64, 2*1024*1024, l3_cache_str}, 371525dfb062Sksadhukh { 0xd1, 4, 64, 1*1024*1024, l3_cache_str}, 371625dfb062Sksadhukh { 0xd0, 4, 64, 512*1024, l3_cache_str}, 371725dfb062Sksadhukh { 0xca, 4, 0, 512, sh_l2_tlb4k_str}, 3718824e4fecSvd224797 { 0xc0, 4, 0, 8, dtlb44_str }, 3719824e4fecSvd224797 { 0xba, 4, 0, 64, dtlb4k_str }, 3720ae115bc7Smrj { 0xb4, 4, 0, 256, dtlb4k_str }, 37217c478bd9Sstevel@tonic-gate { 0xb3, 4, 0, 128, dtlb4k_str }, 372225dfb062Sksadhukh { 0xb2, 4, 0, 64, itlb4k_str }, 37237c478bd9Sstevel@tonic-gate { 0xb0, 4, 0, 128, itlb4k_str }, 37247c478bd9Sstevel@tonic-gate { 0x87, 8, 64, 1024*1024, l2_cache_str}, 37257c478bd9Sstevel@tonic-gate { 0x86, 4, 64, 512*1024, l2_cache_str}, 37267c478bd9Sstevel@tonic-gate { 0x85, 8, 32, 2*1024*1024, l2_cache_str}, 37277c478bd9Sstevel@tonic-gate { 0x84, 8, 32, 1024*1024, l2_cache_str}, 37287c478bd9Sstevel@tonic-gate { 0x83, 8, 32, 512*1024, l2_cache_str}, 37297c478bd9Sstevel@tonic-gate { 0x82, 8, 32, 256*1024, l2_cache_str}, 3730824e4fecSvd224797 { 0x80, 8, 64, 512*1024, l2_cache_str}, 37317c478bd9Sstevel@tonic-gate { 0x7f, 2, 64, 512*1024, l2_cache_str}, 37327c478bd9Sstevel@tonic-gate { 0x7d, 8, 64, 2*1024*1024, sl2_cache_str}, 37337c478bd9Sstevel@tonic-gate { 0x7c, 8, 64, 1024*1024, sl2_cache_str}, 37347c478bd9Sstevel@tonic-gate { 0x7b, 8, 64, 512*1024, sl2_cache_str}, 37357c478bd9Sstevel@tonic-gate { 0x7a, 8, 64, 256*1024, sl2_cache_str}, 37367c478bd9Sstevel@tonic-gate { 0x79, 8, 64, 128*1024, sl2_cache_str}, 37377c478bd9Sstevel@tonic-gate { 0x78, 8, 64, 1024*1024, l2_cache_str}, 3738ae115bc7Smrj { 0x73, 8, 0, 64*1024, itrace_str}, 37397c478bd9Sstevel@tonic-gate { 0x72, 8, 0, 32*1024, itrace_str}, 37407c478bd9Sstevel@tonic-gate { 0x71, 8, 0, 16*1024, itrace_str}, 37417c478bd9Sstevel@tonic-gate { 0x70, 8, 0, 12*1024, itrace_str}, 37427c478bd9Sstevel@tonic-gate { 0x68, 4, 64, 32*1024, sl1_dcache_str}, 37437c478bd9Sstevel@tonic-gate { 0x67, 4, 64, 16*1024, sl1_dcache_str}, 37447c478bd9Sstevel@tonic-gate { 0x66, 4, 64, 8*1024, sl1_dcache_str}, 37457c478bd9Sstevel@tonic-gate { 0x60, 8, 64, 16*1024, sl1_dcache_str}, 37467c478bd9Sstevel@tonic-gate { 0x5d, 0, 0, 256, dtlb44_str}, 37477c478bd9Sstevel@tonic-gate { 0x5c, 0, 0, 128, dtlb44_str}, 37487c478bd9Sstevel@tonic-gate { 0x5b, 0, 0, 64, dtlb44_str}, 374925dfb062Sksadhukh { 0x5a, 4, 0, 32, dtlb24_str}, 3750824e4fecSvd224797 { 0x59, 0, 0, 16, dtlb4k_str}, 3751824e4fecSvd224797 { 0x57, 4, 0, 16, dtlb4k_str}, 3752824e4fecSvd224797 { 0x56, 4, 0, 16, dtlb4M_str}, 375325dfb062Sksadhukh { 0x55, 0, 0, 7, itlb24_str}, 37547c478bd9Sstevel@tonic-gate { 0x52, 0, 0, 256, itlb424_str}, 37557c478bd9Sstevel@tonic-gate { 0x51, 0, 0, 128, itlb424_str}, 37567c478bd9Sstevel@tonic-gate { 0x50, 0, 0, 64, itlb424_str}, 3757824e4fecSvd224797 { 0x4f, 0, 0, 32, itlb4k_str}, 3758824e4fecSvd224797 { 0x4e, 24, 64, 6*1024*1024, l2_cache_str}, 3759ae115bc7Smrj { 0x4d, 16, 64, 16*1024*1024, l3_cache_str}, 3760ae115bc7Smrj { 0x4c, 12, 64, 12*1024*1024, l3_cache_str}, 3761ae115bc7Smrj { 0x4b, 16, 64, 8*1024*1024, l3_cache_str}, 3762ae115bc7Smrj { 0x4a, 12, 64, 6*1024*1024, l3_cache_str}, 3763ae115bc7Smrj { 0x49, 16, 64, 4*1024*1024, l3_cache_str}, 3764824e4fecSvd224797 { 0x48, 12, 64, 3*1024*1024, l2_cache_str}, 3765ae115bc7Smrj { 0x47, 8, 64, 8*1024*1024, l3_cache_str}, 3766ae115bc7Smrj { 0x46, 4, 64, 4*1024*1024, l3_cache_str}, 37677c478bd9Sstevel@tonic-gate { 0x45, 4, 32, 2*1024*1024, l2_cache_str}, 37687c478bd9Sstevel@tonic-gate { 0x44, 4, 32, 1024*1024, l2_cache_str}, 37697c478bd9Sstevel@tonic-gate { 0x43, 4, 32, 512*1024, l2_cache_str}, 37707c478bd9Sstevel@tonic-gate { 0x42, 4, 32, 256*1024, l2_cache_str}, 37717c478bd9Sstevel@tonic-gate { 0x41, 4, 32, 128*1024, l2_cache_str}, 3772ae115bc7Smrj { 0x3e, 4, 64, 512*1024, sl2_cache_str}, 3773ae115bc7Smrj { 0x3d, 6, 64, 384*1024, sl2_cache_str}, 37747c478bd9Sstevel@tonic-gate { 0x3c, 4, 64, 256*1024, sl2_cache_str}, 37757c478bd9Sstevel@tonic-gate { 0x3b, 2, 64, 128*1024, sl2_cache_str}, 3776ae115bc7Smrj { 0x3a, 6, 64, 192*1024, sl2_cache_str}, 37777c478bd9Sstevel@tonic-gate { 0x39, 4, 64, 128*1024, sl2_cache_str}, 37787c478bd9Sstevel@tonic-gate { 0x30, 8, 64, 32*1024, l1_icache_str}, 37797c478bd9Sstevel@tonic-gate { 0x2c, 8, 64, 32*1024, l1_dcache_str}, 37807c478bd9Sstevel@tonic-gate { 0x29, 8, 64, 4096*1024, sl3_cache_str}, 37817c478bd9Sstevel@tonic-gate { 0x25, 8, 64, 2048*1024, sl3_cache_str}, 37827c478bd9Sstevel@tonic-gate { 0x23, 8, 64, 1024*1024, sl3_cache_str}, 37837c478bd9Sstevel@tonic-gate { 0x22, 4, 64, 512*1024, sl3_cache_str}, 3784824e4fecSvd224797 { 0x0e, 6, 64, 24*1024, l1_dcache_str}, 378525dfb062Sksadhukh { 0x0d, 4, 32, 16*1024, l1_dcache_str}, 37867c478bd9Sstevel@tonic-gate { 0x0c, 4, 32, 16*1024, l1_dcache_str}, 3787ae115bc7Smrj { 0x0b, 4, 0, 4, itlb4M_str}, 37887c478bd9Sstevel@tonic-gate { 0x0a, 2, 32, 8*1024, l1_dcache_str}, 37897c478bd9Sstevel@tonic-gate { 0x08, 4, 32, 16*1024, l1_icache_str}, 37907c478bd9Sstevel@tonic-gate { 0x06, 4, 32, 8*1024, l1_icache_str}, 3791824e4fecSvd224797 { 0x05, 4, 0, 32, dtlb4M_str}, 37927c478bd9Sstevel@tonic-gate { 0x04, 4, 0, 8, dtlb4M_str}, 37937c478bd9Sstevel@tonic-gate { 0x03, 4, 0, 64, dtlb4k_str}, 37947c478bd9Sstevel@tonic-gate { 0x02, 4, 0, 2, itlb4M_str}, 37957c478bd9Sstevel@tonic-gate { 0x01, 4, 0, 32, itlb4k_str}, 37967c478bd9Sstevel@tonic-gate { 0 } 37977c478bd9Sstevel@tonic-gate }; 37987c478bd9Sstevel@tonic-gate 37997c478bd9Sstevel@tonic-gate static const struct cachetab cyrix_ctab[] = { 38007c478bd9Sstevel@tonic-gate { 0x70, 4, 0, 32, "tlb-4K" }, 38017c478bd9Sstevel@tonic-gate { 0x80, 4, 16, 16*1024, "l1-cache" }, 38027c478bd9Sstevel@tonic-gate { 0 } 38037c478bd9Sstevel@tonic-gate }; 38047c478bd9Sstevel@tonic-gate 38057c478bd9Sstevel@tonic-gate /* 38067c478bd9Sstevel@tonic-gate * Search a cache table for a matching entry 38077c478bd9Sstevel@tonic-gate */ 38087c478bd9Sstevel@tonic-gate static const struct cachetab * 38097c478bd9Sstevel@tonic-gate find_cacheent(const struct cachetab *ct, uint_t code) 38107c478bd9Sstevel@tonic-gate { 38117c478bd9Sstevel@tonic-gate if (code != 0) { 38127c478bd9Sstevel@tonic-gate for (; ct->ct_code != 0; ct++) 38137c478bd9Sstevel@tonic-gate if (ct->ct_code <= code) 38147c478bd9Sstevel@tonic-gate break; 38157c478bd9Sstevel@tonic-gate if (ct->ct_code == code) 38167c478bd9Sstevel@tonic-gate return (ct); 38177c478bd9Sstevel@tonic-gate } 38187c478bd9Sstevel@tonic-gate return (NULL); 38197c478bd9Sstevel@tonic-gate } 38207c478bd9Sstevel@tonic-gate 38217c478bd9Sstevel@tonic-gate /* 38227dee861bSksadhukh * Populate cachetab entry with L2 or L3 cache-information using 38237dee861bSksadhukh * cpuid function 4. This function is called from intel_walk_cacheinfo() 38247dee861bSksadhukh * when descriptor 0x49 is encountered. It returns 0 if no such cache 38257dee861bSksadhukh * information is found. 38267dee861bSksadhukh */ 38277dee861bSksadhukh static int 38287dee861bSksadhukh intel_cpuid_4_cache_info(struct cachetab *ct, struct cpuid_info *cpi) 38297dee861bSksadhukh { 38307dee861bSksadhukh uint32_t level, i; 38317dee861bSksadhukh int ret = 0; 38327dee861bSksadhukh 38337dee861bSksadhukh for (i = 0; i < cpi->cpi_std_4_size; i++) { 38347dee861bSksadhukh level = CPI_CACHE_LVL(cpi->cpi_std_4[i]); 38357dee861bSksadhukh 38367dee861bSksadhukh if (level == 2 || level == 3) { 38377dee861bSksadhukh ct->ct_assoc = CPI_CACHE_WAYS(cpi->cpi_std_4[i]) + 1; 38387dee861bSksadhukh ct->ct_line_size = 38397dee861bSksadhukh CPI_CACHE_COH_LN_SZ(cpi->cpi_std_4[i]) + 1; 38407dee861bSksadhukh ct->ct_size = ct->ct_assoc * 38417dee861bSksadhukh (CPI_CACHE_PARTS(cpi->cpi_std_4[i]) + 1) * 38427dee861bSksadhukh ct->ct_line_size * 38437dee861bSksadhukh (cpi->cpi_std_4[i]->cp_ecx + 1); 38447dee861bSksadhukh 38457dee861bSksadhukh if (level == 2) { 38467dee861bSksadhukh ct->ct_label = l2_cache_str; 38477dee861bSksadhukh } else if (level == 3) { 38487dee861bSksadhukh ct->ct_label = l3_cache_str; 38497dee861bSksadhukh } 38507dee861bSksadhukh ret = 1; 38517dee861bSksadhukh } 38527dee861bSksadhukh } 38537dee861bSksadhukh 38547dee861bSksadhukh return (ret); 38557dee861bSksadhukh } 38567dee861bSksadhukh 38577dee861bSksadhukh /* 38587c478bd9Sstevel@tonic-gate * Walk the cacheinfo descriptor, applying 'func' to every valid element 38597c478bd9Sstevel@tonic-gate * The walk is terminated if the walker returns non-zero. 38607c478bd9Sstevel@tonic-gate */ 38617c478bd9Sstevel@tonic-gate static void 38627c478bd9Sstevel@tonic-gate intel_walk_cacheinfo(struct cpuid_info *cpi, 38637c478bd9Sstevel@tonic-gate void *arg, int (*func)(void *, const struct cachetab *)) 38647c478bd9Sstevel@tonic-gate { 38657c478bd9Sstevel@tonic-gate const struct cachetab *ct; 3866824e4fecSvd224797 struct cachetab des_49_ct, des_b1_ct; 38677c478bd9Sstevel@tonic-gate uint8_t *dp; 38687c478bd9Sstevel@tonic-gate int i; 38697c478bd9Sstevel@tonic-gate 38707c478bd9Sstevel@tonic-gate if ((dp = cpi->cpi_cacheinfo) == NULL) 38717c478bd9Sstevel@tonic-gate return; 3872f1d742a9Sksadhukh for (i = 0; i < cpi->cpi_ncache; i++, dp++) { 3873f1d742a9Sksadhukh /* 3874f1d742a9Sksadhukh * For overloaded descriptor 0x49 we use cpuid function 4 38757dee861bSksadhukh * if supported by the current processor, to create 3876f1d742a9Sksadhukh * cache information. 3877824e4fecSvd224797 * For overloaded descriptor 0xb1 we use X86_PAE flag 3878824e4fecSvd224797 * to disambiguate the cache information. 3879f1d742a9Sksadhukh */ 38807dee861bSksadhukh if (*dp == 0x49 && cpi->cpi_maxeax >= 0x4 && 38817dee861bSksadhukh intel_cpuid_4_cache_info(&des_49_ct, cpi) == 1) { 38827dee861bSksadhukh ct = &des_49_ct; 3883824e4fecSvd224797 } else if (*dp == 0xb1) { 3884824e4fecSvd224797 des_b1_ct.ct_code = 0xb1; 3885824e4fecSvd224797 des_b1_ct.ct_assoc = 4; 3886824e4fecSvd224797 des_b1_ct.ct_line_size = 0; 38877417cfdeSKuriakose Kuruvilla if (is_x86_feature(x86_featureset, X86FSET_PAE)) { 3888824e4fecSvd224797 des_b1_ct.ct_size = 8; 3889824e4fecSvd224797 des_b1_ct.ct_label = itlb2M_str; 3890824e4fecSvd224797 } else { 3891824e4fecSvd224797 des_b1_ct.ct_size = 4; 3892824e4fecSvd224797 des_b1_ct.ct_label = itlb4M_str; 3893824e4fecSvd224797 } 3894824e4fecSvd224797 ct = &des_b1_ct; 38957dee861bSksadhukh } else { 38967dee861bSksadhukh if ((ct = find_cacheent(intel_ctab, *dp)) == NULL) { 3897f1d742a9Sksadhukh continue; 3898f1d742a9Sksadhukh } 38997dee861bSksadhukh } 3900f1d742a9Sksadhukh 39017dee861bSksadhukh if (func(arg, ct) != 0) { 39027c478bd9Sstevel@tonic-gate break; 39037c478bd9Sstevel@tonic-gate } 39047c478bd9Sstevel@tonic-gate } 3905f1d742a9Sksadhukh } 39067c478bd9Sstevel@tonic-gate 39077c478bd9Sstevel@tonic-gate /* 39087c478bd9Sstevel@tonic-gate * (Like the Intel one, except for Cyrix CPUs) 39097c478bd9Sstevel@tonic-gate */ 39107c478bd9Sstevel@tonic-gate static void 39117c478bd9Sstevel@tonic-gate cyrix_walk_cacheinfo(struct cpuid_info *cpi, 39127c478bd9Sstevel@tonic-gate void *arg, int (*func)(void *, const struct cachetab *)) 39137c478bd9Sstevel@tonic-gate { 39147c478bd9Sstevel@tonic-gate const struct cachetab *ct; 39157c478bd9Sstevel@tonic-gate uint8_t *dp; 39167c478bd9Sstevel@tonic-gate int i; 39177c478bd9Sstevel@tonic-gate 39187c478bd9Sstevel@tonic-gate if ((dp = cpi->cpi_cacheinfo) == NULL) 39197c478bd9Sstevel@tonic-gate return; 39207c478bd9Sstevel@tonic-gate for (i = 0; i < cpi->cpi_ncache; i++, dp++) { 39217c478bd9Sstevel@tonic-gate /* 39227c478bd9Sstevel@tonic-gate * Search Cyrix-specific descriptor table first .. 39237c478bd9Sstevel@tonic-gate */ 39247c478bd9Sstevel@tonic-gate if ((ct = find_cacheent(cyrix_ctab, *dp)) != NULL) { 39257c478bd9Sstevel@tonic-gate if (func(arg, ct) != 0) 39267c478bd9Sstevel@tonic-gate break; 39277c478bd9Sstevel@tonic-gate continue; 39287c478bd9Sstevel@tonic-gate } 39297c478bd9Sstevel@tonic-gate /* 39307c478bd9Sstevel@tonic-gate * .. else fall back to the Intel one 39317c478bd9Sstevel@tonic-gate */ 39327c478bd9Sstevel@tonic-gate if ((ct = find_cacheent(intel_ctab, *dp)) != NULL) { 39337c478bd9Sstevel@tonic-gate if (func(arg, ct) != 0) 39347c478bd9Sstevel@tonic-gate break; 39357c478bd9Sstevel@tonic-gate continue; 39367c478bd9Sstevel@tonic-gate } 39377c478bd9Sstevel@tonic-gate } 39387c478bd9Sstevel@tonic-gate } 39397c478bd9Sstevel@tonic-gate 39407c478bd9Sstevel@tonic-gate /* 39417c478bd9Sstevel@tonic-gate * A cacheinfo walker that adds associativity, line-size, and size properties 39427c478bd9Sstevel@tonic-gate * to the devinfo node it is passed as an argument. 39437c478bd9Sstevel@tonic-gate */ 39447c478bd9Sstevel@tonic-gate static int 39457c478bd9Sstevel@tonic-gate add_cacheent_props(void *arg, const struct cachetab *ct) 39467c478bd9Sstevel@tonic-gate { 39477c478bd9Sstevel@tonic-gate dev_info_t *devi = arg; 39487c478bd9Sstevel@tonic-gate 39497c478bd9Sstevel@tonic-gate add_cache_prop(devi, ct->ct_label, assoc_str, ct->ct_assoc); 39507c478bd9Sstevel@tonic-gate if (ct->ct_line_size != 0) 39517c478bd9Sstevel@tonic-gate add_cache_prop(devi, ct->ct_label, line_str, 39527c478bd9Sstevel@tonic-gate ct->ct_line_size); 39537c478bd9Sstevel@tonic-gate add_cache_prop(devi, ct->ct_label, size_str, ct->ct_size); 39547c478bd9Sstevel@tonic-gate return (0); 39557c478bd9Sstevel@tonic-gate } 39567c478bd9Sstevel@tonic-gate 3957f1d742a9Sksadhukh 39587c478bd9Sstevel@tonic-gate static const char fully_assoc[] = "fully-associative?"; 39597c478bd9Sstevel@tonic-gate 39607c478bd9Sstevel@tonic-gate /* 39617c478bd9Sstevel@tonic-gate * AMD style cache/tlb description 39627c478bd9Sstevel@tonic-gate * 39637c478bd9Sstevel@tonic-gate * Extended functions 5 and 6 directly describe properties of 39647c478bd9Sstevel@tonic-gate * tlbs and various cache levels. 39657c478bd9Sstevel@tonic-gate */ 39667c478bd9Sstevel@tonic-gate static void 39677c478bd9Sstevel@tonic-gate add_amd_assoc(dev_info_t *devi, const char *label, uint_t assoc) 39687c478bd9Sstevel@tonic-gate { 39697c478bd9Sstevel@tonic-gate switch (assoc) { 39707c478bd9Sstevel@tonic-gate case 0: /* reserved; ignore */ 39717c478bd9Sstevel@tonic-gate break; 39727c478bd9Sstevel@tonic-gate default: 39737c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, assoc_str, assoc); 39747c478bd9Sstevel@tonic-gate break; 39757c478bd9Sstevel@tonic-gate case 0xff: 39767c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, fully_assoc, 1); 39777c478bd9Sstevel@tonic-gate break; 39787c478bd9Sstevel@tonic-gate } 39797c478bd9Sstevel@tonic-gate } 39807c478bd9Sstevel@tonic-gate 39817c478bd9Sstevel@tonic-gate static void 39827c478bd9Sstevel@tonic-gate add_amd_tlb(dev_info_t *devi, const char *label, uint_t assoc, uint_t size) 39837c478bd9Sstevel@tonic-gate { 39847c478bd9Sstevel@tonic-gate if (size == 0) 39857c478bd9Sstevel@tonic-gate return; 39867c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, size_str, size); 39877c478bd9Sstevel@tonic-gate add_amd_assoc(devi, label, assoc); 39887c478bd9Sstevel@tonic-gate } 39897c478bd9Sstevel@tonic-gate 39907c478bd9Sstevel@tonic-gate static void 39917c478bd9Sstevel@tonic-gate add_amd_cache(dev_info_t *devi, const char *label, 39927c478bd9Sstevel@tonic-gate uint_t size, uint_t assoc, uint_t lines_per_tag, uint_t line_size) 39937c478bd9Sstevel@tonic-gate { 39947c478bd9Sstevel@tonic-gate if (size == 0 || line_size == 0) 39957c478bd9Sstevel@tonic-gate return; 39967c478bd9Sstevel@tonic-gate add_amd_assoc(devi, label, assoc); 39977c478bd9Sstevel@tonic-gate /* 39987c478bd9Sstevel@tonic-gate * Most AMD parts have a sectored cache. Multiple cache lines are 39997c478bd9Sstevel@tonic-gate * associated with each tag. A sector consists of all cache lines 40007c478bd9Sstevel@tonic-gate * associated with a tag. For example, the AMD K6-III has a sector 40017c478bd9Sstevel@tonic-gate * size of 2 cache lines per tag. 40027c478bd9Sstevel@tonic-gate */ 40037c478bd9Sstevel@tonic-gate if (lines_per_tag != 0) 40047c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, "lines-per-tag", lines_per_tag); 40057c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, line_str, line_size); 40067c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, size_str, size * 1024); 40077c478bd9Sstevel@tonic-gate } 40087c478bd9Sstevel@tonic-gate 40097c478bd9Sstevel@tonic-gate static void 40107c478bd9Sstevel@tonic-gate add_amd_l2_assoc(dev_info_t *devi, const char *label, uint_t assoc) 40117c478bd9Sstevel@tonic-gate { 40127c478bd9Sstevel@tonic-gate switch (assoc) { 40137c478bd9Sstevel@tonic-gate case 0: /* off */ 40147c478bd9Sstevel@tonic-gate break; 40157c478bd9Sstevel@tonic-gate case 1: 40167c478bd9Sstevel@tonic-gate case 2: 40177c478bd9Sstevel@tonic-gate case 4: 40187c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, assoc_str, assoc); 40197c478bd9Sstevel@tonic-gate break; 40207c478bd9Sstevel@tonic-gate case 6: 40217c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, assoc_str, 8); 40227c478bd9Sstevel@tonic-gate break; 40237c478bd9Sstevel@tonic-gate case 8: 40247c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, assoc_str, 16); 40257c478bd9Sstevel@tonic-gate break; 40267c478bd9Sstevel@tonic-gate case 0xf: 40277c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, fully_assoc, 1); 40287c478bd9Sstevel@tonic-gate break; 40297c478bd9Sstevel@tonic-gate default: /* reserved; ignore */ 40307c478bd9Sstevel@tonic-gate break; 40317c478bd9Sstevel@tonic-gate } 40327c478bd9Sstevel@tonic-gate } 40337c478bd9Sstevel@tonic-gate 40347c478bd9Sstevel@tonic-gate static void 40357c478bd9Sstevel@tonic-gate add_amd_l2_tlb(dev_info_t *devi, const char *label, uint_t assoc, uint_t size) 40367c478bd9Sstevel@tonic-gate { 40377c478bd9Sstevel@tonic-gate if (size == 0 || assoc == 0) 40387c478bd9Sstevel@tonic-gate return; 40397c478bd9Sstevel@tonic-gate add_amd_l2_assoc(devi, label, assoc); 40407c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, size_str, size); 40417c478bd9Sstevel@tonic-gate } 40427c478bd9Sstevel@tonic-gate 40437c478bd9Sstevel@tonic-gate static void 40447c478bd9Sstevel@tonic-gate add_amd_l2_cache(dev_info_t *devi, const char *label, 40457c478bd9Sstevel@tonic-gate uint_t size, uint_t assoc, uint_t lines_per_tag, uint_t line_size) 40467c478bd9Sstevel@tonic-gate { 40477c478bd9Sstevel@tonic-gate if (size == 0 || assoc == 0 || line_size == 0) 40487c478bd9Sstevel@tonic-gate return; 40497c478bd9Sstevel@tonic-gate add_amd_l2_assoc(devi, label, assoc); 40507c478bd9Sstevel@tonic-gate if (lines_per_tag != 0) 40517c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, "lines-per-tag", lines_per_tag); 40527c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, line_str, line_size); 40537c478bd9Sstevel@tonic-gate add_cache_prop(devi, label, size_str, size * 1024); 40547c478bd9Sstevel@tonic-gate } 40557c478bd9Sstevel@tonic-gate 40567c478bd9Sstevel@tonic-gate static void 40577c478bd9Sstevel@tonic-gate amd_cache_info(struct cpuid_info *cpi, dev_info_t *devi) 40587c478bd9Sstevel@tonic-gate { 40598949bcd6Sandrei struct cpuid_regs *cp; 40607c478bd9Sstevel@tonic-gate 40617c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax < 0x80000005) 40627c478bd9Sstevel@tonic-gate return; 40637c478bd9Sstevel@tonic-gate cp = &cpi->cpi_extd[5]; 40647c478bd9Sstevel@tonic-gate 40657c478bd9Sstevel@tonic-gate /* 40667c478bd9Sstevel@tonic-gate * 4M/2M L1 TLB configuration 40677c478bd9Sstevel@tonic-gate * 40687c478bd9Sstevel@tonic-gate * We report the size for 2M pages because AMD uses two 40697c478bd9Sstevel@tonic-gate * TLB entries for one 4M page. 40707c478bd9Sstevel@tonic-gate */ 40717c478bd9Sstevel@tonic-gate add_amd_tlb(devi, "dtlb-2M", 40727c478bd9Sstevel@tonic-gate BITX(cp->cp_eax, 31, 24), BITX(cp->cp_eax, 23, 16)); 40737c478bd9Sstevel@tonic-gate add_amd_tlb(devi, "itlb-2M", 40747c478bd9Sstevel@tonic-gate BITX(cp->cp_eax, 15, 8), BITX(cp->cp_eax, 7, 0)); 40757c478bd9Sstevel@tonic-gate 40767c478bd9Sstevel@tonic-gate /* 40777c478bd9Sstevel@tonic-gate * 4K L1 TLB configuration 40787c478bd9Sstevel@tonic-gate */ 40797c478bd9Sstevel@tonic-gate 40807c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 40817c478bd9Sstevel@tonic-gate uint_t nentries; 40827c478bd9Sstevel@tonic-gate case X86_VENDOR_TM: 40837c478bd9Sstevel@tonic-gate if (cpi->cpi_family >= 5) { 40847c478bd9Sstevel@tonic-gate /* 40857c478bd9Sstevel@tonic-gate * Crusoe processors have 256 TLB entries, but 40867c478bd9Sstevel@tonic-gate * cpuid data format constrains them to only 40877c478bd9Sstevel@tonic-gate * reporting 255 of them. 40887c478bd9Sstevel@tonic-gate */ 40897c478bd9Sstevel@tonic-gate if ((nentries = BITX(cp->cp_ebx, 23, 16)) == 255) 40907c478bd9Sstevel@tonic-gate nentries = 256; 40917c478bd9Sstevel@tonic-gate /* 40927c478bd9Sstevel@tonic-gate * Crusoe processors also have a unified TLB 40937c478bd9Sstevel@tonic-gate */ 40947c478bd9Sstevel@tonic-gate add_amd_tlb(devi, "tlb-4K", BITX(cp->cp_ebx, 31, 24), 40957c478bd9Sstevel@tonic-gate nentries); 40967c478bd9Sstevel@tonic-gate break; 40977c478bd9Sstevel@tonic-gate } 40987c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 40997c478bd9Sstevel@tonic-gate default: 41007c478bd9Sstevel@tonic-gate add_amd_tlb(devi, itlb4k_str, 41017c478bd9Sstevel@tonic-gate BITX(cp->cp_ebx, 31, 24), BITX(cp->cp_ebx, 23, 16)); 41027c478bd9Sstevel@tonic-gate add_amd_tlb(devi, dtlb4k_str, 41037c478bd9Sstevel@tonic-gate BITX(cp->cp_ebx, 15, 8), BITX(cp->cp_ebx, 7, 0)); 41047c478bd9Sstevel@tonic-gate break; 41057c478bd9Sstevel@tonic-gate } 41067c478bd9Sstevel@tonic-gate 41077c478bd9Sstevel@tonic-gate /* 41087c478bd9Sstevel@tonic-gate * data L1 cache configuration 41097c478bd9Sstevel@tonic-gate */ 41107c478bd9Sstevel@tonic-gate 41117c478bd9Sstevel@tonic-gate add_amd_cache(devi, l1_dcache_str, 41127c478bd9Sstevel@tonic-gate BITX(cp->cp_ecx, 31, 24), BITX(cp->cp_ecx, 23, 16), 41137c478bd9Sstevel@tonic-gate BITX(cp->cp_ecx, 15, 8), BITX(cp->cp_ecx, 7, 0)); 41147c478bd9Sstevel@tonic-gate 41157c478bd9Sstevel@tonic-gate /* 41167c478bd9Sstevel@tonic-gate * code L1 cache configuration 41177c478bd9Sstevel@tonic-gate */ 41187c478bd9Sstevel@tonic-gate 41197c478bd9Sstevel@tonic-gate add_amd_cache(devi, l1_icache_str, 41207c478bd9Sstevel@tonic-gate BITX(cp->cp_edx, 31, 24), BITX(cp->cp_edx, 23, 16), 41217c478bd9Sstevel@tonic-gate BITX(cp->cp_edx, 15, 8), BITX(cp->cp_edx, 7, 0)); 41227c478bd9Sstevel@tonic-gate 41237c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax < 0x80000006) 41247c478bd9Sstevel@tonic-gate return; 41257c478bd9Sstevel@tonic-gate cp = &cpi->cpi_extd[6]; 41267c478bd9Sstevel@tonic-gate 41277c478bd9Sstevel@tonic-gate /* Check for a unified L2 TLB for large pages */ 41287c478bd9Sstevel@tonic-gate 41297c478bd9Sstevel@tonic-gate if (BITX(cp->cp_eax, 31, 16) == 0) 41307c478bd9Sstevel@tonic-gate add_amd_l2_tlb(devi, "l2-tlb-2M", 41317c478bd9Sstevel@tonic-gate BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0)); 41327c478bd9Sstevel@tonic-gate else { 41337c478bd9Sstevel@tonic-gate add_amd_l2_tlb(devi, "l2-dtlb-2M", 41347c478bd9Sstevel@tonic-gate BITX(cp->cp_eax, 31, 28), BITX(cp->cp_eax, 27, 16)); 41357c478bd9Sstevel@tonic-gate add_amd_l2_tlb(devi, "l2-itlb-2M", 41367c478bd9Sstevel@tonic-gate BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0)); 41377c478bd9Sstevel@tonic-gate } 41387c478bd9Sstevel@tonic-gate 41397c478bd9Sstevel@tonic-gate /* Check for a unified L2 TLB for 4K pages */ 41407c478bd9Sstevel@tonic-gate 41417c478bd9Sstevel@tonic-gate if (BITX(cp->cp_ebx, 31, 16) == 0) { 41427c478bd9Sstevel@tonic-gate add_amd_l2_tlb(devi, "l2-tlb-4K", 41437c478bd9Sstevel@tonic-gate BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0)); 41447c478bd9Sstevel@tonic-gate } else { 41457c478bd9Sstevel@tonic-gate add_amd_l2_tlb(devi, "l2-dtlb-4K", 41467c478bd9Sstevel@tonic-gate BITX(cp->cp_eax, 31, 28), BITX(cp->cp_eax, 27, 16)); 41477c478bd9Sstevel@tonic-gate add_amd_l2_tlb(devi, "l2-itlb-4K", 41487c478bd9Sstevel@tonic-gate BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0)); 41497c478bd9Sstevel@tonic-gate } 41507c478bd9Sstevel@tonic-gate 41517c478bd9Sstevel@tonic-gate add_amd_l2_cache(devi, l2_cache_str, 41527c478bd9Sstevel@tonic-gate BITX(cp->cp_ecx, 31, 16), BITX(cp->cp_ecx, 15, 12), 41537c478bd9Sstevel@tonic-gate BITX(cp->cp_ecx, 11, 8), BITX(cp->cp_ecx, 7, 0)); 41547c478bd9Sstevel@tonic-gate } 41557c478bd9Sstevel@tonic-gate 41567c478bd9Sstevel@tonic-gate /* 41577c478bd9Sstevel@tonic-gate * There are two basic ways that the x86 world describes it cache 41587c478bd9Sstevel@tonic-gate * and tlb architecture - Intel's way and AMD's way. 41597c478bd9Sstevel@tonic-gate * 41607c478bd9Sstevel@tonic-gate * Return which flavor of cache architecture we should use 41617c478bd9Sstevel@tonic-gate */ 41627c478bd9Sstevel@tonic-gate static int 41637c478bd9Sstevel@tonic-gate x86_which_cacheinfo(struct cpuid_info *cpi) 41647c478bd9Sstevel@tonic-gate { 41657c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 41667c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 41677c478bd9Sstevel@tonic-gate if (cpi->cpi_maxeax >= 2) 41687c478bd9Sstevel@tonic-gate return (X86_VENDOR_Intel); 41697c478bd9Sstevel@tonic-gate break; 41707c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 41717c478bd9Sstevel@tonic-gate /* 41727c478bd9Sstevel@tonic-gate * The K5 model 1 was the first part from AMD that reported 41737c478bd9Sstevel@tonic-gate * cache sizes via extended cpuid functions. 41747c478bd9Sstevel@tonic-gate */ 41757c478bd9Sstevel@tonic-gate if (cpi->cpi_family > 5 || 41767c478bd9Sstevel@tonic-gate (cpi->cpi_family == 5 && cpi->cpi_model >= 1)) 41777c478bd9Sstevel@tonic-gate return (X86_VENDOR_AMD); 41787c478bd9Sstevel@tonic-gate break; 41797c478bd9Sstevel@tonic-gate case X86_VENDOR_TM: 41807c478bd9Sstevel@tonic-gate if (cpi->cpi_family >= 5) 41817c478bd9Sstevel@tonic-gate return (X86_VENDOR_AMD); 41827c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 41837c478bd9Sstevel@tonic-gate default: 41847c478bd9Sstevel@tonic-gate /* 41857c478bd9Sstevel@tonic-gate * If they have extended CPU data for 0x80000005 41867c478bd9Sstevel@tonic-gate * then we assume they have AMD-format cache 41877c478bd9Sstevel@tonic-gate * information. 41887c478bd9Sstevel@tonic-gate * 41897c478bd9Sstevel@tonic-gate * If not, and the vendor happens to be Cyrix, 41907c478bd9Sstevel@tonic-gate * then try our-Cyrix specific handler. 41917c478bd9Sstevel@tonic-gate * 41927c478bd9Sstevel@tonic-gate * If we're not Cyrix, then assume we're using Intel's 41937c478bd9Sstevel@tonic-gate * table-driven format instead. 41947c478bd9Sstevel@tonic-gate */ 41957c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax >= 0x80000005) 41967c478bd9Sstevel@tonic-gate return (X86_VENDOR_AMD); 41977c478bd9Sstevel@tonic-gate else if (cpi->cpi_vendor == X86_VENDOR_Cyrix) 41987c478bd9Sstevel@tonic-gate return (X86_VENDOR_Cyrix); 41997c478bd9Sstevel@tonic-gate else if (cpi->cpi_maxeax >= 2) 42007c478bd9Sstevel@tonic-gate return (X86_VENDOR_Intel); 42017c478bd9Sstevel@tonic-gate break; 42027c478bd9Sstevel@tonic-gate } 42037c478bd9Sstevel@tonic-gate return (-1); 42047c478bd9Sstevel@tonic-gate } 42057c478bd9Sstevel@tonic-gate 42067c478bd9Sstevel@tonic-gate void 4207fa96bd91SMichael Corcoran cpuid_set_cpu_properties(void *dip, processorid_t cpu_id, 4208fa96bd91SMichael Corcoran struct cpuid_info *cpi) 42097c478bd9Sstevel@tonic-gate { 42107c478bd9Sstevel@tonic-gate dev_info_t *cpu_devi; 42117c478bd9Sstevel@tonic-gate int create; 42127c478bd9Sstevel@tonic-gate 4213fa96bd91SMichael Corcoran cpu_devi = (dev_info_t *)dip; 42147c478bd9Sstevel@tonic-gate 42157c478bd9Sstevel@tonic-gate /* device_type */ 42167c478bd9Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, cpu_devi, 42177c478bd9Sstevel@tonic-gate "device_type", "cpu"); 42187c478bd9Sstevel@tonic-gate 42197c478bd9Sstevel@tonic-gate /* reg */ 42207c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 42217c478bd9Sstevel@tonic-gate "reg", cpu_id); 42227c478bd9Sstevel@tonic-gate 42237c478bd9Sstevel@tonic-gate /* cpu-mhz, and clock-frequency */ 42247c478bd9Sstevel@tonic-gate if (cpu_freq > 0) { 42257c478bd9Sstevel@tonic-gate long long mul; 42267c478bd9Sstevel@tonic-gate 42277c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 42287c478bd9Sstevel@tonic-gate "cpu-mhz", cpu_freq); 42297c478bd9Sstevel@tonic-gate if ((mul = cpu_freq * 1000000LL) <= INT_MAX) 42307c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 42317c478bd9Sstevel@tonic-gate "clock-frequency", (int)mul); 42327c478bd9Sstevel@tonic-gate } 42337c478bd9Sstevel@tonic-gate 42347417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_CPUID)) { 42357c478bd9Sstevel@tonic-gate return; 42367c478bd9Sstevel@tonic-gate } 42377c478bd9Sstevel@tonic-gate 42387c478bd9Sstevel@tonic-gate /* vendor-id */ 42397c478bd9Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, cpu_devi, 42407c478bd9Sstevel@tonic-gate "vendor-id", cpi->cpi_vendorstr); 42417c478bd9Sstevel@tonic-gate 42427c478bd9Sstevel@tonic-gate if (cpi->cpi_maxeax == 0) { 42437c478bd9Sstevel@tonic-gate return; 42447c478bd9Sstevel@tonic-gate } 42457c478bd9Sstevel@tonic-gate 42467c478bd9Sstevel@tonic-gate /* 42477c478bd9Sstevel@tonic-gate * family, model, and step 42487c478bd9Sstevel@tonic-gate */ 42497c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 42507c478bd9Sstevel@tonic-gate "family", CPI_FAMILY(cpi)); 42517c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 42527c478bd9Sstevel@tonic-gate "cpu-model", CPI_MODEL(cpi)); 42537c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 42547c478bd9Sstevel@tonic-gate "stepping-id", CPI_STEP(cpi)); 42557c478bd9Sstevel@tonic-gate 42567c478bd9Sstevel@tonic-gate /* type */ 42577c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 42587c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 42597c478bd9Sstevel@tonic-gate create = 1; 42607c478bd9Sstevel@tonic-gate break; 42617c478bd9Sstevel@tonic-gate default: 42627c478bd9Sstevel@tonic-gate create = 0; 42637c478bd9Sstevel@tonic-gate break; 42647c478bd9Sstevel@tonic-gate } 42657c478bd9Sstevel@tonic-gate if (create) 42667c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 42677c478bd9Sstevel@tonic-gate "type", CPI_TYPE(cpi)); 42687c478bd9Sstevel@tonic-gate 42697c478bd9Sstevel@tonic-gate /* ext-family */ 42707c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 42717c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 42727c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 42737c478bd9Sstevel@tonic-gate create = cpi->cpi_family >= 0xf; 42747c478bd9Sstevel@tonic-gate break; 42757c478bd9Sstevel@tonic-gate default: 42767c478bd9Sstevel@tonic-gate create = 0; 42777c478bd9Sstevel@tonic-gate break; 42787c478bd9Sstevel@tonic-gate } 42797c478bd9Sstevel@tonic-gate if (create) 42807c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 42817c478bd9Sstevel@tonic-gate "ext-family", CPI_FAMILY_XTD(cpi)); 42827c478bd9Sstevel@tonic-gate 42837c478bd9Sstevel@tonic-gate /* ext-model */ 42847c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 42857c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 428663d3f7dfSkk208521 create = IS_EXTENDED_MODEL_INTEL(cpi); 428768c91426Sdmick break; 42887c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 4289ee88d2b9Skchow create = CPI_FAMILY(cpi) == 0xf; 42907c478bd9Sstevel@tonic-gate break; 42917c478bd9Sstevel@tonic-gate default: 42927c478bd9Sstevel@tonic-gate create = 0; 42937c478bd9Sstevel@tonic-gate break; 42947c478bd9Sstevel@tonic-gate } 42957c478bd9Sstevel@tonic-gate if (create) 42967c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 42977c478bd9Sstevel@tonic-gate "ext-model", CPI_MODEL_XTD(cpi)); 42987c478bd9Sstevel@tonic-gate 42997c478bd9Sstevel@tonic-gate /* generation */ 43007c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 43017c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 43027c478bd9Sstevel@tonic-gate /* 43037c478bd9Sstevel@tonic-gate * AMD K5 model 1 was the first part to support this 43047c478bd9Sstevel@tonic-gate */ 43057c478bd9Sstevel@tonic-gate create = cpi->cpi_xmaxeax >= 0x80000001; 43067c478bd9Sstevel@tonic-gate break; 43077c478bd9Sstevel@tonic-gate default: 43087c478bd9Sstevel@tonic-gate create = 0; 43097c478bd9Sstevel@tonic-gate break; 43107c478bd9Sstevel@tonic-gate } 43117c478bd9Sstevel@tonic-gate if (create) 43127c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 43137c478bd9Sstevel@tonic-gate "generation", BITX((cpi)->cpi_extd[1].cp_eax, 11, 8)); 43147c478bd9Sstevel@tonic-gate 43157c478bd9Sstevel@tonic-gate /* brand-id */ 43167c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 43177c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 43187c478bd9Sstevel@tonic-gate /* 43197c478bd9Sstevel@tonic-gate * brand id first appeared on Pentium III Xeon model 8, 43207c478bd9Sstevel@tonic-gate * and Celeron model 8 processors and Opteron 43217c478bd9Sstevel@tonic-gate */ 43227c478bd9Sstevel@tonic-gate create = cpi->cpi_family > 6 || 43237c478bd9Sstevel@tonic-gate (cpi->cpi_family == 6 && cpi->cpi_model >= 8); 43247c478bd9Sstevel@tonic-gate break; 43257c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 43267c478bd9Sstevel@tonic-gate create = cpi->cpi_family >= 0xf; 43277c478bd9Sstevel@tonic-gate break; 43287c478bd9Sstevel@tonic-gate default: 43297c478bd9Sstevel@tonic-gate create = 0; 43307c478bd9Sstevel@tonic-gate break; 43317c478bd9Sstevel@tonic-gate } 43327c478bd9Sstevel@tonic-gate if (create && cpi->cpi_brandid != 0) { 43337c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 43347c478bd9Sstevel@tonic-gate "brand-id", cpi->cpi_brandid); 43357c478bd9Sstevel@tonic-gate } 43367c478bd9Sstevel@tonic-gate 43377c478bd9Sstevel@tonic-gate /* chunks, and apic-id */ 43387c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 43397c478bd9Sstevel@tonic-gate /* 43407c478bd9Sstevel@tonic-gate * first available on Pentium IV and Opteron (K8) 43417c478bd9Sstevel@tonic-gate */ 43425ff02082Sdmick case X86_VENDOR_Intel: 43435ff02082Sdmick create = IS_NEW_F6(cpi) || cpi->cpi_family >= 0xf; 43445ff02082Sdmick break; 43455ff02082Sdmick case X86_VENDOR_AMD: 43467c478bd9Sstevel@tonic-gate create = cpi->cpi_family >= 0xf; 43477c478bd9Sstevel@tonic-gate break; 43487c478bd9Sstevel@tonic-gate default: 43497c478bd9Sstevel@tonic-gate create = 0; 43507c478bd9Sstevel@tonic-gate break; 43517c478bd9Sstevel@tonic-gate } 43527c478bd9Sstevel@tonic-gate if (create) { 43537c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 43547c478bd9Sstevel@tonic-gate "chunks", CPI_CHUNKS(cpi)); 43557c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 4356b6917abeSmishra "apic-id", cpi->cpi_apicid); 43577aec1d6eScindi if (cpi->cpi_chipid >= 0) { 43587c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 43597c478bd9Sstevel@tonic-gate "chip#", cpi->cpi_chipid); 43607aec1d6eScindi (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 43617aec1d6eScindi "clog#", cpi->cpi_clogid); 43627aec1d6eScindi } 43637c478bd9Sstevel@tonic-gate } 43647c478bd9Sstevel@tonic-gate 43657c478bd9Sstevel@tonic-gate /* cpuid-features */ 43667c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 43677c478bd9Sstevel@tonic-gate "cpuid-features", CPI_FEATURES_EDX(cpi)); 43687c478bd9Sstevel@tonic-gate 43697c478bd9Sstevel@tonic-gate 43707c478bd9Sstevel@tonic-gate /* cpuid-features-ecx */ 43717c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 43727c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 43735ff02082Sdmick create = IS_NEW_F6(cpi) || cpi->cpi_family >= 0xf; 43747c478bd9Sstevel@tonic-gate break; 437563408480SHans Rosenfeld case X86_VENDOR_AMD: 437663408480SHans Rosenfeld create = cpi->cpi_family >= 0xf; 437763408480SHans Rosenfeld break; 43787c478bd9Sstevel@tonic-gate default: 43797c478bd9Sstevel@tonic-gate create = 0; 43807c478bd9Sstevel@tonic-gate break; 43817c478bd9Sstevel@tonic-gate } 43827c478bd9Sstevel@tonic-gate if (create) 43837c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 43847c478bd9Sstevel@tonic-gate "cpuid-features-ecx", CPI_FEATURES_ECX(cpi)); 43857c478bd9Sstevel@tonic-gate 43867c478bd9Sstevel@tonic-gate /* ext-cpuid-features */ 43877c478bd9Sstevel@tonic-gate switch (cpi->cpi_vendor) { 43885ff02082Sdmick case X86_VENDOR_Intel: 43897c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 43907c478bd9Sstevel@tonic-gate case X86_VENDOR_Cyrix: 43917c478bd9Sstevel@tonic-gate case X86_VENDOR_TM: 43927c478bd9Sstevel@tonic-gate case X86_VENDOR_Centaur: 43937c478bd9Sstevel@tonic-gate create = cpi->cpi_xmaxeax >= 0x80000001; 43947c478bd9Sstevel@tonic-gate break; 43957c478bd9Sstevel@tonic-gate default: 43967c478bd9Sstevel@tonic-gate create = 0; 43977c478bd9Sstevel@tonic-gate break; 43987c478bd9Sstevel@tonic-gate } 43995ff02082Sdmick if (create) { 44007c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 44017c478bd9Sstevel@tonic-gate "ext-cpuid-features", CPI_FEATURES_XTD_EDX(cpi)); 44025ff02082Sdmick (void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi, 44035ff02082Sdmick "ext-cpuid-features-ecx", CPI_FEATURES_XTD_ECX(cpi)); 44045ff02082Sdmick } 44057c478bd9Sstevel@tonic-gate 44067c478bd9Sstevel@tonic-gate /* 44077c478bd9Sstevel@tonic-gate * Brand String first appeared in Intel Pentium IV, AMD K5 44087c478bd9Sstevel@tonic-gate * model 1, and Cyrix GXm. On earlier models we try and 44097c478bd9Sstevel@tonic-gate * simulate something similar .. so this string should always 44107c478bd9Sstevel@tonic-gate * same -something- about the processor, however lame. 44117c478bd9Sstevel@tonic-gate */ 44127c478bd9Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, cpu_devi, 44137c478bd9Sstevel@tonic-gate "brand-string", cpi->cpi_brandstr); 44147c478bd9Sstevel@tonic-gate 44157c478bd9Sstevel@tonic-gate /* 44167c478bd9Sstevel@tonic-gate * Finally, cache and tlb information 44177c478bd9Sstevel@tonic-gate */ 44187c478bd9Sstevel@tonic-gate switch (x86_which_cacheinfo(cpi)) { 44197c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 44207c478bd9Sstevel@tonic-gate intel_walk_cacheinfo(cpi, cpu_devi, add_cacheent_props); 44217c478bd9Sstevel@tonic-gate break; 44227c478bd9Sstevel@tonic-gate case X86_VENDOR_Cyrix: 44237c478bd9Sstevel@tonic-gate cyrix_walk_cacheinfo(cpi, cpu_devi, add_cacheent_props); 44247c478bd9Sstevel@tonic-gate break; 44257c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 44267c478bd9Sstevel@tonic-gate amd_cache_info(cpi, cpu_devi); 44277c478bd9Sstevel@tonic-gate break; 44287c478bd9Sstevel@tonic-gate default: 44297c478bd9Sstevel@tonic-gate break; 44307c478bd9Sstevel@tonic-gate } 44317c478bd9Sstevel@tonic-gate } 44327c478bd9Sstevel@tonic-gate 44337c478bd9Sstevel@tonic-gate struct l2info { 44347c478bd9Sstevel@tonic-gate int *l2i_csz; 44357c478bd9Sstevel@tonic-gate int *l2i_lsz; 44367c478bd9Sstevel@tonic-gate int *l2i_assoc; 44377c478bd9Sstevel@tonic-gate int l2i_ret; 44387c478bd9Sstevel@tonic-gate }; 44397c478bd9Sstevel@tonic-gate 44407c478bd9Sstevel@tonic-gate /* 44417c478bd9Sstevel@tonic-gate * A cacheinfo walker that fetches the size, line-size and associativity 44427c478bd9Sstevel@tonic-gate * of the L2 cache 44437c478bd9Sstevel@tonic-gate */ 44447c478bd9Sstevel@tonic-gate static int 44457c478bd9Sstevel@tonic-gate intel_l2cinfo(void *arg, const struct cachetab *ct) 44467c478bd9Sstevel@tonic-gate { 44477c478bd9Sstevel@tonic-gate struct l2info *l2i = arg; 44487c478bd9Sstevel@tonic-gate int *ip; 44497c478bd9Sstevel@tonic-gate 44507c478bd9Sstevel@tonic-gate if (ct->ct_label != l2_cache_str && 44517c478bd9Sstevel@tonic-gate ct->ct_label != sl2_cache_str) 44527c478bd9Sstevel@tonic-gate return (0); /* not an L2 -- keep walking */ 44537c478bd9Sstevel@tonic-gate 44547c478bd9Sstevel@tonic-gate if ((ip = l2i->l2i_csz) != NULL) 44557c478bd9Sstevel@tonic-gate *ip = ct->ct_size; 44567c478bd9Sstevel@tonic-gate if ((ip = l2i->l2i_lsz) != NULL) 44577c478bd9Sstevel@tonic-gate *ip = ct->ct_line_size; 44587c478bd9Sstevel@tonic-gate if ((ip = l2i->l2i_assoc) != NULL) 44597c478bd9Sstevel@tonic-gate *ip = ct->ct_assoc; 44607c478bd9Sstevel@tonic-gate l2i->l2i_ret = ct->ct_size; 44617c478bd9Sstevel@tonic-gate return (1); /* was an L2 -- terminate walk */ 44627c478bd9Sstevel@tonic-gate } 44637c478bd9Sstevel@tonic-gate 4464606303c9Skchow /* 4465606303c9Skchow * AMD L2/L3 Cache and TLB Associativity Field Definition: 4466606303c9Skchow * 4467606303c9Skchow * Unlike the associativity for the L1 cache and tlb where the 8 bit 4468606303c9Skchow * value is the associativity, the associativity for the L2 cache and 4469606303c9Skchow * tlb is encoded in the following table. The 4 bit L2 value serves as 4470606303c9Skchow * an index into the amd_afd[] array to determine the associativity. 4471606303c9Skchow * -1 is undefined. 0 is fully associative. 4472606303c9Skchow */ 4473606303c9Skchow 4474606303c9Skchow static int amd_afd[] = 4475606303c9Skchow {-1, 1, 2, -1, 4, -1, 8, -1, 16, -1, 32, 48, 64, 96, 128, 0}; 4476606303c9Skchow 44777c478bd9Sstevel@tonic-gate static void 44787c478bd9Sstevel@tonic-gate amd_l2cacheinfo(struct cpuid_info *cpi, struct l2info *l2i) 44797c478bd9Sstevel@tonic-gate { 44808949bcd6Sandrei struct cpuid_regs *cp; 44817c478bd9Sstevel@tonic-gate uint_t size, assoc; 4482606303c9Skchow int i; 44837c478bd9Sstevel@tonic-gate int *ip; 44847c478bd9Sstevel@tonic-gate 44857c478bd9Sstevel@tonic-gate if (cpi->cpi_xmaxeax < 0x80000006) 44867c478bd9Sstevel@tonic-gate return; 44877c478bd9Sstevel@tonic-gate cp = &cpi->cpi_extd[6]; 44887c478bd9Sstevel@tonic-gate 4489606303c9Skchow if ((i = BITX(cp->cp_ecx, 15, 12)) != 0 && 44907c478bd9Sstevel@tonic-gate (size = BITX(cp->cp_ecx, 31, 16)) != 0) { 44917c478bd9Sstevel@tonic-gate uint_t cachesz = size * 1024; 4492606303c9Skchow assoc = amd_afd[i]; 44937c478bd9Sstevel@tonic-gate 4494606303c9Skchow ASSERT(assoc != -1); 44957c478bd9Sstevel@tonic-gate 44967c478bd9Sstevel@tonic-gate if ((ip = l2i->l2i_csz) != NULL) 44977c478bd9Sstevel@tonic-gate *ip = cachesz; 44987c478bd9Sstevel@tonic-gate if ((ip = l2i->l2i_lsz) != NULL) 44997c478bd9Sstevel@tonic-gate *ip = BITX(cp->cp_ecx, 7, 0); 45007c478bd9Sstevel@tonic-gate if ((ip = l2i->l2i_assoc) != NULL) 45017c478bd9Sstevel@tonic-gate *ip = assoc; 45027c478bd9Sstevel@tonic-gate l2i->l2i_ret = cachesz; 45037c478bd9Sstevel@tonic-gate } 45047c478bd9Sstevel@tonic-gate } 45057c478bd9Sstevel@tonic-gate 45067c478bd9Sstevel@tonic-gate int 45077c478bd9Sstevel@tonic-gate getl2cacheinfo(cpu_t *cpu, int *csz, int *lsz, int *assoc) 45087c478bd9Sstevel@tonic-gate { 45097c478bd9Sstevel@tonic-gate struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi; 45107c478bd9Sstevel@tonic-gate struct l2info __l2info, *l2i = &__l2info; 45117c478bd9Sstevel@tonic-gate 45127c478bd9Sstevel@tonic-gate l2i->l2i_csz = csz; 45137c478bd9Sstevel@tonic-gate l2i->l2i_lsz = lsz; 45147c478bd9Sstevel@tonic-gate l2i->l2i_assoc = assoc; 45157c478bd9Sstevel@tonic-gate l2i->l2i_ret = -1; 45167c478bd9Sstevel@tonic-gate 45177c478bd9Sstevel@tonic-gate switch (x86_which_cacheinfo(cpi)) { 45187c478bd9Sstevel@tonic-gate case X86_VENDOR_Intel: 45197c478bd9Sstevel@tonic-gate intel_walk_cacheinfo(cpi, l2i, intel_l2cinfo); 45207c478bd9Sstevel@tonic-gate break; 45217c478bd9Sstevel@tonic-gate case X86_VENDOR_Cyrix: 45227c478bd9Sstevel@tonic-gate cyrix_walk_cacheinfo(cpi, l2i, intel_l2cinfo); 45237c478bd9Sstevel@tonic-gate break; 45247c478bd9Sstevel@tonic-gate case X86_VENDOR_AMD: 45257c478bd9Sstevel@tonic-gate amd_l2cacheinfo(cpi, l2i); 45267c478bd9Sstevel@tonic-gate break; 45277c478bd9Sstevel@tonic-gate default: 45287c478bd9Sstevel@tonic-gate break; 45297c478bd9Sstevel@tonic-gate } 45307c478bd9Sstevel@tonic-gate return (l2i->l2i_ret); 45317c478bd9Sstevel@tonic-gate } 4532f98fbcecSbholler 4533843e1988Sjohnlev #if !defined(__xpv) 4534843e1988Sjohnlev 45355b8a6efeSbholler uint32_t * 45365b8a6efeSbholler cpuid_mwait_alloc(cpu_t *cpu) 45375b8a6efeSbholler { 45385b8a6efeSbholler uint32_t *ret; 45395b8a6efeSbholler size_t mwait_size; 45405b8a6efeSbholler 4541a3114836SGerry Liu ASSERT(cpuid_checkpass(CPU, 2)); 45425b8a6efeSbholler 4543a3114836SGerry Liu mwait_size = CPU->cpu_m.mcpu_cpi->cpi_mwait.mon_max; 45445b8a6efeSbholler if (mwait_size == 0) 45455b8a6efeSbholler return (NULL); 45465b8a6efeSbholler 45475b8a6efeSbholler /* 45485b8a6efeSbholler * kmem_alloc() returns cache line size aligned data for mwait_size 45495b8a6efeSbholler * allocations. mwait_size is currently cache line sized. Neither 45505b8a6efeSbholler * of these implementation details are guarantied to be true in the 45515b8a6efeSbholler * future. 45525b8a6efeSbholler * 45535b8a6efeSbholler * First try allocating mwait_size as kmem_alloc() currently returns 45545b8a6efeSbholler * correctly aligned memory. If kmem_alloc() does not return 45555b8a6efeSbholler * mwait_size aligned memory, then use mwait_size ROUNDUP. 45565b8a6efeSbholler * 45575b8a6efeSbholler * Set cpi_mwait.buf_actual and cpi_mwait.size_actual in case we 45585b8a6efeSbholler * decide to free this memory. 45595b8a6efeSbholler */ 45605b8a6efeSbholler ret = kmem_zalloc(mwait_size, KM_SLEEP); 45615b8a6efeSbholler if (ret == (uint32_t *)P2ROUNDUP((uintptr_t)ret, mwait_size)) { 45625b8a6efeSbholler cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual = ret; 45635b8a6efeSbholler cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual = mwait_size; 45645b8a6efeSbholler *ret = MWAIT_RUNNING; 45655b8a6efeSbholler return (ret); 45665b8a6efeSbholler } else { 45675b8a6efeSbholler kmem_free(ret, mwait_size); 45685b8a6efeSbholler ret = kmem_zalloc(mwait_size * 2, KM_SLEEP); 45695b8a6efeSbholler cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual = ret; 45705b8a6efeSbholler cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual = mwait_size * 2; 45715b8a6efeSbholler ret = (uint32_t *)P2ROUNDUP((uintptr_t)ret, mwait_size); 45725b8a6efeSbholler *ret = MWAIT_RUNNING; 45735b8a6efeSbholler return (ret); 45745b8a6efeSbholler } 45755b8a6efeSbholler } 45765b8a6efeSbholler 45775b8a6efeSbholler void 45785b8a6efeSbholler cpuid_mwait_free(cpu_t *cpu) 4579f98fbcecSbholler { 4580a3114836SGerry Liu if (cpu->cpu_m.mcpu_cpi == NULL) { 4581a3114836SGerry Liu return; 4582a3114836SGerry Liu } 45835b8a6efeSbholler 45845b8a6efeSbholler if (cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual != NULL && 45855b8a6efeSbholler cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual > 0) { 45865b8a6efeSbholler kmem_free(cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual, 45875b8a6efeSbholler cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual); 45885b8a6efeSbholler } 45895b8a6efeSbholler 45905b8a6efeSbholler cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual = NULL; 45915b8a6efeSbholler cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual = 0; 4592f98fbcecSbholler } 4593843e1988Sjohnlev 4594247dbb3dSsudheer void 4595247dbb3dSsudheer patch_tsc_read(int flag) 4596247dbb3dSsudheer { 4597247dbb3dSsudheer size_t cnt; 4598e4b86885SCheng Sean Ye 4599247dbb3dSsudheer switch (flag) { 4600263f549eSPatrick Mooney case TSC_NONE: 4601247dbb3dSsudheer cnt = &_no_rdtsc_end - &_no_rdtsc_start; 46022b0bcb26Ssudheer (void) memcpy((void *)tsc_read, (void *)&_no_rdtsc_start, cnt); 4603247dbb3dSsudheer break; 4604263f549eSPatrick Mooney case TSC_RDTSC_MFENCE: 4605247dbb3dSsudheer cnt = &_tsc_mfence_end - &_tsc_mfence_start; 46062b0bcb26Ssudheer (void) memcpy((void *)tsc_read, 46072b0bcb26Ssudheer (void *)&_tsc_mfence_start, cnt); 4608247dbb3dSsudheer break; 4609263f549eSPatrick Mooney case TSC_RDTSC_LFENCE: 461015363b27Ssudheer cnt = &_tsc_lfence_end - &_tsc_lfence_start; 461115363b27Ssudheer (void) memcpy((void *)tsc_read, 461215363b27Ssudheer (void *)&_tsc_lfence_start, cnt); 461315363b27Ssudheer break; 4614263f549eSPatrick Mooney case TSC_TSCP: 4615263f549eSPatrick Mooney cnt = &_tscp_end - &_tscp_start; 4616263f549eSPatrick Mooney (void) memcpy((void *)tsc_read, (void *)&_tscp_start, cnt); 4617263f549eSPatrick Mooney break; 4618247dbb3dSsudheer default: 4619263f549eSPatrick Mooney /* Bail for unexpected TSC types. (TSC_NONE covers 0) */ 4620263f549eSPatrick Mooney cmn_err(CE_PANIC, "Unrecogized TSC type: %d", flag); 4621247dbb3dSsudheer break; 4622247dbb3dSsudheer } 4623263f549eSPatrick Mooney tsc_type = flag; 4624247dbb3dSsudheer } 4625247dbb3dSsudheer 46260e751525SEric Saxe int 46270e751525SEric Saxe cpuid_deep_cstates_supported(void) 46280e751525SEric Saxe { 46290e751525SEric Saxe struct cpuid_info *cpi; 46300e751525SEric Saxe struct cpuid_regs regs; 46310e751525SEric Saxe 46320e751525SEric Saxe ASSERT(cpuid_checkpass(CPU, 1)); 46330e751525SEric Saxe 46340e751525SEric Saxe cpi = CPU->cpu_m.mcpu_cpi; 46350e751525SEric Saxe 46367417cfdeSKuriakose Kuruvilla if (!is_x86_feature(x86_featureset, X86FSET_CPUID)) 46370e751525SEric Saxe return (0); 46380e751525SEric Saxe 46390e751525SEric Saxe switch (cpi->cpi_vendor) { 46400e751525SEric Saxe case X86_VENDOR_Intel: 46410e751525SEric Saxe if (cpi->cpi_xmaxeax < 0x80000007) 46420e751525SEric Saxe return (0); 46430e751525SEric Saxe 46440e751525SEric Saxe /* 46450e751525SEric Saxe * TSC run at a constant rate in all ACPI C-states? 46460e751525SEric Saxe */ 46470e751525SEric Saxe regs.cp_eax = 0x80000007; 46480e751525SEric Saxe (void) __cpuid_insn(®s); 46490e751525SEric Saxe return (regs.cp_edx & CPUID_TSC_CSTATE_INVARIANCE); 46500e751525SEric Saxe 46510e751525SEric Saxe default: 46520e751525SEric Saxe return (0); 46530e751525SEric Saxe } 46540e751525SEric Saxe } 46550e751525SEric Saxe 4656e774b42bSBill Holler #endif /* !__xpv */ 4657e774b42bSBill Holler 4658e774b42bSBill Holler void 4659e774b42bSBill Holler post_startup_cpu_fixups(void) 4660e774b42bSBill Holler { 4661e774b42bSBill Holler #ifndef __xpv 4662e774b42bSBill Holler /* 4663e774b42bSBill Holler * Some AMD processors support C1E state. Entering this state will 4664e774b42bSBill Holler * cause the local APIC timer to stop, which we can't deal with at 4665e774b42bSBill Holler * this time. 4666e774b42bSBill Holler */ 4667e774b42bSBill Holler if (cpuid_getvendor(CPU) == X86_VENDOR_AMD) { 4668e774b42bSBill Holler on_trap_data_t otd; 4669e774b42bSBill Holler uint64_t reg; 4670e774b42bSBill Holler 4671e774b42bSBill Holler if (!on_trap(&otd, OT_DATA_ACCESS)) { 4672e774b42bSBill Holler reg = rdmsr(MSR_AMD_INT_PENDING_CMP_HALT); 4673e774b42bSBill Holler /* Disable C1E state if it is enabled by BIOS */ 4674e774b42bSBill Holler if ((reg >> AMD_ACTONCMPHALT_SHIFT) & 4675e774b42bSBill Holler AMD_ACTONCMPHALT_MASK) { 4676e774b42bSBill Holler reg &= ~(AMD_ACTONCMPHALT_MASK << 4677e774b42bSBill Holler AMD_ACTONCMPHALT_SHIFT); 4678e774b42bSBill Holler wrmsr(MSR_AMD_INT_PENDING_CMP_HALT, reg); 4679e774b42bSBill Holler } 4680e774b42bSBill Holler } 4681e774b42bSBill Holler no_trap(); 4682e774b42bSBill Holler } 4683e774b42bSBill Holler #endif /* !__xpv */ 4684e774b42bSBill Holler } 4685e774b42bSBill Holler 4686cef70d2cSBill Holler /* 46877af88ac7SKuriakose Kuruvilla * Setup necessary registers to enable XSAVE feature on this processor. 46887af88ac7SKuriakose Kuruvilla * This function needs to be called early enough, so that no xsave/xrstor 46897af88ac7SKuriakose Kuruvilla * ops will execute on the processor before the MSRs are properly set up. 46907af88ac7SKuriakose Kuruvilla * 46917af88ac7SKuriakose Kuruvilla * Current implementation has the following assumption: 46927af88ac7SKuriakose Kuruvilla * - cpuid_pass1() is done, so that X86 features are known. 46937af88ac7SKuriakose Kuruvilla * - fpu_probe() is done, so that fp_save_mech is chosen. 46947af88ac7SKuriakose Kuruvilla */ 46957af88ac7SKuriakose Kuruvilla void 46967af88ac7SKuriakose Kuruvilla xsave_setup_msr(cpu_t *cpu) 46977af88ac7SKuriakose Kuruvilla { 46987af88ac7SKuriakose Kuruvilla ASSERT(fp_save_mech == FP_XSAVE); 46997af88ac7SKuriakose Kuruvilla ASSERT(is_x86_feature(x86_featureset, X86FSET_XSAVE)); 47007af88ac7SKuriakose Kuruvilla 47017af88ac7SKuriakose Kuruvilla /* Enable OSXSAVE in CR4. */ 47027af88ac7SKuriakose Kuruvilla setcr4(getcr4() | CR4_OSXSAVE); 47037af88ac7SKuriakose Kuruvilla /* 47047af88ac7SKuriakose Kuruvilla * Update SW copy of ECX, so that /dev/cpu/self/cpuid will report 47057af88ac7SKuriakose Kuruvilla * correct value. 47067af88ac7SKuriakose Kuruvilla */ 47077af88ac7SKuriakose Kuruvilla cpu->cpu_m.mcpu_cpi->cpi_std[1].cp_ecx |= CPUID_INTC_ECX_OSXSAVE; 47087af88ac7SKuriakose Kuruvilla setup_xfem(); 47097af88ac7SKuriakose Kuruvilla } 47107af88ac7SKuriakose Kuruvilla 47117af88ac7SKuriakose Kuruvilla /* 4712cef70d2cSBill Holler * Starting with the Westmere processor the local 4713cef70d2cSBill Holler * APIC timer will continue running in all C-states, 4714cef70d2cSBill Holler * including the deepest C-states. 4715cef70d2cSBill Holler */ 4716cef70d2cSBill Holler int 4717cef70d2cSBill Holler cpuid_arat_supported(void) 4718cef70d2cSBill Holler { 4719cef70d2cSBill Holler struct cpuid_info *cpi; 4720cef70d2cSBill Holler struct cpuid_regs regs; 4721cef70d2cSBill Holler 4722cef70d2cSBill Holler ASSERT(cpuid_checkpass(CPU, 1)); 47237417cfdeSKuriakose Kuruvilla ASSERT(is_x86_feature(x86_featureset, X86FSET_CPUID)); 4724cef70d2cSBill Holler 4725cef70d2cSBill Holler cpi = CPU->cpu_m.mcpu_cpi; 4726cef70d2cSBill Holler 4727cef70d2cSBill Holler switch (cpi->cpi_vendor) { 4728cef70d2cSBill Holler case X86_VENDOR_Intel: 4729cef70d2cSBill Holler /* 4730cef70d2cSBill Holler * Always-running Local APIC Timer is 4731cef70d2cSBill Holler * indicated by CPUID.6.EAX[2]. 4732cef70d2cSBill Holler */ 4733cef70d2cSBill Holler if (cpi->cpi_maxeax >= 6) { 4734cef70d2cSBill Holler regs.cp_eax = 6; 4735cef70d2cSBill Holler (void) cpuid_insn(NULL, ®s); 4736cef70d2cSBill Holler return (regs.cp_eax & CPUID_CSTATE_ARAT); 4737cef70d2cSBill Holler } else { 4738cef70d2cSBill Holler return (0); 4739cef70d2cSBill Holler } 4740cef70d2cSBill Holler default: 4741cef70d2cSBill Holler return (0); 4742cef70d2cSBill Holler } 4743cef70d2cSBill Holler } 4744cef70d2cSBill Holler 4745f21ed392Saubrey.li@intel.com /* 4746f21ed392Saubrey.li@intel.com * Check support for Intel ENERGY_PERF_BIAS feature 4747f21ed392Saubrey.li@intel.com */ 4748f21ed392Saubrey.li@intel.com int 4749f21ed392Saubrey.li@intel.com cpuid_iepb_supported(struct cpu *cp) 4750f21ed392Saubrey.li@intel.com { 4751f21ed392Saubrey.li@intel.com struct cpuid_info *cpi = cp->cpu_m.mcpu_cpi; 4752f21ed392Saubrey.li@intel.com struct cpuid_regs regs; 4753f21ed392Saubrey.li@intel.com 4754f21ed392Saubrey.li@intel.com ASSERT(cpuid_checkpass(cp, 1)); 4755f21ed392Saubrey.li@intel.com 47567417cfdeSKuriakose Kuruvilla if (!(is_x86_feature(x86_featureset, X86FSET_CPUID)) || 47577417cfdeSKuriakose Kuruvilla !(is_x86_feature(x86_featureset, X86FSET_MSR))) { 4758f21ed392Saubrey.li@intel.com return (0); 4759f21ed392Saubrey.li@intel.com } 4760f21ed392Saubrey.li@intel.com 4761f21ed392Saubrey.li@intel.com /* 4762f21ed392Saubrey.li@intel.com * Intel ENERGY_PERF_BIAS MSR is indicated by 4763f21ed392Saubrey.li@intel.com * capability bit CPUID.6.ECX.3 4764f21ed392Saubrey.li@intel.com */ 4765f21ed392Saubrey.li@intel.com if ((cpi->cpi_vendor != X86_VENDOR_Intel) || (cpi->cpi_maxeax < 6)) 4766f21ed392Saubrey.li@intel.com return (0); 4767f21ed392Saubrey.li@intel.com 4768f21ed392Saubrey.li@intel.com regs.cp_eax = 0x6; 4769f21ed392Saubrey.li@intel.com (void) cpuid_insn(NULL, ®s); 4770f21ed392Saubrey.li@intel.com return (regs.cp_ecx & CPUID_EPB_SUPPORT); 4771f21ed392Saubrey.li@intel.com } 4772f21ed392Saubrey.li@intel.com 477341afdfa7SKrishnendu Sadhukhan - Sun Microsystems /* 477441afdfa7SKrishnendu Sadhukhan - Sun Microsystems * Check support for TSC deadline timer 477541afdfa7SKrishnendu Sadhukhan - Sun Microsystems * 477641afdfa7SKrishnendu Sadhukhan - Sun Microsystems * TSC deadline timer provides a superior software programming 477741afdfa7SKrishnendu Sadhukhan - Sun Microsystems * model over local APIC timer that eliminates "time drifts". 477841afdfa7SKrishnendu Sadhukhan - Sun Microsystems * Instead of specifying a relative time, software specifies an 477941afdfa7SKrishnendu Sadhukhan - Sun Microsystems * absolute time as the target at which the processor should 478041afdfa7SKrishnendu Sadhukhan - Sun Microsystems * generate a timer event. 478141afdfa7SKrishnendu Sadhukhan - Sun Microsystems */ 478241afdfa7SKrishnendu Sadhukhan - Sun Microsystems int 478341afdfa7SKrishnendu Sadhukhan - Sun Microsystems cpuid_deadline_tsc_supported(void) 478441afdfa7SKrishnendu Sadhukhan - Sun Microsystems { 478541afdfa7SKrishnendu Sadhukhan - Sun Microsystems struct cpuid_info *cpi = CPU->cpu_m.mcpu_cpi; 478641afdfa7SKrishnendu Sadhukhan - Sun Microsystems struct cpuid_regs regs; 478741afdfa7SKrishnendu Sadhukhan - Sun Microsystems 478841afdfa7SKrishnendu Sadhukhan - Sun Microsystems ASSERT(cpuid_checkpass(CPU, 1)); 478941afdfa7SKrishnendu Sadhukhan - Sun Microsystems ASSERT(is_x86_feature(x86_featureset, X86FSET_CPUID)); 479041afdfa7SKrishnendu Sadhukhan - Sun Microsystems 479141afdfa7SKrishnendu Sadhukhan - Sun Microsystems switch (cpi->cpi_vendor) { 479241afdfa7SKrishnendu Sadhukhan - Sun Microsystems case X86_VENDOR_Intel: 479341afdfa7SKrishnendu Sadhukhan - Sun Microsystems if (cpi->cpi_maxeax >= 1) { 479441afdfa7SKrishnendu Sadhukhan - Sun Microsystems regs.cp_eax = 1; 479541afdfa7SKrishnendu Sadhukhan - Sun Microsystems (void) cpuid_insn(NULL, ®s); 479641afdfa7SKrishnendu Sadhukhan - Sun Microsystems return (regs.cp_ecx & CPUID_DEADLINE_TSC); 479741afdfa7SKrishnendu Sadhukhan - Sun Microsystems } else { 479841afdfa7SKrishnendu Sadhukhan - Sun Microsystems return (0); 479941afdfa7SKrishnendu Sadhukhan - Sun Microsystems } 480041afdfa7SKrishnendu Sadhukhan - Sun Microsystems default: 480141afdfa7SKrishnendu Sadhukhan - Sun Microsystems return (0); 480241afdfa7SKrishnendu Sadhukhan - Sun Microsystems } 480341afdfa7SKrishnendu Sadhukhan - Sun Microsystems } 480441afdfa7SKrishnendu Sadhukhan - Sun Microsystems 480522cc0e45SBill Holler #if defined(__amd64) && !defined(__xpv) 480622cc0e45SBill Holler /* 480722cc0e45SBill Holler * Patch in versions of bcopy for high performance Intel Nhm processors 480822cc0e45SBill Holler * and later... 480922cc0e45SBill Holler */ 481022cc0e45SBill Holler void 481122cc0e45SBill Holler patch_memops(uint_t vendor) 481222cc0e45SBill Holler { 481322cc0e45SBill Holler size_t cnt, i; 481422cc0e45SBill Holler caddr_t to, from; 481522cc0e45SBill Holler 48167417cfdeSKuriakose Kuruvilla if ((vendor == X86_VENDOR_Intel) && 48177417cfdeSKuriakose Kuruvilla is_x86_feature(x86_featureset, X86FSET_SSE4_2)) { 481822cc0e45SBill Holler cnt = &bcopy_patch_end - &bcopy_patch_start; 481922cc0e45SBill Holler to = &bcopy_ck_size; 482022cc0e45SBill Holler from = &bcopy_patch_start; 482122cc0e45SBill Holler for (i = 0; i < cnt; i++) { 482222cc0e45SBill Holler *to++ = *from++; 482322cc0e45SBill Holler } 482422cc0e45SBill Holler } 482522cc0e45SBill Holler } 482622cc0e45SBill Holler #endif /* __amd64 && !__xpv */ 48272d2efdc6SVuong Nguyen 48282d2efdc6SVuong Nguyen /* 48292d2efdc6SVuong Nguyen * This function finds the number of bits to represent the number of cores per 48302d2efdc6SVuong Nguyen * chip and the number of strands per core for the Intel platforms. 48312d2efdc6SVuong Nguyen * It re-uses the x2APIC cpuid code of the cpuid_pass2(). 48322d2efdc6SVuong Nguyen */ 48332d2efdc6SVuong Nguyen void 48342d2efdc6SVuong Nguyen cpuid_get_ext_topo(uint_t vendor, uint_t *core_nbits, uint_t *strand_nbits) 48352d2efdc6SVuong Nguyen { 48362d2efdc6SVuong Nguyen struct cpuid_regs regs; 48372d2efdc6SVuong Nguyen struct cpuid_regs *cp = ®s; 48382d2efdc6SVuong Nguyen 48392d2efdc6SVuong Nguyen if (vendor != X86_VENDOR_Intel) { 48402d2efdc6SVuong Nguyen return; 48412d2efdc6SVuong Nguyen } 48422d2efdc6SVuong Nguyen 48432d2efdc6SVuong Nguyen /* if the cpuid level is 0xB, extended topo is available. */ 48442d2efdc6SVuong Nguyen cp->cp_eax = 0; 48452d2efdc6SVuong Nguyen if (__cpuid_insn(cp) >= 0xB) { 48462d2efdc6SVuong Nguyen 48472d2efdc6SVuong Nguyen cp->cp_eax = 0xB; 48482d2efdc6SVuong Nguyen cp->cp_edx = cp->cp_ebx = cp->cp_ecx = 0; 48492d2efdc6SVuong Nguyen (void) __cpuid_insn(cp); 48502d2efdc6SVuong Nguyen 48512d2efdc6SVuong Nguyen /* 48522d2efdc6SVuong Nguyen * Check CPUID.EAX=0BH, ECX=0H:EBX is non-zero, which 48532d2efdc6SVuong Nguyen * indicates that the extended topology enumeration leaf is 48542d2efdc6SVuong Nguyen * available. 48552d2efdc6SVuong Nguyen */ 48562d2efdc6SVuong Nguyen if (cp->cp_ebx) { 48572d2efdc6SVuong Nguyen uint_t coreid_shift = 0; 48582d2efdc6SVuong Nguyen uint_t chipid_shift = 0; 48592d2efdc6SVuong Nguyen uint_t i; 48602d2efdc6SVuong Nguyen uint_t level; 48612d2efdc6SVuong Nguyen 48622d2efdc6SVuong Nguyen for (i = 0; i < CPI_FNB_ECX_MAX; i++) { 48632d2efdc6SVuong Nguyen cp->cp_eax = 0xB; 48642d2efdc6SVuong Nguyen cp->cp_ecx = i; 48652d2efdc6SVuong Nguyen 48662d2efdc6SVuong Nguyen (void) __cpuid_insn(cp); 48672d2efdc6SVuong Nguyen level = CPI_CPU_LEVEL_TYPE(cp); 48682d2efdc6SVuong Nguyen 48692d2efdc6SVuong Nguyen if (level == 1) { 48702d2efdc6SVuong Nguyen /* 48712d2efdc6SVuong Nguyen * Thread level processor topology 48722d2efdc6SVuong Nguyen * Number of bits shift right APIC ID 48732d2efdc6SVuong Nguyen * to get the coreid. 48742d2efdc6SVuong Nguyen */ 48752d2efdc6SVuong Nguyen coreid_shift = BITX(cp->cp_eax, 4, 0); 48762d2efdc6SVuong Nguyen } else if (level == 2) { 48772d2efdc6SVuong Nguyen /* 48782d2efdc6SVuong Nguyen * Core level processor topology 48792d2efdc6SVuong Nguyen * Number of bits shift right APIC ID 48802d2efdc6SVuong Nguyen * to get the chipid. 48812d2efdc6SVuong Nguyen */ 48822d2efdc6SVuong Nguyen chipid_shift = BITX(cp->cp_eax, 4, 0); 48832d2efdc6SVuong Nguyen } 48842d2efdc6SVuong Nguyen } 48852d2efdc6SVuong Nguyen 48862d2efdc6SVuong Nguyen if (coreid_shift > 0 && chipid_shift > coreid_shift) { 48872d2efdc6SVuong Nguyen *strand_nbits = coreid_shift; 48882d2efdc6SVuong Nguyen *core_nbits = chipid_shift - coreid_shift; 48892d2efdc6SVuong Nguyen } 48902d2efdc6SVuong Nguyen } 48912d2efdc6SVuong Nguyen } 48922d2efdc6SVuong Nguyen } 4893