[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v4 17/28] x86/vvtd: save and restore emulated VT-d
On Fri, Nov 17, 2017 at 02:22:24PM +0800, Chao Gao wrote: > Provide a save-restore pair to save/restore registers and non-register > status. > > Signed-off-by: Chao Gao <chao.gao@xxxxxxxxx> > Signed-off-by: Lan Tianyu <tianyu.lan@xxxxxxxxx> > --- > v3: > - use one entry to save both vvtd registers and other intermediate > state > --- > xen/drivers/passthrough/vtd/vvtd.c | 57 > +++++++++++++++++++++++----------- > xen/include/public/arch-x86/hvm/save.h | 18 ++++++++++- > 2 files changed, 56 insertions(+), 19 deletions(-) > > diff --git a/xen/drivers/passthrough/vtd/vvtd.c > b/xen/drivers/passthrough/vtd/vvtd.c > index 81170ec..f6bde69 100644 > --- a/xen/drivers/passthrough/vtd/vvtd.c > +++ b/xen/drivers/passthrough/vtd/vvtd.c > @@ -27,8 +27,10 @@ > #include <asm/event.h> > #include <asm/io_apic.h> > #include <asm/hvm/domain.h> > +#include <asm/hvm/save.h> > #include <asm/hvm/support.h> > #include <asm/p2m.h> > +#include <public/hvm/save.h> > > #include "iommu.h" > #include "vtd.h" > @@ -38,20 +40,6 @@ > > #define VVTD_FRCD_NUM 1ULL > #define VVTD_FRCD_START (DMAR_IRTA_REG + 8) > -#define VVTD_FRCD_END (VVTD_FRCD_START + VVTD_FRCD_NUM * 16) > -#define VVTD_MAX_OFFSET VVTD_FRCD_END > - > -struct hvm_hw_vvtd { > - bool eim_enabled; > - bool intremap_enabled; > - uint32_t fault_index; > - > - /* Interrupt remapping table base gfn and the max of entries */ > - uint16_t irt_max_entry; > - gfn_t irt; You are changing gfn_t to uint64_t, is gfn_t not working with the migration stream? Also I think this duplication of fields (having all registers in 'regs' and some cached in miscellaneous top level fields is not a good approach. > - > - uint32_t regs[VVTD_MAX_OFFSET/sizeof(uint32_t)]; > -}; > > struct vvtd { > /* Base address of remapping hardware register-set */ > @@ -776,7 +764,7 @@ static void write_gcmd_sirtp(struct vvtd *vvtd, uint32_t > val) > if ( vvtd->hw.intremap_enabled ) > vvtd_info("Update Interrupt Remapping Table when active\n"); > > - if ( gfn_x(vvtd->hw.irt) != PFN_DOWN(DMA_IRTA_ADDR(irta)) || > + if ( vvtd->hw.irt != PFN_DOWN(DMA_IRTA_ADDR(irta)) || > vvtd->hw.irt_max_entry != DMA_IRTA_SIZE(irta) ) > { > if ( vvtd->irt_base ) > @@ -786,14 +774,14 @@ static void write_gcmd_sirtp(struct vvtd *vvtd, > uint32_t val) > sizeof(struct iremap_entry))); > vvtd->irt_base = NULL; > } > - vvtd->hw.irt = _gfn(PFN_DOWN(DMA_IRTA_ADDR(irta))); > + vvtd->hw.irt = PFN_DOWN(DMA_IRTA_ADDR(irta)); > vvtd->hw.irt_max_entry = DMA_IRTA_SIZE(irta); > vvtd->hw.eim_enabled = !!(irta & IRTA_EIME); > vvtd_info("Update IR info (addr=%lx eim=%d size=%d)\n", > - gfn_x(vvtd->hw.irt), vvtd->hw.eim_enabled, > + vvtd->hw.irt, vvtd->hw.eim_enabled, > vvtd->hw.irt_max_entry); > > - vvtd->irt_base = map_guest_pages(vvtd->domain, gfn_x(vvtd->hw.irt), > + vvtd->irt_base = map_guest_pages(vvtd->domain, vvtd->hw.irt, > PFN_UP(vvtd->hw.irt_max_entry * > sizeof(struct > iremap_entry))); > } > @@ -1138,6 +1126,39 @@ static bool vvtd_is_remapping(const struct domain *d, > return !irq_remapping_request_index(irq, &idx); > } > > +static int vvtd_load(struct domain *d, hvm_domain_context_t *h) > +{ > + struct vvtd *vvtd = domain_vvtd(d); > + uint64_t iqa; > + > + if ( !vvtd ) > + return -ENODEV; > + > + if ( hvm_load_entry(VVTD, h, &vvtd->hw) ) > + return -EINVAL; > + > + iqa = vvtd_get_reg_quad(vvtd, DMAR_IQA_REG); > + vvtd->irt_base = map_guest_pages(vvtd->domain, vvtd->hw.irt, > + PFN_UP(vvtd->hw.irt_max_entry * > + sizeof(struct iremap_entry))); > + vvtd->inv_queue_base = map_guest_pages(vvtd->domain, > + PFN_DOWN(DMA_IQA_ADDR(iqa)), > + 1 << DMA_IQA_QS(iqa)); Why are you unconditionally mapping those pages? Shouldn't you check that the relevant features are enabled? Both could be 0 or simply point to garbage. > + return 0; > +} > + > +static int vvtd_save(struct domain *d, hvm_domain_context_t *h) > +{ > + struct vvtd *vvtd = domain_vvtd(d); > + > + if ( !vvtd ) > + return 0; > + > + return hvm_save_entry(VVTD, 0, h, &vvtd->hw); > +} > + > +HVM_REGISTER_SAVE_RESTORE(VVTD, vvtd_save, vvtd_load, 1, HVMSR_PER_DOM); > + > static void vvtd_reset(struct vvtd *vvtd) > { > uint64_t cap = cap_set_num_fault_regs(VVTD_FRCD_NUM) > diff --git a/xen/include/public/arch-x86/hvm/save.h > b/xen/include/public/arch-x86/hvm/save.h > index fd7bf3f..24a513b 100644 > --- a/xen/include/public/arch-x86/hvm/save.h > +++ b/xen/include/public/arch-x86/hvm/save.h > @@ -639,10 +639,26 @@ struct hvm_msr { > > #define CPU_MSR_CODE 20 > > +#define VVTD_MAX_OFFSET 0xd0 You used to have some kind of formula to calculate VVTD_MAX_OFFSET, yet here the value is just hardcoded. Any reason for this? > +struct hvm_hw_vvtd > +{ > + uint32_t eim_enabled : 1, > + intremap_enabled : 1; > + uint32_t fault_index; > + > + /* Interrupt remapping table base gfn and the max of entries */ > + uint32_t irt_max_entry; > + uint64_t irt; > + > + uint32_t regs[VVTD_MAX_OFFSET/sizeof(uint32_t)]; > +}; > + > +DECLARE_HVM_SAVE_TYPE(VVTD, 21, struct hvm_hw_vvtd); Adding new fields to this struct in a migration compatible way is going to be a PITA, but there's no easy solution to this I'm afraid... Thanks, Roger. _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |