|
[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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |