HV: Refine APICv capabilities detection

- by default, ACRN will not support platform without
   below APICv features:
    -- Use TPR shadow
    -- APIC-register virtualization

 - remove mmio emualtion of local APIC for guest

Signed-off-by: Yonghua Huang <yonghua.huang@intel.com>
Acked-by: Anthony Xu <anthony.xu@intel.com>
This commit is contained in:
Yonghua Huang 2018-08-23 18:29:31 +08:00 committed by lijinxia
parent f95d07dc43
commit 7bc1a3f925
5 changed files with 51 additions and 189 deletions

View File

@ -790,26 +790,27 @@ static void apicv_cap_detect(void)
uint8_t features;
uint64_t msr_val;
features = 0U;
msr_val = msr_read(MSR_IA32_VMX_PROCBASED_CTLS);
if (!is_ctrl_setting_allowed(msr_val, VMX_PROCBASED_CTLS_TPR_SHADOW)) {
cpu_caps.apicv_features = 0U;
pr_fatal("APICv: No APIC TPR virtualization support.");
return;
}
features |= VAPIC_FEATURE_TPR_SHADOW;
msr_val = msr_read(MSR_IA32_VMX_PROCBASED_CTLS2);
if (!is_ctrl_setting_allowed(msr_val, VMX_PROCBASED_CTLS2_VAPIC)) {
cpu_caps.apicv_features = features;
pr_fatal("APICv: No APIC-access virtualization support.");
return;
}
features |= VAPIC_FEATURE_VIRT_ACCESS;
if (is_ctrl_setting_allowed(msr_val, VMX_PROCBASED_CTLS2_VAPIC_REGS)) {
features |= VAPIC_FEATURE_VIRT_REG;
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;
}
@ -823,7 +824,6 @@ static void apicv_cap_detect(void)
features |= VAPIC_FEATURE_POST_INTR;
}
}
cpu_caps.apicv_features = features;
}
@ -838,20 +838,11 @@ bool is_ept_supported(void)
return (cpu_caps.ept_features != 0U);
}
bool is_apicv_supported(void)
{
return ((cpu_caps.apicv_features & VAPIC_FEATURE_VIRT_ACCESS) != 0U);
}
bool is_apicv_intr_delivery_supported(void)
{
return ((cpu_caps.apicv_features & VAPIC_FEATURE_INTR_DELIVERY) != 0U);
}
bool is_apicv_virt_reg_supported(void)
{
return ((cpu_caps.apicv_features & VAPIC_FEATURE_VIRT_REG) != 0U);
}
static void cpu_xsave_init(void)
{

View File

@ -1950,81 +1950,6 @@ vlapic_wrmsr(struct vcpu *vcpu, uint32_t msr, uint64_t wval)
return error;
}
int
vlapic_write_mmio_reg(struct vcpu *vcpu, uint64_t gpa, uint64_t wval,
uint8_t size)
{
int error;
uint32_t off;
struct acrn_vlapic *vlapic;
off = (uint32_t)(gpa - DEFAULT_APIC_BASE);
/*
* Memory mapped local apic accesses must be 4 bytes wide and
* aligned on a 16-byte boundary.
*/
if ((size != 4U) || ((off & 0xfU) != 0U)) {
return -EINVAL;
}
vlapic = vcpu->arch_vcpu.vlapic;
error = vlapic_write(vlapic, off, wval);
return error;
}
int
vlapic_read_mmio_reg(struct vcpu *vcpu, uint64_t gpa, uint64_t *rval,
__unused uint8_t size)
{
int error;
uint32_t off;
struct acrn_vlapic *vlapic;
off = (uint32_t)(gpa - DEFAULT_APIC_BASE);
/*
* Memory mapped local apic accesses should be aligned on a
* 16-byte boundary. They are also suggested to be 4 bytes
* wide, alas not all OSes follow suggestions.
*/
off &= ~0x3U;
if ((off & 0xfU) != 0U) {
return -EINVAL;
}
vlapic = vcpu->arch_vcpu.vlapic;
error = vlapic_read(vlapic, off, rval);
return error;
}
int vlapic_mmio_access_handler(struct vcpu *vcpu, struct io_request *io_req,
__unused void *handler_private_data)
{
struct mmio_request *mmio_req = &io_req->reqs.mmio;
uint64_t gpa = mmio_req->address;
int ret = 0;
/* Note all RW to LAPIC are 32-Bit in size */
ASSERT(mmio_req->size == 4UL, "All RW to LAPIC must be 32-bits in size");
if (mmio_req->direction == REQUEST_READ) {
ret = vlapic_read_mmio_reg(vcpu,
gpa,
&mmio_req->value,
mmio_req->size);
} else if (mmio_req->direction == REQUEST_WRITE) {
ret = vlapic_write_mmio_reg(vcpu,
gpa,
mmio_req->value,
mmio_req->size);
} else {
/* Can never happen due to the range of mmio_req->direction. */
}
return ret;
}
int vlapic_create(struct vcpu *vcpu)
{
struct acrn_vlapic *vlapic = calloc(1U, sizeof(struct acrn_vlapic));
@ -2032,34 +1957,21 @@ int vlapic_create(struct vcpu *vcpu)
ASSERT(vlapic != NULL, "vlapic allocate failed");
vlapic->vm = vcpu->vm;
vlapic->vcpu = vcpu;
if (is_apicv_supported()) {
if (is_vcpu_bsp(vcpu)) {
uint64_t *pml4_page =
(uint64_t *)vcpu->vm->arch_vm.nworld_eptp;
ept_mr_del(vcpu->vm, pml4_page,
DEFAULT_APIC_BASE, CPU_PAGE_SIZE);
ept_mr_add(vcpu->vm, pml4_page,
vlapic_apicv_get_apic_access_addr(vcpu->vm),
DEFAULT_APIC_BASE, CPU_PAGE_SIZE,
EPT_WR | EPT_RD | EPT_UNCACHED);
}
} else {
/*No APICv support*/
if (register_mmio_emulation_handler(vcpu->vm,
vlapic_mmio_access_handler,
(uint64_t)DEFAULT_APIC_BASE,
(uint64_t)DEFAULT_APIC_BASE +
CPU_PAGE_SIZE,
(void *) 0) != 0) {
free(vlapic);
return -1;
}
if (is_vcpu_bsp(vcpu)) {
uint64_t *pml4_page =
(uint64_t *)vcpu->vm->arch_vm.nworld_eptp;
ept_mr_del(vcpu->vm, pml4_page,
DEFAULT_APIC_BASE, CPU_PAGE_SIZE);
ept_mr_add(vcpu->vm, pml4_page,
vlapic_apicv_get_apic_access_addr(vcpu->vm),
DEFAULT_APIC_BASE, CPU_PAGE_SIZE,
EPT_WR | EPT_RD | EPT_UNCACHED);
}
vcpu->arch_vcpu.vlapic = vlapic;
vlapic_init(vlapic);
return 0;
}
@ -2075,15 +1987,8 @@ void vlapic_free(struct vcpu *vcpu)
if (vlapic == NULL) {
return;
}
del_timer(&vlapic->vtimer.timer);
if (!is_apicv_supported()) {
unregister_mmio_emulation_handler(vcpu->vm,
(uint64_t)DEFAULT_APIC_BASE,
(uint64_t)DEFAULT_APIC_BASE + CPU_PAGE_SIZE);
}
free(vlapic);
}

View File

@ -953,6 +953,7 @@ static void init_exec_ctrl(struct vcpu *vcpu)
value32 = check_vmx_ctrl(MSR_IA32_VMX_PROCBASED_CTLS,
VMX_PROCBASED_CTLS_TSC_OFF |
/* VMX_PROCBASED_CTLS_RDTSC | */
VMX_PROCBASED_CTLS_TPR_SHADOW|
VMX_PROCBASED_CTLS_IO_BITMAP |
VMX_PROCBASED_CTLS_MSR_BITMAP |
VMX_PROCBASED_CTLS_SECONDARY);
@ -966,15 +967,6 @@ static void init_exec_ctrl(struct vcpu *vcpu)
*/
value32 &= ~VMX_PROCBASED_CTLS_INVLPG;
if (is_apicv_supported()) {
value32 |= VMX_PROCBASED_CTLS_TPR_SHADOW;
} else {
/* Add CR8 VMExit for vlapic */
value32 |=
(VMX_PROCBASED_CTLS_CR8_LOAD |
VMX_PROCBASED_CTLS_CR8_STORE);
}
exec_vmwrite32(VMX_PROC_VM_EXEC_CONTROLS, value32);
pr_dbg("VMX_PROC_VM_EXEC_CONTROLS: 0x%x ", value32);
@ -983,9 +975,11 @@ static void init_exec_ctrl(struct vcpu *vcpu)
* guest (optional)
*/
value32 = check_vmx_ctrl(MSR_IA32_VMX_PROCBASED_CTLS2,
VMX_PROCBASED_CTLS2_VAPIC |
VMX_PROCBASED_CTLS2_EPT |
VMX_PROCBASED_CTLS2_RDTSCP |
VMX_PROCBASED_CTLS2_UNRESTRICT);
VMX_PROCBASED_CTLS2_UNRESTRICT|
VMX_PROCBASED_CTLS2_VAPIC_REGS);
if (vcpu->arch_vcpu.vpid != 0U) {
value32 |= VMX_PROCBASED_CTLS2_VPID;
@ -993,27 +987,18 @@ static void init_exec_ctrl(struct vcpu *vcpu)
value32 &= ~VMX_PROCBASED_CTLS2_VPID;
}
if (is_apicv_supported()) {
value32 |= VMX_PROCBASED_CTLS2_VAPIC;
if (is_apicv_virt_reg_supported()) {
value32 |= VMX_PROCBASED_CTLS2_VAPIC_REGS;
}
if (is_apicv_intr_delivery_supported()) {
value32 |= VMX_PROCBASED_CTLS2_VIRQ;
}
else {
/*
* This field exists only on processors that support
* the 1-setting of the "use TPR shadow"
* VM-execution control.
*
* Set up TPR threshold for virtual interrupt delivery
* - pg 2904 24.6.8
*/
exec_vmwrite32(VMX_TPR_THRESHOLD, 0U);
}
if (is_apicv_intr_delivery_supported()) {
value32 |= VMX_PROCBASED_CTLS2_VIRQ;
} else {
/*
* This field exists only on processors that support
* the 1-setting of the "use TPR shadow"
* VM-execution control.
*
* Set up TPR threshold for virtual interrupt delivery
* - pg 2904 24.6.8
*/
exec_vmwrite32(VMX_TPR_THRESHOLD, 0U);
}
if (cpu_has_cap(X86_FEATURE_OSXSAVE)) {
@ -1024,29 +1009,24 @@ static void init_exec_ctrl(struct vcpu *vcpu)
exec_vmwrite32(VMX_PROC_VM_EXEC_CONTROLS2, value32);
pr_dbg("VMX_PROC_VM_EXEC_CONTROLS2: 0x%x ", value32);
if (is_apicv_supported()) {
/*APIC-v, config APIC-access address*/
value64 = vlapic_apicv_get_apic_access_addr(vcpu->vm);
exec_vmwrite64(VMX_APIC_ACCESS_ADDR_FULL,
value64);
/*APIC-v, config APIC-access address*/
value64 = vlapic_apicv_get_apic_access_addr(vcpu->vm);
exec_vmwrite64(VMX_APIC_ACCESS_ADDR_FULL, value64);
/*APIC-v, config APIC virtualized page address*/
value64 = vlapic_apicv_get_apic_page_addr(
vcpu->arch_vcpu.vlapic);
exec_vmwrite64(VMX_VIRTUAL_APIC_PAGE_ADDR_FULL,
value64);
/*APIC-v, config APIC virtualized page address*/
value64 = vlapic_apicv_get_apic_page_addr(vcpu->arch_vcpu.vlapic);
exec_vmwrite64(VMX_VIRTUAL_APIC_PAGE_ADDR_FULL, value64);
if (is_apicv_intr_delivery_supported()) {
/* Disable all EOI VMEXIT by default and
* clear RVI and SVI.
*/
exec_vmwrite64(VMX_EOI_EXIT0_FULL, 0UL);
exec_vmwrite64(VMX_EOI_EXIT1_FULL, 0UL);
exec_vmwrite64(VMX_EOI_EXIT2_FULL, 0UL);
exec_vmwrite64(VMX_EOI_EXIT3_FULL, 0UL);
if (is_apicv_intr_delivery_supported()) {
/* Disable all EOI VMEXIT by default and
* clear RVI and SVI.
*/
exec_vmwrite64(VMX_EOI_EXIT0_FULL, 0UL);
exec_vmwrite64(VMX_EOI_EXIT1_FULL, 0UL);
exec_vmwrite64(VMX_EOI_EXIT2_FULL, 0UL);
exec_vmwrite64(VMX_EOI_EXIT3_FULL, 0UL);
exec_vmwrite16(VMX_GUEST_INTR_STATUS, 0);
}
exec_vmwrite16(VMX_GUEST_INTR_STATUS, 0);
}
/* Load EPTP execution control

View File

@ -323,9 +323,7 @@ extern struct cpuinfo_x86 boot_cpu_data;
void cpu_do_idle(__unused uint16_t pcpu_id);
void cpu_dead(uint16_t pcpu_id);
void trampoline_start16(void);
bool is_apicv_supported(void);
bool is_apicv_intr_delivery_supported(void);
bool is_apicv_virt_reg_supported(void);
bool is_ept_supported(void);
bool cpu_has_cap(uint32_t bit);
void load_cpu_state_data(void);

View File

@ -60,11 +60,6 @@ struct acrn_vlapic *vm_lapic_from_pcpuid(struct vm *vm, uint16_t pcpu_id);
int vlapic_rdmsr(struct vcpu *vcpu, uint32_t msr, uint64_t *rval);
int vlapic_wrmsr(struct vcpu *vcpu, uint32_t msr, uint64_t wval);
int vlapic_read_mmio_reg(struct vcpu *vcpu, uint64_t gpa, uint64_t *rval,
__unused uint8_t size);
int vlapic_write_mmio_reg(struct vcpu *vcpu, uint64_t gpa,
uint64_t wval, uint8_t size);
/*
* Signals to the LAPIC that an interrupt at 'vector' needs to be generated
* to the 'cpu', the state is recorded in IRR.
@ -107,15 +102,9 @@ void vlapic_reset_tmr(struct acrn_vlapic *vlapic);
void vlapic_set_tmr_one_vec(struct acrn_vlapic *vlapic, uint32_t delmode,
uint32_t vector, bool level);
void
vlapic_apicv_batch_set_tmr(struct acrn_vlapic *vlapic);
int vlapic_mmio_access_handler(struct vcpu *vcpu, struct io_request *io_req,
__unused void *handler_private_data);
void vlapic_apicv_batch_set_tmr(struct acrn_vlapic *vlapic);
uint32_t vlapic_get_id(struct acrn_vlapic *vlapic);
uint8_t vlapic_get_apicid(struct acrn_vlapic *vlapic);
int vlapic_create(struct vcpu *vcpu);
void vlapic_free(struct vcpu *vcpu);
void vlapic_init(struct acrn_vlapic *vlapic);
@ -129,6 +118,5 @@ int apic_access_vmexit_handler(struct vcpu *vcpu);
int apic_write_vmexit_handler(struct vcpu *vcpu);
int veoi_vmexit_handler(struct vcpu *vcpu);
int tpr_below_threshold_vmexit_handler(__unused struct vcpu *vcpu);
void calcvdest(struct vm *vm, uint64_t *dmask, uint32_t dest, bool phys);
#endif /* _VLAPIC_H_ */