QEMU-KVM 介绍2 概述

本文详细介绍了QEMU和KVM的原理及工作流程,包括QEMU与KVM的初始化过程、虚拟机的创建步骤等关键技术细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. QEMU 介绍

QEMU(Quick emulator) QEMU is a generic and open source machine emulator and virtualizer。官方网站:https://www.qemu.org

QEMU可以独立完整模拟一台计算机。基于指令模拟,性能会很差。

2. KVM 介绍

Kernel Virtual MachineKVM (for Kernel-based Virtual Machine) is a full virtualization solution for Linux on x86 hardware containing virtualization extensions (Intel VT or AMD-V). It consists of a loadable kernel module, kvm.ko, that provides the core virtualization infrastructure and a processor specific module, kvm-intel.ko or kvm-amd.ko。官方网站: https://www.linux-kvm.orgKVM 是辅助模块,无法独立模拟。搭载QEMU可以完成基于硬件辅助的虚拟化,性能佳。

3. QEMU-KVM 整体框图

qemu 是用户态进程,kvm是内核模块。qemu通过操作/dev/kvm来与kvm进行通信与控制. QEMUKVM的系统框图如下:

 

4. KVM 初始化

KVM 包含两个内核模块 kvm.ko以及kvm-intel.kokvm-intel.ko依赖kvm.kokvm.ko 所有代码在virt/kvm中它没有模块初始化函数,使用默认的初始化函数。然后看kvm-intel.ko arch/x86/kvmvmx.c 有模块初始化函数module_init(vmx_init)

static int __init vmx_init(void)

{

        int r = kvm_init(&vmx_x86_ops, sizeof(struct vcpu_vmx),

                     __alignof__(struct vcpu_vmx), THIS_MODULE);

        if (r)

                return r;

 

#ifdef CONFIG_KEXEC

        rcu_assign_pointer(crash_vmclear_loaded_vmcss,

                           crash_vmclear_local_loaded_vmcss);

#endif

 

        return 0;

}

函数调用关系如下:

-------

vmx_init

=> kvm_init

=> misc_register(&kvm_dev)

这个函数最主要的功能就是注册了一个杂项设备,其实就是一个字符设备/dev/kvm。这个设备的操作函数如下,

static struct file_operations kvm_chardev_ops = {

        .unlocked_ioctl = kvm_dev_ioctl,

        .compat_ioctl   = kvm_dev_ioctl,

        .llseek         = noop_llseek,

};

 

static struct miscdevice kvm_dev = {

        KVM_MINOR,

        "kvm",

        &kvm_chardev_ops,

};

5. QEMU 初始化以及创建虚拟机的过程

QEMU 建立需要与KVM协作来完成虚拟机的创建。QEMUKVM 使用不同的数据结构来表示虚拟机

QEMU 使用PCMachineState来表示虚拟机

KVM 使用struct kvm 来表示虚拟机

初始化过程包含两部分:

 KVM加速器初始化

 主板以及CPU初始化

 

5.1 KVM加速器初始化

本节主要介绍qemu 怎样通过/dev/kvm 来与kvm进行交互创建虚拟机. qemu 的入口函数在vl.c中,main函数,里面有如下函数初始化加速器,configure_accelerator(current_machine,这里就是KVM。函数调用关系如下:

----------

configure_accelerator

=> accel_init_machine

=> acc->init_machine(ms)[kvm_init]

// accel/kvm/kvm-all.c:    ac->init_machine = kvm_init;

 

kvm_init accel/kvm/kvm-all.c

static int kvm_init(MachineState *ms)

...

    KVMState *s;

...

    //打开/dev/kvm 设备

    s->fd = qemu_open("/dev/kvm", O_RDWR);

...

    // 检查kvm模块的api version是否匹配

    ret = kvm_ioctl(s, KVM_GET_API_VERSION, 0);

...

    // 建立虚拟机, 从这里可以看出,qemu 运行一次会建立一个虚拟机,下面会介绍这个函数

     do {

         ret = kvm_ioctl(s, KVM_CREATE_VM, type);

     } while (ret == -EINTR);

...

    // CPU 架构相关的初始化

    ret = kvm_arch_init(ms, s);

...

    // 注册memory_lister

     kvm_memory_listener_register(s, &s->memory_listener,

                                  &address_space_memory, 0);

 

    // do other things

kvm_init 主要任务建立虚拟机,并初始化后退出,返回到qemumain函数中,继续初始其他的设备。下面主要介绍ret = kvm_ioctl(s, KVM_CREATE_VM, type); 建立虚拟机的过程。对应virt/kvm/kvm_main.c。就是调用ioctl系统调用,并传入参数KVM_CREATE_VM

static long kvm_dev_ioctl(struct file *filp,

                          unsigned int ioctl, unsigned long arg)

{

        long r = -EINVAL;

 

        switch (ioctl) {

        case KVM_GET_API_VERSION:

                if (arg)

                        goto out;

                r = KVM_API_VERSION;

                break;

        case KVM_CREATE_VM:

                r = kvm_dev_ioctl_create_vm(arg);

                break;

        case KVM_CHECK_EXTENSION:

                r = kvm_vm_ioctl_check_extension_generic(NULL, arg);

                break;

        case KVM_GET_VCPU_MMAP_SIZE:

                if (arg)

                        goto out;

                r = PAGE_SIZE;     /* struct kvm_run */

#ifdef CONFIG_X86

                r += PAGE_SIZE;    /* pio data page */

#endif

#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET

                r += PAGE_SIZE;    /* coalesced mmio ring page */

#endif

                break;

        case KVM_TRACE_ENABLE:

        case KVM_TRACE_PAUSE:

        case KVM_TRACE_DISABLE:

                r = -EOPNOTSUPP;

                break;

        default:

                return kvm_arch_dev_ioctl(filp, ioctl, arg);

        }

out:

        return r;

}

kvm_dev_ioctl_create_vm 函数的实现如下,主要功能是初始化struct kvm结构体中的各个字段,并且建立这个虚拟机的fd

static int kvm_dev_ioctl_create_vm(unsigned long type)

{

        int r;

        struct kvm *kvm;

 

        kvm = kvm_create_vm(type); // 分配struct kvm结构体并且初始化

        if (IS_ERR(kvm))

                return PTR_ERR(kvm);

#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET

        r = kvm_coalesced_mmio_init(kvm);

        if (r < 0) {

                kvm_put_kvm(kvm);

                return r;

        }

#endif

        r = anon_inode_getfd("kvm-vm", &kvm_vm_fops, kvm, O_RDWR | O_CLOEXEC); //从进程的文件fd中返回一个fd,代表这个虚拟机

        if (r < 0)

                kvm_put_kvm(kvm);

 

        return r;

}

5.2 主板以及CPU初始化

    也是在vl.c machine_run_board_init(current_machine) 会完成主板以及CPU基本外设的虚拟化。

QEMUMachineClass 结构体代表一个虚拟机,不同类型的虚拟机有不同的类。继承关系如下:

---------

MachineClass

=> PCMachineClass

=> xxx_PCMachineClass

hw/i386/pc_q35.c中通过宏DEFINE_Q35_MACHINE 来定义不同的PCMachineClass,比如:

 DEFINE_Q35_MACHINE(v2_11, "pc-q35-2.11", NULL, pc_q35_2_11_machine_options);

 DEFINE_Q35_MACHINE(v2_10, "pc-q35-2.10", NULL, pc_q35_2_10_machine_options);

通过qemu-system -machine help可以查看支持的machine类型

[[yzg@localhost ~]$ qemu-system-x86_64 -machine help

Supported machines are:

......

pc-0.15              Standard PC (i440FX + PIIX, 1996)

pc-0.14              Standard PC (i440FX + PIIX, 1996)

pc-0.13              Standard PC (i440FX + PIIX, 1996)

pc-0.12              Standard PC (i440FX + PIIX, 1996)

pc-0.11              Standard PC (i440FX + PIIX, 1996)

pc-0.10              Standard PC (i440FX + PIIX, 1996)

// 以上为老式主板,下面是q35较新主板

pc-q35-2.9           Standard PC (Q35 + ICH9, 2009)

pc-q35-2.8           Standard PC (Q35 + ICH9, 2009)

pc-q35-2.7           Standard PC (Q35 + ICH9, 2009)

pc-q35-2.6           Standard PC (Q35 + ICH9, 2009)

pc-q35-2.5           Standard PC (Q35 + ICH9, 2009)

pc-q35-2.4           Standard PC (Q35 + ICH9, 2009)

q35                  Standard PC (Q35 + ICH9, 2009) (alias of pc-q35-2.11)

isapc                ISA-only PC

none                 empty machine

Q35 芯片组 框图如下:

 

 

 machine_run_board_init 调用关系(以Q35主板为例子)如下:

-------------

 machine_run_board_init

=> machine_class->init

=> pc_q35_init

=> pc_cpus_init

=> pc_memory_init

=> pc_basic_device_init

=> pc_vga_init

=> pc_pci_device_init

从函数名字就可以看出,完成了什么功能。这样就完成了整个机器的虚拟化过程。

 

参考文档:

https://www.binss.me/blog/qemu-note-of-Q35-machine/

https://www.qemu.org

https://www.linux-kvm.org

 

转载于:https://www.cnblogs.com/felixyzg/p/8052053.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值