mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-18 19:57:31 +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)
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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) \
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user