diff --git a/hypervisor/arch/x86/guest/pm.c b/hypervisor/arch/x86/guest/pm.c index cf5bf0366..69cb0a775 100644 --- a/hypervisor/arch/x86/guest/pm.c +++ b/hypervisor/arch/x86/guest/pm.c @@ -150,20 +150,25 @@ static bool pm1ab_io_read(struct acrn_vcpu *vcpu, uint16_t addr, size_t width) return true; } -static inline void enter_s5(struct acrn_vm *vm, uint32_t pm1a_cnt_val, uint32_t pm1b_cnt_val) +static inline void enter_s5(struct acrn_vcpu *vcpu, uint32_t pm1a_cnt_val, uint32_t pm1b_cnt_val) { + struct acrn_vm *vm = vcpu->vm; + uint16_t pcpu_id = pcpuid_from_vcpu(vcpu); + get_vm_lock(vm); /* - * It's possible that ACRN come here from SOS and pre-launched VM. Currently, we - * assume SOS has full ACPI power management stack. That means the value from SOS - * should be saved and used to shutdown the system. + * Currently, we assume SOS has full ACPI power management stack. + * That means the value from SOS should be saved and used to shut + * down the system. */ if (is_sos_vm(vm)) { save_s5_reg_val(pm1a_cnt_val, pm1b_cnt_val); } pause_vm(vm); - (void)shutdown_vm(vm); put_vm_lock(vm); + + bitmap_set_nolock(vm->vm_id, &per_cpu(shutdown_vm_bitmap, pcpu_id)); + make_shutdown_vm_request(pcpu_id); } static inline void enter_s3(struct acrn_vm *vm, uint32_t pm1a_cnt_val, uint32_t pm1b_cnt_val) @@ -206,7 +211,7 @@ static bool pm1ab_io_write(struct acrn_vcpu *vcpu, uint16_t addr, size_t width, if (vm->pm.sx_state_data->s3_pkg.val_pm1a == val) { enter_s3(vm, v, 0U); } else if (vm->pm.sx_state_data->s5_pkg.val_pm1a == val) { - enter_s5(vm, v, 0U); + enter_s5(vcpu, v, 0U); } } @@ -220,7 +225,7 @@ static bool pm1ab_io_write(struct acrn_vcpu *vcpu, uint16_t addr, size_t width, if (vm->pm.sx_state_data->s3_pkg.val_pm1b == val) { enter_s3(vm, pm1a_cnt_val, v); } else if (vm->pm.sx_state_data->s5_pkg.val_pm1b == val) { - enter_s5(vm, pm1a_cnt_val, v); + enter_s5(vcpu, pm1a_cnt_val, v); } } else { /* the case broke ACPI spec */ diff --git a/hypervisor/arch/x86/guest/vm_reset.c b/hypervisor/arch/x86/guest/vm_reset.c index 7fabe6048..dd5b30568 100644 --- a/hypervisor/arch/x86/guest/vm_reset.c +++ b/hypervisor/arch/x86/guest/vm_reset.c @@ -52,7 +52,8 @@ void triple_fault_shutdown_vm(struct acrn_vcpu *vcpu) pause_vm(vm); put_vm_lock(vm); - per_cpu(shutdown_vm_id, pcpuid_from_vcpu(vcpu)) = vm->vm_id; + bitmap_set_nolock(vm->vm_id, + &per_cpu(shutdown_vm_bitmap, pcpuid_from_vcpu(vcpu))); make_shutdown_vm_request(pcpuid_from_vcpu(vcpu)); } } @@ -83,8 +84,9 @@ static bool handle_reset_reg_read(struct acrn_vcpu *vcpu, __unused uint16_t addr /** * @pre vm != NULL */ -static bool handle_common_reset_reg_write(struct acrn_vm *vm, bool reset) +static bool handle_common_reset_reg_write(struct acrn_vcpu *vcpu, bool reset) { + struct acrn_vm *vm = vcpu->vm; bool ret = true; get_vm_lock(vm); @@ -104,11 +106,10 @@ static bool handle_common_reset_reg_write(struct acrn_vm *vm, bool reset) * or pre-launched VM reset, * ACRN doesn't support re-launch, just shutdown the guest. */ - const struct acrn_vcpu *bsp = vcpu_from_vid(vm, BSP_CPU_ID); - pause_vm(vm); - per_cpu(shutdown_vm_id, pcpuid_from_vcpu(bsp)) = vm->vm_id; - make_shutdown_vm_request(pcpuid_from_vcpu(bsp)); + bitmap_set_nolock(vm->vm_id, + &per_cpu(shutdown_vm_bitmap, pcpuid_from_vcpu(vcpu))); + make_shutdown_vm_request(pcpuid_from_vcpu(vcpu)); } } else { if (is_postlaunched_vm(vm)) { @@ -132,7 +133,7 @@ static bool handle_common_reset_reg_write(struct acrn_vm *vm, bool reset) static bool handle_kb_write(struct acrn_vcpu *vcpu, __unused uint16_t addr, size_t bytes, uint32_t val) { /* ignore commands other than system reset */ - return handle_common_reset_reg_write(vcpu->vm, ((bytes == 1U) && (val == 0xfeU))); + return handle_common_reset_reg_write(vcpu, ((bytes == 1U) && (val == 0xfeU))); } static bool handle_kb_read(struct acrn_vcpu *vcpu, uint16_t addr, size_t bytes) @@ -163,7 +164,7 @@ static bool handle_kb_read(struct acrn_vcpu *vcpu, uint16_t addr, size_t bytes) static bool handle_cf9_write(struct acrn_vcpu *vcpu, __unused uint16_t addr, size_t bytes, uint32_t val) { /* We don't differentiate among hard/soft/warm/cold reset */ - return handle_common_reset_reg_write(vcpu->vm, + return handle_common_reset_reg_write(vcpu, ((bytes == 1U) && ((val & 0x4U) == 0x4U) && ((val & 0xaU) != 0U))); } @@ -179,7 +180,7 @@ static bool handle_reset_reg_write(struct acrn_vcpu *vcpu, uint16_t addr, size_t struct acpi_reset_reg *reset_reg = get_host_reset_reg_data(); if (val == reset_reg->val) { - ret = handle_common_reset_reg_write(vcpu->vm, true); + ret = handle_common_reset_reg_write(vcpu, true); } else { /* * ACPI defines the reset value but doesn't specify the meaning of other values. @@ -234,7 +235,17 @@ void register_reset_port_handler(struct acrn_vm *vm) void shutdown_vm_from_idle(uint16_t pcpu_id) { - struct acrn_vm *vm = get_vm_from_vmid(per_cpu(shutdown_vm_id, pcpu_id)); + uint16_t vm_id; + uint64_t *vms = &per_cpu(shutdown_vm_bitmap, pcpu_id); + struct acrn_vm *vm; - (void)shutdown_vm(vm); + for (vm_id = fls64(*vms); vm_id < CONFIG_MAX_VM_NUM; vm_id = fls64(*vms)) { + vm = get_vm_from_vmid(vm_id); + get_vm_lock(vm); + if (is_paused_vm(vm)) { + (void)shutdown_vm(vm); + } + put_vm_lock(vm); + bitmap_clear_nolock(vm_id, vms); + } } diff --git a/hypervisor/common/hypercall.c b/hypervisor/common/hypercall.c index ed3f90647..8c00eff1f 100644 --- a/hypervisor/common/hypercall.c +++ b/hypervisor/common/hypercall.c @@ -256,10 +256,13 @@ int32_t hcall_destroy_vm(__unused struct acrn_vm *vm, struct acrn_vm *target_vm, { int32_t ret = -1; + get_vm_lock(target_vm); if (is_paused_vm(target_vm)) { /* TODO: check target_vm guest_flags */ ret = shutdown_vm(target_vm); } + put_vm_lock(target_vm); + return ret; } diff --git a/hypervisor/include/arch/x86/per_cpu.h b/hypervisor/include/arch/x86/per_cpu.h index 05dfbf794..e584a37fe 100644 --- a/hypervisor/include/arch/x86/per_cpu.h +++ b/hypervisor/include/arch/x86/per_cpu.h @@ -57,7 +57,7 @@ struct per_cpu_region { #ifdef PROFILING_ON struct profiling_info_wrapper profiling_info; #endif - uint16_t shutdown_vm_id; + uint64_t shutdown_vm_bitmap; uint64_t tsc_suspend; /* * We maintain a per-pCPU array of vCPUs. vCPUs of a VM won't