From f3627d4839ae2a8d3a4f4ec83fbfdc078aeff4ee Mon Sep 17 00:00:00 2001 From: Sainath Grandhi Date: Mon, 10 Jun 2019 16:54:39 -0700 Subject: [PATCH] hv: Add update_vm_vlapic_state API to sync the VM vLAPIC state This patch introduces vLAPIC state for a VM. The VM vLAPIC state can be one of the following * VM_VLAPIC_X2APIC - All the vCPUs/vLAPICs (Except for those in Disabled mode) of this VM use x2APIC mode * VM_VLAPIC_XAPIC - All the vCPUs/vLAPICs (Except for those in Disabled mode) of this VM use xAPIC mode * VM_VLAPIC_DISABLED - All the vCPUs/vLAPICs of this VM are in Disabled mode * VM_VLAPIC_TRANSITION - Some of the vCPUs/vLAPICs of this VM (Except for those in Disabled mode) are in xAPIC and the others in x2APIC Upon a vCPU updating the IA32_APIC_BASE MSR to switch LAPIC mode, this API is called to sync the vLAPIC state of the VM. Upon VM creation and reset, vLAPIC state is set to VM_VLAPIC_XAPIC, as ACRN starts the vCPUs vLAPIC in XAPIC mode. Tracked-On: #3253 Signed-off-by: Sainath Grandhi Acked-by: Eddie Dong --- hypervisor/arch/x86/guest/vlapic.c | 2 + hypervisor/arch/x86/guest/vm.c | 82 ++++++++++++++++++++++++++ hypervisor/include/arch/x86/guest/vm.h | 11 +++- 3 files changed, 94 insertions(+), 1 deletion(-) diff --git a/hypervisor/arch/x86/guest/vlapic.c b/hypervisor/arch/x86/guest/vlapic.c index c448f982c..43a554b88 100644 --- a/hypervisor/arch/x86/guest/vlapic.c +++ b/hypervisor/arch/x86/guest/vlapic.c @@ -1763,6 +1763,7 @@ int32_t vlapic_set_apicbase(struct acrn_vlapic *vlapic, uint64_t new) int32_t ret = 0; uint64_t changed; bool change_in_vlapic_mode = false; + struct acrn_vcpu *vcpu = vlapic->vcpu; if (vlapic->msr_apicbase != new) { @@ -1783,6 +1784,7 @@ int32_t vlapic_set_apicbase(struct acrn_vlapic *vlapic, uint64_t new) vlapic->msr_apicbase = new; vlapic_build_x2apic_id(vlapic); switch_apicv_mode_x2apic(vlapic->vcpu); + update_vm_vlapic_state(vcpu->vm); } else { /* * TODO: Logic to check for Invalid transitions, Invalid State diff --git a/hypervisor/arch/x86/guest/vm.c b/hypervisor/arch/x86/guest/vm.c index 9f290c64a..aa24020bb 100644 --- a/hypervisor/arch/x86/guest/vm.c +++ b/hypervisor/arch/x86/guest/vm.c @@ -477,6 +477,9 @@ int32_t create_vm(uint16_t vm_id, struct acrn_vm_config *vm_config, struct acrn_ INIT_LIST_HEAD(&vm->softirq_dev_entry_list); spinlock_init(&vm->softirq_dev_lock); + spinlock_init(&vm->vm_lock); + + vm->arch_vm.vlapic_state = VM_VLAPIC_XAPIC; vm->intr_inject_delay_delta = 0UL; /* Set up IO bit-mask such that VM exit occurs on @@ -622,6 +625,11 @@ int32_t reset_vm(struct acrn_vm *vm) foreach_vcpu(i, vm, vcpu) { reset_vcpu(vcpu); } + /* + * Set VM vLAPIC state to VM_VLAPIC_XAPIC + */ + + vm->arch_vm.vlapic_state = VM_VLAPIC_XAPIC; if (is_sos_vm(vm)) { (void )vm_sw_loader(vm); @@ -632,6 +640,7 @@ int32_t reset_vm(struct acrn_vm *vm) destroy_secure_world(vm, false); vm->sworld_control.flag.active = 0UL; vm->state = VM_CREATED; + ret = 0; } else { ret = -1; @@ -759,3 +768,76 @@ void launch_vms(uint16_t pcpu_id) } } } + +/* + * @brief Update state of vLAPICs of a VM + * vLAPICs of VM switch between modes in an asynchronous fashion. This API + * captures the "transition" state triggered when one vLAPIC switches mode. + * When the VM is created, the state is set to "xAPIC" as all vLAPICs are setup + * in xAPIC mode. + * + * Upon reset, all LAPICs switch to xAPIC mode accroding to SDM 10.12.5 + * Considering VM uses x2apic mode for vLAPIC, in reset or shutdown flow, vLAPIC state + * moves to "xAPIC" directly without going thru "transition". + * + * VM_VLAPIC_X2APIC - All the online vCPUs/vLAPICs of this VM use x2APIC mode + * VM_VLAPIC_XAPIC - All the online vCPUs/vLAPICs of this VM use xAPIC mode + * VM_VLAPIC_DISABLED - All the online vCPUs/vLAPICs of this VM are in Disabled mode + * VM_VLAPIC_TRANSITION - Online vCPUs/vLAPICs of this VM are in between transistion + * + * TODO: offline_vcpu need to call this API to reflect the status of rest of the + * vLAPICs that are online. + * + * @pre vm != NULL + */ +void update_vm_vlapic_state(struct acrn_vm *vm) +{ + uint16_t i; + struct acrn_vcpu *vcpu; + uint16_t vcpus_in_x2apic, vcpus_in_xapic; + enum vm_vlapic_state vlapic_state = VM_VLAPIC_XAPIC; + + vcpus_in_x2apic = 0U; + vcpus_in_xapic = 0U; + spinlock_obtain(&vm->vm_lock); + foreach_vcpu(i, vm, vcpu) { + if (is_x2apic_enabled(vcpu_vlapic(vcpu))) { + vcpus_in_x2apic++; + } else if (is_xapic_enabled(vcpu_vlapic(vcpu))) { + vcpus_in_xapic++; + } else { + /* + * vCPU is using vLAPIC in Disabled mode + */ + } + } + + if ((vcpus_in_x2apic == 0U) && (vcpus_in_xapic == 0U)) { + /* + * Check if the counts vcpus_in_x2apic and vcpus_in_xapic are zero + * VM_VLAPIC_DISABLED + */ + vlapic_state = VM_VLAPIC_DISABLED; + } else if ((vcpus_in_x2apic != 0U) && (vcpus_in_xapic != 0U)) { + /* + * Check if the counts vcpus_in_x2apic and vcpus_in_xapic are non-zero + * VM_VLAPIC_TRANSITION + */ + vlapic_state = VM_VLAPIC_TRANSITION; + } else if (vcpus_in_x2apic != 0U) { + /* + * Check if the counts vcpus_in_x2apic is non-zero + * VM_VLAPIC_X2APIC + */ + vlapic_state = VM_VLAPIC_X2APIC; + } else { + /* + * Count vcpus_in_xapic is non-zero + * VM_VLAPIC_XAPIC + */ + vlapic_state = VM_VLAPIC_XAPIC; + } + + vm->arch_vm.vlapic_state = vlapic_state; + spinlock_release(&vm->vm_lock); +} diff --git a/hypervisor/include/arch/x86/guest/vm.h b/hypervisor/include/arch/x86/guest/vm.h index 47a420aef..a1486e68e 100644 --- a/hypervisor/include/arch/x86/guest/vm.h +++ b/hypervisor/include/arch/x86/guest/vm.h @@ -76,6 +76,13 @@ enum vm_state { VM_PAUSED, /* VM paused */ }; +enum vm_vlapic_state { + VM_VLAPIC_DISABLED = 0U, + VM_VLAPIC_XAPIC, + VM_VLAPIC_X2APIC, + VM_VLAPIC_TRANSITION +}; + struct vm_arch { /* I/O bitmaps A and B for this VM, MUST be 4-Kbyte aligned */ uint8_t io_bitmap[PAGE_SIZE*2]; @@ -93,6 +100,7 @@ struct vm_arch { void *tmp_pg_array; /* Page array for tmp guest paging struct */ struct acrn_vioapic vioapic; /* Virtual IOAPIC base address */ struct acrn_vpic vpic; /* Virtual PIC */ + enum vm_vlapic_state vlapic_state; /* Represents vLAPIC state across vCPUs*/ /* reference to virtual platform to come here (as needed) */ } __aligned(PAGE_SIZE); @@ -109,7 +117,7 @@ struct acrn_vm { struct acrn_vuart vuart[MAX_VUART_NUM_PER_VM]; /* Virtual UART */ enum vpic_wire_mode wire_mode; struct iommu_domain *iommu; /* iommu domain of this VM */ - spinlock_t spinlock; /* Spin-lock used to protect VM modifications */ + spinlock_t vm_lock; /* Spin-lock used to protect VM modifications */ uint16_t emul_mmio_regions; /* Number of emulated mmio regions */ struct mem_io_node emul_mmio[CONFIG_MAX_EMULATED_MMIO_REGIONS]; @@ -218,6 +226,7 @@ bool is_lapic_pt_configured(const struct acrn_vm *vm); bool is_rt_vm(const struct acrn_vm *vm); bool is_highest_severity_vm(const struct acrn_vm *vm); bool vm_hide_mtrr(const struct acrn_vm *vm); +void update_vm_vlapic_state(struct acrn_vm *vm); #endif /* !ASSEMBLER */