Author: neel
Date: Fri May  2 00:33:56 2014
New Revision: 265203
URL: http://svnweb.freebsd.org/changeset/base/265203

Log:
  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@

Modified:
  head/sys/amd64/include/vmm.h
  head/sys/amd64/vmm/vmm.c
  head/usr.sbin/bhyve/bhyverun.c

Modified: head/sys/amd64/include/vmm.h
==============================================================================
--- head/sys/amd64/include/vmm.h        Thu May  1 23:34:14 2014        
(r265202)
+++ head/sys/amd64/include/vmm.h        Fri May  2 00:33:56 2014        
(r265203)
@@ -33,6 +33,7 @@ enum vm_suspend_how {
        VM_SUSPEND_NONE,
        VM_SUSPEND_RESET,
        VM_SUSPEND_POWEROFF,
+       VM_SUSPEND_HALT,
        VM_SUSPEND_LAST
 };
 

Modified: head/sys/amd64/vmm/vmm.c
==============================================================================
--- head/sys/amd64/vmm/vmm.c    Thu May  1 23:34:14 2014        (r265202)
+++ head/sys/amd64/vmm/vmm.c    Fri May  2 00:33:56 2014        (r265203)
@@ -142,6 +142,8 @@ struct vm {
 
        int             suspend;
        volatile cpuset_t suspended_cpus;
+
+       volatile cpuset_t halted_cpus;
 };
 
 static int vmm_initialized;
@@ -1006,9 +1008,13 @@ vm_handle_hlt(struct vm *vm, int vcpuid,
 {
        struct vcpu *vcpu;
        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_halted = 0;
+       vm_halted = 0;
 
        vcpu_lock(vcpu);
        while (1) {
@@ -1032,10 +1038,26 @@ vm_handle_hlt(struct vm *vm, int vcpuid,
                        }
                }
 
-               if (vlapic_enabled(vcpu->vlapic))
-                       wmesg = "vmidle";
-               else
+               /*
+                * Some Linux guests implement "halt" by having all vcpus
+                * 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";
+                       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;
                vcpu_require_state_locked(vcpu, VCPU_SLEEPING);
@@ -1043,8 +1065,15 @@ vm_handle_hlt(struct vm *vm, int vcpuid,
                vcpu_require_state_locked(vcpu, VCPU_FROZEN);
                vmm_stat_incr(vm, vcpuid, VCPU_IDLE_TICKS, ticks - t);
        }
+
+       if (vcpu_halted)
+               CPU_CLR_ATOMIC(vcpuid, &vm->halted_cpus);
+
        vcpu_unlock(vcpu);
 
+       if (vm_halted)
+               vm_suspend(vm, VM_SUSPEND_HALT);
+
        return (0);
 }
 

Modified: head/usr.sbin/bhyve/bhyverun.c
==============================================================================
--- head/usr.sbin/bhyve/bhyverun.c      Thu May  1 23:34:14 2014        
(r265202)
+++ head/usr.sbin/bhyve/bhyverun.c      Fri May  2 00:33:56 2014        
(r265203)
@@ -453,7 +453,6 @@ vmexit_suspend(struct vmctx *ctx, struct
        enum vm_suspend_how how;
 
        how = vmexit->u.suspended.how;
-       assert(how == VM_SUSPEND_RESET || how == VM_SUSPEND_POWEROFF);
 
        fbsdrun_deletecpu(ctx, *pvcpu);
 
@@ -470,10 +469,17 @@ vmexit_suspend(struct vmctx *ctx, struct
        }
        pthread_mutex_unlock(&resetcpu_mtx);
 
-       if (how == VM_SUSPEND_RESET)
+       switch (how) {
+       case VM_SUSPEND_RESET:
                exit(0);
-       if (how == VM_SUSPEND_POWEROFF)
+       case VM_SUSPEND_POWEROFF:
                exit(1);
+       case VM_SUSPEND_HALT:
+               exit(2);
+       default:
+               fprintf(stderr, "vmexit_suspend: invalid reason %d\n", how);
+               exit(100);
+       }
        return (0);     /* NOTREACHED */
 }
 
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to