1)什么是HAB,他用来干什么?
如果你了解virtIO的话,就很容易明白HAB是用来干什么的。一句话来说,HAB实际作用和virtIO差不多。以高通8155(host qnx+guest安卓)为例,所有硬件外设驱动都在qnx端,那么安卓端要使用外设(比如触摸输入设备、摄像头设备等),就必须有一套host与guest通信的机制,可以使得qnx可以把数据共享给安卓。VirtIO和HAB都属于这种通信机制。举例说明,可以看到8155平台输入设备、块设备等走的virtIO机制,摄像头设备、硬编解码设备等走的HAB机制。
如下图所示,qnx,quest_shm@开头的都是HAB physical channel对应的共享内存设备树节点,qnx,quest_shm@xxx节点保存有共享内存的地址(即guestOS看到的物理地址,实际是hostOS的虚拟地址)和通信相关的中断向量信息(guestOS和hostOS通过中断通知对方共享内存上有数据处理)。
2)上面的设备树节点是如何被添加的?
Hypervisor进程将设备树+和guestOS加载到内存,然后vm_enry,触发上下文切换,cpu切换到guestOS运行,hyervisor在加载设备树的同时会动态将上述设备树节点添加到设备树。
3)HAB如何确认交互目标?
首先是不同服务的physical channel不同,比如摄像头服务有专门的physical channel,硬编解码服务也有专门的物理channel。不同的物理chanel用MMID标志。
#define MM_CAM_1 201//摄像头
#define MM_VID 501//硬编解码
其次是virtual channel,不同的vcID对应不同的业务。假设Front end(也即guestOS端)想start/stop控制back-end端的摄像头。那么他会在自己这段给自己分配一个vcid,然后再发起一个分配请求到back-end.back-end收到请求后,也会给自己分配一个vcid,这样俩端分别保存有自己的vcid和对端的vcid。相当于俩端建立了一个连接。
Vitual channel通道建立流程如下图:
最终本端的vcid会返回给用户层,后续用户都使用该vcid与对端通信。
用户层uhab.c重点接口:可以看到每个接口都有一个handle参数,他就是本端的vcid
int32_t habmm_socket_open(int32_t *handle, uint32_t mm_ip_id,
uint32_t timeout, uint32_t flags)
int32_t habmm_socket_close(int32_t handle)
int32_t habmm_socket_send(int32_t handle, void *src_buff,
uint32_t size_bytes, uint32_t flags)
int32_t habmm_socket_recv(int32_t handle, void *dst_buff, uint32_t *size_bytes,uint32_t timeout, uint32_t flags)
备注:用户空间的接口名都有一个socket,但实际与socket没什么关系。