mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-28 08:16:54 +00:00
modulization: move functions related with cpu caps into cpu_caps.c
move cpu caps related functions like capability init/detect/check in cpu.c & mmu.c into a new file cpu_caps.c Changes to be committed: modified: developer-guides/hld/hv-memmgt.rst modified: ../hypervisor/Makefile modified: ../hypervisor/arch/x86/cpu.c new file: ../hypervisor/arch/x86/cpu_caps.c modified: ../hypervisor/arch/x86/mmu.c modified: ../hypervisor/arch/x86/vmx_asm.S modified: ../hypervisor/include/arch/x86/cpu.h new file: ../hypervisor/include/arch/x86/cpu_caps.h modified: ../hypervisor/include/arch/x86/guest/vm.h modified: ../hypervisor/include/arch/x86/mmu.h modified: ../hypervisor/include/arch/x86/vmcs.h Tracked-On: #1842 Signed-off-by: Jason Chen CJ <jason.cj.chen@intel.com> Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
parent
b8ffac8bac
commit
746fbe147d
@ -418,9 +418,6 @@ Here is a list of major memory related APIs in HV:
|
||||
EPT/VPID Capability Checking
|
||||
----------------------------
|
||||
|
||||
.. doxygenfunction:: check_vmx_mmu_cap
|
||||
:project: Project ACRN
|
||||
|
||||
Data Transferring between hypervisor and VM
|
||||
-------------------------------------------
|
||||
|
||||
|
@ -136,6 +136,7 @@ S_SRCS += arch/x86/idt.S
|
||||
C_SRCS += arch/x86/ioapic.c
|
||||
C_SRCS += arch/x86/lapic.c
|
||||
C_SRCS += arch/x86/cpu.c
|
||||
C_SRCS += arch/x86/cpu_caps.c
|
||||
C_SRCS += arch/x86/mmu.c
|
||||
C_SRCS += arch/x86/e820.c
|
||||
C_SRCS += arch/x86/pagetable.c
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <version.h>
|
||||
#include <trampoline.h>
|
||||
#include <e820.h>
|
||||
#include <cpu_caps.h>
|
||||
|
||||
struct per_cpu_region per_cpu_data[CONFIG_MAX_PCPU_NUM] __aligned(PAGE_SIZE);
|
||||
uint16_t phys_cpu_num = 0U;
|
||||
@ -20,265 +21,12 @@ static uint64_t startup_paddr = 0UL;
|
||||
/* physical cpu active bitmap, support up to 64 cpus */
|
||||
uint64_t pcpu_active_bitmap = 0UL;
|
||||
|
||||
static bool skip_l1dfl_vmentry;
|
||||
static uint64_t x86_arch_capabilities;
|
||||
|
||||
/* TODO: add more capability per requirement */
|
||||
/* APICv features */
|
||||
#define VAPIC_FEATURE_VIRT_ACCESS (1U << 0U)
|
||||
#define VAPIC_FEATURE_VIRT_REG (1U << 1U)
|
||||
#define VAPIC_FEATURE_INTR_DELIVERY (1U << 2U)
|
||||
#define VAPIC_FEATURE_TPR_SHADOW (1U << 3U)
|
||||
#define VAPIC_FEATURE_POST_INTR (1U << 4U)
|
||||
#define VAPIC_FEATURE_VX2APIC_MODE (1U << 5U)
|
||||
|
||||
struct cpu_capability {
|
||||
uint8_t apicv_features;
|
||||
uint8_t ept_features;
|
||||
};
|
||||
static struct cpu_capability cpu_caps;
|
||||
|
||||
struct cpuinfo_x86 boot_cpu_data;
|
||||
|
||||
static void cpu_cap_detect(void);
|
||||
static void cpu_xsave_init(void);
|
||||
static void set_current_cpu_id(uint16_t pcpu_id);
|
||||
static void print_hv_banner(void);
|
||||
static uint16_t get_cpu_id_from_lapic_id(uint32_t lapic_id);
|
||||
int32_t ibrs_type;
|
||||
static uint64_t start_tsc __attribute__((__section__(".bss_noinit")));
|
||||
|
||||
bool cpu_has_cap(uint32_t bit)
|
||||
{
|
||||
uint32_t feat_idx = bit >> 5U;
|
||||
uint32_t feat_bit = bit & 0x1fU;
|
||||
bool ret;
|
||||
|
||||
if (feat_idx >= FEATURE_WORDS) {
|
||||
ret = false;
|
||||
} else {
|
||||
ret = ((boot_cpu_data.cpuid_leaves[feat_idx] & (1U << feat_bit)) != 0U);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline bool get_monitor_cap(void)
|
||||
{
|
||||
if (cpu_has_cap(X86_FEATURE_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.family != 0x6U) || (boot_cpu_data.model != 0x5cU)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool is_fast_string_erms_supported_and_enabled(void)
|
||||
{
|
||||
bool ret = false;
|
||||
uint32_t misc_enable = (uint32_t)msr_read(MSR_IA32_MISC_ENABLE);
|
||||
|
||||
if ((misc_enable & MSR_IA32_MISC_ENABLE_FAST_STRING) == 0U) {
|
||||
pr_fatal("%s, fast string is not enabled\n", __func__);
|
||||
} else {
|
||||
if (!cpu_has_cap(X86_FEATURE_ERMS)) {
|
||||
pr_fatal("%s, enhanced rep movsb/stosb not supported\n", __func__);
|
||||
} else {
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint64_t get_address_mask(uint8_t limit)
|
||||
{
|
||||
return ((1UL << limit) - 1UL) & PAGE_MASK;
|
||||
}
|
||||
|
||||
static void get_cpu_capabilities(void)
|
||||
{
|
||||
uint32_t eax, unused;
|
||||
uint32_t family, model;
|
||||
|
||||
cpuid(CPUID_VENDORSTRING,
|
||||
&boot_cpu_data.cpuid_level,
|
||||
&unused, &unused, &unused);
|
||||
|
||||
cpuid(CPUID_FEATURES, &eax, &unused,
|
||||
&boot_cpu_data.cpuid_leaves[FEAT_1_ECX],
|
||||
&boot_cpu_data.cpuid_leaves[FEAT_1_EDX]);
|
||||
family = (eax >> 8U) & 0xffU;
|
||||
if (family == 0xFU) {
|
||||
family += (eax >> 20U) & 0xffU;
|
||||
}
|
||||
boot_cpu_data.family = (uint8_t)family;
|
||||
|
||||
model = (eax >> 4U) & 0xfU;
|
||||
if (family >= 0x06U) {
|
||||
model += ((eax >> 16U) & 0xfU) << 4U;
|
||||
}
|
||||
boot_cpu_data.model = (uint8_t)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_MAX_EXTENDED_FUNCTION,
|
||||
&boot_cpu_data.extended_cpuid_level,
|
||||
&unused, &unused, &unused);
|
||||
|
||||
if (boot_cpu_data.extended_cpuid_level >= CPUID_EXTEND_FUNCTION_1) {
|
||||
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]);
|
||||
}
|
||||
|
||||
if (boot_cpu_data.extended_cpuid_level >= CPUID_EXTEND_ADDRESS_SIZE) {
|
||||
cpuid(CPUID_EXTEND_ADDRESS_SIZE, &eax,
|
||||
&boot_cpu_data.cpuid_leaves[FEAT_8000_0008_EBX],
|
||||
&unused, &unused);
|
||||
|
||||
/* EAX bits 07-00: #Physical Address Bits
|
||||
* bits 15-08: #Linear Address Bits
|
||||
*/
|
||||
boot_cpu_data.virt_bits = (uint8_t)((eax >> 8U) & 0xffU);
|
||||
boot_cpu_data.phys_bits = (uint8_t)(eax & 0xffU);
|
||||
boot_cpu_data.physical_address_mask =
|
||||
get_address_mask(boot_cpu_data.phys_bits);
|
||||
}
|
||||
|
||||
/* For speculation defence.
|
||||
* The default way is to set IBRS at vmexit and then do IBPB at vcpu
|
||||
* context switch(ibrs_type == IBRS_RAW).
|
||||
* Now provide an optimized way (ibrs_type == IBRS_OPT) which set
|
||||
* STIBP and do IBPB at vmexit,since having STIBP always set has less
|
||||
* impact than having IBRS always set. Also since IBPB is already done
|
||||
* at vmexit, it is no necessary to do so at vcpu context switch then.
|
||||
*/
|
||||
ibrs_type = IBRS_NONE;
|
||||
|
||||
/* Currently for APL, if we enabled retpoline, then IBRS should not
|
||||
* take effect
|
||||
* TODO: add IA32_ARCH_CAPABILITIES[1] check, if this bit is set, IBRS
|
||||
* should be set all the time instead of relying on retpoline
|
||||
*/
|
||||
#ifndef CONFIG_RETPOLINE
|
||||
if (cpu_has_cap(X86_FEATURE_IBRS_IBPB)) {
|
||||
ibrs_type = IBRS_RAW;
|
||||
if (cpu_has_cap(X86_FEATURE_STIBP)) {
|
||||
ibrs_type = IBRS_OPT;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* basic hardware capability check
|
||||
* we should supplement which feature/capability we must support
|
||||
* here later.
|
||||
*/
|
||||
static int32_t hardware_detect_support(void)
|
||||
{
|
||||
int32_t ret;
|
||||
|
||||
/* Long Mode (x86-64, 64-bit support) */
|
||||
if (!cpu_has_cap(X86_FEATURE_LM)) {
|
||||
pr_fatal("%s, LM not supported\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
if ((boot_cpu_data.phys_bits == 0U) ||
|
||||
(boot_cpu_data.virt_bits == 0U)) {
|
||||
pr_fatal("%s, can't detect Linear/Physical Address size\n",
|
||||
__func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* lapic TSC deadline timer */
|
||||
if (!cpu_has_cap(X86_FEATURE_TSC_DEADLINE)) {
|
||||
pr_fatal("%s, TSC deadline not supported\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Execute Disable */
|
||||
if (!cpu_has_cap(X86_FEATURE_NX)) {
|
||||
pr_fatal("%s, NX not supported\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Supervisor-Mode Execution Prevention */
|
||||
if (!cpu_has_cap(X86_FEATURE_SMEP)) {
|
||||
pr_fatal("%s, SMEP not supported\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Supervisor-Mode Access Prevention */
|
||||
if (!cpu_has_cap(X86_FEATURE_SMAP)) {
|
||||
pr_fatal("%s, SMAP not supported\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!cpu_has_cap(X86_FEATURE_MTRR)) {
|
||||
pr_fatal("%s, MTRR not supported\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!cpu_has_cap(X86_FEATURE_PAGE1GB)) {
|
||||
pr_fatal("%s, not support 1GB page\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!cpu_has_cap(X86_FEATURE_VMX)) {
|
||||
pr_fatal("%s, vmx not supported\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!is_fast_string_erms_supported_and_enabled()) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
||||
if (!cpu_has_vmx_unrestricted_guest_cap()) {
|
||||
pr_fatal("%s, unrestricted guest not supported\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!is_ept_supported()) {
|
||||
pr_fatal("%s, EPT not supported\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (boot_cpu_data.cpuid_level < 0x15U) {
|
||||
pr_fatal("%s, required CPU feature not supported\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (is_vmx_disabled()) {
|
||||
pr_fatal("%s, VMX can not be enabled\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (phys_cpu_num > CONFIG_MAX_PCPU_NUM) {
|
||||
pr_fatal("%s, pcpu number(%d) is out of range\n", __func__, phys_cpu_num);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = check_vmx_mmu_cap();
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
pr_acrnlog("hardware support HV");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void init_percpu_lapic_id(void)
|
||||
{
|
||||
uint16_t i;
|
||||
@ -342,49 +90,6 @@ static void set_fs_base(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void get_cpu_name(void)
|
||||
{
|
||||
cpuid(CPUID_EXTEND_FUNCTION_2,
|
||||
(uint32_t *)(boot_cpu_data.model_name),
|
||||
(uint32_t *)(&boot_cpu_data.model_name[4]),
|
||||
(uint32_t *)(&boot_cpu_data.model_name[8]),
|
||||
(uint32_t *)(&boot_cpu_data.model_name[12]));
|
||||
cpuid(CPUID_EXTEND_FUNCTION_3,
|
||||
(uint32_t *)(&boot_cpu_data.model_name[16]),
|
||||
(uint32_t *)(&boot_cpu_data.model_name[20]),
|
||||
(uint32_t *)(&boot_cpu_data.model_name[24]),
|
||||
(uint32_t *)(&boot_cpu_data.model_name[28]));
|
||||
cpuid(CPUID_EXTEND_FUNCTION_4,
|
||||
(uint32_t *)(&boot_cpu_data.model_name[32]),
|
||||
(uint32_t *)(&boot_cpu_data.model_name[36]),
|
||||
(uint32_t *)(&boot_cpu_data.model_name[40]),
|
||||
(uint32_t *)(&boot_cpu_data.model_name[44]));
|
||||
|
||||
boot_cpu_data.model_name[48] = '\0';
|
||||
}
|
||||
|
||||
static bool check_cpu_security_config(void)
|
||||
{
|
||||
if (cpu_has_cap(X86_FEATURE_ARCH_CAP)) {
|
||||
x86_arch_capabilities = msr_read(MSR_IA32_ARCH_CAPABILITIES);
|
||||
skip_l1dfl_vmentry = ((x86_arch_capabilities
|
||||
& IA32_ARCH_CAP_SKIP_L1DFL_VMENTRY) != 0UL);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((!cpu_has_cap(X86_FEATURE_L1D_FLUSH)) && (!skip_l1dfl_vmentry)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!cpu_has_cap(X86_FEATURE_IBRS_IBPB) &&
|
||||
!cpu_has_cap(X86_FEATURE_STIBP)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void init_cpu_pre(uint16_t pcpu_id)
|
||||
{
|
||||
if (pcpu_id == BOOT_CPU_ID) {
|
||||
@ -688,117 +393,6 @@ void wait_sync_change(uint64_t *sync, uint64_t wake_sync)
|
||||
}
|
||||
}
|
||||
|
||||
/*check allowed ONEs setting in vmx control*/
|
||||
static bool is_ctrl_setting_allowed(uint64_t msr_val, uint32_t ctrl)
|
||||
{
|
||||
/*
|
||||
* Intel SDM Appendix A.3
|
||||
* - bitX in ctrl can be set 1
|
||||
* only if bit 32+X in msr_val is 1
|
||||
*/
|
||||
return ((((uint32_t)(msr_val >> 32UL)) & ctrl) == ctrl);
|
||||
}
|
||||
|
||||
static void ept_cap_detect(void)
|
||||
{
|
||||
uint64_t msr_val;
|
||||
|
||||
cpu_caps.ept_features = 0U;
|
||||
|
||||
/* Read primary processor based VM control. */
|
||||
msr_val = msr_read(MSR_IA32_VMX_PROCBASED_CTLS);
|
||||
|
||||
/*
|
||||
* According to SDM A.3.2 Primary Processor-Based VM-Execution Controls:
|
||||
* The IA32_VMX_PROCBASED_CTLS MSR (index 482H) reports on the allowed
|
||||
* settings of most of the primary processor-based VM-execution controls
|
||||
* (see Section 24.6.2):
|
||||
* Bits 63:32 indicate the allowed 1-settings of these controls.
|
||||
* VM entry allows control X to be 1 if bit 32+X in the MSR is set to 1;
|
||||
* if bit 32+X in the MSR is cleared to 0, VM entry fails if control X
|
||||
* is 1.
|
||||
*/
|
||||
msr_val = msr_val >> 32U;
|
||||
|
||||
/* Check if secondary processor based VM control is available. */
|
||||
if ((msr_val & VMX_PROCBASED_CTLS_SECONDARY) != 0UL) {
|
||||
/* Read secondary processor based VM control. */
|
||||
msr_val = msr_read(MSR_IA32_VMX_PROCBASED_CTLS2);
|
||||
|
||||
if (is_ctrl_setting_allowed(msr_val, VMX_PROCBASED_CTLS2_EPT)) {
|
||||
cpu_caps.ept_features = 1U;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void apicv_cap_detect(void)
|
||||
{
|
||||
uint8_t features;
|
||||
uint64_t msr_val;
|
||||
|
||||
msr_val = msr_read(MSR_IA32_VMX_PROCBASED_CTLS);
|
||||
if (!is_ctrl_setting_allowed(msr_val, VMX_PROCBASED_CTLS_TPR_SHADOW)) {
|
||||
pr_fatal("APICv: No APIC TPR virtualization support.");
|
||||
return;
|
||||
}
|
||||
|
||||
msr_val = msr_read(MSR_IA32_VMX_PROCBASED_CTLS2);
|
||||
if (!is_ctrl_setting_allowed(msr_val, VMX_PROCBASED_CTLS2_VAPIC)) {
|
||||
pr_fatal("APICv: No APIC-access virtualization support.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_ctrl_setting_allowed(msr_val, VMX_PROCBASED_CTLS2_VAPIC_REGS)) {
|
||||
pr_fatal("APICv: No APIC-register virtualization support.");
|
||||
return;
|
||||
}
|
||||
|
||||
features = (VAPIC_FEATURE_TPR_SHADOW
|
||||
| VAPIC_FEATURE_VIRT_ACCESS
|
||||
| VAPIC_FEATURE_VIRT_REG);
|
||||
|
||||
if (is_ctrl_setting_allowed(msr_val, VMX_PROCBASED_CTLS2_VX2APIC)) {
|
||||
features |= VAPIC_FEATURE_VX2APIC_MODE;
|
||||
}
|
||||
|
||||
if (is_ctrl_setting_allowed(msr_val, VMX_PROCBASED_CTLS2_VIRQ)) {
|
||||
features |= VAPIC_FEATURE_INTR_DELIVERY;
|
||||
|
||||
msr_val = msr_read(MSR_IA32_VMX_PINBASED_CTLS);
|
||||
if (is_ctrl_setting_allowed(msr_val,
|
||||
VMX_PINBASED_CTLS_POST_IRQ)) {
|
||||
features |= VAPIC_FEATURE_POST_INTR;
|
||||
}
|
||||
}
|
||||
cpu_caps.apicv_features = features;
|
||||
}
|
||||
|
||||
static void cpu_cap_detect(void)
|
||||
{
|
||||
apicv_cap_detect();
|
||||
ept_cap_detect();
|
||||
}
|
||||
|
||||
bool is_ept_supported(void)
|
||||
{
|
||||
return (cpu_caps.ept_features != 0U);
|
||||
}
|
||||
|
||||
bool is_apicv_reg_virtualization_supported(void)
|
||||
{
|
||||
return ((cpu_caps.apicv_features & VAPIC_FEATURE_VIRT_REG) != 0U);
|
||||
}
|
||||
|
||||
bool is_apicv_intr_delivery_supported(void)
|
||||
{
|
||||
return ((cpu_caps.apicv_features & VAPIC_FEATURE_INTR_DELIVERY) != 0U);
|
||||
}
|
||||
|
||||
bool is_apicv_posted_intr_supported(void)
|
||||
{
|
||||
return ((cpu_caps.apicv_features & VAPIC_FEATURE_POST_INTR) != 0U);
|
||||
}
|
||||
|
||||
static void cpu_xsave_init(void)
|
||||
{
|
||||
uint64_t val64;
|
||||
@ -820,18 +414,3 @@ static void cpu_xsave_init(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_l1d_flush(void)
|
||||
{
|
||||
/*
|
||||
* 'skip_l1dfl_vmentry' will be true on platform that
|
||||
* is not affected by L1TF.
|
||||
*
|
||||
*/
|
||||
if (!skip_l1dfl_vmentry) {
|
||||
if (cpu_has_cap(X86_FEATURE_L1D_FLUSH)) {
|
||||
msr_write(MSR_IA32_FLUSH_CMD, IA32_L1D_FLUSH);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
505
hypervisor/arch/x86/cpu_caps.c
Normal file
505
hypervisor/arch/x86/cpu_caps.c
Normal file
@ -0,0 +1,505 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <types.h>
|
||||
#include <msr.h>
|
||||
#include <page.h>
|
||||
#include <cpufeatures.h>
|
||||
#include <cpuid.h>
|
||||
#include <spinlock.h>
|
||||
#include <cpu.h>
|
||||
#include <per_cpu.h>
|
||||
#include <vmx.h>
|
||||
#include <cpu_caps.h>
|
||||
#include <errno.h>
|
||||
#include <logmsg.h>
|
||||
|
||||
/* TODO: add more capability per requirement */
|
||||
/* APICv features */
|
||||
#define VAPIC_FEATURE_VIRT_ACCESS (1U << 0U)
|
||||
#define VAPIC_FEATURE_VIRT_REG (1U << 1U)
|
||||
#define VAPIC_FEATURE_INTR_DELIVERY (1U << 2U)
|
||||
#define VAPIC_FEATURE_TPR_SHADOW (1U << 3U)
|
||||
#define VAPIC_FEATURE_POST_INTR (1U << 4U)
|
||||
#define VAPIC_FEATURE_VX2APIC_MODE (1U << 5U)
|
||||
|
||||
static struct vmx_capability {
|
||||
uint32_t ept;
|
||||
uint32_t vpid;
|
||||
} vmx_caps;
|
||||
|
||||
struct cpu_capability {
|
||||
uint8_t apicv_features;
|
||||
uint8_t ept_features;
|
||||
};
|
||||
static struct cpu_capability cpu_caps;
|
||||
|
||||
struct cpuinfo_x86 boot_cpu_data;
|
||||
|
||||
static bool skip_l1dfl_vmentry;
|
||||
static uint64_t x86_arch_capabilities;
|
||||
int32_t ibrs_type;
|
||||
|
||||
bool cpu_has_cap(uint32_t bit)
|
||||
{
|
||||
uint32_t feat_idx = bit >> 5U;
|
||||
uint32_t feat_bit = bit & 0x1fU;
|
||||
bool ret;
|
||||
|
||||
if (feat_idx >= FEATURE_WORDS) {
|
||||
ret = false;
|
||||
} else {
|
||||
ret = ((boot_cpu_data.cpuid_leaves[feat_idx] & (1U << feat_bit)) != 0U);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool get_monitor_cap(void)
|
||||
{
|
||||
if (cpu_has_cap(X86_FEATURE_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.family != 0x6U) || (boot_cpu_data.model != 0x5cU)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool is_fast_string_erms_supported_and_enabled(void)
|
||||
{
|
||||
bool ret = false;
|
||||
uint32_t misc_enable = (uint32_t)msr_read(MSR_IA32_MISC_ENABLE);
|
||||
|
||||
if ((misc_enable & MSR_IA32_MISC_ENABLE_FAST_STRING) == 0U) {
|
||||
pr_fatal("%s, fast string is not enabled\n", __func__);
|
||||
} else {
|
||||
if (!cpu_has_cap(X86_FEATURE_ERMS)) {
|
||||
pr_fatal("%s, enhanced rep movsb/stosb not supported\n", __func__);
|
||||
} else {
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint64_t get_address_mask(uint8_t limit)
|
||||
{
|
||||
return ((1UL << limit) - 1UL) & PAGE_MASK;
|
||||
}
|
||||
|
||||
void get_cpu_capabilities(void)
|
||||
{
|
||||
uint32_t eax, unused;
|
||||
uint32_t family, model;
|
||||
|
||||
cpuid(CPUID_VENDORSTRING,
|
||||
&boot_cpu_data.cpuid_level,
|
||||
&unused, &unused, &unused);
|
||||
|
||||
cpuid(CPUID_FEATURES, &eax, &unused,
|
||||
&boot_cpu_data.cpuid_leaves[FEAT_1_ECX],
|
||||
&boot_cpu_data.cpuid_leaves[FEAT_1_EDX]);
|
||||
family = (eax >> 8U) & 0xffU;
|
||||
if (family == 0xFU) {
|
||||
family += (eax >> 20U) & 0xffU;
|
||||
}
|
||||
boot_cpu_data.family = (uint8_t)family;
|
||||
|
||||
model = (eax >> 4U) & 0xfU;
|
||||
if (family >= 0x06U) {
|
||||
model += ((eax >> 16U) & 0xfU) << 4U;
|
||||
}
|
||||
boot_cpu_data.model = (uint8_t)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_MAX_EXTENDED_FUNCTION,
|
||||
&boot_cpu_data.extended_cpuid_level,
|
||||
&unused, &unused, &unused);
|
||||
|
||||
if (boot_cpu_data.extended_cpuid_level >= CPUID_EXTEND_FUNCTION_1) {
|
||||
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]);
|
||||
}
|
||||
|
||||
if (boot_cpu_data.extended_cpuid_level >= CPUID_EXTEND_ADDRESS_SIZE) {
|
||||
cpuid(CPUID_EXTEND_ADDRESS_SIZE, &eax,
|
||||
&boot_cpu_data.cpuid_leaves[FEAT_8000_0008_EBX],
|
||||
&unused, &unused);
|
||||
|
||||
/* EAX bits 07-00: #Physical Address Bits
|
||||
* bits 15-08: #Linear Address Bits
|
||||
*/
|
||||
boot_cpu_data.virt_bits = (uint8_t)((eax >> 8U) & 0xffU);
|
||||
boot_cpu_data.phys_bits = (uint8_t)(eax & 0xffU);
|
||||
boot_cpu_data.physical_address_mask =
|
||||
get_address_mask(boot_cpu_data.phys_bits);
|
||||
}
|
||||
|
||||
/* For speculation defence.
|
||||
* The default way is to set IBRS at vmexit and then do IBPB at vcpu
|
||||
* context switch(ibrs_type == IBRS_RAW).
|
||||
* Now provide an optimized way (ibrs_type == IBRS_OPT) which set
|
||||
* STIBP and do IBPB at vmexit,since having STIBP always set has less
|
||||
* impact than having IBRS always set. Also since IBPB is already done
|
||||
* at vmexit, it is no necessary to do so at vcpu context switch then.
|
||||
*/
|
||||
ibrs_type = IBRS_NONE;
|
||||
|
||||
/* Currently for APL, if we enabled retpoline, then IBRS should not
|
||||
* take effect
|
||||
* TODO: add IA32_ARCH_CAPABILITIES[1] check, if this bit is set, IBRS
|
||||
* should be set all the time instead of relying on retpoline
|
||||
*/
|
||||
#ifndef CONFIG_RETPOLINE
|
||||
if (cpu_has_cap(X86_FEATURE_IBRS_IBPB)) {
|
||||
ibrs_type = IBRS_RAW;
|
||||
if (cpu_has_cap(X86_FEATURE_STIBP)) {
|
||||
ibrs_type = IBRS_OPT;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*check allowed ONEs setting in vmx control*/
|
||||
static bool is_ctrl_setting_allowed(uint64_t msr_val, uint32_t ctrl)
|
||||
{
|
||||
/*
|
||||
* Intel SDM Appendix A.3
|
||||
* - bitX in ctrl can be set 1
|
||||
* only if bit 32+X in msr_val is 1
|
||||
*/
|
||||
return ((((uint32_t)(msr_val >> 32UL)) & ctrl) == ctrl);
|
||||
}
|
||||
|
||||
static void ept_cap_detect(void)
|
||||
{
|
||||
uint64_t msr_val;
|
||||
|
||||
cpu_caps.ept_features = 0U;
|
||||
|
||||
/* Read primary processor based VM control. */
|
||||
msr_val = msr_read(MSR_IA32_VMX_PROCBASED_CTLS);
|
||||
|
||||
/*
|
||||
* According to SDM A.3.2 Primary Processor-Based VM-Execution Controls:
|
||||
* The IA32_VMX_PROCBASED_CTLS MSR (index 482H) reports on the allowed
|
||||
* settings of most of the primary processor-based VM-execution controls
|
||||
* (see Section 24.6.2):
|
||||
* Bits 63:32 indicate the allowed 1-settings of these controls.
|
||||
* VM entry allows control X to be 1 if bit 32+X in the MSR is set to 1;
|
||||
* if bit 32+X in the MSR is cleared to 0, VM entry fails if control X
|
||||
* is 1.
|
||||
*/
|
||||
msr_val = msr_val >> 32U;
|
||||
|
||||
/* Check if secondary processor based VM control is available. */
|
||||
if ((msr_val & VMX_PROCBASED_CTLS_SECONDARY) != 0UL) {
|
||||
/* Read secondary processor based VM control. */
|
||||
msr_val = msr_read(MSR_IA32_VMX_PROCBASED_CTLS2);
|
||||
|
||||
if (is_ctrl_setting_allowed(msr_val, VMX_PROCBASED_CTLS2_EPT)) {
|
||||
cpu_caps.ept_features = 1U;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void apicv_cap_detect(void)
|
||||
{
|
||||
uint8_t features;
|
||||
uint64_t msr_val;
|
||||
|
||||
msr_val = msr_read(MSR_IA32_VMX_PROCBASED_CTLS);
|
||||
if (!is_ctrl_setting_allowed(msr_val, VMX_PROCBASED_CTLS_TPR_SHADOW)) {
|
||||
pr_fatal("APICv: No APIC TPR virtualization support.");
|
||||
return;
|
||||
}
|
||||
|
||||
msr_val = msr_read(MSR_IA32_VMX_PROCBASED_CTLS2);
|
||||
if (!is_ctrl_setting_allowed(msr_val, VMX_PROCBASED_CTLS2_VAPIC)) {
|
||||
pr_fatal("APICv: No APIC-access virtualization support.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_ctrl_setting_allowed(msr_val, VMX_PROCBASED_CTLS2_VAPIC_REGS)) {
|
||||
pr_fatal("APICv: No APIC-register virtualization support.");
|
||||
return;
|
||||
}
|
||||
|
||||
features = (VAPIC_FEATURE_TPR_SHADOW
|
||||
| VAPIC_FEATURE_VIRT_ACCESS
|
||||
| VAPIC_FEATURE_VIRT_REG);
|
||||
|
||||
if (is_ctrl_setting_allowed(msr_val, VMX_PROCBASED_CTLS2_VX2APIC)) {
|
||||
features |= VAPIC_FEATURE_VX2APIC_MODE;
|
||||
}
|
||||
|
||||
if (is_ctrl_setting_allowed(msr_val, VMX_PROCBASED_CTLS2_VIRQ)) {
|
||||
features |= VAPIC_FEATURE_INTR_DELIVERY;
|
||||
|
||||
msr_val = msr_read(MSR_IA32_VMX_PINBASED_CTLS);
|
||||
if (is_ctrl_setting_allowed(msr_val,
|
||||
VMX_PINBASED_CTLS_POST_IRQ)) {
|
||||
features |= VAPIC_FEATURE_POST_INTR;
|
||||
}
|
||||
}
|
||||
cpu_caps.apicv_features = features;
|
||||
}
|
||||
|
||||
void cpu_cap_detect(void)
|
||||
{
|
||||
apicv_cap_detect();
|
||||
ept_cap_detect();
|
||||
}
|
||||
|
||||
bool is_ept_supported(void)
|
||||
{
|
||||
return (cpu_caps.ept_features != 0U);
|
||||
}
|
||||
|
||||
bool is_apicv_reg_virtualization_supported(void)
|
||||
{
|
||||
return ((cpu_caps.apicv_features & VAPIC_FEATURE_VIRT_REG) != 0U);
|
||||
}
|
||||
|
||||
bool is_apicv_intr_delivery_supported(void)
|
||||
{
|
||||
return ((cpu_caps.apicv_features & VAPIC_FEATURE_INTR_DELIVERY) != 0U);
|
||||
}
|
||||
|
||||
bool is_apicv_posted_intr_supported(void)
|
||||
{
|
||||
return ((cpu_caps.apicv_features & VAPIC_FEATURE_POST_INTR) != 0U);
|
||||
}
|
||||
|
||||
void get_cpu_name(void)
|
||||
{
|
||||
cpuid(CPUID_EXTEND_FUNCTION_2,
|
||||
(uint32_t *)(boot_cpu_data.model_name),
|
||||
(uint32_t *)(&boot_cpu_data.model_name[4]),
|
||||
(uint32_t *)(&boot_cpu_data.model_name[8]),
|
||||
(uint32_t *)(&boot_cpu_data.model_name[12]));
|
||||
cpuid(CPUID_EXTEND_FUNCTION_3,
|
||||
(uint32_t *)(&boot_cpu_data.model_name[16]),
|
||||
(uint32_t *)(&boot_cpu_data.model_name[20]),
|
||||
(uint32_t *)(&boot_cpu_data.model_name[24]),
|
||||
(uint32_t *)(&boot_cpu_data.model_name[28]));
|
||||
cpuid(CPUID_EXTEND_FUNCTION_4,
|
||||
(uint32_t *)(&boot_cpu_data.model_name[32]),
|
||||
(uint32_t *)(&boot_cpu_data.model_name[36]),
|
||||
(uint32_t *)(&boot_cpu_data.model_name[40]),
|
||||
(uint32_t *)(&boot_cpu_data.model_name[44]));
|
||||
|
||||
boot_cpu_data.model_name[48] = '\0';
|
||||
}
|
||||
|
||||
bool check_cpu_security_config(void)
|
||||
{
|
||||
if (cpu_has_cap(X86_FEATURE_ARCH_CAP)) {
|
||||
x86_arch_capabilities = msr_read(MSR_IA32_ARCH_CAPABILITIES);
|
||||
skip_l1dfl_vmentry = ((x86_arch_capabilities
|
||||
& IA32_ARCH_CAP_SKIP_L1DFL_VMENTRY) != 0UL);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((!cpu_has_cap(X86_FEATURE_L1D_FLUSH)) && (!skip_l1dfl_vmentry)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!cpu_has_cap(X86_FEATURE_IBRS_IBPB) &&
|
||||
!cpu_has_cap(X86_FEATURE_STIBP)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void cpu_l1d_flush(void)
|
||||
{
|
||||
/*
|
||||
* 'skip_l1dfl_vmentry' will be true on platform that
|
||||
* is not affected by L1TF.
|
||||
*
|
||||
*/
|
||||
if (!skip_l1dfl_vmentry) {
|
||||
if (cpu_has_cap(X86_FEATURE_L1D_FLUSH)) {
|
||||
msr_write(MSR_IA32_FLUSH_CMD, IA32_L1D_FLUSH);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static inline bool is_vmx_disabled(void)
|
||||
{
|
||||
uint64_t msr_val;
|
||||
|
||||
/* Read Feature ControL MSR */
|
||||
msr_val = msr_read(MSR_IA32_FEATURE_CONTROL);
|
||||
|
||||
/* Check if feature control is locked and vmx cannot be enabled */
|
||||
if ((msr_val & MSR_IA32_FEATURE_CONTROL_LOCK) != 0U &&
|
||||
(msr_val & MSR_IA32_FEATURE_CONTROL_VMX_NO_SMX) == 0U) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool cpu_has_vmx_unrestricted_guest_cap(void)
|
||||
{
|
||||
return ((msr_read(MSR_IA32_VMX_MISC) & VMX_SUPPORT_UNRESTRICTED_GUEST)
|
||||
!= 0UL);
|
||||
}
|
||||
|
||||
bool cpu_has_vmx_ept_cap(uint32_t bit_mask)
|
||||
{
|
||||
return ((vmx_caps.ept & bit_mask) != 0U);
|
||||
}
|
||||
|
||||
bool cpu_has_vmx_vpid_cap(uint32_t bit_mask)
|
||||
{
|
||||
return ((vmx_caps.vpid & bit_mask) != 0U);
|
||||
}
|
||||
|
||||
static int32_t check_vmx_mmu_cap(void)
|
||||
{
|
||||
uint64_t val;
|
||||
|
||||
/* Read the MSR register of EPT and VPID Capability - SDM A.10 */
|
||||
val = msr_read(MSR_IA32_VMX_EPT_VPID_CAP);
|
||||
vmx_caps.ept = (uint32_t) val;
|
||||
vmx_caps.vpid = (uint32_t) (val >> 32U);
|
||||
|
||||
if (!cpu_has_vmx_ept_cap(VMX_EPT_INVEPT)) {
|
||||
pr_fatal("%s, invept not supported\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!cpu_has_vmx_vpid_cap(VMX_VPID_INVVPID) ||
|
||||
!cpu_has_vmx_vpid_cap(VMX_VPID_INVVPID_SINGLE_CONTEXT) ||
|
||||
!cpu_has_vmx_vpid_cap(VMX_VPID_INVVPID_GLOBAL_CONTEXT)) {
|
||||
pr_fatal("%s, invvpid not supported\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!cpu_has_vmx_ept_cap(VMX_EPT_1GB_PAGE)) {
|
||||
pr_fatal("%s, ept not support 1GB large page\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* basic hardware capability check
|
||||
* we should supplement which feature/capability we must support
|
||||
* here later.
|
||||
*/
|
||||
int32_t hardware_detect_support(void)
|
||||
{
|
||||
int32_t ret;
|
||||
|
||||
/* Long Mode (x86-64, 64-bit support) */
|
||||
if (!cpu_has_cap(X86_FEATURE_LM)) {
|
||||
pr_fatal("%s, LM not supported\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
if ((boot_cpu_data.phys_bits == 0U) ||
|
||||
(boot_cpu_data.virt_bits == 0U)) {
|
||||
pr_fatal("%s, can't detect Linear/Physical Address size\n",
|
||||
__func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* lapic TSC deadline timer */
|
||||
if (!cpu_has_cap(X86_FEATURE_TSC_DEADLINE)) {
|
||||
pr_fatal("%s, TSC deadline not supported\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Execute Disable */
|
||||
if (!cpu_has_cap(X86_FEATURE_NX)) {
|
||||
pr_fatal("%s, NX not supported\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Supervisor-Mode Execution Prevention */
|
||||
if (!cpu_has_cap(X86_FEATURE_SMEP)) {
|
||||
pr_fatal("%s, SMEP not supported\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Supervisor-Mode Access Prevention */
|
||||
if (!cpu_has_cap(X86_FEATURE_SMAP)) {
|
||||
pr_fatal("%s, SMAP not supported\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!cpu_has_cap(X86_FEATURE_MTRR)) {
|
||||
pr_fatal("%s, MTRR not supported\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!cpu_has_cap(X86_FEATURE_PAGE1GB)) {
|
||||
pr_fatal("%s, not support 1GB page\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!cpu_has_cap(X86_FEATURE_VMX)) {
|
||||
pr_fatal("%s, vmx not supported\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!is_fast_string_erms_supported_and_enabled()) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!cpu_has_vmx_unrestricted_guest_cap()) {
|
||||
pr_fatal("%s, unrestricted guest not supported\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!is_ept_supported()) {
|
||||
pr_fatal("%s, EPT not supported\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (boot_cpu_data.cpuid_level < 0x15U) {
|
||||
pr_fatal("%s, required CPU feature not supported\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (is_vmx_disabled()) {
|
||||
pr_fatal("%s, VMX can not be enabled\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (phys_cpu_num > CONFIG_MAX_PCPU_NUM) {
|
||||
pr_fatal("%s, pcpu number(%d) is out of range\n", __func__, phys_cpu_num);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = check_vmx_mmu_cap();
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
pr_acrnlog("hardware support HV");
|
||||
return 0;
|
||||
}
|
@ -34,11 +34,6 @@
|
||||
static void *ppt_mmu_pml4_addr;
|
||||
static uint8_t sanitized_page[PAGE_SIZE] __aligned(PAGE_SIZE);
|
||||
|
||||
static struct vmx_capability {
|
||||
uint32_t ept;
|
||||
uint32_t vpid;
|
||||
} vmx_caps;
|
||||
|
||||
/*
|
||||
* If the logical processor is in VMX non-root operation and
|
||||
* the "enable VPID" VM-execution control is 1, the current VPID
|
||||
@ -97,45 +92,6 @@ static inline void local_invept(uint64_t type, struct invept_desc desc)
|
||||
ASSERT(error == 0, "invept error");
|
||||
}
|
||||
|
||||
static inline bool cpu_has_vmx_ept_cap(uint32_t bit_mask)
|
||||
{
|
||||
return ((vmx_caps.ept & bit_mask) != 0U);
|
||||
}
|
||||
|
||||
static inline bool cpu_has_vmx_vpid_cap(uint32_t bit_mask)
|
||||
{
|
||||
return ((vmx_caps.vpid & bit_mask) != 0U);
|
||||
}
|
||||
|
||||
int32_t check_vmx_mmu_cap(void)
|
||||
{
|
||||
uint64_t val;
|
||||
|
||||
/* Read the MSR register of EPT and VPID Capability - SDM A.10 */
|
||||
val = msr_read(MSR_IA32_VMX_EPT_VPID_CAP);
|
||||
vmx_caps.ept = (uint32_t) val;
|
||||
vmx_caps.vpid = (uint32_t) (val >> 32U);
|
||||
|
||||
if (!cpu_has_vmx_ept_cap(VMX_EPT_INVEPT)) {
|
||||
pr_fatal("%s, invept not supported\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!cpu_has_vmx_vpid_cap(VMX_VPID_INVVPID) ||
|
||||
!cpu_has_vmx_vpid_cap(VMX_VPID_INVVPID_SINGLE_CONTEXT) ||
|
||||
!cpu_has_vmx_vpid_cap(VMX_VPID_INVVPID_GLOBAL_CONTEXT)) {
|
||||
pr_fatal("%s, invvpid not supported\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!cpu_has_vmx_ept_cap(VMX_EPT_1GB_PAGE)) {
|
||||
pr_fatal("%s, ept not support 1GB large page\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t allocate_vpid(void)
|
||||
{
|
||||
uint16_t vpid = atomic_xadd16(&vmx_vpid_nr, 1U);
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <guest.h>
|
||||
#include <vcpu.h>
|
||||
#include <cpu.h>
|
||||
#include <cpu_caps.h>
|
||||
#include <types.h>
|
||||
|
||||
/* NOTE:
|
||||
|
@ -127,15 +127,6 @@
|
||||
/* Boot CPU ID */
|
||||
#define BOOT_CPU_ID 0U
|
||||
|
||||
/* type of speculation control
|
||||
* 0 - no speculation control support
|
||||
* 1 - raw IBRS + IPBP support
|
||||
* 2 - with STIBP optimization support
|
||||
*/
|
||||
#define IBRS_NONE 0
|
||||
#define IBRS_RAW 1
|
||||
#define IBRS_OPT 2
|
||||
|
||||
#ifndef ASSEMBLER
|
||||
|
||||
#define BUS_LOCK "lock ; "
|
||||
@ -209,8 +200,6 @@ extern uint8_t ld_bss_end;
|
||||
extern uint64_t main_entry[1];
|
||||
extern uint64_t secondary_cpu_stack[1];
|
||||
|
||||
extern int32_t ibrs_type;
|
||||
|
||||
/*
|
||||
* To support per_cpu access, we use a special struct "per_cpu_region" to hold
|
||||
* the pattern of per CPU data. And we allocate memory for per CPU data
|
||||
@ -229,16 +218,6 @@ extern int32_t ibrs_type;
|
||||
* to locate the per cpu data.
|
||||
*/
|
||||
|
||||
/* CPUID feature words */
|
||||
#define FEAT_1_ECX 0U /* CPUID[1].ECX */
|
||||
#define FEAT_1_EDX 1U /* CPUID[1].EDX */
|
||||
#define FEAT_7_0_EBX 2U /* CPUID[EAX=7,ECX=0].EBX */
|
||||
#define FEAT_7_0_ECX 3U /* CPUID[EAX=7,ECX=0].ECX */
|
||||
#define FEAT_7_0_EDX 4U /* CPUID[EAX=7,ECX=0].EDX */
|
||||
#define FEAT_8000_0001_ECX 5U /* CPUID[8000_0001].ECX */
|
||||
#define FEAT_8000_0001_EDX 6U /* CPUID[8000_0001].EDX */
|
||||
#define FEAT_8000_0008_EBX 7U /* CPUID[8000_0008].EAX */
|
||||
#define FEATURE_WORDS 8U
|
||||
/**
|
||||
*The invalid cpu_id (INVALID_CPU_ID) is error
|
||||
*code for error handling, this means that
|
||||
@ -267,24 +246,6 @@ enum pcpu_boot_state {
|
||||
PCPU_STATE_DEAD,
|
||||
};
|
||||
|
||||
struct cpu_state_info {
|
||||
uint8_t px_cnt; /* count of all Px states */
|
||||
const struct cpu_px_data *px_data;
|
||||
uint8_t cx_cnt; /* count of all Cx entries */
|
||||
const struct cpu_cx_data *cx_data;
|
||||
};
|
||||
|
||||
struct cpuinfo_x86 {
|
||||
uint8_t family, model;
|
||||
uint8_t virt_bits;
|
||||
uint8_t phys_bits;
|
||||
uint32_t cpuid_level;
|
||||
uint32_t extended_cpuid_level;
|
||||
uint64_t physical_address_mask;
|
||||
uint32_t cpuid_leaves[FEATURE_WORDS];
|
||||
char model_name[64];
|
||||
struct cpu_state_info state_info;
|
||||
};
|
||||
#ifdef STACK_PROTECTOR
|
||||
struct stack_canary {
|
||||
/* Gcc generates extra code, using [fs:40] to access canary */
|
||||
@ -294,32 +255,16 @@ struct stack_canary {
|
||||
void __stack_chk_fail(void);
|
||||
#endif
|
||||
|
||||
extern struct cpuinfo_x86 boot_cpu_data;
|
||||
|
||||
#define MAX_PSTATE 20U /* max num of supported Px count */
|
||||
#define MAX_CSTATE 8U /* max num of supported Cx count */
|
||||
|
||||
/* We support MAX_CSTATE num of Cx, means have (MAX_CSTATE - 1) Cx entries,
|
||||
* i.e. supported Cx entry index range from 1 to MAX_CX_ENTRY.
|
||||
*/
|
||||
#define MAX_CX_ENTRY (MAX_CSTATE - 1U)
|
||||
|
||||
/* Function prototypes */
|
||||
void cpu_do_idle(void);
|
||||
void cpu_dead(void);
|
||||
void trampoline_start16(void);
|
||||
bool is_apicv_reg_virtualization_supported(void);
|
||||
bool is_apicv_intr_delivery_supported(void);
|
||||
bool is_apicv_posted_intr_supported(void);
|
||||
bool is_ept_supported(void);
|
||||
bool cpu_has_cap(uint32_t bit);
|
||||
void load_cpu_state_data(void);
|
||||
void init_cpu_pre(uint16_t pcpu_id);
|
||||
void init_cpu_post(uint16_t pcpu_id);
|
||||
void start_cpus(void);
|
||||
void stop_cpus(void);
|
||||
void wait_sync_change(uint64_t *sync, uint64_t wake_sync);
|
||||
void cpu_l1d_flush(void);
|
||||
|
||||
#define CPU_SEG_READ(seg, result_ptr) \
|
||||
{ \
|
||||
|
79
hypervisor/include/arch/x86/cpu_caps.h
Normal file
79
hypervisor/include/arch/x86/cpu_caps.h
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef CPUINFO_H
|
||||
#define CPUINFO_H
|
||||
|
||||
/* type of speculation control
|
||||
* 0 - no speculation control support
|
||||
* 1 - raw IBRS + IPBP support
|
||||
* 2 - with STIBP optimization support
|
||||
*/
|
||||
#define IBRS_NONE 0
|
||||
#define IBRS_RAW 1
|
||||
#define IBRS_OPT 2
|
||||
|
||||
#ifndef ASSEMBLER
|
||||
|
||||
extern int32_t ibrs_type;
|
||||
|
||||
struct cpu_state_info {
|
||||
uint8_t px_cnt; /* count of all Px states */
|
||||
const struct cpu_px_data *px_data;
|
||||
uint8_t cx_cnt; /* count of all Cx entries */
|
||||
const struct cpu_cx_data *cx_data;
|
||||
};
|
||||
|
||||
#define MAX_PSTATE 20U /* max num of supported Px count */
|
||||
#define MAX_CSTATE 8U /* max num of supported Cx count */
|
||||
/* We support MAX_CSTATE num of Cx, means have (MAX_CSTATE - 1) Cx entries,
|
||||
* i.e. supported Cx entry index range from 1 to MAX_CX_ENTRY.
|
||||
*/
|
||||
#define MAX_CX_ENTRY (MAX_CSTATE - 1U)
|
||||
|
||||
/* CPUID feature words */
|
||||
#define FEAT_1_ECX 0U /* CPUID[1].ECX */
|
||||
#define FEAT_1_EDX 1U /* CPUID[1].EDX */
|
||||
#define FEAT_7_0_EBX 2U /* CPUID[EAX=7,ECX=0].EBX */
|
||||
#define FEAT_7_0_ECX 3U /* CPUID[EAX=7,ECX=0].ECX */
|
||||
#define FEAT_7_0_EDX 4U /* CPUID[EAX=7,ECX=0].EDX */
|
||||
#define FEAT_8000_0001_ECX 5U /* CPUID[8000_0001].ECX */
|
||||
#define FEAT_8000_0001_EDX 6U /* CPUID[8000_0001].EDX */
|
||||
#define FEAT_8000_0008_EBX 7U /* CPUID[8000_0008].EAX */
|
||||
#define FEATURE_WORDS 8U
|
||||
|
||||
struct cpuinfo_x86 {
|
||||
uint8_t family, model;
|
||||
uint8_t virt_bits;
|
||||
uint8_t phys_bits;
|
||||
uint32_t cpuid_level;
|
||||
uint32_t extended_cpuid_level;
|
||||
uint64_t physical_address_mask;
|
||||
uint32_t cpuid_leaves[FEATURE_WORDS];
|
||||
char model_name[64];
|
||||
struct cpu_state_info state_info;
|
||||
};
|
||||
|
||||
extern struct cpuinfo_x86 boot_cpu_data;
|
||||
|
||||
bool get_monitor_cap(void);
|
||||
bool is_apicv_reg_virtualization_supported(void);
|
||||
bool is_apicv_intr_delivery_supported(void);
|
||||
bool is_apicv_posted_intr_supported(void);
|
||||
bool is_ept_supported(void);
|
||||
bool cpu_has_cap(uint32_t bit);
|
||||
bool cpu_has_vmx_ept_cap(uint32_t bit_mask);
|
||||
bool cpu_has_vmx_vpid_cap(uint32_t bit_mask);
|
||||
void get_cpu_capabilities(void);
|
||||
void get_cpu_name(void);
|
||||
void cpu_cap_detect(void);
|
||||
bool check_cpu_security_config(void);
|
||||
void cpu_l1d_flush(void);
|
||||
int hardware_detect_support(void);
|
||||
|
||||
#endif /* ASSEMBLER */
|
||||
|
||||
#endif /* CPUINFO_H */
|
@ -9,6 +9,7 @@
|
||||
#include <bsp_extern.h>
|
||||
#include <vpci.h>
|
||||
#include <page.h>
|
||||
#include <cpu_caps.h>
|
||||
|
||||
#ifdef CONFIG_PARTITION_MODE
|
||||
#include <mptable.h>
|
||||
|
@ -126,13 +126,6 @@ void mmu_modify_or_del(uint64_t *pml4_page, uint64_t vaddr_base, uint64_t size,
|
||||
uint64_t prot_set, uint64_t prot_clr, const struct memory_ops *mem_ops, uint32_t type);
|
||||
void hv_access_memory_region_update(uint64_t base, uint64_t size);
|
||||
|
||||
/**
|
||||
* @brief EPT and VPID capability checking
|
||||
*
|
||||
* @retval 0 on success
|
||||
* @retval -ENODEV Don't support EPT or VPID capability
|
||||
*/
|
||||
int32_t check_vmx_mmu_cap(void);
|
||||
/**
|
||||
* @brief VPID allocation
|
||||
*
|
||||
|
@ -66,7 +66,6 @@ int32_t vmx_wrmsr_pat(struct acrn_vcpu *vcpu, uint64_t value);
|
||||
|
||||
void vmx_write_cr0(struct acrn_vcpu *vcpu, uint64_t cr0);
|
||||
void vmx_write_cr4(struct acrn_vcpu *vcpu, uint64_t cr4);
|
||||
bool is_vmx_disabled(void);
|
||||
void switch_apicv_mode_x2apic(struct acrn_vcpu *vcpu);
|
||||
|
||||
static inline enum vm_cpu_mode get_vcpu_mode(const struct acrn_vcpu *vcpu)
|
||||
@ -74,12 +73,6 @@ static inline enum vm_cpu_mode get_vcpu_mode(const struct acrn_vcpu *vcpu)
|
||||
return vcpu->arch.cpu_mode;
|
||||
}
|
||||
|
||||
static inline bool cpu_has_vmx_unrestricted_guest_cap(void)
|
||||
{
|
||||
return ((msr_read(MSR_IA32_VMX_MISC) & VMX_SUPPORT_UNRESTRICTED_GUEST)
|
||||
!= 0UL);
|
||||
}
|
||||
|
||||
#endif /* ASSEMBLER */
|
||||
|
||||
#endif /* VMCS_H_ */
|
||||
|
Loading…
Reference in New Issue
Block a user