Xen的体系结构

1. BIOS的虚拟化

xen的启动过程,与x86系统一样,首先要进入保护模式,然后安装中断处理程序。

xen的中断处理程序可以分为几种,有的是直接分发给正在运行的操作系统,有的是分发给安装了硬件驱动的Dom0。以时钟中断为例,既要分发给xen本身,用来调度各个Guest系统的运行,又要分发到运行的Guest中,支持Guest内部的程序调度。

 

BIOS的支持

x86系统在启动过程中需要读取BIOS提供的信息,同时也能使用BIOS提供的调用来对硬件进行直接操作。

这种机制,xen不会提供给Guest,因为它破坏了“Isolation”的原则。

因此,xen通过一种start info page来向Guest提供启动所需的有关BIOS的信息。

 

类似的机制还有:

1). shared info page: 用来在Guest运行的时候可以动态地更新共享的数据。

2). XenStore: 用来确定哪些虚拟的设备是可以使用的。

 

xen使用的是虚拟设备,因此对于DomU的虚拟机来说,只需要实现一种需要的driver就好了。

 

2. Xen的特权级处理

Xen在支持4个特权级别的体系结构中,处于0特权级别,操作系统处于1特权级,而应用程序处于3特权级。

在支持2个特权级别的体系结构中,处于0特权级别,而让操作系统和应用程序一同处于1特权级别。

 

总而言之,Xen一定要接管最高的特权级别,而操作系统的代码则不允许像原来一样可以执行所有的指令。

操作系统执行特权指令时,会抛出General Protection异常。

 

xen的处理逻辑是,由Guest操作系统负责保证,它自己不会执行任何特权级0的专属指令,而会将其替换成hypercall,传递给xen,从而保证这些指令都能够被妥善地处理。

 

3. hypercall的实现

在xen 3及以前,hypercall是通过类似于系统调用的方式实现的,系统调用使用的是0x80号中断,而hypercall使用的是0x82号中断。

现在已经用一种新的机制替换了,这就是hypercall page。

hypercall page是映射到操作系统内存空间的一个内存页,Guest操作系统调用这个内存页中的一个地址,就可以完成hypercall的调用。

 

   1: #define _hypercall1(type, name, a1)                    \
   2: ({                                    \
   3:     __HYPERCALL_DECLS;                        \
   4:     __HYPERCALL_1ARG(a1);                        \
   5:     asm volatile (__HYPERCALL                    \
   6:               : __HYPERCALL_1PARAM                \
   7:               : __HYPERCALL_ENTRY(name)                \
   8:               : __HYPERCALL_CLOBBER1);                \
   9:     (type)__res;                            \
  10: })

做一些翻译处理后

   1: #define _hypercall1(type, name, a1)            \        
   2: ({                                    \
   3:     register unsigned long __res  asm("eax");        \
   4:     register unsigned long __arg1 asm("ebx") = __arg1; \
   5:     register unsigned long __arg2 asm("ecx") = __arg2; \
   6:     register unsigned long __arg3 asm("edx") = __arg3; \
   7:     register unsigned long __arg4 asm("esi") = __arg4; \
   8:     register unsigned long __arg5 asm("edi") = __arg5; \
   9:     __arg1 = (unsigned long)(a1);                      \ 
  10:     asm volatile ("call hypercall_page+%c[offset]"     \              
  11:               : "=r" (__res), "+r" (__arg1)            \   
  12:               : [offset] "i" (__HYPERVISOR_##name * sizeof(hypercall_page[0]))            \
  13:               : "memory", "edi", "esi", "edx", "ecx");                \
  14:     (type)__res;                            \
  15: })

比较奇怪的语法为%c[offset],表示的是名为offset的常量,参考http://stackoverflow.com/q/1672900/941650

因为通常一页有4KB大小,

   1: extern struct { char _entry[32]; } hypercall_page[];

而hypercall_page是包含32bytes的结构体,因此4KB可以保存128项hypercall

   1: ENTRY(hypercall_page)
   2:     .skip PAGE_SIZE
posted @ 2014-01-29 14:54  Daniel King  阅读(600)  评论(0编辑  收藏  举报