1.  VirtIO与VirtualDevice概念

1.1 VirtIO 

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

1.2 Qnx Virtual Device

上图,QNX 虚拟机管理程序 2.0 概述,介绍虚拟机以及Guest访问虚拟或者物理设备的一些方式。

虚拟设备可以模拟物理设备,也可以是半虚拟化设备(不存在完全对应的物理设备的虚拟设备)。虚拟设备(vdev)仅存在于虚拟化环境中。它们是在虚拟机管理程序层运行的软件代码,可以模拟物理设备,也可以提供物理设备提供的功能,而无需模拟任何特定的物理设备。若要使用 vdev,Guest OS需要驱动程序,就像需要驱动程序在非虚拟化环境中使用物理设备一样。

VM(虚拟机) 定义虚拟硬件(Virtual devices),并将其和直通硬件(Pass-through devices)呈现给Guest OS,Guest OS不需要知道它是在VM 中运行还是在硬件直接定义的环境中运行。

网址:QNX Hypervisor 

2. QNX Vdev-VirtIO

代码路径: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

3.  QNX vdev-virtio-i2c

问题://带着问题分析。

  • 依照VirtIO框架,是否Hypervisor Host OS 与 Guset OS都需要Driver?
  • 如果都集成了Driver,那么Gust OS driver跟Host OS driver 有直接联系? 比如接口以及数据结构一致性。
  • 依照VirtIO框架,是否Hypervisor Host OS 与 Guset OS都需要i2c device Driver?(某个设备)
  • 如果只配置了Guest OS I2C及驱动,Guest OS是否可以与硬件通讯?

3.1 原理

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而改变驱动。

3.1.1 virtio-i2c框架

下图为:Virtio-i2c 架构(Hypervisor 为ARCN)

Hypervisor 技术不同,但是virtio-i2c技术确是一致的。 以virtio作为桥梁,实现HOST OS的BE与GestOS FE之间的通讯。

3.1.2 QNX Hypervisor virtio-i2c框架

经过梳理框架图绘制如下:

 FE i2c driver <-> BE i2c driver <--> i2c client <-> i2c resource manager <-> i2c phsyical driver

3.1.3 代码实现框架

依据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.

3.2 使用指南 

上面也说了,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 

4.  实操配置

以IMU Sensor芯片st_asm330lhh 为例。

4.1 QNX I2C设备实际操作

4.1.1 硬件设计

 

 4.1.2 QUP查表-IO映射关系

4.1.3 资源配置

4.1.4 I2C设备配置 

纠正描述: 上图为QUP_SE10 

4.1.5 IO配置(上拉/下拉等)

4.1.6 上电,测试

查询规格书获悉: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
#

读取数据正确。 

4.2 通过VirtIO-I2C  Androd端 I2C设备实际操作  

首先要明白Vdev的原理,Vdev说白了就是虚拟设备---对GVM而言,但是对于PVM来讲他是一个实际的物理设备,VirtIO的作用就是将PVM的物理设备在GVM中虚拟一个设备出来。虚拟设备与物理设备的之间通讯是跨OS的,通讯桥梁是VirtIO

如下图所示:

虚拟I2C 同样拿st_asm330lhh sensor i2c为例。

4.2.1 依照上面思路,确认QNX 环境下的I2C配置

保证QNX环境下I2C3 功能是OK的。具体操作按照<4.1 QNX I2C设备实际操作>步骤来。

确保:

  • 设备存在://如下图

  •  I2C Device通讯正常: //如下图

4.2.2 修改虚拟机配置

配置文件:/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

4.2.3  如果没有vdev-virtio-i2c.so,ftpput一个到qnx fs中

编译输出后的路径: 

qnx_ap/install/aarch64le/lib/dll/vdev-virtio-i2c.so

4.2.4  修改GVM中的DTS配置 //如果没有就需要增加

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 = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
		status = "okay";
	};

4.2.5  编译更新,测试验证

查看log信息:如下,内核log可以看出,virtio-i2c驱动注册OK

查看设备

 

验证通讯

 

O(∩_∩)O哈哈~, 是不是很简单!。首先要理解原理。代码配置只不过就是流程化工作。

点到为止,举一反三,其他virtio 设备一样!

 欢迎后期订阅 <智能座舱核心技术开发> 专栏。Thanks♪(・ω・)ノ

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐