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 <kaige.fu@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
Kaige Fu 2019-03-24 10:15:25 +00:00 committed by ACRN System Integration
parent 2771b46b1d
commit 382acfaf28
3 changed files with 41 additions and 5 deletions

View File

@ -598,7 +598,13 @@ void pause_vcpu(struct acrn_vcpu *vcpu, enum vcpu_state new_state)
if (atomic_load32(&vcpu->running) == 1U) { if (atomic_load32(&vcpu->running) == 1U) {
remove_from_cpu_runqueue(&vcpu->sched_obj, vcpu->pcpu_id); 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); release_schedule_lock(vcpu->pcpu_id);
if (vcpu->pcpu_id != pcpu_id) { if (vcpu->pcpu_id != pcpu_id) {

View File

@ -547,10 +547,21 @@ void pause_vm(struct acrn_vm *vm)
struct acrn_vcpu *vcpu = NULL; struct acrn_vcpu *vcpu = NULL;
if (vm->state != VM_PAUSED) { 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) { vm->state = VM_PAUSED;
pause_vcpu(vcpu, VCPU_ZOMBIE); }
} else {
foreach_vcpu(i, vm, vcpu) {
pause_vcpu(vcpu, VCPU_ZOMBIE);
}
vm->state = VM_PAUSED;
} }
} }
} }

View File

@ -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 xsetbv_vmexit_handler(struct acrn_vcpu *vcpu);
static int32_t wbinvd_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 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 */ /* VM Dispatch table for Exit condition handling */
static const struct vm_exit_dispatch dispatch_table[NR_VMX_EXIT_REASONS] = { 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] = { [VMX_EXIT_REASON_TRIPLE_FAULT] = {
.handler = unhandled_vmexit_handler}, .handler = unhandled_vmexit_handler},
[VMX_EXIT_REASON_INIT_SIGNAL] = { [VMX_EXIT_REASON_INIT_SIGNAL] = {
.handler = unhandled_vmexit_handler}, .handler = init_signal_vmexit_handler},
[VMX_EXIT_REASON_STARTUP_IPI] = { [VMX_EXIT_REASON_STARTUP_IPI] = {
.handler = unhandled_vmexit_handler}, .handler = unhandled_vmexit_handler},
[VMX_EXIT_REASON_IO_SMI] = { [VMX_EXIT_REASON_IO_SMI] = {
@ -343,3 +344,21 @@ static int32_t undefined_vmexit_handler(struct acrn_vcpu *vcpu)
vcpu_inject_ud(vcpu); vcpu_inject_ud(vcpu);
return 0; 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;
}