ゲスト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がありました。幸い、2番目のマッピングはセグメントの最初のマッピングを上書きできます。
  • 私は割り当てられたRAMの量を2倍にしました。ある時点ではメモリの半分だけ使用していました。
  • ゲストにデータキャッシュを無効にしました(とにかく試してみました)。
  • これはベアメタルプログラムなので、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を使って働く答えを誰かが提供できることを望むでしょう。

関連情報