栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

kvmtool学习

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

kvmtool学习

kvmtool 学习
      • 实验环境
      • kvm 简易运行
      • vmware 与 windows 文件共享
      • 编译kvmtool
      • 参考

实验环境

虚拟机:VMware Workstation 16 Player
os: centos7+linux5.10 (自己安装内核)

kvm 简易运行
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(void) {
    int kvm, vmfd, vcpufd,ret;
    uint8_t *mem;
    struct kvm_sregs sregs;
    size_t mmap_size;
    struct kvm_run *run;
    // 每次执行in/out都会触发VM-Exit,KVM将处理VM-Exit,如果是IO导致的,则KVM将继续向上提交,交由QEMU等用户程序将继续处理
    const uint8_t code[] = {
            0xba, 0xf8, 0x03, 
            0xb0, 'K',        
            0xee,             
            0xb0, 'V',        
            0xee,             
            0xb0, 'M',        
            0xee,             
            0xb0, 'n',       
            0xee,             
            0xf4,             
    };
    // 打开KVM模块设备文件
    if((kvm = open("/dev/kvm", O_RDWR | O_CLOEXEC))==-1) { 
        fprintf(stderr,"open kvm Error:%san",strerror(errno)); 
        exit(1); 
    } //  kvm 打开的设备文件dev/kvm的文件描述符
    if((ret = ioctl(kvm, KVM_GET_API_VERSION, NULL))==-1) { 
        fprintf(stderr,"kvm version Error:%san",strerror(errno)); 
        exit(1); 
    } 
    if (ret != 12) {
        fprintf(stderr,"KVM_GET_API_VERSION %d, expected 12",ret); 
        exit(1);
    } // 判断当前kvm 版本是否符合要求
    // 创建虚拟机, 并获取其文件描述符
    if((vmfd =ioctl(kvm, KVM_CREATE_VM, (unsigned long) 0))==-1) { 
        fprintf(stderr,"kvm create Error:%san",strerror(errno)); 
        exit(1); 
    }
    // 创建4KB大小的内存空间(一页匿名页),用于存放VM执行的代码
    mem = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    // 将上述代码拷贝到匿名页中
    memcpy(mem, code, sizeof(code));
    // 将代码映射到VM物理内存(GPA)的第二个页框处,因为第一个页框被实模式保留,用于存放IDT(中断向量表)
    struct kvm_userspace_memory_region region = {
            .slot = 0,                          // 内存卡槽
            .guest_phys_addr = 0x1000,          // GPA的起始映射地址,即第二个页框
            .memory_size = 0x1000,              // 映射内存的大小,4KB
            .userspace_addr = (uint64_t) mem,   // 映射内存的起始地址
    };
    if((ret =ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, ®ion))==-1) { 
        fprintf(stderr,"kvm Error:%san",strerror(errno)); 
        exit(1); 
    }
    // 创建vCPU并获取其文件描述符
    if(( vcpufd = ioctl(vmfd, KVM_CREATE_VCPU, (unsigned long) 0))==-1) { 
        fprintf(stderr,"kvm Error:%san",strerror(errno)); 
        exit(1); 
    }
    // 映射vCPU的共享内存到run中,可以访问其kvm_run结构
    mmap_size = ioctl(kvm, KVM_GET_VCPU_MMAP_SIZE, NULL);
    run = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, vcpufd, 0);
    // 设置代码段寄存器和代码段基址, 这是内存的分段管理
    // 此时我们并没有开启分页管理,因此虚拟地址直接等于物理地址
    // 而虚拟地址是根据线性地址+代码段基址计算的
    // 代码段基址是根据GDT(全局描述符表)和CS(代码段,选择子)确定的
    if((ret = ioctl(vcpufd, KVM_GET_SREGS, &sregs))==-1) { 
        fprintf(stderr,"kvm Error:%san",strerror(errno)); 
        exit(1); 
    }
    sregs.cs.base = 0;
    sregs.cs.selector = 0;
    if(( ret = ioctl(vcpufd, KVM_SET_SREGS, &sregs))==-1) { 
        fprintf(stderr,"kvm Error:%san",strerror(errno)); 
        exit(1); 
    }
    // 关于kvm_sregs和kvm_regs(并不严格):
    // kvm_regs    用于通用寄存器的配置
    // kvm_sregs   用于段计算器的配置
    // 下用于设置rip寄存器, cs.base + rip 既是物理地址(没开启分页,虚拟地址等于物理地址,rip则表示线性地址),
    struct kvm_regs regs = {
            .rip = 0x1000,
    };
    ioctl(vcpufd, KVM_SET_REGS, ®s);

    // 开启一个循环,执行VM的代码,并处理IO事件
    while (1) {
        // 开启vCPU
        if(( ret = ioctl(vcpufd, KVM_RUN, NULL))==-1) { 
            fprintf(stderr,"kvm Error:%san",strerror(errno)); 
            exit(1); 
        }
        // 当VM_Exit时,kvm_run结构中将保留exit_reason, 将基于此知悉退出原因,从而进行相应的处理
        switch (run->exit_reason) {
            case KVM_EXIT_HLT:  // VM关机
                puts("KVM_EXIT_HLT");
                return 0;
            case KVM_EXIT_IO:    // IO事件
                // 在这里,输出写入0x3f8的字符
                if (run->io.direction == KVM_EXIT_IO_OUT && run->io.size == 1 && run->io.port == 0x3f8 && run->io.count == 1)
                    putchar(*(((char *) run) + run->io.data_offset));
                break;
            case KVM_EXIT_FAIL_ENTRY:
                fprintf(stderr, "KVM_EXIT_FAIL_ENTRY: hardware_entry_failure_reason = 0x%llx",
                    (unsigned long long)run->fail_entry.hardware_entry_failure_reason);
            case KVM_EXIT_INTERNAL_ERROR:
                fprintf(stderr, "KVM_EXIT_INTERNAL_ERROR: suberror = 0x%x", run->internal.suberror);
            default:
                fprintf(stderr, "exit_reason = 0x%x", run->exit_reason);
        }
    }
}

vmware+centos7+linux 3.10 运行结果:

vmware+centos7+linux 5.10 运行结果:

vmware 与 windows 文件共享

在虚拟机设置中 点击 选项 在 共享文件夹 添加自己需要的共享文件夹
点击 安装VMware tool 或者更新

# root 用户操作
mkdir /mnt/cdrom
# 挂载
mount -t iso9660 /dev/cdrom /mnt/cdrom 
ls /mnt/cdrom/
cp /mnt/cdrom/VMwareTools-xxx.tar.gz  /root/vm.tar.gz
ls
tar -xzf vm.tar.gz
cd vmware-tools-distrib
# 安装, 一直回车,对于默认no的输入yes
/vmware-install.pl 
# 最后一行 显示 --the VMware team
# 查看之前共享的目录
cd /mnt/hgfs 
# 若没有hgfs目录
# 查看共享文件夹名是什么 
vmware-hgfsclient 
# 没有hgfs的先创建
sudo mkdir hgfs
# 若挂载过,先取消挂载
sudo umount /mnt/hgfs
# 进行挂载 Linux是上面查找的共享文件夹
sudo /usr/bin/vmhgfs-fuse .host:/[填写上面的文件名] /mnt/hgfs -o allow_other -o uid=1000 -o gid=1000 -o umask=022
# 该方法重启可能会消失
sudo /usr/bin/vmhgfs-fuse .host:/linux-share /mnt/hgfs -o allow_other -o uid=1000 -o gid=1000 -o umask=022
编译kvmtool

使用kvmtool启动一台最小虚拟机

# 克隆,或者自己下载kvmtool 解压
git clone https://github.com/kvmtool/kvmtool.git
# unzip kvmtool-master.zip # sudo yum install unzip zip
# mv kvmtool-master kvmtool
cd kvmtool
make
# 编译出现 error: ‘value’ may be used uninitialized in this function 
# 方法一:修改Makefile 注释406行 CFLAGS += -Werror
# 方法二:修改hw/i8042.c  kbd_io 函数 298 行 为 u8 value = 0;
参考
  • 10行代码模拟QEMU/KVM的CPU虚拟化执行
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/880689.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号