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 to struct 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

    • API doc

    • 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 and userspace_addr is HVA

      • slot: multi address space

      • recommand last 21 bits of gpa & uaddr is identical (large page )

    • example

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);