xref: /titanic_52/usr/src/uts/i86pc/os/cpuid.c (revision 3db3a4ac8d5c81055f03a962e4d709dc5e13e2df)
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",
177*3db3a4acSRobert Mustacchi 	"rdseed",
178*3db3a4acSRobert Mustacchi 	"amd_pcec"
179faa20166SBryan Cantrill };
1807417cfdeSKuriakose Kuruvilla 
1817417cfdeSKuriakose Kuruvilla boolean_t
1827417cfdeSKuriakose Kuruvilla is_x86_feature(void *featureset, uint_t feature)
1837417cfdeSKuriakose Kuruvilla {
1847417cfdeSKuriakose Kuruvilla 	ASSERT(feature < NUM_X86_FEATURES);
1857417cfdeSKuriakose Kuruvilla 	return (BT_TEST((ulong_t *)featureset, feature));
1867417cfdeSKuriakose Kuruvilla }
1877417cfdeSKuriakose Kuruvilla 
1887417cfdeSKuriakose Kuruvilla void
1897417cfdeSKuriakose Kuruvilla add_x86_feature(void *featureset, uint_t feature)
1907417cfdeSKuriakose Kuruvilla {
1917417cfdeSKuriakose Kuruvilla 	ASSERT(feature < NUM_X86_FEATURES);
1927417cfdeSKuriakose Kuruvilla 	BT_SET((ulong_t *)featureset, feature);
1937417cfdeSKuriakose Kuruvilla }
1947417cfdeSKuriakose Kuruvilla 
1957417cfdeSKuriakose Kuruvilla void
1967417cfdeSKuriakose Kuruvilla remove_x86_feature(void *featureset, uint_t feature)
1977417cfdeSKuriakose Kuruvilla {
1987417cfdeSKuriakose Kuruvilla 	ASSERT(feature < NUM_X86_FEATURES);
1997417cfdeSKuriakose Kuruvilla 	BT_CLEAR((ulong_t *)featureset, feature);
2007417cfdeSKuriakose Kuruvilla }
2017417cfdeSKuriakose Kuruvilla 
2027417cfdeSKuriakose Kuruvilla boolean_t
2037417cfdeSKuriakose Kuruvilla compare_x86_featureset(void *setA, void *setB)
2047417cfdeSKuriakose Kuruvilla {
2057417cfdeSKuriakose Kuruvilla 	/*
2067417cfdeSKuriakose Kuruvilla 	 * We assume that the unused bits of the bitmap are always zero.
2077417cfdeSKuriakose Kuruvilla 	 */
2087417cfdeSKuriakose Kuruvilla 	if (memcmp(setA, setB, BT_SIZEOFMAP(NUM_X86_FEATURES)) == 0) {
2097417cfdeSKuriakose Kuruvilla 		return (B_TRUE);
2107417cfdeSKuriakose Kuruvilla 	} else {
2117417cfdeSKuriakose Kuruvilla 		return (B_FALSE);
2127417cfdeSKuriakose Kuruvilla 	}
2137417cfdeSKuriakose Kuruvilla }
2147417cfdeSKuriakose Kuruvilla 
2157417cfdeSKuriakose Kuruvilla void
2167417cfdeSKuriakose Kuruvilla print_x86_featureset(void *featureset)
2177417cfdeSKuriakose Kuruvilla {
2187417cfdeSKuriakose Kuruvilla 	uint_t i;
2197417cfdeSKuriakose Kuruvilla 
2207417cfdeSKuriakose Kuruvilla 	for (i = 0; i < NUM_X86_FEATURES; i++) {
2217417cfdeSKuriakose Kuruvilla 		if (is_x86_feature(featureset, i)) {
2227417cfdeSKuriakose Kuruvilla 			cmn_err(CE_CONT, "?x86_feature: %s\n",
2237417cfdeSKuriakose Kuruvilla 			    x86_feature_names[i]);
2247417cfdeSKuriakose Kuruvilla 		}
2257417cfdeSKuriakose Kuruvilla 	}
2267417cfdeSKuriakose Kuruvilla }
2277417cfdeSKuriakose Kuruvilla 
2287af88ac7SKuriakose Kuruvilla static size_t xsave_state_size = 0;
2297af88ac7SKuriakose Kuruvilla uint64_t xsave_bv_all = (XFEATURE_LEGACY_FP | XFEATURE_SSE);
2307af88ac7SKuriakose Kuruvilla boolean_t xsave_force_disable = B_FALSE;
2317af88ac7SKuriakose Kuruvilla 
2327997e108SSurya Prakki /*
23379ec9da8SYuri Pankov  * This is set to platform type we are running on.
2347997e108SSurya Prakki  */
235349b53ddSStuart Maybee static int platform_type = -1;
236349b53ddSStuart Maybee 
237349b53ddSStuart Maybee #if !defined(__xpv)
238349b53ddSStuart Maybee /*
239349b53ddSStuart Maybee  * Variable to patch if hypervisor platform detection needs to be
240349b53ddSStuart Maybee  * disabled (e.g. platform_type will always be HW_NATIVE if this is 0).
241349b53ddSStuart Maybee  */
242349b53ddSStuart Maybee int enable_platform_detection = 1;
243349b53ddSStuart Maybee #endif
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate /*
246f98fbcecSbholler  * monitor/mwait info.
2475b8a6efeSbholler  *
2485b8a6efeSbholler  * size_actual and buf_actual are the real address and size allocated to get
2495b8a6efeSbholler  * proper mwait_buf alignement.  buf_actual and size_actual should be passed
2505b8a6efeSbholler  * to kmem_free().  Currently kmem_alloc() and mwait happen to both use
2515b8a6efeSbholler  * processor cache-line alignment, but this is not guarantied in the furture.
252f98fbcecSbholler  */
253f98fbcecSbholler struct mwait_info {
254f98fbcecSbholler 	size_t		mon_min;	/* min size to avoid missed wakeups */
255f98fbcecSbholler 	size_t		mon_max;	/* size to avoid false wakeups */
2565b8a6efeSbholler 	size_t		size_actual;	/* size actually allocated */
2575b8a6efeSbholler 	void		*buf_actual;	/* memory actually allocated */
258f98fbcecSbholler 	uint32_t	support;	/* processor support of monitor/mwait */
259f98fbcecSbholler };
260f98fbcecSbholler 
261f98fbcecSbholler /*
2627af88ac7SKuriakose Kuruvilla  * xsave/xrestor info.
2637af88ac7SKuriakose Kuruvilla  *
2647af88ac7SKuriakose Kuruvilla  * This structure contains HW feature bits and size of the xsave save area.
2657af88ac7SKuriakose Kuruvilla  * Note: the kernel will use the maximum size required for all hardware
2667af88ac7SKuriakose Kuruvilla  * features. It is not optimize for potential memory savings if features at
2677af88ac7SKuriakose Kuruvilla  * the end of the save area are not enabled.
2687af88ac7SKuriakose Kuruvilla  */
2697af88ac7SKuriakose Kuruvilla struct xsave_info {
2707af88ac7SKuriakose Kuruvilla 	uint32_t	xsav_hw_features_low;   /* Supported HW features */
2717af88ac7SKuriakose Kuruvilla 	uint32_t	xsav_hw_features_high;  /* Supported HW features */
2727af88ac7SKuriakose Kuruvilla 	size_t		xsav_max_size;  /* max size save area for HW features */
2737af88ac7SKuriakose Kuruvilla 	size_t		ymm_size;	/* AVX: size of ymm save area */
2747af88ac7SKuriakose Kuruvilla 	size_t		ymm_offset;	/* AVX: offset for ymm save area */
2757af88ac7SKuriakose Kuruvilla };
2767af88ac7SKuriakose Kuruvilla 
2777af88ac7SKuriakose Kuruvilla 
2787af88ac7SKuriakose Kuruvilla /*
2797c478bd9Sstevel@tonic-gate  * These constants determine how many of the elements of the
2807c478bd9Sstevel@tonic-gate  * cpuid we cache in the cpuid_info data structure; the
2817c478bd9Sstevel@tonic-gate  * remaining elements are accessible via the cpuid instruction.
2827c478bd9Sstevel@tonic-gate  */
2837c478bd9Sstevel@tonic-gate 
284245ac945SRobert Mustacchi #define	NMAX_CPI_STD	8		/* eax = 0 .. 7 */
2857660e73fSHans Rosenfeld #define	NMAX_CPI_EXTD	0x1f		/* eax = 0x80000000 .. 0x8000001e */
2868031591dSSrihari Venkatesan 
2878031591dSSrihari Venkatesan /*
2888031591dSSrihari Venkatesan  * Some terminology needs to be explained:
2898031591dSSrihari Venkatesan  *  - Socket: Something that can be plugged into a motherboard.
2908031591dSSrihari Venkatesan  *  - Package: Same as socket
2918031591dSSrihari Venkatesan  *  - Chip: Same as socket. Note that AMD's documentation uses term "chip"
2928031591dSSrihari Venkatesan  *    differently: there, chip is the same as processor node (below)
2938031591dSSrihari Venkatesan  *  - Processor node: Some AMD processors have more than one
2948031591dSSrihari Venkatesan  *    "subprocessor" embedded in a package. These subprocessors (nodes)
2958031591dSSrihari Venkatesan  *    are fully-functional processors themselves with cores, caches,
2968031591dSSrihari Venkatesan  *    memory controllers, PCI configuration spaces. They are connected
2978031591dSSrihari Venkatesan  *    inside the package with Hypertransport links. On single-node
2988031591dSSrihari Venkatesan  *    processors, processor node is equivalent to chip/socket/package.
2997660e73fSHans Rosenfeld  *  - Compute Unit: Some AMD processors pair cores in "compute units" that
3007660e73fSHans Rosenfeld  *    share the FPU and the I$ and L2 caches.
3018031591dSSrihari Venkatesan  */
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate struct cpuid_info {
3047c478bd9Sstevel@tonic-gate 	uint_t cpi_pass;		/* last pass completed */
3057c478bd9Sstevel@tonic-gate 	/*
3067c478bd9Sstevel@tonic-gate 	 * standard function information
3077c478bd9Sstevel@tonic-gate 	 */
3087c478bd9Sstevel@tonic-gate 	uint_t cpi_maxeax;		/* fn 0: %eax */
3097c478bd9Sstevel@tonic-gate 	char cpi_vendorstr[13];		/* fn 0: %ebx:%ecx:%edx */
3107c478bd9Sstevel@tonic-gate 	uint_t cpi_vendor;		/* enum of cpi_vendorstr */
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	uint_t cpi_family;		/* fn 1: extended family */
3137c478bd9Sstevel@tonic-gate 	uint_t cpi_model;		/* fn 1: extended model */
3147c478bd9Sstevel@tonic-gate 	uint_t cpi_step;		/* fn 1: stepping */
3158031591dSSrihari Venkatesan 	chipid_t cpi_chipid;		/* fn 1: %ebx:  Intel: chip # */
3168031591dSSrihari Venkatesan 					/*		AMD: package/socket # */
3177c478bd9Sstevel@tonic-gate 	uint_t cpi_brandid;		/* fn 1: %ebx: brand ID */
3187c478bd9Sstevel@tonic-gate 	int cpi_clogid;			/* fn 1: %ebx: thread # */
3198949bcd6Sandrei 	uint_t cpi_ncpu_per_chip;	/* fn 1: %ebx: logical cpu count */
3207c478bd9Sstevel@tonic-gate 	uint8_t cpi_cacheinfo[16];	/* fn 2: intel-style cache desc */
3217c478bd9Sstevel@tonic-gate 	uint_t cpi_ncache;		/* fn 2: number of elements */
322d129bde2Sesaxe 	uint_t cpi_ncpu_shr_last_cache;	/* fn 4: %eax: ncpus sharing cache */
323d129bde2Sesaxe 	id_t cpi_last_lvl_cacheid;	/* fn 4: %eax: derived cache id */
324d129bde2Sesaxe 	uint_t cpi_std_4_size;		/* fn 4: number of fn 4 elements */
325d129bde2Sesaxe 	struct cpuid_regs **cpi_std_4;	/* fn 4: %ecx == 0 .. fn4_size */
326245ac945SRobert Mustacchi 	struct cpuid_regs cpi_std[NMAX_CPI_STD];	/* 0 .. 7 */
3277c478bd9Sstevel@tonic-gate 	/*
3287c478bd9Sstevel@tonic-gate 	 * extended function information
3297c478bd9Sstevel@tonic-gate 	 */
3307c478bd9Sstevel@tonic-gate 	uint_t cpi_xmaxeax;		/* fn 0x80000000: %eax */
3317c478bd9Sstevel@tonic-gate 	char cpi_brandstr[49];		/* fn 0x8000000[234] */
3327c478bd9Sstevel@tonic-gate 	uint8_t cpi_pabits;		/* fn 0x80000006: %eax */
3337c478bd9Sstevel@tonic-gate 	uint8_t	cpi_vabits;		/* fn 0x80000006: %eax */
3348031591dSSrihari Venkatesan 	struct	cpuid_regs cpi_extd[NMAX_CPI_EXTD];	/* 0x800000XX */
3358031591dSSrihari Venkatesan 
33610569901Sgavinm 	id_t cpi_coreid;		/* same coreid => strands share core */
33710569901Sgavinm 	int cpi_pkgcoreid;		/* core number within single package */
3388949bcd6Sandrei 	uint_t cpi_ncore_per_chip;	/* AMD: fn 0x80000008: %ecx[7-0] */
3398949bcd6Sandrei 					/* Intel: fn 4: %eax[31-26] */
3407c478bd9Sstevel@tonic-gate 	/*
3417c478bd9Sstevel@tonic-gate 	 * supported feature information
3427c478bd9Sstevel@tonic-gate 	 */
343245ac945SRobert Mustacchi 	uint32_t cpi_support[6];
3447c478bd9Sstevel@tonic-gate #define	STD_EDX_FEATURES	0
3457c478bd9Sstevel@tonic-gate #define	AMD_EDX_FEATURES	1
3467c478bd9Sstevel@tonic-gate #define	TM_EDX_FEATURES		2
3477c478bd9Sstevel@tonic-gate #define	STD_ECX_FEATURES	3
348ae115bc7Smrj #define	AMD_ECX_FEATURES	4
349245ac945SRobert Mustacchi #define	STD_EBX_FEATURES	5
3508a40a695Sgavinm 	/*
3518a40a695Sgavinm 	 * Synthesized information, where known.
3528a40a695Sgavinm 	 */
3538a40a695Sgavinm 	uint32_t cpi_chiprev;		/* See X86_CHIPREV_* in x86_archext.h */
3548a40a695Sgavinm 	const char *cpi_chiprevstr;	/* May be NULL if chiprev unknown */
3558a40a695Sgavinm 	uint32_t cpi_socket;		/* Chip package/socket type */
356f98fbcecSbholler 
357f98fbcecSbholler 	struct mwait_info cpi_mwait;	/* fn 5: monitor/mwait info */
358b6917abeSmishra 	uint32_t cpi_apicid;
3598031591dSSrihari Venkatesan 	uint_t cpi_procnodeid;		/* AMD: nodeID on HT, Intel: chipid */
3608031591dSSrihari Venkatesan 	uint_t cpi_procnodes_per_pkg;	/* AMD: # of nodes in the package */
3618031591dSSrihari Venkatesan 					/* Intel: 1 */
3627660e73fSHans Rosenfeld 	uint_t cpi_compunitid;		/* AMD: ComputeUnit ID, Intel: coreid */
3637660e73fSHans Rosenfeld 	uint_t cpi_cores_per_compunit;	/* AMD: # of cores in the ComputeUnit */
3647af88ac7SKuriakose Kuruvilla 
3657af88ac7SKuriakose Kuruvilla 	struct xsave_info cpi_xsave;	/* fn D: xsave/xrestor info */
3667c478bd9Sstevel@tonic-gate };
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate static struct cpuid_info cpuid_info0;
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate /*
3727c478bd9Sstevel@tonic-gate  * These bit fields are defined by the Intel Application Note AP-485
3737c478bd9Sstevel@tonic-gate  * "Intel Processor Identification and the CPUID Instruction"
3747c478bd9Sstevel@tonic-gate  */
3757c478bd9Sstevel@tonic-gate #define	CPI_FAMILY_XTD(cpi)	BITX((cpi)->cpi_std[1].cp_eax, 27, 20)
3767c478bd9Sstevel@tonic-gate #define	CPI_MODEL_XTD(cpi)	BITX((cpi)->cpi_std[1].cp_eax, 19, 16)
3777c478bd9Sstevel@tonic-gate #define	CPI_TYPE(cpi)		BITX((cpi)->cpi_std[1].cp_eax, 13, 12)
3787c478bd9Sstevel@tonic-gate #define	CPI_FAMILY(cpi)		BITX((cpi)->cpi_std[1].cp_eax, 11, 8)
3797c478bd9Sstevel@tonic-gate #define	CPI_STEP(cpi)		BITX((cpi)->cpi_std[1].cp_eax, 3, 0)
3807c478bd9Sstevel@tonic-gate #define	CPI_MODEL(cpi)		BITX((cpi)->cpi_std[1].cp_eax, 7, 4)
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate #define	CPI_FEATURES_EDX(cpi)		((cpi)->cpi_std[1].cp_edx)
3837c478bd9Sstevel@tonic-gate #define	CPI_FEATURES_ECX(cpi)		((cpi)->cpi_std[1].cp_ecx)
3847c478bd9Sstevel@tonic-gate #define	CPI_FEATURES_XTD_EDX(cpi)	((cpi)->cpi_extd[1].cp_edx)
3857c478bd9Sstevel@tonic-gate #define	CPI_FEATURES_XTD_ECX(cpi)	((cpi)->cpi_extd[1].cp_ecx)
386245ac945SRobert Mustacchi #define	CPI_FEATURES_7_0_EBX(cpi)	((cpi)->cpi_std[7].cp_ebx)
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate #define	CPI_BRANDID(cpi)	BITX((cpi)->cpi_std[1].cp_ebx, 7, 0)
3897c478bd9Sstevel@tonic-gate #define	CPI_CHUNKS(cpi)		BITX((cpi)->cpi_std[1].cp_ebx, 15, 7)
3907c478bd9Sstevel@tonic-gate #define	CPI_CPU_COUNT(cpi)	BITX((cpi)->cpi_std[1].cp_ebx, 23, 16)
3917c478bd9Sstevel@tonic-gate #define	CPI_APIC_ID(cpi)	BITX((cpi)->cpi_std[1].cp_ebx, 31, 24)
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate #define	CPI_MAXEAX_MAX		0x100		/* sanity control */
3947c478bd9Sstevel@tonic-gate #define	CPI_XMAXEAX_MAX		0x80000100
395d129bde2Sesaxe #define	CPI_FN4_ECX_MAX		0x20		/* sanity: max fn 4 levels */
396b6917abeSmishra #define	CPI_FNB_ECX_MAX		0x20		/* sanity: max fn B levels */
397d129bde2Sesaxe 
398d129bde2Sesaxe /*
399d129bde2Sesaxe  * Function 4 (Deterministic Cache Parameters) macros
400d129bde2Sesaxe  * Defined by Intel Application Note AP-485
401d129bde2Sesaxe  */
402d129bde2Sesaxe #define	CPI_NUM_CORES(regs)		BITX((regs)->cp_eax, 31, 26)
403d129bde2Sesaxe #define	CPI_NTHR_SHR_CACHE(regs)	BITX((regs)->cp_eax, 25, 14)
404d129bde2Sesaxe #define	CPI_FULL_ASSOC_CACHE(regs)	BITX((regs)->cp_eax, 9, 9)
405d129bde2Sesaxe #define	CPI_SELF_INIT_CACHE(regs)	BITX((regs)->cp_eax, 8, 8)
406d129bde2Sesaxe #define	CPI_CACHE_LVL(regs)		BITX((regs)->cp_eax, 7, 5)
407d129bde2Sesaxe #define	CPI_CACHE_TYPE(regs)		BITX((regs)->cp_eax, 4, 0)
408b6917abeSmishra #define	CPI_CPU_LEVEL_TYPE(regs)	BITX((regs)->cp_ecx, 15, 8)
409d129bde2Sesaxe 
410d129bde2Sesaxe #define	CPI_CACHE_WAYS(regs)		BITX((regs)->cp_ebx, 31, 22)
411d129bde2Sesaxe #define	CPI_CACHE_PARTS(regs)		BITX((regs)->cp_ebx, 21, 12)
412d129bde2Sesaxe #define	CPI_CACHE_COH_LN_SZ(regs)	BITX((regs)->cp_ebx, 11, 0)
413d129bde2Sesaxe 
414d129bde2Sesaxe #define	CPI_CACHE_SETS(regs)		BITX((regs)->cp_ecx, 31, 0)
415d129bde2Sesaxe 
416d129bde2Sesaxe #define	CPI_PREFCH_STRIDE(regs)		BITX((regs)->cp_edx, 9, 0)
417d129bde2Sesaxe 
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate /*
4205ff02082Sdmick  * A couple of shorthand macros to identify "later" P6-family chips
4215ff02082Sdmick  * like the Pentium M and Core.  First, the "older" P6-based stuff
4225ff02082Sdmick  * (loosely defined as "pre-Pentium-4"):
4235ff02082Sdmick  * P6, PII, Mobile PII, PII Xeon, PIII, Mobile PIII, PIII Xeon
4245ff02082Sdmick  */
4255ff02082Sdmick 
4265ff02082Sdmick #define	IS_LEGACY_P6(cpi) (			\
4275ff02082Sdmick 	cpi->cpi_family == 6 && 		\
4285ff02082Sdmick 		(cpi->cpi_model == 1 ||		\
4295ff02082Sdmick 		cpi->cpi_model == 3 ||		\
4305ff02082Sdmick 		cpi->cpi_model == 5 ||		\
4315ff02082Sdmick 		cpi->cpi_model == 6 ||		\
4325ff02082Sdmick 		cpi->cpi_model == 7 ||		\
4335ff02082Sdmick 		cpi->cpi_model == 8 ||		\
4345ff02082Sdmick 		cpi->cpi_model == 0xA ||	\
4355ff02082Sdmick 		cpi->cpi_model == 0xB)		\
4365ff02082Sdmick )
4375ff02082Sdmick 
4385ff02082Sdmick /* A "new F6" is everything with family 6 that's not the above */
4395ff02082Sdmick #define	IS_NEW_F6(cpi) ((cpi->cpi_family == 6) && !IS_LEGACY_P6(cpi))
4405ff02082Sdmick 
441bf91205bSksadhukh /* Extended family/model support */
442bf91205bSksadhukh #define	IS_EXTENDED_MODEL_INTEL(cpi) (cpi->cpi_family == 0x6 || \
443bf91205bSksadhukh 	cpi->cpi_family >= 0xf)
444bf91205bSksadhukh 
4455ff02082Sdmick /*
446f98fbcecSbholler  * Info for monitor/mwait idle loop.
447f98fbcecSbholler  *
448f98fbcecSbholler  * See cpuid section of "Intel 64 and IA-32 Architectures Software Developer's
449f98fbcecSbholler  * Manual Volume 2A: Instruction Set Reference, A-M" #25366-022US, November
450f98fbcecSbholler  * 2006.
451f98fbcecSbholler  * See MONITOR/MWAIT section of "AMD64 Architecture Programmer's Manual
452f98fbcecSbholler  * Documentation Updates" #33633, Rev 2.05, December 2006.
453f98fbcecSbholler  */
454f98fbcecSbholler #define	MWAIT_SUPPORT		(0x00000001)	/* mwait supported */
455f98fbcecSbholler #define	MWAIT_EXTENSIONS	(0x00000002)	/* extenstion supported */
456f98fbcecSbholler #define	MWAIT_ECX_INT_ENABLE	(0x00000004)	/* ecx 1 extension supported */
457f98fbcecSbholler #define	MWAIT_SUPPORTED(cpi)	((cpi)->cpi_std[1].cp_ecx & CPUID_INTC_ECX_MON)
458f98fbcecSbholler #define	MWAIT_INT_ENABLE(cpi)	((cpi)->cpi_std[5].cp_ecx & 0x2)
459f98fbcecSbholler #define	MWAIT_EXTENSION(cpi)	((cpi)->cpi_std[5].cp_ecx & 0x1)
460f98fbcecSbholler #define	MWAIT_SIZE_MIN(cpi)	BITX((cpi)->cpi_std[5].cp_eax, 15, 0)
461f98fbcecSbholler #define	MWAIT_SIZE_MAX(cpi)	BITX((cpi)->cpi_std[5].cp_ebx, 15, 0)
462f98fbcecSbholler /*
463f98fbcecSbholler  * Number of sub-cstates for a given c-state.
464f98fbcecSbholler  */
465f98fbcecSbholler #define	MWAIT_NUM_SUBC_STATES(cpi, c_state)			\
466f98fbcecSbholler 	BITX((cpi)->cpi_std[5].cp_edx, c_state + 3, c_state)
467f98fbcecSbholler 
4688a40a695Sgavinm /*
4697af88ac7SKuriakose Kuruvilla  * XSAVE leaf 0xD enumeration
4707af88ac7SKuriakose Kuruvilla  */
4717af88ac7SKuriakose Kuruvilla #define	CPUID_LEAFD_2_YMM_OFFSET	576
4727af88ac7SKuriakose Kuruvilla #define	CPUID_LEAFD_2_YMM_SIZE		256
4737af88ac7SKuriakose Kuruvilla 
4747af88ac7SKuriakose Kuruvilla /*
475e4b86885SCheng Sean Ye  * Functions we consune from cpuid_subr.c;  don't publish these in a header
476e4b86885SCheng Sean Ye  * file to try and keep people using the expected cpuid_* interfaces.
4778a40a695Sgavinm  */
478e4b86885SCheng Sean Ye extern uint32_t _cpuid_skt(uint_t, uint_t, uint_t, uint_t);
47989e921d5SKuriakose Kuruvilla extern const char *_cpuid_sktstr(uint_t, uint_t, uint_t, uint_t);
480e4b86885SCheng Sean Ye extern uint32_t _cpuid_chiprev(uint_t, uint_t, uint_t, uint_t);
481e4b86885SCheng Sean Ye extern const char *_cpuid_chiprevstr(uint_t, uint_t, uint_t, uint_t);
482e4b86885SCheng Sean Ye extern uint_t _cpuid_vendorstr_to_vendorcode(char *);
4838a40a695Sgavinm 
4848a40a695Sgavinm /*
485ae115bc7Smrj  * Apply up various platform-dependent restrictions where the
486ae115bc7Smrj  * underlying platform restrictions mean the CPU can be marked
487ae115bc7Smrj  * as less capable than its cpuid instruction would imply.
488ae115bc7Smrj  */
489843e1988Sjohnlev #if defined(__xpv)
490843e1988Sjohnlev static void
491843e1988Sjohnlev platform_cpuid_mangle(uint_t vendor, uint32_t eax, struct cpuid_regs *cp)
492843e1988Sjohnlev {
493843e1988Sjohnlev 	switch (eax) {
494e4b86885SCheng Sean Ye 	case 1: {
495e4b86885SCheng Sean Ye 		uint32_t mcamask = DOMAIN_IS_INITDOMAIN(xen_info) ?
496e4b86885SCheng Sean Ye 		    0 : CPUID_INTC_EDX_MCA;
497843e1988Sjohnlev 		cp->cp_edx &=
498e4b86885SCheng Sean Ye 		    ~(mcamask |
499e4b86885SCheng Sean Ye 		    CPUID_INTC_EDX_PSE |
500843e1988Sjohnlev 		    CPUID_INTC_EDX_VME | CPUID_INTC_EDX_DE |
501843e1988Sjohnlev 		    CPUID_INTC_EDX_SEP | CPUID_INTC_EDX_MTRR |
502843e1988Sjohnlev 		    CPUID_INTC_EDX_PGE | CPUID_INTC_EDX_PAT |
503843e1988Sjohnlev 		    CPUID_AMD_EDX_SYSC | CPUID_INTC_EDX_SEP |
504843e1988Sjohnlev 		    CPUID_INTC_EDX_PSE36 | CPUID_INTC_EDX_HTT);
505843e1988Sjohnlev 		break;
506e4b86885SCheng Sean Ye 	}
507ae115bc7Smrj 
508843e1988Sjohnlev 	case 0x80000001:
509843e1988Sjohnlev 		cp->cp_edx &=
510843e1988Sjohnlev 		    ~(CPUID_AMD_EDX_PSE |
511843e1988Sjohnlev 		    CPUID_INTC_EDX_VME | CPUID_INTC_EDX_DE |
512843e1988Sjohnlev 		    CPUID_AMD_EDX_MTRR | CPUID_AMD_EDX_PGE |
513843e1988Sjohnlev 		    CPUID_AMD_EDX_PAT | CPUID_AMD_EDX_PSE36 |
514843e1988Sjohnlev 		    CPUID_AMD_EDX_SYSC | CPUID_INTC_EDX_SEP |
515843e1988Sjohnlev 		    CPUID_AMD_EDX_TSCP);
516843e1988Sjohnlev 		cp->cp_ecx &= ~CPUID_AMD_ECX_CMP_LGCY;
517843e1988Sjohnlev 		break;
518843e1988Sjohnlev 	default:
519843e1988Sjohnlev 		break;
520843e1988Sjohnlev 	}
521843e1988Sjohnlev 
522843e1988Sjohnlev 	switch (vendor) {
523843e1988Sjohnlev 	case X86_VENDOR_Intel:
524843e1988Sjohnlev 		switch (eax) {
525843e1988Sjohnlev 		case 4:
526843e1988Sjohnlev 			/*
527843e1988Sjohnlev 			 * Zero out the (ncores-per-chip - 1) field
528843e1988Sjohnlev 			 */
529843e1988Sjohnlev 			cp->cp_eax &= 0x03fffffff;
530843e1988Sjohnlev 			break;
531843e1988Sjohnlev 		default:
532843e1988Sjohnlev 			break;
533843e1988Sjohnlev 		}
534843e1988Sjohnlev 		break;
535843e1988Sjohnlev 	case X86_VENDOR_AMD:
536843e1988Sjohnlev 		switch (eax) {
5372ef50f01SJoe Bonasera 
5382ef50f01SJoe Bonasera 		case 0x80000001:
5392ef50f01SJoe Bonasera 			cp->cp_ecx &= ~CPUID_AMD_ECX_CR8D;
5402ef50f01SJoe Bonasera 			break;
5412ef50f01SJoe Bonasera 
542843e1988Sjohnlev 		case 0x80000008:
543843e1988Sjohnlev 			/*
544843e1988Sjohnlev 			 * Zero out the (ncores-per-chip - 1) field
545843e1988Sjohnlev 			 */
546843e1988Sjohnlev 			cp->cp_ecx &= 0xffffff00;
547843e1988Sjohnlev 			break;
548843e1988Sjohnlev 		default:
549843e1988Sjohnlev 			break;
550843e1988Sjohnlev 		}
551843e1988Sjohnlev 		break;
552843e1988Sjohnlev 	default:
553843e1988Sjohnlev 		break;
554843e1988Sjohnlev 	}
555843e1988Sjohnlev }
556843e1988Sjohnlev #else
557ae115bc7Smrj #define	platform_cpuid_mangle(vendor, eax, cp)	/* nothing */
558843e1988Sjohnlev #endif
559ae115bc7Smrj 
560ae115bc7Smrj /*
5617c478bd9Sstevel@tonic-gate  *  Some undocumented ways of patching the results of the cpuid
5627c478bd9Sstevel@tonic-gate  *  instruction to permit running Solaris 10 on future cpus that
5637c478bd9Sstevel@tonic-gate  *  we don't currently support.  Could be set to non-zero values
5647c478bd9Sstevel@tonic-gate  *  via settings in eeprom.
5657c478bd9Sstevel@tonic-gate  */
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_ecx_include;
5687c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_ecx_exclude;
5697c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_edx_include;
5707c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_edx_exclude;
5717c478bd9Sstevel@tonic-gate 
572a3114836SGerry Liu /*
573a3114836SGerry Liu  * Allocate space for mcpu_cpi in the machcpu structure for all non-boot CPUs.
574a3114836SGerry Liu  */
575ae115bc7Smrj void
576ae115bc7Smrj cpuid_alloc_space(cpu_t *cpu)
577ae115bc7Smrj {
578ae115bc7Smrj 	/*
579ae115bc7Smrj 	 * By convention, cpu0 is the boot cpu, which is set up
580ae115bc7Smrj 	 * before memory allocation is available.  All other cpus get
581ae115bc7Smrj 	 * their cpuid_info struct allocated here.
582ae115bc7Smrj 	 */
583ae115bc7Smrj 	ASSERT(cpu->cpu_id != 0);
584a3114836SGerry Liu 	ASSERT(cpu->cpu_m.mcpu_cpi == NULL);
585ae115bc7Smrj 	cpu->cpu_m.mcpu_cpi =
586ae115bc7Smrj 	    kmem_zalloc(sizeof (*cpu->cpu_m.mcpu_cpi), KM_SLEEP);
587ae115bc7Smrj }
588ae115bc7Smrj 
589ae115bc7Smrj void
590ae115bc7Smrj cpuid_free_space(cpu_t *cpu)
591ae115bc7Smrj {
592d129bde2Sesaxe 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
593d129bde2Sesaxe 	int i;
594d129bde2Sesaxe 
595a3114836SGerry Liu 	ASSERT(cpi != NULL);
596a3114836SGerry Liu 	ASSERT(cpi != &cpuid_info0);
597d129bde2Sesaxe 
598d129bde2Sesaxe 	/*
599d129bde2Sesaxe 	 * Free up any function 4 related dynamic storage
600d129bde2Sesaxe 	 */
601d129bde2Sesaxe 	for (i = 1; i < cpi->cpi_std_4_size; i++)
602d129bde2Sesaxe 		kmem_free(cpi->cpi_std_4[i], sizeof (struct cpuid_regs));
603d129bde2Sesaxe 	if (cpi->cpi_std_4_size > 0)
604d129bde2Sesaxe 		kmem_free(cpi->cpi_std_4,
605d129bde2Sesaxe 		    cpi->cpi_std_4_size * sizeof (struct cpuid_regs *));
606d129bde2Sesaxe 
607a3114836SGerry Liu 	kmem_free(cpi, sizeof (*cpi));
608a3114836SGerry Liu 	cpu->cpu_m.mcpu_cpi = NULL;
609ae115bc7Smrj }
610ae115bc7Smrj 
611551bc2a6Smrj #if !defined(__xpv)
612cfe84b82SMatt Amdur /*
613cfe84b82SMatt Amdur  * Determine the type of the underlying platform. This is used to customize
614cfe84b82SMatt Amdur  * initialization of various subsystems (e.g. TSC). determine_platform() must
615cfe84b82SMatt Amdur  * only ever be called once to prevent two processors from seeing different
61679ec9da8SYuri Pankov  * values of platform_type. Must be called before cpuid_pass1(), the earliest
61779ec9da8SYuri Pankov  * consumer to execute (uses _cpuid_chiprev --> synth_amd_info --> get_hwenv).
618cfe84b82SMatt Amdur  */
619cfe84b82SMatt Amdur void
620cfe84b82SMatt Amdur determine_platform(void)
621551bc2a6Smrj {
622551bc2a6Smrj 	struct cpuid_regs cp;
62379ec9da8SYuri Pankov 	uint32_t base;
62479ec9da8SYuri Pankov 	uint32_t regs[4];
62579ec9da8SYuri Pankov 	char *hvstr = (char *)regs;
626551bc2a6Smrj 
627cfe84b82SMatt Amdur 	ASSERT(platform_type == -1);
628cfe84b82SMatt Amdur 
629349b53ddSStuart Maybee 	platform_type = HW_NATIVE;
630349b53ddSStuart Maybee 
631349b53ddSStuart Maybee 	if (!enable_platform_detection)
632349b53ddSStuart Maybee 		return;
633349b53ddSStuart Maybee 
634551bc2a6Smrj 	/*
63579ec9da8SYuri Pankov 	 * If Hypervisor CPUID bit is set, try to determine hypervisor
63679ec9da8SYuri Pankov 	 * vendor signature, and set platform type accordingly.
63779ec9da8SYuri Pankov 	 *
63879ec9da8SYuri Pankov 	 * References:
63979ec9da8SYuri Pankov 	 * http://lkml.org/lkml/2008/10/1/246
64079ec9da8SYuri Pankov 	 * http://kb.vmware.com/kb/1009458
641551bc2a6Smrj 	 */
64279ec9da8SYuri Pankov 	cp.cp_eax = 0x1;
643551bc2a6Smrj 	(void) __cpuid_insn(&cp);
64479ec9da8SYuri Pankov 	if ((cp.cp_ecx & CPUID_INTC_ECX_HV) != 0) {
64579ec9da8SYuri Pankov 		cp.cp_eax = 0x40000000;
64679ec9da8SYuri Pankov 		(void) __cpuid_insn(&cp);
64779ec9da8SYuri Pankov 		regs[0] = cp.cp_ebx;
64879ec9da8SYuri Pankov 		regs[1] = cp.cp_ecx;
64979ec9da8SYuri Pankov 		regs[2] = cp.cp_edx;
65079ec9da8SYuri Pankov 		regs[3] = 0;
65179ec9da8SYuri Pankov 		if (strcmp(hvstr, HVSIG_XEN_HVM) == 0) {
652b9bfdccdSStuart Maybee 			platform_type = HW_XEN_HVM;
6536e5580c9SFrank Van Der Linden 			return;
654551bc2a6Smrj 		}
65579ec9da8SYuri Pankov 		if (strcmp(hvstr, HVSIG_VMWARE) == 0) {
65679ec9da8SYuri Pankov 			platform_type = HW_VMWARE;
65779ec9da8SYuri Pankov 			return;
65879ec9da8SYuri Pankov 		}
65979ec9da8SYuri Pankov 		if (strcmp(hvstr, HVSIG_KVM) == 0) {
66079ec9da8SYuri Pankov 			platform_type = HW_KVM;
66179ec9da8SYuri Pankov 			return;
66279ec9da8SYuri Pankov 		}
66379ec9da8SYuri Pankov 		if (strcmp(hvstr, HVSIG_MICROSOFT) == 0)
66479ec9da8SYuri Pankov 			platform_type = HW_MICROSOFT;
66579ec9da8SYuri Pankov 	} else {
66679ec9da8SYuri Pankov 		/*
66779ec9da8SYuri Pankov 		 * Check older VMware hardware versions. VMware hypervisor is
66879ec9da8SYuri Pankov 		 * detected by performing an IN operation to VMware hypervisor
66979ec9da8SYuri Pankov 		 * port and checking that value returned in %ebx is VMware
67079ec9da8SYuri Pankov 		 * hypervisor magic value.
67179ec9da8SYuri Pankov 		 *
67279ec9da8SYuri Pankov 		 * References: http://kb.vmware.com/kb/1009458
67379ec9da8SYuri Pankov 		 */
67479ec9da8SYuri Pankov 		vmware_port(VMWARE_HVCMD_GETVERSION, regs);
67579ec9da8SYuri Pankov 		if (regs[1] == VMWARE_HVMAGIC) {
67679ec9da8SYuri Pankov 			platform_type = HW_VMWARE;
67779ec9da8SYuri Pankov 			return;
67879ec9da8SYuri Pankov 		}
679b9bfdccdSStuart Maybee 	}
680b9bfdccdSStuart Maybee 
68179ec9da8SYuri Pankov 	/*
68279ec9da8SYuri Pankov 	 * Check Xen hypervisor. In a fully virtualized domain,
68379ec9da8SYuri Pankov 	 * Xen's pseudo-cpuid function returns a string representing the
68479ec9da8SYuri Pankov 	 * Xen signature in %ebx, %ecx, and %edx. %eax contains the maximum
68579ec9da8SYuri Pankov 	 * supported cpuid function. We need at least a (base + 2) leaf value
68679ec9da8SYuri Pankov 	 * to do what we want to do. Try different base values, since the
68779ec9da8SYuri Pankov 	 * hypervisor might use a different one depending on whether Hyper-V
68879ec9da8SYuri Pankov 	 * emulation is switched on by default or not.
68979ec9da8SYuri Pankov 	 */
69079ec9da8SYuri Pankov 	for (base = 0x40000000; base < 0x40010000; base += 0x100) {
69179ec9da8SYuri Pankov 		cp.cp_eax = base;
69279ec9da8SYuri Pankov 		(void) __cpuid_insn(&cp);
69379ec9da8SYuri Pankov 		regs[0] = cp.cp_ebx;
69479ec9da8SYuri Pankov 		regs[1] = cp.cp_ecx;
69579ec9da8SYuri Pankov 		regs[2] = cp.cp_edx;
69679ec9da8SYuri Pankov 		regs[3] = 0;
69779ec9da8SYuri Pankov 		if (strcmp(hvstr, HVSIG_XEN_HVM) == 0 &&
69879ec9da8SYuri Pankov 		    cp.cp_eax >= (base + 2)) {
69979ec9da8SYuri Pankov 			platform_type &= ~HW_NATIVE;
70079ec9da8SYuri Pankov 			platform_type |= HW_XEN_HVM;
70179ec9da8SYuri Pankov 			return;
70279ec9da8SYuri Pankov 		}
70379ec9da8SYuri Pankov 	}
7046e5580c9SFrank Van Der Linden }
7056e5580c9SFrank Van Der Linden 
706b9bfdccdSStuart Maybee int
707b9bfdccdSStuart Maybee get_hwenv(void)
708b9bfdccdSStuart Maybee {
709cfe84b82SMatt Amdur 	ASSERT(platform_type != -1);
710b9bfdccdSStuart Maybee 	return (platform_type);
711b9bfdccdSStuart Maybee }
712b9bfdccdSStuart Maybee 
713b9bfdccdSStuart Maybee int
714b9bfdccdSStuart Maybee is_controldom(void)
715b9bfdccdSStuart Maybee {
716b9bfdccdSStuart Maybee 	return (0);
717b9bfdccdSStuart Maybee }
718b9bfdccdSStuart Maybee 
719b9bfdccdSStuart Maybee #else
720b9bfdccdSStuart Maybee 
721b9bfdccdSStuart Maybee int
722b9bfdccdSStuart Maybee get_hwenv(void)
723b9bfdccdSStuart Maybee {
724b9bfdccdSStuart Maybee 	return (HW_XEN_PV);
725b9bfdccdSStuart Maybee }
726b9bfdccdSStuart Maybee 
727b9bfdccdSStuart Maybee int
728b9bfdccdSStuart Maybee is_controldom(void)
729b9bfdccdSStuart Maybee {
730b9bfdccdSStuart Maybee 	return (DOMAIN_IS_INITDOMAIN(xen_info));
731b9bfdccdSStuart Maybee }
732b9bfdccdSStuart Maybee 
733551bc2a6Smrj #endif	/* __xpv */
734551bc2a6Smrj 
7358031591dSSrihari Venkatesan static void
7367417cfdeSKuriakose Kuruvilla cpuid_intel_getids(cpu_t *cpu, void *feature)
7378031591dSSrihari Venkatesan {
7388031591dSSrihari Venkatesan 	uint_t i;
7398031591dSSrihari Venkatesan 	uint_t chipid_shift = 0;
7408031591dSSrihari Venkatesan 	uint_t coreid_shift = 0;
7418031591dSSrihari Venkatesan 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
7428031591dSSrihari Venkatesan 
7438031591dSSrihari Venkatesan 	for (i = 1; i < cpi->cpi_ncpu_per_chip; i <<= 1)
7448031591dSSrihari Venkatesan 		chipid_shift++;
7458031591dSSrihari Venkatesan 
7468031591dSSrihari Venkatesan 	cpi->cpi_chipid = cpi->cpi_apicid >> chipid_shift;
7478031591dSSrihari Venkatesan 	cpi->cpi_clogid = cpi->cpi_apicid & ((1 << chipid_shift) - 1);
7488031591dSSrihari Venkatesan 
7497417cfdeSKuriakose Kuruvilla 	if (is_x86_feature(feature, X86FSET_CMP)) {
7508031591dSSrihari Venkatesan 		/*
7518031591dSSrihari Venkatesan 		 * Multi-core (and possibly multi-threaded)
7528031591dSSrihari Venkatesan 		 * processors.
7538031591dSSrihari Venkatesan 		 */
7548031591dSSrihari Venkatesan 		uint_t ncpu_per_core;
7558031591dSSrihari Venkatesan 		if (cpi->cpi_ncore_per_chip == 1)
7568031591dSSrihari Venkatesan 			ncpu_per_core = cpi->cpi_ncpu_per_chip;
7578031591dSSrihari Venkatesan 		else if (cpi->cpi_ncore_per_chip > 1)
7588031591dSSrihari Venkatesan 			ncpu_per_core = cpi->cpi_ncpu_per_chip /
7598031591dSSrihari Venkatesan 			    cpi->cpi_ncore_per_chip;
7608031591dSSrihari Venkatesan 		/*
7618031591dSSrihari Venkatesan 		 * 8bit APIC IDs on dual core Pentiums
7628031591dSSrihari Venkatesan 		 * look like this:
7638031591dSSrihari Venkatesan 		 *
7648031591dSSrihari Venkatesan 		 * +-----------------------+------+------+
7658031591dSSrihari Venkatesan 		 * | Physical Package ID   |  MC  |  HT  |
7668031591dSSrihari Venkatesan 		 * +-----------------------+------+------+
7678031591dSSrihari Venkatesan 		 * <------- chipid -------->
7688031591dSSrihari Venkatesan 		 * <------- coreid --------------->
7698031591dSSrihari Venkatesan 		 *			   <--- clogid -->
7708031591dSSrihari Venkatesan 		 *			   <------>
7718031591dSSrihari Venkatesan 		 *			   pkgcoreid
7728031591dSSrihari Venkatesan 		 *
7738031591dSSrihari Venkatesan 		 * Where the number of bits necessary to
7748031591dSSrihari Venkatesan 		 * represent MC and HT fields together equals
7758031591dSSrihari Venkatesan 		 * to the minimum number of bits necessary to
7768031591dSSrihari Venkatesan 		 * store the value of cpi->cpi_ncpu_per_chip.
7778031591dSSrihari Venkatesan 		 * Of those bits, the MC part uses the number
7788031591dSSrihari Venkatesan 		 * of bits necessary to store the value of
7798031591dSSrihari Venkatesan 		 * cpi->cpi_ncore_per_chip.
7808031591dSSrihari Venkatesan 		 */
7818031591dSSrihari Venkatesan 		for (i = 1; i < ncpu_per_core; i <<= 1)
7828031591dSSrihari Venkatesan 			coreid_shift++;
7838031591dSSrihari Venkatesan 		cpi->cpi_coreid = cpi->cpi_apicid >> coreid_shift;
7848031591dSSrihari Venkatesan 		cpi->cpi_pkgcoreid = cpi->cpi_clogid >> coreid_shift;
7857417cfdeSKuriakose Kuruvilla 	} else if (is_x86_feature(feature, X86FSET_HTT)) {
7868031591dSSrihari Venkatesan 		/*
7878031591dSSrihari Venkatesan 		 * Single-core multi-threaded processors.
7888031591dSSrihari Venkatesan 		 */
7898031591dSSrihari Venkatesan 		cpi->cpi_coreid = cpi->cpi_chipid;
7908031591dSSrihari Venkatesan 		cpi->cpi_pkgcoreid = 0;
7918031591dSSrihari Venkatesan 	}
7928031591dSSrihari Venkatesan 	cpi->cpi_procnodeid = cpi->cpi_chipid;
7937660e73fSHans Rosenfeld 	cpi->cpi_compunitid = cpi->cpi_coreid;
7948031591dSSrihari Venkatesan }
7958031591dSSrihari Venkatesan 
7968031591dSSrihari Venkatesan static void
7978031591dSSrihari Venkatesan cpuid_amd_getids(cpu_t *cpu)
7988031591dSSrihari Venkatesan {
7991fbe4a4fSSrihari Venkatesan 	int i, first_half, coreidsz;
8008031591dSSrihari Venkatesan 	uint32_t nb_caps_reg;
8018031591dSSrihari Venkatesan 	uint_t node2_1;
8028031591dSSrihari Venkatesan 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
8037660e73fSHans Rosenfeld 	struct cpuid_regs *cp;
8048031591dSSrihari Venkatesan 
8058031591dSSrihari Venkatesan 	/*
8068031591dSSrihari Venkatesan 	 * AMD CMP chips currently have a single thread per core.
8078031591dSSrihari Venkatesan 	 *
8088031591dSSrihari Venkatesan 	 * Since no two cpus share a core we must assign a distinct coreid
8098031591dSSrihari Venkatesan 	 * per cpu, and we do this by using the cpu_id.  This scheme does not,
8108031591dSSrihari Venkatesan 	 * however, guarantee that sibling cores of a chip will have sequential
8118031591dSSrihari Venkatesan 	 * coreids starting at a multiple of the number of cores per chip -
8128031591dSSrihari Venkatesan 	 * that is usually the case, but if the ACPI MADT table is presented
8138031591dSSrihari Venkatesan 	 * in a different order then we need to perform a few more gymnastics
8148031591dSSrihari Venkatesan 	 * for the pkgcoreid.
8158031591dSSrihari Venkatesan 	 *
8168031591dSSrihari Venkatesan 	 * All processors in the system have the same number of enabled
8178031591dSSrihari Venkatesan 	 * cores. Cores within a processor are always numbered sequentially
8188031591dSSrihari Venkatesan 	 * from 0 regardless of how many or which are disabled, and there
8198031591dSSrihari Venkatesan 	 * is no way for operating system to discover the real core id when some
8208031591dSSrihari Venkatesan 	 * are disabled.
8217660e73fSHans Rosenfeld 	 *
8227660e73fSHans Rosenfeld 	 * In family 0x15, the cores come in pairs called compute units. They
8237660e73fSHans Rosenfeld 	 * share I$ and L2 caches and the FPU. Enumeration of this feature is
8247660e73fSHans Rosenfeld 	 * simplified by the new topology extensions CPUID leaf, indicated by
8257660e73fSHans Rosenfeld 	 * the X86 feature X86FSET_TOPOEXT.
8268031591dSSrihari Venkatesan 	 */
8278031591dSSrihari Venkatesan 
8288031591dSSrihari Venkatesan 	cpi->cpi_coreid = cpu->cpu_id;
8297660e73fSHans Rosenfeld 	cpi->cpi_compunitid = cpu->cpu_id;
8308031591dSSrihari Venkatesan 
8318031591dSSrihari Venkatesan 	if (cpi->cpi_xmaxeax >= 0x80000008) {
8328031591dSSrihari Venkatesan 
8338031591dSSrihari Venkatesan 		coreidsz = BITX((cpi)->cpi_extd[8].cp_ecx, 15, 12);
8348031591dSSrihari Venkatesan 
8358031591dSSrihari Venkatesan 		/*
8368031591dSSrihari Venkatesan 		 * In AMD parlance chip is really a node while Solaris
8378031591dSSrihari Venkatesan 		 * sees chip as equivalent to socket/package.
8388031591dSSrihari Venkatesan 		 */
8398031591dSSrihari Venkatesan 		cpi->cpi_ncore_per_chip =
8408031591dSSrihari Venkatesan 		    BITX((cpi)->cpi_extd[8].cp_ecx, 7, 0) + 1;
8411fbe4a4fSSrihari Venkatesan 		if (coreidsz == 0) {
8428031591dSSrihari Venkatesan 			/* Use legacy method */
8431fbe4a4fSSrihari Venkatesan 			for (i = 1; i < cpi->cpi_ncore_per_chip; i <<= 1)
8441fbe4a4fSSrihari Venkatesan 				coreidsz++;
8451fbe4a4fSSrihari Venkatesan 			if (coreidsz == 0)
8461fbe4a4fSSrihari Venkatesan 				coreidsz = 1;
8471fbe4a4fSSrihari Venkatesan 		}
8488031591dSSrihari Venkatesan 	} else {
8498031591dSSrihari Venkatesan 		/* Assume single-core part */
8501fbe4a4fSSrihari Venkatesan 		cpi->cpi_ncore_per_chip = 1;
85172b70389SJakub Jermar 		coreidsz = 1;
8528031591dSSrihari Venkatesan 	}
8538031591dSSrihari Venkatesan 
8541fbe4a4fSSrihari Venkatesan 	cpi->cpi_clogid = cpi->cpi_pkgcoreid =
8551fbe4a4fSSrihari Venkatesan 	    cpi->cpi_apicid & ((1<<coreidsz) - 1);
8568031591dSSrihari Venkatesan 	cpi->cpi_ncpu_per_chip = cpi->cpi_ncore_per_chip;
8578031591dSSrihari Venkatesan 
8587660e73fSHans Rosenfeld 	/* Get node ID, compute unit ID */
8597660e73fSHans Rosenfeld 	if (is_x86_feature(x86_featureset, X86FSET_TOPOEXT) &&
8607660e73fSHans Rosenfeld 	    cpi->cpi_xmaxeax >= 0x8000001e) {
8617660e73fSHans Rosenfeld 		cp = &cpi->cpi_extd[0x1e];
8627660e73fSHans Rosenfeld 		cp->cp_eax = 0x8000001e;
8637660e73fSHans Rosenfeld 		(void) __cpuid_insn(cp);
8647660e73fSHans Rosenfeld 
8657660e73fSHans Rosenfeld 		cpi->cpi_procnodes_per_pkg = BITX(cp->cp_ecx, 10, 8) + 1;
8667660e73fSHans Rosenfeld 		cpi->cpi_procnodeid = BITX(cp->cp_ecx, 7, 0);
8677660e73fSHans Rosenfeld 		cpi->cpi_cores_per_compunit = BITX(cp->cp_ebx, 15, 8) + 1;
8687660e73fSHans Rosenfeld 		cpi->cpi_compunitid = BITX(cp->cp_ebx, 7, 0)
8697660e73fSHans Rosenfeld 		    + (cpi->cpi_ncore_per_chip / cpi->cpi_cores_per_compunit)
8707660e73fSHans Rosenfeld 		    * (cpi->cpi_procnodeid / cpi->cpi_procnodes_per_pkg);
8717660e73fSHans Rosenfeld 	} else if (cpi->cpi_family == 0xf || cpi->cpi_family >= 0x11) {
8721fbe4a4fSSrihari Venkatesan 		cpi->cpi_procnodeid = (cpi->cpi_apicid >> coreidsz) & 7;
8738031591dSSrihari Venkatesan 	} else if (cpi->cpi_family == 0x10) {
8748031591dSSrihari Venkatesan 		/*
8758031591dSSrihari Venkatesan 		 * See if we are a multi-node processor.
8768031591dSSrihari Venkatesan 		 * All processors in the system have the same number of nodes
8778031591dSSrihari Venkatesan 		 */
8788031591dSSrihari Venkatesan 		nb_caps_reg =  pci_getl_func(0, 24, 3, 0xe8);
8798031591dSSrihari Venkatesan 		if ((cpi->cpi_model < 8) || BITX(nb_caps_reg, 29, 29) == 0) {
8808031591dSSrihari Venkatesan 			/* Single-node */
8811fbe4a4fSSrihari Venkatesan 			cpi->cpi_procnodeid = BITX(cpi->cpi_apicid, 5,
8821fbe4a4fSSrihari Venkatesan 			    coreidsz);
8838031591dSSrihari Venkatesan 		} else {
8848031591dSSrihari Venkatesan 
8858031591dSSrihari Venkatesan 			/*
8868031591dSSrihari Venkatesan 			 * Multi-node revision D (2 nodes per package
8878031591dSSrihari Venkatesan 			 * are supported)
8888031591dSSrihari Venkatesan 			 */
8898031591dSSrihari Venkatesan 			cpi->cpi_procnodes_per_pkg = 2;
8908031591dSSrihari Venkatesan 
8918031591dSSrihari Venkatesan 			first_half = (cpi->cpi_pkgcoreid <=
8928031591dSSrihari Venkatesan 			    (cpi->cpi_ncore_per_chip/2 - 1));
8938031591dSSrihari Venkatesan 
8948031591dSSrihari Venkatesan 			if (cpi->cpi_apicid == cpi->cpi_pkgcoreid) {
8958031591dSSrihari Venkatesan 				/* We are BSP */
8968031591dSSrihari Venkatesan 				cpi->cpi_procnodeid = (first_half ? 0 : 1);
8978031591dSSrihari Venkatesan 			} else {
8988031591dSSrihari Venkatesan 
8998031591dSSrihari Venkatesan 				/* We are AP */
9008031591dSSrihari Venkatesan 				/* NodeId[2:1] bits to use for reading F3xe8 */
9018031591dSSrihari Venkatesan 				node2_1 = BITX(cpi->cpi_apicid, 5, 4) << 1;
9028031591dSSrihari Venkatesan 
9038031591dSSrihari Venkatesan 				nb_caps_reg =
9048031591dSSrihari Venkatesan 				    pci_getl_func(0, 24 + node2_1, 3, 0xe8);
9058031591dSSrihari Venkatesan 
9068031591dSSrihari Venkatesan 				/*
9078031591dSSrihari Venkatesan 				 * Check IntNodeNum bit (31:30, but bit 31 is
9088031591dSSrihari Venkatesan 				 * always 0 on dual-node processors)
9098031591dSSrihari Venkatesan 				 */
9108031591dSSrihari Venkatesan 				if (BITX(nb_caps_reg, 30, 30) == 0)
9118031591dSSrihari Venkatesan 					cpi->cpi_procnodeid = node2_1 +
9128031591dSSrihari Venkatesan 					    !first_half;
9138031591dSSrihari Venkatesan 				else
9148031591dSSrihari Venkatesan 					cpi->cpi_procnodeid = node2_1 +
9158031591dSSrihari Venkatesan 					    first_half;
9168031591dSSrihari Venkatesan 			}
9178031591dSSrihari Venkatesan 		}
9188031591dSSrihari Venkatesan 	} else {
9198031591dSSrihari Venkatesan 		cpi->cpi_procnodeid = 0;
9208031591dSSrihari Venkatesan 	}
9217660e73fSHans Rosenfeld 
9227660e73fSHans Rosenfeld 	cpi->cpi_chipid =
9237660e73fSHans Rosenfeld 	    cpi->cpi_procnodeid / cpi->cpi_procnodes_per_pkg;
9248031591dSSrihari Venkatesan }
9258031591dSSrihari Venkatesan 
9267af88ac7SKuriakose Kuruvilla /*
9277af88ac7SKuriakose Kuruvilla  * Setup XFeature_Enabled_Mask register. Required by xsave feature.
9287af88ac7SKuriakose Kuruvilla  */
9297af88ac7SKuriakose Kuruvilla void
9307af88ac7SKuriakose Kuruvilla setup_xfem(void)
9317af88ac7SKuriakose Kuruvilla {
9327af88ac7SKuriakose Kuruvilla 	uint64_t flags = XFEATURE_LEGACY_FP;
9337af88ac7SKuriakose Kuruvilla 
9347af88ac7SKuriakose Kuruvilla 	ASSERT(is_x86_feature(x86_featureset, X86FSET_XSAVE));
9357af88ac7SKuriakose Kuruvilla 
9367af88ac7SKuriakose Kuruvilla 	if (is_x86_feature(x86_featureset, X86FSET_SSE))
9377af88ac7SKuriakose Kuruvilla 		flags |= XFEATURE_SSE;
9387af88ac7SKuriakose Kuruvilla 
9397af88ac7SKuriakose Kuruvilla 	if (is_x86_feature(x86_featureset, X86FSET_AVX))
9407af88ac7SKuriakose Kuruvilla 		flags |= XFEATURE_AVX;
9417af88ac7SKuriakose Kuruvilla 
9427af88ac7SKuriakose Kuruvilla 	set_xcr(XFEATURE_ENABLED_MASK, flags);
9437af88ac7SKuriakose Kuruvilla 
9447af88ac7SKuriakose Kuruvilla 	xsave_bv_all = flags;
9457af88ac7SKuriakose Kuruvilla }
9467af88ac7SKuriakose Kuruvilla 
947dfea898aSKuriakose Kuruvilla void
948dfea898aSKuriakose Kuruvilla cpuid_pass1(cpu_t *cpu, uchar_t *featureset)
9497c478bd9Sstevel@tonic-gate {
9507c478bd9Sstevel@tonic-gate 	uint32_t mask_ecx, mask_edx;
9517c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi;
9528949bcd6Sandrei 	struct cpuid_regs *cp;
9537c478bd9Sstevel@tonic-gate 	int xcpuid;
954843e1988Sjohnlev #if !defined(__xpv)
9555b8a6efeSbholler 	extern int idle_cpu_prefer_mwait;
956843e1988Sjohnlev #endif
957ae115bc7Smrj 
9587c478bd9Sstevel@tonic-gate 	/*
959a3114836SGerry Liu 	 * Space statically allocated for BSP, ensure pointer is set
9607c478bd9Sstevel@tonic-gate 	 */
9617417cfdeSKuriakose Kuruvilla 	if (cpu->cpu_id == 0) {
9627417cfdeSKuriakose Kuruvilla 		if (cpu->cpu_m.mcpu_cpi == NULL)
963ae115bc7Smrj 			cpu->cpu_m.mcpu_cpi = &cpuid_info0;
9647417cfdeSKuriakose Kuruvilla 	}
9657417cfdeSKuriakose Kuruvilla 
9667417cfdeSKuriakose Kuruvilla 	add_x86_feature(featureset, X86FSET_CPUID);
9677417cfdeSKuriakose Kuruvilla 
968ae115bc7Smrj 	cpi = cpu->cpu_m.mcpu_cpi;
969ae115bc7Smrj 	ASSERT(cpi != NULL);
9707c478bd9Sstevel@tonic-gate 	cp = &cpi->cpi_std[0];
9718949bcd6Sandrei 	cp->cp_eax = 0;
9728949bcd6Sandrei 	cpi->cpi_maxeax = __cpuid_insn(cp);
9737c478bd9Sstevel@tonic-gate 	{
9747c478bd9Sstevel@tonic-gate 		uint32_t *iptr = (uint32_t *)cpi->cpi_vendorstr;
9757c478bd9Sstevel@tonic-gate 		*iptr++ = cp->cp_ebx;
9767c478bd9Sstevel@tonic-gate 		*iptr++ = cp->cp_edx;
9777c478bd9Sstevel@tonic-gate 		*iptr++ = cp->cp_ecx;
9787c478bd9Sstevel@tonic-gate 		*(char *)&cpi->cpi_vendorstr[12] = '\0';
9797c478bd9Sstevel@tonic-gate 	}
9807c478bd9Sstevel@tonic-gate 
981e4b86885SCheng Sean Ye 	cpi->cpi_vendor = _cpuid_vendorstr_to_vendorcode(cpi->cpi_vendorstr);
9827c478bd9Sstevel@tonic-gate 	x86_vendor = cpi->cpi_vendor; /* for compatibility */
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 	/*
9857c478bd9Sstevel@tonic-gate 	 * Limit the range in case of weird hardware
9867c478bd9Sstevel@tonic-gate 	 */
9877c478bd9Sstevel@tonic-gate 	if (cpi->cpi_maxeax > CPI_MAXEAX_MAX)
9887c478bd9Sstevel@tonic-gate 		cpi->cpi_maxeax = CPI_MAXEAX_MAX;
9897c478bd9Sstevel@tonic-gate 	if (cpi->cpi_maxeax < 1)
9907c478bd9Sstevel@tonic-gate 		goto pass1_done;
9917c478bd9Sstevel@tonic-gate 
9927c478bd9Sstevel@tonic-gate 	cp = &cpi->cpi_std[1];
9938949bcd6Sandrei 	cp->cp_eax = 1;
9948949bcd6Sandrei 	(void) __cpuid_insn(cp);
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate 	/*
9977c478bd9Sstevel@tonic-gate 	 * Extract identifying constants for easy access.
9987c478bd9Sstevel@tonic-gate 	 */
9997c478bd9Sstevel@tonic-gate 	cpi->cpi_model = CPI_MODEL(cpi);
10007c478bd9Sstevel@tonic-gate 	cpi->cpi_family = CPI_FAMILY(cpi);
10017c478bd9Sstevel@tonic-gate 
10025ff02082Sdmick 	if (cpi->cpi_family == 0xf)
10037c478bd9Sstevel@tonic-gate 		cpi->cpi_family += CPI_FAMILY_XTD(cpi);
10045ff02082Sdmick 
100568c91426Sdmick 	/*
1006875b116eSkchow 	 * Beware: AMD uses "extended model" iff base *FAMILY* == 0xf.
100768c91426Sdmick 	 * Intel, and presumably everyone else, uses model == 0xf, as
100868c91426Sdmick 	 * one would expect (max value means possible overflow).  Sigh.
100968c91426Sdmick 	 */
101068c91426Sdmick 
101168c91426Sdmick 	switch (cpi->cpi_vendor) {
1012bf91205bSksadhukh 	case X86_VENDOR_Intel:
1013bf91205bSksadhukh 		if (IS_EXTENDED_MODEL_INTEL(cpi))
1014bf91205bSksadhukh 			cpi->cpi_model += CPI_MODEL_XTD(cpi) << 4;
1015447af253Sksadhukh 		break;
101668c91426Sdmick 	case X86_VENDOR_AMD:
1017875b116eSkchow 		if (CPI_FAMILY(cpi) == 0xf)
101868c91426Sdmick 			cpi->cpi_model += CPI_MODEL_XTD(cpi) << 4;
101968c91426Sdmick 		break;
102068c91426Sdmick 	default:
10215ff02082Sdmick 		if (cpi->cpi_model == 0xf)
10227c478bd9Sstevel@tonic-gate 			cpi->cpi_model += CPI_MODEL_XTD(cpi) << 4;
102368c91426Sdmick 		break;
102468c91426Sdmick 	}
10257c478bd9Sstevel@tonic-gate 
10267c478bd9Sstevel@tonic-gate 	cpi->cpi_step = CPI_STEP(cpi);
10277c478bd9Sstevel@tonic-gate 	cpi->cpi_brandid = CPI_BRANDID(cpi);
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate 	/*
10307c478bd9Sstevel@tonic-gate 	 * *default* assumptions:
10317c478bd9Sstevel@tonic-gate 	 * - believe %edx feature word
10327c478bd9Sstevel@tonic-gate 	 * - ignore %ecx feature word
10337c478bd9Sstevel@tonic-gate 	 * - 32-bit virtual and physical addressing
10347c478bd9Sstevel@tonic-gate 	 */
10357c478bd9Sstevel@tonic-gate 	mask_edx = 0xffffffff;
10367c478bd9Sstevel@tonic-gate 	mask_ecx = 0;
10377c478bd9Sstevel@tonic-gate 
10387c478bd9Sstevel@tonic-gate 	cpi->cpi_pabits = cpi->cpi_vabits = 32;
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
10417c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
10427c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5)
10437c478bd9Sstevel@tonic-gate 			x86_type = X86_TYPE_P5;
10445ff02082Sdmick 		else if (IS_LEGACY_P6(cpi)) {
10457c478bd9Sstevel@tonic-gate 			x86_type = X86_TYPE_P6;
10467c478bd9Sstevel@tonic-gate 			pentiumpro_bug4046376 = 1;
10477c478bd9Sstevel@tonic-gate 			/*
10487c478bd9Sstevel@tonic-gate 			 * Clear the SEP bit when it was set erroneously
10497c478bd9Sstevel@tonic-gate 			 */
10507c478bd9Sstevel@tonic-gate 			if (cpi->cpi_model < 3 && cpi->cpi_step < 3)
10517c478bd9Sstevel@tonic-gate 				cp->cp_edx &= ~CPUID_INTC_EDX_SEP;
10525ff02082Sdmick 		} else if (IS_NEW_F6(cpi) || cpi->cpi_family == 0xf) {
10537c478bd9Sstevel@tonic-gate 			x86_type = X86_TYPE_P4;
10547c478bd9Sstevel@tonic-gate 			/*
10557c478bd9Sstevel@tonic-gate 			 * We don't currently depend on any of the %ecx
10567c478bd9Sstevel@tonic-gate 			 * features until Prescott, so we'll only check
10577c478bd9Sstevel@tonic-gate 			 * this from P4 onwards.  We might want to revisit
10587c478bd9Sstevel@tonic-gate 			 * that idea later.
10597c478bd9Sstevel@tonic-gate 			 */
10607c478bd9Sstevel@tonic-gate 			mask_ecx = 0xffffffff;
10617c478bd9Sstevel@tonic-gate 		} else if (cpi->cpi_family > 0xf)
10627c478bd9Sstevel@tonic-gate 			mask_ecx = 0xffffffff;
10637c622d23Sbholler 		/*
10647c622d23Sbholler 		 * We don't support MONITOR/MWAIT if leaf 5 is not available
10657c622d23Sbholler 		 * to obtain the monitor linesize.
10667c622d23Sbholler 		 */
10677c622d23Sbholler 		if (cpi->cpi_maxeax < 5)
10687c622d23Sbholler 			mask_ecx &= ~CPUID_INTC_ECX_MON;
10697c478bd9Sstevel@tonic-gate 		break;
10707c478bd9Sstevel@tonic-gate 	case X86_VENDOR_IntelClone:
10717c478bd9Sstevel@tonic-gate 	default:
10727c478bd9Sstevel@tonic-gate 		break;
10737c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
10747c478bd9Sstevel@tonic-gate #if defined(OPTERON_ERRATUM_108)
10757c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 0xf && cpi->cpi_model == 0xe) {
10767c478bd9Sstevel@tonic-gate 			cp->cp_eax = (0xf0f & cp->cp_eax) | 0xc0;
10777c478bd9Sstevel@tonic-gate 			cpi->cpi_model = 0xc;
10787c478bd9Sstevel@tonic-gate 		} else
10797c478bd9Sstevel@tonic-gate #endif
10807c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5) {
10817c478bd9Sstevel@tonic-gate 			/*
10827c478bd9Sstevel@tonic-gate 			 * AMD K5 and K6
10837c478bd9Sstevel@tonic-gate 			 *
10847c478bd9Sstevel@tonic-gate 			 * These CPUs have an incomplete implementation
10857c478bd9Sstevel@tonic-gate 			 * of MCA/MCE which we mask away.
10867c478bd9Sstevel@tonic-gate 			 */
10878949bcd6Sandrei 			mask_edx &= ~(CPUID_INTC_EDX_MCE | CPUID_INTC_EDX_MCA);
10888949bcd6Sandrei 
10897c478bd9Sstevel@tonic-gate 			/*
10907c478bd9Sstevel@tonic-gate 			 * Model 0 uses the wrong (APIC) bit
10917c478bd9Sstevel@tonic-gate 			 * to indicate PGE.  Fix it here.
10927c478bd9Sstevel@tonic-gate 			 */
10938949bcd6Sandrei 			if (cpi->cpi_model == 0) {
10947c478bd9Sstevel@tonic-gate 				if (cp->cp_edx & 0x200) {
10957c478bd9Sstevel@tonic-gate 					cp->cp_edx &= ~0x200;
10967c478bd9Sstevel@tonic-gate 					cp->cp_edx |= CPUID_INTC_EDX_PGE;
10977c478bd9Sstevel@tonic-gate 				}
10987c478bd9Sstevel@tonic-gate 			}
10998949bcd6Sandrei 
11008949bcd6Sandrei 			/*
11018949bcd6Sandrei 			 * Early models had problems w/ MMX; disable.
11028949bcd6Sandrei 			 */
11038949bcd6Sandrei 			if (cpi->cpi_model < 6)
11048949bcd6Sandrei 				mask_edx &= ~CPUID_INTC_EDX_MMX;
11058949bcd6Sandrei 		}
11068949bcd6Sandrei 
11078949bcd6Sandrei 		/*
11088949bcd6Sandrei 		 * For newer families, SSE3 and CX16, at least, are valid;
11098949bcd6Sandrei 		 * enable all
11108949bcd6Sandrei 		 */
11118949bcd6Sandrei 		if (cpi->cpi_family >= 0xf)
11128949bcd6Sandrei 			mask_ecx = 0xffffffff;
11137c622d23Sbholler 		/*
11147c622d23Sbholler 		 * We don't support MONITOR/MWAIT if leaf 5 is not available
11157c622d23Sbholler 		 * to obtain the monitor linesize.
11167c622d23Sbholler 		 */
11177c622d23Sbholler 		if (cpi->cpi_maxeax < 5)
11187c622d23Sbholler 			mask_ecx &= ~CPUID_INTC_ECX_MON;
11195b8a6efeSbholler 
1120843e1988Sjohnlev #if !defined(__xpv)
11215b8a6efeSbholler 		/*
11225b8a6efeSbholler 		 * Do not use MONITOR/MWAIT to halt in the idle loop on any AMD
11235b8a6efeSbholler 		 * processors.  AMD does not intend MWAIT to be used in the cpu
11245b8a6efeSbholler 		 * idle loop on current and future processors.  10h and future
11255b8a6efeSbholler 		 * AMD processors use more power in MWAIT than HLT.
11265b8a6efeSbholler 		 * Pre-family-10h Opterons do not have the MWAIT instruction.
11275b8a6efeSbholler 		 */
11285b8a6efeSbholler 		idle_cpu_prefer_mwait = 0;
1129843e1988Sjohnlev #endif
11305b8a6efeSbholler 
11317c478bd9Sstevel@tonic-gate 		break;
11327c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
11337c478bd9Sstevel@tonic-gate 		/*
11347c478bd9Sstevel@tonic-gate 		 * workaround the NT workaround in CMS 4.1
11357c478bd9Sstevel@tonic-gate 		 */
11367c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5 && cpi->cpi_model == 4 &&
11377c478bd9Sstevel@tonic-gate 		    (cpi->cpi_step == 2 || cpi->cpi_step == 3))
11387c478bd9Sstevel@tonic-gate 			cp->cp_edx |= CPUID_INTC_EDX_CX8;
11397c478bd9Sstevel@tonic-gate 		break;
11407c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Centaur:
11417c478bd9Sstevel@tonic-gate 		/*
11427c478bd9Sstevel@tonic-gate 		 * workaround the NT workarounds again
11437c478bd9Sstevel@tonic-gate 		 */
11447c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 6)
11457c478bd9Sstevel@tonic-gate 			cp->cp_edx |= CPUID_INTC_EDX_CX8;
11467c478bd9Sstevel@tonic-gate 		break;
11477c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
11487c478bd9Sstevel@tonic-gate 		/*
11497c478bd9Sstevel@tonic-gate 		 * We rely heavily on the probing in locore
11507c478bd9Sstevel@tonic-gate 		 * to actually figure out what parts, if any,
11517c478bd9Sstevel@tonic-gate 		 * of the Cyrix cpuid instruction to believe.
11527c478bd9Sstevel@tonic-gate 		 */
11537c478bd9Sstevel@tonic-gate 		switch (x86_type) {
11547c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_486:
11557c478bd9Sstevel@tonic-gate 			mask_edx = 0;
11567c478bd9Sstevel@tonic-gate 			break;
11577c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_6x86:
11587c478bd9Sstevel@tonic-gate 			mask_edx = 0;
11597c478bd9Sstevel@tonic-gate 			break;
11607c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_6x86L:
11617c478bd9Sstevel@tonic-gate 			mask_edx =
11627c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_DE |
11637c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CX8;
11647c478bd9Sstevel@tonic-gate 			break;
11657c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_6x86MX:
11667c478bd9Sstevel@tonic-gate 			mask_edx =
11677c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_DE |
11687c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MSR |
11697c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CX8 |
11707c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_PGE |
11717c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CMOV |
11727c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MMX;
11737c478bd9Sstevel@tonic-gate 			break;
11747c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_GXm:
11757c478bd9Sstevel@tonic-gate 			mask_edx =
11767c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MSR |
11777c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CX8 |
11787c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CMOV |
11797c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MMX;
11807c478bd9Sstevel@tonic-gate 			break;
11817c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_MediaGX:
11827c478bd9Sstevel@tonic-gate 			break;
11837c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_MII:
11847c478bd9Sstevel@tonic-gate 		case X86_TYPE_VIA_CYRIX_III:
11857c478bd9Sstevel@tonic-gate 			mask_edx =
11867c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_DE |
11877c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_TSC |
11887c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MSR |
11897c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CX8 |
11907c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_PGE |
11917c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CMOV |
11927c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MMX;
11937c478bd9Sstevel@tonic-gate 			break;
11947c478bd9Sstevel@tonic-gate 		default:
11957c478bd9Sstevel@tonic-gate 			break;
11967c478bd9Sstevel@tonic-gate 		}
11977c478bd9Sstevel@tonic-gate 		break;
11987c478bd9Sstevel@tonic-gate 	}
11997c478bd9Sstevel@tonic-gate 
1200843e1988Sjohnlev #if defined(__xpv)
1201843e1988Sjohnlev 	/*
1202843e1988Sjohnlev 	 * Do not support MONITOR/MWAIT under a hypervisor
1203843e1988Sjohnlev 	 */
1204843e1988Sjohnlev 	mask_ecx &= ~CPUID_INTC_ECX_MON;
12057af88ac7SKuriakose Kuruvilla 	/*
12067af88ac7SKuriakose Kuruvilla 	 * Do not support XSAVE under a hypervisor for now
12077af88ac7SKuriakose Kuruvilla 	 */
12087af88ac7SKuriakose Kuruvilla 	xsave_force_disable = B_TRUE;
12097af88ac7SKuriakose Kuruvilla 
1210843e1988Sjohnlev #endif	/* __xpv */
1211843e1988Sjohnlev 
12127af88ac7SKuriakose Kuruvilla 	if (xsave_force_disable) {
12137af88ac7SKuriakose Kuruvilla 		mask_ecx &= ~CPUID_INTC_ECX_XSAVE;
12147af88ac7SKuriakose Kuruvilla 		mask_ecx &= ~CPUID_INTC_ECX_AVX;
1215ebb8ac07SRobert Mustacchi 		mask_ecx &= ~CPUID_INTC_ECX_F16C;
1216245ac945SRobert Mustacchi 		mask_ecx &= ~CPUID_INTC_ECX_FMA;
12177af88ac7SKuriakose Kuruvilla 	}
12187af88ac7SKuriakose Kuruvilla 
12197c478bd9Sstevel@tonic-gate 	/*
12207c478bd9Sstevel@tonic-gate 	 * Now we've figured out the masks that determine
12217c478bd9Sstevel@tonic-gate 	 * which bits we choose to believe, apply the masks
12227c478bd9Sstevel@tonic-gate 	 * to the feature words, then map the kernel's view
12237c478bd9Sstevel@tonic-gate 	 * of these feature words into its feature word.
12247c478bd9Sstevel@tonic-gate 	 */
12257c478bd9Sstevel@tonic-gate 	cp->cp_edx &= mask_edx;
12267c478bd9Sstevel@tonic-gate 	cp->cp_ecx &= mask_ecx;
12277c478bd9Sstevel@tonic-gate 
12287c478bd9Sstevel@tonic-gate 	/*
1229ae115bc7Smrj 	 * apply any platform restrictions (we don't call this
1230ae115bc7Smrj 	 * immediately after __cpuid_insn here, because we need the
1231ae115bc7Smrj 	 * workarounds applied above first)
12327c478bd9Sstevel@tonic-gate 	 */
1233ae115bc7Smrj 	platform_cpuid_mangle(cpi->cpi_vendor, 1, cp);
12347c478bd9Sstevel@tonic-gate 
1235ae115bc7Smrj 	/*
1236245ac945SRobert Mustacchi 	 * In addition to ecx and edx, Intel is storing a bunch of instruction
1237245ac945SRobert Mustacchi 	 * set extensions in leaf 7's ebx.
1238245ac945SRobert Mustacchi 	 */
1239245ac945SRobert Mustacchi 	if (cpi->cpi_vendor == X86_VENDOR_Intel && cpi->cpi_maxeax >= 7) {
1240245ac945SRobert Mustacchi 		struct cpuid_regs *ecp;
1241245ac945SRobert Mustacchi 		ecp = &cpi->cpi_std[7];
1242245ac945SRobert Mustacchi 		ecp->cp_eax = 7;
1243245ac945SRobert Mustacchi 		ecp->cp_ecx = 0;
1244245ac945SRobert Mustacchi 		(void) __cpuid_insn(ecp);
1245245ac945SRobert Mustacchi 		/*
1246245ac945SRobert Mustacchi 		 * If XSAVE has been disabled, just ignore all of the AVX
1247245ac945SRobert Mustacchi 		 * dependent flags here.
1248245ac945SRobert Mustacchi 		 */
1249245ac945SRobert Mustacchi 		if (xsave_force_disable) {
1250245ac945SRobert Mustacchi 			ecp->cp_ebx &= ~CPUID_INTC_EBX_7_0_BMI1;
1251245ac945SRobert Mustacchi 			ecp->cp_ebx &= ~CPUID_INTC_EBX_7_0_BMI2;
1252245ac945SRobert Mustacchi 			ecp->cp_ebx &= ~CPUID_INTC_EBX_7_0_AVX2;
1253245ac945SRobert Mustacchi 		}
1254799823bbSRobert Mustacchi 
1255799823bbSRobert Mustacchi 		if (ecp->cp_ebx & CPUID_INTC_EBX_7_0_SMEP)
1256799823bbSRobert Mustacchi 			add_x86_feature(featureset, X86FSET_SMEP);
1257a3623a38SRobert Mustacchi 
1258a3623a38SRobert Mustacchi 		if (ecp->cp_ebx & CPUID_INTC_EBX_7_0_RDSEED)
1259a3623a38SRobert Mustacchi 			add_x86_feature(featureset, X86FSET_RDSEED);
1260a3623a38SRobert Mustacchi 
1261a3623a38SRobert Mustacchi 		if (ecp->cp_ebx & CPUID_INTC_EBX_7_0_ADX)
1262a3623a38SRobert Mustacchi 			add_x86_feature(featureset, X86FSET_ADX);
1263245ac945SRobert Mustacchi 	}
1264245ac945SRobert Mustacchi 
1265245ac945SRobert Mustacchi 	/*
1266ae115bc7Smrj 	 * fold in overrides from the "eeprom" mechanism
1267ae115bc7Smrj 	 */
12687c478bd9Sstevel@tonic-gate 	cp->cp_edx |= cpuid_feature_edx_include;
12697c478bd9Sstevel@tonic-gate 	cp->cp_edx &= ~cpuid_feature_edx_exclude;
12707c478bd9Sstevel@tonic-gate 
12717c478bd9Sstevel@tonic-gate 	cp->cp_ecx |= cpuid_feature_ecx_include;
12727c478bd9Sstevel@tonic-gate 	cp->cp_ecx &= ~cpuid_feature_ecx_exclude;
12737c478bd9Sstevel@tonic-gate 
12747417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_PSE) {
12757417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_LARGEPAGE);
12767417cfdeSKuriakose Kuruvilla 	}
12777417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_TSC) {
12787417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_TSC);
12797417cfdeSKuriakose Kuruvilla 	}
12807417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_MSR) {
12817417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_MSR);
12827417cfdeSKuriakose Kuruvilla 	}
12837417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_MTRR) {
12847417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_MTRR);
12857417cfdeSKuriakose Kuruvilla 	}
12867417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_PGE) {
12877417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_PGE);
12887417cfdeSKuriakose Kuruvilla 	}
12897417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_CMOV) {
12907417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_CMOV);
12917417cfdeSKuriakose Kuruvilla 	}
12927417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_MMX) {
12937417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_MMX);
12947417cfdeSKuriakose Kuruvilla 	}
12957c478bd9Sstevel@tonic-gate 	if ((cp->cp_edx & CPUID_INTC_EDX_MCE) != 0 &&
12967417cfdeSKuriakose Kuruvilla 	    (cp->cp_edx & CPUID_INTC_EDX_MCA) != 0) {
12977417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_MCA);
12987417cfdeSKuriakose Kuruvilla 	}
12997417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_PAE) {
13007417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_PAE);
13017417cfdeSKuriakose Kuruvilla 	}
13027417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_CX8) {
13037417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_CX8);
13047417cfdeSKuriakose Kuruvilla 	}
13057417cfdeSKuriakose Kuruvilla 	if (cp->cp_ecx & CPUID_INTC_ECX_CX16) {
13067417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_CX16);
13077417cfdeSKuriakose Kuruvilla 	}
13087417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_PAT) {
13097417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_PAT);
13107417cfdeSKuriakose Kuruvilla 	}
13117417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_SEP) {
13127417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_SEP);
13137417cfdeSKuriakose Kuruvilla 	}
13147c478bd9Sstevel@tonic-gate 	if (cp->cp_edx & CPUID_INTC_EDX_FXSR) {
13157c478bd9Sstevel@tonic-gate 		/*
13167c478bd9Sstevel@tonic-gate 		 * In our implementation, fxsave/fxrstor
13177c478bd9Sstevel@tonic-gate 		 * are prerequisites before we'll even
13187c478bd9Sstevel@tonic-gate 		 * try and do SSE things.
13197c478bd9Sstevel@tonic-gate 		 */
13207417cfdeSKuriakose Kuruvilla 		if (cp->cp_edx & CPUID_INTC_EDX_SSE) {
13217417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_SSE);
13227417cfdeSKuriakose Kuruvilla 		}
13237417cfdeSKuriakose Kuruvilla 		if (cp->cp_edx & CPUID_INTC_EDX_SSE2) {
13247417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_SSE2);
13257417cfdeSKuriakose Kuruvilla 		}
13267417cfdeSKuriakose Kuruvilla 		if (cp->cp_ecx & CPUID_INTC_ECX_SSE3) {
13277417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_SSE3);
13287417cfdeSKuriakose Kuruvilla 		}
13297417cfdeSKuriakose Kuruvilla 		if (cp->cp_ecx & CPUID_INTC_ECX_SSSE3) {
13307417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_SSSE3);
13317417cfdeSKuriakose Kuruvilla 		}
13327417cfdeSKuriakose Kuruvilla 		if (cp->cp_ecx & CPUID_INTC_ECX_SSE4_1) {
13337417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_SSE4_1);
13347417cfdeSKuriakose Kuruvilla 		}
13357417cfdeSKuriakose Kuruvilla 		if (cp->cp_ecx & CPUID_INTC_ECX_SSE4_2) {
13367417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_SSE4_2);
13377417cfdeSKuriakose Kuruvilla 		}
13387417cfdeSKuriakose Kuruvilla 		if (cp->cp_ecx & CPUID_INTC_ECX_AES) {
13397417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_AES);
13407417cfdeSKuriakose Kuruvilla 		}
13417417cfdeSKuriakose Kuruvilla 		if (cp->cp_ecx & CPUID_INTC_ECX_PCLMULQDQ) {
13427417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_PCLMULQDQ);
1343d0f8ff6eSkk208521 		}
13447af88ac7SKuriakose Kuruvilla 
13457af88ac7SKuriakose Kuruvilla 		if (cp->cp_ecx & CPUID_INTC_ECX_XSAVE) {
13467af88ac7SKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_XSAVE);
1347ebb8ac07SRobert Mustacchi 
13487af88ac7SKuriakose Kuruvilla 			/* We only test AVX when there is XSAVE */
13497af88ac7SKuriakose Kuruvilla 			if (cp->cp_ecx & CPUID_INTC_ECX_AVX) {
13507af88ac7SKuriakose Kuruvilla 				add_x86_feature(featureset,
13517af88ac7SKuriakose Kuruvilla 				    X86FSET_AVX);
1352ebb8ac07SRobert Mustacchi 
1353245ac945SRobert Mustacchi 				/*
1354245ac945SRobert Mustacchi 				 * Intel says we can't check these without also
1355245ac945SRobert Mustacchi 				 * checking AVX.
1356245ac945SRobert Mustacchi 				 */
1357ebb8ac07SRobert Mustacchi 				if (cp->cp_ecx & CPUID_INTC_ECX_F16C)
1358ebb8ac07SRobert Mustacchi 					add_x86_feature(featureset,
1359ebb8ac07SRobert Mustacchi 					    X86FSET_F16C);
1360245ac945SRobert Mustacchi 
1361245ac945SRobert Mustacchi 				if (cp->cp_ecx & CPUID_INTC_ECX_FMA)
1362245ac945SRobert Mustacchi 					add_x86_feature(featureset,
1363245ac945SRobert Mustacchi 					    X86FSET_FMA);
1364245ac945SRobert Mustacchi 
1365245ac945SRobert Mustacchi 				if (cpi->cpi_std[7].cp_ebx &
1366245ac945SRobert Mustacchi 				    CPUID_INTC_EBX_7_0_BMI1)
1367245ac945SRobert Mustacchi 					add_x86_feature(featureset,
1368245ac945SRobert Mustacchi 					    X86FSET_BMI1);
1369245ac945SRobert Mustacchi 
1370245ac945SRobert Mustacchi 				if (cpi->cpi_std[7].cp_ebx &
1371245ac945SRobert Mustacchi 				    CPUID_INTC_EBX_7_0_BMI2)
1372245ac945SRobert Mustacchi 					add_x86_feature(featureset,
1373245ac945SRobert Mustacchi 					    X86FSET_BMI2);
1374245ac945SRobert Mustacchi 
1375245ac945SRobert Mustacchi 				if (cpi->cpi_std[7].cp_ebx &
1376245ac945SRobert Mustacchi 				    CPUID_INTC_EBX_7_0_AVX2)
1377245ac945SRobert Mustacchi 					add_x86_feature(featureset,
1378245ac945SRobert Mustacchi 					    X86FSET_AVX2);
13797af88ac7SKuriakose Kuruvilla 			}
13807af88ac7SKuriakose Kuruvilla 		}
13817c478bd9Sstevel@tonic-gate 	}
13826eedf6a5SJosef 'Jeff' Sipek 	if (cp->cp_ecx & CPUID_INTC_ECX_X2APIC) {
13836eedf6a5SJosef 'Jeff' Sipek 		add_x86_feature(featureset, X86FSET_X2APIC);
13846eedf6a5SJosef 'Jeff' Sipek 	}
13857417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_DE) {
13867417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_DE);
13877417cfdeSKuriakose Kuruvilla 	}
13881d1a3942SBill Holler #if !defined(__xpv)
1389f98fbcecSbholler 	if (cp->cp_ecx & CPUID_INTC_ECX_MON) {
13901d1a3942SBill Holler 
13911d1a3942SBill Holler 		/*
13921d1a3942SBill Holler 		 * We require the CLFLUSH instruction for erratum workaround
13931d1a3942SBill Holler 		 * to use MONITOR/MWAIT.
13941d1a3942SBill Holler 		 */
13951d1a3942SBill Holler 		if (cp->cp_edx & CPUID_INTC_EDX_CLFSH) {
1396f98fbcecSbholler 			cpi->cpi_mwait.support |= MWAIT_SUPPORT;
13977417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_MWAIT);
13981d1a3942SBill Holler 		} else {
13991d1a3942SBill Holler 			extern int idle_cpu_assert_cflush_monitor;
14001d1a3942SBill Holler 
14011d1a3942SBill Holler 			/*
14021d1a3942SBill Holler 			 * All processors we are aware of which have
14031d1a3942SBill Holler 			 * MONITOR/MWAIT also have CLFLUSH.
14041d1a3942SBill Holler 			 */
14051d1a3942SBill Holler 			if (idle_cpu_assert_cflush_monitor) {
14061d1a3942SBill Holler 				ASSERT((cp->cp_ecx & CPUID_INTC_ECX_MON) &&
14071d1a3942SBill Holler 				    (cp->cp_edx & CPUID_INTC_EDX_CLFSH));
1408f98fbcecSbholler 			}
14091d1a3942SBill Holler 		}
14101d1a3942SBill Holler 	}
14111d1a3942SBill Holler #endif	/* __xpv */
14127c478bd9Sstevel@tonic-gate 
1413faa20166SBryan Cantrill 	if (cp->cp_ecx & CPUID_INTC_ECX_VMX) {
1414faa20166SBryan Cantrill 		add_x86_feature(featureset, X86FSET_VMX);
1415faa20166SBryan Cantrill 	}
1416faa20166SBryan Cantrill 
1417ebb8ac07SRobert Mustacchi 	if (cp->cp_ecx & CPUID_INTC_ECX_RDRAND)
1418ebb8ac07SRobert Mustacchi 		add_x86_feature(featureset, X86FSET_RDRAND);
1419ebb8ac07SRobert Mustacchi 
142086c1f4dcSVikram Hegde 	/*
1421faa20166SBryan Cantrill 	 * Only need it first time, rest of the cpus would follow suit.
142286c1f4dcSVikram Hegde 	 * we only capture this for the bootcpu.
142386c1f4dcSVikram Hegde 	 */
142486c1f4dcSVikram Hegde 	if (cp->cp_edx & CPUID_INTC_EDX_CLFSH) {
14257417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_CLFSH);
142686c1f4dcSVikram Hegde 		x86_clflush_size = (BITX(cp->cp_ebx, 15, 8) * 8);
142786c1f4dcSVikram Hegde 	}
14287417cfdeSKuriakose Kuruvilla 	if (is_x86_feature(featureset, X86FSET_PAE))
14297c478bd9Sstevel@tonic-gate 		cpi->cpi_pabits = 36;
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate 	/*
14327c478bd9Sstevel@tonic-gate 	 * Hyperthreading configuration is slightly tricky on Intel
14337c478bd9Sstevel@tonic-gate 	 * and pure clones, and even trickier on AMD.
14347c478bd9Sstevel@tonic-gate 	 *
14357c478bd9Sstevel@tonic-gate 	 * (AMD chose to set the HTT bit on their CMP processors,
14367c478bd9Sstevel@tonic-gate 	 * even though they're not actually hyperthreaded.  Thus it
14377c478bd9Sstevel@tonic-gate 	 * takes a bit more work to figure out what's really going
1438ae115bc7Smrj 	 * on ... see the handling of the CMP_LGCY bit below)
14397c478bd9Sstevel@tonic-gate 	 */
14407c478bd9Sstevel@tonic-gate 	if (cp->cp_edx & CPUID_INTC_EDX_HTT) {
14417c478bd9Sstevel@tonic-gate 		cpi->cpi_ncpu_per_chip = CPI_CPU_COUNT(cpi);
14427c478bd9Sstevel@tonic-gate 		if (cpi->cpi_ncpu_per_chip > 1)
14437417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_HTT);
14448949bcd6Sandrei 	} else {
14458949bcd6Sandrei 		cpi->cpi_ncpu_per_chip = 1;
14467c478bd9Sstevel@tonic-gate 	}
14477c478bd9Sstevel@tonic-gate 
14487c478bd9Sstevel@tonic-gate 	/*
14497c478bd9Sstevel@tonic-gate 	 * Work on the "extended" feature information, doing
14507c478bd9Sstevel@tonic-gate 	 * some basic initialization for cpuid_pass2()
14517c478bd9Sstevel@tonic-gate 	 */
14527c478bd9Sstevel@tonic-gate 	xcpuid = 0;
14537c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
14547c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
14555ff02082Sdmick 		if (IS_NEW_F6(cpi) || cpi->cpi_family >= 0xf)
14567c478bd9Sstevel@tonic-gate 			xcpuid++;
14577c478bd9Sstevel@tonic-gate 		break;
14587c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
14597c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family > 5 ||
14607c478bd9Sstevel@tonic-gate 		    (cpi->cpi_family == 5 && cpi->cpi_model >= 1))
14617c478bd9Sstevel@tonic-gate 			xcpuid++;
14627c478bd9Sstevel@tonic-gate 		break;
14637c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
14647c478bd9Sstevel@tonic-gate 		/*
14657c478bd9Sstevel@tonic-gate 		 * Only these Cyrix CPUs are -known- to support
14667c478bd9Sstevel@tonic-gate 		 * extended cpuid operations.
14677c478bd9Sstevel@tonic-gate 		 */
14687c478bd9Sstevel@tonic-gate 		if (x86_type == X86_TYPE_VIA_CYRIX_III ||
14697c478bd9Sstevel@tonic-gate 		    x86_type == X86_TYPE_CYRIX_GXm)
14707c478bd9Sstevel@tonic-gate 			xcpuid++;
14717c478bd9Sstevel@tonic-gate 		break;
14727c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Centaur:
14737c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
14747c478bd9Sstevel@tonic-gate 	default:
14757c478bd9Sstevel@tonic-gate 		xcpuid++;
14767c478bd9Sstevel@tonic-gate 		break;
14777c478bd9Sstevel@tonic-gate 	}
14787c478bd9Sstevel@tonic-gate 
14797c478bd9Sstevel@tonic-gate 	if (xcpuid) {
14807c478bd9Sstevel@tonic-gate 		cp = &cpi->cpi_extd[0];
14818949bcd6Sandrei 		cp->cp_eax = 0x80000000;
14828949bcd6Sandrei 		cpi->cpi_xmaxeax = __cpuid_insn(cp);
14837c478bd9Sstevel@tonic-gate 	}
14847c478bd9Sstevel@tonic-gate 
14857c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax & 0x80000000) {
14867c478bd9Sstevel@tonic-gate 
14877c478bd9Sstevel@tonic-gate 		if (cpi->cpi_xmaxeax > CPI_XMAXEAX_MAX)
14887c478bd9Sstevel@tonic-gate 			cpi->cpi_xmaxeax = CPI_XMAXEAX_MAX;
14897c478bd9Sstevel@tonic-gate 
14907c478bd9Sstevel@tonic-gate 		switch (cpi->cpi_vendor) {
14917c478bd9Sstevel@tonic-gate 		case X86_VENDOR_Intel:
14927c478bd9Sstevel@tonic-gate 		case X86_VENDOR_AMD:
14937c478bd9Sstevel@tonic-gate 			if (cpi->cpi_xmaxeax < 0x80000001)
14947c478bd9Sstevel@tonic-gate 				break;
14957c478bd9Sstevel@tonic-gate 			cp = &cpi->cpi_extd[1];
14968949bcd6Sandrei 			cp->cp_eax = 0x80000001;
14978949bcd6Sandrei 			(void) __cpuid_insn(cp);
1498ae115bc7Smrj 
14997c478bd9Sstevel@tonic-gate 			if (cpi->cpi_vendor == X86_VENDOR_AMD &&
15007c478bd9Sstevel@tonic-gate 			    cpi->cpi_family == 5 &&
15017c478bd9Sstevel@tonic-gate 			    cpi->cpi_model == 6 &&
15027c478bd9Sstevel@tonic-gate 			    cpi->cpi_step == 6) {
15037c478bd9Sstevel@tonic-gate 				/*
15047c478bd9Sstevel@tonic-gate 				 * K6 model 6 uses bit 10 to indicate SYSC
15057c478bd9Sstevel@tonic-gate 				 * Later models use bit 11. Fix it here.
15067c478bd9Sstevel@tonic-gate 				 */
15077c478bd9Sstevel@tonic-gate 				if (cp->cp_edx & 0x400) {
15087c478bd9Sstevel@tonic-gate 					cp->cp_edx &= ~0x400;
15097c478bd9Sstevel@tonic-gate 					cp->cp_edx |= CPUID_AMD_EDX_SYSC;
15107c478bd9Sstevel@tonic-gate 				}
15117c478bd9Sstevel@tonic-gate 			}
15127c478bd9Sstevel@tonic-gate 
1513ae115bc7Smrj 			platform_cpuid_mangle(cpi->cpi_vendor, 0x80000001, cp);
1514ae115bc7Smrj 
15157c478bd9Sstevel@tonic-gate 			/*
15167c478bd9Sstevel@tonic-gate 			 * Compute the additions to the kernel's feature word.
15177c478bd9Sstevel@tonic-gate 			 */
15187417cfdeSKuriakose Kuruvilla 			if (cp->cp_edx & CPUID_AMD_EDX_NX) {
15197417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_NX);
15207417cfdeSKuriakose Kuruvilla 			}
15217c478bd9Sstevel@tonic-gate 
152219397407SSherry Moore 			/*
152319397407SSherry Moore 			 * Regardless whether or not we boot 64-bit,
152419397407SSherry Moore 			 * we should have a way to identify whether
152519397407SSherry Moore 			 * the CPU is capable of running 64-bit.
152619397407SSherry Moore 			 */
15277417cfdeSKuriakose Kuruvilla 			if (cp->cp_edx & CPUID_AMD_EDX_LM) {
15287417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_64);
15297417cfdeSKuriakose Kuruvilla 			}
153019397407SSherry Moore 
153102bc52beSkchow #if defined(__amd64)
153202bc52beSkchow 			/* 1 GB large page - enable only for 64 bit kernel */
15337417cfdeSKuriakose Kuruvilla 			if (cp->cp_edx & CPUID_AMD_EDX_1GPG) {
15347417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_1GPG);
15357417cfdeSKuriakose Kuruvilla 			}
153602bc52beSkchow #endif
153702bc52beSkchow 
1538f8801251Skk208521 			if ((cpi->cpi_vendor == X86_VENDOR_AMD) &&
1539f8801251Skk208521 			    (cpi->cpi_std[1].cp_edx & CPUID_INTC_EDX_FXSR) &&
15407417cfdeSKuriakose Kuruvilla 			    (cp->cp_ecx & CPUID_AMD_ECX_SSE4A)) {
15417417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_SSE4A);
15427417cfdeSKuriakose Kuruvilla 			}
1543f8801251Skk208521 
15447c478bd9Sstevel@tonic-gate 			/*
1545ae115bc7Smrj 			 * If both the HTT and CMP_LGCY bits are set,
15468949bcd6Sandrei 			 * then we're not actually HyperThreaded.  Read
15478949bcd6Sandrei 			 * "AMD CPUID Specification" for more details.
15487c478bd9Sstevel@tonic-gate 			 */
15497c478bd9Sstevel@tonic-gate 			if (cpi->cpi_vendor == X86_VENDOR_AMD &&
15507417cfdeSKuriakose Kuruvilla 			    is_x86_feature(featureset, X86FSET_HTT) &&
1551ae115bc7Smrj 			    (cp->cp_ecx & CPUID_AMD_ECX_CMP_LGCY)) {
15527417cfdeSKuriakose Kuruvilla 				remove_x86_feature(featureset, X86FSET_HTT);
15537417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_CMP);
15548949bcd6Sandrei 			}
1555ae115bc7Smrj #if defined(__amd64)
15567c478bd9Sstevel@tonic-gate 			/*
15577c478bd9Sstevel@tonic-gate 			 * It's really tricky to support syscall/sysret in
15587c478bd9Sstevel@tonic-gate 			 * the i386 kernel; we rely on sysenter/sysexit
15597c478bd9Sstevel@tonic-gate 			 * instead.  In the amd64 kernel, things are -way-
15607c478bd9Sstevel@tonic-gate 			 * better.
15617c478bd9Sstevel@tonic-gate 			 */
15627417cfdeSKuriakose Kuruvilla 			if (cp->cp_edx & CPUID_AMD_EDX_SYSC) {
15637417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_ASYSC);
15647417cfdeSKuriakose Kuruvilla 			}
15657c478bd9Sstevel@tonic-gate 
15667c478bd9Sstevel@tonic-gate 			/*
15677c478bd9Sstevel@tonic-gate 			 * While we're thinking about system calls, note
15687c478bd9Sstevel@tonic-gate 			 * that AMD processors don't support sysenter
15697c478bd9Sstevel@tonic-gate 			 * in long mode at all, so don't try to program them.
15707c478bd9Sstevel@tonic-gate 			 */
15717417cfdeSKuriakose Kuruvilla 			if (x86_vendor == X86_VENDOR_AMD) {
15727417cfdeSKuriakose Kuruvilla 				remove_x86_feature(featureset, X86FSET_SEP);
15737417cfdeSKuriakose Kuruvilla 			}
15747c478bd9Sstevel@tonic-gate #endif
15757417cfdeSKuriakose Kuruvilla 			if (cp->cp_edx & CPUID_AMD_EDX_TSCP) {
15767417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_TSCP);
15777417cfdeSKuriakose Kuruvilla 			}
1578faa20166SBryan Cantrill 
1579faa20166SBryan Cantrill 			if (cp->cp_ecx & CPUID_AMD_ECX_SVM) {
1580faa20166SBryan Cantrill 				add_x86_feature(featureset, X86FSET_SVM);
1581faa20166SBryan Cantrill 			}
15827660e73fSHans Rosenfeld 
15837660e73fSHans Rosenfeld 			if (cp->cp_ecx & CPUID_AMD_ECX_TOPOEXT) {
15847660e73fSHans Rosenfeld 				add_x86_feature(featureset, X86FSET_TOPOEXT);
15857660e73fSHans Rosenfeld 			}
1586*3db3a4acSRobert Mustacchi 
1587*3db3a4acSRobert Mustacchi 			if (cp->cp_ecx & CPUID_AMD_ECX_PCEC) {
1588*3db3a4acSRobert Mustacchi 				add_x86_feature(featureset, X86FSET_AMD_PCEC);
1589*3db3a4acSRobert Mustacchi 			}
15907c478bd9Sstevel@tonic-gate 			break;
15917c478bd9Sstevel@tonic-gate 		default:
15927c478bd9Sstevel@tonic-gate 			break;
15937c478bd9Sstevel@tonic-gate 		}
15947c478bd9Sstevel@tonic-gate 
15958949bcd6Sandrei 		/*
15968949bcd6Sandrei 		 * Get CPUID data about processor cores and hyperthreads.
15978949bcd6Sandrei 		 */
15987c478bd9Sstevel@tonic-gate 		switch (cpi->cpi_vendor) {
15997c478bd9Sstevel@tonic-gate 		case X86_VENDOR_Intel:
16008949bcd6Sandrei 			if (cpi->cpi_maxeax >= 4) {
16018949bcd6Sandrei 				cp = &cpi->cpi_std[4];
16028949bcd6Sandrei 				cp->cp_eax = 4;
16038949bcd6Sandrei 				cp->cp_ecx = 0;
16048949bcd6Sandrei 				(void) __cpuid_insn(cp);
1605ae115bc7Smrj 				platform_cpuid_mangle(cpi->cpi_vendor, 4, cp);
16068949bcd6Sandrei 			}
16078949bcd6Sandrei 			/*FALLTHROUGH*/
16087c478bd9Sstevel@tonic-gate 		case X86_VENDOR_AMD:
16097c478bd9Sstevel@tonic-gate 			if (cpi->cpi_xmaxeax < 0x80000008)
16107c478bd9Sstevel@tonic-gate 				break;
16117c478bd9Sstevel@tonic-gate 			cp = &cpi->cpi_extd[8];
16128949bcd6Sandrei 			cp->cp_eax = 0x80000008;
16138949bcd6Sandrei 			(void) __cpuid_insn(cp);
1614ae115bc7Smrj 			platform_cpuid_mangle(cpi->cpi_vendor, 0x80000008, cp);
1615ae115bc7Smrj 
16167c478bd9Sstevel@tonic-gate 			/*
16177c478bd9Sstevel@tonic-gate 			 * Virtual and physical address limits from
16187c478bd9Sstevel@tonic-gate 			 * cpuid override previously guessed values.
16197c478bd9Sstevel@tonic-gate 			 */
16207c478bd9Sstevel@tonic-gate 			cpi->cpi_pabits = BITX(cp->cp_eax, 7, 0);
16217c478bd9Sstevel@tonic-gate 			cpi->cpi_vabits = BITX(cp->cp_eax, 15, 8);
16227c478bd9Sstevel@tonic-gate 			break;
16237c478bd9Sstevel@tonic-gate 		default:
16247c478bd9Sstevel@tonic-gate 			break;
16257c478bd9Sstevel@tonic-gate 		}
16268949bcd6Sandrei 
1627d129bde2Sesaxe 		/*
1628d129bde2Sesaxe 		 * Derive the number of cores per chip
1629d129bde2Sesaxe 		 */
16308949bcd6Sandrei 		switch (cpi->cpi_vendor) {
16318949bcd6Sandrei 		case X86_VENDOR_Intel:
16328949bcd6Sandrei 			if (cpi->cpi_maxeax < 4) {
16338949bcd6Sandrei 				cpi->cpi_ncore_per_chip = 1;
16348949bcd6Sandrei 				break;
16358949bcd6Sandrei 			} else {
16368949bcd6Sandrei 				cpi->cpi_ncore_per_chip =
16378949bcd6Sandrei 				    BITX((cpi)->cpi_std[4].cp_eax, 31, 26) + 1;
16388949bcd6Sandrei 			}
16398949bcd6Sandrei 			break;
16408949bcd6Sandrei 		case X86_VENDOR_AMD:
16418949bcd6Sandrei 			if (cpi->cpi_xmaxeax < 0x80000008) {
16428949bcd6Sandrei 				cpi->cpi_ncore_per_chip = 1;
16438949bcd6Sandrei 				break;
16448949bcd6Sandrei 			} else {
164510569901Sgavinm 				/*
164610569901Sgavinm 				 * On family 0xf cpuid fn 2 ECX[7:0] "NC" is
164710569901Sgavinm 				 * 1 less than the number of physical cores on
164810569901Sgavinm 				 * the chip.  In family 0x10 this value can
164910569901Sgavinm 				 * be affected by "downcoring" - it reflects
165010569901Sgavinm 				 * 1 less than the number of cores actually
165110569901Sgavinm 				 * enabled on this node.
165210569901Sgavinm 				 */
16538949bcd6Sandrei 				cpi->cpi_ncore_per_chip =
16548949bcd6Sandrei 				    BITX((cpi)->cpi_extd[8].cp_ecx, 7, 0) + 1;
16558949bcd6Sandrei 			}
16568949bcd6Sandrei 			break;
16578949bcd6Sandrei 		default:
16588949bcd6Sandrei 			cpi->cpi_ncore_per_chip = 1;
16598949bcd6Sandrei 			break;
16607c478bd9Sstevel@tonic-gate 		}
16610e751525SEric Saxe 
16620e751525SEric Saxe 		/*
16630e751525SEric Saxe 		 * Get CPUID data about TSC Invariance in Deep C-State.
16640e751525SEric Saxe 		 */
16650e751525SEric Saxe 		switch (cpi->cpi_vendor) {
16660e751525SEric Saxe 		case X86_VENDOR_Intel:
16670e751525SEric Saxe 			if (cpi->cpi_maxeax >= 7) {
16680e751525SEric Saxe 				cp = &cpi->cpi_extd[7];
16690e751525SEric Saxe 				cp->cp_eax = 0x80000007;
16700e751525SEric Saxe 				cp->cp_ecx = 0;
16710e751525SEric Saxe 				(void) __cpuid_insn(cp);
16720e751525SEric Saxe 			}
16730e751525SEric Saxe 			break;
16740e751525SEric Saxe 		default:
16750e751525SEric Saxe 			break;
16760e751525SEric Saxe 		}
1677fa2e767eSgavinm 	} else {
1678fa2e767eSgavinm 		cpi->cpi_ncore_per_chip = 1;
16798949bcd6Sandrei 	}
16808949bcd6Sandrei 
16818949bcd6Sandrei 	/*
16828949bcd6Sandrei 	 * If more than one core, then this processor is CMP.
16838949bcd6Sandrei 	 */
16847417cfdeSKuriakose Kuruvilla 	if (cpi->cpi_ncore_per_chip > 1) {
16857417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_CMP);
16867417cfdeSKuriakose Kuruvilla 	}
1687ae115bc7Smrj 
16888949bcd6Sandrei 	/*
16898949bcd6Sandrei 	 * If the number of cores is the same as the number
16908949bcd6Sandrei 	 * of CPUs, then we cannot have HyperThreading.
16918949bcd6Sandrei 	 */
16927417cfdeSKuriakose Kuruvilla 	if (cpi->cpi_ncpu_per_chip == cpi->cpi_ncore_per_chip) {
16937417cfdeSKuriakose Kuruvilla 		remove_x86_feature(featureset, X86FSET_HTT);
16947417cfdeSKuriakose Kuruvilla 	}
16958949bcd6Sandrei 
16968031591dSSrihari Venkatesan 	cpi->cpi_apicid = CPI_APIC_ID(cpi);
16978031591dSSrihari Venkatesan 	cpi->cpi_procnodes_per_pkg = 1;
16987660e73fSHans Rosenfeld 	cpi->cpi_cores_per_compunit = 1;
16997417cfdeSKuriakose Kuruvilla 	if (is_x86_feature(featureset, X86FSET_HTT) == B_FALSE &&
17007417cfdeSKuriakose Kuruvilla 	    is_x86_feature(featureset, X86FSET_CMP) == B_FALSE) {
17018949bcd6Sandrei 		/*
17028949bcd6Sandrei 		 * Single-core single-threaded processors.
17038949bcd6Sandrei 		 */
17047c478bd9Sstevel@tonic-gate 		cpi->cpi_chipid = -1;
17057c478bd9Sstevel@tonic-gate 		cpi->cpi_clogid = 0;
17068949bcd6Sandrei 		cpi->cpi_coreid = cpu->cpu_id;
170710569901Sgavinm 		cpi->cpi_pkgcoreid = 0;
17088031591dSSrihari Venkatesan 		if (cpi->cpi_vendor == X86_VENDOR_AMD)
17098031591dSSrihari Venkatesan 			cpi->cpi_procnodeid = BITX(cpi->cpi_apicid, 3, 0);
17108031591dSSrihari Venkatesan 		else
17118031591dSSrihari Venkatesan 			cpi->cpi_procnodeid = cpi->cpi_chipid;
17127c478bd9Sstevel@tonic-gate 	} else if (cpi->cpi_ncpu_per_chip > 1) {
17138031591dSSrihari Venkatesan 		if (cpi->cpi_vendor == X86_VENDOR_Intel)
17147417cfdeSKuriakose Kuruvilla 			cpuid_intel_getids(cpu, featureset);
17158031591dSSrihari Venkatesan 		else if (cpi->cpi_vendor == X86_VENDOR_AMD)
17168031591dSSrihari Venkatesan 			cpuid_amd_getids(cpu);
17178031591dSSrihari Venkatesan 		else {
17188949bcd6Sandrei 			/*
17198949bcd6Sandrei 			 * All other processors are currently
17208949bcd6Sandrei 			 * assumed to have single cores.
17218949bcd6Sandrei 			 */
17228949bcd6Sandrei 			cpi->cpi_coreid = cpi->cpi_chipid;
172310569901Sgavinm 			cpi->cpi_pkgcoreid = 0;
17248031591dSSrihari Venkatesan 			cpi->cpi_procnodeid = cpi->cpi_chipid;
17257660e73fSHans Rosenfeld 			cpi->cpi_compunitid = cpi->cpi_chipid;
17268949bcd6Sandrei 		}
17277c478bd9Sstevel@tonic-gate 	}
17287c478bd9Sstevel@tonic-gate 
17298a40a695Sgavinm 	/*
17308a40a695Sgavinm 	 * Synthesize chip "revision" and socket type
17318a40a695Sgavinm 	 */
1732e4b86885SCheng Sean Ye 	cpi->cpi_chiprev = _cpuid_chiprev(cpi->cpi_vendor, cpi->cpi_family,
1733e4b86885SCheng Sean Ye 	    cpi->cpi_model, cpi->cpi_step);
1734e4b86885SCheng Sean Ye 	cpi->cpi_chiprevstr = _cpuid_chiprevstr(cpi->cpi_vendor,
1735e4b86885SCheng Sean Ye 	    cpi->cpi_family, cpi->cpi_model, cpi->cpi_step);
1736e4b86885SCheng Sean Ye 	cpi->cpi_socket = _cpuid_skt(cpi->cpi_vendor, cpi->cpi_family,
1737e4b86885SCheng Sean Ye 	    cpi->cpi_model, cpi->cpi_step);
17388a40a695Sgavinm 
17397c478bd9Sstevel@tonic-gate pass1_done:
17407c478bd9Sstevel@tonic-gate 	cpi->cpi_pass = 1;
17417c478bd9Sstevel@tonic-gate }
17427c478bd9Sstevel@tonic-gate 
17437c478bd9Sstevel@tonic-gate /*
17447c478bd9Sstevel@tonic-gate  * Make copies of the cpuid table entries we depend on, in
17457c478bd9Sstevel@tonic-gate  * part for ease of parsing now, in part so that we have only
17467c478bd9Sstevel@tonic-gate  * one place to correct any of it, in part for ease of
17477c478bd9Sstevel@tonic-gate  * later export to userland, and in part so we can look at
17487c478bd9Sstevel@tonic-gate  * this stuff in a crash dump.
17497c478bd9Sstevel@tonic-gate  */
17507c478bd9Sstevel@tonic-gate 
17517c478bd9Sstevel@tonic-gate /*ARGSUSED*/
17527c478bd9Sstevel@tonic-gate void
17537c478bd9Sstevel@tonic-gate cpuid_pass2(cpu_t *cpu)
17547c478bd9Sstevel@tonic-gate {
17557c478bd9Sstevel@tonic-gate 	uint_t n, nmax;
17567c478bd9Sstevel@tonic-gate 	int i;
17578949bcd6Sandrei 	struct cpuid_regs *cp;
17587c478bd9Sstevel@tonic-gate 	uint8_t *dp;
17597c478bd9Sstevel@tonic-gate 	uint32_t *iptr;
17607c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
17617c478bd9Sstevel@tonic-gate 
17627c478bd9Sstevel@tonic-gate 	ASSERT(cpi->cpi_pass == 1);
17637c478bd9Sstevel@tonic-gate 
17647c478bd9Sstevel@tonic-gate 	if (cpi->cpi_maxeax < 1)
17657c478bd9Sstevel@tonic-gate 		goto pass2_done;
17667c478bd9Sstevel@tonic-gate 
17677c478bd9Sstevel@tonic-gate 	if ((nmax = cpi->cpi_maxeax + 1) > NMAX_CPI_STD)
17687c478bd9Sstevel@tonic-gate 		nmax = NMAX_CPI_STD;
17697c478bd9Sstevel@tonic-gate 	/*
17707c478bd9Sstevel@tonic-gate 	 * (We already handled n == 0 and n == 1 in pass 1)
17717c478bd9Sstevel@tonic-gate 	 */
17727c478bd9Sstevel@tonic-gate 	for (n = 2, cp = &cpi->cpi_std[2]; n < nmax; n++, cp++) {
17738949bcd6Sandrei 		cp->cp_eax = n;
1774d129bde2Sesaxe 
1775d129bde2Sesaxe 		/*
1776d129bde2Sesaxe 		 * CPUID function 4 expects %ecx to be initialized
1777d129bde2Sesaxe 		 * with an index which indicates which cache to return
1778d129bde2Sesaxe 		 * information about. The OS is expected to call function 4
1779d129bde2Sesaxe 		 * with %ecx set to 0, 1, 2, ... until it returns with
1780d129bde2Sesaxe 		 * EAX[4:0] set to 0, which indicates there are no more
1781d129bde2Sesaxe 		 * caches.
1782d129bde2Sesaxe 		 *
1783d129bde2Sesaxe 		 * Here, populate cpi_std[4] with the information returned by
1784d129bde2Sesaxe 		 * function 4 when %ecx == 0, and do the rest in cpuid_pass3()
1785d129bde2Sesaxe 		 * when dynamic memory allocation becomes available.
1786d129bde2Sesaxe 		 *
1787d129bde2Sesaxe 		 * Note: we need to explicitly initialize %ecx here, since
1788d129bde2Sesaxe 		 * function 4 may have been previously invoked.
1789d129bde2Sesaxe 		 */
1790d129bde2Sesaxe 		if (n == 4)
1791d129bde2Sesaxe 			cp->cp_ecx = 0;
1792d129bde2Sesaxe 
17938949bcd6Sandrei 		(void) __cpuid_insn(cp);
1794ae115bc7Smrj 		platform_cpuid_mangle(cpi->cpi_vendor, n, cp);
17957c478bd9Sstevel@tonic-gate 		switch (n) {
17967c478bd9Sstevel@tonic-gate 		case 2:
17977c478bd9Sstevel@tonic-gate 			/*
17987c478bd9Sstevel@tonic-gate 			 * "the lower 8 bits of the %eax register
17997c478bd9Sstevel@tonic-gate 			 * contain a value that identifies the number
18007c478bd9Sstevel@tonic-gate 			 * of times the cpuid [instruction] has to be
18017c478bd9Sstevel@tonic-gate 			 * executed to obtain a complete image of the
18027c478bd9Sstevel@tonic-gate 			 * processor's caching systems."
18037c478bd9Sstevel@tonic-gate 			 *
18047c478bd9Sstevel@tonic-gate 			 * How *do* they make this stuff up?
18057c478bd9Sstevel@tonic-gate 			 */
18067c478bd9Sstevel@tonic-gate 			cpi->cpi_ncache = sizeof (*cp) *
18077c478bd9Sstevel@tonic-gate 			    BITX(cp->cp_eax, 7, 0);
18087c478bd9Sstevel@tonic-gate 			if (cpi->cpi_ncache == 0)
18097c478bd9Sstevel@tonic-gate 				break;
18107c478bd9Sstevel@tonic-gate 			cpi->cpi_ncache--;	/* skip count byte */
18117c478bd9Sstevel@tonic-gate 
18127c478bd9Sstevel@tonic-gate 			/*
18137c478bd9Sstevel@tonic-gate 			 * Well, for now, rather than attempt to implement
18147c478bd9Sstevel@tonic-gate 			 * this slightly dubious algorithm, we just look
18157c478bd9Sstevel@tonic-gate 			 * at the first 15 ..
18167c478bd9Sstevel@tonic-gate 			 */
18177c478bd9Sstevel@tonic-gate 			if (cpi->cpi_ncache > (sizeof (*cp) - 1))
18187c478bd9Sstevel@tonic-gate 				cpi->cpi_ncache = sizeof (*cp) - 1;
18197c478bd9Sstevel@tonic-gate 
18207c478bd9Sstevel@tonic-gate 			dp = cpi->cpi_cacheinfo;
18217c478bd9Sstevel@tonic-gate 			if (BITX(cp->cp_eax, 31, 31) == 0) {
18227c478bd9Sstevel@tonic-gate 				uint8_t *p = (void *)&cp->cp_eax;
182363d3f7dfSkk208521 				for (i = 1; i < 4; i++)
18247c478bd9Sstevel@tonic-gate 					if (p[i] != 0)
18257c478bd9Sstevel@tonic-gate 						*dp++ = p[i];
18267c478bd9Sstevel@tonic-gate 			}
18277c478bd9Sstevel@tonic-gate 			if (BITX(cp->cp_ebx, 31, 31) == 0) {
18287c478bd9Sstevel@tonic-gate 				uint8_t *p = (void *)&cp->cp_ebx;
18297c478bd9Sstevel@tonic-gate 				for (i = 0; i < 4; i++)
18307c478bd9Sstevel@tonic-gate 					if (p[i] != 0)
18317c478bd9Sstevel@tonic-gate 						*dp++ = p[i];
18327c478bd9Sstevel@tonic-gate 			}
18337c478bd9Sstevel@tonic-gate 			if (BITX(cp->cp_ecx, 31, 31) == 0) {
18347c478bd9Sstevel@tonic-gate 				uint8_t *p = (void *)&cp->cp_ecx;
18357c478bd9Sstevel@tonic-gate 				for (i = 0; i < 4; i++)
18367c478bd9Sstevel@tonic-gate 					if (p[i] != 0)
18377c478bd9Sstevel@tonic-gate 						*dp++ = p[i];
18387c478bd9Sstevel@tonic-gate 			}
18397c478bd9Sstevel@tonic-gate 			if (BITX(cp->cp_edx, 31, 31) == 0) {
18407c478bd9Sstevel@tonic-gate 				uint8_t *p = (void *)&cp->cp_edx;
18417c478bd9Sstevel@tonic-gate 				for (i = 0; i < 4; i++)
18427c478bd9Sstevel@tonic-gate 					if (p[i] != 0)
18437c478bd9Sstevel@tonic-gate 						*dp++ = p[i];
18447c478bd9Sstevel@tonic-gate 			}
18457c478bd9Sstevel@tonic-gate 			break;
1846f98fbcecSbholler 
18477c478bd9Sstevel@tonic-gate 		case 3:	/* Processor serial number, if PSN supported */
1848f98fbcecSbholler 			break;
1849f98fbcecSbholler 
18507c478bd9Sstevel@tonic-gate 		case 4:	/* Deterministic cache parameters */
1851f98fbcecSbholler 			break;
1852f98fbcecSbholler 
18537c478bd9Sstevel@tonic-gate 		case 5:	/* Monitor/Mwait parameters */
18545b8a6efeSbholler 		{
18555b8a6efeSbholler 			size_t mwait_size;
1856f98fbcecSbholler 
1857f98fbcecSbholler 			/*
1858f98fbcecSbholler 			 * check cpi_mwait.support which was set in cpuid_pass1
1859f98fbcecSbholler 			 */
1860f98fbcecSbholler 			if (!(cpi->cpi_mwait.support & MWAIT_SUPPORT))
1861f98fbcecSbholler 				break;
1862f98fbcecSbholler 
18635b8a6efeSbholler 			/*
18645b8a6efeSbholler 			 * Protect ourself from insane mwait line size.
18655b8a6efeSbholler 			 * Workaround for incomplete hardware emulator(s).
18665b8a6efeSbholler 			 */
18675b8a6efeSbholler 			mwait_size = (size_t)MWAIT_SIZE_MAX(cpi);
18685b8a6efeSbholler 			if (mwait_size < sizeof (uint32_t) ||
18695b8a6efeSbholler 			    !ISP2(mwait_size)) {
18705b8a6efeSbholler #if DEBUG
18715b8a6efeSbholler 				cmn_err(CE_NOTE, "Cannot handle cpu %d mwait "
18725d8efbbcSSaurabh Misra 				    "size %ld", cpu->cpu_id, (long)mwait_size);
18735b8a6efeSbholler #endif
18745b8a6efeSbholler 				break;
18755b8a6efeSbholler 			}
18765b8a6efeSbholler 
1877f98fbcecSbholler 			cpi->cpi_mwait.mon_min = (size_t)MWAIT_SIZE_MIN(cpi);
18785b8a6efeSbholler 			cpi->cpi_mwait.mon_max = mwait_size;
1879f98fbcecSbholler 			if (MWAIT_EXTENSION(cpi)) {
1880f98fbcecSbholler 				cpi->cpi_mwait.support |= MWAIT_EXTENSIONS;
1881f98fbcecSbholler 				if (MWAIT_INT_ENABLE(cpi))
1882f98fbcecSbholler 					cpi->cpi_mwait.support |=
1883f98fbcecSbholler 					    MWAIT_ECX_INT_ENABLE;
1884f98fbcecSbholler 			}
1885f98fbcecSbholler 			break;
18865b8a6efeSbholler 		}
18877c478bd9Sstevel@tonic-gate 		default:
18887c478bd9Sstevel@tonic-gate 			break;
18897c478bd9Sstevel@tonic-gate 		}
18907c478bd9Sstevel@tonic-gate 	}
18917c478bd9Sstevel@tonic-gate 
1892b6917abeSmishra 	if (cpi->cpi_maxeax >= 0xB && cpi->cpi_vendor == X86_VENDOR_Intel) {
18935d8efbbcSSaurabh Misra 		struct cpuid_regs regs;
18945d8efbbcSSaurabh Misra 
18955d8efbbcSSaurabh Misra 		cp = &regs;
1896b6917abeSmishra 		cp->cp_eax = 0xB;
18975d8efbbcSSaurabh Misra 		cp->cp_edx = cp->cp_ebx = cp->cp_ecx = 0;
1898b6917abeSmishra 
1899b6917abeSmishra 		(void) __cpuid_insn(cp);
1900b6917abeSmishra 
1901b6917abeSmishra 		/*
1902b6917abeSmishra 		 * Check CPUID.EAX=0BH, ECX=0H:EBX is non-zero, which
1903b6917abeSmishra 		 * indicates that the extended topology enumeration leaf is
1904b6917abeSmishra 		 * available.
1905b6917abeSmishra 		 */
1906b6917abeSmishra 		if (cp->cp_ebx) {
1907b6917abeSmishra 			uint32_t x2apic_id;
1908b6917abeSmishra 			uint_t coreid_shift = 0;
1909b6917abeSmishra 			uint_t ncpu_per_core = 1;
1910b6917abeSmishra 			uint_t chipid_shift = 0;
1911b6917abeSmishra 			uint_t ncpu_per_chip = 1;
1912b6917abeSmishra 			uint_t i;
1913b6917abeSmishra 			uint_t level;
1914b6917abeSmishra 
1915b6917abeSmishra 			for (i = 0; i < CPI_FNB_ECX_MAX; i++) {
1916b6917abeSmishra 				cp->cp_eax = 0xB;
1917b6917abeSmishra 				cp->cp_ecx = i;
1918b6917abeSmishra 
1919b6917abeSmishra 				(void) __cpuid_insn(cp);
1920b6917abeSmishra 				level = CPI_CPU_LEVEL_TYPE(cp);
1921b6917abeSmishra 
1922b6917abeSmishra 				if (level == 1) {
1923b6917abeSmishra 					x2apic_id = cp->cp_edx;
1924b6917abeSmishra 					coreid_shift = BITX(cp->cp_eax, 4, 0);
1925b6917abeSmishra 					ncpu_per_core = BITX(cp->cp_ebx, 15, 0);
1926b6917abeSmishra 				} else if (level == 2) {
1927b6917abeSmishra 					x2apic_id = cp->cp_edx;
1928b6917abeSmishra 					chipid_shift = BITX(cp->cp_eax, 4, 0);
1929b6917abeSmishra 					ncpu_per_chip = BITX(cp->cp_ebx, 15, 0);
1930b6917abeSmishra 				}
1931b6917abeSmishra 			}
1932b6917abeSmishra 
1933b6917abeSmishra 			cpi->cpi_apicid = x2apic_id;
1934b6917abeSmishra 			cpi->cpi_ncpu_per_chip = ncpu_per_chip;
1935b6917abeSmishra 			cpi->cpi_ncore_per_chip = ncpu_per_chip /
1936b6917abeSmishra 			    ncpu_per_core;
1937b6917abeSmishra 			cpi->cpi_chipid = x2apic_id >> chipid_shift;
1938b6917abeSmishra 			cpi->cpi_clogid = x2apic_id & ((1 << chipid_shift) - 1);
1939b6917abeSmishra 			cpi->cpi_coreid = x2apic_id >> coreid_shift;
1940b6917abeSmishra 			cpi->cpi_pkgcoreid = cpi->cpi_clogid >> coreid_shift;
1941b6917abeSmishra 		}
19425d8efbbcSSaurabh Misra 
19435d8efbbcSSaurabh Misra 		/* Make cp NULL so that we don't stumble on others */
19445d8efbbcSSaurabh Misra 		cp = NULL;
1945b6917abeSmishra 	}
1946b6917abeSmishra 
19477af88ac7SKuriakose Kuruvilla 	/*
19487af88ac7SKuriakose Kuruvilla 	 * XSAVE enumeration
19497af88ac7SKuriakose Kuruvilla 	 */
195063408480SHans Rosenfeld 	if (cpi->cpi_maxeax >= 0xD) {
19517af88ac7SKuriakose Kuruvilla 		struct cpuid_regs regs;
19527af88ac7SKuriakose Kuruvilla 		boolean_t cpuid_d_valid = B_TRUE;
19537af88ac7SKuriakose Kuruvilla 
19547af88ac7SKuriakose Kuruvilla 		cp = &regs;
19557af88ac7SKuriakose Kuruvilla 		cp->cp_eax = 0xD;
19567af88ac7SKuriakose Kuruvilla 		cp->cp_edx = cp->cp_ebx = cp->cp_ecx = 0;
19577af88ac7SKuriakose Kuruvilla 
19587af88ac7SKuriakose Kuruvilla 		(void) __cpuid_insn(cp);
19597af88ac7SKuriakose Kuruvilla 
19607af88ac7SKuriakose Kuruvilla 		/*
19617af88ac7SKuriakose Kuruvilla 		 * Sanity checks for debug
19627af88ac7SKuriakose Kuruvilla 		 */
19637af88ac7SKuriakose Kuruvilla 		if ((cp->cp_eax & XFEATURE_LEGACY_FP) == 0 ||
19647af88ac7SKuriakose Kuruvilla 		    (cp->cp_eax & XFEATURE_SSE) == 0) {
19657af88ac7SKuriakose Kuruvilla 			cpuid_d_valid = B_FALSE;
19667af88ac7SKuriakose Kuruvilla 		}
19677af88ac7SKuriakose Kuruvilla 
19687af88ac7SKuriakose Kuruvilla 		cpi->cpi_xsave.xsav_hw_features_low = cp->cp_eax;
19697af88ac7SKuriakose Kuruvilla 		cpi->cpi_xsave.xsav_hw_features_high = cp->cp_edx;
19707af88ac7SKuriakose Kuruvilla 		cpi->cpi_xsave.xsav_max_size = cp->cp_ecx;
19717af88ac7SKuriakose Kuruvilla 
19727af88ac7SKuriakose Kuruvilla 		/*
19737af88ac7SKuriakose Kuruvilla 		 * If the hw supports AVX, get the size and offset in the save
19747af88ac7SKuriakose Kuruvilla 		 * area for the ymm state.
19757af88ac7SKuriakose Kuruvilla 		 */
19767af88ac7SKuriakose Kuruvilla 		if (cpi->cpi_xsave.xsav_hw_features_low & XFEATURE_AVX) {
19777af88ac7SKuriakose Kuruvilla 			cp->cp_eax = 0xD;
19787af88ac7SKuriakose Kuruvilla 			cp->cp_ecx = 2;
19797af88ac7SKuriakose Kuruvilla 			cp->cp_edx = cp->cp_ebx = 0;
19807af88ac7SKuriakose Kuruvilla 
19817af88ac7SKuriakose Kuruvilla 			(void) __cpuid_insn(cp);
19827af88ac7SKuriakose Kuruvilla 
19837af88ac7SKuriakose Kuruvilla 			if (cp->cp_ebx != CPUID_LEAFD_2_YMM_OFFSET ||
19847af88ac7SKuriakose Kuruvilla 			    cp->cp_eax != CPUID_LEAFD_2_YMM_SIZE) {
19857af88ac7SKuriakose Kuruvilla 				cpuid_d_valid = B_FALSE;
19867af88ac7SKuriakose Kuruvilla 			}
19877af88ac7SKuriakose Kuruvilla 
19887af88ac7SKuriakose Kuruvilla 			cpi->cpi_xsave.ymm_size = cp->cp_eax;
19897af88ac7SKuriakose Kuruvilla 			cpi->cpi_xsave.ymm_offset = cp->cp_ebx;
19907af88ac7SKuriakose Kuruvilla 		}
19917af88ac7SKuriakose Kuruvilla 
19927af88ac7SKuriakose Kuruvilla 		if (is_x86_feature(x86_featureset, X86FSET_XSAVE)) {
19937af88ac7SKuriakose Kuruvilla 			xsave_state_size = 0;
19947af88ac7SKuriakose Kuruvilla 		} else if (cpuid_d_valid) {
19957af88ac7SKuriakose Kuruvilla 			xsave_state_size = cpi->cpi_xsave.xsav_max_size;
19967af88ac7SKuriakose Kuruvilla 		} else {
19977af88ac7SKuriakose Kuruvilla 			/* Broken CPUID 0xD, probably in HVM */
19987af88ac7SKuriakose Kuruvilla 			cmn_err(CE_WARN, "cpu%d: CPUID.0xD returns invalid "
19997af88ac7SKuriakose Kuruvilla 			    "value: hw_low = %d, hw_high = %d, xsave_size = %d"
20007af88ac7SKuriakose Kuruvilla 			    ", ymm_size = %d, ymm_offset = %d\n",
20017af88ac7SKuriakose Kuruvilla 			    cpu->cpu_id, cpi->cpi_xsave.xsav_hw_features_low,
20027af88ac7SKuriakose Kuruvilla 			    cpi->cpi_xsave.xsav_hw_features_high,
20037af88ac7SKuriakose Kuruvilla 			    (int)cpi->cpi_xsave.xsav_max_size,
20047af88ac7SKuriakose Kuruvilla 			    (int)cpi->cpi_xsave.ymm_size,
20057af88ac7SKuriakose Kuruvilla 			    (int)cpi->cpi_xsave.ymm_offset);
20067af88ac7SKuriakose Kuruvilla 
20077af88ac7SKuriakose Kuruvilla 			if (xsave_state_size != 0) {
20087af88ac7SKuriakose Kuruvilla 				/*
20097af88ac7SKuriakose Kuruvilla 				 * This must be a non-boot CPU. We cannot
20107af88ac7SKuriakose Kuruvilla 				 * continue, because boot cpu has already
20117af88ac7SKuriakose Kuruvilla 				 * enabled XSAVE.
20127af88ac7SKuriakose Kuruvilla 				 */
20137af88ac7SKuriakose Kuruvilla 				ASSERT(cpu->cpu_id != 0);
20147af88ac7SKuriakose Kuruvilla 				cmn_err(CE_PANIC, "cpu%d: we have already "
20157af88ac7SKuriakose Kuruvilla 				    "enabled XSAVE on boot cpu, cannot "
20167af88ac7SKuriakose Kuruvilla 				    "continue.", cpu->cpu_id);
20177af88ac7SKuriakose Kuruvilla 			} else {
20187af88ac7SKuriakose Kuruvilla 				/*
2019dcf050afSRobert Mustacchi 				 * If we reached here on the boot CPU, it's also
2020dcf050afSRobert Mustacchi 				 * almost certain that we'll reach here on the
2021dcf050afSRobert Mustacchi 				 * non-boot CPUs. When we're here on a boot CPU
2022dcf050afSRobert Mustacchi 				 * we should disable the feature, on a non-boot
2023dcf050afSRobert Mustacchi 				 * CPU we need to confirm that we have.
20247af88ac7SKuriakose Kuruvilla 				 */
2025dcf050afSRobert Mustacchi 				if (cpu->cpu_id == 0) {
20267af88ac7SKuriakose Kuruvilla 					remove_x86_feature(x86_featureset,
20277af88ac7SKuriakose Kuruvilla 					    X86FSET_XSAVE);
2028dcf050afSRobert Mustacchi 					remove_x86_feature(x86_featureset,
2029dcf050afSRobert Mustacchi 					    X86FSET_AVX);
2030245ac945SRobert Mustacchi 					remove_x86_feature(x86_featureset,
2031245ac945SRobert Mustacchi 					    X86FSET_F16C);
2032245ac945SRobert Mustacchi 					remove_x86_feature(x86_featureset,
2033245ac945SRobert Mustacchi 					    X86FSET_BMI1);
2034245ac945SRobert Mustacchi 					remove_x86_feature(x86_featureset,
2035245ac945SRobert Mustacchi 					    X86FSET_BMI2);
2036245ac945SRobert Mustacchi 					remove_x86_feature(x86_featureset,
2037245ac945SRobert Mustacchi 					    X86FSET_FMA);
2038245ac945SRobert Mustacchi 					remove_x86_feature(x86_featureset,
2039245ac945SRobert Mustacchi 					    X86FSET_AVX2);
2040dcf050afSRobert Mustacchi 					CPI_FEATURES_ECX(cpi) &=
2041dcf050afSRobert Mustacchi 					    ~CPUID_INTC_ECX_XSAVE;
2042dcf050afSRobert Mustacchi 					CPI_FEATURES_ECX(cpi) &=
2043dcf050afSRobert Mustacchi 					    ~CPUID_INTC_ECX_AVX;
2044dcf050afSRobert Mustacchi 					CPI_FEATURES_ECX(cpi) &=
2045dcf050afSRobert Mustacchi 					    ~CPUID_INTC_ECX_F16C;
2046245ac945SRobert Mustacchi 					CPI_FEATURES_ECX(cpi) &=
2047245ac945SRobert Mustacchi 					    ~CPUID_INTC_ECX_FMA;
2048245ac945SRobert Mustacchi 					CPI_FEATURES_7_0_EBX(cpi) &=
2049245ac945SRobert Mustacchi 					    ~CPUID_INTC_EBX_7_0_BMI1;
2050245ac945SRobert Mustacchi 					CPI_FEATURES_7_0_EBX(cpi) &=
2051245ac945SRobert Mustacchi 					    ~CPUID_INTC_EBX_7_0_BMI2;
2052245ac945SRobert Mustacchi 					CPI_FEATURES_7_0_EBX(cpi) &=
2053245ac945SRobert Mustacchi 					    ~CPUID_INTC_EBX_7_0_AVX2;
20547af88ac7SKuriakose Kuruvilla 					xsave_force_disable = B_TRUE;
2055dcf050afSRobert Mustacchi 				} else {
2056dcf050afSRobert Mustacchi 					VERIFY(is_x86_feature(x86_featureset,
2057dcf050afSRobert Mustacchi 					    X86FSET_XSAVE) == B_FALSE);
2058dcf050afSRobert Mustacchi 				}
20597af88ac7SKuriakose Kuruvilla 			}
20607af88ac7SKuriakose Kuruvilla 		}
20617af88ac7SKuriakose Kuruvilla 	}
20627af88ac7SKuriakose Kuruvilla 
20637af88ac7SKuriakose Kuruvilla 
20647c478bd9Sstevel@tonic-gate 	if ((cpi->cpi_xmaxeax & 0x80000000) == 0)
20657c478bd9Sstevel@tonic-gate 		goto pass2_done;
20667c478bd9Sstevel@tonic-gate 
20677c478bd9Sstevel@tonic-gate 	if ((nmax = cpi->cpi_xmaxeax - 0x80000000 + 1) > NMAX_CPI_EXTD)
20687c478bd9Sstevel@tonic-gate 		nmax = NMAX_CPI_EXTD;
20697c478bd9Sstevel@tonic-gate 	/*
20707c478bd9Sstevel@tonic-gate 	 * Copy the extended properties, fixing them as we go.
20717c478bd9Sstevel@tonic-gate 	 * (We already handled n == 0 and n == 1 in pass 1)
20727c478bd9Sstevel@tonic-gate 	 */
20737c478bd9Sstevel@tonic-gate 	iptr = (void *)cpi->cpi_brandstr;
20747c478bd9Sstevel@tonic-gate 	for (n = 2, cp = &cpi->cpi_extd[2]; n < nmax; cp++, n++) {
20758949bcd6Sandrei 		cp->cp_eax = 0x80000000 + n;
20768949bcd6Sandrei 		(void) __cpuid_insn(cp);
2077ae115bc7Smrj 		platform_cpuid_mangle(cpi->cpi_vendor, 0x80000000 + n, cp);
20787c478bd9Sstevel@tonic-gate 		switch (n) {
20797c478bd9Sstevel@tonic-gate 		case 2:
20807c478bd9Sstevel@tonic-gate 		case 3:
20817c478bd9Sstevel@tonic-gate 		case 4:
20827c478bd9Sstevel@tonic-gate 			/*
20837c478bd9Sstevel@tonic-gate 			 * Extract the brand string
20847c478bd9Sstevel@tonic-gate 			 */
20857c478bd9Sstevel@tonic-gate 			*iptr++ = cp->cp_eax;
20867c478bd9Sstevel@tonic-gate 			*iptr++ = cp->cp_ebx;
20877c478bd9Sstevel@tonic-gate 			*iptr++ = cp->cp_ecx;
20887c478bd9Sstevel@tonic-gate 			*iptr++ = cp->cp_edx;
20897c478bd9Sstevel@tonic-gate 			break;
20907c478bd9Sstevel@tonic-gate 		case 5:
20917c478bd9Sstevel@tonic-gate 			switch (cpi->cpi_vendor) {
20927c478bd9Sstevel@tonic-gate 			case X86_VENDOR_AMD:
20937c478bd9Sstevel@tonic-gate 				/*
20947c478bd9Sstevel@tonic-gate 				 * The Athlon and Duron were the first
20957c478bd9Sstevel@tonic-gate 				 * parts to report the sizes of the
20967c478bd9Sstevel@tonic-gate 				 * TLB for large pages. Before then,
20977c478bd9Sstevel@tonic-gate 				 * we don't trust the data.
20987c478bd9Sstevel@tonic-gate 				 */
20997c478bd9Sstevel@tonic-gate 				if (cpi->cpi_family < 6 ||
21007c478bd9Sstevel@tonic-gate 				    (cpi->cpi_family == 6 &&
21017c478bd9Sstevel@tonic-gate 				    cpi->cpi_model < 1))
21027c478bd9Sstevel@tonic-gate 					cp->cp_eax = 0;
21037c478bd9Sstevel@tonic-gate 				break;
21047c478bd9Sstevel@tonic-gate 			default:
21057c478bd9Sstevel@tonic-gate 				break;
21067c478bd9Sstevel@tonic-gate 			}
21077c478bd9Sstevel@tonic-gate 			break;
21087c478bd9Sstevel@tonic-gate 		case 6:
21097c478bd9Sstevel@tonic-gate 			switch (cpi->cpi_vendor) {
21107c478bd9Sstevel@tonic-gate 			case X86_VENDOR_AMD:
21117c478bd9Sstevel@tonic-gate 				/*
21127c478bd9Sstevel@tonic-gate 				 * The Athlon and Duron were the first
21137c478bd9Sstevel@tonic-gate 				 * AMD parts with L2 TLB's.
21147c478bd9Sstevel@tonic-gate 				 * Before then, don't trust the data.
21157c478bd9Sstevel@tonic-gate 				 */
21167c478bd9Sstevel@tonic-gate 				if (cpi->cpi_family < 6 ||
21177c478bd9Sstevel@tonic-gate 				    cpi->cpi_family == 6 &&
21187c478bd9Sstevel@tonic-gate 				    cpi->cpi_model < 1)
21197c478bd9Sstevel@tonic-gate 					cp->cp_eax = cp->cp_ebx = 0;
21207c478bd9Sstevel@tonic-gate 				/*
21217c478bd9Sstevel@tonic-gate 				 * AMD Duron rev A0 reports L2
21227c478bd9Sstevel@tonic-gate 				 * cache size incorrectly as 1K
21237c478bd9Sstevel@tonic-gate 				 * when it is really 64K
21247c478bd9Sstevel@tonic-gate 				 */
21257c478bd9Sstevel@tonic-gate 				if (cpi->cpi_family == 6 &&
21267c478bd9Sstevel@tonic-gate 				    cpi->cpi_model == 3 &&
21277c478bd9Sstevel@tonic-gate 				    cpi->cpi_step == 0) {
21287c478bd9Sstevel@tonic-gate 					cp->cp_ecx &= 0xffff;
21297c478bd9Sstevel@tonic-gate 					cp->cp_ecx |= 0x400000;
21307c478bd9Sstevel@tonic-gate 				}
21317c478bd9Sstevel@tonic-gate 				break;
21327c478bd9Sstevel@tonic-gate 			case X86_VENDOR_Cyrix:	/* VIA C3 */
21337c478bd9Sstevel@tonic-gate 				/*
21347c478bd9Sstevel@tonic-gate 				 * VIA C3 processors are a bit messed
21357c478bd9Sstevel@tonic-gate 				 * up w.r.t. encoding cache sizes in %ecx
21367c478bd9Sstevel@tonic-gate 				 */
21377c478bd9Sstevel@tonic-gate 				if (cpi->cpi_family != 6)
21387c478bd9Sstevel@tonic-gate 					break;
21397c478bd9Sstevel@tonic-gate 				/*
21407c478bd9Sstevel@tonic-gate 				 * model 7 and 8 were incorrectly encoded
21417c478bd9Sstevel@tonic-gate 				 *
21427c478bd9Sstevel@tonic-gate 				 * xxx is model 8 really broken?
21437c478bd9Sstevel@tonic-gate 				 */
21447c478bd9Sstevel@tonic-gate 				if (cpi->cpi_model == 7 ||
21457c478bd9Sstevel@tonic-gate 				    cpi->cpi_model == 8)
21467c478bd9Sstevel@tonic-gate 					cp->cp_ecx =
21477c478bd9Sstevel@tonic-gate 					    BITX(cp->cp_ecx, 31, 24) << 16 |
21487c478bd9Sstevel@tonic-gate 					    BITX(cp->cp_ecx, 23, 16) << 12 |
21497c478bd9Sstevel@tonic-gate 					    BITX(cp->cp_ecx, 15, 8) << 8 |
21507c478bd9Sstevel@tonic-gate 					    BITX(cp->cp_ecx, 7, 0);
21517c478bd9Sstevel@tonic-gate 				/*
21527c478bd9Sstevel@tonic-gate 				 * model 9 stepping 1 has wrong associativity
21537c478bd9Sstevel@tonic-gate 				 */
21547c478bd9Sstevel@tonic-gate 				if (cpi->cpi_model == 9 && cpi->cpi_step == 1)
21557c478bd9Sstevel@tonic-gate 					cp->cp_ecx |= 8 << 12;
21567c478bd9Sstevel@tonic-gate 				break;
21577c478bd9Sstevel@tonic-gate 			case X86_VENDOR_Intel:
21587c478bd9Sstevel@tonic-gate 				/*
21597c478bd9Sstevel@tonic-gate 				 * Extended L2 Cache features function.
21607c478bd9Sstevel@tonic-gate 				 * First appeared on Prescott.
21617c478bd9Sstevel@tonic-gate 				 */
21627c478bd9Sstevel@tonic-gate 			default:
21637c478bd9Sstevel@tonic-gate 				break;
21647c478bd9Sstevel@tonic-gate 			}
21657c478bd9Sstevel@tonic-gate 			break;
21667c478bd9Sstevel@tonic-gate 		default:
21677c478bd9Sstevel@tonic-gate 			break;
21687c478bd9Sstevel@tonic-gate 		}
21697c478bd9Sstevel@tonic-gate 	}
21707c478bd9Sstevel@tonic-gate 
21717c478bd9Sstevel@tonic-gate pass2_done:
21727c478bd9Sstevel@tonic-gate 	cpi->cpi_pass = 2;
21737c478bd9Sstevel@tonic-gate }
21747c478bd9Sstevel@tonic-gate 
21757c478bd9Sstevel@tonic-gate static const char *
21767c478bd9Sstevel@tonic-gate intel_cpubrand(const struct cpuid_info *cpi)
21777c478bd9Sstevel@tonic-gate {
21787c478bd9Sstevel@tonic-gate 	int i;
21797c478bd9Sstevel@tonic-gate 
21807417cfdeSKuriakose Kuruvilla 	if (!is_x86_feature(x86_featureset, X86FSET_CPUID) ||
21817c478bd9Sstevel@tonic-gate 	    cpi->cpi_maxeax < 1 || cpi->cpi_family < 5)
21827c478bd9Sstevel@tonic-gate 		return ("i486");
21837c478bd9Sstevel@tonic-gate 
21847c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_family) {
21857c478bd9Sstevel@tonic-gate 	case 5:
21867c478bd9Sstevel@tonic-gate 		return ("Intel Pentium(r)");
21877c478bd9Sstevel@tonic-gate 	case 6:
21887c478bd9Sstevel@tonic-gate 		switch (cpi->cpi_model) {
21897c478bd9Sstevel@tonic-gate 			uint_t celeron, xeon;
21908949bcd6Sandrei 			const struct cpuid_regs *cp;
21917c478bd9Sstevel@tonic-gate 		case 0:
21927c478bd9Sstevel@tonic-gate 		case 1:
21937c478bd9Sstevel@tonic-gate 		case 2:
21947c478bd9Sstevel@tonic-gate 			return ("Intel Pentium(r) Pro");
21957c478bd9Sstevel@tonic-gate 		case 3:
21967c478bd9Sstevel@tonic-gate 		case 4:
21977c478bd9Sstevel@tonic-gate 			return ("Intel Pentium(r) II");
21987c478bd9Sstevel@tonic-gate 		case 6:
21997c478bd9Sstevel@tonic-gate 			return ("Intel Celeron(r)");
22007c478bd9Sstevel@tonic-gate 		case 5:
22017c478bd9Sstevel@tonic-gate 		case 7:
22027c478bd9Sstevel@tonic-gate 			celeron = xeon = 0;
22037c478bd9Sstevel@tonic-gate 			cp = &cpi->cpi_std[2];	/* cache info */
22047c478bd9Sstevel@tonic-gate 
220563d3f7dfSkk208521 			for (i = 1; i < 4; i++) {
22067c478bd9Sstevel@tonic-gate 				uint_t tmp;
22077c478bd9Sstevel@tonic-gate 
22087c478bd9Sstevel@tonic-gate 				tmp = (cp->cp_eax >> (8 * i)) & 0xff;
22097c478bd9Sstevel@tonic-gate 				if (tmp == 0x40)
22107c478bd9Sstevel@tonic-gate 					celeron++;
22117c478bd9Sstevel@tonic-gate 				if (tmp >= 0x44 && tmp <= 0x45)
22127c478bd9Sstevel@tonic-gate 					xeon++;
22137c478bd9Sstevel@tonic-gate 			}
22147c478bd9Sstevel@tonic-gate 
22157c478bd9Sstevel@tonic-gate 			for (i = 0; i < 2; i++) {
22167c478bd9Sstevel@tonic-gate 				uint_t tmp;
22177c478bd9Sstevel@tonic-gate 
22187c478bd9Sstevel@tonic-gate 				tmp = (cp->cp_ebx >> (8 * i)) & 0xff;
22197c478bd9Sstevel@tonic-gate 				if (tmp == 0x40)
22207c478bd9Sstevel@tonic-gate 					celeron++;
22217c478bd9Sstevel@tonic-gate 				else if (tmp >= 0x44 && tmp <= 0x45)
22227c478bd9Sstevel@tonic-gate 					xeon++;
22237c478bd9Sstevel@tonic-gate 			}
22247c478bd9Sstevel@tonic-gate 
22257c478bd9Sstevel@tonic-gate 			for (i = 0; i < 4; i++) {
22267c478bd9Sstevel@tonic-gate 				uint_t tmp;
22277c478bd9Sstevel@tonic-gate 
22287c478bd9Sstevel@tonic-gate 				tmp = (cp->cp_ecx >> (8 * i)) & 0xff;
22297c478bd9Sstevel@tonic-gate 				if (tmp == 0x40)
22307c478bd9Sstevel@tonic-gate 					celeron++;
22317c478bd9Sstevel@tonic-gate 				else if (tmp >= 0x44 && tmp <= 0x45)
22327c478bd9Sstevel@tonic-gate 					xeon++;
22337c478bd9Sstevel@tonic-gate 			}
22347c478bd9Sstevel@tonic-gate 
22357c478bd9Sstevel@tonic-gate 			for (i = 0; i < 4; i++) {
22367c478bd9Sstevel@tonic-gate 				uint_t tmp;
22377c478bd9Sstevel@tonic-gate 
22387c478bd9Sstevel@tonic-gate 				tmp = (cp->cp_edx >> (8 * i)) & 0xff;
22397c478bd9Sstevel@tonic-gate 				if (tmp == 0x40)
22407c478bd9Sstevel@tonic-gate 					celeron++;
22417c478bd9Sstevel@tonic-gate 				else if (tmp >= 0x44 && tmp <= 0x45)
22427c478bd9Sstevel@tonic-gate 					xeon++;
22437c478bd9Sstevel@tonic-gate 			}
22447c478bd9Sstevel@tonic-gate 
22457c478bd9Sstevel@tonic-gate 			if (celeron)
22467c478bd9Sstevel@tonic-gate 				return ("Intel Celeron(r)");
22477c478bd9Sstevel@tonic-gate 			if (xeon)
22487c478bd9Sstevel@tonic-gate 				return (cpi->cpi_model == 5 ?
22497c478bd9Sstevel@tonic-gate 				    "Intel Pentium(r) II Xeon(tm)" :
22507c478bd9Sstevel@tonic-gate 				    "Intel Pentium(r) III Xeon(tm)");
22517c478bd9Sstevel@tonic-gate 			return (cpi->cpi_model == 5 ?
22527c478bd9Sstevel@tonic-gate 			    "Intel Pentium(r) II or Pentium(r) II Xeon(tm)" :
22537c478bd9Sstevel@tonic-gate 			    "Intel Pentium(r) III or Pentium(r) III Xeon(tm)");
22547c478bd9Sstevel@tonic-gate 		default:
22557c478bd9Sstevel@tonic-gate 			break;
22567c478bd9Sstevel@tonic-gate 		}
22577c478bd9Sstevel@tonic-gate 	default:
22587c478bd9Sstevel@tonic-gate 		break;
22597c478bd9Sstevel@tonic-gate 	}
22607c478bd9Sstevel@tonic-gate 
22615ff02082Sdmick 	/* BrandID is present if the field is nonzero */
22625ff02082Sdmick 	if (cpi->cpi_brandid != 0) {
22637c478bd9Sstevel@tonic-gate 		static const struct {
22647c478bd9Sstevel@tonic-gate 			uint_t bt_bid;
22657c478bd9Sstevel@tonic-gate 			const char *bt_str;
22667c478bd9Sstevel@tonic-gate 		} brand_tbl[] = {
22677c478bd9Sstevel@tonic-gate 			{ 0x1,	"Intel(r) Celeron(r)" },
22687c478bd9Sstevel@tonic-gate 			{ 0x2,	"Intel(r) Pentium(r) III" },
22697c478bd9Sstevel@tonic-gate 			{ 0x3,	"Intel(r) Pentium(r) III Xeon(tm)" },
22707c478bd9Sstevel@tonic-gate 			{ 0x4,	"Intel(r) Pentium(r) III" },
22717c478bd9Sstevel@tonic-gate 			{ 0x6,	"Mobile Intel(r) Pentium(r) III" },
22727c478bd9Sstevel@tonic-gate 			{ 0x7,	"Mobile Intel(r) Celeron(r)" },
22737c478bd9Sstevel@tonic-gate 			{ 0x8,	"Intel(r) Pentium(r) 4" },
22747c478bd9Sstevel@tonic-gate 			{ 0x9,	"Intel(r) Pentium(r) 4" },
22757c478bd9Sstevel@tonic-gate 			{ 0xa,	"Intel(r) Celeron(r)" },
22767c478bd9Sstevel@tonic-gate 			{ 0xb,	"Intel(r) Xeon(tm)" },
22777c478bd9Sstevel@tonic-gate 			{ 0xc,	"Intel(r) Xeon(tm) MP" },
22787c478bd9Sstevel@tonic-gate 			{ 0xe,	"Mobile Intel(r) Pentium(r) 4" },
22795ff02082Sdmick 			{ 0xf,	"Mobile Intel(r) Celeron(r)" },
22805ff02082Sdmick 			{ 0x11, "Mobile Genuine Intel(r)" },
22815ff02082Sdmick 			{ 0x12, "Intel(r) Celeron(r) M" },
22825ff02082Sdmick 			{ 0x13, "Mobile Intel(r) Celeron(r)" },
22835ff02082Sdmick 			{ 0x14, "Intel(r) Celeron(r)" },
22845ff02082Sdmick 			{ 0x15, "Mobile Genuine Intel(r)" },
22855ff02082Sdmick 			{ 0x16,	"Intel(r) Pentium(r) M" },
22865ff02082Sdmick 			{ 0x17, "Mobile Intel(r) Celeron(r)" }
22877c478bd9Sstevel@tonic-gate 		};
22887c478bd9Sstevel@tonic-gate 		uint_t btblmax = sizeof (brand_tbl) / sizeof (brand_tbl[0]);
22897c478bd9Sstevel@tonic-gate 		uint_t sgn;
22907c478bd9Sstevel@tonic-gate 
22917c478bd9Sstevel@tonic-gate 		sgn = (cpi->cpi_family << 8) |
22927c478bd9Sstevel@tonic-gate 		    (cpi->cpi_model << 4) | cpi->cpi_step;
22937c478bd9Sstevel@tonic-gate 
22947c478bd9Sstevel@tonic-gate 		for (i = 0; i < btblmax; i++)
22957c478bd9Sstevel@tonic-gate 			if (brand_tbl[i].bt_bid == cpi->cpi_brandid)
22967c478bd9Sstevel@tonic-gate 				break;
22977c478bd9Sstevel@tonic-gate 		if (i < btblmax) {
22987c478bd9Sstevel@tonic-gate 			if (sgn == 0x6b1 && cpi->cpi_brandid == 3)
22997c478bd9Sstevel@tonic-gate 				return ("Intel(r) Celeron(r)");
23007c478bd9Sstevel@tonic-gate 			if (sgn < 0xf13 && cpi->cpi_brandid == 0xb)
23017c478bd9Sstevel@tonic-gate 				return ("Intel(r) Xeon(tm) MP");
23027c478bd9Sstevel@tonic-gate 			if (sgn < 0xf13 && cpi->cpi_brandid == 0xe)
23037c478bd9Sstevel@tonic-gate 				return ("Intel(r) Xeon(tm)");
23047c478bd9Sstevel@tonic-gate 			return (brand_tbl[i].bt_str);
23057c478bd9Sstevel@tonic-gate 		}
23067c478bd9Sstevel@tonic-gate 	}
23077c478bd9Sstevel@tonic-gate 
23087c478bd9Sstevel@tonic-gate 	return (NULL);
23097c478bd9Sstevel@tonic-gate }
23107c478bd9Sstevel@tonic-gate 
23117c478bd9Sstevel@tonic-gate static const char *
23127c478bd9Sstevel@tonic-gate amd_cpubrand(const struct cpuid_info *cpi)
23137c478bd9Sstevel@tonic-gate {
23147417cfdeSKuriakose Kuruvilla 	if (!is_x86_feature(x86_featureset, X86FSET_CPUID) ||
23157c478bd9Sstevel@tonic-gate 	    cpi->cpi_maxeax < 1 || cpi->cpi_family < 5)
23167c478bd9Sstevel@tonic-gate 		return ("i486 compatible");
23177c478bd9Sstevel@tonic-gate 
23187c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_family) {
23197c478bd9Sstevel@tonic-gate 	case 5:
23207c478bd9Sstevel@tonic-gate 		switch (cpi->cpi_model) {
23217c478bd9Sstevel@tonic-gate 		case 0:
23227c478bd9Sstevel@tonic-gate 		case 1:
23237c478bd9Sstevel@tonic-gate 		case 2:
23247c478bd9Sstevel@tonic-gate 		case 3:
23257c478bd9Sstevel@tonic-gate 		case 4:
23267c478bd9Sstevel@tonic-gate 		case 5:
23277c478bd9Sstevel@tonic-gate 			return ("AMD-K5(r)");
23287c478bd9Sstevel@tonic-gate 		case 6:
23297c478bd9Sstevel@tonic-gate 		case 7:
23307c478bd9Sstevel@tonic-gate 			return ("AMD-K6(r)");
23317c478bd9Sstevel@tonic-gate 		case 8:
23327c478bd9Sstevel@tonic-gate 			return ("AMD-K6(r)-2");
23337c478bd9Sstevel@tonic-gate 		case 9:
23347c478bd9Sstevel@tonic-gate 			return ("AMD-K6(r)-III");
23357c478bd9Sstevel@tonic-gate 		default:
23367c478bd9Sstevel@tonic-gate 			return ("AMD (family 5)");
23377c478bd9Sstevel@tonic-gate 		}
23387c478bd9Sstevel@tonic-gate 	case 6:
23397c478bd9Sstevel@tonic-gate 		switch (cpi->cpi_model) {
23407c478bd9Sstevel@tonic-gate 		case 1:
23417c478bd9Sstevel@tonic-gate 			return ("AMD-K7(tm)");
23427c478bd9Sstevel@tonic-gate 		case 0:
23437c478bd9Sstevel@tonic-gate 		case 2:
23447c478bd9Sstevel@tonic-gate 		case 4:
23457c478bd9Sstevel@tonic-gate 			return ("AMD Athlon(tm)");
23467c478bd9Sstevel@tonic-gate 		case 3:
23477c478bd9Sstevel@tonic-gate 		case 7:
23487c478bd9Sstevel@tonic-gate 			return ("AMD Duron(tm)");
23497c478bd9Sstevel@tonic-gate 		case 6:
23507c478bd9Sstevel@tonic-gate 		case 8:
23517c478bd9Sstevel@tonic-gate 		case 10:
23527c478bd9Sstevel@tonic-gate 			/*
23537c478bd9Sstevel@tonic-gate 			 * Use the L2 cache size to distinguish
23547c478bd9Sstevel@tonic-gate 			 */
23557c478bd9Sstevel@tonic-gate 			return ((cpi->cpi_extd[6].cp_ecx >> 16) >= 256 ?
23567c478bd9Sstevel@tonic-gate 			    "AMD Athlon(tm)" : "AMD Duron(tm)");
23577c478bd9Sstevel@tonic-gate 		default:
23587c478bd9Sstevel@tonic-gate 			return ("AMD (family 6)");
23597c478bd9Sstevel@tonic-gate 		}
23607c478bd9Sstevel@tonic-gate 	default:
23617c478bd9Sstevel@tonic-gate 		break;
23627c478bd9Sstevel@tonic-gate 	}
23637c478bd9Sstevel@tonic-gate 
23647c478bd9Sstevel@tonic-gate 	if (cpi->cpi_family == 0xf && cpi->cpi_model == 5 &&
23657c478bd9Sstevel@tonic-gate 	    cpi->cpi_brandid != 0) {
23667c478bd9Sstevel@tonic-gate 		switch (BITX(cpi->cpi_brandid, 7, 5)) {
23677c478bd9Sstevel@tonic-gate 		case 3:
23687c478bd9Sstevel@tonic-gate 			return ("AMD Opteron(tm) UP 1xx");
23697c478bd9Sstevel@tonic-gate 		case 4:
23707c478bd9Sstevel@tonic-gate 			return ("AMD Opteron(tm) DP 2xx");
23717c478bd9Sstevel@tonic-gate 		case 5:
23727c478bd9Sstevel@tonic-gate 			return ("AMD Opteron(tm) MP 8xx");
23737c478bd9Sstevel@tonic-gate 		default:
23747c478bd9Sstevel@tonic-gate 			return ("AMD Opteron(tm)");
23757c478bd9Sstevel@tonic-gate 		}
23767c478bd9Sstevel@tonic-gate 	}
23777c478bd9Sstevel@tonic-gate 
23787c478bd9Sstevel@tonic-gate 	return (NULL);
23797c478bd9Sstevel@tonic-gate }
23807c478bd9Sstevel@tonic-gate 
23817c478bd9Sstevel@tonic-gate static const char *
23827c478bd9Sstevel@tonic-gate cyrix_cpubrand(struct cpuid_info *cpi, uint_t type)
23837c478bd9Sstevel@tonic-gate {
23847417cfdeSKuriakose Kuruvilla 	if (!is_x86_feature(x86_featureset, X86FSET_CPUID) ||
23857c478bd9Sstevel@tonic-gate 	    cpi->cpi_maxeax < 1 || cpi->cpi_family < 5 ||
23867c478bd9Sstevel@tonic-gate 	    type == X86_TYPE_CYRIX_486)
23877c478bd9Sstevel@tonic-gate 		return ("i486 compatible");
23887c478bd9Sstevel@tonic-gate 
23897c478bd9Sstevel@tonic-gate 	switch (type) {
23907c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_6x86:
23917c478bd9Sstevel@tonic-gate 		return ("Cyrix 6x86");
23927c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_6x86L:
23937c478bd9Sstevel@tonic-gate 		return ("Cyrix 6x86L");
23947c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_6x86MX:
23957c478bd9Sstevel@tonic-gate 		return ("Cyrix 6x86MX");
23967c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_GXm:
23977c478bd9Sstevel@tonic-gate 		return ("Cyrix GXm");
23987c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_MediaGX:
23997c478bd9Sstevel@tonic-gate 		return ("Cyrix MediaGX");
24007c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_MII:
24017c478bd9Sstevel@tonic-gate 		return ("Cyrix M2");
24027c478bd9Sstevel@tonic-gate 	case X86_TYPE_VIA_CYRIX_III:
24037c478bd9Sstevel@tonic-gate 		return ("VIA Cyrix M3");
24047c478bd9Sstevel@tonic-gate 	default:
24057c478bd9Sstevel@tonic-gate 		/*
24067c478bd9Sstevel@tonic-gate 		 * Have another wild guess ..
24077c478bd9Sstevel@tonic-gate 		 */
24087c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 4 && cpi->cpi_model == 9)
24097c478bd9Sstevel@tonic-gate 			return ("Cyrix 5x86");
24107c478bd9Sstevel@tonic-gate 		else if (cpi->cpi_family == 5) {
24117c478bd9Sstevel@tonic-gate 			switch (cpi->cpi_model) {
24127c478bd9Sstevel@tonic-gate 			case 2:
24137c478bd9Sstevel@tonic-gate 				return ("Cyrix 6x86");	/* Cyrix M1 */
24147c478bd9Sstevel@tonic-gate 			case 4:
24157c478bd9Sstevel@tonic-gate 				return ("Cyrix MediaGX");
24167c478bd9Sstevel@tonic-gate 			default:
24177c478bd9Sstevel@tonic-gate 				break;
24187c478bd9Sstevel@tonic-gate 			}
24197c478bd9Sstevel@tonic-gate 		} else if (cpi->cpi_family == 6) {
24207c478bd9Sstevel@tonic-gate 			switch (cpi->cpi_model) {
24217c478bd9Sstevel@tonic-gate 			case 0:
24227c478bd9Sstevel@tonic-gate 				return ("Cyrix 6x86MX"); /* Cyrix M2? */
24237c478bd9Sstevel@tonic-gate 			case 5:
24247c478bd9Sstevel@tonic-gate 			case 6:
24257c478bd9Sstevel@tonic-gate 			case 7:
24267c478bd9Sstevel@tonic-gate 			case 8:
24277c478bd9Sstevel@tonic-gate 			case 9:
24287c478bd9Sstevel@tonic-gate 				return ("VIA C3");
24297c478bd9Sstevel@tonic-gate 			default:
24307c478bd9Sstevel@tonic-gate 				break;
24317c478bd9Sstevel@tonic-gate 			}
24327c478bd9Sstevel@tonic-gate 		}
24337c478bd9Sstevel@tonic-gate 		break;
24347c478bd9Sstevel@tonic-gate 	}
24357c478bd9Sstevel@tonic-gate 	return (NULL);
24367c478bd9Sstevel@tonic-gate }
24377c478bd9Sstevel@tonic-gate 
24387c478bd9Sstevel@tonic-gate /*
24397c478bd9Sstevel@tonic-gate  * This only gets called in the case that the CPU extended
24407c478bd9Sstevel@tonic-gate  * feature brand string (0x80000002, 0x80000003, 0x80000004)
24417c478bd9Sstevel@tonic-gate  * aren't available, or contain null bytes for some reason.
24427c478bd9Sstevel@tonic-gate  */
24437c478bd9Sstevel@tonic-gate static void
24447c478bd9Sstevel@tonic-gate fabricate_brandstr(struct cpuid_info *cpi)
24457c478bd9Sstevel@tonic-gate {
24467c478bd9Sstevel@tonic-gate 	const char *brand = NULL;
24477c478bd9Sstevel@tonic-gate 
24487c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
24497c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
24507c478bd9Sstevel@tonic-gate 		brand = intel_cpubrand(cpi);
24517c478bd9Sstevel@tonic-gate 		break;
24527c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
24537c478bd9Sstevel@tonic-gate 		brand = amd_cpubrand(cpi);
24547c478bd9Sstevel@tonic-gate 		break;
24557c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
24567c478bd9Sstevel@tonic-gate 		brand = cyrix_cpubrand(cpi, x86_type);
24577c478bd9Sstevel@tonic-gate 		break;
24587c478bd9Sstevel@tonic-gate 	case X86_VENDOR_NexGen:
24597c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5 && cpi->cpi_model == 0)
24607c478bd9Sstevel@tonic-gate 			brand = "NexGen Nx586";
24617c478bd9Sstevel@tonic-gate 		break;
24627c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Centaur:
24637c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5)
24647c478bd9Sstevel@tonic-gate 			switch (cpi->cpi_model) {
24657c478bd9Sstevel@tonic-gate 			case 4:
24667c478bd9Sstevel@tonic-gate 				brand = "Centaur C6";
24677c478bd9Sstevel@tonic-gate 				break;
24687c478bd9Sstevel@tonic-gate 			case 8:
24697c478bd9Sstevel@tonic-gate 				brand = "Centaur C2";
24707c478bd9Sstevel@tonic-gate 				break;
24717c478bd9Sstevel@tonic-gate 			case 9:
24727c478bd9Sstevel@tonic-gate 				brand = "Centaur C3";
24737c478bd9Sstevel@tonic-gate 				break;
24747c478bd9Sstevel@tonic-gate 			default:
24757c478bd9Sstevel@tonic-gate 				break;
24767c478bd9Sstevel@tonic-gate 			}
24777c478bd9Sstevel@tonic-gate 		break;
24787c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Rise:
24797c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5 &&
24807c478bd9Sstevel@tonic-gate 		    (cpi->cpi_model == 0 || cpi->cpi_model == 2))
24817c478bd9Sstevel@tonic-gate 			brand = "Rise mP6";
24827c478bd9Sstevel@tonic-gate 		break;
24837c478bd9Sstevel@tonic-gate 	case X86_VENDOR_SiS:
24847c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5 && cpi->cpi_model == 0)
24857c478bd9Sstevel@tonic-gate 			brand = "SiS 55x";
24867c478bd9Sstevel@tonic-gate 		break;
24877c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
24887c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5 && cpi->cpi_model == 4)
24897c478bd9Sstevel@tonic-gate 			brand = "Transmeta Crusoe TM3x00 or TM5x00";
24907c478bd9Sstevel@tonic-gate 		break;
24917c478bd9Sstevel@tonic-gate 	case X86_VENDOR_NSC:
24927c478bd9Sstevel@tonic-gate 	case X86_VENDOR_UMC:
24937c478bd9Sstevel@tonic-gate 	default:
24947c478bd9Sstevel@tonic-gate 		break;
24957c478bd9Sstevel@tonic-gate 	}
24967c478bd9Sstevel@tonic-gate 	if (brand) {
24977c478bd9Sstevel@tonic-gate 		(void) strcpy((char *)cpi->cpi_brandstr, brand);
24987c478bd9Sstevel@tonic-gate 		return;
24997c478bd9Sstevel@tonic-gate 	}
25007c478bd9Sstevel@tonic-gate 
25017c478bd9Sstevel@tonic-gate 	/*
25027c478bd9Sstevel@tonic-gate 	 * If all else fails ...
25037c478bd9Sstevel@tonic-gate 	 */
25047c478bd9Sstevel@tonic-gate 	(void) snprintf(cpi->cpi_brandstr, sizeof (cpi->cpi_brandstr),
25057c478bd9Sstevel@tonic-gate 	    "%s %d.%d.%d", cpi->cpi_vendorstr, cpi->cpi_family,
25067c478bd9Sstevel@tonic-gate 	    cpi->cpi_model, cpi->cpi_step);
25077c478bd9Sstevel@tonic-gate }
25087c478bd9Sstevel@tonic-gate 
25097c478bd9Sstevel@tonic-gate /*
25107c478bd9Sstevel@tonic-gate  * This routine is called just after kernel memory allocation
25117c478bd9Sstevel@tonic-gate  * becomes available on cpu0, and as part of mp_startup() on
25127c478bd9Sstevel@tonic-gate  * the other cpus.
25137c478bd9Sstevel@tonic-gate  *
2514d129bde2Sesaxe  * Fixup the brand string, and collect any information from cpuid
251579ec9da8SYuri Pankov  * that requires dynamically allocated storage to represent.
25167c478bd9Sstevel@tonic-gate  */
25177c478bd9Sstevel@tonic-gate /*ARGSUSED*/
25187c478bd9Sstevel@tonic-gate void
25197c478bd9Sstevel@tonic-gate cpuid_pass3(cpu_t *cpu)
25207c478bd9Sstevel@tonic-gate {
2521d129bde2Sesaxe 	int	i, max, shft, level, size;
2522d129bde2Sesaxe 	struct cpuid_regs regs;
2523d129bde2Sesaxe 	struct cpuid_regs *cp;
25247c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
25257c478bd9Sstevel@tonic-gate 
25267c478bd9Sstevel@tonic-gate 	ASSERT(cpi->cpi_pass == 2);
25277c478bd9Sstevel@tonic-gate 
2528d129bde2Sesaxe 	/*
2529d129bde2Sesaxe 	 * Function 4: Deterministic cache parameters
2530d129bde2Sesaxe 	 *
2531d129bde2Sesaxe 	 * Take this opportunity to detect the number of threads
2532d129bde2Sesaxe 	 * sharing the last level cache, and construct a corresponding
2533d129bde2Sesaxe 	 * cache id. The respective cpuid_info members are initialized
2534d129bde2Sesaxe 	 * to the default case of "no last level cache sharing".
2535d129bde2Sesaxe 	 */
2536d129bde2Sesaxe 	cpi->cpi_ncpu_shr_last_cache = 1;
2537d129bde2Sesaxe 	cpi->cpi_last_lvl_cacheid = cpu->cpu_id;
2538d129bde2Sesaxe 
2539d129bde2Sesaxe 	if (cpi->cpi_maxeax >= 4 && cpi->cpi_vendor == X86_VENDOR_Intel) {
2540d129bde2Sesaxe 
2541d129bde2Sesaxe 		/*
2542d129bde2Sesaxe 		 * Find the # of elements (size) returned by fn 4, and along
2543d129bde2Sesaxe 		 * the way detect last level cache sharing details.
2544d129bde2Sesaxe 		 */
2545d129bde2Sesaxe 		bzero(&regs, sizeof (regs));
2546d129bde2Sesaxe 		cp = &regs;
2547d129bde2Sesaxe 		for (i = 0, max = 0; i < CPI_FN4_ECX_MAX; i++) {
2548d129bde2Sesaxe 			cp->cp_eax = 4;
2549d129bde2Sesaxe 			cp->cp_ecx = i;
2550d129bde2Sesaxe 
2551d129bde2Sesaxe 			(void) __cpuid_insn(cp);
2552d129bde2Sesaxe 
2553d129bde2Sesaxe 			if (CPI_CACHE_TYPE(cp) == 0)
2554d129bde2Sesaxe 				break;
2555d129bde2Sesaxe 			level = CPI_CACHE_LVL(cp);
2556d129bde2Sesaxe 			if (level > max) {
2557d129bde2Sesaxe 				max = level;
2558d129bde2Sesaxe 				cpi->cpi_ncpu_shr_last_cache =
2559d129bde2Sesaxe 				    CPI_NTHR_SHR_CACHE(cp) + 1;
2560d129bde2Sesaxe 			}
2561d129bde2Sesaxe 		}
2562d129bde2Sesaxe 		cpi->cpi_std_4_size = size = i;
2563d129bde2Sesaxe 
2564d129bde2Sesaxe 		/*
2565d129bde2Sesaxe 		 * Allocate the cpi_std_4 array. The first element
2566d129bde2Sesaxe 		 * references the regs for fn 4, %ecx == 0, which
2567d129bde2Sesaxe 		 * cpuid_pass2() stashed in cpi->cpi_std[4].
2568d129bde2Sesaxe 		 */
2569d129bde2Sesaxe 		if (size > 0) {
2570d129bde2Sesaxe 			cpi->cpi_std_4 =
2571d129bde2Sesaxe 			    kmem_alloc(size * sizeof (cp), KM_SLEEP);
2572d129bde2Sesaxe 			cpi->cpi_std_4[0] = &cpi->cpi_std[4];
2573d129bde2Sesaxe 
2574d129bde2Sesaxe 			/*
2575d129bde2Sesaxe 			 * Allocate storage to hold the additional regs
2576d129bde2Sesaxe 			 * for function 4, %ecx == 1 .. cpi_std_4_size.
2577d129bde2Sesaxe 			 *
2578d129bde2Sesaxe 			 * The regs for fn 4, %ecx == 0 has already
2579d129bde2Sesaxe 			 * been allocated as indicated above.
2580d129bde2Sesaxe 			 */
2581d129bde2Sesaxe 			for (i = 1; i < size; i++) {
2582d129bde2Sesaxe 				cp = cpi->cpi_std_4[i] =
2583d129bde2Sesaxe 				    kmem_zalloc(sizeof (regs), KM_SLEEP);
2584d129bde2Sesaxe 				cp->cp_eax = 4;
2585d129bde2Sesaxe 				cp->cp_ecx = i;
2586d129bde2Sesaxe 
2587d129bde2Sesaxe 				(void) __cpuid_insn(cp);
2588d129bde2Sesaxe 			}
2589d129bde2Sesaxe 		}
2590d129bde2Sesaxe 		/*
2591d129bde2Sesaxe 		 * Determine the number of bits needed to represent
2592d129bde2Sesaxe 		 * the number of CPUs sharing the last level cache.
2593d129bde2Sesaxe 		 *
2594d129bde2Sesaxe 		 * Shift off that number of bits from the APIC id to
2595d129bde2Sesaxe 		 * derive the cache id.
2596d129bde2Sesaxe 		 */
2597d129bde2Sesaxe 		shft = 0;
2598d129bde2Sesaxe 		for (i = 1; i < cpi->cpi_ncpu_shr_last_cache; i <<= 1)
2599d129bde2Sesaxe 			shft++;
2600b6917abeSmishra 		cpi->cpi_last_lvl_cacheid = cpi->cpi_apicid >> shft;
2601d129bde2Sesaxe 	}
2602d129bde2Sesaxe 
2603d129bde2Sesaxe 	/*
2604d129bde2Sesaxe 	 * Now fixup the brand string
2605d129bde2Sesaxe 	 */
26067c478bd9Sstevel@tonic-gate 	if ((cpi->cpi_xmaxeax & 0x80000000) == 0) {
26077c478bd9Sstevel@tonic-gate 		fabricate_brandstr(cpi);
2608d129bde2Sesaxe 	} else {
26097c478bd9Sstevel@tonic-gate 
26107c478bd9Sstevel@tonic-gate 		/*
26117c478bd9Sstevel@tonic-gate 		 * If we successfully extracted a brand string from the cpuid
26127c478bd9Sstevel@tonic-gate 		 * instruction, clean it up by removing leading spaces and
26137c478bd9Sstevel@tonic-gate 		 * similar junk.
26147c478bd9Sstevel@tonic-gate 		 */
26157c478bd9Sstevel@tonic-gate 		if (cpi->cpi_brandstr[0]) {
26167c478bd9Sstevel@tonic-gate 			size_t maxlen = sizeof (cpi->cpi_brandstr);
26177c478bd9Sstevel@tonic-gate 			char *src, *dst;
26187c478bd9Sstevel@tonic-gate 
26197c478bd9Sstevel@tonic-gate 			dst = src = (char *)cpi->cpi_brandstr;
26207c478bd9Sstevel@tonic-gate 			src[maxlen - 1] = '\0';
26217c478bd9Sstevel@tonic-gate 			/*
26227c478bd9Sstevel@tonic-gate 			 * strip leading spaces
26237c478bd9Sstevel@tonic-gate 			 */
26247c478bd9Sstevel@tonic-gate 			while (*src == ' ')
26257c478bd9Sstevel@tonic-gate 				src++;
26267c478bd9Sstevel@tonic-gate 			/*
26277c478bd9Sstevel@tonic-gate 			 * Remove any 'Genuine' or "Authentic" prefixes
26287c478bd9Sstevel@tonic-gate 			 */
26297c478bd9Sstevel@tonic-gate 			if (strncmp(src, "Genuine ", 8) == 0)
26307c478bd9Sstevel@tonic-gate 				src += 8;
26317c478bd9Sstevel@tonic-gate 			if (strncmp(src, "Authentic ", 10) == 0)
26327c478bd9Sstevel@tonic-gate 				src += 10;
26337c478bd9Sstevel@tonic-gate 
26347c478bd9Sstevel@tonic-gate 			/*
26357c478bd9Sstevel@tonic-gate 			 * Now do an in-place copy.
26367c478bd9Sstevel@tonic-gate 			 * Map (R) to (r) and (TM) to (tm).
26377c478bd9Sstevel@tonic-gate 			 * The era of teletypes is long gone, and there's
26387c478bd9Sstevel@tonic-gate 			 * -really- no need to shout.
26397c478bd9Sstevel@tonic-gate 			 */
26407c478bd9Sstevel@tonic-gate 			while (*src != '\0') {
26417c478bd9Sstevel@tonic-gate 				if (src[0] == '(') {
26427c478bd9Sstevel@tonic-gate 					if (strncmp(src + 1, "R)", 2) == 0) {
26437c478bd9Sstevel@tonic-gate 						(void) strncpy(dst, "(r)", 3);
26447c478bd9Sstevel@tonic-gate 						src += 3;
26457c478bd9Sstevel@tonic-gate 						dst += 3;
26467c478bd9Sstevel@tonic-gate 						continue;
26477c478bd9Sstevel@tonic-gate 					}
26487c478bd9Sstevel@tonic-gate 					if (strncmp(src + 1, "TM)", 3) == 0) {
26497c478bd9Sstevel@tonic-gate 						(void) strncpy(dst, "(tm)", 4);
26507c478bd9Sstevel@tonic-gate 						src += 4;
26517c478bd9Sstevel@tonic-gate 						dst += 4;
26527c478bd9Sstevel@tonic-gate 						continue;
26537c478bd9Sstevel@tonic-gate 					}
26547c478bd9Sstevel@tonic-gate 				}
26557c478bd9Sstevel@tonic-gate 				*dst++ = *src++;
26567c478bd9Sstevel@tonic-gate 			}
26577c478bd9Sstevel@tonic-gate 			*dst = '\0';
26587c478bd9Sstevel@tonic-gate 
26597c478bd9Sstevel@tonic-gate 			/*
26607c478bd9Sstevel@tonic-gate 			 * Finally, remove any trailing spaces
26617c478bd9Sstevel@tonic-gate 			 */
26627c478bd9Sstevel@tonic-gate 			while (--dst > cpi->cpi_brandstr)
26637c478bd9Sstevel@tonic-gate 				if (*dst == ' ')
26647c478bd9Sstevel@tonic-gate 					*dst = '\0';
26657c478bd9Sstevel@tonic-gate 				else
26667c478bd9Sstevel@tonic-gate 					break;
26677c478bd9Sstevel@tonic-gate 		} else
26687c478bd9Sstevel@tonic-gate 			fabricate_brandstr(cpi);
2669d129bde2Sesaxe 	}
26707c478bd9Sstevel@tonic-gate 	cpi->cpi_pass = 3;
26717c478bd9Sstevel@tonic-gate }
26727c478bd9Sstevel@tonic-gate 
26737c478bd9Sstevel@tonic-gate /*
26747c478bd9Sstevel@tonic-gate  * This routine is called out of bind_hwcap() much later in the life
26757c478bd9Sstevel@tonic-gate  * of the kernel (post_startup()).  The job of this routine is to resolve
26767c478bd9Sstevel@tonic-gate  * the hardware feature support and kernel support for those features into
26777c478bd9Sstevel@tonic-gate  * what we're actually going to tell applications via the aux vector.
26787c478bd9Sstevel@tonic-gate  */
2679ebb8ac07SRobert Mustacchi void
2680ebb8ac07SRobert Mustacchi cpuid_pass4(cpu_t *cpu, uint_t *hwcap_out)
26817c478bd9Sstevel@tonic-gate {
26827c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi;
2683ebb8ac07SRobert Mustacchi 	uint_t hwcap_flags = 0, hwcap_flags_2 = 0;
26847c478bd9Sstevel@tonic-gate 
26857c478bd9Sstevel@tonic-gate 	if (cpu == NULL)
26867c478bd9Sstevel@tonic-gate 		cpu = CPU;
26877c478bd9Sstevel@tonic-gate 	cpi = cpu->cpu_m.mcpu_cpi;
26887c478bd9Sstevel@tonic-gate 
26897c478bd9Sstevel@tonic-gate 	ASSERT(cpi->cpi_pass == 3);
26907c478bd9Sstevel@tonic-gate 
26917c478bd9Sstevel@tonic-gate 	if (cpi->cpi_maxeax >= 1) {
26927c478bd9Sstevel@tonic-gate 		uint32_t *edx = &cpi->cpi_support[STD_EDX_FEATURES];
26937c478bd9Sstevel@tonic-gate 		uint32_t *ecx = &cpi->cpi_support[STD_ECX_FEATURES];
2694245ac945SRobert Mustacchi 		uint32_t *ebx = &cpi->cpi_support[STD_EBX_FEATURES];
26957c478bd9Sstevel@tonic-gate 
26967c478bd9Sstevel@tonic-gate 		*edx = CPI_FEATURES_EDX(cpi);
26977c478bd9Sstevel@tonic-gate 		*ecx = CPI_FEATURES_ECX(cpi);
2698245ac945SRobert Mustacchi 		*ebx = CPI_FEATURES_7_0_EBX(cpi);
26997c478bd9Sstevel@tonic-gate 
27007c478bd9Sstevel@tonic-gate 		/*
27017c478bd9Sstevel@tonic-gate 		 * [these require explicit kernel support]
27027c478bd9Sstevel@tonic-gate 		 */
27037417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_SEP))
27047c478bd9Sstevel@tonic-gate 			*edx &= ~CPUID_INTC_EDX_SEP;
27057c478bd9Sstevel@tonic-gate 
27067417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_SSE))
27077c478bd9Sstevel@tonic-gate 			*edx &= ~(CPUID_INTC_EDX_FXSR|CPUID_INTC_EDX_SSE);
27087417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_SSE2))
27097c478bd9Sstevel@tonic-gate 			*edx &= ~CPUID_INTC_EDX_SSE2;
27107c478bd9Sstevel@tonic-gate 
27117417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_HTT))
27127c478bd9Sstevel@tonic-gate 			*edx &= ~CPUID_INTC_EDX_HTT;
27137c478bd9Sstevel@tonic-gate 
27147417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_SSE3))
27157c478bd9Sstevel@tonic-gate 			*ecx &= ~CPUID_INTC_ECX_SSE3;
27167c478bd9Sstevel@tonic-gate 
27177417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_SSSE3))
2718d0f8ff6eSkk208521 			*ecx &= ~CPUID_INTC_ECX_SSSE3;
27197417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_SSE4_1))
2720d0f8ff6eSkk208521 			*ecx &= ~CPUID_INTC_ECX_SSE4_1;
27217417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_SSE4_2))
2722d0f8ff6eSkk208521 			*ecx &= ~CPUID_INTC_ECX_SSE4_2;
27237417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_AES))
2724a50a8b93SKuriakose Kuruvilla 			*ecx &= ~CPUID_INTC_ECX_AES;
27257417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_PCLMULQDQ))
27267417cfdeSKuriakose Kuruvilla 			*ecx &= ~CPUID_INTC_ECX_PCLMULQDQ;
27277af88ac7SKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_XSAVE))
27287af88ac7SKuriakose Kuruvilla 			*ecx &= ~(CPUID_INTC_ECX_XSAVE |
27297af88ac7SKuriakose Kuruvilla 			    CPUID_INTC_ECX_OSXSAVE);
27307af88ac7SKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_AVX))
27317af88ac7SKuriakose Kuruvilla 			*ecx &= ~CPUID_INTC_ECX_AVX;
2732ebb8ac07SRobert Mustacchi 		if (!is_x86_feature(x86_featureset, X86FSET_F16C))
2733ebb8ac07SRobert Mustacchi 			*ecx &= ~CPUID_INTC_ECX_F16C;
2734245ac945SRobert Mustacchi 		if (!is_x86_feature(x86_featureset, X86FSET_FMA))
2735245ac945SRobert Mustacchi 			*ecx &= ~CPUID_INTC_ECX_FMA;
2736245ac945SRobert Mustacchi 		if (!is_x86_feature(x86_featureset, X86FSET_BMI1))
2737245ac945SRobert Mustacchi 			*ebx &= ~CPUID_INTC_EBX_7_0_BMI1;
2738245ac945SRobert Mustacchi 		if (!is_x86_feature(x86_featureset, X86FSET_BMI2))
2739245ac945SRobert Mustacchi 			*ebx &= ~CPUID_INTC_EBX_7_0_BMI2;
2740245ac945SRobert Mustacchi 		if (!is_x86_feature(x86_featureset, X86FSET_AVX2))
2741245ac945SRobert Mustacchi 			*ebx &= ~CPUID_INTC_EBX_7_0_AVX2;
2742a3623a38SRobert Mustacchi 		if (!is_x86_feature(x86_featureset, X86FSET_RDSEED))
2743a3623a38SRobert Mustacchi 			*ebx &= ~CPUID_INTC_EBX_7_0_RDSEED;
2744a3623a38SRobert Mustacchi 		if (!is_x86_feature(x86_featureset, X86FSET_ADX))
2745a3623a38SRobert Mustacchi 			*ebx &= ~CPUID_INTC_EBX_7_0_ADX;
2746d0f8ff6eSkk208521 
27477c478bd9Sstevel@tonic-gate 		/*
27487c478bd9Sstevel@tonic-gate 		 * [no explicit support required beyond x87 fp context]
27497c478bd9Sstevel@tonic-gate 		 */
27507c478bd9Sstevel@tonic-gate 		if (!fpu_exists)
27517c478bd9Sstevel@tonic-gate 			*edx &= ~(CPUID_INTC_EDX_FPU | CPUID_INTC_EDX_MMX);
27527c478bd9Sstevel@tonic-gate 
27537c478bd9Sstevel@tonic-gate 		/*
27547c478bd9Sstevel@tonic-gate 		 * Now map the supported feature vector to things that we
27557c478bd9Sstevel@tonic-gate 		 * think userland will care about.
27567c478bd9Sstevel@tonic-gate 		 */
27577c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_SEP)
27587c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_SEP;
27597c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_SSE)
27607c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_FXSR | AV_386_SSE;
27617c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_SSE2)
27627c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_SSE2;
27637c478bd9Sstevel@tonic-gate 		if (*ecx & CPUID_INTC_ECX_SSE3)
27647c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_SSE3;
2765d0f8ff6eSkk208521 		if (*ecx & CPUID_INTC_ECX_SSSE3)
2766d0f8ff6eSkk208521 			hwcap_flags |= AV_386_SSSE3;
2767d0f8ff6eSkk208521 		if (*ecx & CPUID_INTC_ECX_SSE4_1)
2768d0f8ff6eSkk208521 			hwcap_flags |= AV_386_SSE4_1;
2769d0f8ff6eSkk208521 		if (*ecx & CPUID_INTC_ECX_SSE4_2)
2770d0f8ff6eSkk208521 			hwcap_flags |= AV_386_SSE4_2;
27715087e485SKrishnendu Sadhukhan - Sun Microsystems 		if (*ecx & CPUID_INTC_ECX_MOVBE)
27725087e485SKrishnendu Sadhukhan - Sun Microsystems 			hwcap_flags |= AV_386_MOVBE;
2773a50a8b93SKuriakose Kuruvilla 		if (*ecx & CPUID_INTC_ECX_AES)
2774a50a8b93SKuriakose Kuruvilla 			hwcap_flags |= AV_386_AES;
2775a50a8b93SKuriakose Kuruvilla 		if (*ecx & CPUID_INTC_ECX_PCLMULQDQ)
2776a50a8b93SKuriakose Kuruvilla 			hwcap_flags |= AV_386_PCLMULQDQ;
27777af88ac7SKuriakose Kuruvilla 		if ((*ecx & CPUID_INTC_ECX_XSAVE) &&
2778f3390f39SRobert Mustacchi 		    (*ecx & CPUID_INTC_ECX_OSXSAVE)) {
27797af88ac7SKuriakose Kuruvilla 			hwcap_flags |= AV_386_XSAVE;
2780f3390f39SRobert Mustacchi 
2781ebb8ac07SRobert Mustacchi 			if (*ecx & CPUID_INTC_ECX_AVX) {
2782f3390f39SRobert Mustacchi 				hwcap_flags |= AV_386_AVX;
2783ebb8ac07SRobert Mustacchi 				if (*ecx & CPUID_INTC_ECX_F16C)
2784ebb8ac07SRobert Mustacchi 					hwcap_flags_2 |= AV_386_2_F16C;
2785245ac945SRobert Mustacchi 				if (*ecx & CPUID_INTC_ECX_FMA)
2786245ac945SRobert Mustacchi 					hwcap_flags_2 |= AV_386_2_FMA;
2787245ac945SRobert Mustacchi 				if (*ebx & CPUID_INTC_EBX_7_0_BMI1)
2788245ac945SRobert Mustacchi 					hwcap_flags_2 |= AV_386_2_BMI1;
2789245ac945SRobert Mustacchi 				if (*ebx & CPUID_INTC_EBX_7_0_BMI2)
2790245ac945SRobert Mustacchi 					hwcap_flags_2 |= AV_386_2_BMI2;
2791245ac945SRobert Mustacchi 				if (*ebx & CPUID_INTC_EBX_7_0_AVX2)
2792245ac945SRobert Mustacchi 					hwcap_flags_2 |= AV_386_2_AVX2;
2793ebb8ac07SRobert Mustacchi 			}
2794f3390f39SRobert Mustacchi 		}
2795faa20166SBryan Cantrill 		if (*ecx & CPUID_INTC_ECX_VMX)
2796faa20166SBryan Cantrill 			hwcap_flags |= AV_386_VMX;
2797f8801251Skk208521 		if (*ecx & CPUID_INTC_ECX_POPCNT)
2798f8801251Skk208521 			hwcap_flags |= AV_386_POPCNT;
27997c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_FPU)
28007c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_FPU;
28017c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_MMX)
28027c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_MMX;
28037c478bd9Sstevel@tonic-gate 
28047c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_TSC)
28057c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_TSC;
28067c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_CX8)
28077c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_CX8;
28087c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_CMOV)
28097c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_CMOV;
28107c478bd9Sstevel@tonic-gate 		if (*ecx & CPUID_INTC_ECX_CX16)
28117c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_CX16;
2812ebb8ac07SRobert Mustacchi 
2813ebb8ac07SRobert Mustacchi 		if (*ecx & CPUID_INTC_ECX_RDRAND)
2814ebb8ac07SRobert Mustacchi 			hwcap_flags_2 |= AV_386_2_RDRAND;
2815a3623a38SRobert Mustacchi 		if (*ebx & CPUID_INTC_EBX_7_0_ADX)
2816a3623a38SRobert Mustacchi 			hwcap_flags_2 |= AV_386_2_ADX;
2817a3623a38SRobert Mustacchi 		if (*ebx & CPUID_INTC_EBX_7_0_RDSEED)
2818a3623a38SRobert Mustacchi 			hwcap_flags_2 |= AV_386_2_RDSEED;
2819b8f64308SRobert Mustacchi 		if (*ebx & CPUID_INTC_EBX_7_0_SHA)
2820b8f64308SRobert Mustacchi 			hwcap_flags_2 |= AV_386_2_SHA;
2821a3623a38SRobert Mustacchi 
28227c478bd9Sstevel@tonic-gate 	}
28237c478bd9Sstevel@tonic-gate 
28247c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax < 0x80000001)
28257c478bd9Sstevel@tonic-gate 		goto pass4_done;
28267c478bd9Sstevel@tonic-gate 
28277c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
28288949bcd6Sandrei 		struct cpuid_regs cp;
2829ae115bc7Smrj 		uint32_t *edx, *ecx;
28307c478bd9Sstevel@tonic-gate 
2831ae115bc7Smrj 	case X86_VENDOR_Intel:
2832ae115bc7Smrj 		/*
2833ae115bc7Smrj 		 * Seems like Intel duplicated what we necessary
2834ae115bc7Smrj 		 * here to make the initial crop of 64-bit OS's work.
2835ae115bc7Smrj 		 * Hopefully, those are the only "extended" bits
2836ae115bc7Smrj 		 * they'll add.
2837ae115bc7Smrj 		 */
2838ae115bc7Smrj 		/*FALLTHROUGH*/
2839ae115bc7Smrj 
28407c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
28417c478bd9Sstevel@tonic-gate 		edx = &cpi->cpi_support[AMD_EDX_FEATURES];
2842ae115bc7Smrj 		ecx = &cpi->cpi_support[AMD_ECX_FEATURES];
28437c478bd9Sstevel@tonic-gate 
28447c478bd9Sstevel@tonic-gate 		*edx = CPI_FEATURES_XTD_EDX(cpi);
2845ae115bc7Smrj 		*ecx = CPI_FEATURES_XTD_ECX(cpi);
2846ae115bc7Smrj 
2847ae115bc7Smrj 		/*
2848ae115bc7Smrj 		 * [these features require explicit kernel support]
2849ae115bc7Smrj 		 */
2850ae115bc7Smrj 		switch (cpi->cpi_vendor) {
2851ae115bc7Smrj 		case X86_VENDOR_Intel:
28527417cfdeSKuriakose Kuruvilla 			if (!is_x86_feature(x86_featureset, X86FSET_TSCP))
2853d36ea5d8Ssudheer 				*edx &= ~CPUID_AMD_EDX_TSCP;
2854ae115bc7Smrj 			break;
2855ae115bc7Smrj 
2856ae115bc7Smrj 		case X86_VENDOR_AMD:
28577417cfdeSKuriakose Kuruvilla 			if (!is_x86_feature(x86_featureset, X86FSET_TSCP))
2858ae115bc7Smrj 				*edx &= ~CPUID_AMD_EDX_TSCP;
28597417cfdeSKuriakose Kuruvilla 			if (!is_x86_feature(x86_featureset, X86FSET_SSE4A))
2860f8801251Skk208521 				*ecx &= ~CPUID_AMD_ECX_SSE4A;
2861ae115bc7Smrj 			break;
2862ae115bc7Smrj 
2863ae115bc7Smrj 		default:
2864ae115bc7Smrj 			break;
2865ae115bc7Smrj 		}
28667c478bd9Sstevel@tonic-gate 
28677c478bd9Sstevel@tonic-gate 		/*
28687c478bd9Sstevel@tonic-gate 		 * [no explicit support required beyond
28697c478bd9Sstevel@tonic-gate 		 * x87 fp context and exception handlers]
28707c478bd9Sstevel@tonic-gate 		 */
28717c478bd9Sstevel@tonic-gate 		if (!fpu_exists)
28727c478bd9Sstevel@tonic-gate 			*edx &= ~(CPUID_AMD_EDX_MMXamd |
28737c478bd9Sstevel@tonic-gate 			    CPUID_AMD_EDX_3DNow | CPUID_AMD_EDX_3DNowx);
28747c478bd9Sstevel@tonic-gate 
28757417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_NX))
28767c478bd9Sstevel@tonic-gate 			*edx &= ~CPUID_AMD_EDX_NX;
2877ae115bc7Smrj #if !defined(__amd64)
28787c478bd9Sstevel@tonic-gate 		*edx &= ~CPUID_AMD_EDX_LM;
28797c478bd9Sstevel@tonic-gate #endif
28807c478bd9Sstevel@tonic-gate 		/*
28817c478bd9Sstevel@tonic-gate 		 * Now map the supported feature vector to
28827c478bd9Sstevel@tonic-gate 		 * things that we think userland will care about.
28837c478bd9Sstevel@tonic-gate 		 */
2884ae115bc7Smrj #if defined(__amd64)
28857c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_AMD_EDX_SYSC)
28867c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_AMD_SYSC;
2887ae115bc7Smrj #endif
28887c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_AMD_EDX_MMXamd)
28897c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_AMD_MMX;
28907c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_AMD_EDX_3DNow)
28917c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_AMD_3DNow;
28927c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_AMD_EDX_3DNowx)
28937c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_AMD_3DNowx;
2894faa20166SBryan Cantrill 		if (*ecx & CPUID_AMD_ECX_SVM)
2895faa20166SBryan Cantrill 			hwcap_flags |= AV_386_AMD_SVM;
2896ae115bc7Smrj 
2897ae115bc7Smrj 		switch (cpi->cpi_vendor) {
2898ae115bc7Smrj 		case X86_VENDOR_AMD:
2899ae115bc7Smrj 			if (*edx & CPUID_AMD_EDX_TSCP)
2900ae115bc7Smrj 				hwcap_flags |= AV_386_TSCP;
2901ae115bc7Smrj 			if (*ecx & CPUID_AMD_ECX_AHF64)
2902ae115bc7Smrj 				hwcap_flags |= AV_386_AHF;
2903f8801251Skk208521 			if (*ecx & CPUID_AMD_ECX_SSE4A)
2904f8801251Skk208521 				hwcap_flags |= AV_386_AMD_SSE4A;
2905f8801251Skk208521 			if (*ecx & CPUID_AMD_ECX_LZCNT)
2906f8801251Skk208521 				hwcap_flags |= AV_386_AMD_LZCNT;
2907ae115bc7Smrj 			break;
2908ae115bc7Smrj 
2909ae115bc7Smrj 		case X86_VENDOR_Intel:
2910d36ea5d8Ssudheer 			if (*edx & CPUID_AMD_EDX_TSCP)
2911d36ea5d8Ssudheer 				hwcap_flags |= AV_386_TSCP;
2912ae115bc7Smrj 			/*
2913ae115bc7Smrj 			 * Aarrgh.
2914ae115bc7Smrj 			 * Intel uses a different bit in the same word.
2915ae115bc7Smrj 			 */
2916ae115bc7Smrj 			if (*ecx & CPUID_INTC_ECX_AHF64)
2917ae115bc7Smrj 				hwcap_flags |= AV_386_AHF;
2918ae115bc7Smrj 			break;
2919ae115bc7Smrj 
2920ae115bc7Smrj 		default:
2921ae115bc7Smrj 			break;
2922ae115bc7Smrj 		}
29237c478bd9Sstevel@tonic-gate 		break;
29247c478bd9Sstevel@tonic-gate 
29257c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
29268949bcd6Sandrei 		cp.cp_eax = 0x80860001;
29278949bcd6Sandrei 		(void) __cpuid_insn(&cp);
29288949bcd6Sandrei 		cpi->cpi_support[TM_EDX_FEATURES] = cp.cp_edx;
29297c478bd9Sstevel@tonic-gate 		break;
29307c478bd9Sstevel@tonic-gate 
29317c478bd9Sstevel@tonic-gate 	default:
29327c478bd9Sstevel@tonic-gate 		break;
29337c478bd9Sstevel@tonic-gate 	}
29347c478bd9Sstevel@tonic-gate 
29357c478bd9Sstevel@tonic-gate pass4_done:
29367c478bd9Sstevel@tonic-gate 	cpi->cpi_pass = 4;
2937ebb8ac07SRobert Mustacchi 	if (hwcap_out != NULL) {
2938ebb8ac07SRobert Mustacchi 		hwcap_out[0] = hwcap_flags;
2939ebb8ac07SRobert Mustacchi 		hwcap_out[1] = hwcap_flags_2;
2940ebb8ac07SRobert Mustacchi 	}
29417c478bd9Sstevel@tonic-gate }
29427c478bd9Sstevel@tonic-gate 
29437c478bd9Sstevel@tonic-gate 
29447c478bd9Sstevel@tonic-gate /*
29457c478bd9Sstevel@tonic-gate  * Simulate the cpuid instruction using the data we previously
29467c478bd9Sstevel@tonic-gate  * captured about this CPU.  We try our best to return the truth
29477c478bd9Sstevel@tonic-gate  * about the hardware, independently of kernel support.
29487c478bd9Sstevel@tonic-gate  */
29497c478bd9Sstevel@tonic-gate uint32_t
29508949bcd6Sandrei cpuid_insn(cpu_t *cpu, struct cpuid_regs *cp)
29517c478bd9Sstevel@tonic-gate {
29527c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi;
29538949bcd6Sandrei 	struct cpuid_regs *xcp;
29547c478bd9Sstevel@tonic-gate 
29557c478bd9Sstevel@tonic-gate 	if (cpu == NULL)
29567c478bd9Sstevel@tonic-gate 		cpu = CPU;
29577c478bd9Sstevel@tonic-gate 	cpi = cpu->cpu_m.mcpu_cpi;
29587c478bd9Sstevel@tonic-gate 
29597c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 3));
29607c478bd9Sstevel@tonic-gate 
29617c478bd9Sstevel@tonic-gate 	/*
29627c478bd9Sstevel@tonic-gate 	 * CPUID data is cached in two separate places: cpi_std for standard
29637c478bd9Sstevel@tonic-gate 	 * CPUID functions, and cpi_extd for extended CPUID functions.
29647c478bd9Sstevel@tonic-gate 	 */
29658949bcd6Sandrei 	if (cp->cp_eax <= cpi->cpi_maxeax && cp->cp_eax < NMAX_CPI_STD)
29668949bcd6Sandrei 		xcp = &cpi->cpi_std[cp->cp_eax];
29678949bcd6Sandrei 	else if (cp->cp_eax >= 0x80000000 && cp->cp_eax <= cpi->cpi_xmaxeax &&
29688949bcd6Sandrei 	    cp->cp_eax < 0x80000000 + NMAX_CPI_EXTD)
29698949bcd6Sandrei 		xcp = &cpi->cpi_extd[cp->cp_eax - 0x80000000];
29707c478bd9Sstevel@tonic-gate 	else
29717c478bd9Sstevel@tonic-gate 		/*
29727c478bd9Sstevel@tonic-gate 		 * The caller is asking for data from an input parameter which
29737c478bd9Sstevel@tonic-gate 		 * the kernel has not cached.  In this case we go fetch from
29747c478bd9Sstevel@tonic-gate 		 * the hardware and return the data directly to the user.
29757c478bd9Sstevel@tonic-gate 		 */
29768949bcd6Sandrei 		return (__cpuid_insn(cp));
29778949bcd6Sandrei 
29788949bcd6Sandrei 	cp->cp_eax = xcp->cp_eax;
29798949bcd6Sandrei 	cp->cp_ebx = xcp->cp_ebx;
29808949bcd6Sandrei 	cp->cp_ecx = xcp->cp_ecx;
29818949bcd6Sandrei 	cp->cp_edx = xcp->cp_edx;
29827c478bd9Sstevel@tonic-gate 	return (cp->cp_eax);
29837c478bd9Sstevel@tonic-gate }
29847c478bd9Sstevel@tonic-gate 
29857c478bd9Sstevel@tonic-gate int
29867c478bd9Sstevel@tonic-gate cpuid_checkpass(cpu_t *cpu, int pass)
29877c478bd9Sstevel@tonic-gate {
29887c478bd9Sstevel@tonic-gate 	return (cpu != NULL && cpu->cpu_m.mcpu_cpi != NULL &&
29897c478bd9Sstevel@tonic-gate 	    cpu->cpu_m.mcpu_cpi->cpi_pass >= pass);
29907c478bd9Sstevel@tonic-gate }
29917c478bd9Sstevel@tonic-gate 
29927c478bd9Sstevel@tonic-gate int
29937c478bd9Sstevel@tonic-gate cpuid_getbrandstr(cpu_t *cpu, char *s, size_t n)
29947c478bd9Sstevel@tonic-gate {
29957c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 3));
29967c478bd9Sstevel@tonic-gate 
29977c478bd9Sstevel@tonic-gate 	return (snprintf(s, n, "%s", cpu->cpu_m.mcpu_cpi->cpi_brandstr));
29987c478bd9Sstevel@tonic-gate }
29997c478bd9Sstevel@tonic-gate 
30007c478bd9Sstevel@tonic-gate int
30018949bcd6Sandrei cpuid_is_cmt(cpu_t *cpu)
30027c478bd9Sstevel@tonic-gate {
30037c478bd9Sstevel@tonic-gate 	if (cpu == NULL)
30047c478bd9Sstevel@tonic-gate 		cpu = CPU;
30057c478bd9Sstevel@tonic-gate 
30067c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
30077c478bd9Sstevel@tonic-gate 
30087c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_chipid >= 0);
30097c478bd9Sstevel@tonic-gate }
30107c478bd9Sstevel@tonic-gate 
30117c478bd9Sstevel@tonic-gate /*
30127c478bd9Sstevel@tonic-gate  * AMD and Intel both implement the 64-bit variant of the syscall
30137c478bd9Sstevel@tonic-gate  * instruction (syscallq), so if there's -any- support for syscall,
30147c478bd9Sstevel@tonic-gate  * cpuid currently says "yes, we support this".
30157c478bd9Sstevel@tonic-gate  *
30167c478bd9Sstevel@tonic-gate  * However, Intel decided to -not- implement the 32-bit variant of the
30177c478bd9Sstevel@tonic-gate  * syscall instruction, so we provide a predicate to allow our caller
30187c478bd9Sstevel@tonic-gate  * to test that subtlety here.
3019843e1988Sjohnlev  *
3020843e1988Sjohnlev  * XXPV	Currently, 32-bit syscall instructions don't work via the hypervisor,
3021843e1988Sjohnlev  *	even in the case where the hardware would in fact support it.
30227c478bd9Sstevel@tonic-gate  */
30237c478bd9Sstevel@tonic-gate /*ARGSUSED*/
30247c478bd9Sstevel@tonic-gate int
30257c478bd9Sstevel@tonic-gate cpuid_syscall32_insn(cpu_t *cpu)
30267c478bd9Sstevel@tonic-gate {
30277c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass((cpu == NULL ? CPU : cpu), 1));
30287c478bd9Sstevel@tonic-gate 
3029843e1988Sjohnlev #if !defined(__xpv)
3030ae115bc7Smrj 	if (cpu == NULL)
3031ae115bc7Smrj 		cpu = CPU;
3032ae115bc7Smrj 
3033ae115bc7Smrj 	/*CSTYLED*/
3034ae115bc7Smrj 	{
3035ae115bc7Smrj 		struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
3036ae115bc7Smrj 
3037ae115bc7Smrj 		if (cpi->cpi_vendor == X86_VENDOR_AMD &&
3038ae115bc7Smrj 		    cpi->cpi_xmaxeax >= 0x80000001 &&
3039ae115bc7Smrj 		    (CPI_FEATURES_XTD_EDX(cpi) & CPUID_AMD_EDX_SYSC))
3040ae115bc7Smrj 			return (1);
3041ae115bc7Smrj 	}
3042843e1988Sjohnlev #endif
30437c478bd9Sstevel@tonic-gate 	return (0);
30447c478bd9Sstevel@tonic-gate }
30457c478bd9Sstevel@tonic-gate 
30467c478bd9Sstevel@tonic-gate int
30477c478bd9Sstevel@tonic-gate cpuid_getidstr(cpu_t *cpu, char *s, size_t n)
30487c478bd9Sstevel@tonic-gate {
30497c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
30507c478bd9Sstevel@tonic-gate 
30517c478bd9Sstevel@tonic-gate 	static const char fmt[] =
3052ecfa43a5Sdmick 	    "x86 (%s %X family %d model %d step %d clock %d MHz)";
30537c478bd9Sstevel@tonic-gate 	static const char fmt_ht[] =
3054ecfa43a5Sdmick 	    "x86 (chipid 0x%x %s %X family %d model %d step %d clock %d MHz)";
30557c478bd9Sstevel@tonic-gate 
30567c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
30577c478bd9Sstevel@tonic-gate 
30588949bcd6Sandrei 	if (cpuid_is_cmt(cpu))
30597c478bd9Sstevel@tonic-gate 		return (snprintf(s, n, fmt_ht, cpi->cpi_chipid,
3060ecfa43a5Sdmick 		    cpi->cpi_vendorstr, cpi->cpi_std[1].cp_eax,
3061ecfa43a5Sdmick 		    cpi->cpi_family, cpi->cpi_model,
30627c478bd9Sstevel@tonic-gate 		    cpi->cpi_step, cpu->cpu_type_info.pi_clock));
30637c478bd9Sstevel@tonic-gate 	return (snprintf(s, n, fmt,
3064ecfa43a5Sdmick 	    cpi->cpi_vendorstr, cpi->cpi_std[1].cp_eax,
3065ecfa43a5Sdmick 	    cpi->cpi_family, cpi->cpi_model,
30667c478bd9Sstevel@tonic-gate 	    cpi->cpi_step, cpu->cpu_type_info.pi_clock));
30677c478bd9Sstevel@tonic-gate }
30687c478bd9Sstevel@tonic-gate 
30697c478bd9Sstevel@tonic-gate const char *
30707c478bd9Sstevel@tonic-gate cpuid_getvendorstr(cpu_t *cpu)
30717c478bd9Sstevel@tonic-gate {
30727c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
30737c478bd9Sstevel@tonic-gate 	return ((const char *)cpu->cpu_m.mcpu_cpi->cpi_vendorstr);
30747c478bd9Sstevel@tonic-gate }
30757c478bd9Sstevel@tonic-gate 
30767c478bd9Sstevel@tonic-gate uint_t
30777c478bd9Sstevel@tonic-gate cpuid_getvendor(cpu_t *cpu)
30787c478bd9Sstevel@tonic-gate {
30797c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
30807c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_vendor);
30817c478bd9Sstevel@tonic-gate }
30827c478bd9Sstevel@tonic-gate 
30837c478bd9Sstevel@tonic-gate uint_t
30847c478bd9Sstevel@tonic-gate cpuid_getfamily(cpu_t *cpu)
30857c478bd9Sstevel@tonic-gate {
30867c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
30877c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_family);
30887c478bd9Sstevel@tonic-gate }
30897c478bd9Sstevel@tonic-gate 
30907c478bd9Sstevel@tonic-gate uint_t
30917c478bd9Sstevel@tonic-gate cpuid_getmodel(cpu_t *cpu)
30927c478bd9Sstevel@tonic-gate {
30937c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
30947c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_model);
30957c478bd9Sstevel@tonic-gate }
30967c478bd9Sstevel@tonic-gate 
30977c478bd9Sstevel@tonic-gate uint_t
30987c478bd9Sstevel@tonic-gate cpuid_get_ncpu_per_chip(cpu_t *cpu)
30997c478bd9Sstevel@tonic-gate {
31007c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
31017c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_ncpu_per_chip);
31027c478bd9Sstevel@tonic-gate }
31037c478bd9Sstevel@tonic-gate 
31047c478bd9Sstevel@tonic-gate uint_t
31058949bcd6Sandrei cpuid_get_ncore_per_chip(cpu_t *cpu)
31068949bcd6Sandrei {
31078949bcd6Sandrei 	ASSERT(cpuid_checkpass(cpu, 1));
31088949bcd6Sandrei 	return (cpu->cpu_m.mcpu_cpi->cpi_ncore_per_chip);
31098949bcd6Sandrei }
31108949bcd6Sandrei 
31118949bcd6Sandrei uint_t
3112d129bde2Sesaxe cpuid_get_ncpu_sharing_last_cache(cpu_t *cpu)
3113d129bde2Sesaxe {
3114d129bde2Sesaxe 	ASSERT(cpuid_checkpass(cpu, 2));
3115d129bde2Sesaxe 	return (cpu->cpu_m.mcpu_cpi->cpi_ncpu_shr_last_cache);
3116d129bde2Sesaxe }
3117d129bde2Sesaxe 
3118d129bde2Sesaxe id_t
3119d129bde2Sesaxe cpuid_get_last_lvl_cacheid(cpu_t *cpu)
3120d129bde2Sesaxe {
3121d129bde2Sesaxe 	ASSERT(cpuid_checkpass(cpu, 2));
3122d129bde2Sesaxe 	return (cpu->cpu_m.mcpu_cpi->cpi_last_lvl_cacheid);
3123d129bde2Sesaxe }
3124d129bde2Sesaxe 
3125d129bde2Sesaxe uint_t
31267c478bd9Sstevel@tonic-gate cpuid_getstep(cpu_t *cpu)
31277c478bd9Sstevel@tonic-gate {
31287c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
31297c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_step);
31307c478bd9Sstevel@tonic-gate }
31317c478bd9Sstevel@tonic-gate 
31322449e17fSsherrym uint_t
31332449e17fSsherrym cpuid_getsig(struct cpu *cpu)
31342449e17fSsherrym {
31352449e17fSsherrym 	ASSERT(cpuid_checkpass(cpu, 1));
31362449e17fSsherrym 	return (cpu->cpu_m.mcpu_cpi->cpi_std[1].cp_eax);
31372449e17fSsherrym }
31382449e17fSsherrym 
31398a40a695Sgavinm uint32_t
31408a40a695Sgavinm cpuid_getchiprev(struct cpu *cpu)
31418a40a695Sgavinm {
31428a40a695Sgavinm 	ASSERT(cpuid_checkpass(cpu, 1));
31438a40a695Sgavinm 	return (cpu->cpu_m.mcpu_cpi->cpi_chiprev);
31448a40a695Sgavinm }
31458a40a695Sgavinm 
31468a40a695Sgavinm const char *
31478a40a695Sgavinm cpuid_getchiprevstr(struct cpu *cpu)
31488a40a695Sgavinm {
31498a40a695Sgavinm 	ASSERT(cpuid_checkpass(cpu, 1));
31508a40a695Sgavinm 	return (cpu->cpu_m.mcpu_cpi->cpi_chiprevstr);
31518a40a695Sgavinm }
31528a40a695Sgavinm 
31538a40a695Sgavinm uint32_t
31548a40a695Sgavinm cpuid_getsockettype(struct cpu *cpu)
31558a40a695Sgavinm {
31568a40a695Sgavinm 	ASSERT(cpuid_checkpass(cpu, 1));
31578a40a695Sgavinm 	return (cpu->cpu_m.mcpu_cpi->cpi_socket);
31588a40a695Sgavinm }
31598a40a695Sgavinm 
316089e921d5SKuriakose Kuruvilla const char *
316189e921d5SKuriakose Kuruvilla cpuid_getsocketstr(cpu_t *cpu)
316289e921d5SKuriakose Kuruvilla {
316389e921d5SKuriakose Kuruvilla 	static const char *socketstr = NULL;
316489e921d5SKuriakose Kuruvilla 	struct cpuid_info *cpi;
316589e921d5SKuriakose Kuruvilla 
316689e921d5SKuriakose Kuruvilla 	ASSERT(cpuid_checkpass(cpu, 1));
316789e921d5SKuriakose Kuruvilla 	cpi = cpu->cpu_m.mcpu_cpi;
316889e921d5SKuriakose Kuruvilla 
316989e921d5SKuriakose Kuruvilla 	/* Assume that socket types are the same across the system */
317089e921d5SKuriakose Kuruvilla 	if (socketstr == NULL)
317189e921d5SKuriakose Kuruvilla 		socketstr = _cpuid_sktstr(cpi->cpi_vendor, cpi->cpi_family,
317289e921d5SKuriakose Kuruvilla 		    cpi->cpi_model, cpi->cpi_step);
317389e921d5SKuriakose Kuruvilla 
317489e921d5SKuriakose Kuruvilla 
317589e921d5SKuriakose Kuruvilla 	return (socketstr);
317689e921d5SKuriakose Kuruvilla }
317789e921d5SKuriakose Kuruvilla 
3178fb2f18f8Sesaxe int
3179fb2f18f8Sesaxe cpuid_get_chipid(cpu_t *cpu)
31807c478bd9Sstevel@tonic-gate {
31817c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
31827c478bd9Sstevel@tonic-gate 
31838949bcd6Sandrei 	if (cpuid_is_cmt(cpu))
31847c478bd9Sstevel@tonic-gate 		return (cpu->cpu_m.mcpu_cpi->cpi_chipid);
31857c478bd9Sstevel@tonic-gate 	return (cpu->cpu_id);
31867c478bd9Sstevel@tonic-gate }
31877c478bd9Sstevel@tonic-gate 
31888949bcd6Sandrei id_t
3189fb2f18f8Sesaxe cpuid_get_coreid(cpu_t *cpu)
31908949bcd6Sandrei {
31918949bcd6Sandrei 	ASSERT(cpuid_checkpass(cpu, 1));
31928949bcd6Sandrei 	return (cpu->cpu_m.mcpu_cpi->cpi_coreid);
31938949bcd6Sandrei }
31948949bcd6Sandrei 
31957c478bd9Sstevel@tonic-gate int
319610569901Sgavinm cpuid_get_pkgcoreid(cpu_t *cpu)
319710569901Sgavinm {
319810569901Sgavinm 	ASSERT(cpuid_checkpass(cpu, 1));
319910569901Sgavinm 	return (cpu->cpu_m.mcpu_cpi->cpi_pkgcoreid);
320010569901Sgavinm }
320110569901Sgavinm 
320210569901Sgavinm int
3203fb2f18f8Sesaxe cpuid_get_clogid(cpu_t *cpu)
32047c478bd9Sstevel@tonic-gate {
32057c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
32067c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_clogid);
32077c478bd9Sstevel@tonic-gate }
32087c478bd9Sstevel@tonic-gate 
3209b885580bSAlexander Kolbasov int
3210b885580bSAlexander Kolbasov cpuid_get_cacheid(cpu_t *cpu)
3211b885580bSAlexander Kolbasov {
3212b885580bSAlexander Kolbasov 	ASSERT(cpuid_checkpass(cpu, 1));
3213b885580bSAlexander Kolbasov 	return (cpu->cpu_m.mcpu_cpi->cpi_last_lvl_cacheid);
3214b885580bSAlexander Kolbasov }
3215b885580bSAlexander Kolbasov 
32168031591dSSrihari Venkatesan uint_t
32178031591dSSrihari Venkatesan cpuid_get_procnodeid(cpu_t *cpu)
32188031591dSSrihari Venkatesan {
32198031591dSSrihari Venkatesan 	ASSERT(cpuid_checkpass(cpu, 1));
32208031591dSSrihari Venkatesan 	return (cpu->cpu_m.mcpu_cpi->cpi_procnodeid);
32218031591dSSrihari Venkatesan }
32228031591dSSrihari Venkatesan 
32238031591dSSrihari Venkatesan uint_t
32248031591dSSrihari Venkatesan cpuid_get_procnodes_per_pkg(cpu_t *cpu)
32258031591dSSrihari Venkatesan {
32268031591dSSrihari Venkatesan 	ASSERT(cpuid_checkpass(cpu, 1));
32278031591dSSrihari Venkatesan 	return (cpu->cpu_m.mcpu_cpi->cpi_procnodes_per_pkg);
32288031591dSSrihari Venkatesan }
32298031591dSSrihari Venkatesan 
32307660e73fSHans Rosenfeld uint_t
32317660e73fSHans Rosenfeld cpuid_get_compunitid(cpu_t *cpu)
32327660e73fSHans Rosenfeld {
32337660e73fSHans Rosenfeld 	ASSERT(cpuid_checkpass(cpu, 1));
32347660e73fSHans Rosenfeld 	return (cpu->cpu_m.mcpu_cpi->cpi_compunitid);
32357660e73fSHans Rosenfeld }
32367660e73fSHans Rosenfeld 
32377660e73fSHans Rosenfeld uint_t
32387660e73fSHans Rosenfeld cpuid_get_cores_per_compunit(cpu_t *cpu)
32397660e73fSHans Rosenfeld {
32407660e73fSHans Rosenfeld 	ASSERT(cpuid_checkpass(cpu, 1));
32417660e73fSHans Rosenfeld 	return (cpu->cpu_m.mcpu_cpi->cpi_cores_per_compunit);
32427660e73fSHans Rosenfeld }
32437660e73fSHans Rosenfeld 
32442ef50f01SJoe Bonasera /*ARGSUSED*/
32452ef50f01SJoe Bonasera int
32462ef50f01SJoe Bonasera cpuid_have_cr8access(cpu_t *cpu)
32472ef50f01SJoe Bonasera {
32482ef50f01SJoe Bonasera #if defined(__amd64)
32492ef50f01SJoe Bonasera 	return (1);
32502ef50f01SJoe Bonasera #else
32512ef50f01SJoe Bonasera 	struct cpuid_info *cpi;
32522ef50f01SJoe Bonasera 
32532ef50f01SJoe Bonasera 	ASSERT(cpu != NULL);
32542ef50f01SJoe Bonasera 	cpi = cpu->cpu_m.mcpu_cpi;
32552ef50f01SJoe Bonasera 	if (cpi->cpi_vendor == X86_VENDOR_AMD && cpi->cpi_maxeax >= 1 &&
32562ef50f01SJoe Bonasera 	    (CPI_FEATURES_XTD_ECX(cpi) & CPUID_AMD_ECX_CR8D) != 0)
32572ef50f01SJoe Bonasera 		return (1);
32582ef50f01SJoe Bonasera 	return (0);
32592ef50f01SJoe Bonasera #endif
32602ef50f01SJoe Bonasera }
32612ef50f01SJoe Bonasera 
3262fa96bd91SMichael Corcoran uint32_t
3263fa96bd91SMichael Corcoran cpuid_get_apicid(cpu_t *cpu)
3264fa96bd91SMichael Corcoran {
3265fa96bd91SMichael Corcoran 	ASSERT(cpuid_checkpass(cpu, 1));
3266fa96bd91SMichael Corcoran 	if (cpu->cpu_m.mcpu_cpi->cpi_maxeax < 1) {
3267fa96bd91SMichael Corcoran 		return (UINT32_MAX);
3268fa96bd91SMichael Corcoran 	} else {
3269fa96bd91SMichael Corcoran 		return (cpu->cpu_m.mcpu_cpi->cpi_apicid);
3270fa96bd91SMichael Corcoran 	}
3271fa96bd91SMichael Corcoran }
3272fa96bd91SMichael Corcoran 
32737c478bd9Sstevel@tonic-gate void
32747c478bd9Sstevel@tonic-gate cpuid_get_addrsize(cpu_t *cpu, uint_t *pabits, uint_t *vabits)
32757c478bd9Sstevel@tonic-gate {
32767c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi;
32777c478bd9Sstevel@tonic-gate 
32787c478bd9Sstevel@tonic-gate 	if (cpu == NULL)
32797c478bd9Sstevel@tonic-gate 		cpu = CPU;
32807c478bd9Sstevel@tonic-gate 	cpi = cpu->cpu_m.mcpu_cpi;
32817c478bd9Sstevel@tonic-gate 
32827c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
32837c478bd9Sstevel@tonic-gate 
32847c478bd9Sstevel@tonic-gate 	if (pabits)
32857c478bd9Sstevel@tonic-gate 		*pabits = cpi->cpi_pabits;
32867c478bd9Sstevel@tonic-gate 	if (vabits)
32877c478bd9Sstevel@tonic-gate 		*vabits = cpi->cpi_vabits;
32887c478bd9Sstevel@tonic-gate }
32897c478bd9Sstevel@tonic-gate 
32907c478bd9Sstevel@tonic-gate /*
32917c478bd9Sstevel@tonic-gate  * Returns the number of data TLB entries for a corresponding
32927c478bd9Sstevel@tonic-gate  * pagesize.  If it can't be computed, or isn't known, the
32937c478bd9Sstevel@tonic-gate  * routine returns zero.  If you ask about an architecturally
32947c478bd9Sstevel@tonic-gate  * impossible pagesize, the routine will panic (so that the
32957c478bd9Sstevel@tonic-gate  * hat implementor knows that things are inconsistent.)
32967c478bd9Sstevel@tonic-gate  */
32977c478bd9Sstevel@tonic-gate uint_t
32987c478bd9Sstevel@tonic-gate cpuid_get_dtlb_nent(cpu_t *cpu, size_t pagesize)
32997c478bd9Sstevel@tonic-gate {
33007c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi;
33017c478bd9Sstevel@tonic-gate 	uint_t dtlb_nent = 0;
33027c478bd9Sstevel@tonic-gate 
33037c478bd9Sstevel@tonic-gate 	if (cpu == NULL)
33047c478bd9Sstevel@tonic-gate 		cpu = CPU;
33057c478bd9Sstevel@tonic-gate 	cpi = cpu->cpu_m.mcpu_cpi;
33067c478bd9Sstevel@tonic-gate 
33077c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
33087c478bd9Sstevel@tonic-gate 
33097c478bd9Sstevel@tonic-gate 	/*
33107c478bd9Sstevel@tonic-gate 	 * Check the L2 TLB info
33117c478bd9Sstevel@tonic-gate 	 */
33127c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax >= 0x80000006) {
33138949bcd6Sandrei 		struct cpuid_regs *cp = &cpi->cpi_extd[6];
33147c478bd9Sstevel@tonic-gate 
33157c478bd9Sstevel@tonic-gate 		switch (pagesize) {
33167c478bd9Sstevel@tonic-gate 
33177c478bd9Sstevel@tonic-gate 		case 4 * 1024:
33187c478bd9Sstevel@tonic-gate 			/*
33197c478bd9Sstevel@tonic-gate 			 * All zero in the top 16 bits of the register
33207c478bd9Sstevel@tonic-gate 			 * indicates a unified TLB. Size is in low 16 bits.
33217c478bd9Sstevel@tonic-gate 			 */
33227c478bd9Sstevel@tonic-gate 			if ((cp->cp_ebx & 0xffff0000) == 0)
33237c478bd9Sstevel@tonic-gate 				dtlb_nent = cp->cp_ebx & 0x0000ffff;
33247c478bd9Sstevel@tonic-gate 			else
33257c478bd9Sstevel@tonic-gate 				dtlb_nent = BITX(cp->cp_ebx, 27, 16);
33267c478bd9Sstevel@tonic-gate 			break;
33277c478bd9Sstevel@tonic-gate 
33287c478bd9Sstevel@tonic-gate 		case 2 * 1024 * 1024:
33297c478bd9Sstevel@tonic-gate 			if ((cp->cp_eax & 0xffff0000) == 0)
33307c478bd9Sstevel@tonic-gate 				dtlb_nent = cp->cp_eax & 0x0000ffff;
33317c478bd9Sstevel@tonic-gate 			else
33327c478bd9Sstevel@tonic-gate 				dtlb_nent = BITX(cp->cp_eax, 27, 16);
33337c478bd9Sstevel@tonic-gate 			break;
33347c478bd9Sstevel@tonic-gate 
33357c478bd9Sstevel@tonic-gate 		default:
33367c478bd9Sstevel@tonic-gate 			panic("unknown L2 pagesize");
33377c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
33387c478bd9Sstevel@tonic-gate 		}
33397c478bd9Sstevel@tonic-gate 	}
33407c478bd9Sstevel@tonic-gate 
33417c478bd9Sstevel@tonic-gate 	if (dtlb_nent != 0)
33427c478bd9Sstevel@tonic-gate 		return (dtlb_nent);
33437c478bd9Sstevel@tonic-gate 
33447c478bd9Sstevel@tonic-gate 	/*
33457c478bd9Sstevel@tonic-gate 	 * No L2 TLB support for this size, try L1.
33467c478bd9Sstevel@tonic-gate 	 */
33477c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax >= 0x80000005) {
33488949bcd6Sandrei 		struct cpuid_regs *cp = &cpi->cpi_extd[5];
33497c478bd9Sstevel@tonic-gate 
33507c478bd9Sstevel@tonic-gate 		switch (pagesize) {
33517c478bd9Sstevel@tonic-gate 		case 4 * 1024:
33527c478bd9Sstevel@tonic-gate 			dtlb_nent = BITX(cp->cp_ebx, 23, 16);
33537c478bd9Sstevel@tonic-gate 			break;
33547c478bd9Sstevel@tonic-gate 		case 2 * 1024 * 1024:
33557c478bd9Sstevel@tonic-gate 			dtlb_nent = BITX(cp->cp_eax, 23, 16);
33567c478bd9Sstevel@tonic-gate 			break;
33577c478bd9Sstevel@tonic-gate 		default:
33587c478bd9Sstevel@tonic-gate 			panic("unknown L1 d-TLB pagesize");
33597c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
33607c478bd9Sstevel@tonic-gate 		}
33617c478bd9Sstevel@tonic-gate 	}
33627c478bd9Sstevel@tonic-gate 
33637c478bd9Sstevel@tonic-gate 	return (dtlb_nent);
33647c478bd9Sstevel@tonic-gate }
33657c478bd9Sstevel@tonic-gate 
33667c478bd9Sstevel@tonic-gate /*
33677c478bd9Sstevel@tonic-gate  * Return 0 if the erratum is not present or not applicable, positive
33687c478bd9Sstevel@tonic-gate  * if it is, and negative if the status of the erratum is unknown.
33697c478bd9Sstevel@tonic-gate  *
33707c478bd9Sstevel@tonic-gate  * See "Revision Guide for AMD Athlon(tm) 64 and AMD Opteron(tm)
33712201b277Skucharsk  * Processors" #25759, Rev 3.57, August 2005
33727c478bd9Sstevel@tonic-gate  */
33737c478bd9Sstevel@tonic-gate int
33747c478bd9Sstevel@tonic-gate cpuid_opteron_erratum(cpu_t *cpu, uint_t erratum)
33757c478bd9Sstevel@tonic-gate {
33767c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
33778949bcd6Sandrei 	uint_t eax;
33787c478bd9Sstevel@tonic-gate 
3379ea99987eSsethg 	/*
3380ea99987eSsethg 	 * Bail out if this CPU isn't an AMD CPU, or if it's
3381ea99987eSsethg 	 * a legacy (32-bit) AMD CPU.
3382ea99987eSsethg 	 */
3383ea99987eSsethg 	if (cpi->cpi_vendor != X86_VENDOR_AMD ||
3384875b116eSkchow 	    cpi->cpi_family == 4 || cpi->cpi_family == 5 ||
3385875b116eSkchow 	    cpi->cpi_family == 6)
33868a40a695Sgavinm 
33877c478bd9Sstevel@tonic-gate 		return (0);
33887c478bd9Sstevel@tonic-gate 
33897c478bd9Sstevel@tonic-gate 	eax = cpi->cpi_std[1].cp_eax;
33907c478bd9Sstevel@tonic-gate 
33917c478bd9Sstevel@tonic-gate #define	SH_B0(eax)	(eax == 0xf40 || eax == 0xf50)
33927c478bd9Sstevel@tonic-gate #define	SH_B3(eax) 	(eax == 0xf51)
3393ee88d2b9Skchow #define	B(eax)		(SH_B0(eax) || SH_B3(eax))
33947c478bd9Sstevel@tonic-gate 
33957c478bd9Sstevel@tonic-gate #define	SH_C0(eax)	(eax == 0xf48 || eax == 0xf58)
33967c478bd9Sstevel@tonic-gate 
33977c478bd9Sstevel@tonic-gate #define	SH_CG(eax)	(eax == 0xf4a || eax == 0xf5a || eax == 0xf7a)
33987c478bd9Sstevel@tonic-gate #define	DH_CG(eax)	(eax == 0xfc0 || eax == 0xfe0 || eax == 0xff0)
33997c478bd9Sstevel@tonic-gate #define	CH_CG(eax)	(eax == 0xf82 || eax == 0xfb2)
3400ee88d2b9Skchow #define	CG(eax)		(SH_CG(eax) || DH_CG(eax) || CH_CG(eax))
34017c478bd9Sstevel@tonic-gate 
34027c478bd9Sstevel@tonic-gate #define	SH_D0(eax)	(eax == 0x10f40 || eax == 0x10f50 || eax == 0x10f70)
34037c478bd9Sstevel@tonic-gate #define	DH_D0(eax)	(eax == 0x10fc0 || eax == 0x10ff0)
34047c478bd9Sstevel@tonic-gate #define	CH_D0(eax)	(eax == 0x10f80 || eax == 0x10fb0)
3405ee88d2b9Skchow #define	D0(eax)		(SH_D0(eax) || DH_D0(eax) || CH_D0(eax))
34067c478bd9Sstevel@tonic-gate 
34077c478bd9Sstevel@tonic-gate #define	SH_E0(eax)	(eax == 0x20f50 || eax == 0x20f40 || eax == 0x20f70)
34087c478bd9Sstevel@tonic-gate #define	JH_E1(eax)	(eax == 0x20f10)	/* JH8_E0 had 0x20f30 */
34097c478bd9Sstevel@tonic-gate #define	DH_E3(eax)	(eax == 0x20fc0 || eax == 0x20ff0)
34107c478bd9Sstevel@tonic-gate #define	SH_E4(eax)	(eax == 0x20f51 || eax == 0x20f71)
34117c478bd9Sstevel@tonic-gate #define	BH_E4(eax)	(eax == 0x20fb1)
34127c478bd9Sstevel@tonic-gate #define	SH_E5(eax)	(eax == 0x20f42)
34137c478bd9Sstevel@tonic-gate #define	DH_E6(eax)	(eax == 0x20ff2 || eax == 0x20fc2)
34147c478bd9Sstevel@tonic-gate #define	JH_E6(eax)	(eax == 0x20f12 || eax == 0x20f32)
3415ee88d2b9Skchow #define	EX(eax)		(SH_E0(eax) || JH_E1(eax) || DH_E3(eax) || \
3416ee88d2b9Skchow 			    SH_E4(eax) || BH_E4(eax) || SH_E5(eax) || \
3417ee88d2b9Skchow 			    DH_E6(eax) || JH_E6(eax))
34187c478bd9Sstevel@tonic-gate 
3419512cf780Skchow #define	DR_AX(eax)	(eax == 0x100f00 || eax == 0x100f01 || eax == 0x100f02)
3420512cf780Skchow #define	DR_B0(eax)	(eax == 0x100f20)
3421512cf780Skchow #define	DR_B1(eax)	(eax == 0x100f21)
3422512cf780Skchow #define	DR_BA(eax)	(eax == 0x100f2a)
3423512cf780Skchow #define	DR_B2(eax)	(eax == 0x100f22)
3424512cf780Skchow #define	DR_B3(eax)	(eax == 0x100f23)
3425512cf780Skchow #define	RB_C0(eax)	(eax == 0x100f40)
3426512cf780Skchow 
34277c478bd9Sstevel@tonic-gate 	switch (erratum) {
34287c478bd9Sstevel@tonic-gate 	case 1:
3429875b116eSkchow 		return (cpi->cpi_family < 0x10);
34307c478bd9Sstevel@tonic-gate 	case 51:	/* what does the asterisk mean? */
34317c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax));
34327c478bd9Sstevel@tonic-gate 	case 52:
34337c478bd9Sstevel@tonic-gate 		return (B(eax));
34347c478bd9Sstevel@tonic-gate 	case 57:
3435512cf780Skchow 		return (cpi->cpi_family <= 0x11);
34367c478bd9Sstevel@tonic-gate 	case 58:
34377c478bd9Sstevel@tonic-gate 		return (B(eax));
34387c478bd9Sstevel@tonic-gate 	case 60:
3439512cf780Skchow 		return (cpi->cpi_family <= 0x11);
34407c478bd9Sstevel@tonic-gate 	case 61:
34417c478bd9Sstevel@tonic-gate 	case 62:
34427c478bd9Sstevel@tonic-gate 	case 63:
34437c478bd9Sstevel@tonic-gate 	case 64:
34447c478bd9Sstevel@tonic-gate 	case 65:
34457c478bd9Sstevel@tonic-gate 	case 66:
34467c478bd9Sstevel@tonic-gate 	case 68:
34477c478bd9Sstevel@tonic-gate 	case 69:
34487c478bd9Sstevel@tonic-gate 	case 70:
34497c478bd9Sstevel@tonic-gate 	case 71:
34507c478bd9Sstevel@tonic-gate 		return (B(eax));
34517c478bd9Sstevel@tonic-gate 	case 72:
34527c478bd9Sstevel@tonic-gate 		return (SH_B0(eax));
34537c478bd9Sstevel@tonic-gate 	case 74:
34547c478bd9Sstevel@tonic-gate 		return (B(eax));
34557c478bd9Sstevel@tonic-gate 	case 75:
3456875b116eSkchow 		return (cpi->cpi_family < 0x10);
34577c478bd9Sstevel@tonic-gate 	case 76:
34587c478bd9Sstevel@tonic-gate 		return (B(eax));
34597c478bd9Sstevel@tonic-gate 	case 77:
3460512cf780Skchow 		return (cpi->cpi_family <= 0x11);
34617c478bd9Sstevel@tonic-gate 	case 78:
34627c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax));
34637c478bd9Sstevel@tonic-gate 	case 79:
34647c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax) || EX(eax));
34657c478bd9Sstevel@tonic-gate 	case 80:
34667c478bd9Sstevel@tonic-gate 	case 81:
34677c478bd9Sstevel@tonic-gate 	case 82:
34687c478bd9Sstevel@tonic-gate 		return (B(eax));
34697c478bd9Sstevel@tonic-gate 	case 83:
34707c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax));
34717c478bd9Sstevel@tonic-gate 	case 85:
3472875b116eSkchow 		return (cpi->cpi_family < 0x10);
34737c478bd9Sstevel@tonic-gate 	case 86:
34747c478bd9Sstevel@tonic-gate 		return (SH_C0(eax) || CG(eax));
34757c478bd9Sstevel@tonic-gate 	case 88:
34767c478bd9Sstevel@tonic-gate #if !defined(__amd64)
34777c478bd9Sstevel@tonic-gate 		return (0);
34787c478bd9Sstevel@tonic-gate #else
34797c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax));
34807c478bd9Sstevel@tonic-gate #endif
34817c478bd9Sstevel@tonic-gate 	case 89:
3482875b116eSkchow 		return (cpi->cpi_family < 0x10);
34837c478bd9Sstevel@tonic-gate 	case 90:
34847c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax));
34857c478bd9Sstevel@tonic-gate 	case 91:
34867c478bd9Sstevel@tonic-gate 	case 92:
34877c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax));
34887c478bd9Sstevel@tonic-gate 	case 93:
34897c478bd9Sstevel@tonic-gate 		return (SH_C0(eax));
34907c478bd9Sstevel@tonic-gate 	case 94:
34917c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax));
34927c478bd9Sstevel@tonic-gate 	case 95:
34937c478bd9Sstevel@tonic-gate #if !defined(__amd64)
34947c478bd9Sstevel@tonic-gate 		return (0);
34957c478bd9Sstevel@tonic-gate #else
34967c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax));
34977c478bd9Sstevel@tonic-gate #endif
34987c478bd9Sstevel@tonic-gate 	case 96:
34997c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax));
35007c478bd9Sstevel@tonic-gate 	case 97:
35017c478bd9Sstevel@tonic-gate 	case 98:
35027c478bd9Sstevel@tonic-gate 		return (SH_C0(eax) || CG(eax));
35037c478bd9Sstevel@tonic-gate 	case 99:
35047c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax));
35057c478bd9Sstevel@tonic-gate 	case 100:
35067c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax));
35077c478bd9Sstevel@tonic-gate 	case 101:
35087c478bd9Sstevel@tonic-gate 	case 103:
35097c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax));
35107c478bd9Sstevel@tonic-gate 	case 104:
35117c478bd9Sstevel@tonic-gate 		return (SH_C0(eax) || CG(eax) || D0(eax));
35127c478bd9Sstevel@tonic-gate 	case 105:
35137c478bd9Sstevel@tonic-gate 	case 106:
35147c478bd9Sstevel@tonic-gate 	case 107:
35157c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax));
35167c478bd9Sstevel@tonic-gate 	case 108:
35177c478bd9Sstevel@tonic-gate 		return (DH_CG(eax));
35187c478bd9Sstevel@tonic-gate 	case 109:
35197c478bd9Sstevel@tonic-gate 		return (SH_C0(eax) || CG(eax) || D0(eax));
35207c478bd9Sstevel@tonic-gate 	case 110:
35217c478bd9Sstevel@tonic-gate 		return (D0(eax) || EX(eax));
35227c478bd9Sstevel@tonic-gate 	case 111:
35237c478bd9Sstevel@tonic-gate 		return (CG(eax));
35247c478bd9Sstevel@tonic-gate 	case 112:
35257c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax) || EX(eax));
35267c478bd9Sstevel@tonic-gate 	case 113:
35277c478bd9Sstevel@tonic-gate 		return (eax == 0x20fc0);
35287c478bd9Sstevel@tonic-gate 	case 114:
35297c478bd9Sstevel@tonic-gate 		return (SH_E0(eax) || JH_E1(eax) || DH_E3(eax));
35307c478bd9Sstevel@tonic-gate 	case 115:
35317c478bd9Sstevel@tonic-gate 		return (SH_E0(eax) || JH_E1(eax));
35327c478bd9Sstevel@tonic-gate 	case 116:
35337c478bd9Sstevel@tonic-gate 		return (SH_E0(eax) || JH_E1(eax) || DH_E3(eax));
35347c478bd9Sstevel@tonic-gate 	case 117:
35357c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax));
35367c478bd9Sstevel@tonic-gate 	case 118:
35377c478bd9Sstevel@tonic-gate 		return (SH_E0(eax) || JH_E1(eax) || SH_E4(eax) || BH_E4(eax) ||
35387c478bd9Sstevel@tonic-gate 		    JH_E6(eax));
35397c478bd9Sstevel@tonic-gate 	case 121:
35407c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax) || EX(eax));
35417c478bd9Sstevel@tonic-gate 	case 122:
3542512cf780Skchow 		return (cpi->cpi_family < 0x10 || cpi->cpi_family == 0x11);
35437c478bd9Sstevel@tonic-gate 	case 123:
35447c478bd9Sstevel@tonic-gate 		return (JH_E1(eax) || BH_E4(eax) || JH_E6(eax));
35452201b277Skucharsk 	case 131:
3546875b116eSkchow 		return (cpi->cpi_family < 0x10);
3547ef50d8c0Sesaxe 	case 6336786:
3548ef50d8c0Sesaxe 		/*
3549ef50d8c0Sesaxe 		 * Test for AdvPowerMgmtInfo.TscPStateInvariant
3550875b116eSkchow 		 * if this is a K8 family or newer processor
3551ef50d8c0Sesaxe 		 */
3552ef50d8c0Sesaxe 		if (CPI_FAMILY(cpi) == 0xf) {
35538949bcd6Sandrei 			struct cpuid_regs regs;
35548949bcd6Sandrei 			regs.cp_eax = 0x80000007;
35558949bcd6Sandrei 			(void) __cpuid_insn(&regs);
35568949bcd6Sandrei 			return (!(regs.cp_edx & 0x100));
3557ef50d8c0Sesaxe 		}
3558ef50d8c0Sesaxe 		return (0);
3559ee88d2b9Skchow 	case 6323525:
3560ee88d2b9Skchow 		return (((((eax >> 12) & 0xff00) + (eax & 0xf00)) |
3561ee88d2b9Skchow 		    (((eax >> 4) & 0xf) | ((eax >> 12) & 0xf0))) < 0xf40);
3562ee88d2b9Skchow 
3563512cf780Skchow 	case 6671130:
3564512cf780Skchow 		/*
3565512cf780Skchow 		 * check for processors (pre-Shanghai) that do not provide
3566512cf780Skchow 		 * optimal management of 1gb ptes in its tlb.
3567512cf780Skchow 		 */
3568512cf780Skchow 		return (cpi->cpi_family == 0x10 && cpi->cpi_model < 4);
3569512cf780Skchow 
3570512cf780Skchow 	case 298:
3571512cf780Skchow 		return (DR_AX(eax) || DR_B0(eax) || DR_B1(eax) || DR_BA(eax) ||
3572512cf780Skchow 		    DR_B2(eax) || RB_C0(eax));
3573512cf780Skchow 
35745e54b56dSHans Rosenfeld 	case 721:
35755e54b56dSHans Rosenfeld #if defined(__amd64)
35765e54b56dSHans Rosenfeld 		return (cpi->cpi_family == 0x10 || cpi->cpi_family == 0x12);
35775e54b56dSHans Rosenfeld #else
35785e54b56dSHans Rosenfeld 		return (0);
35795e54b56dSHans Rosenfeld #endif
35805e54b56dSHans Rosenfeld 
3581512cf780Skchow 	default:
3582512cf780Skchow 		return (-1);
3583512cf780Skchow 
3584512cf780Skchow 	}
3585512cf780Skchow }
3586512cf780Skchow 
3587512cf780Skchow /*
3588512cf780Skchow  * Determine if specified erratum is present via OSVW (OS Visible Workaround).
3589512cf780Skchow  * Return 1 if erratum is present, 0 if not present and -1 if indeterminate.
3590512cf780Skchow  */
3591512cf780Skchow int
3592512cf780Skchow osvw_opteron_erratum(cpu_t *cpu, uint_t erratum)
3593512cf780Skchow {
3594512cf780Skchow 	struct cpuid_info	*cpi;
3595512cf780Skchow 	uint_t			osvwid;
3596512cf780Skchow 	static int		osvwfeature = -1;
3597512cf780Skchow 	uint64_t		osvwlength;
3598512cf780Skchow 
3599512cf780Skchow 
3600512cf780Skchow 	cpi = cpu->cpu_m.mcpu_cpi;
3601512cf780Skchow 
3602512cf780Skchow 	/* confirm OSVW supported */
3603512cf780Skchow 	if (osvwfeature == -1) {
3604512cf780Skchow 		osvwfeature = cpi->cpi_extd[1].cp_ecx & CPUID_AMD_ECX_OSVW;
3605512cf780Skchow 	} else {
3606512cf780Skchow 		/* assert that osvw feature setting is consistent on all cpus */
3607512cf780Skchow 		ASSERT(osvwfeature ==
3608512cf780Skchow 		    (cpi->cpi_extd[1].cp_ecx & CPUID_AMD_ECX_OSVW));
3609512cf780Skchow 	}
3610512cf780Skchow 	if (!osvwfeature)
3611512cf780Skchow 		return (-1);
3612512cf780Skchow 
3613512cf780Skchow 	osvwlength = rdmsr(MSR_AMD_OSVW_ID_LEN) & OSVW_ID_LEN_MASK;
3614512cf780Skchow 
3615512cf780Skchow 	switch (erratum) {
3616512cf780Skchow 	case 298:	/* osvwid is 0 */
3617512cf780Skchow 		osvwid = 0;
3618512cf780Skchow 		if (osvwlength <= (uint64_t)osvwid) {
3619512cf780Skchow 			/* osvwid 0 is unknown */
3620512cf780Skchow 			return (-1);
3621512cf780Skchow 		}
3622512cf780Skchow 
3623512cf780Skchow 		/*
3624512cf780Skchow 		 * Check the OSVW STATUS MSR to determine the state
3625512cf780Skchow 		 * of the erratum where:
3626512cf780Skchow 		 *   0 - fixed by HW
3627512cf780Skchow 		 *   1 - BIOS has applied the workaround when BIOS
3628512cf780Skchow 		 *   workaround is available. (Or for other errata,
3629512cf780Skchow 		 *   OS workaround is required.)
3630512cf780Skchow 		 * For a value of 1, caller will confirm that the
3631512cf780Skchow 		 * erratum 298 workaround has indeed been applied by BIOS.
3632512cf780Skchow 		 *
3633512cf780Skchow 		 * A 1 may be set in cpus that have a HW fix
3634512cf780Skchow 		 * in a mixed cpu system. Regarding erratum 298:
3635512cf780Skchow 		 *   In a multiprocessor platform, the workaround above
3636512cf780Skchow 		 *   should be applied to all processors regardless of
3637512cf780Skchow 		 *   silicon revision when an affected processor is
3638512cf780Skchow 		 *   present.
3639512cf780Skchow 		 */
3640512cf780Skchow 
3641512cf780Skchow 		return (rdmsr(MSR_AMD_OSVW_STATUS +
3642512cf780Skchow 		    (osvwid / OSVW_ID_CNT_PER_MSR)) &
3643512cf780Skchow 		    (1ULL << (osvwid % OSVW_ID_CNT_PER_MSR)));
3644512cf780Skchow 
36457c478bd9Sstevel@tonic-gate 	default:
36467c478bd9Sstevel@tonic-gate 		return (-1);
36477c478bd9Sstevel@tonic-gate 	}
36487c478bd9Sstevel@tonic-gate }
36497c478bd9Sstevel@tonic-gate 
36507c478bd9Sstevel@tonic-gate static const char assoc_str[] = "associativity";
36517c478bd9Sstevel@tonic-gate static const char line_str[] = "line-size";
36527c478bd9Sstevel@tonic-gate static const char size_str[] = "size";
36537c478bd9Sstevel@tonic-gate 
36547c478bd9Sstevel@tonic-gate static void
36557c478bd9Sstevel@tonic-gate add_cache_prop(dev_info_t *devi, const char *label, const char *type,
36567c478bd9Sstevel@tonic-gate     uint32_t val)
36577c478bd9Sstevel@tonic-gate {
36587c478bd9Sstevel@tonic-gate 	char buf[128];
36597c478bd9Sstevel@tonic-gate 
36607c478bd9Sstevel@tonic-gate 	/*
36617c478bd9Sstevel@tonic-gate 	 * ndi_prop_update_int() is used because it is desirable for
36627c478bd9Sstevel@tonic-gate 	 * DDI_PROP_HW_DEF and DDI_PROP_DONTSLEEP to be set.
36637c478bd9Sstevel@tonic-gate 	 */
36647c478bd9Sstevel@tonic-gate 	if (snprintf(buf, sizeof (buf), "%s-%s", label, type) < sizeof (buf))
36657c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, devi, buf, val);
36667c478bd9Sstevel@tonic-gate }
36677c478bd9Sstevel@tonic-gate 
36687c478bd9Sstevel@tonic-gate /*
36697c478bd9Sstevel@tonic-gate  * Intel-style cache/tlb description
36707c478bd9Sstevel@tonic-gate  *
36717c478bd9Sstevel@tonic-gate  * Standard cpuid level 2 gives a randomly ordered
36727c478bd9Sstevel@tonic-gate  * selection of tags that index into a table that describes
36737c478bd9Sstevel@tonic-gate  * cache and tlb properties.
36747c478bd9Sstevel@tonic-gate  */
36757c478bd9Sstevel@tonic-gate 
36767c478bd9Sstevel@tonic-gate static const char l1_icache_str[] = "l1-icache";
36777c478bd9Sstevel@tonic-gate static const char l1_dcache_str[] = "l1-dcache";
36787c478bd9Sstevel@tonic-gate static const char l2_cache_str[] = "l2-cache";
3679ae115bc7Smrj static const char l3_cache_str[] = "l3-cache";
36807c478bd9Sstevel@tonic-gate static const char itlb4k_str[] = "itlb-4K";
36817c478bd9Sstevel@tonic-gate static const char dtlb4k_str[] = "dtlb-4K";
3682824e4fecSvd224797 static const char itlb2M_str[] = "itlb-2M";
36837c478bd9Sstevel@tonic-gate static const char itlb4M_str[] = "itlb-4M";
36847c478bd9Sstevel@tonic-gate static const char dtlb4M_str[] = "dtlb-4M";
368525dfb062Sksadhukh static const char dtlb24_str[] = "dtlb0-2M-4M";
36867c478bd9Sstevel@tonic-gate static const char itlb424_str[] = "itlb-4K-2M-4M";
368725dfb062Sksadhukh static const char itlb24_str[] = "itlb-2M-4M";
36887c478bd9Sstevel@tonic-gate static const char dtlb44_str[] = "dtlb-4K-4M";
36897c478bd9Sstevel@tonic-gate static const char sl1_dcache_str[] = "sectored-l1-dcache";
36907c478bd9Sstevel@tonic-gate static const char sl2_cache_str[] = "sectored-l2-cache";
36917c478bd9Sstevel@tonic-gate static const char itrace_str[] = "itrace-cache";
36927c478bd9Sstevel@tonic-gate static const char sl3_cache_str[] = "sectored-l3-cache";
369325dfb062Sksadhukh static const char sh_l2_tlb4k_str[] = "shared-l2-tlb-4k";
36947c478bd9Sstevel@tonic-gate 
36957c478bd9Sstevel@tonic-gate static const struct cachetab {
36967c478bd9Sstevel@tonic-gate 	uint8_t 	ct_code;
36977c478bd9Sstevel@tonic-gate 	uint8_t		ct_assoc;
36987c478bd9Sstevel@tonic-gate 	uint16_t 	ct_line_size;
36997c478bd9Sstevel@tonic-gate 	size_t		ct_size;
37007c478bd9Sstevel@tonic-gate 	const char	*ct_label;
37017c478bd9Sstevel@tonic-gate } intel_ctab[] = {
3702824e4fecSvd224797 	/*
3703824e4fecSvd224797 	 * maintain descending order!
3704824e4fecSvd224797 	 *
3705824e4fecSvd224797 	 * Codes ignored - Reason
3706824e4fecSvd224797 	 * ----------------------
3707824e4fecSvd224797 	 * 40H - intel_cpuid_4_cache_info() disambiguates l2/l3 cache
3708824e4fecSvd224797 	 * f0H/f1H - Currently we do not interpret prefetch size by design
3709824e4fecSvd224797 	 */
371025dfb062Sksadhukh 	{ 0xe4, 16, 64, 8*1024*1024, l3_cache_str},
371125dfb062Sksadhukh 	{ 0xe3, 16, 64, 4*1024*1024, l3_cache_str},
371225dfb062Sksadhukh 	{ 0xe2, 16, 64, 2*1024*1024, l3_cache_str},
371325dfb062Sksadhukh 	{ 0xde, 12, 64, 6*1024*1024, l3_cache_str},
371425dfb062Sksadhukh 	{ 0xdd, 12, 64, 3*1024*1024, l3_cache_str},
371525dfb062Sksadhukh 	{ 0xdc, 12, 64, ((1*1024*1024)+(512*1024)), l3_cache_str},
371625dfb062Sksadhukh 	{ 0xd8, 8, 64, 4*1024*1024, l3_cache_str},
371725dfb062Sksadhukh 	{ 0xd7, 8, 64, 2*1024*1024, l3_cache_str},
371825dfb062Sksadhukh 	{ 0xd6, 8, 64, 1*1024*1024, l3_cache_str},
371925dfb062Sksadhukh 	{ 0xd2, 4, 64, 2*1024*1024, l3_cache_str},
372025dfb062Sksadhukh 	{ 0xd1, 4, 64, 1*1024*1024, l3_cache_str},
372125dfb062Sksadhukh 	{ 0xd0, 4, 64, 512*1024, l3_cache_str},
372225dfb062Sksadhukh 	{ 0xca, 4, 0, 512, sh_l2_tlb4k_str},
3723824e4fecSvd224797 	{ 0xc0, 4, 0, 8, dtlb44_str },
3724824e4fecSvd224797 	{ 0xba, 4, 0, 64, dtlb4k_str },
3725ae115bc7Smrj 	{ 0xb4, 4, 0, 256, dtlb4k_str },
37267c478bd9Sstevel@tonic-gate 	{ 0xb3, 4, 0, 128, dtlb4k_str },
372725dfb062Sksadhukh 	{ 0xb2, 4, 0, 64, itlb4k_str },
37287c478bd9Sstevel@tonic-gate 	{ 0xb0, 4, 0, 128, itlb4k_str },
37297c478bd9Sstevel@tonic-gate 	{ 0x87, 8, 64, 1024*1024, l2_cache_str},
37307c478bd9Sstevel@tonic-gate 	{ 0x86, 4, 64, 512*1024, l2_cache_str},
37317c478bd9Sstevel@tonic-gate 	{ 0x85, 8, 32, 2*1024*1024, l2_cache_str},
37327c478bd9Sstevel@tonic-gate 	{ 0x84, 8, 32, 1024*1024, l2_cache_str},
37337c478bd9Sstevel@tonic-gate 	{ 0x83, 8, 32, 512*1024, l2_cache_str},
37347c478bd9Sstevel@tonic-gate 	{ 0x82, 8, 32, 256*1024, l2_cache_str},
3735824e4fecSvd224797 	{ 0x80, 8, 64, 512*1024, l2_cache_str},
37367c478bd9Sstevel@tonic-gate 	{ 0x7f, 2, 64, 512*1024, l2_cache_str},
37377c478bd9Sstevel@tonic-gate 	{ 0x7d, 8, 64, 2*1024*1024, sl2_cache_str},
37387c478bd9Sstevel@tonic-gate 	{ 0x7c, 8, 64, 1024*1024, sl2_cache_str},
37397c478bd9Sstevel@tonic-gate 	{ 0x7b, 8, 64, 512*1024, sl2_cache_str},
37407c478bd9Sstevel@tonic-gate 	{ 0x7a, 8, 64, 256*1024, sl2_cache_str},
37417c478bd9Sstevel@tonic-gate 	{ 0x79, 8, 64, 128*1024, sl2_cache_str},
37427c478bd9Sstevel@tonic-gate 	{ 0x78, 8, 64, 1024*1024, l2_cache_str},
3743ae115bc7Smrj 	{ 0x73, 8, 0, 64*1024, itrace_str},
37447c478bd9Sstevel@tonic-gate 	{ 0x72, 8, 0, 32*1024, itrace_str},
37457c478bd9Sstevel@tonic-gate 	{ 0x71, 8, 0, 16*1024, itrace_str},
37467c478bd9Sstevel@tonic-gate 	{ 0x70, 8, 0, 12*1024, itrace_str},
37477c478bd9Sstevel@tonic-gate 	{ 0x68, 4, 64, 32*1024, sl1_dcache_str},
37487c478bd9Sstevel@tonic-gate 	{ 0x67, 4, 64, 16*1024, sl1_dcache_str},
37497c478bd9Sstevel@tonic-gate 	{ 0x66, 4, 64, 8*1024, sl1_dcache_str},
37507c478bd9Sstevel@tonic-gate 	{ 0x60, 8, 64, 16*1024, sl1_dcache_str},
37517c478bd9Sstevel@tonic-gate 	{ 0x5d, 0, 0, 256, dtlb44_str},
37527c478bd9Sstevel@tonic-gate 	{ 0x5c, 0, 0, 128, dtlb44_str},
37537c478bd9Sstevel@tonic-gate 	{ 0x5b, 0, 0, 64, dtlb44_str},
375425dfb062Sksadhukh 	{ 0x5a, 4, 0, 32, dtlb24_str},
3755824e4fecSvd224797 	{ 0x59, 0, 0, 16, dtlb4k_str},
3756824e4fecSvd224797 	{ 0x57, 4, 0, 16, dtlb4k_str},
3757824e4fecSvd224797 	{ 0x56, 4, 0, 16, dtlb4M_str},
375825dfb062Sksadhukh 	{ 0x55, 0, 0, 7, itlb24_str},
37597c478bd9Sstevel@tonic-gate 	{ 0x52, 0, 0, 256, itlb424_str},
37607c478bd9Sstevel@tonic-gate 	{ 0x51, 0, 0, 128, itlb424_str},
37617c478bd9Sstevel@tonic-gate 	{ 0x50, 0, 0, 64, itlb424_str},
3762824e4fecSvd224797 	{ 0x4f, 0, 0, 32, itlb4k_str},
3763824e4fecSvd224797 	{ 0x4e, 24, 64, 6*1024*1024, l2_cache_str},
3764ae115bc7Smrj 	{ 0x4d, 16, 64, 16*1024*1024, l3_cache_str},
3765ae115bc7Smrj 	{ 0x4c, 12, 64, 12*1024*1024, l3_cache_str},
3766ae115bc7Smrj 	{ 0x4b, 16, 64, 8*1024*1024, l3_cache_str},
3767ae115bc7Smrj 	{ 0x4a, 12, 64, 6*1024*1024, l3_cache_str},
3768ae115bc7Smrj 	{ 0x49, 16, 64, 4*1024*1024, l3_cache_str},
3769824e4fecSvd224797 	{ 0x48, 12, 64, 3*1024*1024, l2_cache_str},
3770ae115bc7Smrj 	{ 0x47, 8, 64, 8*1024*1024, l3_cache_str},
3771ae115bc7Smrj 	{ 0x46, 4, 64, 4*1024*1024, l3_cache_str},
37727c478bd9Sstevel@tonic-gate 	{ 0x45, 4, 32, 2*1024*1024, l2_cache_str},
37737c478bd9Sstevel@tonic-gate 	{ 0x44, 4, 32, 1024*1024, l2_cache_str},
37747c478bd9Sstevel@tonic-gate 	{ 0x43, 4, 32, 512*1024, l2_cache_str},
37757c478bd9Sstevel@tonic-gate 	{ 0x42, 4, 32, 256*1024, l2_cache_str},
37767c478bd9Sstevel@tonic-gate 	{ 0x41, 4, 32, 128*1024, l2_cache_str},
3777ae115bc7Smrj 	{ 0x3e, 4, 64, 512*1024, sl2_cache_str},
3778ae115bc7Smrj 	{ 0x3d, 6, 64, 384*1024, sl2_cache_str},
37797c478bd9Sstevel@tonic-gate 	{ 0x3c, 4, 64, 256*1024, sl2_cache_str},
37807c478bd9Sstevel@tonic-gate 	{ 0x3b, 2, 64, 128*1024, sl2_cache_str},
3781ae115bc7Smrj 	{ 0x3a, 6, 64, 192*1024, sl2_cache_str},
37827c478bd9Sstevel@tonic-gate 	{ 0x39, 4, 64, 128*1024, sl2_cache_str},
37837c478bd9Sstevel@tonic-gate 	{ 0x30, 8, 64, 32*1024, l1_icache_str},
37847c478bd9Sstevel@tonic-gate 	{ 0x2c, 8, 64, 32*1024, l1_dcache_str},
37857c478bd9Sstevel@tonic-gate 	{ 0x29, 8, 64, 4096*1024, sl3_cache_str},
37867c478bd9Sstevel@tonic-gate 	{ 0x25, 8, 64, 2048*1024, sl3_cache_str},
37877c478bd9Sstevel@tonic-gate 	{ 0x23, 8, 64, 1024*1024, sl3_cache_str},
37887c478bd9Sstevel@tonic-gate 	{ 0x22, 4, 64, 512*1024, sl3_cache_str},
3789824e4fecSvd224797 	{ 0x0e, 6, 64, 24*1024, l1_dcache_str},
379025dfb062Sksadhukh 	{ 0x0d, 4, 32, 16*1024, l1_dcache_str},
37917c478bd9Sstevel@tonic-gate 	{ 0x0c, 4, 32, 16*1024, l1_dcache_str},
3792ae115bc7Smrj 	{ 0x0b, 4, 0, 4, itlb4M_str},
37937c478bd9Sstevel@tonic-gate 	{ 0x0a, 2, 32, 8*1024, l1_dcache_str},
37947c478bd9Sstevel@tonic-gate 	{ 0x08, 4, 32, 16*1024, l1_icache_str},
37957c478bd9Sstevel@tonic-gate 	{ 0x06, 4, 32, 8*1024, l1_icache_str},
3796824e4fecSvd224797 	{ 0x05, 4, 0, 32, dtlb4M_str},
37977c478bd9Sstevel@tonic-gate 	{ 0x04, 4, 0, 8, dtlb4M_str},
37987c478bd9Sstevel@tonic-gate 	{ 0x03, 4, 0, 64, dtlb4k_str},
37997c478bd9Sstevel@tonic-gate 	{ 0x02, 4, 0, 2, itlb4M_str},
38007c478bd9Sstevel@tonic-gate 	{ 0x01, 4, 0, 32, itlb4k_str},
38017c478bd9Sstevel@tonic-gate 	{ 0 }
38027c478bd9Sstevel@tonic-gate };
38037c478bd9Sstevel@tonic-gate 
38047c478bd9Sstevel@tonic-gate static const struct cachetab cyrix_ctab[] = {
38057c478bd9Sstevel@tonic-gate 	{ 0x70, 4, 0, 32, "tlb-4K" },
38067c478bd9Sstevel@tonic-gate 	{ 0x80, 4, 16, 16*1024, "l1-cache" },
38077c478bd9Sstevel@tonic-gate 	{ 0 }
38087c478bd9Sstevel@tonic-gate };
38097c478bd9Sstevel@tonic-gate 
38107c478bd9Sstevel@tonic-gate /*
38117c478bd9Sstevel@tonic-gate  * Search a cache table for a matching entry
38127c478bd9Sstevel@tonic-gate  */
38137c478bd9Sstevel@tonic-gate static const struct cachetab *
38147c478bd9Sstevel@tonic-gate find_cacheent(const struct cachetab *ct, uint_t code)
38157c478bd9Sstevel@tonic-gate {
38167c478bd9Sstevel@tonic-gate 	if (code != 0) {
38177c478bd9Sstevel@tonic-gate 		for (; ct->ct_code != 0; ct++)
38187c478bd9Sstevel@tonic-gate 			if (ct->ct_code <= code)
38197c478bd9Sstevel@tonic-gate 				break;
38207c478bd9Sstevel@tonic-gate 		if (ct->ct_code == code)
38217c478bd9Sstevel@tonic-gate 			return (ct);
38227c478bd9Sstevel@tonic-gate 	}
38237c478bd9Sstevel@tonic-gate 	return (NULL);
38247c478bd9Sstevel@tonic-gate }
38257c478bd9Sstevel@tonic-gate 
38267c478bd9Sstevel@tonic-gate /*
38277dee861bSksadhukh  * Populate cachetab entry with L2 or L3 cache-information using
38287dee861bSksadhukh  * cpuid function 4. This function is called from intel_walk_cacheinfo()
38297dee861bSksadhukh  * when descriptor 0x49 is encountered. It returns 0 if no such cache
38307dee861bSksadhukh  * information is found.
38317dee861bSksadhukh  */
38327dee861bSksadhukh static int
38337dee861bSksadhukh intel_cpuid_4_cache_info(struct cachetab *ct, struct cpuid_info *cpi)
38347dee861bSksadhukh {
38357dee861bSksadhukh 	uint32_t level, i;
38367dee861bSksadhukh 	int ret = 0;
38377dee861bSksadhukh 
38387dee861bSksadhukh 	for (i = 0; i < cpi->cpi_std_4_size; i++) {
38397dee861bSksadhukh 		level = CPI_CACHE_LVL(cpi->cpi_std_4[i]);
38407dee861bSksadhukh 
38417dee861bSksadhukh 		if (level == 2 || level == 3) {
38427dee861bSksadhukh 			ct->ct_assoc = CPI_CACHE_WAYS(cpi->cpi_std_4[i]) + 1;
38437dee861bSksadhukh 			ct->ct_line_size =
38447dee861bSksadhukh 			    CPI_CACHE_COH_LN_SZ(cpi->cpi_std_4[i]) + 1;
38457dee861bSksadhukh 			ct->ct_size = ct->ct_assoc *
38467dee861bSksadhukh 			    (CPI_CACHE_PARTS(cpi->cpi_std_4[i]) + 1) *
38477dee861bSksadhukh 			    ct->ct_line_size *
38487dee861bSksadhukh 			    (cpi->cpi_std_4[i]->cp_ecx + 1);
38497dee861bSksadhukh 
38507dee861bSksadhukh 			if (level == 2) {
38517dee861bSksadhukh 				ct->ct_label = l2_cache_str;
38527dee861bSksadhukh 			} else if (level == 3) {
38537dee861bSksadhukh 				ct->ct_label = l3_cache_str;
38547dee861bSksadhukh 			}
38557dee861bSksadhukh 			ret = 1;
38567dee861bSksadhukh 		}
38577dee861bSksadhukh 	}
38587dee861bSksadhukh 
38597dee861bSksadhukh 	return (ret);
38607dee861bSksadhukh }
38617dee861bSksadhukh 
38627dee861bSksadhukh /*
38637c478bd9Sstevel@tonic-gate  * Walk the cacheinfo descriptor, applying 'func' to every valid element
38647c478bd9Sstevel@tonic-gate  * The walk is terminated if the walker returns non-zero.
38657c478bd9Sstevel@tonic-gate  */
38667c478bd9Sstevel@tonic-gate static void
38677c478bd9Sstevel@tonic-gate intel_walk_cacheinfo(struct cpuid_info *cpi,
38687c478bd9Sstevel@tonic-gate     void *arg, int (*func)(void *, const struct cachetab *))
38697c478bd9Sstevel@tonic-gate {
38707c478bd9Sstevel@tonic-gate 	const struct cachetab *ct;
3871824e4fecSvd224797 	struct cachetab des_49_ct, des_b1_ct;
38727c478bd9Sstevel@tonic-gate 	uint8_t *dp;
38737c478bd9Sstevel@tonic-gate 	int i;
38747c478bd9Sstevel@tonic-gate 
38757c478bd9Sstevel@tonic-gate 	if ((dp = cpi->cpi_cacheinfo) == NULL)
38767c478bd9Sstevel@tonic-gate 		return;
3877f1d742a9Sksadhukh 	for (i = 0; i < cpi->cpi_ncache; i++, dp++) {
3878f1d742a9Sksadhukh 		/*
3879f1d742a9Sksadhukh 		 * For overloaded descriptor 0x49 we use cpuid function 4
38807dee861bSksadhukh 		 * if supported by the current processor, to create
3881f1d742a9Sksadhukh 		 * cache information.
3882824e4fecSvd224797 		 * For overloaded descriptor 0xb1 we use X86_PAE flag
3883824e4fecSvd224797 		 * to disambiguate the cache information.
3884f1d742a9Sksadhukh 		 */
38857dee861bSksadhukh 		if (*dp == 0x49 && cpi->cpi_maxeax >= 0x4 &&
38867dee861bSksadhukh 		    intel_cpuid_4_cache_info(&des_49_ct, cpi) == 1) {
38877dee861bSksadhukh 				ct = &des_49_ct;
3888824e4fecSvd224797 		} else if (*dp == 0xb1) {
3889824e4fecSvd224797 			des_b1_ct.ct_code = 0xb1;
3890824e4fecSvd224797 			des_b1_ct.ct_assoc = 4;
3891824e4fecSvd224797 			des_b1_ct.ct_line_size = 0;
38927417cfdeSKuriakose Kuruvilla 			if (is_x86_feature(x86_featureset, X86FSET_PAE)) {
3893824e4fecSvd224797 				des_b1_ct.ct_size = 8;
3894824e4fecSvd224797 				des_b1_ct.ct_label = itlb2M_str;
3895824e4fecSvd224797 			} else {
3896824e4fecSvd224797 				des_b1_ct.ct_size = 4;
3897824e4fecSvd224797 				des_b1_ct.ct_label = itlb4M_str;
3898824e4fecSvd224797 			}
3899824e4fecSvd224797 			ct = &des_b1_ct;
39007dee861bSksadhukh 		} else {
39017dee861bSksadhukh 			if ((ct = find_cacheent(intel_ctab, *dp)) == NULL) {
3902f1d742a9Sksadhukh 				continue;
3903f1d742a9Sksadhukh 			}
39047dee861bSksadhukh 		}
3905f1d742a9Sksadhukh 
39067dee861bSksadhukh 		if (func(arg, ct) != 0) {
39077c478bd9Sstevel@tonic-gate 			break;
39087c478bd9Sstevel@tonic-gate 		}
39097c478bd9Sstevel@tonic-gate 	}
3910f1d742a9Sksadhukh }
39117c478bd9Sstevel@tonic-gate 
39127c478bd9Sstevel@tonic-gate /*
39137c478bd9Sstevel@tonic-gate  * (Like the Intel one, except for Cyrix CPUs)
39147c478bd9Sstevel@tonic-gate  */
39157c478bd9Sstevel@tonic-gate static void
39167c478bd9Sstevel@tonic-gate cyrix_walk_cacheinfo(struct cpuid_info *cpi,
39177c478bd9Sstevel@tonic-gate     void *arg, int (*func)(void *, const struct cachetab *))
39187c478bd9Sstevel@tonic-gate {
39197c478bd9Sstevel@tonic-gate 	const struct cachetab *ct;
39207c478bd9Sstevel@tonic-gate 	uint8_t *dp;
39217c478bd9Sstevel@tonic-gate 	int i;
39227c478bd9Sstevel@tonic-gate 
39237c478bd9Sstevel@tonic-gate 	if ((dp = cpi->cpi_cacheinfo) == NULL)
39247c478bd9Sstevel@tonic-gate 		return;
39257c478bd9Sstevel@tonic-gate 	for (i = 0; i < cpi->cpi_ncache; i++, dp++) {
39267c478bd9Sstevel@tonic-gate 		/*
39277c478bd9Sstevel@tonic-gate 		 * Search Cyrix-specific descriptor table first ..
39287c478bd9Sstevel@tonic-gate 		 */
39297c478bd9Sstevel@tonic-gate 		if ((ct = find_cacheent(cyrix_ctab, *dp)) != NULL) {
39307c478bd9Sstevel@tonic-gate 			if (func(arg, ct) != 0)
39317c478bd9Sstevel@tonic-gate 				break;
39327c478bd9Sstevel@tonic-gate 			continue;
39337c478bd9Sstevel@tonic-gate 		}
39347c478bd9Sstevel@tonic-gate 		/*
39357c478bd9Sstevel@tonic-gate 		 * .. else fall back to the Intel one
39367c478bd9Sstevel@tonic-gate 		 */
39377c478bd9Sstevel@tonic-gate 		if ((ct = find_cacheent(intel_ctab, *dp)) != NULL) {
39387c478bd9Sstevel@tonic-gate 			if (func(arg, ct) != 0)
39397c478bd9Sstevel@tonic-gate 				break;
39407c478bd9Sstevel@tonic-gate 			continue;
39417c478bd9Sstevel@tonic-gate 		}
39427c478bd9Sstevel@tonic-gate 	}
39437c478bd9Sstevel@tonic-gate }
39447c478bd9Sstevel@tonic-gate 
39457c478bd9Sstevel@tonic-gate /*
39467c478bd9Sstevel@tonic-gate  * A cacheinfo walker that adds associativity, line-size, and size properties
39477c478bd9Sstevel@tonic-gate  * to the devinfo node it is passed as an argument.
39487c478bd9Sstevel@tonic-gate  */
39497c478bd9Sstevel@tonic-gate static int
39507c478bd9Sstevel@tonic-gate add_cacheent_props(void *arg, const struct cachetab *ct)
39517c478bd9Sstevel@tonic-gate {
39527c478bd9Sstevel@tonic-gate 	dev_info_t *devi = arg;
39537c478bd9Sstevel@tonic-gate 
39547c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, ct->ct_label, assoc_str, ct->ct_assoc);
39557c478bd9Sstevel@tonic-gate 	if (ct->ct_line_size != 0)
39567c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, ct->ct_label, line_str,
39577c478bd9Sstevel@tonic-gate 		    ct->ct_line_size);
39587c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, ct->ct_label, size_str, ct->ct_size);
39597c478bd9Sstevel@tonic-gate 	return (0);
39607c478bd9Sstevel@tonic-gate }
39617c478bd9Sstevel@tonic-gate 
3962f1d742a9Sksadhukh 
39637c478bd9Sstevel@tonic-gate static const char fully_assoc[] = "fully-associative?";
39647c478bd9Sstevel@tonic-gate 
39657c478bd9Sstevel@tonic-gate /*
39667c478bd9Sstevel@tonic-gate  * AMD style cache/tlb description
39677c478bd9Sstevel@tonic-gate  *
39687c478bd9Sstevel@tonic-gate  * Extended functions 5 and 6 directly describe properties of
39697c478bd9Sstevel@tonic-gate  * tlbs and various cache levels.
39707c478bd9Sstevel@tonic-gate  */
39717c478bd9Sstevel@tonic-gate static void
39727c478bd9Sstevel@tonic-gate add_amd_assoc(dev_info_t *devi, const char *label, uint_t assoc)
39737c478bd9Sstevel@tonic-gate {
39747c478bd9Sstevel@tonic-gate 	switch (assoc) {
39757c478bd9Sstevel@tonic-gate 	case 0:	/* reserved; ignore */
39767c478bd9Sstevel@tonic-gate 		break;
39777c478bd9Sstevel@tonic-gate 	default:
39787c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, assoc_str, assoc);
39797c478bd9Sstevel@tonic-gate 		break;
39807c478bd9Sstevel@tonic-gate 	case 0xff:
39817c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, fully_assoc, 1);
39827c478bd9Sstevel@tonic-gate 		break;
39837c478bd9Sstevel@tonic-gate 	}
39847c478bd9Sstevel@tonic-gate }
39857c478bd9Sstevel@tonic-gate 
39867c478bd9Sstevel@tonic-gate static void
39877c478bd9Sstevel@tonic-gate add_amd_tlb(dev_info_t *devi, const char *label, uint_t assoc, uint_t size)
39887c478bd9Sstevel@tonic-gate {
39897c478bd9Sstevel@tonic-gate 	if (size == 0)
39907c478bd9Sstevel@tonic-gate 		return;
39917c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, size_str, size);
39927c478bd9Sstevel@tonic-gate 	add_amd_assoc(devi, label, assoc);
39937c478bd9Sstevel@tonic-gate }
39947c478bd9Sstevel@tonic-gate 
39957c478bd9Sstevel@tonic-gate static void
39967c478bd9Sstevel@tonic-gate add_amd_cache(dev_info_t *devi, const char *label,
39977c478bd9Sstevel@tonic-gate     uint_t size, uint_t assoc, uint_t lines_per_tag, uint_t line_size)
39987c478bd9Sstevel@tonic-gate {
39997c478bd9Sstevel@tonic-gate 	if (size == 0 || line_size == 0)
40007c478bd9Sstevel@tonic-gate 		return;
40017c478bd9Sstevel@tonic-gate 	add_amd_assoc(devi, label, assoc);
40027c478bd9Sstevel@tonic-gate 	/*
40037c478bd9Sstevel@tonic-gate 	 * Most AMD parts have a sectored cache. Multiple cache lines are
40047c478bd9Sstevel@tonic-gate 	 * associated with each tag. A sector consists of all cache lines
40057c478bd9Sstevel@tonic-gate 	 * associated with a tag. For example, the AMD K6-III has a sector
40067c478bd9Sstevel@tonic-gate 	 * size of 2 cache lines per tag.
40077c478bd9Sstevel@tonic-gate 	 */
40087c478bd9Sstevel@tonic-gate 	if (lines_per_tag != 0)
40097c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, "lines-per-tag", lines_per_tag);
40107c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, line_str, line_size);
40117c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, size_str, size * 1024);
40127c478bd9Sstevel@tonic-gate }
40137c478bd9Sstevel@tonic-gate 
40147c478bd9Sstevel@tonic-gate static void
40157c478bd9Sstevel@tonic-gate add_amd_l2_assoc(dev_info_t *devi, const char *label, uint_t assoc)
40167c478bd9Sstevel@tonic-gate {
40177c478bd9Sstevel@tonic-gate 	switch (assoc) {
40187c478bd9Sstevel@tonic-gate 	case 0:	/* off */
40197c478bd9Sstevel@tonic-gate 		break;
40207c478bd9Sstevel@tonic-gate 	case 1:
40217c478bd9Sstevel@tonic-gate 	case 2:
40227c478bd9Sstevel@tonic-gate 	case 4:
40237c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, assoc_str, assoc);
40247c478bd9Sstevel@tonic-gate 		break;
40257c478bd9Sstevel@tonic-gate 	case 6:
40267c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, assoc_str, 8);
40277c478bd9Sstevel@tonic-gate 		break;
40287c478bd9Sstevel@tonic-gate 	case 8:
40297c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, assoc_str, 16);
40307c478bd9Sstevel@tonic-gate 		break;
40317c478bd9Sstevel@tonic-gate 	case 0xf:
40327c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, fully_assoc, 1);
40337c478bd9Sstevel@tonic-gate 		break;
40347c478bd9Sstevel@tonic-gate 	default: /* reserved; ignore */
40357c478bd9Sstevel@tonic-gate 		break;
40367c478bd9Sstevel@tonic-gate 	}
40377c478bd9Sstevel@tonic-gate }
40387c478bd9Sstevel@tonic-gate 
40397c478bd9Sstevel@tonic-gate static void
40407c478bd9Sstevel@tonic-gate add_amd_l2_tlb(dev_info_t *devi, const char *label, uint_t assoc, uint_t size)
40417c478bd9Sstevel@tonic-gate {
40427c478bd9Sstevel@tonic-gate 	if (size == 0 || assoc == 0)
40437c478bd9Sstevel@tonic-gate 		return;
40447c478bd9Sstevel@tonic-gate 	add_amd_l2_assoc(devi, label, assoc);
40457c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, size_str, size);
40467c478bd9Sstevel@tonic-gate }
40477c478bd9Sstevel@tonic-gate 
40487c478bd9Sstevel@tonic-gate static void
40497c478bd9Sstevel@tonic-gate add_amd_l2_cache(dev_info_t *devi, const char *label,
40507c478bd9Sstevel@tonic-gate     uint_t size, uint_t assoc, uint_t lines_per_tag, uint_t line_size)
40517c478bd9Sstevel@tonic-gate {
40527c478bd9Sstevel@tonic-gate 	if (size == 0 || assoc == 0 || line_size == 0)
40537c478bd9Sstevel@tonic-gate 		return;
40547c478bd9Sstevel@tonic-gate 	add_amd_l2_assoc(devi, label, assoc);
40557c478bd9Sstevel@tonic-gate 	if (lines_per_tag != 0)
40567c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, "lines-per-tag", lines_per_tag);
40577c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, line_str, line_size);
40587c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, size_str, size * 1024);
40597c478bd9Sstevel@tonic-gate }
40607c478bd9Sstevel@tonic-gate 
40617c478bd9Sstevel@tonic-gate static void
40627c478bd9Sstevel@tonic-gate amd_cache_info(struct cpuid_info *cpi, dev_info_t *devi)
40637c478bd9Sstevel@tonic-gate {
40648949bcd6Sandrei 	struct cpuid_regs *cp;
40657c478bd9Sstevel@tonic-gate 
40667c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax < 0x80000005)
40677c478bd9Sstevel@tonic-gate 		return;
40687c478bd9Sstevel@tonic-gate 	cp = &cpi->cpi_extd[5];
40697c478bd9Sstevel@tonic-gate 
40707c478bd9Sstevel@tonic-gate 	/*
40717c478bd9Sstevel@tonic-gate 	 * 4M/2M L1 TLB configuration
40727c478bd9Sstevel@tonic-gate 	 *
40737c478bd9Sstevel@tonic-gate 	 * We report the size for 2M pages because AMD uses two
40747c478bd9Sstevel@tonic-gate 	 * TLB entries for one 4M page.
40757c478bd9Sstevel@tonic-gate 	 */
40767c478bd9Sstevel@tonic-gate 	add_amd_tlb(devi, "dtlb-2M",
40777c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_eax, 31, 24), BITX(cp->cp_eax, 23, 16));
40787c478bd9Sstevel@tonic-gate 	add_amd_tlb(devi, "itlb-2M",
40797c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_eax, 15, 8), BITX(cp->cp_eax, 7, 0));
40807c478bd9Sstevel@tonic-gate 
40817c478bd9Sstevel@tonic-gate 	/*
40827c478bd9Sstevel@tonic-gate 	 * 4K L1 TLB configuration
40837c478bd9Sstevel@tonic-gate 	 */
40847c478bd9Sstevel@tonic-gate 
40857c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
40867c478bd9Sstevel@tonic-gate 		uint_t nentries;
40877c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
40887c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family >= 5) {
40897c478bd9Sstevel@tonic-gate 			/*
40907c478bd9Sstevel@tonic-gate 			 * Crusoe processors have 256 TLB entries, but
40917c478bd9Sstevel@tonic-gate 			 * cpuid data format constrains them to only
40927c478bd9Sstevel@tonic-gate 			 * reporting 255 of them.
40937c478bd9Sstevel@tonic-gate 			 */
40947c478bd9Sstevel@tonic-gate 			if ((nentries = BITX(cp->cp_ebx, 23, 16)) == 255)
40957c478bd9Sstevel@tonic-gate 				nentries = 256;
40967c478bd9Sstevel@tonic-gate 			/*
40977c478bd9Sstevel@tonic-gate 			 * Crusoe processors also have a unified TLB
40987c478bd9Sstevel@tonic-gate 			 */
40997c478bd9Sstevel@tonic-gate 			add_amd_tlb(devi, "tlb-4K", BITX(cp->cp_ebx, 31, 24),
41007c478bd9Sstevel@tonic-gate 			    nentries);
41017c478bd9Sstevel@tonic-gate 			break;
41027c478bd9Sstevel@tonic-gate 		}
41037c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
41047c478bd9Sstevel@tonic-gate 	default:
41057c478bd9Sstevel@tonic-gate 		add_amd_tlb(devi, itlb4k_str,
41067c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_ebx, 31, 24), BITX(cp->cp_ebx, 23, 16));
41077c478bd9Sstevel@tonic-gate 		add_amd_tlb(devi, dtlb4k_str,
41087c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_ebx, 15, 8), BITX(cp->cp_ebx, 7, 0));
41097c478bd9Sstevel@tonic-gate 		break;
41107c478bd9Sstevel@tonic-gate 	}
41117c478bd9Sstevel@tonic-gate 
41127c478bd9Sstevel@tonic-gate 	/*
41137c478bd9Sstevel@tonic-gate 	 * data L1 cache configuration
41147c478bd9Sstevel@tonic-gate 	 */
41157c478bd9Sstevel@tonic-gate 
41167c478bd9Sstevel@tonic-gate 	add_amd_cache(devi, l1_dcache_str,
41177c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_ecx, 31, 24), BITX(cp->cp_ecx, 23, 16),
41187c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_ecx, 15, 8), BITX(cp->cp_ecx, 7, 0));
41197c478bd9Sstevel@tonic-gate 
41207c478bd9Sstevel@tonic-gate 	/*
41217c478bd9Sstevel@tonic-gate 	 * code L1 cache configuration
41227c478bd9Sstevel@tonic-gate 	 */
41237c478bd9Sstevel@tonic-gate 
41247c478bd9Sstevel@tonic-gate 	add_amd_cache(devi, l1_icache_str,
41257c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_edx, 31, 24), BITX(cp->cp_edx, 23, 16),
41267c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_edx, 15, 8), BITX(cp->cp_edx, 7, 0));
41277c478bd9Sstevel@tonic-gate 
41287c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax < 0x80000006)
41297c478bd9Sstevel@tonic-gate 		return;
41307c478bd9Sstevel@tonic-gate 	cp = &cpi->cpi_extd[6];
41317c478bd9Sstevel@tonic-gate 
41327c478bd9Sstevel@tonic-gate 	/* Check for a unified L2 TLB for large pages */
41337c478bd9Sstevel@tonic-gate 
41347c478bd9Sstevel@tonic-gate 	if (BITX(cp->cp_eax, 31, 16) == 0)
41357c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-tlb-2M",
41367c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0));
41377c478bd9Sstevel@tonic-gate 	else {
41387c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-dtlb-2M",
41397c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 31, 28), BITX(cp->cp_eax, 27, 16));
41407c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-itlb-2M",
41417c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0));
41427c478bd9Sstevel@tonic-gate 	}
41437c478bd9Sstevel@tonic-gate 
41447c478bd9Sstevel@tonic-gate 	/* Check for a unified L2 TLB for 4K pages */
41457c478bd9Sstevel@tonic-gate 
41467c478bd9Sstevel@tonic-gate 	if (BITX(cp->cp_ebx, 31, 16) == 0) {
41477c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-tlb-4K",
41487c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0));
41497c478bd9Sstevel@tonic-gate 	} else {
41507c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-dtlb-4K",
41517c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 31, 28), BITX(cp->cp_eax, 27, 16));
41527c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-itlb-4K",
41537c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0));
41547c478bd9Sstevel@tonic-gate 	}
41557c478bd9Sstevel@tonic-gate 
41567c478bd9Sstevel@tonic-gate 	add_amd_l2_cache(devi, l2_cache_str,
41577c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_ecx, 31, 16), BITX(cp->cp_ecx, 15, 12),
41587c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_ecx, 11, 8), BITX(cp->cp_ecx, 7, 0));
41597c478bd9Sstevel@tonic-gate }
41607c478bd9Sstevel@tonic-gate 
41617c478bd9Sstevel@tonic-gate /*
41627c478bd9Sstevel@tonic-gate  * There are two basic ways that the x86 world describes it cache
41637c478bd9Sstevel@tonic-gate  * and tlb architecture - Intel's way and AMD's way.
41647c478bd9Sstevel@tonic-gate  *
41657c478bd9Sstevel@tonic-gate  * Return which flavor of cache architecture we should use
41667c478bd9Sstevel@tonic-gate  */
41677c478bd9Sstevel@tonic-gate static int
41687c478bd9Sstevel@tonic-gate x86_which_cacheinfo(struct cpuid_info *cpi)
41697c478bd9Sstevel@tonic-gate {
41707c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
41717c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
41727c478bd9Sstevel@tonic-gate 		if (cpi->cpi_maxeax >= 2)
41737c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_Intel);
41747c478bd9Sstevel@tonic-gate 		break;
41757c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
41767c478bd9Sstevel@tonic-gate 		/*
41777c478bd9Sstevel@tonic-gate 		 * The K5 model 1 was the first part from AMD that reported
41787c478bd9Sstevel@tonic-gate 		 * cache sizes via extended cpuid functions.
41797c478bd9Sstevel@tonic-gate 		 */
41807c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family > 5 ||
41817c478bd9Sstevel@tonic-gate 		    (cpi->cpi_family == 5 && cpi->cpi_model >= 1))
41827c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_AMD);
41837c478bd9Sstevel@tonic-gate 		break;
41847c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
41857c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family >= 5)
41867c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_AMD);
41877c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
41887c478bd9Sstevel@tonic-gate 	default:
41897c478bd9Sstevel@tonic-gate 		/*
41907c478bd9Sstevel@tonic-gate 		 * If they have extended CPU data for 0x80000005
41917c478bd9Sstevel@tonic-gate 		 * then we assume they have AMD-format cache
41927c478bd9Sstevel@tonic-gate 		 * information.
41937c478bd9Sstevel@tonic-gate 		 *
41947c478bd9Sstevel@tonic-gate 		 * If not, and the vendor happens to be Cyrix,
41957c478bd9Sstevel@tonic-gate 		 * then try our-Cyrix specific handler.
41967c478bd9Sstevel@tonic-gate 		 *
41977c478bd9Sstevel@tonic-gate 		 * If we're not Cyrix, then assume we're using Intel's
41987c478bd9Sstevel@tonic-gate 		 * table-driven format instead.
41997c478bd9Sstevel@tonic-gate 		 */
42007c478bd9Sstevel@tonic-gate 		if (cpi->cpi_xmaxeax >= 0x80000005)
42017c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_AMD);
42027c478bd9Sstevel@tonic-gate 		else if (cpi->cpi_vendor == X86_VENDOR_Cyrix)
42037c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_Cyrix);
42047c478bd9Sstevel@tonic-gate 		else if (cpi->cpi_maxeax >= 2)
42057c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_Intel);
42067c478bd9Sstevel@tonic-gate 		break;
42077c478bd9Sstevel@tonic-gate 	}
42087c478bd9Sstevel@tonic-gate 	return (-1);
42097c478bd9Sstevel@tonic-gate }
42107c478bd9Sstevel@tonic-gate 
42117c478bd9Sstevel@tonic-gate void
4212fa96bd91SMichael Corcoran cpuid_set_cpu_properties(void *dip, processorid_t cpu_id,
4213fa96bd91SMichael Corcoran     struct cpuid_info *cpi)
42147c478bd9Sstevel@tonic-gate {
42157c478bd9Sstevel@tonic-gate 	dev_info_t *cpu_devi;
42167c478bd9Sstevel@tonic-gate 	int create;
42177c478bd9Sstevel@tonic-gate 
4218fa96bd91SMichael Corcoran 	cpu_devi = (dev_info_t *)dip;
42197c478bd9Sstevel@tonic-gate 
42207c478bd9Sstevel@tonic-gate 	/* device_type */
42217c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, cpu_devi,
42227c478bd9Sstevel@tonic-gate 	    "device_type", "cpu");
42237c478bd9Sstevel@tonic-gate 
42247c478bd9Sstevel@tonic-gate 	/* reg */
42257c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
42267c478bd9Sstevel@tonic-gate 	    "reg", cpu_id);
42277c478bd9Sstevel@tonic-gate 
42287c478bd9Sstevel@tonic-gate 	/* cpu-mhz, and clock-frequency */
42297c478bd9Sstevel@tonic-gate 	if (cpu_freq > 0) {
42307c478bd9Sstevel@tonic-gate 		long long mul;
42317c478bd9Sstevel@tonic-gate 
42327c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
42337c478bd9Sstevel@tonic-gate 		    "cpu-mhz", cpu_freq);
42347c478bd9Sstevel@tonic-gate 		if ((mul = cpu_freq * 1000000LL) <= INT_MAX)
42357c478bd9Sstevel@tonic-gate 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
42367c478bd9Sstevel@tonic-gate 			    "clock-frequency", (int)mul);
42377c478bd9Sstevel@tonic-gate 	}
42387c478bd9Sstevel@tonic-gate 
42397417cfdeSKuriakose Kuruvilla 	if (!is_x86_feature(x86_featureset, X86FSET_CPUID)) {
42407c478bd9Sstevel@tonic-gate 		return;
42417c478bd9Sstevel@tonic-gate 	}
42427c478bd9Sstevel@tonic-gate 
42437c478bd9Sstevel@tonic-gate 	/* vendor-id */
42447c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, cpu_devi,
42457c478bd9Sstevel@tonic-gate 	    "vendor-id", cpi->cpi_vendorstr);
42467c478bd9Sstevel@tonic-gate 
42477c478bd9Sstevel@tonic-gate 	if (cpi->cpi_maxeax == 0) {
42487c478bd9Sstevel@tonic-gate 		return;
42497c478bd9Sstevel@tonic-gate 	}
42507c478bd9Sstevel@tonic-gate 
42517c478bd9Sstevel@tonic-gate 	/*
42527c478bd9Sstevel@tonic-gate 	 * family, model, and step
42537c478bd9Sstevel@tonic-gate 	 */
42547c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
42557c478bd9Sstevel@tonic-gate 	    "family", CPI_FAMILY(cpi));
42567c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
42577c478bd9Sstevel@tonic-gate 	    "cpu-model", CPI_MODEL(cpi));
42587c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
42597c478bd9Sstevel@tonic-gate 	    "stepping-id", CPI_STEP(cpi));
42607c478bd9Sstevel@tonic-gate 
42617c478bd9Sstevel@tonic-gate 	/* type */
42627c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
42637c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
42647c478bd9Sstevel@tonic-gate 		create = 1;
42657c478bd9Sstevel@tonic-gate 		break;
42667c478bd9Sstevel@tonic-gate 	default:
42677c478bd9Sstevel@tonic-gate 		create = 0;
42687c478bd9Sstevel@tonic-gate 		break;
42697c478bd9Sstevel@tonic-gate 	}
42707c478bd9Sstevel@tonic-gate 	if (create)
42717c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
42727c478bd9Sstevel@tonic-gate 		    "type", CPI_TYPE(cpi));
42737c478bd9Sstevel@tonic-gate 
42747c478bd9Sstevel@tonic-gate 	/* ext-family */
42757c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
42767c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
42777c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
42787c478bd9Sstevel@tonic-gate 		create = cpi->cpi_family >= 0xf;
42797c478bd9Sstevel@tonic-gate 		break;
42807c478bd9Sstevel@tonic-gate 	default:
42817c478bd9Sstevel@tonic-gate 		create = 0;
42827c478bd9Sstevel@tonic-gate 		break;
42837c478bd9Sstevel@tonic-gate 	}
42847c478bd9Sstevel@tonic-gate 	if (create)
42857c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
42867c478bd9Sstevel@tonic-gate 		    "ext-family", CPI_FAMILY_XTD(cpi));
42877c478bd9Sstevel@tonic-gate 
42887c478bd9Sstevel@tonic-gate 	/* ext-model */
42897c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
42907c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
429163d3f7dfSkk208521 		create = IS_EXTENDED_MODEL_INTEL(cpi);
429268c91426Sdmick 		break;
42937c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
4294ee88d2b9Skchow 		create = CPI_FAMILY(cpi) == 0xf;
42957c478bd9Sstevel@tonic-gate 		break;
42967c478bd9Sstevel@tonic-gate 	default:
42977c478bd9Sstevel@tonic-gate 		create = 0;
42987c478bd9Sstevel@tonic-gate 		break;
42997c478bd9Sstevel@tonic-gate 	}
43007c478bd9Sstevel@tonic-gate 	if (create)
43017c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
43027c478bd9Sstevel@tonic-gate 		    "ext-model", CPI_MODEL_XTD(cpi));
43037c478bd9Sstevel@tonic-gate 
43047c478bd9Sstevel@tonic-gate 	/* generation */
43057c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
43067c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
43077c478bd9Sstevel@tonic-gate 		/*
43087c478bd9Sstevel@tonic-gate 		 * AMD K5 model 1 was the first part to support this
43097c478bd9Sstevel@tonic-gate 		 */
43107c478bd9Sstevel@tonic-gate 		create = cpi->cpi_xmaxeax >= 0x80000001;
43117c478bd9Sstevel@tonic-gate 		break;
43127c478bd9Sstevel@tonic-gate 	default:
43137c478bd9Sstevel@tonic-gate 		create = 0;
43147c478bd9Sstevel@tonic-gate 		break;
43157c478bd9Sstevel@tonic-gate 	}
43167c478bd9Sstevel@tonic-gate 	if (create)
43177c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
43187c478bd9Sstevel@tonic-gate 		    "generation", BITX((cpi)->cpi_extd[1].cp_eax, 11, 8));
43197c478bd9Sstevel@tonic-gate 
43207c478bd9Sstevel@tonic-gate 	/* brand-id */
43217c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
43227c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
43237c478bd9Sstevel@tonic-gate 		/*
43247c478bd9Sstevel@tonic-gate 		 * brand id first appeared on Pentium III Xeon model 8,
43257c478bd9Sstevel@tonic-gate 		 * and Celeron model 8 processors and Opteron
43267c478bd9Sstevel@tonic-gate 		 */
43277c478bd9Sstevel@tonic-gate 		create = cpi->cpi_family > 6 ||
43287c478bd9Sstevel@tonic-gate 		    (cpi->cpi_family == 6 && cpi->cpi_model >= 8);
43297c478bd9Sstevel@tonic-gate 		break;
43307c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
43317c478bd9Sstevel@tonic-gate 		create = cpi->cpi_family >= 0xf;
43327c478bd9Sstevel@tonic-gate 		break;
43337c478bd9Sstevel@tonic-gate 	default:
43347c478bd9Sstevel@tonic-gate 		create = 0;
43357c478bd9Sstevel@tonic-gate 		break;
43367c478bd9Sstevel@tonic-gate 	}
43377c478bd9Sstevel@tonic-gate 	if (create && cpi->cpi_brandid != 0) {
43387c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
43397c478bd9Sstevel@tonic-gate 		    "brand-id", cpi->cpi_brandid);
43407c478bd9Sstevel@tonic-gate 	}
43417c478bd9Sstevel@tonic-gate 
43427c478bd9Sstevel@tonic-gate 	/* chunks, and apic-id */
43437c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
43447c478bd9Sstevel@tonic-gate 		/*
43457c478bd9Sstevel@tonic-gate 		 * first available on Pentium IV and Opteron (K8)
43467c478bd9Sstevel@tonic-gate 		 */
43475ff02082Sdmick 	case X86_VENDOR_Intel:
43485ff02082Sdmick 		create = IS_NEW_F6(cpi) || cpi->cpi_family >= 0xf;
43495ff02082Sdmick 		break;
43505ff02082Sdmick 	case X86_VENDOR_AMD:
43517c478bd9Sstevel@tonic-gate 		create = cpi->cpi_family >= 0xf;
43527c478bd9Sstevel@tonic-gate 		break;
43537c478bd9Sstevel@tonic-gate 	default:
43547c478bd9Sstevel@tonic-gate 		create = 0;
43557c478bd9Sstevel@tonic-gate 		break;
43567c478bd9Sstevel@tonic-gate 	}
43577c478bd9Sstevel@tonic-gate 	if (create) {
43587c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
43597c478bd9Sstevel@tonic-gate 		    "chunks", CPI_CHUNKS(cpi));
43607c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
4361b6917abeSmishra 		    "apic-id", cpi->cpi_apicid);
43627aec1d6eScindi 		if (cpi->cpi_chipid >= 0) {
43637c478bd9Sstevel@tonic-gate 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
43647c478bd9Sstevel@tonic-gate 			    "chip#", cpi->cpi_chipid);
43657aec1d6eScindi 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
43667aec1d6eScindi 			    "clog#", cpi->cpi_clogid);
43677aec1d6eScindi 		}
43687c478bd9Sstevel@tonic-gate 	}
43697c478bd9Sstevel@tonic-gate 
43707c478bd9Sstevel@tonic-gate 	/* cpuid-features */
43717c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
43727c478bd9Sstevel@tonic-gate 	    "cpuid-features", CPI_FEATURES_EDX(cpi));
43737c478bd9Sstevel@tonic-gate 
43747c478bd9Sstevel@tonic-gate 
43757c478bd9Sstevel@tonic-gate 	/* cpuid-features-ecx */
43767c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
43777c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
43785ff02082Sdmick 		create = IS_NEW_F6(cpi) || cpi->cpi_family >= 0xf;
43797c478bd9Sstevel@tonic-gate 		break;
438063408480SHans Rosenfeld 	case X86_VENDOR_AMD:
438163408480SHans Rosenfeld 		create = cpi->cpi_family >= 0xf;
438263408480SHans Rosenfeld 		break;
43837c478bd9Sstevel@tonic-gate 	default:
43847c478bd9Sstevel@tonic-gate 		create = 0;
43857c478bd9Sstevel@tonic-gate 		break;
43867c478bd9Sstevel@tonic-gate 	}
43877c478bd9Sstevel@tonic-gate 	if (create)
43887c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
43897c478bd9Sstevel@tonic-gate 		    "cpuid-features-ecx", CPI_FEATURES_ECX(cpi));
43907c478bd9Sstevel@tonic-gate 
43917c478bd9Sstevel@tonic-gate 	/* ext-cpuid-features */
43927c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
43935ff02082Sdmick 	case X86_VENDOR_Intel:
43947c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
43957c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
43967c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
43977c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Centaur:
43987c478bd9Sstevel@tonic-gate 		create = cpi->cpi_xmaxeax >= 0x80000001;
43997c478bd9Sstevel@tonic-gate 		break;
44007c478bd9Sstevel@tonic-gate 	default:
44017c478bd9Sstevel@tonic-gate 		create = 0;
44027c478bd9Sstevel@tonic-gate 		break;
44037c478bd9Sstevel@tonic-gate 	}
44045ff02082Sdmick 	if (create) {
44057c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
44067c478bd9Sstevel@tonic-gate 		    "ext-cpuid-features", CPI_FEATURES_XTD_EDX(cpi));
44075ff02082Sdmick 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
44085ff02082Sdmick 		    "ext-cpuid-features-ecx", CPI_FEATURES_XTD_ECX(cpi));
44095ff02082Sdmick 	}
44107c478bd9Sstevel@tonic-gate 
44117c478bd9Sstevel@tonic-gate 	/*
44127c478bd9Sstevel@tonic-gate 	 * Brand String first appeared in Intel Pentium IV, AMD K5
44137c478bd9Sstevel@tonic-gate 	 * model 1, and Cyrix GXm.  On earlier models we try and
44147c478bd9Sstevel@tonic-gate 	 * simulate something similar .. so this string should always
44157c478bd9Sstevel@tonic-gate 	 * same -something- about the processor, however lame.
44167c478bd9Sstevel@tonic-gate 	 */
44177c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, cpu_devi,
44187c478bd9Sstevel@tonic-gate 	    "brand-string", cpi->cpi_brandstr);
44197c478bd9Sstevel@tonic-gate 
44207c478bd9Sstevel@tonic-gate 	/*
44217c478bd9Sstevel@tonic-gate 	 * Finally, cache and tlb information
44227c478bd9Sstevel@tonic-gate 	 */
44237c478bd9Sstevel@tonic-gate 	switch (x86_which_cacheinfo(cpi)) {
44247c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
44257c478bd9Sstevel@tonic-gate 		intel_walk_cacheinfo(cpi, cpu_devi, add_cacheent_props);
44267c478bd9Sstevel@tonic-gate 		break;
44277c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
44287c478bd9Sstevel@tonic-gate 		cyrix_walk_cacheinfo(cpi, cpu_devi, add_cacheent_props);
44297c478bd9Sstevel@tonic-gate 		break;
44307c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
44317c478bd9Sstevel@tonic-gate 		amd_cache_info(cpi, cpu_devi);
44327c478bd9Sstevel@tonic-gate 		break;
44337c478bd9Sstevel@tonic-gate 	default:
44347c478bd9Sstevel@tonic-gate 		break;
44357c478bd9Sstevel@tonic-gate 	}
44367c478bd9Sstevel@tonic-gate }
44377c478bd9Sstevel@tonic-gate 
44387c478bd9Sstevel@tonic-gate struct l2info {
44397c478bd9Sstevel@tonic-gate 	int *l2i_csz;
44407c478bd9Sstevel@tonic-gate 	int *l2i_lsz;
44417c478bd9Sstevel@tonic-gate 	int *l2i_assoc;
44427c478bd9Sstevel@tonic-gate 	int l2i_ret;
44437c478bd9Sstevel@tonic-gate };
44447c478bd9Sstevel@tonic-gate 
44457c478bd9Sstevel@tonic-gate /*
44467c478bd9Sstevel@tonic-gate  * A cacheinfo walker that fetches the size, line-size and associativity
44477c478bd9Sstevel@tonic-gate  * of the L2 cache
44487c478bd9Sstevel@tonic-gate  */
44497c478bd9Sstevel@tonic-gate static int
44507c478bd9Sstevel@tonic-gate intel_l2cinfo(void *arg, const struct cachetab *ct)
44517c478bd9Sstevel@tonic-gate {
44527c478bd9Sstevel@tonic-gate 	struct l2info *l2i = arg;
44537c478bd9Sstevel@tonic-gate 	int *ip;
44547c478bd9Sstevel@tonic-gate 
44557c478bd9Sstevel@tonic-gate 	if (ct->ct_label != l2_cache_str &&
44567c478bd9Sstevel@tonic-gate 	    ct->ct_label != sl2_cache_str)
44577c478bd9Sstevel@tonic-gate 		return (0);	/* not an L2 -- keep walking */
44587c478bd9Sstevel@tonic-gate 
44597c478bd9Sstevel@tonic-gate 	if ((ip = l2i->l2i_csz) != NULL)
44607c478bd9Sstevel@tonic-gate 		*ip = ct->ct_size;
44617c478bd9Sstevel@tonic-gate 	if ((ip = l2i->l2i_lsz) != NULL)
44627c478bd9Sstevel@tonic-gate 		*ip = ct->ct_line_size;
44637c478bd9Sstevel@tonic-gate 	if ((ip = l2i->l2i_assoc) != NULL)
44647c478bd9Sstevel@tonic-gate 		*ip = ct->ct_assoc;
44657c478bd9Sstevel@tonic-gate 	l2i->l2i_ret = ct->ct_size;
44667c478bd9Sstevel@tonic-gate 	return (1);		/* was an L2 -- terminate walk */
44677c478bd9Sstevel@tonic-gate }
44687c478bd9Sstevel@tonic-gate 
4469606303c9Skchow /*
4470606303c9Skchow  * AMD L2/L3 Cache and TLB Associativity Field Definition:
4471606303c9Skchow  *
4472606303c9Skchow  *	Unlike the associativity for the L1 cache and tlb where the 8 bit
4473606303c9Skchow  *	value is the associativity, the associativity for the L2 cache and
4474606303c9Skchow  *	tlb is encoded in the following table. The 4 bit L2 value serves as
4475606303c9Skchow  *	an index into the amd_afd[] array to determine the associativity.
4476606303c9Skchow  *	-1 is undefined. 0 is fully associative.
4477606303c9Skchow  */
4478606303c9Skchow 
4479606303c9Skchow static int amd_afd[] =
4480606303c9Skchow 	{-1, 1, 2, -1, 4, -1, 8, -1, 16, -1, 32, 48, 64, 96, 128, 0};
4481606303c9Skchow 
44827c478bd9Sstevel@tonic-gate static void
44837c478bd9Sstevel@tonic-gate amd_l2cacheinfo(struct cpuid_info *cpi, struct l2info *l2i)
44847c478bd9Sstevel@tonic-gate {
44858949bcd6Sandrei 	struct cpuid_regs *cp;
44867c478bd9Sstevel@tonic-gate 	uint_t size, assoc;
4487606303c9Skchow 	int i;
44887c478bd9Sstevel@tonic-gate 	int *ip;
44897c478bd9Sstevel@tonic-gate 
44907c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax < 0x80000006)
44917c478bd9Sstevel@tonic-gate 		return;
44927c478bd9Sstevel@tonic-gate 	cp = &cpi->cpi_extd[6];
44937c478bd9Sstevel@tonic-gate 
4494606303c9Skchow 	if ((i = BITX(cp->cp_ecx, 15, 12)) != 0 &&
44957c478bd9Sstevel@tonic-gate 	    (size = BITX(cp->cp_ecx, 31, 16)) != 0) {
44967c478bd9Sstevel@tonic-gate 		uint_t cachesz = size * 1024;
4497606303c9Skchow 		assoc = amd_afd[i];
44987c478bd9Sstevel@tonic-gate 
4499606303c9Skchow 		ASSERT(assoc != -1);
45007c478bd9Sstevel@tonic-gate 
45017c478bd9Sstevel@tonic-gate 		if ((ip = l2i->l2i_csz) != NULL)
45027c478bd9Sstevel@tonic-gate 			*ip = cachesz;
45037c478bd9Sstevel@tonic-gate 		if ((ip = l2i->l2i_lsz) != NULL)
45047c478bd9Sstevel@tonic-gate 			*ip = BITX(cp->cp_ecx, 7, 0);
45057c478bd9Sstevel@tonic-gate 		if ((ip = l2i->l2i_assoc) != NULL)
45067c478bd9Sstevel@tonic-gate 			*ip = assoc;
45077c478bd9Sstevel@tonic-gate 		l2i->l2i_ret = cachesz;
45087c478bd9Sstevel@tonic-gate 	}
45097c478bd9Sstevel@tonic-gate }
45107c478bd9Sstevel@tonic-gate 
45117c478bd9Sstevel@tonic-gate int
45127c478bd9Sstevel@tonic-gate getl2cacheinfo(cpu_t *cpu, int *csz, int *lsz, int *assoc)
45137c478bd9Sstevel@tonic-gate {
45147c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
45157c478bd9Sstevel@tonic-gate 	struct l2info __l2info, *l2i = &__l2info;
45167c478bd9Sstevel@tonic-gate 
45177c478bd9Sstevel@tonic-gate 	l2i->l2i_csz = csz;
45187c478bd9Sstevel@tonic-gate 	l2i->l2i_lsz = lsz;
45197c478bd9Sstevel@tonic-gate 	l2i->l2i_assoc = assoc;
45207c478bd9Sstevel@tonic-gate 	l2i->l2i_ret = -1;
45217c478bd9Sstevel@tonic-gate 
45227c478bd9Sstevel@tonic-gate 	switch (x86_which_cacheinfo(cpi)) {
45237c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
45247c478bd9Sstevel@tonic-gate 		intel_walk_cacheinfo(cpi, l2i, intel_l2cinfo);
45257c478bd9Sstevel@tonic-gate 		break;
45267c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
45277c478bd9Sstevel@tonic-gate 		cyrix_walk_cacheinfo(cpi, l2i, intel_l2cinfo);
45287c478bd9Sstevel@tonic-gate 		break;
45297c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
45307c478bd9Sstevel@tonic-gate 		amd_l2cacheinfo(cpi, l2i);
45317c478bd9Sstevel@tonic-gate 		break;
45327c478bd9Sstevel@tonic-gate 	default:
45337c478bd9Sstevel@tonic-gate 		break;
45347c478bd9Sstevel@tonic-gate 	}
45357c478bd9Sstevel@tonic-gate 	return (l2i->l2i_ret);
45367c478bd9Sstevel@tonic-gate }
4537f98fbcecSbholler 
4538843e1988Sjohnlev #if !defined(__xpv)
4539843e1988Sjohnlev 
45405b8a6efeSbholler uint32_t *
45415b8a6efeSbholler cpuid_mwait_alloc(cpu_t *cpu)
45425b8a6efeSbholler {
45435b8a6efeSbholler 	uint32_t	*ret;
45445b8a6efeSbholler 	size_t		mwait_size;
45455b8a6efeSbholler 
4546a3114836SGerry Liu 	ASSERT(cpuid_checkpass(CPU, 2));
45475b8a6efeSbholler 
4548a3114836SGerry Liu 	mwait_size = CPU->cpu_m.mcpu_cpi->cpi_mwait.mon_max;
45495b8a6efeSbholler 	if (mwait_size == 0)
45505b8a6efeSbholler 		return (NULL);
45515b8a6efeSbholler 
45525b8a6efeSbholler 	/*
45535b8a6efeSbholler 	 * kmem_alloc() returns cache line size aligned data for mwait_size
45545b8a6efeSbholler 	 * allocations.  mwait_size is currently cache line sized.  Neither
45555b8a6efeSbholler 	 * of these implementation details are guarantied to be true in the
45565b8a6efeSbholler 	 * future.
45575b8a6efeSbholler 	 *
45585b8a6efeSbholler 	 * First try allocating mwait_size as kmem_alloc() currently returns
45595b8a6efeSbholler 	 * correctly aligned memory.  If kmem_alloc() does not return
45605b8a6efeSbholler 	 * mwait_size aligned memory, then use mwait_size ROUNDUP.
45615b8a6efeSbholler 	 *
45625b8a6efeSbholler 	 * Set cpi_mwait.buf_actual and cpi_mwait.size_actual in case we
45635b8a6efeSbholler 	 * decide to free this memory.
45645b8a6efeSbholler 	 */
45655b8a6efeSbholler 	ret = kmem_zalloc(mwait_size, KM_SLEEP);
45665b8a6efeSbholler 	if (ret == (uint32_t *)P2ROUNDUP((uintptr_t)ret, mwait_size)) {
45675b8a6efeSbholler 		cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual = ret;
45685b8a6efeSbholler 		cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual = mwait_size;
45695b8a6efeSbholler 		*ret = MWAIT_RUNNING;
45705b8a6efeSbholler 		return (ret);
45715b8a6efeSbholler 	} else {
45725b8a6efeSbholler 		kmem_free(ret, mwait_size);
45735b8a6efeSbholler 		ret = kmem_zalloc(mwait_size * 2, KM_SLEEP);
45745b8a6efeSbholler 		cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual = ret;
45755b8a6efeSbholler 		cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual = mwait_size * 2;
45765b8a6efeSbholler 		ret = (uint32_t *)P2ROUNDUP((uintptr_t)ret, mwait_size);
45775b8a6efeSbholler 		*ret = MWAIT_RUNNING;
45785b8a6efeSbholler 		return (ret);
45795b8a6efeSbholler 	}
45805b8a6efeSbholler }
45815b8a6efeSbholler 
45825b8a6efeSbholler void
45835b8a6efeSbholler cpuid_mwait_free(cpu_t *cpu)
4584f98fbcecSbholler {
4585a3114836SGerry Liu 	if (cpu->cpu_m.mcpu_cpi == NULL) {
4586a3114836SGerry Liu 		return;
4587a3114836SGerry Liu 	}
45885b8a6efeSbholler 
45895b8a6efeSbholler 	if (cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual != NULL &&
45905b8a6efeSbholler 	    cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual > 0) {
45915b8a6efeSbholler 		kmem_free(cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual,
45925b8a6efeSbholler 		    cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual);
45935b8a6efeSbholler 	}
45945b8a6efeSbholler 
45955b8a6efeSbholler 	cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual = NULL;
45965b8a6efeSbholler 	cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual = 0;
4597f98fbcecSbholler }
4598843e1988Sjohnlev 
4599247dbb3dSsudheer void
4600247dbb3dSsudheer patch_tsc_read(int flag)
4601247dbb3dSsudheer {
4602247dbb3dSsudheer 	size_t cnt;
4603e4b86885SCheng Sean Ye 
4604247dbb3dSsudheer 	switch (flag) {
4605263f549eSPatrick Mooney 	case TSC_NONE:
4606247dbb3dSsudheer 		cnt = &_no_rdtsc_end - &_no_rdtsc_start;
46072b0bcb26Ssudheer 		(void) memcpy((void *)tsc_read, (void *)&_no_rdtsc_start, cnt);
4608247dbb3dSsudheer 		break;
4609263f549eSPatrick Mooney 	case TSC_RDTSC_MFENCE:
4610247dbb3dSsudheer 		cnt = &_tsc_mfence_end - &_tsc_mfence_start;
46112b0bcb26Ssudheer 		(void) memcpy((void *)tsc_read,
46122b0bcb26Ssudheer 		    (void *)&_tsc_mfence_start, cnt);
4613247dbb3dSsudheer 		break;
4614263f549eSPatrick Mooney 	case TSC_RDTSC_LFENCE:
461515363b27Ssudheer 		cnt = &_tsc_lfence_end - &_tsc_lfence_start;
461615363b27Ssudheer 		(void) memcpy((void *)tsc_read,
461715363b27Ssudheer 		    (void *)&_tsc_lfence_start, cnt);
461815363b27Ssudheer 		break;
4619263f549eSPatrick Mooney 	case TSC_TSCP:
4620263f549eSPatrick Mooney 		cnt = &_tscp_end - &_tscp_start;
4621263f549eSPatrick Mooney 		(void) memcpy((void *)tsc_read, (void *)&_tscp_start, cnt);
4622263f549eSPatrick Mooney 		break;
4623247dbb3dSsudheer 	default:
4624263f549eSPatrick Mooney 		/* Bail for unexpected TSC types. (TSC_NONE covers 0) */
4625263f549eSPatrick Mooney 		cmn_err(CE_PANIC, "Unrecogized TSC type: %d", flag);
4626247dbb3dSsudheer 		break;
4627247dbb3dSsudheer 	}
4628263f549eSPatrick Mooney 	tsc_type = flag;
4629247dbb3dSsudheer }
4630247dbb3dSsudheer 
46310e751525SEric Saxe int
46320e751525SEric Saxe cpuid_deep_cstates_supported(void)
46330e751525SEric Saxe {
46340e751525SEric Saxe 	struct cpuid_info *cpi;
46350e751525SEric Saxe 	struct cpuid_regs regs;
46360e751525SEric Saxe 
46370e751525SEric Saxe 	ASSERT(cpuid_checkpass(CPU, 1));
46380e751525SEric Saxe 
46390e751525SEric Saxe 	cpi = CPU->cpu_m.mcpu_cpi;
46400e751525SEric Saxe 
46417417cfdeSKuriakose Kuruvilla 	if (!is_x86_feature(x86_featureset, X86FSET_CPUID))
46420e751525SEric Saxe 		return (0);
46430e751525SEric Saxe 
46440e751525SEric Saxe 	switch (cpi->cpi_vendor) {
46450e751525SEric Saxe 	case X86_VENDOR_Intel:
46460e751525SEric Saxe 		if (cpi->cpi_xmaxeax < 0x80000007)
46470e751525SEric Saxe 			return (0);
46480e751525SEric Saxe 
46490e751525SEric Saxe 		/*
46500e751525SEric Saxe 		 * TSC run at a constant rate in all ACPI C-states?
46510e751525SEric Saxe 		 */
46520e751525SEric Saxe 		regs.cp_eax = 0x80000007;
46530e751525SEric Saxe 		(void) __cpuid_insn(&regs);
46540e751525SEric Saxe 		return (regs.cp_edx & CPUID_TSC_CSTATE_INVARIANCE);
46550e751525SEric Saxe 
46560e751525SEric Saxe 	default:
46570e751525SEric Saxe 		return (0);
46580e751525SEric Saxe 	}
46590e751525SEric Saxe }
46600e751525SEric Saxe 
4661e774b42bSBill Holler #endif	/* !__xpv */
4662e774b42bSBill Holler 
4663e774b42bSBill Holler void
4664e774b42bSBill Holler post_startup_cpu_fixups(void)
4665e774b42bSBill Holler {
4666e774b42bSBill Holler #ifndef __xpv
4667e774b42bSBill Holler 	/*
4668e774b42bSBill Holler 	 * Some AMD processors support C1E state. Entering this state will
4669e774b42bSBill Holler 	 * cause the local APIC timer to stop, which we can't deal with at
4670e774b42bSBill Holler 	 * this time.
4671e774b42bSBill Holler 	 */
4672e774b42bSBill Holler 	if (cpuid_getvendor(CPU) == X86_VENDOR_AMD) {
4673e774b42bSBill Holler 		on_trap_data_t otd;
4674e774b42bSBill Holler 		uint64_t reg;
4675e774b42bSBill Holler 
4676e774b42bSBill Holler 		if (!on_trap(&otd, OT_DATA_ACCESS)) {
4677e774b42bSBill Holler 			reg = rdmsr(MSR_AMD_INT_PENDING_CMP_HALT);
4678e774b42bSBill Holler 			/* Disable C1E state if it is enabled by BIOS */
4679e774b42bSBill Holler 			if ((reg >> AMD_ACTONCMPHALT_SHIFT) &
4680e774b42bSBill Holler 			    AMD_ACTONCMPHALT_MASK) {
4681e774b42bSBill Holler 				reg &= ~(AMD_ACTONCMPHALT_MASK <<
4682e774b42bSBill Holler 				    AMD_ACTONCMPHALT_SHIFT);
4683e774b42bSBill Holler 				wrmsr(MSR_AMD_INT_PENDING_CMP_HALT, reg);
4684e774b42bSBill Holler 			}
4685e774b42bSBill Holler 		}
4686e774b42bSBill Holler 		no_trap();
4687e774b42bSBill Holler 	}
4688e774b42bSBill Holler #endif	/* !__xpv */
4689e774b42bSBill Holler }
4690e774b42bSBill Holler 
4691cef70d2cSBill Holler /*
46927af88ac7SKuriakose Kuruvilla  * Setup necessary registers to enable XSAVE feature on this processor.
46937af88ac7SKuriakose Kuruvilla  * This function needs to be called early enough, so that no xsave/xrstor
46947af88ac7SKuriakose Kuruvilla  * ops will execute on the processor before the MSRs are properly set up.
46957af88ac7SKuriakose Kuruvilla  *
46967af88ac7SKuriakose Kuruvilla  * Current implementation has the following assumption:
46977af88ac7SKuriakose Kuruvilla  * - cpuid_pass1() is done, so that X86 features are known.
46987af88ac7SKuriakose Kuruvilla  * - fpu_probe() is done, so that fp_save_mech is chosen.
46997af88ac7SKuriakose Kuruvilla  */
47007af88ac7SKuriakose Kuruvilla void
47017af88ac7SKuriakose Kuruvilla xsave_setup_msr(cpu_t *cpu)
47027af88ac7SKuriakose Kuruvilla {
47037af88ac7SKuriakose Kuruvilla 	ASSERT(fp_save_mech == FP_XSAVE);
47047af88ac7SKuriakose Kuruvilla 	ASSERT(is_x86_feature(x86_featureset, X86FSET_XSAVE));
47057af88ac7SKuriakose Kuruvilla 
47067af88ac7SKuriakose Kuruvilla 	/* Enable OSXSAVE in CR4. */
47077af88ac7SKuriakose Kuruvilla 	setcr4(getcr4() | CR4_OSXSAVE);
47087af88ac7SKuriakose Kuruvilla 	/*
47097af88ac7SKuriakose Kuruvilla 	 * Update SW copy of ECX, so that /dev/cpu/self/cpuid will report
47107af88ac7SKuriakose Kuruvilla 	 * correct value.
47117af88ac7SKuriakose Kuruvilla 	 */
47127af88ac7SKuriakose Kuruvilla 	cpu->cpu_m.mcpu_cpi->cpi_std[1].cp_ecx |= CPUID_INTC_ECX_OSXSAVE;
47137af88ac7SKuriakose Kuruvilla 	setup_xfem();
47147af88ac7SKuriakose Kuruvilla }
47157af88ac7SKuriakose Kuruvilla 
47167af88ac7SKuriakose Kuruvilla /*
4717cef70d2cSBill Holler  * Starting with the Westmere processor the local
4718cef70d2cSBill Holler  * APIC timer will continue running in all C-states,
4719cef70d2cSBill Holler  * including the deepest C-states.
4720cef70d2cSBill Holler  */
4721cef70d2cSBill Holler int
4722cef70d2cSBill Holler cpuid_arat_supported(void)
4723cef70d2cSBill Holler {
4724cef70d2cSBill Holler 	struct cpuid_info *cpi;
4725cef70d2cSBill Holler 	struct cpuid_regs regs;
4726cef70d2cSBill Holler 
4727cef70d2cSBill Holler 	ASSERT(cpuid_checkpass(CPU, 1));
47287417cfdeSKuriakose Kuruvilla 	ASSERT(is_x86_feature(x86_featureset, X86FSET_CPUID));
4729cef70d2cSBill Holler 
4730cef70d2cSBill Holler 	cpi = CPU->cpu_m.mcpu_cpi;
4731cef70d2cSBill Holler 
4732cef70d2cSBill Holler 	switch (cpi->cpi_vendor) {
4733cef70d2cSBill Holler 	case X86_VENDOR_Intel:
4734cef70d2cSBill Holler 		/*
4735cef70d2cSBill Holler 		 * Always-running Local APIC Timer is
4736cef70d2cSBill Holler 		 * indicated by CPUID.6.EAX[2].
4737cef70d2cSBill Holler 		 */
4738cef70d2cSBill Holler 		if (cpi->cpi_maxeax >= 6) {
4739cef70d2cSBill Holler 			regs.cp_eax = 6;
4740cef70d2cSBill Holler 			(void) cpuid_insn(NULL, &regs);
4741cef70d2cSBill Holler 			return (regs.cp_eax & CPUID_CSTATE_ARAT);
4742cef70d2cSBill Holler 		} else {
4743cef70d2cSBill Holler 			return (0);
4744cef70d2cSBill Holler 		}
4745cef70d2cSBill Holler 	default:
4746cef70d2cSBill Holler 		return (0);
4747cef70d2cSBill Holler 	}
4748cef70d2cSBill Holler }
4749cef70d2cSBill Holler 
4750f21ed392Saubrey.li@intel.com /*
4751f21ed392Saubrey.li@intel.com  * Check support for Intel ENERGY_PERF_BIAS feature
4752f21ed392Saubrey.li@intel.com  */
4753f21ed392Saubrey.li@intel.com int
4754f21ed392Saubrey.li@intel.com cpuid_iepb_supported(struct cpu *cp)
4755f21ed392Saubrey.li@intel.com {
4756f21ed392Saubrey.li@intel.com 	struct cpuid_info *cpi = cp->cpu_m.mcpu_cpi;
4757f21ed392Saubrey.li@intel.com 	struct cpuid_regs regs;
4758f21ed392Saubrey.li@intel.com 
4759f21ed392Saubrey.li@intel.com 	ASSERT(cpuid_checkpass(cp, 1));
4760f21ed392Saubrey.li@intel.com 
47617417cfdeSKuriakose Kuruvilla 	if (!(is_x86_feature(x86_featureset, X86FSET_CPUID)) ||
47627417cfdeSKuriakose Kuruvilla 	    !(is_x86_feature(x86_featureset, X86FSET_MSR))) {
4763f21ed392Saubrey.li@intel.com 		return (0);
4764f21ed392Saubrey.li@intel.com 	}
4765f21ed392Saubrey.li@intel.com 
4766f21ed392Saubrey.li@intel.com 	/*
4767f21ed392Saubrey.li@intel.com 	 * Intel ENERGY_PERF_BIAS MSR is indicated by
4768f21ed392Saubrey.li@intel.com 	 * capability bit CPUID.6.ECX.3
4769f21ed392Saubrey.li@intel.com 	 */
4770f21ed392Saubrey.li@intel.com 	if ((cpi->cpi_vendor != X86_VENDOR_Intel) || (cpi->cpi_maxeax < 6))
4771f21ed392Saubrey.li@intel.com 		return (0);
4772f21ed392Saubrey.li@intel.com 
4773f21ed392Saubrey.li@intel.com 	regs.cp_eax = 0x6;
4774f21ed392Saubrey.li@intel.com 	(void) cpuid_insn(NULL, &regs);
4775f21ed392Saubrey.li@intel.com 	return (regs.cp_ecx & CPUID_EPB_SUPPORT);
4776f21ed392Saubrey.li@intel.com }
4777f21ed392Saubrey.li@intel.com 
477841afdfa7SKrishnendu Sadhukhan - Sun Microsystems /*
477941afdfa7SKrishnendu Sadhukhan - Sun Microsystems  * Check support for TSC deadline timer
478041afdfa7SKrishnendu Sadhukhan - Sun Microsystems  *
478141afdfa7SKrishnendu Sadhukhan - Sun Microsystems  * TSC deadline timer provides a superior software programming
478241afdfa7SKrishnendu Sadhukhan - Sun Microsystems  * model over local APIC timer that eliminates "time drifts".
478341afdfa7SKrishnendu Sadhukhan - Sun Microsystems  * Instead of specifying a relative time, software specifies an
478441afdfa7SKrishnendu Sadhukhan - Sun Microsystems  * absolute time as the target at which the processor should
478541afdfa7SKrishnendu Sadhukhan - Sun Microsystems  * generate a timer event.
478641afdfa7SKrishnendu Sadhukhan - Sun Microsystems  */
478741afdfa7SKrishnendu Sadhukhan - Sun Microsystems int
478841afdfa7SKrishnendu Sadhukhan - Sun Microsystems cpuid_deadline_tsc_supported(void)
478941afdfa7SKrishnendu Sadhukhan - Sun Microsystems {
479041afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	struct cpuid_info *cpi = CPU->cpu_m.mcpu_cpi;
479141afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	struct cpuid_regs regs;
479241afdfa7SKrishnendu Sadhukhan - Sun Microsystems 
479341afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	ASSERT(cpuid_checkpass(CPU, 1));
479441afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	ASSERT(is_x86_feature(x86_featureset, X86FSET_CPUID));
479541afdfa7SKrishnendu Sadhukhan - Sun Microsystems 
479641afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	switch (cpi->cpi_vendor) {
479741afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	case X86_VENDOR_Intel:
479841afdfa7SKrishnendu Sadhukhan - Sun Microsystems 		if (cpi->cpi_maxeax >= 1) {
479941afdfa7SKrishnendu Sadhukhan - Sun Microsystems 			regs.cp_eax = 1;
480041afdfa7SKrishnendu Sadhukhan - Sun Microsystems 			(void) cpuid_insn(NULL, &regs);
480141afdfa7SKrishnendu Sadhukhan - Sun Microsystems 			return (regs.cp_ecx & CPUID_DEADLINE_TSC);
480241afdfa7SKrishnendu Sadhukhan - Sun Microsystems 		} else {
480341afdfa7SKrishnendu Sadhukhan - Sun Microsystems 			return (0);
480441afdfa7SKrishnendu Sadhukhan - Sun Microsystems 		}
480541afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	default:
480641afdfa7SKrishnendu Sadhukhan - Sun Microsystems 		return (0);
480741afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	}
480841afdfa7SKrishnendu Sadhukhan - Sun Microsystems }
480941afdfa7SKrishnendu Sadhukhan - Sun Microsystems 
481022cc0e45SBill Holler #if defined(__amd64) && !defined(__xpv)
481122cc0e45SBill Holler /*
481222cc0e45SBill Holler  * Patch in versions of bcopy for high performance Intel Nhm processors
481322cc0e45SBill Holler  * and later...
481422cc0e45SBill Holler  */
481522cc0e45SBill Holler void
481622cc0e45SBill Holler patch_memops(uint_t vendor)
481722cc0e45SBill Holler {
481822cc0e45SBill Holler 	size_t cnt, i;
481922cc0e45SBill Holler 	caddr_t to, from;
482022cc0e45SBill Holler 
48217417cfdeSKuriakose Kuruvilla 	if ((vendor == X86_VENDOR_Intel) &&
48227417cfdeSKuriakose Kuruvilla 	    is_x86_feature(x86_featureset, X86FSET_SSE4_2)) {
482322cc0e45SBill Holler 		cnt = &bcopy_patch_end - &bcopy_patch_start;
482422cc0e45SBill Holler 		to = &bcopy_ck_size;
482522cc0e45SBill Holler 		from = &bcopy_patch_start;
482622cc0e45SBill Holler 		for (i = 0; i < cnt; i++) {
482722cc0e45SBill Holler 			*to++ = *from++;
482822cc0e45SBill Holler 		}
482922cc0e45SBill Holler 	}
483022cc0e45SBill Holler }
483122cc0e45SBill Holler #endif  /* __amd64 && !__xpv */
48322d2efdc6SVuong Nguyen 
48332d2efdc6SVuong Nguyen /*
48342d2efdc6SVuong Nguyen  * This function finds the number of bits to represent the number of cores per
48352d2efdc6SVuong Nguyen  * chip and the number of strands per core for the Intel platforms.
48362d2efdc6SVuong Nguyen  * It re-uses the x2APIC cpuid code of the cpuid_pass2().
48372d2efdc6SVuong Nguyen  */
48382d2efdc6SVuong Nguyen void
48392d2efdc6SVuong Nguyen cpuid_get_ext_topo(uint_t vendor, uint_t *core_nbits, uint_t *strand_nbits)
48402d2efdc6SVuong Nguyen {
48412d2efdc6SVuong Nguyen 	struct cpuid_regs regs;
48422d2efdc6SVuong Nguyen 	struct cpuid_regs *cp = &regs;
48432d2efdc6SVuong Nguyen 
48442d2efdc6SVuong Nguyen 	if (vendor != X86_VENDOR_Intel) {
48452d2efdc6SVuong Nguyen 		return;
48462d2efdc6SVuong Nguyen 	}
48472d2efdc6SVuong Nguyen 
48482d2efdc6SVuong Nguyen 	/* if the cpuid level is 0xB, extended topo is available. */
48492d2efdc6SVuong Nguyen 	cp->cp_eax = 0;
48502d2efdc6SVuong Nguyen 	if (__cpuid_insn(cp) >= 0xB) {
48512d2efdc6SVuong Nguyen 
48522d2efdc6SVuong Nguyen 		cp->cp_eax = 0xB;
48532d2efdc6SVuong Nguyen 		cp->cp_edx = cp->cp_ebx = cp->cp_ecx = 0;
48542d2efdc6SVuong Nguyen 		(void) __cpuid_insn(cp);
48552d2efdc6SVuong Nguyen 
48562d2efdc6SVuong Nguyen 		/*
48572d2efdc6SVuong Nguyen 		 * Check CPUID.EAX=0BH, ECX=0H:EBX is non-zero, which
48582d2efdc6SVuong Nguyen 		 * indicates that the extended topology enumeration leaf is
48592d2efdc6SVuong Nguyen 		 * available.
48602d2efdc6SVuong Nguyen 		 */
48612d2efdc6SVuong Nguyen 		if (cp->cp_ebx) {
48622d2efdc6SVuong Nguyen 			uint_t coreid_shift = 0;
48632d2efdc6SVuong Nguyen 			uint_t chipid_shift = 0;
48642d2efdc6SVuong Nguyen 			uint_t i;
48652d2efdc6SVuong Nguyen 			uint_t level;
48662d2efdc6SVuong Nguyen 
48672d2efdc6SVuong Nguyen 			for (i = 0; i < CPI_FNB_ECX_MAX; i++) {
48682d2efdc6SVuong Nguyen 				cp->cp_eax = 0xB;
48692d2efdc6SVuong Nguyen 				cp->cp_ecx = i;
48702d2efdc6SVuong Nguyen 
48712d2efdc6SVuong Nguyen 				(void) __cpuid_insn(cp);
48722d2efdc6SVuong Nguyen 				level = CPI_CPU_LEVEL_TYPE(cp);
48732d2efdc6SVuong Nguyen 
48742d2efdc6SVuong Nguyen 				if (level == 1) {
48752d2efdc6SVuong Nguyen 					/*
48762d2efdc6SVuong Nguyen 					 * Thread level processor topology
48772d2efdc6SVuong Nguyen 					 * Number of bits shift right APIC ID
48782d2efdc6SVuong Nguyen 					 * to get the coreid.
48792d2efdc6SVuong Nguyen 					 */
48802d2efdc6SVuong Nguyen 					coreid_shift = BITX(cp->cp_eax, 4, 0);
48812d2efdc6SVuong Nguyen 				} else if (level == 2) {
48822d2efdc6SVuong Nguyen 					/*
48832d2efdc6SVuong Nguyen 					 * Core level processor topology
48842d2efdc6SVuong Nguyen 					 * Number of bits shift right APIC ID
48852d2efdc6SVuong Nguyen 					 * to get the chipid.
48862d2efdc6SVuong Nguyen 					 */
48872d2efdc6SVuong Nguyen 					chipid_shift = BITX(cp->cp_eax, 4, 0);
48882d2efdc6SVuong Nguyen 				}
48892d2efdc6SVuong Nguyen 			}
48902d2efdc6SVuong Nguyen 
48912d2efdc6SVuong Nguyen 			if (coreid_shift > 0 && chipid_shift > coreid_shift) {
48922d2efdc6SVuong Nguyen 				*strand_nbits = coreid_shift;
48932d2efdc6SVuong Nguyen 				*core_nbits = chipid_shift - coreid_shift;
48942d2efdc6SVuong Nguyen 			}
48952d2efdc6SVuong Nguyen 		}
48962d2efdc6SVuong Nguyen 	}
48972d2efdc6SVuong Nguyen }
4898