小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

KVM虛擬機(jī)創(chuàng)建功能詳細(xì)講解

 浪子小新 2016-08-06

一.KVM虛擬機(jī)創(chuàng)建的用戶操作

對(duì)于用戶或者管理員來(lái)說(shuō),虛擬機(jī)的創(chuàng)建有著很多的方法,例如:kvm自帶命令行工

具、使用virsh命令來(lái)創(chuàng)建、使用具有圖形界面的virt-manager等等。但是它們底層實(shí)現(xiàn)的原理都是一樣的,而且它們基本上都是通過(guò)開(kāi)源的虛擬化庫(kù)Libvirt來(lái)開(kāi)發(fā)的。下面就講一講三種用戶可以創(chuàng)建虛擬機(jī)的方式。

1.1 利用kvm自帶命令行工具進(jìn)行創(chuàng)建

kvm常用命令如下:

參數(shù)

示例

說(shuō)明

-hda

-hda /data/windows.img

指定windows.img作為硬盤(pán)鏡像

-cdrom

-cdrom /data/windows.iso

指定windows.iso作為光盤(pán)鏡像

-boot

-boot c

從硬盤(pán)啟動(dòng)

 

-boot d

從光盤(pán)啟動(dòng)

-m

-m 512

分配512M內(nèi)存給虛擬系統(tǒng)

-vnc

-vnc :0

作為vnc服務(wù)器

-cpu

-cpu ?

列出支持的CPU

 

-cpu core2duo

指定CPU為core2duo

-smp

-smp 2

指定虛擬機(jī)有2個(gè)CPU

-net

-net nic

為虛擬機(jī)網(wǎng)卡(默認(rèn)為tap0)

 

-net tap

系統(tǒng)分配tap設(shè)備(默認(rèn)為tap0)1

 

-net nic -net tap

將虛擬機(jī)的網(wǎng)卡eth0連接真機(jī)里的tap0

具體創(chuàng)建一個(gè)虛擬機(jī)的步驟如下:

(1)生成硬盤(pán)鏡像文件

root@host:kvm-img create -f rawtest.img 10G

其中“-f raw”指定鏡像文件的格式為“raw”,“10G”指定鏡像文件大小。

(2)從光盤(pán)啟動(dòng)虛擬機(jī)來(lái)安裝操作系統(tǒng)

root@host:kvm -boot d -hda test.img-cdrom test.iso -m 512

其中“-boot d”指定虛擬機(jī)從光盤(pán)啟動(dòng),“-hda test.img”指定硬盤(pán)鏡像的位置,“-cdrom test.iso”指定光盤(pán)鏡像的位置,“-m 512”指定虛擬機(jī)的內(nèi)存為512M。

(3)安裝操作系統(tǒng)后便可直接從硬盤(pán)啟動(dòng)虛擬機(jī)

root@host:kvm -boot c -hda test.img-m 512

1.2 利用virsh命令行工具進(jìn)行創(chuàng)建

1.2.1 virsh工具簡(jiǎn)介

Virsh是由一個(gè)名叫l(wèi)ibvirt的軟件提供的管理工具,提供管理虛擬機(jī)比較高級(jí)的能力。Virsh可以管理KVM以及xen等虛擬機(jī)。

下面是virsh的一些常見(jiàn)的命令行選項(xiàng):

??

Description

help

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

list

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

dumpxml

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

create

從? XML 配?置?文?件?生?成?客?戶?端?并?啟?動(dòng)?新?客?戶?端?。?

start

啟?動(dòng)?未?激?活?的?客?戶?端?。?

destroy

強(qiáng)?制?客?戶?端?停?止?。?

define

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

domid

顯?示?客?戶?端? ID。?

domuuid

顯?示?客?戶?端? UUID。?

dominfo

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

domname

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

domstate

顯?示?客?戶?端?狀?態(tài)?。?

quit

退?出?這?個(gè)?互?動(dòng)?終?端?。?

reboot

重?新?啟?動(dòng)?客?戶?端?。?

restore

恢?復(fù)?以?前?保?存?在?文?件?中?的?客?戶?端?。?

resume

恢?復(fù)?暫?停?的?客?戶?端?。?

save

將?客?戶?端?當(dāng)?前?狀?態(tài)?保?存?到?某?個(gè)?文?件?中?。?

shutdown

關(guān)?閉?某?個(gè)?域?。?

suspend

暫?停?客?戶?端?。?

undefine

刪?除?與?客?戶?端?關(guān)?聯(lián)?的?所?有?文?件?。?

migrate

將?客?戶?端?遷?移?到?另?一?臺(tái)?主?機(jī)?中?。?

??

Description

setmem

為?客?戶?端?設(shè)?定?分?配?的?內(nèi)?存?。?

setmaxmem

為?管?理?程?序?設(shè)?定?內(nèi)?存?上?限?。?

setvcpus

修?改?為?客?戶?端?分?配?的?虛?擬? CPU 數(shù)?目?。?

vcpuinfo

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

vcpupin

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

domblkstat

顯?示?正?在?運(yùn)?行?的?客?戶?端?的?塊?設(shè)?備?統(tǒng)?計(jì)?。?

domifstat

顯?示?正?在?運(yùn)?行?的?客?戶?端?的?網(wǎng)?絡(luò)?接?口?統(tǒng)?計(jì)?。?

attach-device

使?用? XML 文?件?中?的?設(shè)?備?定?義?在?客?戶?端?中?添?加?設(shè)?備?。?

attach-disk

在?客?戶?端?中?附?加?新?磁?盤(pán)?設(shè)?備?。?

attach-interface

在?客?戶?端?中?附?加?新?網(wǎng)?絡(luò)?接?口?。?

detach-device

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

detach-disk

從?客?戶?端?中?分?離?磁?盤(pán)?設(shè)?備?。?

detach-interface

從?客?戶?端?中?分?離?網(wǎng)?絡(luò)?接?口?。?

??

Description

version

顯?示? virsh 版?本?

nodeinfo

有?關(guān)?管?理?程?序?的?輸?出?信?息?

1.2.2 virsh命令來(lái)創(chuàng)建虛擬機(jī)步驟

(1)生成硬盤(pán)鏡像文件

root@host:kvm-img create -f rawtest.img 10G

(2)編寫(xiě)xml配置文件,這一步在1.2.3節(jié)具體介紹

(3)創(chuàng)建并運(yùn)行虛擬機(jī)

root@host:virsh create test.xml

其中“test.xml”指定步驟(2)中創(chuàng)建的xml文件

       這樣一個(gè)虛擬機(jī)便創(chuàng)建起來(lái)了。

1.2.3 xml配置文件的編寫(xiě)

利用virsh工具創(chuàng)建虛擬機(jī)必須編寫(xiě)xml配置文件,該文件指定虛擬機(jī)的各項(xiàng)參數(shù),比如虛擬機(jī)名稱、磁盤(pán)鏡像的位置、內(nèi)存大小、顯示配置等等。下面給出一個(gè)簡(jiǎn)單的配置文件的例子。

#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>

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

(1)<domain>元素的type屬性指定運(yùn)行域的虛擬機(jī)管理器,針對(duì)kvm應(yīng)當(dāng)選擇“qemu”。

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

(3)<memory>元素和<currentMemory>元素的內(nèi)容非別指定啟動(dòng)時(shí)為域分配的最大內(nèi)存和實(shí)際分配的內(nèi)存。

(4)<os></os>元素之間的內(nèi)容用來(lái)指定操作系統(tǒng)啟動(dòng)的一些信息。其中重復(fù)的<boot>元素形成了一個(gè)啟動(dòng)順序表,比如例子中先從磁盤(pán)啟動(dòng),磁盤(pán)無(wú)法啟動(dòng)再?gòu)墓獗P(pán)啟動(dòng)。

(5)<disk>元素的device屬性指明不同的設(shè)備,<source>標(biāo)簽的file屬性指明這些設(shè)備的位置。

1.3 如何通過(guò)圖形化界面virt-manager來(lái)創(chuàng)建虛擬機(jī)

   Virt-manger既虛擬機(jī)管理器,是創(chuàng)建和管理虛擬客戶端的圖形工具。具體的操作步驟為:

①   從控制臺(tái)窗口啟動(dòng)這個(gè)工具,從root身份輸入virt-manager命令,點(diǎn)擊file菜單

的”新建”選項(xiàng)。

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

為hypervisor。

③  選擇虛擬機(jī)名稱和指定一種安裝方法,通過(guò)網(wǎng)絡(luò)安裝服務(wù)器或者本地CD/DVD驅(qū)動(dòng)包括本地ISO文件,在此我用本地ISO的安裝方法。

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

⑤ 設(shè)置虛擬機(jī)使用的內(nèi)存容量和處理器數(shù)量。

 ⑥  配置虛擬機(jī)的存儲(chǔ)方法。對(duì)于存儲(chǔ)后端有兩種選擇:物理存儲(chǔ)設(shè)備或者使用之前建立的磁盤(pán)文件。如果處于簡(jiǎn)單測(cè)試,創(chuàng)建文件作為存儲(chǔ)后端。當(dāng)創(chuàng)建虛擬磁盤(pán)時(shí),默認(rèn)為10GB。

 ⑦ 網(wǎng)絡(luò)配置,在這里選擇NAT方式。

這樣一個(gè)虛擬機(jī)就開(kāi)始啟動(dòng)起來(lái)了,將會(huì)出現(xiàn)啟動(dòng)界面,最后出現(xiàn)虛擬機(jī)中操作系統(tǒng)的界面。

 

二.libvirt函數(shù)庫(kù)如何實(shí)現(xiàn)虛擬機(jī)創(chuàng)建

2.1 virsh工具”create”命令源碼  

在libvirt軟件包安裝完成之后,就可以看到libvirt的源碼,這個(gè)源碼實(shí)現(xiàn)了很多的開(kāi)發(fā)虛擬化軟件的用戶接口,也就是開(kāi)發(fā)的API。里面也實(shí)現(xiàn)了工具virsh,這個(gè)工具也實(shí)現(xiàn)了很多的功能。在/tools下面有一個(gè)virsh.c,這個(gè)文件里面實(shí)現(xiàn)virsh的功能,這里就具體把創(chuàng)建這部分代碼選取出來(lái)。

     /*

 * "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;

  上面這個(gè)結(jié)構(gòu)體是關(guān)于命令的鍵值對(duì)信息,命令一般包含兩個(gè)名稱:命令的名字和命令的描述信息。

  ⑵ typedef struct{

        const char *name;

        vshCmdOptType type;

        unsigned int flags;

        const char *help;

     }vshCmdOptDef;

  上面這個(gè)結(jié)構(gòu)體是關(guān)于命令選項(xiàng)的定義,該結(jié)構(gòu)體一般包括四個(gè)字段:選項(xiàng)的名稱,選項(xiàng)類型,標(biāo)志,幫助信息。其中選項(xiàng)類型包括:bool類型,字符串類型,整型,字符數(shù)據(jù),剩余的參數(shù)。

  ⑶ 在cmdCreate主程序中有一個(gè)特別重要的函數(shù):virDomainCreateXML(),這個(gè)函數(shù)的最初原型是: virDomainPtr virDomainCreateXML (virConnectPtr conn,const char*xmlDesc,unsigned int flags),這個(gè)函數(shù)是基于一個(gè)指定的XML文件來(lái)創(chuàng)建一個(gè)虛擬機(jī),其中conn表示一個(gè)指向hypervisor的連接,xmlDesc表示一個(gè)XML文件,flags表示命令選項(xiàng)的標(biāo)志。

2.2 通過(guò)libvirt創(chuàng)建虛擬機(jī)的關(guān)鍵API

通過(guò)分析2.1中的virsh源碼我們可以看出,使用libvirt進(jìn)行虛擬機(jī)創(chuàng)建要調(diào)用兩個(gè)關(guān)鍵的API-- virFileReadAll和virDomainCreateXML,下面分別進(jìn)行說(shuō)明。

2.2.1 virFileReadAll

    該函數(shù)原型為intvirFileReadAll(const char *path, int maxlen, char **buf),功能是將參數(shù)“path”指定路徑的文件內(nèi)容讀到一個(gè)緩沖區(qū)中,并將緩沖區(qū)地址記錄在參數(shù)“*buf”中,而參數(shù)“maxlen”指定文件的最大長(zhǎng)度。利用該API,我們可以將xml配置文件都到一個(gè)緩沖區(qū)中,以方便接下來(lái)的使用。

2.2.2virDomainCreateXML

該函數(shù)原型為virDomainPtr    virDomainCreateXML      (virConnectPtrconn,  const char * xmlDesc,  unsigned int flags),功能是根據(jù)參數(shù)“xmlDesc”定義的配置方式創(chuàng)建一個(gè)域并返回該域的指針。參數(shù)“conn”是指向虛擬機(jī)管理器的指針,而通過(guò)設(shè)置不同的“flags”標(biāo)志,可以使創(chuàng)建的域具有不同的屬性。


三. 利用libvirt庫(kù)編寫(xiě)自己的虛擬機(jī)創(chuàng)建程序

   Virsh命令用來(lái)創(chuàng)建虛擬機(jī)的命令是:virsh create,這個(gè)命令主要是從給定的XML文件生成客戶端并啟動(dòng)客戶端。

  下面用一個(gè)測(cè)試?yán)觼?lái)說(shuō)明如何通過(guò)virsh命令來(lái)創(chuàng)建虛擬機(jī)的。

   具體的操作實(shí)踐步驟是:

  1. 首先需要?jiǎng)?chuàng)建虛擬硬盤(pán),為了放置操作系統(tǒng)的地方,命令是:kvm-img create

701.img10G,也就是創(chuàng)建一個(gè)大小為10G的虛擬硬盤(pán)。

   2.  編寫(xiě)一個(gè)xml文件,這個(gè)文件里面包含啟動(dòng)操作系統(tǒng)的一些特征,比如:內(nèi)存容量,操作系統(tǒng)位置,虛擬硬盤(pán)位置等等,其實(shí)有很多的字段,可以簡(jiǎn)寫(xiě)一個(gè)xml文件,如果有些字段沒(méi)有定義,那么系統(tǒng)就會(huì)默認(rèn),下面給出一個(gè)xml文件,命名為701.xml,程序?yàn)椋?/p>

      <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.  接著編寫(xiě)一個(gè)c文件,名稱為701.c這個(gè)文件主要實(shí)現(xiàn)的功能就是調(diào)用這個(gè)xml文件來(lái)創(chuàng)建并啟動(dòng)虛擬機(jī)。這個(gè)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. 在命令窗口中先執(zhí)行g(shù)cc -lvirt -o 701 701.c  ,然后執(zhí)行./701 701.xml,就可以看到這個(gè)虛擬機(jī)被創(chuàng)建并啟動(dòng)起來(lái)了。

 

四.KVM內(nèi)核如何實(shí)現(xiàn)底層虛擬機(jī)創(chuàng)建功能

4.1 KVM虛擬機(jī)創(chuàng)建和運(yùn)行虛擬機(jī)的流程

   開(kāi)源的Lbvirt庫(kù)實(shí)現(xiàn)了很多的虛擬化API,這些API的實(shí)現(xiàn)還是要靠底層的KVM內(nèi)核的實(shí)現(xiàn),下面重點(diǎn)講講KVM內(nèi)核中是如何實(shí)現(xiàn)虛擬機(jī)創(chuàng)建和運(yùn)行功能的操作系統(tǒng)層的實(shí)現(xiàn)。

    KVM虛擬機(jī)創(chuàng)建和運(yùn)行虛擬機(jī)分為用戶態(tài)和核心態(tài)兩個(gè)部分,用戶態(tài)主要提供應(yīng)用程序接口,為虛擬機(jī)創(chuàng)建虛擬機(jī)上下文環(huán)境,在libkvm中提供訪問(wèn)內(nèi)核字符設(shè)備/dev/kvm的接口;內(nèi)核態(tài)為添加到內(nèi)核中的字符設(shè)備/dev/kvm,模塊加載進(jìn)內(nèi)核后,即可進(jìn)行接口用戶空間調(diào)用創(chuàng)建虛擬機(jī)。在創(chuàng)建虛擬機(jī)過(guò)程中,kvm字符設(shè)備主要為客戶機(jī)創(chuàng)建kvm數(shù)據(jù)結(jié)構(gòu),創(chuàng)建該虛擬機(jī)的虛擬機(jī)文件描述符及其相應(yīng)的數(shù)據(jù)結(jié)構(gòu)以及創(chuàng)建虛擬機(jī)處理器及其相應(yīng)的數(shù)據(jù)結(jié)構(gòu)。kvm創(chuàng)建虛擬機(jī)的流程如下圖:

    根據(jù)上圖就可以大致知道虛擬機(jī)創(chuàng)建和運(yùn)行的流程了。首先申明一個(gè)kvm_context_t變量用以描述用戶態(tài)虛擬機(jī)上下文信息,然后調(diào)用kvm_init()函數(shù)初始化虛擬機(jī)上下文信息;函數(shù)kvm_create()創(chuàng)建虛擬機(jī)實(shí)例,該函數(shù)通過(guò)ioctl系統(tǒng)調(diào)用創(chuàng)建虛擬機(jī)相關(guān)的內(nèi)核數(shù)據(jù)結(jié)構(gòu)并且返回文件描述符給用戶態(tài)kvm_context_t數(shù)據(jù)結(jié)構(gòu);創(chuàng)建完內(nèi)核虛擬機(jī)數(shù)據(jù)結(jié)構(gòu)后,再創(chuàng)建內(nèi)核pit以及mmio等外設(shè)模擬設(shè)備,然后調(diào)用kvm_create_vcpu()函數(shù)來(lái)創(chuàng)建虛擬處理器,kvm_create_vcpu()函數(shù)通過(guò)系統(tǒng)調(diào)用向由vm_fd文件描述符指向的虛擬文件調(diào)用創(chuàng)建虛擬處理器,并將虛擬處理器的文件描述符返回給用戶態(tài)程序,供以后的調(diào)度使用;創(chuàng)建完虛擬處理器后,由用戶態(tài)的QEMU程序申請(qǐng)客戶機(jī)用戶空間,用以加載和運(yùn)行客戶機(jī)代碼;為了使得客戶虛擬機(jī)正確執(zhí)行,必須要在內(nèi)核中為客戶機(jī)建立正確的內(nèi)存映射關(guān)系,即影子頁(yè)表信息。因此,申請(qǐng)客戶機(jī)內(nèi)存地址空間之后,調(diào)用函數(shù)kvm_create_phys_mem()創(chuàng)建客戶機(jī)內(nèi)存映射關(guān)系,該函數(shù)主要通過(guò)ioctl系統(tǒng)調(diào)用向vm_fd指向隊(duì)的虛擬文件調(diào)用設(shè)置內(nèi)核數(shù)據(jù)結(jié)構(gòu)中客戶機(jī)內(nèi)存映射關(guān)系,主要建立影子頁(yè)表信息;當(dāng)創(chuàng)建好虛擬處理器和影子頁(yè)表后,即可讀取客戶機(jī)到指定分配的空間中,然后調(diào)度虛擬處理器運(yùn)行。調(diào)度虛擬機(jī)的函數(shù)為kvm_run(),該函數(shù)通過(guò)ioctl系統(tǒng)調(diào)用調(diào)用由虛擬處理器文件描述符指向的虛擬文件調(diào)度處理函數(shù)kvm_run()調(diào)度虛擬處理器的執(zhí)行,該系統(tǒng)調(diào)用將虛擬處理器vcpu信息加載到物理處理器中,通過(guò)vm_entry執(zhí)行進(jìn)入客戶機(jī)執(zhí)行。在客戶機(jī)正常運(yùn)行期間kvm_run()函數(shù)不返回,只有發(fā)生以下兩種情況時(shí),函數(shù)返回:1,發(fā)生了I/O事件,如客戶機(jī)發(fā)出讀寫(xiě)I/O的指令;2,產(chǎn)生了客戶機(jī)和內(nèi)核KVM都無(wú)法處理的異常。I/O事件處理完畢后,通過(guò)重新調(diào)用KVM_RUN()函數(shù)繼續(xù)調(diào)度客戶機(jī)的執(zhí)行。

4.2 KVM虛擬機(jī)創(chuàng)建和運(yùn)行虛擬機(jī)的主要函數(shù)分析以及流程

    1.函數(shù)kvm_init():該函數(shù)在用戶態(tài)創(chuàng)建一個(gè)虛擬機(jī)上下文,用以在用戶態(tài)保存基本的虛擬機(jī)信息,這個(gè)函數(shù)是創(chuàng)建虛擬機(jī)的第一個(gè)需要調(diào)用的函數(shù),函數(shù)返回一個(gè)kvm_context_t結(jié)構(gòu)體。該函數(shù)原型的實(shí)現(xiàn)在libkvm.c中,該函數(shù)原型是:

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

參數(shù):callbacks為結(jié)構(gòu)體kvm_callbacks變量,該結(jié)構(gòu)體包含指向函數(shù)的一組指針,用于在客戶機(jī)執(zhí)行過(guò)程中因?yàn)镮/O事件退出到用戶態(tài)的時(shí)候處理的回調(diào)函數(shù)。參數(shù)opaque一般未使用。

    函數(shù)執(zhí)行基本過(guò)程:打開(kāi)字符設(shè)備dev/kvm,申請(qǐng)?zhí)摂M機(jī)上下文變量kvm_context_t空間,初始化上下文的基本信息:設(shè)置fd文件描述符指向/dev/kvm,禁止虛擬機(jī)文件描述符vm_fd(-1),設(shè)置I/O事件回調(diào)函數(shù)結(jié)構(gòu)體,設(shè)置IRQ和PIT的標(biāo)志位以及內(nèi)存頁(yè)面記錄的標(biāo)志位。

    用戶態(tài)數(shù)據(jù)結(jié)構(gòu)kvm_context_t用以描述虛擬機(jī)實(shí)例的用戶態(tài)上下文信息。在kvm_common.h文件里面有kvm_context的結(jié)構(gòu)體定義。

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;

};

   各個(gè)數(shù)據(jù)域的解釋為:

int fd :指向內(nèi)核標(biāo)準(zhǔn)字符設(shè)備/dev/kvm的文件描述符。

int vm_fd:指向所創(chuàng)建的內(nèi)核虛擬機(jī)數(shù)據(jù)結(jié)構(gòu)相關(guān)文件的文件描述符。

intvcpu_fd[MAX_VCPUS]:指向虛擬機(jī)所有的虛擬處理器的文件描述符數(shù)組。

struct kvm_run*run[MAX_VCPUS]:指向虛擬機(jī)運(yùn)行環(huán)境上下文的指針數(shù)組。

struct kvm_callbacks*call_backs: 回調(diào)函數(shù)結(jié)構(gòu)體指針,該結(jié)構(gòu)體用于處理用戶態(tài)I/O事件。

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

int dirty_page_log_all:設(shè)置是否記錄臟頁(yè)面的標(biāo)志。

int no_ira_creation: 用于設(shè)置是否再kernel里設(shè)置irq芯片。

int_irqchip_in_kernel:內(nèi)核中irqchip的狀態(tài)

structkvm_callbacks:該結(jié)構(gòu)體用于在用戶態(tài)中處理I/O事件,在KVM中調(diào)用KVM_QEMU實(shí)現(xiàn),主要包含的數(shù)據(jù)域?yàn)椋?/p>

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

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

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

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

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

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

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

int (*mmio_write)(void *opaque, uint64_taddr, uint8_t *data,int len):用于模擬客戶機(jī)執(zhí)行mmio寫(xiě)指令。

int (*debug)(void *opaque, void *env,struct kvm_debug_exit_arch *arch_info):用戶客戶機(jī)調(diào)試的回調(diào)函數(shù)。

int (*halt)(void *opaque, int vcpu):用于客戶機(jī)執(zhí)行halt指令的響應(yīng)。

int (*shutdown)(void *opaque, void *env):用于客戶機(jī)執(zhí)行shutdown指令的響應(yīng)。

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

int (*try_push_interrupts)(void *opaque):用于注入中斷的回調(diào)函數(shù)。

void (*push_nmi)(void *opaque):用于注入nmi中斷的函數(shù)。

void (*post_kvm_run)(void *opaque, void*env);用戶得到kvm運(yùn)行狀態(tài)函數(shù)。

int (*pre_kvm_run)(void *opaque, void*env);用于獲得kvm之前運(yùn)行狀態(tài)的函數(shù)

int (*tpr_access)(void *opaque, int vcpu,uint64_t rip, int is_write);獲得tpr訪問(wèn)處理函數(shù)

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寫(xiě)操作

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的重設(shè)處理。

}

 

當(dāng)客戶機(jī)執(zhí)行I/O事件或者停機(jī)操作等事件時(shí),KVM會(huì)交給用戶態(tài)的QEMU模擬外部I/O事件,調(diào)用這個(gè)結(jié)構(gòu)體指向的相關(guān)的函數(shù)進(jìn)行處理。

Struct kvm_run: 用于KVM運(yùn)行時(shí)一些的一些狀態(tài)信息。主要包含的數(shù)據(jù)域?yàn)椋?/p>

__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 */  客戶機(jī)執(zhí)行過(guò)程中執(zhí)行VM_ENTRY失敗。

struct {

       __u64hardware_entry_failure_reason;

} fail_entry;

/* KVM_EXIT_EXCEPTION */  客戶機(jī)因?yàn)楫惓M顺?/p>

struct {

       __u32exception;

       __u32error_code;

} ex;

/* KVM_EXIT_IO */   客戶機(jī)因?yàn)镮O事件退出。

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 */ 客戶機(jī)因?yàn)镸MIO退出

struct {

__u64 phys_addr;

__u8 data[8];

__u32 len;

__u8 is_write;

} mmio;

/* KVM_EXIT_HYPERCALL */ 客戶機(jī)退出的超調(diào)用參數(shù)。

struct {

__u64 nr;

__u64 args[6];

__u64 ret;

__u32 longmode;

__u32 pad;

} hypercall;

              /*KVM_EXIT_TPR_ACCESS */ 客戶機(jī)退出訪問(wèn)TPR參數(shù)

struct {

       __u64rip;

       __u32is_write;

       __u32pad;

} tpr_access;

/* KVM_EXIT_S390_SIEIC */  和S390相關(guān)數(shù)據(jù)

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. 函數(shù)kvm_create():該函數(shù)主要用于創(chuàng)建一個(gè)虛擬機(jī)內(nèi)核環(huán)境。該函數(shù)原型為:

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

參數(shù):kvm_context_t 表示傳遞的用戶態(tài)虛擬機(jī)上下文環(huán)境,phys_mem_bytes表示需要?jiǎng)?chuàng)建的物理內(nèi)存的大小,phys_mem表示創(chuàng)建虛擬機(jī)的首地址。這個(gè)函數(shù)首先調(diào)用kvm_create_vm()分配IRQ并且初始化為0,設(shè)置vcpu[0]的值為-1,即不允許調(diào)度虛擬機(jī)執(zhí)行。然后調(diào)用ioctl系統(tǒng)調(diào)用ioctl(fd,KVM_CREATE_VM,0)來(lái)創(chuàng)建虛擬機(jī)內(nèi)核數(shù)據(jù)結(jié)構(gòu)struct kvm。

3. 系統(tǒng)調(diào)用函數(shù)ioctl(fd,KVM_CREATE_VM,0),用于在內(nèi)核中創(chuàng)建和虛擬機(jī)相關(guān)的數(shù)據(jù)結(jié)構(gòu)。該函數(shù)原型為:

Static long kvm_dev_ioctl(struct file *filp,unsigned intioctl, unsignedlong arg);其中ioctl表示命令。這個(gè)函數(shù)調(diào)用kvm_dev_ioctl_create_vm()創(chuàng)建虛擬機(jī)實(shí)例內(nèi)核相關(guān)數(shù)據(jù)結(jié)構(gòu)。該函數(shù)首先通過(guò)內(nèi)核中kvm_create_vm()函數(shù)創(chuàng)建內(nèi)核中kvm上下文struct kvm,然后通過(guò)函數(shù)

Anno_inode_getfd(“kvm_vm”,&kvm_vm_fops,kvm,0)返回該虛擬機(jī)的文件描述符,返回給用戶調(diào)用函數(shù),由2中描述的函數(shù)賦值給用戶態(tài)虛擬機(jī)上下文變量中的虛擬機(jī)描述符kvm_vm_fd。

4. 內(nèi)核創(chuàng)建虛擬機(jī)kvm對(duì)象后,接著調(diào)用kvm_arch_create函數(shù)用于創(chuàng)建一些體系結(jié)構(gòu)相關(guān)的信息,主要包括kvm_init_tss、kvm_create_pit以及kvm_init_coalsced_mmio等信息。然后調(diào)用kvm_create_phys_mem創(chuàng)建物理內(nèi)存,函數(shù)kvm_create_irqchip用于創(chuàng)建內(nèi)核irq信息,通過(guò)系統(tǒng)調(diào)用ioctl(kvm->vm_fd,KVM_CREATE_IRQCHIP)。

5,函數(shù)kvm_create_vcpu():用于創(chuàng)建虛擬處理器。該函數(shù)原型為:

int kvm_create_vcpu(kvm_context_t kvm, intslot);

參數(shù):kvm表示對(duì)應(yīng)用戶態(tài)虛擬機(jī)上下文,slot表示需要?jiǎng)?chuàng)建的虛擬處理器的個(gè)數(shù)。

該函數(shù)通過(guò)ioctl系統(tǒng)調(diào)用ioctl(kvm->vm_fd,KVM_CREATE_VCPU,slot)創(chuàng)建屬于該虛擬機(jī)的虛擬處理器。該系統(tǒng)調(diào)用函數(shù):

Static init kvm_vm_ioctl_create_vcpu(struct*kvm, n) 參數(shù)kvm為內(nèi)核虛擬機(jī)實(shí)例數(shù)據(jù)結(jié)構(gòu),n為創(chuàng)建的虛擬CPU的數(shù)目。

6,函數(shù)kvm_create_phys_mem()用于創(chuàng)建虛擬機(jī)內(nèi)存空間,該函數(shù)原型:

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

參數(shù):kvm 表示用戶態(tài)虛擬機(jī)上下文信息,phys_start為分配給該虛擬機(jī)的物理起始地址,len表示內(nèi)存大小,log表示是否記錄臟頁(yè)面,writable表示該段內(nèi)存對(duì)應(yīng)的頁(yè)表是否可寫(xiě)。

該函數(shù)首先申請(qǐng)一個(gè)結(jié)構(gòu)體kvm_userspace_memory_region 然后通過(guò)系統(tǒng)調(diào)用KVM_SET_USER_MEMORY_REGION來(lái)設(shè)置內(nèi)核中對(duì)應(yīng)的內(nèi)存的屬性。該系統(tǒng)調(diào)用函數(shù)原型:

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

參數(shù):第一個(gè)參數(shù)vm_fd為指向內(nèi)核虛擬機(jī)實(shí)例對(duì)象的文件描述符,第二個(gè)參數(shù)KVM_SET_USER_MEMORY_REGION為系統(tǒng)調(diào)用命令參數(shù),表示該系統(tǒng)調(diào)用為創(chuàng)建內(nèi)核客戶機(jī)映射,即影子頁(yè)表。第三個(gè)參數(shù)memory表示指向該虛擬機(jī)的內(nèi)存空間地址。系統(tǒng)調(diào)用首先通過(guò)參數(shù)memory通過(guò)函數(shù)copy_from_user從用戶空間復(fù)制struct_user_momory_region 變量,然后通過(guò)kvm_vm_ioctl_set_memory_region函數(shù)設(shè)置內(nèi)核中對(duì)應(yīng)的內(nèi)存域。該函數(shù)原型:

Int kvm_vm_ioctl_set_memory_region(struct*kvm,struct kvm_usersapce_memory_region *mem,int user_alloc);該函數(shù)再調(diào)用函數(shù)kvm_set_memory_resgion()設(shè)置影子頁(yè)表。當(dāng)這一切都準(zhǔn)備完畢后,調(diào)用kvm_run()函數(shù)即可調(diào)度執(zhí)行虛擬處理器。

7,函數(shù)kvm_run():用于調(diào)度運(yùn)行虛擬處理器。該函數(shù)原型為:

Int kvm_run(kvm_context_t kvm,int vcpu,void *env) 該函數(shù)首先得到vcpu的描述符,然后調(diào)用系統(tǒng)調(diào)用ioctl(fd,kvm_run,0)調(diào)度運(yùn)行虛擬處理器。Kvm_run函數(shù)在正常運(yùn)行情況下并不返回,除非發(fā)生以下事件之一:一是發(fā)生了I/O事件,I/O事件由用戶態(tài)的QEMU處理;一個(gè)是發(fā)生了客戶機(jī)和KVM都無(wú)法處理的異常事件。KVM_RUN()中返回截獲的事件,主要是I/O以及停機(jī)等事件。

 


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多