RAMBlock

对于一个地址空间,我们有了树状的MemoryRegion,有了一维的FlatView,但是还没有讲真正对应的内存在哪里。

在qemu中,这部分的工作交给了RAMBlock。

虚拟机内存的分配流程

按照惯例,我们来看一眼一台虚拟机是如何获得对应的内存的。这个过程有点长,在这里只列出关键的部分。

pc_memory_init()
  memory_region_allocate_system_memory()
    allocate_system_memory_nonnuma()
      memory_region_init_ram_nomigrate()
        memory_region_init_ram_shared_nomigrate()
        {
          mr->ram = true;
          mr->destructor = memory_region_destructor_ram;
          mr->ram_block = qemu_ram_alloc(size, share, mr, errp);
        }

埋得很深,最终还是找到。主要工作还是和MemoryRegion相关,设置了其中几个关键的成员:

  • ram: 表示有内存对应

  • destructor: 释放时的操作

  • ram_block: 这个就是本节要讲的RAMBlock了

ram_list按照空间大小排序的链表

其实到这里已经没啥好多说的了,RAMBlock数据结构就是描述虚拟机在主机上对应的内存空间的。不过呢,在qemu上还用了一个链表把他们连起来。这说明qemu上可以分配不止一个RAMBlock。而且在链表上,他们是按照空间大小排序的。

这部分可以看ram_block_add()函数的注释。

/* Keep the list sorted from biggest to smallest block.  Unlike QTAILQ,
 * QLIST (which has an RCU-friendly variant) does not have insertion at
 * tail, so save the last element in last_block.
 */
RAMBLOCK_FOREACH(block) {
    last_block = block;
    if (block->max_length < new_block->max_length) {
        break;
    }
}

用一张图来让大家增加一些直观印象。

  ram_list (RAMList)
  +------------------------------+
  |dirty_memory[]                |
  |    (unsigned long *)         |
  +------------------------------+
  |blocks                        |
  |    QLIST_HEAD                |
  +------------------------------+
   |
   |     RAMBlock                                     RAMBlock
   |     +---------------------------+                +---------------------------+
   +---> |next                       | -------------> |next                       |
         |    QLIST_ENTRY(RAMBlock)  |                |    QLIST_ENTRY(RAMBlock)  |
         +---------------------------+                +---------------------------+
         |offset                     |                |offset                     |
         |used_length                |                |used_length                |
         |max_length                 |                |max_length                 |
         |    (ram_addr_t)           |                |    (ram_addr_t)           |
         +---------------------------+                +---------------------------+

地址对应关系

有了RAMBlock后,其中关键的一点就是GPA(Guest Physical Address)是如何和HVP(Host Virtual Address)的映射关系就建立了。

我们用一张图来解释。

         RAMBlock                                                     RAMBlock
         +---------------------------+                                +---------------------------+
         |next                       | -----------------------------> |next                       |
         |    QLIST_ENTRY(RAMBlock)  |                                |    QLIST_ENTRY(RAMBlock)  |
         +---------------------------+                                +---------------------------+
         |offset                     |                                |offset                     |
         |used_length                |                                |used_length                |
         |max_length                 |                                |max_length                 |
         |    (ram_addr_t)           |                                |    (ram_addr_t)           |
         +---------------------------+                                +---------------------------+
         |host                       |  virtual address of a ram      |host                       |  
         |    (uint8_t *)            |  in host (mmap)                |    (uint8_t *)            |
         +---------------------------+                                +---------------------------+
         |mr                         |                                |mr                         |
         |    (struct MemoryRegion *)|                                |    (struct MemoryRegion *)|
         +---------------------------+                                +---------------------------+
          |                                                            |
          |                                                            |
          |                                                            |
          |   struct MemoryRegion                                      |   struct MemoryRegion
          +-->+------------------------+                               +-->+------------------------+
              |name                    |                                   |name                    |
              |  (const char *)        |                                   |  (const char *)        |
              +------------------------+                                   +------------------------+
              |addr                    |  physical address in guest        |addr                    |
              |  (hwaddr)              |  (offset in RAMBlock)             |  (hwaddr)              |
              |size                    |                                   |size                    |
              |  (Int128)              |                                   |  (Int128)              |
              +------------------------+                                   +------------------------+

GPA -> HVA 的映射由MemoryRegion->addr到RAMBlock->host完成。

是不是有种明心见性的感觉~

Last updated