1. 程式人生 > >KVM虛擬機器建立功能詳細講解

KVM虛擬機器建立功能詳細講解

一.KVM虛擬機器建立的使用者操作

對於使用者或者管理員來說,虛擬機器的建立有著很多的方法,例如:kvm自帶命令列工

具、使用virsh命令來建立、使用具有圖形介面的virt-manager等等。但是它們底層實現的原理都是一樣的,而且它們基本上都是通過開源的虛擬化庫Libvirt來開發的。下面就講一講三種使用者可以建立虛擬機器的方式。

1.1 利用kvm自帶命令列工具進行建立

kvm常用命令如下:

引數

示例

說明

-hda

-hda /data/windows.img

指定windows.img作為硬碟映象

-cdrom

-cdrom /data/windows.iso

指定windows.iso作為光碟映象

-boot

-boot c

從硬碟啟動

-boot d

從光碟啟動

-m

-m 512

分配512M記憶體給虛擬系統

-vnc

-vnc :0

作為vnc伺服器

-cpu

-cpu ?

列出支援的CPU

-cpu core2duo

指定CPU為core2duo

-smp

-smp 2

指定虛擬機器有2個CPU

-net

-net nic

為虛擬機器網絡卡(預設為tap0)

-net tap

系統分配tap裝置(預設為tap0)1

-net nic -net tap

將虛擬機器的網絡卡eth0連線真機裡的tap0

具體建立一個虛擬機器的步驟如下:

(1)生成硬碟映象檔案

[email protected]:kvm-img create -f rawtest.img 10G

其中“-f raw”指定映象檔案的格式為“raw”,“10G”指定映象檔案大小。

(2)從光碟啟動虛擬機器來安裝作業系統

[email protected]:kvm -boot d -hda test.img-cdrom test.iso -m 512

其中“-boot d”指定虛擬機器從光碟啟動,“-hda test.img”指定硬碟映象的位置,“-cdrom test.iso”指定光碟映象的位置,“-m 512”指定虛擬機器的記憶體為512M。

(3)安裝作業系統後便可直接從硬碟啟動虛擬機器

[email protected]:kvm -boot c -hda test.img-m 512

1.2 利用virsh命令列工具進行建立

1.2.1 virsh工具簡介

Virsh是由一個名叫libvirt的軟體提供的管理工具,提供管理虛擬機器比較高階的能力。Virsh可以管理KVM以及xen等虛擬機器。

下面是virsh的一些常見的命令列選項:

Description

help

打​印​基​本​幫​助​信​息​。​

list

列​出​所​有​客​戶​端​。​

dumpxml

輸​出​客​戶​端​ XML 配​置​文​件​。​

create

從​ XML 配​置​文​件​生​成​客​戶​端​並​啟​動​新​客​戶​端​。​

start

啟​動​未​激​活​的​客​戶​端​。​

destroy

強​制​客​戶​端​停​止​。​

define

為​客​戶​端​輸​出​ XML 配​置​文​件​。​

domid

顯​示​客​戶​端​ ID。​

domuuid

顯​示​客​戶​端​ UUID。​

dominfo

顯​示​客​戶​端​信​息​。​

domname

顯​示​客​戶​端​名​稱​。​

domstate

顯​示​客​戶​端​狀​態​。​

quit

退​出​這​個​互​動​終​端​。​

reboot

重​新​啟​動​客​戶​端​。​

restore

恢​復​以​前​保​存​在​文​件​中​的​客​戶​端​。​

resume

恢​復​暫​停​的​客​戶​端​。​

save

將​客​戶​端​當​前​狀​態​保​存​到​某​個​文​件​中​。​

shutdown

關​閉​某​個​域​。​

suspend

暫​停​客​戶​端​。​

undefine

刪​除​與​客​戶​端​關​聯​的​所​有​文​件​。​

migrate

將​客​戶​端​遷​移​到​另​一​臺​主​機​中​。​

Description

setmem

為​客​戶​端​設​定​分​配​的​內​存​。​

setmaxmem

為​管​理​程​序​設​定​內​存​上​限​。​

setvcpus

修​改​為​客​戶​端​分​配​的​虛​擬​ CPU 數​目​。​

vcpuinfo

顯​示​客​戶​端​的​虛​擬​ CPU 信​息​。​

vcpupin

控​制​客​戶​端​的​虛​擬​ CPU 親​和​性​。​

domblkstat

顯​示​正​在​運​行​的​客​戶​端​的​塊​設​備​統​計​。​

domifstat

顯​示​正​在​運​行​的​客​戶​端​的​網​絡​接​口​統​計​。​

attach-device

使​用​ XML 文​件​中​的​設​備​定​義​在​客​戶​端​中​添​加​設​備​。​

attach-disk

在​客​戶​端​中​附​加​新​磁​盤​設​備​。​

attach-interface

在​客​戶​端​中​附​加​新​網​絡​接​口​。​

detach-device

從​客​戶​端​中​分​離​設​備​,使​用​同​樣​的​ XML 描​述​作​為​命​令​attach-device。​

detach-disk

從​客​戶​端​中​分​離​磁​盤​設​備​。​

detach-interface

從​客​戶​端​中​分​離​網​絡​接​口​。​

Description

version

顯​示​ virsh 版​本​

nodeinfo

有​關​管​理​程​序​的​輸​出​信​息​

1.2.2 virsh命令來建立虛擬機器步驟

(1)生成硬碟映象檔案

[email protected]:kvm-img create -f rawtest.img 10G

(2)編寫xml配置檔案,這一步在1.2.3節具體介紹

(3)建立並執行虛擬機器

[email protected]:virsh create test.xml

其中“test.xml”指定步驟(2)中建立的xml檔案

       這樣一個虛擬機器便建立起來了。

1.2.3 xml配置檔案的編寫

利用virsh工具建立虛擬機器必須編寫xml配置檔案,該檔案指定虛擬機器的各項引數,比如虛擬機器名稱、磁碟映象的位置、記憶體大小、顯示配置等等。下面給出一個簡單的配置檔案的例子。

#test.xml

<domain type='qemu'>

  <name>windowsXP</name>

  <uuid></uuid>

  <memory>500000</memory>

  <currentMemory>500000</currentMemory>

  <vcpu>1</vcpu>

  <os>

    <type arch='i686'machine='pc'>hvm</type>  

    <boot dev='hd'/>

    <boot dev='cdrom'/>

  </os>

  <devices>

    <emulator>/usr/bin/qemu-system-x86_64</emulator>

    <disk type='file' device='cdrom'>

      <sourcefile='/home/turnupthesun/kvm/windowsXP.iso'/>

      <target dev='hdc'/>

      <readonly/>

    </disk>

    <disk type='file' device='disk'>

      <sourcefile='/home/turnupthesun/kvm/windowsXP.img'/>

      <target dev='hda'/>

    </disk>

       <graphicstype='vnc' port='14' listen='127.0.0.1'/>

  </devices>

</domain>

下面介紹其中幾個比較重要的元素及屬性。

(1)<domain>元素的type屬性指定執行域的虛擬機器管理器,針對kvm應當選擇“qemu”。

(2)<name>元素的內容指定域的名字。

(3)<memory>元素和<currentMemory>元素的內容非別指定啟動時為域分配的最大記憶體和實際分配的記憶體。

(4)<os></os>元素之間的內容用來指定作業系統啟動的一些資訊。其中重複的<boot>元素形成了一個啟動順序表,比如例子中先從磁碟啟動,磁碟無法啟動再從光碟啟動。

(5)<disk>元素的device屬性指明不同的裝置,<source>標籤的file屬性指明這些裝置的位置。

1.3 如何通過圖形化介面virt-manager來建立虛擬機器

Virt-manger既虛擬機器管理器,是建立和管理虛擬客戶端的圖形工具。具體的操作步驟為:

①   從控制檯視窗啟動這個工具,從root身份輸入virt-manager命令,點選file選單

的”新建”選項。

②   virt-manager顯示兩種虛擬化方法:Qemu/KVM或者Xen,這裡選擇Qemu/KVM作

為hypervisor。

③  選擇虛擬機器名稱和指定一種安裝方法,通過網路安裝伺服器或者本地CD/DVD驅動包括本地ISO檔案,在此我用本地ISO的安裝方法。

④ 輸入本地ISO檔案路徑和檔名(假設本地ISO的路徑就在根目錄下,名稱為Mini-BT3.6.1.iso)

⑤ 設定虛擬機器使用的記憶體容量和處理器數量。

 ⑥  配置虛擬機器的儲存方法。對於儲存後端有兩種選擇:物理儲存裝置或者使用之前建立的磁碟檔案。如果處於簡單測試,建立檔案作為儲存後端。當建立虛擬磁碟時,預設為10GB。

 ⑦ 網路配置,在這裡選擇NAT方式。

這樣一個虛擬機器就開始啟動起來了,將會出現啟動介面,最後出現虛擬機器中作業系統的介面。

二.libvirt函式庫如何實現虛擬機器建立

2.1 virsh工具”create”命令原始碼  

在libvirt軟體包安裝完成之後,就可以看到libvirt的原始碼,這個原始碼實現了很多的開發虛擬化軟體的使用者介面,也就是開發的API。裡面也實現了工具virsh,這個工具也實現了很多的功能。在/tools下面有一個virsh.c,這個檔案裡面實現virsh的功能,這裡就具體把建立這部分程式碼選取出來。

     /*

 * "create" command

 */

static const vshCmdInfo info_create[] ={

   {"help", N_("create a domain from an XML file")},

   {"desc", N_("Create a domain.")},

   {NULL, NULL}

};

static const vshCmdOptDef opts_create[]= {

   {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containingan XML domain description")},

#ifndef WIN32

   {"console", VSH_OT_BOOL, 0, N_("attach to console after creation")},

#endif

   {"paused", VSH_OT_BOOL, 0, N_("leave the guest pausedafter creation")},

  {"autodestroy", VSH_OT_BOOL, 0, N_("automatically destroythe guest when virsh disconnects")},

   {NULL, 0, 0, NULL}

};

static bool

cmdCreate(vshControl *ctl, const vshCmd*cmd)

{

   virDomainPtr dom;

   const char *from = NULL;

   bool ret = true;

   char *buffer;

#ifndef WIN32

   int console = vshCommandOptBool(cmd, "console");

#endif

   unsigned int flags = VIR_DOMAIN_NONE;

   if (!vshConnectionUsability(ctl, ctl->conn))

       return false;

   if (vshCommandOptString(cmd, "file", &from) <= 0)

       return false;

   if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)

       return false;

   if (vshCommandOptBool(cmd, "paused"))

       flags |= VIR_DOMAIN_START_PAUSED;

   if (vshCommandOptBool(cmd, "autodestroy"))

       flags |= VIR_DOMAIN_START_AUTODESTROY;

   dom = virDomainCreateXML(ctl->conn, buffer, flags);

   VIR_FREE(buffer);

   if (dom != NULL) {

       vshPrint(ctl, _("Domain %s created from %s\n"),

                 virDomainGetName(dom), from);

#ifndef WIN32

       if (console)

           cmdRunConsole(ctl, dom,NULL);

#endif

       virDomainFree(dom);

   } else {

       vshError(ctl, _("Failed to create domain from %s"), from);

       ret = false;

   }

   return ret;

}

程式碼的講解:

  ⑴ typedef struct{

       const char *name;

       const char *data;

     }vshCmdInfo;

  上面這個結構體是關於命令的鍵值對資訊,命令一般包含兩個名稱:命令的名字和命令的描述資訊。

  ⑵ typedef struct{

        const char *name;

        vshCmdOptType type;

        unsigned int flags;

        const char *help;

     }vshCmdOptDef;

  上面這個結構體是關於命令選項的定義,該結構體一般包括四個欄位:選項的名稱,選項型別,標誌,幫助資訊。其中選項型別包括:bool型別,字串型別,整型,字元資料,剩餘的引數。

  ⑶ 在cmdCreate主程式中有一個特別重要的函式:virDomainCreateXML(),這個函式的最初原型是: virDomainPtr virDomainCreateXML (virConnectPtr conn,const char*xmlDesc,unsigned int flags),這個函式是基於一個指定的XML檔案來建立一個虛擬機器,其中conn表示一個指向hypervisor的連線,xmlDesc表示一個XML檔案,flags表示命令選項的標誌。

2.2 通過libvirt建立虛擬機器的關鍵API

通過分析2.1中的virsh原始碼我們可以看出,使用libvirt進行虛擬機器建立要呼叫兩個關鍵的API-- virFileReadAll和virDomainCreateXML,下面分別進行說明。

2.2.1 virFileReadAll

    該函式原型為intvirFileReadAll(const char *path, int maxlen, char **buf),功能是將引數“path”指定路徑的檔案內容讀到一個緩衝區中,並將緩衝區地址記錄在引數“*buf”中,而引數“maxlen”指定檔案的最大長度。利用該API,我們可以將xml配置檔案都到一個緩衝區中,以方便接下來的使用。

2.2.2virDomainCreateXML

該函式原型為virDomainPtr    virDomainCreateXML      (virConnectPtrconn,  const char * xmlDesc,  unsigned int flags),功能是根據引數“xmlDesc”定義的配置方式建立一個域並返回該域的指標。引數“conn”是指向虛擬機器管理器的指標,而通過設定不同的“flags”標誌,可以使建立的域具有不同的屬性。

三. 利用libvirt庫編寫自己的虛擬機器建立程式

Virsh命令用來建立虛擬機器的命令是:virsh create,這個命令主要是從給定的XML檔案生成客戶端並啟動客戶端。

  下面用一個測試例子來說明如何通過virsh命令來建立虛擬機器的。

   具體的操作實踐步驟是:

  1. 首先需要建立虛擬硬碟,為了放置作業系統的地方,命令是:kvm-img create

701.img10G,也就是建立一個大小為10G的虛擬硬碟。

   2.  編寫一個xml檔案,這個檔案裡面包含啟動作業系統的一些特徵,比如:記憶體容量,作業系統位置,虛擬硬碟位置等等,其實有很多的欄位,可以簡寫一個xml檔案,如果有些欄位沒有定義,那麼系統就會預設,下面給出一個xml檔案,命名為701.xml,程式為:

      <domain type='qemu'>

      <name>linux10.0421</name>

      <uuid></uuid>

     <memory>512000</memory>

     <currentMemory>512000</currentMemory>

     <vcpu>1</vcpu>

      <os>

        <type arch='i686' machine='pc'>hvm</type>

        <boot dev='cdrom'/> 

        <boot dev='hd'/>

     </os>

        <devices>

           <emulator>/usr/bin/qemu-system-x86_64</emulator>

           <disk type='file' device='cdrom'>

           <source file='/usr/src/ubuntu-10.04-desktop-i386.iso'/>

        <target dev='hdc'/>

        <readonly/>

      </disk>

        <disk type='file' device='disk'>

         <sourcefile='/var/lib/libvirt/images/701.img'/>

        <target dev='hda'/>

      </disk>

           <graphics type='vnc' port='5901'listen='127.0.0.1'/>

       </devices>

     </domain>

    3.  接著編寫一個c檔案,名稱為701.c這個檔案主要實現的功能就是呼叫這個xml檔案來建立並啟動虛擬機器。這個c程式程式碼為:

     #include<stdio.h>

     #include<stdlib.h>

     #include<memory.h>

     #include<libvirt/libvirt.h>

     const char *from=NULL;

     static virConnectPtr conn=NULL;

     #define VIRSH_MAX_XML_FILE 10*1024*1024

     void closeConn()

     {

         if(conn!=NULL)

         virConnectClose(conn);

     }

     int cmdCreate()

     {

        virDomainPtr dom;

        char *buffer;

        unsigned int flags=VIR_DOMAIN_NONE;

       conn=virConnectOpen("qemu:///system");

        if(conn==NULL)

        {

           fprintf(stderr,"failed to connect tohypervisor/n");

           closeConn();

           return 0;

        }

       if(virFileReadAll(from,VIRSH_MAX_XML_FILE,&buffer)<0)

         return 0;

       dom=virDomainCreateXML(conn,buffer,flags);

        memset(buffer,0,sizeof(buffer));

        if(dom!=NULL){

           fprintf(stdout,"Domain %screated from %s\n",virDomainGetName(dom),from);

           virDomainFree(dom);

       }

      else{

          fprintf(stdout,"Failed to createdomain from %s",from);

        }

      }

       int main(int argc,char *argv[])

       {

         if(argc<2){

         fprintf(stdout,"there are too fewparameters,should has two more parameters!");

       }

      from=*++argv;

      cmdCreate();

      return 0;

      }

    4. 在命令視窗中先執行gcc -lvirt -o 701 701.c  ,然後執行./701 701.xml,就可以看到這個虛擬機器被建立並啟動起來了。

四.KVM核心如何實現底層虛擬機器建立功能

4.1 KVM虛擬機器建立和執行虛擬機器的流程

   開源的Lbvirt庫實現了很多的虛擬化API,這些API的實現還是要靠底層的KVM核心的實現,下面重點講講KVM核心中是如何實現虛擬機器建立和執行功能的作業系統層的實現。

    KVM虛擬機器建立和執行虛擬機器分為使用者態和核心態兩個部分,使用者態主要提供應用程式介面,為虛擬機器建立虛擬機器上下文環境,在libkvm中提供訪問核心字元裝置/dev/kvm的介面;核心態為新增到核心中的字元裝置/dev/kvm,模組載入進核心後,即可進行介面使用者空間呼叫建立虛擬機器。在建立虛擬機器過程中,kvm字元裝置主要為客戶機建立kvm資料結構,建立該虛擬機器的虛擬機器檔案描述符及其相應的資料結構以及建立虛擬機器處理器及其相應的資料結構。kvm建立虛擬機器的流程如下圖:

    根據上圖就可以大致知道虛擬機器建立和執行的流程了。首先申明一個kvm_context_t變數用以描述使用者態虛擬機器上下文資訊,然後呼叫kvm_init()函式初始化虛擬機器上下文資訊;函式kvm_create()建立虛擬機器例項,該函式通過ioctl系統呼叫建立虛擬機器相關的核心資料結構並且返回檔案描述符給使用者態kvm_context_t資料結構;建立完核心虛擬機器資料結構後,再建立核心pit以及mmio等外設模擬裝置,然後呼叫kvm_create_vcpu()函式來建立虛擬處理器,kvm_create_vcpu()函式通過系統呼叫向由vm_fd檔案描述符指向的虛擬檔案呼叫建立虛擬處理器,並將虛擬處理器的檔案描述符返回給使用者態程式,供以後的排程使用;建立完虛擬處理器後,由使用者態的QEMU程式申請客戶機使用者空間,用以載入和執行客戶機程式碼;為了使得客戶虛擬機器正確執行,必須要在核心中為客戶機建立正確的記憶體對映關係,即影子頁表資訊。因此,申請客戶機記憶體地址空間之後,呼叫函式kvm_create_phys_mem()建立客戶機記憶體對映關係,該函式主要通過ioctl系統呼叫向vm_fd指向隊的虛擬檔案呼叫設定核心資料結構中客戶機記憶體對映關係,主要建立影子頁表資訊;當建立好虛擬處理器和影子頁表後,即可讀取客戶機到指定分配的空間中,然後排程虛擬處理器執行。排程虛擬機器的函式為kvm_run(),該函式通過ioctl系統呼叫呼叫由虛擬處理器檔案描述符指向的虛擬檔案排程處理函式kvm_run()排程虛擬處理器的執行,該系統呼叫將虛擬處理器vcpu資訊載入到物理處理器中,通過vm_entry執行進入客戶機執行。在客戶機正常執行期間kvm_run()函式不返回,只有發生以下兩種情況時,函式返回:1,發生了I/O事件,如客戶機發出讀寫I/O的指令;2,產生了客戶機和核心KVM都無法處理的異常。I/O事件處理完畢後,通過重新呼叫KVM_RUN()函式繼續排程客戶機的執行。

4.2 KVM虛擬機器建立和執行虛擬機器的主要函式分析以及流程

    1.函式kvm_init():該函式在使用者態建立一個虛擬機器上下文,用以在使用者態儲存基本的虛擬機器資訊,這個函式是建立虛擬機器的第一個需要呼叫的函式,函式返回一個kvm_context_t結構體。該函式原型的實現在libkvm.c中,該函式原型是:

kvm_context_t kvm_init(struct kvm_callbacks*callbacks,void *opaque);

引數:callbacks為結構體kvm_callbacks變數,該結構體包含指向函式的一組指標,用於在客戶機執行過程中因為I/O事件退出到使用者態的時候處理的回撥函式。引數opaque一般未使用。

    函式執行基本過程:開啟字元裝置dev/kvm,申請虛擬機器上下文變數kvm_context_t空間,初始化上下文的基本資訊:設定fd檔案描述符指向/dev/kvm,禁止虛擬機器檔案描述符vm_fd(-1),設定I/O事件回撥函式結構體,設定IRQ和PIT的標誌位以及記憶體頁面記錄的標誌位。

    使用者態資料結構kvm_context_t用以描述虛擬機器例項的使用者態上下文資訊。在kvm_common.h檔案裡面有kvm_context的結構體定義。

structkvm_context {

    /// Filedescriptor to /dev/kvm

    int fd;

    int vm_fd;

    int vcpu_fd[MAX_VCPUS];

    struct kvm_run *run[MAX_VCPUS];

    /// Callbacks that KVM uses to emulatevarious unvirtualizable functionality

    struct kvm_callbacks *callbacks;

    void *opaque;

    /// A pointer to the memory used as thephysical memory for the guest

    void *physical_memory;

    /// is dirty pages logging enabled for allregions or not

    int dirty_pages_log_all;

    /// memory regions parameters

    struct kvm_memory_regionmem_regions[KVM_MAX_NUM_MEM_REGIONS];

    /// do not create in-kernel irqchip if set

    int no_irqchip_creation;

    /// in-kernel irqchip status

    int irqchip_in_kernel;

};

   各個資料域的解釋為:

int fd :指向核心標準字元裝置/dev/kvm的檔案描述符。

int vm_fd:指向所建立的核心虛擬機器資料結構相關檔案的檔案描述符。

intvcpu_fd[MAX_VCPUS]:指向虛擬機器所有的虛擬處理器的檔案描述符陣列。

struct kvm_run*run[MAX_VCPUS]:指向虛擬機器執行環境上下文的指標陣列。

struct kvm_callbacks*call_backs: 回撥函式結構體指標,該結構體用於處理使用者態I/O事件。

void *opaque:指標(還未弄清楚)

int dirty_page_log_all:設定是否記錄髒頁面的標誌。

int no_ira_creation: 用於設定是否再kernel裡設定irq晶片。

int_irqchip_in_kernel:核心中irqchip的狀態

structkvm_callbacks:該結構體用於在使用者態中處理I/O事件,在KVM中呼叫KVM_QEMU實現,主要包含的資料域為:

int (*inb)(void *opaque, uint16_t addr,uint8_t *data):用於模擬客戶機執行8位的inb指令。

int (*inw)(void *opaque, uint16_t addr,uint16_t *data):用於模擬客戶機執行16位的inw指令。

int (*inl)(void *opaque, uint16_t addr,uint32_t *data):用於模擬客戶機執行32位的inl指令。

int (*outb)(void *opaque, uint16_t addr,uint8_t data):用於模擬客戶機執行8位的outb指令。

int (*outw)(void *opaque, uint16_t addr,uint16_t data):用於模擬客戶機執行16位的outw指令。

int (*outl)(void *opaque, uint16_t addr,uint32_t data):用於模擬客戶機執行32位的outl指令。

int (*mmio_read)(void *opaque, uint64_taddr, uint8_t *data,int len):用於模擬客戶機執行mmio讀指令。

int (*mmio_write)(void *opaque, uint64_taddr, uint8_t *data,int len):用於模擬客戶機執行mmio寫指令。

int (*debug)(void *opaque, void *env,struct kvm_debug_exit_arch *arch_info):使用者客戶機除錯的回撥函式。

int (*halt)(void *opaque, int vcpu):用於客戶機執行halt指令的響應。

int (*shutdown)(void *opaque, void *env):用於客戶機執行shutdown指令的響應。

int (*io_window)(void *opaque):用於獲得客戶機io_windows。

int (*try_push_interrupts)(void *opaque):用於注入中斷的回撥函式。

void (*push_nmi)(void *opaque):用於注入nmi中斷的函式。

void (*post_kvm_run)(void *opaque, void*env);使用者得到kvm執行狀態函式。

int (*pre_kvm_run)(void *opaque, void*env);用於獲得kvm之前執行狀態的函式

int (*tpr_access)(void *opaque, int vcpu,uint64_t rip, int is_write);獲得tpr訪問處理函式

int (*powerpc_dcr_read)(int vcpu, uint32_tdcrn, uint32_t *data);用於powerpc的dcr讀操作

nt (*powerpc_dcr_write)(int vcpu, uint32_tdcrn, uint32_t data);用於powerpc的dcr寫操作

int (*s390_handle_intercept)(kvm_context_tcontext, int vcpu,struct kvm_run *run);用於s390的中斷處理。

int (*s390_handle_reset)(kvm_context_tcontext, int vcpu,struct kvm_run *run);用於s390的重設處理。

}

當客戶機執行I/O事件或者停機操作等事件時,KVM會交給使用者態的QEMU模擬外部I/O事件,呼叫這個結構體指向的相關的函式進行處理。

Struct kvm_run: 用於KVM執行時一些的一些狀態資訊。主要包含的資料域為:

__u8 request_interrupt_window;

__u8 padding1[7];

__u32 exit_reason;

__u8 ready_for_interrupt_injection;

__u8 if_flag;

__u8 padding2[2];

/* in (pre_kvm_run), out (post_kvm_run) */

__u64 cr8;

__u64 apic_base;

union {

/* KVM_EXIT_UNKNOWN */

struct {

__u64 hardware_exit_reason; 記錄退出原因

} hw;

/* KVM_EXIT_FAIL_ENTRY */  客戶機執行過程中執行VM_ENTRY失敗。

struct {

       __u64hardware_entry_failure_reason;

} fail_entry;

/* KVM_EXIT_EXCEPTION */  客戶機因為異常退出

struct {

       __u32exception;

       __u32error_code;

} ex;

/* KVM_EXIT_IO */   客戶機因為IO事件退出。

struct kvm_io {

#define KVM_EXIT_IO_IN  0

#define KVM_EXIT_IO_OUT 1

__u8 direction;

__u8 size; /* bytes */

__u16 port;

__u32 count;

__u64 data_offset; /* relative to kvm_runstart */

} io;

struct {

struct kvm_debug_exit_arch arch;

} debug;

/* KVM_EXIT_MMIO */ 客戶機因為MMIO退出

struct {

__u64 phys_addr;

__u8 data[8];

__u32 len;

__u8 is_write;

} mmio;

/* KVM_EXIT_HYPERCALL */ 客戶機退出的超呼叫引數。

struct {

__u64 nr;

__u64 args[6];

__u64 ret;

__u32 longmode;

__u32 pad;

} hypercall;

              /*KVM_EXIT_TPR_ACCESS */ 客戶機退出訪問TPR引數

struct {

       __u64rip;

       __u32is_write;

       __u32pad;

} tpr_access;

/* KVM_EXIT_S390_SIEIC */  和S390相關資料

struct {

__u8 icptcode;

__u64 mask; /* psw upper half */

__u64 addr; /* psw lower half */

__u16 ipa;

__u32 ipb;

} s390_sieic;

/* KVM_EXIT_S390_RESET */

#define KVM_S390_RESET_POR       1

#define KVM_S390_RESET_CLEAR     2

#define KVM_S390_RESET_SUBSYSTEM 4

#define KVM_S390_RESET_CPU_INIT  8

#define KVM_S390_RESET_IPL       16

__u64 s390_reset_flags;

/* KVM_EXIT_DCR */

struct {

       __u32dcrn;

       __u32data;

       __u8  is_write;

} dcr;

/* Fix the size of the union. */

char padding[256];

2. 函式kvm_create():該函式主要用於建立一個虛擬機器核心環境。該函式原型為:

int kvm_create(kvm_context_t kvm,unsignedlong phys_mem_bytes, void **phys_mem);

引數:kvm_context_t 表示傳遞的使用者態虛擬機器上下文環境,phys_mem_bytes表示需要建立的實體記憶體的大小,phys_mem表示建立虛擬機器的首地址。這個函式首先呼叫kvm_create_vm()分配IRQ並且初始化為0,設定vcpu[0]的值為-1,即不允許排程虛擬機器執行。然後呼叫ioctl系統呼叫ioctl(fd,KVM_CREATE_VM,0)來建立虛擬機器核心資料結構struct kvm。

3. 系統呼叫函式ioctl(fd,KVM_CREATE_VM,0),用於在核心中建立和虛擬機器相關的資料結構。該函式原型為:

Static long kvm_dev_ioctl(struct file *filp,unsigned intioctl, unsignedlong arg);其中ioctl表示命令。這個函式呼叫kvm_dev_ioctl_create_vm()建立虛擬機器例項核心相關資料結構。該函式首先通過核心中kvm_create_vm()函式建立核心中kvm上下文struct kvm,然後通過函式

Anno_inode_getfd(“kvm_vm”,&kvm_vm_fops,kvm,0)返回該虛擬機器的檔案描述符,返回給使用者呼叫函式,由2中描述的函式賦值給使用者態虛擬機器上下文變數中的虛擬機器描述符kvm_vm_fd。

4. 核心建立虛擬機器kvm物件後,接著呼叫kvm_arch_create函式用於建立一些體系結構相關的資訊,主要包括kvm_init_tss、kvm_create_pit以及kvm_init_coalsced_mmio等資訊。然後呼叫kvm_create_phys_mem建立實體記憶體,函式kvm_create_irqchip用於建立核心irq資訊,通過系統呼叫ioctl(kvm->vm_fd,KVM_CREATE_IRQCHIP)。

5,函式kvm_create_vcpu():用於建立虛擬處理器。該函式原型為:

int kvm_create_vcpu(kvm_context_t kvm, intslot);

引數:kvm表示對應使用者態虛擬機器上下文,slot表示需要建立的虛擬處理器的個數。

該函式通過ioctl系統呼叫ioctl(kvm->vm_fd,KVM_CREATE_VCPU,slot)建立屬於該虛擬機器的虛擬處理器。該系統呼叫函式:

Static init kvm_vm_ioctl_create_vcpu(struct*kvm, n) 引數kvm為核心虛擬機器例項資料結構,n為建立的虛擬CPU的數目。

6,函式kvm_create_phys_mem()用於建立虛擬機器記憶體空間,該函式原型:

Void * kvm_create_phys_mem(kvm_context_tkvm,unsigned long phys_start,unsigned len,int log,int writable);

引數:kvm 表示使用者態虛擬機器上下文資訊,phys_start為分配給該虛擬機器的物理起始地址,len表示記憶體大小,log表示是否記錄髒頁面,writable表示該段記憶體對應的頁表是否可寫。

該函式首先申請一個結構體kvm_userspace_memory_region 然後通過系統呼叫KVM_SET_USER_MEMORY_REGION來設定核心中對應的記憶體的屬性。該系統呼叫函式原型:

Ioctl(int kvm->vm_fd,KVM_SET_USER_MEMORY_REGION,&memory);

引數:第一個引數vm_fd為指向核心虛擬機器例項物件的檔案描述符,第二個引數KVM_SET_USER_MEMORY_REGION為系統呼叫命令引數,表示該系統呼叫為建立核心客戶機對映,即影子頁表。第三個引數memory表示指向該虛擬機器的記憶體空間地址。系統呼叫首先通過引數memory通過函式copy_from_user從使用者空間複製struct_user_momory_region 變數,然後通過kvm_vm_ioctl_set_memory_region函式設定核心中對應的記憶體域。該函式原型:

Int kvm_vm_ioctl_set_memory_region(struct*kvm,struct kvm_usersapce_memory_region *mem,int user_alloc);該函式再呼叫函式kvm_set_memory_resgion()設定影子頁表。當這一切都準備完畢後,呼叫kvm_run()函式即可排程執行虛擬處理器。

7,函式kvm_run():用於排程執行虛擬處理器。該函式原型為:

Int kvm_run(kvm_context_t kvm,int vcpu,void *env) 該函式首先得到vcpu的描述符,然後呼叫系統呼叫ioctl(fd,kvm_run,0)排程執行虛擬處理器。Kvm_run函式在正常執行情況下並不返回,除非發生以下事件之一:一是發生了I/O事件,I/O事件由使用者態的QEMU處理;一個是發生了客戶機和KVM都無法處理的異常事件。KVM_RUN()中返回截獲的事件,主要是I/O以及停機等事件。


相關推薦

KVM虛擬機器建立功能詳細講解

一.KVM虛擬機器建立的使用者操作 對於使用者或者管理員來說,虛擬機器的建立有著很多的方法,例如:kvm自帶命令列工 具、使用virsh命令來建立、使用具有圖形介面的virt-manager等等。但是它們底層實現的原理都是一樣的,而且它們基本上都是通過開源的虛擬化庫Libvirt來開發的。下面就講一講三種使

kvm虛擬機器建立:使用qemu-img建立img基礎映象以及增量映象

最近在學習虛擬化方面的知識,也只是剛剛入門階段,這裡把學習的一些筆記貼出來:qcow2和raw區別https://www.ibm.com/developerworks/cn/linux/1409_qiaoly_qemuimgages/建立kvm虛擬機器映象:基礎映象qemu-

虛擬化技術之kvm虛擬機器建立工具qemu-kvm

  在前邊的部落格中我們介紹瞭如何建立kvm虛擬機器,以及一些常用的工具的介紹和使用,今天我們來了解下kvm原始工具qemu-kvm;為什麼說qemu-kvm是一個原始的工具呢,如果你用kvm虛擬機器,心細的你一定會發現我們不管用什麼工具建立kvm虛擬機器,在宿主機上表現的都是一個以/usr/libexec/

雙硬碟(系統盤和資料盤)建立第一臺kvm虛擬機器

一,kvm虛擬機器磁碟規劃 磁碟A:60G,用於安裝作業系統,分割槽方法MBR,boot分割槽300M,swap分割槽2G,剩餘的空間全部作為根分割槽(/),磁碟為lvm+xfs。 磁碟B:200G,用於存放資料,分割槽方法GPT,建立一個分割槽,直接掛載到/dat

單磁碟(根和資料放在不同分割槽)建立第一臺kvm虛擬機器、克隆虛擬機器

一,建立第一臺虛擬機器( 此步是在宿主機系統上進行的操作; 目的是作為克隆虛擬機器的模板): 1,虛擬機器磁碟規劃 磁碟A:大小260G 分割槽規劃,swap分割槽2048M,boot分割槽300M,根分割槽60G(lvm+xfs),資料分割槽(

KVM虛擬機器快照建立與檢視

[[email protected] images]# virsh snapshot-create-as icp pureOS Domain snapshot pureOS created 備註: 建立快照之前最好先關閉虛擬計算機,否則可能失敗。失敗與虛擬機器的

kvm虛擬機器管理(建立、連線)

建立虛機、遠端管理kvm虛機、virsh命令列下管理虛機、、kvm通過virsh console 連入虛擬機器   一、建立虛機 1)開啟虛擬化管理器   2)選擇ISO安裝

Qemu-KVM虛擬機器初始化及建立過程原始碼簡要分析(一)

    我們知道,Qemu-KVM實際上包括Qemu和KVM兩部分,那麼在建立以及初始化虛擬機器時,實際上也是在這兩部分進行的。     KVM實際上就是kvm核心模組,包括kvm.ko、kvm-intel.ko、kvm-amd.ko三部分,後兩部分分別對應Intel體系的

Qemu-KVM虛擬機器初始化及建立過程原始碼簡要分析(二)

    前面我們講了KVM核心層建立及初始化虛擬機器的一些工作過程,現在講一下Qemu層的流程以及與KVM核心層的配合過程。         Qemu層是從vl.c中的main()函式開始的,這裡通過在程式碼中新增一些註釋的方式來進行講解,中間省略了很多不重要或者我也沒有搞

centos7上使用virt-install命令建立kvm虛擬機器

  一、使用virt-install命令建立虛擬機器       virt-install命令既可以互動執行,也可以以自動的方式建立與部署虛擬機器系統,配合kickstart技術可以實現無人值守安裝虛擬機器作業系統。該命令提供了很多選

建立kvm虛擬機器以及搭建openstack平臺

準備環境 (真機) 禁用 selinux 配置檔案 /etc/selinux/config SELINUX=disabled 禁用 firewalld systemctl stop firewalld //關閉防火牆,但當其他應用程式呼叫到防火牆時,會再次啟動防火牆

如何使用 virsh 命令建立、還原和刪除 KVM 虛擬機器快照 | Linux 中國

如果你在使用基於 KVM 的虛擬機器管理程式,那麼可以使用 virsh 命令獲取虛擬機器或域快照

CentOS7環境下建立kvm虛擬機器,搭建橋接環境,並實現用命令列控制虛擬機器

宿主機網路橋接配置我們要求建立的虛擬機器可以和宿主主機共享網段,拓撲圖如下: 圖1而橋接環境的宿主機的網路構架如下: 圖2這是宿主機有兩塊網絡卡的情況下,如果沒有兩塊網絡卡(如上圖沒有eth1)也行,只要把物理網絡卡(eth0)作為對

003.KVM虛擬機器部署-CentOS6.8

一 實驗說明 CentOS 7的KVM虛擬機器推薦使用qcow2磁碟格式,本實驗在KVM中安裝CentOS 6.8 64虛擬機器。 二 命令部署過程 2.1 上傳映象 使用winscp上傳至/data/iso/ 2.2 格式化磁碟 1 virt-install --network bridge=br0

Linux環境下實現多臺kvm虛擬機器之間組成amp架構連線

規劃圖 一、安裝kvm 1、環境準備 安裝之前,需要lscpu看flag是否包含svm或者vmx,該標誌表示cpu是否支援硬體虛擬化,而且需要64位架構,命令:lscpu | egrep 'vmx|lv|svm' 如果用的是vmware,需要開啟 開機後再檢視,模組已經裝入(Cent

KVM虛擬機器IO處理過程(二) ----QEMU/KVM I/O 處理過程

接著KVM虛擬機器IO處理過程中Guest Vm IO處理過程(http://blog.csdn.net/dashulu/article/details/16820281),本篇文章主要描述IO從guest vm跳轉到kvm和qemu後的處理過程.     首先回顧一下kvm

KVM虛擬機器IO處理過程(一) ----Guest VM I/O 處理過程

   虛擬化技術主要包含三部分內容:CPU虛擬化,記憶體虛擬化,裝置虛擬化.本系列文章主要描述磁碟裝置的虛擬化過程,包含了一個讀操作的I/O請求如何從Guest Vm到其最終被處理的整個過程.本系列文章中引用到的linux核心程式碼版本為3.7.10,使用的虛擬化平臺是KVM,q

在linux上基於KVM虛擬機器搭建lamp

1.準備網路拓撲圖實現基於KVM的虛擬化,需要三臺kvm虛擬機器,分別安裝mysql,php-fpm,httpd,其次,需要在安裝php-fpm上安裝php-mysql,用來使php能夠連線上mysql資料庫,同時需要兩個虛擬網橋,以及一個物理橋用來保證外部與php-fpm伺服器的連線,同時保證mysql伺服

Kvm虛擬機器上實現amp分機搭建

          Kvm虛擬機器上實現amp分機搭建   ##實驗前提    在搭建之前,我們需要做好一個amp的實驗圖。       如上圖所示,需要上三臺kvm

KVM虛擬機器安裝、管理

一、詳解1、虛擬化產品對比表2、KVM簡介KVM全稱Kernel-based Virtual Machine,翻譯過來是基於核心的虛擬機器,實際它是Linux核心的一個模組。該模組將Linux變為一個Hypervisor,由Quramnet開發,支援x86、s390、Powerpc等CPU。它使用Linux自