diff options
author | Peter Xu <peterx@redhat.com> | 2019-03-29 14:14:21 +0800 |
---|---|---|
committer | Michael S. Tsirkin <mst@redhat.com> | 2019-04-02 11:49:14 -0400 |
commit | 2811af3b497b2bfadf38cda0fc92a709f83e8a7e (patch) | |
tree | 685b0c5fc0fa2777f3831c2cb5eb571051f72ff7 /hw/i386 | |
parent | 20f86a75a75efe7d2743d2f746d2933d01d582f1 (diff) |
intel_iommu: Fix root_scalable migration breakage
When introducing the initial support for scalable mode we added a
new field into vmstate however we blindly migrate that field without
notice. That'll break migration no matter forward or backward.
The normal way should be that we use something like
VMSTATE_UINT32_TEST() or subsections for the new vmstate field however
for this case of vt-d we can even make it simpler because we've
already migrated all the registers and it'll be fairly simple that we
re-generate root_scalable field from the register values during post
load of the device.
Fixes: fb43cf739e ("intel_iommu: scalable mode emulation")
Reviewed-by: Yi Sun <yi.y.sun@linux.intel.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
Message-Id: <20190329061422.7926-2-peterx@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'hw/i386')
-rw-r--r-- | hw/i386/intel_iommu.c | 24 |
1 files changed, 20 insertions, 4 deletions
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 146cd16dd2..9318854c51 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -162,6 +162,15 @@ static inline void vtd_iommu_unlock(IntelIOMMUState *s) qemu_mutex_unlock(&s->iommu_lock); } +static void vtd_update_scalable_state(IntelIOMMUState *s) +{ + uint64_t val = vtd_get_quad_raw(s, DMAR_RTADDR_REG); + + if (s->scalable_mode) { + s->root_scalable = val & VTD_RTADDR_SMT; + } +} + /* Whether the address space needs to notify new mappings */ static inline gboolean vtd_as_has_map_notifier(VTDAddressSpace *as) { @@ -1710,11 +1719,10 @@ static void vtd_root_table_setup(IntelIOMMUState *s) { s->root = vtd_get_quad_raw(s, DMAR_RTADDR_REG); s->root_extended = s->root & VTD_RTADDR_RTT; - if (s->scalable_mode) { - s->root_scalable = s->root & VTD_RTADDR_SMT; - } s->root &= VTD_RTADDR_ADDR_MASK(s->aw_bits); + vtd_update_scalable_state(s); + trace_vtd_reg_dmar_root(s->root, s->root_extended); } @@ -2945,6 +2953,15 @@ static int vtd_post_load(void *opaque, int version_id) */ vtd_switch_address_space_all(iommu); + /* + * We don't need to migrate the root_scalable because we can + * simply do the calculation after the loading is complete. We + * can actually do similar things with root, dmar_enabled, etc. + * however since we've had them already so we'd better keep them + * for compatibility of migration. + */ + vtd_update_scalable_state(iommu); + return 0; } @@ -2966,7 +2983,6 @@ static const VMStateDescription vtd_vmstate = { VMSTATE_UINT8_ARRAY(csr, IntelIOMMUState, DMAR_REG_SIZE), VMSTATE_UINT8(iq_last_desc_type, IntelIOMMUState), VMSTATE_BOOL(root_extended, IntelIOMMUState), - VMSTATE_BOOL(root_scalable, IntelIOMMUState), VMSTATE_BOOL(dmar_enabled, IntelIOMMUState), VMSTATE_BOOL(qi_enabled, IntelIOMMUState), VMSTATE_BOOL(intr_enabled, IntelIOMMUState), |