虚拟化原理之xen-cpu虚拟化

第3章 CPU虚拟化

3.1   xen基本机制和提供的服务

为了实现半虚拟化的目标,VMM必须提供一系列的机制。讨论一下这些机制需要实现的功能:

q 计算机系统启动的时候,需要读BIOS获得机器的内存,硬盘参数等物理信息。在虚拟化的情况下,BIOS是不存在的。所以VMM需要模拟这部分的功能。

q VMM运行在保护模式,而Guest OS也运行在保护模式,需要提供保护模式下的信息共享机制。

q VMM运作在最高优先级(0级),而Guest OS运行在低优先级。这意味着虚拟机的内核不能执行某些特权指令,VMM必须提供执行这些特权指令的接口。

q VMM要通知事件到VM,需要机制实现这种事件机制。

q Linux系统进程之间有通信机制。而虚拟机之间也需要一种安全高效的通信机制。

为实现这些功能,xen提供了一系列的机制来完成这些功能。

3.1.1 启动信息页

启动信息页包含了内核启动所需要的信息。启动信息页是一个start_info的数据结构,定义在/xen/include/public/xen.h文件。启动信息页包括了分配给domain的内存页面数,xen store通信页表的机器页号,保存共享信息页的物理地址等等。

3.1.2 共享信息页

启动信息页在domain启动或者恢复时候才发挥作用,而共享信息页在整个系统运行的过程中都发挥作用。共享信息页的结构shared_info同样在/xen/include/public/xen.h文件中定义。

共享信息页主要是与VCPU和虚拟机状态相关的信息,包括VCPU状态信息,时钟信息和虚拟中断状态信息。共享信息页能够被xenGuest OS访问,因此可以用来在xenGuest OS之间共享信息。

3.1.3 超级调用

超级调用为Guest OS提供了实现特权指令的机制。在linux系统中,内核提供了系统调用功能,这是通过软中断指令(int  80H)实现。超级调用也是通过软中断实现的, 它使用了0x82这个软中断调用号。

3.1.4 事件通道

事件通道提供了xendomain之间的事件通知机制。虚拟机的中断也是通过事件通道方式来实现。事件通道在xen使用非常广泛,domain之间通信,虚拟处理器间中断都是通过事件通道来实现的。

3.1.5 授权表

授权表提供了domain间的共享内存机制。和共享内存不同的是,必须经过共享内存所有者domain的授权才有权访问。这也是授权表名称的由来。

3.1.6 Xen storexen bus

  Xen store类似windows里面的注册表。Xen store存储了各个VM的配置信息,前后端设备的信息,虚拟机状态等等。Xen store是一种高级通信机制,它是基于低级通信机制共享页面和事件通道来实现的。Xen store提供了更高级的操作,它提供了一个具有层次结构的目录,类似linux里面的树形目录。通过xen store可以列出目录,读写值,写入值等等。

  Xen bus可以看做是一条虚拟的总线。<object data="data:application/x-silverlight-2," 它是对具体物理总线的模拟,在后面章节将详细讨论xenbus

3.2 虚拟化数据结构

前文讲到VMM通过VCPU来保证VM之间的隔离,同时通过VCPU来调度虚拟机。VMM定义了一些数据结构来完成这些任务,其中最重要的有四个数据结构。

q Vcpu结构:保存vcpu

q Arch_vcpu结构:

q Vcpu_guest_context:

q Vcpu_info:

3.2.1 VCPU数据结构

VCPU结构保存了vcpu的基本信息,同时有成员指针指向arch_vcpu结构。Vcpu的基本信息包括cpu IDvcpu调度相关信息,vcpu状态信息等。

代码清单2-1  VCPU结构

<object data="data:application/x-silverlight-2," struct vcpu 

{

    int              vcpu_id;

    int              processor;

    vcpu_info_t     *vcpu_info;

    struct domain   *domain;

    struct vcpu     *next_in_list;

    uint64_t         periodic_period;

    uint64_t         periodic_last_event;

    struct timer     periodic_timer;

    struct timer     singleshot_timer;

    struct timer     poll_timer;    /* timeout for SCHEDOP_poll */

    void            *sched_priv;    /* scheduler-specific data */

    struct vcpu_runstate_info runstate;

    /* Has the FPU been initialised? */

    bool_t           fpu_initialised;

    /* Has the FPU been used since it was last saved? */

    bool_t           fpu_dirtied;

    /* Is this VCPU polling any event channels (SCHEDOP_poll)? */

    bool_t           is_polling;

    /* Initialization completed for this VCPU? */

    bool_t           is_initialised;

    /* Currently running on a CPU? */

    bool_t           is_running;

    /* NMI callback pending for this VCPU? */

    bool_t           nmi_pending;

    /* Avoid NMI reentry by allowing NMIs to be masked for short periods. */

    bool_t           nmi_masked;

    /* Require shutdown to be deferred for some asynchronous operation? */

    bool_t           defer_shutdown;

    /* VCPU is paused following shutdown request (d->is_shutting_down)? */

    bool_t           paused_for_shutdown;

    unsigned long    pause_flags;

    atomic_t         pause_count;

    u16              virq_to_evtchn[NR_VIRQS];

    /* Bitmask of CPUs on which this VCPU may run. */

    cpumask_t        cpu_affinity;

    unsigned long    nmi_addr;      /* NMI callback address. */

    /* Bitmask of CPUs which are holding onto this VCPU's state. */

    cpumask_t        vcpu_dirty_cpumask;

    struct arch_vcpu arch;

};

type="application/x-silverlight-2"

每一个domain可以拥有多个VCPU,这些VCPU通过成员next_in_list组成了一个单向链表。通过这个链表,可以遍历一个domain内的所有VCPU

runstate这个成员则是保存VCPU的状态以及在各个状态运行的时间。

代码清单2-2  vcpu运行状态

<object data="data:application/x-silverlight-2," struct vcpu_runstate_info {

    /* VCPU's current state (RUNSTATE_*). */

    int      state;

    /* When was current state entered (system time, ns)? */

    uint64_t state_entry_time;

    /*

     * Time spent in each RUNSTATE_* (ns). The sum of these times is

     * guaranteed not to drift from system time.

     */

    uint64_t time[4];

};type="application/x-silverlight-2"

可以看到,time变量是个四个成员的数组,说明vcpu有四种状态。这四种状态分别是运行态,可运行态,阻塞态和离线态。运行态是vcpu处于运行中,而可运行态说明vcpu已经具备运行的条件,但是还没有分配物理cpu。阻塞态则说明vcpu还需要等待某些资源才能运行。

3.2.2 arch_vcpu

Arch_vcpu结构是跟物理cpu有关的结构,它保存的信息和物理cpu的架构有关。通常包括和vcpu调度有关的函数指针,堆栈信息和上下文切换相关的信息。每种cpu架构都有各自不同的arch_vcpu结构,下文展示x86结构的arch_vcpu结构。

代码清单2-3  Arch_vcpu

<object data="data:application/x-silverlight-2," struct arch_vcpu

{

    /* Needs 16-byte aligment for FXSAVE/FXRSTOR. */

    struct vcpu_guest_context guest_context

    __attribute__((__aligned__(16)));

    struct pae_l3_cache pae_l3_cache;

    unsigned long      flags; /* TF_ */

    void (*schedule_tail) (struct vcpu *);

    void (*ctxt_switch_from) (struct vcpu *);

    void (*ctxt_switch_to) (struct vcpu *);

    /* Bounce information for propagating an exception to guest OS. */

    struct trap_bounce trap_bounce;

    /* I/O-port access bitmap. */

    XEN_GUEST_HANDLE(uint8_t) iobmp; /* Guest kernel virtual address of the bitmap. */

    int iobmp_limit;  /* Number of ports represented in the bitmap.  */

    int iopl;         /* Current IOPL for this VCPU. */

    struct desc_struct int80_desc;

    /* Virtual Machine Extensions */

    struct hvm_vcpu hvm_vcpu;

    l1_pgentry_t *perdomain_ptes;

    pagetable_t guest_table;            /* (MFN) guest notion of cr3 */

    /* guest_table holds a ref to the page, and also a type-count unless

     * shadow refcounts are in use */

    pagetable_t shadow_table[4];        /* (MFN) shadow(s) of guest */

    pagetable_t monitor_table;          /* (MFN) hypervisor PT (for HVM) */

    unsigned long cr3;               /* (MA) value to install in HW CR3 */

    /* Current LDT details. */

    unsigned long shadow_ldt_mapcnt;

    struct paging_vcpu paging;

} __cacheline_aligned;type="application/x-silverlight-2"

这里的guest_context变量保存的就是cpu切换时候的寄存器信息和GDT,LDT等描述符信息。

而函数指针ctxt_switch_from ctxt_switch_to是要在vcpu切换的时候调用,对于xen的半虚拟化和全虚拟化来说,它们的实现也是各自不同的。

shadow_table则保存了和影子页表有关的信息。

 

3.2.3 vcpu_guest_context 

代码清单2-4  vcpu_guest_context

struct vcpu_guest_context {

    /* FPU registers come first so they can be aligned for FXSAVE/FXRSTOR. */

    struct { char x[512]; } fpu_ctxt;       /* User-level FPU registers     */

#define VGCF_I387_VALID                (1<<0)

#define VGCF_IN_KERNEL                 (1<<2)

#define _VGCF_i387_valid               0

#define VGCF_i387_valid                (1<<_VGCF_i387_valid)

#define _VGCF_in_kernel                2

#define VGCF_in_kernel                 (1<<_VGCF_in_kernel)

#define _VGCF_failsafe_disables_events 3

#define VGCF_failsafe_disables_events  (1<<_VGCF_failsafe_disables_events)

#define _VGCF_syscall_disables_events  4

#define VGCF_syscall_disables_events   (1<<_VGCF_syscall_disables_events)

#define _VGCF_online                   5

#define VGCF_online                    (1<<_VGCF_online)

    unsigned long flags;                    /* VGCF_* flags                 */

    struct cpu_user_regs user_regs;         /* User-level CPU registers     */

    struct trap_info trap_ctxt[256];        /* Virtual IDT                  */

    unsigned long ldt_base, ldt_ents;       /* LDT (linear address, # ents) */

    unsigned long gdt_frames[16], gdt_ents; /* GDT (machine frames, # ents) */

    unsigned long kernel_ss, kernel_sp;     /* Virtual TSS (only SS1/SP1)   */

    /* NB. User pagetable on x86/64 is placed in ctrlreg[1]. */

    unsigned long ctrlreg[8];               /* CR0-CR7 (control registers)  */

    unsigned long debugreg[8];              /* DB0-DB7 (debug registers)    */

#ifdef __i386__

    unsigned long event_callback_cs;        /* CS:EIP of event callback     */

    unsigned long event_callback_eip;

    unsigned long failsafe_callback_cs;     /* CS:EIP of failsafe callback  */

    unsigned long failsafe_callback_eip;

#else

    unsigned long event_callback_eip;

    unsigned long failsafe_callback_eip;

#ifdef __XEN__

    union {

        unsigned long syscall_callback_eip;

        struct {

            unsigned int event_callback_cs;    /* compat CS of event cb     */

            unsigned int failsafe_callback_cs; /* compat CS of failsafe cb  */

        };

    };

#else

    unsigned long syscall_callback_eip;

#endif

#endif

    unsigned long vm_assist;                /* VMASST_TYPE_* bitmap */

#ifdef __x86_64__

    /* Segment base addresses. */

    uint64_t      fs_base;

    uint64_t      gs_base_kernel;

    uint64_t      gs_base_user;

#endif

};

struct vcpu_guest_context {

    /* FPU registers come first so they can be aligned for FXSAVE/FXRSTOR. */

    struct { char x[512]; } fpu_ctxt;       /* User-level FPU registers     */

#define VGCF_I387_VALID                (1<<0)

#define VGCF_IN_KERNEL                 (1<<2)

#define _

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值