MemoryRegion是qemu中管理内存空间的一个重要数据结构,这里我们就花点时间观察一下它。
初始化 -- memory_region_init
首先想到的是如何初始化这个数据结构,其中有一个重要的函数入口:memory_region_init。不过如果你打开仔细观察后,这个函数调用了另外两个函数进行初始化:
后者比较明显,而前者则隐藏在TYPE_MEMORY_REGION类型的实例化函数中。
但是总的来讲也没有做什么太多工作,无非是初始化了一些重要的成员:
用一个简单的图来展示一下:
struct MemoryRegion
+------------------------+
|name |
| (const char *) |
+------------------------+
|ops |
| (MemoryRegionOps *) |
+------------------------+
|addr |
| (hwaddr) |
|size |
| (Int128) |
+------------------------+
|subregions |
| QTAILQ_HEAD() |
+------------------------+
一棵树 -- memory_region_add_subregion
细心的朋友在上面这张图中可能已经发现了,在这个数据结构的末尾我列出了另一个重要的成员变量subregions。从字面上就看出一个MemoryRegion可带有多个subregions。
这个过程是通过memory_region_add_subregion()函数实现的,这个过程很简单,运行后的结果如下:
struct MemoryRegion
+------------------------+
|name |
| (const char *) |
+------------------------+
|addr |
| (hwaddr) |
|size |
| (Int128) |
+------------------------+
|subregions |
| QTAILQ_HEAD() |
+------------------------+
|
|
----+-------------------+---------------------+----
| |
| |
| |
struct MemoryRegion struct MemoryRegion
+------------------------+ +------------------------+
|name | |name |
| (const char *) | | (const char *) |
+------------------------+ +------------------------+
|addr | |addr |
| (hwaddr) | | (hwaddr) |
|size | |size |
| (Int128) | | (Int128) |
+------------------------+ +------------------------+
|subregions | |subregions |
| QTAILQ_HEAD() | | QTAILQ_HEAD() |
+------------------------+ +------------------------+
想起了熟悉的pci树,好久没摸pci了,感慨一下。
内存模拟 -- address_space_rw
好了,该说到重点的重点了。MemoryRegion的存在是为了模拟内存空间,那究竟是怎么做的呢?
还记得刚才说MemoryRegion中有一个成员叫ops么?就是它了。当然最后进行读写的方法有很多,这里只讲其中之一:
address_space_rw()
...
memory_region_dispatch_read()
...
mr->ops->read()
mr->ops->read_with_attrs()
中间需要跳掉一些东西,因为这些数据结构暂时还没有讲到。这里主要是展示MemoryRegion的根本作用是虚拟机和主机之间地址空间的信息交换。