在 PPC QEMU 中将访客 RAM 段映射到主机文件

在 PPC QEMU 中将访客 RAM 段映射到主机文件

我的愿望在概念上很简单,我在主机上有一个文件(实际上是来自 /sys/bus/pci/device/.... 的 PCIe 资源文件,但这不是太相关),我希望在来宾中的某个位置可用记忆,以便任何一方的变化都能相互反映。由于我的目标是实际映射主机中有限的 PCIe 地址空间段,因此我无法高效地映射整个来宾 RAM。下面列出了我尝试添加的基本命令。目标是获取映射的内存 id“bar0.ram”某处在客人的记忆中。

qemu-system-ppc -M ppce500 -cpu e500 -m 64M  -d guest_errors,unimp -bios $PWD/test.elf  -s -object memory-backend-file,size=1m,id=bar0.ram,mem-path=/sys/bus/pci/devices/0000\:04\:00.0/resource0,share=on  -monitor telnet:127.0.0.1:4999,server,nowait -nographic

也许这在 ARM 或 x86 上会更容易,但 PPC 不提供持久内存、nvram、由不同文件支持的多个内存插槽或类似的技巧(我可以弄清楚如何开始工作)。它确实提供了 ivshmem,但我无法弄清楚如何将其透明地映射到来宾地址空间。

模糊有用/相关资源:

答案1

我不得不希望这绝对是解决我遇到的问题的错误方法,但它有效:我以愚蠢的方式破解了 QEMU。

在 hw/ppc/e500.c 中,我创建了一个全局变量,当设置该变量时,在初始寄存器内存之后,我根据全局变量中的内容添加了另一个子区域。是的,您看到了我将内存硬编码的地址。

@@ -893,6 +893,8 @@ static void ppce500_power_off(void *opaque, int line, int on)
   }
 }

+MemoryRegion *magicbar0 = NULL;
+
 void ppce500_init(MachineState *machine)
 {
     MemoryRegion *address_space_mem = get_system_memory();
@@ -985,6 +987,12 @@ void ppce500_init(MachineState *machine)

     /* Register Memory */
     memory_region_add_subregion(address_space_mem, 0, machine->ram);
+    {
+        if (magicbar0)
+        {
+            memory_region_add_subregion(address_space_mem, 0x8000000, magicbar0);
+        }
+    }

     dev = qdev_new("e500-ccsr");
     object_property_add_child(OBJECT(machine), "e500-ccsr", OBJECT(dev));

另外,在 softmmu/memory.c 中,我查找了我的魔法区域名称并将其存储到全局变量中。丑陋,是的。在我放弃并使用全局变量之前,我用头敲打 QOM 太久了。

@@ -1618,6 +1618,9 @@ void memory_region_init_ram_from_file(MemoryRegion *mr,
         object_unparent(OBJECT(mr));
         error_propagate(errp, err);
     }
+    extern MemoryRegion *magicbar0;
+    if (!strcmp(name, "bar0.ram"))
+        magicbar0 = mr;
 }

 void memory_region_init_ram_from_fd(MemoryRegion *mr,

我所做的可能是不需要的事情:

  • 我让主机 RAM 覆盖了整个内存范围,包括我试图映射的条形,这样 MMU 和朋友们就能很好地发挥作用。幸运的是,第二个映射能够覆盖该段的第一个映射。
  • 我将分配的 RAM 量增加了一倍——有一次它只使用了一半的内存。
  • 我让客人禁用了数据缓存(无论如何我都尝试过)
  • 这是一个裸机程序,因此我创建了一个全 RAM TLB 缓存,让我可以访问仅部分 RAM 的默认映射之上的地址空间。

我运行的命令包括:

qemu-system-ppc -M ppce500,memory-backend=foo.ram -cpu e500 -m 256M,slots=2,maxmem=1g  -d guest_errors,unimp -bios $PWD/test.elf  -s -object memory-backend-file,size=256m,id=foo.ram,mem-path=$PWD/realmemory,share=on,prealloc=on -object memory-backend-file,size=1m,id=bar0.ram,mem-path=/sys/bus/pci/devices/0000\:04\:00.0/resource0,share=on  -monitor telnet:127.0.0.1:4999,server,nowait -nographic -S

完成所有这些后,使用上面的命令info mtree显示了所需的结果:

0000000000000000-000000000fffffff (prio 0, ram): foo.ram
0000000008000000-00000000080fffff (prio 0, ram): bar0.ram

更好的是,通过处理地址 0x800_0000 处的内存,朋友可以成功地读取和写入主机后面的 PCIe 卡,而无需客户机拥有该卡(或操作系统)的 PCIe 驱动程序。

只是为了记录这一点(我想是为了我自己),我在来宾中使用了以下汇编器来禁用数据缓存:

#define CONFIG_SYS_HID0_FINAL (HID0_ICE | HID0_ABE | HID0_EMCP)
    lis     r3, CONFIG_SYS_HID0_FINAL@h
    ori     r3, r3, CONFIG_SYS_HID0_FINAL@l
    SYNC
    mtspr   SPRN_HID0, r3

我在来宾中使用以下 C 来添加 TLB 条目(是的,硬编码的 ram 大小):

set_tlb(1,
          0x0000000,
          0x0000000,
          MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX,
          0,
          0,
          2,
          BOOKE_PAGESZ_256M,
          0);

对于已经走到这一步的人来说,我想我们都可以希望有人能够提供一个适用于 QEMU API 的答案,而不是我最终所做的事情。

相关内容