mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-19 04:02:05 +00:00
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:
parent
95b6661540
commit
bf1a312fa6
139
arch/x86/cpu.c
139
arch/x86/cpu.c
@ -73,39 +73,84 @@ DEFINE_CPU_DATA(int, state);
|
|||||||
#define VAPIC_FEATURE_VX2APIC_MODE (1 << 5)
|
#define VAPIC_FEATURE_VX2APIC_MODE (1 << 5)
|
||||||
|
|
||||||
struct cpu_capability {
|
struct cpu_capability {
|
||||||
bool tsc_adjust_supported;
|
|
||||||
bool ibrs_ibpb_supported;
|
|
||||||
bool stibp_supported;
|
|
||||||
uint8_t vapic_features;
|
uint8_t vapic_features;
|
||||||
bool monitor_supported;
|
|
||||||
};
|
};
|
||||||
static struct cpu_capability cpu_caps;
|
static struct cpu_capability cpu_caps;
|
||||||
|
|
||||||
|
struct cpuinfo_x86 boot_cpu_data;
|
||||||
|
|
||||||
static void vapic_cap_detect(void);
|
static void vapic_cap_detect(void);
|
||||||
static void monitor_cap_detect(void);
|
|
||||||
static void cpu_set_logical_id(uint32_t logical_id);
|
static void cpu_set_logical_id(uint32_t logical_id);
|
||||||
static void print_hv_banner(void);
|
static void print_hv_banner(void);
|
||||||
static inline bool get_monitor_cap(void);
|
|
||||||
int cpu_find_logical_id(uint32_t lapic_id);
|
int cpu_find_logical_id(uint32_t lapic_id);
|
||||||
#ifndef CONFIG_EFI_STUB
|
#ifndef CONFIG_EFI_STUB
|
||||||
static void start_cpus();
|
static void start_cpus();
|
||||||
#endif
|
#endif
|
||||||
static void pcpu_sync_sleep(unsigned long *sync, int mask_bit);
|
static void pcpu_sync_sleep(unsigned long *sync, int mask_bit);
|
||||||
int ibrs_type;
|
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) ?
|
static inline bool get_monitor_cap(void)
|
||||||
(true) : (false);
|
{
|
||||||
cpu_caps.ibrs_ibpb_supported = (edx & CPUID_EDX_IBRS_IBPB) ?
|
if (boot_cpu_data.cpuid_leaves[FEAT_1_ECX] & CPUID_ECX_MONITOR) {
|
||||||
(true) : (false);
|
/* don't use monitor for CPU (family: 0x6 model: 0x5c)
|
||||||
cpu_caps.stibp_supported = (edx & CPUID_EDX_STIBP) ?
|
* in hypervisor, but still expose it to the guests and
|
||||||
(true) : (false);
|
* 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.
|
/* For speculation defence.
|
||||||
* The default way is to set IBRS at vmexit and then do IBPB at vcpu
|
* 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
|
* should be set all the time instead of relying on retpoline
|
||||||
*/
|
*/
|
||||||
#ifndef CONFIG_RETPOLINE
|
#ifndef CONFIG_RETPOLINE
|
||||||
if (cpu_caps.ibrs_ibpb_supported) {
|
if (get_ibrs_ibpb_cap()) {
|
||||||
ibrs_type = IBRS_RAW;
|
ibrs_type = IBRS_RAW;
|
||||||
if (cpu_caps.stibp_supported)
|
if (get_stibp_cap())
|
||||||
ibrs_type = IBRS_OPT;
|
ibrs_type = IBRS_OPT;
|
||||||
}
|
}
|
||||||
#endif
|
#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)
|
static void alloc_phy_cpu_data(int pcpu_num)
|
||||||
{
|
{
|
||||||
phy_cpu_num = pcpu_num;
|
phy_cpu_num = pcpu_num;
|
||||||
@ -313,12 +343,10 @@ void bsp_boot_init(void)
|
|||||||
set_fs_base();
|
set_fs_base();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
check_cpu_capability();
|
get_cpu_capabilities();
|
||||||
|
|
||||||
vapic_cap_detect();
|
vapic_cap_detect();
|
||||||
|
|
||||||
monitor_cap_detect();
|
|
||||||
|
|
||||||
/* Set state for this CPU to initializing */
|
/* Set state for this CPU to initializing */
|
||||||
cpu_set_current_state(CPU_BOOT_ID, CPU_STATE_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);
|
pr_dbg("Core %d is up", CPU_BOOT_ID);
|
||||||
|
|
||||||
/* Warn for security feature not ready */
|
/* 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("SECURITY WARNING!!!!!!");
|
||||||
pr_fatal("Please apply the latest CPU uCode patch!");
|
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);
|
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;
|
|
||||||
}
|
|
||||||
|
@ -325,8 +325,6 @@ send_startup_ipi(enum intr_cpu_startup_shorthand cpu_startup_shorthand,
|
|||||||
union apic_icr icr;
|
union apic_icr icr;
|
||||||
uint8_t shorthand;
|
uint8_t shorthand;
|
||||||
int status = 0;
|
int status = 0;
|
||||||
uint32_t eax, ebx, ecx, edx;
|
|
||||||
uint32_t family;
|
|
||||||
|
|
||||||
if (cpu_startup_shorthand >= INTR_CPU_STARTUP_UNKNOWN)
|
if (cpu_startup_shorthand >= INTR_CPU_STARTUP_UNKNOWN)
|
||||||
status = -EINVAL;
|
status = -EINVAL;
|
||||||
@ -344,15 +342,6 @@ send_startup_ipi(enum intr_cpu_startup_shorthand cpu_startup_shorthand,
|
|||||||
icr.value_32.hi_32 = 0;
|
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 */
|
/* Assert INIT IPI */
|
||||||
write_lapic_reg32(LAPIC_INT_COMMAND_REGISTER_1, icr.value_32.hi_32);
|
write_lapic_reg32(LAPIC_INT_COMMAND_REGISTER_1, icr.value_32.hi_32);
|
||||||
icr.bits.shorthand = shorthand;
|
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.
|
/* Give 10ms for INIT sequence to complete for old processors.
|
||||||
* Modern processors (family == 6) don't need to wait here.
|
* Modern processors (family == 6) don't need to wait here.
|
||||||
*/
|
*/
|
||||||
if (family != 6)
|
if (boot_cpu_data.x86 != 6)
|
||||||
mdelay(10);
|
mdelay(10);
|
||||||
|
|
||||||
/* De-assert INIT IPI */
|
/* 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);
|
write_lapic_reg32(LAPIC_INT_COMMAND_REGISTER_0, icr.value_32.lo_32);
|
||||||
wait_for_delivery();
|
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);
|
udelay(10);
|
||||||
else /* 200us for old processors */
|
else /* 200us for old processors */
|
||||||
udelay(200);
|
udelay(200);
|
||||||
|
@ -93,17 +93,6 @@ static inline int exec_vmxon(void *addr)
|
|||||||
return status;
|
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)
|
int exec_vmxon_instr(void)
|
||||||
{
|
{
|
||||||
uint64_t tmp64;
|
uint64_t tmp64;
|
||||||
|
@ -216,18 +216,35 @@ extern int phy_cpu_num;
|
|||||||
/* get percpu data for current pcpu */
|
/* get percpu data for current pcpu */
|
||||||
#define get_cpu_var(name) per_cpu(name, get_cpu_id())
|
#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 */
|
/* Function prototypes */
|
||||||
void cpu_halt(uint32_t logical_id);
|
void cpu_halt(uint32_t logical_id);
|
||||||
uint64_t cpu_cycles_per_second(void);
|
uint64_t cpu_cycles_per_second(void);
|
||||||
uint64_t tsc_cycles_in_period(uint16_t timer_period_in_us);
|
uint64_t tsc_cycles_in_period(uint16_t timer_period_in_us);
|
||||||
void cpu_secondary_reset(void);
|
void cpu_secondary_reset(void);
|
||||||
int hv_main(int cpu_id);
|
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_supported(void);
|
||||||
bool is_vapic_intr_delivery_supported(void);
|
bool is_vapic_intr_delivery_supported(void);
|
||||||
bool is_vapic_virt_reg_supported(void);
|
bool is_vapic_virt_reg_supported(void);
|
||||||
|
bool get_vmx_cap(void);
|
||||||
|
|
||||||
/* Read control register */
|
/* Read control register */
|
||||||
#define CPU_CR_READ(cr, result_ptr) \
|
#define CPU_CR_READ(cr, result_ptr) \
|
||||||
|
@ -427,7 +427,6 @@
|
|||||||
#define PAGE_PROTECTED_MODE 2
|
#define PAGE_PROTECTED_MODE 2
|
||||||
|
|
||||||
/* External Interfaces */
|
/* External Interfaces */
|
||||||
bool get_vmx_cap(void);
|
|
||||||
int exec_vmxon_instr(void);
|
int exec_vmxon_instr(void);
|
||||||
uint64_t exec_vmread(uint32_t field);
|
uint64_t exec_vmread(uint32_t field);
|
||||||
uint64_t exec_vmread64(uint32_t field_full);
|
uint64_t exec_vmread64(uint32_t field_full);
|
||||||
|
Loading…
Reference in New Issue
Block a user