summaryrefslogtreecommitdiffstats
path: root/sys/amd64/vmm/io/vlapic.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/amd64/vmm/io/vlapic.c')
-rw-r--r--sys/amd64/vmm/io/vlapic.c140
1 files changed, 103 insertions, 37 deletions
diff --git a/sys/amd64/vmm/io/vlapic.c b/sys/amd64/vmm/io/vlapic.c
index 2395247..6e8c433 100644
--- a/sys/amd64/vmm/io/vlapic.c
+++ b/sys/amd64/vmm/io/vlapic.c
@@ -289,9 +289,11 @@ vlapic_set_intr_ready(struct vlapic *vlapic, int vector, bool level)
* the vlapic TMR registers.
*/
tmrptr = &lapic->tmr0;
- KASSERT((tmrptr[idx] & mask) == (level ? mask : 0),
- ("vlapic TMR[%d] is 0x%08x but interrupt is %s-triggered",
- idx / 4, tmrptr[idx], level ? "level" : "edge"));
+ if ((tmrptr[idx] & mask) != (level ? mask : 0)) {
+ VLAPIC_CTR3(vlapic, "vlapic TMR[%d] is 0x%08x but "
+ "interrupt is %s-triggered", idx / 4, tmrptr[idx],
+ level ? "level" : "edge");
+ }
VLAPIC_CTR_IRR(vlapic, "vlapic_set_intr_ready");
return (1);
@@ -997,6 +999,20 @@ vlapic_icrlo_write_handler(struct vlapic *vlapic, bool *retu)
return (1);
}
+void
+vlapic_self_ipi_handler(struct vlapic *vlapic, uint64_t val)
+{
+ int vec;
+
+ KASSERT(x2apic(vlapic), ("SELF_IPI does not exist in xAPIC mode"));
+
+ vec = val & 0xff;
+ lapic_intr_edge(vlapic->vm, vlapic->vcpuid, vec);
+ vmm_stat_array_incr(vlapic->vm, vlapic->vcpuid, IPIS_SENT,
+ vlapic->vcpuid, 1);
+ VLAPIC_CTR1(vlapic, "vlapic self-ipi %d", vec);
+}
+
int
vlapic_pending_intr(struct vlapic *vlapic, int *vecptr)
{
@@ -1105,12 +1121,31 @@ vlapic_svr_write_handler(struct vlapic *vlapic)
}
int
-vlapic_read(struct vlapic *vlapic, uint64_t offset, uint64_t *data, bool *retu)
+vlapic_read(struct vlapic *vlapic, int mmio_access, uint64_t offset,
+ uint64_t *data, bool *retu)
{
struct LAPIC *lapic = vlapic->apic_page;
uint32_t *reg;
int i;
+ /* Ignore MMIO accesses in x2APIC mode */
+ if (x2apic(vlapic) && mmio_access) {
+ VLAPIC_CTR1(vlapic, "MMIO read from offset %#lx in x2APIC mode",
+ offset);
+ *data = 0;
+ goto done;
+ }
+
+ if (!x2apic(vlapic) && !mmio_access) {
+ /*
+ * XXX Generate GP fault for MSR accesses in xAPIC mode
+ */
+ VLAPIC_CTR1(vlapic, "x2APIC MSR read from offset %#lx in "
+ "xAPIC mode", offset);
+ *data = 0;
+ goto done;
+ }
+
if (offset > sizeof(*lapic)) {
*data = 0;
goto done;
@@ -1190,6 +1225,12 @@ vlapic_read(struct vlapic *vlapic, uint64_t offset, uint64_t *data, bool *retu)
case APIC_OFFSET_TIMER_DCR:
*data = lapic->dcr_timer;
break;
+ case APIC_OFFSET_SELF_IPI:
+ /*
+ * XXX generate a GP fault if vlapic is in x2apic mode
+ */
+ *data = 0;
+ break;
case APIC_OFFSET_RRR:
default:
*data = 0;
@@ -1201,7 +1242,8 @@ done:
}
int
-vlapic_write(struct vlapic *vlapic, uint64_t offset, uint64_t data, bool *retu)
+vlapic_write(struct vlapic *vlapic, int mmio_access, uint64_t offset,
+ uint64_t data, bool *retu)
{
struct LAPIC *lapic = vlapic->apic_page;
uint32_t *regptr;
@@ -1210,10 +1252,26 @@ vlapic_write(struct vlapic *vlapic, uint64_t offset, uint64_t data, bool *retu)
KASSERT((offset & 0xf) == 0 && offset < PAGE_SIZE,
("vlapic_write: invalid offset %#lx", offset));
- VLAPIC_CTR2(vlapic, "vlapic write offset %#x, data %#lx", offset, data);
+ VLAPIC_CTR2(vlapic, "vlapic write offset %#lx, data %#lx",
+ offset, data);
- if (offset > sizeof(*lapic)) {
- return 0;
+ if (offset > sizeof(*lapic))
+ return (0);
+
+ /* Ignore MMIO accesses in x2APIC mode */
+ if (x2apic(vlapic) && mmio_access) {
+ VLAPIC_CTR2(vlapic, "MMIO write of %#lx to offset %#lx "
+ "in x2APIC mode", data, offset);
+ return (0);
+ }
+
+ /*
+ * XXX Generate GP fault for MSR accesses in xAPIC mode
+ */
+ if (!x2apic(vlapic) && !mmio_access) {
+ VLAPIC_CTR2(vlapic, "x2APIC MSR write of %#lx to offset %#lx "
+ "in xAPIC mode", data, offset);
+ return (0);
}
retval = 0;
@@ -1270,6 +1328,12 @@ vlapic_write(struct vlapic *vlapic, uint64_t offset, uint64_t data, bool *retu)
case APIC_OFFSET_ESR:
vlapic_esr_write_handler(vlapic);
break;
+
+ case APIC_OFFSET_SELF_IPI:
+ if (x2apic(vlapic))
+ vlapic_self_ipi_handler(vlapic, data);
+ break;
+
case APIC_OFFSET_VER:
case APIC_OFFSET_APR:
case APIC_OFFSET_PPR:
@@ -1354,50 +1418,52 @@ vlapic_get_apicbase(struct vlapic *vlapic)
return (vlapic->msr_apicbase);
}
-void
+int
vlapic_set_apicbase(struct vlapic *vlapic, uint64_t new)
{
- struct LAPIC *lapic;
- enum x2apic_state state;
- uint64_t old;
- int err;
-
- err = vm_get_x2apic_state(vlapic->vm, vlapic->vcpuid, &state);
- if (err)
- panic("vlapic_set_apicbase: err %d fetching x2apic state", err);
-
- if (state == X2APIC_DISABLED)
- new &= ~APICBASE_X2APIC;
-
- old = vlapic->msr_apicbase;
- vlapic->msr_apicbase = new;
- /*
- * If the vlapic is switching between xAPIC and x2APIC modes then
- * reset the mode-dependent registers.
- */
- if ((old ^ new) & APICBASE_X2APIC) {
- lapic = vlapic->apic_page;
- lapic->id = vlapic_get_id(vlapic);
- if (x2apic(vlapic)) {
- lapic->ldr = x2apic_ldr(vlapic);
- lapic->dfr = 0;
- } else {
- lapic->ldr = 0;
- lapic->dfr = 0xffffffff;
- }
+ if (vlapic->msr_apicbase != new) {
+ VLAPIC_CTR2(vlapic, "Changing APIC_BASE MSR from %#lx to %#lx "
+ "not supported", vlapic->msr_apicbase, new);
+ return (-1);
}
+
+ return (0);
}
void
vlapic_set_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state state)
{
struct vlapic *vlapic;
+ struct LAPIC *lapic;
vlapic = vm_lapic(vm, vcpuid);
if (state == X2APIC_DISABLED)
vlapic->msr_apicbase &= ~APICBASE_X2APIC;
+ else
+ vlapic->msr_apicbase |= APICBASE_X2APIC;
+
+ /*
+ * Reset the local APIC registers whose values are mode-dependent.
+ *
+ * XXX this works because the APIC mode can be changed only at vcpu
+ * initialization time.
+ */
+ lapic = vlapic->apic_page;
+ lapic->id = vlapic_get_id(vlapic);
+ if (x2apic(vlapic)) {
+ lapic->ldr = x2apic_ldr(vlapic);
+ lapic->dfr = 0;
+ } else {
+ lapic->ldr = 0;
+ lapic->dfr = 0xffffffff;
+ }
+
+ if (state == X2APIC_ENABLED) {
+ if (vlapic->ops.enable_x2apic_mode)
+ (*vlapic->ops.enable_x2apic_mode)(vlapic);
+ }
}
void
OpenPOWER on IntegriCloud