mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-27 15:56:54 +00:00
hv: vm: properly reset pCPUs with LAPIC PT enabled during VM shutdown/reset
When a VM is configured with LAPIC PT mode and its vCPU is in x2APIC mode, the corresponding pCPU needs to be reset during VM shutdown/reset as its physical LAPIC was used by its guest This commit fixes an issue where this reset never happens. is_lapic_pt_enabled() needs to be called before reset_vcpu() to be able to correctly reflect a vCPU's APIC mode. A vCPU with LAPIC PT mode but in xAPIC mode does not require such reset, since its physical LAPIC was not touched by its guest directly. Tracked-On: #3708 Signed-off-by: Peter Fang <peter.fang@intel.com> Reviewed-by: Eddie Dong <eddie.dong@intel.com> Reviewed-by: Jack Ren <jack.ren@intel.com>
This commit is contained in:
parent
bad753299b
commit
e5f733fb98
@ -545,6 +545,8 @@ int32_t create_vm(uint16_t vm_id, struct acrn_vm_config *vm_config, struct acrn_
|
|||||||
int32_t shutdown_vm(struct acrn_vm *vm)
|
int32_t shutdown_vm(struct acrn_vm *vm)
|
||||||
{
|
{
|
||||||
uint16_t i;
|
uint16_t i;
|
||||||
|
uint16_t this_pcpu_id = get_pcpu_id();
|
||||||
|
bool offline_pcpu;
|
||||||
uint64_t mask = 0UL;
|
uint64_t mask = 0UL;
|
||||||
struct acrn_vcpu *vcpu = NULL;
|
struct acrn_vcpu *vcpu = NULL;
|
||||||
struct acrn_vm_config *vm_config = NULL;
|
struct acrn_vm_config *vm_config = NULL;
|
||||||
@ -557,18 +559,26 @@ int32_t shutdown_vm(struct acrn_vm *vm)
|
|||||||
vm->state = VM_POWERED_OFF;
|
vm->state = VM_POWERED_OFF;
|
||||||
|
|
||||||
foreach_vcpu(i, vm, vcpu) {
|
foreach_vcpu(i, vm, vcpu) {
|
||||||
|
offline_pcpu = is_lapic_pt_enabled(vcpu);
|
||||||
reset_vcpu(vcpu);
|
reset_vcpu(vcpu);
|
||||||
offline_vcpu(vcpu);
|
offline_vcpu(vcpu);
|
||||||
|
|
||||||
if (is_lapic_pt_enabled(vcpu)) {
|
if (offline_pcpu) {
|
||||||
bitmap_set_nolock(vcpu->pcpu_id, &mask);
|
/*
|
||||||
|
* If the current pcpu needs to offline itself,
|
||||||
|
* it will be done after shutdown_vm() completes
|
||||||
|
* in the idle thread.
|
||||||
|
*/
|
||||||
|
if (this_pcpu_id != vcpu->pcpu_id) {
|
||||||
|
bitmap_set_nolock(vcpu->pcpu_id, &mask);
|
||||||
|
}
|
||||||
make_pcpu_offline(vcpu->pcpu_id);
|
make_pcpu_offline(vcpu->pcpu_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wait_pcpus_offline(mask);
|
wait_pcpus_offline(mask);
|
||||||
|
|
||||||
if (is_lapic_pt_configured(vm) && !start_pcpus(mask)) {
|
if (mask != 0UL && !start_pcpus(mask)) {
|
||||||
pr_fatal("Failed to start all cpus in mask(0x%llx)", mask);
|
pr_fatal("Failed to start all cpus in mask(0x%llx)", mask);
|
||||||
ret = -ETIMEDOUT;
|
ret = -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
@ -591,10 +601,8 @@ int32_t shutdown_vm(struct acrn_vm *vm)
|
|||||||
|
|
||||||
/* Free EPT allocated resources assigned to VM */
|
/* Free EPT allocated resources assigned to VM */
|
||||||
destroy_ept(vm);
|
destroy_ept(vm);
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
} else {
|
} else {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return status to caller */
|
/* Return status to caller */
|
||||||
@ -621,17 +629,39 @@ void start_vm(struct acrn_vm *vm)
|
|||||||
int32_t reset_vm(struct acrn_vm *vm)
|
int32_t reset_vm(struct acrn_vm *vm)
|
||||||
{
|
{
|
||||||
uint16_t i;
|
uint16_t i;
|
||||||
|
uint16_t this_pcpu_id = get_pcpu_id();
|
||||||
|
bool offline_pcpu;
|
||||||
|
uint64_t mask = 0UL;
|
||||||
struct acrn_vcpu *vcpu = NULL;
|
struct acrn_vcpu *vcpu = NULL;
|
||||||
int32_t ret;
|
int32_t ret = 0;
|
||||||
|
|
||||||
if (vm->state == VM_PAUSED) {
|
if (vm->state == VM_PAUSED) {
|
||||||
foreach_vcpu(i, vm, vcpu) {
|
foreach_vcpu(i, vm, vcpu) {
|
||||||
|
offline_pcpu = is_lapic_pt_enabled(vcpu);
|
||||||
reset_vcpu(vcpu);
|
reset_vcpu(vcpu);
|
||||||
|
|
||||||
|
if (offline_pcpu) {
|
||||||
|
if (this_pcpu_id != vcpu->pcpu_id) {
|
||||||
|
bitmap_set_nolock(vcpu->pcpu_id, &mask);
|
||||||
|
make_pcpu_offline(vcpu->pcpu_id);
|
||||||
|
} else {
|
||||||
|
pr_warn("%s: cannot offline self(%u)",
|
||||||
|
__func__, this_pcpu_id);
|
||||||
|
ret = -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wait_pcpus_offline(mask);
|
||||||
|
|
||||||
|
if (mask != 0UL && !start_pcpus(mask)) {
|
||||||
|
pr_fatal("Failed to start all cpus in mask(0x%llx)", mask);
|
||||||
|
ret = -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set VM vLAPIC state to VM_VLAPIC_XAPIC
|
* Set VM vLAPIC state to VM_VLAPIC_XAPIC
|
||||||
*/
|
*/
|
||||||
|
|
||||||
vm->arch_vm.vlapic_state = VM_VLAPIC_XAPIC;
|
vm->arch_vm.vlapic_state = VM_VLAPIC_XAPIC;
|
||||||
|
|
||||||
if (is_sos_vm(vm)) {
|
if (is_sos_vm(vm)) {
|
||||||
@ -643,10 +673,8 @@ int32_t reset_vm(struct acrn_vm *vm)
|
|||||||
destroy_secure_world(vm, false);
|
destroy_secure_world(vm, false);
|
||||||
vm->sworld_control.flag.active = 0UL;
|
vm->sworld_control.flag.active = 0UL;
|
||||||
vm->state = VM_CREATED;
|
vm->state = VM_CREATED;
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
} else {
|
} else {
|
||||||
ret = -1;
|
ret = -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
Loading…
Reference in New Issue
Block a user