Memory Usage in ivshmem¶
ivshmem 處理 shared memory 的原理, 簡單來說就是.
ivshmem 建立了一個 RAM type 的
MemoryRegion
來封裝 host OS 上的 shared memory.ivshmem 將該
MemoryRegion
註冊成自己 PCI device 的 BAR2. QEMU PCI framework 會將所有 PCI device 的 BAR 加入到system_memory
當中, 進行 guest OS memory 的管理.當
MemoryRegion
被加入到system_memory
時, QEMU 就會透過 KVM API 對 guest OS 的記憶體進行對應的操作. 舉例來說操作可能是在 page table 建立 memory mapping 或是為了 trap-and-emulate 而把 page table 的 mapping 刪掉, 這根據MemoryRegion
的 type 決定. ivshmem 這邊的操作則是將 shared memory mapping 到 guest OS 的記憶體.
接下來就個別講解細節.
ivshmem CLI option¶
ivshmem CLI option 包含 shared memory 的路徑跟大小, 這兩個資料會被傳入 IVShmemState 的 class member 當中.
CLI option:
-device ivshmem,shm=hello,size=1
=>IVShmemState
IVShmemState->shmobj = "hello" // shm IVShmemState->sizearg = 1 // size
細節請參考: device parameters
desugar_shm(): create MemoryRegion
¶
Create TYPE_MEMORY_BACKEND_FILE
and MemoryRegion
by IVShmemState->shmobj
.
Assign the MemoryRegion
to IVShmemState->hostmem
.
hostmem = object_new(TYPE_MEMORY_BACKEND_FILE)
hostmem->properties["mem-path"] = "/dev/shm/" + IVShmemState->shmobj
user_creatable_complete(hostmem)
create
MemoryRegion
mmap()
file to QEMU process memory
register MemoryRegion
as PCI BAR2¶
ivshmem 將該 MemoryRegion
註冊成自己 PCI device 的 BAR2.
IVShmemState->ivshmem_bar2 = host_memory_backend_get_memory(IVShmemState->hostmem)
pci_register_bar(PCI_DEVICE(s), 2, attr, IVShmemState->ivshmem_bar2);
Then, we should dig into QEMU PCI framework.
PCI framework¶
QEMU PCI framework 會將所有 PCI device 的 BAR 加入到 system_memory
當中, 進行 guest OS memory 的管理.
pci_register_bar(): 把
MemoryRegion
的資料放到 pci_dev->io_region[bar_num]pci_update_mapping():
更新 pci_dev->io_region[bar_num], 將該
MemoryRegion
加入system_memory
當中 (memory_region_add_subregion()
)memory_region_add_subregion_overlap(r->address_space, r->addr, r->memory, 1); // PCIIORegion* r;
PCI device 使用的 address_space 為何?
PCIIORegion->address_space
is fromPCIBus->address_space_{mem,io}
PCIBus->address_space_mem
is init at PCI Host Bridge start
More: MemoryListener and MemoryRegion transaction, KVMMemoryListener
Details¶
TYPE_MEMORY_BACKEND_FILE:
// user_creatable_complete() create MemoryRegion and do mmap() user_creatable_complete() => host_memory_backend_memory_complete() => file_backend_memory_alloc() => memory_region_init_ram_from_file() // inheritance: TYPE_MEMORY_BACKEND_FILE => TYPE_MEMORY_BACKEND => TYPE_OBJECT [TYPE_MEMORY_BACKEND] UserCreatableClass* ucc->complete = host_memory_backend_memory_complete [TYPE_MEMORY_BACKEND_FILE] HostMemoryBackendClass* bc->alloc = file_backend_memory_alloc host_memory_backend_memory_complete() => bc->alloc() = file_backend_memory_alloc() => memory_region_init_ram_from_file()
pci_{set,get}_{byte,word,…}: pointer dereference with endianness.
struct
PCIDevice
PCIIORegion io_regions[]; // all PCI BAR, each element of array is single PCI BAR
PCIBus bus;
uint8_t* config; // PCI config space. each PCI BAR has some space.
uint8_t* wmask, cmask;
PCIIORegion
pcibus_t addr, size; // MMIO region, addr may equal to PCI_BAR_UNMAPPED;
MemoryRegion memory; // one PCI BAR maps to one QEMU MemoryRegion
MemoryRegion address_space; // one of pci_dev->bus->address_space_{mem,io}
PCIBus
MemoryRegion address_space_io, address_space_mem;
init at PCI Host Bridge (e.g.
i440fx_init()
)
misc: gdb print MemoryRegion linked list:
(gdb) memory_region_p mr->subregions->tqh_first
MemoryRegion 'kvm-apic-msi': size=0/100000, is_ram 0, is_ro 0, hwaddr fee00000, callback addr 0x555555eeae00
(gdb) memory_region_p mr->subregions->tqh_first->subregions_link.tqe_next
MemoryRegion 'ram-above-4g': size=0/40000000, is_ram 0, is_ro 0, hwaddr 100000000, callback addr 0x555555ee6780
(gdb) memory_region_p mr->subregions->tqh_first->subregions_link.tqe_next->subregions_link.tqe_next
MemoryRegion 'ram-below-4g': size=0/c0000000, is_ram 0, is_ro 0, hwaddr 0, callback addr 0x555555ee6780
(gdb) memory_region_p mr->subregions->tqh_first->subregions_link.tqe_next->subregions_link.tqe_next->subregions_link.tqe_next
MemoryRegion 'pci': size=1/0, is_ram 0, is_ro 0, hwaddr 0, callback addr 0x555555ee6780