virtio 是一种 I/O 半虚拟化解决方案,是一套通用 I/O 设备虚拟化的程序,是对半虚拟化Hypervisor 中的一组通用 I/O 设备的抽象。提供了一套上层应用与各 Hypervisor 虚拟化设备(KVM,Xen,VMware等)之间的通信框架和编程接口,减少跨平台所带来的兼容性问题,大大提高驱动程序开发效率。
在完全虚拟化的解决方案中,guest VM 要使用底层 host 资源,需要 Hypervisor 来截获所有的请求指令,然后模拟出这些指令的行为,这样势必会带来很多性能上的开销。半虚拟化通过底层硬件辅助的方式,将部分没必要虚拟化的指令通过硬件来完成,Hypervisor 只负责完成部分指令的虚拟化,要做到这点,需要 guest 来配合,guest 完成不同设备的前端驱动程序,Hypervisor 配合 guest 完成相应的后端驱动程序,这样两者之间通过某种交互机制就可以实现高效的虚拟化过程。
图:ACRN Kernel Land Virtio Framework
参考:
virtio 简介 - bakari - 博客园 (cnblogs.com)
ACRN Hypervisor
上图,QNX 虚拟机管理程序 2.0 概述,介绍虚拟机以及Guest访问虚拟或者物理设备的一些方式。
虚拟设备可以模拟物理设备,也可以是半虚拟化设备(不存在完全对应的物理设备的虚拟设备)。虚拟设备(vdev)仅存在于虚拟化环境中。它们是在虚拟机管理程序层运行的软件代码,可以模拟物理设备,也可以提供物理设备提供的功能,而无需模拟任何特定的物理设备。若要使用 vdev,Guest OS需要驱动程序,就像需要驱动程序在非虚拟化环境中使用物理设备一样。
VM(虚拟机) 定义虚拟硬件(Virtual devices),并将其和直通硬件(Pass-through devices)呈现给Guest OS,Guest OS不需要知道它是在VM 中运行还是在硬件直接定义的环境中运行。
网址:QNX Hypervisor
代码路径:qnx_ap/AMSS/platform/vm/vdev
目录结构:
.├── Makefile
├── vdev-glink-ssr
│ ├── aarch64
│ ├── common.mk
│ ├── Makefile
│ ├── pinfo.mk
│ ├── protected
│ ├── vdev.c
│ └── vdev.use
├── vdev-io
│ ├── 8155
│ ├── common.mk
│ ├── inc
│ ├── main.c
│ ├── Makefile
│ └── protected
├── vdev-minidump
│ ├── aarch64
│ ├── common.mk
│ ├── Makefile
│ ├── vdev-minidump.c
│ └── vdev-minidump.use
├── vdev-mmu-s2
│ ├── aarch64
│ ├── common.mk
│ ├── main.c
│ ├── Makefile
│ ├── pinfo.mk
│ ├── protected
│ └── vdev-mmu-s2.use
├── vdev-msm
│ ├── aarch64
│ ├── common.mk
│ ├── Makefile
│ ├── vdev-msm.c
│ └── vdev-msm.use
├── vdev-virtio-clock
│ ├── aarch64
│ ├── common.mk
│ ├── Makefile
│ ├── vdev-virtio-clock.c
│ └── vdev-virtio-clock.use
├── vdev-virtio-fastrpc
│ ├── aarch64
│ ├── common.mk
│ ├── inc
│ ├── Makefile
│ ├── src
│ └── vdev-virtio-fastrpc.use
├── vdev-virtio-i2c
│ ├── aarch64
│ ├── common.mk
│ ├── Makefile
│ ├── vdev-virtio-i2c.c
│ └── vdev-virtio-i2c.use
├── vdev-virtio-keyboard
│ ├── aarch64
│ ├── common.mk
│ ├── inc
│ ├── Makefile
│ ├── vdev-virtio-keyboard.c
│ └── vdev-virtio-keyboard.use
├── vdev-virtio-regulator
│ ├── aarch64
│ ├── common.mk
│ ├── Makefile
│ ├── vdev-virtio-regulator.c
│ └── vdev-virtio-regulator.use
└── vdev-virtio-spmi
├── aarch64
├── common.mk
├── Makefile
├── vdev-virtio-spmi.c
└── vdev-virtio-spmi.use
看Code可以看出Vdev 基本带着Virtio,这俩是如胶似漆啊。  ̄□ ̄||
原理与Linux实现类似,不做过多介绍,详细看QNX官网开发手册。
GusetOS与Hardware之间数据传递实现方式://下图,通过virtqueues
图:数据从GuestOS中的虚拟队列传递到硬件,GuesOS和qvm进程共享相同的地址空间。
详细: QNX Vdev-VirIO
问题://带着问题分析。
virtio - I2C提供了一个虚拟I2C适配器,支持将多个本机I2C适配器下的多个从设备映射到一个virtio I2C适配器。从设备的地址没有改变。Virtio-i2c还提供了一个为从设备添加acpi节点的接口,这样客户操作系统中的从设备驱动程序就不需要更改了。
英文原文:Virtio-i2c provides a virtual I2C adapter that supports mapping multiple slave devices under multiple native I2C adapters to one virtio I2C adapter. The address for the slave device is not changed. Virtio-i2c also provides an interface to add an acpi node for slave devices so that the slave device driver in the guest OS does not need to change.
简单理解:Guest OS/User OS(座舱:Android) i2c设备驱动该咋写就咋写,不需要因为是virtio-i2c而改变驱动。
下图为:Virtio-i2c 架构(Hypervisor 为ARCN)
Hypervisor 技术不同,但是virtio-i2c技术确是一致的。 以virtio作为桥梁,实现HOST OS的BE与GestOS FE之间的通讯。
经过梳理框架图绘制如下:
FE i2c driver <-> BE i2c driver <--> i2c client <-> i2c resource manager <-> i2c phsyical driver
依据3.1.2 框架图,梳理SA8155 virtio-i2c代码实现。
QNX: //BE
qnx_ap/AMSS/platform/vm/vdev/vdev-virtio-i2c/vdev-virtio-i2c.c
注册接口:
static void __attribute__((constructor)) vio_i2c_register(void)
{
static const char * const vio_i2c_options[] = { "verbose", "device", NULL };
static struct vdev_factory vio_i2c_factory = {
.next = NULL, // patched
.control = vio_i2c_control,
.vread = vio_i2c_vread,
.vwrite = vio_i2c_vwrite,
.option_list = vio_i2c_options,
.name = NULL, // patched
.factory_flags = VFF_NONE,
.acc_sizes = 1u << sizeof(uint32_t),
.extra_space = sizeof(vio_i2c_dev_t),
.safety = VDEV_SAFETY_SELECTED,
};
vdev_register_factory(&vio_i2c_factory, QVM_VDEV_ABI);
}
open:
vio_i2c_control->i2c_open
write/read
void *i2c_transfer(void * arg) {
...
case DESC_IDX_BUF:
if (!req) {
QVM_LOG(VIOLOG_ERROR, dev,"request pointer is NULL");
ret = -1;
break;
}
if (req->len == 0) {
QVM_LOG(VIOLOG_ERROR, dev,"request len is zero");
ret = -1;
break;
}
switch (req->type) {
case VIO_I2C_READ:
ret = i2c_read(dev->fd, (void*)src, req->len);
break;
case VIO_I2C_WRITE:
ret = i2c_write(dev->fd, (void*)src, req->len);
break;
case VIO_I2C_RDWR:
ret = i2c_combined_writeread(dev->fd, (void*)src, req->len, \
(void*)src + req->len, req->total_len - req->len);
break;
default:
QVM_LOG(VIOLOG_ERROR, dev,"invalid request type");
break;
}
break;
...
}
LA(Android): FE
android/kernel/drivers/i2c/busses/virtio-i2c.
上面也说了,GustOS 使用Vdev时候无需关注这个device在什么环境运行的,就像使用常规设备一样使用。
问题回答:
- 依照VirtIO框架,是否Hypervisor Host OS 与 Guset OS都需要virtio-i2c Driver?
A: 需要
- 如果都集成了Driver,那么Gust OS driver跟Host OS driver 有直接联系? 比如接口以及数据结构一致性
A: 接口以及数据存在一致性。(都是基于VirtIO)
- 依照VirtIO框架,是否Hypervisor Host OS 与 Guset OS都需要i2c device Driver?(某个设备)
A: 不需要,既然i2c已经虚拟了,GuestOS 添加I2C 设备直接使用即可,该怎么用就怎么 用,无需关注该I2C是虚拟还是实质的。
- 如果只配置了Guest OS I2C及驱动,Guest OS是否可以与硬件通讯?
A: 除非设置了直通模式,或者是Vhsot-user模式,否则不行。
TODO
以IMU Sensor芯片st_asm330lhh 为例。
纠正描述: 上图为QUP_SE10
查询规格书获悉:st_asm330lhh 芯片i2c地址为0x6a
那么读写寄存器看看:
# i2cdbgr /dev/i2c3 0x6a read 1 0x02 1
addr: 0x2 data : 0x3f
# i2cdbgr /dev/i2c3 0x6a read 1 0x0f 1
addr: 0xf data : 0x6b
#
读取数据正确。
首先要明白Vdev的原理,Vdev说白了就是虚拟设备---对GVM而言,但是对于PVM来讲他是一个实际的物理设备,VirtIO的作用就是将PVM的物理设备在GVM中虚拟一个设备出来。虚拟设备与物理设备的之间通讯是跨OS的,通讯桥梁是VirtIO
如下图所示:
虚拟I2C 同样拿st_asm330lhh sensor i2c为例。
保证QNX环境下I2C3 功能是OK的。具体操作按照<4.1 QNX I2C设备实际操作>步骤来。
确保:
配置文件:/vm/images/linux-la.config
添加内容如下:
vdev vdev-virtio-i2c.so loc 0x1c270000 intr gic:100 verbose 3 device i2c3
大概描述下:
vdev-virtio-i2c.so //QNX自带的code,编译成so
loc 0x1c270000 //vdev地址 -- 与GVM绑定的,自行定义,只要不冲突就可以
intr gic:100 //虚拟中断号,自行定义,只要不冲突就可以
verbose 3 device i2c3 //参数 --- 具体看vdev-virtio-i2c.c代码
i2c3 就是需要虚拟的实际设备 /dev/i2c3
编译输出后的路径:
qnx_ap/install/aarch64le/lib/dll/vdev-virtio-i2c.so
devicetree 路径:android/vendor/qcom/proprietary/devicetree
搜索发现virtio 配置文件是 quin-vm-common.dtsi
./qcom/sa8155-vm.dtsi:#include "quin-vm-common.dtsi"
找到恰当的位置添加如下内容:
方便大家copy,贴code
i2c_bus: virtio-i2c@1c270000 {
compatible = "virtio,mmio";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x1c270000 0x100>;
interrupts = ;
status = "okay";
};
查看log信息:如下,内核log可以看出,virtio-i2c驱动注册OK
查看设备
验证通讯
O(∩_∩)O哈哈~, 是不是很简单!。首先要理解原理。代码配置只不过就是流程化工作。
点到为止,举一反三,其他virtio 设备一样!
❤ 欢迎后期订阅 <智能座舱核心技术开发> 专栏。Thanks♪(・ω・)ノ