qemu/kvm学习笔记
qemu/kvm架构

cpu虚拟化的示例
Reference: kvmtest.c [LWN.net]
主要步骤:
- QEMU通过/dev/kvm设备文件发起KVM_CREATE_VM ioctl,请求KVM创建一个虚拟机。KVM创建虚拟机相应的结构体,并为QEMU返回一个虚拟机文件描述符
- QEMU通过虚拟机文件描述符发起KVM_CREATE_VCPU ioctl,请求KVM创建一个vCPU。KVM创建vCPU相应的结构体并初始化,返回一个vCPU文件描述符。
- QEMU通过vCPU文件描述符发起KVM_RUN ioctl,vCPU线程执行VMLAUNCH指令进入非根模式,执行虚拟机代码直至发生VM-Exit。
- KVM根据VM-Exit的原因进行相应处理,如果与IO有关,则需要进一步返回到QEMU中进行处理。
运行结果:

代码实现:
/* Sample code for /dev/kvm API */#include <err.h>
#include <fcntl.h>
#include <linux/kvm.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>int main(void)
{int kvm, vmfd, vcpufd, ret;const uint8_t code[] = {/* 写入指定端口 0x3f8,输出 Hello */0xba, 0xf8, 0x03, /* mov $0x3f8, %dx */0x00, 0xd8, /* add %bl, %al */0x04, '0', /* add $'0', %al */0xee, /* out %al, (%dx) */0xb0, '\n', /* mov $'\n', %al */0xee, /* out %al, (%dx) */0xb0, 'H', /* mov $'H', %al */0xee, /* out %al, (%dx) */0xb0, 'e', /* mov $'e', %al */0xee, /* out %al, (%dx) */0xb0, 'l', /* mov $'l', %al */0xee, /* out %al, (%dx) */0xb0, 'l', /* mov $'l', %al */0xee, /* out %al, (%dx) */0xb0, 'o', /* mov $'o', %al */0xee, /* out %al, (%dx) */0xb0, '\n', /* mov $'\n', %al */0xee, /* out %al, (%dx) */0xf4, /* hlt */};uint8_t *mem;struct kvm_sregs sregs;size_t mmap_size;struct kvm_run *run;// ** step 1. 打开 KVM 模块设备文件kvm = open("/dev/kvm", O_RDWR | O_CLOEXEC);if (kvm == -1)err(1, "/dev/kvm");// 获取 KVM API 版本/* Make sure we have the stable version of the API */ret = ioctl(kvm, KVM_GET_API_VERSION, NULL);if (ret == -1)err(1, "KVM_GET_API_VERSION");if (ret != 12)errx(1, "KVM_GET_API_VERSION %d, expected 12", ret);// ** step 2. KVM_CREATE_VM 创建虚拟机获得虚拟机文件描述符vmfd = ioctl(kvm, KVM_CREATE_VM, (unsigned long)0);if (vmfd == -1)err(1, "KVM_CREATE_VM");// 分配 4KB 内存空间存放二进制代码// 这里的 0x1000(HVA)/* Allocate one aligned page of guest memory to hold the code. */mem = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);if (!mem)err(1, "allocating guest memory");// 将二进制代码复制至分配的内存页中memcpy(mem, code, sizeof(code));// KVM_SET_USER_MEMORY_REGION 将该内存页映射至虚拟机物理地址 0x1000(GPA) 处/* Map it to the second page frame (to avoid the real-mode IDT at 0). */struct kvm_userspace_memory_region region = {.slot = 0,.guest_phys_addr = 0x1000,.memory_size = 0x1000,.userspace_addr = (uint64_t)mem,};ret = ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, ®ion);if (ret == -1)err(1, "KVM_SET_USER_MEMORY_REGION");// ** step 3. KVM_CREATE_VCPU 创建 vCPU 获得 vCPU 文件描述符vcpufd = ioctl(vmfd, KVM_CREATE_VCPU, (unsigned long)0);if (vcpufd == -1)err(1, "KVM_CREATE_VCPU");// ** step 4. 获取 QEMU/KVM 共享内存空间大小,并映射 kvm_run 结构体/* Map the shared kvm_run structure and following data. */ret = ioctl(kvm, KVM_GET_VCPU_MMAP_SIZE, NULL);if (ret == -1)err(1, "KVM_GET_VCPU_MMAP_SIZE");mmap_size = ret;if (mmap_size < sizeof(*run))errx(1, "KVM_GET_VCPU_MMAP_SIZE unexpectedly small");// 使用 vCPU 文件描述符// 映射 kvm_run 结构体run = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, vcpufd, 0);if (!run)err(1, "mmap vcpu");// ** step 5. 设置 CS 寄存器和 RIP 寄存器,使得 vCPU 从 0x1000 处开始执行/* Initialize CS to point at 0, via a read-modify-write of sregs. */ret = ioctl(vcpufd, KVM_GET_SREGS, &sregs);if (ret == -1)err(1, "KVM_GET_SREGS");sregs.cs.base = 0;sregs.cs.selector = 0;ret = ioctl(vcpufd, KVM_SET_SREGS, &sregs);if (ret == -1)err(1, "KVM_SET_SREGS");/* Initialize registers: instruction pointer for our code, addends, and* initial flags required by x86 architecture. */struct kvm_regs regs = {.rip = 0x1000,.rax = 2,.rbx = 2,.rflags = 0x2,};ret = ioctl(vcpufd, KVM_SET_REGS, ®s);if (ret == -1)err(1, "KVM_SET_REGS");/* Repeatedly run code and handle VM exits. */while (1) {// ** step 6. KVM_RUN 运行 vCPUret = ioctl(vcpufd, KVM_RUN, NULL);if (ret == -1)err(1, "KVM_RUN");// ** step 7. 处理 VM-Exitswitch (run->exit_reason) {case KVM_EXIT_HLT: // hlt 指令触发 VM-Exitputs("KVM_EXIT_HLT");return 0; // 退出程序case KVM_EXIT_IO: // 依次调用 out 指令向 0x3f8 端口写入字符时,会触发 VM-Exit,使得程序返回到用户态处理// 输出写入 0x3f8 端口的字符if (run->io.direction == KVM_EXIT_IO_OUT && run->io.size == 1 && run->io.port == 0x3f8 && run->io.count == 1)// 调用 putchar 函数输出字符putchar(*(((char *)run) + run->io.data_offset));elseerrx(1, "unhandled KVM_EXIT_IO");break;case KVM_EXIT_FAIL_ENTRY:errx(1, "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:errx(1, "KVM_EXIT_INTERNAL_ERROR: suberror = 0x%x", run->internal.suberror);default:errx(1, "exit_reason = 0x%x", run->exit_reason);}}
}
KVM API
/usr/include/linux/kvm.h
| ioctl | KVM API | Description | Example |
|---|---|---|---|
| ioctls for /dev/kvm fds | KVM_GET_API_VERSION | 获取 KVM API 版本 | kvm = open("/dev/kvm", O_RDWR | O_CLOEXEC) ret = ioctl(kvm, KVM_GET_API_VERSION, NULL) |
| KVM_CREATE_VM | 创建虚拟机获得虚拟机文件描述符 | vmfd = ioctl(kvm, KVM_CREATE_VM, 0) | |
| ioctls for VM fds | KVM_SET_USER_MEMORY_REGION | 将内存页映射至虚拟机物理地址处 | ret = ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, ®ion) |
| KVM_CREATE_VCPU | 创建 vCPU 获得 vCPU 文件描述符 | vcpufd = ioctl(vmfd, KVM_CREATE_VCPU, 0) | |
| KVM_GET_VCPU_MMAP_SIZE | 获取 QEMU/KVM 共享内存空间大小 | mmap_size = ioctl(kvm, KVM_GET_VCPU_MMAP_SIZE, NULL); 使用 vCPU 文件描述符,映射 kvm_run 结构体 run = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, vcpufd, 0) | |
| ioctls for vcpu fds | KVM_GET_SREGS | 获取 CS 寄存器和 RIP 寄存器 | ret = ioctl(vcpufd, KVM_GET_SREGS, &sregs) |
| KVM_SET_SREGS | 设置 CS 寄存器和 RIP 寄存器 | sregs.cs.base = 0 sregs.cs.selector = 0 ret = ioctl(vcpufd, KVM_SET_SREGS, &sregs) struct kvm_regs regs = { .rip = 0x1000, .rax = 2, .rbx = 2, .rflags = 0x2, } ret = ioctl(vcpufd, KVM_SET_REGS, ®s) | |
| KVM_RUN | 运行 vCPU | ret = ioctl(vcpufd, KVM_RUN, NULL) |
相关文章:
qemu/kvm学习笔记
qemu/kvm架构 cpu虚拟化的示例 Reference: kvmtest.c [LWN.net] 主要步骤: QEMU通过/dev/kvm设备文件发起KVM_CREATE_VM ioctl,请求KVM创建一个虚拟机。KVM创建虚拟机相应的结构体,并为QEMU返回一个虚拟机文件描述符QEMU通过虚拟机文件描述…...
android 车载widget小部件部分详细源码实战开发-千里马车载车机framework开发实战课程
官网参考链接:https://developer.android.google.cn/develop/ui/views/appwidgets/overview 1、什么是小部件 App widgets are miniature application views that can be embedded in other applications (such as the home screen) and receive periodic updates…...
如何使用CSS画一个三角形
原理:其实就是规定元素的四个边框颜色及边框宽度,将元素宽高设置为0。如果要哪个方向的三角形,将对应其他三个方向的边框宽和颜色设置为0和透明transparent即可 1.元素设置边框,宽高,背景色 <style>.border {w…...
第15章_锁: (表级锁、页级锁、行锁、悲观锁、乐观锁、全局锁、死锁)
3.2 从数据操作的粒度划分:表级锁、页级锁、行锁 为了提高数据库并发度,每次锁定的数据范围越小越好,理论上每次只锁定当前操作的数据的方案会得到最大的并发度,但管理锁是很耗资源(涉及获取、检查、释放锁等动作)。因…...
python音频转文字调用baidu
python音频转文字调用的是百度智能云的接口,因业务需求会涉及比较多数字,所以这里做了数字的处理,可根据自己的需求修改。 from flask import Flask, request, jsonify import requestsfrom flask_limiter import Limiterapp Flask(__name_…...
靶场溯源第二题
关卡描述:1. 网站后台登陆地址是多少?(相对路径) 首先这种确定的网站访问的都是http或者https协议,搜索http看看。关于http的就这两个信息,然后172.16.60.199出现最多,先过滤这个ip看看 这个很…...
mysql 的增删改查以及模糊查询、字符集语句的使用
一、mysql启动与登陆(windows下的mysql操作) 1.启动mysql服务 net start mysql81 2.登陆mysql mysql -uroot -p 3.查看所有数据库 show databases; 二、模糊查询(like) 1. _代表查询单个 2.%代表查询多个 3.查找所有含有schema的数据库;…...
Python Django框架中文教程:学习简单、灵活、高效的Web应用程序框架
概述: Python Django是一种流行的Web应用程序框架,被广泛应用于开发高效、可扩展的网站和Web应用程序。Django以其简单、灵活和高效而受到开发者们的青睐。它提供了强大的工具和功能,使开发过程更加容易和高效。 Django的主要目标是帮助开发者快速构建…...
Docker认识即安装
Docker及相关概念 Docker和虚拟机方式的区别:虚拟机技术是虚拟出一套硬件后,在其上运行一个完整的操作系统,在该系统上在运行所需应用进程;而容器内的应用进程是直接运行于宿主的内核,容器内没有自己的内核࿰…...
chrome 谷歌浏览器 导出插件拓展和导入插件拓展
给同事部署 微软 RPA时,需要用到对应的chrome浏览器插件;谷歌浏览器没有外网是不能直接下载拓展弄了半小时后才弄好,竟发现没有现成的教程,遂补充; 如何打包导出 谷歌浏览器 地址栏敲 chrome://extensions/在对应的地…...
fastjson漏洞批量检测工具
JsonExp 简介 版本:1.3.5 1. 根据现有payload,检测目标是否存在fastjson或jackson漏洞(工具仅用于检测漏洞)2. 若存在漏洞,可根据对应payload进行后渗透利用3. 若出现新的漏洞时,可将最新的payload新增至…...
Vue进阶(六十七)页面刷新路由传参丢失问题分析及解决
文章目录 一、前言二、问题排查三、延伸阅读3.1 Apache服务器access_log日志3.2 浏览器的常见User Agent 各字段的解释 一、前言 问题描述:Vue项目上线后,在IE浏览器上,从A页面跳转至B页面,B页面通过data中接收来自A页面的参数信…...
阿里云ubuntu服务器搭建ftp服务器
阿里云ubuntu服务器搭建ftp服务器 服务器环境安装步骤一.创建用户二.安装 vsftp三 配置vsftp四.配置阿里云安全组 服务器环境 阿里云上的云服务器,操作系统为 ubuntu20.04。 安装步骤 一.创建用户 为什么需要创建用户? 这里的用户,指的是…...
03 卷积操作图片
一、均值滤波 # 卷积操作 # 输入图片. input, 必须是4维tensor(图片数量, 图片高度, 图片的宽度, 图片的通道数) # filters, 卷积核, 必须是4维的tensor(卷积核的高度和宽度, 输入图片的通道数, 卷积核的个数) # strides, 步长, 卷积核在图片的各个维度上的移动步长, (1, 1, 1,…...
软考:中级软件设计师:程序语言基础:表达式,标准分类,法律法规,程序语言特点,函数传值传址
软考:中级软件设计师:程序语言基础:表达式 提示:系列被面试官问的问题,我自己当时不会,所以下来自己复盘一下,认真学习和总结,以应对未来更多的可能性 关于互联网大厂的笔试面试,都…...
Java“牵手”1688商品详情数据,1688商品详情API接口,1688API接口申请指南
1688平台商品详情接口是开放平台提供的一种API接口,通过调用API接口,开发者可以获取1688商品的标题、价格、库存、月销量、总销量、库存、详情描述、图片等详细信息 。 获取商品详情接口API是一种用于获取电商平台上商品详情数据的接口,通过…...
stable diffusion实践操作-批次出图
系列文章目录 stable diffusion实践操作 文章目录 系列文章目录前言一、批次出图介绍1.1 webUI设置1.2 参数介绍 二、批次出图使用2.1 如何设置2.1 效果展示 总结 前言 本章主要介绍SD批次出图。 想要一次产生多张图片的时候使用。 一、批次出图介绍 1.1 webUI设置 1.2 参数…...
LeetCode热题100 【cpp】题解(一)哈希表和双指针
文章目录 1. 两数之和49. 字母异位词分组128. 最长连续序列283. 移动零11. 盛最多水的容器15. 三数之和42. 接雨水 题单链接: LeetCode 热题 100 1. 两数之和 leetcode题目链接 题解1:暴力枚举 时间复杂度: O ( n 2 ) O(n^2) O(n2) class …...
Python爬虫常见代理池实现和优化
在这篇文章中,我们将探讨Python爬虫中常见的代理池实现和优化方法。在爬取网站数据时,为防止被目标网站封禁IP,我们通常会使用代理IP进行访问。一个高效且稳定的代理池可以帮助我们轻松应对各种反爬策略。 首先,我们来了解一下…...
前端面试的话术集锦第 3 篇:进阶篇上
这是记录前端面试的话术集锦第三篇博文——进阶篇上,我会不断更新前端面试话术的博文。❗❗❗ 1 谈谈变量提升 当执⾏JS代码时,会⽣成执⾏环境,只要代码不是写在函数中的,就是在全局执⾏环境中,函数中的代码会产⽣函数执⾏环境,只此两种执⾏环境。 b() // call b conso…...
Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
Java数值运算常见陷阱与规避方法
整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能
1. 开发环境准备 安装DevEco Studio 3.1: 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK 项目配置: // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...
JDK 17 序列化是怎么回事
如何序列化?其实很简单,就是根据每个类型,用工厂类调用。逐个完成。 没什么漂亮的代码,只有有效、稳定的代码。 代码中调用toJson toJson 代码 mapper.writeValueAsString ObjectMapper DefaultSerializerProvider 一堆实…...
TJCTF 2025
还以为是天津的。这个比较容易,虽然绕了点弯,可还是把CP AK了,不过我会的别人也会,还是没啥名次。记录一下吧。 Crypto bacon-bits with open(flag.txt) as f: flag f.read().strip() with open(text.txt) as t: text t.read…...
pgsql:还原数据库后出现重复序列导致“more than one owned sequence found“报错问题的解决
问题: pgsql数据库通过备份数据库文件进行还原时,如果表中有自增序列,还原后可能会出现重复的序列,此时若向表中插入新行时会出现“more than one owned sequence found”的报错提示。 点击菜单“其它”-》“序列”,…...
python基础语法Ⅰ
python基础语法Ⅰ 常量和表达式变量是什么变量的语法1.定义变量使用变量 变量的类型1.整数2.浮点数(小数)3.字符串4.布尔5.其他 动态类型特征注释注释是什么注释的语法1.行注释2.文档字符串 注释的规范 常量和表达式 我们可以把python当作一个计算器,来进行一些算术…...
