我的愿望在概念上很简单,我在主机上有一个文件(实际上是来自 /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 的答案,而不是我最终所做的事情。