xref: /titanic_53/usr/src/uts/i86pc/os/cpuid.c (revision 79ec9da85c2648e2e165ce68612ad0cb6e185618)
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.
24*79ec9da8SYuri Pankov  * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
257c478bd9Sstevel@tonic-gate  */
26cef70d2cSBill Holler /*
2741afdfa7SKrishnendu Sadhukhan - Sun Microsystems  * Copyright (c) 2010, Intel Corporation.
28cef70d2cSBill Holler  * All rights reserved.
29cef70d2cSBill Holler  */
308031591dSSrihari Venkatesan /*
318031591dSSrihari Venkatesan  * Portions Copyright 2009 Advanced Micro Devices, Inc.
328031591dSSrihari Venkatesan  */
33faa20166SBryan Cantrill /*
34f3390f39SRobert Mustacchi  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
35faa20166SBryan Cantrill  */
367c478bd9Sstevel@tonic-gate /*
377c478bd9Sstevel@tonic-gate  * Various routines to handle identification
387c478bd9Sstevel@tonic-gate  * and classification of x86 processors.
397c478bd9Sstevel@tonic-gate  */
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate #include <sys/types.h>
427c478bd9Sstevel@tonic-gate #include <sys/archsystm.h>
437c478bd9Sstevel@tonic-gate #include <sys/x86_archext.h>
447c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
457c478bd9Sstevel@tonic-gate #include <sys/systm.h>
467c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
477c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
487c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
497c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
507c478bd9Sstevel@tonic-gate #include <sys/processor.h>
515b8a6efeSbholler #include <sys/sysmacros.h>
52fb2f18f8Sesaxe #include <sys/pg.h>
537c478bd9Sstevel@tonic-gate #include <sys/fp.h>
547c478bd9Sstevel@tonic-gate #include <sys/controlregs.h>
557c478bd9Sstevel@tonic-gate #include <sys/bitmap.h>
56dfea898aSKuriakose Kuruvilla #include <sys/auxv_386.h>
577c478bd9Sstevel@tonic-gate #include <sys/memnode.h>
588031591dSSrihari Venkatesan #include <sys/pci_cfgspace.h>
597c478bd9Sstevel@tonic-gate 
60e4b86885SCheng Sean Ye #ifdef __xpv
61e4b86885SCheng Sean Ye #include <sys/hypervisor.h>
62e774b42bSBill Holler #else
63e774b42bSBill Holler #include <sys/ontrap.h>
64e4b86885SCheng Sean Ye #endif
65e4b86885SCheng Sean Ye 
667c478bd9Sstevel@tonic-gate /*
677c478bd9Sstevel@tonic-gate  * Pass 0 of cpuid feature analysis happens in locore. It contains special code
687c478bd9Sstevel@tonic-gate  * to recognize Cyrix processors that are not cpuid-compliant, and to deal with
697c478bd9Sstevel@tonic-gate  * them accordingly. For most modern processors, feature detection occurs here
707c478bd9Sstevel@tonic-gate  * in pass 1.
717c478bd9Sstevel@tonic-gate  *
727c478bd9Sstevel@tonic-gate  * Pass 1 of cpuid feature analysis happens just at the beginning of mlsetup()
737c478bd9Sstevel@tonic-gate  * for the boot CPU and does the basic analysis that the early kernel needs.
747417cfdeSKuriakose Kuruvilla  * x86_featureset is set based on the return value of cpuid_pass1() of the boot
757c478bd9Sstevel@tonic-gate  * CPU.
767c478bd9Sstevel@tonic-gate  *
777c478bd9Sstevel@tonic-gate  * Pass 1 includes:
787c478bd9Sstevel@tonic-gate  *
797c478bd9Sstevel@tonic-gate  *	o Determining vendor/model/family/stepping and setting x86_type and
807c478bd9Sstevel@tonic-gate  *	  x86_vendor accordingly.
817c478bd9Sstevel@tonic-gate  *	o Processing the feature flags returned by the cpuid instruction while
827c478bd9Sstevel@tonic-gate  *	  applying any workarounds or tricks for the specific processor.
837c478bd9Sstevel@tonic-gate  *	o Mapping the feature flags into Solaris feature bits (X86_*).
847c478bd9Sstevel@tonic-gate  *	o Processing extended feature flags if supported by the processor,
857c478bd9Sstevel@tonic-gate  *	  again while applying specific processor knowledge.
867c478bd9Sstevel@tonic-gate  *	o Determining the CMT characteristics of the system.
877c478bd9Sstevel@tonic-gate  *
887c478bd9Sstevel@tonic-gate  * Pass 1 is done on non-boot CPUs during their initialization and the results
897c478bd9Sstevel@tonic-gate  * are used only as a meager attempt at ensuring that all processors within the
907c478bd9Sstevel@tonic-gate  * system support the same features.
917c478bd9Sstevel@tonic-gate  *
927c478bd9Sstevel@tonic-gate  * Pass 2 of cpuid feature analysis happens just at the beginning
937c478bd9Sstevel@tonic-gate  * of startup().  It just copies in and corrects the remainder
947c478bd9Sstevel@tonic-gate  * of the cpuid data we depend on: standard cpuid functions that we didn't
957c478bd9Sstevel@tonic-gate  * need for pass1 feature analysis, and extended cpuid functions beyond the
967c478bd9Sstevel@tonic-gate  * simple feature processing done in pass1.
977c478bd9Sstevel@tonic-gate  *
987c478bd9Sstevel@tonic-gate  * Pass 3 of cpuid analysis is invoked after basic kernel services; in
997c478bd9Sstevel@tonic-gate  * particular kernel memory allocation has been made available. It creates a
1007c478bd9Sstevel@tonic-gate  * readable brand string based on the data collected in the first two passes.
1017c478bd9Sstevel@tonic-gate  *
1027c478bd9Sstevel@tonic-gate  * Pass 4 of cpuid analysis is invoked after post_startup() when all
1037c478bd9Sstevel@tonic-gate  * the support infrastructure for various hardware features has been
1047c478bd9Sstevel@tonic-gate  * initialized. It determines which processor features will be reported
1057c478bd9Sstevel@tonic-gate  * to userland via the aux vector.
1067c478bd9Sstevel@tonic-gate  *
1077c478bd9Sstevel@tonic-gate  * All passes are executed on all CPUs, but only the boot CPU determines what
1087c478bd9Sstevel@tonic-gate  * features the kernel will use.
1097c478bd9Sstevel@tonic-gate  *
1107c478bd9Sstevel@tonic-gate  * Much of the worst junk in this file is for the support of processors
1117c478bd9Sstevel@tonic-gate  * that didn't really implement the cpuid instruction properly.
1127c478bd9Sstevel@tonic-gate  *
1137c478bd9Sstevel@tonic-gate  * NOTE: The accessor functions (cpuid_get*) are aware of, and ASSERT upon,
1147c478bd9Sstevel@tonic-gate  * the pass numbers.  Accordingly, changes to the pass code may require changes
1157c478bd9Sstevel@tonic-gate  * to the accessor code.
1167c478bd9Sstevel@tonic-gate  */
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate uint_t x86_vendor = X86_VENDOR_IntelClone;
1197c478bd9Sstevel@tonic-gate uint_t x86_type = X86_TYPE_OTHER;
12086c1f4dcSVikram Hegde uint_t x86_clflush_size = 0;
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate uint_t pentiumpro_bug4046376;
1237c478bd9Sstevel@tonic-gate uint_t pentiumpro_bug4064495;
1247c478bd9Sstevel@tonic-gate 
125dfea898aSKuriakose Kuruvilla uchar_t x86_featureset[BT_SIZEOFMAP(NUM_X86_FEATURES)];
1267417cfdeSKuriakose Kuruvilla 
127dfea898aSKuriakose Kuruvilla static char *x86_feature_names[NUM_X86_FEATURES] = {
1287417cfdeSKuriakose Kuruvilla 	"lgpg",
1297417cfdeSKuriakose Kuruvilla 	"tsc",
1307417cfdeSKuriakose Kuruvilla 	"msr",
1317417cfdeSKuriakose Kuruvilla 	"mtrr",
1327417cfdeSKuriakose Kuruvilla 	"pge",
1337417cfdeSKuriakose Kuruvilla 	"de",
1347417cfdeSKuriakose Kuruvilla 	"cmov",
1357417cfdeSKuriakose Kuruvilla 	"mmx",
1367417cfdeSKuriakose Kuruvilla 	"mca",
1377417cfdeSKuriakose Kuruvilla 	"pae",
1387417cfdeSKuriakose Kuruvilla 	"cv8",
1397417cfdeSKuriakose Kuruvilla 	"pat",
1407417cfdeSKuriakose Kuruvilla 	"sep",
1417417cfdeSKuriakose Kuruvilla 	"sse",
1427417cfdeSKuriakose Kuruvilla 	"sse2",
1437417cfdeSKuriakose Kuruvilla 	"htt",
1447417cfdeSKuriakose Kuruvilla 	"asysc",
1457417cfdeSKuriakose Kuruvilla 	"nx",
1467417cfdeSKuriakose Kuruvilla 	"sse3",
1477417cfdeSKuriakose Kuruvilla 	"cx16",
1487417cfdeSKuriakose Kuruvilla 	"cmp",
1497417cfdeSKuriakose Kuruvilla 	"tscp",
1507417cfdeSKuriakose Kuruvilla 	"mwait",
1517417cfdeSKuriakose Kuruvilla 	"sse4a",
1527417cfdeSKuriakose Kuruvilla 	"cpuid",
1537417cfdeSKuriakose Kuruvilla 	"ssse3",
1547417cfdeSKuriakose Kuruvilla 	"sse4_1",
1557417cfdeSKuriakose Kuruvilla 	"sse4_2",
1567417cfdeSKuriakose Kuruvilla 	"1gpg",
1577417cfdeSKuriakose Kuruvilla 	"clfsh",
1587417cfdeSKuriakose Kuruvilla 	"64",
1597417cfdeSKuriakose Kuruvilla 	"aes",
1607af88ac7SKuriakose Kuruvilla 	"pclmulqdq",
1617af88ac7SKuriakose Kuruvilla 	"xsave",
162faa20166SBryan Cantrill 	"avx",
163faa20166SBryan Cantrill 	"vmx",
1647660e73fSHans Rosenfeld 	"svm",
165ebb8ac07SRobert Mustacchi 	"topoext",
166ebb8ac07SRobert Mustacchi 	"f16c",
167ebb8ac07SRobert Mustacchi 	"rdrand"
168faa20166SBryan Cantrill };
1697417cfdeSKuriakose Kuruvilla 
1707417cfdeSKuriakose Kuruvilla boolean_t
1717417cfdeSKuriakose Kuruvilla is_x86_feature(void *featureset, uint_t feature)
1727417cfdeSKuriakose Kuruvilla {
1737417cfdeSKuriakose Kuruvilla 	ASSERT(feature < NUM_X86_FEATURES);
1747417cfdeSKuriakose Kuruvilla 	return (BT_TEST((ulong_t *)featureset, feature));
1757417cfdeSKuriakose Kuruvilla }
1767417cfdeSKuriakose Kuruvilla 
1777417cfdeSKuriakose Kuruvilla void
1787417cfdeSKuriakose Kuruvilla add_x86_feature(void *featureset, uint_t feature)
1797417cfdeSKuriakose Kuruvilla {
1807417cfdeSKuriakose Kuruvilla 	ASSERT(feature < NUM_X86_FEATURES);
1817417cfdeSKuriakose Kuruvilla 	BT_SET((ulong_t *)featureset, feature);
1827417cfdeSKuriakose Kuruvilla }
1837417cfdeSKuriakose Kuruvilla 
1847417cfdeSKuriakose Kuruvilla void
1857417cfdeSKuriakose Kuruvilla remove_x86_feature(void *featureset, uint_t feature)
1867417cfdeSKuriakose Kuruvilla {
1877417cfdeSKuriakose Kuruvilla 	ASSERT(feature < NUM_X86_FEATURES);
1887417cfdeSKuriakose Kuruvilla 	BT_CLEAR((ulong_t *)featureset, feature);
1897417cfdeSKuriakose Kuruvilla }
1907417cfdeSKuriakose Kuruvilla 
1917417cfdeSKuriakose Kuruvilla boolean_t
1927417cfdeSKuriakose Kuruvilla compare_x86_featureset(void *setA, void *setB)
1937417cfdeSKuriakose Kuruvilla {
1947417cfdeSKuriakose Kuruvilla 	/*
1957417cfdeSKuriakose Kuruvilla 	 * We assume that the unused bits of the bitmap are always zero.
1967417cfdeSKuriakose Kuruvilla 	 */
1977417cfdeSKuriakose Kuruvilla 	if (memcmp(setA, setB, BT_SIZEOFMAP(NUM_X86_FEATURES)) == 0) {
1987417cfdeSKuriakose Kuruvilla 		return (B_TRUE);
1997417cfdeSKuriakose Kuruvilla 	} else {
2007417cfdeSKuriakose Kuruvilla 		return (B_FALSE);
2017417cfdeSKuriakose Kuruvilla 	}
2027417cfdeSKuriakose Kuruvilla }
2037417cfdeSKuriakose Kuruvilla 
2047417cfdeSKuriakose Kuruvilla void
2057417cfdeSKuriakose Kuruvilla print_x86_featureset(void *featureset)
2067417cfdeSKuriakose Kuruvilla {
2077417cfdeSKuriakose Kuruvilla 	uint_t i;
2087417cfdeSKuriakose Kuruvilla 
2097417cfdeSKuriakose Kuruvilla 	for (i = 0; i < NUM_X86_FEATURES; i++) {
2107417cfdeSKuriakose Kuruvilla 		if (is_x86_feature(featureset, i)) {
2117417cfdeSKuriakose Kuruvilla 			cmn_err(CE_CONT, "?x86_feature: %s\n",
2127417cfdeSKuriakose Kuruvilla 			    x86_feature_names[i]);
2137417cfdeSKuriakose Kuruvilla 		}
2147417cfdeSKuriakose Kuruvilla 	}
2157417cfdeSKuriakose Kuruvilla }
2167417cfdeSKuriakose Kuruvilla 
2177c478bd9Sstevel@tonic-gate uint_t enable486;
2187af88ac7SKuriakose Kuruvilla 
2197af88ac7SKuriakose Kuruvilla static size_t xsave_state_size = 0;
2207af88ac7SKuriakose Kuruvilla uint64_t xsave_bv_all = (XFEATURE_LEGACY_FP | XFEATURE_SSE);
2217af88ac7SKuriakose Kuruvilla boolean_t xsave_force_disable = B_FALSE;
2227af88ac7SKuriakose Kuruvilla 
2237997e108SSurya Prakki /*
224*79ec9da8SYuri Pankov  * This is set to platform type we are running on.
2257997e108SSurya Prakki  */
226349b53ddSStuart Maybee static int platform_type = -1;
227349b53ddSStuart Maybee 
228349b53ddSStuart Maybee #if !defined(__xpv)
229349b53ddSStuart Maybee /*
230349b53ddSStuart Maybee  * Variable to patch if hypervisor platform detection needs to be
231349b53ddSStuart Maybee  * disabled (e.g. platform_type will always be HW_NATIVE if this is 0).
232349b53ddSStuart Maybee  */
233349b53ddSStuart Maybee int enable_platform_detection = 1;
234349b53ddSStuart Maybee #endif
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate /*
237f98fbcecSbholler  * monitor/mwait info.
2385b8a6efeSbholler  *
2395b8a6efeSbholler  * size_actual and buf_actual are the real address and size allocated to get
2405b8a6efeSbholler  * proper mwait_buf alignement.  buf_actual and size_actual should be passed
2415b8a6efeSbholler  * to kmem_free().  Currently kmem_alloc() and mwait happen to both use
2425b8a6efeSbholler  * processor cache-line alignment, but this is not guarantied in the furture.
243f98fbcecSbholler  */
244f98fbcecSbholler struct mwait_info {
245f98fbcecSbholler 	size_t		mon_min;	/* min size to avoid missed wakeups */
246f98fbcecSbholler 	size_t		mon_max;	/* size to avoid false wakeups */
2475b8a6efeSbholler 	size_t		size_actual;	/* size actually allocated */
2485b8a6efeSbholler 	void		*buf_actual;	/* memory actually allocated */
249f98fbcecSbholler 	uint32_t	support;	/* processor support of monitor/mwait */
250f98fbcecSbholler };
251f98fbcecSbholler 
252f98fbcecSbholler /*
2537af88ac7SKuriakose Kuruvilla  * xsave/xrestor info.
2547af88ac7SKuriakose Kuruvilla  *
2557af88ac7SKuriakose Kuruvilla  * This structure contains HW feature bits and size of the xsave save area.
2567af88ac7SKuriakose Kuruvilla  * Note: the kernel will use the maximum size required for all hardware
2577af88ac7SKuriakose Kuruvilla  * features. It is not optimize for potential memory savings if features at
2587af88ac7SKuriakose Kuruvilla  * the end of the save area are not enabled.
2597af88ac7SKuriakose Kuruvilla  */
2607af88ac7SKuriakose Kuruvilla struct xsave_info {
2617af88ac7SKuriakose Kuruvilla 	uint32_t	xsav_hw_features_low;   /* Supported HW features */
2627af88ac7SKuriakose Kuruvilla 	uint32_t	xsav_hw_features_high;  /* Supported HW features */
2637af88ac7SKuriakose Kuruvilla 	size_t		xsav_max_size;  /* max size save area for HW features */
2647af88ac7SKuriakose Kuruvilla 	size_t		ymm_size;	/* AVX: size of ymm save area */
2657af88ac7SKuriakose Kuruvilla 	size_t		ymm_offset;	/* AVX: offset for ymm save area */
2667af88ac7SKuriakose Kuruvilla };
2677af88ac7SKuriakose Kuruvilla 
2687af88ac7SKuriakose Kuruvilla 
2697af88ac7SKuriakose Kuruvilla /*
2707c478bd9Sstevel@tonic-gate  * These constants determine how many of the elements of the
2717c478bd9Sstevel@tonic-gate  * cpuid we cache in the cpuid_info data structure; the
2727c478bd9Sstevel@tonic-gate  * remaining elements are accessible via the cpuid instruction.
2737c478bd9Sstevel@tonic-gate  */
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate #define	NMAX_CPI_STD	6		/* eax = 0 .. 5 */
2767660e73fSHans Rosenfeld #define	NMAX_CPI_EXTD	0x1f		/* eax = 0x80000000 .. 0x8000001e */
2778031591dSSrihari Venkatesan 
2788031591dSSrihari Venkatesan /*
2798031591dSSrihari Venkatesan  * Some terminology needs to be explained:
2808031591dSSrihari Venkatesan  *  - Socket: Something that can be plugged into a motherboard.
2818031591dSSrihari Venkatesan  *  - Package: Same as socket
2828031591dSSrihari Venkatesan  *  - Chip: Same as socket. Note that AMD's documentation uses term "chip"
2838031591dSSrihari Venkatesan  *    differently: there, chip is the same as processor node (below)
2848031591dSSrihari Venkatesan  *  - Processor node: Some AMD processors have more than one
2858031591dSSrihari Venkatesan  *    "subprocessor" embedded in a package. These subprocessors (nodes)
2868031591dSSrihari Venkatesan  *    are fully-functional processors themselves with cores, caches,
2878031591dSSrihari Venkatesan  *    memory controllers, PCI configuration spaces. They are connected
2888031591dSSrihari Venkatesan  *    inside the package with Hypertransport links. On single-node
2898031591dSSrihari Venkatesan  *    processors, processor node is equivalent to chip/socket/package.
2907660e73fSHans Rosenfeld  *  - Compute Unit: Some AMD processors pair cores in "compute units" that
2917660e73fSHans Rosenfeld  *    share the FPU and the I$ and L2 caches.
2928031591dSSrihari Venkatesan  */
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate struct cpuid_info {
2957c478bd9Sstevel@tonic-gate 	uint_t cpi_pass;		/* last pass completed */
2967c478bd9Sstevel@tonic-gate 	/*
2977c478bd9Sstevel@tonic-gate 	 * standard function information
2987c478bd9Sstevel@tonic-gate 	 */
2997c478bd9Sstevel@tonic-gate 	uint_t cpi_maxeax;		/* fn 0: %eax */
3007c478bd9Sstevel@tonic-gate 	char cpi_vendorstr[13];		/* fn 0: %ebx:%ecx:%edx */
3017c478bd9Sstevel@tonic-gate 	uint_t cpi_vendor;		/* enum of cpi_vendorstr */
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	uint_t cpi_family;		/* fn 1: extended family */
3047c478bd9Sstevel@tonic-gate 	uint_t cpi_model;		/* fn 1: extended model */
3057c478bd9Sstevel@tonic-gate 	uint_t cpi_step;		/* fn 1: stepping */
3068031591dSSrihari Venkatesan 	chipid_t cpi_chipid;		/* fn 1: %ebx:  Intel: chip # */
3078031591dSSrihari Venkatesan 					/*		AMD: package/socket # */
3087c478bd9Sstevel@tonic-gate 	uint_t cpi_brandid;		/* fn 1: %ebx: brand ID */
3097c478bd9Sstevel@tonic-gate 	int cpi_clogid;			/* fn 1: %ebx: thread # */
3108949bcd6Sandrei 	uint_t cpi_ncpu_per_chip;	/* fn 1: %ebx: logical cpu count */
3117c478bd9Sstevel@tonic-gate 	uint8_t cpi_cacheinfo[16];	/* fn 2: intel-style cache desc */
3127c478bd9Sstevel@tonic-gate 	uint_t cpi_ncache;		/* fn 2: number of elements */
313d129bde2Sesaxe 	uint_t cpi_ncpu_shr_last_cache;	/* fn 4: %eax: ncpus sharing cache */
314d129bde2Sesaxe 	id_t cpi_last_lvl_cacheid;	/* fn 4: %eax: derived cache id */
315d129bde2Sesaxe 	uint_t cpi_std_4_size;		/* fn 4: number of fn 4 elements */
316d129bde2Sesaxe 	struct cpuid_regs **cpi_std_4;	/* fn 4: %ecx == 0 .. fn4_size */
3178949bcd6Sandrei 	struct cpuid_regs cpi_std[NMAX_CPI_STD];	/* 0 .. 5 */
3187c478bd9Sstevel@tonic-gate 	/*
3197c478bd9Sstevel@tonic-gate 	 * extended function information
3207c478bd9Sstevel@tonic-gate 	 */
3217c478bd9Sstevel@tonic-gate 	uint_t cpi_xmaxeax;		/* fn 0x80000000: %eax */
3227c478bd9Sstevel@tonic-gate 	char cpi_brandstr[49];		/* fn 0x8000000[234] */
3237c478bd9Sstevel@tonic-gate 	uint8_t cpi_pabits;		/* fn 0x80000006: %eax */
3247c478bd9Sstevel@tonic-gate 	uint8_t	cpi_vabits;		/* fn 0x80000006: %eax */
3258031591dSSrihari Venkatesan 	struct	cpuid_regs cpi_extd[NMAX_CPI_EXTD];	/* 0x800000XX */
3268031591dSSrihari Venkatesan 
32710569901Sgavinm 	id_t cpi_coreid;		/* same coreid => strands share core */
32810569901Sgavinm 	int cpi_pkgcoreid;		/* core number within single package */
3298949bcd6Sandrei 	uint_t cpi_ncore_per_chip;	/* AMD: fn 0x80000008: %ecx[7-0] */
3308949bcd6Sandrei 					/* Intel: fn 4: %eax[31-26] */
3317c478bd9Sstevel@tonic-gate 	/*
3327c478bd9Sstevel@tonic-gate 	 * supported feature information
3337c478bd9Sstevel@tonic-gate 	 */
334ae115bc7Smrj 	uint32_t cpi_support[5];
3357c478bd9Sstevel@tonic-gate #define	STD_EDX_FEATURES	0
3367c478bd9Sstevel@tonic-gate #define	AMD_EDX_FEATURES	1
3377c478bd9Sstevel@tonic-gate #define	TM_EDX_FEATURES		2
3387c478bd9Sstevel@tonic-gate #define	STD_ECX_FEATURES	3
339ae115bc7Smrj #define	AMD_ECX_FEATURES	4
3408a40a695Sgavinm 	/*
3418a40a695Sgavinm 	 * Synthesized information, where known.
3428a40a695Sgavinm 	 */
3438a40a695Sgavinm 	uint32_t cpi_chiprev;		/* See X86_CHIPREV_* in x86_archext.h */
3448a40a695Sgavinm 	const char *cpi_chiprevstr;	/* May be NULL if chiprev unknown */
3458a40a695Sgavinm 	uint32_t cpi_socket;		/* Chip package/socket type */
346f98fbcecSbholler 
347f98fbcecSbholler 	struct mwait_info cpi_mwait;	/* fn 5: monitor/mwait info */
348b6917abeSmishra 	uint32_t cpi_apicid;
3498031591dSSrihari Venkatesan 	uint_t cpi_procnodeid;		/* AMD: nodeID on HT, Intel: chipid */
3508031591dSSrihari Venkatesan 	uint_t cpi_procnodes_per_pkg;	/* AMD: # of nodes in the package */
3518031591dSSrihari Venkatesan 					/* Intel: 1 */
3527660e73fSHans Rosenfeld 	uint_t cpi_compunitid;		/* AMD: ComputeUnit ID, Intel: coreid */
3537660e73fSHans Rosenfeld 	uint_t cpi_cores_per_compunit;	/* AMD: # of cores in the ComputeUnit */
3547af88ac7SKuriakose Kuruvilla 
3557af88ac7SKuriakose Kuruvilla 	struct xsave_info cpi_xsave;	/* fn D: xsave/xrestor info */
3567c478bd9Sstevel@tonic-gate };
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate static struct cpuid_info cpuid_info0;
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate /*
3627c478bd9Sstevel@tonic-gate  * These bit fields are defined by the Intel Application Note AP-485
3637c478bd9Sstevel@tonic-gate  * "Intel Processor Identification and the CPUID Instruction"
3647c478bd9Sstevel@tonic-gate  */
3657c478bd9Sstevel@tonic-gate #define	CPI_FAMILY_XTD(cpi)	BITX((cpi)->cpi_std[1].cp_eax, 27, 20)
3667c478bd9Sstevel@tonic-gate #define	CPI_MODEL_XTD(cpi)	BITX((cpi)->cpi_std[1].cp_eax, 19, 16)
3677c478bd9Sstevel@tonic-gate #define	CPI_TYPE(cpi)		BITX((cpi)->cpi_std[1].cp_eax, 13, 12)
3687c478bd9Sstevel@tonic-gate #define	CPI_FAMILY(cpi)		BITX((cpi)->cpi_std[1].cp_eax, 11, 8)
3697c478bd9Sstevel@tonic-gate #define	CPI_STEP(cpi)		BITX((cpi)->cpi_std[1].cp_eax, 3, 0)
3707c478bd9Sstevel@tonic-gate #define	CPI_MODEL(cpi)		BITX((cpi)->cpi_std[1].cp_eax, 7, 4)
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate #define	CPI_FEATURES_EDX(cpi)		((cpi)->cpi_std[1].cp_edx)
3737c478bd9Sstevel@tonic-gate #define	CPI_FEATURES_ECX(cpi)		((cpi)->cpi_std[1].cp_ecx)
3747c478bd9Sstevel@tonic-gate #define	CPI_FEATURES_XTD_EDX(cpi)	((cpi)->cpi_extd[1].cp_edx)
3757c478bd9Sstevel@tonic-gate #define	CPI_FEATURES_XTD_ECX(cpi)	((cpi)->cpi_extd[1].cp_ecx)
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate #define	CPI_BRANDID(cpi)	BITX((cpi)->cpi_std[1].cp_ebx, 7, 0)
3787c478bd9Sstevel@tonic-gate #define	CPI_CHUNKS(cpi)		BITX((cpi)->cpi_std[1].cp_ebx, 15, 7)
3797c478bd9Sstevel@tonic-gate #define	CPI_CPU_COUNT(cpi)	BITX((cpi)->cpi_std[1].cp_ebx, 23, 16)
3807c478bd9Sstevel@tonic-gate #define	CPI_APIC_ID(cpi)	BITX((cpi)->cpi_std[1].cp_ebx, 31, 24)
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate #define	CPI_MAXEAX_MAX		0x100		/* sanity control */
3837c478bd9Sstevel@tonic-gate #define	CPI_XMAXEAX_MAX		0x80000100
384d129bde2Sesaxe #define	CPI_FN4_ECX_MAX		0x20		/* sanity: max fn 4 levels */
385b6917abeSmishra #define	CPI_FNB_ECX_MAX		0x20		/* sanity: max fn B levels */
386d129bde2Sesaxe 
387d129bde2Sesaxe /*
388d129bde2Sesaxe  * Function 4 (Deterministic Cache Parameters) macros
389d129bde2Sesaxe  * Defined by Intel Application Note AP-485
390d129bde2Sesaxe  */
391d129bde2Sesaxe #define	CPI_NUM_CORES(regs)		BITX((regs)->cp_eax, 31, 26)
392d129bde2Sesaxe #define	CPI_NTHR_SHR_CACHE(regs)	BITX((regs)->cp_eax, 25, 14)
393d129bde2Sesaxe #define	CPI_FULL_ASSOC_CACHE(regs)	BITX((regs)->cp_eax, 9, 9)
394d129bde2Sesaxe #define	CPI_SELF_INIT_CACHE(regs)	BITX((regs)->cp_eax, 8, 8)
395d129bde2Sesaxe #define	CPI_CACHE_LVL(regs)		BITX((regs)->cp_eax, 7, 5)
396d129bde2Sesaxe #define	CPI_CACHE_TYPE(regs)		BITX((regs)->cp_eax, 4, 0)
397b6917abeSmishra #define	CPI_CPU_LEVEL_TYPE(regs)	BITX((regs)->cp_ecx, 15, 8)
398d129bde2Sesaxe 
399d129bde2Sesaxe #define	CPI_CACHE_WAYS(regs)		BITX((regs)->cp_ebx, 31, 22)
400d129bde2Sesaxe #define	CPI_CACHE_PARTS(regs)		BITX((regs)->cp_ebx, 21, 12)
401d129bde2Sesaxe #define	CPI_CACHE_COH_LN_SZ(regs)	BITX((regs)->cp_ebx, 11, 0)
402d129bde2Sesaxe 
403d129bde2Sesaxe #define	CPI_CACHE_SETS(regs)		BITX((regs)->cp_ecx, 31, 0)
404d129bde2Sesaxe 
405d129bde2Sesaxe #define	CPI_PREFCH_STRIDE(regs)		BITX((regs)->cp_edx, 9, 0)
406d129bde2Sesaxe 
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate /*
4095ff02082Sdmick  * A couple of shorthand macros to identify "later" P6-family chips
4105ff02082Sdmick  * like the Pentium M and Core.  First, the "older" P6-based stuff
4115ff02082Sdmick  * (loosely defined as "pre-Pentium-4"):
4125ff02082Sdmick  * P6, PII, Mobile PII, PII Xeon, PIII, Mobile PIII, PIII Xeon
4135ff02082Sdmick  */
4145ff02082Sdmick 
4155ff02082Sdmick #define	IS_LEGACY_P6(cpi) (			\
4165ff02082Sdmick 	cpi->cpi_family == 6 && 		\
4175ff02082Sdmick 		(cpi->cpi_model == 1 ||		\
4185ff02082Sdmick 		cpi->cpi_model == 3 ||		\
4195ff02082Sdmick 		cpi->cpi_model == 5 ||		\
4205ff02082Sdmick 		cpi->cpi_model == 6 ||		\
4215ff02082Sdmick 		cpi->cpi_model == 7 ||		\
4225ff02082Sdmick 		cpi->cpi_model == 8 ||		\
4235ff02082Sdmick 		cpi->cpi_model == 0xA ||	\
4245ff02082Sdmick 		cpi->cpi_model == 0xB)		\
4255ff02082Sdmick )
4265ff02082Sdmick 
4275ff02082Sdmick /* A "new F6" is everything with family 6 that's not the above */
4285ff02082Sdmick #define	IS_NEW_F6(cpi) ((cpi->cpi_family == 6) && !IS_LEGACY_P6(cpi))
4295ff02082Sdmick 
430bf91205bSksadhukh /* Extended family/model support */
431bf91205bSksadhukh #define	IS_EXTENDED_MODEL_INTEL(cpi) (cpi->cpi_family == 0x6 || \
432bf91205bSksadhukh 	cpi->cpi_family >= 0xf)
433bf91205bSksadhukh 
4345ff02082Sdmick /*
435f98fbcecSbholler  * Info for monitor/mwait idle loop.
436f98fbcecSbholler  *
437f98fbcecSbholler  * See cpuid section of "Intel 64 and IA-32 Architectures Software Developer's
438f98fbcecSbholler  * Manual Volume 2A: Instruction Set Reference, A-M" #25366-022US, November
439f98fbcecSbholler  * 2006.
440f98fbcecSbholler  * See MONITOR/MWAIT section of "AMD64 Architecture Programmer's Manual
441f98fbcecSbholler  * Documentation Updates" #33633, Rev 2.05, December 2006.
442f98fbcecSbholler  */
443f98fbcecSbholler #define	MWAIT_SUPPORT		(0x00000001)	/* mwait supported */
444f98fbcecSbholler #define	MWAIT_EXTENSIONS	(0x00000002)	/* extenstion supported */
445f98fbcecSbholler #define	MWAIT_ECX_INT_ENABLE	(0x00000004)	/* ecx 1 extension supported */
446f98fbcecSbholler #define	MWAIT_SUPPORTED(cpi)	((cpi)->cpi_std[1].cp_ecx & CPUID_INTC_ECX_MON)
447f98fbcecSbholler #define	MWAIT_INT_ENABLE(cpi)	((cpi)->cpi_std[5].cp_ecx & 0x2)
448f98fbcecSbholler #define	MWAIT_EXTENSION(cpi)	((cpi)->cpi_std[5].cp_ecx & 0x1)
449f98fbcecSbholler #define	MWAIT_SIZE_MIN(cpi)	BITX((cpi)->cpi_std[5].cp_eax, 15, 0)
450f98fbcecSbholler #define	MWAIT_SIZE_MAX(cpi)	BITX((cpi)->cpi_std[5].cp_ebx, 15, 0)
451f98fbcecSbholler /*
452f98fbcecSbholler  * Number of sub-cstates for a given c-state.
453f98fbcecSbholler  */
454f98fbcecSbholler #define	MWAIT_NUM_SUBC_STATES(cpi, c_state)			\
455f98fbcecSbholler 	BITX((cpi)->cpi_std[5].cp_edx, c_state + 3, c_state)
456f98fbcecSbholler 
4578a40a695Sgavinm /*
4587af88ac7SKuriakose Kuruvilla  * XSAVE leaf 0xD enumeration
4597af88ac7SKuriakose Kuruvilla  */
4607af88ac7SKuriakose Kuruvilla #define	CPUID_LEAFD_2_YMM_OFFSET	576
4617af88ac7SKuriakose Kuruvilla #define	CPUID_LEAFD_2_YMM_SIZE		256
4627af88ac7SKuriakose Kuruvilla 
4637af88ac7SKuriakose Kuruvilla /*
464e4b86885SCheng Sean Ye  * Functions we consune from cpuid_subr.c;  don't publish these in a header
465e4b86885SCheng Sean Ye  * file to try and keep people using the expected cpuid_* interfaces.
4668a40a695Sgavinm  */
467e4b86885SCheng Sean Ye extern uint32_t _cpuid_skt(uint_t, uint_t, uint_t, uint_t);
46889e921d5SKuriakose Kuruvilla extern const char *_cpuid_sktstr(uint_t, uint_t, uint_t, uint_t);
469e4b86885SCheng Sean Ye extern uint32_t _cpuid_chiprev(uint_t, uint_t, uint_t, uint_t);
470e4b86885SCheng Sean Ye extern const char *_cpuid_chiprevstr(uint_t, uint_t, uint_t, uint_t);
471e4b86885SCheng Sean Ye extern uint_t _cpuid_vendorstr_to_vendorcode(char *);
4728a40a695Sgavinm 
4738a40a695Sgavinm /*
474ae115bc7Smrj  * Apply up various platform-dependent restrictions where the
475ae115bc7Smrj  * underlying platform restrictions mean the CPU can be marked
476ae115bc7Smrj  * as less capable than its cpuid instruction would imply.
477ae115bc7Smrj  */
478843e1988Sjohnlev #if defined(__xpv)
479843e1988Sjohnlev static void
480843e1988Sjohnlev platform_cpuid_mangle(uint_t vendor, uint32_t eax, struct cpuid_regs *cp)
481843e1988Sjohnlev {
482843e1988Sjohnlev 	switch (eax) {
483e4b86885SCheng Sean Ye 	case 1: {
484e4b86885SCheng Sean Ye 		uint32_t mcamask = DOMAIN_IS_INITDOMAIN(xen_info) ?
485e4b86885SCheng Sean Ye 		    0 : CPUID_INTC_EDX_MCA;
486843e1988Sjohnlev 		cp->cp_edx &=
487e4b86885SCheng Sean Ye 		    ~(mcamask |
488e4b86885SCheng Sean Ye 		    CPUID_INTC_EDX_PSE |
489843e1988Sjohnlev 		    CPUID_INTC_EDX_VME | CPUID_INTC_EDX_DE |
490843e1988Sjohnlev 		    CPUID_INTC_EDX_SEP | CPUID_INTC_EDX_MTRR |
491843e1988Sjohnlev 		    CPUID_INTC_EDX_PGE | CPUID_INTC_EDX_PAT |
492843e1988Sjohnlev 		    CPUID_AMD_EDX_SYSC | CPUID_INTC_EDX_SEP |
493843e1988Sjohnlev 		    CPUID_INTC_EDX_PSE36 | CPUID_INTC_EDX_HTT);
494843e1988Sjohnlev 		break;
495e4b86885SCheng Sean Ye 	}
496ae115bc7Smrj 
497843e1988Sjohnlev 	case 0x80000001:
498843e1988Sjohnlev 		cp->cp_edx &=
499843e1988Sjohnlev 		    ~(CPUID_AMD_EDX_PSE |
500843e1988Sjohnlev 		    CPUID_INTC_EDX_VME | CPUID_INTC_EDX_DE |
501843e1988Sjohnlev 		    CPUID_AMD_EDX_MTRR | CPUID_AMD_EDX_PGE |
502843e1988Sjohnlev 		    CPUID_AMD_EDX_PAT | CPUID_AMD_EDX_PSE36 |
503843e1988Sjohnlev 		    CPUID_AMD_EDX_SYSC | CPUID_INTC_EDX_SEP |
504843e1988Sjohnlev 		    CPUID_AMD_EDX_TSCP);
505843e1988Sjohnlev 		cp->cp_ecx &= ~CPUID_AMD_ECX_CMP_LGCY;
506843e1988Sjohnlev 		break;
507843e1988Sjohnlev 	default:
508843e1988Sjohnlev 		break;
509843e1988Sjohnlev 	}
510843e1988Sjohnlev 
511843e1988Sjohnlev 	switch (vendor) {
512843e1988Sjohnlev 	case X86_VENDOR_Intel:
513843e1988Sjohnlev 		switch (eax) {
514843e1988Sjohnlev 		case 4:
515843e1988Sjohnlev 			/*
516843e1988Sjohnlev 			 * Zero out the (ncores-per-chip - 1) field
517843e1988Sjohnlev 			 */
518843e1988Sjohnlev 			cp->cp_eax &= 0x03fffffff;
519843e1988Sjohnlev 			break;
520843e1988Sjohnlev 		default:
521843e1988Sjohnlev 			break;
522843e1988Sjohnlev 		}
523843e1988Sjohnlev 		break;
524843e1988Sjohnlev 	case X86_VENDOR_AMD:
525843e1988Sjohnlev 		switch (eax) {
5262ef50f01SJoe Bonasera 
5272ef50f01SJoe Bonasera 		case 0x80000001:
5282ef50f01SJoe Bonasera 			cp->cp_ecx &= ~CPUID_AMD_ECX_CR8D;
5292ef50f01SJoe Bonasera 			break;
5302ef50f01SJoe Bonasera 
531843e1988Sjohnlev 		case 0x80000008:
532843e1988Sjohnlev 			/*
533843e1988Sjohnlev 			 * Zero out the (ncores-per-chip - 1) field
534843e1988Sjohnlev 			 */
535843e1988Sjohnlev 			cp->cp_ecx &= 0xffffff00;
536843e1988Sjohnlev 			break;
537843e1988Sjohnlev 		default:
538843e1988Sjohnlev 			break;
539843e1988Sjohnlev 		}
540843e1988Sjohnlev 		break;
541843e1988Sjohnlev 	default:
542843e1988Sjohnlev 		break;
543843e1988Sjohnlev 	}
544843e1988Sjohnlev }
545843e1988Sjohnlev #else
546ae115bc7Smrj #define	platform_cpuid_mangle(vendor, eax, cp)	/* nothing */
547843e1988Sjohnlev #endif
548ae115bc7Smrj 
549ae115bc7Smrj /*
5507c478bd9Sstevel@tonic-gate  *  Some undocumented ways of patching the results of the cpuid
5517c478bd9Sstevel@tonic-gate  *  instruction to permit running Solaris 10 on future cpus that
5527c478bd9Sstevel@tonic-gate  *  we don't currently support.  Could be set to non-zero values
5537c478bd9Sstevel@tonic-gate  *  via settings in eeprom.
5547c478bd9Sstevel@tonic-gate  */
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_ecx_include;
5577c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_ecx_exclude;
5587c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_edx_include;
5597c478bd9Sstevel@tonic-gate uint32_t cpuid_feature_edx_exclude;
5607c478bd9Sstevel@tonic-gate 
561a3114836SGerry Liu /*
562a3114836SGerry Liu  * Allocate space for mcpu_cpi in the machcpu structure for all non-boot CPUs.
563a3114836SGerry Liu  */
564ae115bc7Smrj void
565ae115bc7Smrj cpuid_alloc_space(cpu_t *cpu)
566ae115bc7Smrj {
567ae115bc7Smrj 	/*
568ae115bc7Smrj 	 * By convention, cpu0 is the boot cpu, which is set up
569ae115bc7Smrj 	 * before memory allocation is available.  All other cpus get
570ae115bc7Smrj 	 * their cpuid_info struct allocated here.
571ae115bc7Smrj 	 */
572ae115bc7Smrj 	ASSERT(cpu->cpu_id != 0);
573a3114836SGerry Liu 	ASSERT(cpu->cpu_m.mcpu_cpi == NULL);
574ae115bc7Smrj 	cpu->cpu_m.mcpu_cpi =
575ae115bc7Smrj 	    kmem_zalloc(sizeof (*cpu->cpu_m.mcpu_cpi), KM_SLEEP);
576ae115bc7Smrj }
577ae115bc7Smrj 
578ae115bc7Smrj void
579ae115bc7Smrj cpuid_free_space(cpu_t *cpu)
580ae115bc7Smrj {
581d129bde2Sesaxe 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
582d129bde2Sesaxe 	int i;
583d129bde2Sesaxe 
584a3114836SGerry Liu 	ASSERT(cpi != NULL);
585a3114836SGerry Liu 	ASSERT(cpi != &cpuid_info0);
586d129bde2Sesaxe 
587d129bde2Sesaxe 	/*
588d129bde2Sesaxe 	 * Free up any function 4 related dynamic storage
589d129bde2Sesaxe 	 */
590d129bde2Sesaxe 	for (i = 1; i < cpi->cpi_std_4_size; i++)
591d129bde2Sesaxe 		kmem_free(cpi->cpi_std_4[i], sizeof (struct cpuid_regs));
592d129bde2Sesaxe 	if (cpi->cpi_std_4_size > 0)
593d129bde2Sesaxe 		kmem_free(cpi->cpi_std_4,
594d129bde2Sesaxe 		    cpi->cpi_std_4_size * sizeof (struct cpuid_regs *));
595d129bde2Sesaxe 
596a3114836SGerry Liu 	kmem_free(cpi, sizeof (*cpi));
597a3114836SGerry Liu 	cpu->cpu_m.mcpu_cpi = NULL;
598ae115bc7Smrj }
599ae115bc7Smrj 
600551bc2a6Smrj #if !defined(__xpv)
601cfe84b82SMatt Amdur /*
602cfe84b82SMatt Amdur  * Determine the type of the underlying platform. This is used to customize
603cfe84b82SMatt Amdur  * initialization of various subsystems (e.g. TSC). determine_platform() must
604cfe84b82SMatt Amdur  * only ever be called once to prevent two processors from seeing different
605*79ec9da8SYuri Pankov  * values of platform_type. Must be called before cpuid_pass1(), the earliest
606*79ec9da8SYuri Pankov  * consumer to execute (uses _cpuid_chiprev --> synth_amd_info --> get_hwenv).
607cfe84b82SMatt Amdur  */
608cfe84b82SMatt Amdur void
609cfe84b82SMatt Amdur determine_platform(void)
610551bc2a6Smrj {
611551bc2a6Smrj 	struct cpuid_regs cp;
612*79ec9da8SYuri Pankov 	uint32_t base;
613*79ec9da8SYuri Pankov 	uint32_t regs[4];
614*79ec9da8SYuri Pankov 	char *hvstr = (char *)regs;
615551bc2a6Smrj 
616cfe84b82SMatt Amdur 	ASSERT(platform_type == -1);
617cfe84b82SMatt Amdur 
618349b53ddSStuart Maybee 	platform_type = HW_NATIVE;
619349b53ddSStuart Maybee 
620349b53ddSStuart Maybee 	if (!enable_platform_detection)
621349b53ddSStuart Maybee 		return;
622349b53ddSStuart Maybee 
623551bc2a6Smrj 	/*
624*79ec9da8SYuri Pankov 	 * If Hypervisor CPUID bit is set, try to determine hypervisor
625*79ec9da8SYuri Pankov 	 * vendor signature, and set platform type accordingly.
626*79ec9da8SYuri Pankov 	 *
627*79ec9da8SYuri Pankov 	 * References:
628*79ec9da8SYuri Pankov 	 * http://lkml.org/lkml/2008/10/1/246
629*79ec9da8SYuri Pankov 	 * http://kb.vmware.com/kb/1009458
630551bc2a6Smrj 	 */
631*79ec9da8SYuri Pankov 	cp.cp_eax = 0x1;
632551bc2a6Smrj 	(void) __cpuid_insn(&cp);
633*79ec9da8SYuri Pankov 	if ((cp.cp_ecx & CPUID_INTC_ECX_HV) != 0) {
634*79ec9da8SYuri Pankov 		cp.cp_eax = 0x40000000;
635*79ec9da8SYuri Pankov 		(void) __cpuid_insn(&cp);
636*79ec9da8SYuri Pankov 		regs[0] = cp.cp_ebx;
637*79ec9da8SYuri Pankov 		regs[1] = cp.cp_ecx;
638*79ec9da8SYuri Pankov 		regs[2] = cp.cp_edx;
639*79ec9da8SYuri Pankov 		regs[3] = 0;
640*79ec9da8SYuri Pankov 		if (strcmp(hvstr, HVSIG_XEN_HVM) == 0) {
641b9bfdccdSStuart Maybee 			platform_type = HW_XEN_HVM;
6426e5580c9SFrank Van Der Linden 			return;
643551bc2a6Smrj 		}
644*79ec9da8SYuri Pankov 		if (strcmp(hvstr, HVSIG_VMWARE) == 0) {
645*79ec9da8SYuri Pankov 			platform_type = HW_VMWARE;
646*79ec9da8SYuri Pankov 			return;
647*79ec9da8SYuri Pankov 		}
648*79ec9da8SYuri Pankov 		if (strcmp(hvstr, HVSIG_KVM) == 0) {
649*79ec9da8SYuri Pankov 			platform_type = HW_KVM;
650*79ec9da8SYuri Pankov 			return;
651*79ec9da8SYuri Pankov 		}
652*79ec9da8SYuri Pankov 		if (strcmp(hvstr, HVSIG_MICROSOFT) == 0)
653*79ec9da8SYuri Pankov 			platform_type = HW_MICROSOFT;
654*79ec9da8SYuri Pankov 	} else {
655*79ec9da8SYuri Pankov 		/*
656*79ec9da8SYuri Pankov 		 * Check older VMware hardware versions. VMware hypervisor is
657*79ec9da8SYuri Pankov 		 * detected by performing an IN operation to VMware hypervisor
658*79ec9da8SYuri Pankov 		 * port and checking that value returned in %ebx is VMware
659*79ec9da8SYuri Pankov 		 * hypervisor magic value.
660*79ec9da8SYuri Pankov 		 *
661*79ec9da8SYuri Pankov 		 * References: http://kb.vmware.com/kb/1009458
662*79ec9da8SYuri Pankov 		 */
663*79ec9da8SYuri Pankov 		vmware_port(VMWARE_HVCMD_GETVERSION, regs);
664*79ec9da8SYuri Pankov 		if (regs[1] == VMWARE_HVMAGIC) {
665*79ec9da8SYuri Pankov 			platform_type = HW_VMWARE;
666*79ec9da8SYuri Pankov 			return;
667*79ec9da8SYuri Pankov 		}
668b9bfdccdSStuart Maybee 	}
669b9bfdccdSStuart Maybee 
670*79ec9da8SYuri Pankov 	/*
671*79ec9da8SYuri Pankov 	 * Check Xen hypervisor. In a fully virtualized domain,
672*79ec9da8SYuri Pankov 	 * Xen's pseudo-cpuid function returns a string representing the
673*79ec9da8SYuri Pankov 	 * Xen signature in %ebx, %ecx, and %edx. %eax contains the maximum
674*79ec9da8SYuri Pankov 	 * supported cpuid function. We need at least a (base + 2) leaf value
675*79ec9da8SYuri Pankov 	 * to do what we want to do. Try different base values, since the
676*79ec9da8SYuri Pankov 	 * hypervisor might use a different one depending on whether Hyper-V
677*79ec9da8SYuri Pankov 	 * emulation is switched on by default or not.
678*79ec9da8SYuri Pankov 	 */
679*79ec9da8SYuri Pankov 	for (base = 0x40000000; base < 0x40010000; base += 0x100) {
680*79ec9da8SYuri Pankov 		cp.cp_eax = base;
681*79ec9da8SYuri Pankov 		(void) __cpuid_insn(&cp);
682*79ec9da8SYuri Pankov 		regs[0] = cp.cp_ebx;
683*79ec9da8SYuri Pankov 		regs[1] = cp.cp_ecx;
684*79ec9da8SYuri Pankov 		regs[2] = cp.cp_edx;
685*79ec9da8SYuri Pankov 		regs[3] = 0;
686*79ec9da8SYuri Pankov 		if (strcmp(hvstr, HVSIG_XEN_HVM) == 0 &&
687*79ec9da8SYuri Pankov 		    cp.cp_eax >= (base + 2)) {
688*79ec9da8SYuri Pankov 			platform_type &= ~HW_NATIVE;
689*79ec9da8SYuri Pankov 			platform_type |= HW_XEN_HVM;
690*79ec9da8SYuri Pankov 			return;
691*79ec9da8SYuri Pankov 		}
692*79ec9da8SYuri Pankov 	}
6936e5580c9SFrank Van Der Linden }
6946e5580c9SFrank Van Der Linden 
695b9bfdccdSStuart Maybee int
696b9bfdccdSStuart Maybee get_hwenv(void)
697b9bfdccdSStuart Maybee {
698cfe84b82SMatt Amdur 	ASSERT(platform_type != -1);
699b9bfdccdSStuart Maybee 	return (platform_type);
700b9bfdccdSStuart Maybee }
701b9bfdccdSStuart Maybee 
702b9bfdccdSStuart Maybee int
703b9bfdccdSStuart Maybee is_controldom(void)
704b9bfdccdSStuart Maybee {
705b9bfdccdSStuart Maybee 	return (0);
706b9bfdccdSStuart Maybee }
707b9bfdccdSStuart Maybee 
708b9bfdccdSStuart Maybee #else
709b9bfdccdSStuart Maybee 
710b9bfdccdSStuart Maybee int
711b9bfdccdSStuart Maybee get_hwenv(void)
712b9bfdccdSStuart Maybee {
713b9bfdccdSStuart Maybee 	return (HW_XEN_PV);
714b9bfdccdSStuart Maybee }
715b9bfdccdSStuart Maybee 
716b9bfdccdSStuart Maybee int
717b9bfdccdSStuart Maybee is_controldom(void)
718b9bfdccdSStuart Maybee {
719b9bfdccdSStuart Maybee 	return (DOMAIN_IS_INITDOMAIN(xen_info));
720b9bfdccdSStuart Maybee }
721b9bfdccdSStuart Maybee 
722551bc2a6Smrj #endif	/* __xpv */
723551bc2a6Smrj 
7248031591dSSrihari Venkatesan static void
7257417cfdeSKuriakose Kuruvilla cpuid_intel_getids(cpu_t *cpu, void *feature)
7268031591dSSrihari Venkatesan {
7278031591dSSrihari Venkatesan 	uint_t i;
7288031591dSSrihari Venkatesan 	uint_t chipid_shift = 0;
7298031591dSSrihari Venkatesan 	uint_t coreid_shift = 0;
7308031591dSSrihari Venkatesan 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
7318031591dSSrihari Venkatesan 
7328031591dSSrihari Venkatesan 	for (i = 1; i < cpi->cpi_ncpu_per_chip; i <<= 1)
7338031591dSSrihari Venkatesan 		chipid_shift++;
7348031591dSSrihari Venkatesan 
7358031591dSSrihari Venkatesan 	cpi->cpi_chipid = cpi->cpi_apicid >> chipid_shift;
7368031591dSSrihari Venkatesan 	cpi->cpi_clogid = cpi->cpi_apicid & ((1 << chipid_shift) - 1);
7378031591dSSrihari Venkatesan 
7387417cfdeSKuriakose Kuruvilla 	if (is_x86_feature(feature, X86FSET_CMP)) {
7398031591dSSrihari Venkatesan 		/*
7408031591dSSrihari Venkatesan 		 * Multi-core (and possibly multi-threaded)
7418031591dSSrihari Venkatesan 		 * processors.
7428031591dSSrihari Venkatesan 		 */
7438031591dSSrihari Venkatesan 		uint_t ncpu_per_core;
7448031591dSSrihari Venkatesan 		if (cpi->cpi_ncore_per_chip == 1)
7458031591dSSrihari Venkatesan 			ncpu_per_core = cpi->cpi_ncpu_per_chip;
7468031591dSSrihari Venkatesan 		else if (cpi->cpi_ncore_per_chip > 1)
7478031591dSSrihari Venkatesan 			ncpu_per_core = cpi->cpi_ncpu_per_chip /
7488031591dSSrihari Venkatesan 			    cpi->cpi_ncore_per_chip;
7498031591dSSrihari Venkatesan 		/*
7508031591dSSrihari Venkatesan 		 * 8bit APIC IDs on dual core Pentiums
7518031591dSSrihari Venkatesan 		 * look like this:
7528031591dSSrihari Venkatesan 		 *
7538031591dSSrihari Venkatesan 		 * +-----------------------+------+------+
7548031591dSSrihari Venkatesan 		 * | Physical Package ID   |  MC  |  HT  |
7558031591dSSrihari Venkatesan 		 * +-----------------------+------+------+
7568031591dSSrihari Venkatesan 		 * <------- chipid -------->
7578031591dSSrihari Venkatesan 		 * <------- coreid --------------->
7588031591dSSrihari Venkatesan 		 *			   <--- clogid -->
7598031591dSSrihari Venkatesan 		 *			   <------>
7608031591dSSrihari Venkatesan 		 *			   pkgcoreid
7618031591dSSrihari Venkatesan 		 *
7628031591dSSrihari Venkatesan 		 * Where the number of bits necessary to
7638031591dSSrihari Venkatesan 		 * represent MC and HT fields together equals
7648031591dSSrihari Venkatesan 		 * to the minimum number of bits necessary to
7658031591dSSrihari Venkatesan 		 * store the value of cpi->cpi_ncpu_per_chip.
7668031591dSSrihari Venkatesan 		 * Of those bits, the MC part uses the number
7678031591dSSrihari Venkatesan 		 * of bits necessary to store the value of
7688031591dSSrihari Venkatesan 		 * cpi->cpi_ncore_per_chip.
7698031591dSSrihari Venkatesan 		 */
7708031591dSSrihari Venkatesan 		for (i = 1; i < ncpu_per_core; i <<= 1)
7718031591dSSrihari Venkatesan 			coreid_shift++;
7728031591dSSrihari Venkatesan 		cpi->cpi_coreid = cpi->cpi_apicid >> coreid_shift;
7738031591dSSrihari Venkatesan 		cpi->cpi_pkgcoreid = cpi->cpi_clogid >> coreid_shift;
7747417cfdeSKuriakose Kuruvilla 	} else if (is_x86_feature(feature, X86FSET_HTT)) {
7758031591dSSrihari Venkatesan 		/*
7768031591dSSrihari Venkatesan 		 * Single-core multi-threaded processors.
7778031591dSSrihari Venkatesan 		 */
7788031591dSSrihari Venkatesan 		cpi->cpi_coreid = cpi->cpi_chipid;
7798031591dSSrihari Venkatesan 		cpi->cpi_pkgcoreid = 0;
7808031591dSSrihari Venkatesan 	}
7818031591dSSrihari Venkatesan 	cpi->cpi_procnodeid = cpi->cpi_chipid;
7827660e73fSHans Rosenfeld 	cpi->cpi_compunitid = cpi->cpi_coreid;
7838031591dSSrihari Venkatesan }
7848031591dSSrihari Venkatesan 
7858031591dSSrihari Venkatesan static void
7868031591dSSrihari Venkatesan cpuid_amd_getids(cpu_t *cpu)
7878031591dSSrihari Venkatesan {
7881fbe4a4fSSrihari Venkatesan 	int i, first_half, coreidsz;
7898031591dSSrihari Venkatesan 	uint32_t nb_caps_reg;
7908031591dSSrihari Venkatesan 	uint_t node2_1;
7918031591dSSrihari Venkatesan 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
7927660e73fSHans Rosenfeld 	struct cpuid_regs *cp;
7938031591dSSrihari Venkatesan 
7948031591dSSrihari Venkatesan 	/*
7958031591dSSrihari Venkatesan 	 * AMD CMP chips currently have a single thread per core.
7968031591dSSrihari Venkatesan 	 *
7978031591dSSrihari Venkatesan 	 * Since no two cpus share a core we must assign a distinct coreid
7988031591dSSrihari Venkatesan 	 * per cpu, and we do this by using the cpu_id.  This scheme does not,
7998031591dSSrihari Venkatesan 	 * however, guarantee that sibling cores of a chip will have sequential
8008031591dSSrihari Venkatesan 	 * coreids starting at a multiple of the number of cores per chip -
8018031591dSSrihari Venkatesan 	 * that is usually the case, but if the ACPI MADT table is presented
8028031591dSSrihari Venkatesan 	 * in a different order then we need to perform a few more gymnastics
8038031591dSSrihari Venkatesan 	 * for the pkgcoreid.
8048031591dSSrihari Venkatesan 	 *
8058031591dSSrihari Venkatesan 	 * All processors in the system have the same number of enabled
8068031591dSSrihari Venkatesan 	 * cores. Cores within a processor are always numbered sequentially
8078031591dSSrihari Venkatesan 	 * from 0 regardless of how many or which are disabled, and there
8088031591dSSrihari Venkatesan 	 * is no way for operating system to discover the real core id when some
8098031591dSSrihari Venkatesan 	 * are disabled.
8107660e73fSHans Rosenfeld 	 *
8117660e73fSHans Rosenfeld 	 * In family 0x15, the cores come in pairs called compute units. They
8127660e73fSHans Rosenfeld 	 * share I$ and L2 caches and the FPU. Enumeration of this feature is
8137660e73fSHans Rosenfeld 	 * simplified by the new topology extensions CPUID leaf, indicated by
8147660e73fSHans Rosenfeld 	 * the X86 feature X86FSET_TOPOEXT.
8158031591dSSrihari Venkatesan 	 */
8168031591dSSrihari Venkatesan 
8178031591dSSrihari Venkatesan 	cpi->cpi_coreid = cpu->cpu_id;
8187660e73fSHans Rosenfeld 	cpi->cpi_compunitid = cpu->cpu_id;
8198031591dSSrihari Venkatesan 
8208031591dSSrihari Venkatesan 	if (cpi->cpi_xmaxeax >= 0x80000008) {
8218031591dSSrihari Venkatesan 
8228031591dSSrihari Venkatesan 		coreidsz = BITX((cpi)->cpi_extd[8].cp_ecx, 15, 12);
8238031591dSSrihari Venkatesan 
8248031591dSSrihari Venkatesan 		/*
8258031591dSSrihari Venkatesan 		 * In AMD parlance chip is really a node while Solaris
8268031591dSSrihari Venkatesan 		 * sees chip as equivalent to socket/package.
8278031591dSSrihari Venkatesan 		 */
8288031591dSSrihari Venkatesan 		cpi->cpi_ncore_per_chip =
8298031591dSSrihari Venkatesan 		    BITX((cpi)->cpi_extd[8].cp_ecx, 7, 0) + 1;
8301fbe4a4fSSrihari Venkatesan 		if (coreidsz == 0) {
8318031591dSSrihari Venkatesan 			/* Use legacy method */
8321fbe4a4fSSrihari Venkatesan 			for (i = 1; i < cpi->cpi_ncore_per_chip; i <<= 1)
8331fbe4a4fSSrihari Venkatesan 				coreidsz++;
8341fbe4a4fSSrihari Venkatesan 			if (coreidsz == 0)
8351fbe4a4fSSrihari Venkatesan 				coreidsz = 1;
8361fbe4a4fSSrihari Venkatesan 		}
8378031591dSSrihari Venkatesan 	} else {
8388031591dSSrihari Venkatesan 		/* Assume single-core part */
8391fbe4a4fSSrihari Venkatesan 		cpi->cpi_ncore_per_chip = 1;
84072b70389SJakub Jermar 		coreidsz = 1;
8418031591dSSrihari Venkatesan 	}
8428031591dSSrihari Venkatesan 
8431fbe4a4fSSrihari Venkatesan 	cpi->cpi_clogid = cpi->cpi_pkgcoreid =
8441fbe4a4fSSrihari Venkatesan 	    cpi->cpi_apicid & ((1<<coreidsz) - 1);
8458031591dSSrihari Venkatesan 	cpi->cpi_ncpu_per_chip = cpi->cpi_ncore_per_chip;
8468031591dSSrihari Venkatesan 
8477660e73fSHans Rosenfeld 	/* Get node ID, compute unit ID */
8487660e73fSHans Rosenfeld 	if (is_x86_feature(x86_featureset, X86FSET_TOPOEXT) &&
8497660e73fSHans Rosenfeld 	    cpi->cpi_xmaxeax >= 0x8000001e) {
8507660e73fSHans Rosenfeld 		cp = &cpi->cpi_extd[0x1e];
8517660e73fSHans Rosenfeld 		cp->cp_eax = 0x8000001e;
8527660e73fSHans Rosenfeld 		(void) __cpuid_insn(cp);
8537660e73fSHans Rosenfeld 
8547660e73fSHans Rosenfeld 		cpi->cpi_procnodes_per_pkg = BITX(cp->cp_ecx, 10, 8) + 1;
8557660e73fSHans Rosenfeld 		cpi->cpi_procnodeid = BITX(cp->cp_ecx, 7, 0);
8567660e73fSHans Rosenfeld 		cpi->cpi_cores_per_compunit = BITX(cp->cp_ebx, 15, 8) + 1;
8577660e73fSHans Rosenfeld 		cpi->cpi_compunitid = BITX(cp->cp_ebx, 7, 0)
8587660e73fSHans Rosenfeld 		    + (cpi->cpi_ncore_per_chip / cpi->cpi_cores_per_compunit)
8597660e73fSHans Rosenfeld 		    * (cpi->cpi_procnodeid / cpi->cpi_procnodes_per_pkg);
8607660e73fSHans Rosenfeld 	} else if (cpi->cpi_family == 0xf || cpi->cpi_family >= 0x11) {
8611fbe4a4fSSrihari Venkatesan 		cpi->cpi_procnodeid = (cpi->cpi_apicid >> coreidsz) & 7;
8628031591dSSrihari Venkatesan 	} else if (cpi->cpi_family == 0x10) {
8638031591dSSrihari Venkatesan 		/*
8648031591dSSrihari Venkatesan 		 * See if we are a multi-node processor.
8658031591dSSrihari Venkatesan 		 * All processors in the system have the same number of nodes
8668031591dSSrihari Venkatesan 		 */
8678031591dSSrihari Venkatesan 		nb_caps_reg =  pci_getl_func(0, 24, 3, 0xe8);
8688031591dSSrihari Venkatesan 		if ((cpi->cpi_model < 8) || BITX(nb_caps_reg, 29, 29) == 0) {
8698031591dSSrihari Venkatesan 			/* Single-node */
8701fbe4a4fSSrihari Venkatesan 			cpi->cpi_procnodeid = BITX(cpi->cpi_apicid, 5,
8711fbe4a4fSSrihari Venkatesan 			    coreidsz);
8728031591dSSrihari Venkatesan 		} else {
8738031591dSSrihari Venkatesan 
8748031591dSSrihari Venkatesan 			/*
8758031591dSSrihari Venkatesan 			 * Multi-node revision D (2 nodes per package
8768031591dSSrihari Venkatesan 			 * are supported)
8778031591dSSrihari Venkatesan 			 */
8788031591dSSrihari Venkatesan 			cpi->cpi_procnodes_per_pkg = 2;
8798031591dSSrihari Venkatesan 
8808031591dSSrihari Venkatesan 			first_half = (cpi->cpi_pkgcoreid <=
8818031591dSSrihari Venkatesan 			    (cpi->cpi_ncore_per_chip/2 - 1));
8828031591dSSrihari Venkatesan 
8838031591dSSrihari Venkatesan 			if (cpi->cpi_apicid == cpi->cpi_pkgcoreid) {
8848031591dSSrihari Venkatesan 				/* We are BSP */
8858031591dSSrihari Venkatesan 				cpi->cpi_procnodeid = (first_half ? 0 : 1);
8868031591dSSrihari Venkatesan 			} else {
8878031591dSSrihari Venkatesan 
8888031591dSSrihari Venkatesan 				/* We are AP */
8898031591dSSrihari Venkatesan 				/* NodeId[2:1] bits to use for reading F3xe8 */
8908031591dSSrihari Venkatesan 				node2_1 = BITX(cpi->cpi_apicid, 5, 4) << 1;
8918031591dSSrihari Venkatesan 
8928031591dSSrihari Venkatesan 				nb_caps_reg =
8938031591dSSrihari Venkatesan 				    pci_getl_func(0, 24 + node2_1, 3, 0xe8);
8948031591dSSrihari Venkatesan 
8958031591dSSrihari Venkatesan 				/*
8968031591dSSrihari Venkatesan 				 * Check IntNodeNum bit (31:30, but bit 31 is
8978031591dSSrihari Venkatesan 				 * always 0 on dual-node processors)
8988031591dSSrihari Venkatesan 				 */
8998031591dSSrihari Venkatesan 				if (BITX(nb_caps_reg, 30, 30) == 0)
9008031591dSSrihari Venkatesan 					cpi->cpi_procnodeid = node2_1 +
9018031591dSSrihari Venkatesan 					    !first_half;
9028031591dSSrihari Venkatesan 				else
9038031591dSSrihari Venkatesan 					cpi->cpi_procnodeid = node2_1 +
9048031591dSSrihari Venkatesan 					    first_half;
9058031591dSSrihari Venkatesan 			}
9068031591dSSrihari Venkatesan 		}
9078031591dSSrihari Venkatesan 	} else {
9088031591dSSrihari Venkatesan 		cpi->cpi_procnodeid = 0;
9098031591dSSrihari Venkatesan 	}
9107660e73fSHans Rosenfeld 
9117660e73fSHans Rosenfeld 	cpi->cpi_chipid =
9127660e73fSHans Rosenfeld 	    cpi->cpi_procnodeid / cpi->cpi_procnodes_per_pkg;
9138031591dSSrihari Venkatesan }
9148031591dSSrihari Venkatesan 
9157af88ac7SKuriakose Kuruvilla /*
9167af88ac7SKuriakose Kuruvilla  * Setup XFeature_Enabled_Mask register. Required by xsave feature.
9177af88ac7SKuriakose Kuruvilla  */
9187af88ac7SKuriakose Kuruvilla void
9197af88ac7SKuriakose Kuruvilla setup_xfem(void)
9207af88ac7SKuriakose Kuruvilla {
9217af88ac7SKuriakose Kuruvilla 	uint64_t flags = XFEATURE_LEGACY_FP;
9227af88ac7SKuriakose Kuruvilla 
9237af88ac7SKuriakose Kuruvilla 	ASSERT(is_x86_feature(x86_featureset, X86FSET_XSAVE));
9247af88ac7SKuriakose Kuruvilla 
9257af88ac7SKuriakose Kuruvilla 	if (is_x86_feature(x86_featureset, X86FSET_SSE))
9267af88ac7SKuriakose Kuruvilla 		flags |= XFEATURE_SSE;
9277af88ac7SKuriakose Kuruvilla 
9287af88ac7SKuriakose Kuruvilla 	if (is_x86_feature(x86_featureset, X86FSET_AVX))
9297af88ac7SKuriakose Kuruvilla 		flags |= XFEATURE_AVX;
9307af88ac7SKuriakose Kuruvilla 
9317af88ac7SKuriakose Kuruvilla 	set_xcr(XFEATURE_ENABLED_MASK, flags);
9327af88ac7SKuriakose Kuruvilla 
9337af88ac7SKuriakose Kuruvilla 	xsave_bv_all = flags;
9347af88ac7SKuriakose Kuruvilla }
9357af88ac7SKuriakose Kuruvilla 
936dfea898aSKuriakose Kuruvilla void
937dfea898aSKuriakose Kuruvilla cpuid_pass1(cpu_t *cpu, uchar_t *featureset)
9387c478bd9Sstevel@tonic-gate {
9397c478bd9Sstevel@tonic-gate 	uint32_t mask_ecx, mask_edx;
9407c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi;
9418949bcd6Sandrei 	struct cpuid_regs *cp;
9427c478bd9Sstevel@tonic-gate 	int xcpuid;
943843e1988Sjohnlev #if !defined(__xpv)
9445b8a6efeSbholler 	extern int idle_cpu_prefer_mwait;
945843e1988Sjohnlev #endif
946ae115bc7Smrj 
9477c478bd9Sstevel@tonic-gate 	/*
948a3114836SGerry Liu 	 * Space statically allocated for BSP, ensure pointer is set
9497c478bd9Sstevel@tonic-gate 	 */
9507417cfdeSKuriakose Kuruvilla 	if (cpu->cpu_id == 0) {
9517417cfdeSKuriakose Kuruvilla 		if (cpu->cpu_m.mcpu_cpi == NULL)
952ae115bc7Smrj 			cpu->cpu_m.mcpu_cpi = &cpuid_info0;
9537417cfdeSKuriakose Kuruvilla 	}
9547417cfdeSKuriakose Kuruvilla 
9557417cfdeSKuriakose Kuruvilla 	add_x86_feature(featureset, X86FSET_CPUID);
9567417cfdeSKuriakose Kuruvilla 
957ae115bc7Smrj 	cpi = cpu->cpu_m.mcpu_cpi;
958ae115bc7Smrj 	ASSERT(cpi != NULL);
9597c478bd9Sstevel@tonic-gate 	cp = &cpi->cpi_std[0];
9608949bcd6Sandrei 	cp->cp_eax = 0;
9618949bcd6Sandrei 	cpi->cpi_maxeax = __cpuid_insn(cp);
9627c478bd9Sstevel@tonic-gate 	{
9637c478bd9Sstevel@tonic-gate 		uint32_t *iptr = (uint32_t *)cpi->cpi_vendorstr;
9647c478bd9Sstevel@tonic-gate 		*iptr++ = cp->cp_ebx;
9657c478bd9Sstevel@tonic-gate 		*iptr++ = cp->cp_edx;
9667c478bd9Sstevel@tonic-gate 		*iptr++ = cp->cp_ecx;
9677c478bd9Sstevel@tonic-gate 		*(char *)&cpi->cpi_vendorstr[12] = '\0';
9687c478bd9Sstevel@tonic-gate 	}
9697c478bd9Sstevel@tonic-gate 
970e4b86885SCheng Sean Ye 	cpi->cpi_vendor = _cpuid_vendorstr_to_vendorcode(cpi->cpi_vendorstr);
9717c478bd9Sstevel@tonic-gate 	x86_vendor = cpi->cpi_vendor; /* for compatibility */
9727c478bd9Sstevel@tonic-gate 
9737c478bd9Sstevel@tonic-gate 	/*
9747c478bd9Sstevel@tonic-gate 	 * Limit the range in case of weird hardware
9757c478bd9Sstevel@tonic-gate 	 */
9767c478bd9Sstevel@tonic-gate 	if (cpi->cpi_maxeax > CPI_MAXEAX_MAX)
9777c478bd9Sstevel@tonic-gate 		cpi->cpi_maxeax = CPI_MAXEAX_MAX;
9787c478bd9Sstevel@tonic-gate 	if (cpi->cpi_maxeax < 1)
9797c478bd9Sstevel@tonic-gate 		goto pass1_done;
9807c478bd9Sstevel@tonic-gate 
9817c478bd9Sstevel@tonic-gate 	cp = &cpi->cpi_std[1];
9828949bcd6Sandrei 	cp->cp_eax = 1;
9838949bcd6Sandrei 	(void) __cpuid_insn(cp);
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 	/*
9867c478bd9Sstevel@tonic-gate 	 * Extract identifying constants for easy access.
9877c478bd9Sstevel@tonic-gate 	 */
9887c478bd9Sstevel@tonic-gate 	cpi->cpi_model = CPI_MODEL(cpi);
9897c478bd9Sstevel@tonic-gate 	cpi->cpi_family = CPI_FAMILY(cpi);
9907c478bd9Sstevel@tonic-gate 
9915ff02082Sdmick 	if (cpi->cpi_family == 0xf)
9927c478bd9Sstevel@tonic-gate 		cpi->cpi_family += CPI_FAMILY_XTD(cpi);
9935ff02082Sdmick 
99468c91426Sdmick 	/*
995875b116eSkchow 	 * Beware: AMD uses "extended model" iff base *FAMILY* == 0xf.
99668c91426Sdmick 	 * Intel, and presumably everyone else, uses model == 0xf, as
99768c91426Sdmick 	 * one would expect (max value means possible overflow).  Sigh.
99868c91426Sdmick 	 */
99968c91426Sdmick 
100068c91426Sdmick 	switch (cpi->cpi_vendor) {
1001bf91205bSksadhukh 	case X86_VENDOR_Intel:
1002bf91205bSksadhukh 		if (IS_EXTENDED_MODEL_INTEL(cpi))
1003bf91205bSksadhukh 			cpi->cpi_model += CPI_MODEL_XTD(cpi) << 4;
1004447af253Sksadhukh 		break;
100568c91426Sdmick 	case X86_VENDOR_AMD:
1006875b116eSkchow 		if (CPI_FAMILY(cpi) == 0xf)
100768c91426Sdmick 			cpi->cpi_model += CPI_MODEL_XTD(cpi) << 4;
100868c91426Sdmick 		break;
100968c91426Sdmick 	default:
10105ff02082Sdmick 		if (cpi->cpi_model == 0xf)
10117c478bd9Sstevel@tonic-gate 			cpi->cpi_model += CPI_MODEL_XTD(cpi) << 4;
101268c91426Sdmick 		break;
101368c91426Sdmick 	}
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 	cpi->cpi_step = CPI_STEP(cpi);
10167c478bd9Sstevel@tonic-gate 	cpi->cpi_brandid = CPI_BRANDID(cpi);
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate 	/*
10197c478bd9Sstevel@tonic-gate 	 * *default* assumptions:
10207c478bd9Sstevel@tonic-gate 	 * - believe %edx feature word
10217c478bd9Sstevel@tonic-gate 	 * - ignore %ecx feature word
10227c478bd9Sstevel@tonic-gate 	 * - 32-bit virtual and physical addressing
10237c478bd9Sstevel@tonic-gate 	 */
10247c478bd9Sstevel@tonic-gate 	mask_edx = 0xffffffff;
10257c478bd9Sstevel@tonic-gate 	mask_ecx = 0;
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 	cpi->cpi_pabits = cpi->cpi_vabits = 32;
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
10307c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
10317c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5)
10327c478bd9Sstevel@tonic-gate 			x86_type = X86_TYPE_P5;
10335ff02082Sdmick 		else if (IS_LEGACY_P6(cpi)) {
10347c478bd9Sstevel@tonic-gate 			x86_type = X86_TYPE_P6;
10357c478bd9Sstevel@tonic-gate 			pentiumpro_bug4046376 = 1;
10367c478bd9Sstevel@tonic-gate 			pentiumpro_bug4064495 = 1;
10377c478bd9Sstevel@tonic-gate 			/*
10387c478bd9Sstevel@tonic-gate 			 * Clear the SEP bit when it was set erroneously
10397c478bd9Sstevel@tonic-gate 			 */
10407c478bd9Sstevel@tonic-gate 			if (cpi->cpi_model < 3 && cpi->cpi_step < 3)
10417c478bd9Sstevel@tonic-gate 				cp->cp_edx &= ~CPUID_INTC_EDX_SEP;
10425ff02082Sdmick 		} else if (IS_NEW_F6(cpi) || cpi->cpi_family == 0xf) {
10437c478bd9Sstevel@tonic-gate 			x86_type = X86_TYPE_P4;
10447c478bd9Sstevel@tonic-gate 			/*
10457c478bd9Sstevel@tonic-gate 			 * We don't currently depend on any of the %ecx
10467c478bd9Sstevel@tonic-gate 			 * features until Prescott, so we'll only check
10477c478bd9Sstevel@tonic-gate 			 * this from P4 onwards.  We might want to revisit
10487c478bd9Sstevel@tonic-gate 			 * that idea later.
10497c478bd9Sstevel@tonic-gate 			 */
10507c478bd9Sstevel@tonic-gate 			mask_ecx = 0xffffffff;
10517c478bd9Sstevel@tonic-gate 		} else if (cpi->cpi_family > 0xf)
10527c478bd9Sstevel@tonic-gate 			mask_ecx = 0xffffffff;
10537c622d23Sbholler 		/*
10547c622d23Sbholler 		 * We don't support MONITOR/MWAIT if leaf 5 is not available
10557c622d23Sbholler 		 * to obtain the monitor linesize.
10567c622d23Sbholler 		 */
10577c622d23Sbholler 		if (cpi->cpi_maxeax < 5)
10587c622d23Sbholler 			mask_ecx &= ~CPUID_INTC_ECX_MON;
10597c478bd9Sstevel@tonic-gate 		break;
10607c478bd9Sstevel@tonic-gate 	case X86_VENDOR_IntelClone:
10617c478bd9Sstevel@tonic-gate 	default:
10627c478bd9Sstevel@tonic-gate 		break;
10637c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
10647c478bd9Sstevel@tonic-gate #if defined(OPTERON_ERRATUM_108)
10657c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 0xf && cpi->cpi_model == 0xe) {
10667c478bd9Sstevel@tonic-gate 			cp->cp_eax = (0xf0f & cp->cp_eax) | 0xc0;
10677c478bd9Sstevel@tonic-gate 			cpi->cpi_model = 0xc;
10687c478bd9Sstevel@tonic-gate 		} else
10697c478bd9Sstevel@tonic-gate #endif
10707c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5) {
10717c478bd9Sstevel@tonic-gate 			/*
10727c478bd9Sstevel@tonic-gate 			 * AMD K5 and K6
10737c478bd9Sstevel@tonic-gate 			 *
10747c478bd9Sstevel@tonic-gate 			 * These CPUs have an incomplete implementation
10757c478bd9Sstevel@tonic-gate 			 * of MCA/MCE which we mask away.
10767c478bd9Sstevel@tonic-gate 			 */
10778949bcd6Sandrei 			mask_edx &= ~(CPUID_INTC_EDX_MCE | CPUID_INTC_EDX_MCA);
10788949bcd6Sandrei 
10797c478bd9Sstevel@tonic-gate 			/*
10807c478bd9Sstevel@tonic-gate 			 * Model 0 uses the wrong (APIC) bit
10817c478bd9Sstevel@tonic-gate 			 * to indicate PGE.  Fix it here.
10827c478bd9Sstevel@tonic-gate 			 */
10838949bcd6Sandrei 			if (cpi->cpi_model == 0) {
10847c478bd9Sstevel@tonic-gate 				if (cp->cp_edx & 0x200) {
10857c478bd9Sstevel@tonic-gate 					cp->cp_edx &= ~0x200;
10867c478bd9Sstevel@tonic-gate 					cp->cp_edx |= CPUID_INTC_EDX_PGE;
10877c478bd9Sstevel@tonic-gate 				}
10887c478bd9Sstevel@tonic-gate 			}
10898949bcd6Sandrei 
10908949bcd6Sandrei 			/*
10918949bcd6Sandrei 			 * Early models had problems w/ MMX; disable.
10928949bcd6Sandrei 			 */
10938949bcd6Sandrei 			if (cpi->cpi_model < 6)
10948949bcd6Sandrei 				mask_edx &= ~CPUID_INTC_EDX_MMX;
10958949bcd6Sandrei 		}
10968949bcd6Sandrei 
10978949bcd6Sandrei 		/*
10988949bcd6Sandrei 		 * For newer families, SSE3 and CX16, at least, are valid;
10998949bcd6Sandrei 		 * enable all
11008949bcd6Sandrei 		 */
11018949bcd6Sandrei 		if (cpi->cpi_family >= 0xf)
11028949bcd6Sandrei 			mask_ecx = 0xffffffff;
11037c622d23Sbholler 		/*
11047c622d23Sbholler 		 * We don't support MONITOR/MWAIT if leaf 5 is not available
11057c622d23Sbholler 		 * to obtain the monitor linesize.
11067c622d23Sbholler 		 */
11077c622d23Sbholler 		if (cpi->cpi_maxeax < 5)
11087c622d23Sbholler 			mask_ecx &= ~CPUID_INTC_ECX_MON;
11095b8a6efeSbholler 
1110843e1988Sjohnlev #if !defined(__xpv)
11115b8a6efeSbholler 		/*
11125b8a6efeSbholler 		 * Do not use MONITOR/MWAIT to halt in the idle loop on any AMD
11135b8a6efeSbholler 		 * processors.  AMD does not intend MWAIT to be used in the cpu
11145b8a6efeSbholler 		 * idle loop on current and future processors.  10h and future
11155b8a6efeSbholler 		 * AMD processors use more power in MWAIT than HLT.
11165b8a6efeSbholler 		 * Pre-family-10h Opterons do not have the MWAIT instruction.
11175b8a6efeSbholler 		 */
11185b8a6efeSbholler 		idle_cpu_prefer_mwait = 0;
1119843e1988Sjohnlev #endif
11205b8a6efeSbholler 
11217c478bd9Sstevel@tonic-gate 		break;
11227c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
11237c478bd9Sstevel@tonic-gate 		/*
11247c478bd9Sstevel@tonic-gate 		 * workaround the NT workaround in CMS 4.1
11257c478bd9Sstevel@tonic-gate 		 */
11267c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5 && cpi->cpi_model == 4 &&
11277c478bd9Sstevel@tonic-gate 		    (cpi->cpi_step == 2 || cpi->cpi_step == 3))
11287c478bd9Sstevel@tonic-gate 			cp->cp_edx |= CPUID_INTC_EDX_CX8;
11297c478bd9Sstevel@tonic-gate 		break;
11307c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Centaur:
11317c478bd9Sstevel@tonic-gate 		/*
11327c478bd9Sstevel@tonic-gate 		 * workaround the NT workarounds again
11337c478bd9Sstevel@tonic-gate 		 */
11347c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 6)
11357c478bd9Sstevel@tonic-gate 			cp->cp_edx |= CPUID_INTC_EDX_CX8;
11367c478bd9Sstevel@tonic-gate 		break;
11377c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
11387c478bd9Sstevel@tonic-gate 		/*
11397c478bd9Sstevel@tonic-gate 		 * We rely heavily on the probing in locore
11407c478bd9Sstevel@tonic-gate 		 * to actually figure out what parts, if any,
11417c478bd9Sstevel@tonic-gate 		 * of the Cyrix cpuid instruction to believe.
11427c478bd9Sstevel@tonic-gate 		 */
11437c478bd9Sstevel@tonic-gate 		switch (x86_type) {
11447c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_486:
11457c478bd9Sstevel@tonic-gate 			mask_edx = 0;
11467c478bd9Sstevel@tonic-gate 			break;
11477c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_6x86:
11487c478bd9Sstevel@tonic-gate 			mask_edx = 0;
11497c478bd9Sstevel@tonic-gate 			break;
11507c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_6x86L:
11517c478bd9Sstevel@tonic-gate 			mask_edx =
11527c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_DE |
11537c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CX8;
11547c478bd9Sstevel@tonic-gate 			break;
11557c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_6x86MX:
11567c478bd9Sstevel@tonic-gate 			mask_edx =
11577c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_DE |
11587c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MSR |
11597c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CX8 |
11607c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_PGE |
11617c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CMOV |
11627c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MMX;
11637c478bd9Sstevel@tonic-gate 			break;
11647c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_GXm:
11657c478bd9Sstevel@tonic-gate 			mask_edx =
11667c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MSR |
11677c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CX8 |
11687c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CMOV |
11697c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MMX;
11707c478bd9Sstevel@tonic-gate 			break;
11717c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_MediaGX:
11727c478bd9Sstevel@tonic-gate 			break;
11737c478bd9Sstevel@tonic-gate 		case X86_TYPE_CYRIX_MII:
11747c478bd9Sstevel@tonic-gate 		case X86_TYPE_VIA_CYRIX_III:
11757c478bd9Sstevel@tonic-gate 			mask_edx =
11767c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_DE |
11777c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_TSC |
11787c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MSR |
11797c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CX8 |
11807c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_PGE |
11817c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_CMOV |
11827c478bd9Sstevel@tonic-gate 			    CPUID_INTC_EDX_MMX;
11837c478bd9Sstevel@tonic-gate 			break;
11847c478bd9Sstevel@tonic-gate 		default:
11857c478bd9Sstevel@tonic-gate 			break;
11867c478bd9Sstevel@tonic-gate 		}
11877c478bd9Sstevel@tonic-gate 		break;
11887c478bd9Sstevel@tonic-gate 	}
11897c478bd9Sstevel@tonic-gate 
1190843e1988Sjohnlev #if defined(__xpv)
1191843e1988Sjohnlev 	/*
1192843e1988Sjohnlev 	 * Do not support MONITOR/MWAIT under a hypervisor
1193843e1988Sjohnlev 	 */
1194843e1988Sjohnlev 	mask_ecx &= ~CPUID_INTC_ECX_MON;
11957af88ac7SKuriakose Kuruvilla 	/*
11967af88ac7SKuriakose Kuruvilla 	 * Do not support XSAVE under a hypervisor for now
11977af88ac7SKuriakose Kuruvilla 	 */
11987af88ac7SKuriakose Kuruvilla 	xsave_force_disable = B_TRUE;
11997af88ac7SKuriakose Kuruvilla 
1200843e1988Sjohnlev #endif	/* __xpv */
1201843e1988Sjohnlev 
12027af88ac7SKuriakose Kuruvilla 	if (xsave_force_disable) {
12037af88ac7SKuriakose Kuruvilla 		mask_ecx &= ~CPUID_INTC_ECX_XSAVE;
12047af88ac7SKuriakose Kuruvilla 		mask_ecx &= ~CPUID_INTC_ECX_AVX;
1205ebb8ac07SRobert Mustacchi 		mask_ecx &= ~CPUID_INTC_ECX_F16C;
12067af88ac7SKuriakose Kuruvilla 	}
12077af88ac7SKuriakose Kuruvilla 
12087c478bd9Sstevel@tonic-gate 	/*
12097c478bd9Sstevel@tonic-gate 	 * Now we've figured out the masks that determine
12107c478bd9Sstevel@tonic-gate 	 * which bits we choose to believe, apply the masks
12117c478bd9Sstevel@tonic-gate 	 * to the feature words, then map the kernel's view
12127c478bd9Sstevel@tonic-gate 	 * of these feature words into its feature word.
12137c478bd9Sstevel@tonic-gate 	 */
12147c478bd9Sstevel@tonic-gate 	cp->cp_edx &= mask_edx;
12157c478bd9Sstevel@tonic-gate 	cp->cp_ecx &= mask_ecx;
12167c478bd9Sstevel@tonic-gate 
12177c478bd9Sstevel@tonic-gate 	/*
1218ae115bc7Smrj 	 * apply any platform restrictions (we don't call this
1219ae115bc7Smrj 	 * immediately after __cpuid_insn here, because we need the
1220ae115bc7Smrj 	 * workarounds applied above first)
12217c478bd9Sstevel@tonic-gate 	 */
1222ae115bc7Smrj 	platform_cpuid_mangle(cpi->cpi_vendor, 1, cp);
12237c478bd9Sstevel@tonic-gate 
1224ae115bc7Smrj 	/*
1225ae115bc7Smrj 	 * fold in overrides from the "eeprom" mechanism
1226ae115bc7Smrj 	 */
12277c478bd9Sstevel@tonic-gate 	cp->cp_edx |= cpuid_feature_edx_include;
12287c478bd9Sstevel@tonic-gate 	cp->cp_edx &= ~cpuid_feature_edx_exclude;
12297c478bd9Sstevel@tonic-gate 
12307c478bd9Sstevel@tonic-gate 	cp->cp_ecx |= cpuid_feature_ecx_include;
12317c478bd9Sstevel@tonic-gate 	cp->cp_ecx &= ~cpuid_feature_ecx_exclude;
12327c478bd9Sstevel@tonic-gate 
12337417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_PSE) {
12347417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_LARGEPAGE);
12357417cfdeSKuriakose Kuruvilla 	}
12367417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_TSC) {
12377417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_TSC);
12387417cfdeSKuriakose Kuruvilla 	}
12397417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_MSR) {
12407417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_MSR);
12417417cfdeSKuriakose Kuruvilla 	}
12427417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_MTRR) {
12437417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_MTRR);
12447417cfdeSKuriakose Kuruvilla 	}
12457417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_PGE) {
12467417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_PGE);
12477417cfdeSKuriakose Kuruvilla 	}
12487417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_CMOV) {
12497417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_CMOV);
12507417cfdeSKuriakose Kuruvilla 	}
12517417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_MMX) {
12527417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_MMX);
12537417cfdeSKuriakose Kuruvilla 	}
12547c478bd9Sstevel@tonic-gate 	if ((cp->cp_edx & CPUID_INTC_EDX_MCE) != 0 &&
12557417cfdeSKuriakose Kuruvilla 	    (cp->cp_edx & CPUID_INTC_EDX_MCA) != 0) {
12567417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_MCA);
12577417cfdeSKuriakose Kuruvilla 	}
12587417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_PAE) {
12597417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_PAE);
12607417cfdeSKuriakose Kuruvilla 	}
12617417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_CX8) {
12627417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_CX8);
12637417cfdeSKuriakose Kuruvilla 	}
12647417cfdeSKuriakose Kuruvilla 	if (cp->cp_ecx & CPUID_INTC_ECX_CX16) {
12657417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_CX16);
12667417cfdeSKuriakose Kuruvilla 	}
12677417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_PAT) {
12687417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_PAT);
12697417cfdeSKuriakose Kuruvilla 	}
12707417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_SEP) {
12717417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_SEP);
12727417cfdeSKuriakose Kuruvilla 	}
12737c478bd9Sstevel@tonic-gate 	if (cp->cp_edx & CPUID_INTC_EDX_FXSR) {
12747c478bd9Sstevel@tonic-gate 		/*
12757c478bd9Sstevel@tonic-gate 		 * In our implementation, fxsave/fxrstor
12767c478bd9Sstevel@tonic-gate 		 * are prerequisites before we'll even
12777c478bd9Sstevel@tonic-gate 		 * try and do SSE things.
12787c478bd9Sstevel@tonic-gate 		 */
12797417cfdeSKuriakose Kuruvilla 		if (cp->cp_edx & CPUID_INTC_EDX_SSE) {
12807417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_SSE);
12817417cfdeSKuriakose Kuruvilla 		}
12827417cfdeSKuriakose Kuruvilla 		if (cp->cp_edx & CPUID_INTC_EDX_SSE2) {
12837417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_SSE2);
12847417cfdeSKuriakose Kuruvilla 		}
12857417cfdeSKuriakose Kuruvilla 		if (cp->cp_ecx & CPUID_INTC_ECX_SSE3) {
12867417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_SSE3);
12877417cfdeSKuriakose Kuruvilla 		}
12887417cfdeSKuriakose Kuruvilla 		if (cp->cp_ecx & CPUID_INTC_ECX_SSSE3) {
12897417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_SSSE3);
12907417cfdeSKuriakose Kuruvilla 		}
12917417cfdeSKuriakose Kuruvilla 		if (cp->cp_ecx & CPUID_INTC_ECX_SSE4_1) {
12927417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_SSE4_1);
12937417cfdeSKuriakose Kuruvilla 		}
12947417cfdeSKuriakose Kuruvilla 		if (cp->cp_ecx & CPUID_INTC_ECX_SSE4_2) {
12957417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_SSE4_2);
12967417cfdeSKuriakose Kuruvilla 		}
12977417cfdeSKuriakose Kuruvilla 		if (cp->cp_ecx & CPUID_INTC_ECX_AES) {
12987417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_AES);
12997417cfdeSKuriakose Kuruvilla 		}
13007417cfdeSKuriakose Kuruvilla 		if (cp->cp_ecx & CPUID_INTC_ECX_PCLMULQDQ) {
13017417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_PCLMULQDQ);
1302d0f8ff6eSkk208521 		}
13037af88ac7SKuriakose Kuruvilla 
13047af88ac7SKuriakose Kuruvilla 		if (cp->cp_ecx & CPUID_INTC_ECX_XSAVE) {
13057af88ac7SKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_XSAVE);
1306ebb8ac07SRobert Mustacchi 
13077af88ac7SKuriakose Kuruvilla 			/* We only test AVX when there is XSAVE */
13087af88ac7SKuriakose Kuruvilla 			if (cp->cp_ecx & CPUID_INTC_ECX_AVX) {
13097af88ac7SKuriakose Kuruvilla 				add_x86_feature(featureset,
13107af88ac7SKuriakose Kuruvilla 				    X86FSET_AVX);
1311ebb8ac07SRobert Mustacchi 
1312ebb8ac07SRobert Mustacchi 				if (cp->cp_ecx & CPUID_INTC_ECX_F16C)
1313ebb8ac07SRobert Mustacchi 					add_x86_feature(featureset,
1314ebb8ac07SRobert Mustacchi 					    X86FSET_F16C);
13157af88ac7SKuriakose Kuruvilla 			}
13167af88ac7SKuriakose Kuruvilla 		}
13177c478bd9Sstevel@tonic-gate 	}
13187417cfdeSKuriakose Kuruvilla 	if (cp->cp_edx & CPUID_INTC_EDX_DE) {
13197417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_DE);
13207417cfdeSKuriakose Kuruvilla 	}
13211d1a3942SBill Holler #if !defined(__xpv)
1322f98fbcecSbholler 	if (cp->cp_ecx & CPUID_INTC_ECX_MON) {
13231d1a3942SBill Holler 
13241d1a3942SBill Holler 		/*
13251d1a3942SBill Holler 		 * We require the CLFLUSH instruction for erratum workaround
13261d1a3942SBill Holler 		 * to use MONITOR/MWAIT.
13271d1a3942SBill Holler 		 */
13281d1a3942SBill Holler 		if (cp->cp_edx & CPUID_INTC_EDX_CLFSH) {
1329f98fbcecSbholler 			cpi->cpi_mwait.support |= MWAIT_SUPPORT;
13307417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_MWAIT);
13311d1a3942SBill Holler 		} else {
13321d1a3942SBill Holler 			extern int idle_cpu_assert_cflush_monitor;
13331d1a3942SBill Holler 
13341d1a3942SBill Holler 			/*
13351d1a3942SBill Holler 			 * All processors we are aware of which have
13361d1a3942SBill Holler 			 * MONITOR/MWAIT also have CLFLUSH.
13371d1a3942SBill Holler 			 */
13381d1a3942SBill Holler 			if (idle_cpu_assert_cflush_monitor) {
13391d1a3942SBill Holler 				ASSERT((cp->cp_ecx & CPUID_INTC_ECX_MON) &&
13401d1a3942SBill Holler 				    (cp->cp_edx & CPUID_INTC_EDX_CLFSH));
1341f98fbcecSbholler 			}
13421d1a3942SBill Holler 		}
13431d1a3942SBill Holler 	}
13441d1a3942SBill Holler #endif	/* __xpv */
13457c478bd9Sstevel@tonic-gate 
1346faa20166SBryan Cantrill 	if (cp->cp_ecx & CPUID_INTC_ECX_VMX) {
1347faa20166SBryan Cantrill 		add_x86_feature(featureset, X86FSET_VMX);
1348faa20166SBryan Cantrill 	}
1349faa20166SBryan Cantrill 
1350ebb8ac07SRobert Mustacchi 	if (cp->cp_ecx & CPUID_INTC_ECX_RDRAND)
1351ebb8ac07SRobert Mustacchi 		add_x86_feature(featureset, X86FSET_RDRAND);
1352ebb8ac07SRobert Mustacchi 
135386c1f4dcSVikram Hegde 	/*
1354faa20166SBryan Cantrill 	 * Only need it first time, rest of the cpus would follow suit.
135586c1f4dcSVikram Hegde 	 * we only capture this for the bootcpu.
135686c1f4dcSVikram Hegde 	 */
135786c1f4dcSVikram Hegde 	if (cp->cp_edx & CPUID_INTC_EDX_CLFSH) {
13587417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_CLFSH);
135986c1f4dcSVikram Hegde 		x86_clflush_size = (BITX(cp->cp_ebx, 15, 8) * 8);
136086c1f4dcSVikram Hegde 	}
13617417cfdeSKuriakose Kuruvilla 	if (is_x86_feature(featureset, X86FSET_PAE))
13627c478bd9Sstevel@tonic-gate 		cpi->cpi_pabits = 36;
13637c478bd9Sstevel@tonic-gate 
13647c478bd9Sstevel@tonic-gate 	/*
13657c478bd9Sstevel@tonic-gate 	 * Hyperthreading configuration is slightly tricky on Intel
13667c478bd9Sstevel@tonic-gate 	 * and pure clones, and even trickier on AMD.
13677c478bd9Sstevel@tonic-gate 	 *
13687c478bd9Sstevel@tonic-gate 	 * (AMD chose to set the HTT bit on their CMP processors,
13697c478bd9Sstevel@tonic-gate 	 * even though they're not actually hyperthreaded.  Thus it
13707c478bd9Sstevel@tonic-gate 	 * takes a bit more work to figure out what's really going
1371ae115bc7Smrj 	 * on ... see the handling of the CMP_LGCY bit below)
13727c478bd9Sstevel@tonic-gate 	 */
13737c478bd9Sstevel@tonic-gate 	if (cp->cp_edx & CPUID_INTC_EDX_HTT) {
13747c478bd9Sstevel@tonic-gate 		cpi->cpi_ncpu_per_chip = CPI_CPU_COUNT(cpi);
13757c478bd9Sstevel@tonic-gate 		if (cpi->cpi_ncpu_per_chip > 1)
13767417cfdeSKuriakose Kuruvilla 			add_x86_feature(featureset, X86FSET_HTT);
13778949bcd6Sandrei 	} else {
13788949bcd6Sandrei 		cpi->cpi_ncpu_per_chip = 1;
13797c478bd9Sstevel@tonic-gate 	}
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate 	/*
13827c478bd9Sstevel@tonic-gate 	 * Work on the "extended" feature information, doing
13837c478bd9Sstevel@tonic-gate 	 * some basic initialization for cpuid_pass2()
13847c478bd9Sstevel@tonic-gate 	 */
13857c478bd9Sstevel@tonic-gate 	xcpuid = 0;
13867c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
13877c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
13885ff02082Sdmick 		if (IS_NEW_F6(cpi) || cpi->cpi_family >= 0xf)
13897c478bd9Sstevel@tonic-gate 			xcpuid++;
13907c478bd9Sstevel@tonic-gate 		break;
13917c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
13927c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family > 5 ||
13937c478bd9Sstevel@tonic-gate 		    (cpi->cpi_family == 5 && cpi->cpi_model >= 1))
13947c478bd9Sstevel@tonic-gate 			xcpuid++;
13957c478bd9Sstevel@tonic-gate 		break;
13967c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
13977c478bd9Sstevel@tonic-gate 		/*
13987c478bd9Sstevel@tonic-gate 		 * Only these Cyrix CPUs are -known- to support
13997c478bd9Sstevel@tonic-gate 		 * extended cpuid operations.
14007c478bd9Sstevel@tonic-gate 		 */
14017c478bd9Sstevel@tonic-gate 		if (x86_type == X86_TYPE_VIA_CYRIX_III ||
14027c478bd9Sstevel@tonic-gate 		    x86_type == X86_TYPE_CYRIX_GXm)
14037c478bd9Sstevel@tonic-gate 			xcpuid++;
14047c478bd9Sstevel@tonic-gate 		break;
14057c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Centaur:
14067c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
14077c478bd9Sstevel@tonic-gate 	default:
14087c478bd9Sstevel@tonic-gate 		xcpuid++;
14097c478bd9Sstevel@tonic-gate 		break;
14107c478bd9Sstevel@tonic-gate 	}
14117c478bd9Sstevel@tonic-gate 
14127c478bd9Sstevel@tonic-gate 	if (xcpuid) {
14137c478bd9Sstevel@tonic-gate 		cp = &cpi->cpi_extd[0];
14148949bcd6Sandrei 		cp->cp_eax = 0x80000000;
14158949bcd6Sandrei 		cpi->cpi_xmaxeax = __cpuid_insn(cp);
14167c478bd9Sstevel@tonic-gate 	}
14177c478bd9Sstevel@tonic-gate 
14187c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax & 0x80000000) {
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate 		if (cpi->cpi_xmaxeax > CPI_XMAXEAX_MAX)
14217c478bd9Sstevel@tonic-gate 			cpi->cpi_xmaxeax = CPI_XMAXEAX_MAX;
14227c478bd9Sstevel@tonic-gate 
14237c478bd9Sstevel@tonic-gate 		switch (cpi->cpi_vendor) {
14247c478bd9Sstevel@tonic-gate 		case X86_VENDOR_Intel:
14257c478bd9Sstevel@tonic-gate 		case X86_VENDOR_AMD:
14267c478bd9Sstevel@tonic-gate 			if (cpi->cpi_xmaxeax < 0x80000001)
14277c478bd9Sstevel@tonic-gate 				break;
14287c478bd9Sstevel@tonic-gate 			cp = &cpi->cpi_extd[1];
14298949bcd6Sandrei 			cp->cp_eax = 0x80000001;
14308949bcd6Sandrei 			(void) __cpuid_insn(cp);
1431ae115bc7Smrj 
14327c478bd9Sstevel@tonic-gate 			if (cpi->cpi_vendor == X86_VENDOR_AMD &&
14337c478bd9Sstevel@tonic-gate 			    cpi->cpi_family == 5 &&
14347c478bd9Sstevel@tonic-gate 			    cpi->cpi_model == 6 &&
14357c478bd9Sstevel@tonic-gate 			    cpi->cpi_step == 6) {
14367c478bd9Sstevel@tonic-gate 				/*
14377c478bd9Sstevel@tonic-gate 				 * K6 model 6 uses bit 10 to indicate SYSC
14387c478bd9Sstevel@tonic-gate 				 * Later models use bit 11. Fix it here.
14397c478bd9Sstevel@tonic-gate 				 */
14407c478bd9Sstevel@tonic-gate 				if (cp->cp_edx & 0x400) {
14417c478bd9Sstevel@tonic-gate 					cp->cp_edx &= ~0x400;
14427c478bd9Sstevel@tonic-gate 					cp->cp_edx |= CPUID_AMD_EDX_SYSC;
14437c478bd9Sstevel@tonic-gate 				}
14447c478bd9Sstevel@tonic-gate 			}
14457c478bd9Sstevel@tonic-gate 
1446ae115bc7Smrj 			platform_cpuid_mangle(cpi->cpi_vendor, 0x80000001, cp);
1447ae115bc7Smrj 
14487c478bd9Sstevel@tonic-gate 			/*
14497c478bd9Sstevel@tonic-gate 			 * Compute the additions to the kernel's feature word.
14507c478bd9Sstevel@tonic-gate 			 */
14517417cfdeSKuriakose Kuruvilla 			if (cp->cp_edx & CPUID_AMD_EDX_NX) {
14527417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_NX);
14537417cfdeSKuriakose Kuruvilla 			}
14547c478bd9Sstevel@tonic-gate 
145519397407SSherry Moore 			/*
145619397407SSherry Moore 			 * Regardless whether or not we boot 64-bit,
145719397407SSherry Moore 			 * we should have a way to identify whether
145819397407SSherry Moore 			 * the CPU is capable of running 64-bit.
145919397407SSherry Moore 			 */
14607417cfdeSKuriakose Kuruvilla 			if (cp->cp_edx & CPUID_AMD_EDX_LM) {
14617417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_64);
14627417cfdeSKuriakose Kuruvilla 			}
146319397407SSherry Moore 
146402bc52beSkchow #if defined(__amd64)
146502bc52beSkchow 			/* 1 GB large page - enable only for 64 bit kernel */
14667417cfdeSKuriakose Kuruvilla 			if (cp->cp_edx & CPUID_AMD_EDX_1GPG) {
14677417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_1GPG);
14687417cfdeSKuriakose Kuruvilla 			}
146902bc52beSkchow #endif
147002bc52beSkchow 
1471f8801251Skk208521 			if ((cpi->cpi_vendor == X86_VENDOR_AMD) &&
1472f8801251Skk208521 			    (cpi->cpi_std[1].cp_edx & CPUID_INTC_EDX_FXSR) &&
14737417cfdeSKuriakose Kuruvilla 			    (cp->cp_ecx & CPUID_AMD_ECX_SSE4A)) {
14747417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_SSE4A);
14757417cfdeSKuriakose Kuruvilla 			}
1476f8801251Skk208521 
14777c478bd9Sstevel@tonic-gate 			/*
1478ae115bc7Smrj 			 * If both the HTT and CMP_LGCY bits are set,
14798949bcd6Sandrei 			 * then we're not actually HyperThreaded.  Read
14808949bcd6Sandrei 			 * "AMD CPUID Specification" for more details.
14817c478bd9Sstevel@tonic-gate 			 */
14827c478bd9Sstevel@tonic-gate 			if (cpi->cpi_vendor == X86_VENDOR_AMD &&
14837417cfdeSKuriakose Kuruvilla 			    is_x86_feature(featureset, X86FSET_HTT) &&
1484ae115bc7Smrj 			    (cp->cp_ecx & CPUID_AMD_ECX_CMP_LGCY)) {
14857417cfdeSKuriakose Kuruvilla 				remove_x86_feature(featureset, X86FSET_HTT);
14867417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_CMP);
14878949bcd6Sandrei 			}
1488ae115bc7Smrj #if defined(__amd64)
14897c478bd9Sstevel@tonic-gate 			/*
14907c478bd9Sstevel@tonic-gate 			 * It's really tricky to support syscall/sysret in
14917c478bd9Sstevel@tonic-gate 			 * the i386 kernel; we rely on sysenter/sysexit
14927c478bd9Sstevel@tonic-gate 			 * instead.  In the amd64 kernel, things are -way-
14937c478bd9Sstevel@tonic-gate 			 * better.
14947c478bd9Sstevel@tonic-gate 			 */
14957417cfdeSKuriakose Kuruvilla 			if (cp->cp_edx & CPUID_AMD_EDX_SYSC) {
14967417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_ASYSC);
14977417cfdeSKuriakose Kuruvilla 			}
14987c478bd9Sstevel@tonic-gate 
14997c478bd9Sstevel@tonic-gate 			/*
15007c478bd9Sstevel@tonic-gate 			 * While we're thinking about system calls, note
15017c478bd9Sstevel@tonic-gate 			 * that AMD processors don't support sysenter
15027c478bd9Sstevel@tonic-gate 			 * in long mode at all, so don't try to program them.
15037c478bd9Sstevel@tonic-gate 			 */
15047417cfdeSKuriakose Kuruvilla 			if (x86_vendor == X86_VENDOR_AMD) {
15057417cfdeSKuriakose Kuruvilla 				remove_x86_feature(featureset, X86FSET_SEP);
15067417cfdeSKuriakose Kuruvilla 			}
15077c478bd9Sstevel@tonic-gate #endif
15087417cfdeSKuriakose Kuruvilla 			if (cp->cp_edx & CPUID_AMD_EDX_TSCP) {
15097417cfdeSKuriakose Kuruvilla 				add_x86_feature(featureset, X86FSET_TSCP);
15107417cfdeSKuriakose Kuruvilla 			}
1511faa20166SBryan Cantrill 
1512faa20166SBryan Cantrill 			if (cp->cp_ecx & CPUID_AMD_ECX_SVM) {
1513faa20166SBryan Cantrill 				add_x86_feature(featureset, X86FSET_SVM);
1514faa20166SBryan Cantrill 			}
15157660e73fSHans Rosenfeld 
15167660e73fSHans Rosenfeld 			if (cp->cp_ecx & CPUID_AMD_ECX_TOPOEXT) {
15177660e73fSHans Rosenfeld 				add_x86_feature(featureset, X86FSET_TOPOEXT);
15187660e73fSHans Rosenfeld 			}
15197c478bd9Sstevel@tonic-gate 			break;
15207c478bd9Sstevel@tonic-gate 		default:
15217c478bd9Sstevel@tonic-gate 			break;
15227c478bd9Sstevel@tonic-gate 		}
15237c478bd9Sstevel@tonic-gate 
15248949bcd6Sandrei 		/*
15258949bcd6Sandrei 		 * Get CPUID data about processor cores and hyperthreads.
15268949bcd6Sandrei 		 */
15277c478bd9Sstevel@tonic-gate 		switch (cpi->cpi_vendor) {
15287c478bd9Sstevel@tonic-gate 		case X86_VENDOR_Intel:
15298949bcd6Sandrei 			if (cpi->cpi_maxeax >= 4) {
15308949bcd6Sandrei 				cp = &cpi->cpi_std[4];
15318949bcd6Sandrei 				cp->cp_eax = 4;
15328949bcd6Sandrei 				cp->cp_ecx = 0;
15338949bcd6Sandrei 				(void) __cpuid_insn(cp);
1534ae115bc7Smrj 				platform_cpuid_mangle(cpi->cpi_vendor, 4, cp);
15358949bcd6Sandrei 			}
15368949bcd6Sandrei 			/*FALLTHROUGH*/
15377c478bd9Sstevel@tonic-gate 		case X86_VENDOR_AMD:
15387c478bd9Sstevel@tonic-gate 			if (cpi->cpi_xmaxeax < 0x80000008)
15397c478bd9Sstevel@tonic-gate 				break;
15407c478bd9Sstevel@tonic-gate 			cp = &cpi->cpi_extd[8];
15418949bcd6Sandrei 			cp->cp_eax = 0x80000008;
15428949bcd6Sandrei 			(void) __cpuid_insn(cp);
1543ae115bc7Smrj 			platform_cpuid_mangle(cpi->cpi_vendor, 0x80000008, cp);
1544ae115bc7Smrj 
15457c478bd9Sstevel@tonic-gate 			/*
15467c478bd9Sstevel@tonic-gate 			 * Virtual and physical address limits from
15477c478bd9Sstevel@tonic-gate 			 * cpuid override previously guessed values.
15487c478bd9Sstevel@tonic-gate 			 */
15497c478bd9Sstevel@tonic-gate 			cpi->cpi_pabits = BITX(cp->cp_eax, 7, 0);
15507c478bd9Sstevel@tonic-gate 			cpi->cpi_vabits = BITX(cp->cp_eax, 15, 8);
15517c478bd9Sstevel@tonic-gate 			break;
15527c478bd9Sstevel@tonic-gate 		default:
15537c478bd9Sstevel@tonic-gate 			break;
15547c478bd9Sstevel@tonic-gate 		}
15558949bcd6Sandrei 
1556d129bde2Sesaxe 		/*
1557d129bde2Sesaxe 		 * Derive the number of cores per chip
1558d129bde2Sesaxe 		 */
15598949bcd6Sandrei 		switch (cpi->cpi_vendor) {
15608949bcd6Sandrei 		case X86_VENDOR_Intel:
15618949bcd6Sandrei 			if (cpi->cpi_maxeax < 4) {
15628949bcd6Sandrei 				cpi->cpi_ncore_per_chip = 1;
15638949bcd6Sandrei 				break;
15648949bcd6Sandrei 			} else {
15658949bcd6Sandrei 				cpi->cpi_ncore_per_chip =
15668949bcd6Sandrei 				    BITX((cpi)->cpi_std[4].cp_eax, 31, 26) + 1;
15678949bcd6Sandrei 			}
15688949bcd6Sandrei 			break;
15698949bcd6Sandrei 		case X86_VENDOR_AMD:
15708949bcd6Sandrei 			if (cpi->cpi_xmaxeax < 0x80000008) {
15718949bcd6Sandrei 				cpi->cpi_ncore_per_chip = 1;
15728949bcd6Sandrei 				break;
15738949bcd6Sandrei 			} else {
157410569901Sgavinm 				/*
157510569901Sgavinm 				 * On family 0xf cpuid fn 2 ECX[7:0] "NC" is
157610569901Sgavinm 				 * 1 less than the number of physical cores on
157710569901Sgavinm 				 * the chip.  In family 0x10 this value can
157810569901Sgavinm 				 * be affected by "downcoring" - it reflects
157910569901Sgavinm 				 * 1 less than the number of cores actually
158010569901Sgavinm 				 * enabled on this node.
158110569901Sgavinm 				 */
15828949bcd6Sandrei 				cpi->cpi_ncore_per_chip =
15838949bcd6Sandrei 				    BITX((cpi)->cpi_extd[8].cp_ecx, 7, 0) + 1;
15848949bcd6Sandrei 			}
15858949bcd6Sandrei 			break;
15868949bcd6Sandrei 		default:
15878949bcd6Sandrei 			cpi->cpi_ncore_per_chip = 1;
15888949bcd6Sandrei 			break;
15897c478bd9Sstevel@tonic-gate 		}
15900e751525SEric Saxe 
15910e751525SEric Saxe 		/*
15920e751525SEric Saxe 		 * Get CPUID data about TSC Invariance in Deep C-State.
15930e751525SEric Saxe 		 */
15940e751525SEric Saxe 		switch (cpi->cpi_vendor) {
15950e751525SEric Saxe 		case X86_VENDOR_Intel:
15960e751525SEric Saxe 			if (cpi->cpi_maxeax >= 7) {
15970e751525SEric Saxe 				cp = &cpi->cpi_extd[7];
15980e751525SEric Saxe 				cp->cp_eax = 0x80000007;
15990e751525SEric Saxe 				cp->cp_ecx = 0;
16000e751525SEric Saxe 				(void) __cpuid_insn(cp);
16010e751525SEric Saxe 			}
16020e751525SEric Saxe 			break;
16030e751525SEric Saxe 		default:
16040e751525SEric Saxe 			break;
16050e751525SEric Saxe 		}
1606fa2e767eSgavinm 	} else {
1607fa2e767eSgavinm 		cpi->cpi_ncore_per_chip = 1;
16088949bcd6Sandrei 	}
16098949bcd6Sandrei 
16108949bcd6Sandrei 	/*
16118949bcd6Sandrei 	 * If more than one core, then this processor is CMP.
16128949bcd6Sandrei 	 */
16137417cfdeSKuriakose Kuruvilla 	if (cpi->cpi_ncore_per_chip > 1) {
16147417cfdeSKuriakose Kuruvilla 		add_x86_feature(featureset, X86FSET_CMP);
16157417cfdeSKuriakose Kuruvilla 	}
1616ae115bc7Smrj 
16178949bcd6Sandrei 	/*
16188949bcd6Sandrei 	 * If the number of cores is the same as the number
16198949bcd6Sandrei 	 * of CPUs, then we cannot have HyperThreading.
16208949bcd6Sandrei 	 */
16217417cfdeSKuriakose Kuruvilla 	if (cpi->cpi_ncpu_per_chip == cpi->cpi_ncore_per_chip) {
16227417cfdeSKuriakose Kuruvilla 		remove_x86_feature(featureset, X86FSET_HTT);
16237417cfdeSKuriakose Kuruvilla 	}
16248949bcd6Sandrei 
16258031591dSSrihari Venkatesan 	cpi->cpi_apicid = CPI_APIC_ID(cpi);
16268031591dSSrihari Venkatesan 	cpi->cpi_procnodes_per_pkg = 1;
16277660e73fSHans Rosenfeld 	cpi->cpi_cores_per_compunit = 1;
16287417cfdeSKuriakose Kuruvilla 	if (is_x86_feature(featureset, X86FSET_HTT) == B_FALSE &&
16297417cfdeSKuriakose Kuruvilla 	    is_x86_feature(featureset, X86FSET_CMP) == B_FALSE) {
16308949bcd6Sandrei 		/*
16318949bcd6Sandrei 		 * Single-core single-threaded processors.
16328949bcd6Sandrei 		 */
16337c478bd9Sstevel@tonic-gate 		cpi->cpi_chipid = -1;
16347c478bd9Sstevel@tonic-gate 		cpi->cpi_clogid = 0;
16358949bcd6Sandrei 		cpi->cpi_coreid = cpu->cpu_id;
163610569901Sgavinm 		cpi->cpi_pkgcoreid = 0;
16378031591dSSrihari Venkatesan 		if (cpi->cpi_vendor == X86_VENDOR_AMD)
16388031591dSSrihari Venkatesan 			cpi->cpi_procnodeid = BITX(cpi->cpi_apicid, 3, 0);
16398031591dSSrihari Venkatesan 		else
16408031591dSSrihari Venkatesan 			cpi->cpi_procnodeid = cpi->cpi_chipid;
16417c478bd9Sstevel@tonic-gate 	} else if (cpi->cpi_ncpu_per_chip > 1) {
16428031591dSSrihari Venkatesan 		if (cpi->cpi_vendor == X86_VENDOR_Intel)
16437417cfdeSKuriakose Kuruvilla 			cpuid_intel_getids(cpu, featureset);
16448031591dSSrihari Venkatesan 		else if (cpi->cpi_vendor == X86_VENDOR_AMD)
16458031591dSSrihari Venkatesan 			cpuid_amd_getids(cpu);
16468031591dSSrihari Venkatesan 		else {
16478949bcd6Sandrei 			/*
16488949bcd6Sandrei 			 * All other processors are currently
16498949bcd6Sandrei 			 * assumed to have single cores.
16508949bcd6Sandrei 			 */
16518949bcd6Sandrei 			cpi->cpi_coreid = cpi->cpi_chipid;
165210569901Sgavinm 			cpi->cpi_pkgcoreid = 0;
16538031591dSSrihari Venkatesan 			cpi->cpi_procnodeid = cpi->cpi_chipid;
16547660e73fSHans Rosenfeld 			cpi->cpi_compunitid = cpi->cpi_chipid;
16558949bcd6Sandrei 		}
16567c478bd9Sstevel@tonic-gate 	}
16577c478bd9Sstevel@tonic-gate 
16588a40a695Sgavinm 	/*
16598a40a695Sgavinm 	 * Synthesize chip "revision" and socket type
16608a40a695Sgavinm 	 */
1661e4b86885SCheng Sean Ye 	cpi->cpi_chiprev = _cpuid_chiprev(cpi->cpi_vendor, cpi->cpi_family,
1662e4b86885SCheng Sean Ye 	    cpi->cpi_model, cpi->cpi_step);
1663e4b86885SCheng Sean Ye 	cpi->cpi_chiprevstr = _cpuid_chiprevstr(cpi->cpi_vendor,
1664e4b86885SCheng Sean Ye 	    cpi->cpi_family, cpi->cpi_model, cpi->cpi_step);
1665e4b86885SCheng Sean Ye 	cpi->cpi_socket = _cpuid_skt(cpi->cpi_vendor, cpi->cpi_family,
1666e4b86885SCheng Sean Ye 	    cpi->cpi_model, cpi->cpi_step);
16678a40a695Sgavinm 
16687c478bd9Sstevel@tonic-gate pass1_done:
16697c478bd9Sstevel@tonic-gate 	cpi->cpi_pass = 1;
16707c478bd9Sstevel@tonic-gate }
16717c478bd9Sstevel@tonic-gate 
16727c478bd9Sstevel@tonic-gate /*
16737c478bd9Sstevel@tonic-gate  * Make copies of the cpuid table entries we depend on, in
16747c478bd9Sstevel@tonic-gate  * part for ease of parsing now, in part so that we have only
16757c478bd9Sstevel@tonic-gate  * one place to correct any of it, in part for ease of
16767c478bd9Sstevel@tonic-gate  * later export to userland, and in part so we can look at
16777c478bd9Sstevel@tonic-gate  * this stuff in a crash dump.
16787c478bd9Sstevel@tonic-gate  */
16797c478bd9Sstevel@tonic-gate 
16807c478bd9Sstevel@tonic-gate /*ARGSUSED*/
16817c478bd9Sstevel@tonic-gate void
16827c478bd9Sstevel@tonic-gate cpuid_pass2(cpu_t *cpu)
16837c478bd9Sstevel@tonic-gate {
16847c478bd9Sstevel@tonic-gate 	uint_t n, nmax;
16857c478bd9Sstevel@tonic-gate 	int i;
16868949bcd6Sandrei 	struct cpuid_regs *cp;
16877c478bd9Sstevel@tonic-gate 	uint8_t *dp;
16887c478bd9Sstevel@tonic-gate 	uint32_t *iptr;
16897c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
16907c478bd9Sstevel@tonic-gate 
16917c478bd9Sstevel@tonic-gate 	ASSERT(cpi->cpi_pass == 1);
16927c478bd9Sstevel@tonic-gate 
16937c478bd9Sstevel@tonic-gate 	if (cpi->cpi_maxeax < 1)
16947c478bd9Sstevel@tonic-gate 		goto pass2_done;
16957c478bd9Sstevel@tonic-gate 
16967c478bd9Sstevel@tonic-gate 	if ((nmax = cpi->cpi_maxeax + 1) > NMAX_CPI_STD)
16977c478bd9Sstevel@tonic-gate 		nmax = NMAX_CPI_STD;
16987c478bd9Sstevel@tonic-gate 	/*
16997c478bd9Sstevel@tonic-gate 	 * (We already handled n == 0 and n == 1 in pass 1)
17007c478bd9Sstevel@tonic-gate 	 */
17017c478bd9Sstevel@tonic-gate 	for (n = 2, cp = &cpi->cpi_std[2]; n < nmax; n++, cp++) {
17028949bcd6Sandrei 		cp->cp_eax = n;
1703d129bde2Sesaxe 
1704d129bde2Sesaxe 		/*
1705d129bde2Sesaxe 		 * CPUID function 4 expects %ecx to be initialized
1706d129bde2Sesaxe 		 * with an index which indicates which cache to return
1707d129bde2Sesaxe 		 * information about. The OS is expected to call function 4
1708d129bde2Sesaxe 		 * with %ecx set to 0, 1, 2, ... until it returns with
1709d129bde2Sesaxe 		 * EAX[4:0] set to 0, which indicates there are no more
1710d129bde2Sesaxe 		 * caches.
1711d129bde2Sesaxe 		 *
1712d129bde2Sesaxe 		 * Here, populate cpi_std[4] with the information returned by
1713d129bde2Sesaxe 		 * function 4 when %ecx == 0, and do the rest in cpuid_pass3()
1714d129bde2Sesaxe 		 * when dynamic memory allocation becomes available.
1715d129bde2Sesaxe 		 *
1716d129bde2Sesaxe 		 * Note: we need to explicitly initialize %ecx here, since
1717d129bde2Sesaxe 		 * function 4 may have been previously invoked.
1718d129bde2Sesaxe 		 */
1719d129bde2Sesaxe 		if (n == 4)
1720d129bde2Sesaxe 			cp->cp_ecx = 0;
1721d129bde2Sesaxe 
17228949bcd6Sandrei 		(void) __cpuid_insn(cp);
1723ae115bc7Smrj 		platform_cpuid_mangle(cpi->cpi_vendor, n, cp);
17247c478bd9Sstevel@tonic-gate 		switch (n) {
17257c478bd9Sstevel@tonic-gate 		case 2:
17267c478bd9Sstevel@tonic-gate 			/*
17277c478bd9Sstevel@tonic-gate 			 * "the lower 8 bits of the %eax register
17287c478bd9Sstevel@tonic-gate 			 * contain a value that identifies the number
17297c478bd9Sstevel@tonic-gate 			 * of times the cpuid [instruction] has to be
17307c478bd9Sstevel@tonic-gate 			 * executed to obtain a complete image of the
17317c478bd9Sstevel@tonic-gate 			 * processor's caching systems."
17327c478bd9Sstevel@tonic-gate 			 *
17337c478bd9Sstevel@tonic-gate 			 * How *do* they make this stuff up?
17347c478bd9Sstevel@tonic-gate 			 */
17357c478bd9Sstevel@tonic-gate 			cpi->cpi_ncache = sizeof (*cp) *
17367c478bd9Sstevel@tonic-gate 			    BITX(cp->cp_eax, 7, 0);
17377c478bd9Sstevel@tonic-gate 			if (cpi->cpi_ncache == 0)
17387c478bd9Sstevel@tonic-gate 				break;
17397c478bd9Sstevel@tonic-gate 			cpi->cpi_ncache--;	/* skip count byte */
17407c478bd9Sstevel@tonic-gate 
17417c478bd9Sstevel@tonic-gate 			/*
17427c478bd9Sstevel@tonic-gate 			 * Well, for now, rather than attempt to implement
17437c478bd9Sstevel@tonic-gate 			 * this slightly dubious algorithm, we just look
17447c478bd9Sstevel@tonic-gate 			 * at the first 15 ..
17457c478bd9Sstevel@tonic-gate 			 */
17467c478bd9Sstevel@tonic-gate 			if (cpi->cpi_ncache > (sizeof (*cp) - 1))
17477c478bd9Sstevel@tonic-gate 				cpi->cpi_ncache = sizeof (*cp) - 1;
17487c478bd9Sstevel@tonic-gate 
17497c478bd9Sstevel@tonic-gate 			dp = cpi->cpi_cacheinfo;
17507c478bd9Sstevel@tonic-gate 			if (BITX(cp->cp_eax, 31, 31) == 0) {
17517c478bd9Sstevel@tonic-gate 				uint8_t *p = (void *)&cp->cp_eax;
175263d3f7dfSkk208521 				for (i = 1; i < 4; i++)
17537c478bd9Sstevel@tonic-gate 					if (p[i] != 0)
17547c478bd9Sstevel@tonic-gate 						*dp++ = p[i];
17557c478bd9Sstevel@tonic-gate 			}
17567c478bd9Sstevel@tonic-gate 			if (BITX(cp->cp_ebx, 31, 31) == 0) {
17577c478bd9Sstevel@tonic-gate 				uint8_t *p = (void *)&cp->cp_ebx;
17587c478bd9Sstevel@tonic-gate 				for (i = 0; i < 4; i++)
17597c478bd9Sstevel@tonic-gate 					if (p[i] != 0)
17607c478bd9Sstevel@tonic-gate 						*dp++ = p[i];
17617c478bd9Sstevel@tonic-gate 			}
17627c478bd9Sstevel@tonic-gate 			if (BITX(cp->cp_ecx, 31, 31) == 0) {
17637c478bd9Sstevel@tonic-gate 				uint8_t *p = (void *)&cp->cp_ecx;
17647c478bd9Sstevel@tonic-gate 				for (i = 0; i < 4; i++)
17657c478bd9Sstevel@tonic-gate 					if (p[i] != 0)
17667c478bd9Sstevel@tonic-gate 						*dp++ = p[i];
17677c478bd9Sstevel@tonic-gate 			}
17687c478bd9Sstevel@tonic-gate 			if (BITX(cp->cp_edx, 31, 31) == 0) {
17697c478bd9Sstevel@tonic-gate 				uint8_t *p = (void *)&cp->cp_edx;
17707c478bd9Sstevel@tonic-gate 				for (i = 0; i < 4; i++)
17717c478bd9Sstevel@tonic-gate 					if (p[i] != 0)
17727c478bd9Sstevel@tonic-gate 						*dp++ = p[i];
17737c478bd9Sstevel@tonic-gate 			}
17747c478bd9Sstevel@tonic-gate 			break;
1775f98fbcecSbholler 
17767c478bd9Sstevel@tonic-gate 		case 3:	/* Processor serial number, if PSN supported */
1777f98fbcecSbholler 			break;
1778f98fbcecSbholler 
17797c478bd9Sstevel@tonic-gate 		case 4:	/* Deterministic cache parameters */
1780f98fbcecSbholler 			break;
1781f98fbcecSbholler 
17827c478bd9Sstevel@tonic-gate 		case 5:	/* Monitor/Mwait parameters */
17835b8a6efeSbholler 		{
17845b8a6efeSbholler 			size_t mwait_size;
1785f98fbcecSbholler 
1786f98fbcecSbholler 			/*
1787f98fbcecSbholler 			 * check cpi_mwait.support which was set in cpuid_pass1
1788f98fbcecSbholler 			 */
1789f98fbcecSbholler 			if (!(cpi->cpi_mwait.support & MWAIT_SUPPORT))
1790f98fbcecSbholler 				break;
1791f98fbcecSbholler 
17925b8a6efeSbholler 			/*
17935b8a6efeSbholler 			 * Protect ourself from insane mwait line size.
17945b8a6efeSbholler 			 * Workaround for incomplete hardware emulator(s).
17955b8a6efeSbholler 			 */
17965b8a6efeSbholler 			mwait_size = (size_t)MWAIT_SIZE_MAX(cpi);
17975b8a6efeSbholler 			if (mwait_size < sizeof (uint32_t) ||
17985b8a6efeSbholler 			    !ISP2(mwait_size)) {
17995b8a6efeSbholler #if DEBUG
18005b8a6efeSbholler 				cmn_err(CE_NOTE, "Cannot handle cpu %d mwait "
18015d8efbbcSSaurabh Misra 				    "size %ld", cpu->cpu_id, (long)mwait_size);
18025b8a6efeSbholler #endif
18035b8a6efeSbholler 				break;
18045b8a6efeSbholler 			}
18055b8a6efeSbholler 
1806f98fbcecSbholler 			cpi->cpi_mwait.mon_min = (size_t)MWAIT_SIZE_MIN(cpi);
18075b8a6efeSbholler 			cpi->cpi_mwait.mon_max = mwait_size;
1808f98fbcecSbholler 			if (MWAIT_EXTENSION(cpi)) {
1809f98fbcecSbholler 				cpi->cpi_mwait.support |= MWAIT_EXTENSIONS;
1810f98fbcecSbholler 				if (MWAIT_INT_ENABLE(cpi))
1811f98fbcecSbholler 					cpi->cpi_mwait.support |=
1812f98fbcecSbholler 					    MWAIT_ECX_INT_ENABLE;
1813f98fbcecSbholler 			}
1814f98fbcecSbholler 			break;
18155b8a6efeSbholler 		}
18167c478bd9Sstevel@tonic-gate 		default:
18177c478bd9Sstevel@tonic-gate 			break;
18187c478bd9Sstevel@tonic-gate 		}
18197c478bd9Sstevel@tonic-gate 	}
18207c478bd9Sstevel@tonic-gate 
1821b6917abeSmishra 	if (cpi->cpi_maxeax >= 0xB && cpi->cpi_vendor == X86_VENDOR_Intel) {
18225d8efbbcSSaurabh Misra 		struct cpuid_regs regs;
18235d8efbbcSSaurabh Misra 
18245d8efbbcSSaurabh Misra 		cp = &regs;
1825b6917abeSmishra 		cp->cp_eax = 0xB;
18265d8efbbcSSaurabh Misra 		cp->cp_edx = cp->cp_ebx = cp->cp_ecx = 0;
1827b6917abeSmishra 
1828b6917abeSmishra 		(void) __cpuid_insn(cp);
1829b6917abeSmishra 
1830b6917abeSmishra 		/*
1831b6917abeSmishra 		 * Check CPUID.EAX=0BH, ECX=0H:EBX is non-zero, which
1832b6917abeSmishra 		 * indicates that the extended topology enumeration leaf is
1833b6917abeSmishra 		 * available.
1834b6917abeSmishra 		 */
1835b6917abeSmishra 		if (cp->cp_ebx) {
1836b6917abeSmishra 			uint32_t x2apic_id;
1837b6917abeSmishra 			uint_t coreid_shift = 0;
1838b6917abeSmishra 			uint_t ncpu_per_core = 1;
1839b6917abeSmishra 			uint_t chipid_shift = 0;
1840b6917abeSmishra 			uint_t ncpu_per_chip = 1;
1841b6917abeSmishra 			uint_t i;
1842b6917abeSmishra 			uint_t level;
1843b6917abeSmishra 
1844b6917abeSmishra 			for (i = 0; i < CPI_FNB_ECX_MAX; i++) {
1845b6917abeSmishra 				cp->cp_eax = 0xB;
1846b6917abeSmishra 				cp->cp_ecx = i;
1847b6917abeSmishra 
1848b6917abeSmishra 				(void) __cpuid_insn(cp);
1849b6917abeSmishra 				level = CPI_CPU_LEVEL_TYPE(cp);
1850b6917abeSmishra 
1851b6917abeSmishra 				if (level == 1) {
1852b6917abeSmishra 					x2apic_id = cp->cp_edx;
1853b6917abeSmishra 					coreid_shift = BITX(cp->cp_eax, 4, 0);
1854b6917abeSmishra 					ncpu_per_core = BITX(cp->cp_ebx, 15, 0);
1855b6917abeSmishra 				} else if (level == 2) {
1856b6917abeSmishra 					x2apic_id = cp->cp_edx;
1857b6917abeSmishra 					chipid_shift = BITX(cp->cp_eax, 4, 0);
1858b6917abeSmishra 					ncpu_per_chip = BITX(cp->cp_ebx, 15, 0);
1859b6917abeSmishra 				}
1860b6917abeSmishra 			}
1861b6917abeSmishra 
1862b6917abeSmishra 			cpi->cpi_apicid = x2apic_id;
1863b6917abeSmishra 			cpi->cpi_ncpu_per_chip = ncpu_per_chip;
1864b6917abeSmishra 			cpi->cpi_ncore_per_chip = ncpu_per_chip /
1865b6917abeSmishra 			    ncpu_per_core;
1866b6917abeSmishra 			cpi->cpi_chipid = x2apic_id >> chipid_shift;
1867b6917abeSmishra 			cpi->cpi_clogid = x2apic_id & ((1 << chipid_shift) - 1);
1868b6917abeSmishra 			cpi->cpi_coreid = x2apic_id >> coreid_shift;
1869b6917abeSmishra 			cpi->cpi_pkgcoreid = cpi->cpi_clogid >> coreid_shift;
1870b6917abeSmishra 		}
18715d8efbbcSSaurabh Misra 
18725d8efbbcSSaurabh Misra 		/* Make cp NULL so that we don't stumble on others */
18735d8efbbcSSaurabh Misra 		cp = NULL;
1874b6917abeSmishra 	}
1875b6917abeSmishra 
18767af88ac7SKuriakose Kuruvilla 	/*
18777af88ac7SKuriakose Kuruvilla 	 * XSAVE enumeration
18787af88ac7SKuriakose Kuruvilla 	 */
187963408480SHans Rosenfeld 	if (cpi->cpi_maxeax >= 0xD) {
18807af88ac7SKuriakose Kuruvilla 		struct cpuid_regs regs;
18817af88ac7SKuriakose Kuruvilla 		boolean_t cpuid_d_valid = B_TRUE;
18827af88ac7SKuriakose Kuruvilla 
18837af88ac7SKuriakose Kuruvilla 		cp = &regs;
18847af88ac7SKuriakose Kuruvilla 		cp->cp_eax = 0xD;
18857af88ac7SKuriakose Kuruvilla 		cp->cp_edx = cp->cp_ebx = cp->cp_ecx = 0;
18867af88ac7SKuriakose Kuruvilla 
18877af88ac7SKuriakose Kuruvilla 		(void) __cpuid_insn(cp);
18887af88ac7SKuriakose Kuruvilla 
18897af88ac7SKuriakose Kuruvilla 		/*
18907af88ac7SKuriakose Kuruvilla 		 * Sanity checks for debug
18917af88ac7SKuriakose Kuruvilla 		 */
18927af88ac7SKuriakose Kuruvilla 		if ((cp->cp_eax & XFEATURE_LEGACY_FP) == 0 ||
18937af88ac7SKuriakose Kuruvilla 		    (cp->cp_eax & XFEATURE_SSE) == 0) {
18947af88ac7SKuriakose Kuruvilla 			cpuid_d_valid = B_FALSE;
18957af88ac7SKuriakose Kuruvilla 		}
18967af88ac7SKuriakose Kuruvilla 
18977af88ac7SKuriakose Kuruvilla 		cpi->cpi_xsave.xsav_hw_features_low = cp->cp_eax;
18987af88ac7SKuriakose Kuruvilla 		cpi->cpi_xsave.xsav_hw_features_high = cp->cp_edx;
18997af88ac7SKuriakose Kuruvilla 		cpi->cpi_xsave.xsav_max_size = cp->cp_ecx;
19007af88ac7SKuriakose Kuruvilla 
19017af88ac7SKuriakose Kuruvilla 		/*
19027af88ac7SKuriakose Kuruvilla 		 * If the hw supports AVX, get the size and offset in the save
19037af88ac7SKuriakose Kuruvilla 		 * area for the ymm state.
19047af88ac7SKuriakose Kuruvilla 		 */
19057af88ac7SKuriakose Kuruvilla 		if (cpi->cpi_xsave.xsav_hw_features_low & XFEATURE_AVX) {
19067af88ac7SKuriakose Kuruvilla 			cp->cp_eax = 0xD;
19077af88ac7SKuriakose Kuruvilla 			cp->cp_ecx = 2;
19087af88ac7SKuriakose Kuruvilla 			cp->cp_edx = cp->cp_ebx = 0;
19097af88ac7SKuriakose Kuruvilla 
19107af88ac7SKuriakose Kuruvilla 			(void) __cpuid_insn(cp);
19117af88ac7SKuriakose Kuruvilla 
19127af88ac7SKuriakose Kuruvilla 			if (cp->cp_ebx != CPUID_LEAFD_2_YMM_OFFSET ||
19137af88ac7SKuriakose Kuruvilla 			    cp->cp_eax != CPUID_LEAFD_2_YMM_SIZE) {
19147af88ac7SKuriakose Kuruvilla 				cpuid_d_valid = B_FALSE;
19157af88ac7SKuriakose Kuruvilla 			}
19167af88ac7SKuriakose Kuruvilla 
19177af88ac7SKuriakose Kuruvilla 			cpi->cpi_xsave.ymm_size = cp->cp_eax;
19187af88ac7SKuriakose Kuruvilla 			cpi->cpi_xsave.ymm_offset = cp->cp_ebx;
19197af88ac7SKuriakose Kuruvilla 		}
19207af88ac7SKuriakose Kuruvilla 
19217af88ac7SKuriakose Kuruvilla 		if (is_x86_feature(x86_featureset, X86FSET_XSAVE)) {
19227af88ac7SKuriakose Kuruvilla 			xsave_state_size = 0;
19237af88ac7SKuriakose Kuruvilla 		} else if (cpuid_d_valid) {
19247af88ac7SKuriakose Kuruvilla 			xsave_state_size = cpi->cpi_xsave.xsav_max_size;
19257af88ac7SKuriakose Kuruvilla 		} else {
19267af88ac7SKuriakose Kuruvilla 			/* Broken CPUID 0xD, probably in HVM */
19277af88ac7SKuriakose Kuruvilla 			cmn_err(CE_WARN, "cpu%d: CPUID.0xD returns invalid "
19287af88ac7SKuriakose Kuruvilla 			    "value: hw_low = %d, hw_high = %d, xsave_size = %d"
19297af88ac7SKuriakose Kuruvilla 			    ", ymm_size = %d, ymm_offset = %d\n",
19307af88ac7SKuriakose Kuruvilla 			    cpu->cpu_id, cpi->cpi_xsave.xsav_hw_features_low,
19317af88ac7SKuriakose Kuruvilla 			    cpi->cpi_xsave.xsav_hw_features_high,
19327af88ac7SKuriakose Kuruvilla 			    (int)cpi->cpi_xsave.xsav_max_size,
19337af88ac7SKuriakose Kuruvilla 			    (int)cpi->cpi_xsave.ymm_size,
19347af88ac7SKuriakose Kuruvilla 			    (int)cpi->cpi_xsave.ymm_offset);
19357af88ac7SKuriakose Kuruvilla 
19367af88ac7SKuriakose Kuruvilla 			if (xsave_state_size != 0) {
19377af88ac7SKuriakose Kuruvilla 				/*
19387af88ac7SKuriakose Kuruvilla 				 * This must be a non-boot CPU. We cannot
19397af88ac7SKuriakose Kuruvilla 				 * continue, because boot cpu has already
19407af88ac7SKuriakose Kuruvilla 				 * enabled XSAVE.
19417af88ac7SKuriakose Kuruvilla 				 */
19427af88ac7SKuriakose Kuruvilla 				ASSERT(cpu->cpu_id != 0);
19437af88ac7SKuriakose Kuruvilla 				cmn_err(CE_PANIC, "cpu%d: we have already "
19447af88ac7SKuriakose Kuruvilla 				    "enabled XSAVE on boot cpu, cannot "
19457af88ac7SKuriakose Kuruvilla 				    "continue.", cpu->cpu_id);
19467af88ac7SKuriakose Kuruvilla 			} else {
19477af88ac7SKuriakose Kuruvilla 				/*
19487af88ac7SKuriakose Kuruvilla 				 * Must be from boot CPU, OK to disable XSAVE.
19497af88ac7SKuriakose Kuruvilla 				 */
19507af88ac7SKuriakose Kuruvilla 				ASSERT(cpu->cpu_id == 0);
19517af88ac7SKuriakose Kuruvilla 				remove_x86_feature(x86_featureset,
19527af88ac7SKuriakose Kuruvilla 				    X86FSET_XSAVE);
19537af88ac7SKuriakose Kuruvilla 				remove_x86_feature(x86_featureset, X86FSET_AVX);
19547af88ac7SKuriakose Kuruvilla 				CPI_FEATURES_ECX(cpi) &= ~CPUID_INTC_ECX_XSAVE;
19557af88ac7SKuriakose Kuruvilla 				CPI_FEATURES_ECX(cpi) &= ~CPUID_INTC_ECX_AVX;
1956ebb8ac07SRobert Mustacchi 				CPI_FEATURES_ECX(cpi) &= ~CPUID_INTC_ECX_F16C;
19577af88ac7SKuriakose Kuruvilla 				xsave_force_disable = B_TRUE;
19587af88ac7SKuriakose Kuruvilla 			}
19597af88ac7SKuriakose Kuruvilla 		}
19607af88ac7SKuriakose Kuruvilla 	}
19617af88ac7SKuriakose Kuruvilla 
19627af88ac7SKuriakose Kuruvilla 
19637c478bd9Sstevel@tonic-gate 	if ((cpi->cpi_xmaxeax & 0x80000000) == 0)
19647c478bd9Sstevel@tonic-gate 		goto pass2_done;
19657c478bd9Sstevel@tonic-gate 
19667c478bd9Sstevel@tonic-gate 	if ((nmax = cpi->cpi_xmaxeax - 0x80000000 + 1) > NMAX_CPI_EXTD)
19677c478bd9Sstevel@tonic-gate 		nmax = NMAX_CPI_EXTD;
19687c478bd9Sstevel@tonic-gate 	/*
19697c478bd9Sstevel@tonic-gate 	 * Copy the extended properties, fixing them as we go.
19707c478bd9Sstevel@tonic-gate 	 * (We already handled n == 0 and n == 1 in pass 1)
19717c478bd9Sstevel@tonic-gate 	 */
19727c478bd9Sstevel@tonic-gate 	iptr = (void *)cpi->cpi_brandstr;
19737c478bd9Sstevel@tonic-gate 	for (n = 2, cp = &cpi->cpi_extd[2]; n < nmax; cp++, n++) {
19748949bcd6Sandrei 		cp->cp_eax = 0x80000000 + n;
19758949bcd6Sandrei 		(void) __cpuid_insn(cp);
1976ae115bc7Smrj 		platform_cpuid_mangle(cpi->cpi_vendor, 0x80000000 + n, cp);
19777c478bd9Sstevel@tonic-gate 		switch (n) {
19787c478bd9Sstevel@tonic-gate 		case 2:
19797c478bd9Sstevel@tonic-gate 		case 3:
19807c478bd9Sstevel@tonic-gate 		case 4:
19817c478bd9Sstevel@tonic-gate 			/*
19827c478bd9Sstevel@tonic-gate 			 * Extract the brand string
19837c478bd9Sstevel@tonic-gate 			 */
19847c478bd9Sstevel@tonic-gate 			*iptr++ = cp->cp_eax;
19857c478bd9Sstevel@tonic-gate 			*iptr++ = cp->cp_ebx;
19867c478bd9Sstevel@tonic-gate 			*iptr++ = cp->cp_ecx;
19877c478bd9Sstevel@tonic-gate 			*iptr++ = cp->cp_edx;
19887c478bd9Sstevel@tonic-gate 			break;
19897c478bd9Sstevel@tonic-gate 		case 5:
19907c478bd9Sstevel@tonic-gate 			switch (cpi->cpi_vendor) {
19917c478bd9Sstevel@tonic-gate 			case X86_VENDOR_AMD:
19927c478bd9Sstevel@tonic-gate 				/*
19937c478bd9Sstevel@tonic-gate 				 * The Athlon and Duron were the first
19947c478bd9Sstevel@tonic-gate 				 * parts to report the sizes of the
19957c478bd9Sstevel@tonic-gate 				 * TLB for large pages. Before then,
19967c478bd9Sstevel@tonic-gate 				 * we don't trust the data.
19977c478bd9Sstevel@tonic-gate 				 */
19987c478bd9Sstevel@tonic-gate 				if (cpi->cpi_family < 6 ||
19997c478bd9Sstevel@tonic-gate 				    (cpi->cpi_family == 6 &&
20007c478bd9Sstevel@tonic-gate 				    cpi->cpi_model < 1))
20017c478bd9Sstevel@tonic-gate 					cp->cp_eax = 0;
20027c478bd9Sstevel@tonic-gate 				break;
20037c478bd9Sstevel@tonic-gate 			default:
20047c478bd9Sstevel@tonic-gate 				break;
20057c478bd9Sstevel@tonic-gate 			}
20067c478bd9Sstevel@tonic-gate 			break;
20077c478bd9Sstevel@tonic-gate 		case 6:
20087c478bd9Sstevel@tonic-gate 			switch (cpi->cpi_vendor) {
20097c478bd9Sstevel@tonic-gate 			case X86_VENDOR_AMD:
20107c478bd9Sstevel@tonic-gate 				/*
20117c478bd9Sstevel@tonic-gate 				 * The Athlon and Duron were the first
20127c478bd9Sstevel@tonic-gate 				 * AMD parts with L2 TLB's.
20137c478bd9Sstevel@tonic-gate 				 * Before then, don't trust the data.
20147c478bd9Sstevel@tonic-gate 				 */
20157c478bd9Sstevel@tonic-gate 				if (cpi->cpi_family < 6 ||
20167c478bd9Sstevel@tonic-gate 				    cpi->cpi_family == 6 &&
20177c478bd9Sstevel@tonic-gate 				    cpi->cpi_model < 1)
20187c478bd9Sstevel@tonic-gate 					cp->cp_eax = cp->cp_ebx = 0;
20197c478bd9Sstevel@tonic-gate 				/*
20207c478bd9Sstevel@tonic-gate 				 * AMD Duron rev A0 reports L2
20217c478bd9Sstevel@tonic-gate 				 * cache size incorrectly as 1K
20227c478bd9Sstevel@tonic-gate 				 * when it is really 64K
20237c478bd9Sstevel@tonic-gate 				 */
20247c478bd9Sstevel@tonic-gate 				if (cpi->cpi_family == 6 &&
20257c478bd9Sstevel@tonic-gate 				    cpi->cpi_model == 3 &&
20267c478bd9Sstevel@tonic-gate 				    cpi->cpi_step == 0) {
20277c478bd9Sstevel@tonic-gate 					cp->cp_ecx &= 0xffff;
20287c478bd9Sstevel@tonic-gate 					cp->cp_ecx |= 0x400000;
20297c478bd9Sstevel@tonic-gate 				}
20307c478bd9Sstevel@tonic-gate 				break;
20317c478bd9Sstevel@tonic-gate 			case X86_VENDOR_Cyrix:	/* VIA C3 */
20327c478bd9Sstevel@tonic-gate 				/*
20337c478bd9Sstevel@tonic-gate 				 * VIA C3 processors are a bit messed
20347c478bd9Sstevel@tonic-gate 				 * up w.r.t. encoding cache sizes in %ecx
20357c478bd9Sstevel@tonic-gate 				 */
20367c478bd9Sstevel@tonic-gate 				if (cpi->cpi_family != 6)
20377c478bd9Sstevel@tonic-gate 					break;
20387c478bd9Sstevel@tonic-gate 				/*
20397c478bd9Sstevel@tonic-gate 				 * model 7 and 8 were incorrectly encoded
20407c478bd9Sstevel@tonic-gate 				 *
20417c478bd9Sstevel@tonic-gate 				 * xxx is model 8 really broken?
20427c478bd9Sstevel@tonic-gate 				 */
20437c478bd9Sstevel@tonic-gate 				if (cpi->cpi_model == 7 ||
20447c478bd9Sstevel@tonic-gate 				    cpi->cpi_model == 8)
20457c478bd9Sstevel@tonic-gate 					cp->cp_ecx =
20467c478bd9Sstevel@tonic-gate 					    BITX(cp->cp_ecx, 31, 24) << 16 |
20477c478bd9Sstevel@tonic-gate 					    BITX(cp->cp_ecx, 23, 16) << 12 |
20487c478bd9Sstevel@tonic-gate 					    BITX(cp->cp_ecx, 15, 8) << 8 |
20497c478bd9Sstevel@tonic-gate 					    BITX(cp->cp_ecx, 7, 0);
20507c478bd9Sstevel@tonic-gate 				/*
20517c478bd9Sstevel@tonic-gate 				 * model 9 stepping 1 has wrong associativity
20527c478bd9Sstevel@tonic-gate 				 */
20537c478bd9Sstevel@tonic-gate 				if (cpi->cpi_model == 9 && cpi->cpi_step == 1)
20547c478bd9Sstevel@tonic-gate 					cp->cp_ecx |= 8 << 12;
20557c478bd9Sstevel@tonic-gate 				break;
20567c478bd9Sstevel@tonic-gate 			case X86_VENDOR_Intel:
20577c478bd9Sstevel@tonic-gate 				/*
20587c478bd9Sstevel@tonic-gate 				 * Extended L2 Cache features function.
20597c478bd9Sstevel@tonic-gate 				 * First appeared on Prescott.
20607c478bd9Sstevel@tonic-gate 				 */
20617c478bd9Sstevel@tonic-gate 			default:
20627c478bd9Sstevel@tonic-gate 				break;
20637c478bd9Sstevel@tonic-gate 			}
20647c478bd9Sstevel@tonic-gate 			break;
20657c478bd9Sstevel@tonic-gate 		default:
20667c478bd9Sstevel@tonic-gate 			break;
20677c478bd9Sstevel@tonic-gate 		}
20687c478bd9Sstevel@tonic-gate 	}
20697c478bd9Sstevel@tonic-gate 
20707c478bd9Sstevel@tonic-gate pass2_done:
20717c478bd9Sstevel@tonic-gate 	cpi->cpi_pass = 2;
20727c478bd9Sstevel@tonic-gate }
20737c478bd9Sstevel@tonic-gate 
20747c478bd9Sstevel@tonic-gate static const char *
20757c478bd9Sstevel@tonic-gate intel_cpubrand(const struct cpuid_info *cpi)
20767c478bd9Sstevel@tonic-gate {
20777c478bd9Sstevel@tonic-gate 	int i;
20787c478bd9Sstevel@tonic-gate 
20797417cfdeSKuriakose Kuruvilla 	if (!is_x86_feature(x86_featureset, X86FSET_CPUID) ||
20807c478bd9Sstevel@tonic-gate 	    cpi->cpi_maxeax < 1 || cpi->cpi_family < 5)
20817c478bd9Sstevel@tonic-gate 		return ("i486");
20827c478bd9Sstevel@tonic-gate 
20837c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_family) {
20847c478bd9Sstevel@tonic-gate 	case 5:
20857c478bd9Sstevel@tonic-gate 		return ("Intel Pentium(r)");
20867c478bd9Sstevel@tonic-gate 	case 6:
20877c478bd9Sstevel@tonic-gate 		switch (cpi->cpi_model) {
20887c478bd9Sstevel@tonic-gate 			uint_t celeron, xeon;
20898949bcd6Sandrei 			const struct cpuid_regs *cp;
20907c478bd9Sstevel@tonic-gate 		case 0:
20917c478bd9Sstevel@tonic-gate 		case 1:
20927c478bd9Sstevel@tonic-gate 		case 2:
20937c478bd9Sstevel@tonic-gate 			return ("Intel Pentium(r) Pro");
20947c478bd9Sstevel@tonic-gate 		case 3:
20957c478bd9Sstevel@tonic-gate 		case 4:
20967c478bd9Sstevel@tonic-gate 			return ("Intel Pentium(r) II");
20977c478bd9Sstevel@tonic-gate 		case 6:
20987c478bd9Sstevel@tonic-gate 			return ("Intel Celeron(r)");
20997c478bd9Sstevel@tonic-gate 		case 5:
21007c478bd9Sstevel@tonic-gate 		case 7:
21017c478bd9Sstevel@tonic-gate 			celeron = xeon = 0;
21027c478bd9Sstevel@tonic-gate 			cp = &cpi->cpi_std[2];	/* cache info */
21037c478bd9Sstevel@tonic-gate 
210463d3f7dfSkk208521 			for (i = 1; i < 4; i++) {
21057c478bd9Sstevel@tonic-gate 				uint_t tmp;
21067c478bd9Sstevel@tonic-gate 
21077c478bd9Sstevel@tonic-gate 				tmp = (cp->cp_eax >> (8 * i)) & 0xff;
21087c478bd9Sstevel@tonic-gate 				if (tmp == 0x40)
21097c478bd9Sstevel@tonic-gate 					celeron++;
21107c478bd9Sstevel@tonic-gate 				if (tmp >= 0x44 && tmp <= 0x45)
21117c478bd9Sstevel@tonic-gate 					xeon++;
21127c478bd9Sstevel@tonic-gate 			}
21137c478bd9Sstevel@tonic-gate 
21147c478bd9Sstevel@tonic-gate 			for (i = 0; i < 2; i++) {
21157c478bd9Sstevel@tonic-gate 				uint_t tmp;
21167c478bd9Sstevel@tonic-gate 
21177c478bd9Sstevel@tonic-gate 				tmp = (cp->cp_ebx >> (8 * i)) & 0xff;
21187c478bd9Sstevel@tonic-gate 				if (tmp == 0x40)
21197c478bd9Sstevel@tonic-gate 					celeron++;
21207c478bd9Sstevel@tonic-gate 				else if (tmp >= 0x44 && tmp <= 0x45)
21217c478bd9Sstevel@tonic-gate 					xeon++;
21227c478bd9Sstevel@tonic-gate 			}
21237c478bd9Sstevel@tonic-gate 
21247c478bd9Sstevel@tonic-gate 			for (i = 0; i < 4; i++) {
21257c478bd9Sstevel@tonic-gate 				uint_t tmp;
21267c478bd9Sstevel@tonic-gate 
21277c478bd9Sstevel@tonic-gate 				tmp = (cp->cp_ecx >> (8 * i)) & 0xff;
21287c478bd9Sstevel@tonic-gate 				if (tmp == 0x40)
21297c478bd9Sstevel@tonic-gate 					celeron++;
21307c478bd9Sstevel@tonic-gate 				else if (tmp >= 0x44 && tmp <= 0x45)
21317c478bd9Sstevel@tonic-gate 					xeon++;
21327c478bd9Sstevel@tonic-gate 			}
21337c478bd9Sstevel@tonic-gate 
21347c478bd9Sstevel@tonic-gate 			for (i = 0; i < 4; i++) {
21357c478bd9Sstevel@tonic-gate 				uint_t tmp;
21367c478bd9Sstevel@tonic-gate 
21377c478bd9Sstevel@tonic-gate 				tmp = (cp->cp_edx >> (8 * i)) & 0xff;
21387c478bd9Sstevel@tonic-gate 				if (tmp == 0x40)
21397c478bd9Sstevel@tonic-gate 					celeron++;
21407c478bd9Sstevel@tonic-gate 				else if (tmp >= 0x44 && tmp <= 0x45)
21417c478bd9Sstevel@tonic-gate 					xeon++;
21427c478bd9Sstevel@tonic-gate 			}
21437c478bd9Sstevel@tonic-gate 
21447c478bd9Sstevel@tonic-gate 			if (celeron)
21457c478bd9Sstevel@tonic-gate 				return ("Intel Celeron(r)");
21467c478bd9Sstevel@tonic-gate 			if (xeon)
21477c478bd9Sstevel@tonic-gate 				return (cpi->cpi_model == 5 ?
21487c478bd9Sstevel@tonic-gate 				    "Intel Pentium(r) II Xeon(tm)" :
21497c478bd9Sstevel@tonic-gate 				    "Intel Pentium(r) III Xeon(tm)");
21507c478bd9Sstevel@tonic-gate 			return (cpi->cpi_model == 5 ?
21517c478bd9Sstevel@tonic-gate 			    "Intel Pentium(r) II or Pentium(r) II Xeon(tm)" :
21527c478bd9Sstevel@tonic-gate 			    "Intel Pentium(r) III or Pentium(r) III Xeon(tm)");
21537c478bd9Sstevel@tonic-gate 		default:
21547c478bd9Sstevel@tonic-gate 			break;
21557c478bd9Sstevel@tonic-gate 		}
21567c478bd9Sstevel@tonic-gate 	default:
21577c478bd9Sstevel@tonic-gate 		break;
21587c478bd9Sstevel@tonic-gate 	}
21597c478bd9Sstevel@tonic-gate 
21605ff02082Sdmick 	/* BrandID is present if the field is nonzero */
21615ff02082Sdmick 	if (cpi->cpi_brandid != 0) {
21627c478bd9Sstevel@tonic-gate 		static const struct {
21637c478bd9Sstevel@tonic-gate 			uint_t bt_bid;
21647c478bd9Sstevel@tonic-gate 			const char *bt_str;
21657c478bd9Sstevel@tonic-gate 		} brand_tbl[] = {
21667c478bd9Sstevel@tonic-gate 			{ 0x1,	"Intel(r) Celeron(r)" },
21677c478bd9Sstevel@tonic-gate 			{ 0x2,	"Intel(r) Pentium(r) III" },
21687c478bd9Sstevel@tonic-gate 			{ 0x3,	"Intel(r) Pentium(r) III Xeon(tm)" },
21697c478bd9Sstevel@tonic-gate 			{ 0x4,	"Intel(r) Pentium(r) III" },
21707c478bd9Sstevel@tonic-gate 			{ 0x6,	"Mobile Intel(r) Pentium(r) III" },
21717c478bd9Sstevel@tonic-gate 			{ 0x7,	"Mobile Intel(r) Celeron(r)" },
21727c478bd9Sstevel@tonic-gate 			{ 0x8,	"Intel(r) Pentium(r) 4" },
21737c478bd9Sstevel@tonic-gate 			{ 0x9,	"Intel(r) Pentium(r) 4" },
21747c478bd9Sstevel@tonic-gate 			{ 0xa,	"Intel(r) Celeron(r)" },
21757c478bd9Sstevel@tonic-gate 			{ 0xb,	"Intel(r) Xeon(tm)" },
21767c478bd9Sstevel@tonic-gate 			{ 0xc,	"Intel(r) Xeon(tm) MP" },
21777c478bd9Sstevel@tonic-gate 			{ 0xe,	"Mobile Intel(r) Pentium(r) 4" },
21785ff02082Sdmick 			{ 0xf,	"Mobile Intel(r) Celeron(r)" },
21795ff02082Sdmick 			{ 0x11, "Mobile Genuine Intel(r)" },
21805ff02082Sdmick 			{ 0x12, "Intel(r) Celeron(r) M" },
21815ff02082Sdmick 			{ 0x13, "Mobile Intel(r) Celeron(r)" },
21825ff02082Sdmick 			{ 0x14, "Intel(r) Celeron(r)" },
21835ff02082Sdmick 			{ 0x15, "Mobile Genuine Intel(r)" },
21845ff02082Sdmick 			{ 0x16,	"Intel(r) Pentium(r) M" },
21855ff02082Sdmick 			{ 0x17, "Mobile Intel(r) Celeron(r)" }
21867c478bd9Sstevel@tonic-gate 		};
21877c478bd9Sstevel@tonic-gate 		uint_t btblmax = sizeof (brand_tbl) / sizeof (brand_tbl[0]);
21887c478bd9Sstevel@tonic-gate 		uint_t sgn;
21897c478bd9Sstevel@tonic-gate 
21907c478bd9Sstevel@tonic-gate 		sgn = (cpi->cpi_family << 8) |
21917c478bd9Sstevel@tonic-gate 		    (cpi->cpi_model << 4) | cpi->cpi_step;
21927c478bd9Sstevel@tonic-gate 
21937c478bd9Sstevel@tonic-gate 		for (i = 0; i < btblmax; i++)
21947c478bd9Sstevel@tonic-gate 			if (brand_tbl[i].bt_bid == cpi->cpi_brandid)
21957c478bd9Sstevel@tonic-gate 				break;
21967c478bd9Sstevel@tonic-gate 		if (i < btblmax) {
21977c478bd9Sstevel@tonic-gate 			if (sgn == 0x6b1 && cpi->cpi_brandid == 3)
21987c478bd9Sstevel@tonic-gate 				return ("Intel(r) Celeron(r)");
21997c478bd9Sstevel@tonic-gate 			if (sgn < 0xf13 && cpi->cpi_brandid == 0xb)
22007c478bd9Sstevel@tonic-gate 				return ("Intel(r) Xeon(tm) MP");
22017c478bd9Sstevel@tonic-gate 			if (sgn < 0xf13 && cpi->cpi_brandid == 0xe)
22027c478bd9Sstevel@tonic-gate 				return ("Intel(r) Xeon(tm)");
22037c478bd9Sstevel@tonic-gate 			return (brand_tbl[i].bt_str);
22047c478bd9Sstevel@tonic-gate 		}
22057c478bd9Sstevel@tonic-gate 	}
22067c478bd9Sstevel@tonic-gate 
22077c478bd9Sstevel@tonic-gate 	return (NULL);
22087c478bd9Sstevel@tonic-gate }
22097c478bd9Sstevel@tonic-gate 
22107c478bd9Sstevel@tonic-gate static const char *
22117c478bd9Sstevel@tonic-gate amd_cpubrand(const struct cpuid_info *cpi)
22127c478bd9Sstevel@tonic-gate {
22137417cfdeSKuriakose Kuruvilla 	if (!is_x86_feature(x86_featureset, X86FSET_CPUID) ||
22147c478bd9Sstevel@tonic-gate 	    cpi->cpi_maxeax < 1 || cpi->cpi_family < 5)
22157c478bd9Sstevel@tonic-gate 		return ("i486 compatible");
22167c478bd9Sstevel@tonic-gate 
22177c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_family) {
22187c478bd9Sstevel@tonic-gate 	case 5:
22197c478bd9Sstevel@tonic-gate 		switch (cpi->cpi_model) {
22207c478bd9Sstevel@tonic-gate 		case 0:
22217c478bd9Sstevel@tonic-gate 		case 1:
22227c478bd9Sstevel@tonic-gate 		case 2:
22237c478bd9Sstevel@tonic-gate 		case 3:
22247c478bd9Sstevel@tonic-gate 		case 4:
22257c478bd9Sstevel@tonic-gate 		case 5:
22267c478bd9Sstevel@tonic-gate 			return ("AMD-K5(r)");
22277c478bd9Sstevel@tonic-gate 		case 6:
22287c478bd9Sstevel@tonic-gate 		case 7:
22297c478bd9Sstevel@tonic-gate 			return ("AMD-K6(r)");
22307c478bd9Sstevel@tonic-gate 		case 8:
22317c478bd9Sstevel@tonic-gate 			return ("AMD-K6(r)-2");
22327c478bd9Sstevel@tonic-gate 		case 9:
22337c478bd9Sstevel@tonic-gate 			return ("AMD-K6(r)-III");
22347c478bd9Sstevel@tonic-gate 		default:
22357c478bd9Sstevel@tonic-gate 			return ("AMD (family 5)");
22367c478bd9Sstevel@tonic-gate 		}
22377c478bd9Sstevel@tonic-gate 	case 6:
22387c478bd9Sstevel@tonic-gate 		switch (cpi->cpi_model) {
22397c478bd9Sstevel@tonic-gate 		case 1:
22407c478bd9Sstevel@tonic-gate 			return ("AMD-K7(tm)");
22417c478bd9Sstevel@tonic-gate 		case 0:
22427c478bd9Sstevel@tonic-gate 		case 2:
22437c478bd9Sstevel@tonic-gate 		case 4:
22447c478bd9Sstevel@tonic-gate 			return ("AMD Athlon(tm)");
22457c478bd9Sstevel@tonic-gate 		case 3:
22467c478bd9Sstevel@tonic-gate 		case 7:
22477c478bd9Sstevel@tonic-gate 			return ("AMD Duron(tm)");
22487c478bd9Sstevel@tonic-gate 		case 6:
22497c478bd9Sstevel@tonic-gate 		case 8:
22507c478bd9Sstevel@tonic-gate 		case 10:
22517c478bd9Sstevel@tonic-gate 			/*
22527c478bd9Sstevel@tonic-gate 			 * Use the L2 cache size to distinguish
22537c478bd9Sstevel@tonic-gate 			 */
22547c478bd9Sstevel@tonic-gate 			return ((cpi->cpi_extd[6].cp_ecx >> 16) >= 256 ?
22557c478bd9Sstevel@tonic-gate 			    "AMD Athlon(tm)" : "AMD Duron(tm)");
22567c478bd9Sstevel@tonic-gate 		default:
22577c478bd9Sstevel@tonic-gate 			return ("AMD (family 6)");
22587c478bd9Sstevel@tonic-gate 		}
22597c478bd9Sstevel@tonic-gate 	default:
22607c478bd9Sstevel@tonic-gate 		break;
22617c478bd9Sstevel@tonic-gate 	}
22627c478bd9Sstevel@tonic-gate 
22637c478bd9Sstevel@tonic-gate 	if (cpi->cpi_family == 0xf && cpi->cpi_model == 5 &&
22647c478bd9Sstevel@tonic-gate 	    cpi->cpi_brandid != 0) {
22657c478bd9Sstevel@tonic-gate 		switch (BITX(cpi->cpi_brandid, 7, 5)) {
22667c478bd9Sstevel@tonic-gate 		case 3:
22677c478bd9Sstevel@tonic-gate 			return ("AMD Opteron(tm) UP 1xx");
22687c478bd9Sstevel@tonic-gate 		case 4:
22697c478bd9Sstevel@tonic-gate 			return ("AMD Opteron(tm) DP 2xx");
22707c478bd9Sstevel@tonic-gate 		case 5:
22717c478bd9Sstevel@tonic-gate 			return ("AMD Opteron(tm) MP 8xx");
22727c478bd9Sstevel@tonic-gate 		default:
22737c478bd9Sstevel@tonic-gate 			return ("AMD Opteron(tm)");
22747c478bd9Sstevel@tonic-gate 		}
22757c478bd9Sstevel@tonic-gate 	}
22767c478bd9Sstevel@tonic-gate 
22777c478bd9Sstevel@tonic-gate 	return (NULL);
22787c478bd9Sstevel@tonic-gate }
22797c478bd9Sstevel@tonic-gate 
22807c478bd9Sstevel@tonic-gate static const char *
22817c478bd9Sstevel@tonic-gate cyrix_cpubrand(struct cpuid_info *cpi, uint_t type)
22827c478bd9Sstevel@tonic-gate {
22837417cfdeSKuriakose Kuruvilla 	if (!is_x86_feature(x86_featureset, X86FSET_CPUID) ||
22847c478bd9Sstevel@tonic-gate 	    cpi->cpi_maxeax < 1 || cpi->cpi_family < 5 ||
22857c478bd9Sstevel@tonic-gate 	    type == X86_TYPE_CYRIX_486)
22867c478bd9Sstevel@tonic-gate 		return ("i486 compatible");
22877c478bd9Sstevel@tonic-gate 
22887c478bd9Sstevel@tonic-gate 	switch (type) {
22897c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_6x86:
22907c478bd9Sstevel@tonic-gate 		return ("Cyrix 6x86");
22917c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_6x86L:
22927c478bd9Sstevel@tonic-gate 		return ("Cyrix 6x86L");
22937c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_6x86MX:
22947c478bd9Sstevel@tonic-gate 		return ("Cyrix 6x86MX");
22957c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_GXm:
22967c478bd9Sstevel@tonic-gate 		return ("Cyrix GXm");
22977c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_MediaGX:
22987c478bd9Sstevel@tonic-gate 		return ("Cyrix MediaGX");
22997c478bd9Sstevel@tonic-gate 	case X86_TYPE_CYRIX_MII:
23007c478bd9Sstevel@tonic-gate 		return ("Cyrix M2");
23017c478bd9Sstevel@tonic-gate 	case X86_TYPE_VIA_CYRIX_III:
23027c478bd9Sstevel@tonic-gate 		return ("VIA Cyrix M3");
23037c478bd9Sstevel@tonic-gate 	default:
23047c478bd9Sstevel@tonic-gate 		/*
23057c478bd9Sstevel@tonic-gate 		 * Have another wild guess ..
23067c478bd9Sstevel@tonic-gate 		 */
23077c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 4 && cpi->cpi_model == 9)
23087c478bd9Sstevel@tonic-gate 			return ("Cyrix 5x86");
23097c478bd9Sstevel@tonic-gate 		else if (cpi->cpi_family == 5) {
23107c478bd9Sstevel@tonic-gate 			switch (cpi->cpi_model) {
23117c478bd9Sstevel@tonic-gate 			case 2:
23127c478bd9Sstevel@tonic-gate 				return ("Cyrix 6x86");	/* Cyrix M1 */
23137c478bd9Sstevel@tonic-gate 			case 4:
23147c478bd9Sstevel@tonic-gate 				return ("Cyrix MediaGX");
23157c478bd9Sstevel@tonic-gate 			default:
23167c478bd9Sstevel@tonic-gate 				break;
23177c478bd9Sstevel@tonic-gate 			}
23187c478bd9Sstevel@tonic-gate 		} else if (cpi->cpi_family == 6) {
23197c478bd9Sstevel@tonic-gate 			switch (cpi->cpi_model) {
23207c478bd9Sstevel@tonic-gate 			case 0:
23217c478bd9Sstevel@tonic-gate 				return ("Cyrix 6x86MX"); /* Cyrix M2? */
23227c478bd9Sstevel@tonic-gate 			case 5:
23237c478bd9Sstevel@tonic-gate 			case 6:
23247c478bd9Sstevel@tonic-gate 			case 7:
23257c478bd9Sstevel@tonic-gate 			case 8:
23267c478bd9Sstevel@tonic-gate 			case 9:
23277c478bd9Sstevel@tonic-gate 				return ("VIA C3");
23287c478bd9Sstevel@tonic-gate 			default:
23297c478bd9Sstevel@tonic-gate 				break;
23307c478bd9Sstevel@tonic-gate 			}
23317c478bd9Sstevel@tonic-gate 		}
23327c478bd9Sstevel@tonic-gate 		break;
23337c478bd9Sstevel@tonic-gate 	}
23347c478bd9Sstevel@tonic-gate 	return (NULL);
23357c478bd9Sstevel@tonic-gate }
23367c478bd9Sstevel@tonic-gate 
23377c478bd9Sstevel@tonic-gate /*
23387c478bd9Sstevel@tonic-gate  * This only gets called in the case that the CPU extended
23397c478bd9Sstevel@tonic-gate  * feature brand string (0x80000002, 0x80000003, 0x80000004)
23407c478bd9Sstevel@tonic-gate  * aren't available, or contain null bytes for some reason.
23417c478bd9Sstevel@tonic-gate  */
23427c478bd9Sstevel@tonic-gate static void
23437c478bd9Sstevel@tonic-gate fabricate_brandstr(struct cpuid_info *cpi)
23447c478bd9Sstevel@tonic-gate {
23457c478bd9Sstevel@tonic-gate 	const char *brand = NULL;
23467c478bd9Sstevel@tonic-gate 
23477c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
23487c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
23497c478bd9Sstevel@tonic-gate 		brand = intel_cpubrand(cpi);
23507c478bd9Sstevel@tonic-gate 		break;
23517c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
23527c478bd9Sstevel@tonic-gate 		brand = amd_cpubrand(cpi);
23537c478bd9Sstevel@tonic-gate 		break;
23547c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
23557c478bd9Sstevel@tonic-gate 		brand = cyrix_cpubrand(cpi, x86_type);
23567c478bd9Sstevel@tonic-gate 		break;
23577c478bd9Sstevel@tonic-gate 	case X86_VENDOR_NexGen:
23587c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5 && cpi->cpi_model == 0)
23597c478bd9Sstevel@tonic-gate 			brand = "NexGen Nx586";
23607c478bd9Sstevel@tonic-gate 		break;
23617c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Centaur:
23627c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5)
23637c478bd9Sstevel@tonic-gate 			switch (cpi->cpi_model) {
23647c478bd9Sstevel@tonic-gate 			case 4:
23657c478bd9Sstevel@tonic-gate 				brand = "Centaur C6";
23667c478bd9Sstevel@tonic-gate 				break;
23677c478bd9Sstevel@tonic-gate 			case 8:
23687c478bd9Sstevel@tonic-gate 				brand = "Centaur C2";
23697c478bd9Sstevel@tonic-gate 				break;
23707c478bd9Sstevel@tonic-gate 			case 9:
23717c478bd9Sstevel@tonic-gate 				brand = "Centaur C3";
23727c478bd9Sstevel@tonic-gate 				break;
23737c478bd9Sstevel@tonic-gate 			default:
23747c478bd9Sstevel@tonic-gate 				break;
23757c478bd9Sstevel@tonic-gate 			}
23767c478bd9Sstevel@tonic-gate 		break;
23777c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Rise:
23787c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5 &&
23797c478bd9Sstevel@tonic-gate 		    (cpi->cpi_model == 0 || cpi->cpi_model == 2))
23807c478bd9Sstevel@tonic-gate 			brand = "Rise mP6";
23817c478bd9Sstevel@tonic-gate 		break;
23827c478bd9Sstevel@tonic-gate 	case X86_VENDOR_SiS:
23837c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5 && cpi->cpi_model == 0)
23847c478bd9Sstevel@tonic-gate 			brand = "SiS 55x";
23857c478bd9Sstevel@tonic-gate 		break;
23867c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
23877c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family == 5 && cpi->cpi_model == 4)
23887c478bd9Sstevel@tonic-gate 			brand = "Transmeta Crusoe TM3x00 or TM5x00";
23897c478bd9Sstevel@tonic-gate 		break;
23907c478bd9Sstevel@tonic-gate 	case X86_VENDOR_NSC:
23917c478bd9Sstevel@tonic-gate 	case X86_VENDOR_UMC:
23927c478bd9Sstevel@tonic-gate 	default:
23937c478bd9Sstevel@tonic-gate 		break;
23947c478bd9Sstevel@tonic-gate 	}
23957c478bd9Sstevel@tonic-gate 	if (brand) {
23967c478bd9Sstevel@tonic-gate 		(void) strcpy((char *)cpi->cpi_brandstr, brand);
23977c478bd9Sstevel@tonic-gate 		return;
23987c478bd9Sstevel@tonic-gate 	}
23997c478bd9Sstevel@tonic-gate 
24007c478bd9Sstevel@tonic-gate 	/*
24017c478bd9Sstevel@tonic-gate 	 * If all else fails ...
24027c478bd9Sstevel@tonic-gate 	 */
24037c478bd9Sstevel@tonic-gate 	(void) snprintf(cpi->cpi_brandstr, sizeof (cpi->cpi_brandstr),
24047c478bd9Sstevel@tonic-gate 	    "%s %d.%d.%d", cpi->cpi_vendorstr, cpi->cpi_family,
24057c478bd9Sstevel@tonic-gate 	    cpi->cpi_model, cpi->cpi_step);
24067c478bd9Sstevel@tonic-gate }
24077c478bd9Sstevel@tonic-gate 
24087c478bd9Sstevel@tonic-gate /*
24097c478bd9Sstevel@tonic-gate  * This routine is called just after kernel memory allocation
24107c478bd9Sstevel@tonic-gate  * becomes available on cpu0, and as part of mp_startup() on
24117c478bd9Sstevel@tonic-gate  * the other cpus.
24127c478bd9Sstevel@tonic-gate  *
2413d129bde2Sesaxe  * Fixup the brand string, and collect any information from cpuid
2414*79ec9da8SYuri Pankov  * that requires dynamically allocated storage to represent.
24157c478bd9Sstevel@tonic-gate  */
24167c478bd9Sstevel@tonic-gate /*ARGSUSED*/
24177c478bd9Sstevel@tonic-gate void
24187c478bd9Sstevel@tonic-gate cpuid_pass3(cpu_t *cpu)
24197c478bd9Sstevel@tonic-gate {
2420d129bde2Sesaxe 	int	i, max, shft, level, size;
2421d129bde2Sesaxe 	struct cpuid_regs regs;
2422d129bde2Sesaxe 	struct cpuid_regs *cp;
24237c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
24247c478bd9Sstevel@tonic-gate 
24257c478bd9Sstevel@tonic-gate 	ASSERT(cpi->cpi_pass == 2);
24267c478bd9Sstevel@tonic-gate 
2427d129bde2Sesaxe 	/*
2428d129bde2Sesaxe 	 * Function 4: Deterministic cache parameters
2429d129bde2Sesaxe 	 *
2430d129bde2Sesaxe 	 * Take this opportunity to detect the number of threads
2431d129bde2Sesaxe 	 * sharing the last level cache, and construct a corresponding
2432d129bde2Sesaxe 	 * cache id. The respective cpuid_info members are initialized
2433d129bde2Sesaxe 	 * to the default case of "no last level cache sharing".
2434d129bde2Sesaxe 	 */
2435d129bde2Sesaxe 	cpi->cpi_ncpu_shr_last_cache = 1;
2436d129bde2Sesaxe 	cpi->cpi_last_lvl_cacheid = cpu->cpu_id;
2437d129bde2Sesaxe 
2438d129bde2Sesaxe 	if (cpi->cpi_maxeax >= 4 && cpi->cpi_vendor == X86_VENDOR_Intel) {
2439d129bde2Sesaxe 
2440d129bde2Sesaxe 		/*
2441d129bde2Sesaxe 		 * Find the # of elements (size) returned by fn 4, and along
2442d129bde2Sesaxe 		 * the way detect last level cache sharing details.
2443d129bde2Sesaxe 		 */
2444d129bde2Sesaxe 		bzero(&regs, sizeof (regs));
2445d129bde2Sesaxe 		cp = &regs;
2446d129bde2Sesaxe 		for (i = 0, max = 0; i < CPI_FN4_ECX_MAX; i++) {
2447d129bde2Sesaxe 			cp->cp_eax = 4;
2448d129bde2Sesaxe 			cp->cp_ecx = i;
2449d129bde2Sesaxe 
2450d129bde2Sesaxe 			(void) __cpuid_insn(cp);
2451d129bde2Sesaxe 
2452d129bde2Sesaxe 			if (CPI_CACHE_TYPE(cp) == 0)
2453d129bde2Sesaxe 				break;
2454d129bde2Sesaxe 			level = CPI_CACHE_LVL(cp);
2455d129bde2Sesaxe 			if (level > max) {
2456d129bde2Sesaxe 				max = level;
2457d129bde2Sesaxe 				cpi->cpi_ncpu_shr_last_cache =
2458d129bde2Sesaxe 				    CPI_NTHR_SHR_CACHE(cp) + 1;
2459d129bde2Sesaxe 			}
2460d129bde2Sesaxe 		}
2461d129bde2Sesaxe 		cpi->cpi_std_4_size = size = i;
2462d129bde2Sesaxe 
2463d129bde2Sesaxe 		/*
2464d129bde2Sesaxe 		 * Allocate the cpi_std_4 array. The first element
2465d129bde2Sesaxe 		 * references the regs for fn 4, %ecx == 0, which
2466d129bde2Sesaxe 		 * cpuid_pass2() stashed in cpi->cpi_std[4].
2467d129bde2Sesaxe 		 */
2468d129bde2Sesaxe 		if (size > 0) {
2469d129bde2Sesaxe 			cpi->cpi_std_4 =
2470d129bde2Sesaxe 			    kmem_alloc(size * sizeof (cp), KM_SLEEP);
2471d129bde2Sesaxe 			cpi->cpi_std_4[0] = &cpi->cpi_std[4];
2472d129bde2Sesaxe 
2473d129bde2Sesaxe 			/*
2474d129bde2Sesaxe 			 * Allocate storage to hold the additional regs
2475d129bde2Sesaxe 			 * for function 4, %ecx == 1 .. cpi_std_4_size.
2476d129bde2Sesaxe 			 *
2477d129bde2Sesaxe 			 * The regs for fn 4, %ecx == 0 has already
2478d129bde2Sesaxe 			 * been allocated as indicated above.
2479d129bde2Sesaxe 			 */
2480d129bde2Sesaxe 			for (i = 1; i < size; i++) {
2481d129bde2Sesaxe 				cp = cpi->cpi_std_4[i] =
2482d129bde2Sesaxe 				    kmem_zalloc(sizeof (regs), KM_SLEEP);
2483d129bde2Sesaxe 				cp->cp_eax = 4;
2484d129bde2Sesaxe 				cp->cp_ecx = i;
2485d129bde2Sesaxe 
2486d129bde2Sesaxe 				(void) __cpuid_insn(cp);
2487d129bde2Sesaxe 			}
2488d129bde2Sesaxe 		}
2489d129bde2Sesaxe 		/*
2490d129bde2Sesaxe 		 * Determine the number of bits needed to represent
2491d129bde2Sesaxe 		 * the number of CPUs sharing the last level cache.
2492d129bde2Sesaxe 		 *
2493d129bde2Sesaxe 		 * Shift off that number of bits from the APIC id to
2494d129bde2Sesaxe 		 * derive the cache id.
2495d129bde2Sesaxe 		 */
2496d129bde2Sesaxe 		shft = 0;
2497d129bde2Sesaxe 		for (i = 1; i < cpi->cpi_ncpu_shr_last_cache; i <<= 1)
2498d129bde2Sesaxe 			shft++;
2499b6917abeSmishra 		cpi->cpi_last_lvl_cacheid = cpi->cpi_apicid >> shft;
2500d129bde2Sesaxe 	}
2501d129bde2Sesaxe 
2502d129bde2Sesaxe 	/*
2503d129bde2Sesaxe 	 * Now fixup the brand string
2504d129bde2Sesaxe 	 */
25057c478bd9Sstevel@tonic-gate 	if ((cpi->cpi_xmaxeax & 0x80000000) == 0) {
25067c478bd9Sstevel@tonic-gate 		fabricate_brandstr(cpi);
2507d129bde2Sesaxe 	} else {
25087c478bd9Sstevel@tonic-gate 
25097c478bd9Sstevel@tonic-gate 		/*
25107c478bd9Sstevel@tonic-gate 		 * If we successfully extracted a brand string from the cpuid
25117c478bd9Sstevel@tonic-gate 		 * instruction, clean it up by removing leading spaces and
25127c478bd9Sstevel@tonic-gate 		 * similar junk.
25137c478bd9Sstevel@tonic-gate 		 */
25147c478bd9Sstevel@tonic-gate 		if (cpi->cpi_brandstr[0]) {
25157c478bd9Sstevel@tonic-gate 			size_t maxlen = sizeof (cpi->cpi_brandstr);
25167c478bd9Sstevel@tonic-gate 			char *src, *dst;
25177c478bd9Sstevel@tonic-gate 
25187c478bd9Sstevel@tonic-gate 			dst = src = (char *)cpi->cpi_brandstr;
25197c478bd9Sstevel@tonic-gate 			src[maxlen - 1] = '\0';
25207c478bd9Sstevel@tonic-gate 			/*
25217c478bd9Sstevel@tonic-gate 			 * strip leading spaces
25227c478bd9Sstevel@tonic-gate 			 */
25237c478bd9Sstevel@tonic-gate 			while (*src == ' ')
25247c478bd9Sstevel@tonic-gate 				src++;
25257c478bd9Sstevel@tonic-gate 			/*
25267c478bd9Sstevel@tonic-gate 			 * Remove any 'Genuine' or "Authentic" prefixes
25277c478bd9Sstevel@tonic-gate 			 */
25287c478bd9Sstevel@tonic-gate 			if (strncmp(src, "Genuine ", 8) == 0)
25297c478bd9Sstevel@tonic-gate 				src += 8;
25307c478bd9Sstevel@tonic-gate 			if (strncmp(src, "Authentic ", 10) == 0)
25317c478bd9Sstevel@tonic-gate 				src += 10;
25327c478bd9Sstevel@tonic-gate 
25337c478bd9Sstevel@tonic-gate 			/*
25347c478bd9Sstevel@tonic-gate 			 * Now do an in-place copy.
25357c478bd9Sstevel@tonic-gate 			 * Map (R) to (r) and (TM) to (tm).
25367c478bd9Sstevel@tonic-gate 			 * The era of teletypes is long gone, and there's
25377c478bd9Sstevel@tonic-gate 			 * -really- no need to shout.
25387c478bd9Sstevel@tonic-gate 			 */
25397c478bd9Sstevel@tonic-gate 			while (*src != '\0') {
25407c478bd9Sstevel@tonic-gate 				if (src[0] == '(') {
25417c478bd9Sstevel@tonic-gate 					if (strncmp(src + 1, "R)", 2) == 0) {
25427c478bd9Sstevel@tonic-gate 						(void) strncpy(dst, "(r)", 3);
25437c478bd9Sstevel@tonic-gate 						src += 3;
25447c478bd9Sstevel@tonic-gate 						dst += 3;
25457c478bd9Sstevel@tonic-gate 						continue;
25467c478bd9Sstevel@tonic-gate 					}
25477c478bd9Sstevel@tonic-gate 					if (strncmp(src + 1, "TM)", 3) == 0) {
25487c478bd9Sstevel@tonic-gate 						(void) strncpy(dst, "(tm)", 4);
25497c478bd9Sstevel@tonic-gate 						src += 4;
25507c478bd9Sstevel@tonic-gate 						dst += 4;
25517c478bd9Sstevel@tonic-gate 						continue;
25527c478bd9Sstevel@tonic-gate 					}
25537c478bd9Sstevel@tonic-gate 				}
25547c478bd9Sstevel@tonic-gate 				*dst++ = *src++;
25557c478bd9Sstevel@tonic-gate 			}
25567c478bd9Sstevel@tonic-gate 			*dst = '\0';
25577c478bd9Sstevel@tonic-gate 
25587c478bd9Sstevel@tonic-gate 			/*
25597c478bd9Sstevel@tonic-gate 			 * Finally, remove any trailing spaces
25607c478bd9Sstevel@tonic-gate 			 */
25617c478bd9Sstevel@tonic-gate 			while (--dst > cpi->cpi_brandstr)
25627c478bd9Sstevel@tonic-gate 				if (*dst == ' ')
25637c478bd9Sstevel@tonic-gate 					*dst = '\0';
25647c478bd9Sstevel@tonic-gate 				else
25657c478bd9Sstevel@tonic-gate 					break;
25667c478bd9Sstevel@tonic-gate 		} else
25677c478bd9Sstevel@tonic-gate 			fabricate_brandstr(cpi);
2568d129bde2Sesaxe 	}
25697c478bd9Sstevel@tonic-gate 	cpi->cpi_pass = 3;
25707c478bd9Sstevel@tonic-gate }
25717c478bd9Sstevel@tonic-gate 
25727c478bd9Sstevel@tonic-gate /*
25737c478bd9Sstevel@tonic-gate  * This routine is called out of bind_hwcap() much later in the life
25747c478bd9Sstevel@tonic-gate  * of the kernel (post_startup()).  The job of this routine is to resolve
25757c478bd9Sstevel@tonic-gate  * the hardware feature support and kernel support for those features into
25767c478bd9Sstevel@tonic-gate  * what we're actually going to tell applications via the aux vector.
25777c478bd9Sstevel@tonic-gate  */
2578ebb8ac07SRobert Mustacchi void
2579ebb8ac07SRobert Mustacchi cpuid_pass4(cpu_t *cpu, uint_t *hwcap_out)
25807c478bd9Sstevel@tonic-gate {
25817c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi;
2582ebb8ac07SRobert Mustacchi 	uint_t hwcap_flags = 0, hwcap_flags_2 = 0;
25837c478bd9Sstevel@tonic-gate 
25847c478bd9Sstevel@tonic-gate 	if (cpu == NULL)
25857c478bd9Sstevel@tonic-gate 		cpu = CPU;
25867c478bd9Sstevel@tonic-gate 	cpi = cpu->cpu_m.mcpu_cpi;
25877c478bd9Sstevel@tonic-gate 
25887c478bd9Sstevel@tonic-gate 	ASSERT(cpi->cpi_pass == 3);
25897c478bd9Sstevel@tonic-gate 
25907c478bd9Sstevel@tonic-gate 	if (cpi->cpi_maxeax >= 1) {
25917c478bd9Sstevel@tonic-gate 		uint32_t *edx = &cpi->cpi_support[STD_EDX_FEATURES];
25927c478bd9Sstevel@tonic-gate 		uint32_t *ecx = &cpi->cpi_support[STD_ECX_FEATURES];
25937c478bd9Sstevel@tonic-gate 
25947c478bd9Sstevel@tonic-gate 		*edx = CPI_FEATURES_EDX(cpi);
25957c478bd9Sstevel@tonic-gate 		*ecx = CPI_FEATURES_ECX(cpi);
25967c478bd9Sstevel@tonic-gate 
25977c478bd9Sstevel@tonic-gate 		/*
25987c478bd9Sstevel@tonic-gate 		 * [these require explicit kernel support]
25997c478bd9Sstevel@tonic-gate 		 */
26007417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_SEP))
26017c478bd9Sstevel@tonic-gate 			*edx &= ~CPUID_INTC_EDX_SEP;
26027c478bd9Sstevel@tonic-gate 
26037417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_SSE))
26047c478bd9Sstevel@tonic-gate 			*edx &= ~(CPUID_INTC_EDX_FXSR|CPUID_INTC_EDX_SSE);
26057417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_SSE2))
26067c478bd9Sstevel@tonic-gate 			*edx &= ~CPUID_INTC_EDX_SSE2;
26077c478bd9Sstevel@tonic-gate 
26087417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_HTT))
26097c478bd9Sstevel@tonic-gate 			*edx &= ~CPUID_INTC_EDX_HTT;
26107c478bd9Sstevel@tonic-gate 
26117417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_SSE3))
26127c478bd9Sstevel@tonic-gate 			*ecx &= ~CPUID_INTC_ECX_SSE3;
26137c478bd9Sstevel@tonic-gate 
26147417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_SSSE3))
2615d0f8ff6eSkk208521 			*ecx &= ~CPUID_INTC_ECX_SSSE3;
26167417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_SSE4_1))
2617d0f8ff6eSkk208521 			*ecx &= ~CPUID_INTC_ECX_SSE4_1;
26187417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_SSE4_2))
2619d0f8ff6eSkk208521 			*ecx &= ~CPUID_INTC_ECX_SSE4_2;
26207417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_AES))
2621a50a8b93SKuriakose Kuruvilla 			*ecx &= ~CPUID_INTC_ECX_AES;
26227417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_PCLMULQDQ))
26237417cfdeSKuriakose Kuruvilla 			*ecx &= ~CPUID_INTC_ECX_PCLMULQDQ;
26247af88ac7SKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_XSAVE))
26257af88ac7SKuriakose Kuruvilla 			*ecx &= ~(CPUID_INTC_ECX_XSAVE |
26267af88ac7SKuriakose Kuruvilla 			    CPUID_INTC_ECX_OSXSAVE);
26277af88ac7SKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_AVX))
26287af88ac7SKuriakose Kuruvilla 			*ecx &= ~CPUID_INTC_ECX_AVX;
2629ebb8ac07SRobert Mustacchi 		if (!is_x86_feature(x86_featureset, X86FSET_F16C))
2630ebb8ac07SRobert Mustacchi 			*ecx &= ~CPUID_INTC_ECX_F16C;
2631d0f8ff6eSkk208521 
26327c478bd9Sstevel@tonic-gate 		/*
26337c478bd9Sstevel@tonic-gate 		 * [no explicit support required beyond x87 fp context]
26347c478bd9Sstevel@tonic-gate 		 */
26357c478bd9Sstevel@tonic-gate 		if (!fpu_exists)
26367c478bd9Sstevel@tonic-gate 			*edx &= ~(CPUID_INTC_EDX_FPU | CPUID_INTC_EDX_MMX);
26377c478bd9Sstevel@tonic-gate 
26387c478bd9Sstevel@tonic-gate 		/*
26397c478bd9Sstevel@tonic-gate 		 * Now map the supported feature vector to things that we
26407c478bd9Sstevel@tonic-gate 		 * think userland will care about.
26417c478bd9Sstevel@tonic-gate 		 */
26427c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_SEP)
26437c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_SEP;
26447c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_SSE)
26457c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_FXSR | AV_386_SSE;
26467c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_SSE2)
26477c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_SSE2;
26487c478bd9Sstevel@tonic-gate 		if (*ecx & CPUID_INTC_ECX_SSE3)
26497c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_SSE3;
2650d0f8ff6eSkk208521 		if (*ecx & CPUID_INTC_ECX_SSSE3)
2651d0f8ff6eSkk208521 			hwcap_flags |= AV_386_SSSE3;
2652d0f8ff6eSkk208521 		if (*ecx & CPUID_INTC_ECX_SSE4_1)
2653d0f8ff6eSkk208521 			hwcap_flags |= AV_386_SSE4_1;
2654d0f8ff6eSkk208521 		if (*ecx & CPUID_INTC_ECX_SSE4_2)
2655d0f8ff6eSkk208521 			hwcap_flags |= AV_386_SSE4_2;
26565087e485SKrishnendu Sadhukhan - Sun Microsystems 		if (*ecx & CPUID_INTC_ECX_MOVBE)
26575087e485SKrishnendu Sadhukhan - Sun Microsystems 			hwcap_flags |= AV_386_MOVBE;
2658a50a8b93SKuriakose Kuruvilla 		if (*ecx & CPUID_INTC_ECX_AES)
2659a50a8b93SKuriakose Kuruvilla 			hwcap_flags |= AV_386_AES;
2660a50a8b93SKuriakose Kuruvilla 		if (*ecx & CPUID_INTC_ECX_PCLMULQDQ)
2661a50a8b93SKuriakose Kuruvilla 			hwcap_flags |= AV_386_PCLMULQDQ;
26627af88ac7SKuriakose Kuruvilla 		if ((*ecx & CPUID_INTC_ECX_XSAVE) &&
2663f3390f39SRobert Mustacchi 		    (*ecx & CPUID_INTC_ECX_OSXSAVE)) {
26647af88ac7SKuriakose Kuruvilla 			hwcap_flags |= AV_386_XSAVE;
2665f3390f39SRobert Mustacchi 
2666ebb8ac07SRobert Mustacchi 			if (*ecx & CPUID_INTC_ECX_AVX) {
2667f3390f39SRobert Mustacchi 				hwcap_flags |= AV_386_AVX;
2668ebb8ac07SRobert Mustacchi 				if (*ecx & CPUID_INTC_ECX_F16C)
2669ebb8ac07SRobert Mustacchi 					hwcap_flags_2 |= AV_386_2_F16C;
2670ebb8ac07SRobert Mustacchi 			}
2671f3390f39SRobert Mustacchi 		}
2672faa20166SBryan Cantrill 		if (*ecx & CPUID_INTC_ECX_VMX)
2673faa20166SBryan Cantrill 			hwcap_flags |= AV_386_VMX;
2674f8801251Skk208521 		if (*ecx & CPUID_INTC_ECX_POPCNT)
2675f8801251Skk208521 			hwcap_flags |= AV_386_POPCNT;
26767c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_FPU)
26777c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_FPU;
26787c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_MMX)
26797c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_MMX;
26807c478bd9Sstevel@tonic-gate 
26817c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_TSC)
26827c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_TSC;
26837c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_CX8)
26847c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_CX8;
26857c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_INTC_EDX_CMOV)
26867c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_CMOV;
26877c478bd9Sstevel@tonic-gate 		if (*ecx & CPUID_INTC_ECX_CX16)
26887c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_CX16;
2689ebb8ac07SRobert Mustacchi 
2690ebb8ac07SRobert Mustacchi 		if (*ecx & CPUID_INTC_ECX_RDRAND)
2691ebb8ac07SRobert Mustacchi 			hwcap_flags_2 |= AV_386_2_RDRAND;
26927c478bd9Sstevel@tonic-gate 	}
26937c478bd9Sstevel@tonic-gate 
26947c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax < 0x80000001)
26957c478bd9Sstevel@tonic-gate 		goto pass4_done;
26967c478bd9Sstevel@tonic-gate 
26977c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
26988949bcd6Sandrei 		struct cpuid_regs cp;
2699ae115bc7Smrj 		uint32_t *edx, *ecx;
27007c478bd9Sstevel@tonic-gate 
2701ae115bc7Smrj 	case X86_VENDOR_Intel:
2702ae115bc7Smrj 		/*
2703ae115bc7Smrj 		 * Seems like Intel duplicated what we necessary
2704ae115bc7Smrj 		 * here to make the initial crop of 64-bit OS's work.
2705ae115bc7Smrj 		 * Hopefully, those are the only "extended" bits
2706ae115bc7Smrj 		 * they'll add.
2707ae115bc7Smrj 		 */
2708ae115bc7Smrj 		/*FALLTHROUGH*/
2709ae115bc7Smrj 
27107c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
27117c478bd9Sstevel@tonic-gate 		edx = &cpi->cpi_support[AMD_EDX_FEATURES];
2712ae115bc7Smrj 		ecx = &cpi->cpi_support[AMD_ECX_FEATURES];
27137c478bd9Sstevel@tonic-gate 
27147c478bd9Sstevel@tonic-gate 		*edx = CPI_FEATURES_XTD_EDX(cpi);
2715ae115bc7Smrj 		*ecx = CPI_FEATURES_XTD_ECX(cpi);
2716ae115bc7Smrj 
2717ae115bc7Smrj 		/*
2718ae115bc7Smrj 		 * [these features require explicit kernel support]
2719ae115bc7Smrj 		 */
2720ae115bc7Smrj 		switch (cpi->cpi_vendor) {
2721ae115bc7Smrj 		case X86_VENDOR_Intel:
27227417cfdeSKuriakose Kuruvilla 			if (!is_x86_feature(x86_featureset, X86FSET_TSCP))
2723d36ea5d8Ssudheer 				*edx &= ~CPUID_AMD_EDX_TSCP;
2724ae115bc7Smrj 			break;
2725ae115bc7Smrj 
2726ae115bc7Smrj 		case X86_VENDOR_AMD:
27277417cfdeSKuriakose Kuruvilla 			if (!is_x86_feature(x86_featureset, X86FSET_TSCP))
2728ae115bc7Smrj 				*edx &= ~CPUID_AMD_EDX_TSCP;
27297417cfdeSKuriakose Kuruvilla 			if (!is_x86_feature(x86_featureset, X86FSET_SSE4A))
2730f8801251Skk208521 				*ecx &= ~CPUID_AMD_ECX_SSE4A;
2731ae115bc7Smrj 			break;
2732ae115bc7Smrj 
2733ae115bc7Smrj 		default:
2734ae115bc7Smrj 			break;
2735ae115bc7Smrj 		}
27367c478bd9Sstevel@tonic-gate 
27377c478bd9Sstevel@tonic-gate 		/*
27387c478bd9Sstevel@tonic-gate 		 * [no explicit support required beyond
27397c478bd9Sstevel@tonic-gate 		 * x87 fp context and exception handlers]
27407c478bd9Sstevel@tonic-gate 		 */
27417c478bd9Sstevel@tonic-gate 		if (!fpu_exists)
27427c478bd9Sstevel@tonic-gate 			*edx &= ~(CPUID_AMD_EDX_MMXamd |
27437c478bd9Sstevel@tonic-gate 			    CPUID_AMD_EDX_3DNow | CPUID_AMD_EDX_3DNowx);
27447c478bd9Sstevel@tonic-gate 
27457417cfdeSKuriakose Kuruvilla 		if (!is_x86_feature(x86_featureset, X86FSET_NX))
27467c478bd9Sstevel@tonic-gate 			*edx &= ~CPUID_AMD_EDX_NX;
2747ae115bc7Smrj #if !defined(__amd64)
27487c478bd9Sstevel@tonic-gate 		*edx &= ~CPUID_AMD_EDX_LM;
27497c478bd9Sstevel@tonic-gate #endif
27507c478bd9Sstevel@tonic-gate 		/*
27517c478bd9Sstevel@tonic-gate 		 * Now map the supported feature vector to
27527c478bd9Sstevel@tonic-gate 		 * things that we think userland will care about.
27537c478bd9Sstevel@tonic-gate 		 */
2754ae115bc7Smrj #if defined(__amd64)
27557c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_AMD_EDX_SYSC)
27567c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_AMD_SYSC;
2757ae115bc7Smrj #endif
27587c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_AMD_EDX_MMXamd)
27597c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_AMD_MMX;
27607c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_AMD_EDX_3DNow)
27617c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_AMD_3DNow;
27627c478bd9Sstevel@tonic-gate 		if (*edx & CPUID_AMD_EDX_3DNowx)
27637c478bd9Sstevel@tonic-gate 			hwcap_flags |= AV_386_AMD_3DNowx;
2764faa20166SBryan Cantrill 		if (*ecx & CPUID_AMD_ECX_SVM)
2765faa20166SBryan Cantrill 			hwcap_flags |= AV_386_AMD_SVM;
2766ae115bc7Smrj 
2767ae115bc7Smrj 		switch (cpi->cpi_vendor) {
2768ae115bc7Smrj 		case X86_VENDOR_AMD:
2769ae115bc7Smrj 			if (*edx & CPUID_AMD_EDX_TSCP)
2770ae115bc7Smrj 				hwcap_flags |= AV_386_TSCP;
2771ae115bc7Smrj 			if (*ecx & CPUID_AMD_ECX_AHF64)
2772ae115bc7Smrj 				hwcap_flags |= AV_386_AHF;
2773f8801251Skk208521 			if (*ecx & CPUID_AMD_ECX_SSE4A)
2774f8801251Skk208521 				hwcap_flags |= AV_386_AMD_SSE4A;
2775f8801251Skk208521 			if (*ecx & CPUID_AMD_ECX_LZCNT)
2776f8801251Skk208521 				hwcap_flags |= AV_386_AMD_LZCNT;
2777ae115bc7Smrj 			break;
2778ae115bc7Smrj 
2779ae115bc7Smrj 		case X86_VENDOR_Intel:
2780d36ea5d8Ssudheer 			if (*edx & CPUID_AMD_EDX_TSCP)
2781d36ea5d8Ssudheer 				hwcap_flags |= AV_386_TSCP;
2782ae115bc7Smrj 			/*
2783ae115bc7Smrj 			 * Aarrgh.
2784ae115bc7Smrj 			 * Intel uses a different bit in the same word.
2785ae115bc7Smrj 			 */
2786ae115bc7Smrj 			if (*ecx & CPUID_INTC_ECX_AHF64)
2787ae115bc7Smrj 				hwcap_flags |= AV_386_AHF;
2788ae115bc7Smrj 			break;
2789ae115bc7Smrj 
2790ae115bc7Smrj 		default:
2791ae115bc7Smrj 			break;
2792ae115bc7Smrj 		}
27937c478bd9Sstevel@tonic-gate 		break;
27947c478bd9Sstevel@tonic-gate 
27957c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
27968949bcd6Sandrei 		cp.cp_eax = 0x80860001;
27978949bcd6Sandrei 		(void) __cpuid_insn(&cp);
27988949bcd6Sandrei 		cpi->cpi_support[TM_EDX_FEATURES] = cp.cp_edx;
27997c478bd9Sstevel@tonic-gate 		break;
28007c478bd9Sstevel@tonic-gate 
28017c478bd9Sstevel@tonic-gate 	default:
28027c478bd9Sstevel@tonic-gate 		break;
28037c478bd9Sstevel@tonic-gate 	}
28047c478bd9Sstevel@tonic-gate 
28057c478bd9Sstevel@tonic-gate pass4_done:
28067c478bd9Sstevel@tonic-gate 	cpi->cpi_pass = 4;
2807ebb8ac07SRobert Mustacchi 	if (hwcap_out != NULL) {
2808ebb8ac07SRobert Mustacchi 		hwcap_out[0] = hwcap_flags;
2809ebb8ac07SRobert Mustacchi 		hwcap_out[1] = hwcap_flags_2;
2810ebb8ac07SRobert Mustacchi 	}
28117c478bd9Sstevel@tonic-gate }
28127c478bd9Sstevel@tonic-gate 
28137c478bd9Sstevel@tonic-gate 
28147c478bd9Sstevel@tonic-gate /*
28157c478bd9Sstevel@tonic-gate  * Simulate the cpuid instruction using the data we previously
28167c478bd9Sstevel@tonic-gate  * captured about this CPU.  We try our best to return the truth
28177c478bd9Sstevel@tonic-gate  * about the hardware, independently of kernel support.
28187c478bd9Sstevel@tonic-gate  */
28197c478bd9Sstevel@tonic-gate uint32_t
28208949bcd6Sandrei cpuid_insn(cpu_t *cpu, struct cpuid_regs *cp)
28217c478bd9Sstevel@tonic-gate {
28227c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi;
28238949bcd6Sandrei 	struct cpuid_regs *xcp;
28247c478bd9Sstevel@tonic-gate 
28257c478bd9Sstevel@tonic-gate 	if (cpu == NULL)
28267c478bd9Sstevel@tonic-gate 		cpu = CPU;
28277c478bd9Sstevel@tonic-gate 	cpi = cpu->cpu_m.mcpu_cpi;
28287c478bd9Sstevel@tonic-gate 
28297c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 3));
28307c478bd9Sstevel@tonic-gate 
28317c478bd9Sstevel@tonic-gate 	/*
28327c478bd9Sstevel@tonic-gate 	 * CPUID data is cached in two separate places: cpi_std for standard
28337c478bd9Sstevel@tonic-gate 	 * CPUID functions, and cpi_extd for extended CPUID functions.
28347c478bd9Sstevel@tonic-gate 	 */
28358949bcd6Sandrei 	if (cp->cp_eax <= cpi->cpi_maxeax && cp->cp_eax < NMAX_CPI_STD)
28368949bcd6Sandrei 		xcp = &cpi->cpi_std[cp->cp_eax];
28378949bcd6Sandrei 	else if (cp->cp_eax >= 0x80000000 && cp->cp_eax <= cpi->cpi_xmaxeax &&
28388949bcd6Sandrei 	    cp->cp_eax < 0x80000000 + NMAX_CPI_EXTD)
28398949bcd6Sandrei 		xcp = &cpi->cpi_extd[cp->cp_eax - 0x80000000];
28407c478bd9Sstevel@tonic-gate 	else
28417c478bd9Sstevel@tonic-gate 		/*
28427c478bd9Sstevel@tonic-gate 		 * The caller is asking for data from an input parameter which
28437c478bd9Sstevel@tonic-gate 		 * the kernel has not cached.  In this case we go fetch from
28447c478bd9Sstevel@tonic-gate 		 * the hardware and return the data directly to the user.
28457c478bd9Sstevel@tonic-gate 		 */
28468949bcd6Sandrei 		return (__cpuid_insn(cp));
28478949bcd6Sandrei 
28488949bcd6Sandrei 	cp->cp_eax = xcp->cp_eax;
28498949bcd6Sandrei 	cp->cp_ebx = xcp->cp_ebx;
28508949bcd6Sandrei 	cp->cp_ecx = xcp->cp_ecx;
28518949bcd6Sandrei 	cp->cp_edx = xcp->cp_edx;
28527c478bd9Sstevel@tonic-gate 	return (cp->cp_eax);
28537c478bd9Sstevel@tonic-gate }
28547c478bd9Sstevel@tonic-gate 
28557c478bd9Sstevel@tonic-gate int
28567c478bd9Sstevel@tonic-gate cpuid_checkpass(cpu_t *cpu, int pass)
28577c478bd9Sstevel@tonic-gate {
28587c478bd9Sstevel@tonic-gate 	return (cpu != NULL && cpu->cpu_m.mcpu_cpi != NULL &&
28597c478bd9Sstevel@tonic-gate 	    cpu->cpu_m.mcpu_cpi->cpi_pass >= pass);
28607c478bd9Sstevel@tonic-gate }
28617c478bd9Sstevel@tonic-gate 
28627c478bd9Sstevel@tonic-gate int
28637c478bd9Sstevel@tonic-gate cpuid_getbrandstr(cpu_t *cpu, char *s, size_t n)
28647c478bd9Sstevel@tonic-gate {
28657c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 3));
28667c478bd9Sstevel@tonic-gate 
28677c478bd9Sstevel@tonic-gate 	return (snprintf(s, n, "%s", cpu->cpu_m.mcpu_cpi->cpi_brandstr));
28687c478bd9Sstevel@tonic-gate }
28697c478bd9Sstevel@tonic-gate 
28707c478bd9Sstevel@tonic-gate int
28718949bcd6Sandrei cpuid_is_cmt(cpu_t *cpu)
28727c478bd9Sstevel@tonic-gate {
28737c478bd9Sstevel@tonic-gate 	if (cpu == NULL)
28747c478bd9Sstevel@tonic-gate 		cpu = CPU;
28757c478bd9Sstevel@tonic-gate 
28767c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
28777c478bd9Sstevel@tonic-gate 
28787c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_chipid >= 0);
28797c478bd9Sstevel@tonic-gate }
28807c478bd9Sstevel@tonic-gate 
28817c478bd9Sstevel@tonic-gate /*
28827c478bd9Sstevel@tonic-gate  * AMD and Intel both implement the 64-bit variant of the syscall
28837c478bd9Sstevel@tonic-gate  * instruction (syscallq), so if there's -any- support for syscall,
28847c478bd9Sstevel@tonic-gate  * cpuid currently says "yes, we support this".
28857c478bd9Sstevel@tonic-gate  *
28867c478bd9Sstevel@tonic-gate  * However, Intel decided to -not- implement the 32-bit variant of the
28877c478bd9Sstevel@tonic-gate  * syscall instruction, so we provide a predicate to allow our caller
28887c478bd9Sstevel@tonic-gate  * to test that subtlety here.
2889843e1988Sjohnlev  *
2890843e1988Sjohnlev  * XXPV	Currently, 32-bit syscall instructions don't work via the hypervisor,
2891843e1988Sjohnlev  *	even in the case where the hardware would in fact support it.
28927c478bd9Sstevel@tonic-gate  */
28937c478bd9Sstevel@tonic-gate /*ARGSUSED*/
28947c478bd9Sstevel@tonic-gate int
28957c478bd9Sstevel@tonic-gate cpuid_syscall32_insn(cpu_t *cpu)
28967c478bd9Sstevel@tonic-gate {
28977c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass((cpu == NULL ? CPU : cpu), 1));
28987c478bd9Sstevel@tonic-gate 
2899843e1988Sjohnlev #if !defined(__xpv)
2900ae115bc7Smrj 	if (cpu == NULL)
2901ae115bc7Smrj 		cpu = CPU;
2902ae115bc7Smrj 
2903ae115bc7Smrj 	/*CSTYLED*/
2904ae115bc7Smrj 	{
2905ae115bc7Smrj 		struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
2906ae115bc7Smrj 
2907ae115bc7Smrj 		if (cpi->cpi_vendor == X86_VENDOR_AMD &&
2908ae115bc7Smrj 		    cpi->cpi_xmaxeax >= 0x80000001 &&
2909ae115bc7Smrj 		    (CPI_FEATURES_XTD_EDX(cpi) & CPUID_AMD_EDX_SYSC))
2910ae115bc7Smrj 			return (1);
2911ae115bc7Smrj 	}
2912843e1988Sjohnlev #endif
29137c478bd9Sstevel@tonic-gate 	return (0);
29147c478bd9Sstevel@tonic-gate }
29157c478bd9Sstevel@tonic-gate 
29167c478bd9Sstevel@tonic-gate int
29177c478bd9Sstevel@tonic-gate cpuid_getidstr(cpu_t *cpu, char *s, size_t n)
29187c478bd9Sstevel@tonic-gate {
29197c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
29207c478bd9Sstevel@tonic-gate 
29217c478bd9Sstevel@tonic-gate 	static const char fmt[] =
2922ecfa43a5Sdmick 	    "x86 (%s %X family %d model %d step %d clock %d MHz)";
29237c478bd9Sstevel@tonic-gate 	static const char fmt_ht[] =
2924ecfa43a5Sdmick 	    "x86 (chipid 0x%x %s %X family %d model %d step %d clock %d MHz)";
29257c478bd9Sstevel@tonic-gate 
29267c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
29277c478bd9Sstevel@tonic-gate 
29288949bcd6Sandrei 	if (cpuid_is_cmt(cpu))
29297c478bd9Sstevel@tonic-gate 		return (snprintf(s, n, fmt_ht, cpi->cpi_chipid,
2930ecfa43a5Sdmick 		    cpi->cpi_vendorstr, cpi->cpi_std[1].cp_eax,
2931ecfa43a5Sdmick 		    cpi->cpi_family, cpi->cpi_model,
29327c478bd9Sstevel@tonic-gate 		    cpi->cpi_step, cpu->cpu_type_info.pi_clock));
29337c478bd9Sstevel@tonic-gate 	return (snprintf(s, n, fmt,
2934ecfa43a5Sdmick 	    cpi->cpi_vendorstr, cpi->cpi_std[1].cp_eax,
2935ecfa43a5Sdmick 	    cpi->cpi_family, cpi->cpi_model,
29367c478bd9Sstevel@tonic-gate 	    cpi->cpi_step, cpu->cpu_type_info.pi_clock));
29377c478bd9Sstevel@tonic-gate }
29387c478bd9Sstevel@tonic-gate 
29397c478bd9Sstevel@tonic-gate const char *
29407c478bd9Sstevel@tonic-gate cpuid_getvendorstr(cpu_t *cpu)
29417c478bd9Sstevel@tonic-gate {
29427c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
29437c478bd9Sstevel@tonic-gate 	return ((const char *)cpu->cpu_m.mcpu_cpi->cpi_vendorstr);
29447c478bd9Sstevel@tonic-gate }
29457c478bd9Sstevel@tonic-gate 
29467c478bd9Sstevel@tonic-gate uint_t
29477c478bd9Sstevel@tonic-gate cpuid_getvendor(cpu_t *cpu)
29487c478bd9Sstevel@tonic-gate {
29497c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
29507c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_vendor);
29517c478bd9Sstevel@tonic-gate }
29527c478bd9Sstevel@tonic-gate 
29537c478bd9Sstevel@tonic-gate uint_t
29547c478bd9Sstevel@tonic-gate cpuid_getfamily(cpu_t *cpu)
29557c478bd9Sstevel@tonic-gate {
29567c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
29577c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_family);
29587c478bd9Sstevel@tonic-gate }
29597c478bd9Sstevel@tonic-gate 
29607c478bd9Sstevel@tonic-gate uint_t
29617c478bd9Sstevel@tonic-gate cpuid_getmodel(cpu_t *cpu)
29627c478bd9Sstevel@tonic-gate {
29637c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
29647c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_model);
29657c478bd9Sstevel@tonic-gate }
29667c478bd9Sstevel@tonic-gate 
29677c478bd9Sstevel@tonic-gate uint_t
29687c478bd9Sstevel@tonic-gate cpuid_get_ncpu_per_chip(cpu_t *cpu)
29697c478bd9Sstevel@tonic-gate {
29707c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
29717c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_ncpu_per_chip);
29727c478bd9Sstevel@tonic-gate }
29737c478bd9Sstevel@tonic-gate 
29747c478bd9Sstevel@tonic-gate uint_t
29758949bcd6Sandrei cpuid_get_ncore_per_chip(cpu_t *cpu)
29768949bcd6Sandrei {
29778949bcd6Sandrei 	ASSERT(cpuid_checkpass(cpu, 1));
29788949bcd6Sandrei 	return (cpu->cpu_m.mcpu_cpi->cpi_ncore_per_chip);
29798949bcd6Sandrei }
29808949bcd6Sandrei 
29818949bcd6Sandrei uint_t
2982d129bde2Sesaxe cpuid_get_ncpu_sharing_last_cache(cpu_t *cpu)
2983d129bde2Sesaxe {
2984d129bde2Sesaxe 	ASSERT(cpuid_checkpass(cpu, 2));
2985d129bde2Sesaxe 	return (cpu->cpu_m.mcpu_cpi->cpi_ncpu_shr_last_cache);
2986d129bde2Sesaxe }
2987d129bde2Sesaxe 
2988d129bde2Sesaxe id_t
2989d129bde2Sesaxe cpuid_get_last_lvl_cacheid(cpu_t *cpu)
2990d129bde2Sesaxe {
2991d129bde2Sesaxe 	ASSERT(cpuid_checkpass(cpu, 2));
2992d129bde2Sesaxe 	return (cpu->cpu_m.mcpu_cpi->cpi_last_lvl_cacheid);
2993d129bde2Sesaxe }
2994d129bde2Sesaxe 
2995d129bde2Sesaxe uint_t
29967c478bd9Sstevel@tonic-gate cpuid_getstep(cpu_t *cpu)
29977c478bd9Sstevel@tonic-gate {
29987c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
29997c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_step);
30007c478bd9Sstevel@tonic-gate }
30017c478bd9Sstevel@tonic-gate 
30022449e17fSsherrym uint_t
30032449e17fSsherrym cpuid_getsig(struct cpu *cpu)
30042449e17fSsherrym {
30052449e17fSsherrym 	ASSERT(cpuid_checkpass(cpu, 1));
30062449e17fSsherrym 	return (cpu->cpu_m.mcpu_cpi->cpi_std[1].cp_eax);
30072449e17fSsherrym }
30082449e17fSsherrym 
30098a40a695Sgavinm uint32_t
30108a40a695Sgavinm cpuid_getchiprev(struct cpu *cpu)
30118a40a695Sgavinm {
30128a40a695Sgavinm 	ASSERT(cpuid_checkpass(cpu, 1));
30138a40a695Sgavinm 	return (cpu->cpu_m.mcpu_cpi->cpi_chiprev);
30148a40a695Sgavinm }
30158a40a695Sgavinm 
30168a40a695Sgavinm const char *
30178a40a695Sgavinm cpuid_getchiprevstr(struct cpu *cpu)
30188a40a695Sgavinm {
30198a40a695Sgavinm 	ASSERT(cpuid_checkpass(cpu, 1));
30208a40a695Sgavinm 	return (cpu->cpu_m.mcpu_cpi->cpi_chiprevstr);
30218a40a695Sgavinm }
30228a40a695Sgavinm 
30238a40a695Sgavinm uint32_t
30248a40a695Sgavinm cpuid_getsockettype(struct cpu *cpu)
30258a40a695Sgavinm {
30268a40a695Sgavinm 	ASSERT(cpuid_checkpass(cpu, 1));
30278a40a695Sgavinm 	return (cpu->cpu_m.mcpu_cpi->cpi_socket);
30288a40a695Sgavinm }
30298a40a695Sgavinm 
303089e921d5SKuriakose Kuruvilla const char *
303189e921d5SKuriakose Kuruvilla cpuid_getsocketstr(cpu_t *cpu)
303289e921d5SKuriakose Kuruvilla {
303389e921d5SKuriakose Kuruvilla 	static const char *socketstr = NULL;
303489e921d5SKuriakose Kuruvilla 	struct cpuid_info *cpi;
303589e921d5SKuriakose Kuruvilla 
303689e921d5SKuriakose Kuruvilla 	ASSERT(cpuid_checkpass(cpu, 1));
303789e921d5SKuriakose Kuruvilla 	cpi = cpu->cpu_m.mcpu_cpi;
303889e921d5SKuriakose Kuruvilla 
303989e921d5SKuriakose Kuruvilla 	/* Assume that socket types are the same across the system */
304089e921d5SKuriakose Kuruvilla 	if (socketstr == NULL)
304189e921d5SKuriakose Kuruvilla 		socketstr = _cpuid_sktstr(cpi->cpi_vendor, cpi->cpi_family,
304289e921d5SKuriakose Kuruvilla 		    cpi->cpi_model, cpi->cpi_step);
304389e921d5SKuriakose Kuruvilla 
304489e921d5SKuriakose Kuruvilla 
304589e921d5SKuriakose Kuruvilla 	return (socketstr);
304689e921d5SKuriakose Kuruvilla }
304789e921d5SKuriakose Kuruvilla 
3048fb2f18f8Sesaxe int
3049fb2f18f8Sesaxe cpuid_get_chipid(cpu_t *cpu)
30507c478bd9Sstevel@tonic-gate {
30517c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
30527c478bd9Sstevel@tonic-gate 
30538949bcd6Sandrei 	if (cpuid_is_cmt(cpu))
30547c478bd9Sstevel@tonic-gate 		return (cpu->cpu_m.mcpu_cpi->cpi_chipid);
30557c478bd9Sstevel@tonic-gate 	return (cpu->cpu_id);
30567c478bd9Sstevel@tonic-gate }
30577c478bd9Sstevel@tonic-gate 
30588949bcd6Sandrei id_t
3059fb2f18f8Sesaxe cpuid_get_coreid(cpu_t *cpu)
30608949bcd6Sandrei {
30618949bcd6Sandrei 	ASSERT(cpuid_checkpass(cpu, 1));
30628949bcd6Sandrei 	return (cpu->cpu_m.mcpu_cpi->cpi_coreid);
30638949bcd6Sandrei }
30648949bcd6Sandrei 
30657c478bd9Sstevel@tonic-gate int
306610569901Sgavinm cpuid_get_pkgcoreid(cpu_t *cpu)
306710569901Sgavinm {
306810569901Sgavinm 	ASSERT(cpuid_checkpass(cpu, 1));
306910569901Sgavinm 	return (cpu->cpu_m.mcpu_cpi->cpi_pkgcoreid);
307010569901Sgavinm }
307110569901Sgavinm 
307210569901Sgavinm int
3073fb2f18f8Sesaxe cpuid_get_clogid(cpu_t *cpu)
30747c478bd9Sstevel@tonic-gate {
30757c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
30767c478bd9Sstevel@tonic-gate 	return (cpu->cpu_m.mcpu_cpi->cpi_clogid);
30777c478bd9Sstevel@tonic-gate }
30787c478bd9Sstevel@tonic-gate 
3079b885580bSAlexander Kolbasov int
3080b885580bSAlexander Kolbasov cpuid_get_cacheid(cpu_t *cpu)
3081b885580bSAlexander Kolbasov {
3082b885580bSAlexander Kolbasov 	ASSERT(cpuid_checkpass(cpu, 1));
3083b885580bSAlexander Kolbasov 	return (cpu->cpu_m.mcpu_cpi->cpi_last_lvl_cacheid);
3084b885580bSAlexander Kolbasov }
3085b885580bSAlexander Kolbasov 
30868031591dSSrihari Venkatesan uint_t
30878031591dSSrihari Venkatesan cpuid_get_procnodeid(cpu_t *cpu)
30888031591dSSrihari Venkatesan {
30898031591dSSrihari Venkatesan 	ASSERT(cpuid_checkpass(cpu, 1));
30908031591dSSrihari Venkatesan 	return (cpu->cpu_m.mcpu_cpi->cpi_procnodeid);
30918031591dSSrihari Venkatesan }
30928031591dSSrihari Venkatesan 
30938031591dSSrihari Venkatesan uint_t
30948031591dSSrihari Venkatesan cpuid_get_procnodes_per_pkg(cpu_t *cpu)
30958031591dSSrihari Venkatesan {
30968031591dSSrihari Venkatesan 	ASSERT(cpuid_checkpass(cpu, 1));
30978031591dSSrihari Venkatesan 	return (cpu->cpu_m.mcpu_cpi->cpi_procnodes_per_pkg);
30988031591dSSrihari Venkatesan }
30998031591dSSrihari Venkatesan 
31007660e73fSHans Rosenfeld uint_t
31017660e73fSHans Rosenfeld cpuid_get_compunitid(cpu_t *cpu)
31027660e73fSHans Rosenfeld {
31037660e73fSHans Rosenfeld 	ASSERT(cpuid_checkpass(cpu, 1));
31047660e73fSHans Rosenfeld 	return (cpu->cpu_m.mcpu_cpi->cpi_compunitid);
31057660e73fSHans Rosenfeld }
31067660e73fSHans Rosenfeld 
31077660e73fSHans Rosenfeld uint_t
31087660e73fSHans Rosenfeld cpuid_get_cores_per_compunit(cpu_t *cpu)
31097660e73fSHans Rosenfeld {
31107660e73fSHans Rosenfeld 	ASSERT(cpuid_checkpass(cpu, 1));
31117660e73fSHans Rosenfeld 	return (cpu->cpu_m.mcpu_cpi->cpi_cores_per_compunit);
31127660e73fSHans Rosenfeld }
31137660e73fSHans Rosenfeld 
31142ef50f01SJoe Bonasera /*ARGSUSED*/
31152ef50f01SJoe Bonasera int
31162ef50f01SJoe Bonasera cpuid_have_cr8access(cpu_t *cpu)
31172ef50f01SJoe Bonasera {
31182ef50f01SJoe Bonasera #if defined(__amd64)
31192ef50f01SJoe Bonasera 	return (1);
31202ef50f01SJoe Bonasera #else
31212ef50f01SJoe Bonasera 	struct cpuid_info *cpi;
31222ef50f01SJoe Bonasera 
31232ef50f01SJoe Bonasera 	ASSERT(cpu != NULL);
31242ef50f01SJoe Bonasera 	cpi = cpu->cpu_m.mcpu_cpi;
31252ef50f01SJoe Bonasera 	if (cpi->cpi_vendor == X86_VENDOR_AMD && cpi->cpi_maxeax >= 1 &&
31262ef50f01SJoe Bonasera 	    (CPI_FEATURES_XTD_ECX(cpi) & CPUID_AMD_ECX_CR8D) != 0)
31272ef50f01SJoe Bonasera 		return (1);
31282ef50f01SJoe Bonasera 	return (0);
31292ef50f01SJoe Bonasera #endif
31302ef50f01SJoe Bonasera }
31312ef50f01SJoe Bonasera 
3132fa96bd91SMichael Corcoran uint32_t
3133fa96bd91SMichael Corcoran cpuid_get_apicid(cpu_t *cpu)
3134fa96bd91SMichael Corcoran {
3135fa96bd91SMichael Corcoran 	ASSERT(cpuid_checkpass(cpu, 1));
3136fa96bd91SMichael Corcoran 	if (cpu->cpu_m.mcpu_cpi->cpi_maxeax < 1) {
3137fa96bd91SMichael Corcoran 		return (UINT32_MAX);
3138fa96bd91SMichael Corcoran 	} else {
3139fa96bd91SMichael Corcoran 		return (cpu->cpu_m.mcpu_cpi->cpi_apicid);
3140fa96bd91SMichael Corcoran 	}
3141fa96bd91SMichael Corcoran }
3142fa96bd91SMichael Corcoran 
31437c478bd9Sstevel@tonic-gate void
31447c478bd9Sstevel@tonic-gate cpuid_get_addrsize(cpu_t *cpu, uint_t *pabits, uint_t *vabits)
31457c478bd9Sstevel@tonic-gate {
31467c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi;
31477c478bd9Sstevel@tonic-gate 
31487c478bd9Sstevel@tonic-gate 	if (cpu == NULL)
31497c478bd9Sstevel@tonic-gate 		cpu = CPU;
31507c478bd9Sstevel@tonic-gate 	cpi = cpu->cpu_m.mcpu_cpi;
31517c478bd9Sstevel@tonic-gate 
31527c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
31537c478bd9Sstevel@tonic-gate 
31547c478bd9Sstevel@tonic-gate 	if (pabits)
31557c478bd9Sstevel@tonic-gate 		*pabits = cpi->cpi_pabits;
31567c478bd9Sstevel@tonic-gate 	if (vabits)
31577c478bd9Sstevel@tonic-gate 		*vabits = cpi->cpi_vabits;
31587c478bd9Sstevel@tonic-gate }
31597c478bd9Sstevel@tonic-gate 
31607c478bd9Sstevel@tonic-gate /*
31617c478bd9Sstevel@tonic-gate  * Returns the number of data TLB entries for a corresponding
31627c478bd9Sstevel@tonic-gate  * pagesize.  If it can't be computed, or isn't known, the
31637c478bd9Sstevel@tonic-gate  * routine returns zero.  If you ask about an architecturally
31647c478bd9Sstevel@tonic-gate  * impossible pagesize, the routine will panic (so that the
31657c478bd9Sstevel@tonic-gate  * hat implementor knows that things are inconsistent.)
31667c478bd9Sstevel@tonic-gate  */
31677c478bd9Sstevel@tonic-gate uint_t
31687c478bd9Sstevel@tonic-gate cpuid_get_dtlb_nent(cpu_t *cpu, size_t pagesize)
31697c478bd9Sstevel@tonic-gate {
31707c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi;
31717c478bd9Sstevel@tonic-gate 	uint_t dtlb_nent = 0;
31727c478bd9Sstevel@tonic-gate 
31737c478bd9Sstevel@tonic-gate 	if (cpu == NULL)
31747c478bd9Sstevel@tonic-gate 		cpu = CPU;
31757c478bd9Sstevel@tonic-gate 	cpi = cpu->cpu_m.mcpu_cpi;
31767c478bd9Sstevel@tonic-gate 
31777c478bd9Sstevel@tonic-gate 	ASSERT(cpuid_checkpass(cpu, 1));
31787c478bd9Sstevel@tonic-gate 
31797c478bd9Sstevel@tonic-gate 	/*
31807c478bd9Sstevel@tonic-gate 	 * Check the L2 TLB info
31817c478bd9Sstevel@tonic-gate 	 */
31827c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax >= 0x80000006) {
31838949bcd6Sandrei 		struct cpuid_regs *cp = &cpi->cpi_extd[6];
31847c478bd9Sstevel@tonic-gate 
31857c478bd9Sstevel@tonic-gate 		switch (pagesize) {
31867c478bd9Sstevel@tonic-gate 
31877c478bd9Sstevel@tonic-gate 		case 4 * 1024:
31887c478bd9Sstevel@tonic-gate 			/*
31897c478bd9Sstevel@tonic-gate 			 * All zero in the top 16 bits of the register
31907c478bd9Sstevel@tonic-gate 			 * indicates a unified TLB. Size is in low 16 bits.
31917c478bd9Sstevel@tonic-gate 			 */
31927c478bd9Sstevel@tonic-gate 			if ((cp->cp_ebx & 0xffff0000) == 0)
31937c478bd9Sstevel@tonic-gate 				dtlb_nent = cp->cp_ebx & 0x0000ffff;
31947c478bd9Sstevel@tonic-gate 			else
31957c478bd9Sstevel@tonic-gate 				dtlb_nent = BITX(cp->cp_ebx, 27, 16);
31967c478bd9Sstevel@tonic-gate 			break;
31977c478bd9Sstevel@tonic-gate 
31987c478bd9Sstevel@tonic-gate 		case 2 * 1024 * 1024:
31997c478bd9Sstevel@tonic-gate 			if ((cp->cp_eax & 0xffff0000) == 0)
32007c478bd9Sstevel@tonic-gate 				dtlb_nent = cp->cp_eax & 0x0000ffff;
32017c478bd9Sstevel@tonic-gate 			else
32027c478bd9Sstevel@tonic-gate 				dtlb_nent = BITX(cp->cp_eax, 27, 16);
32037c478bd9Sstevel@tonic-gate 			break;
32047c478bd9Sstevel@tonic-gate 
32057c478bd9Sstevel@tonic-gate 		default:
32067c478bd9Sstevel@tonic-gate 			panic("unknown L2 pagesize");
32077c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
32087c478bd9Sstevel@tonic-gate 		}
32097c478bd9Sstevel@tonic-gate 	}
32107c478bd9Sstevel@tonic-gate 
32117c478bd9Sstevel@tonic-gate 	if (dtlb_nent != 0)
32127c478bd9Sstevel@tonic-gate 		return (dtlb_nent);
32137c478bd9Sstevel@tonic-gate 
32147c478bd9Sstevel@tonic-gate 	/*
32157c478bd9Sstevel@tonic-gate 	 * No L2 TLB support for this size, try L1.
32167c478bd9Sstevel@tonic-gate 	 */
32177c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax >= 0x80000005) {
32188949bcd6Sandrei 		struct cpuid_regs *cp = &cpi->cpi_extd[5];
32197c478bd9Sstevel@tonic-gate 
32207c478bd9Sstevel@tonic-gate 		switch (pagesize) {
32217c478bd9Sstevel@tonic-gate 		case 4 * 1024:
32227c478bd9Sstevel@tonic-gate 			dtlb_nent = BITX(cp->cp_ebx, 23, 16);
32237c478bd9Sstevel@tonic-gate 			break;
32247c478bd9Sstevel@tonic-gate 		case 2 * 1024 * 1024:
32257c478bd9Sstevel@tonic-gate 			dtlb_nent = BITX(cp->cp_eax, 23, 16);
32267c478bd9Sstevel@tonic-gate 			break;
32277c478bd9Sstevel@tonic-gate 		default:
32287c478bd9Sstevel@tonic-gate 			panic("unknown L1 d-TLB pagesize");
32297c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
32307c478bd9Sstevel@tonic-gate 		}
32317c478bd9Sstevel@tonic-gate 	}
32327c478bd9Sstevel@tonic-gate 
32337c478bd9Sstevel@tonic-gate 	return (dtlb_nent);
32347c478bd9Sstevel@tonic-gate }
32357c478bd9Sstevel@tonic-gate 
32367c478bd9Sstevel@tonic-gate /*
32377c478bd9Sstevel@tonic-gate  * Return 0 if the erratum is not present or not applicable, positive
32387c478bd9Sstevel@tonic-gate  * if it is, and negative if the status of the erratum is unknown.
32397c478bd9Sstevel@tonic-gate  *
32407c478bd9Sstevel@tonic-gate  * See "Revision Guide for AMD Athlon(tm) 64 and AMD Opteron(tm)
32412201b277Skucharsk  * Processors" #25759, Rev 3.57, August 2005
32427c478bd9Sstevel@tonic-gate  */
32437c478bd9Sstevel@tonic-gate int
32447c478bd9Sstevel@tonic-gate cpuid_opteron_erratum(cpu_t *cpu, uint_t erratum)
32457c478bd9Sstevel@tonic-gate {
32467c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
32478949bcd6Sandrei 	uint_t eax;
32487c478bd9Sstevel@tonic-gate 
3249ea99987eSsethg 	/*
3250ea99987eSsethg 	 * Bail out if this CPU isn't an AMD CPU, or if it's
3251ea99987eSsethg 	 * a legacy (32-bit) AMD CPU.
3252ea99987eSsethg 	 */
3253ea99987eSsethg 	if (cpi->cpi_vendor != X86_VENDOR_AMD ||
3254875b116eSkchow 	    cpi->cpi_family == 4 || cpi->cpi_family == 5 ||
3255875b116eSkchow 	    cpi->cpi_family == 6)
32568a40a695Sgavinm 
32577c478bd9Sstevel@tonic-gate 		return (0);
32587c478bd9Sstevel@tonic-gate 
32597c478bd9Sstevel@tonic-gate 	eax = cpi->cpi_std[1].cp_eax;
32607c478bd9Sstevel@tonic-gate 
32617c478bd9Sstevel@tonic-gate #define	SH_B0(eax)	(eax == 0xf40 || eax == 0xf50)
32627c478bd9Sstevel@tonic-gate #define	SH_B3(eax) 	(eax == 0xf51)
3263ee88d2b9Skchow #define	B(eax)		(SH_B0(eax) || SH_B3(eax))
32647c478bd9Sstevel@tonic-gate 
32657c478bd9Sstevel@tonic-gate #define	SH_C0(eax)	(eax == 0xf48 || eax == 0xf58)
32667c478bd9Sstevel@tonic-gate 
32677c478bd9Sstevel@tonic-gate #define	SH_CG(eax)	(eax == 0xf4a || eax == 0xf5a || eax == 0xf7a)
32687c478bd9Sstevel@tonic-gate #define	DH_CG(eax)	(eax == 0xfc0 || eax == 0xfe0 || eax == 0xff0)
32697c478bd9Sstevel@tonic-gate #define	CH_CG(eax)	(eax == 0xf82 || eax == 0xfb2)
3270ee88d2b9Skchow #define	CG(eax)		(SH_CG(eax) || DH_CG(eax) || CH_CG(eax))
32717c478bd9Sstevel@tonic-gate 
32727c478bd9Sstevel@tonic-gate #define	SH_D0(eax)	(eax == 0x10f40 || eax == 0x10f50 || eax == 0x10f70)
32737c478bd9Sstevel@tonic-gate #define	DH_D0(eax)	(eax == 0x10fc0 || eax == 0x10ff0)
32747c478bd9Sstevel@tonic-gate #define	CH_D0(eax)	(eax == 0x10f80 || eax == 0x10fb0)
3275ee88d2b9Skchow #define	D0(eax)		(SH_D0(eax) || DH_D0(eax) || CH_D0(eax))
32767c478bd9Sstevel@tonic-gate 
32777c478bd9Sstevel@tonic-gate #define	SH_E0(eax)	(eax == 0x20f50 || eax == 0x20f40 || eax == 0x20f70)
32787c478bd9Sstevel@tonic-gate #define	JH_E1(eax)	(eax == 0x20f10)	/* JH8_E0 had 0x20f30 */
32797c478bd9Sstevel@tonic-gate #define	DH_E3(eax)	(eax == 0x20fc0 || eax == 0x20ff0)
32807c478bd9Sstevel@tonic-gate #define	SH_E4(eax)	(eax == 0x20f51 || eax == 0x20f71)
32817c478bd9Sstevel@tonic-gate #define	BH_E4(eax)	(eax == 0x20fb1)
32827c478bd9Sstevel@tonic-gate #define	SH_E5(eax)	(eax == 0x20f42)
32837c478bd9Sstevel@tonic-gate #define	DH_E6(eax)	(eax == 0x20ff2 || eax == 0x20fc2)
32847c478bd9Sstevel@tonic-gate #define	JH_E6(eax)	(eax == 0x20f12 || eax == 0x20f32)
3285ee88d2b9Skchow #define	EX(eax)		(SH_E0(eax) || JH_E1(eax) || DH_E3(eax) || \
3286ee88d2b9Skchow 			    SH_E4(eax) || BH_E4(eax) || SH_E5(eax) || \
3287ee88d2b9Skchow 			    DH_E6(eax) || JH_E6(eax))
32887c478bd9Sstevel@tonic-gate 
3289512cf780Skchow #define	DR_AX(eax)	(eax == 0x100f00 || eax == 0x100f01 || eax == 0x100f02)
3290512cf780Skchow #define	DR_B0(eax)	(eax == 0x100f20)
3291512cf780Skchow #define	DR_B1(eax)	(eax == 0x100f21)
3292512cf780Skchow #define	DR_BA(eax)	(eax == 0x100f2a)
3293512cf780Skchow #define	DR_B2(eax)	(eax == 0x100f22)
3294512cf780Skchow #define	DR_B3(eax)	(eax == 0x100f23)
3295512cf780Skchow #define	RB_C0(eax)	(eax == 0x100f40)
3296512cf780Skchow 
32977c478bd9Sstevel@tonic-gate 	switch (erratum) {
32987c478bd9Sstevel@tonic-gate 	case 1:
3299875b116eSkchow 		return (cpi->cpi_family < 0x10);
33007c478bd9Sstevel@tonic-gate 	case 51:	/* what does the asterisk mean? */
33017c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax));
33027c478bd9Sstevel@tonic-gate 	case 52:
33037c478bd9Sstevel@tonic-gate 		return (B(eax));
33047c478bd9Sstevel@tonic-gate 	case 57:
3305512cf780Skchow 		return (cpi->cpi_family <= 0x11);
33067c478bd9Sstevel@tonic-gate 	case 58:
33077c478bd9Sstevel@tonic-gate 		return (B(eax));
33087c478bd9Sstevel@tonic-gate 	case 60:
3309512cf780Skchow 		return (cpi->cpi_family <= 0x11);
33107c478bd9Sstevel@tonic-gate 	case 61:
33117c478bd9Sstevel@tonic-gate 	case 62:
33127c478bd9Sstevel@tonic-gate 	case 63:
33137c478bd9Sstevel@tonic-gate 	case 64:
33147c478bd9Sstevel@tonic-gate 	case 65:
33157c478bd9Sstevel@tonic-gate 	case 66:
33167c478bd9Sstevel@tonic-gate 	case 68:
33177c478bd9Sstevel@tonic-gate 	case 69:
33187c478bd9Sstevel@tonic-gate 	case 70:
33197c478bd9Sstevel@tonic-gate 	case 71:
33207c478bd9Sstevel@tonic-gate 		return (B(eax));
33217c478bd9Sstevel@tonic-gate 	case 72:
33227c478bd9Sstevel@tonic-gate 		return (SH_B0(eax));
33237c478bd9Sstevel@tonic-gate 	case 74:
33247c478bd9Sstevel@tonic-gate 		return (B(eax));
33257c478bd9Sstevel@tonic-gate 	case 75:
3326875b116eSkchow 		return (cpi->cpi_family < 0x10);
33277c478bd9Sstevel@tonic-gate 	case 76:
33287c478bd9Sstevel@tonic-gate 		return (B(eax));
33297c478bd9Sstevel@tonic-gate 	case 77:
3330512cf780Skchow 		return (cpi->cpi_family <= 0x11);
33317c478bd9Sstevel@tonic-gate 	case 78:
33327c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax));
33337c478bd9Sstevel@tonic-gate 	case 79:
33347c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax) || EX(eax));
33357c478bd9Sstevel@tonic-gate 	case 80:
33367c478bd9Sstevel@tonic-gate 	case 81:
33377c478bd9Sstevel@tonic-gate 	case 82:
33387c478bd9Sstevel@tonic-gate 		return (B(eax));
33397c478bd9Sstevel@tonic-gate 	case 83:
33407c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax));
33417c478bd9Sstevel@tonic-gate 	case 85:
3342875b116eSkchow 		return (cpi->cpi_family < 0x10);
33437c478bd9Sstevel@tonic-gate 	case 86:
33447c478bd9Sstevel@tonic-gate 		return (SH_C0(eax) || CG(eax));
33457c478bd9Sstevel@tonic-gate 	case 88:
33467c478bd9Sstevel@tonic-gate #if !defined(__amd64)
33477c478bd9Sstevel@tonic-gate 		return (0);
33487c478bd9Sstevel@tonic-gate #else
33497c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax));
33507c478bd9Sstevel@tonic-gate #endif
33517c478bd9Sstevel@tonic-gate 	case 89:
3352875b116eSkchow 		return (cpi->cpi_family < 0x10);
33537c478bd9Sstevel@tonic-gate 	case 90:
33547c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax));
33557c478bd9Sstevel@tonic-gate 	case 91:
33567c478bd9Sstevel@tonic-gate 	case 92:
33577c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax));
33587c478bd9Sstevel@tonic-gate 	case 93:
33597c478bd9Sstevel@tonic-gate 		return (SH_C0(eax));
33607c478bd9Sstevel@tonic-gate 	case 94:
33617c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax));
33627c478bd9Sstevel@tonic-gate 	case 95:
33637c478bd9Sstevel@tonic-gate #if !defined(__amd64)
33647c478bd9Sstevel@tonic-gate 		return (0);
33657c478bd9Sstevel@tonic-gate #else
33667c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax));
33677c478bd9Sstevel@tonic-gate #endif
33687c478bd9Sstevel@tonic-gate 	case 96:
33697c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax));
33707c478bd9Sstevel@tonic-gate 	case 97:
33717c478bd9Sstevel@tonic-gate 	case 98:
33727c478bd9Sstevel@tonic-gate 		return (SH_C0(eax) || CG(eax));
33737c478bd9Sstevel@tonic-gate 	case 99:
33747c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax));
33757c478bd9Sstevel@tonic-gate 	case 100:
33767c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax));
33777c478bd9Sstevel@tonic-gate 	case 101:
33787c478bd9Sstevel@tonic-gate 	case 103:
33797c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax));
33807c478bd9Sstevel@tonic-gate 	case 104:
33817c478bd9Sstevel@tonic-gate 		return (SH_C0(eax) || CG(eax) || D0(eax));
33827c478bd9Sstevel@tonic-gate 	case 105:
33837c478bd9Sstevel@tonic-gate 	case 106:
33847c478bd9Sstevel@tonic-gate 	case 107:
33857c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax));
33867c478bd9Sstevel@tonic-gate 	case 108:
33877c478bd9Sstevel@tonic-gate 		return (DH_CG(eax));
33887c478bd9Sstevel@tonic-gate 	case 109:
33897c478bd9Sstevel@tonic-gate 		return (SH_C0(eax) || CG(eax) || D0(eax));
33907c478bd9Sstevel@tonic-gate 	case 110:
33917c478bd9Sstevel@tonic-gate 		return (D0(eax) || EX(eax));
33927c478bd9Sstevel@tonic-gate 	case 111:
33937c478bd9Sstevel@tonic-gate 		return (CG(eax));
33947c478bd9Sstevel@tonic-gate 	case 112:
33957c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax) || EX(eax));
33967c478bd9Sstevel@tonic-gate 	case 113:
33977c478bd9Sstevel@tonic-gate 		return (eax == 0x20fc0);
33987c478bd9Sstevel@tonic-gate 	case 114:
33997c478bd9Sstevel@tonic-gate 		return (SH_E0(eax) || JH_E1(eax) || DH_E3(eax));
34007c478bd9Sstevel@tonic-gate 	case 115:
34017c478bd9Sstevel@tonic-gate 		return (SH_E0(eax) || JH_E1(eax));
34027c478bd9Sstevel@tonic-gate 	case 116:
34037c478bd9Sstevel@tonic-gate 		return (SH_E0(eax) || JH_E1(eax) || DH_E3(eax));
34047c478bd9Sstevel@tonic-gate 	case 117:
34057c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax));
34067c478bd9Sstevel@tonic-gate 	case 118:
34077c478bd9Sstevel@tonic-gate 		return (SH_E0(eax) || JH_E1(eax) || SH_E4(eax) || BH_E4(eax) ||
34087c478bd9Sstevel@tonic-gate 		    JH_E6(eax));
34097c478bd9Sstevel@tonic-gate 	case 121:
34107c478bd9Sstevel@tonic-gate 		return (B(eax) || SH_C0(eax) || CG(eax) || D0(eax) || EX(eax));
34117c478bd9Sstevel@tonic-gate 	case 122:
3412512cf780Skchow 		return (cpi->cpi_family < 0x10 || cpi->cpi_family == 0x11);
34137c478bd9Sstevel@tonic-gate 	case 123:
34147c478bd9Sstevel@tonic-gate 		return (JH_E1(eax) || BH_E4(eax) || JH_E6(eax));
34152201b277Skucharsk 	case 131:
3416875b116eSkchow 		return (cpi->cpi_family < 0x10);
3417ef50d8c0Sesaxe 	case 6336786:
3418ef50d8c0Sesaxe 		/*
3419ef50d8c0Sesaxe 		 * Test for AdvPowerMgmtInfo.TscPStateInvariant
3420875b116eSkchow 		 * if this is a K8 family or newer processor
3421ef50d8c0Sesaxe 		 */
3422ef50d8c0Sesaxe 		if (CPI_FAMILY(cpi) == 0xf) {
34238949bcd6Sandrei 			struct cpuid_regs regs;
34248949bcd6Sandrei 			regs.cp_eax = 0x80000007;
34258949bcd6Sandrei 			(void) __cpuid_insn(&regs);
34268949bcd6Sandrei 			return (!(regs.cp_edx & 0x100));
3427ef50d8c0Sesaxe 		}
3428ef50d8c0Sesaxe 		return (0);
3429ee88d2b9Skchow 	case 6323525:
3430ee88d2b9Skchow 		return (((((eax >> 12) & 0xff00) + (eax & 0xf00)) |
3431ee88d2b9Skchow 		    (((eax >> 4) & 0xf) | ((eax >> 12) & 0xf0))) < 0xf40);
3432ee88d2b9Skchow 
3433512cf780Skchow 	case 6671130:
3434512cf780Skchow 		/*
3435512cf780Skchow 		 * check for processors (pre-Shanghai) that do not provide
3436512cf780Skchow 		 * optimal management of 1gb ptes in its tlb.
3437512cf780Skchow 		 */
3438512cf780Skchow 		return (cpi->cpi_family == 0x10 && cpi->cpi_model < 4);
3439512cf780Skchow 
3440512cf780Skchow 	case 298:
3441512cf780Skchow 		return (DR_AX(eax) || DR_B0(eax) || DR_B1(eax) || DR_BA(eax) ||
3442512cf780Skchow 		    DR_B2(eax) || RB_C0(eax));
3443512cf780Skchow 
34445e54b56dSHans Rosenfeld 	case 721:
34455e54b56dSHans Rosenfeld #if defined(__amd64)
34465e54b56dSHans Rosenfeld 		return (cpi->cpi_family == 0x10 || cpi->cpi_family == 0x12);
34475e54b56dSHans Rosenfeld #else
34485e54b56dSHans Rosenfeld 		return (0);
34495e54b56dSHans Rosenfeld #endif
34505e54b56dSHans Rosenfeld 
3451512cf780Skchow 	default:
3452512cf780Skchow 		return (-1);
3453512cf780Skchow 
3454512cf780Skchow 	}
3455512cf780Skchow }
3456512cf780Skchow 
3457512cf780Skchow /*
3458512cf780Skchow  * Determine if specified erratum is present via OSVW (OS Visible Workaround).
3459512cf780Skchow  * Return 1 if erratum is present, 0 if not present and -1 if indeterminate.
3460512cf780Skchow  */
3461512cf780Skchow int
3462512cf780Skchow osvw_opteron_erratum(cpu_t *cpu, uint_t erratum)
3463512cf780Skchow {
3464512cf780Skchow 	struct cpuid_info	*cpi;
3465512cf780Skchow 	uint_t			osvwid;
3466512cf780Skchow 	static int		osvwfeature = -1;
3467512cf780Skchow 	uint64_t		osvwlength;
3468512cf780Skchow 
3469512cf780Skchow 
3470512cf780Skchow 	cpi = cpu->cpu_m.mcpu_cpi;
3471512cf780Skchow 
3472512cf780Skchow 	/* confirm OSVW supported */
3473512cf780Skchow 	if (osvwfeature == -1) {
3474512cf780Skchow 		osvwfeature = cpi->cpi_extd[1].cp_ecx & CPUID_AMD_ECX_OSVW;
3475512cf780Skchow 	} else {
3476512cf780Skchow 		/* assert that osvw feature setting is consistent on all cpus */
3477512cf780Skchow 		ASSERT(osvwfeature ==
3478512cf780Skchow 		    (cpi->cpi_extd[1].cp_ecx & CPUID_AMD_ECX_OSVW));
3479512cf780Skchow 	}
3480512cf780Skchow 	if (!osvwfeature)
3481512cf780Skchow 		return (-1);
3482512cf780Skchow 
3483512cf780Skchow 	osvwlength = rdmsr(MSR_AMD_OSVW_ID_LEN) & OSVW_ID_LEN_MASK;
3484512cf780Skchow 
3485512cf780Skchow 	switch (erratum) {
3486512cf780Skchow 	case 298:	/* osvwid is 0 */
3487512cf780Skchow 		osvwid = 0;
3488512cf780Skchow 		if (osvwlength <= (uint64_t)osvwid) {
3489512cf780Skchow 			/* osvwid 0 is unknown */
3490512cf780Skchow 			return (-1);
3491512cf780Skchow 		}
3492512cf780Skchow 
3493512cf780Skchow 		/*
3494512cf780Skchow 		 * Check the OSVW STATUS MSR to determine the state
3495512cf780Skchow 		 * of the erratum where:
3496512cf780Skchow 		 *   0 - fixed by HW
3497512cf780Skchow 		 *   1 - BIOS has applied the workaround when BIOS
3498512cf780Skchow 		 *   workaround is available. (Or for other errata,
3499512cf780Skchow 		 *   OS workaround is required.)
3500512cf780Skchow 		 * For a value of 1, caller will confirm that the
3501512cf780Skchow 		 * erratum 298 workaround has indeed been applied by BIOS.
3502512cf780Skchow 		 *
3503512cf780Skchow 		 * A 1 may be set in cpus that have a HW fix
3504512cf780Skchow 		 * in a mixed cpu system. Regarding erratum 298:
3505512cf780Skchow 		 *   In a multiprocessor platform, the workaround above
3506512cf780Skchow 		 *   should be applied to all processors regardless of
3507512cf780Skchow 		 *   silicon revision when an affected processor is
3508512cf780Skchow 		 *   present.
3509512cf780Skchow 		 */
3510512cf780Skchow 
3511512cf780Skchow 		return (rdmsr(MSR_AMD_OSVW_STATUS +
3512512cf780Skchow 		    (osvwid / OSVW_ID_CNT_PER_MSR)) &
3513512cf780Skchow 		    (1ULL << (osvwid % OSVW_ID_CNT_PER_MSR)));
3514512cf780Skchow 
35157c478bd9Sstevel@tonic-gate 	default:
35167c478bd9Sstevel@tonic-gate 		return (-1);
35177c478bd9Sstevel@tonic-gate 	}
35187c478bd9Sstevel@tonic-gate }
35197c478bd9Sstevel@tonic-gate 
35207c478bd9Sstevel@tonic-gate static const char assoc_str[] = "associativity";
35217c478bd9Sstevel@tonic-gate static const char line_str[] = "line-size";
35227c478bd9Sstevel@tonic-gate static const char size_str[] = "size";
35237c478bd9Sstevel@tonic-gate 
35247c478bd9Sstevel@tonic-gate static void
35257c478bd9Sstevel@tonic-gate add_cache_prop(dev_info_t *devi, const char *label, const char *type,
35267c478bd9Sstevel@tonic-gate     uint32_t val)
35277c478bd9Sstevel@tonic-gate {
35287c478bd9Sstevel@tonic-gate 	char buf[128];
35297c478bd9Sstevel@tonic-gate 
35307c478bd9Sstevel@tonic-gate 	/*
35317c478bd9Sstevel@tonic-gate 	 * ndi_prop_update_int() is used because it is desirable for
35327c478bd9Sstevel@tonic-gate 	 * DDI_PROP_HW_DEF and DDI_PROP_DONTSLEEP to be set.
35337c478bd9Sstevel@tonic-gate 	 */
35347c478bd9Sstevel@tonic-gate 	if (snprintf(buf, sizeof (buf), "%s-%s", label, type) < sizeof (buf))
35357c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, devi, buf, val);
35367c478bd9Sstevel@tonic-gate }
35377c478bd9Sstevel@tonic-gate 
35387c478bd9Sstevel@tonic-gate /*
35397c478bd9Sstevel@tonic-gate  * Intel-style cache/tlb description
35407c478bd9Sstevel@tonic-gate  *
35417c478bd9Sstevel@tonic-gate  * Standard cpuid level 2 gives a randomly ordered
35427c478bd9Sstevel@tonic-gate  * selection of tags that index into a table that describes
35437c478bd9Sstevel@tonic-gate  * cache and tlb properties.
35447c478bd9Sstevel@tonic-gate  */
35457c478bd9Sstevel@tonic-gate 
35467c478bd9Sstevel@tonic-gate static const char l1_icache_str[] = "l1-icache";
35477c478bd9Sstevel@tonic-gate static const char l1_dcache_str[] = "l1-dcache";
35487c478bd9Sstevel@tonic-gate static const char l2_cache_str[] = "l2-cache";
3549ae115bc7Smrj static const char l3_cache_str[] = "l3-cache";
35507c478bd9Sstevel@tonic-gate static const char itlb4k_str[] = "itlb-4K";
35517c478bd9Sstevel@tonic-gate static const char dtlb4k_str[] = "dtlb-4K";
3552824e4fecSvd224797 static const char itlb2M_str[] = "itlb-2M";
35537c478bd9Sstevel@tonic-gate static const char itlb4M_str[] = "itlb-4M";
35547c478bd9Sstevel@tonic-gate static const char dtlb4M_str[] = "dtlb-4M";
355525dfb062Sksadhukh static const char dtlb24_str[] = "dtlb0-2M-4M";
35567c478bd9Sstevel@tonic-gate static const char itlb424_str[] = "itlb-4K-2M-4M";
355725dfb062Sksadhukh static const char itlb24_str[] = "itlb-2M-4M";
35587c478bd9Sstevel@tonic-gate static const char dtlb44_str[] = "dtlb-4K-4M";
35597c478bd9Sstevel@tonic-gate static const char sl1_dcache_str[] = "sectored-l1-dcache";
35607c478bd9Sstevel@tonic-gate static const char sl2_cache_str[] = "sectored-l2-cache";
35617c478bd9Sstevel@tonic-gate static const char itrace_str[] = "itrace-cache";
35627c478bd9Sstevel@tonic-gate static const char sl3_cache_str[] = "sectored-l3-cache";
356325dfb062Sksadhukh static const char sh_l2_tlb4k_str[] = "shared-l2-tlb-4k";
35647c478bd9Sstevel@tonic-gate 
35657c478bd9Sstevel@tonic-gate static const struct cachetab {
35667c478bd9Sstevel@tonic-gate 	uint8_t 	ct_code;
35677c478bd9Sstevel@tonic-gate 	uint8_t		ct_assoc;
35687c478bd9Sstevel@tonic-gate 	uint16_t 	ct_line_size;
35697c478bd9Sstevel@tonic-gate 	size_t		ct_size;
35707c478bd9Sstevel@tonic-gate 	const char	*ct_label;
35717c478bd9Sstevel@tonic-gate } intel_ctab[] = {
3572824e4fecSvd224797 	/*
3573824e4fecSvd224797 	 * maintain descending order!
3574824e4fecSvd224797 	 *
3575824e4fecSvd224797 	 * Codes ignored - Reason
3576824e4fecSvd224797 	 * ----------------------
3577824e4fecSvd224797 	 * 40H - intel_cpuid_4_cache_info() disambiguates l2/l3 cache
3578824e4fecSvd224797 	 * f0H/f1H - Currently we do not interpret prefetch size by design
3579824e4fecSvd224797 	 */
358025dfb062Sksadhukh 	{ 0xe4, 16, 64, 8*1024*1024, l3_cache_str},
358125dfb062Sksadhukh 	{ 0xe3, 16, 64, 4*1024*1024, l3_cache_str},
358225dfb062Sksadhukh 	{ 0xe2, 16, 64, 2*1024*1024, l3_cache_str},
358325dfb062Sksadhukh 	{ 0xde, 12, 64, 6*1024*1024, l3_cache_str},
358425dfb062Sksadhukh 	{ 0xdd, 12, 64, 3*1024*1024, l3_cache_str},
358525dfb062Sksadhukh 	{ 0xdc, 12, 64, ((1*1024*1024)+(512*1024)), l3_cache_str},
358625dfb062Sksadhukh 	{ 0xd8, 8, 64, 4*1024*1024, l3_cache_str},
358725dfb062Sksadhukh 	{ 0xd7, 8, 64, 2*1024*1024, l3_cache_str},
358825dfb062Sksadhukh 	{ 0xd6, 8, 64, 1*1024*1024, l3_cache_str},
358925dfb062Sksadhukh 	{ 0xd2, 4, 64, 2*1024*1024, l3_cache_str},
359025dfb062Sksadhukh 	{ 0xd1, 4, 64, 1*1024*1024, l3_cache_str},
359125dfb062Sksadhukh 	{ 0xd0, 4, 64, 512*1024, l3_cache_str},
359225dfb062Sksadhukh 	{ 0xca, 4, 0, 512, sh_l2_tlb4k_str},
3593824e4fecSvd224797 	{ 0xc0, 4, 0, 8, dtlb44_str },
3594824e4fecSvd224797 	{ 0xba, 4, 0, 64, dtlb4k_str },
3595ae115bc7Smrj 	{ 0xb4, 4, 0, 256, dtlb4k_str },
35967c478bd9Sstevel@tonic-gate 	{ 0xb3, 4, 0, 128, dtlb4k_str },
359725dfb062Sksadhukh 	{ 0xb2, 4, 0, 64, itlb4k_str },
35987c478bd9Sstevel@tonic-gate 	{ 0xb0, 4, 0, 128, itlb4k_str },
35997c478bd9Sstevel@tonic-gate 	{ 0x87, 8, 64, 1024*1024, l2_cache_str},
36007c478bd9Sstevel@tonic-gate 	{ 0x86, 4, 64, 512*1024, l2_cache_str},
36017c478bd9Sstevel@tonic-gate 	{ 0x85, 8, 32, 2*1024*1024, l2_cache_str},
36027c478bd9Sstevel@tonic-gate 	{ 0x84, 8, 32, 1024*1024, l2_cache_str},
36037c478bd9Sstevel@tonic-gate 	{ 0x83, 8, 32, 512*1024, l2_cache_str},
36047c478bd9Sstevel@tonic-gate 	{ 0x82, 8, 32, 256*1024, l2_cache_str},
3605824e4fecSvd224797 	{ 0x80, 8, 64, 512*1024, l2_cache_str},
36067c478bd9Sstevel@tonic-gate 	{ 0x7f, 2, 64, 512*1024, l2_cache_str},
36077c478bd9Sstevel@tonic-gate 	{ 0x7d, 8, 64, 2*1024*1024, sl2_cache_str},
36087c478bd9Sstevel@tonic-gate 	{ 0x7c, 8, 64, 1024*1024, sl2_cache_str},
36097c478bd9Sstevel@tonic-gate 	{ 0x7b, 8, 64, 512*1024, sl2_cache_str},
36107c478bd9Sstevel@tonic-gate 	{ 0x7a, 8, 64, 256*1024, sl2_cache_str},
36117c478bd9Sstevel@tonic-gate 	{ 0x79, 8, 64, 128*1024, sl2_cache_str},
36127c478bd9Sstevel@tonic-gate 	{ 0x78, 8, 64, 1024*1024, l2_cache_str},
3613ae115bc7Smrj 	{ 0x73, 8, 0, 64*1024, itrace_str},
36147c478bd9Sstevel@tonic-gate 	{ 0x72, 8, 0, 32*1024, itrace_str},
36157c478bd9Sstevel@tonic-gate 	{ 0x71, 8, 0, 16*1024, itrace_str},
36167c478bd9Sstevel@tonic-gate 	{ 0x70, 8, 0, 12*1024, itrace_str},
36177c478bd9Sstevel@tonic-gate 	{ 0x68, 4, 64, 32*1024, sl1_dcache_str},
36187c478bd9Sstevel@tonic-gate 	{ 0x67, 4, 64, 16*1024, sl1_dcache_str},
36197c478bd9Sstevel@tonic-gate 	{ 0x66, 4, 64, 8*1024, sl1_dcache_str},
36207c478bd9Sstevel@tonic-gate 	{ 0x60, 8, 64, 16*1024, sl1_dcache_str},
36217c478bd9Sstevel@tonic-gate 	{ 0x5d, 0, 0, 256, dtlb44_str},
36227c478bd9Sstevel@tonic-gate 	{ 0x5c, 0, 0, 128, dtlb44_str},
36237c478bd9Sstevel@tonic-gate 	{ 0x5b, 0, 0, 64, dtlb44_str},
362425dfb062Sksadhukh 	{ 0x5a, 4, 0, 32, dtlb24_str},
3625824e4fecSvd224797 	{ 0x59, 0, 0, 16, dtlb4k_str},
3626824e4fecSvd224797 	{ 0x57, 4, 0, 16, dtlb4k_str},
3627824e4fecSvd224797 	{ 0x56, 4, 0, 16, dtlb4M_str},
362825dfb062Sksadhukh 	{ 0x55, 0, 0, 7, itlb24_str},
36297c478bd9Sstevel@tonic-gate 	{ 0x52, 0, 0, 256, itlb424_str},
36307c478bd9Sstevel@tonic-gate 	{ 0x51, 0, 0, 128, itlb424_str},
36317c478bd9Sstevel@tonic-gate 	{ 0x50, 0, 0, 64, itlb424_str},
3632824e4fecSvd224797 	{ 0x4f, 0, 0, 32, itlb4k_str},
3633824e4fecSvd224797 	{ 0x4e, 24, 64, 6*1024*1024, l2_cache_str},
3634ae115bc7Smrj 	{ 0x4d, 16, 64, 16*1024*1024, l3_cache_str},
3635ae115bc7Smrj 	{ 0x4c, 12, 64, 12*1024*1024, l3_cache_str},
3636ae115bc7Smrj 	{ 0x4b, 16, 64, 8*1024*1024, l3_cache_str},
3637ae115bc7Smrj 	{ 0x4a, 12, 64, 6*1024*1024, l3_cache_str},
3638ae115bc7Smrj 	{ 0x49, 16, 64, 4*1024*1024, l3_cache_str},
3639824e4fecSvd224797 	{ 0x48, 12, 64, 3*1024*1024, l2_cache_str},
3640ae115bc7Smrj 	{ 0x47, 8, 64, 8*1024*1024, l3_cache_str},
3641ae115bc7Smrj 	{ 0x46, 4, 64, 4*1024*1024, l3_cache_str},
36427c478bd9Sstevel@tonic-gate 	{ 0x45, 4, 32, 2*1024*1024, l2_cache_str},
36437c478bd9Sstevel@tonic-gate 	{ 0x44, 4, 32, 1024*1024, l2_cache_str},
36447c478bd9Sstevel@tonic-gate 	{ 0x43, 4, 32, 512*1024, l2_cache_str},
36457c478bd9Sstevel@tonic-gate 	{ 0x42, 4, 32, 256*1024, l2_cache_str},
36467c478bd9Sstevel@tonic-gate 	{ 0x41, 4, 32, 128*1024, l2_cache_str},
3647ae115bc7Smrj 	{ 0x3e, 4, 64, 512*1024, sl2_cache_str},
3648ae115bc7Smrj 	{ 0x3d, 6, 64, 384*1024, sl2_cache_str},
36497c478bd9Sstevel@tonic-gate 	{ 0x3c, 4, 64, 256*1024, sl2_cache_str},
36507c478bd9Sstevel@tonic-gate 	{ 0x3b, 2, 64, 128*1024, sl2_cache_str},
3651ae115bc7Smrj 	{ 0x3a, 6, 64, 192*1024, sl2_cache_str},
36527c478bd9Sstevel@tonic-gate 	{ 0x39, 4, 64, 128*1024, sl2_cache_str},
36537c478bd9Sstevel@tonic-gate 	{ 0x30, 8, 64, 32*1024, l1_icache_str},
36547c478bd9Sstevel@tonic-gate 	{ 0x2c, 8, 64, 32*1024, l1_dcache_str},
36557c478bd9Sstevel@tonic-gate 	{ 0x29, 8, 64, 4096*1024, sl3_cache_str},
36567c478bd9Sstevel@tonic-gate 	{ 0x25, 8, 64, 2048*1024, sl3_cache_str},
36577c478bd9Sstevel@tonic-gate 	{ 0x23, 8, 64, 1024*1024, sl3_cache_str},
36587c478bd9Sstevel@tonic-gate 	{ 0x22, 4, 64, 512*1024, sl3_cache_str},
3659824e4fecSvd224797 	{ 0x0e, 6, 64, 24*1024, l1_dcache_str},
366025dfb062Sksadhukh 	{ 0x0d, 4, 32, 16*1024, l1_dcache_str},
36617c478bd9Sstevel@tonic-gate 	{ 0x0c, 4, 32, 16*1024, l1_dcache_str},
3662ae115bc7Smrj 	{ 0x0b, 4, 0, 4, itlb4M_str},
36637c478bd9Sstevel@tonic-gate 	{ 0x0a, 2, 32, 8*1024, l1_dcache_str},
36647c478bd9Sstevel@tonic-gate 	{ 0x08, 4, 32, 16*1024, l1_icache_str},
36657c478bd9Sstevel@tonic-gate 	{ 0x06, 4, 32, 8*1024, l1_icache_str},
3666824e4fecSvd224797 	{ 0x05, 4, 0, 32, dtlb4M_str},
36677c478bd9Sstevel@tonic-gate 	{ 0x04, 4, 0, 8, dtlb4M_str},
36687c478bd9Sstevel@tonic-gate 	{ 0x03, 4, 0, 64, dtlb4k_str},
36697c478bd9Sstevel@tonic-gate 	{ 0x02, 4, 0, 2, itlb4M_str},
36707c478bd9Sstevel@tonic-gate 	{ 0x01, 4, 0, 32, itlb4k_str},
36717c478bd9Sstevel@tonic-gate 	{ 0 }
36727c478bd9Sstevel@tonic-gate };
36737c478bd9Sstevel@tonic-gate 
36747c478bd9Sstevel@tonic-gate static const struct cachetab cyrix_ctab[] = {
36757c478bd9Sstevel@tonic-gate 	{ 0x70, 4, 0, 32, "tlb-4K" },
36767c478bd9Sstevel@tonic-gate 	{ 0x80, 4, 16, 16*1024, "l1-cache" },
36777c478bd9Sstevel@tonic-gate 	{ 0 }
36787c478bd9Sstevel@tonic-gate };
36797c478bd9Sstevel@tonic-gate 
36807c478bd9Sstevel@tonic-gate /*
36817c478bd9Sstevel@tonic-gate  * Search a cache table for a matching entry
36827c478bd9Sstevel@tonic-gate  */
36837c478bd9Sstevel@tonic-gate static const struct cachetab *
36847c478bd9Sstevel@tonic-gate find_cacheent(const struct cachetab *ct, uint_t code)
36857c478bd9Sstevel@tonic-gate {
36867c478bd9Sstevel@tonic-gate 	if (code != 0) {
36877c478bd9Sstevel@tonic-gate 		for (; ct->ct_code != 0; ct++)
36887c478bd9Sstevel@tonic-gate 			if (ct->ct_code <= code)
36897c478bd9Sstevel@tonic-gate 				break;
36907c478bd9Sstevel@tonic-gate 		if (ct->ct_code == code)
36917c478bd9Sstevel@tonic-gate 			return (ct);
36927c478bd9Sstevel@tonic-gate 	}
36937c478bd9Sstevel@tonic-gate 	return (NULL);
36947c478bd9Sstevel@tonic-gate }
36957c478bd9Sstevel@tonic-gate 
36967c478bd9Sstevel@tonic-gate /*
36977dee861bSksadhukh  * Populate cachetab entry with L2 or L3 cache-information using
36987dee861bSksadhukh  * cpuid function 4. This function is called from intel_walk_cacheinfo()
36997dee861bSksadhukh  * when descriptor 0x49 is encountered. It returns 0 if no such cache
37007dee861bSksadhukh  * information is found.
37017dee861bSksadhukh  */
37027dee861bSksadhukh static int
37037dee861bSksadhukh intel_cpuid_4_cache_info(struct cachetab *ct, struct cpuid_info *cpi)
37047dee861bSksadhukh {
37057dee861bSksadhukh 	uint32_t level, i;
37067dee861bSksadhukh 	int ret = 0;
37077dee861bSksadhukh 
37087dee861bSksadhukh 	for (i = 0; i < cpi->cpi_std_4_size; i++) {
37097dee861bSksadhukh 		level = CPI_CACHE_LVL(cpi->cpi_std_4[i]);
37107dee861bSksadhukh 
37117dee861bSksadhukh 		if (level == 2 || level == 3) {
37127dee861bSksadhukh 			ct->ct_assoc = CPI_CACHE_WAYS(cpi->cpi_std_4[i]) + 1;
37137dee861bSksadhukh 			ct->ct_line_size =
37147dee861bSksadhukh 			    CPI_CACHE_COH_LN_SZ(cpi->cpi_std_4[i]) + 1;
37157dee861bSksadhukh 			ct->ct_size = ct->ct_assoc *
37167dee861bSksadhukh 			    (CPI_CACHE_PARTS(cpi->cpi_std_4[i]) + 1) *
37177dee861bSksadhukh 			    ct->ct_line_size *
37187dee861bSksadhukh 			    (cpi->cpi_std_4[i]->cp_ecx + 1);
37197dee861bSksadhukh 
37207dee861bSksadhukh 			if (level == 2) {
37217dee861bSksadhukh 				ct->ct_label = l2_cache_str;
37227dee861bSksadhukh 			} else if (level == 3) {
37237dee861bSksadhukh 				ct->ct_label = l3_cache_str;
37247dee861bSksadhukh 			}
37257dee861bSksadhukh 			ret = 1;
37267dee861bSksadhukh 		}
37277dee861bSksadhukh 	}
37287dee861bSksadhukh 
37297dee861bSksadhukh 	return (ret);
37307dee861bSksadhukh }
37317dee861bSksadhukh 
37327dee861bSksadhukh /*
37337c478bd9Sstevel@tonic-gate  * Walk the cacheinfo descriptor, applying 'func' to every valid element
37347c478bd9Sstevel@tonic-gate  * The walk is terminated if the walker returns non-zero.
37357c478bd9Sstevel@tonic-gate  */
37367c478bd9Sstevel@tonic-gate static void
37377c478bd9Sstevel@tonic-gate intel_walk_cacheinfo(struct cpuid_info *cpi,
37387c478bd9Sstevel@tonic-gate     void *arg, int (*func)(void *, const struct cachetab *))
37397c478bd9Sstevel@tonic-gate {
37407c478bd9Sstevel@tonic-gate 	const struct cachetab *ct;
3741824e4fecSvd224797 	struct cachetab des_49_ct, des_b1_ct;
37427c478bd9Sstevel@tonic-gate 	uint8_t *dp;
37437c478bd9Sstevel@tonic-gate 	int i;
37447c478bd9Sstevel@tonic-gate 
37457c478bd9Sstevel@tonic-gate 	if ((dp = cpi->cpi_cacheinfo) == NULL)
37467c478bd9Sstevel@tonic-gate 		return;
3747f1d742a9Sksadhukh 	for (i = 0; i < cpi->cpi_ncache; i++, dp++) {
3748f1d742a9Sksadhukh 		/*
3749f1d742a9Sksadhukh 		 * For overloaded descriptor 0x49 we use cpuid function 4
37507dee861bSksadhukh 		 * if supported by the current processor, to create
3751f1d742a9Sksadhukh 		 * cache information.
3752824e4fecSvd224797 		 * For overloaded descriptor 0xb1 we use X86_PAE flag
3753824e4fecSvd224797 		 * to disambiguate the cache information.
3754f1d742a9Sksadhukh 		 */
37557dee861bSksadhukh 		if (*dp == 0x49 && cpi->cpi_maxeax >= 0x4 &&
37567dee861bSksadhukh 		    intel_cpuid_4_cache_info(&des_49_ct, cpi) == 1) {
37577dee861bSksadhukh 				ct = &des_49_ct;
3758824e4fecSvd224797 		} else if (*dp == 0xb1) {
3759824e4fecSvd224797 			des_b1_ct.ct_code = 0xb1;
3760824e4fecSvd224797 			des_b1_ct.ct_assoc = 4;
3761824e4fecSvd224797 			des_b1_ct.ct_line_size = 0;
37627417cfdeSKuriakose Kuruvilla 			if (is_x86_feature(x86_featureset, X86FSET_PAE)) {
3763824e4fecSvd224797 				des_b1_ct.ct_size = 8;
3764824e4fecSvd224797 				des_b1_ct.ct_label = itlb2M_str;
3765824e4fecSvd224797 			} else {
3766824e4fecSvd224797 				des_b1_ct.ct_size = 4;
3767824e4fecSvd224797 				des_b1_ct.ct_label = itlb4M_str;
3768824e4fecSvd224797 			}
3769824e4fecSvd224797 			ct = &des_b1_ct;
37707dee861bSksadhukh 		} else {
37717dee861bSksadhukh 			if ((ct = find_cacheent(intel_ctab, *dp)) == NULL) {
3772f1d742a9Sksadhukh 				continue;
3773f1d742a9Sksadhukh 			}
37747dee861bSksadhukh 		}
3775f1d742a9Sksadhukh 
37767dee861bSksadhukh 		if (func(arg, ct) != 0) {
37777c478bd9Sstevel@tonic-gate 			break;
37787c478bd9Sstevel@tonic-gate 		}
37797c478bd9Sstevel@tonic-gate 	}
3780f1d742a9Sksadhukh }
37817c478bd9Sstevel@tonic-gate 
37827c478bd9Sstevel@tonic-gate /*
37837c478bd9Sstevel@tonic-gate  * (Like the Intel one, except for Cyrix CPUs)
37847c478bd9Sstevel@tonic-gate  */
37857c478bd9Sstevel@tonic-gate static void
37867c478bd9Sstevel@tonic-gate cyrix_walk_cacheinfo(struct cpuid_info *cpi,
37877c478bd9Sstevel@tonic-gate     void *arg, int (*func)(void *, const struct cachetab *))
37887c478bd9Sstevel@tonic-gate {
37897c478bd9Sstevel@tonic-gate 	const struct cachetab *ct;
37907c478bd9Sstevel@tonic-gate 	uint8_t *dp;
37917c478bd9Sstevel@tonic-gate 	int i;
37927c478bd9Sstevel@tonic-gate 
37937c478bd9Sstevel@tonic-gate 	if ((dp = cpi->cpi_cacheinfo) == NULL)
37947c478bd9Sstevel@tonic-gate 		return;
37957c478bd9Sstevel@tonic-gate 	for (i = 0; i < cpi->cpi_ncache; i++, dp++) {
37967c478bd9Sstevel@tonic-gate 		/*
37977c478bd9Sstevel@tonic-gate 		 * Search Cyrix-specific descriptor table first ..
37987c478bd9Sstevel@tonic-gate 		 */
37997c478bd9Sstevel@tonic-gate 		if ((ct = find_cacheent(cyrix_ctab, *dp)) != NULL) {
38007c478bd9Sstevel@tonic-gate 			if (func(arg, ct) != 0)
38017c478bd9Sstevel@tonic-gate 				break;
38027c478bd9Sstevel@tonic-gate 			continue;
38037c478bd9Sstevel@tonic-gate 		}
38047c478bd9Sstevel@tonic-gate 		/*
38057c478bd9Sstevel@tonic-gate 		 * .. else fall back to the Intel one
38067c478bd9Sstevel@tonic-gate 		 */
38077c478bd9Sstevel@tonic-gate 		if ((ct = find_cacheent(intel_ctab, *dp)) != NULL) {
38087c478bd9Sstevel@tonic-gate 			if (func(arg, ct) != 0)
38097c478bd9Sstevel@tonic-gate 				break;
38107c478bd9Sstevel@tonic-gate 			continue;
38117c478bd9Sstevel@tonic-gate 		}
38127c478bd9Sstevel@tonic-gate 	}
38137c478bd9Sstevel@tonic-gate }
38147c478bd9Sstevel@tonic-gate 
38157c478bd9Sstevel@tonic-gate /*
38167c478bd9Sstevel@tonic-gate  * A cacheinfo walker that adds associativity, line-size, and size properties
38177c478bd9Sstevel@tonic-gate  * to the devinfo node it is passed as an argument.
38187c478bd9Sstevel@tonic-gate  */
38197c478bd9Sstevel@tonic-gate static int
38207c478bd9Sstevel@tonic-gate add_cacheent_props(void *arg, const struct cachetab *ct)
38217c478bd9Sstevel@tonic-gate {
38227c478bd9Sstevel@tonic-gate 	dev_info_t *devi = arg;
38237c478bd9Sstevel@tonic-gate 
38247c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, ct->ct_label, assoc_str, ct->ct_assoc);
38257c478bd9Sstevel@tonic-gate 	if (ct->ct_line_size != 0)
38267c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, ct->ct_label, line_str,
38277c478bd9Sstevel@tonic-gate 		    ct->ct_line_size);
38287c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, ct->ct_label, size_str, ct->ct_size);
38297c478bd9Sstevel@tonic-gate 	return (0);
38307c478bd9Sstevel@tonic-gate }
38317c478bd9Sstevel@tonic-gate 
3832f1d742a9Sksadhukh 
38337c478bd9Sstevel@tonic-gate static const char fully_assoc[] = "fully-associative?";
38347c478bd9Sstevel@tonic-gate 
38357c478bd9Sstevel@tonic-gate /*
38367c478bd9Sstevel@tonic-gate  * AMD style cache/tlb description
38377c478bd9Sstevel@tonic-gate  *
38387c478bd9Sstevel@tonic-gate  * Extended functions 5 and 6 directly describe properties of
38397c478bd9Sstevel@tonic-gate  * tlbs and various cache levels.
38407c478bd9Sstevel@tonic-gate  */
38417c478bd9Sstevel@tonic-gate static void
38427c478bd9Sstevel@tonic-gate add_amd_assoc(dev_info_t *devi, const char *label, uint_t assoc)
38437c478bd9Sstevel@tonic-gate {
38447c478bd9Sstevel@tonic-gate 	switch (assoc) {
38457c478bd9Sstevel@tonic-gate 	case 0:	/* reserved; ignore */
38467c478bd9Sstevel@tonic-gate 		break;
38477c478bd9Sstevel@tonic-gate 	default:
38487c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, assoc_str, assoc);
38497c478bd9Sstevel@tonic-gate 		break;
38507c478bd9Sstevel@tonic-gate 	case 0xff:
38517c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, fully_assoc, 1);
38527c478bd9Sstevel@tonic-gate 		break;
38537c478bd9Sstevel@tonic-gate 	}
38547c478bd9Sstevel@tonic-gate }
38557c478bd9Sstevel@tonic-gate 
38567c478bd9Sstevel@tonic-gate static void
38577c478bd9Sstevel@tonic-gate add_amd_tlb(dev_info_t *devi, const char *label, uint_t assoc, uint_t size)
38587c478bd9Sstevel@tonic-gate {
38597c478bd9Sstevel@tonic-gate 	if (size == 0)
38607c478bd9Sstevel@tonic-gate 		return;
38617c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, size_str, size);
38627c478bd9Sstevel@tonic-gate 	add_amd_assoc(devi, label, assoc);
38637c478bd9Sstevel@tonic-gate }
38647c478bd9Sstevel@tonic-gate 
38657c478bd9Sstevel@tonic-gate static void
38667c478bd9Sstevel@tonic-gate add_amd_cache(dev_info_t *devi, const char *label,
38677c478bd9Sstevel@tonic-gate     uint_t size, uint_t assoc, uint_t lines_per_tag, uint_t line_size)
38687c478bd9Sstevel@tonic-gate {
38697c478bd9Sstevel@tonic-gate 	if (size == 0 || line_size == 0)
38707c478bd9Sstevel@tonic-gate 		return;
38717c478bd9Sstevel@tonic-gate 	add_amd_assoc(devi, label, assoc);
38727c478bd9Sstevel@tonic-gate 	/*
38737c478bd9Sstevel@tonic-gate 	 * Most AMD parts have a sectored cache. Multiple cache lines are
38747c478bd9Sstevel@tonic-gate 	 * associated with each tag. A sector consists of all cache lines
38757c478bd9Sstevel@tonic-gate 	 * associated with a tag. For example, the AMD K6-III has a sector
38767c478bd9Sstevel@tonic-gate 	 * size of 2 cache lines per tag.
38777c478bd9Sstevel@tonic-gate 	 */
38787c478bd9Sstevel@tonic-gate 	if (lines_per_tag != 0)
38797c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, "lines-per-tag", lines_per_tag);
38807c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, line_str, line_size);
38817c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, size_str, size * 1024);
38827c478bd9Sstevel@tonic-gate }
38837c478bd9Sstevel@tonic-gate 
38847c478bd9Sstevel@tonic-gate static void
38857c478bd9Sstevel@tonic-gate add_amd_l2_assoc(dev_info_t *devi, const char *label, uint_t assoc)
38867c478bd9Sstevel@tonic-gate {
38877c478bd9Sstevel@tonic-gate 	switch (assoc) {
38887c478bd9Sstevel@tonic-gate 	case 0:	/* off */
38897c478bd9Sstevel@tonic-gate 		break;
38907c478bd9Sstevel@tonic-gate 	case 1:
38917c478bd9Sstevel@tonic-gate 	case 2:
38927c478bd9Sstevel@tonic-gate 	case 4:
38937c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, assoc_str, assoc);
38947c478bd9Sstevel@tonic-gate 		break;
38957c478bd9Sstevel@tonic-gate 	case 6:
38967c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, assoc_str, 8);
38977c478bd9Sstevel@tonic-gate 		break;
38987c478bd9Sstevel@tonic-gate 	case 8:
38997c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, assoc_str, 16);
39007c478bd9Sstevel@tonic-gate 		break;
39017c478bd9Sstevel@tonic-gate 	case 0xf:
39027c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, fully_assoc, 1);
39037c478bd9Sstevel@tonic-gate 		break;
39047c478bd9Sstevel@tonic-gate 	default: /* reserved; ignore */
39057c478bd9Sstevel@tonic-gate 		break;
39067c478bd9Sstevel@tonic-gate 	}
39077c478bd9Sstevel@tonic-gate }
39087c478bd9Sstevel@tonic-gate 
39097c478bd9Sstevel@tonic-gate static void
39107c478bd9Sstevel@tonic-gate add_amd_l2_tlb(dev_info_t *devi, const char *label, uint_t assoc, uint_t size)
39117c478bd9Sstevel@tonic-gate {
39127c478bd9Sstevel@tonic-gate 	if (size == 0 || assoc == 0)
39137c478bd9Sstevel@tonic-gate 		return;
39147c478bd9Sstevel@tonic-gate 	add_amd_l2_assoc(devi, label, assoc);
39157c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, size_str, size);
39167c478bd9Sstevel@tonic-gate }
39177c478bd9Sstevel@tonic-gate 
39187c478bd9Sstevel@tonic-gate static void
39197c478bd9Sstevel@tonic-gate add_amd_l2_cache(dev_info_t *devi, const char *label,
39207c478bd9Sstevel@tonic-gate     uint_t size, uint_t assoc, uint_t lines_per_tag, uint_t line_size)
39217c478bd9Sstevel@tonic-gate {
39227c478bd9Sstevel@tonic-gate 	if (size == 0 || assoc == 0 || line_size == 0)
39237c478bd9Sstevel@tonic-gate 		return;
39247c478bd9Sstevel@tonic-gate 	add_amd_l2_assoc(devi, label, assoc);
39257c478bd9Sstevel@tonic-gate 	if (lines_per_tag != 0)
39267c478bd9Sstevel@tonic-gate 		add_cache_prop(devi, label, "lines-per-tag", lines_per_tag);
39277c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, line_str, line_size);
39287c478bd9Sstevel@tonic-gate 	add_cache_prop(devi, label, size_str, size * 1024);
39297c478bd9Sstevel@tonic-gate }
39307c478bd9Sstevel@tonic-gate 
39317c478bd9Sstevel@tonic-gate static void
39327c478bd9Sstevel@tonic-gate amd_cache_info(struct cpuid_info *cpi, dev_info_t *devi)
39337c478bd9Sstevel@tonic-gate {
39348949bcd6Sandrei 	struct cpuid_regs *cp;
39357c478bd9Sstevel@tonic-gate 
39367c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax < 0x80000005)
39377c478bd9Sstevel@tonic-gate 		return;
39387c478bd9Sstevel@tonic-gate 	cp = &cpi->cpi_extd[5];
39397c478bd9Sstevel@tonic-gate 
39407c478bd9Sstevel@tonic-gate 	/*
39417c478bd9Sstevel@tonic-gate 	 * 4M/2M L1 TLB configuration
39427c478bd9Sstevel@tonic-gate 	 *
39437c478bd9Sstevel@tonic-gate 	 * We report the size for 2M pages because AMD uses two
39447c478bd9Sstevel@tonic-gate 	 * TLB entries for one 4M page.
39457c478bd9Sstevel@tonic-gate 	 */
39467c478bd9Sstevel@tonic-gate 	add_amd_tlb(devi, "dtlb-2M",
39477c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_eax, 31, 24), BITX(cp->cp_eax, 23, 16));
39487c478bd9Sstevel@tonic-gate 	add_amd_tlb(devi, "itlb-2M",
39497c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_eax, 15, 8), BITX(cp->cp_eax, 7, 0));
39507c478bd9Sstevel@tonic-gate 
39517c478bd9Sstevel@tonic-gate 	/*
39527c478bd9Sstevel@tonic-gate 	 * 4K L1 TLB configuration
39537c478bd9Sstevel@tonic-gate 	 */
39547c478bd9Sstevel@tonic-gate 
39557c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
39567c478bd9Sstevel@tonic-gate 		uint_t nentries;
39577c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
39587c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family >= 5) {
39597c478bd9Sstevel@tonic-gate 			/*
39607c478bd9Sstevel@tonic-gate 			 * Crusoe processors have 256 TLB entries, but
39617c478bd9Sstevel@tonic-gate 			 * cpuid data format constrains them to only
39627c478bd9Sstevel@tonic-gate 			 * reporting 255 of them.
39637c478bd9Sstevel@tonic-gate 			 */
39647c478bd9Sstevel@tonic-gate 			if ((nentries = BITX(cp->cp_ebx, 23, 16)) == 255)
39657c478bd9Sstevel@tonic-gate 				nentries = 256;
39667c478bd9Sstevel@tonic-gate 			/*
39677c478bd9Sstevel@tonic-gate 			 * Crusoe processors also have a unified TLB
39687c478bd9Sstevel@tonic-gate 			 */
39697c478bd9Sstevel@tonic-gate 			add_amd_tlb(devi, "tlb-4K", BITX(cp->cp_ebx, 31, 24),
39707c478bd9Sstevel@tonic-gate 			    nentries);
39717c478bd9Sstevel@tonic-gate 			break;
39727c478bd9Sstevel@tonic-gate 		}
39737c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
39747c478bd9Sstevel@tonic-gate 	default:
39757c478bd9Sstevel@tonic-gate 		add_amd_tlb(devi, itlb4k_str,
39767c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_ebx, 31, 24), BITX(cp->cp_ebx, 23, 16));
39777c478bd9Sstevel@tonic-gate 		add_amd_tlb(devi, dtlb4k_str,
39787c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_ebx, 15, 8), BITX(cp->cp_ebx, 7, 0));
39797c478bd9Sstevel@tonic-gate 		break;
39807c478bd9Sstevel@tonic-gate 	}
39817c478bd9Sstevel@tonic-gate 
39827c478bd9Sstevel@tonic-gate 	/*
39837c478bd9Sstevel@tonic-gate 	 * data L1 cache configuration
39847c478bd9Sstevel@tonic-gate 	 */
39857c478bd9Sstevel@tonic-gate 
39867c478bd9Sstevel@tonic-gate 	add_amd_cache(devi, l1_dcache_str,
39877c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_ecx, 31, 24), BITX(cp->cp_ecx, 23, 16),
39887c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_ecx, 15, 8), BITX(cp->cp_ecx, 7, 0));
39897c478bd9Sstevel@tonic-gate 
39907c478bd9Sstevel@tonic-gate 	/*
39917c478bd9Sstevel@tonic-gate 	 * code L1 cache configuration
39927c478bd9Sstevel@tonic-gate 	 */
39937c478bd9Sstevel@tonic-gate 
39947c478bd9Sstevel@tonic-gate 	add_amd_cache(devi, l1_icache_str,
39957c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_edx, 31, 24), BITX(cp->cp_edx, 23, 16),
39967c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_edx, 15, 8), BITX(cp->cp_edx, 7, 0));
39977c478bd9Sstevel@tonic-gate 
39987c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax < 0x80000006)
39997c478bd9Sstevel@tonic-gate 		return;
40007c478bd9Sstevel@tonic-gate 	cp = &cpi->cpi_extd[6];
40017c478bd9Sstevel@tonic-gate 
40027c478bd9Sstevel@tonic-gate 	/* Check for a unified L2 TLB for large pages */
40037c478bd9Sstevel@tonic-gate 
40047c478bd9Sstevel@tonic-gate 	if (BITX(cp->cp_eax, 31, 16) == 0)
40057c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-tlb-2M",
40067c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0));
40077c478bd9Sstevel@tonic-gate 	else {
40087c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-dtlb-2M",
40097c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 31, 28), BITX(cp->cp_eax, 27, 16));
40107c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-itlb-2M",
40117c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0));
40127c478bd9Sstevel@tonic-gate 	}
40137c478bd9Sstevel@tonic-gate 
40147c478bd9Sstevel@tonic-gate 	/* Check for a unified L2 TLB for 4K pages */
40157c478bd9Sstevel@tonic-gate 
40167c478bd9Sstevel@tonic-gate 	if (BITX(cp->cp_ebx, 31, 16) == 0) {
40177c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-tlb-4K",
40187c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0));
40197c478bd9Sstevel@tonic-gate 	} else {
40207c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-dtlb-4K",
40217c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 31, 28), BITX(cp->cp_eax, 27, 16));
40227c478bd9Sstevel@tonic-gate 		add_amd_l2_tlb(devi, "l2-itlb-4K",
40237c478bd9Sstevel@tonic-gate 		    BITX(cp->cp_eax, 15, 12), BITX(cp->cp_eax, 11, 0));
40247c478bd9Sstevel@tonic-gate 	}
40257c478bd9Sstevel@tonic-gate 
40267c478bd9Sstevel@tonic-gate 	add_amd_l2_cache(devi, l2_cache_str,
40277c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_ecx, 31, 16), BITX(cp->cp_ecx, 15, 12),
40287c478bd9Sstevel@tonic-gate 	    BITX(cp->cp_ecx, 11, 8), BITX(cp->cp_ecx, 7, 0));
40297c478bd9Sstevel@tonic-gate }
40307c478bd9Sstevel@tonic-gate 
40317c478bd9Sstevel@tonic-gate /*
40327c478bd9Sstevel@tonic-gate  * There are two basic ways that the x86 world describes it cache
40337c478bd9Sstevel@tonic-gate  * and tlb architecture - Intel's way and AMD's way.
40347c478bd9Sstevel@tonic-gate  *
40357c478bd9Sstevel@tonic-gate  * Return which flavor of cache architecture we should use
40367c478bd9Sstevel@tonic-gate  */
40377c478bd9Sstevel@tonic-gate static int
40387c478bd9Sstevel@tonic-gate x86_which_cacheinfo(struct cpuid_info *cpi)
40397c478bd9Sstevel@tonic-gate {
40407c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
40417c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
40427c478bd9Sstevel@tonic-gate 		if (cpi->cpi_maxeax >= 2)
40437c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_Intel);
40447c478bd9Sstevel@tonic-gate 		break;
40457c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
40467c478bd9Sstevel@tonic-gate 		/*
40477c478bd9Sstevel@tonic-gate 		 * The K5 model 1 was the first part from AMD that reported
40487c478bd9Sstevel@tonic-gate 		 * cache sizes via extended cpuid functions.
40497c478bd9Sstevel@tonic-gate 		 */
40507c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family > 5 ||
40517c478bd9Sstevel@tonic-gate 		    (cpi->cpi_family == 5 && cpi->cpi_model >= 1))
40527c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_AMD);
40537c478bd9Sstevel@tonic-gate 		break;
40547c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
40557c478bd9Sstevel@tonic-gate 		if (cpi->cpi_family >= 5)
40567c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_AMD);
40577c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
40587c478bd9Sstevel@tonic-gate 	default:
40597c478bd9Sstevel@tonic-gate 		/*
40607c478bd9Sstevel@tonic-gate 		 * If they have extended CPU data for 0x80000005
40617c478bd9Sstevel@tonic-gate 		 * then we assume they have AMD-format cache
40627c478bd9Sstevel@tonic-gate 		 * information.
40637c478bd9Sstevel@tonic-gate 		 *
40647c478bd9Sstevel@tonic-gate 		 * If not, and the vendor happens to be Cyrix,
40657c478bd9Sstevel@tonic-gate 		 * then try our-Cyrix specific handler.
40667c478bd9Sstevel@tonic-gate 		 *
40677c478bd9Sstevel@tonic-gate 		 * If we're not Cyrix, then assume we're using Intel's
40687c478bd9Sstevel@tonic-gate 		 * table-driven format instead.
40697c478bd9Sstevel@tonic-gate 		 */
40707c478bd9Sstevel@tonic-gate 		if (cpi->cpi_xmaxeax >= 0x80000005)
40717c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_AMD);
40727c478bd9Sstevel@tonic-gate 		else if (cpi->cpi_vendor == X86_VENDOR_Cyrix)
40737c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_Cyrix);
40747c478bd9Sstevel@tonic-gate 		else if (cpi->cpi_maxeax >= 2)
40757c478bd9Sstevel@tonic-gate 			return (X86_VENDOR_Intel);
40767c478bd9Sstevel@tonic-gate 		break;
40777c478bd9Sstevel@tonic-gate 	}
40787c478bd9Sstevel@tonic-gate 	return (-1);
40797c478bd9Sstevel@tonic-gate }
40807c478bd9Sstevel@tonic-gate 
40817c478bd9Sstevel@tonic-gate void
4082fa96bd91SMichael Corcoran cpuid_set_cpu_properties(void *dip, processorid_t cpu_id,
4083fa96bd91SMichael Corcoran     struct cpuid_info *cpi)
40847c478bd9Sstevel@tonic-gate {
40857c478bd9Sstevel@tonic-gate 	dev_info_t *cpu_devi;
40867c478bd9Sstevel@tonic-gate 	int create;
40877c478bd9Sstevel@tonic-gate 
4088fa96bd91SMichael Corcoran 	cpu_devi = (dev_info_t *)dip;
40897c478bd9Sstevel@tonic-gate 
40907c478bd9Sstevel@tonic-gate 	/* device_type */
40917c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, cpu_devi,
40927c478bd9Sstevel@tonic-gate 	    "device_type", "cpu");
40937c478bd9Sstevel@tonic-gate 
40947c478bd9Sstevel@tonic-gate 	/* reg */
40957c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
40967c478bd9Sstevel@tonic-gate 	    "reg", cpu_id);
40977c478bd9Sstevel@tonic-gate 
40987c478bd9Sstevel@tonic-gate 	/* cpu-mhz, and clock-frequency */
40997c478bd9Sstevel@tonic-gate 	if (cpu_freq > 0) {
41007c478bd9Sstevel@tonic-gate 		long long mul;
41017c478bd9Sstevel@tonic-gate 
41027c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
41037c478bd9Sstevel@tonic-gate 		    "cpu-mhz", cpu_freq);
41047c478bd9Sstevel@tonic-gate 		if ((mul = cpu_freq * 1000000LL) <= INT_MAX)
41057c478bd9Sstevel@tonic-gate 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
41067c478bd9Sstevel@tonic-gate 			    "clock-frequency", (int)mul);
41077c478bd9Sstevel@tonic-gate 	}
41087c478bd9Sstevel@tonic-gate 
41097417cfdeSKuriakose Kuruvilla 	if (!is_x86_feature(x86_featureset, X86FSET_CPUID)) {
41107c478bd9Sstevel@tonic-gate 		return;
41117c478bd9Sstevel@tonic-gate 	}
41127c478bd9Sstevel@tonic-gate 
41137c478bd9Sstevel@tonic-gate 	/* vendor-id */
41147c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, cpu_devi,
41157c478bd9Sstevel@tonic-gate 	    "vendor-id", cpi->cpi_vendorstr);
41167c478bd9Sstevel@tonic-gate 
41177c478bd9Sstevel@tonic-gate 	if (cpi->cpi_maxeax == 0) {
41187c478bd9Sstevel@tonic-gate 		return;
41197c478bd9Sstevel@tonic-gate 	}
41207c478bd9Sstevel@tonic-gate 
41217c478bd9Sstevel@tonic-gate 	/*
41227c478bd9Sstevel@tonic-gate 	 * family, model, and step
41237c478bd9Sstevel@tonic-gate 	 */
41247c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
41257c478bd9Sstevel@tonic-gate 	    "family", CPI_FAMILY(cpi));
41267c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
41277c478bd9Sstevel@tonic-gate 	    "cpu-model", CPI_MODEL(cpi));
41287c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
41297c478bd9Sstevel@tonic-gate 	    "stepping-id", CPI_STEP(cpi));
41307c478bd9Sstevel@tonic-gate 
41317c478bd9Sstevel@tonic-gate 	/* type */
41327c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
41337c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
41347c478bd9Sstevel@tonic-gate 		create = 1;
41357c478bd9Sstevel@tonic-gate 		break;
41367c478bd9Sstevel@tonic-gate 	default:
41377c478bd9Sstevel@tonic-gate 		create = 0;
41387c478bd9Sstevel@tonic-gate 		break;
41397c478bd9Sstevel@tonic-gate 	}
41407c478bd9Sstevel@tonic-gate 	if (create)
41417c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
41427c478bd9Sstevel@tonic-gate 		    "type", CPI_TYPE(cpi));
41437c478bd9Sstevel@tonic-gate 
41447c478bd9Sstevel@tonic-gate 	/* ext-family */
41457c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
41467c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
41477c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
41487c478bd9Sstevel@tonic-gate 		create = cpi->cpi_family >= 0xf;
41497c478bd9Sstevel@tonic-gate 		break;
41507c478bd9Sstevel@tonic-gate 	default:
41517c478bd9Sstevel@tonic-gate 		create = 0;
41527c478bd9Sstevel@tonic-gate 		break;
41537c478bd9Sstevel@tonic-gate 	}
41547c478bd9Sstevel@tonic-gate 	if (create)
41557c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
41567c478bd9Sstevel@tonic-gate 		    "ext-family", CPI_FAMILY_XTD(cpi));
41577c478bd9Sstevel@tonic-gate 
41587c478bd9Sstevel@tonic-gate 	/* ext-model */
41597c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
41607c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
416163d3f7dfSkk208521 		create = IS_EXTENDED_MODEL_INTEL(cpi);
416268c91426Sdmick 		break;
41637c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
4164ee88d2b9Skchow 		create = CPI_FAMILY(cpi) == 0xf;
41657c478bd9Sstevel@tonic-gate 		break;
41667c478bd9Sstevel@tonic-gate 	default:
41677c478bd9Sstevel@tonic-gate 		create = 0;
41687c478bd9Sstevel@tonic-gate 		break;
41697c478bd9Sstevel@tonic-gate 	}
41707c478bd9Sstevel@tonic-gate 	if (create)
41717c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
41727c478bd9Sstevel@tonic-gate 		    "ext-model", CPI_MODEL_XTD(cpi));
41737c478bd9Sstevel@tonic-gate 
41747c478bd9Sstevel@tonic-gate 	/* generation */
41757c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
41767c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
41777c478bd9Sstevel@tonic-gate 		/*
41787c478bd9Sstevel@tonic-gate 		 * AMD K5 model 1 was the first part to support this
41797c478bd9Sstevel@tonic-gate 		 */
41807c478bd9Sstevel@tonic-gate 		create = cpi->cpi_xmaxeax >= 0x80000001;
41817c478bd9Sstevel@tonic-gate 		break;
41827c478bd9Sstevel@tonic-gate 	default:
41837c478bd9Sstevel@tonic-gate 		create = 0;
41847c478bd9Sstevel@tonic-gate 		break;
41857c478bd9Sstevel@tonic-gate 	}
41867c478bd9Sstevel@tonic-gate 	if (create)
41877c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
41887c478bd9Sstevel@tonic-gate 		    "generation", BITX((cpi)->cpi_extd[1].cp_eax, 11, 8));
41897c478bd9Sstevel@tonic-gate 
41907c478bd9Sstevel@tonic-gate 	/* brand-id */
41917c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
41927c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
41937c478bd9Sstevel@tonic-gate 		/*
41947c478bd9Sstevel@tonic-gate 		 * brand id first appeared on Pentium III Xeon model 8,
41957c478bd9Sstevel@tonic-gate 		 * and Celeron model 8 processors and Opteron
41967c478bd9Sstevel@tonic-gate 		 */
41977c478bd9Sstevel@tonic-gate 		create = cpi->cpi_family > 6 ||
41987c478bd9Sstevel@tonic-gate 		    (cpi->cpi_family == 6 && cpi->cpi_model >= 8);
41997c478bd9Sstevel@tonic-gate 		break;
42007c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
42017c478bd9Sstevel@tonic-gate 		create = cpi->cpi_family >= 0xf;
42027c478bd9Sstevel@tonic-gate 		break;
42037c478bd9Sstevel@tonic-gate 	default:
42047c478bd9Sstevel@tonic-gate 		create = 0;
42057c478bd9Sstevel@tonic-gate 		break;
42067c478bd9Sstevel@tonic-gate 	}
42077c478bd9Sstevel@tonic-gate 	if (create && cpi->cpi_brandid != 0) {
42087c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
42097c478bd9Sstevel@tonic-gate 		    "brand-id", cpi->cpi_brandid);
42107c478bd9Sstevel@tonic-gate 	}
42117c478bd9Sstevel@tonic-gate 
42127c478bd9Sstevel@tonic-gate 	/* chunks, and apic-id */
42137c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
42147c478bd9Sstevel@tonic-gate 		/*
42157c478bd9Sstevel@tonic-gate 		 * first available on Pentium IV and Opteron (K8)
42167c478bd9Sstevel@tonic-gate 		 */
42175ff02082Sdmick 	case X86_VENDOR_Intel:
42185ff02082Sdmick 		create = IS_NEW_F6(cpi) || cpi->cpi_family >= 0xf;
42195ff02082Sdmick 		break;
42205ff02082Sdmick 	case X86_VENDOR_AMD:
42217c478bd9Sstevel@tonic-gate 		create = cpi->cpi_family >= 0xf;
42227c478bd9Sstevel@tonic-gate 		break;
42237c478bd9Sstevel@tonic-gate 	default:
42247c478bd9Sstevel@tonic-gate 		create = 0;
42257c478bd9Sstevel@tonic-gate 		break;
42267c478bd9Sstevel@tonic-gate 	}
42277c478bd9Sstevel@tonic-gate 	if (create) {
42287c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
42297c478bd9Sstevel@tonic-gate 		    "chunks", CPI_CHUNKS(cpi));
42307c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
4231b6917abeSmishra 		    "apic-id", cpi->cpi_apicid);
42327aec1d6eScindi 		if (cpi->cpi_chipid >= 0) {
42337c478bd9Sstevel@tonic-gate 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
42347c478bd9Sstevel@tonic-gate 			    "chip#", cpi->cpi_chipid);
42357aec1d6eScindi 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
42367aec1d6eScindi 			    "clog#", cpi->cpi_clogid);
42377aec1d6eScindi 		}
42387c478bd9Sstevel@tonic-gate 	}
42397c478bd9Sstevel@tonic-gate 
42407c478bd9Sstevel@tonic-gate 	/* cpuid-features */
42417c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
42427c478bd9Sstevel@tonic-gate 	    "cpuid-features", CPI_FEATURES_EDX(cpi));
42437c478bd9Sstevel@tonic-gate 
42447c478bd9Sstevel@tonic-gate 
42457c478bd9Sstevel@tonic-gate 	/* cpuid-features-ecx */
42467c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
42477c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
42485ff02082Sdmick 		create = IS_NEW_F6(cpi) || cpi->cpi_family >= 0xf;
42497c478bd9Sstevel@tonic-gate 		break;
425063408480SHans Rosenfeld 	case X86_VENDOR_AMD:
425163408480SHans Rosenfeld 		create = cpi->cpi_family >= 0xf;
425263408480SHans Rosenfeld 		break;
42537c478bd9Sstevel@tonic-gate 	default:
42547c478bd9Sstevel@tonic-gate 		create = 0;
42557c478bd9Sstevel@tonic-gate 		break;
42567c478bd9Sstevel@tonic-gate 	}
42577c478bd9Sstevel@tonic-gate 	if (create)
42587c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
42597c478bd9Sstevel@tonic-gate 		    "cpuid-features-ecx", CPI_FEATURES_ECX(cpi));
42607c478bd9Sstevel@tonic-gate 
42617c478bd9Sstevel@tonic-gate 	/* ext-cpuid-features */
42627c478bd9Sstevel@tonic-gate 	switch (cpi->cpi_vendor) {
42635ff02082Sdmick 	case X86_VENDOR_Intel:
42647c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
42657c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
42667c478bd9Sstevel@tonic-gate 	case X86_VENDOR_TM:
42677c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Centaur:
42687c478bd9Sstevel@tonic-gate 		create = cpi->cpi_xmaxeax >= 0x80000001;
42697c478bd9Sstevel@tonic-gate 		break;
42707c478bd9Sstevel@tonic-gate 	default:
42717c478bd9Sstevel@tonic-gate 		create = 0;
42727c478bd9Sstevel@tonic-gate 		break;
42737c478bd9Sstevel@tonic-gate 	}
42745ff02082Sdmick 	if (create) {
42757c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
42767c478bd9Sstevel@tonic-gate 		    "ext-cpuid-features", CPI_FEATURES_XTD_EDX(cpi));
42775ff02082Sdmick 		(void) ndi_prop_update_int(DDI_DEV_T_NONE, cpu_devi,
42785ff02082Sdmick 		    "ext-cpuid-features-ecx", CPI_FEATURES_XTD_ECX(cpi));
42795ff02082Sdmick 	}
42807c478bd9Sstevel@tonic-gate 
42817c478bd9Sstevel@tonic-gate 	/*
42827c478bd9Sstevel@tonic-gate 	 * Brand String first appeared in Intel Pentium IV, AMD K5
42837c478bd9Sstevel@tonic-gate 	 * model 1, and Cyrix GXm.  On earlier models we try and
42847c478bd9Sstevel@tonic-gate 	 * simulate something similar .. so this string should always
42857c478bd9Sstevel@tonic-gate 	 * same -something- about the processor, however lame.
42867c478bd9Sstevel@tonic-gate 	 */
42877c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_string(DDI_DEV_T_NONE, cpu_devi,
42887c478bd9Sstevel@tonic-gate 	    "brand-string", cpi->cpi_brandstr);
42897c478bd9Sstevel@tonic-gate 
42907c478bd9Sstevel@tonic-gate 	/*
42917c478bd9Sstevel@tonic-gate 	 * Finally, cache and tlb information
42927c478bd9Sstevel@tonic-gate 	 */
42937c478bd9Sstevel@tonic-gate 	switch (x86_which_cacheinfo(cpi)) {
42947c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
42957c478bd9Sstevel@tonic-gate 		intel_walk_cacheinfo(cpi, cpu_devi, add_cacheent_props);
42967c478bd9Sstevel@tonic-gate 		break;
42977c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
42987c478bd9Sstevel@tonic-gate 		cyrix_walk_cacheinfo(cpi, cpu_devi, add_cacheent_props);
42997c478bd9Sstevel@tonic-gate 		break;
43007c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
43017c478bd9Sstevel@tonic-gate 		amd_cache_info(cpi, cpu_devi);
43027c478bd9Sstevel@tonic-gate 		break;
43037c478bd9Sstevel@tonic-gate 	default:
43047c478bd9Sstevel@tonic-gate 		break;
43057c478bd9Sstevel@tonic-gate 	}
43067c478bd9Sstevel@tonic-gate }
43077c478bd9Sstevel@tonic-gate 
43087c478bd9Sstevel@tonic-gate struct l2info {
43097c478bd9Sstevel@tonic-gate 	int *l2i_csz;
43107c478bd9Sstevel@tonic-gate 	int *l2i_lsz;
43117c478bd9Sstevel@tonic-gate 	int *l2i_assoc;
43127c478bd9Sstevel@tonic-gate 	int l2i_ret;
43137c478bd9Sstevel@tonic-gate };
43147c478bd9Sstevel@tonic-gate 
43157c478bd9Sstevel@tonic-gate /*
43167c478bd9Sstevel@tonic-gate  * A cacheinfo walker that fetches the size, line-size and associativity
43177c478bd9Sstevel@tonic-gate  * of the L2 cache
43187c478bd9Sstevel@tonic-gate  */
43197c478bd9Sstevel@tonic-gate static int
43207c478bd9Sstevel@tonic-gate intel_l2cinfo(void *arg, const struct cachetab *ct)
43217c478bd9Sstevel@tonic-gate {
43227c478bd9Sstevel@tonic-gate 	struct l2info *l2i = arg;
43237c478bd9Sstevel@tonic-gate 	int *ip;
43247c478bd9Sstevel@tonic-gate 
43257c478bd9Sstevel@tonic-gate 	if (ct->ct_label != l2_cache_str &&
43267c478bd9Sstevel@tonic-gate 	    ct->ct_label != sl2_cache_str)
43277c478bd9Sstevel@tonic-gate 		return (0);	/* not an L2 -- keep walking */
43287c478bd9Sstevel@tonic-gate 
43297c478bd9Sstevel@tonic-gate 	if ((ip = l2i->l2i_csz) != NULL)
43307c478bd9Sstevel@tonic-gate 		*ip = ct->ct_size;
43317c478bd9Sstevel@tonic-gate 	if ((ip = l2i->l2i_lsz) != NULL)
43327c478bd9Sstevel@tonic-gate 		*ip = ct->ct_line_size;
43337c478bd9Sstevel@tonic-gate 	if ((ip = l2i->l2i_assoc) != NULL)
43347c478bd9Sstevel@tonic-gate 		*ip = ct->ct_assoc;
43357c478bd9Sstevel@tonic-gate 	l2i->l2i_ret = ct->ct_size;
43367c478bd9Sstevel@tonic-gate 	return (1);		/* was an L2 -- terminate walk */
43377c478bd9Sstevel@tonic-gate }
43387c478bd9Sstevel@tonic-gate 
4339606303c9Skchow /*
4340606303c9Skchow  * AMD L2/L3 Cache and TLB Associativity Field Definition:
4341606303c9Skchow  *
4342606303c9Skchow  *	Unlike the associativity for the L1 cache and tlb where the 8 bit
4343606303c9Skchow  *	value is the associativity, the associativity for the L2 cache and
4344606303c9Skchow  *	tlb is encoded in the following table. The 4 bit L2 value serves as
4345606303c9Skchow  *	an index into the amd_afd[] array to determine the associativity.
4346606303c9Skchow  *	-1 is undefined. 0 is fully associative.
4347606303c9Skchow  */
4348606303c9Skchow 
4349606303c9Skchow static int amd_afd[] =
4350606303c9Skchow 	{-1, 1, 2, -1, 4, -1, 8, -1, 16, -1, 32, 48, 64, 96, 128, 0};
4351606303c9Skchow 
43527c478bd9Sstevel@tonic-gate static void
43537c478bd9Sstevel@tonic-gate amd_l2cacheinfo(struct cpuid_info *cpi, struct l2info *l2i)
43547c478bd9Sstevel@tonic-gate {
43558949bcd6Sandrei 	struct cpuid_regs *cp;
43567c478bd9Sstevel@tonic-gate 	uint_t size, assoc;
4357606303c9Skchow 	int i;
43587c478bd9Sstevel@tonic-gate 	int *ip;
43597c478bd9Sstevel@tonic-gate 
43607c478bd9Sstevel@tonic-gate 	if (cpi->cpi_xmaxeax < 0x80000006)
43617c478bd9Sstevel@tonic-gate 		return;
43627c478bd9Sstevel@tonic-gate 	cp = &cpi->cpi_extd[6];
43637c478bd9Sstevel@tonic-gate 
4364606303c9Skchow 	if ((i = BITX(cp->cp_ecx, 15, 12)) != 0 &&
43657c478bd9Sstevel@tonic-gate 	    (size = BITX(cp->cp_ecx, 31, 16)) != 0) {
43667c478bd9Sstevel@tonic-gate 		uint_t cachesz = size * 1024;
4367606303c9Skchow 		assoc = amd_afd[i];
43687c478bd9Sstevel@tonic-gate 
4369606303c9Skchow 		ASSERT(assoc != -1);
43707c478bd9Sstevel@tonic-gate 
43717c478bd9Sstevel@tonic-gate 		if ((ip = l2i->l2i_csz) != NULL)
43727c478bd9Sstevel@tonic-gate 			*ip = cachesz;
43737c478bd9Sstevel@tonic-gate 		if ((ip = l2i->l2i_lsz) != NULL)
43747c478bd9Sstevel@tonic-gate 			*ip = BITX(cp->cp_ecx, 7, 0);
43757c478bd9Sstevel@tonic-gate 		if ((ip = l2i->l2i_assoc) != NULL)
43767c478bd9Sstevel@tonic-gate 			*ip = assoc;
43777c478bd9Sstevel@tonic-gate 		l2i->l2i_ret = cachesz;
43787c478bd9Sstevel@tonic-gate 	}
43797c478bd9Sstevel@tonic-gate }
43807c478bd9Sstevel@tonic-gate 
43817c478bd9Sstevel@tonic-gate int
43827c478bd9Sstevel@tonic-gate getl2cacheinfo(cpu_t *cpu, int *csz, int *lsz, int *assoc)
43837c478bd9Sstevel@tonic-gate {
43847c478bd9Sstevel@tonic-gate 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
43857c478bd9Sstevel@tonic-gate 	struct l2info __l2info, *l2i = &__l2info;
43867c478bd9Sstevel@tonic-gate 
43877c478bd9Sstevel@tonic-gate 	l2i->l2i_csz = csz;
43887c478bd9Sstevel@tonic-gate 	l2i->l2i_lsz = lsz;
43897c478bd9Sstevel@tonic-gate 	l2i->l2i_assoc = assoc;
43907c478bd9Sstevel@tonic-gate 	l2i->l2i_ret = -1;
43917c478bd9Sstevel@tonic-gate 
43927c478bd9Sstevel@tonic-gate 	switch (x86_which_cacheinfo(cpi)) {
43937c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Intel:
43947c478bd9Sstevel@tonic-gate 		intel_walk_cacheinfo(cpi, l2i, intel_l2cinfo);
43957c478bd9Sstevel@tonic-gate 		break;
43967c478bd9Sstevel@tonic-gate 	case X86_VENDOR_Cyrix:
43977c478bd9Sstevel@tonic-gate 		cyrix_walk_cacheinfo(cpi, l2i, intel_l2cinfo);
43987c478bd9Sstevel@tonic-gate 		break;
43997c478bd9Sstevel@tonic-gate 	case X86_VENDOR_AMD:
44007c478bd9Sstevel@tonic-gate 		amd_l2cacheinfo(cpi, l2i);
44017c478bd9Sstevel@tonic-gate 		break;
44027c478bd9Sstevel@tonic-gate 	default:
44037c478bd9Sstevel@tonic-gate 		break;
44047c478bd9Sstevel@tonic-gate 	}
44057c478bd9Sstevel@tonic-gate 	return (l2i->l2i_ret);
44067c478bd9Sstevel@tonic-gate }
4407f98fbcecSbholler 
4408843e1988Sjohnlev #if !defined(__xpv)
4409843e1988Sjohnlev 
44105b8a6efeSbholler uint32_t *
44115b8a6efeSbholler cpuid_mwait_alloc(cpu_t *cpu)
44125b8a6efeSbholler {
44135b8a6efeSbholler 	uint32_t	*ret;
44145b8a6efeSbholler 	size_t		mwait_size;
44155b8a6efeSbholler 
4416a3114836SGerry Liu 	ASSERT(cpuid_checkpass(CPU, 2));
44175b8a6efeSbholler 
4418a3114836SGerry Liu 	mwait_size = CPU->cpu_m.mcpu_cpi->cpi_mwait.mon_max;
44195b8a6efeSbholler 	if (mwait_size == 0)
44205b8a6efeSbholler 		return (NULL);
44215b8a6efeSbholler 
44225b8a6efeSbholler 	/*
44235b8a6efeSbholler 	 * kmem_alloc() returns cache line size aligned data for mwait_size
44245b8a6efeSbholler 	 * allocations.  mwait_size is currently cache line sized.  Neither
44255b8a6efeSbholler 	 * of these implementation details are guarantied to be true in the
44265b8a6efeSbholler 	 * future.
44275b8a6efeSbholler 	 *
44285b8a6efeSbholler 	 * First try allocating mwait_size as kmem_alloc() currently returns
44295b8a6efeSbholler 	 * correctly aligned memory.  If kmem_alloc() does not return
44305b8a6efeSbholler 	 * mwait_size aligned memory, then use mwait_size ROUNDUP.
44315b8a6efeSbholler 	 *
44325b8a6efeSbholler 	 * Set cpi_mwait.buf_actual and cpi_mwait.size_actual in case we
44335b8a6efeSbholler 	 * decide to free this memory.
44345b8a6efeSbholler 	 */
44355b8a6efeSbholler 	ret = kmem_zalloc(mwait_size, KM_SLEEP);
44365b8a6efeSbholler 	if (ret == (uint32_t *)P2ROUNDUP((uintptr_t)ret, mwait_size)) {
44375b8a6efeSbholler 		cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual = ret;
44385b8a6efeSbholler 		cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual = mwait_size;
44395b8a6efeSbholler 		*ret = MWAIT_RUNNING;
44405b8a6efeSbholler 		return (ret);
44415b8a6efeSbholler 	} else {
44425b8a6efeSbholler 		kmem_free(ret, mwait_size);
44435b8a6efeSbholler 		ret = kmem_zalloc(mwait_size * 2, KM_SLEEP);
44445b8a6efeSbholler 		cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual = ret;
44455b8a6efeSbholler 		cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual = mwait_size * 2;
44465b8a6efeSbholler 		ret = (uint32_t *)P2ROUNDUP((uintptr_t)ret, mwait_size);
44475b8a6efeSbholler 		*ret = MWAIT_RUNNING;
44485b8a6efeSbholler 		return (ret);
44495b8a6efeSbholler 	}
44505b8a6efeSbholler }
44515b8a6efeSbholler 
44525b8a6efeSbholler void
44535b8a6efeSbholler cpuid_mwait_free(cpu_t *cpu)
4454f98fbcecSbholler {
4455a3114836SGerry Liu 	if (cpu->cpu_m.mcpu_cpi == NULL) {
4456a3114836SGerry Liu 		return;
4457a3114836SGerry Liu 	}
44585b8a6efeSbholler 
44595b8a6efeSbholler 	if (cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual != NULL &&
44605b8a6efeSbholler 	    cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual > 0) {
44615b8a6efeSbholler 		kmem_free(cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual,
44625b8a6efeSbholler 		    cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual);
44635b8a6efeSbholler 	}
44645b8a6efeSbholler 
44655b8a6efeSbholler 	cpu->cpu_m.mcpu_cpi->cpi_mwait.buf_actual = NULL;
44665b8a6efeSbholler 	cpu->cpu_m.mcpu_cpi->cpi_mwait.size_actual = 0;
4467f98fbcecSbholler }
4468843e1988Sjohnlev 
4469247dbb3dSsudheer void
4470247dbb3dSsudheer patch_tsc_read(int flag)
4471247dbb3dSsudheer {
4472247dbb3dSsudheer 	size_t cnt;
4473e4b86885SCheng Sean Ye 
4474247dbb3dSsudheer 	switch (flag) {
4475247dbb3dSsudheer 	case X86_NO_TSC:
4476247dbb3dSsudheer 		cnt = &_no_rdtsc_end - &_no_rdtsc_start;
44772b0bcb26Ssudheer 		(void) memcpy((void *)tsc_read, (void *)&_no_rdtsc_start, cnt);
4478247dbb3dSsudheer 		break;
4479247dbb3dSsudheer 	case X86_HAVE_TSCP:
4480247dbb3dSsudheer 		cnt = &_tscp_end - &_tscp_start;
44812b0bcb26Ssudheer 		(void) memcpy((void *)tsc_read, (void *)&_tscp_start, cnt);
4482247dbb3dSsudheer 		break;
4483247dbb3dSsudheer 	case X86_TSC_MFENCE:
4484247dbb3dSsudheer 		cnt = &_tsc_mfence_end - &_tsc_mfence_start;
44852b0bcb26Ssudheer 		(void) memcpy((void *)tsc_read,
44862b0bcb26Ssudheer 		    (void *)&_tsc_mfence_start, cnt);
4487247dbb3dSsudheer 		break;
448815363b27Ssudheer 	case X86_TSC_LFENCE:
448915363b27Ssudheer 		cnt = &_tsc_lfence_end - &_tsc_lfence_start;
449015363b27Ssudheer 		(void) memcpy((void *)tsc_read,
449115363b27Ssudheer 		    (void *)&_tsc_lfence_start, cnt);
449215363b27Ssudheer 		break;
4493247dbb3dSsudheer 	default:
4494247dbb3dSsudheer 		break;
4495247dbb3dSsudheer 	}
4496247dbb3dSsudheer }
4497247dbb3dSsudheer 
44980e751525SEric Saxe int
44990e751525SEric Saxe cpuid_deep_cstates_supported(void)
45000e751525SEric Saxe {
45010e751525SEric Saxe 	struct cpuid_info *cpi;
45020e751525SEric Saxe 	struct cpuid_regs regs;
45030e751525SEric Saxe 
45040e751525SEric Saxe 	ASSERT(cpuid_checkpass(CPU, 1));
45050e751525SEric Saxe 
45060e751525SEric Saxe 	cpi = CPU->cpu_m.mcpu_cpi;
45070e751525SEric Saxe 
45087417cfdeSKuriakose Kuruvilla 	if (!is_x86_feature(x86_featureset, X86FSET_CPUID))
45090e751525SEric Saxe 		return (0);
45100e751525SEric Saxe 
45110e751525SEric Saxe 	switch (cpi->cpi_vendor) {
45120e751525SEric Saxe 	case X86_VENDOR_Intel:
45130e751525SEric Saxe 		if (cpi->cpi_xmaxeax < 0x80000007)
45140e751525SEric Saxe 			return (0);
45150e751525SEric Saxe 
45160e751525SEric Saxe 		/*
45170e751525SEric Saxe 		 * TSC run at a constant rate in all ACPI C-states?
45180e751525SEric Saxe 		 */
45190e751525SEric Saxe 		regs.cp_eax = 0x80000007;
45200e751525SEric Saxe 		(void) __cpuid_insn(&regs);
45210e751525SEric Saxe 		return (regs.cp_edx & CPUID_TSC_CSTATE_INVARIANCE);
45220e751525SEric Saxe 
45230e751525SEric Saxe 	default:
45240e751525SEric Saxe 		return (0);
45250e751525SEric Saxe 	}
45260e751525SEric Saxe }
45270e751525SEric Saxe 
4528e774b42bSBill Holler #endif	/* !__xpv */
4529e774b42bSBill Holler 
4530e774b42bSBill Holler void
4531e774b42bSBill Holler post_startup_cpu_fixups(void)
4532e774b42bSBill Holler {
4533e774b42bSBill Holler #ifndef __xpv
4534e774b42bSBill Holler 	/*
4535e774b42bSBill Holler 	 * Some AMD processors support C1E state. Entering this state will
4536e774b42bSBill Holler 	 * cause the local APIC timer to stop, which we can't deal with at
4537e774b42bSBill Holler 	 * this time.
4538e774b42bSBill Holler 	 */
4539e774b42bSBill Holler 	if (cpuid_getvendor(CPU) == X86_VENDOR_AMD) {
4540e774b42bSBill Holler 		on_trap_data_t otd;
4541e774b42bSBill Holler 		uint64_t reg;
4542e774b42bSBill Holler 
4543e774b42bSBill Holler 		if (!on_trap(&otd, OT_DATA_ACCESS)) {
4544e774b42bSBill Holler 			reg = rdmsr(MSR_AMD_INT_PENDING_CMP_HALT);
4545e774b42bSBill Holler 			/* Disable C1E state if it is enabled by BIOS */
4546e774b42bSBill Holler 			if ((reg >> AMD_ACTONCMPHALT_SHIFT) &
4547e774b42bSBill Holler 			    AMD_ACTONCMPHALT_MASK) {
4548e774b42bSBill Holler 				reg &= ~(AMD_ACTONCMPHALT_MASK <<
4549e774b42bSBill Holler 				    AMD_ACTONCMPHALT_SHIFT);
4550e774b42bSBill Holler 				wrmsr(MSR_AMD_INT_PENDING_CMP_HALT, reg);
4551e774b42bSBill Holler 			}
4552e774b42bSBill Holler 		}
4553e774b42bSBill Holler 		no_trap();
4554e774b42bSBill Holler 	}
4555e774b42bSBill Holler #endif	/* !__xpv */
4556e774b42bSBill Holler }
4557e774b42bSBill Holler 
4558cef70d2cSBill Holler /*
45597af88ac7SKuriakose Kuruvilla  * Setup necessary registers to enable XSAVE feature on this processor.
45607af88ac7SKuriakose Kuruvilla  * This function needs to be called early enough, so that no xsave/xrstor
45617af88ac7SKuriakose Kuruvilla  * ops will execute on the processor before the MSRs are properly set up.
45627af88ac7SKuriakose Kuruvilla  *
45637af88ac7SKuriakose Kuruvilla  * Current implementation has the following assumption:
45647af88ac7SKuriakose Kuruvilla  * - cpuid_pass1() is done, so that X86 features are known.
45657af88ac7SKuriakose Kuruvilla  * - fpu_probe() is done, so that fp_save_mech is chosen.
45667af88ac7SKuriakose Kuruvilla  */
45677af88ac7SKuriakose Kuruvilla void
45687af88ac7SKuriakose Kuruvilla xsave_setup_msr(cpu_t *cpu)
45697af88ac7SKuriakose Kuruvilla {
45707af88ac7SKuriakose Kuruvilla 	ASSERT(fp_save_mech == FP_XSAVE);
45717af88ac7SKuriakose Kuruvilla 	ASSERT(is_x86_feature(x86_featureset, X86FSET_XSAVE));
45727af88ac7SKuriakose Kuruvilla 
45737af88ac7SKuriakose Kuruvilla 	/* Enable OSXSAVE in CR4. */
45747af88ac7SKuriakose Kuruvilla 	setcr4(getcr4() | CR4_OSXSAVE);
45757af88ac7SKuriakose Kuruvilla 	/*
45767af88ac7SKuriakose Kuruvilla 	 * Update SW copy of ECX, so that /dev/cpu/self/cpuid will report
45777af88ac7SKuriakose Kuruvilla 	 * correct value.
45787af88ac7SKuriakose Kuruvilla 	 */
45797af88ac7SKuriakose Kuruvilla 	cpu->cpu_m.mcpu_cpi->cpi_std[1].cp_ecx |= CPUID_INTC_ECX_OSXSAVE;
45807af88ac7SKuriakose Kuruvilla 	setup_xfem();
45817af88ac7SKuriakose Kuruvilla }
45827af88ac7SKuriakose Kuruvilla 
45837af88ac7SKuriakose Kuruvilla /*
4584cef70d2cSBill Holler  * Starting with the Westmere processor the local
4585cef70d2cSBill Holler  * APIC timer will continue running in all C-states,
4586cef70d2cSBill Holler  * including the deepest C-states.
4587cef70d2cSBill Holler  */
4588cef70d2cSBill Holler int
4589cef70d2cSBill Holler cpuid_arat_supported(void)
4590cef70d2cSBill Holler {
4591cef70d2cSBill Holler 	struct cpuid_info *cpi;
4592cef70d2cSBill Holler 	struct cpuid_regs regs;
4593cef70d2cSBill Holler 
4594cef70d2cSBill Holler 	ASSERT(cpuid_checkpass(CPU, 1));
45957417cfdeSKuriakose Kuruvilla 	ASSERT(is_x86_feature(x86_featureset, X86FSET_CPUID));
4596cef70d2cSBill Holler 
4597cef70d2cSBill Holler 	cpi = CPU->cpu_m.mcpu_cpi;
4598cef70d2cSBill Holler 
4599cef70d2cSBill Holler 	switch (cpi->cpi_vendor) {
4600cef70d2cSBill Holler 	case X86_VENDOR_Intel:
4601cef70d2cSBill Holler 		/*
4602cef70d2cSBill Holler 		 * Always-running Local APIC Timer is
4603cef70d2cSBill Holler 		 * indicated by CPUID.6.EAX[2].
4604cef70d2cSBill Holler 		 */
4605cef70d2cSBill Holler 		if (cpi->cpi_maxeax >= 6) {
4606cef70d2cSBill Holler 			regs.cp_eax = 6;
4607cef70d2cSBill Holler 			(void) cpuid_insn(NULL, &regs);
4608cef70d2cSBill Holler 			return (regs.cp_eax & CPUID_CSTATE_ARAT);
4609cef70d2cSBill Holler 		} else {
4610cef70d2cSBill Holler 			return (0);
4611cef70d2cSBill Holler 		}
4612cef70d2cSBill Holler 	default:
4613cef70d2cSBill Holler 		return (0);
4614cef70d2cSBill Holler 	}
4615cef70d2cSBill Holler }
4616cef70d2cSBill Holler 
4617f21ed392Saubrey.li@intel.com /*
4618f21ed392Saubrey.li@intel.com  * Check support for Intel ENERGY_PERF_BIAS feature
4619f21ed392Saubrey.li@intel.com  */
4620f21ed392Saubrey.li@intel.com int
4621f21ed392Saubrey.li@intel.com cpuid_iepb_supported(struct cpu *cp)
4622f21ed392Saubrey.li@intel.com {
4623f21ed392Saubrey.li@intel.com 	struct cpuid_info *cpi = cp->cpu_m.mcpu_cpi;
4624f21ed392Saubrey.li@intel.com 	struct cpuid_regs regs;
4625f21ed392Saubrey.li@intel.com 
4626f21ed392Saubrey.li@intel.com 	ASSERT(cpuid_checkpass(cp, 1));
4627f21ed392Saubrey.li@intel.com 
46287417cfdeSKuriakose Kuruvilla 	if (!(is_x86_feature(x86_featureset, X86FSET_CPUID)) ||
46297417cfdeSKuriakose Kuruvilla 	    !(is_x86_feature(x86_featureset, X86FSET_MSR))) {
4630f21ed392Saubrey.li@intel.com 		return (0);
4631f21ed392Saubrey.li@intel.com 	}
4632f21ed392Saubrey.li@intel.com 
4633f21ed392Saubrey.li@intel.com 	/*
4634f21ed392Saubrey.li@intel.com 	 * Intel ENERGY_PERF_BIAS MSR is indicated by
4635f21ed392Saubrey.li@intel.com 	 * capability bit CPUID.6.ECX.3
4636f21ed392Saubrey.li@intel.com 	 */
4637f21ed392Saubrey.li@intel.com 	if ((cpi->cpi_vendor != X86_VENDOR_Intel) || (cpi->cpi_maxeax < 6))
4638f21ed392Saubrey.li@intel.com 		return (0);
4639f21ed392Saubrey.li@intel.com 
4640f21ed392Saubrey.li@intel.com 	regs.cp_eax = 0x6;
4641f21ed392Saubrey.li@intel.com 	(void) cpuid_insn(NULL, &regs);
4642f21ed392Saubrey.li@intel.com 	return (regs.cp_ecx & CPUID_EPB_SUPPORT);
4643f21ed392Saubrey.li@intel.com }
4644f21ed392Saubrey.li@intel.com 
464541afdfa7SKrishnendu Sadhukhan - Sun Microsystems /*
464641afdfa7SKrishnendu Sadhukhan - Sun Microsystems  * Check support for TSC deadline timer
464741afdfa7SKrishnendu Sadhukhan - Sun Microsystems  *
464841afdfa7SKrishnendu Sadhukhan - Sun Microsystems  * TSC deadline timer provides a superior software programming
464941afdfa7SKrishnendu Sadhukhan - Sun Microsystems  * model over local APIC timer that eliminates "time drifts".
465041afdfa7SKrishnendu Sadhukhan - Sun Microsystems  * Instead of specifying a relative time, software specifies an
465141afdfa7SKrishnendu Sadhukhan - Sun Microsystems  * absolute time as the target at which the processor should
465241afdfa7SKrishnendu Sadhukhan - Sun Microsystems  * generate a timer event.
465341afdfa7SKrishnendu Sadhukhan - Sun Microsystems  */
465441afdfa7SKrishnendu Sadhukhan - Sun Microsystems int
465541afdfa7SKrishnendu Sadhukhan - Sun Microsystems cpuid_deadline_tsc_supported(void)
465641afdfa7SKrishnendu Sadhukhan - Sun Microsystems {
465741afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	struct cpuid_info *cpi = CPU->cpu_m.mcpu_cpi;
465841afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	struct cpuid_regs regs;
465941afdfa7SKrishnendu Sadhukhan - Sun Microsystems 
466041afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	ASSERT(cpuid_checkpass(CPU, 1));
466141afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	ASSERT(is_x86_feature(x86_featureset, X86FSET_CPUID));
466241afdfa7SKrishnendu Sadhukhan - Sun Microsystems 
466341afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	switch (cpi->cpi_vendor) {
466441afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	case X86_VENDOR_Intel:
466541afdfa7SKrishnendu Sadhukhan - Sun Microsystems 		if (cpi->cpi_maxeax >= 1) {
466641afdfa7SKrishnendu Sadhukhan - Sun Microsystems 			regs.cp_eax = 1;
466741afdfa7SKrishnendu Sadhukhan - Sun Microsystems 			(void) cpuid_insn(NULL, &regs);
466841afdfa7SKrishnendu Sadhukhan - Sun Microsystems 			return (regs.cp_ecx & CPUID_DEADLINE_TSC);
466941afdfa7SKrishnendu Sadhukhan - Sun Microsystems 		} else {
467041afdfa7SKrishnendu Sadhukhan - Sun Microsystems 			return (0);
467141afdfa7SKrishnendu Sadhukhan - Sun Microsystems 		}
467241afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	default:
467341afdfa7SKrishnendu Sadhukhan - Sun Microsystems 		return (0);
467441afdfa7SKrishnendu Sadhukhan - Sun Microsystems 	}
467541afdfa7SKrishnendu Sadhukhan - Sun Microsystems }
467641afdfa7SKrishnendu Sadhukhan - Sun Microsystems 
467722cc0e45SBill Holler #if defined(__amd64) && !defined(__xpv)
467822cc0e45SBill Holler /*
467922cc0e45SBill Holler  * Patch in versions of bcopy for high performance Intel Nhm processors
468022cc0e45SBill Holler  * and later...
468122cc0e45SBill Holler  */
468222cc0e45SBill Holler void
468322cc0e45SBill Holler patch_memops(uint_t vendor)
468422cc0e45SBill Holler {
468522cc0e45SBill Holler 	size_t cnt, i;
468622cc0e45SBill Holler 	caddr_t to, from;
468722cc0e45SBill Holler 
46887417cfdeSKuriakose Kuruvilla 	if ((vendor == X86_VENDOR_Intel) &&
46897417cfdeSKuriakose Kuruvilla 	    is_x86_feature(x86_featureset, X86FSET_SSE4_2)) {
469022cc0e45SBill Holler 		cnt = &bcopy_patch_end - &bcopy_patch_start;
469122cc0e45SBill Holler 		to = &bcopy_ck_size;
469222cc0e45SBill Holler 		from = &bcopy_patch_start;
469322cc0e45SBill Holler 		for (i = 0; i < cnt; i++) {
469422cc0e45SBill Holler 			*to++ = *from++;
469522cc0e45SBill Holler 		}
469622cc0e45SBill Holler 	}
469722cc0e45SBill Holler }
469822cc0e45SBill Holler #endif  /* __amd64 && !__xpv */
46992d2efdc6SVuong Nguyen 
47002d2efdc6SVuong Nguyen /*
47012d2efdc6SVuong Nguyen  * This function finds the number of bits to represent the number of cores per
47022d2efdc6SVuong Nguyen  * chip and the number of strands per core for the Intel platforms.
47032d2efdc6SVuong Nguyen  * It re-uses the x2APIC cpuid code of the cpuid_pass2().
47042d2efdc6SVuong Nguyen  */
47052d2efdc6SVuong Nguyen void
47062d2efdc6SVuong Nguyen cpuid_get_ext_topo(uint_t vendor, uint_t *core_nbits, uint_t *strand_nbits)
47072d2efdc6SVuong Nguyen {
47082d2efdc6SVuong Nguyen 	struct cpuid_regs regs;
47092d2efdc6SVuong Nguyen 	struct cpuid_regs *cp = &regs;
47102d2efdc6SVuong Nguyen 
47112d2efdc6SVuong Nguyen 	if (vendor != X86_VENDOR_Intel) {
47122d2efdc6SVuong Nguyen 		return;
47132d2efdc6SVuong Nguyen 	}
47142d2efdc6SVuong Nguyen 
47152d2efdc6SVuong Nguyen 	/* if the cpuid level is 0xB, extended topo is available. */
47162d2efdc6SVuong Nguyen 	cp->cp_eax = 0;
47172d2efdc6SVuong Nguyen 	if (__cpuid_insn(cp) >= 0xB) {
47182d2efdc6SVuong Nguyen 
47192d2efdc6SVuong Nguyen 		cp->cp_eax = 0xB;
47202d2efdc6SVuong Nguyen 		cp->cp_edx = cp->cp_ebx = cp->cp_ecx = 0;
47212d2efdc6SVuong Nguyen 		(void) __cpuid_insn(cp);
47222d2efdc6SVuong Nguyen 
47232d2efdc6SVuong Nguyen 		/*
47242d2efdc6SVuong Nguyen 		 * Check CPUID.EAX=0BH, ECX=0H:EBX is non-zero, which
47252d2efdc6SVuong Nguyen 		 * indicates that the extended topology enumeration leaf is
47262d2efdc6SVuong Nguyen 		 * available.
47272d2efdc6SVuong Nguyen 		 */
47282d2efdc6SVuong Nguyen 		if (cp->cp_ebx) {
47292d2efdc6SVuong Nguyen 			uint_t coreid_shift = 0;
47302d2efdc6SVuong Nguyen 			uint_t chipid_shift = 0;
47312d2efdc6SVuong Nguyen 			uint_t i;
47322d2efdc6SVuong Nguyen 			uint_t level;
47332d2efdc6SVuong Nguyen 
47342d2efdc6SVuong Nguyen 			for (i = 0; i < CPI_FNB_ECX_MAX; i++) {
47352d2efdc6SVuong Nguyen 				cp->cp_eax = 0xB;
47362d2efdc6SVuong Nguyen 				cp->cp_ecx = i;
47372d2efdc6SVuong Nguyen 
47382d2efdc6SVuong Nguyen 				(void) __cpuid_insn(cp);
47392d2efdc6SVuong Nguyen 				level = CPI_CPU_LEVEL_TYPE(cp);
47402d2efdc6SVuong Nguyen 
47412d2efdc6SVuong Nguyen 				if (level == 1) {
47422d2efdc6SVuong Nguyen 					/*
47432d2efdc6SVuong Nguyen 					 * Thread level processor topology
47442d2efdc6SVuong Nguyen 					 * Number of bits shift right APIC ID
47452d2efdc6SVuong Nguyen 					 * to get the coreid.
47462d2efdc6SVuong Nguyen 					 */
47472d2efdc6SVuong Nguyen 					coreid_shift = BITX(cp->cp_eax, 4, 0);
47482d2efdc6SVuong Nguyen 				} else if (level == 2) {
47492d2efdc6SVuong Nguyen 					/*
47502d2efdc6SVuong Nguyen 					 * Core level processor topology
47512d2efdc6SVuong Nguyen 					 * Number of bits shift right APIC ID
47522d2efdc6SVuong Nguyen 					 * to get the chipid.
47532d2efdc6SVuong Nguyen 					 */
47542d2efdc6SVuong Nguyen 					chipid_shift = BITX(cp->cp_eax, 4, 0);
47552d2efdc6SVuong Nguyen 				}
47562d2efdc6SVuong Nguyen 			}
47572d2efdc6SVuong Nguyen 
47582d2efdc6SVuong Nguyen 			if (coreid_shift > 0 && chipid_shift > coreid_shift) {
47592d2efdc6SVuong Nguyen 				*strand_nbits = coreid_shift;
47602d2efdc6SVuong Nguyen 				*core_nbits = chipid_shift - coreid_shift;
47612d2efdc6SVuong Nguyen 			}
47622d2efdc6SVuong Nguyen 		}
47632d2efdc6SVuong Nguyen 	}
47642d2efdc6SVuong Nguyen }
4765