load_file(vm_mem + 0x100000, av[2]); virDomainCreateXM

来源:互联网 发布:c和汇编混合编程 编辑:程序博客网 时间:2024/06/04 01:15
清单 1. 测试 KVM 系统管理程序的应用程序片断
int main(){void *vm_mem;kvm = kvm_init(&test_callbacks, 0);if (!kvm) {    fprintf(stderr, "kvm_init failed\n");    return 1;}if (kvm_create(kvm, 128 * 1024 * 1024, &vm_mem) < 0) {    kvm_finalize(kvm);    fprintf(stderr, "kvm_create failed\n");    return 1;}if (ac > 1)    if (strcmp(av[1], "-32") != 0)load_file(vm_mem + 0xf0000, av[1]);    elseenter_32(kvm);if (ac > 2)    load_file(vm_mem + 0x100000, av[2]);kvm_show_regs(kvm, 0);kvm_run(kvm, 0);return 0;}

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,就可以看到这个虚拟机被创建并启动起来了。

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以及停机等事件。

0 0
原创粉丝点击