DevVGA_VDMA.cpp revision 1c43af4ec8987b1bed2306144f8bdce2d36d5572
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** @file
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Video DMA (VDMA) support.
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Copyright (C) 2006-2012 Oracle Corporation
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * available from http://www.virtualbox.org. This file is free software;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * you can redistribute it and/or modify it under the terms of the GNU
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * General Public License (GPL) as published by the Free Software
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync//#include <VBox/VMMDev.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include <VBox/vmm/pdmdev.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include <VBox/VBoxVideo.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include <iprt/semaphore.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include <iprt/thread.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include <iprt/mem.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include <iprt/asm.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include "DevVGA.h"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include "HGSMI/SHGSMIHost.h"
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync#include "HGSMI/HGSMIHostHlp.h"
b0db50948c349fa76655abf252f7946b515e8204vboxsync
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync#include <VBox/VBoxVideo3D.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync#ifdef DEBUG_misha
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define WARN_BP() do { AssertFailed(); } while (0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#else
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync#define WARN_BP() do { } while (0)
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define WARN(_msg) do { \
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync LogRel(_msg); \
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync WARN_BP(); \
4569bf0ad094b40d2e177299a00d37e94d28616cvboxsync } while (0)
4569bf0ad094b40d2e177299a00d37e94d28616cvboxsync
4569bf0ad094b40d2e177299a00d37e94d28616cvboxsync#ifdef VBOX_VDMA_WITH_WORKERTHREAD
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef enum
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync VBOXVDMAPIPE_STATE_CLOSED = 0,
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync VBOXVDMAPIPE_STATE_CREATED = 1,
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync VBOXVDMAPIPE_STATE_OPENNED = 2,
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync VBOXVDMAPIPE_STATE_CLOSING = 3
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync} VBOXVDMAPIPE_STATE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef struct VBOXVDMAPIPE
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTSEMEVENT hEvent;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* critical section for accessing pipe properties */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTCRITSECT hCritSect;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync VBOXVDMAPIPE_STATE enmState;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* true iff the other end needs Event notification */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool bNeedNotify;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync} VBOXVDMAPIPE, *PVBOXVDMAPIPE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef enum
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync VBOXVDMAPIPE_CMD_TYPE_UNDEFINED = 0,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync VBOXVDMAPIPE_CMD_TYPE_DMACMD = 1,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync VBOXVDMAPIPE_CMD_TYPE_DMACTL = 2
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync} VBOXVDMAPIPE_CMD_TYPE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef struct VBOXVDMAPIPE_CMD_BODY
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync VBOXVDMAPIPE_CMD_TYPE enmType;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync union
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PVBOXVDMACBUF_DR pDr;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PVBOXVDMA_CTL pCtl;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync void *pvCmd;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync } u;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}VBOXVDMAPIPE_CMD_BODY, *PVBOXVDMAPIPE_CMD_BODY;
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsynctypedef struct VBOXVDMAPIPE_CMD
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync HGSMILISTENTRY Entry;
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync VBOXVDMAPIPE_CMD_BODY Cmd;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync} VBOXVDMAPIPE_CMD, *PVBOXVDMAPIPE_CMD;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync#define VBOXVDMAPIPE_CMD_FROM_ENTRY(_pE) ( (PVBOXVDMAPIPE_CMD)((uint8_t *)(_pE) - RT_OFFSETOF(VBOXVDMAPIPE_CMD, Entry)) )
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsynctypedef struct VBOXVDMAPIPE_CMD_POOL
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync{
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync HGSMILIST List;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync uint32_t cCmds;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync VBOXVDMAPIPE_CMD aCmds[1];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync} VBOXVDMAPIPE_CMD_POOL, *PVBOXVDMAPIPE_CMD_POOL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync/* state transformations:
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync *
0c4004948fca34f2db87e7b38013137e9472c306vboxsync * submitter | processor
0c4004948fca34f2db87e7b38013137e9472c306vboxsync * STOPPED
0c4004948fca34f2db87e7b38013137e9472c306vboxsync * |
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * |
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * >
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * LISTENING ---> PROCESSING
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * ^ _/
44a2ecaf2d0fc196ab76cab13b3f909299e386d1vboxsync * | _/
44a2ecaf2d0fc196ab76cab13b3f909299e386d1vboxsync * | _/
4569bf0ad094b40d2e177299a00d37e94d28616cvboxsync * | _/
4569bf0ad094b40d2e177299a00d37e94d28616cvboxsync * | _/
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * | _/
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * | /
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * < >
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * PAUSED
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync *
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define VBVAEXHOSTCONTEXT_STATE_STOPPED 0
0381007ae929f1a0885e69644b7d586a1dbb3a2avboxsync#define VBVAEXHOSTCONTEXT_STATE_LISTENING 1
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync#define VBVAEXHOSTCONTEXT_STATE_PROCESSING 2
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync#define VBVAEXHOSTCONTEXT_STATE_PAUSED 3
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsynctypedef struct VBVAEXHOSTCONTEXT
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync{
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync VBVABUFFER *pVBVA;
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync uint32_t cbCurData;
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync volatile uint32_t u32State;
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync volatile uint32_t u32Pause;
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync volatile uint32_t u32cOtherCommands;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync} VBVAEXHOSTCONTEXT;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync/* VBoxVBVAExHP**, i.e. processor functions, can NOT be called concurrently with each other,
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * but can be called with other VBoxVBVAExS** (submitter) functions except Init/Start/Term aparently.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Can only be called be the processor, i.e. the entity that acquired the processor state by direct or indirect call to the VBoxVBVAExHSCheckCommands
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync * see mor edetailed comments in headers for function definitions */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic bool VBoxVBVAExHPCmdCheckRelease(struct VBVAEXHOSTCONTEXT *pCmdVbva);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsyncstatic int VBoxVBVAExHPCmdGet(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t **ppCmd, uint32_t *pcbCmd);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync/* VBoxVBVAExHP**, i.e. processor functions, can NOT be called concurrently with each other,
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync/* can be called concurrently with istelf as well as with other VBoxVBVAEx** functions except Init/Start/Term aparently */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsyncstatic int VBoxVBVAExHSCheckCommands(struct VBVAEXHOSTCONTEXT *pCmdVbva);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsyncstatic void VBoxVBVAExHSInit(struct VBVAEXHOSTCONTEXT *pCmdVbva);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsyncstatic int VBoxVBVAExHSEnable(struct VBVAEXHOSTCONTEXT *pCmdVbva, VBVABUFFER *pVBVA);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsyncstatic int VBoxVBVAExHSDisable(struct VBVAEXHOSTCONTEXT *pCmdVbva);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsyncstatic void VBoxVBVAExHSTerm(struct VBVAEXHOSTCONTEXT *pCmdVbva);
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsyncstatic int VBoxVBVAExHSSaveState(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t* pu8VramBase, PSSMHANDLE pSSM);
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsyncstatic int VBoxVBVAExHSLoadState(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t* pu8VramBase, PSSMHANDLE pSSM, uint32_t u32Version);
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsynctypedef struct VBOXVDMAHOST
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PHGSMIINSTANCE pHgsmi;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync PVGASTATE pVGAState;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync VBVAEXHOSTCONTEXT CmdVbva;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync#ifdef VBOX_VDMA_WITH_WATCHDOG
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PTMTIMERR3 WatchDogTimer;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync#endif
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync#ifdef VBOX_VDMA_WITH_WORKERTHREAD
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync VBOXVDMAPIPE Pipe;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync HGSMILIST PendingList;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync RTTHREAD hWorkerThread;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync VBOXVDMAPIPE_CMD_POOL CmdPool;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync#endif
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync} VBOXVDMAHOST, *PVBOXVDMAHOST;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync#ifdef VBOX_WITH_CRHGSMI
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsynctypedef DECLCALLBACK(void) FNVBOXVDMACRCTL_CALLBACK(PVGASTATE pVGAState, PVBOXVDMACMD_CHROMIUM_CTL pCmd, void* pvContext);
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsynctypedef FNVBOXVDMACRCTL_CALLBACK *PFNVBOXVDMACRCTL_CALLBACK;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsynctypedef struct VBOXVDMACMD_CHROMIUM_CTL_PRIVATE
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync{
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync uint32_t cRefs;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync int32_t rc;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync PFNVBOXVDMACRCTL_CALLBACK pfnCompletion;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync void *pvCompletion;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync VBOXVDMACMD_CHROMIUM_CTL Cmd;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync} VBOXVDMACMD_CHROMIUM_CTL_PRIVATE, *PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE;
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync#define VBOXVDMACMD_CHROMIUM_CTL_PRIVATE_FROM_CTL(_p) ((PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE)(((uint8_t*)(_p)) - RT_OFFSETOF(VBOXVDMACMD_CHROMIUM_CTL_PRIVATE, Cmd)))
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync
93f91841f87620d1cb6d0238b3d0d5e52cd3b9a4vboxsyncstatic PVBOXVDMACMD_CHROMIUM_CTL vboxVDMACrCtlCreate(VBOXVDMACMD_CHROMIUM_CTL_TYPE enmCmd, uint32_t cbCmd)
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync{
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE pHdr = (PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE)RTMemAllocZ(cbCmd + RT_OFFSETOF(VBOXVDMACMD_CHROMIUM_CTL_PRIVATE, Cmd));
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync Assert(pHdr);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync if (pHdr)
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync {
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync pHdr->cRefs = 1;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pHdr->rc = VERR_NOT_IMPLEMENTED;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync pHdr->Cmd.enmType = enmCmd;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync pHdr->Cmd.cbCmd = cbCmd;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync return &pHdr->Cmd;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync }
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return NULL;
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync}
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsyncDECLINLINE(void) vboxVDMACrCtlRelease (PVBOXVDMACMD_CHROMIUM_CTL pCmd)
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE pHdr = VBOXVDMACMD_CHROMIUM_CTL_PRIVATE_FROM_CTL(pCmd);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync uint32_t cRefs = ASMAtomicDecU32(&pHdr->cRefs);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if(!cRefs)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync RTMemFree(pHdr);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsyncDECLINLINE(void) vboxVDMACrCtlRetain (PVBOXVDMACMD_CHROMIUM_CTL pCmd)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE pHdr = VBOXVDMACMD_CHROMIUM_CTL_PRIVATE_FROM_CTL(pCmd);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ASMAtomicIncU32(&pHdr->cRefs);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
f687f34bd232be13744edbc0cc5155fa5d4540edvboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncDECLINLINE(int) vboxVDMACrCtlGetRc (PVBOXVDMACMD_CHROMIUM_CTL pCmd)
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync{
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE pHdr = VBOXVDMACMD_CHROMIUM_CTL_PRIVATE_FROM_CTL(pCmd);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync return pHdr->rc;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync}
0dd6dfbebcda0af90da4413aaea5f3b9d1817556vboxsync
0dd6dfbebcda0af90da4413aaea5f3b9d1817556vboxsyncstatic DECLCALLBACK(void) vboxVDMACrCtlCbSetEvent(PVGASTATE pVGAState, PVBOXVDMACMD_CHROMIUM_CTL pCmd, void* pvContext)
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync{
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync RTSemEventSignal((RTSEMEVENT)pvContext);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync}
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsyncstatic DECLCALLBACK(void) vboxVDMACrCtlCbReleaseCmd(PVGASTATE pVGAState, PVBOXVDMACMD_CHROMIUM_CTL pCmd, void* pvContext)
ead016c68c61b5f2e1fe4d237054eebea9327d4bvboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync vboxVDMACrCtlRelease(pCmd);
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync}
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync
7ccfefe49db4cd93c3701d7b60873ebf404b5b87vboxsyncstatic int vboxVDMACrCtlPostAsync (PVGASTATE pVGAState, PVBOXVDMACMD_CHROMIUM_CTL pCmd, uint32_t cbCmd, PFNVBOXVDMACRCTL_CALLBACK pfnCompletion, void *pvCompletion)
7ccfefe49db4cd93c3701d7b60873ebf404b5b87vboxsync{
7ccfefe49db4cd93c3701d7b60873ebf404b5b87vboxsync if ( pVGAState->pDrv
7ccfefe49db4cd93c3701d7b60873ebf404b5b87vboxsync && pVGAState->pDrv->pfnCrHgsmiControlProcess)
7ccfefe49db4cd93c3701d7b60873ebf404b5b87vboxsync {
7ccfefe49db4cd93c3701d7b60873ebf404b5b87vboxsync PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE pHdr = VBOXVDMACMD_CHROMIUM_CTL_PRIVATE_FROM_CTL(pCmd);
7ccfefe49db4cd93c3701d7b60873ebf404b5b87vboxsync pHdr->pfnCompletion = pfnCompletion;
64f58e4154eaa20c47782b429eeaff09070369bfvboxsync pHdr->pvCompletion = pvCompletion;
64f58e4154eaa20c47782b429eeaff09070369bfvboxsync pVGAState->pDrv->pfnCrHgsmiControlProcess(pVGAState->pDrv, pCmd, cbCmd);
64f58e4154eaa20c47782b429eeaff09070369bfvboxsync return VINF_SUCCESS;
64f58e4154eaa20c47782b429eeaff09070369bfvboxsync }
64f58e4154eaa20c47782b429eeaff09070369bfvboxsync#ifdef DEBUG_misha
64f58e4154eaa20c47782b429eeaff09070369bfvboxsync Assert(0);
64f58e4154eaa20c47782b429eeaff09070369bfvboxsync#endif
64f58e4154eaa20c47782b429eeaff09070369bfvboxsync return VERR_NOT_SUPPORTED;
64f58e4154eaa20c47782b429eeaff09070369bfvboxsync}
64f58e4154eaa20c47782b429eeaff09070369bfvboxsync
7ccfefe49db4cd93c3701d7b60873ebf404b5b87vboxsyncstatic int vboxVDMACrCtlPost(PVGASTATE pVGAState, PVBOXVDMACMD_CHROMIUM_CTL pCmd, uint32_t cbCmd)
7ccfefe49db4cd93c3701d7b60873ebf404b5b87vboxsync{
7ccfefe49db4cd93c3701d7b60873ebf404b5b87vboxsync RTSEMEVENT hComplEvent;
7ccfefe49db4cd93c3701d7b60873ebf404b5b87vboxsync int rc = RTSemEventCreate(&hComplEvent);
7ccfefe49db4cd93c3701d7b60873ebf404b5b87vboxsync AssertRC(rc);
7ccfefe49db4cd93c3701d7b60873ebf404b5b87vboxsync if(RT_SUCCESS(rc))
7ccfefe49db4cd93c3701d7b60873ebf404b5b87vboxsync {
64f58e4154eaa20c47782b429eeaff09070369bfvboxsync rc = vboxVDMACrCtlPostAsync (pVGAState, pCmd, cbCmd, vboxVDMACrCtlCbSetEvent, (void*)hComplEvent);
7ccfefe49db4cd93c3701d7b60873ebf404b5b87vboxsync#ifdef DEBUG_misha
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync AssertRC(rc);
7ccfefe49db4cd93c3701d7b60873ebf404b5b87vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_SUCCESS(rc))
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = RTSemEventWaitNoResume(hComplEvent, RT_INDEFINITE_WAIT);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertRC(rc);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync if(RT_SUCCESS(rc))
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync {
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync RTSemEventDestroy(hComplEvent);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync }
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /* the command is completed */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTSemEventDestroy(hComplEvent);
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync }
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
0dd6dfbebcda0af90da4413aaea5f3b9d1817556vboxsync}
0dd6dfbebcda0af90da4413aaea5f3b9d1817556vboxsync
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsyncstatic void vboxVDMACrCmdNotifyPerform(struct VBOXVDMAHOST *pVdma)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync PVGASTATE pVGAState = pVdma->pVGAState;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync pVGAState->pDrv->pfnCrCmdNotifyCmds(pVGAState->pDrv);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync/*
4569bf0ad094b40d2e177299a00d37e94d28616cvboxsync * @returns
4569bf0ad094b40d2e177299a00d37e94d28616cvboxsync *
4569bf0ad094b40d2e177299a00d37e94d28616cvboxsync */
4569bf0ad094b40d2e177299a00d37e94d28616cvboxsyncstatic int vboxVDMACrCmdPreprocess(struct VBOXVDMAHOST *pVdma, uint8_t* pu8Cmd, uint32_t cbCmd)
4569bf0ad094b40d2e177299a00d37e94d28616cvboxsync{
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync if (*pu8Cmd == VBOXCMDVBVA_OPTYPE_NOP)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_EOF;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync PVBOXCMDVBVA_HDR pCmd = (PVBOXCMDVBVA_HDR)pu8Cmd;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync /* check if the command is cancelled */
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync if (!ASMAtomicCmpXchgU8(&pCmd->u8State, VBOXCMDVBVA_STATE_IN_PROGRESS, VBOXCMDVBVA_STATE_SUBMITTED))
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync {
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync Assert(pCmd->u8State == VBOXCMDVBVA_STATE_CANCELLED);
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync return VINF_EOF;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /* come commands can be handled right away? */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync switch (pCmd->u8OpCode)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync case VBOXCMDVBVA_OPTYPE_NOPCMD:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pCmd->i8Result = 0;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync return VINF_EOF;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync default:
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync return VINF_SUCCESS;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync }
0dd6dfbebcda0af90da4413aaea5f3b9d1817556vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsyncstatic DECLCALLBACK(int) vboxVDMACrCmdCltCmdGet(HVBOXCRCMDCLT hClt, PVBOXCMDVBVA_HDR *ppNextCmd, uint32_t *pcbNextCmd)
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync{
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync struct VBOXVDMAHOST *pVdma = hClt;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync VBoxVBVAExHPCmdCheckRelease(&pVdma->CmdVbva);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync
0dd6dfbebcda0af90da4413aaea5f3b9d1817556vboxsync uint32_t cbCmd;
0dd6dfbebcda0af90da4413aaea5f3b9d1817556vboxsync uint8_t *pu8Cmd;
0dd6dfbebcda0af90da4413aaea5f3b9d1817556vboxsync
4569bf0ad094b40d2e177299a00d37e94d28616cvboxsync for(;;)
4569bf0ad094b40d2e177299a00d37e94d28616cvboxsync {
4569bf0ad094b40d2e177299a00d37e94d28616cvboxsync int rc = VBoxVBVAExHPCmdGet(&pVdma->CmdVbva, &pu8Cmd, &cbCmd);
4569bf0ad094b40d2e177299a00d37e94d28616cvboxsync switch (rc)
4569bf0ad094b40d2e177299a00d37e94d28616cvboxsync {
4569bf0ad094b40d2e177299a00d37e94d28616cvboxsync case VINF_SUCCESS:
4569bf0ad094b40d2e177299a00d37e94d28616cvboxsync {
4569bf0ad094b40d2e177299a00d37e94d28616cvboxsync rc = vboxVDMACrCmdPreprocess(pVdma, pu8Cmd, cbCmd);
4569bf0ad094b40d2e177299a00d37e94d28616cvboxsync switch (rc)
4569bf0ad094b40d2e177299a00d37e94d28616cvboxsync {
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync case VINF_SUCCESS:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *ppNextCmd = (PVBOXCMDVBVA_HDR)pu8Cmd;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync *pcbNextCmd = cbCmd;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case VINF_EOF:
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync continue;
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync default:
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync Assert(!RT_FAILURE(rc));
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync return RT_FAILURE(rc) ? rc : VERR_INTERNAL_ERROR;
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync }
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync break;
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync }
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync case VINF_EOF:
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync return VINF_EOF;
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync case VINF_PERMISSION_DENIED:
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync /* processing was paused, processing state was released, only VBoxVBVAExHS*** calls are now allowed */
c2f2661efd8da5281e2a3af6ddd10e737d333909vboxsync return VINF_EOF;
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync case VINF_INTERRUPTED:
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync /* command processing was interrupted, processor state remains set. client can process any commands */
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync vboxVDMACrCmdNotifyPerform(pVdma);
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync return VINF_EOF;
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync default:
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync Assert(!RT_FAILURE(rc));
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync return RT_FAILURE(rc) ? rc : VERR_INTERNAL_ERROR;
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync }
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync }
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync WARN(("Warning: vboxVDMACrCmdCltCmdGet unexpected state\n"));
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync return VERR_INTERNAL_ERROR;
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync}
4569bf0ad094b40d2e177299a00d37e94d28616cvboxsync
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsyncstatic int vboxVDMACrCtlHgsmiSetup(struct VBOXVDMAHOST *pVdma)
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync{
fc78e01f665145ab3641c5f8095e9ae984ddcb84vboxsync PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP pCmd;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pCmd = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP) vboxVDMACrCtlCreate (VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP,
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync sizeof (*pCmd));
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync if (pCmd)
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync {
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync VBOXCRCMD_CLTINFO CltInfo;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync CltInfo.hClient = pVdma;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync CltInfo.pfnCmdGet = vboxVDMACrCmdCltCmdGet;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PVGASTATE pVGAState = pVdma->pVGAState;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pCmd->pvVRamBase = pVGAState->vram_ptrR3;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pCmd->cbVRam = pVGAState->vram_size;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pCmd->pCrCmdClientInfo = &CltInfo;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync int rc = vboxVDMACrCtlPost(pVGAState, &pCmd->Hdr, sizeof (*pCmd));
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync Assert(RT_SUCCESS(rc) || rc == VERR_NOT_SUPPORTED);
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync if (RT_SUCCESS(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync rc = vboxVDMACrCtlGetRc(&pCmd->Hdr);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync vboxVDMACrCtlRelease(&pCmd->Hdr);
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync return rc;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync }
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync return VERR_NO_MEMORY;
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync}
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync
71f6a34b72f9cc873da208630959de49df1a28a5vboxsyncstatic int vboxVDMACmdExecBpbTransfer(PVBOXVDMAHOST pVdma, const PVBOXVDMACMD_DMA_BPB_TRANSFER pTransfer, uint32_t cbBuffer);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* check if this is external cmd to be passed to chromium backend */
d7125f3a1b435761c393f9ec406e85a73ae2a3e7vboxsyncstatic int vboxVDMACmdCheckCrCmd(struct VBOXVDMAHOST *pVdma, PVBOXVDMACBUF_DR pCmdDr, uint32_t cbCmdDr)
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync{
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync PVBOXVDMACMD pDmaCmd = NULL;
d7125f3a1b435761c393f9ec406e85a73ae2a3e7vboxsync uint32_t cbDmaCmd = 0;
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync uint8_t * pvRam = pVdma->pVGAState->vram_ptrR3;
d7125f3a1b435761c393f9ec406e85a73ae2a3e7vboxsync int rc = VINF_NOT_SUPPORTED;
d7125f3a1b435761c393f9ec406e85a73ae2a3e7vboxsync
0c4004948fca34f2db87e7b38013137e9472c306vboxsync cbDmaCmd = pCmdDr->cbBuf;
d7125f3a1b435761c393f9ec406e85a73ae2a3e7vboxsync
0c4004948fca34f2db87e7b38013137e9472c306vboxsync if (pCmdDr->fFlags & VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR)
0c4004948fca34f2db87e7b38013137e9472c306vboxsync {
d7125f3a1b435761c393f9ec406e85a73ae2a3e7vboxsync if (cbCmdDr < sizeof (*pCmdDr) + VBOXVDMACMD_HEADER_SIZE())
d7125f3a1b435761c393f9ec406e85a73ae2a3e7vboxsync {
d7125f3a1b435761c393f9ec406e85a73ae2a3e7vboxsync AssertMsgFailed(("invalid buffer data!"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VERR_INVALID_PARAMETER;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync if (cbDmaCmd < cbCmdDr - sizeof (*pCmdDr) - VBOXVDMACMD_HEADER_SIZE())
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("invalid command buffer data!"));
0c4004948fca34f2db87e7b38013137e9472c306vboxsync return VERR_INVALID_PARAMETER;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
0c4004948fca34f2db87e7b38013137e9472c306vboxsync
0c4004948fca34f2db87e7b38013137e9472c306vboxsync pDmaCmd = VBOXVDMACBUF_DR_TAIL(pCmdDr, VBOXVDMACMD);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (pCmdDr->fFlags & VBOXVDMACBUF_FLAG_BUF_VRAM_OFFSET)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync VBOXVIDEOOFFSET offBuf = pCmdDr->Location.offVramBuf;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (offBuf + cbDmaCmd > pVdma->pVGAState->vram_size)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("invalid command buffer data from offset!"));
0c4004948fca34f2db87e7b38013137e9472c306vboxsync return VERR_INVALID_PARAMETER;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pDmaCmd = (VBOXVDMACMD*)(pvRam + offBuf);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pDmaCmd)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Assert(cbDmaCmd >= VBOXVDMACMD_HEADER_SIZE());
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cbBody = VBOXVDMACMD_BODY_SIZE(cbDmaCmd);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync switch (pDmaCmd->enmType)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case VBOXVDMACMD_TYPE_CHROMIUM_CMD:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PVBOXVDMACMD_CHROMIUM_CMD pCrCmd = VBOXVDMACMD_BODY(pDmaCmd, VBOXVDMACMD_CHROMIUM_CMD);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (cbBody < sizeof (*pCrCmd))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("invalid chromium command buffer size!"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VERR_INVALID_PARAMETER;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PVGASTATE pVGAState = pVdma->pVGAState;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = VINF_SUCCESS;
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync if (pVGAState->pDrv->pfnCrHgsmiCommandProcess)
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync {
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync VBoxSHGSMICommandMarkAsynchCompletion(pCmdDr);
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync pVGAState->pDrv->pfnCrHgsmiCommandProcess(pVGAState->pDrv, pCrCmd, cbBody);
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync break;
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync }
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync else
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync {
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync Assert(0);
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync }
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync
8a339f91959bb7a3315b51a23461b68c7b0cb50evboxsync int tmpRc = VBoxSHGSMICommandComplete (pVdma->pHgsmi, pCmdDr);
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync AssertRC(tmpRc);
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync break;
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync }
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync case VBOXVDMACMD_TYPE_DMA_BPB_TRANSFER:
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync {
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync PVBOXVDMACMD_DMA_BPB_TRANSFER pTransfer = VBOXVDMACMD_BODY(pDmaCmd, VBOXVDMACMD_DMA_BPB_TRANSFER);
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync if (cbBody < sizeof (*pTransfer))
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("invalid bpb transfer buffer size!"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VERR_INVALID_PARAMETER;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync rc = vboxVDMACmdExecBpbTransfer(pVdma, pTransfer, sizeof (*pTransfer));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertRC(rc);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_SUCCESS(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync pCmdDr->rc = VINF_SUCCESS;
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync rc = VBoxSHGSMICommandComplete (pVdma->pHgsmi, pCmdDr);
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync AssertRC(rc);
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync rc = VINF_SUCCESS;
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync }
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync break;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync }
d7125f3a1b435761c393f9ec406e85a73ae2a3e7vboxsync default:
d7125f3a1b435761c393f9ec406e85a73ae2a3e7vboxsync break;
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync }
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync }
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync return rc;
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync}
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncint vboxVDMACrHgsmiCommandCompleteAsync(PPDMIDISPLAYVBVACALLBACKS pInterface, PVBOXVDMACMD_CHROMIUM_CMD pCmd, int rc)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PVGASTATE pVGAState = PPDMIDISPLAYVBVACALLBACKS_2_PVGASTATE(pInterface);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync VBOXVDMACMD *pDmaHdr = VBOXVDMACMD_FROM_BODY(pCmd);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync VBOXVDMACBUF_DR *pDr = VBOXVDMACBUF_DR_FROM_TAIL(pDmaHdr);
b0db50948c349fa76655abf252f7946b515e8204vboxsync AssertRC(rc);
b0db50948c349fa76655abf252f7946b515e8204vboxsync pDr->rc = rc;
b0db50948c349fa76655abf252f7946b515e8204vboxsync
b0db50948c349fa76655abf252f7946b515e8204vboxsync Assert(pVGAState->fGuestCaps & VBVACAPS_COMPLETEGCMD_BY_IOREAD);
b0db50948c349fa76655abf252f7946b515e8204vboxsync rc = VBoxSHGSMICommandComplete(pIns, pDr);
b0db50948c349fa76655abf252f7946b515e8204vboxsync AssertRC(rc);
b0db50948c349fa76655abf252f7946b515e8204vboxsync return rc;
b0db50948c349fa76655abf252f7946b515e8204vboxsync}
b0db50948c349fa76655abf252f7946b515e8204vboxsync
b0db50948c349fa76655abf252f7946b515e8204vboxsyncint vboxVDMACrHgsmiControlCompleteAsync(PPDMIDISPLAYVBVACALLBACKS pInterface, PVBOXVDMACMD_CHROMIUM_CTL pCmd, int rc)
b0db50948c349fa76655abf252f7946b515e8204vboxsync{
b0db50948c349fa76655abf252f7946b515e8204vboxsync PVGASTATE pVGAState = PPDMIDISPLAYVBVACALLBACKS_2_PVGASTATE(pInterface);
b0db50948c349fa76655abf252f7946b515e8204vboxsync PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE pCmdPrivate = VBOXVDMACMD_CHROMIUM_CTL_PRIVATE_FROM_CTL(pCmd);
b0db50948c349fa76655abf252f7946b515e8204vboxsync pCmdPrivate->rc = rc;
b0db50948c349fa76655abf252f7946b515e8204vboxsync if (pCmdPrivate->pfnCompletion)
b0db50948c349fa76655abf252f7946b515e8204vboxsync {
b0db50948c349fa76655abf252f7946b515e8204vboxsync pCmdPrivate->pfnCompletion(pVGAState, pCmd, pCmdPrivate->pvCompletion);
b0db50948c349fa76655abf252f7946b515e8204vboxsync }
b0db50948c349fa76655abf252f7946b515e8204vboxsync return VINF_SUCCESS;
b0db50948c349fa76655abf252f7946b515e8204vboxsync}
b0db50948c349fa76655abf252f7946b515e8204vboxsync
b0db50948c349fa76655abf252f7946b515e8204vboxsync#endif
b0db50948c349fa76655abf252f7946b515e8204vboxsync
b0db50948c349fa76655abf252f7946b515e8204vboxsync#ifdef VBOX_VDMA_WITH_WORKERTHREAD
b0db50948c349fa76655abf252f7946b515e8204vboxsync/* to simplify things and to avoid extra backend if modifications we assume the VBOXVDMA_RECTL is the same as VBVACMDHDR */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncAssertCompile(sizeof(VBOXVDMA_RECTL) == sizeof(VBVACMDHDR));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncAssertCompile(RT_SIZEOFMEMB(VBOXVDMA_RECTL, left) == RT_SIZEOFMEMB(VBVACMDHDR, x));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncAssertCompile(RT_SIZEOFMEMB(VBOXVDMA_RECTL, top) == RT_SIZEOFMEMB(VBVACMDHDR, y));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncAssertCompile(RT_SIZEOFMEMB(VBOXVDMA_RECTL, width) == RT_SIZEOFMEMB(VBVACMDHDR, w));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncAssertCompile(RT_SIZEOFMEMB(VBOXVDMA_RECTL, height) == RT_SIZEOFMEMB(VBVACMDHDR, h));
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsyncAssertCompile(RT_OFFSETOF(VBOXVDMA_RECTL, left) == RT_OFFSETOF(VBVACMDHDR, x));
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsyncAssertCompile(RT_OFFSETOF(VBOXVDMA_RECTL, top) == RT_OFFSETOF(VBVACMDHDR, y));
b0db50948c349fa76655abf252f7946b515e8204vboxsyncAssertCompile(RT_OFFSETOF(VBOXVDMA_RECTL, width) == RT_OFFSETOF(VBVACMDHDR, w));
b0db50948c349fa76655abf252f7946b515e8204vboxsyncAssertCompile(RT_OFFSETOF(VBOXVDMA_RECTL, height) == RT_OFFSETOF(VBVACMDHDR, h));
b0db50948c349fa76655abf252f7946b515e8204vboxsync
b0db50948c349fa76655abf252f7946b515e8204vboxsyncstatic int vboxVDMANotifyPrimaryUpdate (PVGASTATE pVGAState, unsigned uScreenId, const VBOXVDMA_RECTL * pRectl)
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync{
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync pVGAState->pDrv->pfnVBVAUpdateBegin (pVGAState->pDrv, uScreenId);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync /* Updates the rectangle and sends the command to the VRDP server. */
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync pVGAState->pDrv->pfnVBVAUpdateProcess (pVGAState->pDrv, uScreenId,
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync (const PVBVACMDHDR)pRectl /* <- see above AssertCompile's and comments */,
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync sizeof (VBOXVDMA_RECTL));
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync pVGAState->pDrv->pfnVBVAUpdateEnd (pVGAState->pDrv, uScreenId, pRectl->left, pRectl->top,
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync pRectl->width, pRectl->height);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
faee255cc48bfbf17cb9f72fca70c8b9d3020ec4vboxsync#endif
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int vboxVDMACmdExecBltPerform(PVBOXVDMAHOST pVdma,
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync uint8_t *pvDstSurf, const uint8_t *pvSrcSurf,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync const PVBOXVDMA_SURF_DESC pDstDesc, const PVBOXVDMA_SURF_DESC pSrcDesc,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync const VBOXVDMA_RECTL * pDstRectl, const VBOXVDMA_RECTL * pSrcRectl)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* we do not support color conversion */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync Assert(pDstDesc->format == pSrcDesc->format);
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync /* we do not support stretching */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync Assert(pDstRectl->height == pSrcRectl->height);
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync Assert(pDstRectl->width == pSrcRectl->width);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pDstDesc->format != pSrcDesc->format)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VERR_INVALID_FUNCTION;
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync if (pDstDesc->width == pDstRectl->width
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync && pSrcDesc->width == pSrcRectl->width
a39ea3668b7019c23a68936259545f9b71bce1aavboxsync && pSrcDesc->width == pDstDesc->width)
0db6a029780d9f9b347500e117320a8d5661efe5vboxsync {
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync Assert(!pDstRectl->left);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync Assert(!pSrcRectl->left);
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync uint32_t cbOff = pDstDesc->pitch * pDstRectl->top;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cbSize = pDstDesc->pitch * pDstRectl->height;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync memcpy(pvDstSurf + cbOff, pvSrcSurf + cbOff, cbSize);
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync }
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync else
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync {
0c4004948fca34f2db87e7b38013137e9472c306vboxsync uint32_t offDstLineStart = pDstRectl->left * pDstDesc->bpp >> 3;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync uint32_t offDstLineEnd = ((pDstRectl->left * pDstDesc->bpp + 7) >> 3) + ((pDstDesc->bpp * pDstRectl->width + 7) >> 3);
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync uint32_t cbDstLine = offDstLineEnd - offDstLineStart;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync uint32_t offDstStart = pDstDesc->pitch * pDstRectl->top + offDstLineStart;
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync Assert(cbDstLine <= pDstDesc->pitch);
0c4004948fca34f2db87e7b38013137e9472c306vboxsync uint32_t cbDstSkip = pDstDesc->pitch;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync uint8_t * pvDstStart = pvDstSurf + offDstStart;
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync uint32_t offSrcLineStart = pSrcRectl->left * pSrcDesc->bpp >> 3;
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync uint32_t offSrcLineEnd = ((pSrcRectl->left * pSrcDesc->bpp + 7) >> 3) + ((pSrcDesc->bpp * pSrcRectl->width + 7) >> 3);
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync uint32_t cbSrcLine = offSrcLineEnd - offSrcLineStart;
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync uint32_t offSrcStart = pSrcDesc->pitch * pSrcRectl->top + offSrcLineStart;
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync Assert(cbSrcLine <= pSrcDesc->pitch);
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync uint32_t cbSrcSkip = pSrcDesc->pitch;
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync const uint8_t * pvSrcStart = pvSrcSurf + offSrcStart;
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync Assert(cbDstLine == cbSrcLine);
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync for (uint32_t i = 0; ; ++i)
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync {
0c4004948fca34f2db87e7b38013137e9472c306vboxsync memcpy (pvDstStart, pvSrcStart, cbDstLine);
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync if (i == pDstRectl->height)
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync break;
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync pvDstStart += cbDstSkip;
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync pvSrcStart += cbSrcSkip;
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync }
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync }
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync return VINF_SUCCESS;
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync}
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync
71f6a34b72f9cc873da208630959de49df1a28a5vboxsyncstatic void vboxVDMARectlUnite(VBOXVDMA_RECTL * pRectl1, const VBOXVDMA_RECTL * pRectl2)
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync{
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync if (!pRectl1->width)
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync *pRectl1 = *pRectl2;
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync else
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync {
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync int16_t x21 = pRectl1->left + pRectl1->width;
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync int16_t x22 = pRectl2->left + pRectl2->width;
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync if (pRectl1->left > pRectl2->left)
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync {
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync pRectl1->left = pRectl2->left;
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync pRectl1->width = x21 < x22 ? x22 - pRectl1->left : x21 - pRectl1->left;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync }
0c4004948fca34f2db87e7b38013137e9472c306vboxsync else if (x21 < x22)
0c4004948fca34f2db87e7b38013137e9472c306vboxsync pRectl1->width = x22 - pRectl1->left;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync
0c4004948fca34f2db87e7b38013137e9472c306vboxsync x21 = pRectl1->top + pRectl1->height;
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync x22 = pRectl2->top + pRectl2->height;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync if (pRectl1->top > pRectl2->top)
0c4004948fca34f2db87e7b38013137e9472c306vboxsync {
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync pRectl1->top = pRectl2->top;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync pRectl1->height = x21 < x22 ? x22 - pRectl1->top : x21 - pRectl1->top;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync }
0c4004948fca34f2db87e7b38013137e9472c306vboxsync else if (x21 < x22)
0c4004948fca34f2db87e7b38013137e9472c306vboxsync pRectl1->height = x22 - pRectl1->top;
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync }
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync}
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync/*
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync * @return on success the number of bytes the command contained, otherwise - VERR_xxx error code
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync */
71f6a34b72f9cc873da208630959de49df1a28a5vboxsyncstatic int vboxVDMACmdExecBlt(PVBOXVDMAHOST pVdma, const PVBOXVDMACMD_DMA_PRESENT_BLT pBlt, uint32_t cbBuffer)
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync{
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync const uint32_t cbBlt = VBOXVDMACMD_BODY_FIELD_OFFSET(uint32_t, VBOXVDMACMD_DMA_PRESENT_BLT, aDstSubRects[pBlt->cDstSubRects]);
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync Assert(cbBlt <= cbBuffer);
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync if (cbBuffer < cbBlt)
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync return VERR_INVALID_FUNCTION;
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync /* we do not support stretching for now */
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync Assert(pBlt->srcRectl.width == pBlt->dstRectl.width);
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync Assert(pBlt->srcRectl.height == pBlt->dstRectl.height);
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync if (pBlt->srcRectl.width != pBlt->dstRectl.width)
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync return VERR_INVALID_FUNCTION;
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync if (pBlt->srcRectl.height != pBlt->dstRectl.height)
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync return VERR_INVALID_FUNCTION;
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync Assert(pBlt->cDstSubRects);
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync
0c4004948fca34f2db87e7b38013137e9472c306vboxsync uint8_t * pvRam = pVdma->pVGAState->vram_ptrR3;
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync VBOXVDMA_RECTL updateRectl = {0, 0, 0, 0};
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync if (pBlt->cDstSubRects)
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync {
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync VBOXVDMA_RECTL dstRectl, srcRectl;
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync const VBOXVDMA_RECTL *pDstRectl, *pSrcRectl;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync for (uint32_t i = 0; i < pBlt->cDstSubRects; ++i)
0c4004948fca34f2db87e7b38013137e9472c306vboxsync {
0c4004948fca34f2db87e7b38013137e9472c306vboxsync pDstRectl = &pBlt->aDstSubRects[i];
0c4004948fca34f2db87e7b38013137e9472c306vboxsync if (pBlt->dstRectl.left || pBlt->dstRectl.top)
0c4004948fca34f2db87e7b38013137e9472c306vboxsync {
0c4004948fca34f2db87e7b38013137e9472c306vboxsync dstRectl.left = pDstRectl->left + pBlt->dstRectl.left;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync dstRectl.top = pDstRectl->top + pBlt->dstRectl.top;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync dstRectl.width = pDstRectl->width;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync dstRectl.height = pDstRectl->height;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync pDstRectl = &dstRectl;
0c4004948fca34f2db87e7b38013137e9472c306vboxsync }
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync pSrcRectl = &pBlt->aDstSubRects[i];
0c4004948fca34f2db87e7b38013137e9472c306vboxsync if (pBlt->srcRectl.left || pBlt->srcRectl.top)
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync {
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync srcRectl.left = pSrcRectl->left + pBlt->srcRectl.left;
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync srcRectl.top = pSrcRectl->top + pBlt->srcRectl.top;
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync srcRectl.width = pSrcRectl->width;
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync srcRectl.height = pSrcRectl->height;
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync pSrcRectl = &srcRectl;
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync }
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync int rc = vboxVDMACmdExecBltPerform(pVdma, pvRam + pBlt->offDst, pvRam + pBlt->offSrc,
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync &pBlt->dstDesc, &pBlt->srcDesc,
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync pDstRectl,
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync pSrcRectl);
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync AssertRC(rc);
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync if (!RT_SUCCESS(rc))
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync return rc;
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync vboxVDMARectlUnite(&updateRectl, pDstRectl);
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync }
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync }
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync else
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync {
0c4004948fca34f2db87e7b38013137e9472c306vboxsync int rc = vboxVDMACmdExecBltPerform(pVdma, pvRam + pBlt->offDst, pvRam + pBlt->offSrc,
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync &pBlt->dstDesc, &pBlt->srcDesc,
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync &pBlt->dstRectl,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync &pBlt->srcRectl);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertRC(rc);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!RT_SUCCESS(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync vboxVDMARectlUnite(&updateRectl, &pBlt->dstRectl);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef VBOX_VDMA_WITH_WORKERTHREAD
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int iView = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* @todo: fixme: check if update is needed and get iView */
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync vboxVDMANotifyPrimaryUpdate (pVdma->pVGAState, iView, &updateRectl);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return cbBlt;
8cd2f2e64725096acb682f34a5568b7fb816eda7vboxsync}
8cd2f2e64725096acb682f34a5568b7fb816eda7vboxsync
8cd2f2e64725096acb682f34a5568b7fb816eda7vboxsyncstatic int vboxVDMACmdExecBpbTransfer(PVBOXVDMAHOST pVdma, const PVBOXVDMACMD_DMA_BPB_TRANSFER pTransfer, uint32_t cbBuffer)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (cbBuffer < sizeof (*pTransfer))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VERR_INVALID_PARAMETER;
26947320577c481b4afefdb0afbb855181e5b2e8vboxsync
26947320577c481b4afefdb0afbb855181e5b2e8vboxsync PVGASTATE pVGAState = pVdma->pVGAState;
26947320577c481b4afefdb0afbb855181e5b2e8vboxsync uint8_t * pvRam = pVGAState->vram_ptrR3;
26947320577c481b4afefdb0afbb855181e5b2e8vboxsync PGMPAGEMAPLOCK SrcLock;
26947320577c481b4afefdb0afbb855181e5b2e8vboxsync PGMPAGEMAPLOCK DstLock;
26947320577c481b4afefdb0afbb855181e5b2e8vboxsync PPDMDEVINS pDevIns = pVdma->pVGAState->pDevInsR3;
26947320577c481b4afefdb0afbb855181e5b2e8vboxsync const void * pvSrc;
26947320577c481b4afefdb0afbb855181e5b2e8vboxsync void * pvDst;
26947320577c481b4afefdb0afbb855181e5b2e8vboxsync int rc = VINF_SUCCESS;
26947320577c481b4afefdb0afbb855181e5b2e8vboxsync uint32_t cbTransfer = pTransfer->cbTransferSize;
26947320577c481b4afefdb0afbb855181e5b2e8vboxsync uint32_t cbTransfered = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool bSrcLocked = false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool bDstLocked = false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync do
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cbSubTransfer = cbTransfer;
cba6719bd64ec749967bbe931230452664109857vboxsync if (pTransfer->fFlags & VBOXVDMACMD_DMA_BPB_TRANSFER_F_SRC_VRAMOFFSET)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync pvSrc = pvRam + pTransfer->Src.offVramBuf + cbTransfered;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync {
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync RTGCPHYS phPage = pTransfer->Src.phBuf;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync phPage += cbTransfered;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpPhysGCPhys2CCPtrReadOnly(pDevIns, phPage, 0, &pvSrc, &SrcLock);
a8139954a84d6e9090dd3a8371aa788351d45bc3vboxsync AssertRC(rc);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_SUCCESS(rc))
a8139954a84d6e9090dd3a8371aa788351d45bc3vboxsync {
a8139954a84d6e9090dd3a8371aa788351d45bc3vboxsync bSrcLocked = true;
a8139954a84d6e9090dd3a8371aa788351d45bc3vboxsync cbSubTransfer = RT_MIN(cbSubTransfer, 0x1000);
a8139954a84d6e9090dd3a8371aa788351d45bc3vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync {
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
cba6719bd64ec749967bbe931230452664109857vboxsync if (pTransfer->fFlags & VBOXVDMACMD_DMA_BPB_TRANSFER_F_DST_VRAMOFFSET)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pvDst = pvRam + pTransfer->Dst.offVramBuf + cbTransfered;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync RTGCPHYS phPage = pTransfer->Dst.phBuf;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync phPage += cbTransfered;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpPhysGCPhys2CCPtr(pDevIns, phPage, 0, &pvDst, &DstLock);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertRC(rc);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_SUCCESS(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync bDstLocked = true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbSubTransfer = RT_MIN(cbSubTransfer, 0x1000);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
0db6a029780d9f9b347500e117320a8d5661efe5vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_SUCCESS(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync memcpy(pvDst, pvSrc, cbSubTransfer);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbTransfer -= cbSubTransfer;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbTransfered += cbSubTransfer;
0db6a029780d9f9b347500e117320a8d5661efe5vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbTransfer = 0; /* to break */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (bSrcLocked)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpPhysReleasePageMappingLock(pDevIns, &SrcLock);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (bDstLocked)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpPhysReleasePageMappingLock(pDevIns, &DstLock);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync } while (cbTransfer);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync if (RT_SUCCESS(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return sizeof (*pTransfer);
cba6719bd64ec749967bbe931230452664109857vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9b789c281103a2489742bf32f6ab500e38b2ecd5vboxsync
9b789c281103a2489742bf32f6ab500e38b2ecd5vboxsyncstatic int vboxVDMACmdExec(PVBOXVDMAHOST pVdma, const uint8_t *pvBuffer, uint32_t cbBuffer)
9b789c281103a2489742bf32f6ab500e38b2ecd5vboxsync{
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync do
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync {
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync Assert(pvBuffer);
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync Assert(cbBuffer >= VBOXVDMACMD_HEADER_SIZE());
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync if (!pvBuffer)
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync return VERR_INVALID_PARAMETER;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync if (cbBuffer < VBOXVDMACMD_HEADER_SIZE())
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync return VERR_INVALID_PARAMETER;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync PVBOXVDMACMD pCmd = (PVBOXVDMACMD)pvBuffer;
ea779b55cc87f3e3fadddca4672c6697c82606edvboxsync uint32_t cbCmd = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync switch (pCmd->enmType)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9b789c281103a2489742bf32f6ab500e38b2ecd5vboxsync case VBOXVDMACMD_TYPE_CHROMIUM_CMD:
9b789c281103a2489742bf32f6ab500e38b2ecd5vboxsync {
9b789c281103a2489742bf32f6ab500e38b2ecd5vboxsync#ifdef VBOXWDDM_TEST_UHGSMI
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync static int count = 0;
c91345f92b829d3fba05ce7a97206d83c5183ce0vboxsync static uint64_t start, end;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (count==0)
c91345f92b829d3fba05ce7a97206d83c5183ce0vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync start = RTTimeNanoTS();
44a2ecaf2d0fc196ab76cab13b3f909299e386d1vboxsync }
44a2ecaf2d0fc196ab76cab13b3f909299e386d1vboxsync ++count;
44a2ecaf2d0fc196ab76cab13b3f909299e386d1vboxsync if (count==100000)
44a2ecaf2d0fc196ab76cab13b3f909299e386d1vboxsync {
44a2ecaf2d0fc196ab76cab13b3f909299e386d1vboxsync end = RTTimeNanoTS();
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync float ems = (end-start)/1000000.f;
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync LogRel(("100000 calls took %i ms, %i cps\n", (int)ems, (int)(100000.f*1000.f/ems) ));
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync }
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync#endif
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync /* todo: post the buffer to chromium */
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync return VINF_SUCCESS;
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync }
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync case VBOXVDMACMD_TYPE_DMA_PRESENT_BLT:
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync {
b0db50948c349fa76655abf252f7946b515e8204vboxsync const PVBOXVDMACMD_DMA_PRESENT_BLT pBlt = VBOXVDMACMD_BODY(pCmd, VBOXVDMACMD_DMA_PRESENT_BLT);
b0db50948c349fa76655abf252f7946b515e8204vboxsync int cbBlt = vboxVDMACmdExecBlt(pVdma, pBlt, cbBuffer);
71f6a34b72f9cc873da208630959de49df1a28a5vboxsync Assert(cbBlt >= 0);
b0db50948c349fa76655abf252f7946b515e8204vboxsync Assert((uint32_t)cbBlt <= cbBuffer);
b0db50948c349fa76655abf252f7946b515e8204vboxsync if (cbBlt >= 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ((uint32_t)cbBlt == cbBuffer)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbBuffer -= (uint32_t)cbBlt;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pvBuffer -= cbBlt;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return cbBlt; /* error */
5b465a7c1237993faf8bb50120d247f3f0319adavboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync case VBOXVDMACMD_TYPE_DMA_BPB_TRANSFER:
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync {
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync const PVBOXVDMACMD_DMA_BPB_TRANSFER pTransfer = VBOXVDMACMD_BODY(pCmd, VBOXVDMACMD_DMA_BPB_TRANSFER);
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync int cbTransfer = vboxVDMACmdExecBpbTransfer(pVdma, pTransfer, cbBuffer);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Assert(cbTransfer >= 0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Assert((uint32_t)cbTransfer <= cbBuffer);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (cbTransfer >= 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ((uint32_t)cbTransfer == cbBuffer)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbBuffer -= (uint32_t)cbTransfer;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pvBuffer -= cbTransfer;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return cbTransfer; /* error */
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync break;
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case VBOXVDMACMD_TYPE_DMA_NOP:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case VBOXVDMACMD_TYPE_CHILD_STATUS_IRQ:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync default:
d4e9ccea0ea1ed303b5708ff94f6c202755f0dc6vboxsync AssertBreakpoint();
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VERR_INVALID_FUNCTION;
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync } while (1);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
cba6719bd64ec749967bbe931230452664109857vboxsync /* we should not be here */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertBreakpoint();
cba6719bd64ec749967bbe931230452664109857vboxsync return VERR_INVALID_STATE;
d7125f3a1b435761c393f9ec406e85a73ae2a3e7vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
8f0fc87a72dee210b62acc9dd859a4bebf8bfb33vboxsync#ifdef VBOX_VDMA_WITH_WORKERTHREAD
cba6719bd64ec749967bbe931230452664109857vboxsync
cba6719bd64ec749967bbe931230452664109857vboxsyncint vboxVDMAPipeConstruct(PVBOXVDMAPIPE pPipe)
cba6719bd64ec749967bbe931230452664109857vboxsync{
cba6719bd64ec749967bbe931230452664109857vboxsync int rc = RTSemEventCreate(&pPipe->hEvent);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertRC(rc);
44a2ecaf2d0fc196ab76cab13b3f909299e386d1vboxsync if (RT_SUCCESS(rc))
{
rc = RTCritSectInit(&pPipe->hCritSect);
AssertRC(rc);
if (RT_SUCCESS(rc))
{
pPipe->enmState = VBOXVDMAPIPE_STATE_CREATED;
pPipe->bNeedNotify = true;
return VINF_SUCCESS;
// RTCritSectDelete(pPipe->hCritSect);
}
RTSemEventDestroy(pPipe->hEvent);
}
return rc;
}
int vboxVDMAPipeOpenServer(PVBOXVDMAPIPE pPipe)
{
int rc = RTCritSectEnter(&pPipe->hCritSect);
AssertRC(rc);
if (RT_SUCCESS(rc))
{
Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED);
switch (pPipe->enmState)
{
case VBOXVDMAPIPE_STATE_CREATED:
pPipe->enmState = VBOXVDMAPIPE_STATE_OPENNED;
pPipe->bNeedNotify = false;
rc = VINF_SUCCESS;
break;
case VBOXVDMAPIPE_STATE_OPENNED:
pPipe->bNeedNotify = false;
rc = VINF_ALREADY_INITIALIZED;
break;
default:
AssertBreakpoint();
rc = VERR_INVALID_STATE;
break;
}
RTCritSectLeave(&pPipe->hCritSect);
}
return rc;
}
int vboxVDMAPipeCloseServer(PVBOXVDMAPIPE pPipe)
{
int rc = RTCritSectEnter(&pPipe->hCritSect);
AssertRC(rc);
if (RT_SUCCESS(rc))
{
Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED
|| pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING);
switch (pPipe->enmState)
{
case VBOXVDMAPIPE_STATE_CLOSING:
pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
rc = VINF_SUCCESS;
break;
case VBOXVDMAPIPE_STATE_CLOSED:
rc = VINF_ALREADY_INITIALIZED;
break;
default:
AssertBreakpoint();
rc = VERR_INVALID_STATE;
break;
}
RTCritSectLeave(&pPipe->hCritSect);
}
return rc;
}
int vboxVDMAPipeCloseClient(PVBOXVDMAPIPE pPipe)
{
int rc = RTCritSectEnter(&pPipe->hCritSect);
AssertRC(rc);
if (RT_SUCCESS(rc))
{
bool bNeedNotify = false;
Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED
|| pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED
|| pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED);
switch (pPipe->enmState)
{
case VBOXVDMAPIPE_STATE_OPENNED:
pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSING;
bNeedNotify = pPipe->bNeedNotify;
pPipe->bNeedNotify = false;
break;
case VBOXVDMAPIPE_STATE_CREATED:
pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
pPipe->bNeedNotify = false;
break;
case VBOXVDMAPIPE_STATE_CLOSED:
rc = VINF_ALREADY_INITIALIZED;
break;
default:
AssertBreakpoint();
rc = VERR_INVALID_STATE;
break;
}
RTCritSectLeave(&pPipe->hCritSect);
if (bNeedNotify)
{
rc = RTSemEventSignal(pPipe->hEvent);
AssertRC(rc);
}
}
return rc;
}
typedef DECLCALLBACK(bool) FNHVBOXVDMARWCB(PVBOXVDMAPIPE pPipe, void *pvCallback);
typedef FNHVBOXVDMARWCB *PFNHVBOXVDMARWCB;
int vboxVDMAPipeModifyServer(PVBOXVDMAPIPE pPipe, PFNHVBOXVDMARWCB pfnCallback, void * pvCallback)
{
int rc = RTCritSectEnter(&pPipe->hCritSect);
AssertRC(rc);
if (RT_SUCCESS(rc))
{
do
{
Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED
|| pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING);
if (pPipe->enmState >= VBOXVDMAPIPE_STATE_OPENNED)
{
bool bProcessing = pfnCallback(pPipe, pvCallback);
pPipe->bNeedNotify = !bProcessing;
if (bProcessing)
{
RTCritSectLeave(&pPipe->hCritSect);
rc = VINF_SUCCESS;
break;
}
else if (pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSING)
{
pPipe->enmState = VBOXVDMAPIPE_STATE_CLOSED;
RTCritSectLeave(&pPipe->hCritSect);
rc = VINF_EOF;
break;
}
}
else
{
AssertBreakpoint();
rc = VERR_INVALID_STATE;
RTCritSectLeave(&pPipe->hCritSect);
break;
}
RTCritSectLeave(&pPipe->hCritSect);
rc = RTSemEventWait(pPipe->hEvent, RT_INDEFINITE_WAIT);
AssertRC(rc);
if (!RT_SUCCESS(rc))
break;
rc = RTCritSectEnter(&pPipe->hCritSect);
AssertRC(rc);
if (!RT_SUCCESS(rc))
break;
} while (1);
}
return rc;
}
int vboxVDMAPipeModifyClient(PVBOXVDMAPIPE pPipe, PFNHVBOXVDMARWCB pfnCallback, void * pvCallback)
{
int rc = RTCritSectEnter(&pPipe->hCritSect);
AssertRC(rc);
if (RT_SUCCESS(rc))
{
bool bNeedNotify = false;
Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED);
if (pPipe->enmState == VBOXVDMAPIPE_STATE_OPENNED)
{
bool bModified = pfnCallback(pPipe, pvCallback);
if (bModified)
{
bNeedNotify = pPipe->bNeedNotify;
pPipe->bNeedNotify = false;
}
}
else
rc = VERR_INVALID_STATE;
RTCritSectLeave(&pPipe->hCritSect);
if (bNeedNotify)
{
rc = RTSemEventSignal(pPipe->hEvent);
AssertRC(rc);
}
}
return rc;
}
int vboxVDMAPipeDestruct(PVBOXVDMAPIPE pPipe)
{
Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED
|| pPipe->enmState == VBOXVDMAPIPE_STATE_CREATED);
/* ensure the pipe is closed */
vboxVDMAPipeCloseClient(pPipe);
Assert(pPipe->enmState == VBOXVDMAPIPE_STATE_CLOSED);
if (pPipe->enmState != VBOXVDMAPIPE_STATE_CLOSED)
return VERR_INVALID_STATE;
int rc = RTCritSectDelete(&pPipe->hCritSect);
AssertRC(rc);
rc = RTSemEventDestroy(pPipe->hEvent);
AssertRC(rc);
return VINF_SUCCESS;
}
#endif
static void vboxVDMACommandProcess(PVBOXVDMAHOST pVdma, PVBOXVDMACBUF_DR pCmd, uint32_t cbCmd)
{
PHGSMIINSTANCE pHgsmi = pVdma->pHgsmi;
const uint8_t * pvBuf;
PGMPAGEMAPLOCK Lock;
int rc;
bool bReleaseLocked = false;
do
{
PPDMDEVINS pDevIns = pVdma->pVGAState->pDevInsR3;
if (pCmd->fFlags & VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR)
pvBuf = VBOXVDMACBUF_DR_TAIL(pCmd, const uint8_t);
else if (pCmd->fFlags & VBOXVDMACBUF_FLAG_BUF_VRAM_OFFSET)
{
uint8_t * pvRam = pVdma->pVGAState->vram_ptrR3;
pvBuf = pvRam + pCmd->Location.offVramBuf;
}
else
{
RTGCPHYS phPage = pCmd->Location.phBuf & ~0xfffULL;
uint32_t offset = pCmd->Location.phBuf & 0xfff;
Assert(offset + pCmd->cbBuf <= 0x1000);
if (offset + pCmd->cbBuf > 0x1000)
{
/* @todo: more advanced mechanism of command buffer proc is actually needed */
rc = VERR_INVALID_PARAMETER;
break;
}
const void * pvPageBuf;
rc = PDMDevHlpPhysGCPhys2CCPtrReadOnly(pDevIns, phPage, 0, &pvPageBuf, &Lock);
AssertRC(rc);
if (!RT_SUCCESS(rc))
{
/* @todo: if (rc == VERR_PGM_PHYS_PAGE_RESERVED) -> fall back on using PGMPhysRead ?? */
break;
}
pvBuf = (const uint8_t *)pvPageBuf;
pvBuf += offset;
bReleaseLocked = true;
}
rc = vboxVDMACmdExec(pVdma, pvBuf, pCmd->cbBuf);
AssertRC(rc);
if (bReleaseLocked)
PDMDevHlpPhysReleasePageMappingLock(pDevIns, &Lock);
} while (0);
pCmd->rc = rc;
rc = VBoxSHGSMICommandComplete (pHgsmi, pCmd);
AssertRC(rc);
}
static void vboxVDMAControlProcess(PVBOXVDMAHOST pVdma, PVBOXVDMA_CTL pCmd)
{
PHGSMIINSTANCE pHgsmi = pVdma->pHgsmi;
pCmd->i32Result = VINF_SUCCESS;
int rc = VBoxSHGSMICommandComplete (pHgsmi, pCmd);
AssertRC(rc);
}
#ifdef VBOX_VDMA_WITH_WORKERTHREAD
typedef struct
{
struct VBOXVDMAHOST *pVdma;
VBOXVDMAPIPE_CMD_BODY Cmd;
bool bHasCmd;
} VBOXVDMACMD_PROCESS_CONTEXT, *PVBOXVDMACMD_PROCESS_CONTEXT;
static DECLCALLBACK(bool) vboxVDMACommandProcessCb(PVBOXVDMAPIPE pPipe, void *pvCallback)
{
PVBOXVDMACMD_PROCESS_CONTEXT pContext = (PVBOXVDMACMD_PROCESS_CONTEXT)pvCallback;
struct VBOXVDMAHOST *pVdma = pContext->pVdma;
HGSMILISTENTRY *pEntry = hgsmiListRemoveHead(&pVdma->PendingList);
if (pEntry)
{
PVBOXVDMAPIPE_CMD pPipeCmd = VBOXVDMAPIPE_CMD_FROM_ENTRY(pEntry);
Assert(pPipeCmd);
pContext->Cmd = pPipeCmd->Cmd;
hgsmiListPrepend(&pVdma->CmdPool.List, pEntry);
pContext->bHasCmd = true;
return true;
}
pContext->bHasCmd = false;
return false;
}
static DECLCALLBACK(int) vboxVDMAWorkerThread(RTTHREAD ThreadSelf, void *pvUser)
{
PVBOXVDMAHOST pVdma = (PVBOXVDMAHOST)pvUser;
PHGSMIINSTANCE pHgsmi = pVdma->pHgsmi;
VBOXVDMACMD_PROCESS_CONTEXT Context;
Context.pVdma = pVdma;
int rc = vboxVDMAPipeOpenServer(&pVdma->Pipe);
AssertRC(rc);
if (RT_SUCCESS(rc))
{
do
{
rc = vboxVDMAPipeModifyServer(&pVdma->Pipe, vboxVDMACommandProcessCb, &Context);
AssertRC(rc);
if (RT_SUCCESS(rc))
{
switch (Context.Cmd.enmType)
{
case VBOXVDMAPIPE_CMD_TYPE_DMACMD:
{
PVBOXVDMACBUF_DR pDr = Context.Cmd.u.pDr;
vboxVDMACommandProcess(pVdma, pDr);
break;
}
case VBOXVDMAPIPE_CMD_TYPE_DMACTL:
{
PVBOXVDMA_CTL pCtl = Context.Cmd.u.pCtl;
vboxVDMAControlProcess(pVdma, pCtl);
break;
}
default:
AssertBreakpoint();
break;
}
if (rc == VINF_EOF)
{
rc = VINF_SUCCESS;
break;
}
}
else
break;
} while (1);
}
/* always try to close the pipe to make sure the client side is notified */
int tmpRc = vboxVDMAPipeCloseServer(&pVdma->Pipe);
AssertRC(tmpRc);
return rc;
}
#endif
#ifdef VBOX_VDMA_WITH_WATCHDOG
static DECLCALLBACK(void) vboxVDMAWatchDogTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
{
VBOXVDMAHOST *pVdma = (VBOXVDMAHOST *)pvUser;
PVGASTATE pVGAState = pVdma->pVGAState;
VBVARaiseIrq(pVGAState, HGSMIHOSTFLAGS_WATCHDOG);
}
static int vboxVDMAWatchDogCtl(struct VBOXVDMAHOST *pVdma, uint32_t cMillis)
{
PPDMDEVINS pDevIns = pVdma->pVGAState->pDevInsR3;
if (cMillis)
TMTimerSetMillies(pVdma->WatchDogTimer, cMillis);
else
TMTimerStop(pVdma->WatchDogTimer);
return VINF_SUCCESS;
}
#endif
int vboxVDMAConstruct(PVGASTATE pVGAState, uint32_t cPipeElements)
{
int rc;
#ifdef VBOX_VDMA_WITH_WORKERTHREAD
PVBOXVDMAHOST pVdma = (PVBOXVDMAHOST)RTMemAllocZ(RT_OFFSETOF(VBOXVDMAHOST, CmdPool.aCmds[cPipeElements]));
#else
PVBOXVDMAHOST pVdma = (PVBOXVDMAHOST)RTMemAllocZ(sizeof(*pVdma));
#endif
Assert(pVdma);
if (pVdma)
{
pVdma->pHgsmi = pVGAState->pHGSMI;
pVdma->pVGAState = pVGAState;
#ifdef VBOX_VDMA_WITH_WATCHDOG
rc = PDMDevHlpTMTimerCreate(pVGAState->pDevInsR3, TMCLOCK_REAL, vboxVDMAWatchDogTimer,
pVdma, TMTIMER_FLAGS_NO_CRIT_SECT,
"VDMA WatchDog Timer", &pVdma->WatchDogTimer);
AssertRC(rc);
#endif
#ifdef VBOX_VDMA_WITH_WORKERTHREAD
hgsmiListInit(&pVdma->PendingList);
rc = vboxVDMAPipeConstruct(&pVdma->Pipe);
AssertRC(rc);
if (RT_SUCCESS(rc))
{
rc = RTThreadCreate(&pVdma->hWorkerThread, vboxVDMAWorkerThread, pVdma, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "VDMA");
AssertRC(rc);
if (RT_SUCCESS(rc))
{
hgsmiListInit(&pVdma->CmdPool.List);
pVdma->CmdPool.cCmds = cPipeElements;
for (uint32_t i = 0; i < cPipeElements; ++i)
{
hgsmiListAppend(&pVdma->CmdPool.List, &pVdma->CmdPool.aCmds[i].Entry);
}
# if 0 //def VBOX_WITH_CRHGSMI
int tmpRc = vboxVDMACrCtlHgsmiSetup(pVdma);
# endif
#endif
pVGAState->pVdma = pVdma;
VBoxVBVAExHSInit(&pVdma->CmdVbva);
#ifdef VBOX_WITH_CRHGSMI
int rcIgnored = vboxVDMACrCtlHgsmiSetup(pVdma); NOREF(rcIgnored); /** @todo is this ignoring intentional? */
#endif
return VINF_SUCCESS;
#ifdef VBOX_VDMA_WITH_WORKERTHREAD
}
int tmpRc = vboxVDMAPipeDestruct(&pVdma->Pipe);
AssertRC(tmpRc);
}
RTMemFree(pVdma);
#endif
}
else
rc = VERR_OUT_OF_RESOURCES;
return rc;
}
int vboxVDMADestruct(struct VBOXVDMAHOST *pVdma)
{
#ifdef VBOX_VDMA_WITH_WORKERTHREAD
/* @todo: implement*/
AssertBreakpoint();
#endif
VBoxVBVAExHSTerm(&pVdma->CmdVbva);
RTMemFree(pVdma);
return VINF_SUCCESS;
}
#ifdef VBOX_VDMA_WITH_WORKERTHREAD
typedef struct
{
struct VBOXVDMAHOST *pVdma;
VBOXVDMAPIPE_CMD_BODY Cmd;
bool bQueued;
} VBOXVDMACMD_SUBMIT_CONTEXT, *PVBOXVDMACMD_SUBMIT_CONTEXT;
DECLCALLBACK(bool) vboxVDMACommandSubmitCb(PVBOXVDMAPIPE pPipe, void *pvCallback)
{
PVBOXVDMACMD_SUBMIT_CONTEXT pContext = (PVBOXVDMACMD_SUBMIT_CONTEXT)pvCallback;
struct VBOXVDMAHOST *pVdma = pContext->pVdma;
HGSMILISTENTRY *pEntry = hgsmiListRemoveHead(&pVdma->CmdPool.List);
Assert(pEntry);
if (pEntry)
{
PVBOXVDMAPIPE_CMD pPipeCmd = VBOXVDMAPIPE_CMD_FROM_ENTRY(pEntry);
pPipeCmd->Cmd = pContext->Cmd;
VBoxSHGSMICommandMarkAsynchCompletion(pContext->Cmd.u.pvCmd);
pContext->bQueued = true;
hgsmiListAppend(&pVdma->PendingList, pEntry);
return true;
}
/* @todo: should we try to flush some commands here? */
pContext->bQueued = false;
return false;
}
#endif
int vboxVDMASaveStateExecPrep(struct VBOXVDMAHOST *pVdma, PSSMHANDLE pSSM)
{
#ifdef VBOX_WITH_CRHGSMI
PVGASTATE pVGAState = pVdma->pVGAState;
PVBOXVDMACMD_CHROMIUM_CTL pCmd = (PVBOXVDMACMD_CHROMIUM_CTL)vboxVDMACrCtlCreate(
VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_BEGIN, sizeof (*pCmd));
Assert(pCmd);
if (pCmd)
{
int rc = vboxVDMACrCtlPost(pVGAState, pCmd, sizeof (*pCmd));
AssertRC(rc);
if (RT_SUCCESS(rc))
{
rc = vboxVDMACrCtlGetRc(pCmd);
}
vboxVDMACrCtlRelease(pCmd);
return rc;
}
return VERR_NO_MEMORY;
#else
return VINF_SUCCESS;
#endif
}
int vboxVDMASaveStateExecDone(struct VBOXVDMAHOST *pVdma, PSSMHANDLE pSSM)
{
#ifdef VBOX_WITH_CRHGSMI
PVGASTATE pVGAState = pVdma->pVGAState;
PVBOXVDMACMD_CHROMIUM_CTL pCmd = (PVBOXVDMACMD_CHROMIUM_CTL)vboxVDMACrCtlCreate(
VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_END, sizeof (*pCmd));
Assert(pCmd);
if (pCmd)
{
int rc = vboxVDMACrCtlPost(pVGAState, pCmd, sizeof (*pCmd));
AssertRC(rc);
if (RT_SUCCESS(rc))
{
rc = vboxVDMACrCtlGetRc(pCmd);
}
vboxVDMACrCtlRelease(pCmd);
return rc;
}
return VERR_NO_MEMORY;
#else
return VINF_SUCCESS;
#endif
}
void vboxVDMAControl(struct VBOXVDMAHOST *pVdma, PVBOXVDMA_CTL pCmd, uint32_t cbCmd)
{
#if 1
PHGSMIINSTANCE pIns = pVdma->pHgsmi;
switch (pCmd->enmCtl)
{
case VBOXVDMA_CTL_TYPE_ENABLE:
pCmd->i32Result = VINF_SUCCESS;
break;
case VBOXVDMA_CTL_TYPE_DISABLE:
pCmd->i32Result = VINF_SUCCESS;
break;
case VBOXVDMA_CTL_TYPE_FLUSH:
pCmd->i32Result = VINF_SUCCESS;
break;
#ifdef VBOX_VDMA_WITH_WATCHDOG
case VBOXVDMA_CTL_TYPE_WATCHDOG:
pCmd->i32Result = vboxVDMAWatchDogCtl(pVdma, pCmd->u32Offset);
break;
#endif
default:
AssertBreakpoint();
pCmd->i32Result = VERR_NOT_SUPPORTED;
}
int rc = VBoxSHGSMICommandComplete (pIns, pCmd);
AssertRC(rc);
#else
/* test asinch completion */
VBOXVDMACMD_SUBMIT_CONTEXT Context;
Context.pVdma = pVdma;
Context.Cmd.enmType = VBOXVDMAPIPE_CMD_TYPE_DMACTL;
Context.Cmd.u.pCtl = pCmd;
int rc = vboxVDMAPipeModifyClient(&pVdma->Pipe, vboxVDMACommandSubmitCb, &Context);
AssertRC(rc);
if (RT_SUCCESS(rc))
{
Assert(Context.bQueued);
if (Context.bQueued)
{
/* success */
return;
}
rc = VERR_OUT_OF_RESOURCES;
}
/* failure */
Assert(RT_FAILURE(rc));
PHGSMIINSTANCE pIns = pVdma->pHgsmi;
pCmd->i32Result = rc;
int tmpRc = VBoxSHGSMICommandComplete (pIns, pCmd);
AssertRC(tmpRc);
#endif
}
void vboxVDMACommand(struct VBOXVDMAHOST *pVdma, PVBOXVDMACBUF_DR pCmd, uint32_t cbCmd)
{
int rc = VERR_NOT_IMPLEMENTED;
#ifdef VBOX_WITH_CRHGSMI
/* chromium commands are processed by crhomium hgcm thread independently from our internal cmd processing pipeline
* this is why we process them specially */
rc = vboxVDMACmdCheckCrCmd(pVdma, pCmd, cbCmd);
if (rc == VINF_SUCCESS)
return;
if (RT_FAILURE(rc))
{
pCmd->rc = rc;
rc = VBoxSHGSMICommandComplete (pVdma->pHgsmi, pCmd);
AssertRC(rc);
return;
}
#endif
#ifndef VBOX_VDMA_WITH_WORKERTHREAD
vboxVDMACommandProcess(pVdma, pCmd, cbCmd);
#else
# ifdef DEBUG_misha
Assert(0);
# endif
VBOXVDMACMD_SUBMIT_CONTEXT Context;
Context.pVdma = pVdma;
Context.Cmd.enmType = VBOXVDMAPIPE_CMD_TYPE_DMACMD;
Context.Cmd.u.pDr = pCmd;
rc = vboxVDMAPipeModifyClient(&pVdma->Pipe, vboxVDMACommandSubmitCb, &Context);
AssertRC(rc);
if (RT_SUCCESS(rc))
{
Assert(Context.bQueued);
if (Context.bQueued)
{
/* success */
return;
}
rc = VERR_OUT_OF_RESOURCES;
}
/* failure */
Assert(RT_FAILURE(rc));
PHGSMIINSTANCE pIns = pVdma->pHgsmi;
pCmd->rc = rc;
int tmpRc = VBoxSHGSMICommandComplete (pIns, pCmd);
AssertRC(tmpRc);
#endif
}
/**/
static int vboxVBVAExHSProcessorAcquire(struct VBVAEXHOSTCONTEXT *pCmdVbva)
{
Assert(pCmdVbva->u32State == VBVAEXHOSTCONTEXT_STATE_STOPPED);
uint32_t oldState;
if (!ASMAtomicReadU32(&pCmdVbva->u32Pause))
{
if (ASMAtomicCmpXchgExU32(&pCmdVbva->u32State, VBVAEXHOSTCONTEXT_STATE_PROCESSING, VBVAEXHOSTCONTEXT_STATE_LISTENING, &oldState))
return VINF_SUCCESS;
return oldState == VBVAEXHOSTCONTEXT_STATE_PROCESSING ? VERR_SEM_BUSY : VERR_INVALID_STATE;
}
return VERR_INVALID_STATE;
}
static bool vboxVBVAExHPCheckPause(struct VBVAEXHOSTCONTEXT *pCmdVbva)
{
Assert(pCmdVbva->u32State == VBVAEXHOSTCONTEXT_STATE_PROCESSING);
if (!ASMAtomicReadU32(&pCmdVbva->u32Pause))
return false;
ASMAtomicWriteU32(&pCmdVbva->u32State, VBVAEXHOSTCONTEXT_STATE_PAUSED);
return true;
}
static bool vboxVBVAExHPCheckOtherCommands(struct VBVAEXHOSTCONTEXT *pCmdVbva)
{
Assert(pCmdVbva->u32State == VBVAEXHOSTCONTEXT_STATE_PROCESSING);
return !!ASMAtomicUoReadU32(&pCmdVbva->u32cOtherCommands);
}
static void vboxVBVAExHPProcessorRelease(struct VBVAEXHOSTCONTEXT *pCmdVbva)
{
Assert(pCmdVbva->u32State == VBVAEXHOSTCONTEXT_STATE_PROCESSING);
if (!vboxVBVAExHPCheckPause(pCmdVbva))
ASMAtomicWriteU32(&pCmdVbva->u32State, VBVAEXHOSTCONTEXT_STATE_LISTENING);
else
ASMAtomicWriteU32(&pCmdVbva->u32State, VBVAEXHOSTCONTEXT_STATE_PAUSED);
}
static void vboxVBVAExHPHgEventSet(struct VBVAEXHOSTCONTEXT *pCmdVbva)
{
Assert(pCmdVbva->u32State == VBVAEXHOSTCONTEXT_STATE_PROCESSING);
ASMAtomicOrU32(&pCmdVbva->pVBVA->hostFlags.u32HostEvents, VBVA_F_STATE_PROCESSING);
}
static void vboxVBVAExHPHgEventClear(struct VBVAEXHOSTCONTEXT *pCmdVbva)
{
Assert(pCmdVbva->u32State == VBVAEXHOSTCONTEXT_STATE_PROCESSING);
ASMAtomicAndU32(&pCmdVbva->pVBVA->hostFlags.u32HostEvents, ~VBVA_F_STATE_PROCESSING);
}
static bool vboxVBVAExHPCmdCheckRelease(struct VBVAEXHOSTCONTEXT *pCmdVbva)
{
if (!pCmdVbva->cbCurData)
return false;
VBVABUFFER *pVBVA = pCmdVbva->pVBVA;
pVBVA->off32Data = (pVBVA->off32Data + pCmdVbva->cbCurData) % pVBVA->cbData;
pVBVA->indexRecordFirst = (pVBVA->indexRecordFirst + 1) % RT_ELEMENTS(pVBVA->aRecords);
pCmdVbva->cbCurData = 0;
return true;
}
static int vboxVBVAExHPCmdGet(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t **ppCmd, uint32_t *pcbCmd)
{
Assert(pCmdVbva->u32State == VBVAEXHOSTCONTEXT_STATE_PROCESSING);
VBVABUFFER *pVBVA = pCmdVbva->pVBVA;
uint32_t indexRecordFirst = pVBVA->indexRecordFirst;
uint32_t indexRecordFree = pVBVA->indexRecordFree;
Log(("first = %d, free = %d\n",
indexRecordFirst, indexRecordFree));
if (indexRecordFirst == indexRecordFree)
{
/* No records to process. Return without assigning output variables. */
return VINF_EOF;
}
uint32_t cbRecordCurrent = ASMAtomicReadU32(&pVBVA->aRecords[indexRecordFirst].cbRecord);
/* A new record need to be processed. */
if (cbRecordCurrent & VBVA_F_RECORD_PARTIAL)
{
/* the record is being recorded, try again */
return VINF_TRY_AGAIN;
}
uint32_t cbRecord = cbRecordCurrent & ~VBVA_F_RECORD_PARTIAL;
if (!cbRecord)
{
/* the record is being recorded, try again */
return VINF_TRY_AGAIN;
}
/* we should not get partial commands here actually */
Assert(cbRecord);
/* The size of largest contiguous chunk in the ring biffer. */
uint32_t u32BytesTillBoundary = pVBVA->cbData - pVBVA->off32Data;
/* The pointer to data in the ring buffer. */
uint8_t *pSrc = &pVBVA->au8Data[pVBVA->off32Data];
/* Fetch or point the data. */
if (u32BytesTillBoundary >= cbRecord)
{
/* The command does not cross buffer boundary. Return address in the buffer. */
*ppCmd = pSrc;
*pcbCmd = cbRecord;
pCmdVbva->cbCurData = cbRecord;
return VINF_SUCCESS;
}
LogRel(("CmdVbva: cross-bound writes unsupported\n"));
return VERR_INVALID_STATE;
}
/* Resumes command processing
* @returns - same as VBoxVBVAExHSCheckCommands
*/
static int vboxVBVAExHSResume(struct VBVAEXHOSTCONTEXT *pCmdVbva)
{
Assert(pCmdVbva->u32State != VBVAEXHOSTCONTEXT_STATE_STOPPED);
ASMAtomicWriteU32(&pCmdVbva->u32State, VBVAEXHOSTCONTEXT_STATE_LISTENING);
return VBoxVBVAExHSCheckCommands(pCmdVbva);
}
/* pause the command processing. this will make the processor stop the command processing and release the processing state
* to resume the command processing the vboxVBVAExHSResume must be called */
static void vboxVBVAExHSPause(struct VBVAEXHOSTCONTEXT *pCmdVbva)
{
Assert(pCmdVbva->u32State != VBVAEXHOSTCONTEXT_STATE_STOPPED);
Assert(!pCmdVbva->u32Pause);
ASMAtomicWriteU32(&pCmdVbva->u32Pause, 1);
for(;;)
{
if (ASMAtomicCmpXchgU32(&pCmdVbva->u32State, VBVAEXHOSTCONTEXT_STATE_PAUSED, VBVAEXHOSTCONTEXT_STATE_LISTENING))
break;
if (ASMAtomicReadU32(&pCmdVbva->u32State) == VBVAEXHOSTCONTEXT_STATE_PAUSED)
break;
RTThreadSleep(2);
}
pCmdVbva->u32Pause = 0;
}
/* releases (completed) the command previously acquired by VBoxVBVAExHCmdGet
* for convenience can be called if no command is currently acquired
* in that case it will do nothing and return false.
* if the completion notification is needed returns true. */
static bool VBoxVBVAExHPCmdCheckRelease(struct VBVAEXHOSTCONTEXT *pCmdVbva)
{
Assert(pCmdVbva->u32State == VBVAEXHOSTCONTEXT_STATE_PROCESSING);
return vboxVBVAExHPCmdCheckRelease(pCmdVbva);
}
/*
* @returns
* VINF_SUCCESS - new command is obtained
* VINF_EOF - processor has completed all commands and release the processing state, only VBoxVBVAExHS*** calls are now allowed
* VINF_PERMISSION_DENIED - processing was paused, processing state was released, only VBoxVBVAExHS*** calls are now allowed
* VINF_INTERRUPTED - command processing was interrupted, processor state remains set. client can process any commands,
* and call VBoxVBVAExHPCmdGet again for further processing
* VERR_** - error happened, most likely guest corrupted VBVA data
*
*/
static int VBoxVBVAExHPCmdGet(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t **ppCmd, uint32_t *pcbCmd)
{
Assert(pCmdVbva->u32State == VBVAEXHOSTCONTEXT_STATE_PROCESSING);
for(;;)
{
if (vboxVBVAExHPCheckPause(pCmdVbva))
return VINF_PERMISSION_DENIED;
if (vboxVBVAExHPCheckOtherCommands(pCmdVbva))
return VINF_INTERRUPTED;
int rc = vboxVBVAExHPCmdGet(pCmdVbva, ppCmd, pcbCmd);
switch (rc)
{
case VINF_SUCCESS:
return VINF_SUCCESS;
case VINF_EOF:
vboxVBVAExHPHgEventClear(pCmdVbva);
vboxVBVAExHPProcessorRelease(pCmdVbva);
/* we need to prevent racing between us clearing the flag and command check/submission thread, i.e.
* 1. we check the queue -> and it is empty
* 2. submitter adds command to the queue
* 3. submitter checks the "processing" -> and it is true , thus it does not submit a notification
* 4. we clear the "processing" state
* 5. ->here we need to re-check the queue state to ensure we do not leak the notification of the above command
* 6. if the queue appears to be not-empty set the "processing" state back to "true"
**/
if (VBoxVBVAExHSCheckCommands(pCmdVbva) == VINF_SUCCESS)
continue;
return VINF_EOF;
case VINF_TRY_AGAIN:
RTThreadSleep(1);
continue;
default:
/* this is something really unexpected, i.e. most likely guest has written something incorrect to the VBVA buffer */
if (RT_FAILURE(rc))
return rc;
WARN(("Warning: vboxVBVAExHCmdGet returned unexpected success status %d\n", rc));
return VERR_INTERNAL_ERROR;
}
}
WARN(("Warning: VBoxVBVAExHCmdGet unexpected state\n"));
return VERR_INTERNAL_ERROR;
}
/* Checks whether the new commands are ready for processing
* @returns
* VINF_SUCCESS - there are commands are in a queue, and the given thread is now the processor (i.e. typically it would delegate processing to a worker thread)
* VINF_EOF - no commands in a queue
* VINF_ALREADY_INITIALIZED - another thread already processing the commands
* VERR_INVALID_STATE - the VBVA is paused or pausing */
static int VBoxVBVAExHSCheckCommands(struct VBVAEXHOSTCONTEXT *pCmdVbva)
{
if (ASMAtomicUoReadU32(&pCmdVbva->u32State) == VBVAEXHOSTCONTEXT_STATE_STOPPED)
return VINF_EOF;
int rc = vboxVBVAExHSProcessorAcquire(pCmdVbva);
if (RT_SUCCESS(rc))
{
/* we are the processor now */
VBVABUFFER *pVBVA = pCmdVbva->pVBVA;
uint32_t indexRecordFirst = pVBVA->indexRecordFirst;
uint32_t indexRecordFree = pVBVA->indexRecordFree;
if (indexRecordFirst != indexRecordFree)
{
vboxVBVAExHPHgEventSet(pCmdVbva);
return VINF_SUCCESS;
}
vboxVBVAExHPProcessorRelease(pCmdVbva);
return VINF_EOF;
}
if (rc == VERR_SEM_BUSY)
return VINF_ALREADY_INITIALIZED;
Assert(rc == VERR_INVALID_STATE);
return VERR_INVALID_STATE;
}
static void VBoxVBVAExHSInit(struct VBVAEXHOSTCONTEXT *pCmdVbva)
{
memset(pCmdVbva, 0, sizeof (*pCmdVbva));
}
static int VBoxVBVAExHSEnable(struct VBVAEXHOSTCONTEXT *pCmdVbva, VBVABUFFER *pVBVA)
{
if (ASMAtomicUoReadU32(&pCmdVbva->u32State) != VBVAEXHOSTCONTEXT_STATE_STOPPED)
return VINF_ALREADY_INITIALIZED;
pCmdVbva->pVBVA = pVBVA;
pCmdVbva->pVBVA->hostFlags.u32HostEvents = 0;
ASMAtomicWriteU32(&pCmdVbva->u32State, VBVAEXHOSTCONTEXT_STATE_LISTENING);
return VINF_SUCCESS;
}
static int VBoxVBVAExHSDisable(struct VBVAEXHOSTCONTEXT *pCmdVbva)
{
if (ASMAtomicUoReadU32(&pCmdVbva->u32State) == VBVAEXHOSTCONTEXT_STATE_STOPPED)
return VINF_SUCCESS;
/* ensure no commands pending and one tries to submit them */
int rc = vboxVBVAExHSProcessorAcquire(pCmdVbva);
if (RT_SUCCESS(rc))
{
pCmdVbva->pVBVA->hostFlags.u32HostEvents = 0;
memset(pCmdVbva, 0, sizeof (*pCmdVbva));
return VINF_SUCCESS;
}
return VERR_INVALID_STATE;
}
static void VBoxVBVAExHSTerm(struct VBVAEXHOSTCONTEXT *pCmdVbva)
{
/* ensure the processor is stopped */
if (ASMAtomicUoReadU32(&pCmdVbva->u32State) == VBVAEXHOSTCONTEXT_STATE_STOPPED)
return;
/* ensure no one tries to submit the command */
vboxVBVAExHSPause(pCmdVbva);
pCmdVbva->pVBVA->hostFlags.u32HostEvents = 0;
memset(pCmdVbva, 0, sizeof (*pCmdVbva));
}
/* Saves state
* @returns - same as VBoxVBVAExHSCheckCommands, or failure on load state fail
*/
static int VBoxVBVAExHSSaveState(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t* pu8VramBase, PSSMHANDLE pSSM)
{
int rc;
if (ASMAtomicUoReadU32(&pCmdVbva->u32State) != VBVAEXHOSTCONTEXT_STATE_STOPPED)
{
vboxVBVAExHSPause(pCmdVbva);
rc = SSMR3PutU32(pSSM, (uint32_t)(((uint8_t*)pCmdVbva->pVBVA) - pu8VramBase));
AssertRCReturn(rc, rc);
return vboxVBVAExHSResume(pCmdVbva);
}
rc = SSMR3PutU32(pSSM, 0xffffffff);
AssertRCReturn(rc, rc);
return VINF_EOF;
}
/* Loads state
* @returns - same as VBoxVBVAExHSCheckCommands, or failure on load state fail
*/
static int VBoxVBVAExHSLoadState(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t* pu8VramBase, PSSMHANDLE pSSM, uint32_t u32Version)
{
uint32_t u32;
int rc = SSMR3GetU32(pSSM, &u32);
AssertRCReturn(rc, rc);
if (u32 != 0xffffffff)
{
VBVABUFFER *pVBVA = (VBVABUFFER*)pu8VramBase + u32;
rc = VBoxVBVAExHSEnable(pCmdVbva, pVBVA);
AssertRCReturn(rc, rc);
return VBoxVBVAExHSCheckCommands(pCmdVbva);
}
return VINF_EOF;
}
int vboxCmdVBVAEnable(PVGASTATE pVGAState, VBVABUFFER *pVBVA)
{
struct VBOXVDMAHOST *pVdma = pVGAState->pVdma;
return VBoxVBVAExHSEnable(&pVdma->CmdVbva, pVBVA);
}
int vboxCmdVBVADisable(PVGASTATE pVGAState)
{
struct VBOXVDMAHOST *pVdma = pVGAState->pVdma;
return VBoxVBVAExHSDisable(&pVdma->CmdVbva);
}
static int vboxCmdVBVACmdSubmitPerform(PVGASTATE pVGAState)
{
struct VBOXVDMAHOST *pVdma = pVGAState->pVdma;
int rc = VBoxVBVAExHSCheckCommands(&pVdma->CmdVbva);
switch (rc)
{
case VINF_SUCCESS:
return pVGAState->pDrv->pfnCrCmdNotifyCmds(pVGAState->pDrv);
case VINF_ALREADY_INITIALIZED:
case VINF_EOF:
case VERR_INVALID_STATE:
return VINF_SUCCESS;
default:
Assert(!RT_FAILURE(rc));
return RT_FAILURE(rc) ? rc : VERR_INTERNAL_ERROR;
}
}
int vboxCmdVBVACmdSubmit(PVGASTATE pVGAState)
{
return vboxCmdVBVACmdSubmitPerform(pVGAState);
}
int vboxCmdVBVACmdFlush(PVGASTATE pVGAState)
{
return vboxCmdVBVACmdSubmitPerform(pVGAState);
}
void vboxCmdVBVACmdTimer(PVGASTATE pVGAState)
{
vboxCmdVBVACmdSubmitPerform(pVGAState);
}