Skip to content

Commit 7bc1a3f

Browse files
yonghuahlijinxia
authored andcommitted
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>
1 parent f95d07d commit 7bc1a3f

File tree

5 files changed

+54
-192
lines changed

5 files changed

+54
-192
lines changed

hypervisor/arch/x86/cpu.c

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -790,26 +790,27 @@ static void apicv_cap_detect(void)
790790
uint8_t features;
791791
uint64_t msr_val;
792792

793-
features = 0U;
794-
795793
msr_val = msr_read(MSR_IA32_VMX_PROCBASED_CTLS);
796794
if (!is_ctrl_setting_allowed(msr_val, VMX_PROCBASED_CTLS_TPR_SHADOW)) {
797-
cpu_caps.apicv_features = 0U;
795+
pr_fatal("APICv: No APIC TPR virtualization support.");
798796
return;
799797
}
800-
features |= VAPIC_FEATURE_TPR_SHADOW;
801798

802799
msr_val = msr_read(MSR_IA32_VMX_PROCBASED_CTLS2);
803800
if (!is_ctrl_setting_allowed(msr_val, VMX_PROCBASED_CTLS2_VAPIC)) {
804-
cpu_caps.apicv_features = features;
801+
pr_fatal("APICv: No APIC-access virtualization support.");
805802
return;
806803
}
807-
features |= VAPIC_FEATURE_VIRT_ACCESS;
808804

809-
if (is_ctrl_setting_allowed(msr_val, VMX_PROCBASED_CTLS2_VAPIC_REGS)) {
810-
features |= VAPIC_FEATURE_VIRT_REG;
805+
if (!is_ctrl_setting_allowed(msr_val, VMX_PROCBASED_CTLS2_VAPIC_REGS)) {
806+
pr_fatal("APICv: No APIC-register virtualization support.");
807+
return;
811808
}
812809

810+
features = (VAPIC_FEATURE_TPR_SHADOW
811+
| VAPIC_FEATURE_VIRT_ACCESS
812+
| VAPIC_FEATURE_VIRT_REG);
813+
813814
if (is_ctrl_setting_allowed(msr_val, VMX_PROCBASED_CTLS2_VX2APIC)) {
814815
features |= VAPIC_FEATURE_VX2APIC_MODE;
815816
}
@@ -823,7 +824,6 @@ static void apicv_cap_detect(void)
823824
features |= VAPIC_FEATURE_POST_INTR;
824825
}
825826
}
826-
827827
cpu_caps.apicv_features = features;
828828
}
829829

@@ -838,20 +838,11 @@ bool is_ept_supported(void)
838838
return (cpu_caps.ept_features != 0U);
839839
}
840840

841-
bool is_apicv_supported(void)
842-
{
843-
return ((cpu_caps.apicv_features & VAPIC_FEATURE_VIRT_ACCESS) != 0U);
844-
}
845-
846841
bool is_apicv_intr_delivery_supported(void)
847842
{
848843
return ((cpu_caps.apicv_features & VAPIC_FEATURE_INTR_DELIVERY) != 0U);
849844
}
850845

851-
bool is_apicv_virt_reg_supported(void)
852-
{
853-
return ((cpu_caps.apicv_features & VAPIC_FEATURE_VIRT_REG) != 0U);
854-
}
855846

856847
static void cpu_xsave_init(void)
857848
{

hypervisor/arch/x86/guest/vlapic.c

Lines changed: 11 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -1950,116 +1950,28 @@ vlapic_wrmsr(struct vcpu *vcpu, uint32_t msr, uint64_t wval)
19501950
return error;
19511951
}
19521952

1953-
int
1954-
vlapic_write_mmio_reg(struct vcpu *vcpu, uint64_t gpa, uint64_t wval,
1955-
uint8_t size)
1956-
{
1957-
int error;
1958-
uint32_t off;
1959-
struct acrn_vlapic *vlapic;
1960-
1961-
off = (uint32_t)(gpa - DEFAULT_APIC_BASE);
1962-
1963-
/*
1964-
* Memory mapped local apic accesses must be 4 bytes wide and
1965-
* aligned on a 16-byte boundary.
1966-
*/
1967-
if ((size != 4U) || ((off & 0xfU) != 0U)) {
1968-
return -EINVAL;
1969-
}
1970-
1971-
vlapic = vcpu->arch_vcpu.vlapic;
1972-
error = vlapic_write(vlapic, off, wval);
1973-
return error;
1974-
}
1975-
1976-
int
1977-
vlapic_read_mmio_reg(struct vcpu *vcpu, uint64_t gpa, uint64_t *rval,
1978-
__unused uint8_t size)
1979-
{
1980-
int error;
1981-
uint32_t off;
1982-
struct acrn_vlapic *vlapic;
1983-
1984-
off = (uint32_t)(gpa - DEFAULT_APIC_BASE);
1985-
1986-
/*
1987-
* Memory mapped local apic accesses should be aligned on a
1988-
* 16-byte boundary. They are also suggested to be 4 bytes
1989-
* wide, alas not all OSes follow suggestions.
1990-
*/
1991-
off &= ~0x3U;
1992-
if ((off & 0xfU) != 0U) {
1993-
return -EINVAL;
1994-
}
1995-
1996-
vlapic = vcpu->arch_vcpu.vlapic;
1997-
error = vlapic_read(vlapic, off, rval);
1998-
return error;
1999-
}
2000-
2001-
int vlapic_mmio_access_handler(struct vcpu *vcpu, struct io_request *io_req,
2002-
__unused void *handler_private_data)
2003-
{
2004-
struct mmio_request *mmio_req = &io_req->reqs.mmio;
2005-
uint64_t gpa = mmio_req->address;
2006-
int ret = 0;
2007-
2008-
/* Note all RW to LAPIC are 32-Bit in size */
2009-
ASSERT(mmio_req->size == 4UL, "All RW to LAPIC must be 32-bits in size");
2010-
2011-
if (mmio_req->direction == REQUEST_READ) {
2012-
ret = vlapic_read_mmio_reg(vcpu,
2013-
gpa,
2014-
&mmio_req->value,
2015-
mmio_req->size);
2016-
} else if (mmio_req->direction == REQUEST_WRITE) {
2017-
ret = vlapic_write_mmio_reg(vcpu,
2018-
gpa,
2019-
mmio_req->value,
2020-
mmio_req->size);
2021-
} else {
2022-
/* Can never happen due to the range of mmio_req->direction. */
2023-
}
2024-
2025-
return ret;
2026-
}
2027-
20281953
int vlapic_create(struct vcpu *vcpu)
20291954
{
20301955
struct acrn_vlapic *vlapic = calloc(1U, sizeof(struct acrn_vlapic));
20311956

20321957
ASSERT(vlapic != NULL, "vlapic allocate failed");
20331958
vlapic->vm = vcpu->vm;
20341959
vlapic->vcpu = vcpu;
2035-
if (is_apicv_supported()) {
2036-
if (is_vcpu_bsp(vcpu)) {
2037-
uint64_t *pml4_page =
2038-
(uint64_t *)vcpu->vm->arch_vm.nworld_eptp;
2039-
ept_mr_del(vcpu->vm, pml4_page,
2040-
DEFAULT_APIC_BASE, CPU_PAGE_SIZE);
2041-
2042-
ept_mr_add(vcpu->vm, pml4_page,
2043-
vlapic_apicv_get_apic_access_addr(vcpu->vm),
2044-
DEFAULT_APIC_BASE, CPU_PAGE_SIZE,
2045-
EPT_WR | EPT_RD | EPT_UNCACHED);
2046-
}
2047-
} else {
2048-
/*No APICv support*/
2049-
if (register_mmio_emulation_handler(vcpu->vm,
2050-
vlapic_mmio_access_handler,
2051-
(uint64_t)DEFAULT_APIC_BASE,
2052-
(uint64_t)DEFAULT_APIC_BASE +
2053-
CPU_PAGE_SIZE,
2054-
(void *) 0) != 0) {
2055-
free(vlapic);
2056-
return -1;
2057-
}
1960+
1961+
if (is_vcpu_bsp(vcpu)) {
1962+
uint64_t *pml4_page =
1963+
(uint64_t *)vcpu->vm->arch_vm.nworld_eptp;
1964+
ept_mr_del(vcpu->vm, pml4_page,
1965+
DEFAULT_APIC_BASE, CPU_PAGE_SIZE);
1966+
1967+
ept_mr_add(vcpu->vm, pml4_page,
1968+
vlapic_apicv_get_apic_access_addr(vcpu->vm),
1969+
DEFAULT_APIC_BASE, CPU_PAGE_SIZE,
1970+
EPT_WR | EPT_RD | EPT_UNCACHED);
20581971
}
20591972

20601973
vcpu->arch_vcpu.vlapic = vlapic;
20611974
vlapic_init(vlapic);
2062-
20631975
return 0;
20641976
}
20651977

@@ -2075,15 +1987,8 @@ void vlapic_free(struct vcpu *vcpu)
20751987
if (vlapic == NULL) {
20761988
return;
20771989
}
2078-
20791990
del_timer(&vlapic->vtimer.timer);
20801991

2081-
if (!is_apicv_supported()) {
2082-
unregister_mmio_emulation_handler(vcpu->vm,
2083-
(uint64_t)DEFAULT_APIC_BASE,
2084-
(uint64_t)DEFAULT_APIC_BASE + CPU_PAGE_SIZE);
2085-
}
2086-
20871992
free(vlapic);
20881993
}
20891994

hypervisor/arch/x86/vmx.c

Lines changed: 33 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -953,6 +953,7 @@ static void init_exec_ctrl(struct vcpu *vcpu)
953953
value32 = check_vmx_ctrl(MSR_IA32_VMX_PROCBASED_CTLS,
954954
VMX_PROCBASED_CTLS_TSC_OFF |
955955
/* VMX_PROCBASED_CTLS_RDTSC | */
956+
VMX_PROCBASED_CTLS_TPR_SHADOW|
956957
VMX_PROCBASED_CTLS_IO_BITMAP |
957958
VMX_PROCBASED_CTLS_MSR_BITMAP |
958959
VMX_PROCBASED_CTLS_SECONDARY);
@@ -966,15 +967,6 @@ static void init_exec_ctrl(struct vcpu *vcpu)
966967
*/
967968
value32 &= ~VMX_PROCBASED_CTLS_INVLPG;
968969

969-
if (is_apicv_supported()) {
970-
value32 |= VMX_PROCBASED_CTLS_TPR_SHADOW;
971-
} else {
972-
/* Add CR8 VMExit for vlapic */
973-
value32 |=
974-
(VMX_PROCBASED_CTLS_CR8_LOAD |
975-
VMX_PROCBASED_CTLS_CR8_STORE);
976-
}
977-
978970
exec_vmwrite32(VMX_PROC_VM_EXEC_CONTROLS, value32);
979971
pr_dbg("VMX_PROC_VM_EXEC_CONTROLS: 0x%x ", value32);
980972

@@ -983,37 +975,30 @@ static void init_exec_ctrl(struct vcpu *vcpu)
983975
* guest (optional)
984976
*/
985977
value32 = check_vmx_ctrl(MSR_IA32_VMX_PROCBASED_CTLS2,
978+
VMX_PROCBASED_CTLS2_VAPIC |
986979
VMX_PROCBASED_CTLS2_EPT |
987980
VMX_PROCBASED_CTLS2_RDTSCP |
988-
VMX_PROCBASED_CTLS2_UNRESTRICT);
981+
VMX_PROCBASED_CTLS2_UNRESTRICT|
982+
VMX_PROCBASED_CTLS2_VAPIC_REGS);
989983

990984
if (vcpu->arch_vcpu.vpid != 0U) {
991985
value32 |= VMX_PROCBASED_CTLS2_VPID;
992986
} else {
993987
value32 &= ~VMX_PROCBASED_CTLS2_VPID;
994988
}
995989

996-
if (is_apicv_supported()) {
997-
value32 |= VMX_PROCBASED_CTLS2_VAPIC;
998-
999-
if (is_apicv_virt_reg_supported()) {
1000-
value32 |= VMX_PROCBASED_CTLS2_VAPIC_REGS;
1001-
}
1002-
1003-
if (is_apicv_intr_delivery_supported()) {
1004-
value32 |= VMX_PROCBASED_CTLS2_VIRQ;
1005-
}
1006-
else {
1007-
/*
1008-
* This field exists only on processors that support
1009-
* the 1-setting of the "use TPR shadow"
1010-
* VM-execution control.
1011-
*
1012-
* Set up TPR threshold for virtual interrupt delivery
1013-
* - pg 2904 24.6.8
1014-
*/
1015-
exec_vmwrite32(VMX_TPR_THRESHOLD, 0U);
1016-
}
990+
if (is_apicv_intr_delivery_supported()) {
991+
value32 |= VMX_PROCBASED_CTLS2_VIRQ;
992+
} else {
993+
/*
994+
* This field exists only on processors that support
995+
* the 1-setting of the "use TPR shadow"
996+
* VM-execution control.
997+
*
998+
* Set up TPR threshold for virtual interrupt delivery
999+
* - pg 2904 24.6.8
1000+
*/
1001+
exec_vmwrite32(VMX_TPR_THRESHOLD, 0U);
10171002
}
10181003

10191004
if (cpu_has_cap(X86_FEATURE_OSXSAVE)) {
@@ -1024,29 +1009,24 @@ static void init_exec_ctrl(struct vcpu *vcpu)
10241009
exec_vmwrite32(VMX_PROC_VM_EXEC_CONTROLS2, value32);
10251010
pr_dbg("VMX_PROC_VM_EXEC_CONTROLS2: 0x%x ", value32);
10261011

1027-
if (is_apicv_supported()) {
1028-
/*APIC-v, config APIC-access address*/
1029-
value64 = vlapic_apicv_get_apic_access_addr(vcpu->vm);
1030-
exec_vmwrite64(VMX_APIC_ACCESS_ADDR_FULL,
1031-
value64);
1032-
1033-
/*APIC-v, config APIC virtualized page address*/
1034-
value64 = vlapic_apicv_get_apic_page_addr(
1035-
vcpu->arch_vcpu.vlapic);
1036-
exec_vmwrite64(VMX_VIRTUAL_APIC_PAGE_ADDR_FULL,
1037-
value64);
1038-
1039-
if (is_apicv_intr_delivery_supported()) {
1040-
/* Disable all EOI VMEXIT by default and
1041-
* clear RVI and SVI.
1042-
*/
1043-
exec_vmwrite64(VMX_EOI_EXIT0_FULL, 0UL);
1044-
exec_vmwrite64(VMX_EOI_EXIT1_FULL, 0UL);
1045-
exec_vmwrite64(VMX_EOI_EXIT2_FULL, 0UL);
1046-
exec_vmwrite64(VMX_EOI_EXIT3_FULL, 0UL);
1012+
/*APIC-v, config APIC-access address*/
1013+
value64 = vlapic_apicv_get_apic_access_addr(vcpu->vm);
1014+
exec_vmwrite64(VMX_APIC_ACCESS_ADDR_FULL, value64);
10471015

1048-
exec_vmwrite16(VMX_GUEST_INTR_STATUS, 0);
1049-
}
1016+
/*APIC-v, config APIC virtualized page address*/
1017+
value64 = vlapic_apicv_get_apic_page_addr(vcpu->arch_vcpu.vlapic);
1018+
exec_vmwrite64(VMX_VIRTUAL_APIC_PAGE_ADDR_FULL, value64);
1019+
1020+
if (is_apicv_intr_delivery_supported()) {
1021+
/* Disable all EOI VMEXIT by default and
1022+
* clear RVI and SVI.
1023+
*/
1024+
exec_vmwrite64(VMX_EOI_EXIT0_FULL, 0UL);
1025+
exec_vmwrite64(VMX_EOI_EXIT1_FULL, 0UL);
1026+
exec_vmwrite64(VMX_EOI_EXIT2_FULL, 0UL);
1027+
exec_vmwrite64(VMX_EOI_EXIT3_FULL, 0UL);
1028+
1029+
exec_vmwrite16(VMX_GUEST_INTR_STATUS, 0);
10501030
}
10511031

10521032
/* Load EPTP execution control

hypervisor/include/arch/x86/cpu.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,9 +323,7 @@ extern struct cpuinfo_x86 boot_cpu_data;
323323
void cpu_do_idle(__unused uint16_t pcpu_id);
324324
void cpu_dead(uint16_t pcpu_id);
325325
void trampoline_start16(void);
326-
bool is_apicv_supported(void);
327326
bool is_apicv_intr_delivery_supported(void);
328-
bool is_apicv_virt_reg_supported(void);
329327
bool is_ept_supported(void);
330328
bool cpu_has_cap(uint32_t bit);
331329
void load_cpu_state_data(void);

hypervisor/include/arch/x86/guest/vlapic.h

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,6 @@ struct acrn_vlapic *vm_lapic_from_pcpuid(struct vm *vm, uint16_t pcpu_id);
6060
int vlapic_rdmsr(struct vcpu *vcpu, uint32_t msr, uint64_t *rval);
6161
int vlapic_wrmsr(struct vcpu *vcpu, uint32_t msr, uint64_t wval);
6262

63-
int vlapic_read_mmio_reg(struct vcpu *vcpu, uint64_t gpa, uint64_t *rval,
64-
__unused uint8_t size);
65-
int vlapic_write_mmio_reg(struct vcpu *vcpu, uint64_t gpa,
66-
uint64_t wval, uint8_t size);
67-
6863
/*
6964
* Signals to the LAPIC that an interrupt at 'vector' needs to be generated
7065
* to the 'cpu', the state is recorded in IRR.
@@ -107,15 +102,9 @@ void vlapic_reset_tmr(struct acrn_vlapic *vlapic);
107102
void vlapic_set_tmr_one_vec(struct acrn_vlapic *vlapic, uint32_t delmode,
108103
uint32_t vector, bool level);
109104

110-
void
111-
vlapic_apicv_batch_set_tmr(struct acrn_vlapic *vlapic);
112-
113-
int vlapic_mmio_access_handler(struct vcpu *vcpu, struct io_request *io_req,
114-
__unused void *handler_private_data);
115-
105+
void vlapic_apicv_batch_set_tmr(struct acrn_vlapic *vlapic);
116106
uint32_t vlapic_get_id(struct acrn_vlapic *vlapic);
117107
uint8_t vlapic_get_apicid(struct acrn_vlapic *vlapic);
118-
119108
int vlapic_create(struct vcpu *vcpu);
120109
void vlapic_free(struct vcpu *vcpu);
121110
void vlapic_init(struct acrn_vlapic *vlapic);
@@ -129,6 +118,5 @@ int apic_access_vmexit_handler(struct vcpu *vcpu);
129118
int apic_write_vmexit_handler(struct vcpu *vcpu);
130119
int veoi_vmexit_handler(struct vcpu *vcpu);
131120
int tpr_below_threshold_vmexit_handler(__unused struct vcpu *vcpu);
132-
133121
void calcvdest(struct vm *vm, uint64_t *dmask, uint32_t dest, bool phys);
134122
#endif /* _VLAPIC_H_ */

0 commit comments

Comments
 (0)