QEMUのARM Virtマシンのペリフェラルメモリマップは何処を見ればいいんだっけ......とよく忘れるので、パスと見るべきところをメモします。
マシンを定義しているファイルはこれ。
qemu/virt.c at master · qemu/qemu · GitHub
メモリマップは125行目辺り MemMapEntry a15memmap[]
にかかれています。
以下、該当コードを引用します。
static const MemMapEntry a15memmap[] = { /* Space up to 0x8000000 is reserved for a boot ROM */ [VIRT_FLASH] = { 0, 0x08000000 }, [VIRT_CPUPERIPHS] = { 0x08000000, 0x00020000 }, /* GIC distributor and CPU interfaces sit inside the CPU peripheral space */ [VIRT_GIC_DIST] = { 0x08000000, 0x00010000 }, [VIRT_GIC_CPU] = { 0x08010000, 0x00010000 }, [VIRT_GIC_V2M] = { 0x08020000, 0x00001000 }, /* The space in between here is reserved for GICv3 CPU/vCPU/HYP */ [VIRT_GIC_ITS] = { 0x08080000, 0x00020000 }, /* This redistributor space allows up to 2*64kB*123 CPUs */ [VIRT_GIC_REDIST] = { 0x080A0000, 0x00F60000 }, [VIRT_UART] = { 0x09000000, 0x00001000 }, [VIRT_RTC] = { 0x09010000, 0x00001000 }, [VIRT_FW_CFG] = { 0x09020000, 0x00000018 }, [VIRT_GPIO] = { 0x09030000, 0x00001000 }, [VIRT_SECURE_UART] = { 0x09040000, 0x00001000 }, [VIRT_MMIO] = { 0x0a000000, 0x00000200 }, /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */ [VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 }, [VIRT_SECURE_MEM] = { 0x0e000000, 0x01000000 }, [VIRT_PCIE_MMIO] = { 0x10000000, 0x2eff0000 }, [VIRT_PCIE_PIO] = { 0x3eff0000, 0x00010000 }, [VIRT_PCIE_ECAM] = { 0x3f000000, 0x01000000 }, [VIRT_MEM] = { 0x40000000, RAMLIMIT_BYTES }, /* Second PCIe window, 512GB wide at the 512GB boundary */ [VIRT_PCIE_MMIO_HIGH] = { 0x8000000000ULL, 0x8000000000ULL }, };
どのペリフェラルが使われているかはここからはわからないので、memmapの1列目の文字列から探していく必要があります。
例えばUARTなら、VIRT_UARTで検索をすると1422行目あたりに create_uart
関数を呼び出しているところが見つかります。
create_uart(vms, pic, VIRT_UART, sysmem, serial_hds[0]);
この create_uart
関数の定義は644行目あたりにあり、このコードを見ていくと頭の方にペリフェラルの名前が書いてあるので、PL011が使われていることがわかります。
static void create_uart(const VirtMachineState *vms, qemu_irq *pic, int uart, MemoryRegion *mem, Chardev *chr) { char *nodename; hwaddr base = vms->memmap[uart].base; hwaddr size = vms->memmap[uart].size; int irq = vms->irqmap[uart]; const char compat[] = "arm,pl011\0arm,primecell";
後はペリフェラルの資料を探して読んでドライバを実装すればOKです。
おしまい。