@@ -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
@@ -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);
}
@@ -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 */
+
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);
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;
+ }
+ }
if ( !pdev || !pdev->vpci )
{
read_unlock(&d->pci_lock);
@@ -571,9 +618,21 @@ void vpci_write(pci_sbdf_t sbdf, unsigned int reg, unsigned int size,
* are modifying BARs, so there is a room for improvement.
*/
write_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 )
+ {
+ write_unlock(&d->pci_lock);
+ return;
+ }
+ }
if ( !pdev || !pdev->vpci )
{
/* Ignore writes to read-only devices, which have no ->vpci. */