|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH V2 12/25] x86/vvtd: Add MMIO handler for VVTD
On Wed, Aug 09, 2017 at 04:34:13PM -0400, Lan Tianyu wrote:
> From: Chao Gao <chao.gao@xxxxxxxxx>
>
> This patch adds VVTD MMIO handler to deal with MMIO access.
>
> Signed-off-by: Chao Gao <chao.gao@xxxxxxxxx>
> Signed-off-by: Lan Tianyu <tianyu.lan@xxxxxxxxx>
> ---
> xen/drivers/passthrough/vtd/vvtd.c | 114
> +++++++++++++++++++++++++++++++++++++
> 1 file changed, 114 insertions(+)
>
> diff --git a/xen/drivers/passthrough/vtd/vvtd.c
> b/xen/drivers/passthrough/vtd/vvtd.c
> index 353fafe..94680e6 100644
> --- a/xen/drivers/passthrough/vtd/vvtd.c
> +++ b/xen/drivers/passthrough/vtd/vvtd.c
> @@ -50,6 +50,38 @@ struct vvtd {
> struct page_info *regs_page;
> };
>
> +#define __DEBUG_VVTD__
> +#ifdef __DEBUG_VVTD__
Why do you need this define? You can use NDEBUG which is the global
Xen debug define.
> +extern unsigned int vvtd_debug_level;
> +#define VVTD_DBG_INFO 1
> +#define VVTD_DBG_TRANS (1<<1)
> +#define VVTD_DBG_RW (1<<2)
> +#define VVTD_DBG_FAULT (1<<3)
> +#define VVTD_DBG_EOI (1<<4)
> +#define VVTD_DEBUG(lvl, _f, _a...) do { \
> + if ( vvtd_debug_level & lvl ) \
> + printk("VVTD %s:" _f "\n", __func__, ## _a); \
> +} while(0)
> +#else
> +#define VVTD_DEBUG(fmt...) do {} while(0)
> +#endif
> +
> +unsigned int vvtd_debug_level __read_mostly;
> +integer_param("vvtd_debug", vvtd_debug_level);
I think this should be a top level option for viommu, not a vtd
specific one, like it's done for iommu. I would prefer to have
something like:
viommu=verbose,[...]
So that we can add further options to it in the future, and that
should be shared between all the vIOMMU implementations.
> +
> +struct vvtd *domain_vvtd(struct domain *d)
> +{
> + struct viommu_info *info = &d->viommu;
> +
> + BUILD_BUG_ON(NR_VIOMMU_PER_DOMAIN != 1);
> + return (info && info->viommu[0]) ? info->viommu[0]->priv : NULL;
> +}
> +
> +static inline struct vvtd *vcpu_vvtd(struct vcpu *v)
> +{
> + return domain_vvtd(v->domain);
> +}
Do you really need the above helper? Seems quite trivial to directly
open code the call to domain_vvtd.
> +
> static inline void vvtd_set_reg(struct vvtd *vtd, uint32_t reg,
> uint32_t value)
> {
> @@ -76,6 +108,87 @@ static inline uint8_t vvtd_get_reg_byte(struct vvtd *vtd,
> uint32_t reg)
> vvtd_set_reg(vvtd, (reg) + 4, (val) >> 32); \
> } while(0)
>
> +static int vvtd_range(struct vcpu *v, unsigned long addr)
bool and maybe vvtd_in_range is more descriptive.
> +{
> + struct vvtd *vvtd = vcpu_vvtd(v);
> +
> + if ( vvtd )
> + return (addr >= vvtd->base_addr) &&
> + (addr < vvtd->base_addr + PAGE_SIZE);
So here you simply hardcode PAGE_SIZE, which makes me think that the
size parameter is indeed not needed.
> + return 0;
> +}
> +
> +static int vvtd_read(struct vcpu *v, unsigned long addr,
> + unsigned int len, unsigned long *pval)
> +{
> + struct vvtd *vvtd = vcpu_vvtd(v);
> + unsigned int offset = addr - vvtd->base_addr;
> + unsigned int offset_aligned = offset & ~3;
This is not needed IMHO.
> +
> + VVTD_DEBUG(VVTD_DBG_RW, "READ INFO: offset %x len %d.", offset, len);
> +
> + if ( !pval )
> + return X86EMUL_UNHANDLEABLE;
I don't think you can get a NULL pval here.
> +
> + if ( (offset & 3) || ((len != 4) && (len != 8)) )
Do you really intend to allow non-aligned 8 byte accesses? If so my
previous recommendation to use a union for the vvtd struct data field
is moot.
> + {
> + VVTD_DEBUG(VVTD_DBG_RW, "Alignment or length is not canonical");
> + return X86EMUL_UNHANDLEABLE;
IMHO you should not return X86EMUL_UNHANDLEABLE here. The read does
indeed belong to the vIOMMU region, so what does bare-metal hardware
do when a non-aligned or non size compliant read is performed?
> + }
> +
> + if ( len == 4 )
> + *pval = vvtd_get_reg(vvtd, offset_aligned);
You can just use offset here and below, the check that you do above
guarantees that offset & 3 == 0 (ie: at this point offset ==
offset_aligned).
> + else
> + vvtd_get_reg_quad(vvtd, offset_aligned, *pval);
Newline
> + return X86EMUL_OKAY;
> +}
> +
> +static int vvtd_write(struct vcpu *v, unsigned long addr,
> + unsigned int len, unsigned long val)
> +{
> + struct vvtd *vvtd = vcpu_vvtd(v);
> + unsigned int offset = addr - vvtd->base_addr;
> + unsigned int offset_aligned = offset & ~0x3;
> + int ret;
> +
> + VVTD_DEBUG(VVTD_DBG_RW, "WRITE INFO: offset %x len %d val %lx.",
> + offset, len, val);
> +
> + if ( (offset & 3) || ((len != 4) && (len != 8)) )
Same comment about alignment.
> + {
> + VVTD_DEBUG(VVTD_DBG_RW, "Alignment or length is not canonical");
> + return X86EMUL_UNHANDLEABLE;
> + }
> +
> + ret = X86EMUL_UNHANDLEABLE;
Same here, you should not return X86EMUL_UNHANDLEABLE but instead do
what the native hardware would do, which I guess is to just ignore the
write?
> + if ( len == 4 )
> + {
> + switch ( offset_aligned )
> + {
> + case DMAR_IEDATA_REG:
> + case DMAR_IEADDR_REG:
> + case DMAR_IEUADDR_REG:
> + case DMAR_FEDATA_REG:
> + case DMAR_FEADDR_REG:
> + case DMAR_FEUADDR_REG:
> + vvtd_set_reg(vvtd, offset_aligned, val);
> + ret = X86EMUL_OKAY;
> + break;
> +
> + default:
> + break;
> + }
> + }
> +
> + return ret;
> +}
> +
> +static const struct hvm_mmio_ops vvtd_mmio_ops = {
> + .check = vvtd_range,
> + .read = vvtd_read,
> + .write = vvtd_write
> +};
> +
> static void vvtd_reset(struct vvtd *vvtd, uint64_t capability)
> {
> uint64_t cap = DMA_CAP_NFR | DMA_CAP_SLLPS | DMA_CAP_FRO |
> @@ -122,6 +235,7 @@ static int vvtd_create(struct domain *d, struct viommu
> *viommu)
> vvtd->length = viommu->length;
> vvtd->domain = d;
> vvtd->status = VIOMMU_STATUS_DEFAULT;
> + register_mmio_handler(d, &vvtd_mmio_ops);
Newline.
Roger.
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |