From 382acfaf28a33fcd2bf01aa8189107096c034fbb Mon Sep 17 00:00:00 2001 From: Kaige Fu Date: Sun, 24 Mar 2019 10:15:25 +0000 Subject: [PATCH] HV: Using INIT to kick vCPUs off when RTVM poweroff by itself When RTVM is trying to poweroff by itself, we use INIT to kick vCPUs off the non-root mode. For RTVM, only if vm state equal VM_POWERING_OFF, we take action to pause the vCPUs with INIT signal. Otherwise, we will reject the pause request. Tracked-On: #2865 Signed-off-by: Kaige Fu Acked-by: Eddie Dong --- hypervisor/arch/x86/guest/vcpu.c | 8 +++++++- hypervisor/arch/x86/guest/vm.c | 17 ++++++++++++++--- hypervisor/arch/x86/guest/vmexit.c | 21 ++++++++++++++++++++- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/hypervisor/arch/x86/guest/vcpu.c b/hypervisor/arch/x86/guest/vcpu.c index 38a0f3429..81bcc1a75 100644 --- a/hypervisor/arch/x86/guest/vcpu.c +++ b/hypervisor/arch/x86/guest/vcpu.c @@ -598,7 +598,13 @@ void pause_vcpu(struct acrn_vcpu *vcpu, enum vcpu_state new_state) if (atomic_load32(&vcpu->running) == 1U) { remove_from_cpu_runqueue(&vcpu->sched_obj, vcpu->pcpu_id); - make_reschedule_request(vcpu->pcpu_id, DEL_MODE_IPI); + + if (is_lapic_pt(vcpu->vm)) { + make_reschedule_request(vcpu->pcpu_id, DEL_MODE_INIT); + } else { + make_reschedule_request(vcpu->pcpu_id, DEL_MODE_IPI); + } + release_schedule_lock(vcpu->pcpu_id); if (vcpu->pcpu_id != pcpu_id) { diff --git a/hypervisor/arch/x86/guest/vm.c b/hypervisor/arch/x86/guest/vm.c index 5d3502e24..50e3647f8 100644 --- a/hypervisor/arch/x86/guest/vm.c +++ b/hypervisor/arch/x86/guest/vm.c @@ -547,10 +547,21 @@ void pause_vm(struct acrn_vm *vm) struct acrn_vcpu *vcpu = NULL; if (vm->state != VM_PAUSED) { - vm->state = VM_PAUSED; + if (is_rt_vm(vm)) { + /* Only when RTVM is powering off by itself, we can pause vcpu */ + if (vm->state == VM_POWERING_OFF) { + foreach_vcpu(i, vm, vcpu) { + pause_vcpu(vcpu, VCPU_ZOMBIE); + } - foreach_vcpu(i, vm, vcpu) { - pause_vcpu(vcpu, VCPU_ZOMBIE); + vm->state = VM_PAUSED; + } + } else { + foreach_vcpu(i, vm, vcpu) { + pause_vcpu(vcpu, VCPU_ZOMBIE); + } + + vm->state = VM_PAUSED; } } } diff --git a/hypervisor/arch/x86/guest/vmexit.c b/hypervisor/arch/x86/guest/vmexit.c index dfab91e5e..acc91f01d 100644 --- a/hypervisor/arch/x86/guest/vmexit.c +++ b/hypervisor/arch/x86/guest/vmexit.c @@ -28,6 +28,7 @@ static int32_t unhandled_vmexit_handler(struct acrn_vcpu *vcpu); static int32_t xsetbv_vmexit_handler(struct acrn_vcpu *vcpu); static int32_t wbinvd_vmexit_handler(struct acrn_vcpu *vcpu); static int32_t undefined_vmexit_handler(struct acrn_vcpu *vcpu); +static int32_t init_signal_vmexit_handler(__unused struct acrn_vcpu *vcpu); /* VM Dispatch table for Exit condition handling */ static const struct vm_exit_dispatch dispatch_table[NR_VMX_EXIT_REASONS] = { @@ -38,7 +39,7 @@ static const struct vm_exit_dispatch dispatch_table[NR_VMX_EXIT_REASONS] = { [VMX_EXIT_REASON_TRIPLE_FAULT] = { .handler = unhandled_vmexit_handler}, [VMX_EXIT_REASON_INIT_SIGNAL] = { - .handler = unhandled_vmexit_handler}, + .handler = init_signal_vmexit_handler}, [VMX_EXIT_REASON_STARTUP_IPI] = { .handler = unhandled_vmexit_handler}, [VMX_EXIT_REASON_IO_SMI] = { @@ -343,3 +344,21 @@ static int32_t undefined_vmexit_handler(struct acrn_vcpu *vcpu) vcpu_inject_ud(vcpu); return 0; } + +/* + * This handler is only triggered by INIT signal when poweroff from inside of RTVM + */ +static int32_t init_signal_vmexit_handler(__unused struct acrn_vcpu *vcpu) +{ + /* + * Intel SDM Volume 3, 25.2: + * INIT signals. INIT signals cause VM exits. A logical processer performs none + * of the operations normally associated with these events. Such exits do not modify + * register state or clear pending events as they would outside of VMX operation (If + * a logical processor is the wait-for-SIPI state, INIT signals are blocked. They do + * not cause VM exits in this case). + * + * So, it is safe to ignore the signal and reture here. + */ + return 0; +}