[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

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.