Add cpuinfo_x86 to cache cpu capability/feature

Add a global boot_cpu_data to cache common cpu capbility/feature
for detect cpu capbility/feature.

Signed-off-by: Li, Fei1 <fei1.li@intel.com>
Acked-by: Xu, Anthony <anthony.xu@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
Li, Fei1 2018-03-21 21:14:14 +08:00 committed by fuzhongl
parent 95b6661540
commit bf1a312fa6
5 changed files with 87 additions and 102 deletions

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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) \

View File

@ -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);