一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

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

 浪子小新 2016-08-06

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

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

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

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

kvm常用命令如下:

參數(shù)

示例

說明

-hda

-hda /data/windows.img

指定windows.img作為硬盤鏡像

-cdrom

-cdrom /data/windows.iso

指定windows.iso作為光盤鏡像

-boot

-boot c

從硬盤啟動

 

-boot d

從光盤啟動

-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個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)建一個虛擬機(jī)的步驟如下:

(1)生成硬盤鏡像文件

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

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

(2)從光盤啟動虛擬機(jī)來安裝操作系統(tǒng)

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

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

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

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

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

1.2.1 virsh工具簡介

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

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

??

Description

help

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

list

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

dumpxml

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

create

從? XML 配?置?文?件?生?成?客?戶?端?并?啟?動?新?客?戶?端?。?

start

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

destroy

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

define

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

domid

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

domuuid

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

dominfo

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

domname

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

domstate

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

quit

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

reboot

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

restore

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

resume

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

save

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

shutdown

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

suspend

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

undefine

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

migrate

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

??

Description

setmem

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

setmaxmem

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

setvcpus

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

vcpuinfo

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

vcpupin

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

domblkstat

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

domifstat

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

attach-device

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

attach-disk

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

attach-interface

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

detach-device

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

detach-disk

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

detach-interface

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

??

Description

version

顯?示? virsh 版?本?

nodeinfo

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

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

(1)生成硬盤鏡像文件

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

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

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

root@host:virsh create test.xml

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

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

1.2.3 xml配置文件的編寫

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

#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屬性指定運行域的虛擬機(jī)管理器,針對kvm應(yīng)當(dāng)選擇“qemu”。

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

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

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

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

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

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

①   從控制臺窗口啟動這個工具,從root身份輸入virt-manager命令,點擊file菜單

的”新建”選項。

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

為hypervisor。

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

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

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

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

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

這樣一個虛擬機(jī)就開始啟動起來了,將會出現(xiàn)啟動界面,最后出現(xiàn)虛擬機(jī)中操作系統(tǒng)的界面。

 

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

2.1 virsh工具”create”命令源碼  

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

     /*

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

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

  ⑵ typedef struct{

        const char *name;

        vshCmdOptType type;

        unsigned int flags;

        const char *help;

     }vshCmdOptDef;

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

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

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

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

2.2.1 virFileReadAll

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

2.2.2virDomainCreateXML

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


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

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

  下面用一個測試?yán)觼碚f明如何通過virsh命令來創(chuàng)建虛擬機(jī)的。

   具體的操作實踐步驟是:

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

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

   2.  編寫一個xml文件,這個文件里面包含啟動操作系統(tǒng)的一些特征,比如:內(nèi)存容量,操作系統(tǒng)位置,虛擬硬盤位置等等,其實有很多的字段,可以簡寫一個xml文件,如果有些字段沒有定義,那么系統(tǒng)就會默認(rèn),下面給出一個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這個文件主要實現(xiàn)的功能就是調(diào)用這個xml文件來創(chuàng)建并啟動虛擬機(jī)。這個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,就可以看到這個虛擬機(jī)被創(chuàng)建并啟動起來了。

 

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

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

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

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

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

    1.函數(shù)kvm_init():該函數(shù)在用戶態(tài)創(chuàng)建一個虛擬機(jī)上下文,用以在用戶態(tài)保存基本的虛擬機(jī)信息,這個函數(shù)是創(chuàng)建虛擬機(jī)的第一個需要調(diào)用的函數(shù),函數(shù)返回一個kvm_context_t結(jié)構(gòu)體。該函數(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í)行過程中因為I/O事件退出到用戶態(tài)的時候處理的回調(diào)函數(shù)。參數(shù)opaque一般未使用。

    函數(shù)執(zhí)行基本過程:打開字符設(shè)備dev/kvm,申請?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)存頁面記錄的標(biāo)志位。

    用戶態(tài)數(shù)據(jù)結(jié)構(gòu)kvm_context_t用以描述虛擬機(jī)實例的用戶態(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;

};

   各個數(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ī)運行環(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è)置是否記錄臟頁面的標(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實現(xiàn),主要包含的數(shù)據(jù)域為:

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寫指令。

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運行狀態(tài)函數(shù)。

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

int (*tpr_access)(void *opaque, int vcpu,uint64_t rip, int is_write);獲得tpr訪問處理函數(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寫操作

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ī)操作等事件時,KVM會交給用戶態(tài)的QEMU模擬外部I/O事件,調(diào)用這個結(jié)構(gòu)體指向的相關(guān)的函數(shù)進(jìn)行處理。

Struct kvm_run: 用于KVM運行時一些的一些狀態(tài)信息。主要包含的數(shù)據(jù)域為:

__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í)行過程中執(zhí)行VM_ENTRY失敗。

struct {

       __u64hardware_entry_failure_reason;

} fail_entry;

/* KVM_EXIT_EXCEPTION */  客戶機(jī)因為異常退出

struct {

       __u32exception;

       __u32error_code;

} ex;

/* KVM_EXIT_IO */   客戶機(jī)因為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 */ 客戶機(jī)因為MMIO退出

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ī)退出訪問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)建一個虛擬機(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表示需要創(chuàng)建的物理內(nèi)存的大小,phys_mem表示創(chuàng)建虛擬機(jī)的首地址。這個函數(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)來創(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表示命令。這個函數(shù)調(diào)用kvm_dev_ioctl_create_vm()創(chuàng)建虛擬機(jī)實例內(nèi)核相關(guān)數(shù)據(jù)結(jié)構(gòu)。該函數(shù)首先通過內(nèi)核中kvm_create_vm()函數(shù)創(chuàng)建內(nèi)核中kvm上下文struct kvm,然后通過函數(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對象后,接著調(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信息,通過系統(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表示對應(yīng)用戶態(tài)虛擬機(jī)上下文,slot表示需要創(chuàng)建的虛擬處理器的個數(shù)。

該函數(shù)通過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ù)據(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表示是否記錄臟頁面,writable表示該段內(nèi)存對應(yīng)的頁表是否可寫。

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

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

參數(shù):第一個參數(shù)vm_fd為指向內(nèi)核虛擬機(jī)實例對象的文件描述符,第二個參數(shù)KVM_SET_USER_MEMORY_REGION為系統(tǒng)調(diào)用命令參數(shù),表示該系統(tǒng)調(diào)用為創(chuàng)建內(nèi)核客戶機(jī)映射,即影子頁表。第三個參數(shù)memory表示指向該虛擬機(jī)的內(nèi)存空間地址。系統(tǒng)調(diào)用首先通過參數(shù)memory通過函數(shù)copy_from_user從用戶空間復(fù)制struct_user_momory_region 變量,然后通過kvm_vm_ioctl_set_memory_region函數(shù)設(shè)置內(nèi)核中對應(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è)置影子頁表。當(dāng)這一切都準(zhǔn)備完畢后,調(diào)用kvm_run()函數(shù)即可調(diào)度執(zhí)行虛擬處理器。

7,函數(shù)kvm_run():用于調(diào)度運行虛擬處理器。該函數(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)度運行虛擬處理器。Kvm_run函數(shù)在正常運行情況下并不返回,除非發(fā)生以下事件之一:一是發(fā)生了I/O事件,I/O事件由用戶態(tài)的QEMU處理;一個是發(fā)生了客戶機(jī)和KVM都無法處理的異常事件。KVM_RUN()中返回截獲的事件,主要是I/O以及停機(jī)等事件。

 


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

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    精品推荐久久久国产av| 九九热这里只有精品视频| 国产精品美女午夜福利| 日本在线视频播放91| 日韩日韩日韩日韩在线| 中文字幕乱码亚洲三区| 99久久精品免费看国产高清| 国产白丝粉嫩av在线免费观看| 久久中文字人妻熟女小妇| 欧美日韩中国性生活视频| 国产精品免费视频视频| 国产欧美性成人精品午夜| 国产精品蜜桃久久一区二区| 中文字幕精品人妻一区| 不卡中文字幕在线免费看| 婷婷色香五月综合激激情| 午夜国产精品国自产拍av| 年轻女房东2中文字幕| 热情的邻居在线中文字幕| 精品国产91亚洲一区二区三区| 中文人妻精品一区二区三区四区| 一区二区不卡免费观看免费| 国产av精品高清一区二区三区 | 欧美大黄片在线免费观看| 亚洲av熟女国产一区二区三区站 | 91人人妻人人爽人人狠狠| 中国一区二区三区人妻| 久久热九九这里只有精品| 开心激情网 激情五月天| 久久精品国产亚洲熟女| 欧美日韩视频中文字幕| 沐浴偷拍一区二区视频| 91精品国产综合久久不卡| 欧美午夜一级特黄大片| av免费视屏在线观看| 日韩国产传媒在线精品| 在线观看日韩欧美综合黄片| 日韩18一区二区三区| 欧美午夜一级艳片免费看| 国产又猛又大又长又粗| 91人妻久久精品一区二区三区|