Mctrain's Blog

What I learned in IT, as well as thought about life

Xen的内存布局

| Comments

我会在接下来几篇博客里面介绍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
/*
 * Memory layout:
 *  0x0000000000000000 - 0x00007fffffffffff [128TB, 2^47 bytes, PML4:0-255]
 *    Guest-defined use (see below for compatibility mode guests).
 *  0x0000800000000000 - 0xffff7fffffffffff [16EB]
 *    Inaccessible: current arch only supports 48-bit sign-extended VAs.
 *  0xffff800000000000 - 0xffff803fffffffff [256GB, 2^38 bytes, PML4:256]
 *    Read-only machine-to-phys translation table (GUEST ACCESSIBLE).
 *  0xffff804000000000 - 0xffff807fffffffff [256GB, 2^38 bytes, PML4:256]
 *    Reserved for future shared info with the guest OS (GUEST ACCESSIBLE).
 *  0xffff808000000000 - 0xffff80ffffffffff [512GB, 2^39 bytes, PML4:257]
 *    ioremap for PCI mmconfig space
 *  0xffff810000000000 - 0xffff817fffffffff [512GB, 2^39 bytes, PML4:258]
 *    Guest linear page table.
 *  0xffff818000000000 - 0xffff81ffffffffff [512GB, 2^39 bytes, PML4:259]
 *    Shadow linear page table.
 *  0xffff820000000000 - 0xffff827fffffffff [512GB, 2^39 bytes, PML4:260]
 *    Per-domain mappings (e.g., GDT, LDT).
 *  0xffff828000000000 - 0xffff82bfffffffff [256GB, 2^38 bytes, PML4:261]
 *    Machine-to-phys translation table.
 *  0xffff82c000000000 - 0xffff82cfffffffff [64GB,  2^36 bytes, PML4:261]
 *    vmap()/ioremap()/fixmap area.
 *  0xffff82d000000000 - 0xffff82d03fffffff [1GB,   2^30 bytes, PML4:261]
 *    Compatibility machine-to-phys translation table.
 *  0xffff82d040000000 - 0xffff82d07fffffff [1GB,   2^30 bytes, PML4:261]
 *    High read-only compatibility machine-to-phys translation table.
 *  0xffff82d080000000 - 0xffff82d0bfffffff [1GB,   2^30 bytes, PML4:261]
 *    Xen text, static data, bss.
 *  0xffff82d0c0000000 - 0xffff82dffbffffff [61GB - 64MB,       PML4:261]
 *    Reserved for future use.
 *  0xffff82dffc000000 - 0xffff82dfffffffff [64MB,  2^26 bytes, PML4:261]
 *    Super-page information array.
 *  0xffff82e000000000 - 0xffff82ffffffffff [128GB, 2^37 bytes, PML4:261]
 *    Page-frame information array.
 *  0xffff830000000000 - 0xffff87ffffffffff [5TB, 5*2^40 bytes, PML4:262-271]
 *    1:1 direct mapping of all physical memory.
 *  0xffff880000000000 - 0xffffffffffffffff [120TB,             PML4:272-511]
 *    PV: Guest-defined use.
 *  0xffff880000000000 - 0xffffff7fffffffff [119.5TB,           PML4:272-510]
 *    HVM/idle: continuation of 1:1 mapping
 *  0xffffff8000000000 - 0xffffffffffffffff [512GB, 2^39 bytes  PML4:511]
 *    HVM/idle: unused
 *
 * Compatibility guest area layout:
 *  0x0000000000000000 - 0x00000000f57fffff [3928MB,            PML4:0]
 *    Guest-defined use.
 *  0x00000000f5800000 - 0x00000000ffffffff [168MB,             PML4:0]
 *    Read-only machine-to-phys translation table (GUEST ACCESSIBLE).
 *  0x0000000100000000 - 0x0000007fffffffff [508GB,             PML4:0]
 *    Unused.
 *  0x0000008000000000 - 0x000000ffffffffff [512GB, 2^39 bytes, PML4:1]
 *    Hypercall argument translation area.
 *  0x0000010000000000 - 0x00007fffffffffff [127TB, 2^46 bytes, PML4:2-255]
 *    Reserved for future use.
 */

这里有几个比较关键的地址空间(注: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
static inline void *__maddr_to_virt(unsigned long ma)
{
    ASSERT(pfn_to_pdx(ma >> PAGE_SHIFT) < (DIRECTMAP_SIZE >> PAGE_SHIFT));
    return (void *)(DIRECTMAP_VIRT_START +
                    ((ma & ma_va_bottom_mask) |
                     ((ma & ma_top_mask) >> pfn_pdx_hole_shift)));
}

#define maddr_to_virt(ma)   __maddr_to_virt((unsigned long)(ma))

#define __va(x)             (maddr_to_virt(x))

其中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
struct page_info
{
    union {
        struct page_list_entry list;
        paddr_t up;
        struct page_sharing_info *sharing;
    };
    unsigned long count_info;
    union {
        struct {
            unsigned long type_info;
        } inuse;
        struct {
            unsigned long type:5;   /* What kind of shadow is this? */
            unsigned long pinned:1; /* Is the shadow pinned? */
            unsigned long head:1;   /* Is this the first page of the shadow? */
            unsigned long count:25; /* Reference count */
        } sh;
        struct {
            bool_t need_tlbflush;
        } free;
    } u;

    union {
        struct {
            __pdx_t _domain;
        } inuse;
        struct {
            __pdx_t back;
        } sh;
        struct {
            unsigned int order;
        } free;
    } v;

    union {
        u32 tlbflush_timestamp;
        struct {
            u16 nr_validated_ptes;
            s8 partial_pte;
        };
        u32 shadow_flags;
        __pdx_t next_shadow;
    };
};

其中主要记录了该页相关的一些信息,比如它是什么类型(normal page,或者是页表页,或者是free的)?被引用的次数(count_info)?以及和其它page之间的链表关系等。这些信息在相关page被回收或者分配的时候会被用到。

其它的内存映射的具体细节就需要在之后慢慢进行介绍了。

最后我们画一张图,来总体描述一下各个内存地址空间在整个页表中的分布情况:

xen page table

Comments