在场景工程中新增虚拟机实例
虚拟机实例节点配置
通过向场景工程中的 quickvisor.cfg
配置文件添加 qv-guest
节点,可以新增一个虚拟机实例。虚拟机实例节点主要由三个部分组成,包括:虚拟机节点标识、虚拟机配置信息、虚拟处理器信息、虚拟机设备信息。
guest0 {
/* 虚拟机节点标识 */
compatible = "qv-guest";
/* 虚拟机配置信息 */
guest_name = "vm0";
guest_domain = "domain0";
guest_startup = <1>;
guest_window = <50>;
guest_permiss = <0x3>;
/* 虚拟处理器信息 */
guest_cpu_nr = <2>;
guest_cpu_pc = <0x40000000>;
guest_cpu_r0 = <0x42000000>;
/* 虚拟机设备信息 */
ram0 {
compatible = "qv-guest-device";
guest_device_type = "vdev";
guest_device_class = "ram";
guest_device_fw = "/guest-vm0.bin";
guest_aspace_gpa = <0x0 0x40000000>;
guest_aspace_siz = <0x0 0x02000000>;
};
};
虚拟机节点标识主要用于标识该设备树节点是一个虚拟机实例节点,该节点的 compatible
属性必须为 "qv-guest"
,该节点必须放置在 guests
节点下。虚拟机配置信息主要包括:
- guest_name:虚拟机的名字,虚拟机的名字在所有虚拟机中必须唯一,虚拟机名字的最大长度默认设置为 32 个字节,在编译 quickvisor_sdk 时可以修改最大长度限制。
- guest_domain:虚拟机所属的 CPU 域,虚拟机的 vcpu 只会被调度到 CPU 域所属的 pcpu 中,至于 vcpu 如何被调度到 pcpu 中,是由 CPU 域配置的调度算法决定的;
- guest_startup:虚拟机创建完成后是否自动启动,0 代表不启动,1 代表自动启动,对于创建后不启动的虚拟机可以通过 hypervisor 的命令行进行启动,或者由其它虚拟机调用 hypcall 唤醒。
- guest_window:虚拟机占用的 CPU 时间窗大小,50 代表占用 50 个 CPU 域 tick 的时间,CPU 域的 tick 时间 / tick 频率 由 domain 节点中的 dom_ticks 属性指定。
- guest_permiss:虚拟机的权限位,用于控制 hypcall 接口的访问权限,第 0 位置位代表可以通过 hypcall 调用获取 hypervisor 的信息,第 1 位置位代表可以调用管理虚拟机自身的 hypcall 接口,第 2 位置位代表可以调用管理器其他虚拟机的 hypcall 接口,其它位保留。
当前 quickvisor 仅支持部分虚拟处理器信息的配置,主要包括:
- guest_cpu_nr:虚拟机实例所包含的虚拟处理器个数;
- guest_cpu_pc:虚拟机启动时,虚拟处理器的开始执行的入口地址;
- guest_cpu_r0:虚拟机启动时,虚拟处理器 r0~r4 参数寄存器的初始值。
当前 quickvisor 仅支持虚拟机中虚拟设备和直通设备的配置,主要包括:
- compatible:虚拟机实例中所有设备节点的
compatible
属性必须为"qv-guest-device"
; - guest_device_type:用于标识该设备是虚拟设备(vdev)还是直通设备(pdev);
- guest_device_class:用于标识该设备所属的设备类型:rom、ram、irq、dev;
- guest_device_fw:用于标识该设备是否存在固件,虚拟机启动时将使用固件初始化设备内存;
- guest_aspace_gpa:用于标识该设备所占用的客户机物理地址空间;
- guest_aspace_siz:用于标识该设备所占用的客户机物理地址空间大小;
- guest_interrupt_guest:用于标识该设备所占用的客户机中断号列表;
虚拟机内存节点配置
虚拟机的内存有两种类型:ROM 和 RAM。ROM 类型的内存节点可以指定固件,该固件需要存放在 quickvisor 的 romfs 中,quickvisor 在创建 ROM 类型的内存设备时,会将指定的固件加载到该内存设备所属的物理内存中。虚拟机的 ROM 和 RAM 均使用设备节点进行描述,节点的 compatible
属性必须为 "qv-guest-device"
。虚拟机的物理内存有两种分配方式:自动分配和预分配,分别对应于虚拟内存设备和直通内存设备。虚拟内存设备的物理内存是由 quickvisor 自动分配的,直通内存设备的物理内存是由 quickvisor bsp 中预留给指定虚拟机使用的。
/**************************************/
/* 虚拟机所使用的内存由 quickvisor 分配 */
/**************************************/
rom01 {
compatible = "qv-guest-device";
guest_device_type = "vdev";
guest_device_class = "rom";
guest_device_fw = "/guest-vm0.bin";
guest_aspace_gpa = <0x0 0x8c400000>;
guest_aspace_siz = <0x0 0x01000000>;
};
ram02 {
compatible = "qv-guest-device";
guest_device_type = "vdev";
guest_device_class = "ram";
guest_aspace_gpa = <0x0 0x90000000>;
guest_aspace_siz = <0x0 0x20000000>;
};
/**************************************/
/* 虚拟机所使用 quickvisor bsp 预留的内存 */
/**************************************/
rom11 {
compatible = "qv-guest-device";
guest_device_type = "pdev";
guest_device_class = "rom";
guest_device_fw = "/guest-vm0.bin";
guest_aspace_gpa = <0x0 0x8a000000>;
guest_aspace_siz = <0x0 0x02000000>;
guest_aspace_hpa = <0x0 0x8a000000>;
};
ram12 {
compatible = "qv-guest-device";
guest_device_type = "pdev";
guest_device_class = "ram";
guest_aspace_gpa = <0x0 0x90000000>;
guest_aspace_siz = <0x0 0x20000000>;
guest_aspace_hpa = <0x0 0x90000000>;
};
虚拟内存设备 ram02
占用了从 <0x90000000>
起始,总共 <0x20000000>
字节的虚拟机物理地址空间。直通内存设备 ram12
占用了从 <0x90000000>
起始,总共 <0x20000000>
字节的虚拟机物理地址空间,并且这段地址空间被映射到了起始地址为 <0x90000000>
的真实物理内存。
虚拟机中断节点配置
虚拟机的中断节点指的是虚拟机的中断控制器节点,quickvisor 仅提供和物理硬件平台一致的虚拟中断控制器,即物理中断控制器为 GICv3 则虚拟机的中断控制器必须为 vGICv3,这一限制主要是减少虚拟设备的模拟以及尽可能使用硬件本身提供的虚拟化能力。
/*****************************************/
/* 在使用 GICv2 的平台上虚拟机必须使用 vGICv2 */
/*****************************************/
gic_dist {
compatible = "qv-guest-device";
guest_device_type = "vdev";
guest_device_class = "irq";
guest_device_model = "arm,vgicv2,dist";
guest_aspace_gpa = <0x0 0x08000000>;
guest_aspace_siz = <0x0 0x10000>;
};
gic_cpu0 {
compatible = "qv-guest-device";
guest_device_type = "pdev";
guest_device_class = "dev";
guest_aspace_gpa = <0x0 0x08010000>;
guest_aspace_siz = <0x0 0x10000>;
guest_aspace_hpa = <0x0 0x01460000>;
};
/*****************************************/
/* 在使用 GICv3 的平台上虚拟机必须使用 vGICv3 */
/*****************************************/
gic_dist {
compatible = "qv-guest-device";
guest_device_type = "vdev";
guest_device_class = "irq";
guest_device_model = "arm,vgicv3,dist";
guest_aspace_gpa = <0x0 0x01400000>;
guest_aspace_siz = <0x0 0x10000>;
};
gic_rdst0 {
compatible = "qv-guest-device";
guest_device_type = "vdev";
guest_device_class = "dev";
guest_device_model = "arm,vgicv3,rdst";
guest_aspace_gpa = <0x0 0x01480000>;
guest_aspace_siz = <0x0 0x20000>;
};
当虚拟机使用 vGICv2 时,gic_dist
必须设置为:type = "vdev"
,class = "irq"
,model = "arm,vgicv2,dist"
,设备占用的地址空间开发者可以自行调整;gic_cpu
必须设置为:type = "pdev"
,class = "dev"
,设备占用的地址空间必须被映射到 GICv2 的 virtual cpu interface registers
,gic_cpu
节点的个数必须和 vcpu 的个数相同。
当虚拟机使用 vGICv3 时,gic_dist
必须设置为:type = "vdev"
,class = "irq"
,model = "arm,vgicv3,dist"
,设备占用的地址空间开发者可以自行调整;gic_rdst
必须设置为:type = "pdev"
,class = "dev"
,model = "arm,vgicv3,rdst"
,设备占用的地址空间开发者可以自行调整。
虚拟机定时器节点配置
虚拟机定时器节点实质上是作为一个普通的虚拟设备被添加到虚拟机中的,在 ARM 平台下,当前仅支持 guest_device_model = "arm,vgtimer"
类型的定时器,虚拟中程序可以使用 generic timer
中的物理定时器和虚拟定时器。
gen_timer {
compatible = "qv-guest-device";
guest_device_type = "vdev";
guest_device_class = "dev";
guest_device_model = "arm,vgtimer";
};
虚拟机虚拟设备节点配置
虚拟设备节点的 guest_device_type
属性必须为 "vdev"
,且必须指定一个 guest_device_model
属性。以虚拟调试串口节点为例,虚拟设备节点的配置主要包括:地址空间配置、中断号配置和虚拟设备后端配置。地址空间是指虚拟的物理地址空间,中断号也是指虚拟机的中断控制器所属的中断号。对于虚拟串口设备而言,它的后端为虚拟串口线。quickvisor 目前仅支持 arm,pl011
型号的虚拟设备。
uart0 {
compatible = "qv-guest-device";
guest_device_type = "vdev";
guest_device_class = "dev";
guest_device_model = "arm,pl011";
guest_aspace_gpa = <0x0 0x09000000>;
guest_aspace_siz = <0x0 0x1000>;
guest_interrupt_guest = <86>;
guest_backend_name = "serial0";
guest_backend_chan = <0>;
};
虚拟机直通设备节点配置
直通设备节点的 guest_device_type
属性必须设置为 "pdev"
,必须将 guest_aspace_gpa
映射到物理设备的真实物理地址 guest_aspace_hpa
,必须将 guest_interrupt_guest
映射到物理设备的真实中断号 guest_interrupt_host
,中断号列表默认最多可以记录 16 个中断号,可以通过修改 quickvisor 的配置来修改这一限制。
/* pdev: ethernet@3200c000 */
net {
compatible = "qv-guest-device";
guest_device_type = "pdev";
guest_device_class = "dev";
guest_aspace_gpa = <0x0 0x3200c000>;
guest_aspace_siz = <0x0 0x2000>;
guest_aspace_hpa = <0x0 0x3200c000>;
guest_interrupt_guest = <87 88 89 90 60 61 62 63>;
guest_interrupt_host = <87 88 89 90 60 61 62 63>;
};
虚拟机虚拟网卡节点配置
QuickVisor 仅支持 virtio-v1.0 版本的 virtio-net 虚拟网卡,开发者可以配置虚拟网卡的 MAC 地址、MMIO 地址区间、中断号列表、以及连接到哪个虚拟网桥的哪个端口。
/********************************************************************/
/* compatible: "qv-hvdev" 标识这是一个 hypervisor 层的虚拟设备节点 */
/* hvdev_name: 用于配置该虚拟设备的名字,该名字在 hvdevs 中必须唯一 */
/* hvdev_type: "net-bridge" 标识这是一个虚拟网桥设备 */
/* hvdev_mem_size: 用于配置虚拟设备占用的内存大小,虚拟网桥一般配置为0 */
/* hvdev_port_num: 用于配置虚拟设备具有的端口总数,可根据实际连接数确定 */
/********************************************************************/
hvdevs {
...
hvdev4 {
compatible = "qv-hvdev";
hvdev_name = "bridge0";
hvdev_type = "net-bridge";
hvdev_mem_size = <0>;
hvdev_port_num = <8>;
};
...
};
/********************************************************************/
/* compatible: "qv-guest-device" 标识这是一个虚拟机的设备节点 */
/* guest_device_type: 用于标识这是一个虚拟设备还是一个直通设备 */
/* guest_device_class: 用于标识这个设备所属的设备类型 */
/* guest_device_model: 如果是虚拟设备,用于标识该虚拟设备的型号 */
/* guest_device_serial: 用于配置虚拟设备具有的硬件序列号,如 MAC 地址 */
/* guest_backend_name: 用于配置虚拟设备的后端,虚拟网卡的后端一般为虚拟网桥 */
/* guest_backend_chan: 用于配置虚拟设备连接到后端的哪个通道或端口上 */
/********************************************************************/
guest0 {
compatible = "qv-guest";
...
netdev {
compatible = "qv-guest-device";
guest_device_type = "vdev";
guest_device_class = "dev";
guest_device_model = "virtio,net";
guest_device_serial = "02:81:48:fd:de:80";
guest_aspace_gpa = <0x0 0x21e0000>;
guest_aspace_siz = <0x0 0x10000>;
guest_interrupt_guest = <88>;
guest_backend_name = "bridge0";
guest_backend_chan = <0>;
};
...
};
guest1 {
compatible = "qv-guest";
...
netdev {
compatible = "qv-guest-device";
guest_device_type = "vdev";
guest_device_class = "dev";
guest_device_model = "virtio,net";
guest_device_serial = "02:81:48:fd:de:81";
guest_aspace_gpa = <0x0 0x21e0000>;
guest_aspace_siz = <0x0 0x10000>;
guest_interrupt_guest = <89>;
guest_backend_name = "bridge0";
guest_backend_chan = <1>;
};
...
};
虚拟机虚拟磁盘节点配置
QuickVisor 仅支持 virtio-v1.0 版本的 virtio-blk 虚拟磁盘,开发者可以配置虚拟磁盘的 硬件序列号、MMIO 地址区间、中断号列表、以及连接到哪个后端存储设备。
/********************************************************************/
/* compatible: "qv-hvdev" 标识这是一个 hypervisor 层的虚拟设备节点 */
/* hvdev_name: 用于配置该虚拟设备的名字,该名字在 hvdevs 中必须唯一 */
/* hvdev_type: "blk-disk" 标识这是一个虚拟块设备 */
/* hvdev_mem_size: 用于配置虚拟设备占用的内存大小,虚拟块设备一般配置为0 */
/* hvdev_port_num: 用于配置虚拟设备具有的端口总数,虚拟块设备只能配置为1 */
/********************************************************************/
hvdevs {
...
hvdev5 {
compatible = "qv-hvdev";
hvdev_name = "disk-vm1";
hvdev_type = "blk-disk";
hvdev_mem_size = <0>;
hvdev_port_num = <1>;
hvdev_host_dev = "ramdisk-p1";
};
...
};
/********************************************************************/
/* compatible: "qv-guest-device" 标识这是一个虚拟机的设备节点 */
/* guest_device_type: 用于标识这是一个虚拟设备还是一个直通设备 */
/* guest_device_class: 用于标识这个设备所属的设备类型 */
/* guest_device_model: 如果是虚拟设备,用于标识该虚拟设备的型号 */
/* guest_device_serial: 用于配置虚拟设备具有的硬件序列号,如磁盘序列号 */
/* guest_backend_name: 用于配置虚拟设备的后端,虚拟磁盘的后端一般为虚拟块设备 */
/* guest_backend_chan: 用于配置虚拟设备连接到后端的哪个通道或端口上 */
/********************************************************************/
guest0 {
compatible = "qv-guest";
...
blkdev {
compatible = "qv-guest-device";
guest_device_type = "vdev";
guest_device_class = "dev";
guest_device_model = "virtio,blk";
guest_device_serial = "3435_4D30_4B66_3937_0025";
guest_aspace_gpa = <0x0 0x21f0000>;
guest_aspace_siz = <0x0 0x10000>;
guest_interrupt_guest = <90>;
guest_backend_name = "disk-vm1";
guest_backend_chan = <0>;
};
...
};
虚拟机共享内存节点配置
QuickVisor 支持裸共享内存设备用于虚拟机间通信。在 QuickVisor 配置文件中创建共享内存虚拟设备 shm-bank0
,然后在虚拟机实例中添加 "vmipc,vshm"
虚拟设备并绑定到共享内存虚拟设备即可。
/********************************************************************/
/* compatible: "qv-hvdev" 标识这是一个 hypervisor 层的虚拟设备节点 */
/* hvdev_name: 用于配置该虚拟设备的名字,该名字在 hvdevs 中必须唯一 */
/* hvdev_type: "shmem-device" 标识这是一个虚拟内存设备 */
/* hvdev_mem_size: 用于配置共享内存设备占用的内存大小,必须按页对齐 */
/* hvdev_port_num: 用于配置共享内存设备具有的端口总数,当前必须配置为 2 */
/********************************************************************/
hvdevs {
...
hvdev9 {
compatible = "qv-hvdev";
hvdev_name = "shm-bank0";
hvdev_type = "shmem-device";
hvdev_mem_size = <0x00001000>;
hvdev_port_num = <2>;
};
...
};
/********************************************************************/
/* compatible: "qv-guest-device" 标识这是一个虚拟机的设备节点 */
/* guest_device_type: 用于标识这是一个虚拟设备还是一个直通设备 */
/* guest_device_class: 用于标识这个设备所属的设备类型 */
/* guest_device_model: 如果是虚拟设备,用于标识该虚拟设备的型号 */
/* guest_aspace_siz: 虚拟内存设备必须和后端的共享内存设备保持一致的内存大小 */
/* guest_interrupt_guest: 当对端虚拟更新共享内存后可以通过 hvc 触发此中断 */
/* guest_backend_name: 用于指定当前虚拟内存设备所绑定的后端共享内存设备 */
/********************************************************************/
guest0 {
compatible = "qv-guest";
...
shmdev {
compatible = "qv-guest-device";
guest_device_type = "vdev";
guest_device_class = "dev";
guest_device_model = "vmipc,vshm";
guest_aspace_gpa = <0x0 0x02200000>;
guest_aspace_siz = <0x0 0x1000>;
guest_interrupt_guest = <167>;
guest_backend_name = "shm-bank0";
guest_backend_chan = <0>;
};
...
};
guest1 {
compatible = "qv-guest";
...
shmdev {
compatible = "qv-guest-device";
guest_device_type = "vdev";
guest_device_class = "dev";
guest_device_model = "vmipc,vshm";
guest_aspace_gpa = <0x0 0x0a002000>;
guest_aspace_siz = <0x0 0x1000>;
guest_interrupt_guest = <89>;
guest_backend_name = "shm-bank0";
guest_backend_chan = <1>;
};
...
};