VirtualBox中HGCM通信机制分析(SharedFolder)

VirtualBox中HGCM通信机制分析(SharedFolder)

HGCM全称Host Guest Communication Manager。virtualbox暴露出一个虚拟pci设备VMMDev给客户机,用作宿主机与客户机之间进行数据通信的通道。


HGCM的一个重要的使用场景在共享文件夹功能,因此下文中以共享文件夹(SharedFolder)为例,通过数据的流向来分析hgcm通信过程。

共享文件夹功能简要的分为以下几块:

  1. guest端文件驱动
  2. guest端HGCM模块
  3. host端HGCM模块
  4. host端文件服务模块

本文重点在分析HGCM的工作流程,即guest端HGCM模块、host端HGCM模块,而guest端文件驱动以及host端文件服务模块则简略而过

HGCM通信的发起者–guest端文件驱动
  • 驱动入口初始化(以window客户端为例)
DriverEntry		// Additions/WINNT/SharedFolders/driver/vbsf.c
    vbsfInitMRxDispatch
    	// --snip--
    	VBoxMRxDispatch.MRxQueryDirectory = VBoxMRxQueryDirectory;
		VBoxMRxDispatch.MRxQueryFileInfo = VBoxMRxQueryFileInfo;
		// --snip--
    
  • 以函数VBoxMRxQueryFileInfo为例,分析其调用hgcm的流程
VBoxMRxQueryFileInfo
    // Additions/common/VBoxGuest/lib/VBoxGuestR0LibSharedFolders.c
    VbglR0SfFsInfo( , , , SHFL_INFO_GET | SHFL_INFO_FILE, &cbHGCMBuffer, (PSHFLDIRINFO)pHGCMBuffer);
		// 初始化请求相关信息,
		// 请求类型为SHFL_FN_INFORMATION --> include/VBox/shflsvc.h, 在host端文件服务模块会根据该类型来处理请求
		VBOX_INIT_CALL(&data.callInfo, INFORMATION, pClient);
		
		// Additions/common/VBoxGuest/lib/VBoxGuestR0LibHGCM.cpp
		// 执行对应的hgcm请求
		VbglR0HGCMCallRaw(pClient->handle, &data.callInfo, sizeof(data));
            // 发送irp请求,类型为VBGL_IOCTL_HGCM_CALL,此处仍位于kernel部分
			// PS,应用程序如VBoxService的自动挂载共享文件夹(VBoxServiceAutoMount.cpp),最终也会调用到类似代码(如VbglR3SharedFolderGetName)
            VbglR0IdcCallRaw(&handle->IdcHandle, VBGL_IOCTL_HGCM_CALL(cbData), &pData->Hdr, cbData);
HGCM数据流–guest端HGCM模块
  • irp请求VBGL_IOCTL_HGCM_CALL最终进入到内核ioctl
// Additions/common/VBoxGuest/VBoxGuest.cpp
VGDrvCommonIoCtl
    vgdrvIoCtl_HGCMCallWrapper
    	vgdrvIoCtl_HGCMCallInner
    		// 此处为关键函数,在这里初始化HGCM Call、发送HGCM Call、回写返回数据。
    		VbglR0HGCMInternalCall(pInfo, cbInfo, fFlags, vgdrvHgcmAsyncWaitCallback, pDevExt, cMillies);
  • VbglR0HGCMInternalCall中通过写io的方式,vm-exit退出到host
// Additions/common/VBoxGuest/lib/VBoxGuestR0LibHGCMInternal.cpp
VbglR0HGCMInternalCall
    vbglR0HGCMInternalPreprocessCall
    
    // vboxguest端实现了一套简单的小内存管理机制,且VbglR0GRAlloc添加了一层VMMDevRequestHeader包头
    // 具体详见Additions/common/VBoxGuest/lib/VBoxGuestR0LibGenericRequest.cpp
    VbglR0GRAlloc
    
    // 主要工作是将guest空间的虚拟地址转(VMMDevHGCMParmType_LinAddr)化为物理地址(VMMDevHGCMParmType_PageList)
    vbglR0HGCMInternalInitCall
    
    vbglR0HGCMInternalDoCall(pHGCMCall, pfnAsyncCallback, pvAsyncData, u32AsyncData, &fLeakIt);
		rc = VbglR0GRPerform(&pHGCMCall->header.header);
			// 对虚拟设备VMMDev执行IO调用,产生vm-exit事件,回到host
			ASMOutU32(g_vbgldata.portVMMDev + VMMDEV_PORT_OFF_REQUEST, (uint32_t)PhysAddr);
		
        // 若返回值为异步标志VINF_HGCM_ASYNC_EXECUTE,则执行异步的Callback
		// fnAsyncCallback主要工作是等待pHGCMCall->header.fu32Flags被置位VBOX_HGCM_REQ_DONE,该标志是host端HGCM模块完成所有工作时写入
        fnAsyncCallback(&pHGCMCall->header, pvAsyncData, u32AsyncData);

		// 若标志VBOX_HGCM_REQ_DONE超时,则发送VMMDevReq_HGCMCancel2请求
		VbglR0GRAlloc((VMMDevRequestHeader **)&pCancelReq, sizeof(*pCancelReq), VMMDevReq_HGCMCancel2);
    
    vbglR0HGCMInternalCopyBackResult

至此HGCM的guest端的请求过程已完成,下一步即将到达host。

  • Guest虚拟PCI设备VMMDev

    客户机设备驱动中对虚拟设备对应portio读写,会被映射到virtualbox注册的回调函数,在host端HGCM模块中会详细分析

// Additions/common/VBoxGuest/VBoxGuest.cpp
vgdrvNtSetupDevice
    // scan pci的设备资源,这里VMMDev提供Port资源
        // CmResourceTypePort、CmResourceTypeInterrupt、CmResourceTypeMemory、
    vgdrvNtScanPCIResourceList

    // 设备的物理地址映射为虚拟地址
    vgdrvNtMapVMMDevMemory

    VGDrvCommonInitDevExtResources(&pDevExt->Core,
                                   pDevExt->Core.IOPortBase,
                                   pvMMIOBase, cbMMIO,
                                   vgdrvNtVersionToOSType(g_enmVGDrvNtVer),
                                   VMMDEV_EVENT_MOUSE_POSITION_CHANGED);

        VbglR0InitPrimary(pDevExt->IOPortBase, (VMMDevMemory *)pDevExt->pVMMDevMemory);
			// 初始化小内存管理的链表头
            vbglR0InitCommon()
            
            // 初始化全局变量g_vbgldata,后续hgcm相关的地层调用通过该结构体进行
            g_vbgldata.portVMMDev    = portVMMDev;
            g_vbgldata.pVMMDevMemory = pVMMDevMemory;
            g_vbgldata.status        = VbglStatusReady;
HGCM数据流–host端HGCM模块

host端vmmdev设备初始化

// src/VBox/Devices/build/VBoxDD.cpp
VBoxDevicesRegister
    // src/VBox/Devices/VMMDev/VMMDev.cpp
    g_DeviceVMMDev
        // src/VBox/Devices/VMMDev/VMMDevHGCM.cpp
        vmmdevConstruct
    		// vmmdev一起注册了IO、MEM、
    		PDMDevHlpPCIIORegionRegister(pDevIns, 0, 0x20, PCI_ADDRESS_SPACE_IO, vmmdevIOPortRegionMap);

// src/VBox/Devices/VMMDev/VMMDev.cpp
vmmdevIOPortRegionMap
    // hgcm是vmmdev request众多功能之一,具体见vmmdevReqDispatcher中的case项
	PDMDevHlpIOPortRegister(xxx, GCPhysAddress + VMMDEV_PORT_OFF_REQUEST, 1,xxx, vmmdevRequestHandler, NULL, NULL, NULL, "VMMDev Request Handler");
// src/VBox/Devices/VMMDev/VMMDev.cpp
vmmdevRequestHandler
    vmmdevReqHandler_HGCMConnect
    vmmdevReqHandler_HGCMDisconnect
    
    // 核心函数
    vmmdevReqHandler_HGCMCall
    	// src/VBox/Devices/VMMDev/VMMDevHGCM.cpp
    	vmmdevHGCMCall

TODO:未完待续

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值