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

Re: [PATCH v20 2/2] vpci: translate virtual PCI bus topology for guests


  • To: Roger Pau Monné <roger.pau@xxxxxxxxxx>
  • From: Stewart Hildebrand <stewart.hildebrand@xxxxxxx>
  • Date: Tue, 6 May 2025 23:05:13 -0400
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=citrix.com smtp.mailfrom=amd.com; dmarc=pass (p=quarantine sp=quarantine pct=100) action=none header.from=amd.com; dkim=none (message not signed); arc=none (0)
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=IwyhJFY4vesrDhBtFfHi8Dqt7X4llzuSAR5ElpLhNME=; b=EpXxGA5CVaO/4j4w0bk4SJ4HUi+iFsJ1VbSW1o9OIB+JDDBek9O9K3UhqTf1WazPRMr9zUhNnXtAsp9LVJYiB3TBvOaf6BuFDGQzJxjcuUFdB7i7GJLhslpt7Wv3pKWKbCHl13HbwQKjAHxtRrWkf1rYpgYcwtGeFybJ4DvpjmN0nrGk/iT64tvd2vV7sXg8UMkaPE7180EQqUWLQnEiq96L8k0Fzqdx2TNnR2Ppp+Ld/5kBkojxigkDYhM4RQXa3lw1CRj9zDANBNhGzYd/IlB8V8PloZG2ptS00MmG+fRLrsfaALxV6OCoclOLlyMxeGT6lcdd+g93YcCgk23pMg==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=o7i+HHccn0r67Kg83M1lWF16AKzB409EQR/gIV/1yBZZFTjl8uFz/s2P7cclKbAJN13PHAc8AB1N9UQjqMNYQxNnia83OHYGc1x/xz5Pvj2U1d/47wn6AMnRP2ymiTAJqnbdP3Woadxb3N3lGU+blVSlltiXYgdUYBd2+5ZHI54RQ5WlcNpCsDhkndsHRE/tuSS1oAhg8p45Di06qGZkv6sFAOR4lV9ZLD3FE4M9Hux4JpjE/ZJJN2Wq6SJDq4qOryW/x1NRe4v9zf7wyabyea7qHNR+YgnH48pth8RZ6qzBNUJtSfcPDjZPpQHPU44djOlVdXRfYYaHiKjCZmRmsA==
  • Cc: <xen-devel@xxxxxxxxxxxxxxxxxxxx>, Oleksandr Andrushchenko <oleksandr_andrushchenko@xxxxxxxx>, Anthony PERARD <anthony.perard@xxxxxxxxxx>, Stefano Stabellini <sstabellini@xxxxxxxxxx>, Julien Grall <julien@xxxxxxx>, Bertrand Marquis <bertrand.marquis@xxxxxxx>, Michal Orzel <michal.orzel@xxxxxxx>, Volodymyr Babchuk <Volodymyr_Babchuk@xxxxxxxx>, Jiqian Chen <Jiqian.Chen@xxxxxxx>, "Mykyta Poturai" <Mykyta_Poturai@xxxxxxxx>
  • Delivery-date: Wed, 07 May 2025 03:05:36 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

On 5/6/25 07:16, Roger Pau Monné wrote:
> Hello,
> 
> Sorry I haven't looked at this before, I was confused with the cover
> letter having ARM in the subject and somehow assumed all the code was
> ARM related.

No worries, thanks for taking a look.

> On Fri, Apr 18, 2025 at 02:58:37PM -0400, Stewart Hildebrand wrote:
>> From: Oleksandr Andrushchenko <oleksandr_andrushchenko@xxxxxxxx>
>>
>> There are two originators for the PCI configuration space access:
>> 1. The domain that owns physical host bridge: MMIO handlers are
>> there so we can update vPCI register handlers with the values
>> written by the hardware domain, e.g. physical view of the registers
>> vs guest's view on the configuration space.
>> 2. Guest access to the passed through PCI devices: we need to properly
>> map virtual bus topology to the physical one, e.g. pass the configuration
>> space access to the corresponding physical devices.
>>
>> In vpci_read(), use the access size to create a mask so as to not set
>> any bits above the access size when returning an error.
> 
> I see this here, and the code below, yet I'm not following why this is
> a requirement for the code added here.  It seems like an unrelated
> change?

See below

>> Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@xxxxxxxx>
>> Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@xxxxxxxx>
>> Signed-off-by: Stewart Hildebrand <stewart.hildebrand@xxxxxxx>
>> ---
>> In v20:
>> * call translate_virtual_device() from within locked context of
>>   vpci_{read,write}
>> * update commit message
>> In v19:
>> * move locking to pre-patch
>> In v18:
>> * address warning in vpci test suite
>> In v17:
>> * move lock to inside vpci_translate_virtual_device()
>> * acks were previously given for Arm [0] and vPCI [1], but since it was
>>   two releases ago and the patch has changed, I didn't pick them up
>>
>> [0] 
>> https://lore.kernel.org/xen-devel/4afe33f2-72e6-4755-98ce-d7f9da374e90@xxxxxxx/
>> [1] https://lore.kernel.org/xen-devel/Zk70udmiriruMt0r@macbook/
>>
>> In v15:
>> - base on top of ("arm/vpci: honor access size when returning an error")
>> In v11:
>> - Fixed format issues
>> - Added ASSERT_UNREACHABLE() to the dummy implementation of
>> vpci_translate_virtual_device()
>> - Moved variable in vpci_sbdf_from_gpa(), now it is easier to follow
>> the logic in the function
>> Since v9:
>> - Commend about required lock replaced with ASSERT()
>> - Style fixes
>> - call to vpci_translate_virtual_device folded into vpci_sbdf_from_gpa
>> Since v8:
>> - locks moved out of vpci_translate_virtual_device()
>> Since v6:
>> - add pcidevs locking to vpci_translate_virtual_device
>> - update wrt to the new locking scheme
>> Since v5:
>> - add vpci_translate_virtual_device for #ifndef CONFIG_HAS_VPCI_GUEST_SUPPORT
>>   case to simplify ifdefery
>> - add ASSERT(!is_hardware_domain(d)); to vpci_translate_virtual_device
>> - reset output register on failed virtual SBDF translation
>> Since v4:
>> - indentation fixes
>> - constify struct domain
>> - updated commit message
>> - updates to the new locking scheme (pdev->vpci_lock)
>> Since v3:
>> - revisit locking
>> - move code to vpci.c
>> Since v2:
>>  - pass struct domain instead of struct vcpu
>>  - constify arguments where possible
>>  - gate relevant code with CONFIG_HAS_VPCI_GUEST_SUPPORT
>> New in v2
>> ---
>>  tools/tests/vpci/emul.h |  2 +-
>>  xen/arch/arm/vpci.c     |  4 +++
>>  xen/drivers/vpci/vpci.c | 73 +++++++++++++++++++++++++++++++++++++----
>>  3 files changed, 71 insertions(+), 8 deletions(-)
>>
>> diff --git a/tools/tests/vpci/emul.h b/tools/tests/vpci/emul.h
>> index da446bba86b4..dd048cffbf9d 100644
>> --- a/tools/tests/vpci/emul.h
>> +++ b/tools/tests/vpci/emul.h
>> @@ -89,7 +89,7 @@ typedef union {
>>  
>>  #define __hwdom_init
>>  
>> -#define is_hardware_domain(d) ((void)(d), false)
>> +#define is_hardware_domain(d) ((void)(d), true)
>>  
>>  #define has_vpci(d) true
>>  
>> diff --git a/xen/arch/arm/vpci.c b/xen/arch/arm/vpci.c
>> index b63a356bb4a8..618ddb7f6547 100644
>> --- a/xen/arch/arm/vpci.c
>> +++ b/xen/arch/arm/vpci.c
>> @@ -34,6 +34,8 @@ static int vpci_mmio_read(struct vcpu *v, mmio_info_t 
>> *info,
>>      /* data is needed to prevent a pointer cast on 32bit */
>>      unsigned long data;
>>  
>> +    ASSERT(!bridge == !is_hardware_domain(v->domain));
>> +
>>      if ( vpci_ecam_read(sbdf, ECAM_REG_OFFSET(info->gpa),
>>                          1U << info->dabt.size, &data) )
>>      {
>> @@ -52,6 +54,8 @@ static int vpci_mmio_write(struct vcpu *v, mmio_info_t 
>> *info,
>>      struct pci_host_bridge *bridge = p;
>>      pci_sbdf_t sbdf = vpci_sbdf_from_gpa(bridge, info->gpa);
>>  
>> +    ASSERT(!bridge == !is_hardware_domain(v->domain));
>> +
>>      return vpci_ecam_write(sbdf, ECAM_REG_OFFSET(info->gpa),
>>                             1U << info->dabt.size, r);
>>  }
>> diff --git a/xen/drivers/vpci/vpci.c b/xen/drivers/vpci/vpci.c
>> index 1e6aa5d799b9..fc409f3fc346 100644
>> --- a/xen/drivers/vpci/vpci.c
>> +++ b/xen/drivers/vpci/vpci.c
>> @@ -174,6 +174,41 @@ int vpci_assign_device(struct pci_dev *pdev)
>>  }
>>  #endif /* __XEN__ */
>>  
>> +#ifdef CONFIG_HAS_VPCI_GUEST_SUPPORT
>> +/*
>> + * Find the physical device which is mapped to the virtual device
>> + * and translate virtual SBDF to the physical one.
>> + */
>> +static const struct pci_dev *translate_virtual_device(const struct domain 
>> *d,
>> +                                                      pci_sbdf_t *sbdf)
>> +{
>> +    const struct pci_dev *pdev;
>> +
>> +    ASSERT(!is_hardware_domain(d));
>> +    ASSERT(rw_is_locked(&d->pci_lock));
>> +
>> +    for_each_pdev ( d, pdev )
>> +    {
>> +        if ( pdev->vpci && (pdev->vpci->guest_sbdf.sbdf == sbdf->sbdf) )
>> +        {
>> +            /* Replace guest SBDF with the physical one. */
>> +            *sbdf = pdev->sbdf;
>> +            return pdev;
>> +        }
>> +    }
>> +
>> +    return NULL;
>> +}
>> +#else
>> +static const struct pci_dev *translate_virtual_device(const struct domain 
>> *d,
>> +                                                      pci_sbdf_t *sbdf)
>> +{
>> +    ASSERT_UNREACHABLE();
>> +
>> +    return NULL;
>> +}
>> +#endif /* CONFIG_HAS_VPCI_GUEST_SUPPORT */
> 
> Jan's suggestion avoids having duplicate headers, and results in less
> code overall:
> 
> static const struct pci_dev *translate_virtual_device(const struct domain *d,
>                                                       pci_sbdf_t *sbdf)
> {
> #ifdef CONFIG_HAS_VPCI_GUEST_SUPPORT
>     const struct pci_dev *pdev;
>     ...
> #else /* !CONFIG_HAS_VPCI_GUEST_SUPPORT */
>     ASSERT_UNREACHABLE()
> #endif /* CONFIG_HAS_VPCI_GUEST_SUPPORT */
> 
>     return NULL;
> }
> 
> I've not overly fuzzed either way, but if changes are required you
> might as well change to this form.

Will do

>>  static int vpci_register_cmp(const struct vpci_register *r1,
>>                               const struct vpci_register *r2)
>>  {
>> @@ -438,7 +473,7 @@ uint32_t vpci_read(pci_sbdf_t sbdf, unsigned int reg, 
>> unsigned int size)
>>      const struct pci_dev *pdev;
>>      const struct vpci_register *r;
>>      unsigned int data_offset = 0;
>> -    uint32_t data = ~(uint32_t)0;
>> +    uint32_t data = 0xffffffffU >> (32 - 8 * size);
> 
> This seems kind of unrelated to the rest of the code in the patch,
> why is this needed?  Isn't it always fine to return all ones, and let
> the caller truncate to the required size?
> 
> Otherwise the code in vpci_read_hw() also needs to be adjusted.

On Arm, since 9a5e22b64266 ("xen/arm: check read handler behavior") we
assert that the read handlers don't set any bits above the access size.
I had adjusted data here due to returning it directly from vpci_read()
in the current form of the patch. With your suggestion below we would
only need to adjust vpci_read_hw() (and then data here would not
strictly need adjusting).

> And
> you can likely use GENMASK(size * 8, 0) as it's easier to read.

OK. I'll then also provide a definition for GENMASK in
tools/tests/vpci/emul.h.

>>  
>>      if ( !size )
>>      {
>> @@ -453,9 +488,21 @@ uint32_t vpci_read(pci_sbdf_t sbdf, unsigned int reg, 
>> unsigned int size)
>>       * pci_lock is sufficient.
>>       */
>>      read_lock(&d->pci_lock);
>> -    pdev = pci_get_pdev(d, sbdf);
>> -    if ( !pdev && is_hardware_domain(d) )
>> -        pdev = pci_get_pdev(dom_xen, sbdf);
>> +    if ( is_hardware_domain(d) )
>> +    {
>> +        pdev = pci_get_pdev(d, sbdf);
>> +        if ( !pdev )
>> +            pdev = pci_get_pdev(dom_xen, sbdf);
>> +    }
>> +    else
>> +    {
>> +        pdev = translate_virtual_device(d, &sbdf);
>> +        if ( !pdev )
>> +        {
>> +            read_unlock(&d->pci_lock);
>> +            return data;
>> +        }
> 
> You don't need this checking here, as the check below will already be
> enough AFAICT, iow:
> 
>     if ( is_hardware_domain(d) )
>     {
>         pdev = pci_get_pdev(d, sbdf);
>         if ( !pdev )
>             pdev = pci_get_pdev(dom_xen, sbdf);
>     }
>     else
>         pdev = translate_virtual_device(d, &sbdf);
> 
>     if ( !pdev || !pdev->vpci )
>     {
>         read_unlock(&d->pci_lock);
>         return vpci_read_hw(sbdf, reg, size);
>     }
> 
> Achieves the same and is more compact by having a single return for
> all the possible cases?  Same for the write case below.

Seeing as there is a is_hardware_domain check inside vpci_read_hw(),
that is okay. I'll make the adjustment here and in vpci_write.



 


Rackspace

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