Skip to content

Commit 7d44cd5

Browse files
Sainath Grandhiwenlingz
authored andcommitted
hv: Introduce check_vm_vlapic_state API
This patch introduces check_vm_vlapic_state API instead of is_lapic_pt_enabled to check if all the vCPUs of a VM are using x2APIC mode and LAPIC pass-through is enabled on all of them. When the VM is in VM_VLAPIC_TRANSITION or VM_VLAPIC_DISABLED state, following conditions apply. 1) For pass-thru MSI interrupts, interrupt source is not programmed. 2) For DM emulated device MSI interrupts, interrupt is not delivered. 3) For IPIs, it will work only if the sender and destination are both in x2APIC mode. Tracked-On: #3253 Signed-off-by: Sainath Grandhi <sainath.grandhi@intel.com> Acked-by: Eddie Dong <eddie.dong@intel.com>
1 parent f3627d4 commit 7d44cd5

File tree

9 files changed

+98
-35
lines changed

9 files changed

+98
-35
lines changed

hypervisor/arch/x86/guest/assign.c

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -636,24 +636,49 @@ int32_t ptirq_msix_remap(struct acrn_vm *vm, uint16_t virt_bdf, uint16_t phys_bd
636636
spinlock_release(&ptdev_lock);
637637

638638
if (entry != NULL) {
639+
ret = 0;
639640
if (is_entry_active(entry) && (info->vmsi_data.full == 0U)) {
640641
/* handle destroy case */
641642
info->pmsi_data.full = 0U;
642643
} else {
643644
/* build physical config MSI, update to info->pmsi_xxx */
644-
if (is_lapic_pt_enabled(vm)) {
645-
/* for vm with lapic-pt, keep vector from guest */
646-
ptirq_build_physical_msi(vm, info, entry, (uint32_t)info->vmsi_data.bits.vector);
645+
if (is_lapic_pt_configured(vm)) {
646+
enum vm_vlapic_state vlapic_state = check_vm_vlapic_state(vm);
647+
if (vlapic_state == VM_VLAPIC_X2APIC) {
648+
/*
649+
* All the vCPUs are in x2APIC mode and LAPIC is Pass-through
650+
* Use guest vector to program the interrupt source
651+
*/
652+
ptirq_build_physical_msi(vm, info, entry, (uint32_t)info->vmsi_data.bits.vector);
653+
} else if (vlapic_state == VM_VLAPIC_XAPIC) {
654+
/*
655+
* All the vCPUs are in xAPIC mode and LAPIC is emulated
656+
* Use host vector to program the interrupt source
657+
*/
658+
ptirq_build_physical_msi(vm, info, entry, irq_to_vector(entry->allocated_pirq));
659+
} else if (vlapic_state == VM_VLAPIC_TRANSITION) {
660+
/*
661+
* vCPUs are in middle of transition, so do not program interrupt source
662+
* TODO: Devices programmed during transistion do not work after transition
663+
* as device is not programmed with interrupt info. Need to implement a
664+
* method to get interrupts working after transition.
665+
*/
666+
ret = -EFAULT;
667+
} else {
668+
/* Do nothing for VM_VLAPIC_DISABLED */
669+
ret = -EFAULT;
670+
}
647671
} else {
648672
ptirq_build_physical_msi(vm, info, entry, irq_to_vector(entry->allocated_pirq));
649673
}
650674

651-
entry->msi = *info;
652-
dev_dbg(ACRN_DBG_IRQ, "PCI %x:%x.%x MSI VR[%d] 0x%x->0x%x assigned to vm%d",
653-
pci_bus(virt_bdf), pci_slot(virt_bdf), pci_func(virt_bdf), entry_nr,
654-
info->vmsi_data.bits.vector, irq_to_vector(entry->allocated_pirq), entry->vm->vm_id);
675+
if (ret == 0) {
676+
entry->msi = *info;
677+
dev_dbg(ACRN_DBG_IRQ, "PCI %x:%x.%x MSI VR[%d] 0x%x->0x%x assigned to vm%d",
678+
pci_bus(virt_bdf), pci_slot(virt_bdf), pci_func(virt_bdf), entry_nr,
679+
info->vmsi_data.bits.vector, irq_to_vector(entry->allocated_pirq), entry->vm->vm_id);
680+
}
655681
}
656-
ret = 0;
657682
}
658683

659684
return ret;

hypervisor/arch/x86/guest/vcpu.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,7 @@ void pause_vcpu(struct acrn_vcpu *vcpu, enum vcpu_state new_state)
595595
if (atomic_load32(&vcpu->running) == 1U) {
596596
remove_from_cpu_runqueue(&vcpu->sched_obj, vcpu->pcpu_id);
597597

598-
if (is_lapic_pt_enabled(vcpu->vm)) {
598+
if (is_lapic_pt_enabled(vcpu)) {
599599
make_reschedule_request(vcpu->pcpu_id, DEL_MODE_INIT);
600600
} else {
601601
make_reschedule_request(vcpu->pcpu_id, DEL_MODE_IPI);
@@ -738,3 +738,17 @@ uint64_t vcpumask2pcpumask(struct acrn_vm *vm, uint64_t vdmask)
738738

739739
return dmask;
740740
}
741+
742+
/*
743+
* @brief Check if vCPU uses LAPIC in x2APIC mode and the VM, vCPU belongs to, is configured for
744+
* LAPIC Pass-through
745+
*
746+
* @pre vcpu != NULL
747+
*
748+
* @return true, if vCPU LAPIC is in x2APIC mode and VM, vCPU belongs to, is configured for
749+
* LAPIC Pass-through
750+
*/
751+
bool is_lapic_pt_enabled(struct acrn_vcpu *vcpu)
752+
{
753+
return ((is_x2apic_enabled(vcpu_vlapic(vcpu))) && (is_lapic_pt_configured(vcpu->vm)));
754+
}

hypervisor/arch/x86/guest/vlapic.c

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2042,6 +2042,9 @@ vlapic_x2apic_pt_icr_access(struct acrn_vm *vm, uint64_t val)
20422042
if ((phys == false) || (shorthand != APIC_DEST_DESTFLD)) {
20432043
pr_err("Logical destination mode or shorthands \
20442044
not supported in ICR forpartition mode\n");
2045+
/*
2046+
* TODO: To support logical destination and shorthand modes
2047+
*/
20452048
} else {
20462049
vcpu_id = vm_apicid2vcpu_id(vm, vapic_id);
20472050
if ((vcpu_id < vm->hw.created_vcpus) && (vm->hw.vcpu_array[vcpu_id].state != VCPU_OFFLINE)) {
@@ -2056,11 +2059,13 @@ vlapic_x2apic_pt_icr_access(struct acrn_vm *vm, uint64_t val)
20562059
break;
20572060
default:
20582061
/* convert the dest from virtual apic_id to physical apic_id */
2059-
papic_id = per_cpu(lapic_id, target_vcpu->pcpu_id);
2060-
dev_dbg(ACRN_DBG_LAPICPT,
2061-
"%s vapic_id: 0x%08lx papic_id: 0x%08lx icr_low:0x%08lx",
2062-
__func__, vapic_id, papic_id, icr_low);
2063-
msr_write(MSR_IA32_EXT_APIC_ICR, (((uint64_t)papic_id) << 32U) | icr_low);
2062+
if (is_x2apic_enabled(vcpu_vlapic(target_vcpu))) {
2063+
papic_id = per_cpu(lapic_id, target_vcpu->pcpu_id);
2064+
dev_dbg(ACRN_DBG_LAPICPT,
2065+
"%s vapic_id: 0x%08lx papic_id: 0x%08lx icr_low:0x%08lx",
2066+
__func__, vapic_id, papic_id, icr_low);
2067+
msr_write(MSR_IA32_EXT_APIC_ICR, (((uint64_t)papic_id) << 32U) | icr_low);
2068+
}
20642069
break;
20652070
}
20662071
ret = 0;
@@ -2602,14 +2607,3 @@ void vlapic_set_apicv_ops(void)
26022607
apicv_ops = &apicv_basic_ops;
26032608
}
26042609
}
2605-
2606-
/**
2607-
* @pre vm != NULL
2608-
* @pre vm->vmid < CONFIG_MAX_VM_NUM
2609-
*/
2610-
bool is_lapic_pt_enabled(struct acrn_vm *vm)
2611-
{
2612-
struct acrn_vcpu *vcpu = vcpu_from_vid(vm, 0U);
2613-
2614-
return ((is_x2apic_enabled(vcpu_vlapic(vcpu))) && (is_lapic_pt_configured(vm)));
2615-
}

hypervisor/arch/x86/guest/vm.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -559,15 +559,15 @@ int32_t shutdown_vm(struct acrn_vm *vm)
559559
reset_vcpu(vcpu);
560560
offline_vcpu(vcpu);
561561

562-
if (is_lapic_pt_enabled(vm)) {
562+
if (is_lapic_pt_enabled(vcpu)) {
563563
bitmap_set_nolock(vcpu->pcpu_id, &mask);
564564
make_pcpu_offline(vcpu->pcpu_id);
565565
}
566566
}
567567

568568
wait_pcpus_offline(mask);
569569

570-
if (is_lapic_pt_enabled(vm) && !start_pcpus(mask)) {
570+
if (is_lapic_pt_configured(vm) && !start_pcpus(mask)) {
571571
pr_fatal("Failed to start all cpus in mask(0x%llx)", mask);
572572
ret = -ETIMEDOUT;
573573
}
@@ -841,3 +841,16 @@ void update_vm_vlapic_state(struct acrn_vm *vm)
841841
vm->arch_vm.vlapic_state = vlapic_state;
842842
spinlock_release(&vm->vm_lock);
843843
}
844+
845+
/*
846+
* @brief Check state of vLAPICs of a VM
847+
*
848+
* @pre vm != NULL
849+
*/
850+
enum vm_vlapic_state check_vm_vlapic_state(const struct acrn_vm *vm)
851+
{
852+
enum vm_vlapic_state vlapic_state;
853+
854+
vlapic_state = vm->arch_vm.vlapic_state;
855+
return vlapic_state;
856+
}

hypervisor/common/hv_main.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ void vcpu_thread(struct sched_object *obj)
2727
init_vmcs(vcpu);
2828
}
2929

30-
if (!is_lapic_pt_enabled(vcpu->vm)) {
30+
if (!is_lapic_pt_enabled(vcpu)) {
3131
/* handle pending softirq when irq enable*/
3232
do_softirq();
3333
CPU_IRQ_DISABLE();
@@ -64,7 +64,7 @@ void vcpu_thread(struct sched_object *obj)
6464

6565
profiling_pre_vmexit_handler(vcpu);
6666

67-
if (!is_lapic_pt_enabled(vcpu->vm)) {
67+
if (!is_lapic_pt_enabled(vcpu)) {
6868
CPU_IRQ_ENABLE();
6969
}
7070
/* Dispatch handler */

hypervisor/common/hypercall.c

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -484,9 +484,27 @@ int32_t hcall_inject_msi(struct acrn_vm *vm, uint16_t vmid, uint64_t param)
484484
pr_err("%s: Unable copy param to vm\n", __func__);
485485
} else {
486486
/* For target cpu with lapic pt, send ipi instead of injection via vlapic */
487-
if (is_lapic_pt_enabled(target_vm)) {
488-
inject_msi_lapic_pt(target_vm, &msi);
489-
ret = 0;
487+
if (is_lapic_pt_configured(target_vm)) {
488+
enum vm_vlapic_state vlapic_state = check_vm_vlapic_state(vm);
489+
if (vlapic_state == VM_VLAPIC_X2APIC) {
490+
/*
491+
* All the vCPUs of VM are in x2APIC mode and LAPIC is PT
492+
* Inject the vMSI as an IPI directly to VM
493+
*/
494+
inject_msi_lapic_pt(target_vm, &msi);
495+
ret = 0;
496+
} else if (vlapic_state == VM_VLAPIC_XAPIC) {
497+
/*
498+
* All the vCPUs of VM are in xAPIC and use vLAPIC
499+
* Inject using vLAPIC
500+
*/
501+
ret = vlapic_intr_msi(target_vm, msi.msi_addr, msi.msi_data);
502+
} else {
503+
/*
504+
* For cases VM_VLAPIC_DISABLED and VM_VLAPIC_TRANSITION
505+
* Silently drop interrupt
506+
*/
507+
}
490508
} else {
491509
ret = vlapic_intr_msi(target_vm, msi.msi_addr, msi.msi_data);
492510
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -747,7 +747,7 @@ int32_t prepare_vcpu(struct acrn_vm *vm, uint16_t pcpu_id);
747747
* @return The physical destination CPU mask
748748
*/
749749
uint64_t vcpumask2pcpumask(struct acrn_vm *vm, uint64_t vdmask);
750-
750+
bool is_lapic_pt_enabled(struct acrn_vcpu *vcpu);
751751
/**
752752
* @}
753753
*/

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,6 @@ void vlapic_calc_dest(struct acrn_vm *vm, uint64_t *dmask, bool is_broadcast,
210210
uint32_t dest, bool phys, bool lowprio);
211211
void vlapic_calc_dest_lapic_pt(struct acrn_vm *vm, uint64_t *dmask, bool is_broadcast,
212212
uint32_t dest, bool phys);
213-
bool is_lapic_pt_enabled(struct acrn_vm *vm);
214213
bool is_x2apic_enabled(const struct acrn_vlapic *vlapic);
215214
bool is_xapic_enabled(const struct acrn_vlapic *vlapic);
216215
/**

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ bool is_rt_vm(const struct acrn_vm *vm);
227227
bool is_highest_severity_vm(const struct acrn_vm *vm);
228228
bool vm_hide_mtrr(const struct acrn_vm *vm);
229229
void update_vm_vlapic_state(struct acrn_vm *vm);
230-
230+
enum vm_vlapic_state check_vm_vlapic_state(const struct acrn_vm *vm);
231231
#endif /* !ASSEMBLER */
232232

233233
#endif /* VM_H_ */

0 commit comments

Comments
 (0)