diff mbox series

vfio-pci: add Ascend devices passthrough quirks

Message ID 20201029114048.700-1-wubinfeng@huawei.com
State New
Headers show
Series vfio-pci: add Ascend devices passthrough quirks | expand

Commit Message

Binfeng Wu Oct. 29, 2020, 11:40 a.m. UTC
Ascend is a series of SoC processors developed by Huawei. Ascend310/910
are highly efficient, flexible, and programmable AI processors in this
series and support device passthrough via vfio-pci. Ascends device
xloader update is only allowed in host, because update triggered by vm
users may affect other users when Ascend devices passthrough to vm.
Set a bar quirk is an effective method to keep vm users from updating
xloader. In this patch, two bar quirks were proposed to cover
Ascend310/910 respectively.

Signed-off-by: Binfeng Wu <wubinfeng@huawei.com>
---
 hw/vfio/pci-quirks.c | 104 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 104 insertions(+)

Comments

Alex Williamson Oct. 30, 2020, 3:07 a.m. UTC | #1
On Thu, 29 Oct 2020 19:40:48 +0800
Binfeng Wu <wubinfeng@huawei.com> wrote:

> Ascend is a series of SoC processors developed by Huawei. Ascend310/910

> are highly efficient, flexible, and programmable AI processors in this

> series and support device passthrough via vfio-pci. Ascends device

> xloader update is only allowed in host, because update triggered by vm

> users may affect other users when Ascend devices passthrough to vm.

> Set a bar quirk is an effective method to keep vm users from updating

> xloader. In this patch, two bar quirks were proposed to cover

> Ascend310/910 respectively.



If you're trying to say that userspace, not just a VM, should not be
able to update this feature, then is QEMU the right place to implement
this quirk versus device specific protection within the host kernel?
Thanks,

Alex

> Signed-off-by: Binfeng Wu <wubinfeng@huawei.com>

> ---

>  hw/vfio/pci-quirks.c | 104 +++++++++++++++++++++++++++++++++++++++++++

>  1 file changed, 104 insertions(+)

> 

> diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c

> index 57150913b7..291a45d3ab 100644

> --- a/hw/vfio/pci-quirks.c

> +++ b/hw/vfio/pci-quirks.c

> @@ -1202,6 +1202,108 @@ int vfio_pci_igd_opregion_init(VFIOPCIDevice *vdev,

>      return 0;

>  }

>  

> +#define PCI_VENDOR_ID_HUAWEI      0x19e5

> +#define PCI_DEVICE_ID_ASCEND910   0xd801

> +#define PCI_DEVICE_ID_ASCEND310   0xd100

> +#define ASCEND910_XLOADER_SIZE    4

> +#define ASCEND910_XLOADER_OFFSET  0x80400

> +#define ASCEND310_XLOADER_SIZE    4

> +#define ASCEND310_XLOADER_OFFSET  0x400

> +

> +typedef struct VFIOAscendBarQuirk {

> +    struct VFIOPCIDevice *vdev;

> +    pcibus_t offset;

> +    uint8_t bar;

> +    MemoryRegion *mem;

> +} VFIOAscendBarQuirk;

> +

> +static uint64_t vfio_ascend_quirk_read(void *opaque,

> +                                       hwaddr addr, unsigned size)

> +{

> +    VFIOAscendBarQuirk *quirk = opaque;

> +    VFIOPCIDevice *vdev = quirk->vdev;

> +

> +    return vfio_region_read(&vdev->bars[quirk->bar].region,

> +                            addr + quirk->offset, size);

> +}

> +

> +static void vfio_ascend_quirk_write(void *opaque, hwaddr addr,

> +                                    uint64_t data, unsigned size)

> +{

> +}

> +

> +static const MemoryRegionOps vfio_ascend_intercept_regs_quirk = {

> +    .read = vfio_ascend_quirk_read,

> +    .write = vfio_ascend_quirk_write,

> +    .endianness = DEVICE_LITTLE_ENDIAN,

> +};

> +

> +static void vfio_probe_ascend_bar0_quirk(VFIOPCIDevice *vdev, int nr)

> +{

> +    VFIOQuirk *quirk;

> +    VFIOAscendBarQuirk *bar0_quirk;

> +

> +    if (!vfio_pci_is(vdev, PCI_VENDOR_ID_HUAWEI, PCI_DEVICE_ID_ASCEND910) ||

> +        nr != 0) {

> +        return;

> +    }

> +

> +    quirk = g_malloc0(sizeof(*quirk));

> +    quirk->nr_mem = 1;

> +    quirk->mem = g_new0(MemoryRegion, quirk->nr_mem);

> +    bar0_quirk = quirk->data = g_new0(typeof(*bar0_quirk), quirk->nr_mem);

> +    bar0_quirk[0].vdev = vdev;

> +    bar0_quirk[0].offset = ASCEND910_XLOADER_OFFSET;

> +    bar0_quirk[0].bar = nr;

> +

> +    /*

> +     * intercept w/r to the xloader-updating register,

> +     * so the vm can't enable xloader-updating

> +     */

> +    memory_region_init_io(&quirk->mem[0], OBJECT(vdev),

> +                          &vfio_ascend_intercept_regs_quirk,

> +                          &bar0_quirk[0],

> +                          "vfio-ascend-bar0-intercept-regs-quirk",

> +                          ASCEND910_XLOADER_SIZE);

> +    memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,

> +                                        bar0_quirk[0].offset,

> +                                        &quirk->mem[0], 1);

> +    QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);

> +}

> +

> +static void vfio_probe_ascend_bar4_quirk(VFIOPCIDevice *vdev, int nr)

> +{

> +    VFIOQuirk *quirk;

> +    VFIOAscendBarQuirk *bar4_quirk;

> +

> +    if (!vfio_pci_is(vdev, PCI_VENDOR_ID_HUAWEI, PCI_DEVICE_ID_ASCEND310) ||

> +        nr != 4) {

> +        return;

> +    }

> +

> +    quirk = g_malloc0(sizeof(*quirk));

> +    quirk->nr_mem = 1;

> +    quirk->mem = g_new0(MemoryRegion, quirk->nr_mem);

> +    bar4_quirk = quirk->data = g_new0(typeof(*bar4_quirk), quirk->nr_mem);

> +    bar4_quirk[0].vdev = vdev;

> +    bar4_quirk[0].offset = ASCEND310_XLOADER_OFFSET;

> +    bar4_quirk[0].bar = nr;

> +

> +    /*

> +     * intercept w/r to the xloader-updating register,

> +     * so the vm can't enable xloader-updating

> +     */

> +    memory_region_init_io(&quirk->mem[0], OBJECT(vdev),

> +                          &vfio_ascend_intercept_regs_quirk,

> +                          &bar4_quirk[0],

> +                          "vfio-ascend-bar4-intercept-regs-quirk",

> +                          ASCEND310_XLOADER_SIZE);

> +    memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,

> +                                        bar4_quirk[0].offset,

> +                                        &quirk->mem[0], 1);

> +    QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);

> +}

> +

>  /*

>   * Common quirk probe entry points.

>   */

> @@ -1251,6 +1353,8 @@ void vfio_bar_quirk_setup(VFIOPCIDevice *vdev, int nr)

>      vfio_probe_nvidia_bar5_quirk(vdev, nr);

>      vfio_probe_nvidia_bar0_quirk(vdev, nr);

>      vfio_probe_rtl8168_bar2_quirk(vdev, nr);

> +    vfio_probe_ascend_bar0_quirk(vdev, nr);

> +    vfio_probe_ascend_bar4_quirk(vdev, nr);

>  #ifdef CONFIG_VFIO_IGD

>      vfio_probe_igd_bar4_quirk(vdev, nr);

>  #endif
diff mbox series

Patch

diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c
index 57150913b7..291a45d3ab 100644
--- a/hw/vfio/pci-quirks.c
+++ b/hw/vfio/pci-quirks.c
@@ -1202,6 +1202,108 @@  int vfio_pci_igd_opregion_init(VFIOPCIDevice *vdev,
     return 0;
 }
 
+#define PCI_VENDOR_ID_HUAWEI      0x19e5
+#define PCI_DEVICE_ID_ASCEND910   0xd801
+#define PCI_DEVICE_ID_ASCEND310   0xd100
+#define ASCEND910_XLOADER_SIZE    4
+#define ASCEND910_XLOADER_OFFSET  0x80400
+#define ASCEND310_XLOADER_SIZE    4
+#define ASCEND310_XLOADER_OFFSET  0x400
+
+typedef struct VFIOAscendBarQuirk {
+    struct VFIOPCIDevice *vdev;
+    pcibus_t offset;
+    uint8_t bar;
+    MemoryRegion *mem;
+} VFIOAscendBarQuirk;
+
+static uint64_t vfio_ascend_quirk_read(void *opaque,
+                                       hwaddr addr, unsigned size)
+{
+    VFIOAscendBarQuirk *quirk = opaque;
+    VFIOPCIDevice *vdev = quirk->vdev;
+
+    return vfio_region_read(&vdev->bars[quirk->bar].region,
+                            addr + quirk->offset, size);
+}
+
+static void vfio_ascend_quirk_write(void *opaque, hwaddr addr,
+                                    uint64_t data, unsigned size)
+{
+}
+
+static const MemoryRegionOps vfio_ascend_intercept_regs_quirk = {
+    .read = vfio_ascend_quirk_read,
+    .write = vfio_ascend_quirk_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void vfio_probe_ascend_bar0_quirk(VFIOPCIDevice *vdev, int nr)
+{
+    VFIOQuirk *quirk;
+    VFIOAscendBarQuirk *bar0_quirk;
+
+    if (!vfio_pci_is(vdev, PCI_VENDOR_ID_HUAWEI, PCI_DEVICE_ID_ASCEND910) ||
+        nr != 0) {
+        return;
+    }
+
+    quirk = g_malloc0(sizeof(*quirk));
+    quirk->nr_mem = 1;
+    quirk->mem = g_new0(MemoryRegion, quirk->nr_mem);
+    bar0_quirk = quirk->data = g_new0(typeof(*bar0_quirk), quirk->nr_mem);
+    bar0_quirk[0].vdev = vdev;
+    bar0_quirk[0].offset = ASCEND910_XLOADER_OFFSET;
+    bar0_quirk[0].bar = nr;
+
+    /*
+     * intercept w/r to the xloader-updating register,
+     * so the vm can't enable xloader-updating
+     */
+    memory_region_init_io(&quirk->mem[0], OBJECT(vdev),
+                          &vfio_ascend_intercept_regs_quirk,
+                          &bar0_quirk[0],
+                          "vfio-ascend-bar0-intercept-regs-quirk",
+                          ASCEND910_XLOADER_SIZE);
+    memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
+                                        bar0_quirk[0].offset,
+                                        &quirk->mem[0], 1);
+    QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
+}
+
+static void vfio_probe_ascend_bar4_quirk(VFIOPCIDevice *vdev, int nr)
+{
+    VFIOQuirk *quirk;
+    VFIOAscendBarQuirk *bar4_quirk;
+
+    if (!vfio_pci_is(vdev, PCI_VENDOR_ID_HUAWEI, PCI_DEVICE_ID_ASCEND310) ||
+        nr != 4) {
+        return;
+    }
+
+    quirk = g_malloc0(sizeof(*quirk));
+    quirk->nr_mem = 1;
+    quirk->mem = g_new0(MemoryRegion, quirk->nr_mem);
+    bar4_quirk = quirk->data = g_new0(typeof(*bar4_quirk), quirk->nr_mem);
+    bar4_quirk[0].vdev = vdev;
+    bar4_quirk[0].offset = ASCEND310_XLOADER_OFFSET;
+    bar4_quirk[0].bar = nr;
+
+    /*
+     * intercept w/r to the xloader-updating register,
+     * so the vm can't enable xloader-updating
+     */
+    memory_region_init_io(&quirk->mem[0], OBJECT(vdev),
+                          &vfio_ascend_intercept_regs_quirk,
+                          &bar4_quirk[0],
+                          "vfio-ascend-bar4-intercept-regs-quirk",
+                          ASCEND310_XLOADER_SIZE);
+    memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
+                                        bar4_quirk[0].offset,
+                                        &quirk->mem[0], 1);
+    QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
+}
+
 /*
  * Common quirk probe entry points.
  */
@@ -1251,6 +1353,8 @@  void vfio_bar_quirk_setup(VFIOPCIDevice *vdev, int nr)
     vfio_probe_nvidia_bar5_quirk(vdev, nr);
     vfio_probe_nvidia_bar0_quirk(vdev, nr);
     vfio_probe_rtl8168_bar2_quirk(vdev, nr);
+    vfio_probe_ascend_bar0_quirk(vdev, nr);
+    vfio_probe_ascend_bar4_quirk(vdev, nr);
 #ifdef CONFIG_VFIO_IGD
     vfio_probe_igd_bar4_quirk(vdev, nr);
 #endif