HGCMInternal.cpp revision 0c88062033e31a82f230397ded75f2627b1132eb
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync/* $Revision$ */
2291faee92ebb5cc9722cd3f22e499900a5a411fvboxsync/** @file
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * VBoxGuestLib - Host-Guest Communication Manager internal functions, implemented by VBoxGuest
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync */
2291faee92ebb5cc9722cd3f22e499900a5a411fvboxsync
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync/*
9496b6f77d66eb89f088668752b8838d578d6e10vboxsync * Copyright (C) 2006-2007 Oracle Corporation
9496b6f77d66eb89f088668752b8838d578d6e10vboxsync *
9496b6f77d66eb89f088668752b8838d578d6e10vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
9496b6f77d66eb89f088668752b8838d578d6e10vboxsync * available from http://www.virtualbox.org. This file is free software;
9496b6f77d66eb89f088668752b8838d578d6e10vboxsync * you can redistribute it and/or modify it under the terms of the GNU
9496b6f77d66eb89f088668752b8838d578d6e10vboxsync * General Public License (GPL) as published by the Free Software
9496b6f77d66eb89f088668752b8838d578d6e10vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync *
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync * The contents of this file may alternatively be used under the terms
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync * of the Common Development and Distribution License Version 1.0
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync * VirtualBox OSE distribution, in which case the provisions of the
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync * CDDL are applicable instead of those of the GPL.
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync *
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync * You may elect to license modified versions of this file under the
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * terms and conditions of either the GPL or the CDDL or both.
0486df2e670fa5d25ca947fd92b19dd54229692dvboxsync */
0486df2e670fa5d25ca947fd92b19dd54229692dvboxsync
2c18e977ea3600677b8c58c9de0caa61792ba428vboxsync/* Entire file is ifdef'ed with VBGL_VBOXGUEST */
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync#ifdef VBGL_VBOXGUEST
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync/*******************************************************************************
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync* Header Files *
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync*******************************************************************************/
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync#define LOG_GROUP LOG_GROUP_HGCM
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync#include "VBGLInternal.h"
6cf17994e7631a6e8711c17848689c2064d5ccacvboxsync#include <iprt/alloca.h>
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync#include <iprt/asm.h>
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync#include <iprt/assert.h>
6cf17994e7631a6e8711c17848689c2064d5ccacvboxsync#include <iprt/mem.h>
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync#include <iprt/memobj.h>
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync#include <iprt/string.h>
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync#include <iprt/thread.h>
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync#include <iprt/time.h>
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync/*******************************************************************************
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync* Defined Constants And Macros *
0c8b774aca1168c2007424a49f6fa159fc23e42bvboxsync*******************************************************************************/
0c8b774aca1168c2007424a49f6fa159fc23e42bvboxsync/** The max parameter buffer size for a user request. */
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync#define VBGLR0_MAX_HGCM_USER_PARM (24*_1M)
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync/** The max parameter buffer size for a kernel request. */
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync#define VBGLR0_MAX_HGCM_KERNEL_PARM (16*_1M)
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync#ifdef RT_OS_LINUX
f4ccb18a71e0e531719734918583f84fbc72ebfevboxsync/** Linux needs to use bounce buffers since RTR0MemObjLockUser has unwanted
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync * side effects. */
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync# define USE_BOUNCE_BUFFERS
b0a3d0ec5780199a2f379da63c59ccf48f1a73b9vboxsync#endif
b0a3d0ec5780199a2f379da63c59ccf48f1a73b9vboxsync
b0a3d0ec5780199a2f379da63c59ccf48f1a73b9vboxsync
b0a3d0ec5780199a2f379da63c59ccf48f1a73b9vboxsync/*******************************************************************************
b0a3d0ec5780199a2f379da63c59ccf48f1a73b9vboxsync* Structures and Typedefs *
b0a3d0ec5780199a2f379da63c59ccf48f1a73b9vboxsync*******************************************************************************/
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync/**
b0a3d0ec5780199a2f379da63c59ccf48f1a73b9vboxsync * Lock info structure used by VbglR0HGCMInternalCall and its helpers.
b0a3d0ec5780199a2f379da63c59ccf48f1a73b9vboxsync */
f4ccb18a71e0e531719734918583f84fbc72ebfevboxsyncstruct VbglR0ParmInfo
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync{
b0a3d0ec5780199a2f379da63c59ccf48f1a73b9vboxsync uint32_t cLockBufs;
b0a3d0ec5780199a2f379da63c59ccf48f1a73b9vboxsync struct
b0a3d0ec5780199a2f379da63c59ccf48f1a73b9vboxsync {
b0a3d0ec5780199a2f379da63c59ccf48f1a73b9vboxsync uint32_t iParm;
b0a3d0ec5780199a2f379da63c59ccf48f1a73b9vboxsync RTR0MEMOBJ hObj;
b0a3d0ec5780199a2f379da63c59ccf48f1a73b9vboxsync#ifdef USE_BOUNCE_BUFFERS
b0a3d0ec5780199a2f379da63c59ccf48f1a73b9vboxsync void *pvSmallBuf;
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync#endif
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync } aLockBufs[10];
95714accc37694e6f4ae3c646dd01f3827c3d260vboxsync};
0c8b774aca1168c2007424a49f6fa159fc23e42bvboxsync
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync
771761cda2c81e899526a0dce22c8cd2510fff82vboxsync
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsync/* These functions can be only used by VBoxGuest. */
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsyncDECLVBGL(int) VbglR0HGCMInternalConnect (VBoxGuestHGCMConnectInfo *pConnectInfo,
53e1c27c7564c45ad0b92676ddea561591a3e869vboxsync PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData)
53e1c27c7564c45ad0b92676ddea561591a3e869vboxsync{
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync VMMDevHGCMConnect *pHGCMConnect;
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync int rc;
b459362b1c9b5ce5e6bf4ceb32ffe1294c08be07vboxsync
b459362b1c9b5ce5e6bf4ceb32ffe1294c08be07vboxsync if (!pConnectInfo || !pfnAsyncCallback)
b459362b1c9b5ce5e6bf4ceb32ffe1294c08be07vboxsync return VERR_INVALID_PARAMETER;
53e1c27c7564c45ad0b92676ddea561591a3e869vboxsync
53e1c27c7564c45ad0b92676ddea561591a3e869vboxsync pHGCMConnect = NULL;
b459362b1c9b5ce5e6bf4ceb32ffe1294c08be07vboxsync
53e1c27c7564c45ad0b92676ddea561591a3e869vboxsync /* Allocate request */
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync rc = VbglGRAlloc ((VMMDevRequestHeader **)&pHGCMConnect, sizeof (VMMDevHGCMConnect), VMMDevReq_HGCMConnect);
53e1c27c7564c45ad0b92676ddea561591a3e869vboxsync
53e1c27c7564c45ad0b92676ddea561591a3e869vboxsync if (RT_SUCCESS(rc))
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync {
0c8b774aca1168c2007424a49f6fa159fc23e42bvboxsync /* Initialize request memory */
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsync pHGCMConnect->header.fu32Flags = 0;
0c8b774aca1168c2007424a49f6fa159fc23e42bvboxsync
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsync memcpy (&pHGCMConnect->loc, &pConnectInfo->Loc, sizeof (HGCMServiceLocation));
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsync pHGCMConnect->u32ClientID = 0;
0c8b774aca1168c2007424a49f6fa159fc23e42bvboxsync
0c8b774aca1168c2007424a49f6fa159fc23e42bvboxsync /* Issue request */
0c8b774aca1168c2007424a49f6fa159fc23e42bvboxsync rc = VbglGRPerform (&pHGCMConnect->header.header);
0c8b774aca1168c2007424a49f6fa159fc23e42bvboxsync
0c8b774aca1168c2007424a49f6fa159fc23e42bvboxsync if (RT_SUCCESS(rc))
0c8b774aca1168c2007424a49f6fa159fc23e42bvboxsync {
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync /* Check if host decides to process the request asynchronously. */
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync if (rc == VINF_HGCM_ASYNC_EXECUTE)
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync {
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync /* Wait for request completion interrupt notification from host */
41e3b5da61b49017cb647f2f32a231c524fc370avboxsync pfnAsyncCallback (&pHGCMConnect->header, pvAsyncData, u32AsyncData);
41e3b5da61b49017cb647f2f32a231c524fc370avboxsync }
41e3b5da61b49017cb647f2f32a231c524fc370avboxsync
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync pConnectInfo->result = pHGCMConnect->header.result;
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync if (RT_SUCCESS (pConnectInfo->result))
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync pConnectInfo->u32ClientID = pHGCMConnect->u32ClientID;
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync }
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync VbglGRFree (&pHGCMConnect->header.header);
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync }
cfd41a3683178a30bac4417128b4673806653797vboxsync
cfd41a3683178a30bac4417128b4673806653797vboxsync return rc;
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync}
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsyncDECLR0VBGL(int) VbglR0HGCMInternalDisconnect (VBoxGuestHGCMDisconnectInfo *pDisconnectInfo,
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData)
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync{
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync VMMDevHGCMDisconnect *pHGCMDisconnect;
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync int rc;
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync if (!pDisconnectInfo || !pfnAsyncCallback)
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync return VERR_INVALID_PARAMETER;
613c0d015cbaef93be47fc03f0708744c5c24f79vboxsync
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync pHGCMDisconnect = NULL;
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync /* Allocate request */
907ba2c9b3d1821f95be17115ecad9fe8a2cae02vboxsync rc = VbglGRAlloc ((VMMDevRequestHeader **)&pHGCMDisconnect, sizeof (VMMDevHGCMDisconnect), VMMDevReq_HGCMDisconnect);
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync if (RT_SUCCESS(rc))
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync {
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync /* Initialize request memory */
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync pHGCMDisconnect->header.fu32Flags = 0;
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync pHGCMDisconnect->u32ClientID = pDisconnectInfo->u32ClientID;
771761cda2c81e899526a0dce22c8cd2510fff82vboxsync
f6cc81e94c29cc9b39b896cf32ecfe0501b4a1e5vboxsync /* Issue request */
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync rc = VbglGRPerform (&pHGCMDisconnect->header.header);
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync
efbdd9fc22305720d20be7cc37b4f45f43146b09vboxsync if (RT_SUCCESS(rc))
9c59bcefe2993070fafaf0d6cee9673f48479128vboxsync {
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync /* Check if host decides to process the request asynchronously. */
933606e7609b250f207a2f97112f8388f88998c1vboxsync if (rc == VINF_HGCM_ASYNC_EXECUTE)
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync {
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync /* Wait for request completion interrupt notification from host */
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync pfnAsyncCallback (&pHGCMDisconnect->header, pvAsyncData, u32AsyncData);
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync }
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync pDisconnectInfo->result = pHGCMDisconnect->header.result;
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync }
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync VbglGRFree (&pHGCMDisconnect->header.header);
9c59bcefe2993070fafaf0d6cee9673f48479128vboxsync }
9c59bcefe2993070fafaf0d6cee9673f48479128vboxsync
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync return rc;
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync}
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync
13b516eac15d19e108e587a9d9ecc85e1961ac6dvboxsync
13b516eac15d19e108e587a9d9ecc85e1961ac6dvboxsync/**
13b516eac15d19e108e587a9d9ecc85e1961ac6dvboxsync * Preprocesses the HGCM call, validating and locking/buffering parameters.
13b516eac15d19e108e587a9d9ecc85e1961ac6dvboxsync *
2ebf77e955a41ebc4eaa4a0d2a9aaf05540d2e4dvboxsync * @returns VBox status code.
2ebf77e955a41ebc4eaa4a0d2a9aaf05540d2e4dvboxsync *
2ebf77e955a41ebc4eaa4a0d2a9aaf05540d2e4dvboxsync * @param pCallInfo The call info.
2ebf77e955a41ebc4eaa4a0d2a9aaf05540d2e4dvboxsync * @param cbCallInfo The size of the call info structure.
2ebf77e955a41ebc4eaa4a0d2a9aaf05540d2e4dvboxsync * @param fIsUser Is it a user request or kernel request.
2ebf77e955a41ebc4eaa4a0d2a9aaf05540d2e4dvboxsync * @param pcbExtra Where to return the extra request space needed for
2ebf77e955a41ebc4eaa4a0d2a9aaf05540d2e4dvboxsync * physical page lists.
2ebf77e955a41ebc4eaa4a0d2a9aaf05540d2e4dvboxsync */
af8ba507921d1f8c4e22a120b24de396b08e19efvboxsyncstatic int vbglR0HGCMInternalPreprocessCall(VBoxGuestHGCMCallInfo const *pCallInfo, uint32_t cbCallInfo,
af8ba507921d1f8c4e22a120b24de396b08e19efvboxsync bool fIsUser, struct VbglR0ParmInfo *pParmInfo, size_t *pcbExtra)
af8ba507921d1f8c4e22a120b24de396b08e19efvboxsync{
af8ba507921d1f8c4e22a120b24de396b08e19efvboxsync HGCMFunctionParameter const *pSrcParm = VBOXGUEST_HGCM_CALL_PARMS(pCallInfo);
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync uint32_t cParms = pCallInfo->cParms;
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync uint32_t iParm;
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync uint32_t cb;
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync /*
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync * Lock down the any linear buffers so we can get their addresses
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync * and figure out how much extra storage we need for page lists.
9c59bcefe2993070fafaf0d6cee9673f48479128vboxsync *
9c59bcefe2993070fafaf0d6cee9673f48479128vboxsync * Note! With kernel mode users we can be assertive. For user mode users
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync * we should just (debug) log it and fail without any fanfare.
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync */
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync *pcbExtra = 0;
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync pParmInfo->cLockBufs = 0;
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync for (iParm = 0; iParm < cParms; iParm++, pSrcParm++)
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync {
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync switch (pSrcParm->type)
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync {
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync case VMMDevHGCMParmType_32bit:
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync Log4(("GstHGCMCall: parm=%u type=32bit: %#010x\n", iParm, pSrcParm->u.value32));
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync break;
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsync case VMMDevHGCMParmType_64bit:
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsync Log4(("GstHGCMCall: parm=%u type=64bit: %#018x\n", iParm, pSrcParm->u.value64));
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsync break;
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsync case VMMDevHGCMParmType_PageList:
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsync if (fIsUser)
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsync return VERR_INVALID_PARAMETER;
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync cb = pSrcParm->u.PageList.size;
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync if (cb)
45eeaa1736817a425d69d35b3aa5f0dc38a7f7efvboxsync {
45eeaa1736817a425d69d35b3aa5f0dc38a7f7efvboxsync uint32_t off = pSrcParm->u.PageList.offset;
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync HGCMPageListInfo *pPgLst;
01f38d7bedc71f105edc6e67f8cbb9a0bf325442vboxsync uint32_t cPages;
01f38d7bedc71f105edc6e67f8cbb9a0bf325442vboxsync uint32_t u32;
62e5c2cfabb91397405d7bfe7908ec2b3a483831vboxsync
62e5c2cfabb91397405d7bfe7908ec2b3a483831vboxsync AssertMsgReturn(cb <= VBGLR0_MAX_HGCM_KERNEL_PARM, ("%#x > %#x\n", cb, VBGLR0_MAX_HGCM_KERNEL_PARM),
2c18e977ea3600677b8c58c9de0caa61792ba428vboxsync VERR_OUT_OF_RANGE);
2c18e977ea3600677b8c58c9de0caa61792ba428vboxsync AssertMsgReturn( off >= pCallInfo->cParms * sizeof(HGCMFunctionParameter)
2c18e977ea3600677b8c58c9de0caa61792ba428vboxsync && off <= cbCallInfo - sizeof(HGCMPageListInfo),
2c18e977ea3600677b8c58c9de0caa61792ba428vboxsync ("offset=%#x cParms=%#x cbCallInfo=%#x\n", off, pCallInfo->cParms, cbCallInfo),
2c18e977ea3600677b8c58c9de0caa61792ba428vboxsync VERR_INVALID_PARAMETER);
2c18e977ea3600677b8c58c9de0caa61792ba428vboxsync
2c18e977ea3600677b8c58c9de0caa61792ba428vboxsync pPgLst = (HGCMPageListInfo *)((uint8_t *)pCallInfo + off);
01f38d7bedc71f105edc6e67f8cbb9a0bf325442vboxsync cPages = pPgLst->cPages;
01f38d7bedc71f105edc6e67f8cbb9a0bf325442vboxsync u32 = RT_OFFSETOF(HGCMPageListInfo, aPages[cPages]) + off;
01f38d7bedc71f105edc6e67f8cbb9a0bf325442vboxsync AssertMsgReturn(u32 <= cbCallInfo,
01f38d7bedc71f105edc6e67f8cbb9a0bf325442vboxsync ("u32=%#x (cPages=%#x offset=%#x) cbCallInfo=%#x\n", u32, cPages, off, cbCallInfo),
01f38d7bedc71f105edc6e67f8cbb9a0bf325442vboxsync VERR_INVALID_PARAMETER);
01f38d7bedc71f105edc6e67f8cbb9a0bf325442vboxsync AssertMsgReturn(pPgLst->offFirstPage < PAGE_SIZE, ("#x\n", pPgLst->offFirstPage), VERR_INVALID_PARAMETER);
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync u32 = RT_ALIGN_32(pPgLst->offFirstPage + cb, PAGE_SIZE) >> PAGE_SHIFT;
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsync AssertMsgReturn(cPages == u32, ("cPages=%#x u32=%#x\n", cPages, u32), VERR_INVALID_PARAMETER);
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync AssertMsgReturn(VBOX_HGCM_F_PARM_ARE_VALID(pPgLst->flags), ("%#x\n", pPgLst->flags), VERR_INVALID_PARAMETER);
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync Log4(("GstHGCMCall: parm=%u type=pglst: cb=%#010x cPgs=%u offPg0=%#x flags=%#x\n",
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync iParm, cb, cPages, pPgLst->offFirstPage, pPgLst->flags));
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync u32 = cPages;
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync while (u32-- > 0)
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync {
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync Log4(("GstHGCMCall: pg#%u=%RHp\n", u32, pPgLst->aPages[u32]));
01f38d7bedc71f105edc6e67f8cbb9a0bf325442vboxsync AssertMsgReturn(!(pPgLst->aPages[u32] & (PAGE_OFFSET_MASK | UINT64_C(0xfff0000000000000))),
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsync ("pg#%u=%RHp\n", u32, pPgLst->aPages[u32]),
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsync VERR_INVALID_PARAMETER);
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync }
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsync *pcbExtra += RT_OFFSETOF(HGCMPageListInfo, aPages[pPgLst->cPages]);
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsync }
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync else
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync Log4(("GstHGCMCall: parm=%u type=pglst: cb=0\n", iParm));
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsync break;
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsync
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsync case VMMDevHGCMParmType_LinAddr_Locked_In:
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsync case VMMDevHGCMParmType_LinAddr_Locked_Out:
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync case VMMDevHGCMParmType_LinAddr_Locked:
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync if (fIsUser)
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync return VERR_INVALID_PARAMETER;
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync if (!VBGLR0_CAN_USE_PHYS_PAGE_LIST())
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync {
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync cb = pSrcParm->u.Pointer.size;
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync AssertMsgReturn(cb <= VBGLR0_MAX_HGCM_KERNEL_PARM, ("%#x > %#x\n", cb, VBGLR0_MAX_HGCM_KERNEL_PARM),
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync VERR_OUT_OF_RANGE);
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync if (cb != 0)
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync Log4(("GstHGCMCall: parm=%u type=%#x: cb=%#010x pv=%p\n",
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync iParm, pSrcParm->type, cb, pSrcParm->u.Pointer.u.linearAddr));
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync else
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync Log4(("GstHGCMCall: parm=%u type=%#x: cb=0\n", iParm, pSrcParm->type));
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync break;
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync }
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync /* fall thru */
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync case VMMDevHGCMParmType_LinAddr_In:
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync case VMMDevHGCMParmType_LinAddr_Out:
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync case VMMDevHGCMParmType_LinAddr:
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync cb = pSrcParm->u.Pointer.size;
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync if (cb != 0)
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync {
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync#ifdef USE_BOUNCE_BUFFERS
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync void *pvSmallBuf = NULL;
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync#endif
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync uint32_t iLockBuf = pParmInfo->cLockBufs;
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync RTR0MEMOBJ hObj;
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync int rc;
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync uint32_t fAccess = pSrcParm->type == VMMDevHGCMParmType_LinAddr_In
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync || pSrcParm->type == VMMDevHGCMParmType_LinAddr_Locked_In
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync ? RTMEM_PROT_READ
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync : RTMEM_PROT_READ | RTMEM_PROT_WRITE;
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync AssertReturn(iLockBuf < RT_ELEMENTS(pParmInfo->aLockBufs), VERR_INVALID_PARAMETER);
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync if (!fIsUser)
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync {
693d9f3305eb4a4684a6613b8a41a6fa150cc101vboxsync AssertMsgReturn(cb <= VBGLR0_MAX_HGCM_KERNEL_PARM, ("%#x > %#x\n", cb, VBGLR0_MAX_HGCM_KERNEL_PARM),
933606e7609b250f207a2f97112f8388f88998c1vboxsync VERR_OUT_OF_RANGE);
933606e7609b250f207a2f97112f8388f88998c1vboxsync rc = RTR0MemObjLockKernel(&hObj, (void *)pSrcParm->u.Pointer.u.linearAddr, cb, fAccess);
933606e7609b250f207a2f97112f8388f88998c1vboxsync if (RT_FAILURE(rc))
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync {
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync Log(("GstHGCMCall: id=%#x fn=%u parm=%u RTR0MemObjLockKernel(,%p,%#x) -> %Rrc\n",
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync pCallInfo->u32ClientID, pCallInfo->u32Function, iParm, pSrcParm->u.Pointer.u.linearAddr, cb, rc));
9ced981a0263f6280ccbf5dc64c0e81fbe4a2fdavboxsync return rc;
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync }
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync Log3(("GstHGCMCall: parm=%u type=%#x: cb=%#010x pv=%p locked kernel -> %p\n",
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync iParm, pSrcParm->type, cb, pSrcParm->u.Pointer.u.linearAddr, hObj));
1ace73711fa06807748eff26632c7273a1f7c2dbvboxsync }
1ace73711fa06807748eff26632c7273a1f7c2dbvboxsync else if (cb > VBGLR0_MAX_HGCM_USER_PARM)
1ace73711fa06807748eff26632c7273a1f7c2dbvboxsync {
1ace73711fa06807748eff26632c7273a1f7c2dbvboxsync Log(("GstHGCMCall: id=%#x fn=%u parm=%u pv=%p cb=%#x > %#x -> out of range\n",
1ace73711fa06807748eff26632c7273a1f7c2dbvboxsync pCallInfo->u32ClientID, pCallInfo->u32Function, iParm, pSrcParm->u.Pointer.u.linearAddr,
1ace73711fa06807748eff26632c7273a1f7c2dbvboxsync cb, VBGLR0_MAX_HGCM_USER_PARM));
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync return VERR_OUT_OF_RANGE;
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync }
1ace73711fa06807748eff26632c7273a1f7c2dbvboxsync else
1ace73711fa06807748eff26632c7273a1f7c2dbvboxsync {
1ace73711fa06807748eff26632c7273a1f7c2dbvboxsync#ifndef USE_BOUNCE_BUFFERS
5f9ec43969b9ba00f6c2d03bafc9ac36a41c95e1vboxsync rc = RTR0MemObjLockUser(&hObj, (RTR3PTR)pSrcParm->u.Pointer.u.linearAddr, cb, fAccess, NIL_RTR0PROCESS);
5f9ec43969b9ba00f6c2d03bafc9ac36a41c95e1vboxsync if (RT_FAILURE(rc))
1ace73711fa06807748eff26632c7273a1f7c2dbvboxsync {
5f9ec43969b9ba00f6c2d03bafc9ac36a41c95e1vboxsync Log(("GstHGCMCall: id=%#x fn=%u parm=%u RTR0MemObjLockUser(,%p,%#x,nil) -> %Rrc\n",
5f9ec43969b9ba00f6c2d03bafc9ac36a41c95e1vboxsync pCallInfo->u32ClientID, pCallInfo->u32Function, iParm, pSrcParm->u.Pointer.u.linearAddr, cb, rc));
5f9ec43969b9ba00f6c2d03bafc9ac36a41c95e1vboxsync return rc;
5f9ec43969b9ba00f6c2d03bafc9ac36a41c95e1vboxsync }
5f9ec43969b9ba00f6c2d03bafc9ac36a41c95e1vboxsync Log3(("GstHGCMCall: parm=%u type=%#x: cb=%#010x pv=%p locked user -> %p\n",
5f9ec43969b9ba00f6c2d03bafc9ac36a41c95e1vboxsync iParm, pSrcParm->type, cb, pSrcParm->u.Pointer.u.linearAddr, hObj));
5f9ec43969b9ba00f6c2d03bafc9ac36a41c95e1vboxsync
5f9ec43969b9ba00f6c2d03bafc9ac36a41c95e1vboxsync#else /* USE_BOUNCE_BUFFERS */
5f9ec43969b9ba00f6c2d03bafc9ac36a41c95e1vboxsync /*
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync * This is a bit massive, but we don't want to waste a
9ced981a0263f6280ccbf5dc64c0e81fbe4a2fdavboxsync * whole page for a 3 byte string buffer (guest props).
e12a6ea07ddb7a02b3575e78b24960e13f42bf4cvboxsync *
9ced981a0263f6280ccbf5dc64c0e81fbe4a2fdavboxsync * The threshold is ASSUMING sizeof(RTMEMHDR) == 16 and
9ced981a0263f6280ccbf5dc64c0e81fbe4a2fdavboxsync * the system is using some power of two allocator.
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync */
53e1c27c7564c45ad0b92676ddea561591a3e869vboxsync /** @todo A more efficient strategy would be to combine buffers. However it
53e1c27c7564c45ad0b92676ddea561591a3e869vboxsync * is probably going to be more massive than the current code, so
1d258b8772ee104b5fab3d1743eabc2f5cfe2fa4vboxsync * it can wait till later. */
1d258b8772ee104b5fab3d1743eabc2f5cfe2fa4vboxsync bool fCopyIn = pSrcParm->type != VMMDevHGCMParmType_LinAddr_Out
53e1c27c7564c45ad0b92676ddea561591a3e869vboxsync && pSrcParm->type != VMMDevHGCMParmType_LinAddr_Locked_Out;
1d258b8772ee104b5fab3d1743eabc2f5cfe2fa4vboxsync if (cb <= PAGE_SIZE / 2 - 16)
1d258b8772ee104b5fab3d1743eabc2f5cfe2fa4vboxsync {
53e1c27c7564c45ad0b92676ddea561591a3e869vboxsync pvSmallBuf = fCopyIn ? RTMemTmpAlloc(cb) : RTMemTmpAllocZ(cb);
53e1c27c7564c45ad0b92676ddea561591a3e869vboxsync if (RT_UNLIKELY(!pvSmallBuf))
53e1c27c7564c45ad0b92676ddea561591a3e869vboxsync return VERR_NO_MEMORY;
53e1c27c7564c45ad0b92676ddea561591a3e869vboxsync if (fCopyIn)
1d258b8772ee104b5fab3d1743eabc2f5cfe2fa4vboxsync {
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsync rc = RTR0MemUserCopyFrom(pvSmallBuf, pSrcParm->u.Pointer.u.linearAddr, cb);
1d258b8772ee104b5fab3d1743eabc2f5cfe2fa4vboxsync if (RT_FAILURE(rc))
1d258b8772ee104b5fab3d1743eabc2f5cfe2fa4vboxsync {
1d258b8772ee104b5fab3d1743eabc2f5cfe2fa4vboxsync RTMemTmpFree(pvSmallBuf);
1d258b8772ee104b5fab3d1743eabc2f5cfe2fa4vboxsync Log(("GstHGCMCall: id=%#x fn=%u parm=%u RTR0MemUserCopyFrom(,%p,%#x) -> %Rrc\n",
1d258b8772ee104b5fab3d1743eabc2f5cfe2fa4vboxsync pCallInfo->u32ClientID, pCallInfo->u32Function, iParm,
53e1c27c7564c45ad0b92676ddea561591a3e869vboxsync pSrcParm->u.Pointer.u.linearAddr, cb, rc));
53e1c27c7564c45ad0b92676ddea561591a3e869vboxsync return rc;
53e1c27c7564c45ad0b92676ddea561591a3e869vboxsync }
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsync }
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsync rc = RTR0MemObjLockKernel(&hObj, pvSmallBuf, cb, fAccess);
1d258b8772ee104b5fab3d1743eabc2f5cfe2fa4vboxsync if (RT_FAILURE(rc))
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsync {
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsync RTMemTmpFree(pvSmallBuf);
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsync Log(("GstHGCMCall: RTR0MemObjLockKernel failed for small buffer: rc=%Rrc pvSmallBuf=%p cb=%#x\n",
1826861f34e9be70b29cd5e1a6038caf9fbf37bevboxsync rc, pvSmallBuf, cb));
53e1c27c7564c45ad0b92676ddea561591a3e869vboxsync return rc;
53e1c27c7564c45ad0b92676ddea561591a3e869vboxsync }
674c51d0cb8c72a2852b315b70f76d11d82b20f5vboxsync Log3(("GstHGCMCall: parm=%u type=%#x: cb=%#010x pv=%p small buffer %p -> %p\n",
674c51d0cb8c72a2852b315b70f76d11d82b20f5vboxsync iParm, pSrcParm->type, cb, pSrcParm->u.Pointer.u.linearAddr, pvSmallBuf, hObj));
674c51d0cb8c72a2852b315b70f76d11d82b20f5vboxsync }
674c51d0cb8c72a2852b315b70f76d11d82b20f5vboxsync else
674c51d0cb8c72a2852b315b70f76d11d82b20f5vboxsync {
e12a6ea07ddb7a02b3575e78b24960e13f42bf4cvboxsync rc = RTR0MemObjAllocPage(&hObj, cb, false /*fExecutable*/);
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync if (RT_FAILURE(rc))
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync return rc;
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync if (!fCopyIn)
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync memset(RTR0MemObjAddress(hObj), '\0', cb);
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync else
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync {
53e1c27c7564c45ad0b92676ddea561591a3e869vboxsync rc = RTR0MemUserCopyFrom(RTR0MemObjAddress(hObj), pSrcParm->u.Pointer.u.linearAddr, cb);
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync if (RT_FAILURE(rc))
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync {
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync RTR0MemObjFree(hObj, false /*fFreeMappings*/);
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync Log(("GstHGCMCall: id=%#x fn=%u parm=%u RTR0MemUserCopyFrom(,%p,%#x) -> %Rrc\n",
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync pCallInfo->u32ClientID, pCallInfo->u32Function, iParm,
6e3cc82d5d5effda92c9fec18b870d54386f99favboxsync pSrcParm->u.Pointer.u.linearAddr, cb, rc));
6e3cc82d5d5effda92c9fec18b870d54386f99favboxsync return rc;
771761cda2c81e899526a0dce22c8cd2510fff82vboxsync }
771761cda2c81e899526a0dce22c8cd2510fff82vboxsync }
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync Log3(("GstHGCMCall: parm=%u type=%#x: cb=%#010x pv=%p big buffer -> %p\n",
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync iParm, pSrcParm->type, cb, pSrcParm->u.Pointer.u.linearAddr, hObj));
9ced981a0263f6280ccbf5dc64c0e81fbe4a2fdavboxsync }
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync#endif /* USE_BOUNCE_BUFFERS */
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync }
9a1578b66f9e563cf99c75ffa881db476f477e3avboxsync
69069b36d01e6c0e9965baca5fcb58d57a1030b6vboxsync pParmInfo->aLockBufs[iLockBuf].iParm = iParm;
9b5e4e8f5c00e8cd2289a73d173c96e551c79397vboxsync pParmInfo->aLockBufs[iLockBuf].hObj = hObj;
69069b36d01e6c0e9965baca5fcb58d57a1030b6vboxsync#ifdef USE_BOUNCE_BUFFERS
9b5e4e8f5c00e8cd2289a73d173c96e551c79397vboxsync pParmInfo->aLockBufs[iLockBuf].pvSmallBuf = pvSmallBuf;
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync#endif
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync pParmInfo->cLockBufs = iLockBuf + 1;
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync if (VBGLR0_CAN_USE_PHYS_PAGE_LIST())
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync {
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync size_t const cPages = RTR0MemObjSize(hObj) >> PAGE_SHIFT;
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync *pcbExtra += RT_OFFSETOF(HGCMPageListInfo, aPages[cPages]);
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync }
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync }
d95b7fbc09277b5375b98812fa76b08c6ce8535cvboxsync else
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync Log4(("GstHGCMCall: parm=%u type=%#x: cb=0\n", iParm, pSrcParm->type));
d95b7fbc09277b5375b98812fa76b08c6ce8535cvboxsync break;
d95b7fbc09277b5375b98812fa76b08c6ce8535cvboxsync
d95b7fbc09277b5375b98812fa76b08c6ce8535cvboxsync default:
f2ba84c335a6e7ac91f69863ff51b10c65c9d40fvboxsync return VERR_INVALID_PARAMETER;
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync }
97674677e4f2aeae576c39f966568dd664ba7979vboxsync }
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync return VINF_SUCCESS;
77c85c820fe4467a0856134e0c9e5c5790cd847evboxsync}
72f66530e1bf87aa6894a5f55f1b4d36caa5761fvboxsync
97674677e4f2aeae576c39f966568dd664ba7979vboxsync
97674677e4f2aeae576c39f966568dd664ba7979vboxsync/**
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * Translates locked linear address to the normal type.
* The locked types are only for the guest side and not handled by the host.
*
* @returns normal linear address type.
* @param enmType The type.
*/
static HGCMFunctionParameterType vbglR0HGCMInternalConvertLinAddrType(HGCMFunctionParameterType enmType)
{
switch (enmType)
{
case VMMDevHGCMParmType_LinAddr_Locked_In:
return VMMDevHGCMParmType_LinAddr_In;
case VMMDevHGCMParmType_LinAddr_Locked_Out:
return VMMDevHGCMParmType_LinAddr_Out;
case VMMDevHGCMParmType_LinAddr_Locked:
return VMMDevHGCMParmType_LinAddr;
default:
return enmType;
}
}
/**
* Translates linear address types to page list direction flags.
*
* @returns page list flags.
* @param enmType The type.
*/
static uint32_t vbglR0HGCMInternalLinAddrTypeToPageListFlags(HGCMFunctionParameterType enmType)
{
switch (enmType)
{
case VMMDevHGCMParmType_LinAddr_In:
case VMMDevHGCMParmType_LinAddr_Locked_In:
return VBOX_HGCM_F_PARM_DIRECTION_TO_HOST;
case VMMDevHGCMParmType_LinAddr_Out:
case VMMDevHGCMParmType_LinAddr_Locked_Out:
return VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST;
default: AssertFailed();
case VMMDevHGCMParmType_LinAddr:
case VMMDevHGCMParmType_LinAddr_Locked:
return VBOX_HGCM_F_PARM_DIRECTION_BOTH;
}
}
/**
* Initializes the call request that we're sending to the host.
*
* @returns VBox status code.
*
* @param pCallInfo The call info.
* @param cbCallInfo The size of the call info structure.
* @param fIsUser Is it a user request or kernel request.
* @param pcbExtra Where to return the extra request space needed for
* physical page lists.
*/
static void vbglR0HGCMInternalInitCall(VMMDevHGCMCall *pHGCMCall, VBoxGuestHGCMCallInfo const *pCallInfo,
uint32_t cbCallInfo, bool fIsUser, struct VbglR0ParmInfo *pParmInfo)
{
HGCMFunctionParameter const *pSrcParm = VBOXGUEST_HGCM_CALL_PARMS(pCallInfo);
HGCMFunctionParameter *pDstParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
uint32_t cParms = pCallInfo->cParms;
uint32_t offExtra = (uintptr_t)(pDstParm + cParms) - (uintptr_t)pHGCMCall;
uint32_t iLockBuf = 0;
uint32_t iParm;
/*
* The call request headers.
*/
pHGCMCall->header.fu32Flags = 0;
pHGCMCall->header.result = VINF_SUCCESS;
pHGCMCall->u32ClientID = pCallInfo->u32ClientID;
pHGCMCall->u32Function = pCallInfo->u32Function;
pHGCMCall->cParms = cParms;
/*
* The parameters.
*/
for (iParm = 0; iParm < pCallInfo->cParms; iParm++, pSrcParm++, pDstParm++)
{
switch (pSrcParm->type)
{
case VMMDevHGCMParmType_32bit:
case VMMDevHGCMParmType_64bit:
*pDstParm = *pSrcParm;
break;
case VMMDevHGCMParmType_PageList:
pDstParm->type = VMMDevHGCMParmType_PageList;
pDstParm->u.PageList.size = pSrcParm->u.PageList.size;
if (pSrcParm->u.PageList.size)
{
HGCMPageListInfo const *pSrcPgLst = (HGCMPageListInfo *)((uint8_t *)pCallInfo + pSrcParm->u.PageList.offset);
HGCMPageListInfo *pDstPgLst = (HGCMPageListInfo *)((uint8_t *)pHGCMCall + offExtra);
uint32_t const cPages = pSrcPgLst->cPages;
uint32_t iPage;
pDstParm->u.PageList.offset = offExtra;
pDstPgLst->flags = pSrcPgLst->flags;
pDstPgLst->offFirstPage = pSrcPgLst->offFirstPage;
pDstPgLst->cPages = cPages;
for (iPage = 0; iPage < cPages; iPage++)
pDstPgLst->aPages[iPage] = pSrcPgLst->aPages[iPage];
offExtra += RT_OFFSETOF(HGCMPageListInfo, aPages[cPages]);
}
else
pDstParm->u.PageList.offset = 0;
break;
case VMMDevHGCMParmType_LinAddr_Locked_In:
case VMMDevHGCMParmType_LinAddr_Locked_Out:
case VMMDevHGCMParmType_LinAddr_Locked:
if (!VBGLR0_CAN_USE_PHYS_PAGE_LIST())
{
*pDstParm = *pSrcParm;
pDstParm->type = vbglR0HGCMInternalConvertLinAddrType(pSrcParm->type);
break;
}
/* fall thru */
case VMMDevHGCMParmType_LinAddr_In:
case VMMDevHGCMParmType_LinAddr_Out:
case VMMDevHGCMParmType_LinAddr:
if (pSrcParm->u.Pointer.size != 0)
{
#ifdef USE_BOUNCE_BUFFERS
void *pvSmallBuf = pParmInfo->aLockBufs[iLockBuf].pvSmallBuf;
#endif
RTR0MEMOBJ hObj = pParmInfo->aLockBufs[iLockBuf].hObj;
Assert(iParm == pParmInfo->aLockBufs[iLockBuf].iParm);
if (VBGLR0_CAN_USE_PHYS_PAGE_LIST())
{
HGCMPageListInfo *pDstPgLst = (HGCMPageListInfo *)((uint8_t *)pHGCMCall + offExtra);
size_t const cPages = RTR0MemObjSize(hObj) >> PAGE_SHIFT;
size_t iPage;
pDstParm->type = VMMDevHGCMParmType_PageList;
pDstParm->u.PageList.size = pSrcParm->u.Pointer.size;
pDstParm->u.PageList.offset = offExtra;
pDstPgLst->flags = vbglR0HGCMInternalLinAddrTypeToPageListFlags(pSrcParm->type);
#ifdef USE_BOUNCE_BUFFERS
if (fIsUser)
pDstPgLst->offFirstPage = (uintptr_t)pvSmallBuf & PAGE_OFFSET_MASK;
else
#endif
pDstPgLst->offFirstPage = pSrcParm->u.Pointer.u.linearAddr & PAGE_OFFSET_MASK;
pDstPgLst->cPages = cPages; Assert(pDstPgLst->cPages == cPages);
for (iPage = 0; iPage < cPages; iPage++)
{
pDstPgLst->aPages[iPage] = RTR0MemObjGetPagePhysAddr(hObj, iPage);
Assert(pDstPgLst->aPages[iPage] != NIL_RTHCPHYS);
}
offExtra += RT_OFFSETOF(HGCMPageListInfo, aPages[cPages]);
}
else
{
pDstParm->type = vbglR0HGCMInternalConvertLinAddrType(pSrcParm->type);
pDstParm->u.Pointer.size = pSrcParm->u.Pointer.size;
#ifdef USE_BOUNCE_BUFFERS
if (fIsUser)
pDstParm->u.Pointer.u.linearAddr = pvSmallBuf
? (uintptr_t)pvSmallBuf
: (uintptr_t)RTR0MemObjAddress(hObj);
else
#endif
pDstParm->u.Pointer.u.linearAddr = pSrcParm->u.Pointer.u.linearAddr;
}
iLockBuf++;
}
else
{
pDstParm->type = vbglR0HGCMInternalConvertLinAddrType(pSrcParm->type);
pDstParm->u.Pointer.size = 0;
pDstParm->u.Pointer.u.linearAddr = 0;
}
break;
default:
AssertFailed();
pDstParm->type = VMMDevHGCMParmType_Invalid;
break;
}
}
}
/**
* Performs the call and completion wait.
*
* @returns VBox status code of this operation, not necessarily the call.
*
* @param pHGCMCall The HGCM call info.
* @param pfnAsyncCallback The async callback that will wait for the call
* to complete.
* @param pvAsyncData Argument for the callback.
* @param u32AsyncData Argument for the callback.
* @param pfLeakIt Where to return the leak it / free it,
* indicator. Cancellation fun.
*/
static int vbglR0HGCMInternalDoCall(VMMDevHGCMCall *pHGCMCall, PFNVBGLHGCMCALLBACK pfnAsyncCallback,
void *pvAsyncData, uint32_t u32AsyncData, bool *pfLeakIt)
{
int rc;
Log(("calling VbglGRPerform\n"));
rc = VbglGRPerform(&pHGCMCall->header.header);
Log(("VbglGRPerform rc = %Rrc (header rc=%d)\n", rc, pHGCMCall->header.result));
/*
* If the call failed, but as a result of the request itself, then pretend
* success. Upper layers will interpret the result code in the packet.
*/
if ( RT_FAILURE(rc)
&& rc == pHGCMCall->header.result)
{
Assert(pHGCMCall->header.fu32Flags & VBOX_HGCM_REQ_DONE);
rc = VINF_SUCCESS;
}
/*
* Check if host decides to process the request asynchronously,
* if so, we wait for it to complete using the caller supplied callback.
*/
*pfLeakIt = false;
if (rc == VINF_HGCM_ASYNC_EXECUTE)
{
Log(("Processing HGCM call asynchronously\n"));
rc = pfnAsyncCallback(&pHGCMCall->header, pvAsyncData, u32AsyncData);
if (pHGCMCall->header.fu32Flags & VBOX_HGCM_REQ_DONE)
{
Assert(!(pHGCMCall->header.fu32Flags & VBOX_HGCM_REQ_CANCELLED));
rc = VINF_SUCCESS;
}
else
{
/*
* The request didn't complete in time or the call was interrupted,
* the RC from the callback indicates which. Try cancel the request.
*
* This is a bit messy because we're racing request completion. Sorry.
*/
/** @todo It would be nice if we could use the waiter callback to do further
* waiting in case of a completion race. If it wasn't for WINNT having its own
* version of all that stuff, I would've done it already. */
VMMDevHGCMCancel2 *pCancelReq;
int rc2 = VbglGRAlloc((VMMDevRequestHeader **)&pCancelReq, sizeof(*pCancelReq), VMMDevReq_HGCMCancel2);
if (RT_SUCCESS(rc2))
{
pCancelReq->physReqToCancel = VbglPhysHeapGetPhysAddr(pHGCMCall);
rc2 = VbglGRPerform(&pCancelReq->header);
VbglGRFree(&pCancelReq->header);
}
#if 1 /** @todo ADDVER: Remove this on next minor version change. */
if (rc2 == VERR_NOT_IMPLEMENTED)
{
/* host is too old, or we're out of heap. */
pHGCMCall->header.fu32Flags |= VBOX_HGCM_REQ_CANCELLED;
pHGCMCall->header.header.requestType = VMMDevReq_HGCMCancel;
rc2 = VbglGRPerform(&pHGCMCall->header.header);
if (rc2 == VERR_INVALID_PARAMETER)
rc2 = VERR_NOT_FOUND;
else if (RT_SUCCESS(rc))
RTThreadSleep(1);
}
#endif
if (RT_SUCCESS(rc)) rc = VERR_INTERRUPTED; /** @todo weed this out from the WINNT VBoxGuest code. */
if (RT_SUCCESS(rc2))
{
Log(("vbglR0HGCMInternalDoCall: successfully cancelled\n"));
pHGCMCall->header.fu32Flags |= VBOX_HGCM_REQ_CANCELLED;
}
else
{
/*
* Wait for a bit while the host (hopefully) completes it.
*/
uint64_t u64Start = RTTimeSystemMilliTS();
uint32_t cMilliesToWait = rc2 == VERR_NOT_FOUND || rc2 == VERR_SEM_DESTROYED ? 500 : 2000;
uint64_t cElapsed = 0;
if (rc2 != VERR_NOT_FOUND)
{
static unsigned s_cErrors = 0;
if (s_cErrors++ < 32)
LogRel(("vbglR0HGCMInternalDoCall: Failed to cancel the HGCM call on %Rrc: rc2=%Rrc\n", rc, rc2));
}
else
Log(("vbglR0HGCMInternalDoCall: Cancel race rc=%Rrc rc2=%Rrc\n", rc, rc2));
do
{
ASMCompilerBarrier(); /* paranoia */
if (pHGCMCall->header.fu32Flags & VBOX_HGCM_REQ_DONE)
break;
RTThreadSleep(1);
cElapsed = RTTimeSystemMilliTS() - u64Start;
} while (cElapsed < cMilliesToWait);
ASMCompilerBarrier(); /* paranoia^2 */
if (pHGCMCall->header.fu32Flags & VBOX_HGCM_REQ_DONE)
rc = VINF_SUCCESS;
else
{
LogRel(("vbglR0HGCMInternalDoCall: Leaking %u bytes. Pending call to %u with %u parms. (rc2=%Rrc)\n",
pHGCMCall->header.header.size, pHGCMCall->u32Function, pHGCMCall->cParms, rc2));
*pfLeakIt = true;
}
Log(("vbglR0HGCMInternalDoCall: Cancel race ended with rc=%Rrc (rc2=%Rrc) after %llu ms\n", rc, rc2, cElapsed));
}
}
}
Log(("GstHGCMCall: rc=%Rrc result=%Rrc fu32Flags=%#x fLeakIt=%d\n",
rc, pHGCMCall->header.result, pHGCMCall->header.fu32Flags, *pfLeakIt));
return rc;
}
/**
* Copies the result of the call back to the caller info structure and user
* buffers (if using bounce buffers).
*
* @returns rc, unless RTR0MemUserCopyTo fails.
* @param pCallInfo Call info structure to update.
* @param pHGCMCall HGCM call request.
* @param pParmInfo Parameter locking/buffering info.
* @param fIsUser Is it a user (true) or kernel request.
* @param rc The current result code. Passed along to
* preserve informational status codes.
*/
static int vbglR0HGCMInternalCopyBackResult(VBoxGuestHGCMCallInfo *pCallInfo, VMMDevHGCMCall const *pHGCMCall,
struct VbglR0ParmInfo *pParmInfo, bool fIsUser, int rc)
{
HGCMFunctionParameter const *pSrcParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
HGCMFunctionParameter *pDstParm = VBOXGUEST_HGCM_CALL_PARMS(pCallInfo);
uint32_t cParms = pCallInfo->cParms;
#ifdef USE_BOUNCE_BUFFERS
uint32_t iLockBuf = 0;
#endif
uint32_t iParm;
/*
* The call result.
*/
pCallInfo->result = pHGCMCall->header.result;
/*
* Copy back parameters.
*/
for (iParm = 0; iParm < cParms; iParm++, pSrcParm++, pDstParm++)
{
switch (pDstParm->type)
{
case VMMDevHGCMParmType_32bit:
case VMMDevHGCMParmType_64bit:
*pDstParm = *pSrcParm;
break;
case VMMDevHGCMParmType_PageList:
pDstParm->u.PageList.size = pSrcParm->u.PageList.size;
break;
case VMMDevHGCMParmType_LinAddr_Locked_In:
case VMMDevHGCMParmType_LinAddr_In:
#ifdef USE_BOUNCE_BUFFERS
if ( fIsUser
&& iLockBuf < pParmInfo->cLockBufs
&& iParm == pParmInfo->aLockBufs[iLockBuf].iParm)
iLockBuf++;
#endif
pDstParm->u.Pointer.size = pSrcParm->u.Pointer.size;
break;
case VMMDevHGCMParmType_LinAddr_Locked_Out:
case VMMDevHGCMParmType_LinAddr_Locked:
if (!VBGLR0_CAN_USE_PHYS_PAGE_LIST())
{
pDstParm->u.Pointer.size = pSrcParm->u.Pointer.size;
break;
}
/* fall thru */
case VMMDevHGCMParmType_LinAddr_Out:
case VMMDevHGCMParmType_LinAddr:
{
#ifdef USE_BOUNCE_BUFFERS
if (fIsUser)
{
size_t cbOut = RT_MIN(pSrcParm->u.Pointer.size, pDstParm->u.Pointer.size);
if (cbOut)
{
int rc2;
Assert(pParmInfo->aLockBufs[iLockBuf].iParm == iParm);
rc2 = RTR0MemUserCopyTo((RTR3PTR)pDstParm->u.Pointer.u.linearAddr,
pParmInfo->aLockBufs[iLockBuf].pvSmallBuf
? pParmInfo->aLockBufs[iLockBuf].pvSmallBuf
: RTR0MemObjAddress(pParmInfo->aLockBufs[iLockBuf].hObj),
cbOut);
if (RT_FAILURE(rc2))
return rc2;
iLockBuf++;
}
else if ( iLockBuf < pParmInfo->cLockBufs
&& iParm == pParmInfo->aLockBufs[iLockBuf].iParm)
iLockBuf++;
}
#endif
pDstParm->u.Pointer.size = pSrcParm->u.Pointer.size;
break;
}
default:
AssertFailed();
rc = VERR_INTERNAL_ERROR_4;
break;
}
}
#ifdef USE_BOUNCE_BUFFERS
Assert(!fIsUser || pParmInfo->cLockBufs == iLockBuf);
#endif
return rc;
}
DECLR0VBGL(int) VbglR0HGCMInternalCall(VBoxGuestHGCMCallInfo *pCallInfo, uint32_t cbCallInfo, uint32_t fFlags,
PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData)
{
bool fIsUser = (fFlags & VBGLR0_HGCMCALL_F_MODE_MASK) == VBGLR0_HGCMCALL_F_USER;
struct VbglR0ParmInfo ParmInfo;
size_t cbExtra;
int rc;
/*
* Basic validation.
*/
AssertMsgReturn( !pCallInfo
|| !pfnAsyncCallback
|| pCallInfo->cParms > VBOX_HGCM_MAX_PARMS
|| !(fFlags & ~VBGLR0_HGCMCALL_F_MODE_MASK),
("pCallInfo=%p pfnAsyncCallback=%p fFlags=%#x\n", pCallInfo, pfnAsyncCallback, fFlags),
VERR_INVALID_PARAMETER);
AssertReturn( cbCallInfo >= sizeof(VBoxGuestHGCMCallInfo)
|| cbCallInfo >= pCallInfo->cParms * sizeof(HGCMFunctionParameter),
VERR_INVALID_PARAMETER);
Log(("GstHGCMCall: u32ClientID=%#x u32Function=%u cParms=%u cbCallInfo=%#x fFlags=%#x\n",
pCallInfo->u32ClientID, pCallInfo->u32ClientID, pCallInfo->u32Function, pCallInfo->cParms, cbCallInfo, fFlags));
/*
* Validate, lock and buffer the parameters for the call.
* This will calculate the amount of extra space for physical page list.
*/
rc = vbglR0HGCMInternalPreprocessCall(pCallInfo, cbCallInfo, fIsUser, &ParmInfo, &cbExtra);
if (RT_SUCCESS(rc))
{
/*
* Allocate the request buffer and recreate the call request.
*/
VMMDevHGCMCall *pHGCMCall;
rc = VbglGRAlloc((VMMDevRequestHeader **)&pHGCMCall,
sizeof(VMMDevHGCMCall) + pCallInfo->cParms * sizeof(HGCMFunctionParameter) + cbExtra,
VMMDevReq_HGCMCall);
if (RT_SUCCESS(rc))
{
bool fLeakIt;
vbglR0HGCMInternalInitCall(pHGCMCall, pCallInfo, cbCallInfo, fIsUser, &ParmInfo);
/*
* Perform the call.
*/
rc = vbglR0HGCMInternalDoCall(pHGCMCall, pfnAsyncCallback, pvAsyncData, u32AsyncData, &fLeakIt);
if (RT_SUCCESS(rc))
{
/*
* Copy back the result (parameters and buffers that changed).
*/
rc = vbglR0HGCMInternalCopyBackResult(pCallInfo, pHGCMCall, &ParmInfo, fIsUser, rc);
}
else
{
if ( rc != VERR_INTERRUPTED
&& rc != VERR_TIMEOUT)
{
static unsigned s_cErrors = 0;
if (s_cErrors++ < 32)
LogRel(("VbglR0HGCMInternalCall: vbglR0HGCMInternalDoCall failed. rc=%Rrc\n", rc));
}
}
if (!fLeakIt)
VbglGRFree(&pHGCMCall->header.header);
}
}
else
LogRel(("VbglR0HGCMInternalCall: vbglR0HGCMInternalPreprocessCall failed. rc=%Rrc\n", rc));
/*
* Release locks and free bounce buffers.
*/
if (ParmInfo.cLockBufs)
while (ParmInfo.cLockBufs-- > 0)
{
RTR0MemObjFree(ParmInfo.aLockBufs[ParmInfo.cLockBufs].hObj, false /*fFreeMappings*/);
#ifdef USE_BOUNCE_BUFFERS
RTMemTmpFree(ParmInfo.aLockBufs[ParmInfo.cLockBufs].pvSmallBuf);
#endif
}
return rc;
}
#if ARCH_BITS == 64
DECLR0VBGL(int) VbglR0HGCMInternalCall32(VBoxGuestHGCMCallInfo *pCallInfo, uint32_t cbCallInfo, uint32_t fFlags,
PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData)
{
VBoxGuestHGCMCallInfo *pCallInfo64 = NULL;
HGCMFunctionParameter *pParm64 = NULL;
HGCMFunctionParameter32 *pParm32 = NULL;
uint32_t cParms = 0;
uint32_t iParm = 0;
int rc = VINF_SUCCESS;
/*
* Input validation.
*/
AssertMsgReturn( !pCallInfo
|| !pfnAsyncCallback
|| pCallInfo->cParms > VBOX_HGCM_MAX_PARMS
|| !(fFlags & ~VBGLR0_HGCMCALL_F_MODE_MASK),
("pCallInfo=%p pfnAsyncCallback=%p fFlags=%#x\n", pCallInfo, pfnAsyncCallback, fFlags),
VERR_INVALID_PARAMETER);
AssertReturn( cbCallInfo >= sizeof(VBoxGuestHGCMCallInfo)
|| cbCallInfo >= pCallInfo->cParms * sizeof(HGCMFunctionParameter32),
VERR_INVALID_PARAMETER);
/* This Assert does not work on Solaris/Windows 64/32 mixed mode, not sure why, skipping for now */
#if !defined(RT_OS_SOLARIS) && !defined(RT_OS_WINDOWS)
AssertReturn((fFlags & VBGLR0_HGCMCALL_F_MODE_MASK) == VBGLR0_HGCMCALL_F_KERNEL, VERR_WRONG_ORDER);
#endif
cParms = pCallInfo->cParms;
Log(("VbglR0HGCMInternalCall32: cParms=%d, u32Function=%d, fFlags=%#x\n", cParms, pCallInfo->u32Function, fFlags));
/*
* The simple approach, allocate a temporary request and convert the parameters.
*/
pCallInfo64 = (VBoxGuestHGCMCallInfo *)RTMemTmpAllocZ(sizeof(*pCallInfo64) + cParms * sizeof(HGCMFunctionParameter));
if (!pCallInfo64)
return VERR_NO_TMP_MEMORY;
*pCallInfo64 = *pCallInfo;
pParm32 = VBOXGUEST_HGCM_CALL_PARMS32(pCallInfo);
pParm64 = VBOXGUEST_HGCM_CALL_PARMS(pCallInfo64);
for (iParm = 0; iParm < cParms; iParm++, pParm32++, pParm64++)
{
switch (pParm32->type)
{
case VMMDevHGCMParmType_32bit:
pParm64->type = VMMDevHGCMParmType_32bit;
pParm64->u.value32 = pParm32->u.value32;
break;
case VMMDevHGCMParmType_64bit:
pParm64->type = VMMDevHGCMParmType_64bit;
pParm64->u.value64 = pParm32->u.value64;
break;
case VMMDevHGCMParmType_LinAddr_Out:
case VMMDevHGCMParmType_LinAddr:
case VMMDevHGCMParmType_LinAddr_In:
pParm64->type = pParm32->type;
pParm64->u.Pointer.size = pParm32->u.Pointer.size;
pParm64->u.Pointer.u.linearAddr = pParm32->u.Pointer.u.linearAddr;
break;
default:
rc = VERR_INVALID_PARAMETER;
LogRel(("VbglR0HGCMInternalCall32: pParm32 type %#x invalid.\n", pParm32->type));
break;
}
if (RT_FAILURE(rc))
break;
}
if (RT_SUCCESS(rc))
{
rc = VbglR0HGCMInternalCall(pCallInfo64, sizeof(*pCallInfo64) + cParms * sizeof(HGCMFunctionParameter), fFlags,
pfnAsyncCallback, pvAsyncData, u32AsyncData);
if (RT_SUCCESS(rc))
{
*pCallInfo = *pCallInfo64;
/*
* Copy back.
*/
pParm32 = VBOXGUEST_HGCM_CALL_PARMS32(pCallInfo);
pParm64 = VBOXGUEST_HGCM_CALL_PARMS(pCallInfo64);
for (iParm = 0; iParm < cParms; iParm++, pParm32++, pParm64++)
{
switch (pParm64->type)
{
case VMMDevHGCMParmType_32bit:
pParm32->u.value32 = pParm64->u.value32;
break;
case VMMDevHGCMParmType_64bit:
pParm32->u.value64 = pParm64->u.value64;
break;
case VMMDevHGCMParmType_LinAddr_Out:
case VMMDevHGCMParmType_LinAddr:
case VMMDevHGCMParmType_LinAddr_In:
pParm32->u.Pointer.size = pParm64->u.Pointer.size;
break;
default:
LogRel(("VbglR0HGCMInternalCall32: failed invalid pParm32 type %d\n", pParm32->type));
rc = VERR_INTERNAL_ERROR_3;
break;
}
}
}
else
{
static unsigned s_cErrors = 0;
if (s_cErrors++ < 32)
LogRel(("VbglR0HGCMInternalCall32: VbglR0HGCMInternalCall failed. rc=%Rrc\n", rc));
}
}
else
{
static unsigned s_cErrors = 0;
if (s_cErrors++ < 32)
LogRel(("VbglR0HGCMInternalCall32: failed. rc=%Rrc\n", rc));
}
RTMemTmpFree(pCallInfo64);
return rc;
}
#endif /* ARCH_BITS == 64 */
#endif /* VBGL_VBOXGUEST */