KVMMemoryListener¶
Interface¶
MemoryRegionSection: 代表一段 memory address range; memory 特性跟指向的 MemoryRegion 一致
memory address (
MemoryRegionSection* section
)gpa start: (hwaddr) section->offset_within_address_space
hva start: (void*) memory_region_get_ram_ptr(section->mr) + section->offset_within_region
size: section->size
MemoryListener API:
MemoryListener->region_add(MemoryListener *listener, MemoryRegionSection *section) MemoryListener->region_del(MemoryListener *listener, MemoryRegionSection *section) 把 section 加入到 guest memory / 從 guest memory 刪除. 以 KVMMemoryListener 為例, 就是透過 KVM API 對 guest OS 加入/刪除 memory page.
KVMMemoryListener 實作
kvm_region_add() / kvm_region_del()
KVM API:
kvm_vm_ioctl(KVM_SET_USER_MEMORY_REGION);
Contents¶
kvm_region_add() / kvm_region_del()
都會轉成kvm_set_phys_mem()
, 用 bool 參數 add 來分辨.kvm_set_phys_mem()
功能: 把 MemoryRegionSection 這段 hwaddr range 加入/刪除到 KVM 的記憶體管理.
前置行為
把 address range 進行 page alignment, 只留中間有 page-aligned 的 memory (小於 page size 則直接消失)
如果是非 ram 的 MemoryRegion, 則大部份 MR 會直接取消 mapping 或是從 region_add 轉成 region_del. 具體 condition 請見 source code.
實作方式:
先當成 region_del, 把現有的 KVMSlot 之中, 跟 MemoryRegionSection 有交集的全部取出, 並且砍掉這些交集.
如果是 region_add 的話, 再把該 MemoryRegionSection 轉成 KVMSlot 之後, 加入 KVM 的記憶體管理.
例外: 如果是 region_add, 並且 Section 的 address range 包含於取出的 KVMSlot, 就只更新 KVMSlot 的 flag. 並且函式直接 return
砍掉交集的演算法:
KVMSlot old - MemoryRegionSection new
移除 old 的 KVMSlot
新增兩個 KVMSlot prefix, suffix = ([old.start, new.start], [new.end, old.end])
API
取出交集的 KVMSlot:
kvm_lookup_overlapping_slot()
加入 KVM 的記憶體管理 / 砍掉交集:
kvm_set_user_memory_region()
更新 KVMSlot 的 flag:
kvm_slot_update_flags()
=>kvm_set_user_memory_region()
API detail:
static KVMSlot *kvm_lookup_overlapping_slot: 找出跟 (start_addr, end_addr) overlap 且 start_addr 最小的 KVMSlot, KVMSlot from kml - overlap algor: a->end > b->start && a->start < b->end kvm_slot_update_flags(kml, mem, mr): 從 mr(MemoryRegion) 抽出 kvm_mem_slot 的 flag, 如果需要更新則透過 kvm_set_user_memory_region() 更新.
KVM Memory API wrapper:
kvm_set_user_memory_region(KVMMemoryListener *kml, KVMSlot *slot)
call
kvm_vm_ioctl(KVM_SET_USER_MEMORY_REGION);
struct KVMSlot
tostruct kvm_userspace_memory_region
:int slot | (kml->as_id << 16) => slot hwaddr start_addr => guest_phys_addr (gpa) void* ram => userspace_addr (uaddr) ram_addr_t memory_size => memory_size int flags => flags
KVMSlot
stored in KML: KVMMemoryListener kml; KVMSlot *mem = &kml->slots[i];`
數目(nr_slots init):
s->nr_slots = kvm_check_extension(s, KVM_CAP_NR_MEMSLOTS);
More
開始有 pointer 是 hva, hwaddr 是 gpa 的感覺了.
function path:
kvm_region_add()
=>kvm_set_phy_ram()
=>kvm_set_user_memory_region()
data path:
MemoryRegionSection
=>KVMSlot
=>struct kvm_userspace_memory_region
KVM memory API¶
VM ioctl - KVM_SET_USER_MEMORY_REGION
create, modify, and delete guest physical memory slot. it controls guest physical memory.
slot can be moved, or its flag can be modified. it can’t be resized.
slots may not overlapped in GPA space.
mapping the memory page in HVA to GPA (addrs trans: GPA => HPA)
parameter: struct kvm_userspace_memory_region
guest_phys_addr
is GPA anduserspace_addr
is HVAslot: multi address space
recommand last 21 bits of gpa & uaddr is identical (large page )
example
-
mapping: GPA = 0x80000000, HVA =
mmap()
return value.fails currently.
-
Misc¶
KVM memory¶
mmap VM fd is gpa ??
kvm_vm_ioctl_set_memory_region() => __kvm_set_memory_region()
kvm_memslots, kvm_memory_slot, slot = (as_id, id)
[arm] arch_prepare_memory_region() => unmap_stage2_range(kvm, mem->guest_phys_addr, mem->memory_size);