修改QEMU

不同的操作系统修改QEMU的操作步骤不同,可直接参考表1直接跳转到对应的内容。

表1 操作系统参考步骤

虚拟机操作系统

参考步骤

openEuler 22.03 LTS x86

openEuler 20.03 LTS

BC Linux 8.2

BC Linux 21.10

CULinux 3.0

Kylin V10 Arm

Kylin V10 SP2

Kylin V10 SP3

UOS V20(1050e)

UOS V20(1050u2e)

操作步骤

CentOS 7.5(5.10.0)

Tlinux3.1

操作步骤

Ubuntu 20.04

Ubuntu 22.04

veLinux 1.1

veLinux 1.1(5.10.200)

操作步骤

veLinux 1.2

Debian10.8

Debian10.13

Debian11.8

操作步骤

Debian10(veLinux 1.3)

操作步骤

openEuler 22.03 LTS x86/openEuler 20.03 LTS/Kylin V10 SP2/Kylin V10 Arm/BC Linux 21.10/UOS V20(1050e)/CULinux 3.0/UOS V20(1050u2e)/Kylin V10 SP3/BC Linux 8.2

  1. 执行如下命令,安装必要的工具软件和库文件。

    yum install spice-server spice-server-devel -y

    显示如下,表示安装成功。

    Complete!

  2. 执行如下命令,查看当前环境使用的QEMU版本。

    virsh version

    Compiled against library: libvirt 7.0.0
    Using library: libvirt 7.0.0
    Using API: QEMU 7.0.0
    Running hypervisor: QEMU 4.1.0

  3. 单击QEMU网站下载4.1.0版本的QEMU源码包,并将下载的源码包上传至环境中。
  4. 执行如下命令,修改目录权限。

    chmod +x ./qemu-4.1.0.tar.xz

  5. 执行如下命令,解压QEMU源码包。

    tar -xf ./qemu-4.1.0.tar.xz

  6. 执行如下命令,进入QEMU源码目录。

    cd qemu-4.1.0/

  7. 修改QEMU源码。

    1. 执行如下命令,修改“pci-quirks.c”文件。

      vi ./hw/vfio/pci-quirks.c

      增加如下加粗字体标注的代码并保存:

      …
      #include "hw/nvram/fw_cfg.h"
      #include "pci.h"
      #include "trace.h"
       
      // ascend-patch begin
      #define PCI_VENDOR_ID_HUAWEI      0x19e5
      #define PCI_DEVICE_ID_ASCEND910   0xd801
      #define PCI_DEVICE_ID_ASCEND910_A2  0xd802
      #define PCI_DEVICE_ID_ASCEND310P   0xd500
      #define PCI_DEVICE_ID_ASCEND310B   0xd105
      #define PCI_DEVICE_ID_ASCEND310   0xd100
      #define PCI_SUB_DEVICE_ID_ASCEND310P_1P_MIN  0x100
      #define PCI_SUB_DEVICE_ID_ASCEND310P_1P_MAX  0x10f
      #define PCI_SUB_DEVICE_ID_ASCEND310P_2P_MIN  0x110
      #define PCI_SUB_DEVICE_ID_ASCEND310P_2P_MAX  0x11f
      #define ASCEND910_XLOADER_SIZE    4
      #define ASCEND910_XLOADER_OFFSET  0x80400
      #define ASCEND910_A2_XLOADER_SIZE   4
      #define ASCEND910_A2_XLOADER_OFFSET    0x18208430
      #define ASCEND310P_2P_BASE         (128 * 1024 * 1024)
      #define ASCEND310P_1P_DEVNUM       1
      #define ASCEND310P_2P_DEVNUM       2
      #define ASCEND310P_XLOADER_SIZE    4
      #define ASCEND310P_XLOADER_OFFSET  0x100430
      #define ASCEND310B_XLOADER_SIZE    4
      #define ASCEND310B_XLOADER_OFFSET  0x4430
      #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;
          qemu_log("read RO region! addr=0x%" HWADDR_PRIx ", size=%d\n",
                  addr + quirk->offset, size);
          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)
      {
          VFIOAscendBarQuirk *quirk = opaque;
          qemu_log("modifying RO region is not allowed! addr=0x%"
                  HWADDR_PRIx ", data=0x%" PRIx64 ", size=%d\n",
                  addr + quirk->offset, data, 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_ascend910_a2_bar2_quirk(VFIOPCIDevice *vdev, int nr)
      {
          VFIOQuirk *quirk;
          VFIOAscendBarQuirk *bar2_quirk;
       
          if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 2
              || vdev->device_id != PCI_DEVICE_ID_ASCEND910_A2) {
              return;
          }
       
          quirk = g_malloc0(sizeof(*quirk));
          quirk->nr_mem = 1;
          quirk->mem = g_new0(MemoryRegion, quirk->nr_mem);
          bar2_quirk = quirk->data = g_new0(typeof(*bar2_quirk), quirk->nr_mem);
          bar2_quirk[0].vdev = vdev;
          bar2_quirk[0].offset = ASCEND910_A2_XLOADER_OFFSET;
          bar2_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,
                                &bar2_quirk[0],
                                "vfio-ascend910_a2-bar2-intercept-regs-quirk",
                                ASCEND910_A2_XLOADER_SIZE);
          memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
                                              bar2_quirk[0].offset,
                                              &quirk->mem[0], 1);
          QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
      }
      static void vfio_probe_ascend910_bar0_quirk(VFIOPCIDevice *vdev, int nr)
      {
          VFIOQuirk *quirk;
          VFIOAscendBarQuirk *bar0_quirk;
          if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 0 ||
              vdev->device_id != PCI_DEVICE_ID_ASCEND910) {
              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-ascend910-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_ascend310p_bar2_quirk(VFIOPCIDevice *vdev, int nr)
      {
          VFIOQuirk *quirk;
          VFIOAscendBarQuirk *bar2_quirk;
          int sub_device_id;
          int devnum = 0;
          if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 2 ||
              vdev->device_id != PCI_DEVICE_ID_ASCEND310P) {
              return;
          }
          sub_device_id = pci_get_word(vdev->pdev.config + PCI_SUBSYSTEM_ID);
          if (sub_device_id >= PCI_SUB_DEVICE_ID_ASCEND310P_1P_MIN &&
              sub_device_id <= PCI_SUB_DEVICE_ID_ASCEND310P_1P_MAX) {
              devnum = ASCEND310P_1P_DEVNUM;
          } else if (sub_device_id >= PCI_SUB_DEVICE_ID_ASCEND310P_2P_MIN &&
                     sub_device_id <= PCI_SUB_DEVICE_ID_ASCEND310P_2P_MAX) {
              devnum = ASCEND310P_2P_DEVNUM;
          }
          if (devnum != ASCEND310P_1P_DEVNUM && devnum != ASCEND310P_2P_DEVNUM) {
              return;
          }
          quirk = g_malloc0(sizeof(*quirk));
          quirk->nr_mem = devnum;
          quirk->mem = g_new0(MemoryRegion, quirk->nr_mem);
          bar2_quirk = quirk->data = g_new0(typeof(*bar2_quirk), quirk->nr_mem);
          bar2_quirk[0].vdev = vdev;
          bar2_quirk[0].offset = ASCEND310P_XLOADER_OFFSET;
          bar2_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,
                                &bar2_quirk[0],
                                "vfio-ascend310p-bar2-1p-intercept-regs-quirk",
                                ASCEND310P_XLOADER_SIZE);
          memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
                                              bar2_quirk[0].offset,
                                              &quirk->mem[0], 1);
          if (devnum == ASCEND310P_2P_DEVNUM) {
              bar2_quirk[1].vdev = vdev;
              bar2_quirk[1].offset = (ASCEND310P_2P_BASE + ASCEND310P_XLOADER_OFFSET);
              bar2_quirk[1].bar = nr;
              memory_region_init_io(&quirk->mem[1], OBJECT(vdev),
                                    &vfio_ascend_intercept_regs_quirk,
                                    &bar2_quirk[1],
                                    "vfio-ascend310p-bar2-2p-intercept-regs-quirk",
                                    ASCEND310P_XLOADER_SIZE);
              memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
                                                  bar2_quirk[1].offset,
                                                  &quirk->mem[1], 1);
          }
          QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
      }
      static void vfio_probe_ascend310b_bar2_quirk(VFIOPCIDevice *vdev, int nr)
      {
          VFIOQuirk *quirk;
          VFIOAscendBarQuirk *bar2_quirk;
       
          if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 2
              || vdev->device_id != PCI_DEVICE_ID_ASCEND310B) {
              return;
          }
       
          quirk = g_malloc0(sizeof(*quirk));
          quirk->nr_mem = 1;
          quirk->mem = g_new0(MemoryRegion, quirk->nr_mem);
          bar2_quirk = quirk->data = g_new0(typeof(*bar2_quirk), quirk->nr_mem);
          bar2_quirk[0].vdev = vdev;
          bar2_quirk[0].offset = ASCEND310B_XLOADER_OFFSET;
          bar2_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,
                                &bar2_quirk[0],
                                "vfio-ascend310b-bar2-intercept-regs-quirk",
                                ASCEND310B_XLOADER_SIZE);
          memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
                                              bar2_quirk[0].offset,
                                              &quirk->mem[0], 1);
          QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
      }
      static void vfio_probe_ascend310_bar4_quirk(VFIOPCIDevice *vdev, int nr)
      {
          VFIOQuirk *quirk;
          VFIOAscendBarQuirk *bar4_quirk;
          if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 4 ||
              vdev->device_id != PCI_DEVICE_ID_ASCEND310) {
              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-ascend310-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);
      }
      // ascend-patch end
    2. 修改vfio_bar_quirk_setup函数,增加如下加粗字体标注的代码并保存。
      void vfio_bar_quirk_setup(VFIOPCIDevice *vdev, int nr)
      {
          vfio_probe_ati_bar4_quirk(vdev, nr);
          vfio_probe_ati_bar2_quirk(vdev, nr);
          vfio_probe_nvidia_bar5_quirk(vdev, nr);
          vfio_probe_nvidia_bar0_quirk(vdev, nr);
       
          // ascend-patch begin
          vfio_probe_ascend910_a2_bar2_quirk(vdev, nr);
          vfio_probe_ascend910_bar0_quirk(vdev, nr);
          vfio_probe_ascend310p_bar2_quirk(vdev, nr);
          vfio_probe_ascend310b_bar2_quirk(vdev, nr);
          vfio_probe_ascend310_bar4_quirk(vdev, nr);
          // ascend-patch end
       
          vfio_probe_rtl8168_bar2_quirk(vdev, nr);
          vfio_probe_igd_bar4_quirk(vdev, nr);
      }…
    3. (可选)对于Atlas 800 训练服务器(型号:9000)/Atlas 800 训练服务器(型号:9010),请跳过此步骤。

      执行如下命令,修改配置文件“./linux-user/syscall.c”的TARGET_NR_stime函数。

      vi ./linux-user/syscall.c

      增加如下加粗字体内容并保存。
      #ifdef TARGET_NR_stime /* not on alpha */
             case TARGET_NR_stime:
                   {
                        time_t host_time;
                        if (get_user_sal(host_time, argl))
                             return -TARGET_EFAULT;
                      struct timespec res;
                      res.tv_sec = host_time;
                      return get_errno(clock_settime(CLOCK_REALTIME, &res));
                   }
      #endif
    4. 执行如下命令,修改“configure”文件。

      vi ./configure

      修改如下加粗字体的参数取值为“yes”并保存。

      qom_cast_debug="yes"
      trace_backends="log"
      trace_file="trace"
      spice="yes"
      rbd=""
      smartcard=""
      libusb=""
      usb_redir=""
      opengl=""
      opengl_dmabuf="no"
      cpuid_h="no"
      avx2_opt=""

  8. 执行如下命令,配置QEMU的构建环境和构建参数。

    ./configure --enable-kvm

  9. 执行如下命令,启动构建。

    make -j 64

  10. 执行如下命令,安装QEMU。

    make install

  11. 检查QEMU版本。

    1. 执行如下命令,重启libvirtd服务。

      sudo service libvirtd restart

      不同的OS回显信息不同,具体回显信息请以实际环境为准。

      Redirecting to /bin/systemctl restart libvirtd.service
    2. 执行如下命令,关闭AppArmor

      sudo systemctl disable apparmor

    3. 执行如下命令,重启系统。

      sudo reboot

    4. 执行如下命令,查看QEMU版本。

      virsh version

      Compiled against library: libvirt 6.0.0
      Using library: libvirt 6.0.0
      Using API: QEMU 6.0.0
      Running hypervisor: QEMU 4.1.0

CentOS 7.5(5.10.0)/Tlinux3.1

  1. 执行如下命令,安装必要的工具软件和库文件。

    yum install spice-server spice-server-devel -y

    对于Tlinux3.1:还需执行yum install -y python3 perl

    显示如下,表示安装成功。

    Complete!

  2. 执行如下命令,查看当前环境使用的QEMU版本。

    virsh version

    Compiled against library: libvirt 7.0.0
    Using library: libvirt 7.0.0
    Using API: QEMU 7.0.0
    Running hypervisor: QEMU 4.1.0

  3. 单击QEMU网站下载5.2.0版本的QEMU源码包,并将下载的源码包上传至环境中。
  4. 执行如下命令,修改目录权限。

    chmod +x ./qemu-5.2.0.tar.xz

  5. 执行如下命令,解压QEMU源码包。

    tar -xf ./qemu-5.2.0.tar.xz

  6. 执行如下命令,进入QEMU源码目录。

    cd qemu-5.2.0/

  7. 修改QEMU源码。

    1. 执行如下命令,修改“pci-quirks.c”文件。

      vi ./hw/vfio/pci-quirks.c

      增加如下加粗字体标注的代码并保存:

      …
      #include "hw/nvram/fw_cfg.h"
      #include "pci.h"
      #include "trace.h"
       
      // ascend-patch begin
      #define PCI_VENDOR_ID_HUAWEI      0x19e5
      #define PCI_DEVICE_ID_ASCEND910   0xd801
      #define PCI_DEVICE_ID_ASCEND910_A2  0xd802
      #define PCI_DEVICE_ID_ASCEND310P   0xd500
      #define PCI_DEVICE_ID_ASCEND310B   0xd105
      #define PCI_DEVICE_ID_ASCEND310   0xd100
      #define PCI_SUB_DEVICE_ID_ASCEND310P_1P_MIN  0x100
      #define PCI_SUB_DEVICE_ID_ASCEND310P_1P_MAX  0x10f
      #define PCI_SUB_DEVICE_ID_ASCEND310P_2P_MIN  0x110
      #define PCI_SUB_DEVICE_ID_ASCEND310P_2P_MAX  0x11f
      #define ASCEND910_XLOADER_SIZE    4
      #define ASCEND910_XLOADER_OFFSET  0x80400
      #define ASCEND910_A2_XLOADER_SIZE   4
      #define ASCEND910_A2_XLOADER_OFFSET    0x18208430
      #define ASCEND310P_2P_BASE         (128 * 1024 * 1024)
      #define ASCEND310P_1P_DEVNUM       1
      #define ASCEND310P_2P_DEVNUM       2
      #define ASCEND310P_XLOADER_SIZE    4
      #define ASCEND310P_XLOADER_OFFSET  0x100430
      #define ASCEND310B_XLOADER_SIZE    4
      #define ASCEND310B_XLOADER_OFFSET  0x4430
      #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;
          qemu_log("read RO region! addr=0x%" HWADDR_PRIx ", size=%d\n",
                  addr + quirk->offset, size);
          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)
      {
          VFIOAscendBarQuirk *quirk = opaque;
          qemu_log("modifying RO region is not allowed! addr=0x%"
                  HWADDR_PRIx ", data=0x%" PRIx64 ", size=%d\n",
                  addr + quirk->offset, data, 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_ascend910_a2_bar2_quirk(VFIOPCIDevice *vdev, int nr)
      {
          VFIOQuirk *quirk;
          VFIOAscendBarQuirk *bar2_quirk;
       
          if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 2
              || vdev->device_id != PCI_DEVICE_ID_ASCEND910_A2) {
              return;
          }
       
          quirk = g_malloc0(sizeof(*quirk));
          quirk->nr_mem = 1;
          quirk->mem = g_new0(MemoryRegion, quirk->nr_mem);
          bar2_quirk = quirk->data = g_new0(typeof(*bar2_quirk), quirk->nr_mem);
          bar2_quirk[0].vdev = vdev;
          bar2_quirk[0].offset = ASCEND910_A2_XLOADER_OFFSET;
          bar2_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,
                                &bar2_quirk[0],
                                "vfio-ascend910_a2-bar2-intercept-regs-quirk",
                                ASCEND910_A2_XLOADER_SIZE);
          memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
                                              bar2_quirk[0].offset,
                                              &quirk->mem[0], 1);
          QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
      }
      static void vfio_probe_ascend910_bar0_quirk(VFIOPCIDevice *vdev, int nr)
      {
          VFIOQuirk *quirk;
          VFIOAscendBarQuirk *bar0_quirk;
          if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 0 ||
              vdev->device_id != PCI_DEVICE_ID_ASCEND910) {
              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-ascend910-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_ascend310p_bar2_quirk(VFIOPCIDevice *vdev, int nr)
      {
          VFIOQuirk *quirk;
          VFIOAscendBarQuirk *bar2_quirk;
          int sub_device_id;
          int devnum = 0;
          if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 2 ||
              vdev->device_id != PCI_DEVICE_ID_ASCEND310P) {
              return;
          }
          sub_device_id = pci_get_word(vdev->pdev.config + PCI_SUBSYSTEM_ID);
          if (sub_device_id >= PCI_SUB_DEVICE_ID_ASCEND310P_1P_MIN &&
              sub_device_id <= PCI_SUB_DEVICE_ID_ASCEND310P_1P_MAX) {
              devnum = ASCEND310P_1P_DEVNUM;
          } else if (sub_device_id >= PCI_SUB_DEVICE_ID_ASCEND310P_2P_MIN &&
                     sub_device_id <= PCI_SUB_DEVICE_ID_ASCEND310P_2P_MAX) {
              devnum = ASCEND310P_2P_DEVNUM;
          }
          if (devnum != ASCEND310P_1P_DEVNUM && devnum != ASCEND310P_2P_DEVNUM) {
              return;
          }
          quirk = g_malloc0(sizeof(*quirk));
          quirk->nr_mem = devnum;
          quirk->mem = g_new0(MemoryRegion, quirk->nr_mem);
          bar2_quirk = quirk->data = g_new0(typeof(*bar2_quirk), quirk->nr_mem);
          bar2_quirk[0].vdev = vdev;
          bar2_quirk[0].offset = ASCEND310P_XLOADER_OFFSET;
          bar2_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,
                                &bar2_quirk[0],
                                "vfio-ascend310p-bar2-1p-intercept-regs-quirk",
                                ASCEND310P_XLOADER_SIZE);
          memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
                                              bar2_quirk[0].offset,
                                              &quirk->mem[0], 1);
          if (devnum == ASCEND310P_2P_DEVNUM) {
              bar2_quirk[1].vdev = vdev;
              bar2_quirk[1].offset = (ASCEND310P_2P_BASE + ASCEND310P_XLOADER_OFFSET);
              bar2_quirk[1].bar = nr;
              memory_region_init_io(&quirk->mem[1], OBJECT(vdev),
                                    &vfio_ascend_intercept_regs_quirk,
                                    &bar2_quirk[1],
                                    "vfio-ascend310p-bar2-2p-intercept-regs-quirk",
                                    ASCEND310P_XLOADER_SIZE);
              memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
                                                  bar2_quirk[1].offset,
                                                  &quirk->mem[1], 1);
          }
          QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
      }
      static void vfio_probe_ascend310b_bar2_quirk(VFIOPCIDevice *vdev, int nr)
      {
          VFIOQuirk *quirk;
          VFIOAscendBarQuirk *bar2_quirk;
       
          if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 2
              || vdev->device_id != PCI_DEVICE_ID_ASCEND310B) {
              return;
          }
       
          quirk = g_malloc0(sizeof(*quirk));
          quirk->nr_mem = 1;
          quirk->mem = g_new0(MemoryRegion, quirk->nr_mem);
          bar2_quirk = quirk->data = g_new0(typeof(*bar2_quirk), quirk->nr_mem);
          bar2_quirk[0].vdev = vdev;
          bar2_quirk[0].offset = ASCEND310B_XLOADER_OFFSET;
          bar2_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,
                                &bar2_quirk[0],
                                "vfio-ascend310b-bar2-intercept-regs-quirk",
                                ASCEND310B_XLOADER_SIZE);
          memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
                                              bar2_quirk[0].offset,
                                              &quirk->mem[0], 1);
          QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
      }
      static void vfio_probe_ascend310_bar4_quirk(VFIOPCIDevice *vdev, int nr)
      {
          VFIOQuirk *quirk;
          VFIOAscendBarQuirk *bar4_quirk;
          if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 4 ||
              vdev->device_id != PCI_DEVICE_ID_ASCEND310) {
              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-ascend310-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);
      }
      // ascend-patch end
    2. 修改vfio_bar_quirk_setup函数,增加如下加粗字体标注的代码并保存。
      void vfio_bar_quirk_setup(VFIOPCIDevice *vdev, int nr)
      {
          vfio_probe_ati_bar4_quirk(vdev, nr);
          vfio_probe_ati_bar2_quirk(vdev, nr);
          vfio_probe_nvidia_bar5_quirk(vdev, nr);
          vfio_probe_nvidia_bar0_quirk(vdev, nr);
       
          // ascend-patch begin
          vfio_probe_ascend910_a2_bar2_quirk(vdev, nr);
          vfio_probe_ascend910_bar0_quirk(vdev, nr);
          vfio_probe_ascend310p_bar2_quirk(vdev, nr);
          vfio_probe_ascend310b_bar2_quirk(vdev, nr);
          vfio_probe_ascend310_bar4_quirk(vdev, nr);
          // ascend-patch end
       
          vfio_probe_rtl8168_bar2_quirk(vdev, nr);
          vfio_probe_igd_bar4_quirk(vdev, nr);
      }…
    3. 执行如下命令,修改配置文件“./linux-user/syscall.c”的TARGET_NR_stime函数。

      vi ./linux-user/syscall.c

      增加如下加粗字体标注的内容并保存。
      #ifdef TARGET_NR_stime /* not on alpha */
             case TARGET_NR_stime:
                   {
                        time_t host_time;
                        if (get_user_sal(host_time, argl))
                             return -TARGET_EFAULT;
                      struct timespec res;
                      res.tv_sec = host_time;
                      return get_errno(clock_settime(CLOCK_REALTIME, &res));
                   }
      #endif
    4. 执行如下命令,修改配置文件“target/i386/cpu.c”的x86_cpu_realizefn函数。

      vi ./target/i386/cpu.c

      增加如下加粗字体标注的内容并保存。

      static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
      {
          …
          if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) {
              if (accel_uses_host_cpuid()) {
                  uint32_t host_phys_bits = x86_host_phys_bits();
                  static bool warned;
                cpu->host_phys_bits = true;
                  …
              } else {
                 …
      }
      …
      }
    5. 对于CentOS 7.5(5.10.0),执行如下命令修改“linux-user/strace.c”文件。

      vi ./linux-user/strace.c

      增加如下加粗字体内容并保存。

      #include "qemu/osdep.h"
      #include <sys/ipc.h>
      #include <sys/msg.h>
      #include <sys/sem.h>
      #include <sys/shm.h>
      #include <sys/select.h>
      #include <sys/mount.h>
      #include <arpa/inet.h>
      #include <netinet/tcp.h>
      #include <linux/if_packet.h>
      #include <linux/netlink.h>
      #include <linux/falloc.h>
      #include <sched.h>
      #include "qemu.h"
    6. 执行如下命令,修改“configure”文件。

      vi ./configure

      修改如下加粗字体的参数取值为“yes”并保存。

      qom_cast_debug="yes"
      trace_backends="log"
      trace_file="trace"
      spice="yes"
      rbd=""
      smartcard=""
      libusb=""
      usb_redir=""
      opengl=""
      opengl_dmabuf="no"
      cpuid_h="no"
      avx2_opt=""

  8. 安装QEMU所需依赖。

    • 对于CentOS 7.5(5.10.0),请执行以下步骤
      1. 执行如下命令,配置网络源。

        yum install -y http://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm

        显示如下,表示安装成功。

        Complete!
      2. 执行如下命令,安装依赖。

        yum install -y ninja-build libffi-devel unzip

        显示如下,表示安装成功。

        Complete!
      3. 升级python3(以上以3.75为例)。
        1. 用户自行准备Python-3.7.5源码包并上传至服务器任意目录(例如/opt),执行如下命令解压。

          unzip Python-3.7.5.zip

        2. 进入解压后的文件夹,执行如下命令。

          配置命令:cd Python-3.7.5

          编译命令:./configure --prefix=/usr/local/python3.7.5 --enable-loadable-sqlite-extensions --enable-shared

          安装命令:make -j && make install

        3. 安装完成之后,执行如下命令查看安装版本,如果返回相关版本信息,则说明安装成功。

          python3 --version

    • 对于Tlinux3.1,请执行如下命令,安装依赖。

      yum install -y ninja-build libffi-devel unzip

      显示如下,表示安装成功。

      Complete!

  9. 执行如下命令,配置QEMU的构建环境和构建参数。

    ./configure --enable-kvm

  10. 执行如下命令,启动构建。

    make -j 64

  11. 执行如下命令,安装QEMU。

    make install

  12. 检查QEMU版本。

    1. 执行如下命令,重启libvirtd服务。

      sudo service libvirtd restart

      不同的OS回显信息不同,具体回显信息请以实际环境为准。

      Redirecting to /bin/systemctl restart libvirtd.service
    2. 执行如下命令,关闭AppArmor

      sudo systemctl disable apparmor

    3. 执行如下命令,重启系统。

      sudo reboot

    4. 执行如下命令,查看QEMU版本。

      virsh version

      Compiled against library: libvirt 6.0.0
      Using library: libvirt 6.0.0
      Using API: QEMU 6.0.0
      Running hypervisor: QEMU 5.2.0

Ubuntu 20.04/Ubuntu 22.04/veLinux 1.1/veLinux 1.1(5.10.200)

  1. 执行如下命令,安装必要的工具软件和库文件。

    apt-get install -y ninja-build gcc pkg-config build-essential zlib1g-dev libglib2.0-dev libmount-dev libpixman-1-dev

    apt-get install -y libusbredirhost-dev libusbredirhost1 libusbredirparser-dev libusbredirparser1 usbredirserver

    apt-get install libspice-server-dev libspice-server1

    Reading package lists... DoneBuilding dependency treeReading state information... Donelibspice-server1 is already the newest version (0.14.2-4ubuntu3.1).libspice-server1 set to manually installed.The following NEW packages will be installed:  libspice-protocol-dev libspice-server-dev0 upgraded, 2 newly installed, 0 to remove and 263 not upgraded.Need to get 31.8 kB of archives.After this operation, 198 kB of additional disk space will be used.Get:1 http://ports.ubuntu.com/ubuntu-ports focal/main arm64 libspice-protocol-dev all 0.14.0-0ubuntu1 [21.5 kB]Get:2 http://ports.ubuntu.com/ubuntu-ports focal-updates/main arm64 libspice-server-dev arm64 0.14.2-4ubuntu3.1 [10.3 kB]Fetched 31.8 kB in 8s (3,903 B/s)Selecting previously unselected package libspice-protocol-dev.(Reading database ... 97326 files and directories currently installed.)Preparing to unpack .../libspice-protocol-dev_0.14.0-0ubuntu1_all.deb ...

  2. 执行如下命令,查看当前环境使用的QEMU版本。

    virsh version

    Compiled against library: libvirt 7.0.0
    Using library: libvirt 7.0.0
    Using API: QEMU 7.0.0
    Running hypervisor: QEMU 4.1.0

  3. 单击QEMU网站下载4.1.0版本的QEMU源码包,并将下载的源码包上传至环境中。

    对于Atlas 200T A2 Box16 异构子框,建议下载5.2.0版本的QEMU源码包。

  4. 执行如下命令,修改目录权限。

    chmod +x ./qemu-4.1.0.tar.xz

  5. 执行如下命令,解压QEMU源码包。

    tar -xf ./qemu-4.1.0.tar.xz

  6. 执行如下命令,进入QEMU源码目录。

    cd qemu-4.1.0/

  7. 修改QEMU源码。

    1. 执行如下命令,修改“pci-quirks.c”文件。

      vi ./hw/vfio/pci-quirks.c

      增加如下加粗字体标注的代码并保存:

      …
      #include "hw/nvram/fw_cfg.h"
      #include "pci.h"
      #include "trace.h"
       
      // ascend-patch begin
      #define PCI_VENDOR_ID_HUAWEI      0x19e5
      #define PCI_DEVICE_ID_ASCEND910   0xd801
      #define PCI_DEVICE_ID_ASCEND910_A2  0xd802
      #define PCI_DEVICE_ID_ASCEND310P   0xd500
      #define PCI_DEVICE_ID_ASCEND310B   0xd105
      #define PCI_DEVICE_ID_ASCEND310   0xd100
      #define PCI_SUB_DEVICE_ID_ASCEND310P_1P_MIN  0x100
      #define PCI_SUB_DEVICE_ID_ASCEND310P_1P_MAX  0x10f
      #define PCI_SUB_DEVICE_ID_ASCEND310P_2P_MIN  0x110
      #define PCI_SUB_DEVICE_ID_ASCEND310P_2P_MAX  0x11f
      #define ASCEND910_XLOADER_SIZE    4
      #define ASCEND910_XLOADER_OFFSET  0x80400
      #define ASCEND910_A2_XLOADER_SIZE   4
      #define ASCEND910_A2_XLOADER_OFFSET    0x18208430
      #define ASCEND310P_2P_BASE         (128 * 1024 * 1024)
      #define ASCEND310P_1P_DEVNUM       1
      #define ASCEND310P_2P_DEVNUM       2
      #define ASCEND310P_XLOADER_SIZE    4
      #define ASCEND310P_XLOADER_OFFSET  0x100430
      #define ASCEND310B_XLOADER_SIZE    4
      #define ASCEND310B_XLOADER_OFFSET  0x4430
      #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;
          qemu_log("read RO region! addr=0x%" HWADDR_PRIx ", size=%d\n",
                  addr + quirk->offset, size);
          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)
      {
          VFIOAscendBarQuirk *quirk = opaque;
          qemu_log("modifying RO region is not allowed! addr=0x%"
                  HWADDR_PRIx ", data=0x%" PRIx64 ", size=%d\n",
                  addr + quirk->offset, data, 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_ascend910_a2_bar2_quirk(VFIOPCIDevice *vdev, int nr)
      {
          VFIOQuirk *quirk;
          VFIOAscendBarQuirk *bar2_quirk;
       
          if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 2
              || vdev->device_id != PCI_DEVICE_ID_ASCEND910_A2) {
              return;
          }
       
          quirk = g_malloc0(sizeof(*quirk));
          quirk->nr_mem = 1;
          quirk->mem = g_new0(MemoryRegion, quirk->nr_mem);
          bar2_quirk = quirk->data = g_new0(typeof(*bar2_quirk), quirk->nr_mem);
          bar2_quirk[0].vdev = vdev;
          bar2_quirk[0].offset = ASCEND910_A2_XLOADER_OFFSET;
          bar2_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,
                                &bar2_quirk[0],
                                "vfio-ascend910_a2-bar2-intercept-regs-quirk",
                                ASCEND910_A2_XLOADER_SIZE);
          memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
                                              bar2_quirk[0].offset,
                                              &quirk->mem[0], 1);
          QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
      }
      static void vfio_probe_ascend910_bar0_quirk(VFIOPCIDevice *vdev, int nr)
      {
          VFIOQuirk *quirk;
          VFIOAscendBarQuirk *bar0_quirk;
          if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 0 ||
              vdev->device_id != PCI_DEVICE_ID_ASCEND910) {
              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-ascend910-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_ascend310p_bar2_quirk(VFIOPCIDevice *vdev, int nr)
      {
          VFIOQuirk *quirk;
          VFIOAscendBarQuirk *bar2_quirk;
          int sub_device_id;
          int devnum = 0;
          if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 2 ||
              vdev->device_id != PCI_DEVICE_ID_ASCEND310P) {
              return;
          }
          sub_device_id = pci_get_word(vdev->pdev.config + PCI_SUBSYSTEM_ID);
          if (sub_device_id >= PCI_SUB_DEVICE_ID_ASCEND310P_1P_MIN &&
              sub_device_id <= PCI_SUB_DEVICE_ID_ASCEND310P_1P_MAX) {
              devnum = ASCEND310P_1P_DEVNUM;
          } else if (sub_device_id >= PCI_SUB_DEVICE_ID_ASCEND310P_2P_MIN &&
                     sub_device_id <= PCI_SUB_DEVICE_ID_ASCEND310P_2P_MAX) {
              devnum = ASCEND310P_2P_DEVNUM;
          }
          if (devnum != ASCEND310P_1P_DEVNUM && devnum != ASCEND310P_2P_DEVNUM) {
              return;
          }
          quirk = g_malloc0(sizeof(*quirk));
          quirk->nr_mem = devnum;
          quirk->mem = g_new0(MemoryRegion, quirk->nr_mem);
          bar2_quirk = quirk->data = g_new0(typeof(*bar2_quirk), quirk->nr_mem);
          bar2_quirk[0].vdev = vdev;
          bar2_quirk[0].offset = ASCEND310P_XLOADER_OFFSET;
          bar2_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,
                                &bar2_quirk[0],
                                "vfio-ascend310p-bar2-1p-intercept-regs-quirk",
                                ASCEND310P_XLOADER_SIZE);
          memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
                                              bar2_quirk[0].offset,
                                              &quirk->mem[0], 1);
          if (devnum == ASCEND310P_2P_DEVNUM) {
              bar2_quirk[1].vdev = vdev;
              bar2_quirk[1].offset = (ASCEND310P_2P_BASE + ASCEND310P_XLOADER_OFFSET);
              bar2_quirk[1].bar = nr;
              memory_region_init_io(&quirk->mem[1], OBJECT(vdev),
                                    &vfio_ascend_intercept_regs_quirk,
                                    &bar2_quirk[1],
                                    "vfio-ascend310p-bar2-2p-intercept-regs-quirk",
                                    ASCEND310P_XLOADER_SIZE);
              memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
                                                  bar2_quirk[1].offset,
                                                  &quirk->mem[1], 1);
          }
          QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
      }
      static void vfio_probe_ascend310b_bar2_quirk(VFIOPCIDevice *vdev, int nr)
      {
          VFIOQuirk *quirk;
          VFIOAscendBarQuirk *bar2_quirk;
       
          if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 2
              || vdev->device_id != PCI_DEVICE_ID_ASCEND310B) {
              return;
          }
       
          quirk = g_malloc0(sizeof(*quirk));
          quirk->nr_mem = 1;
          quirk->mem = g_new0(MemoryRegion, quirk->nr_mem);
          bar2_quirk = quirk->data = g_new0(typeof(*bar2_quirk), quirk->nr_mem);
          bar2_quirk[0].vdev = vdev;
          bar2_quirk[0].offset = ASCEND310B_XLOADER_OFFSET;
          bar2_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,
                                &bar2_quirk[0],
                                "vfio-ascend310b-bar2-intercept-regs-quirk",
                                ASCEND310B_XLOADER_SIZE);
          memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
                                              bar2_quirk[0].offset,
                                              &quirk->mem[0], 1);
          QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
      }
      static void vfio_probe_ascend310_bar4_quirk(VFIOPCIDevice *vdev, int nr)
      {
          VFIOQuirk *quirk;
          VFIOAscendBarQuirk *bar4_quirk;
          if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 4 ||
              vdev->device_id != PCI_DEVICE_ID_ASCEND310) {
              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-ascend310-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);
      }
      // ascend-patch end
    2. 修改vfio_bar_quirk_setup函数,增加如下加粗字体标注的代码并保存。
      void vfio_bar_quirk_setup(VFIOPCIDevice *vdev, int nr)
      {
          vfio_probe_ati_bar4_quirk(vdev, nr);
          vfio_probe_ati_bar2_quirk(vdev, nr);
          vfio_probe_nvidia_bar5_quirk(vdev, nr);
          vfio_probe_nvidia_bar0_quirk(vdev, nr);
       
          // ascend-patch begin
          vfio_probe_ascend910_a2_bar2_quirk(vdev, nr);
          vfio_probe_ascend910_bar0_quirk(vdev, nr);
          vfio_probe_ascend310p_bar2_quirk(vdev, nr);
          vfio_probe_ascend310b_bar2_quirk(vdev, nr);
          vfio_probe_ascend310_bar4_quirk(vdev, nr);
          // ascend-patch end
       
          vfio_probe_rtl8168_bar2_quirk(vdev, nr);
          vfio_probe_igd_bar4_quirk(vdev, nr);
      }…
    3. 执行如下命令,修改配置文件“./linux-user/syscall.c”的TARGET_NR_stime函数。

      对于Atlas 800 训练服务器(型号:9000)/Atlas 800 训练服务器(型号:9010),请跳过此步骤。

      vi ./linux-user/syscall.c

      增加如下加粗字体内容并保存。
      #ifdef TARGET_NR_stime /* not on alpha */
             case TARGET_NR_stime:
                   {
                        time_t host_time;
                        if (get_user_sal(host_time, argl))
                             return -TARGET_EFAULT;
                      struct timespec res;
                      res.tv_sec = host_time;
                      return get_errno(clock_settime(CLOCK_REALTIME, &res));
                   }
      #endif
    4. 对于Atlas 200T A2 Box16 异构子框,执行如下命令修改配置文件“target/i386/cpu.c”的x86_cpu_realizefn函数。

      vi ./target/i386/cpu.c

      增加如下加粗字体内容并保存。

      static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
      {
          …
          if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) {
              if (accel_uses_host_cpuid()) {
                  uint32_t host_phys_bits = x86_host_phys_bits();
                  static bool warned;
                cpu->host_phys_bits = true;
                  …
              } else {
                 …
      }
      …
      }
    5. 执行如下命令,修改“configure”文件。

      vi ./configure

      修改如下加粗字体的参数取值为“yes”并保存。

      qom_cast_debug="yes"
      trace_backends="log"
      trace_file="trace"
      spice="yes"
      rbd=""
      smartcard=""
      libusb=""
      usb_redir=""
      opengl=""
      opengl_dmabuf="no"
      cpuid_h="no"
      avx2_opt=""

  8. 执行如下命令,配置QEMU的构建环境和构建参数。

    ./configure --enable-kvm

  9. 执行如下命令,启动构建。

    make -j 64

  10. 执行如下命令,安装QEMU。

    make install

  11. 检查QEMU版本。

    1. 执行如下命令,重启libvirtd服务。

      sudo service libvirtd restart

      不同的OS回显信息不同,具体回显信息请以实际环境为准。

      Redirecting to /bin/systemctl restart libvirtd.service
    2. 执行如下命令,关闭AppArmor

      sudo systemctl disable apparmor

    3. 执行如下命令,重启系统。

      sudo reboot

    4. 执行如下命令,查看QEMU版本。

      virsh version

      Compiled against library: libvirt 6.0.0
      Using library: libvirt 6.0.0
      Using API: QEMU 6.0.0
      Running hypervisor: QEMU 4.1.0

Debian11.8/Debian10.13/veLinux 1.2/Debian10.8

  1. 执行如下命令,安装必要的工具软件和库文件。

    apt install -y make gcc pkg-config build-essential zlib1g-dev libglib2.0-dev libmount-dev libpixman-1-dev --allow-unauthenticated

    apt install -y libusbredirhost1 libusbredirparser1

    apt install libspice-server1 ninja*

    Reading package lists... Done
    Building dependency tree... Done
    Reading state information... Done
    libspice-server1 is already the newest version (0.14.3-2.1).
    0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

  2. 执行如下命令,查看当前环境使用的QEMU版本。

    virsh version

    Compiled against library: libvirt 7.0.0
    Using library: libvirt 7.0.0
    Using API: QEMU 7.0.0
    Running hypervisor: QEMU 4.1.0

  3. 单击QEMU网站下载4.1.0版本的QEMU源码包,并将下载的源码包上传至环境中。
  4. 执行如下命令,修改目录权限。

    chmod +x ./qemu-4.1.0.tar.xz

  5. 执行如下命令,解压QEMU源码包。

    tar -xf ./qemu-4.1.0.tar.xz

  6. 执行如下命令,进入QEMU源码目录。

    cd qemu-4.1.0/

  7. 修改QEMU源码。

    1. 执行如下命令,修改“pci-quirks.c”文件。

      vi ./hw/vfio/pci-quirks.c

      增加如下加粗字体标注的代码并保存:

      …
      #include "hw/nvram/fw_cfg.h"
      #include "pci.h"
      #include "trace.h"
       
      // ascend-patch begin
      #define PCI_VENDOR_ID_HUAWEI      0x19e5
      #define PCI_DEVICE_ID_ASCEND910   0xd801
      #define PCI_DEVICE_ID_ASCEND910_A2  0xd802
      #define PCI_DEVICE_ID_ASCEND310P   0xd500
      #define PCI_DEVICE_ID_ASCEND310B   0xd105
      #define PCI_DEVICE_ID_ASCEND310   0xd100
      #define PCI_SUB_DEVICE_ID_ASCEND310P_1P_MIN  0x100
      #define PCI_SUB_DEVICE_ID_ASCEND310P_1P_MAX  0x10f
      #define PCI_SUB_DEVICE_ID_ASCEND310P_2P_MIN  0x110
      #define PCI_SUB_DEVICE_ID_ASCEND310P_2P_MAX  0x11f
      #define ASCEND910_XLOADER_SIZE    4
      #define ASCEND910_XLOADER_OFFSET  0x80400
      #define ASCEND910_A2_XLOADER_SIZE   4
      #define ASCEND910_A2_XLOADER_OFFSET    0x18208430
      #define ASCEND310P_2P_BASE         (128 * 1024 * 1024)
      #define ASCEND310P_1P_DEVNUM       1
      #define ASCEND310P_2P_DEVNUM       2
      #define ASCEND310P_XLOADER_SIZE    4
      #define ASCEND310P_XLOADER_OFFSET  0x100430
      #define ASCEND310B_XLOADER_SIZE    4
      #define ASCEND310B_XLOADER_OFFSET  0x4430
      #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;
          qemu_log("read RO region! addr=0x%" HWADDR_PRIx ", size=%d\n",
                  addr + quirk->offset, size);
          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)
      {
          VFIOAscendBarQuirk *quirk = opaque;
          qemu_log("modifying RO region is not allowed! addr=0x%"
                  HWADDR_PRIx ", data=0x%" PRIx64 ", size=%d\n",
                  addr + quirk->offset, data, 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_ascend910_a2_bar2_quirk(VFIOPCIDevice *vdev, int nr)
      {
          VFIOQuirk *quirk;
          VFIOAscendBarQuirk *bar2_quirk;
       
          if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 2
              || vdev->device_id != PCI_DEVICE_ID_ASCEND910_A2) {
              return;
          }
       
          quirk = g_malloc0(sizeof(*quirk));
          quirk->nr_mem = 1;
          quirk->mem = g_new0(MemoryRegion, quirk->nr_mem);
          bar2_quirk = quirk->data = g_new0(typeof(*bar2_quirk), quirk->nr_mem);
          bar2_quirk[0].vdev = vdev;
          bar2_quirk[0].offset = ASCEND910_A2_XLOADER_OFFSET;
          bar2_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,
                                &bar2_quirk[0],
                                "vfio-ascend910_a2-bar2-intercept-regs-quirk",
                                ASCEND910_A2_XLOADER_SIZE);
          memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
                                              bar2_quirk[0].offset,
                                              &quirk->mem[0], 1);
          QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
      }
      static void vfio_probe_ascend910_bar0_quirk(VFIOPCIDevice *vdev, int nr)
      {
          VFIOQuirk *quirk;
          VFIOAscendBarQuirk *bar0_quirk;
          if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 0 ||
              vdev->device_id != PCI_DEVICE_ID_ASCEND910) {
              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-ascend910-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_ascend310p_bar2_quirk(VFIOPCIDevice *vdev, int nr)
      {
          VFIOQuirk *quirk;
          VFIOAscendBarQuirk *bar2_quirk;
          int sub_device_id;
          int devnum = 0;
          if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 2 ||
              vdev->device_id != PCI_DEVICE_ID_ASCEND310P) {
              return;
          }
          sub_device_id = pci_get_word(vdev->pdev.config + PCI_SUBSYSTEM_ID);
          if (sub_device_id >= PCI_SUB_DEVICE_ID_ASCEND310P_1P_MIN &&
              sub_device_id <= PCI_SUB_DEVICE_ID_ASCEND310P_1P_MAX) {
              devnum = ASCEND310P_1P_DEVNUM;
          } else if (sub_device_id >= PCI_SUB_DEVICE_ID_ASCEND310P_2P_MIN &&
                     sub_device_id <= PCI_SUB_DEVICE_ID_ASCEND310P_2P_MAX) {
              devnum = ASCEND310P_2P_DEVNUM;
          }
          if (devnum != ASCEND310P_1P_DEVNUM && devnum != ASCEND310P_2P_DEVNUM) {
              return;
          }
          quirk = g_malloc0(sizeof(*quirk));
          quirk->nr_mem = devnum;
          quirk->mem = g_new0(MemoryRegion, quirk->nr_mem);
          bar2_quirk = quirk->data = g_new0(typeof(*bar2_quirk), quirk->nr_mem);
          bar2_quirk[0].vdev = vdev;
          bar2_quirk[0].offset = ASCEND310P_XLOADER_OFFSET;
          bar2_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,
                                &bar2_quirk[0],
                                "vfio-ascend310p-bar2-1p-intercept-regs-quirk",
                                ASCEND310P_XLOADER_SIZE);
          memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
                                              bar2_quirk[0].offset,
                                              &quirk->mem[0], 1);
          if (devnum == ASCEND310P_2P_DEVNUM) {
              bar2_quirk[1].vdev = vdev;
              bar2_quirk[1].offset = (ASCEND310P_2P_BASE + ASCEND310P_XLOADER_OFFSET);
              bar2_quirk[1].bar = nr;
              memory_region_init_io(&quirk->mem[1], OBJECT(vdev),
                                    &vfio_ascend_intercept_regs_quirk,
                                    &bar2_quirk[1],
                                    "vfio-ascend310p-bar2-2p-intercept-regs-quirk",
                                    ASCEND310P_XLOADER_SIZE);
              memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
                                                  bar2_quirk[1].offset,
                                                  &quirk->mem[1], 1);
          }
          QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
      }
      static void vfio_probe_ascend310b_bar2_quirk(VFIOPCIDevice *vdev, int nr)
      {
          VFIOQuirk *quirk;
          VFIOAscendBarQuirk *bar2_quirk;
       
          if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 2
              || vdev->device_id != PCI_DEVICE_ID_ASCEND310B) {
              return;
          }
       
          quirk = g_malloc0(sizeof(*quirk));
          quirk->nr_mem = 1;
          quirk->mem = g_new0(MemoryRegion, quirk->nr_mem);
          bar2_quirk = quirk->data = g_new0(typeof(*bar2_quirk), quirk->nr_mem);
          bar2_quirk[0].vdev = vdev;
          bar2_quirk[0].offset = ASCEND310B_XLOADER_OFFSET;
          bar2_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,
                                &bar2_quirk[0],
                                "vfio-ascend310b-bar2-intercept-regs-quirk",
                                ASCEND310B_XLOADER_SIZE);
          memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
                                              bar2_quirk[0].offset,
                                              &quirk->mem[0], 1);
          QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
      }
      static void vfio_probe_ascend310_bar4_quirk(VFIOPCIDevice *vdev, int nr)
      {
          VFIOQuirk *quirk;
          VFIOAscendBarQuirk *bar4_quirk;
          if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 4 ||
              vdev->device_id != PCI_DEVICE_ID_ASCEND310) {
              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-ascend310-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);
      }
      // ascend-patch end
    2. 修改vfio_bar_quirk_setup函数,增加如下加粗字体标注的代码并保存。
      void vfio_bar_quirk_setup(VFIOPCIDevice *vdev, int nr)
      {
          vfio_probe_ati_bar4_quirk(vdev, nr);
          vfio_probe_ati_bar2_quirk(vdev, nr);
          vfio_probe_nvidia_bar5_quirk(vdev, nr);
          vfio_probe_nvidia_bar0_quirk(vdev, nr);
       
          // ascend-patch begin
          vfio_probe_ascend910_a2_bar2_quirk(vdev, nr);
          vfio_probe_ascend910_bar0_quirk(vdev, nr);
          vfio_probe_ascend310p_bar2_quirk(vdev, nr);
          vfio_probe_ascend310b_bar2_quirk(vdev, nr);
          vfio_probe_ascend310_bar4_quirk(vdev, nr);
          // ascend-patch end
       
          vfio_probe_rtl8168_bar2_quirk(vdev, nr);
          vfio_probe_igd_bar4_quirk(vdev, nr);
      }…
    3. 执行如下命令,修改配置文件“./linux-user/syscall.c”的TARGET_NR_stime函数。

      vi ./linux-user/syscall.c

      增加如下加粗字体标注的代码并保存。
      #ifdef TARGET_NR_stime /* not on alpha */
             case TARGET_NR_stime:
                   {
                        time_t host_time;
                        if (get_user_sal(host_time, argl))
                             return -TARGET_EFAULT;
                      struct timespec res;
                      res.tv_sec = host_time;
                      return get_errno(clock_settime(CLOCK_REALTIME, &res));
                   }
      #endif

  8. 执行如下命令,配置QEMU的构建环境和构建参数。

    ./configure --enable-kvm

  9. 执行如下命令,启动构建。

    make -j 64

  10. 执行如下命令,安装QEMU。

    make install

  11. 检查QEMU版本。

    1. 执行如下命令,重启libvirtd服务。

      sudo service libvirtd restart

      不同的OS回显信息不同,具体回显信息请以实际环境为准。

      Redirecting to /bin/systemctl restart libvirtd.service
    2. 执行如下命令,关闭AppArmor

      sudo systemctl disable apparmor

      不同的OS回显信息不同,具体回显信息请以实际环境为准。

      Synchronizing state of apparmor.service with SysV service script with /lib/systemd/systemd-sysv-install.
      Executing: /lib/systemd/systemd-sysv-install disable apparmor
      Removed /etc/systemd/system/sysinit.target.wants/apparmor.service

      若系统环境为Debian10.13/veLinux 1.2系统,可跳过此步骤。

    3. 执行如下命令,查看QEMU版本。

      virsh version

      Compiled against library: libvirt 6.0.0
      Using library: libvirt 6.0.0
      Using API: QEMU 6.0.0
      Running hypervisor: QEMU 4.1.0

Debian10(veLinux 1.3)

  1. 执行如下命令,安装必要的工具软件和库文件。

    • 对于Debian10(veLinux 1.3)执行:

      apt install -y make gcc pkg-config build-essential zlib1g-dev libglib2.0-dev libmount-dev libpixman-1-dev --allow-unauthenticated

      apt install -y libusbredirhost1 libusbredirparser1

      apt install libspice-server1 ninja* bison flex numactl libnuma-dev
      Reading package lists... Done
      Building dependency tree... Done
      Reading state information... Done
      libspice-server1 is already the newest version (0.14.3-2.1).
      0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

  2. 执行如下命令,查看当前环境使用的QEMU版本。

    virsh version

    Compiled against library: libvirt 7.0.0
    Using library: libvirt 7.0.0
    Using API: QEMU 7.0.0
    Running hypervisor: QEMU 4.1.0

  3. 单击QEMU网站下载8.1.0版本的QEMU源码包,并将下载的源码包上传至环境中。
  4. 执行如下命令,修改目录权限。

    chmod +x ./qemu-8.1.0.tar.xz

  5. 执行如下命令,解压QEMU源码包。

    tar -xf ./qemu-8.1.0.tar.xz

  6. 执行如下命令,进入QEMU源码目录。

    cd qemu-8.1.0/

  7. 修改QEMU源码。

    1. 执行如下命令,修改“pci-quirks.c”文件。

      vi ./hw/vfio/pci-quirks.c

      增加如下加粗字体标注的代码并保存:

      …
      #include "hw/nvram/fw_cfg.h"
      #include "pci.h"
      #include "trace.h"
       
      // ascend-patch begin
      #define PCI_VENDOR_ID_HUAWEI      0x19e5
      #define PCI_DEVICE_ID_ASCEND910   0xd801
      #define PCI_DEVICE_ID_ASCEND910_A2  0xd802
      #define PCI_DEVICE_ID_ASCEND910_A3  0xd803
      #define PCI_DEVICE_ID_ASCEND310P   0xd500
      #define PCI_DEVICE_ID_ASCEND310B   0xd105
      #define PCI_DEVICE_ID_ASCEND310   0xd100
      #define PCI_SUB_DEVICE_ID_ASCEND310P_1P_MIN  0x100
      #define PCI_SUB_DEVICE_ID_ASCEND310P_1P_MAX  0x10f
      #define PCI_SUB_DEVICE_ID_ASCEND310P_2P_MIN  0x110
      #define PCI_SUB_DEVICE_ID_ASCEND310P_2P_MAX  0x11f
      #define ASCEND910_XLOADER_SIZE    4
      #define ASCEND910_XLOADER_OFFSET  0x80400
      #define ASCEND910_A2_XLOADER_SIZE   4
      #define ASCEND910_A2_XLOADER_OFFSET    0x18208430
      #define ASCEND910_A3_XLOADER_SIZE   4
      #define ASCEND910_A3_XLOADER_OFFSET    0x18208430
      #define ASCEND910_A3_FEATURE_SIZE   4
      #define ASCEND910_A3_FEATURE_OFFSET    0x182085f8
      #define ASCEND310P_2P_BASE         (128 * 1024 * 1024)
      #define ASCEND310P_1P_DEVNUM       1
      #define ASCEND310P_2P_DEVNUM       2
      #define ASCEND310P_XLOADER_SIZE    4
      #define ASCEND310P_XLOADER_OFFSET  0x100430
      #define ASCEND310B_XLOADER_SIZE    4
      #define ASCEND310B_XLOADER_OFFSET  0x4430
      #define ASCEND310_XLOADER_SIZE    4
      #define ASCEND310_XLOADER_OFFSET  0x400
      enum {
          VFIO_ASCEND_TYPE_ERR            = 0,
          VFIO_ASCEND_TYPE_XLOADER        = 1,
          VFIO_ASCEND_TYPE_FEATURE        = 2,
      };
      enum {
          QIURK_READ_SIZE_1_BYTE          = 1,
          QIURK_READ_SIZE_2_BYTE          = 2,
          QIURK_READ_SIZE_4_BYTE          = 4,
      }; 
      typedef struct VFIOAscendBarQuirk {
          struct VFIOPCIDevice *vdev;
          pcibus_t offset;
          unsigned int flags;         /* for normal NC */
          int type;                   /* XLOADER or FEATURE or etc. */
          uint8_t bar;
          MemoryRegion *mem;
      } VFIOAscendBarQuirk;
      static uint64_t vfio_ascend_quirk_read(void *opaque,
                                             hwaddr addr, unsigned size)
      {
          uint64_t value, off_value;
          const unsigned byte_size = 8;
          unsigned start = addr * byte_size, length_size = size * byte_size; 
          VFIOAscendBarQuirk *quirk = opaque;
          VFIOPCIDevice *vdev = quirk->vdev;
          qemu_log("read RO region! addr=0x%" HWADDR_PRIx ", size=%d\n",
                  addr + quirk->offset, size);
          switch (quirk->type) {
              case VFIO_ASCEND_TYPE_XLOADER:
                  value = vfio_region_read(&vdev->bars[quirk->bar].region,
                                           addr + quirk->offset, size);
                  break;
              case VFIO_ASCEND_TYPE_FEATURE:
                  switch (size) {
                      case QIURK_READ_SIZE_1_BYTE:
                      case QIURK_READ_SIZE_2_BYTE:
                      case QIURK_READ_SIZE_4_BYTE:
                          off_value = ((uint64_t)quirk->flags >> start) & ((1UL << length_size) - 1);
                          return le64_to_cpu(off_value);
                      default:
                          qemu_log("Ascend quirk unsupported read size, %d bytes\n", size);
                          return 0;
                  }
              default:
                  qemu_log("read RO region error type! addr=0x%" HWADDR_PRIx ", size=%d\n",
                           addr + quirk->offset, size);
                  return 0;
          }
          return value; 
      }
      static void vfio_ascend_quirk_write(void *opaque, hwaddr addr,
                                          uint64_t data, unsigned size)
      {
          VFIOAscendBarQuirk *quirk = opaque;
          qemu_log("modifying RO region is not allowed! addr=0x%"
                  HWADDR_PRIx ", data=0x%" PRIx64 ", size=%d\n",
                  addr + quirk->offset, data, size);
      }
      static unsigned int vfio_ascend_get_region_flags(VFIOPCIDevice *vdev, int nr)
      {
          int ret = 0;
          unsigned int flags;
          VFIODevice *vbasedev = &vdev->vbasedev;
          struct vfio_region_info *reg_info;
       
          ret = vfio_get_region_info(vbasedev, nr, &reg_info);
          if (ret != 0) {
              qemu_log("Ascend failed to get region %d info\n", nr);
              return 0;
          }
          flags = reg_info->flags;
          g_free(reg_info);
       
          return flags;
      }
      static unsigned int vfio_ascend_get_all_regions_flags(VFIOPCIDevice *vdev)
      {
          int i = 0;
          unsigned int flag = 0, flags = 0;
       
          for (i = VFIO_PCI_BAR0_REGION_INDEX; i < VFIO_PCI_ROM_REGION_INDEX; i++) {
              flag = vfio_ascend_get_region_flags(vdev, i);
              if (flag & VFIO_REGION_INFO_FLAG_NORMAL_NC) {
                  flags |= (1 << i);
              }
          }
       
          return flags;
      }
      static void vfio_ascend_set_bar_quirk_array(VFIOAscendBarQuirk *bar_quirk,
                                                  VFIOPCIDevice *vdev, int index,
                                                  pcibus_t offset, unsigned int flags,
                                                  int type, uint8_t bar)
      {
          bar_quirk[index].vdev = vdev;
          bar_quirk[index].offset = offset;
          bar_quirk[index].flags = flags;
          bar_quirk[index].type = type;
          bar_quirk[index].bar = bar;
      } 
      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_ascend910_a2_bar2_quirk(VFIOPCIDevice *vdev, int nr)
      {
          VFIOQuirk *quirk;
          VFIOAscendBarQuirk *bar2_quirk;
       
          if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 2
              || vdev->device_id != PCI_DEVICE_ID_ASCEND910_A2) {
              return;
          }
          quirk = g_malloc0(sizeof(*quirk));
          quirk->nr_mem = 1;
          quirk->mem = g_new0(MemoryRegion, quirk->nr_mem);
          bar2_quirk = quirk->data = g_new0(typeof(*bar2_quirk), quirk->nr_mem);
          bar2_quirk[0].vdev = vdev;
          bar2_quirk[0].offset = ASCEND910_A2_XLOADER_OFFSET;
          bar2_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,
                                &bar2_quirk[0],
                                "vfio-ascend910_a2-bar2-intercept-regs-quirk",
                                ASCEND910_A2_XLOADER_SIZE);
          memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
                                              bar2_quirk[0].offset,
                                              &quirk->mem[0], 1);
          QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
      }
      static void vfio_probe_ascend910_a3_bar2_quirk(VFIOPCIDevice *vdev, int nr)
       {
           VFIOQuirk *quirk;
           VFIOAscendBarQuirk *bar2_quirk;
            const int quirk_region_num = 2; /* XLOADER and FEATURE */
           if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 2
               || vdev->device_id != PCI_DEVICE_ID_ASCEND910_A3) {
               return;
           }
           quirk = vfio_quirk_alloc(quirk_region_num);  
           bar2_quirk = quirk->data = g_new0(typeof(*bar2_quirk), quirk->nr_mem);
           vfio_ascend_set_bar_quirk_array(bar2_quirk, vdev, 0, ASCEND910_A3_XLOADER_OFFSET,
                                          0, VFIO_ASCEND_TYPE_XLOADER, 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,
                                 &bar2_quirk[0],
                                 "vfio-ascend910_a3-bar2-intercept-regs-quirk",
                                 ASCEND910_A3_XLOADER_SIZE);
           memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
                                               bar2_quirk[0].offset,
                                               &quirk->mem[0], 1);
          /* 910_A3 FEATURE */
          vfio_ascend_set_bar_quirk_array(bar2_quirk, vdev, 1, ASCEND910_A3_FEATURE_OFFSET,
                                          vfio_ascend_get_all_regions_flags(vdev),
                                          VFIO_ASCEND_TYPE_FEATURE, nr);
          memory_region_init_io(&quirk->mem[1], OBJECT(vdev),
                                &vfio_ascend_intercept_regs_quirk,
                                &bar2_quirk[1],
                                "vfio-ascend910_a3-bar2-feature-regs-quirk",
                                ASCEND910_A3_FEATURE_SIZE);
          memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
                                              bar2_quirk[1].offset,
                                              &quirk->mem[1], 1);
           QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
       }
      static void vfio_probe_ascend910_bar0_quirk(VFIOPCIDevice *vdev, int nr)
      {
          VFIOQuirk *quirk;
          VFIOAscendBarQuirk *bar0_quirk;
          if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 0 ||
              vdev->device_id != PCI_DEVICE_ID_ASCEND910) {
              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-ascend910-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_ascend310p_bar2_quirk(VFIOPCIDevice *vdev, int nr)
      {
          VFIOQuirk *quirk;
          VFIOAscendBarQuirk *bar2_quirk;
          int sub_device_id;
          int devnum = 0;
          if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 2 ||
              vdev->device_id != PCI_DEVICE_ID_ASCEND310P) {
              return;
          }
          sub_device_id = pci_get_word(vdev->pdev.config + PCI_SUBSYSTEM_ID);
          if (sub_device_id >= PCI_SUB_DEVICE_ID_ASCEND310P_1P_MIN &&
              sub_device_id <= PCI_SUB_DEVICE_ID_ASCEND310P_1P_MAX) {
              devnum = ASCEND310P_1P_DEVNUM;
          } else if (sub_device_id >= PCI_SUB_DEVICE_ID_ASCEND310P_2P_MIN &&
                     sub_device_id <= PCI_SUB_DEVICE_ID_ASCEND310P_2P_MAX) {
              devnum = ASCEND310P_2P_DEVNUM;
          }
          if (devnum != ASCEND310P_1P_DEVNUM && devnum != ASCEND310P_2P_DEVNUM) {
              return;
          }
          quirk = g_malloc0(sizeof(*quirk));
          quirk->nr_mem = devnum;
          quirk->mem = g_new0(MemoryRegion, quirk->nr_mem);
          bar2_quirk = quirk->data = g_new0(typeof(*bar2_quirk), quirk->nr_mem);
          bar2_quirk[0].vdev = vdev;
          bar2_quirk[0].offset = ASCEND310P_XLOADER_OFFSET;
          bar2_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,
                                &bar2_quirk[0],
                                "vfio-ascend310p-bar2-1p-intercept-regs-quirk",
                                ASCEND310P_XLOADER_SIZE);
          memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
                                              bar2_quirk[0].offset,
                                              &quirk->mem[0], 1);
          if (devnum == ASCEND310P_2P_DEVNUM) {
              bar2_quirk[1].vdev = vdev;
              bar2_quirk[1].offset = (ASCEND310P_2P_BASE + ASCEND310P_XLOADER_OFFSET);
              bar2_quirk[1].bar = nr;
              memory_region_init_io(&quirk->mem[1], OBJECT(vdev),
                                    &vfio_ascend_intercept_regs_quirk,
                                    &bar2_quirk[1],
                                    "vfio-ascend310p-bar2-2p-intercept-regs-quirk",
                                    ASCEND310P_XLOADER_SIZE);
              memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
                                                  bar2_quirk[1].offset,
                                                  &quirk->mem[1], 1);
          }
          QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
      }
      static void vfio_probe_ascend310b_bar2_quirk(VFIOPCIDevice *vdev, int nr)
      {
          VFIOQuirk *quirk;
          VFIOAscendBarQuirk *bar2_quirk;
       
          if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 2
              || vdev->device_id != PCI_DEVICE_ID_ASCEND310B) {
              return;
          }
       
          quirk = g_malloc0(sizeof(*quirk));
          quirk->nr_mem = 1;
          quirk->mem = g_new0(MemoryRegion, quirk->nr_mem);
          bar2_quirk = quirk->data = g_new0(typeof(*bar2_quirk), quirk->nr_mem);
          bar2_quirk[0].vdev = vdev;
          bar2_quirk[0].offset = ASCEND310B_XLOADER_OFFSET;
          bar2_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,
                                &bar2_quirk[0],
                                "vfio-ascend310b-bar2-intercept-regs-quirk",
                                ASCEND310B_XLOADER_SIZE);
          memory_region_add_subregion_overlap(vdev->bars[nr].region.mem,
                                              bar2_quirk[0].offset,
                                              &quirk->mem[0], 1);
          QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
      }
      static void vfio_probe_ascend310_bar4_quirk(VFIOPCIDevice *vdev, int nr)
      {
          VFIOQuirk *quirk;
          VFIOAscendBarQuirk *bar4_quirk;
          if (vdev->vendor_id != PCI_VENDOR_ID_HUAWEI || nr != 4 ||
              vdev->device_id != PCI_DEVICE_ID_ASCEND310) {
              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-ascend310-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);
      }
      // ascend-patch end
    2. 修改vfio_bar_quirk_setup函数,增加如下加粗字体标注的代码并保存。
      void vfio_bar_quirk_setup(VFIOPCIDevice *vdev, int nr)
      {
          vfio_probe_ati_bar4_quirk(vdev, nr);
          vfio_probe_ati_bar2_quirk(vdev, nr);
          vfio_probe_nvidia_bar5_quirk(vdev, nr);
          vfio_probe_nvidia_bar0_quirk(vdev, nr);
       
          // ascend-patch begin
          vfio_probe_ascend910_a2_bar2_quirk(vdev, nr);
          vfio_probe_ascend910_a3_bar2_quirk(vdev, nr);
          vfio_probe_ascend910_bar0_quirk(vdev, nr);
          vfio_probe_ascend310p_bar2_quirk(vdev, nr);
          vfio_probe_ascend310b_bar2_quirk(vdev, nr);
          vfio_probe_ascend310_bar4_quirk(vdev, nr);
          // ascend-patch end
       
      #ifdef CONFIG_VFIO_IGD
          vfio_probe_igd_bar4_quirk(vdev, nr);
      #endif
      }…
    3. 执行如下命令,修改配置文件“./linux-headers/linux/vfio.h”中的vfio_region_info结构体。

      vi ./linux-headers/linux/vfio.h

      增加如下加粗字体标注的代码并保存。

      struct vfio_region_info {
          __u32   argsz;
          __u32   flags;
      #define VFIO_REGION_INFO_FLAG_READ (1 << 0) /* Region supports read */
      #define VFIO_REGION_INFO_FLAG_WRITE (1 << 1) /* Region supports write */
      #define VFIO_REGION_INFO_FLAG_MMAP (1 << 2) /* Region supports mmap */
      #define VFIO_REGION_INFO_FLAG_CAPS (1 << 3) /* Info supports caps */
      #define VFIO_REGION_INFO_FLAG_NORMAL_NC (1 << 4) /* Region supports normal NC */
          __u32   index;       /* Region index */
          __u32   cap_offset;  /* Offset within info struct of first cap */
          __u64   size;       /* Region size (bytes) */
          __u64   offset;      /* Region offset from start of device fd */
      };
    4. 执行如下命令,修改“virt.c”文件。

      vi ./hw/arm/virt.c

      修改extended_memmap数组定义,加粗字体由512修改至2048后保存。

      static MemMapEntry extended_memmap[] = {
          /* Additional 64 MB redist region (can contain up to 512 redistributors) */
          [VIRT_HIGH_GIC_REDIST2] =   { 0x0, 64 * MiB },
          [VIRT_HIGH_PCIE_ECAM] =     { 0x0, 256 * MiB },
          /* Second PCIe window */
          [VIRT_HIGH_PCIE_MMIO] =     { 0x0, 2048 * GiB },

  8. 执行如下命令,配置QEMU的构建环境和构建参数。

    ./configure --enable-kvm --enable-numa

  9. 执行如下命令,启动构建。

    make -j 64

  10. 执行如下命令,安装QEMU。

    make install

  11. 打开并修改/etc/libvirt/qemu.conf配置文件。

    修改虚拟机msix中断个数,如下加粗字体标注的内容。

    #max_processes = 0
    max_files = 8192

  12. 检查QEMU版本。

    1. 执行如下命令,重启libvirtd服务。

      sudo service libvirtd restart

      不同的OS回显信息不同,具体回显信息请以实际环境为准。

      Redirecting to /bin/systemctl restart libvirtd.service
    2. 执行如下命令,查看QEMU版本。

      virsh version

      Compiled against library: libvirt 9.4.0
      Using library: libvirt 9.4.0
      Using API: QEMU 9.4.0
      Running hypervisor: QEMU 8.1.0