Add logic in the HLT exit handler to detect if the guest has put all vcpus
to sleep permanently by executing a HLT with interrupts disabled. When this condition is detected the guest with be suspended with a reason of VM_SUSPEND_HALT and the bhyve(8) process will exit. Tested by executing "halt" inside a RHEL7-beta guest. Discussed with: grehan@ Reviewed by: jhb@, tychon@
This commit is contained in:
parent
eab20bceca
commit
e50ce2aa06
@ -33,6 +33,7 @@ enum vm_suspend_how {
|
|||||||
VM_SUSPEND_NONE,
|
VM_SUSPEND_NONE,
|
||||||
VM_SUSPEND_RESET,
|
VM_SUSPEND_RESET,
|
||||||
VM_SUSPEND_POWEROFF,
|
VM_SUSPEND_POWEROFF,
|
||||||
|
VM_SUSPEND_HALT,
|
||||||
VM_SUSPEND_LAST
|
VM_SUSPEND_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -142,6 +142,8 @@ struct vm {
|
|||||||
|
|
||||||
int suspend;
|
int suspend;
|
||||||
volatile cpuset_t suspended_cpus;
|
volatile cpuset_t suspended_cpus;
|
||||||
|
|
||||||
|
volatile cpuset_t halted_cpus;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int vmm_initialized;
|
static int vmm_initialized;
|
||||||
@ -1006,9 +1008,13 @@ vm_handle_hlt(struct vm *vm, int vcpuid, bool intr_disabled, bool *retu)
|
|||||||
{
|
{
|
||||||
struct vcpu *vcpu;
|
struct vcpu *vcpu;
|
||||||
const char *wmesg;
|
const char *wmesg;
|
||||||
int t;
|
int t, vcpu_halted, vm_halted;
|
||||||
|
|
||||||
|
KASSERT(!CPU_ISSET(vcpuid, &vm->halted_cpus), ("vcpu already halted"));
|
||||||
|
|
||||||
vcpu = &vm->vcpu[vcpuid];
|
vcpu = &vm->vcpu[vcpuid];
|
||||||
|
vcpu_halted = 0;
|
||||||
|
vm_halted = 0;
|
||||||
|
|
||||||
vcpu_lock(vcpu);
|
vcpu_lock(vcpu);
|
||||||
while (1) {
|
while (1) {
|
||||||
@ -1032,10 +1038,26 @@ vm_handle_hlt(struct vm *vm, int vcpuid, bool intr_disabled, bool *retu)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vlapic_enabled(vcpu->vlapic))
|
/*
|
||||||
wmesg = "vmidle";
|
* Some Linux guests implement "halt" by having all vcpus
|
||||||
else
|
* execute HLT with interrupts disabled. 'halted_cpus' keeps
|
||||||
|
* track of the vcpus that have entered this state. When all
|
||||||
|
* vcpus enter the halted state the virtual machine is halted.
|
||||||
|
*/
|
||||||
|
if (intr_disabled) {
|
||||||
wmesg = "vmhalt";
|
wmesg = "vmhalt";
|
||||||
|
VCPU_CTR0(vm, vcpuid, "Halted");
|
||||||
|
if (!vcpu_halted) {
|
||||||
|
vcpu_halted = 1;
|
||||||
|
CPU_SET_ATOMIC(vcpuid, &vm->halted_cpus);
|
||||||
|
}
|
||||||
|
if (CPU_CMP(&vm->halted_cpus, &vm->active_cpus) == 0) {
|
||||||
|
vm_halted = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
wmesg = "vmidle";
|
||||||
|
}
|
||||||
|
|
||||||
t = ticks;
|
t = ticks;
|
||||||
vcpu_require_state_locked(vcpu, VCPU_SLEEPING);
|
vcpu_require_state_locked(vcpu, VCPU_SLEEPING);
|
||||||
@ -1043,8 +1065,15 @@ vm_handle_hlt(struct vm *vm, int vcpuid, bool intr_disabled, bool *retu)
|
|||||||
vcpu_require_state_locked(vcpu, VCPU_FROZEN);
|
vcpu_require_state_locked(vcpu, VCPU_FROZEN);
|
||||||
vmm_stat_incr(vm, vcpuid, VCPU_IDLE_TICKS, ticks - t);
|
vmm_stat_incr(vm, vcpuid, VCPU_IDLE_TICKS, ticks - t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (vcpu_halted)
|
||||||
|
CPU_CLR_ATOMIC(vcpuid, &vm->halted_cpus);
|
||||||
|
|
||||||
vcpu_unlock(vcpu);
|
vcpu_unlock(vcpu);
|
||||||
|
|
||||||
|
if (vm_halted)
|
||||||
|
vm_suspend(vm, VM_SUSPEND_HALT);
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -453,7 +453,6 @@ vmexit_suspend(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
|
|||||||
enum vm_suspend_how how;
|
enum vm_suspend_how how;
|
||||||
|
|
||||||
how = vmexit->u.suspended.how;
|
how = vmexit->u.suspended.how;
|
||||||
assert(how == VM_SUSPEND_RESET || how == VM_SUSPEND_POWEROFF);
|
|
||||||
|
|
||||||
fbsdrun_deletecpu(ctx, *pvcpu);
|
fbsdrun_deletecpu(ctx, *pvcpu);
|
||||||
|
|
||||||
@ -470,10 +469,17 @@ vmexit_suspend(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
|
|||||||
}
|
}
|
||||||
pthread_mutex_unlock(&resetcpu_mtx);
|
pthread_mutex_unlock(&resetcpu_mtx);
|
||||||
|
|
||||||
if (how == VM_SUSPEND_RESET)
|
switch (how) {
|
||||||
|
case VM_SUSPEND_RESET:
|
||||||
exit(0);
|
exit(0);
|
||||||
if (how == VM_SUSPEND_POWEROFF)
|
case VM_SUSPEND_POWEROFF:
|
||||||
exit(1);
|
exit(1);
|
||||||
|
case VM_SUSPEND_HALT:
|
||||||
|
exit(2);
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "vmexit_suspend: invalid reason %d\n", how);
|
||||||
|
exit(100);
|
||||||
|
}
|
||||||
return (0); /* NOTREACHED */
|
return (0); /* NOTREACHED */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user