Author: neel
Date: Fri Dec 27 20:18:19 2013
New Revision: 259961
URL: http://svnweb.freebsd.org/changeset/base/259961

Log:
  Modify handling of writes to the vlapic ICR_TIMER, DCR_TIMER, ICRLO and ESR
  registers.
  
  The handler is now called after the register value is updated in the virtual
  APIC page. This will make it easier to handle APIC-write VM-exits with APIC
  register virtualization turned on.
  
  We can no longer rely on the value of 'icr_timer' on the APIC page
  in the callout handler. With APIC register virtualization the value of
  'icr_timer' will be updated by the processor in guest-context before an
  APIC-write VM-exit.
  
  Clear the 'delivery status' bit in the ICRLO register in the write handler.
  With APIC register virtualization the write happens in guest-context and
  we cannot prevent a (buggy) guest from setting this bit.

Modified:
  head/sys/amd64/vmm/io/vlapic.c
  head/sys/amd64/vmm/io/vlapic.h

Modified: head/sys/amd64/vmm/io/vlapic.c
==============================================================================
--- head/sys/amd64/vmm/io/vlapic.c      Fri Dec 27 19:53:42 2013        
(r259960)
+++ head/sys/amd64/vmm/io/vlapic.c      Fri Dec 27 20:18:19 2013        
(r259961)
@@ -100,14 +100,9 @@ do {                                                       
                \
 
 /*
  * The 'vlapic->timer_mtx' is used to provide mutual exclusion between the
- * vlapic_callout_handler() and vcpu accesses to the following registers:
- * - initial count register aka icr_timer
- * - current count register aka ccr_timer
- * - divide config register aka dcr_timer
+ * vlapic_callout_handler() and vcpu accesses to:
+ * - timer_freq_bt, timer_period_bt, timer_fire_bt
  * - timer LVT register
- *
- * Note that the vlapic_callout_handler() does not write to any of these
- * registers so they can be safely read from the vcpu context without locking.
  */
 #define        VLAPIC_TIMER_LOCK(vlapic)       
mtx_lock_spin(&((vlapic)->timer_mtx))
 #define        VLAPIC_TIMER_UNLOCK(vlapic)     
mtx_unlock_spin(&((vlapic)->timer_mtx))
@@ -273,8 +268,8 @@ vlapic_get_ccr(struct vlapic *vlapic)
        return (ccr);
 }
 
-static void
-vlapic_set_dcr(struct vlapic *vlapic, uint32_t dcr)
+void
+vlapic_dcr_write_handler(struct vlapic *vlapic)
 {
        struct LAPIC *lapic;
        int divisor;
@@ -282,9 +277,9 @@ vlapic_set_dcr(struct vlapic *vlapic, ui
        lapic = vlapic->apic_page;
        VLAPIC_TIMER_LOCK(vlapic);
 
-       lapic->dcr_timer = dcr;
-       divisor = vlapic_timer_divisor(dcr);
-       VLAPIC_CTR2(vlapic, "vlapic dcr_timer=%#x, divisor=%d", dcr, divisor);
+       divisor = vlapic_timer_divisor(lapic->dcr_timer);
+       VLAPIC_CTR2(vlapic, "vlapic dcr_timer=%#x, divisor=%d",
+           lapic->dcr_timer, divisor);
 
        /*
         * Update the timer frequency and the timer period.
@@ -299,8 +294,8 @@ vlapic_set_dcr(struct vlapic *vlapic, ui
        VLAPIC_TIMER_UNLOCK(vlapic);
 }
 
-static void
-vlapic_update_errors(struct vlapic *vlapic)
+void
+vlapic_esr_write_handler(struct vlapic *vlapic)
 {
        struct LAPIC *lapic;
        
@@ -323,7 +318,9 @@ vlapic_reset(struct vlapic *vlapic)
        lapic->dfr = 0xffffffff;
        lapic->svr = APIC_SVR_VECTOR;
        vlapic_mask_lvts(vlapic);
-       vlapic_set_dcr(vlapic, 0);
+
+       lapic->dcr_timer = 0;
+       vlapic_dcr_write_handler(vlapic);
 
        if (vlapic->vcpuid == 0)
                vlapic->boot_state = BS_RUNNING;        /* BSP */
@@ -711,8 +708,6 @@ vlapic_callout_handler(void *arg)
 
        callout_deactivate(&vlapic->callout);
 
-       KASSERT(vlapic->apic_page->icr_timer != 0, ("timer is disabled"));
-
        vlapic_fire_timer(vlapic);
 
        if (vlapic_periodic_timer(vlapic)) {
@@ -757,16 +752,17 @@ done:
        VLAPIC_TIMER_UNLOCK(vlapic);
 }
 
-static void
-vlapic_set_icr_timer(struct vlapic *vlapic, uint32_t icr_timer)
+void
+vlapic_icrtmr_write_handler(struct vlapic *vlapic)
 {
        struct LAPIC *lapic;
        sbintime_t sbt;
+       uint32_t icr_timer;
 
        VLAPIC_TIMER_LOCK(vlapic);
 
        lapic = vlapic->apic_page;
-       lapic->icr_timer = icr_timer;
+       icr_timer = lapic->icr_timer;
 
        vlapic->timer_period_bt = vlapic->timer_freq_bt;
        bintime_mul(&vlapic->timer_period_bt, icr_timer);
@@ -888,16 +884,22 @@ vlapic_calcdest(struct vm *vm, cpuset_t 
 
 static VMM_STAT_ARRAY(IPIS_SENT, VM_MAXCPU, "ipis sent to vcpu");
 
-static int
-lapic_process_icr(struct vlapic *vlapic, uint64_t icrval, bool *retu)
+int
+vlapic_icrlo_write_handler(struct vlapic *vlapic, bool *retu)
 {
        int i;
        bool phys;
        cpuset_t dmask;
+       uint64_t icrval;
        uint32_t dest, vec, mode;
        struct vlapic *vlapic2;
        struct vm_exit *vmexit;
-       
+       struct LAPIC *lapic;
+
+       lapic = vlapic->apic_page;
+       lapic->icr_lo &= ~APIC_DELSTAT_PEND;
+       icrval = ((uint64_t)lapic->icr_hi << 32) | lapic->icr_lo;
+
        if (x2apic(vlapic))
                dest = icrval >> 32;
        else
@@ -1088,7 +1090,7 @@ vlapic_svr_write_handler(struct vlapic *
                         */
                        VLAPIC_CTR0(vlapic, "vlapic is software-enabled");
                        if (vlapic_periodic_timer(vlapic))
-                               vlapic_set_icr_timer(vlapic, lapic->icr_timer);
+                               vlapic_icrtmr_write_handler(vlapic);
                }
        }
 }
@@ -1155,6 +1157,8 @@ vlapic_read(struct vlapic *vlapic, uint6
                        break;
                case APIC_OFFSET_ICR_LOW: 
                        *data = lapic->icr_lo;
+                       if (x2apic(vlapic))
+                               *data |= (uint64_t)lapic->icr_hi << 32;
                        break;
                case APIC_OFFSET_ICR_HI: 
                        *data = lapic->icr_hi;
@@ -1224,32 +1228,30 @@ vlapic_write(struct vlapic *vlapic, uint
                        vlapic_svr_write_handler(vlapic);
                        break;
                case APIC_OFFSET_ICR_LOW: 
-                       if (!x2apic(vlapic)) {
-                               data &= 0xffffffff;
-                               data |= (uint64_t)lapic->icr_hi << 32;
-                       }
-                       retval = lapic_process_icr(vlapic, data, retu);
+                       lapic->icr_lo = data;
+                       if (x2apic(vlapic))
+                               lapic->icr_hi = data >> 32;
+                       retval = vlapic_icrlo_write_handler(vlapic, retu);
                        break;
                case APIC_OFFSET_ICR_HI:
-                       if (!x2apic(vlapic)) {
-                               retval = 0;
-                               lapic->icr_hi = data;
-                       }
+                       lapic->icr_hi = data;
                        break;
                case APIC_OFFSET_CMCI_LVT:
                case APIC_OFFSET_TIMER_LVT ... APIC_OFFSET_ERROR_LVT:
                        vlapic_set_lvt(vlapic, offset, data);
                        break;
                case APIC_OFFSET_TIMER_ICR:
-                       vlapic_set_icr_timer(vlapic, data);
+                       lapic->icr_timer = data;
+                       vlapic_icrtmr_write_handler(vlapic);
                        break;
 
                case APIC_OFFSET_TIMER_DCR:
-                       vlapic_set_dcr(vlapic, data);
+                       lapic->dcr_timer = data;
+                       vlapic_dcr_write_handler(vlapic);
                        break;
 
                case APIC_OFFSET_ESR:
-                       vlapic_update_errors(vlapic);
+                       vlapic_esr_write_handler(vlapic);
                        break;
                case APIC_OFFSET_VER:
                case APIC_OFFSET_APR:

Modified: head/sys/amd64/vmm/io/vlapic.h
==============================================================================
--- head/sys/amd64/vmm/io/vlapic.h      Fri Dec 27 19:53:42 2013        
(r259960)
+++ head/sys/amd64/vmm/io/vlapic.h      Fri Dec 27 20:18:19 2013        
(r259961)
@@ -76,4 +76,8 @@ void vlapic_id_write_handler(struct vlap
 void vlapic_ldr_write_handler(struct vlapic *vlapic);
 void vlapic_dfr_write_handler(struct vlapic *vlapic);
 void vlapic_svr_write_handler(struct vlapic *vlapic);
+void vlapic_esr_write_handler(struct vlapic *vlapic);
+int vlapic_icrlo_write_handler(struct vlapic *vlapic, bool *retu);
+void vlapic_icrtmr_write_handler(struct vlapic *vlapic);
+void vlapic_dcr_write_handler(struct vlapic *vlapic);
 #endif /* _VLAPIC_H_ */
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to