1*e1973c51Sdv /* $OpenBSD: identcpu.c,v 1.148 2024/10/07 20:30:17 dv Exp $ */ 2f5df1827Smickey /* $NetBSD: identcpu.c,v 1.1 2003/04/26 18:39:28 fvdl Exp $ */ 3f5df1827Smickey 4f5df1827Smickey /* 5f5df1827Smickey * Copyright (c) 2003 Wasabi Systems, Inc. 6f5df1827Smickey * All rights reserved. 7f5df1827Smickey * 8f5df1827Smickey * Written by Frank van der Linden for Wasabi Systems, Inc. 9f5df1827Smickey * 10f5df1827Smickey * Redistribution and use in source and binary forms, with or without 11f5df1827Smickey * modification, are permitted provided that the following conditions 12f5df1827Smickey * are met: 13f5df1827Smickey * 1. Redistributions of source code must retain the above copyright 14f5df1827Smickey * notice, this list of conditions and the following disclaimer. 15f5df1827Smickey * 2. Redistributions in binary form must reproduce the above copyright 16f5df1827Smickey * notice, this list of conditions and the following disclaimer in the 17f5df1827Smickey * documentation and/or other materials provided with the distribution. 18f5df1827Smickey * 3. All advertising materials mentioning features or use of this software 19f5df1827Smickey * must display the following acknowledgement: 20f5df1827Smickey * This product includes software developed for the NetBSD Project by 21f5df1827Smickey * Wasabi Systems, Inc. 22f5df1827Smickey * 4. The name of Wasabi Systems, Inc. may not be used to endorse 23f5df1827Smickey * or promote products derived from this software without specific prior 24f5df1827Smickey * written permission. 25f5df1827Smickey * 26f5df1827Smickey * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 27f5df1827Smickey * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28f5df1827Smickey * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29f5df1827Smickey * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 30f5df1827Smickey * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31f5df1827Smickey * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32f5df1827Smickey * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33f5df1827Smickey * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34f5df1827Smickey * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35f5df1827Smickey * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36f5df1827Smickey * POSSIBILITY OF SUCH DAMAGE. 37f5df1827Smickey */ 38f5df1827Smickey 395922251fSderaadt #include <sys/param.h> 40f5df1827Smickey #include <sys/systm.h> 41b4cf4983Sclaudio #include <sys/atomic.h> 42b4cf4983Sclaudio #include <sys/proc.h> 435922251fSderaadt #include <sys/sysctl.h> 4477d6d4a2Smlarkin 4577d6d4a2Smlarkin #include "vmm.h" 461d2c60d6Spatrick #include "pvbus.h" 4777d6d4a2Smlarkin 48f5df1827Smickey #include <machine/cpu.h> 49f5df1827Smickey #include <machine/cpufunc.h> 50f5df1827Smickey 511d2c60d6Spatrick #if NPVBUS > 0 521d2c60d6Spatrick #include <dev/pv/pvvar.h> 531d2c60d6Spatrick #endif 541d2c60d6Spatrick 55ab8e1d10Sjsg void replacesmap(void); 561fc8fad1Sguenther void replacemeltdown(void); 57eb35b7b4Smikeb uint64_t cpu_freq(struct cpu_info *); 582db82850Skettenis void tsc_identify(struct cpu_info *); 5949acae7eSmikeb void tsc_timecounter_init(struct cpu_info *, uint64_t); 605fe96b9aSderaadt #if NVMM > 0 6177d6d4a2Smlarkin void cpu_check_vmm_cap(struct cpu_info *); 625fe96b9aSderaadt #endif /* NVMM > 0 */ 63ab8e1d10Sjsg 64f5df1827Smickey /* sysctl wants this. */ 65f5df1827Smickey char cpu_model[48]; 665922251fSderaadt int cpuspeed; 67d1449161Sthib 68f3e61100Smatthieu int amd64_has_xcrypt; 69ebaf145fSbluhm int amd64_pos_cbit; /* C bit position for SEV */ 7031816377Sjsg int has_rdrand; 71f63c0148Sjsg int has_rdseed; 72f5df1827Smickey 735922251fSderaadt int 745922251fSderaadt cpu_amd64speed(int *freq) 755922251fSderaadt { 765922251fSderaadt *freq = cpuspeed; 775922251fSderaadt return (0); 785922251fSderaadt } 795922251fSderaadt 800b390b5dStedu #ifndef SMALL_KERNEL 81b4cf4983Sclaudio void intelcore_update_sensor(void *); 82b4cf4983Sclaudio void cpu_hz_update_sensor(void *); 83b4cf4983Sclaudio 840b390b5dStedu /* 850b390b5dStedu * Temperature read on the CPU is relative to the maximum 860b390b5dStedu * temperature supported by the CPU, Tj(Max). 877a17d890Sjsg * Refer to: 887a17d890Sjsg * 64-ia-32-architectures-software-developer-vol-3c-part-3-manual.pdf 897a17d890Sjsg * Section 35 and 907a17d890Sjsg * http://www.intel.com/content/dam/www/public/us/en/documents/ 917a17d890Sjsg * white-papers/cpu-monitoring-dts-peci-paper.pdf 927a17d890Sjsg * 937a17d890Sjsg * The temperature on Intel CPUs can be between 70 and 105 degC, since 947a17d890Sjsg * Westmere we can read the TJmax from the die. For older CPUs we have 957a17d890Sjsg * to guess or use undocumented MSRs. Then we subtract the temperature 967a17d890Sjsg * portion of thermal status from max to get current temperature. 970b390b5dStedu */ 980b390b5dStedu void 990b390b5dStedu intelcore_update_sensor(void *args) 1000b390b5dStedu { 1010b390b5dStedu struct cpu_info *ci = (struct cpu_info *) args; 1020b390b5dStedu u_int64_t msr; 1030b390b5dStedu int max = 100; 1040b390b5dStedu 1058c49ce85Skrw /* Only some Core family chips have MSR_TEMPERATURE_TARGET. */ 1067a17d890Sjsg if (ci->ci_model == 0x0e && 1077a17d890Sjsg (rdmsr(MSR_TEMPERATURE_TARGET_UNDOCUMENTED) & 1087a17d890Sjsg MSR_TEMPERATURE_TARGET_LOW_BIT_UNDOCUMENTED)) 1090b390b5dStedu max = 85; 1100b390b5dStedu 1117a17d890Sjsg /* 1127a17d890Sjsg * Newer CPUs can tell you what their max temperature is. 1137a17d890Sjsg * See: '64-ia-32-architectures-software-developer- 1147a17d890Sjsg * vol-3c-part-3-manual.pdf' 1157a17d890Sjsg */ 1167a17d890Sjsg if (ci->ci_model > 0x17 && ci->ci_model != 0x1c && 1177a17d890Sjsg ci->ci_model != 0x26 && ci->ci_model != 0x27 && 1187a17d890Sjsg ci->ci_model != 0x35 && ci->ci_model != 0x36) 1197a17d890Sjsg max = MSR_TEMPERATURE_TARGET_TJMAX( 1207a17d890Sjsg rdmsr(MSR_TEMPERATURE_TARGET)); 1217a17d890Sjsg 1220b390b5dStedu msr = rdmsr(MSR_THERM_STATUS); 1230b390b5dStedu if (msr & MSR_THERM_STATUS_VALID_BIT) { 1240b390b5dStedu ci->ci_sensor.value = max - MSR_THERM_STATUS_TEMP(msr); 125e1772967Stedu /* micro degrees */ 1260b390b5dStedu ci->ci_sensor.value *= 1000000; 1270b390b5dStedu /* kelvin */ 1280b390b5dStedu ci->ci_sensor.value += 273150000; 1290b390b5dStedu ci->ci_sensor.flags &= ~SENSOR_FINVALID; 1300b390b5dStedu } else { 1310b390b5dStedu ci->ci_sensor.value = 0; 1320b390b5dStedu ci->ci_sensor.flags |= SENSOR_FINVALID; 1330b390b5dStedu } 1340b390b5dStedu } 1350b390b5dStedu 136b4cf4983Sclaudio /* 137b4cf4983Sclaudio * Effective CPU frequency measurement 138b4cf4983Sclaudio * 139b4cf4983Sclaudio * Refer to: 140b4cf4983Sclaudio * 64-ia-32-architectures-software-developer-vol-3b-part-2-manual.pdf 141b4cf4983Sclaudio * Section 14.2 and 142b4cf4983Sclaudio * OSRR for AMD Family 17h processors Section 2.1.2 143b4cf4983Sclaudio * Round to 50Mhz which is the accuracy of this measurement. 144b4cf4983Sclaudio */ 145b4cf4983Sclaudio #define FREQ_50MHZ (50ULL * 1000000ULL * 1000000ULL) 146b4cf4983Sclaudio void 147b4cf4983Sclaudio cpu_hz_update_sensor(void *args) 148b4cf4983Sclaudio { 149b4cf4983Sclaudio extern uint64_t tsc_frequency; 150b4cf4983Sclaudio struct cpu_info *ci = args; 151b4cf4983Sclaudio uint64_t mperf, aperf, mdelta, adelta, val; 152b4cf4983Sclaudio unsigned long s; 153b4cf4983Sclaudio 154b4cf4983Sclaudio sched_peg_curproc(ci); 155b4cf4983Sclaudio 156b4cf4983Sclaudio s = intr_disable(); 157b4cf4983Sclaudio mperf = rdmsr(MSR_MPERF); 158b4cf4983Sclaudio aperf = rdmsr(MSR_APERF); 159b4cf4983Sclaudio intr_restore(s); 160b4cf4983Sclaudio 161b4cf4983Sclaudio mdelta = mperf - ci->ci_hz_mperf; 162b4cf4983Sclaudio adelta = aperf - ci->ci_hz_aperf; 163b4cf4983Sclaudio ci->ci_hz_mperf = mperf; 164b4cf4983Sclaudio ci->ci_hz_aperf = aperf; 165b4cf4983Sclaudio 166b4cf4983Sclaudio if (mdelta > 0) { 167b4cf4983Sclaudio val = (adelta * 1000000) / mdelta * tsc_frequency; 168b4cf4983Sclaudio val = ((val + FREQ_50MHZ / 2) / FREQ_50MHZ) * FREQ_50MHZ; 169b4cf4983Sclaudio ci->ci_hz_sensor.value = val; 170b4cf4983Sclaudio } 171b4cf4983Sclaudio 172cf31dfdeSmpi sched_unpeg_curproc(); 173b4cf4983Sclaudio } 1740b390b5dStedu #endif 1750b390b5dStedu 1765714d2eaSgwk void (*setperf_setup)(struct cpu_info *); 1775714d2eaSgwk 178f3e61100Smatthieu void via_nano_setup(struct cpu_info *ci); 179f3e61100Smatthieu 180ec99753cShaesbaert void cpu_topology(struct cpu_info *ci); 181ec99753cShaesbaert 182f3e61100Smatthieu void 183f3e61100Smatthieu via_nano_setup(struct cpu_info *ci) 184f3e61100Smatthieu { 185f3e61100Smatthieu u_int32_t regs[4], val; 186f3e61100Smatthieu u_int64_t msreg; 187f3e61100Smatthieu int model = (ci->ci_signature >> 4) & 15; 188f3e61100Smatthieu 189f3e61100Smatthieu if (model >= 9) { 190f3e61100Smatthieu CPUID(0xC0000000, regs[0], regs[1], regs[2], regs[3]); 191f3e61100Smatthieu val = regs[0]; 192f3e61100Smatthieu if (val >= 0xC0000001) { 193f3e61100Smatthieu CPUID(0xC0000001, regs[0], regs[1], regs[2], regs[3]); 194f3e61100Smatthieu val = regs[3]; 195f3e61100Smatthieu } else 196f3e61100Smatthieu val = 0; 197f3e61100Smatthieu 198f3e61100Smatthieu if (val & (C3_CPUID_HAS_RNG | C3_CPUID_HAS_ACE)) 199f3e61100Smatthieu printf("%s:", ci->ci_dev->dv_xname); 200f3e61100Smatthieu 201f3e61100Smatthieu /* Enable RNG if present and disabled */ 202f3e61100Smatthieu if (val & C3_CPUID_HAS_RNG) { 203f3e61100Smatthieu extern int viac3_rnd_present; 204f3e61100Smatthieu 205f3e61100Smatthieu if (!(val & C3_CPUID_DO_RNG)) { 206f3e61100Smatthieu msreg = rdmsr(0x110B); 207f3e61100Smatthieu msreg |= 0x40; 208f3e61100Smatthieu wrmsr(0x110B, msreg); 209f3e61100Smatthieu } 210f3e61100Smatthieu viac3_rnd_present = 1; 211f3e61100Smatthieu printf(" RNG"); 212f3e61100Smatthieu } 213f3e61100Smatthieu 214f3e61100Smatthieu /* Enable AES engine if present and disabled */ 215f3e61100Smatthieu if (val & C3_CPUID_HAS_ACE) { 216f3e61100Smatthieu #ifdef CRYPTO 217f3e61100Smatthieu if (!(val & C3_CPUID_DO_ACE)) { 218f3e61100Smatthieu msreg = rdmsr(0x1107); 219f3e61100Smatthieu msreg |= (0x01 << 28); 220f3e61100Smatthieu wrmsr(0x1107, msreg); 221f3e61100Smatthieu } 222f3e61100Smatthieu amd64_has_xcrypt |= C3_HAS_AES; 223f3e61100Smatthieu #endif /* CRYPTO */ 224f3e61100Smatthieu printf(" AES"); 225f3e61100Smatthieu } 226f3e61100Smatthieu 227f3e61100Smatthieu /* Enable ACE2 engine if present and disabled */ 228f3e61100Smatthieu if (val & C3_CPUID_HAS_ACE2) { 229f3e61100Smatthieu #ifdef CRYPTO 230f3e61100Smatthieu if (!(val & C3_CPUID_DO_ACE2)) { 231f3e61100Smatthieu msreg = rdmsr(0x1107); 232f3e61100Smatthieu msreg |= (0x01 << 28); 233f3e61100Smatthieu wrmsr(0x1107, msreg); 234f3e61100Smatthieu } 235f3e61100Smatthieu amd64_has_xcrypt |= C3_HAS_AESCTR; 236f3e61100Smatthieu #endif /* CRYPTO */ 237f3e61100Smatthieu printf(" AES-CTR"); 238f3e61100Smatthieu } 239f3e61100Smatthieu 240f3e61100Smatthieu /* Enable SHA engine if present and disabled */ 241f3e61100Smatthieu if (val & C3_CPUID_HAS_PHE) { 242f3e61100Smatthieu #ifdef CRYPTO 243f3e61100Smatthieu if (!(val & C3_CPUID_DO_PHE)) { 244f3e61100Smatthieu msreg = rdmsr(0x1107); 245f3e61100Smatthieu msreg |= (0x01 << 28/**/); 246f3e61100Smatthieu wrmsr(0x1107, msreg); 247f3e61100Smatthieu } 248f3e61100Smatthieu amd64_has_xcrypt |= C3_HAS_SHA; 249f3e61100Smatthieu #endif /* CRYPTO */ 250f3e61100Smatthieu printf(" SHA1 SHA256"); 251f3e61100Smatthieu } 252f3e61100Smatthieu 253f3e61100Smatthieu /* Enable MM engine if present and disabled */ 254f3e61100Smatthieu if (val & C3_CPUID_HAS_PMM) { 255f3e61100Smatthieu #ifdef CRYPTO 256f3e61100Smatthieu if (!(val & C3_CPUID_DO_PMM)) { 257f3e61100Smatthieu msreg = rdmsr(0x1107); 258f3e61100Smatthieu msreg |= (0x01 << 28/**/); 259f3e61100Smatthieu wrmsr(0x1107, msreg); 260f3e61100Smatthieu } 261f3e61100Smatthieu amd64_has_xcrypt |= C3_HAS_MM; 262f3e61100Smatthieu #endif /* CRYPTO */ 263f3e61100Smatthieu printf(" RSA"); 264f3e61100Smatthieu } 265f3e61100Smatthieu 266f3e61100Smatthieu printf("\n"); 267f3e61100Smatthieu } 268f3e61100Smatthieu } 269f3e61100Smatthieu 270554ce152Skevlo #ifndef SMALL_KERNEL 271554ce152Skevlo void via_update_sensor(void *args); 272554ce152Skevlo void 273554ce152Skevlo via_update_sensor(void *args) 274554ce152Skevlo { 275554ce152Skevlo struct cpu_info *ci = (struct cpu_info *) args; 276554ce152Skevlo u_int64_t msr; 277554ce152Skevlo 278554ce152Skevlo msr = rdmsr(MSR_CENT_TMTEMPERATURE); 279554ce152Skevlo ci->ci_sensor.value = (msr & 0xffffff); 280554ce152Skevlo /* micro degrees */ 281554ce152Skevlo ci->ci_sensor.value *= 1000000; 282554ce152Skevlo ci->ci_sensor.value += 273150000; 283554ce152Skevlo ci->ci_sensor.flags &= ~SENSOR_FINVALID; 284554ce152Skevlo } 285554ce152Skevlo #endif 286554ce152Skevlo 287eb35b7b4Smikeb uint64_t 2888998e210Sguenther cpu_freq_ctr(struct cpu_info *ci, uint32_t cpu_perf_eax, 2898998e210Sguenther uint32_t cpu_perf_edx) 2908d742180Sdlg { 291eb35b7b4Smikeb uint64_t count, last_count, msr; 2928d742180Sdlg 2938d742180Sdlg if ((ci->ci_flags & CPUF_CONST_TSC) == 0 || 2948d742180Sdlg (cpu_perf_eax & CPUIDEAX_VERID) <= 1 || 2958d742180Sdlg CPUIDEDX_NUM_FC(cpu_perf_edx) <= 1) 2968d742180Sdlg return (0); 2978d742180Sdlg 2988d742180Sdlg msr = rdmsr(MSR_PERF_FIXED_CTR_CTRL); 2998d742180Sdlg if (msr & MSR_PERF_FIXED_CTR_FC(1, MSR_PERF_FIXED_CTR_FC_MASK)) { 3008d742180Sdlg /* some hypervisor is dicking us around */ 3018d742180Sdlg return (0); 3028d742180Sdlg } 3038d742180Sdlg 3048d742180Sdlg msr |= MSR_PERF_FIXED_CTR_FC(1, MSR_PERF_FIXED_CTR_FC_1); 3058d742180Sdlg wrmsr(MSR_PERF_FIXED_CTR_CTRL, msr); 3068d742180Sdlg 3078d742180Sdlg msr = rdmsr(MSR_PERF_GLOBAL_CTRL) | MSR_PERF_GLOBAL_CTR1_EN; 3088d742180Sdlg wrmsr(MSR_PERF_GLOBAL_CTRL, msr); 3098d742180Sdlg 3108d742180Sdlg last_count = rdmsr(MSR_PERF_FIXED_CTR1); 3118d742180Sdlg delay(100000); 3128d742180Sdlg count = rdmsr(MSR_PERF_FIXED_CTR1); 3138d742180Sdlg 3148d742180Sdlg msr = rdmsr(MSR_PERF_FIXED_CTR_CTRL); 3158d742180Sdlg msr &= MSR_PERF_FIXED_CTR_FC(1, MSR_PERF_FIXED_CTR_FC_MASK); 3168d742180Sdlg wrmsr(MSR_PERF_FIXED_CTR_CTRL, msr); 3178d742180Sdlg 3188d742180Sdlg msr = rdmsr(MSR_PERF_GLOBAL_CTRL); 3198d742180Sdlg msr &= ~MSR_PERF_GLOBAL_CTR1_EN; 3208d742180Sdlg wrmsr(MSR_PERF_GLOBAL_CTRL, msr); 3218d742180Sdlg 3228d742180Sdlg return ((count - last_count) * 10); 3238d742180Sdlg } 3248d742180Sdlg 325eb35b7b4Smikeb uint64_t 326eb35b7b4Smikeb cpu_freq(struct cpu_info *ci) 3278d742180Sdlg { 328eb35b7b4Smikeb uint64_t last_count, count; 3299c3f850cSreyk 3308d742180Sdlg last_count = rdtsc(); 3318d742180Sdlg delay(100000); 3328d742180Sdlg count = rdtsc(); 3338d742180Sdlg 3348d742180Sdlg return ((count - last_count) * 10); 3358d742180Sdlg } 3368d742180Sdlg 33773556a19Sguenther /* print flags from one cpuid for cpu0 */ 33873556a19Sguenther static inline void 33973556a19Sguenther pcpu0id3(const char *id, char reg1, uint32_t val1, const char *bits1, 34073556a19Sguenther char reg2, uint32_t val2, const char *bits2, 34173556a19Sguenther char reg3, uint32_t val3, const char *bits3) 34273556a19Sguenther { 34373556a19Sguenther if (val1 || val2 || val3) { 34473556a19Sguenther printf("\ncpu0: cpuid %s", id); 34573556a19Sguenther if (val1) 34673556a19Sguenther printf(" e%cx=%b", reg1, val1, bits1); 34773556a19Sguenther if (val2) 34873556a19Sguenther printf(" e%cx=%b", reg2, val2, bits2); 34973556a19Sguenther if (val3) 35073556a19Sguenther printf(" e%cx=%b", reg3, val3, bits3); 35173556a19Sguenther } 35273556a19Sguenther } 35373556a19Sguenther 35473556a19Sguenther /* print flags from one, 32-bit MSR for cpu0 */ 35573556a19Sguenther static inline void 35673556a19Sguenther pmsr032(uint32_t msr, uint32_t value, const char *bits) 35773556a19Sguenther { 35873556a19Sguenther if (value) 35973556a19Sguenther printf("\ncpu0: msr %x=%b", msr, value, bits); 36073556a19Sguenther } 36173556a19Sguenther 36273556a19Sguenther static void 36373556a19Sguenther pbitdiff(uint32_t value, uint32_t base_value, const char *bits) 36473556a19Sguenther { 36573556a19Sguenther uint32_t minus; 36673556a19Sguenther if (value == base_value) 36773556a19Sguenther return; 36873556a19Sguenther minus = base_value & ~value; 36973556a19Sguenther value &= ~base_value; 37073556a19Sguenther if (minus) 37173556a19Sguenther printf("-%b", minus, bits); 37273556a19Sguenther if (value) 37373556a19Sguenther printf("+%b", value, bits); 37473556a19Sguenther } 37573556a19Sguenther 37673556a19Sguenther static inline void 37773556a19Sguenther pcpuid(struct cpu_info *ci, const char *id, char reg, uint32_t val, 37873556a19Sguenther uint32_t prev_val, const char *bits) 37973556a19Sguenther { 38073556a19Sguenther if (CPU_IS_PRIMARY(ci)) 38173556a19Sguenther pcpu0id3(id, reg, val, bits, 0, 0, NULL, 0, 0, NULL); 38273556a19Sguenther else if (val != prev_val) { 38373556a19Sguenther printf("\n%s: cpuid %s e%cx=", ci->ci_dev->dv_xname, id, reg); 38473556a19Sguenther pbitdiff(val, prev_val, bits); 38573556a19Sguenther } 38673556a19Sguenther } 38773556a19Sguenther 38873556a19Sguenther static inline void 38973556a19Sguenther pcpuid2(struct cpu_info *ci, const char *id, 39073556a19Sguenther char reg1, uint32_t val1, uint32_t prev_val1, const char *bits1, 39173556a19Sguenther char reg2, uint32_t val2, uint32_t prev_val2, const char *bits2) 39273556a19Sguenther { 39373556a19Sguenther if (CPU_IS_PRIMARY(ci)) 39473556a19Sguenther pcpu0id3(id, reg1, val1, bits1, reg2, val2, bits2, 0, 0, 39573556a19Sguenther NULL); 39673556a19Sguenther else if (val1 != prev_val1 || val2 != prev_val2) { 39773556a19Sguenther printf("\n%s: cpuid %s", ci->ci_dev->dv_xname, id); 39873556a19Sguenther if (val1 != prev_val1) { 39973556a19Sguenther printf(" e%cx=", reg1); 40073556a19Sguenther pbitdiff(val1, prev_val1, bits1); 40173556a19Sguenther } 40273556a19Sguenther if (val2 != prev_val2) { 40373556a19Sguenther printf(" e%cx=", reg2); 40473556a19Sguenther pbitdiff(val2, prev_val2, bits2); 40573556a19Sguenther } 40673556a19Sguenther } 40773556a19Sguenther } 40873556a19Sguenther 40973556a19Sguenther static inline void 41073556a19Sguenther pcpuid3(struct cpu_info *ci, const char *id, 41173556a19Sguenther char reg1, uint32_t val1, uint32_t prev_val1, const char *bits1, 41273556a19Sguenther char reg2, uint32_t val2, uint32_t prev_val2, const char *bits2, 41373556a19Sguenther char reg3, uint32_t val3, uint32_t prev_val3, const char *bits3) 41473556a19Sguenther { 41573556a19Sguenther if (CPU_IS_PRIMARY(ci)) 41673556a19Sguenther pcpu0id3(id, reg1, val1, bits1, reg2, val2, bits2, reg3, val3, 41773556a19Sguenther bits3); 41873556a19Sguenther else if (val1 != prev_val1 || val2 != prev_val2 || val3 != prev_val3) { 41973556a19Sguenther printf("\n%s: cpuid %s", ci->ci_dev->dv_xname, id); 42073556a19Sguenther if (val1 != prev_val1) { 42173556a19Sguenther printf(" e%cx=", reg1); 42273556a19Sguenther pbitdiff(val1, prev_val1, bits1); 42373556a19Sguenther } 42473556a19Sguenther if (val2 != prev_val2) { 42573556a19Sguenther printf(" e%cx=", reg2); 42673556a19Sguenther pbitdiff(val2, prev_val2, bits2); 42773556a19Sguenther } 42873556a19Sguenther if (val3 != prev_val3) { 42973556a19Sguenther printf(" e%cx=", reg3); 43073556a19Sguenther pbitdiff(val3, prev_val3, bits3); 43173556a19Sguenther } 43273556a19Sguenther } 43373556a19Sguenther } 43473556a19Sguenther 43573556a19Sguenther static inline void 43673556a19Sguenther pmsr32(struct cpu_info *ci, uint32_t msr, uint32_t value, uint32_t prev_value, 43773556a19Sguenther const char *bits) 43873556a19Sguenther { 43973556a19Sguenther if (CPU_IS_PRIMARY(ci)) 44073556a19Sguenther pmsr032(msr, value, bits); 44173556a19Sguenther else if (value != prev_value) { 44273556a19Sguenther printf("\n%s: msr %x=", ci->ci_dev->dv_xname, msr); 44373556a19Sguenther pbitdiff(value, prev_value, bits); 44473556a19Sguenther } 44573556a19Sguenther } 44673556a19Sguenther 44773556a19Sguenther #ifdef MULTIPROCESSOR 44873556a19Sguenther static uint32_t prevcpu_perf_eax; 44973556a19Sguenther static uint32_t prevcpu_perf_edx; 45073556a19Sguenther #endif 45173556a19Sguenther 45273556a19Sguenther static inline void 4538998e210Sguenther print_perf_cpuid(struct cpu_info *ci, uint32_t cpu_perf_eax, 4548998e210Sguenther uint32_t cpu_perf_edx) 45573556a19Sguenther { 4568998e210Sguenther uint32_t version; 45773556a19Sguenther 45873556a19Sguenther if (CPU_IS_PRIMARY(ci)) { 4598998e210Sguenther version = cpu_perf_eax & CPUIDEAX_VERID; 46073556a19Sguenther if (version == 0) 46173556a19Sguenther return; 46273556a19Sguenther } 46373556a19Sguenther #ifdef MULTIPROCESSOR 46473556a19Sguenther else { 46573556a19Sguenther /* if no difference on the bits we care about, say nothing */ 4668998e210Sguenther if (((cpu_perf_eax ^ prevcpu_perf_eax) & 0x00ffffff) == 0 && 4678998e210Sguenther ((cpu_perf_edx ^ prevcpu_perf_edx) & 0x00001fff) == 0) 46873556a19Sguenther return; 4698998e210Sguenther version = cpu_perf_eax & CPUIDEAX_VERID; 47073556a19Sguenther } 4718998e210Sguenther prevcpu_perf_eax = cpu_perf_eax; 4728998e210Sguenther prevcpu_perf_edx = cpu_perf_edx; 47373556a19Sguenther #endif 47473556a19Sguenther 47573556a19Sguenther printf("\n%s: cpuid a vers=%d", ci->ci_dev->dv_xname, version); 47673556a19Sguenther if (version) { 4778998e210Sguenther printf(", gp=%d, gpwidth=%d", CPUIDEAX_NUM_GC(cpu_perf_eax), 4788998e210Sguenther CPUIDEAX_BIT_GC(cpu_perf_eax)); 47973556a19Sguenther if (version > 1) { 4808998e210Sguenther printf(", ff=%d, ffwidth=%d", 4818998e210Sguenther CPUIDEDX_NUM_FC(cpu_perf_edx), 4828998e210Sguenther CPUIDEDX_BIT_FC(cpu_perf_edx)); 48373556a19Sguenther } 48473556a19Sguenther } 48573556a19Sguenther } 48673556a19Sguenther 487f5df1827Smickey void 488f5df1827Smickey identifycpu(struct cpu_info *ci) 489f5df1827Smickey { 49073556a19Sguenther static uint32_t prevcpu_1_ecx, prevcpu_tpm_ecxflags, prevcpu_d_1_eax; 49173556a19Sguenther static uint32_t prevcpu_apmi_edx, prevcpu_arch_capa; 49273556a19Sguenther static struct cpu_info *prevci = &cpu_info_primary; 49373556a19Sguenther #define CPUID_MEMBER(member) ci->member, prevci->member 49473556a19Sguenther uint32_t cflushsz, curcpu_1_ecx, curcpu_apmi_edx = 0; 4958998e210Sguenther uint32_t curcpu_perf_eax = 0, curcpu_perf_edx = 0; 49673556a19Sguenther uint32_t curcpu_tpm_ecxflags = 0, curcpu_d_1_eax = 0; 497eb35b7b4Smikeb uint64_t freq = 0; 49873556a19Sguenther u_int32_t dummy; 4996c090d7fShaesbaert char mycpu_model[48]; 5002c60510eSgrange char *brandstr_from, *brandstr_to; 5012c60510eSgrange int skipspace; 502f5df1827Smickey 50377d6d4a2Smlarkin CPUID(0x80000000, ci->ci_pnfeatset, dummy, dummy, dummy); 50473556a19Sguenther CPUID(0x80000001, ci->ci_efeature_eax, dummy, ci->ci_efeature_ecx, 50573556a19Sguenther ci->ci_feature_eflags); 50673556a19Sguenther 50773556a19Sguenther if (CPU_IS_PRIMARY(ci)) { 50873556a19Sguenther ci->ci_signature = cpu_id; 50973556a19Sguenther ci->ci_feature_flags = cpu_feature & ~CPUID_NXE; 51073556a19Sguenther cflushsz = cpu_ebxfeature; 51173556a19Sguenther curcpu_1_ecx = cpu_ecxfeature; 51277d6d4a2Smlarkin ecpu_ecxfeature = ci->ci_efeature_ecx; 51373556a19Sguenther } else { 51473556a19Sguenther CPUID(1, ci->ci_signature, cflushsz, curcpu_1_ecx, 51573556a19Sguenther ci->ci_feature_flags); 51629636fcfSmlarkin /* Let cpu_feature be the common bits */ 51773556a19Sguenther cpu_feature &= ci->ci_feature_flags | 51873556a19Sguenther (ci->ci_feature_eflags & CPUID_NXE); 519a14dd3ebSguenther cpu_ecxfeature &= curcpu_1_ecx; 52073556a19Sguenther } 52173556a19Sguenther /* cflush cacheline size is equal to bits 15-8 of ebx * 8 */ 52273556a19Sguenther ci->ci_cflushsz = ((cflushsz >> 8) & 0xff) * 8; 5236c090d7fShaesbaert 52477d6d4a2Smlarkin CPUID(0x80000002, ci->ci_brand[0], 52577d6d4a2Smlarkin ci->ci_brand[1], ci->ci_brand[2], ci->ci_brand[3]); 52677d6d4a2Smlarkin CPUID(0x80000003, ci->ci_brand[4], 52777d6d4a2Smlarkin ci->ci_brand[5], ci->ci_brand[6], ci->ci_brand[7]); 52877d6d4a2Smlarkin CPUID(0x80000004, ci->ci_brand[8], 52977d6d4a2Smlarkin ci->ci_brand[9], ci->ci_brand[10], ci->ci_brand[11]); 53077d6d4a2Smlarkin strlcpy(mycpu_model, (char *)ci->ci_brand, sizeof(mycpu_model)); 531f5df1827Smickey 532def6b364Skettenis /* Remove leading, trailing and duplicated spaces from mycpu_model */ 5336c090d7fShaesbaert brandstr_from = brandstr_to = mycpu_model; 5342c60510eSgrange skipspace = 1; 5352c60510eSgrange while (*brandstr_from != '\0') { 5362c60510eSgrange if (!skipspace || *brandstr_from != ' ') { 5372c60510eSgrange skipspace = 0; 5382c60510eSgrange *(brandstr_to++) = *brandstr_from; 5392c60510eSgrange } 5402c60510eSgrange if (*brandstr_from == ' ') 5412c60510eSgrange skipspace = 1; 5422c60510eSgrange brandstr_from++; 5432c60510eSgrange } 544def6b364Skettenis if (skipspace && brandstr_to > mycpu_model) 545def6b364Skettenis brandstr_to--; 5462c60510eSgrange *brandstr_to = '\0'; 5472c60510eSgrange 5486c090d7fShaesbaert if (mycpu_model[0] == 0) 5496c090d7fShaesbaert strlcpy(mycpu_model, "Opteron or Athlon 64", 5506c090d7fShaesbaert sizeof(mycpu_model)); 5516c090d7fShaesbaert 5526c090d7fShaesbaert /* If primary cpu, fill in the global cpu_model used by sysctl */ 553dca1e8dbSfcambus if (CPU_IS_PRIMARY(ci)) 5546c090d7fShaesbaert strlcpy(cpu_model, mycpu_model, sizeof(cpu_model)); 555f5df1827Smickey 55640d90450Sjsg ci->ci_family = (ci->ci_signature >> 8) & 0x0f; 55740d90450Sjsg ci->ci_model = (ci->ci_signature >> 4) & 0x0f; 55840d90450Sjsg if (ci->ci_family == 0x6 || ci->ci_family == 0xf) { 55940d90450Sjsg ci->ci_family += (ci->ci_signature >> 20) & 0xff; 56040d90450Sjsg ci->ci_model += ((ci->ci_signature >> 16) & 0x0f) << 4; 56140d90450Sjsg } 56240d90450Sjsg 5631d2c60d6Spatrick #if NPVBUS > 0 5641d2c60d6Spatrick /* Detect hypervisors early, attach the paravirtual bus later */ 5651d2c60d6Spatrick if (CPU_IS_PRIMARY(ci) && cpu_ecxfeature & CPUIDECX_HV) 5661d2c60d6Spatrick pvbus_identify(); 5671d2c60d6Spatrick #endif 5681d2c60d6Spatrick 5698998e210Sguenther if (ci->ci_pnfeatset >= 0x80000007) 5708998e210Sguenther CPUID(0x80000007, dummy, dummy, dummy, curcpu_apmi_edx); 5718998e210Sguenther 57207166672Smglocker if (ci->ci_feature_flags && ci->ci_feature_flags & CPUID_TSC) { 57307166672Smglocker /* Has TSC, check if it's constant */ 574ccd74f94Sguenther if (ci->ci_vendor == CPUV_INTEL) { 57507166672Smglocker if ((ci->ci_family == 0x0f && ci->ci_model >= 0x03) || 57607166672Smglocker (ci->ci_family == 0x06 && ci->ci_model >= 0x0e)) { 5770403d5bcSguenther atomic_setbits_int(&ci->ci_flags, CPUF_CONST_TSC); 57807166672Smglocker } 579ccd74f94Sguenther } else if (ci->ci_vendor == CPUV_VIA) { 58007166672Smglocker /* VIA */ 58107166672Smglocker if (ci->ci_model >= 0x0f) { 5820403d5bcSguenther atomic_setbits_int(&ci->ci_flags, CPUF_CONST_TSC); 58307166672Smglocker } 584ccd74f94Sguenther } else if (ci->ci_vendor == CPUV_AMD) { 5858998e210Sguenther if (curcpu_apmi_edx & CPUIDEDX_ITSC) { 5860403d5bcSguenther /* Invariant TSC indicates constant TSC on AMD */ 5870403d5bcSguenther atomic_setbits_int(&ci->ci_flags, CPUF_CONST_TSC); 58807166672Smglocker } 58907166672Smglocker } 5909c3f850cSreyk 5919c3f850cSreyk /* Check if it's an invariant TSC */ 5928998e210Sguenther if (curcpu_apmi_edx & CPUIDEDX_ITSC) 5930403d5bcSguenther atomic_setbits_int(&ci->ci_flags, CPUF_INVAR_TSC); 5942db82850Skettenis 5952db82850Skettenis tsc_identify(ci); 59607166672Smglocker } 59707166672Smglocker 5988998e210Sguenther if (ci->ci_cpuid_level >= 0xa) { 5998998e210Sguenther CPUID(0xa, curcpu_perf_eax, dummy, dummy, curcpu_perf_edx); 6008998e210Sguenther 6018998e210Sguenther freq = cpu_freq_ctr(ci, curcpu_perf_eax, curcpu_perf_edx); 6028998e210Sguenther } 6038998e210Sguenther if (freq == 0) 604eb35b7b4Smikeb freq = cpu_freq(ci); 605f5df1827Smickey 60673556a19Sguenther if (ci->ci_cpuid_level >= 0x07) { 60773556a19Sguenther /* "Structured Extended Feature Flags" */ 60873556a19Sguenther CPUID_LEAF(0x7, 0, dummy, ci->ci_feature_sefflags_ebx, 60973556a19Sguenther ci->ci_feature_sefflags_ecx, ci->ci_feature_sefflags_edx); 61073556a19Sguenther /* SEFF0ECX_OSPKE is set late on AP */ 61173556a19Sguenther ci->ci_feature_sefflags_ecx &= ~SEFF0ECX_OSPKE; 61273556a19Sguenther } 61373556a19Sguenther 6146c090d7fShaesbaert printf("%s: %s", ci->ci_dev->dv_xname, mycpu_model); 615f5df1827Smickey 616eb35b7b4Smikeb if (freq != 0) 617eb35b7b4Smikeb printf(", %llu.%02llu MHz", (freq + 4999) / 1000000, 618eb35b7b4Smikeb ((freq + 4999) / 10000) % 100); 6196c090d7fShaesbaert 620dca1e8dbSfcambus if (CPU_IS_PRIMARY(ci)) { 621eb35b7b4Smikeb cpuspeed = (freq + 4999) / 1000000; 6225922251fSderaadt cpu_cpuspeed = cpu_amd64speed; 6236c090d7fShaesbaert } 624f5df1827Smickey 62555992104Sjsg printf(", %02x-%02x-%02x", ci->ci_family, ci->ci_model, 62655992104Sjsg ci->ci_signature & 0x0f); 62755992104Sjsg 628f5923053Sjsg if ((cpu_ecxfeature & CPUIDECX_HV) == 0) { 629f5923053Sjsg uint64_t level = 0; 630f5923053Sjsg uint32_t dummy; 631f5923053Sjsg 632ccd74f94Sguenther if (ci->ci_vendor == CPUV_AMD) { 633f5923053Sjsg level = rdmsr(MSR_PATCH_LEVEL); 634ccd74f94Sguenther } else if (ci->ci_vendor == CPUV_INTEL) { 635f5923053Sjsg wrmsr(MSR_BIOS_SIGN, 0); 636f5923053Sjsg CPUID(1, dummy, dummy, dummy, dummy); 637f5923053Sjsg level = rdmsr(MSR_BIOS_SIGN) >> 32; 638f5923053Sjsg } 639f5923053Sjsg if (level != 0) 640f5923053Sjsg printf(", patch %08llx", level); 641f5923053Sjsg } 642f5923053Sjsg 64373556a19Sguenther if (ci->ci_cpuid_level >= 0x06) 64473556a19Sguenther CPUID(0x06, ci->ci_feature_tpmflags, dummy, 64573556a19Sguenther curcpu_tpm_ecxflags, dummy); 64673556a19Sguenther if (ci->ci_vendor == CPUV_AMD && ci->ci_family >= 0x12) 64783ef434fSkettenis ci->ci_feature_tpmflags |= TPM_ARAT; 64873556a19Sguenther 64973556a19Sguenther /* xsave subfeatures */ 65073556a19Sguenther if (ci->ci_cpuid_level >= 0xd) 65173556a19Sguenther CPUID_LEAF(0xd, 1, curcpu_d_1_eax, dummy, dummy, dummy); 65273556a19Sguenther 65373556a19Sguenther pcpuid2(ci, "1", 'd', CPUID_MEMBER(ci_feature_flags), CPUID_EDX_BITS, 65473556a19Sguenther 'c', curcpu_1_ecx, prevcpu_1_ecx, CPUID_ECX_BITS); 65573556a19Sguenther pcpuid2(ci, "6", 'a', CPUID_MEMBER(ci_feature_tpmflags), TPM_EAX_BITS, 65673556a19Sguenther 'c', curcpu_tpm_ecxflags, prevcpu_tpm_ecxflags, TPM_ECX_BITS); 65773556a19Sguenther pcpuid3(ci, "7.0", 65873556a19Sguenther 'b', CPUID_MEMBER(ci_feature_sefflags_ebx), SEFF0_EBX_BITS, 65973556a19Sguenther 'c', CPUID_MEMBER(ci_feature_sefflags_ecx), SEFF0_ECX_BITS, 66073556a19Sguenther 'd', CPUID_MEMBER(ci_feature_sefflags_edx), SEFF0_EDX_BITS); 6618998e210Sguenther print_perf_cpuid(ci, curcpu_perf_eax, curcpu_perf_edx); 66273556a19Sguenther pcpuid(ci, "d.1", 'a', curcpu_d_1_eax, prevcpu_d_1_eax, XSAVE_BITS); 66373556a19Sguenther pcpuid2(ci, "80000001", 66473556a19Sguenther 'd', CPUID_MEMBER(ci_feature_eflags), CPUIDE_EDX_BITS, 66573556a19Sguenther 'c', CPUID_MEMBER(ci_efeature_ecx), CPUIDE_ECX_BITS); 66673556a19Sguenther pcpuid(ci, "80000007", 'd', curcpu_apmi_edx, prevcpu_apmi_edx, 66773556a19Sguenther CPUID_APMI_EDX_BITS); 66873556a19Sguenther #ifdef MULTIPROCESSOR 66973556a19Sguenther prevcpu_1_ecx = curcpu_1_ecx; 67073556a19Sguenther prevcpu_tpm_ecxflags = curcpu_tpm_ecxflags; 67173556a19Sguenther prevcpu_d_1_eax = curcpu_d_1_eax; 67273556a19Sguenther prevcpu_apmi_edx = curcpu_apmi_edx; 67373556a19Sguenther #endif 674cf77ca15Sguenther 675b70fbf0aSguenther /* speculation control features */ 676ccd74f94Sguenther if (ci->ci_vendor == CPUV_AMD) { 677d9b434b4Smlarkin if (ci->ci_pnfeatset >= 0x80000008) { 678d9b434b4Smlarkin CPUID(0x80000008, dummy, ci->ci_feature_amdspec_ebx, 679d9b434b4Smlarkin dummy, dummy); 68073556a19Sguenther pcpuid(ci, "80000008", 'b', 68173556a19Sguenther CPUID_MEMBER(ci_feature_amdspec_ebx), 68273556a19Sguenther CPUID_AMDSPEC_EBX_BITS); 683d9b434b4Smlarkin } 68473556a19Sguenther } else if (ci->ci_vendor == CPUV_INTEL) { 68573556a19Sguenther if (ci->ci_feature_sefflags_edx & SEFF0EDX_ARCH_CAP) { 68673556a19Sguenther uint32_t msr = rdmsr(MSR_ARCH_CAPABILITIES); 687b70fbf0aSguenther 68873556a19Sguenther pmsr32(ci, MSR_ARCH_CAPABILITIES, msr, 68973556a19Sguenther prevcpu_arch_capa, ARCH_CAP_MSR_BITS); 69073556a19Sguenther prevcpu_arch_capa = msr; 69173556a19Sguenther if (!CPU_IS_PRIMARY(ci) && cpu_meltdown && 69273556a19Sguenther (msr & ARCH_CAP_RDCL_NO)) 69373556a19Sguenther printf("\n%s: -MELTDOWN", ci->ci_dev->dv_xname); 694d9b434b4Smlarkin } 69573556a19Sguenther if (cpu_meltdown && CPU_IS_PRIMARY(ci)) 69673556a19Sguenther printf("\n%s: MELTDOWN", ci->ci_dev->dv_xname); 6974c13963cSguenther } 6984c13963cSguenther 699f880dfafSbluhm /* AMD secure memory encryption and encrypted virtualization features */ 700f880dfafSbluhm if (ci->ci_vendor == CPUV_AMD && 701f880dfafSbluhm ci->ci_pnfeatset >= CPUID_AMD_SEV_CAP) { 702f880dfafSbluhm CPUID(CPUID_AMD_SEV_CAP, ci->ci_feature_amdsev_eax, 703f880dfafSbluhm ci->ci_feature_amdsev_ebx, ci->ci_feature_amdsev_ecx, 704f880dfafSbluhm ci->ci_feature_amdsev_edx); 705f880dfafSbluhm pcpuid3(ci, "8000001F", 706f880dfafSbluhm 'a', CPUID_MEMBER(ci_feature_amdsev_eax), 707f880dfafSbluhm CPUID_AMDSEV_EAX_BITS, 708f880dfafSbluhm 'c', CPUID_MEMBER(ci_feature_amdsev_ecx), 709f880dfafSbluhm CPUID_AMDSEV_ECX_BITS, 710f880dfafSbluhm 'd', CPUID_MEMBER(ci_feature_amdsev_edx), 711f880dfafSbluhm CPUID_AMDSEV_EDX_BITS); 712f880dfafSbluhm amd64_pos_cbit = (ci->ci_feature_amdsev_ebx & 0x3f); 713f880dfafSbluhm } 714f880dfafSbluhm 7154aac7a55Smickey printf("\n"); 716f5df1827Smickey 717f95e373fSguenther replacemeltdown(); 718f5df1827Smickey x86_print_cacheinfo(ci); 71934b4ab5eSuwe 720dca1e8dbSfcambus if (CPU_IS_PRIMARY(ci)) { 721c61a50a0Sderaadt #ifndef SMALL_KERNEL 722ccd74f94Sguenther if (ci->ci_vendor == CPUV_AMD && 72377d6d4a2Smlarkin ci->ci_pnfeatset >= 0x80000007) { 72473556a19Sguenther if (curcpu_apmi_edx & 0x06) { 725cba131fcSmlarkin if ((ci->ci_signature & 0xF00) == 0xF00) 7265714d2eaSgwk setperf_setup = k8_powernow_init; 72734b4ab5eSuwe } 728fb8a9091Sderaadt if (ci->ci_family >= 0x10) 7290df720aaSclaudio setperf_setup = k1x_init; 73034b4ab5eSuwe } 731d279ab14Stom 7326c090d7fShaesbaert if (cpu_ecxfeature & CPUIDECX_EST) 7330b390b5dStedu setperf_setup = est_init; 734c61a50a0Sderaadt #endif 73504bf4ebbSgwk 73631816377Sjsg if (cpu_ecxfeature & CPUIDECX_RDRAND) 73731816377Sjsg has_rdrand = 1; 738ab8e1d10Sjsg 739f63c0148Sjsg if (ci->ci_feature_sefflags_ebx & SEFF0EBX_RDSEED) 740f63c0148Sjsg has_rdseed = 1; 741f63c0148Sjsg 74277d6d4a2Smlarkin if (ci->ci_feature_sefflags_ebx & SEFF0EBX_SMAP) 743ab8e1d10Sjsg replacesmap(); 7446c090d7fShaesbaert } 745c8cdbfc9Sjsg 746c8cdbfc9Sjsg #ifndef SMALL_KERNEL 747b7f63170Skn if (CPU_IS_PRIMARY(ci) && (ci->ci_feature_tpmflags & TPM_SENSOR) && 748b7f63170Skn ci->ci_vendor == CPUV_INTEL) { 7490b390b5dStedu ci->ci_sensor.type = SENSOR_TEMP; 7500b390b5dStedu sensor_task_register(ci, intelcore_update_sensor, 5); 7510b390b5dStedu sensor_attach(&ci->ci_sensordev, &ci->ci_sensor); 7520b390b5dStedu } 7537e5f337fStb #endif 7540b390b5dStedu 755ccd74f94Sguenther if (CPU_IS_PRIMARY(ci) && ci->ci_vendor == CPUV_VIA) { 756f3e61100Smatthieu ci->cpu_setup = via_nano_setup; 757554ce152Skevlo #ifndef SMALL_KERNEL 758554ce152Skevlo ci->ci_sensor.type = SENSOR_TEMP; 759554ce152Skevlo sensor_task_register(ci, via_update_sensor, 5); 760554ce152Skevlo sensor_attach(&ci->ci_sensordev, &ci->ci_sensor); 761554ce152Skevlo #endif 762554ce152Skevlo } 763ec99753cShaesbaert 76449acae7eSmikeb tsc_timecounter_init(ci, freq); 7659c3f850cSreyk 766ec99753cShaesbaert cpu_topology(ci); 7675fe96b9aSderaadt #if NVMM > 0 76877d6d4a2Smlarkin cpu_check_vmm_cap(ci); 7695fe96b9aSderaadt #endif /* NVMM > 0 */ 770b4cf4983Sclaudio 771b4cf4983Sclaudio /* Check for effective frequency via MPERF, APERF */ 77273556a19Sguenther if ((curcpu_tpm_ecxflags & TPM_EFFFREQ) && ci->ci_smt_id == 0) { 773b4cf4983Sclaudio #ifndef SMALL_KERNEL 774b4cf4983Sclaudio ci->ci_hz_sensor.type = SENSOR_FREQ; 775b4cf4983Sclaudio sensor_task_register(ci, cpu_hz_update_sensor, 1); 776b4cf4983Sclaudio sensor_attach(&ci->ci_sensordev, &ci->ci_hz_sensor); 777b4cf4983Sclaudio #endif 778b4cf4983Sclaudio } 77973556a19Sguenther prevci = ci; 780ec99753cShaesbaert } 781ec99753cShaesbaert 782ec99753cShaesbaert #ifndef SMALL_KERNEL 783ec99753cShaesbaert /* 784ec99753cShaesbaert * Base 2 logarithm of an int. returns 0 for 0 (yeye, I know). 785ec99753cShaesbaert */ 786ec99753cShaesbaert static int 787ec99753cShaesbaert log2(unsigned int i) 788ec99753cShaesbaert { 789ec99753cShaesbaert int ret = 0; 790ec99753cShaesbaert 791ec99753cShaesbaert while (i >>= 1) 792ec99753cShaesbaert ret++; 793ec99753cShaesbaert 794ec99753cShaesbaert return (ret); 795ec99753cShaesbaert } 796ec99753cShaesbaert 797ec99753cShaesbaert static int 798ec99753cShaesbaert mask_width(u_int x) 799ec99753cShaesbaert { 800ec99753cShaesbaert int bit; 801ec99753cShaesbaert int mask; 802ec99753cShaesbaert int powerof2; 803ec99753cShaesbaert 804ec99753cShaesbaert powerof2 = ((x - 1) & x) == 0; 805ec99753cShaesbaert mask = (x << (1 - powerof2)) - 1; 806ec99753cShaesbaert 807ec99753cShaesbaert /* fls */ 808ec99753cShaesbaert if (mask == 0) 809ec99753cShaesbaert return (0); 810ec99753cShaesbaert for (bit = 1; mask != 1; bit++) 811ec99753cShaesbaert mask = (unsigned int)mask >> 1; 812ec99753cShaesbaert 813ec99753cShaesbaert return (bit); 814ec99753cShaesbaert } 815ec99753cShaesbaert #endif 816ec99753cShaesbaert 817ec99753cShaesbaert /* 818ec99753cShaesbaert * Build up cpu topology for given cpu, must run on the core itself. 819ec99753cShaesbaert */ 820ec99753cShaesbaert void 821ec99753cShaesbaert cpu_topology(struct cpu_info *ci) 822ec99753cShaesbaert { 823ec99753cShaesbaert #ifndef SMALL_KERNEL 824ec99753cShaesbaert u_int32_t eax, ebx, ecx, edx; 82552f20651Smlarkin u_int32_t apicid, max_apicid = 0, max_coreid = 0; 82652f20651Smlarkin u_int32_t smt_bits = 0, core_bits, pkg_bits = 0; 82752f20651Smlarkin u_int32_t smt_mask = 0, core_mask, pkg_mask = 0; 828ec99753cShaesbaert 829ec99753cShaesbaert /* We need at least apicid at CPUID 1 */ 830ccd74f94Sguenther if (ci->ci_cpuid_level < 1) 831ec99753cShaesbaert goto no_topology; 832ec99753cShaesbaert 833ec99753cShaesbaert /* Initial apicid */ 834ec99753cShaesbaert CPUID(1, eax, ebx, ecx, edx); 835ec99753cShaesbaert apicid = (ebx >> 24) & 0xff; 836ec99753cShaesbaert 837ccd74f94Sguenther if (ci->ci_vendor == CPUV_AMD) { 838fccfca3aSdlg uint32_t nthreads = 1; /* per core */ 839fccfca3aSdlg uint32_t thread_id; /* within a package */ 840fccfca3aSdlg 841ec99753cShaesbaert /* We need at least apicid at CPUID 0x80000008 */ 8427c3cbf8aSguenther if (ci->ci_pnfeatset < 0x80000008) 843ec99753cShaesbaert goto no_topology; 844ec99753cShaesbaert 845ec99753cShaesbaert CPUID(0x80000008, eax, ebx, ecx, edx); 846ec99753cShaesbaert core_bits = (ecx >> 12) & 0xf; 847fccfca3aSdlg 848fccfca3aSdlg if (ci->ci_pnfeatset >= 0x8000001e) { 849fccfca3aSdlg CPUID(0x8000001e, eax, ebx, ecx, edx); 850fccfca3aSdlg nthreads = ((ebx >> 8) & 0xf) + 1; 851121fa492Ssthen } 852fccfca3aSdlg 853fccfca3aSdlg /* Shift the core_bits off to get at the pkg bits */ 854fccfca3aSdlg ci->ci_pkg_id = apicid >> core_bits; 855fccfca3aSdlg 856fccfca3aSdlg /* Get rid of the package bits */ 85741d7544aSbluhm core_mask = (1U << core_bits) - 1; 858fccfca3aSdlg thread_id = apicid & core_mask; 859fccfca3aSdlg 860fccfca3aSdlg /* Cut logical thread_id into core id, and smt id in a core */ 861fccfca3aSdlg ci->ci_core_id = thread_id / nthreads; 862fccfca3aSdlg ci->ci_smt_id = thread_id % nthreads; 863ccd74f94Sguenther } else if (ci->ci_vendor == CPUV_INTEL) { 864ec99753cShaesbaert /* We only support leaf 1/4 detection */ 865ccd74f94Sguenther if (ci->ci_cpuid_level < 4) 866ec99753cShaesbaert goto no_topology; 867ec99753cShaesbaert /* Get max_apicid */ 868ec99753cShaesbaert CPUID(1, eax, ebx, ecx, edx); 869ec99753cShaesbaert max_apicid = (ebx >> 16) & 0xff; 870ec99753cShaesbaert /* Get max_coreid */ 871ec99753cShaesbaert CPUID_LEAF(4, 0, eax, ebx, ecx, edx); 872ec99753cShaesbaert max_coreid = ((eax >> 26) & 0x3f) + 1; 873ec99753cShaesbaert /* SMT */ 874ec99753cShaesbaert smt_bits = mask_width(max_apicid / max_coreid); 87541d7544aSbluhm smt_mask = (1U << smt_bits) - 1; 876ec99753cShaesbaert /* Core */ 877ec99753cShaesbaert core_bits = log2(max_coreid); 87841d7544aSbluhm core_mask = (1U << (core_bits + smt_bits)) - 1; 879ec99753cShaesbaert core_mask ^= smt_mask; 880ec99753cShaesbaert /* Pkg */ 881ec99753cShaesbaert pkg_bits = core_bits + smt_bits; 88241d7544aSbluhm pkg_mask = ~0U << core_bits; 883ec99753cShaesbaert 884f4828eb5Ssthen ci->ci_smt_id = apicid & smt_mask; 885ec99753cShaesbaert ci->ci_core_id = (apicid & core_mask) >> smt_bits; 886ec99753cShaesbaert ci->ci_pkg_id = (apicid & pkg_mask) >> pkg_bits; 887ec99753cShaesbaert } else 888ec99753cShaesbaert goto no_topology; 889ec99753cShaesbaert #ifdef DEBUG 890ec99753cShaesbaert printf("cpu%d: smt %u, core %u, pkg %u " 891ec99753cShaesbaert "(apicid 0x%x, max_apicid 0x%x, max_coreid 0x%x, smt_bits 0x%x, smt_mask 0x%x, " 892ec99753cShaesbaert "core_bits 0x%x, core_mask 0x%x, pkg_bits 0x%x, pkg_mask 0x%x)\n", 893ec99753cShaesbaert ci->ci_cpuid, ci->ci_smt_id, ci->ci_core_id, ci->ci_pkg_id, 894ec99753cShaesbaert apicid, max_apicid, max_coreid, smt_bits, smt_mask, core_bits, 895ec99753cShaesbaert core_mask, pkg_bits, pkg_mask); 896ec99753cShaesbaert #else 897ec99753cShaesbaert printf("cpu%d: smt %u, core %u, package %u\n", ci->ci_cpuid, 898ec99753cShaesbaert ci->ci_smt_id, ci->ci_core_id, ci->ci_pkg_id); 899ec99753cShaesbaert 900ec99753cShaesbaert #endif 901ec99753cShaesbaert return; 902ec99753cShaesbaert /* We can't map, so consider ci_core_id as ci_cpuid */ 903ec99753cShaesbaert no_topology: 904ec99753cShaesbaert #endif 905ec99753cShaesbaert ci->ci_smt_id = 0; 906ec99753cShaesbaert ci->ci_core_id = ci->ci_cpuid; 907ec99753cShaesbaert ci->ci_pkg_id = 0; 908f5df1827Smickey } 90977d6d4a2Smlarkin 9105fe96b9aSderaadt #if NVMM > 0 91177d6d4a2Smlarkin /* 91277d6d4a2Smlarkin * cpu_check_vmm_cap 91377d6d4a2Smlarkin * 91477d6d4a2Smlarkin * Checks for VMM capabilities for 'ci'. Initializes certain per-cpu VMM 91577d6d4a2Smlarkin * state in 'ci' if virtualization extensions are found. 91677d6d4a2Smlarkin * 91777d6d4a2Smlarkin * Parameters: 91877d6d4a2Smlarkin * ci: the cpu being checked 91977d6d4a2Smlarkin */ 92077d6d4a2Smlarkin void 92177d6d4a2Smlarkin cpu_check_vmm_cap(struct cpu_info *ci) 92277d6d4a2Smlarkin { 92377d6d4a2Smlarkin uint64_t msr; 924a937696cSmlarkin uint32_t cap, dummy, edx; 92577d6d4a2Smlarkin 92677d6d4a2Smlarkin /* 92777d6d4a2Smlarkin * Check for workable VMX 92877d6d4a2Smlarkin */ 92977d6d4a2Smlarkin if (cpu_ecxfeature & CPUIDECX_VMX) { 93077d6d4a2Smlarkin msr = rdmsr(MSR_IA32_FEATURE_CONTROL); 93177d6d4a2Smlarkin 93277d6d4a2Smlarkin if (!(msr & IA32_FEATURE_CONTROL_LOCK)) 93377d6d4a2Smlarkin ci->ci_vmm_flags |= CI_VMM_VMX; 93477d6d4a2Smlarkin else { 93577d6d4a2Smlarkin if (msr & IA32_FEATURE_CONTROL_VMX_EN) 93677d6d4a2Smlarkin ci->ci_vmm_flags |= CI_VMM_VMX; 937b4ff5abaSmartijn else 938b4ff5abaSmartijn ci->ci_vmm_flags |= CI_VMM_DIS; 93977d6d4a2Smlarkin } 94077d6d4a2Smlarkin } 94177d6d4a2Smlarkin 94277d6d4a2Smlarkin /* 9430a1af29dSmlarkin * Check for EPT (Intel Nested Paging) and other secondary 9440a1af29dSmlarkin * controls 94577d6d4a2Smlarkin */ 94677d6d4a2Smlarkin if (ci->ci_vmm_flags & CI_VMM_VMX) { 94777d6d4a2Smlarkin /* Secondary controls available? */ 94877d6d4a2Smlarkin /* XXX should we check true procbased ctls here if avail? */ 94977d6d4a2Smlarkin msr = rdmsr(IA32_VMX_PROCBASED_CTLS); 95077d6d4a2Smlarkin if (msr & (IA32_VMX_ACTIVATE_SECONDARY_CONTROLS) << 32) { 95177d6d4a2Smlarkin msr = rdmsr(IA32_VMX_PROCBASED2_CTLS); 95277d6d4a2Smlarkin /* EPT available? */ 95377d6d4a2Smlarkin if (msr & (IA32_VMX_ENABLE_EPT) << 32) 95477d6d4a2Smlarkin ci->ci_vmm_flags |= CI_VMM_EPT; 95577d6d4a2Smlarkin } 95677d6d4a2Smlarkin } 95777d6d4a2Smlarkin 95877d6d4a2Smlarkin /* 95977d6d4a2Smlarkin * Check startup config (VMX) 96077d6d4a2Smlarkin */ 96177d6d4a2Smlarkin if (ci->ci_vmm_flags & CI_VMM_VMX) { 96277d6d4a2Smlarkin /* CR0 fixed and flexible bits */ 96377d6d4a2Smlarkin msr = rdmsr(IA32_VMX_CR0_FIXED0); 96477d6d4a2Smlarkin ci->ci_vmm_cap.vcc_vmx.vmx_cr0_fixed0 = msr; 96577d6d4a2Smlarkin msr = rdmsr(IA32_VMX_CR0_FIXED1); 96677d6d4a2Smlarkin ci->ci_vmm_cap.vcc_vmx.vmx_cr0_fixed1 = msr; 96777d6d4a2Smlarkin 96877d6d4a2Smlarkin /* CR4 fixed and flexible bits */ 96977d6d4a2Smlarkin msr = rdmsr(IA32_VMX_CR4_FIXED0); 97077d6d4a2Smlarkin ci->ci_vmm_cap.vcc_vmx.vmx_cr4_fixed0 = msr; 97177d6d4a2Smlarkin msr = rdmsr(IA32_VMX_CR4_FIXED1); 97277d6d4a2Smlarkin ci->ci_vmm_cap.vcc_vmx.vmx_cr4_fixed1 = msr; 97377d6d4a2Smlarkin 97477d6d4a2Smlarkin /* VMXON region revision ID (bits 30:0 of IA32_VMX_BASIC) */ 97577d6d4a2Smlarkin msr = rdmsr(IA32_VMX_BASIC); 97677d6d4a2Smlarkin ci->ci_vmm_cap.vcc_vmx.vmx_vmxon_revision = 97777d6d4a2Smlarkin (uint32_t)(msr & 0x7FFFFFFF); 97877d6d4a2Smlarkin 97977d6d4a2Smlarkin /* MSR save / load table size */ 98077d6d4a2Smlarkin msr = rdmsr(IA32_VMX_MISC); 98177d6d4a2Smlarkin ci->ci_vmm_cap.vcc_vmx.vmx_msr_table_size = 98277d6d4a2Smlarkin (uint32_t)(msr & IA32_VMX_MSR_LIST_SIZE_MASK) >> 25; 9832a5b1ebdSmlarkin 9842a5b1ebdSmlarkin /* CR3 target count size */ 9852a5b1ebdSmlarkin ci->ci_vmm_cap.vcc_vmx.vmx_cr3_tgt_count = 9862a5b1ebdSmlarkin (uint32_t)(msr & IA32_VMX_CR3_TGT_SIZE_MASK) >> 16; 98777d6d4a2Smlarkin } 98877d6d4a2Smlarkin 98977d6d4a2Smlarkin /* 99077d6d4a2Smlarkin * Check for workable SVM 99177d6d4a2Smlarkin */ 99277d6d4a2Smlarkin if (ecpu_ecxfeature & CPUIDECX_SVM) { 99377d6d4a2Smlarkin msr = rdmsr(MSR_AMD_VM_CR); 99477d6d4a2Smlarkin 99577d6d4a2Smlarkin if (!(msr & AMD_SVMDIS)) 99677d6d4a2Smlarkin ci->ci_vmm_flags |= CI_VMM_SVM; 997b49f7c39Smlarkin 998a937696cSmlarkin CPUID(CPUID_AMD_SVM_CAP, dummy, 999a937696cSmlarkin ci->ci_vmm_cap.vcc_svm.svm_max_asid, dummy, edx); 1000b49f7c39Smlarkin 10012aa3e17eSmlarkin if (ci->ci_vmm_cap.vcc_svm.svm_max_asid > 0xFFF) 10022aa3e17eSmlarkin ci->ci_vmm_cap.vcc_svm.svm_max_asid = 0xFFF; 1003a937696cSmlarkin 1004a937696cSmlarkin if (edx & AMD_SVM_FLUSH_BY_ASID_CAP) 1005a937696cSmlarkin ci->ci_vmm_cap.vcc_svm.svm_flush_by_asid = 1; 1006a937696cSmlarkin 1007a937696cSmlarkin if (edx & AMD_SVM_VMCB_CLEAN_CAP) 1008a937696cSmlarkin ci->ci_vmm_cap.vcc_svm.svm_vmcb_clean = 1; 100918126f0eSdv 101018126f0eSdv if (edx & AMD_SVM_DECODE_ASSIST_CAP) 101118126f0eSdv ci->ci_vmm_cap.vcc_svm.svm_decode_assist = 1; 101277d6d4a2Smlarkin } 101377d6d4a2Smlarkin 101477d6d4a2Smlarkin /* 101577d6d4a2Smlarkin * Check for SVM Nested Paging 101677d6d4a2Smlarkin */ 10177c3cbf8aSguenther if ((ci->ci_vmm_flags & CI_VMM_SVM) && 10187c3cbf8aSguenther ci->ci_pnfeatset >= CPUID_AMD_SVM_CAP) { 101977d6d4a2Smlarkin CPUID(CPUID_AMD_SVM_CAP, dummy, dummy, dummy, cap); 102077d6d4a2Smlarkin if (cap & AMD_SVM_NESTED_PAGING_CAP) 102177d6d4a2Smlarkin ci->ci_vmm_flags |= CI_VMM_RVI; 102277d6d4a2Smlarkin } 1023c844c4adSderaadt 1024c844c4adSderaadt /* 1025c844c4adSderaadt * Check "L1 flush on VM entry" (Intel L1TF vuln) semantics 1026d31beec1Sguenther * Full details can be found here: 1027d31beec1Sguenther * https://software.intel.com/security-software-guidance/insights/deep-dive-intel-analysis-l1-terminal-fault 1028c844c4adSderaadt */ 1029ccd74f94Sguenther if (ci->ci_vendor == CPUV_INTEL) { 1030c844c4adSderaadt if (ci->ci_feature_sefflags_edx & SEFF0EDX_L1DF) 1031c844c4adSderaadt ci->ci_vmm_cap.vcc_vmx.vmx_has_l1_flush_msr = 1; 1032c844c4adSderaadt else 1033c844c4adSderaadt ci->ci_vmm_cap.vcc_vmx.vmx_has_l1_flush_msr = 0; 1034c844c4adSderaadt 1035c844c4adSderaadt /* 1036c844c4adSderaadt * Certain CPUs may have the vulnerability remedied in 1037d31beec1Sguenther * hardware (RDCL_NO), or we may be nested in an VMM that 1038d31beec1Sguenther * is doing flushes (SKIP_L1DFL_VMENTRY) using the MSR. 1039d31beec1Sguenther * In either case no mitigation at all is necessary. 1040c844c4adSderaadt */ 1041c844c4adSderaadt if (ci->ci_feature_sefflags_edx & SEFF0EDX_ARCH_CAP) { 1042c844c4adSderaadt msr = rdmsr(MSR_ARCH_CAPABILITIES); 10439ff0cc92Sguenther if ((msr & ARCH_CAP_RDCL_NO) || 10449ff0cc92Sguenther ((msr & ARCH_CAP_SKIP_L1DFL_VMENTRY) && 1045d31beec1Sguenther ci->ci_vmm_cap.vcc_vmx.vmx_has_l1_flush_msr)) 1046c844c4adSderaadt ci->ci_vmm_cap.vcc_vmx.vmx_has_l1_flush_msr = 1047c844c4adSderaadt VMX_SKIP_L1D_FLUSH; 1048c844c4adSderaadt } 1049c844c4adSderaadt } 105077d6d4a2Smlarkin } 10515fe96b9aSderaadt #endif /* NVMM > 0 */ 1052