게스트 RAM 세그먼트를 PPC QEMU의 호스트 파일에 매핑

게스트 RAM 세그먼트를 PPC QEMU의 호스트 파일에 매핑

제 바람은 개념적으로 간단합니다. 게스트에 원하는 파일이 호스트에 있습니다(실제로는 /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,

내가 한 일은 아마도 불필요했을 것입니다.

  • MMU와 친구들이 원활하게 작동할 수 있도록 매핑하려는 막대를 포함하여 전체 메모리 범위를 포괄하는 호스트 RAM이 있었습니다. 다행히 두 번째 매핑은 세그먼트의 첫 번째 매핑을 덮어쓸 수 있습니다.
  • 나는 할당된 RAM의 양을 두 배로 늘렸습니다. 어느 시점에서는 메모리의 절반만 사용하고 있었습니다.
  • 게스트에게 데이터 캐싱을 비활성화하도록 했습니다(어쨌든 시도해 보았습니다).
  • 이것은 베어 메탈 프로그램이므로 RAM 일부의 기본 매핑 위의 주소 공간에 대한 액세스를 제공하는 전체 RAM TLB 캐시를 만들었습니다.

내가 실행한 명령은 다음과 같습니다.

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

TLB 항목(예, 하드코딩된 RAM 크기)을 추가하기 위해 게스트에서 다음 C를 사용하고 있습니다.

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를 사용하여 작동하는 답변을 누군가 제공할 수 있기를 바랄 것입니다.

관련 정보