svn commit: r259961 - head/sys/amd64/vmm/io
Neel Natu
neel at FreeBSD.org
Fri Dec 27 20:18:20 UTC 2013
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_ */
More information about the svn-src-head
mailing list