我会在接下来几篇博客里面介绍Xen的memory。这些都是我在看了各种资料,并且研究了Xen的代码之后的个人总结。之所以写这个系列,是感觉现在网络上没有什么比较具体介绍Xen内存的资料,这里有一个,但是是比较老的版本,而且主要介绍的是32位的系统。而我现在看的是Xen最新的版本(4.6),然后介绍的主要是64位的系统,希望能把自己花时间学到的东西分享出去。如果有什么错误的,或者解释的不清楚的地方,也希望各位指出来,共同讨论。
我应该会从五个方面来介绍Xen的内存:
现在我也还在研究中,所以这些应该会随着我自己学习的深入慢慢的进行整理。
好啦,不说废话了,直接进入这篇博客的主题:Xen内存布局的总体概览。
一般情况下我们讨论一个虚拟化系统中的内存,我们主要考虑的是客户虚拟机的内存机制,所以我们会提到shadow page table(影子页表),或者硬件内存虚拟化机制EPT(for Intel)/NPT(for AMD)等。然而这些其实都是针对于客户虚拟机来说的,也就是说对于客户虚拟机来说,它所看到的内存是怎么样的。但是如果我们从Xen本身的角度来考虑的话,Xen所看到的内存又是怎么样的呢?另外,对于整个系统来说,它的内存又是如何分布的呢?
首先我们要搞清楚几个概念:
第一,Xen有一个自己的页表,它是Xen的虚拟地址到物理地址的映射,这也是我们今天主要介绍的内容;
第二,客户虚拟机也有一个自己的页表,但是这个页表是关于客户虚拟机客户虚拟地址到客户物理地址的映射,Xen帮其维护了一个客户物理地址到机器物理地址的映射,这个会在之后的系列进行详细介绍;
第三,特权级虚拟机(即Domain-0)的内存管理和普通的客户虚拟机的内存管理不同。这也会在之后进行介绍。
好了,大致了解了上述几个概念,我们开始介绍Xen的虚拟内存布局。换句话说,在Xen的内存实现中,不同的虚拟地址范围对应的都是什么物理地址?在第一点里提到的Xen的那个页表到底是如何对虚拟内存进行映射的?
在Xen源码的xen/include/asm-x86/config.h
文件中描述了该映射:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
|
这里有几个比较关键的地址空间(注:PML4:M-N表示该地址空间占用了第四级页表的第M到第N项):
0x0000000000000000 - 0x00007fffffffffff [128TB, PML4:0-255]
是为客户虚拟机准备的虚拟地址空间,这个会在之后的系列里面讨论,我现在也还不是很清楚它们是如何被使用的。0xffff800000000000 - 0xffff803fffffffff [256GB, PML4:256]
是客户虚拟机只读的machine-to-physical table(MPT),MPT会在介绍客户虚拟机的时候进行介绍,现在只需要知道它是记录了HPA到GPA的映射的表。0xffff804000000000 - 0xffff807fffffffff [256GB, PML4:256]
是Xen和虚拟机共享shared info信息的内存地址,shared info会在虚拟机启动的时候进行介绍,其主要是一些Xen需要让客户虚拟机启动时用到的一些信息。0xffff810000000000 - 0xffff817fffffffff [512GB, PML4:258]
记录了每个客户虚拟机的page table,这个在客户虚拟机部分进行介绍,现在暂时还不清楚是用来干嘛的。0xffff818000000000 - 0xffff81ffffffffff [512GB, PML4:259]
记录shadow page table的信息。0xffff820000000000 - 0xffff827fffffffff [512GB, PML4:260]
这是记录每个虚拟机的(per-domain mapping)一些相关信息,包括一些GDT,LDT之类的,也是在之后客户虚拟机部分进行介绍。0xffff828000000000 - 0xffff82bfffffffff [256GB, PML4:261]
这个也是MPT,但是客户虚拟机不可访问,现在我还不太清楚具体是做什么的,我猜它应该是P2M。0xffff82c000000000 - 0xffff82cfffffffff [64GB, PML4:261]
用于vmap()/ioremap()/fixmap,现在还不清楚是做什么的。0xffff82d080000000 - 0xffff82d0bfffffff [1GB, PML4:261]
这个最重要,映射了Xen的code和data,还包括bss之类的。这也是在Xen启动的时候会被最早映射到物理内存中的内容。0xffff82dffc000000 - 0xffff82dfffffffff [64MB, PML4:261]
这个用于记录一些superpage相关的信息。0xffff82e000000000 - 0xffff82ffffffffff [128GB, PML4:261]
这个也非常关键,Xen会为每个物理页都生成一个page frame的数据结构,里面记录了每个物理页相关的信息。0xffff830000000000 - 0xffff87ffffffffff [5TB, PML4:262-271]
这个是一个一对一的直接映射,即每一个物理地址都会在这个地址空间中找到一个相应的虚拟地址的映射。在Xen的代码里面__va()
这个宏就是对应了这个地址空间中的某个地址。0xffff880000000000 - 0xffffffffffffffff [120TB, PML4:272-511]
用于PV的客户虚拟机,这个之后介绍,现在也不清楚要如何用。0xffff880000000000 - 0xffffff7fffffffff [119.5TB, PML4:272-510]
用于HVM客户虚拟机。当然还有一些其它的,现在我也还暂时不清楚到底是用来做什么的,先在这里列出来吧:
0xffff808000000000 - 0xffff80ffffffffff [512GB, PML4:257]
用于ioremap for PCI mmconfig space。0xffff82d000000000 - 0xffff82d03fffffff [1GB, PML4:261]
又是一个MPT,叫做Compatibility MPT,现在不清楚是做什么的。0xffff82d040000000 - 0xffff82d07fffffff [1GB, PML4:261]
又是一个MPT,叫做High read-only compatibility MPT。这里有几个点需要强调一下:
首先,上面所说的这个内存分布状况会被反映在Xen的页表中,同时某些信息也会被映射在虚拟机的内存空间中,至于有哪些我们在之后的系列慢慢介绍。
另外,所有虚拟内存到物理内存的映射都会在[PML4:262-271]
,也就是direct map那里反映出来,如果我们看__va()
的实现:
1 2 3 4 5 6 7 8 9 10 11 |
|
其中DIRECTMAP_VIRT_START
就是direct map虚拟地址的首地址:0xffff830000000000
。
另外,对于page frame,也即前面提到的,Xen会为每一个物理页生成一个对应的page_info数据结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
|
其中主要记录了该页相关的一些信息,比如它是什么类型(normal page,或者是页表页,或者是free的)?被引用的次数(count_info)?以及和其它page之间的链表关系等。这些信息在相关page被回收或者分配的时候会被用到。
其它的内存映射的具体细节就需要在之后慢慢进行介绍了。
最后我们画一张图,来总体描述一下各个内存地址空间在整个页表中的分布情况: