[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH v3 07/10] ioreq: allow decoding accesses to MMCFG regions



On 30.09.2019 15:32, Roger Pau Monne wrote:
> --- a/xen/arch/x86/hvm/io.c
> +++ b/xen/arch/x86/hvm/io.c
> @@ -279,6 +279,18 @@ unsigned int hvm_pci_decode_addr(unsigned int cf8, 
> unsigned int addr,
>      return CF8_ADDR_LO(cf8) | (addr & 3);
>  }
>  
> +unsigned int hvm_mmcfg_decode_addr(const struct hvm_mmcfg *mmcfg,
> +                                   paddr_t addr, pci_sbdf_t *sbdf)
> +{
> +    addr -= mmcfg->addr;

As the function isn't even static, wouldn't it be helpful to at least
assert that addr >= mmcfg->addr ahead of this, and addr < mmcfg->size
afterwards?

> @@ -574,6 +550,17 @@ void destroy_vpci_mmcfg(struct domain *d)
>      write_unlock(&d->arch.hvm.mmcfg_lock);
>  }
>  
> +const struct hvm_mmcfg *hvm_mmcfg_find(const struct domain *d, paddr_t addr)
> +{
> +    const struct hvm_mmcfg *mmcfg;
> +
> +    list_for_each_entry ( mmcfg, &d->arch.hvm.mmcfg_regions, next )
> +        if ( addr >= mmcfg->addr && addr < mmcfg->addr + mmcfg->size )

As a minor remark, this could be coded without even a theoretical risk
of overflow as

        if ( addr >= mmcfg->addr && addr - mmcfg->addr < mmcfg->size )

> --- a/xen/arch/x86/hvm/ioreq.c
> +++ b/xen/arch/x86/hvm/ioreq.c
> @@ -1326,27 +1326,34 @@ ioservid_t hvm_select_ioreq_server(struct domain *d, 
> ioreq_t *p)
>      uint8_t type;
>      uint64_t addr;
>      unsigned int id;
> +    const struct hvm_mmcfg *mmcfg;
>  
>      if ( p->type != IOREQ_TYPE_COPY && p->type != IOREQ_TYPE_PIO )
>          return XEN_INVALID_IOSERVID;
>  
>      cf8 = d->arch.hvm.pci_cf8;
>  
> -    if ( p->type == IOREQ_TYPE_PIO &&
> -         (p->addr & ~3) == 0xcfc &&
> -         CF8_ENABLED(cf8) )
> +    read_lock(&d->arch.hvm.mmcfg_lock);
> +    if ( (p->type == IOREQ_TYPE_PIO &&
> +          (p->addr & ~3) == 0xcfc &&
> +          CF8_ENABLED(cf8)) ||
> +         (p->type == IOREQ_TYPE_COPY &&
> +          (mmcfg = hvm_mmcfg_find(d, p->addr)) != NULL) )
>      {
>          uint32_t x86_fam;
>          pci_sbdf_t sbdf;
>          unsigned int reg;
>  
> -        reg = hvm_pci_decode_addr(cf8, p->addr, &sbdf);
> +        reg = p->type == IOREQ_TYPE_PIO ? hvm_pci_decode_addr(cf8, p->addr,
> +                                                              &sbdf)
> +                                        : hvm_mmcfg_decode_addr(mmcfg, 
> p->addr,
> +                                                                &sbdf);

I'm afraid old gcc will consider this use of mmcfg "potentially
uninitialized". I.e. I think the variable wants to gain a NULL
initializer, at which point you can slightly shorten the above
to

        reg = mmcfg ? hvm_mmcfg_decode_addr(mmcfg, p->addr, &sbdf)
                    : hvm_pci_decode_addr(cf8, p->addr, &sbdf);


also eliminating a pointer deref (i.e. likely producing minimally
more efficient code).

>          /* PCI config data cycle */
>          type = XEN_DMOP_IO_RANGE_PCI;
>          addr = ((uint64_t)sbdf.sbdf << 32) | reg;
>          /* AMD extended configuration space access? */
> -        if ( CF8_ADDR_HI(cf8) &&
> +        if ( p->type == IOREQ_TYPE_PIO && CF8_ADDR_HI(cf8) &&

Would be "!mmcfg && ..." then here.

> --- a/xen/include/asm-x86/hvm/io.h
> +++ b/xen/include/asm-x86/hvm/io.h
> @@ -165,9 +165,19 @@ void stdvga_deinit(struct domain *d);
>  
>  extern void hvm_dpci_msi_eoi(struct domain *d, int vector);
>  
> -/* Decode a PCI port IO access into a bus/slot/func/reg. */
> +struct hvm_mmcfg {
> +    struct list_head next;
> +    paddr_t addr;
> +    unsigned int size;
> +    uint16_t segment;
> +    uint8_t start_bus;
> +};
> +
> +/* Decode a PCI port IO or MMCFG access into a bus/slot/func/reg. */
>  unsigned int hvm_pci_decode_addr(unsigned int cf8, unsigned int addr,
>                                   pci_sbdf_t *sbdf);
> +unsigned int hvm_mmcfg_decode_addr(const struct hvm_mmcfg *mmcfg,
> +                                   paddr_t addr, pci_sbdf_t *sbdf);

The latest now the comment also wants to include "seg/", I think.

> @@ -178,15 +188,18 @@ void register_g2m_portio_handler(struct domain *d);
>  /* HVM port IO handler for vPCI accesses. */
>  void register_vpci_portio_handler(struct domain *d);
>  
> -/* HVM MMIO handler for PCI MMCFG accesses. */
> -int register_vpci_mmcfg_handler(struct domain *d, paddr_t addr,
> -                                unsigned int start_bus, unsigned int end_bus,
> -                                unsigned int seg);
> -/* Destroy tracked MMCFG areas. */
> -void destroy_vpci_mmcfg(struct domain *d);
> +/* HVM PCI MMCFG regions registration. */
> +int hvm_register_mmcfg(struct domain *d, paddr_t addr,
> +                       unsigned int start_bus, unsigned int end_bus,
> +                       unsigned int seg);

As - from a hierarchy perspective - the segment is more significant, can
you put it ahead of the start/end bus numbers please?

> +void hvm_free_mmcfg(struct domain *d);
> +const struct hvm_mmcfg *hvm_mmcfg_find(const struct domain *d, paddr_t addr);
>  
>  /* Check if an address is between a MMCFG region for a domain. */
> -bool vpci_is_mmcfg_address(const struct domain *d, paddr_t addr);
> +static inline bool hvm_is_mmcfg_address(const struct domain *d, paddr_t addr)
> +{
> +    return hvm_mmcfg_find(d, addr);
> +}

Hmm, yet another instance where the size of an access doesn't matter
in such a predicate. Is it a good idea (or is there a fair reason)
to extend this bad practice? But yes, I do see that vpci_mmcfg_accept()
has no way to pass a size here, and that you you effectively only
move the code here.

Jan

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

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