diff --git a/arch/x86/cpu.c b/arch/x86/cpu.c index 4542d7f85..fb83f1033 100644 --- a/arch/x86/cpu.c +++ b/arch/x86/cpu.c @@ -73,39 +73,84 @@ DEFINE_CPU_DATA(int, state); #define VAPIC_FEATURE_VX2APIC_MODE (1 << 5) struct cpu_capability { - bool tsc_adjust_supported; - bool ibrs_ibpb_supported; - bool stibp_supported; uint8_t vapic_features; - bool monitor_supported; }; static struct cpu_capability cpu_caps; +struct cpuinfo_x86 boot_cpu_data; + static void vapic_cap_detect(void); -static void monitor_cap_detect(void); static void cpu_set_logical_id(uint32_t logical_id); static void print_hv_banner(void); -static inline bool get_monitor_cap(void); int cpu_find_logical_id(uint32_t lapic_id); #ifndef CONFIG_EFI_STUB static void start_cpus(); #endif static void pcpu_sync_sleep(unsigned long *sync, int mask_bit); int ibrs_type; -static void check_cpu_capability(void) + +static inline bool get_tsc_adjust_cap(void) { - uint32_t eax, ebx, ecx, edx; + return !!(boot_cpu_data.cpuid_leaves[FEAT_7_0_EBX] & CPUID_EBX_TSC_ADJ); +} - memset(&cpu_caps, 0, sizeof(struct cpu_capability)); +static inline bool get_ibrs_ibpb_cap(void) +{ + return !!(boot_cpu_data.cpuid_leaves[FEAT_7_0_EDX] & + CPUID_EDX_IBRS_IBPB); +} - cpuid(CPUID_EXTEND_FEATURE, &eax, &ebx, &ecx, &edx); +static inline bool get_stibp_cap(void) +{ + return !!(boot_cpu_data.cpuid_leaves[FEAT_7_0_EDX] & CPUID_EDX_STIBP); +} - cpu_caps.tsc_adjust_supported = (ebx & CPUID_EBX_TSC_ADJ) ? - (true) : (false); - cpu_caps.ibrs_ibpb_supported = (edx & CPUID_EDX_IBRS_IBPB) ? - (true) : (false); - cpu_caps.stibp_supported = (edx & CPUID_EDX_STIBP) ? - (true) : (false); +static inline bool get_monitor_cap(void) +{ + if (boot_cpu_data.cpuid_leaves[FEAT_1_ECX] & CPUID_ECX_MONITOR) { + /* don't use monitor for CPU (family: 0x6 model: 0x5c) + * in hypervisor, but still expose it to the guests and + * let them handle it correctly + */ + if (boot_cpu_data.x86 != 0x6 || boot_cpu_data.x86_model != 0x5c) + return true; + } + + return false; +} + +inline bool get_vmx_cap(void) +{ + return !!(boot_cpu_data.cpuid_leaves[FEAT_1_ECX] & CPUID_ECX_VMX); +} + +static void get_cpu_capabilities(void) +{ + uint32_t eax, unused; + uint32_t family, model; + + cpuid(CPUID_FEATURES, &eax, &unused, + &boot_cpu_data.cpuid_leaves[FEAT_1_ECX], + &boot_cpu_data.cpuid_leaves[FEAT_1_EDX]); + family = (eax >> 8) & 0xff; + if (family == 0xF) + family += (eax >> 20) & 0xff; + boot_cpu_data.x86 = family; + + model = (eax >> 4) & 0xf; + if (family >= 0x06) + model += ((eax >> 16) & 0xf) << 4; + boot_cpu_data.x86_model = model; + + + cpuid(CPUID_EXTEND_FEATURE, &unused, + &boot_cpu_data.cpuid_leaves[FEAT_7_0_EBX], + &boot_cpu_data.cpuid_leaves[FEAT_7_0_ECX], + &boot_cpu_data.cpuid_leaves[FEAT_7_0_EDX]); + + cpuid(CPUID_EXTEND_FUNCTION_1, &unused, &unused, + &boot_cpu_data.cpuid_leaves[FEAT_8000_0001_ECX], + &boot_cpu_data.cpuid_leaves[FEAT_8000_0001_EDX]); /* For speculation defence. * The default way is to set IBRS at vmexit and then do IBPB at vcpu @@ -123,29 +168,14 @@ static void check_cpu_capability(void) * should be set all the time instead of relying on retpoline */ #ifndef CONFIG_RETPOLINE - if (cpu_caps.ibrs_ibpb_supported) { + if (get_ibrs_ibpb_cap()) { ibrs_type = IBRS_RAW; - if (cpu_caps.stibp_supported) + if (get_stibp_cap()) ibrs_type = IBRS_OPT; } #endif } -bool check_tsc_adjust_support(void) -{ - return cpu_caps.tsc_adjust_supported; -} - -bool check_ibrs_ibpb_support(void) -{ - return cpu_caps.ibrs_ibpb_supported; -} - -bool check_stibp_support(void) -{ - return cpu_caps.stibp_supported; -} - static void alloc_phy_cpu_data(int pcpu_num) { phy_cpu_num = pcpu_num; @@ -313,12 +343,10 @@ void bsp_boot_init(void) set_fs_base(); #endif - check_cpu_capability(); + get_cpu_capabilities(); vapic_cap_detect(); - monitor_cap_detect(); - /* Set state for this CPU to initializing */ cpu_set_current_state(CPU_BOOT_ID, CPU_STATE_INITIALIZING); @@ -361,7 +389,7 @@ void bsp_boot_init(void) pr_dbg("Core %d is up", CPU_BOOT_ID); /* Warn for security feature not ready */ - if (!check_ibrs_ibpb_support() && !check_stibp_support()) { + if (!get_ibrs_ibpb_cap() && !get_stibp_cap()) { pr_fatal("SECURITY WARNING!!!!!!"); pr_fatal("Please apply the latest CPU uCode patch!"); } @@ -654,40 +682,3 @@ bool is_vapic_virt_reg_supported(void) { return ((cpu_caps.vapic_features & VAPIC_FEATURE_VIRT_REG) != 0); } - -static void monitor_cap_detect(void) -{ - uint32_t eax, ebx, ecx, edx; - uint32_t family; - uint32_t model; - - /* Run CPUID to determine if MONITOR support available */ - cpuid(CPUID_FEATURES, &eax, &ebx, &ecx, &edx); - - /* See if MONITOR feature bit is set in ECX */ - if (ecx & CPUID_ECX_MONITOR) - cpu_caps.monitor_supported = true; - - /* don't use monitor for CPU (family: 0x6 model: 0x5c) - * in hypervisor, but still expose it to the guests and - * let them handle it correctly - */ - family = (eax >> 8) & 0xff; - if (family == 0xF) - family += (eax >> 20) & 0xff; - - model = (eax >> 4) & 0xf; - if (family >= 0x06) - model += ((eax >> 16) & 0xf) << 4; - - if (cpu_caps.monitor_supported && - (family == 0x06) && - (model == 0x5c)) { - cpu_caps.monitor_supported = false; - } -} - -static inline bool get_monitor_cap(void) -{ - return cpu_caps.monitor_supported; -} diff --git a/arch/x86/intr_lapic.c b/arch/x86/intr_lapic.c index f9eb07e39..3c69d3666 100644 --- a/arch/x86/intr_lapic.c +++ b/arch/x86/intr_lapic.c @@ -325,8 +325,6 @@ send_startup_ipi(enum intr_cpu_startup_shorthand cpu_startup_shorthand, union apic_icr icr; uint8_t shorthand; int status = 0; - uint32_t eax, ebx, ecx, edx; - uint32_t family; if (cpu_startup_shorthand >= INTR_CPU_STARTUP_UNKNOWN) status = -EINVAL; @@ -344,15 +342,6 @@ send_startup_ipi(enum intr_cpu_startup_shorthand cpu_startup_shorthand, icr.value_32.hi_32 = 0; } - /* - * family calculation from SDM Vol. 2A - * CPUID with INPUT EAX=01h:Returns Model, Family, Stepping Information - */ - cpuid(CPUID_FEATURES, &eax, &ebx, &ecx, &edx); - family = (eax >> 8) & 0xff; - if (family == 0xF) - family += (eax >> 20) & 0xff; - /* Assert INIT IPI */ write_lapic_reg32(LAPIC_INT_COMMAND_REGISTER_1, icr.value_32.hi_32); icr.bits.shorthand = shorthand; @@ -365,7 +354,7 @@ send_startup_ipi(enum intr_cpu_startup_shorthand cpu_startup_shorthand, /* Give 10ms for INIT sequence to complete for old processors. * Modern processors (family == 6) don't need to wait here. */ - if (family != 6) + if (boot_cpu_data.x86 != 6) mdelay(10); /* De-assert INIT IPI */ @@ -383,7 +372,7 @@ send_startup_ipi(enum intr_cpu_startup_shorthand cpu_startup_shorthand, write_lapic_reg32(LAPIC_INT_COMMAND_REGISTER_0, icr.value_32.lo_32); wait_for_delivery(); - if (family == 6) /* 10us is enough for Modern processors */ + if (boot_cpu_data.x86 == 6) /* 10us is enough for Modern processors */ udelay(10); else /* 200us for old processors */ udelay(200); diff --git a/arch/x86/vmx.c b/arch/x86/vmx.c index ac04e20de..fe53f16a5 100644 --- a/arch/x86/vmx.c +++ b/arch/x86/vmx.c @@ -93,17 +93,6 @@ static inline int exec_vmxon(void *addr) return status; } -bool get_vmx_cap(void) -{ - uint32_t eax, ebx, ecx, edx; - - /* Run CPUID to determine if VTX support available */ - cpuid(CPUID_FEATURES, &eax, &ebx, &ecx, &edx); - - /* See if VMX feature bit is set in ECX */ - return !!(ecx & CPUID_ECX_VMX); -} - int exec_vmxon_instr(void) { uint64_t tmp64; diff --git a/include/arch/x86/cpu.h b/include/arch/x86/cpu.h index 8f6c5dccd..300eb64d8 100644 --- a/include/arch/x86/cpu.h +++ b/include/arch/x86/cpu.h @@ -216,18 +216,35 @@ extern int phy_cpu_num; /* get percpu data for current pcpu */ #define get_cpu_var(name) per_cpu(name, get_cpu_id()) +/* CPUID feature words */ +enum feature_word { + FEAT_1_ECX, /* CPUID[1].ECX */ + FEAT_1_EDX, /* CPUID[1].EDX */ + FEAT_7_0_EBX, /* CPUID[EAX=7,ECX=0].EBX */ + FEAT_7_0_ECX, /* CPUID[EAX=7,ECX=0].ECX */ + FEAT_7_0_EDX, /* CPUID[EAX=7,ECX=0].EDX */ + FEAT_8000_0001_ECX, /* CPUID[8000_0001].ECX */ + FEAT_8000_0001_EDX, /* CPUID[8000_0001].EDX */ + FEATURE_WORDS, +}; + +struct cpuinfo_x86 { + uint8_t x86, x86_model; + uint32_t cpuid_leaves[FEATURE_WORDS]; +}; + +extern struct cpuinfo_x86 boot_cpu_data; + /* Function prototypes */ void cpu_halt(uint32_t logical_id); uint64_t cpu_cycles_per_second(void); uint64_t tsc_cycles_in_period(uint16_t timer_period_in_us); void cpu_secondary_reset(void); int hv_main(int cpu_id); -bool check_tsc_adjust_support(void); -bool check_ibrs_ibpb_support(void); -bool check_stibp_support(void); bool is_vapic_supported(void); bool is_vapic_intr_delivery_supported(void); bool is_vapic_virt_reg_supported(void); +bool get_vmx_cap(void); /* Read control register */ #define CPU_CR_READ(cr, result_ptr) \ diff --git a/include/arch/x86/vmx.h b/include/arch/x86/vmx.h index 34507d625..317f1e1a6 100644 --- a/include/arch/x86/vmx.h +++ b/include/arch/x86/vmx.h @@ -427,7 +427,6 @@ #define PAGE_PROTECTED_MODE 2 /* External Interfaces */ -bool get_vmx_cap(void); int exec_vmxon_instr(void); uint64_t exec_vmread(uint32_t field); uint64_t exec_vmread64(uint32_t field_full);