VirtualBox

source: vbox/trunk/src/VBox/Devices/Graphics/DevVGA_VDMA.cpp@ 51816

Last change on this file since 51816 was 51816, checked in by vboxsync, 10 years ago

vga/CmdVbva: var initialization

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 108.8 KB
Line 
1/** @file
2 * Video DMA (VDMA) support.
3 */
4
5/*
6 * Copyright (C) 2006-2012 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 */
16#include <VBox/VMMDev.h>
17#include <VBox/vmm/pdmdev.h>
18#include <VBox/VBoxVideo.h>
19#include <iprt/semaphore.h>
20#include <iprt/thread.h>
21#include <iprt/mem.h>
22#include <iprt/asm.h>
23#include <iprt/list.h>
24#include <iprt/param.h>
25
26#include "DevVGA.h"
27#include "HGSMI/SHGSMIHost.h"
28
29#include <VBox/VBoxVideo3D.h>
30#include <VBox/VBoxVideoHost3D.h>
31
32#ifdef DEBUG_misha
33# define VBOXVDBG_MEMCACHE_DISABLE
34#endif
35
36#ifndef VBOXVDBG_MEMCACHE_DISABLE
37# include <iprt/memcache.h>
38#endif
39
40#ifdef DEBUG_misha
41#define WARN_BP() do { AssertFailed(); } while (0)
42#else
43#define WARN_BP() do { } while (0)
44#endif
45#define WARN(_msg) do { \
46 LogRel(_msg); \
47 WARN_BP(); \
48 } while (0)
49
50#define VBOXVDMATHREAD_STATE_TERMINATED 0
51#define VBOXVDMATHREAD_STATE_CREATING 1
52#define VBOXVDMATHREAD_STATE_CREATED 3
53#define VBOXVDMATHREAD_STATE_TERMINATING 4
54
55struct VBOXVDMATHREAD;
56
57typedef DECLCALLBACKPTR(void, PFNVBOXVDMATHREAD_CHANGED)(struct VBOXVDMATHREAD *pThread, int rc, void *pvThreadContext, void *pvChangeContext);
58
59typedef struct VBOXVDMATHREAD
60{
61 RTTHREAD hWorkerThread;
62 RTSEMEVENT hEvent;
63 volatile uint32_t u32State;
64 PFNVBOXVDMATHREAD_CHANGED pfnChanged;
65 void *pvChanged;
66} VBOXVDMATHREAD, *PVBOXVDMATHREAD;
67
68
69/* state transformations:
70 *
71 * submitter | processor
72 *
73 * LISTENING ---> PROCESSING
74 *
75 * */
76#define VBVAEXHOSTCONTEXT_STATE_LISTENING 0
77#define VBVAEXHOSTCONTEXT_STATE_PROCESSING 1
78
79#define VBVAEXHOSTCONTEXT_ESTATE_DISABLED -1
80#define VBVAEXHOSTCONTEXT_ESTATE_PAUSED 0
81#define VBVAEXHOSTCONTEXT_ESTATE_ENABLED 1
82
83typedef struct VBVAEXHOSTCONTEXT
84{
85 VBVABUFFER *pVBVA;
86 volatile int32_t i32State;
87 volatile int32_t i32EnableState;
88 volatile uint32_t u32cCtls;
89 /* critical section for accessing ctl lists */
90 RTCRITSECT CltCritSect;
91 RTLISTANCHOR GuestCtlList;
92 RTLISTANCHOR HostCtlList;
93#ifndef VBOXVDBG_MEMCACHE_DISABLE
94 RTMEMCACHE CtlCache;
95#endif
96} VBVAEXHOSTCONTEXT;
97
98typedef enum
99{
100 VBVAEXHOSTCTL_TYPE_UNDEFINED = 0,
101 VBVAEXHOSTCTL_TYPE_HH_INTERNAL_PAUSE,
102 VBVAEXHOSTCTL_TYPE_HH_INTERNAL_RESUME,
103 VBVAEXHOSTCTL_TYPE_HH_SAVESTATE,
104 VBVAEXHOSTCTL_TYPE_HH_LOADSTATE,
105 VBVAEXHOSTCTL_TYPE_HH_LOADSTATE_DONE,
106 VBVAEXHOSTCTL_TYPE_HH_BE_OPAQUE,
107 VBVAEXHOSTCTL_TYPE_HH_ON_HGCM_UNLOAD,
108 VBVAEXHOSTCTL_TYPE_GHH_BE_OPAQUE,
109 VBVAEXHOSTCTL_TYPE_GHH_ENABLE,
110 VBVAEXHOSTCTL_TYPE_GHH_ENABLE_PAUSED,
111 VBVAEXHOSTCTL_TYPE_GHH_DISABLE,
112 VBVAEXHOSTCTL_TYPE_GHH_RESIZE
113} VBVAEXHOSTCTL_TYPE;
114
115struct VBVAEXHOSTCTL;
116
117typedef DECLCALLBACKPTR(void, PFNVBVAEXHOSTCTL_COMPLETE)(VBVAEXHOSTCONTEXT *pVbva, struct VBVAEXHOSTCTL *pCtl, int rc, void *pvComplete);
118
119typedef struct VBVAEXHOSTCTL
120{
121 RTLISTNODE Node;
122 VBVAEXHOSTCTL_TYPE enmType;
123 union
124 {
125 struct
126 {
127 uint8_t * pu8Cmd;
128 uint32_t cbCmd;
129 } cmd;
130
131 struct
132 {
133 PSSMHANDLE pSSM;
134 uint32_t u32Version;
135 } state;
136 } u;
137 PFNVBVAEXHOSTCTL_COMPLETE pfnComplete;
138 void *pvComplete;
139} VBVAEXHOSTCTL;
140
141/* VBoxVBVAExHP**, i.e. processor functions, can NOT be called concurrently with each other,
142 * but can be called with other VBoxVBVAExS** (submitter) functions except Init/Start/Term aparently.
143 * Can only be called be the processor, i.e. the entity that acquired the processor state by direct or indirect call to the VBoxVBVAExHSCheckCommands
144 * see mor edetailed comments in headers for function definitions */
145typedef enum
146{
147 VBVAEXHOST_DATA_TYPE_NO_DATA = 0,
148 VBVAEXHOST_DATA_TYPE_CMD,
149 VBVAEXHOST_DATA_TYPE_HOSTCTL,
150 VBVAEXHOST_DATA_TYPE_GUESTCTL
151} VBVAEXHOST_DATA_TYPE;
152
153static DECLCALLBACK(int) vdmaVBVANotifyDisable(PVGASTATE pVGAState);
154
155
156static VBVAEXHOST_DATA_TYPE VBoxVBVAExHPDataGet(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t **ppCmd, uint32_t *pcbCmd);
157
158static void VBoxVBVAExHPDataCompleteCmd(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint32_t cbCmd);
159static void VBoxVBVAExHPDataCompleteCtl(struct VBVAEXHOSTCONTEXT *pCmdVbva, VBVAEXHOSTCTL *pCtl, int rc);
160
161/* VBoxVBVAExHP**, i.e. processor functions, can NOT be called concurrently with each other,
162 * can be called concurrently with istelf as well as with other VBoxVBVAEx** functions except Init/Start/Term aparently */
163static int VBoxVBVAExHSCheckCommands(struct VBVAEXHOSTCONTEXT *pCmdVbva);
164
165static int VBoxVBVAExHSInit(struct VBVAEXHOSTCONTEXT *pCmdVbva);
166static int VBoxVBVAExHSEnable(struct VBVAEXHOSTCONTEXT *pCmdVbva, VBVABUFFER *pVBVA);
167static int VBoxVBVAExHSDisable(struct VBVAEXHOSTCONTEXT *pCmdVbva);
168static void VBoxVBVAExHSTerm(struct VBVAEXHOSTCONTEXT *pCmdVbva);
169static int VBoxVBVAExHSSaveState(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t* pu8VramBase, PSSMHANDLE pSSM);
170static int VBoxVBVAExHSLoadState(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t* pu8VramBase, PSSMHANDLE pSSM, uint32_t u32Version);
171
172static VBVAEXHOSTCTL* VBoxVBVAExHCtlAlloc(VBVAEXHOSTCONTEXT *pCmdVbva)
173{
174#ifndef VBOXVDBG_MEMCACHE_DISABLE
175 return (VBVAEXHOSTCTL*)RTMemCacheAlloc(pCmdVbva->CtlCache);
176#else
177 return (VBVAEXHOSTCTL*)RTMemAlloc(sizeof (VBVAEXHOSTCTL));
178#endif
179}
180
181static void VBoxVBVAExHCtlFree(VBVAEXHOSTCONTEXT *pCmdVbva, VBVAEXHOSTCTL *pCtl)
182{
183#ifndef VBOXVDBG_MEMCACHE_DISABLE
184 RTMemCacheFree(pCmdVbva->CtlCache, pCtl);
185#else
186 RTMemFree(pCtl);
187#endif
188}
189
190static VBVAEXHOSTCTL* VBoxVBVAExHCtlCreate(VBVAEXHOSTCONTEXT *pCmdVbva, VBVAEXHOSTCTL_TYPE enmType)
191{
192 VBVAEXHOSTCTL* pCtl = VBoxVBVAExHCtlAlloc(pCmdVbva);
193 if (!pCtl)
194 {
195 WARN(("VBoxVBVAExHCtlAlloc failed\n"));
196 return NULL;
197 }
198
199 pCtl->enmType = enmType;
200 return pCtl;
201}
202
203static int vboxVBVAExHSProcessorAcquire(struct VBVAEXHOSTCONTEXT *pCmdVbva)
204{
205 Assert(pCmdVbva->i32State >= VBVAEXHOSTCONTEXT_STATE_LISTENING);
206
207 if (ASMAtomicCmpXchgS32(&pCmdVbva->i32State, VBVAEXHOSTCONTEXT_STATE_PROCESSING, VBVAEXHOSTCONTEXT_STATE_LISTENING))
208 return VINF_SUCCESS;
209 return VERR_SEM_BUSY;
210}
211
212static VBVAEXHOSTCTL* vboxVBVAExHPCheckCtl(struct VBVAEXHOSTCONTEXT *pCmdVbva, bool *pfHostCtl, bool fHostOnlyMode)
213{
214 Assert(pCmdVbva->i32State == VBVAEXHOSTCONTEXT_STATE_PROCESSING);
215
216 if(!fHostOnlyMode && !ASMAtomicUoReadU32(&pCmdVbva->u32cCtls))
217 return NULL;
218
219 int rc = RTCritSectEnter(&pCmdVbva->CltCritSect);
220 if (RT_SUCCESS(rc))
221 {
222 VBVAEXHOSTCTL* pCtl = RTListGetFirst(&pCmdVbva->HostCtlList, VBVAEXHOSTCTL, Node);
223 if (pCtl)
224 *pfHostCtl = true;
225 else if (!fHostOnlyMode)
226 {
227 if (ASMAtomicUoReadS32(&pCmdVbva->i32EnableState) != VBVAEXHOSTCONTEXT_ESTATE_PAUSED)
228 {
229 pCtl = RTListGetFirst(&pCmdVbva->GuestCtlList, VBVAEXHOSTCTL, Node);
230 /* pCtl can not be null here since pCmdVbva->u32cCtls is not null,
231 * and there are no HostCtl commands*/
232 Assert(pCtl);
233 *pfHostCtl = false;
234 }
235 }
236
237 if (pCtl)
238 {
239 RTListNodeRemove(&pCtl->Node);
240 ASMAtomicDecU32(&pCmdVbva->u32cCtls);
241 }
242
243 RTCritSectLeave(&pCmdVbva->CltCritSect);
244
245 return pCtl;
246 }
247 else
248 WARN(("RTCritSectEnter failed %d\n", rc));
249
250 return NULL;
251}
252
253static VBVAEXHOSTCTL* VBoxVBVAExHPCheckHostCtlOnDisable(struct VBVAEXHOSTCONTEXT *pCmdVbva)
254{
255 bool fHostCtl = false;
256 VBVAEXHOSTCTL* pCtl = vboxVBVAExHPCheckCtl(pCmdVbva, &fHostCtl, true);
257 Assert(!pCtl || fHostCtl);
258 return pCtl;
259}
260
261static int VBoxVBVAExHPPause(struct VBVAEXHOSTCONTEXT *pCmdVbva)
262{
263 if (pCmdVbva->i32EnableState < VBVAEXHOSTCONTEXT_ESTATE_PAUSED)
264 {
265 WARN(("Invalid state\n"));
266 return VERR_INVALID_STATE;
267 }
268
269 ASMAtomicWriteS32(&pCmdVbva->i32EnableState, VBVAEXHOSTCONTEXT_ESTATE_PAUSED);
270 return VINF_SUCCESS;
271}
272
273static int VBoxVBVAExHPResume(struct VBVAEXHOSTCONTEXT *pCmdVbva)
274{
275 if (pCmdVbva->i32EnableState != VBVAEXHOSTCONTEXT_ESTATE_PAUSED)
276 {
277 WARN(("Invalid state\n"));
278 return VERR_INVALID_STATE;
279 }
280
281 ASMAtomicWriteS32(&pCmdVbva->i32EnableState, VBVAEXHOSTCONTEXT_ESTATE_ENABLED);
282 return VINF_SUCCESS;
283}
284
285
286static bool vboxVBVAExHPCheckProcessCtlInternal(struct VBVAEXHOSTCONTEXT *pCmdVbva, VBVAEXHOSTCTL* pCtl)
287{
288 switch (pCtl->enmType)
289 {
290 case VBVAEXHOSTCTL_TYPE_HH_INTERNAL_PAUSE:
291 {
292 int rc = VBoxVBVAExHPPause(pCmdVbva);
293 VBoxVBVAExHPDataCompleteCtl(pCmdVbva, pCtl, VINF_SUCCESS);
294 return true;
295 }
296 case VBVAEXHOSTCTL_TYPE_HH_INTERNAL_RESUME:
297 {
298 int rc = VBoxVBVAExHPResume(pCmdVbva);
299 VBoxVBVAExHPDataCompleteCtl(pCmdVbva, pCtl, VINF_SUCCESS);
300 return true;
301 }
302 default:
303 return false;
304 }
305}
306
307static void vboxVBVAExHPProcessorRelease(struct VBVAEXHOSTCONTEXT *pCmdVbva)
308{
309 Assert(pCmdVbva->i32State == VBVAEXHOSTCONTEXT_STATE_PROCESSING);
310
311 ASMAtomicWriteS32(&pCmdVbva->i32State, VBVAEXHOSTCONTEXT_STATE_LISTENING);
312}
313
314static void vboxVBVAExHPHgEventSet(struct VBVAEXHOSTCONTEXT *pCmdVbva)
315{
316 Assert(pCmdVbva->i32State == VBVAEXHOSTCONTEXT_STATE_PROCESSING);
317 if (pCmdVbva->pVBVA)
318 ASMAtomicOrU32(&pCmdVbva->pVBVA->hostFlags.u32HostEvents, VBVA_F_STATE_PROCESSING);
319}
320
321static void vboxVBVAExHPHgEventClear(struct VBVAEXHOSTCONTEXT *pCmdVbva)
322{
323 Assert(pCmdVbva->i32State == VBVAEXHOSTCONTEXT_STATE_PROCESSING);
324 if (pCmdVbva->pVBVA)
325 ASMAtomicAndU32(&pCmdVbva->pVBVA->hostFlags.u32HostEvents, ~VBVA_F_STATE_PROCESSING);
326}
327
328static int vboxVBVAExHPCmdGet(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t **ppCmd, uint32_t *pcbCmd)
329{
330 Assert(pCmdVbva->i32State == VBVAEXHOSTCONTEXT_STATE_PROCESSING);
331 Assert(pCmdVbva->i32EnableState > VBVAEXHOSTCONTEXT_ESTATE_PAUSED);
332
333 VBVABUFFER *pVBVA = pCmdVbva->pVBVA;
334
335 uint32_t indexRecordFirst = pVBVA->indexRecordFirst;
336 uint32_t indexRecordFree = pVBVA->indexRecordFree;
337
338 Log(("first = %d, free = %d\n",
339 indexRecordFirst, indexRecordFree));
340
341 if (indexRecordFirst == indexRecordFree)
342 {
343 /* No records to process. Return without assigning output variables. */
344 return VINF_EOF;
345 }
346
347 uint32_t cbRecordCurrent = ASMAtomicReadU32(&pVBVA->aRecords[indexRecordFirst].cbRecord);
348
349 /* A new record need to be processed. */
350 if (cbRecordCurrent & VBVA_F_RECORD_PARTIAL)
351 {
352 /* the record is being recorded, try again */
353 return VINF_TRY_AGAIN;
354 }
355
356 uint32_t cbRecord = cbRecordCurrent & ~VBVA_F_RECORD_PARTIAL;
357
358 if (!cbRecord)
359 {
360 /* the record is being recorded, try again */
361 return VINF_TRY_AGAIN;
362 }
363
364 /* we should not get partial commands here actually */
365 Assert(cbRecord);
366
367 /* The size of largest contiguous chunk in the ring biffer. */
368 uint32_t u32BytesTillBoundary = pVBVA->cbData - pVBVA->off32Data;
369
370 /* The pointer to data in the ring buffer. */
371 uint8_t *pSrc = &pVBVA->au8Data[pVBVA->off32Data];
372
373 /* Fetch or point the data. */
374 if (u32BytesTillBoundary >= cbRecord)
375 {
376 /* The command does not cross buffer boundary. Return address in the buffer. */
377 *ppCmd = pSrc;
378 *pcbCmd = cbRecord;
379 return VINF_SUCCESS;
380 }
381
382 LogRel(("CmdVbva: cross-bound writes unsupported\n"));
383 return VERR_INVALID_STATE;
384}
385
386static void VBoxVBVAExHPDataCompleteCmd(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint32_t cbCmd)
387{
388 VBVABUFFER *pVBVA = pCmdVbva->pVBVA;
389 pVBVA->off32Data = (pVBVA->off32Data + cbCmd) % pVBVA->cbData;
390
391 pVBVA->indexRecordFirst = (pVBVA->indexRecordFirst + 1) % RT_ELEMENTS(pVBVA->aRecords);
392}
393
394static void VBoxVBVAExHPDataCompleteCtl(struct VBVAEXHOSTCONTEXT *pCmdVbva, VBVAEXHOSTCTL *pCtl, int rc)
395{
396 if (pCtl->pfnComplete)
397 pCtl->pfnComplete(pCmdVbva, pCtl, rc, pCtl->pvComplete);
398 else
399 VBoxVBVAExHCtlFree(pCmdVbva, pCtl);
400}
401
402static VBVAEXHOST_DATA_TYPE vboxVBVAExHPDataGet(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t **ppCmd, uint32_t *pcbCmd)
403{
404 Assert(pCmdVbva->i32State == VBVAEXHOSTCONTEXT_STATE_PROCESSING);
405 VBVAEXHOSTCTL*pCtl;
406 bool fHostClt;
407
408 for(;;)
409 {
410 pCtl = vboxVBVAExHPCheckCtl(pCmdVbva, &fHostClt, false);
411 if (pCtl)
412 {
413 if (fHostClt)
414 {
415 if (!vboxVBVAExHPCheckProcessCtlInternal(pCmdVbva, pCtl))
416 {
417 *ppCmd = (uint8_t*)pCtl;
418 *pcbCmd = sizeof (*pCtl);
419 return VBVAEXHOST_DATA_TYPE_HOSTCTL;
420 }
421 continue;
422 }
423 else
424 {
425 *ppCmd = (uint8_t*)pCtl;
426 *pcbCmd = sizeof (*pCtl);
427 return VBVAEXHOST_DATA_TYPE_GUESTCTL;
428 }
429 }
430
431 if (ASMAtomicUoReadS32(&pCmdVbva->i32EnableState) <= VBVAEXHOSTCONTEXT_ESTATE_PAUSED)
432 return VBVAEXHOST_DATA_TYPE_NO_DATA;
433
434 int rc = vboxVBVAExHPCmdGet(pCmdVbva, ppCmd, pcbCmd);
435 switch (rc)
436 {
437 case VINF_SUCCESS:
438 return VBVAEXHOST_DATA_TYPE_CMD;
439 case VINF_EOF:
440 return VBVAEXHOST_DATA_TYPE_NO_DATA;
441 case VINF_TRY_AGAIN:
442 RTThreadSleep(1);
443 continue;
444 default:
445 /* this is something really unexpected, i.e. most likely guest has written something incorrect to the VBVA buffer */
446 WARN(("Warning: vboxVBVAExHCmdGet returned unexpected status %d\n", rc));
447 return VBVAEXHOST_DATA_TYPE_NO_DATA;
448 }
449 }
450
451 WARN(("Warning: VBoxVBVAExHCmdGet unexpected state\n"));
452 return VBVAEXHOST_DATA_TYPE_NO_DATA;
453}
454
455static VBVAEXHOST_DATA_TYPE VBoxVBVAExHPDataGet(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t **ppCmd, uint32_t *pcbCmd)
456{
457 VBVAEXHOST_DATA_TYPE enmType = vboxVBVAExHPDataGet(pCmdVbva, ppCmd, pcbCmd);
458 if (enmType == VBVAEXHOST_DATA_TYPE_NO_DATA)
459 {
460 vboxVBVAExHPHgEventClear(pCmdVbva);
461 vboxVBVAExHPProcessorRelease(pCmdVbva);
462 /* we need to prevent racing between us clearing the flag and command check/submission thread, i.e.
463 * 1. we check the queue -> and it is empty
464 * 2. submitter adds command to the queue
465 * 3. submitter checks the "processing" -> and it is true , thus it does not submit a notification
466 * 4. we clear the "processing" state
467 * 5. ->here we need to re-check the queue state to ensure we do not leak the notification of the above command
468 * 6. if the queue appears to be not-empty set the "processing" state back to "true"
469 **/
470 int rc = vboxVBVAExHSProcessorAcquire(pCmdVbva);
471 if (RT_SUCCESS(rc))
472 {
473 /* we are the processor now */
474 enmType = vboxVBVAExHPDataGet(pCmdVbva, ppCmd, pcbCmd);
475 if (enmType == VBVAEXHOST_DATA_TYPE_NO_DATA)
476 {
477 vboxVBVAExHPProcessorRelease(pCmdVbva);
478 return VBVAEXHOST_DATA_TYPE_NO_DATA;
479 }
480
481 vboxVBVAExHPHgEventSet(pCmdVbva);
482 }
483 }
484
485 return enmType;
486}
487
488DECLINLINE(bool) vboxVBVAExHSHasCommands(struct VBVAEXHOSTCONTEXT *pCmdVbva)
489{
490 VBVABUFFER *pVBVA = pCmdVbva->pVBVA;
491
492 if (pVBVA)
493 {
494 uint32_t indexRecordFirst = pVBVA->indexRecordFirst;
495 uint32_t indexRecordFree = pVBVA->indexRecordFree;
496
497 if (indexRecordFirst != indexRecordFree)
498 return true;
499 }
500
501 return !!ASMAtomicReadU32(&pCmdVbva->u32cCtls);
502}
503
504/* Checks whether the new commands are ready for processing
505 * @returns
506 * 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)
507 * VINF_EOF - no commands in a queue
508 * VINF_ALREADY_INITIALIZED - another thread already processing the commands
509 * VERR_INVALID_STATE - the VBVA is paused or pausing */
510static int VBoxVBVAExHSCheckCommands(struct VBVAEXHOSTCONTEXT *pCmdVbva)
511{
512 int rc = vboxVBVAExHSProcessorAcquire(pCmdVbva);
513 if (RT_SUCCESS(rc))
514 {
515 /* we are the processor now */
516 if (vboxVBVAExHSHasCommands(pCmdVbva))
517 {
518 vboxVBVAExHPHgEventSet(pCmdVbva);
519 return VINF_SUCCESS;
520 }
521
522 vboxVBVAExHPProcessorRelease(pCmdVbva);
523 return VINF_EOF;
524 }
525 if (rc == VERR_SEM_BUSY)
526 return VINF_ALREADY_INITIALIZED;
527 return VERR_INVALID_STATE;
528}
529
530static int VBoxVBVAExHSInit(struct VBVAEXHOSTCONTEXT *pCmdVbva)
531{
532 memset(pCmdVbva, 0, sizeof (*pCmdVbva));
533 int rc = RTCritSectInit(&pCmdVbva->CltCritSect);
534 if (RT_SUCCESS(rc))
535 {
536#ifndef VBOXVDBG_MEMCACHE_DISABLE
537 rc = RTMemCacheCreate(&pCmdVbva->CtlCache, sizeof (VBVAEXHOSTCTL),
538 0, /* size_t cbAlignment */
539 UINT32_MAX, /* uint32_t cMaxObjects */
540 NULL, /* PFNMEMCACHECTOR pfnCtor*/
541 NULL, /* PFNMEMCACHEDTOR pfnDtor*/
542 NULL, /* void *pvUser*/
543 0 /* uint32_t fFlags*/
544 );
545 if (RT_SUCCESS(rc))
546#endif
547 {
548 RTListInit(&pCmdVbva->GuestCtlList);
549 RTListInit(&pCmdVbva->HostCtlList);
550 pCmdVbva->i32State = VBVAEXHOSTCONTEXT_STATE_PROCESSING;
551 pCmdVbva->i32EnableState = VBVAEXHOSTCONTEXT_ESTATE_DISABLED;
552 return VINF_SUCCESS;
553 }
554#ifndef VBOXVDBG_MEMCACHE_DISABLE
555 else
556 WARN(("RTMemCacheCreate failed %d\n", rc));
557#endif
558 }
559 else
560 WARN(("RTCritSectInit failed %d\n", rc));
561
562 return rc;
563}
564
565DECLINLINE(bool) VBoxVBVAExHSIsEnabled(struct VBVAEXHOSTCONTEXT *pCmdVbva)
566{
567 return (ASMAtomicUoReadS32(&pCmdVbva->i32EnableState) >= VBVAEXHOSTCONTEXT_ESTATE_PAUSED);
568}
569
570DECLINLINE(bool) VBoxVBVAExHSIsDisabled(struct VBVAEXHOSTCONTEXT *pCmdVbva)
571{
572 return (ASMAtomicUoReadS32(&pCmdVbva->i32EnableState) == VBVAEXHOSTCONTEXT_ESTATE_DISABLED);
573}
574
575static int VBoxVBVAExHSEnable(struct VBVAEXHOSTCONTEXT *pCmdVbva, VBVABUFFER *pVBVA)
576{
577 if (VBoxVBVAExHSIsEnabled(pCmdVbva))
578 {
579 WARN(("VBVAEx is enabled already\n"));
580 return VERR_INVALID_STATE;
581 }
582
583 pCmdVbva->pVBVA = pVBVA;
584 pCmdVbva->pVBVA->hostFlags.u32HostEvents = 0;
585 ASMAtomicWriteS32(&pCmdVbva->i32EnableState, VBVAEXHOSTCONTEXT_ESTATE_ENABLED);
586 return VINF_SUCCESS;
587}
588
589static int VBoxVBVAExHSDisable(struct VBVAEXHOSTCONTEXT *pCmdVbva)
590{
591 if (VBoxVBVAExHSIsDisabled(pCmdVbva))
592 return VINF_SUCCESS;
593
594 ASMAtomicWriteS32(&pCmdVbva->i32EnableState, VBVAEXHOSTCONTEXT_ESTATE_DISABLED);
595 return VINF_SUCCESS;
596}
597
598static void VBoxVBVAExHSTerm(struct VBVAEXHOSTCONTEXT *pCmdVbva)
599{
600 /* ensure the processor is stopped */
601 Assert(pCmdVbva->i32State >= VBVAEXHOSTCONTEXT_STATE_LISTENING);
602
603 /* ensure no one tries to submit the command */
604 if (pCmdVbva->pVBVA)
605 pCmdVbva->pVBVA->hostFlags.u32HostEvents = 0;
606
607 Assert(RTListIsEmpty(&pCmdVbva->GuestCtlList));
608 Assert(RTListIsEmpty(&pCmdVbva->HostCtlList));
609
610 RTCritSectDelete(&pCmdVbva->CltCritSect);
611
612#ifndef VBOXVDBG_MEMCACHE_DISABLE
613 RTMemCacheDestroy(pCmdVbva->CtlCache);
614#endif
615
616 memset(pCmdVbva, 0, sizeof (*pCmdVbva));
617}
618
619static int vboxVBVAExHSSaveGuestCtl(struct VBVAEXHOSTCONTEXT *pCmdVbva, VBVAEXHOSTCTL* pCtl, uint8_t* pu8VramBase, PSSMHANDLE pSSM)
620{
621 int rc = SSMR3PutU32(pSSM, pCtl->enmType);
622 AssertRCReturn(rc, rc);
623 rc = SSMR3PutU32(pSSM, pCtl->u.cmd.cbCmd);
624 AssertRCReturn(rc, rc);
625 rc = SSMR3PutU32(pSSM, (uint32_t)(pCtl->u.cmd.pu8Cmd - pu8VramBase));
626 AssertRCReturn(rc, rc);
627
628 return VINF_SUCCESS;
629}
630
631static int vboxVBVAExHSSaveStateLocked(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t* pu8VramBase, PSSMHANDLE pSSM)
632{
633 if (ASMAtomicUoReadS32(&pCmdVbva->i32EnableState) != VBVAEXHOSTCONTEXT_ESTATE_PAUSED)
634 {
635 WARN(("vbva not paused\n"));
636 return VERR_INVALID_STATE;
637 }
638
639 VBVAEXHOSTCTL* pCtl;
640 int rc;
641 RTListForEach(&pCmdVbva->GuestCtlList, pCtl, VBVAEXHOSTCTL, Node)
642 {
643 rc = vboxVBVAExHSSaveGuestCtl(pCmdVbva, pCtl, pu8VramBase, pSSM);
644 AssertRCReturn(rc, rc);
645 }
646
647 rc = SSMR3PutU32(pSSM, 0);
648 AssertRCReturn(rc, rc);
649
650 return VINF_SUCCESS;
651}
652/* Saves state
653 * @returns - same as VBoxVBVAExHSCheckCommands, or failure on load state fail
654 */
655static int VBoxVBVAExHSSaveState(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t* pu8VramBase, PSSMHANDLE pSSM)
656{
657 int rc = RTCritSectEnter(&pCmdVbva->CltCritSect);
658 if (RT_FAILURE(rc))
659 {
660 WARN(("RTCritSectEnter failed %d\n", rc));
661 return rc;
662 }
663
664 rc = vboxVBVAExHSSaveStateLocked(pCmdVbva, pu8VramBase, pSSM);
665 if (RT_FAILURE(rc))
666 WARN(("vboxVBVAExHSSaveStateLocked failed %d\n", rc));
667
668 RTCritSectLeave(&pCmdVbva->CltCritSect);
669
670 return rc;
671}
672
673static int vboxVBVAExHSLoadGuestCtl(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t* pu8VramBase, PSSMHANDLE pSSM, uint32_t u32Version)
674{
675 uint32_t u32;
676 int rc = SSMR3GetU32(pSSM, &u32);
677 AssertRCReturn(rc, rc);
678
679 if (!u32)
680 return VINF_EOF;
681
682 VBVAEXHOSTCTL* pHCtl = VBoxVBVAExHCtlCreate(pCmdVbva, (VBVAEXHOSTCTL_TYPE)u32);
683 if (!pHCtl)
684 {
685 WARN(("VBoxVBVAExHCtlCreate failed\n"));
686 return VERR_NO_MEMORY;
687 }
688
689 rc = SSMR3GetU32(pSSM, &u32);
690 AssertRCReturn(rc, rc);
691 pHCtl->u.cmd.cbCmd = u32;
692
693 rc = SSMR3GetU32(pSSM, &u32);
694 AssertRCReturn(rc, rc);
695 pHCtl->u.cmd.pu8Cmd = pu8VramBase + u32;
696
697 RTListAppend(&pCmdVbva->GuestCtlList, &pHCtl->Node);
698 ++pCmdVbva->u32cCtls;
699
700 return VINF_SUCCESS;
701}
702
703
704static int vboxVBVAExHSLoadStateLocked(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t* pu8VramBase, PSSMHANDLE pSSM, uint32_t u32Version)
705{
706 if (ASMAtomicUoReadS32(&pCmdVbva->i32EnableState) != VBVAEXHOSTCONTEXT_ESTATE_PAUSED)
707 {
708 WARN(("vbva not stopped\n"));
709 return VERR_INVALID_STATE;
710 }
711
712 int rc;
713
714 do {
715 rc = vboxVBVAExHSLoadGuestCtl(pCmdVbva, pu8VramBase, pSSM, u32Version);
716 AssertRCReturn(rc, rc);
717 } while (VINF_EOF != rc);
718
719 return VINF_SUCCESS;
720}
721
722/* Loads state
723 * @returns - same as VBoxVBVAExHSCheckCommands, or failure on load state fail
724 */
725static int VBoxVBVAExHSLoadState(struct VBVAEXHOSTCONTEXT *pCmdVbva, uint8_t* pu8VramBase, PSSMHANDLE pSSM, uint32_t u32Version)
726{
727 Assert(VGA_SAVEDSTATE_VERSION_3D <= u32Version);
728 int rc = RTCritSectEnter(&pCmdVbva->CltCritSect);
729 if (RT_FAILURE(rc))
730 {
731 WARN(("RTCritSectEnter failed %d\n", rc));
732 return rc;
733 }
734
735 rc = vboxVBVAExHSLoadStateLocked(pCmdVbva, pu8VramBase, pSSM, u32Version);
736 if (RT_FAILURE(rc))
737 WARN(("vboxVBVAExHSSaveStateLocked failed %d\n", rc));
738
739 RTCritSectLeave(&pCmdVbva->CltCritSect);
740
741 return rc;
742}
743
744typedef enum
745{
746 VBVAEXHOSTCTL_SOURCE_GUEST = 0,
747 VBVAEXHOSTCTL_SOURCE_HOST
748} VBVAEXHOSTCTL_SOURCE;
749
750
751static int VBoxVBVAExHCtlSubmit(VBVAEXHOSTCONTEXT *pCmdVbva, VBVAEXHOSTCTL* pCtl, VBVAEXHOSTCTL_SOURCE enmSource, PFNVBVAEXHOSTCTL_COMPLETE pfnComplete, void *pvComplete)
752{
753 if (!VBoxVBVAExHSIsEnabled(pCmdVbva))
754 {
755 Log(("cmd vbva not enabled\n"));
756 return VERR_INVALID_STATE;
757 }
758
759 pCtl->pfnComplete = pfnComplete;
760 pCtl->pvComplete = pvComplete;
761
762 int rc = RTCritSectEnter(&pCmdVbva->CltCritSect);
763 if (RT_SUCCESS(rc))
764 {
765 if (!VBoxVBVAExHSIsEnabled(pCmdVbva))
766 {
767 Log(("cmd vbva not enabled\n"));
768 RTCritSectLeave(&pCmdVbva->CltCritSect);
769 return VERR_INVALID_STATE;
770 }
771
772 if (enmSource > VBVAEXHOSTCTL_SOURCE_GUEST)
773 {
774 RTListAppend(&pCmdVbva->HostCtlList, &pCtl->Node);
775 }
776 else
777 RTListAppend(&pCmdVbva->GuestCtlList, &pCtl->Node);
778
779 ASMAtomicIncU32(&pCmdVbva->u32cCtls);
780
781 RTCritSectLeave(&pCmdVbva->CltCritSect);
782
783 rc = VBoxVBVAExHSCheckCommands(pCmdVbva);
784 }
785 else
786 WARN(("RTCritSectEnter failed %d\n", rc));
787
788 return rc;
789}
790
791#ifdef VBOX_WITH_CRHGSMI
792typedef struct VBOXVDMA_SOURCE
793{
794 VBVAINFOSCREEN Screen;
795 VBOXCMDVBVA_SCREENMAP_DECL(uint32_t, aTargetMap);
796} VBOXVDMA_SOURCE;
797#endif
798
799typedef struct VBOXVDMAHOST
800{
801 PHGSMIINSTANCE pHgsmi;
802 PVGASTATE pVGAState;
803#ifdef VBOX_WITH_CRHGSMI
804 VBVAEXHOSTCONTEXT CmdVbva;
805 VBOXVDMATHREAD Thread;
806 VBOXCRCMD_SVRINFO CrSrvInfo;
807 VBVAEXHOSTCTL* pCurRemainingHostCtl;
808 RTSEMEVENTMULTI HostCrCtlCompleteEvent;
809 int32_t volatile i32cHostCrCtlCompleted;
810// VBOXVDMA_SOURCE aSources[VBOX_VIDEO_MAX_SCREENS];
811#endif
812#ifdef VBOX_VDMA_WITH_WATCHDOG
813 PTMTIMERR3 WatchDogTimer;
814#endif
815} VBOXVDMAHOST, *PVBOXVDMAHOST;
816
817#ifdef VBOX_WITH_CRHGSMI
818
819void VBoxVDMAThreadNotifyConstructSucceeded(PVBOXVDMATHREAD pThread, void *pvThreadContext)
820{
821 Assert(pThread->u32State == VBOXVDMATHREAD_STATE_CREATING);
822 PFNVBOXVDMATHREAD_CHANGED pfnChanged = pThread->pfnChanged;
823 void *pvChanged = pThread->pvChanged;
824
825 pThread->pfnChanged = NULL;
826 pThread->pvChanged = NULL;
827
828 ASMAtomicWriteU32(&pThread->u32State, VBOXVDMATHREAD_STATE_CREATED);
829
830 if (pfnChanged)
831 pfnChanged(pThread, VINF_SUCCESS, pvThreadContext, pvChanged);
832}
833
834void VBoxVDMAThreadNotifyTerminatingSucceeded(PVBOXVDMATHREAD pThread, void *pvThreadContext)
835{
836 Assert(pThread->u32State == VBOXVDMATHREAD_STATE_TERMINATING);
837 PFNVBOXVDMATHREAD_CHANGED pfnChanged = pThread->pfnChanged;
838 void *pvChanged = pThread->pvChanged;
839
840 pThread->pfnChanged = NULL;
841 pThread->pvChanged = NULL;
842
843 if (pfnChanged)
844 pfnChanged(pThread, VINF_SUCCESS, pvThreadContext, pvChanged);
845}
846
847DECLINLINE(bool) VBoxVDMAThreadIsTerminating(PVBOXVDMATHREAD pThread)
848{
849 return ASMAtomicUoReadU32(&pThread->u32State) == VBOXVDMATHREAD_STATE_TERMINATING;
850}
851
852void VBoxVDMAThreadInit(PVBOXVDMATHREAD pThread)
853{
854 memset(pThread, 0, sizeof (*pThread));
855 pThread->u32State = VBOXVDMATHREAD_STATE_TERMINATED;
856}
857
858int VBoxVDMAThreadCleanup(PVBOXVDMATHREAD pThread)
859{
860 uint32_t u32State = ASMAtomicUoReadU32(&pThread->u32State);
861 switch (u32State)
862 {
863 case VBOXVDMATHREAD_STATE_TERMINATED:
864 return VINF_SUCCESS;
865 case VBOXVDMATHREAD_STATE_TERMINATING:
866 {
867 int rc = RTThreadWait(pThread->hWorkerThread, RT_INDEFINITE_WAIT, NULL);
868 if (!RT_SUCCESS(rc))
869 {
870 WARN(("RTThreadWait failed %d\n", rc));
871 return rc;
872 }
873
874 RTSemEventDestroy(pThread->hEvent);
875
876 ASMAtomicWriteU32(&pThread->u32State, VBOXVDMATHREAD_STATE_TERMINATED);
877 return VINF_SUCCESS;
878 }
879 default:
880 WARN(("invalid state"));
881 return VERR_INVALID_STATE;
882 }
883}
884
885int VBoxVDMAThreadCreate(PVBOXVDMATHREAD pThread, PFNRTTHREAD pfnThread, void *pvThread, PFNVBOXVDMATHREAD_CHANGED pfnCreated, void*pvCreated)
886{
887 int rc = VBoxVDMAThreadCleanup(pThread);
888 if (RT_FAILURE(rc))
889 {
890 WARN(("VBoxVDMAThreadCleanup failed %d\n", rc));
891 return rc;
892 }
893
894 rc = RTSemEventCreate(&pThread->hEvent);
895 if (RT_SUCCESS(rc))
896 {
897 pThread->u32State = VBOXVDMATHREAD_STATE_CREATING;
898 pThread->pfnChanged = pfnCreated;
899 pThread->pvChanged = pvCreated;
900 rc = RTThreadCreate(&pThread->hWorkerThread, pfnThread, pvThread, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "VDMA");
901 if (RT_SUCCESS(rc))
902 return VINF_SUCCESS;
903 else
904 WARN(("RTThreadCreate failed %d\n", rc));
905
906 RTSemEventDestroy(pThread->hEvent);
907 }
908 else
909 WARN(("RTSemEventCreate failed %d\n", rc));
910
911 pThread->u32State = VBOXVDMATHREAD_STATE_TERMINATED;
912
913 return rc;
914}
915
916DECLINLINE(int) VBoxVDMAThreadEventNotify(PVBOXVDMATHREAD pThread)
917{
918 int rc = RTSemEventSignal(pThread->hEvent);
919 AssertRC(rc);
920 return rc;
921}
922
923DECLINLINE(int) VBoxVDMAThreadEventWait(PVBOXVDMATHREAD pThread, RTMSINTERVAL cMillies)
924{
925 int rc = RTSemEventWait(pThread->hEvent, cMillies);
926 AssertRC(rc);
927 return rc;
928}
929
930int VBoxVDMAThreadTerm(PVBOXVDMATHREAD pThread, PFNVBOXVDMATHREAD_CHANGED pfnTerminated, void*pvTerminated, bool fNotify)
931{
932 int rc;
933 do
934 {
935 uint32_t u32State = ASMAtomicUoReadU32(&pThread->u32State);
936 switch (u32State)
937 {
938 case VBOXVDMATHREAD_STATE_CREATED:
939 pThread->pfnChanged = pfnTerminated;
940 pThread->pvChanged = pvTerminated;
941 ASMAtomicWriteU32(&pThread->u32State, VBOXVDMATHREAD_STATE_TERMINATING);
942 if (fNotify)
943 {
944 rc = VBoxVDMAThreadEventNotify(pThread);
945 AssertRC(rc);
946 }
947 return VINF_SUCCESS;
948 case VBOXVDMATHREAD_STATE_TERMINATING:
949 case VBOXVDMATHREAD_STATE_TERMINATED:
950 {
951 WARN(("thread is marked to termination or terminated\nn"));
952 return VERR_INVALID_STATE;
953 }
954 case VBOXVDMATHREAD_STATE_CREATING:
955 {
956 /* wait till the thread creation is completed */
957 WARN(("concurrent thread create/destron\n"));
958 RTThreadYield();
959 continue;
960 }
961 default:
962 WARN(("invalid state"));
963 return VERR_INVALID_STATE;
964 }
965 } while (1);
966
967 WARN(("should never be here\n"));
968 return VERR_INTERNAL_ERROR;
969}
970
971static int vdmaVBVACtlSubmitSync(PVBOXVDMAHOST pVdma, VBVAEXHOSTCTL* pCtl, VBVAEXHOSTCTL_SOURCE enmSource);
972
973typedef DECLCALLBACK(void) FNVBOXVDMACRCTL_CALLBACK(PVGASTATE pVGAState, PVBOXVDMACMD_CHROMIUM_CTL pCmd, void* pvContext);
974typedef FNVBOXVDMACRCTL_CALLBACK *PFNVBOXVDMACRCTL_CALLBACK;
975
976typedef struct VBOXVDMACMD_CHROMIUM_CTL_PRIVATE
977{
978 uint32_t cRefs;
979 int32_t rc;
980 PFNVBOXVDMACRCTL_CALLBACK pfnCompletion;
981 void *pvCompletion;
982 VBOXVDMACMD_CHROMIUM_CTL Cmd;
983} VBOXVDMACMD_CHROMIUM_CTL_PRIVATE, *PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE;
984
985#define VBOXVDMACMD_CHROMIUM_CTL_PRIVATE_FROM_CTL(_p) ((PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE)(((uint8_t*)(_p)) - RT_OFFSETOF(VBOXVDMACMD_CHROMIUM_CTL_PRIVATE, Cmd)))
986
987static PVBOXVDMACMD_CHROMIUM_CTL vboxVDMACrCtlCreate(VBOXVDMACMD_CHROMIUM_CTL_TYPE enmCmd, uint32_t cbCmd)
988{
989 PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE pHdr = (PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE)RTMemAllocZ(cbCmd + RT_OFFSETOF(VBOXVDMACMD_CHROMIUM_CTL_PRIVATE, Cmd));
990 Assert(pHdr);
991 if (pHdr)
992 {
993 pHdr->cRefs = 1;
994 pHdr->rc = VERR_NOT_IMPLEMENTED;
995 pHdr->Cmd.enmType = enmCmd;
996 pHdr->Cmd.cbCmd = cbCmd;
997 return &pHdr->Cmd;
998 }
999
1000 return NULL;
1001}
1002
1003DECLINLINE(void) vboxVDMACrCtlRelease (PVBOXVDMACMD_CHROMIUM_CTL pCmd)
1004{
1005 PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE pHdr = VBOXVDMACMD_CHROMIUM_CTL_PRIVATE_FROM_CTL(pCmd);
1006 uint32_t cRefs = ASMAtomicDecU32(&pHdr->cRefs);
1007 if(!cRefs)
1008 {
1009 RTMemFree(pHdr);
1010 }
1011}
1012
1013DECLINLINE(void) vboxVDMACrCtlRetain (PVBOXVDMACMD_CHROMIUM_CTL pCmd)
1014{
1015 PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE pHdr = VBOXVDMACMD_CHROMIUM_CTL_PRIVATE_FROM_CTL(pCmd);
1016 ASMAtomicIncU32(&pHdr->cRefs);
1017}
1018
1019DECLINLINE(int) vboxVDMACrCtlGetRc (PVBOXVDMACMD_CHROMIUM_CTL pCmd)
1020{
1021 PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE pHdr = VBOXVDMACMD_CHROMIUM_CTL_PRIVATE_FROM_CTL(pCmd);
1022 return pHdr->rc;
1023}
1024
1025static DECLCALLBACK(void) vboxVDMACrCtlCbSetEvent(PVGASTATE pVGAState, PVBOXVDMACMD_CHROMIUM_CTL pCmd, void* pvContext)
1026{
1027 RTSemEventSignal((RTSEMEVENT)pvContext);
1028}
1029
1030static DECLCALLBACK(void) vboxVDMACrCtlCbReleaseCmd(PVGASTATE pVGAState, PVBOXVDMACMD_CHROMIUM_CTL pCmd, void* pvContext)
1031{
1032 vboxVDMACrCtlRelease(pCmd);
1033}
1034
1035
1036static int vboxVDMACrCtlPostAsync (PVGASTATE pVGAState, PVBOXVDMACMD_CHROMIUM_CTL pCmd, uint32_t cbCmd, PFNVBOXVDMACRCTL_CALLBACK pfnCompletion, void *pvCompletion)
1037{
1038 if ( pVGAState->pDrv
1039 && pVGAState->pDrv->pfnCrHgsmiControlProcess)
1040 {
1041 PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE pHdr = VBOXVDMACMD_CHROMIUM_CTL_PRIVATE_FROM_CTL(pCmd);
1042 pHdr->pfnCompletion = pfnCompletion;
1043 pHdr->pvCompletion = pvCompletion;
1044 pVGAState->pDrv->pfnCrHgsmiControlProcess(pVGAState->pDrv, pCmd, cbCmd);
1045 return VINF_SUCCESS;
1046 }
1047#ifdef DEBUG_misha
1048 Assert(0);
1049#endif
1050 return VERR_NOT_SUPPORTED;
1051}
1052
1053static int vboxVDMACrCtlPost(PVGASTATE pVGAState, PVBOXVDMACMD_CHROMIUM_CTL pCmd, uint32_t cbCmd)
1054{
1055 RTSEMEVENT hComplEvent;
1056 int rc = RTSemEventCreate(&hComplEvent);
1057 AssertRC(rc);
1058 if(RT_SUCCESS(rc))
1059 {
1060 rc = vboxVDMACrCtlPostAsync(pVGAState, pCmd, cbCmd, vboxVDMACrCtlCbSetEvent, (void*)hComplEvent);
1061#ifdef DEBUG_misha
1062 AssertRC(rc);
1063#endif
1064 if (RT_SUCCESS(rc))
1065 {
1066 rc = RTSemEventWaitNoResume(hComplEvent, RT_INDEFINITE_WAIT);
1067 AssertRC(rc);
1068 if(RT_SUCCESS(rc))
1069 {
1070 RTSemEventDestroy(hComplEvent);
1071 }
1072 }
1073 else
1074 {
1075 /* the command is completed */
1076 RTSemEventDestroy(hComplEvent);
1077 }
1078 }
1079 return rc;
1080}
1081
1082typedef struct VDMA_VBVA_CTL_CYNC_COMPLETION
1083{
1084 int rc;
1085 RTSEMEVENT hEvent;
1086} VDMA_VBVA_CTL_CYNC_COMPLETION;
1087
1088static DECLCALLBACK(void) vboxVDMACrHgcmSubmitSyncCompletion(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd, int rc, void *pvCompletion)
1089{
1090 VDMA_VBVA_CTL_CYNC_COMPLETION *pData = (VDMA_VBVA_CTL_CYNC_COMPLETION*)pvCompletion;
1091 pData->rc = rc;
1092 rc = RTSemEventSignal(pData->hEvent);
1093 if (!RT_SUCCESS(rc))
1094 WARN(("RTSemEventSignal failed %d\n", rc));
1095}
1096
1097static int vboxVDMACrHgcmSubmitSync(struct VBOXVDMAHOST *pVdma, VBOXCRCMDCTL* pCtl, uint32_t cbCtl)
1098{
1099 VDMA_VBVA_CTL_CYNC_COMPLETION Data;
1100 Data.rc = VERR_NOT_IMPLEMENTED;
1101 int rc = RTSemEventCreate(&Data.hEvent);
1102 if (!RT_SUCCESS(rc))
1103 {
1104 WARN(("RTSemEventCreate failed %d\n", rc));
1105 return rc;
1106 }
1107
1108 PVGASTATE pVGAState = pVdma->pVGAState;
1109 rc = pVGAState->pDrv->pfnCrHgcmCtlSubmit(pVGAState->pDrv, pCtl, cbCtl, vboxVDMACrHgcmSubmitSyncCompletion, &Data);
1110 if (RT_SUCCESS(rc))
1111 {
1112 rc = RTSemEventWait(Data.hEvent, RT_INDEFINITE_WAIT);
1113 if (RT_SUCCESS(rc))
1114 {
1115 rc = Data.rc;
1116 if (!RT_SUCCESS(rc))
1117 {
1118 WARN(("pfnCrHgcmCtlSubmit command failed %d\n", rc));
1119 }
1120
1121 }
1122 else
1123 WARN(("RTSemEventWait failed %d\n", rc));
1124 }
1125 else
1126 WARN(("pfnCrHgcmCtlSubmit failed %d\n", rc));
1127
1128
1129 RTSemEventDestroy(Data.hEvent);
1130
1131 return rc;
1132}
1133
1134static int vdmaVBVACtlDisableSync(PVBOXVDMAHOST pVdma)
1135{
1136 VBVAEXHOSTCTL HCtl;
1137 HCtl.enmType = VBVAEXHOSTCTL_TYPE_GHH_DISABLE;
1138 int rc = vdmaVBVACtlSubmitSync(pVdma, &HCtl, VBVAEXHOSTCTL_SOURCE_HOST);
1139 if (RT_FAILURE(rc))
1140 {
1141 Log(("vdmaVBVACtlSubmitSync failed %d\n", rc));
1142 return rc;
1143 }
1144
1145 vgaUpdateDisplayAll(pVdma->pVGAState);
1146
1147 return VINF_SUCCESS;
1148}
1149
1150static DECLCALLBACK(uint8_t*) vboxVDMACrHgcmHandleEnableRemainingHostCommand(HVBOXCRCMDCTL_REMAINING_HOST_COMMAND hClient, uint32_t *pcbCtl, int prevCmdRc)
1151{
1152 struct VBOXVDMAHOST *pVdma = hClient;
1153 if (!pVdma->pCurRemainingHostCtl)
1154 {
1155 /* disable VBVA, all subsequent host commands will go HGCM way */
1156 VBoxVBVAExHSDisable(&pVdma->CmdVbva);
1157 }
1158 else
1159 {
1160 VBoxVBVAExHPDataCompleteCtl(&pVdma->CmdVbva, pVdma->pCurRemainingHostCtl, prevCmdRc);
1161 }
1162
1163 pVdma->pCurRemainingHostCtl = VBoxVBVAExHPCheckHostCtlOnDisable(&pVdma->CmdVbva);
1164 if (pVdma->pCurRemainingHostCtl)
1165 {
1166 *pcbCtl = pVdma->pCurRemainingHostCtl->u.cmd.cbCmd;
1167 return pVdma->pCurRemainingHostCtl->u.cmd.pu8Cmd;
1168 }
1169
1170 *pcbCtl = 0;
1171 return NULL;
1172}
1173
1174static DECLCALLBACK(void) vboxVDMACrHgcmNotifyTerminatingDoneCb(HVBOXCRCMDCTL_NOTIFY_TERMINATING hClient)
1175{
1176 struct VBOXVDMAHOST *pVdma = hClient;
1177 Assert(pVdma->CmdVbva.i32State == VBVAEXHOSTCONTEXT_STATE_PROCESSING);
1178 Assert(pVdma->Thread.u32State == VBOXVDMATHREAD_STATE_TERMINATING);
1179}
1180
1181static DECLCALLBACK(int) vboxVDMACrHgcmNotifyTerminatingCb(HVBOXCRCMDCTL_NOTIFY_TERMINATING hClient, VBOXCRCMDCTL_HGCMENABLE_DATA *pHgcmEnableData)
1182{
1183 struct VBOXVDMAHOST *pVdma = hClient;
1184 VBVAEXHOSTCTL HCtl;
1185 HCtl.enmType = VBVAEXHOSTCTL_TYPE_HH_ON_HGCM_UNLOAD;
1186 int rc = vdmaVBVACtlSubmitSync(pVdma, &HCtl, VBVAEXHOSTCTL_SOURCE_HOST);
1187
1188 pHgcmEnableData->hRHCmd = pVdma;
1189 pHgcmEnableData->pfnRHCmd = vboxVDMACrHgcmHandleEnableRemainingHostCommand;
1190
1191 if (RT_FAILURE(rc))
1192 {
1193 if (rc == VERR_INVALID_STATE)
1194 rc = VINF_SUCCESS;
1195 else
1196 WARN(("vdmaVBVACtlSubmitSync failed %d\n", rc));
1197 }
1198
1199 return rc;
1200}
1201
1202static int vboxVDMACrHgcmHandleEnable(struct VBOXVDMAHOST *pVdma)
1203{
1204 VBOXCRCMDCTL_ENABLE Enable;
1205 Enable.Hdr.enmType = VBOXCRCMDCTL_TYPE_ENABLE;
1206 Enable.Data.hRHCmd = pVdma;
1207 Enable.Data.pfnRHCmd = vboxVDMACrHgcmHandleEnableRemainingHostCommand;
1208
1209 int rc = vboxVDMACrHgcmSubmitSync(pVdma, &Enable.Hdr, sizeof (Enable));
1210 Assert(!pVdma->pCurRemainingHostCtl);
1211 if (RT_SUCCESS(rc))
1212 {
1213 Assert(!VBoxVBVAExHSIsEnabled(&pVdma->CmdVbva));
1214 return VINF_SUCCESS;
1215 }
1216
1217 Assert(VBoxVBVAExHSIsEnabled(&pVdma->CmdVbva));
1218 WARN(("vboxVDMACrHgcmSubmitSync failed %d\n", rc));
1219
1220 return rc;
1221}
1222
1223static int vdmaVBVAEnableProcess(struct VBOXVDMAHOST *pVdma, uint32_t u32Offset)
1224{
1225 if (VBoxVBVAExHSIsEnabled(&pVdma->CmdVbva))
1226 {
1227 WARN(("vdma VBVA is already enabled\n"));
1228 return VERR_INVALID_STATE;
1229 }
1230
1231 VBVABUFFER *pVBVA = (VBVABUFFER *)HGSMIOffsetToPointerHost(pVdma->pHgsmi, u32Offset);
1232 if (!pVBVA)
1233 {
1234 WARN(("invalid offset %d\n", u32Offset));
1235 return VERR_INVALID_PARAMETER;
1236 }
1237
1238 if (!pVdma->CrSrvInfo.pfnEnable)
1239 {
1240#ifdef DEBUG_misha
1241 WARN(("pfnEnable is NULL\n"));
1242 return VERR_NOT_SUPPORTED;
1243#endif
1244 }
1245
1246 int rc = VBoxVBVAExHSEnable(&pVdma->CmdVbva, pVBVA);
1247 if (RT_SUCCESS(rc))
1248 {
1249 VBOXCRCMDCTL_DISABLE Disable;
1250 Disable.Hdr.enmType = VBOXCRCMDCTL_TYPE_DISABLE;
1251 Disable.Data.hNotifyTerm = pVdma;
1252 Disable.Data.pfnNotifyTerm = vboxVDMACrHgcmNotifyTerminatingCb;
1253 Disable.Data.pfnNotifyTermDone = vboxVDMACrHgcmNotifyTerminatingDoneCb;
1254 rc = vboxVDMACrHgcmSubmitSync(pVdma, &Disable.Hdr, sizeof (Disable));
1255 if (RT_SUCCESS(rc))
1256 {
1257 PVGASTATE pVGAState = pVdma->pVGAState;
1258 VBOXCRCMD_SVRENABLE_INFO Info;
1259 Info.hCltScr = pVGAState->pDrv;
1260 Info.pfnCltScrUpdateBegin = pVGAState->pDrv->pfnVBVAUpdateBegin;
1261 Info.pfnCltScrUpdateProcess = pVGAState->pDrv->pfnVBVAUpdateProcess;
1262 Info.pfnCltScrUpdateEnd = pVGAState->pDrv->pfnVBVAUpdateEnd;
1263 rc = pVdma->CrSrvInfo.pfnEnable(pVdma->CrSrvInfo.hSvr, &Info);
1264 if (RT_SUCCESS(rc))
1265 return VINF_SUCCESS;
1266 else
1267 WARN(("pfnEnable failed %d\n", rc));
1268
1269 vboxVDMACrHgcmHandleEnable(pVdma);
1270 }
1271 else
1272 WARN(("vboxVDMACrHgcmSubmitSync failed %d\n", rc));
1273
1274 VBoxVBVAExHSDisable(&pVdma->CmdVbva);
1275 }
1276 else
1277 WARN(("VBoxVBVAExHSEnable failed %d\n", rc));
1278
1279 return rc;
1280}
1281
1282static int vdmaVBVADisableProcess(struct VBOXVDMAHOST *pVdma, bool fDoHgcmEnable)
1283{
1284 if (!VBoxVBVAExHSIsEnabled(&pVdma->CmdVbva))
1285 {
1286 Log(("vdma VBVA is already disabled\n"));
1287 return VINF_SUCCESS;
1288 }
1289
1290 int rc = pVdma->CrSrvInfo.pfnDisable(pVdma->CrSrvInfo.hSvr);
1291 if (RT_SUCCESS(rc))
1292 {
1293 if (fDoHgcmEnable)
1294 {
1295 PVGASTATE pVGAState = pVdma->pVGAState;
1296
1297 /* disable is a bit tricky
1298 * we need to ensure the host ctl commands do not come out of order
1299 * and do not come over HGCM channel until after it is enabled */
1300 rc = vboxVDMACrHgcmHandleEnable(pVdma);
1301 if (RT_SUCCESS(rc))
1302 {
1303 vdmaVBVANotifyDisable(pVGAState);
1304 return VINF_SUCCESS;
1305 }
1306
1307 VBOXCRCMD_SVRENABLE_INFO Info;
1308 Info.hCltScr = pVGAState->pDrv;
1309 Info.pfnCltScrUpdateBegin = pVGAState->pDrv->pfnVBVAUpdateBegin;
1310 Info.pfnCltScrUpdateProcess = pVGAState->pDrv->pfnVBVAUpdateProcess;
1311 Info.pfnCltScrUpdateEnd = pVGAState->pDrv->pfnVBVAUpdateEnd;
1312 pVdma->CrSrvInfo.pfnEnable(pVdma->CrSrvInfo.hSvr, &Info);
1313 }
1314 }
1315 else
1316 WARN(("pfnDisable failed %d\n", rc));
1317
1318 return rc;
1319}
1320
1321static int vboxVDMACrHostCtlProcess(struct VBOXVDMAHOST *pVdma, VBVAEXHOSTCTL *pCmd, bool *pfContinue)
1322{
1323 *pfContinue = true;
1324
1325 switch (pCmd->enmType)
1326 {
1327 case VBVAEXHOSTCTL_TYPE_GHH_BE_OPAQUE:
1328 {
1329 if (!VBoxVBVAExHSIsEnabled(&pVdma->CmdVbva))
1330 {
1331 WARN(("VBVAEXHOSTCTL_TYPE_GHH_BE_OPAQUE for disabled vdma VBVA\n"));
1332 return VERR_INVALID_STATE;
1333 }
1334 return pVdma->CrSrvInfo.pfnHostCtl(pVdma->CrSrvInfo.hSvr, pCmd->u.cmd.pu8Cmd, pCmd->u.cmd.cbCmd);
1335 }
1336 case VBVAEXHOSTCTL_TYPE_GHH_DISABLE:
1337 {
1338 int rc = vdmaVBVADisableProcess(pVdma, true);
1339 if (RT_FAILURE(rc))
1340 {
1341 WARN(("vdmaVBVADisableProcess failed %d\n", rc));
1342 return rc;
1343 }
1344
1345 return VBoxVDMAThreadTerm(&pVdma->Thread, NULL, NULL, false);
1346 }
1347 case VBVAEXHOSTCTL_TYPE_HH_ON_HGCM_UNLOAD:
1348 {
1349 int rc = vdmaVBVADisableProcess(pVdma, false);
1350 if (RT_FAILURE(rc))
1351 {
1352 WARN(("vdmaVBVADisableProcess failed %d\n", rc));
1353 return rc;
1354 }
1355
1356 rc = VBoxVDMAThreadTerm(&pVdma->Thread, NULL, NULL, true);
1357 if (RT_FAILURE(rc))
1358 {
1359 WARN(("VBoxVDMAThreadTerm failed %d\n", rc));
1360 return rc;
1361 }
1362
1363 *pfContinue = false;
1364 return VINF_SUCCESS;
1365 }
1366 case VBVAEXHOSTCTL_TYPE_HH_SAVESTATE:
1367 {
1368 PVGASTATE pVGAState = pVdma->pVGAState;
1369 uint8_t * pu8VramBase = pVGAState->vram_ptrR3;
1370 int rc = VBoxVBVAExHSSaveState(&pVdma->CmdVbva, pu8VramBase, pCmd->u.state.pSSM);
1371 if (RT_FAILURE(rc))
1372 {
1373 WARN(("VBoxVBVAExHSSaveState failed %d\n", rc));
1374 return rc;
1375 }
1376 return pVdma->CrSrvInfo.pfnSaveState(pVdma->CrSrvInfo.hSvr, pCmd->u.state.pSSM);
1377 }
1378 case VBVAEXHOSTCTL_TYPE_HH_LOADSTATE:
1379 {
1380 PVGASTATE pVGAState = pVdma->pVGAState;
1381 uint8_t * pu8VramBase = pVGAState->vram_ptrR3;
1382
1383 int rc = VBoxVBVAExHSLoadState(&pVdma->CmdVbva, pu8VramBase, pCmd->u.state.pSSM, pCmd->u.state.u32Version);
1384 if (RT_FAILURE(rc))
1385 {
1386 WARN(("VBoxVBVAExHSSaveState failed %d\n", rc));
1387 return rc;
1388 }
1389
1390 rc = pVdma->CrSrvInfo.pfnLoadState(pVdma->CrSrvInfo.hSvr, pCmd->u.state.pSSM, pCmd->u.state.u32Version);
1391 if (RT_FAILURE(rc))
1392 {
1393 WARN(("pfnLoadState failed %d\n", rc));
1394 return rc;
1395 }
1396
1397 return VINF_SUCCESS;
1398 }
1399 case VBVAEXHOSTCTL_TYPE_HH_LOADSTATE_DONE:
1400 {
1401 PVGASTATE pVGAState = pVdma->pVGAState;
1402
1403 for (uint32_t i = 0; i < pVGAState->cMonitors; ++i)
1404 {
1405 VBVAINFOSCREEN CurScreen;
1406 VBVAINFOVIEW CurView;
1407
1408 int rc = VBVAGetInfoViewAndScreen(pVGAState, i, &CurView, &CurScreen);
1409 if (RT_FAILURE(rc))
1410 {
1411 WARN(("VBVAGetInfoViewAndScreen failed %d\n", rc));
1412 return rc;
1413 }
1414
1415 rc = VBVAInfoScreen(pVGAState, &CurScreen);
1416 if (RT_FAILURE(rc))
1417 {
1418 WARN(("VBVAInfoScreen failed %d\n", rc));
1419 return rc;
1420 }
1421 }
1422
1423 return VINF_SUCCESS;
1424 }
1425 default:
1426 WARN(("unexpected host ctl type %d\n", pCmd->enmType));
1427 return VERR_INVALID_PARAMETER;
1428 }
1429}
1430
1431static int vboxVDMACrGuestCtlResizeEntryProcess(struct VBOXVDMAHOST *pVdma, VBOXCMDVBVA_RESIZE_ENTRY *pEntry)
1432{
1433 PVGASTATE pVGAState = pVdma->pVGAState;
1434 VBVAINFOSCREEN Screen = pEntry->Screen;
1435 VBVAINFOVIEW View;
1436 VBOXCMDVBVA_SCREENMAP_DECL(uint32_t, aTargetMap);
1437 uint32_t u32ViewIndex = Screen.u32ViewIndex;
1438 uint16_t u16Flags = Screen.u16Flags;
1439 bool fDisable = false;
1440
1441 memcpy(aTargetMap, pEntry->aTargetMap, sizeof (aTargetMap));
1442
1443 ASMBitClearRange(aTargetMap, pVGAState->cMonitors, VBOX_VIDEO_MAX_SCREENS);
1444
1445 if (u16Flags & VBVA_SCREEN_F_DISABLED)
1446 {
1447 fDisable = true;
1448 memset(&Screen, 0, sizeof (Screen));
1449 Screen.u32ViewIndex = u32ViewIndex;
1450 Screen.u16Flags = VBVA_SCREEN_F_ACTIVE | VBVA_SCREEN_F_DISABLED;
1451 }
1452
1453 if (u32ViewIndex > pVGAState->cMonitors)
1454 {
1455 if (u32ViewIndex != 0xffffffff)
1456 {
1457 WARN(("invalid view index\n"));
1458 return VERR_INVALID_PARAMETER;
1459 }
1460 else if (!fDisable)
1461 {
1462 WARN(("0xffffffff view index only valid for disable requests\n"));
1463 return VERR_INVALID_PARAMETER;
1464 }
1465 }
1466
1467 View.u32ViewOffset = 0;
1468 View.u32ViewSize = Screen.u32LineSize * Screen.u32Height + Screen.u32StartOffset;
1469 View.u32MaxScreenSize = View.u32ViewSize + Screen.u32Width + 1; /* <- make VBVAInfoScreen logic (offEnd < pView->u32MaxScreenSize) happy */
1470
1471 int rc = VINF_SUCCESS;
1472
1473 for (int i = ASMBitFirstSet(aTargetMap, pVGAState->cMonitors);
1474 i >= 0;
1475 i = ASMBitNextSet(aTargetMap, pVGAState->cMonitors, i))
1476 {
1477 Screen.u32ViewIndex = i;
1478
1479 VBVAINFOSCREEN CurScreen;
1480 VBVAINFOVIEW CurView;
1481
1482 rc = VBVAGetInfoViewAndScreen(pVGAState, i, &CurView, &CurScreen);
1483 AssertRC(rc);
1484
1485 if (!memcmp(&Screen, &CurScreen, sizeof (CurScreen)))
1486 continue;
1487
1488 if (!fDisable || !CurView.u32ViewSize)
1489 {
1490 View.u32ViewIndex = Screen.u32ViewIndex;
1491
1492 rc = VBVAInfoView(pVGAState, &View);
1493 if (RT_FAILURE(rc))
1494 {
1495 WARN(("VBVAInfoView failed %d\n", rc));
1496 break;
1497 }
1498 }
1499
1500 rc = VBVAInfoScreen(pVGAState, &Screen);
1501 if (RT_FAILURE(rc))
1502 {
1503 WARN(("VBVAInfoScreen failed %d\n", rc));
1504 break;
1505 }
1506 }
1507
1508 if (RT_FAILURE(rc))
1509 return rc;
1510
1511 Screen.u32ViewIndex = u32ViewIndex;
1512
1513 rc = pVdma->CrSrvInfo.pfnResize(pVdma->CrSrvInfo.hSvr, &Screen, aTargetMap);
1514 if (RT_FAILURE(rc))
1515 WARN(("pfnResize failed %d\n", rc));
1516
1517 return rc;
1518}
1519
1520static int vboxVDMACrGuestCtlProcess(struct VBOXVDMAHOST *pVdma, VBVAEXHOSTCTL *pCmd)
1521{
1522 VBVAEXHOSTCTL_TYPE enmType = pCmd->enmType;
1523 switch (enmType)
1524 {
1525 case VBVAEXHOSTCTL_TYPE_GHH_BE_OPAQUE:
1526 {
1527 if (!VBoxVBVAExHSIsEnabled(&pVdma->CmdVbva))
1528 {
1529 WARN(("VBVAEXHOSTCTL_TYPE_GHH_BE_OPAQUE for disabled vdma VBVA\n"));
1530 return VERR_INVALID_STATE;
1531 }
1532 return pVdma->CrSrvInfo.pfnGuestCtl(pVdma->CrSrvInfo.hSvr, pCmd->u.cmd.pu8Cmd, pCmd->u.cmd.cbCmd);
1533 }
1534 case VBVAEXHOSTCTL_TYPE_GHH_RESIZE:
1535 {
1536 if (!VBoxVBVAExHSIsEnabled(&pVdma->CmdVbva))
1537 {
1538 WARN(("VBVAEXHOSTCTL_TYPE_GHH_BE_OPAQUE for disabled vdma VBVA\n"));
1539 return VERR_INVALID_STATE;
1540 }
1541
1542 uint32_t cbCmd = pCmd->u.cmd.cbCmd;
1543
1544 if (cbCmd % sizeof (VBOXCMDVBVA_RESIZE_ENTRY))
1545 {
1546 WARN(("invalid buffer size\n"));
1547 return VERR_INVALID_PARAMETER;
1548 }
1549
1550 uint32_t cElements = cbCmd / sizeof (VBOXCMDVBVA_RESIZE_ENTRY);
1551 if (!cElements)
1552 {
1553 WARN(("invalid buffer size\n"));
1554 return VERR_INVALID_PARAMETER;
1555 }
1556
1557 VBOXCMDVBVA_RESIZE *pResize = (VBOXCMDVBVA_RESIZE*)pCmd->u.cmd.pu8Cmd;
1558
1559 int rc = VINF_SUCCESS;
1560
1561 for (uint32_t i = 0; i < cElements; ++i)
1562 {
1563 VBOXCMDVBVA_RESIZE_ENTRY *pEntry = &pResize->aEntries[i];
1564 rc = vboxVDMACrGuestCtlResizeEntryProcess(pVdma, pEntry);
1565 if (RT_FAILURE(rc))
1566 {
1567 WARN(("vboxVDMACrGuestCtlResizeEntryProcess failed %d\n", rc));
1568 break;
1569 }
1570 }
1571 return rc;
1572 }
1573 case VBVAEXHOSTCTL_TYPE_GHH_ENABLE:
1574 case VBVAEXHOSTCTL_TYPE_GHH_ENABLE_PAUSED:
1575 {
1576 VBVAENABLE *pEnable = (VBVAENABLE *)pCmd->u.cmd.pu8Cmd;
1577 Assert(pCmd->u.cmd.cbCmd == sizeof (VBVAENABLE));
1578 uint32_t u32Offset = pEnable->u32Offset;
1579 int rc = vdmaVBVAEnableProcess(pVdma, u32Offset);
1580 if (!RT_SUCCESS(rc))
1581 {
1582 WARN(("vdmaVBVAEnableProcess failed %d\n", rc));
1583 return rc;
1584 }
1585
1586 if (enmType == VBVAEXHOSTCTL_TYPE_GHH_ENABLE_PAUSED)
1587 {
1588 rc = VBoxVBVAExHPPause(&pVdma->CmdVbva);
1589 if (!RT_SUCCESS(rc))
1590 {
1591 WARN(("VBoxVBVAExHPPause failed %d\n", rc));
1592 return rc;
1593 }
1594 }
1595
1596 return VINF_SUCCESS;
1597 }
1598 case VBVAEXHOSTCTL_TYPE_GHH_DISABLE:
1599 {
1600 int rc = vdmaVBVADisableProcess(pVdma, true);
1601 if (RT_FAILURE(rc))
1602 {
1603 WARN(("vdmaVBVADisableProcess failed %d\n", rc));
1604 return rc;
1605 }
1606
1607 /* do vgaUpdateDisplayAll right away */
1608 vgaUpdateDisplayAll(pVdma->pVGAState);
1609
1610 return VBoxVDMAThreadTerm(&pVdma->Thread, NULL, NULL, false);
1611 }
1612 default:
1613 WARN(("unexpected ctl type %d\n", pCmd->enmType));
1614 return VERR_INVALID_PARAMETER;
1615 }
1616}
1617
1618/**
1619 * @param fIn - whether this is a page in or out op.
1620 * the direction is VRA#M - related, so fIn == true - transfer to VRAM); false - transfer from VRAM
1621 */
1622static int vboxVDMACrCmdVbvaProcessPagingEl(PPDMDEVINS pDevIns, VBOXCMDVBVAPAGEIDX iPage, uint8_t *pu8Vram, bool fIn)
1623{
1624 RTGCPHYS phPage = (RTGCPHYS)iPage << PAGE_SHIFT;
1625 PGMPAGEMAPLOCK Lock;
1626 int rc;
1627
1628 if (fIn)
1629 {
1630 const void * pvPage;
1631 rc = PDMDevHlpPhysGCPhys2CCPtrReadOnly(pDevIns, phPage, 0, &pvPage, &Lock);
1632 if (!RT_SUCCESS(rc))
1633 {
1634 WARN(("PDMDevHlpPhysGCPhys2CCPtrReadOnly failed %d", rc));
1635 return rc;
1636 }
1637
1638 memcpy(pu8Vram, pvPage, PAGE_SIZE);
1639
1640 PDMDevHlpPhysReleasePageMappingLock(pDevIns, &Lock);
1641 }
1642 else
1643 {
1644 void * pvPage;
1645 rc = PDMDevHlpPhysGCPhys2CCPtr(pDevIns, phPage, 0, &pvPage, &Lock);
1646 if (!RT_SUCCESS(rc))
1647 {
1648 WARN(("PDMDevHlpPhysGCPhys2CCPtr failed %d", rc));
1649 return rc;
1650 }
1651
1652 memcpy(pvPage, pu8Vram, PAGE_SIZE);
1653
1654 PDMDevHlpPhysReleasePageMappingLock(pDevIns, &Lock);
1655 }
1656
1657 return VINF_SUCCESS;
1658}
1659
1660static int vboxVDMACrCmdVbvaProcessPagingEls(PPDMDEVINS pDevIns, const VBOXCMDVBVAPAGEIDX *piPages, uint32_t cPages, uint8_t *pu8Vram, bool fIn)
1661{
1662 for (uint32_t i = 0; i < cPages; ++i, pu8Vram += PAGE_SIZE)
1663 {
1664 int rc = vboxVDMACrCmdVbvaProcessPagingEl(pDevIns, piPages[i], pu8Vram, fIn);
1665 if (!RT_SUCCESS(rc))
1666 {
1667 WARN(("vboxVDMACrCmdVbvaProcessPagingEl failed %d", rc));
1668 return rc;
1669 }
1670 }
1671
1672 return VINF_SUCCESS;
1673}
1674
1675static int8_t vboxVDMACrCmdVbvaPagingDataInit(PVGASTATE pVGAState, const VBOXCMDVBVA_HDR *pHdr, const VBOXCMDVBVA_PAGING_TRANSFER_DATA *pData, uint32_t cbCmd,
1676 const VBOXCMDVBVAPAGEIDX **ppPages, VBOXCMDVBVAPAGEIDX *pcPages,
1677 uint8_t **ppu8Vram, bool *pfIn)
1678{
1679 if (cbCmd < sizeof (VBOXCMDVBVA_PAGING_TRANSFER))
1680 {
1681 WARN(("cmd too small"));
1682 return -1;
1683 }
1684
1685 VBOXCMDVBVAPAGEIDX cPages = cbCmd - RT_OFFSETOF(VBOXCMDVBVA_PAGING_TRANSFER, Data.aPageNumbers);
1686 if (cPages % sizeof (VBOXCMDVBVAPAGEIDX))
1687 {
1688 WARN(("invalid cmd size"));
1689 return -1;
1690 }
1691 cPages /= sizeof (VBOXCMDVBVAPAGEIDX);
1692
1693 VBOXCMDVBVAOFFSET offVRAM = pData->Alloc.u.offVRAM;
1694 if (offVRAM & PAGE_OFFSET_MASK)
1695 {
1696 WARN(("offVRAM address is not on page boundary\n"));
1697 return -1;
1698 }
1699 const VBOXCMDVBVAPAGEIDX *pPages = pData->aPageNumbers;
1700
1701 uint8_t * pu8VramBase = pVGAState->vram_ptrR3;
1702 uint8_t *pu8VramMax = pu8VramBase + pVGAState->vram_size;
1703 if (offVRAM >= pVGAState->vram_size)
1704 {
1705 WARN(("invalid vram offset"));
1706 return -1;
1707 }
1708
1709 if (~(~(VBOXCMDVBVAPAGEIDX)0 >> PAGE_SHIFT) & cPages)
1710 {
1711 WARN(("invalid cPages %d", cPages));
1712 return -1;
1713 }
1714
1715 if (offVRAM + ((VBOXCMDVBVAOFFSET)cPages << PAGE_SHIFT) >= pVGAState->vram_size)
1716 {
1717 WARN(("invalid cPages %d, exceeding vram size", cPages));
1718 return -1;
1719 }
1720
1721 uint8_t *pu8Vram = pu8VramBase + offVRAM;
1722 bool fIn = !!(pHdr->u8Flags & VBOXCMDVBVA_OPF_PAGING_TRANSFER_IN);
1723
1724 *ppPages = pPages;
1725 *pcPages = cPages;
1726 *ppu8Vram = pu8Vram;
1727 *pfIn = fIn;
1728 return 0;
1729}
1730
1731static int8_t vboxVDMACrCmdVbvaPagingFill(PVGASTATE pVGAState, VBOXCMDVBVA_PAGING_FILL *pFill)
1732{
1733 VBOXCMDVBVAOFFSET offVRAM = pFill->offVRAM;
1734 if (offVRAM & PAGE_OFFSET_MASK)
1735 {
1736 WARN(("offVRAM address is not on page boundary\n"));
1737 return -1;
1738 }
1739
1740 uint8_t * pu8VramBase = pVGAState->vram_ptrR3;
1741 uint8_t *pu8VramMax = pu8VramBase + pVGAState->vram_size;
1742 if (offVRAM >= pVGAState->vram_size)
1743 {
1744 WARN(("invalid vram offset"));
1745 return -1;
1746 }
1747
1748 uint32_t cbFill = pFill->u32CbFill;
1749
1750 if (offVRAM + cbFill >= pVGAState->vram_size)
1751 {
1752 WARN(("invalid cPages"));
1753 return -1;
1754 }
1755
1756 uint32_t *pu32Vram = (uint32_t*)(pu8VramBase + offVRAM);
1757 uint32_t u32Color = pFill->u32Pattern;
1758
1759 Assert(!(cbFill % 4));
1760 for (uint32_t i = 0; i < cbFill / 4; ++i)
1761 {
1762 pu32Vram[i] = u32Color;
1763 }
1764
1765 return 0;
1766}
1767
1768static int8_t vboxVDMACrCmdVbvaProcessCmdData(struct VBOXVDMAHOST *pVdma, const VBOXCMDVBVA_HDR *pCmd, uint32_t cbCmd)
1769{
1770 switch (pCmd->u8OpCode)
1771 {
1772 case VBOXCMDVBVA_OPTYPE_NOPCMD:
1773 return 0;
1774 case VBOXCMDVBVA_OPTYPE_PAGING_TRANSFER:
1775 {
1776 PVGASTATE pVGAState = pVdma->pVGAState;
1777 const VBOXCMDVBVAPAGEIDX *pPages;
1778 uint32_t cPages;
1779 uint8_t *pu8Vram;
1780 bool fIn;
1781 int8_t i8Result = vboxVDMACrCmdVbvaPagingDataInit(pVGAState, pCmd, &((VBOXCMDVBVA_PAGING_TRANSFER*)pCmd)->Data, cbCmd,
1782 &pPages, &cPages,
1783 &pu8Vram, &fIn);
1784 if (i8Result < 0)
1785 {
1786 WARN(("vboxVDMACrCmdVbvaPagingDataInit failed %d", i8Result));
1787 return i8Result;
1788 }
1789
1790 PPDMDEVINS pDevIns = pVGAState->pDevInsR3;
1791 int rc = vboxVDMACrCmdVbvaProcessPagingEls(pDevIns, pPages, cPages, pu8Vram, fIn);
1792 if (!RT_SUCCESS(rc))
1793 {
1794 WARN(("vboxVDMACrCmdVbvaProcessPagingEls failed %d", rc));
1795 return -1;
1796 }
1797
1798 return 0;
1799 }
1800 case VBOXCMDVBVA_OPTYPE_PAGING_FILL:
1801 {
1802 PVGASTATE pVGAState = pVdma->pVGAState;
1803 if (cbCmd != sizeof (VBOXCMDVBVA_PAGING_FILL))
1804 {
1805 WARN(("cmd too small"));
1806 return -1;
1807 }
1808
1809 return vboxVDMACrCmdVbvaPagingFill(pVGAState, (VBOXCMDVBVA_PAGING_FILL*)pCmd);
1810 }
1811 default:
1812 return pVdma->CrSrvInfo.pfnCmd(pVdma->CrSrvInfo.hSvr, pCmd, cbCmd);
1813 }
1814}
1815
1816#if 0
1817typedef struct VBOXCMDVBVA_PAGING_TRANSFER
1818{
1819 VBOXCMDVBVA_HDR Hdr;
1820 /* for now can only contain offVRAM.
1821 * paging transfer can NOT be initiated for allocations having host 3D object (hostID) associated */
1822 VBOXCMDVBVA_ALLOCINFO Alloc;
1823 uint32_t u32Reserved;
1824 VBOXCMDVBVA_SYSMEMEL aSysMem[1];
1825} VBOXCMDVBVA_PAGING_TRANSFER;
1826#endif
1827
1828AssertCompile(sizeof (VBOXCMDVBVA_HDR) == 8);
1829AssertCompile(sizeof (VBOXCMDVBVA_ALLOCINFO) == 4);
1830AssertCompile(sizeof (VBOXCMDVBVAPAGEIDX) == 4);
1831AssertCompile(!(PAGE_SIZE % sizeof (VBOXCMDVBVAPAGEIDX)));
1832
1833#define VBOXCMDVBVA_NUM_SYSMEMEL_PER_PAGE (PAGE_SIZE / sizeof (VBOXCMDVBVA_SYSMEMEL))
1834
1835static int8_t vboxVDMACrCmdVbvaProcess(struct VBOXVDMAHOST *pVdma, const VBOXCMDVBVA_HDR *pCmd, uint32_t cbCmd)
1836{
1837 switch (pCmd->u8OpCode)
1838 {
1839 case VBOXCMDVBVA_OPTYPE_SYSMEMCMD:
1840 {
1841 if (cbCmd < sizeof (VBOXCMDVBVA_SYSMEMCMD))
1842 {
1843 WARN(("invalid command size"));
1844 return -1;
1845 }
1846 VBOXCMDVBVA_SYSMEMCMD *pSysmemCmd = (VBOXCMDVBVA_SYSMEMCMD*)pCmd;
1847 const VBOXCMDVBVA_HDR *pRealCmdHdr;
1848 uint32_t cbRealCmd = pCmd->u8Flags;
1849 cbRealCmd |= (uint32_t)pCmd->u.u8PrimaryID << 8;
1850 if (cbRealCmd < sizeof (VBOXCMDVBVA_HDR))
1851 {
1852 WARN(("invalid sysmem cmd size"));
1853 return -1;
1854 }
1855
1856 RTGCPHYS phCmd = (RTGCPHYS)pSysmemCmd->phCmd;
1857
1858 PGMPAGEMAPLOCK Lock;
1859 PVGASTATE pVGAState = pVdma->pVGAState;
1860 PPDMDEVINS pDevIns = pVGAState->pDevInsR3;
1861 const void * pvCmd;
1862 int rc = PDMDevHlpPhysGCPhys2CCPtrReadOnly(pDevIns, phCmd, 0, &pvCmd, &Lock);
1863 if (!RT_SUCCESS(rc))
1864 {
1865 WARN(("PDMDevHlpPhysGCPhys2CCPtrReadOnly failed %d\n", rc));
1866 return -1;
1867 }
1868
1869 Assert((phCmd & PAGE_OFFSET_MASK) == (((uintptr_t)pvCmd) & PAGE_OFFSET_MASK));
1870
1871 uint32_t cbCmdPart = PAGE_SIZE - (((uintptr_t)pvCmd) & PAGE_OFFSET_MASK);
1872
1873 if (cbRealCmd <= cbCmdPart)
1874 {
1875 pRealCmdHdr = (const VBOXCMDVBVA_HDR *)pvCmd;
1876 uint8_t i8Result = vboxVDMACrCmdVbvaProcessCmdData(pVdma, pRealCmdHdr, cbRealCmd);
1877 PDMDevHlpPhysReleasePageMappingLock(pDevIns, &Lock);
1878 return i8Result;
1879 }
1880
1881 VBOXCMDVBVA_HDR Hdr;
1882 const void *pvCurCmdTail;
1883 uint32_t cbCurCmdTail;
1884 if (cbCmdPart >= sizeof (*pRealCmdHdr))
1885 {
1886 pRealCmdHdr = (const VBOXCMDVBVA_HDR *)pvCmd;
1887 pvCurCmdTail = (const void*)(pRealCmdHdr + 1);
1888 cbCurCmdTail = cbCmdPart - sizeof (*pRealCmdHdr);
1889 }
1890 else
1891 {
1892 memcpy(&Hdr, pvCmd, cbCmdPart);
1893 PDMDevHlpPhysReleasePageMappingLock(pDevIns, &Lock);
1894 phCmd += cbCmdPart;
1895 Assert(!(phCmd & PAGE_OFFSET_MASK));
1896 rc = PDMDevHlpPhysGCPhys2CCPtrReadOnly(pDevIns, phCmd, 0, &pvCmd, &Lock);
1897 if (!RT_SUCCESS(rc))
1898 {
1899 WARN(("PDMDevHlpPhysGCPhys2CCPtrReadOnly failed %d\n", rc));
1900 return -1;
1901 }
1902
1903 cbCmdPart = sizeof (*pRealCmdHdr) - cbCmdPart;
1904 memcpy(((uint8_t*)(&Hdr)) + cbCmdPart, pvCmd, cbCmdPart);
1905 pRealCmdHdr = &Hdr;
1906 pvCurCmdTail = (const void*)(((uint8_t*)pvCmd) + cbCmdPart);
1907 cbCurCmdTail = PAGE_SIZE - cbCmdPart;
1908 }
1909
1910 if (cbCurCmdTail > cbRealCmd - sizeof (*pRealCmdHdr))
1911 cbCurCmdTail = cbRealCmd - sizeof (*pRealCmdHdr);
1912
1913 int8_t i8Result = 0;
1914
1915 switch (pRealCmdHdr->u8OpCode)
1916 {
1917 case VBOXCMDVBVA_OPTYPE_PAGING_TRANSFER:
1918 {
1919 const uint32_t *pPages;
1920 uint32_t cPages;
1921 uint8_t *pu8Vram;
1922 bool fIn;
1923 i8Result = vboxVDMACrCmdVbvaPagingDataInit(pVGAState, pRealCmdHdr, (const VBOXCMDVBVA_PAGING_TRANSFER_DATA*)pvCurCmdTail, cbRealCmd,
1924 &pPages, &cPages,
1925 &pu8Vram, &fIn);
1926 if (i8Result < 0)
1927 {
1928 WARN(("vboxVDMACrCmdVbvaPagingDataInit failed %d", i8Result));
1929 /* we need to break, not return, to ensure currently locked page is released */
1930 break;
1931 }
1932
1933 if (cbCurCmdTail & 3)
1934 {
1935 WARN(("command is not alligned properly %d", cbCurCmdTail));
1936 i8Result = -1;
1937 /* we need to break, not return, to ensure currently locked page is released */
1938 break;
1939 }
1940
1941 uint32_t cCurPages = cbCurCmdTail / sizeof (VBOXCMDVBVAPAGEIDX);
1942 Assert(cCurPages < cPages);
1943
1944 do
1945 {
1946 rc = vboxVDMACrCmdVbvaProcessPagingEls(pDevIns, pPages, cCurPages, pu8Vram, fIn);
1947 if (!RT_SUCCESS(rc))
1948 {
1949 WARN(("vboxVDMACrCmdVbvaProcessPagingEls failed %d", rc));
1950 i8Result = -1;
1951 /* we need to break, not return, to ensure currently locked page is released */
1952 break;
1953 }
1954
1955 Assert(cPages >= cCurPages);
1956 cPages -= cCurPages;
1957
1958 if (!cPages)
1959 break;
1960
1961 PDMDevHlpPhysReleasePageMappingLock(pDevIns, &Lock);
1962
1963 Assert(!(phCmd & PAGE_OFFSET_MASK));
1964
1965 phCmd += PAGE_SIZE;
1966 pu8Vram += (VBOXCMDVBVAOFFSET)cCurPages << PAGE_SHIFT;
1967
1968 rc = PDMDevHlpPhysGCPhys2CCPtrReadOnly(pDevIns, phCmd, 0, &pvCmd, &Lock);
1969 if (!RT_SUCCESS(rc))
1970 {
1971 WARN(("PDMDevHlpPhysGCPhys2CCPtrReadOnly failed %d\n", rc));
1972 /* the page is not locked, return */
1973 return -1;
1974 }
1975
1976 cCurPages = PAGE_SIZE / sizeof (VBOXCMDVBVAPAGEIDX);
1977 if (cCurPages > cPages)
1978 cCurPages = cPages;
1979 } while (1);
1980 break;
1981 }
1982 default:
1983 WARN(("command can not be splitted"));
1984 i8Result = -1;
1985 break;
1986 }
1987
1988 PDMDevHlpPhysReleasePageMappingLock(pDevIns, &Lock);
1989 return i8Result;
1990 }
1991 case VBOXCMDVBVA_OPTYPE_COMPLEXCMD:
1992 {
1993 Assert(cbCmd >= sizeof (VBOXCMDVBVA_HDR));
1994 ++pCmd;
1995 cbCmd -= sizeof (*pCmd);
1996 uint32_t cbCurCmd = 0;
1997 for ( ; cbCmd; cbCmd -= cbCurCmd, pCmd = (VBOXCMDVBVA_HDR*)(((uint8_t*)pCmd) + cbCurCmd))
1998 {
1999 if (cbCmd < sizeof (VBOXCMDVBVA_HDR))
2000 {
2001 WARN(("invalid command size"));
2002 return -1;
2003 }
2004
2005 cbCurCmd = pCmd->u2.complexCmdEl.u16CbCmdHost;
2006 if (cbCmd < cbCurCmd)
2007 {
2008 WARN(("invalid command size"));
2009 return -1;
2010 }
2011
2012 int8_t i8Result = vboxVDMACrCmdVbvaProcess(pVdma, pCmd, cbCurCmd);
2013 if (i8Result < 0)
2014 {
2015 WARN(("vboxVDMACrCmdVbvaProcess failed"));
2016 return i8Result;
2017 }
2018 }
2019 return 0;
2020 }
2021 default:
2022 return vboxVDMACrCmdVbvaProcessCmdData(pVdma, pCmd, cbCmd);
2023 }
2024}
2025
2026static void vboxVDMACrCmdProcess(struct VBOXVDMAHOST *pVdma, uint8_t* pu8Cmd, uint32_t cbCmd)
2027{
2028 if (*pu8Cmd == VBOXCMDVBVA_OPTYPE_NOP)
2029 return;
2030
2031 if (cbCmd < sizeof (VBOXCMDVBVA_HDR))
2032 {
2033 WARN(("invalid command size"));
2034 return;
2035 }
2036
2037 PVBOXCMDVBVA_HDR pCmd = (PVBOXCMDVBVA_HDR)pu8Cmd;
2038
2039 /* check if the command is cancelled */
2040 if (!ASMAtomicCmpXchgU8(&pCmd->u8State, VBOXCMDVBVA_STATE_IN_PROGRESS, VBOXCMDVBVA_STATE_SUBMITTED))
2041 {
2042 Assert(pCmd->u8State == VBOXCMDVBVA_STATE_CANCELLED);
2043 return;
2044 }
2045
2046 pCmd->u.i8Result = vboxVDMACrCmdVbvaProcess(pVdma, pCmd, cbCmd);
2047}
2048
2049static int vboxVDMACrCtlHgsmiSetup(struct VBOXVDMAHOST *pVdma)
2050{
2051 PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP pCmd = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP)
2052 vboxVDMACrCtlCreate (VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP, sizeof (*pCmd));
2053 int rc = VERR_NO_MEMORY;
2054 if (pCmd)
2055 {
2056 PVGASTATE pVGAState = pVdma->pVGAState;
2057 pCmd->pvVRamBase = pVGAState->vram_ptrR3;
2058 pCmd->cbVRam = pVGAState->vram_size;
2059 pCmd->pLed = &pVGAState->Led3D;
2060 rc = vboxVDMACrCtlPost(pVGAState, &pCmd->Hdr, sizeof (*pCmd));
2061 if (RT_SUCCESS(rc))
2062 {
2063 rc = vboxVDMACrCtlGetRc(&pCmd->Hdr);
2064 if (RT_SUCCESS(rc))
2065 pVdma->CrSrvInfo = pCmd->CrCmdServerInfo;
2066 else if (rc != VERR_NOT_SUPPORTED)
2067 WARN(("vboxVDMACrCtlGetRc returned %d\n", rc));
2068 }
2069 else
2070 WARN(("vboxVDMACrCtlPost failed %d\n", rc));
2071
2072 vboxVDMACrCtlRelease(&pCmd->Hdr);
2073 }
2074
2075 if (!RT_SUCCESS(rc))
2076 memset(&pVdma->CrSrvInfo, 0, sizeof (pVdma->CrSrvInfo));
2077
2078 return rc;
2079}
2080
2081static int vboxVDMACmdExecBpbTransfer(PVBOXVDMAHOST pVdma, const PVBOXVDMACMD_DMA_BPB_TRANSFER pTransfer, uint32_t cbBuffer);
2082
2083/* check if this is external cmd to be passed to chromium backend */
2084static int vboxVDMACmdCheckCrCmd(struct VBOXVDMAHOST *pVdma, PVBOXVDMACBUF_DR pCmdDr, uint32_t cbCmdDr)
2085{
2086 PVBOXVDMACMD pDmaCmd = NULL;
2087 uint32_t cbDmaCmd = 0;
2088 uint8_t * pvRam = pVdma->pVGAState->vram_ptrR3;
2089 int rc = VINF_NOT_SUPPORTED;
2090
2091 cbDmaCmd = pCmdDr->cbBuf;
2092
2093 if (pCmdDr->fFlags & VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR)
2094 {
2095 if (cbCmdDr < sizeof (*pCmdDr) + VBOXVDMACMD_HEADER_SIZE())
2096 {
2097 AssertMsgFailed(("invalid buffer data!"));
2098 return VERR_INVALID_PARAMETER;
2099 }
2100
2101 if (cbDmaCmd < cbCmdDr - sizeof (*pCmdDr) - VBOXVDMACMD_HEADER_SIZE())
2102 {
2103 AssertMsgFailed(("invalid command buffer data!"));
2104 return VERR_INVALID_PARAMETER;
2105 }
2106
2107 pDmaCmd = VBOXVDMACBUF_DR_TAIL(pCmdDr, VBOXVDMACMD);
2108 }
2109 else if (pCmdDr->fFlags & VBOXVDMACBUF_FLAG_BUF_VRAM_OFFSET)
2110 {
2111 VBOXVIDEOOFFSET offBuf = pCmdDr->Location.offVramBuf;
2112 if (offBuf + cbDmaCmd > pVdma->pVGAState->vram_size)
2113 {
2114 AssertMsgFailed(("invalid command buffer data from offset!"));
2115 return VERR_INVALID_PARAMETER;
2116 }
2117 pDmaCmd = (VBOXVDMACMD*)(pvRam + offBuf);
2118 }
2119
2120 if (pDmaCmd)
2121 {
2122 Assert(cbDmaCmd >= VBOXVDMACMD_HEADER_SIZE());
2123 uint32_t cbBody = VBOXVDMACMD_BODY_SIZE(cbDmaCmd);
2124
2125 switch (pDmaCmd->enmType)
2126 {
2127 case VBOXVDMACMD_TYPE_CHROMIUM_CMD:
2128 {
2129 PVBOXVDMACMD_CHROMIUM_CMD pCrCmd = VBOXVDMACMD_BODY(pDmaCmd, VBOXVDMACMD_CHROMIUM_CMD);
2130 if (cbBody < sizeof (*pCrCmd))
2131 {
2132 AssertMsgFailed(("invalid chromium command buffer size!"));
2133 return VERR_INVALID_PARAMETER;
2134 }
2135 PVGASTATE pVGAState = pVdma->pVGAState;
2136 rc = VINF_SUCCESS;
2137 if (pVGAState->pDrv->pfnCrHgsmiCommandProcess)
2138 {
2139 VBoxSHGSMICommandMarkAsynchCompletion(pCmdDr);
2140 pVGAState->pDrv->pfnCrHgsmiCommandProcess(pVGAState->pDrv, pCrCmd, cbBody);
2141 break;
2142 }
2143 else
2144 {
2145 Assert(0);
2146 }
2147
2148 int tmpRc = VBoxSHGSMICommandComplete (pVdma->pHgsmi, pCmdDr);
2149 AssertRC(tmpRc);
2150 break;
2151 }
2152 case VBOXVDMACMD_TYPE_DMA_BPB_TRANSFER:
2153 {
2154 PVBOXVDMACMD_DMA_BPB_TRANSFER pTransfer = VBOXVDMACMD_BODY(pDmaCmd, VBOXVDMACMD_DMA_BPB_TRANSFER);
2155 if (cbBody < sizeof (*pTransfer))
2156 {
2157 AssertMsgFailed(("invalid bpb transfer buffer size!"));
2158 return VERR_INVALID_PARAMETER;
2159 }
2160
2161 rc = vboxVDMACmdExecBpbTransfer(pVdma, pTransfer, sizeof (*pTransfer));
2162 AssertRC(rc);
2163 if (RT_SUCCESS(rc))
2164 {
2165 pCmdDr->rc = VINF_SUCCESS;
2166 rc = VBoxSHGSMICommandComplete (pVdma->pHgsmi, pCmdDr);
2167 AssertRC(rc);
2168 rc = VINF_SUCCESS;
2169 }
2170 break;
2171 }
2172 default:
2173 break;
2174 }
2175 }
2176 return rc;
2177}
2178
2179int vboxVDMACrHgsmiCommandCompleteAsync(PPDMIDISPLAYVBVACALLBACKS pInterface, PVBOXVDMACMD_CHROMIUM_CMD pCmd, int rc)
2180{
2181 PVGASTATE pVGAState = PPDMIDISPLAYVBVACALLBACKS_2_PVGASTATE(pInterface);
2182 PHGSMIINSTANCE pIns = pVGAState->pHGSMI;
2183 VBOXVDMACMD *pDmaHdr = VBOXVDMACMD_FROM_BODY(pCmd);
2184 VBOXVDMACBUF_DR *pDr = VBOXVDMACBUF_DR_FROM_TAIL(pDmaHdr);
2185 AssertRC(rc);
2186 pDr->rc = rc;
2187
2188 Assert(pVGAState->fGuestCaps & VBVACAPS_COMPLETEGCMD_BY_IOREAD);
2189 rc = VBoxSHGSMICommandComplete(pIns, pDr);
2190 AssertRC(rc);
2191 return rc;
2192}
2193
2194int vboxVDMACrHgsmiControlCompleteAsync(PPDMIDISPLAYVBVACALLBACKS pInterface, PVBOXVDMACMD_CHROMIUM_CTL pCmd, int rc)
2195{
2196 PVGASTATE pVGAState = PPDMIDISPLAYVBVACALLBACKS_2_PVGASTATE(pInterface);
2197 PVBOXVDMACMD_CHROMIUM_CTL_PRIVATE pCmdPrivate = VBOXVDMACMD_CHROMIUM_CTL_PRIVATE_FROM_CTL(pCmd);
2198 pCmdPrivate->rc = rc;
2199 if (pCmdPrivate->pfnCompletion)
2200 {
2201 pCmdPrivate->pfnCompletion(pVGAState, pCmd, pCmdPrivate->pvCompletion);
2202 }
2203 return VINF_SUCCESS;
2204}
2205
2206static int vboxVDMACmdExecBltPerform(PVBOXVDMAHOST pVdma,
2207 uint8_t *pvDstSurf, const uint8_t *pvSrcSurf,
2208 const PVBOXVDMA_SURF_DESC pDstDesc, const PVBOXVDMA_SURF_DESC pSrcDesc,
2209 const VBOXVDMA_RECTL * pDstRectl, const VBOXVDMA_RECTL * pSrcRectl)
2210{
2211 /* we do not support color conversion */
2212 Assert(pDstDesc->format == pSrcDesc->format);
2213 /* we do not support stretching */
2214 Assert(pDstRectl->height == pSrcRectl->height);
2215 Assert(pDstRectl->width == pSrcRectl->width);
2216 if (pDstDesc->format != pSrcDesc->format)
2217 return VERR_INVALID_FUNCTION;
2218 if (pDstDesc->width == pDstRectl->width
2219 && pSrcDesc->width == pSrcRectl->width
2220 && pSrcDesc->width == pDstDesc->width)
2221 {
2222 Assert(!pDstRectl->left);
2223 Assert(!pSrcRectl->left);
2224 uint32_t cbOff = pDstDesc->pitch * pDstRectl->top;
2225 uint32_t cbSize = pDstDesc->pitch * pDstRectl->height;
2226 memcpy(pvDstSurf + cbOff, pvSrcSurf + cbOff, cbSize);
2227 }
2228 else
2229 {
2230 uint32_t offDstLineStart = pDstRectl->left * pDstDesc->bpp >> 3;
2231 uint32_t offDstLineEnd = ((pDstRectl->left * pDstDesc->bpp + 7) >> 3) + ((pDstDesc->bpp * pDstRectl->width + 7) >> 3);
2232 uint32_t cbDstLine = offDstLineEnd - offDstLineStart;
2233 uint32_t offDstStart = pDstDesc->pitch * pDstRectl->top + offDstLineStart;
2234 Assert(cbDstLine <= pDstDesc->pitch);
2235 uint32_t cbDstSkip = pDstDesc->pitch;
2236 uint8_t * pvDstStart = pvDstSurf + offDstStart;
2237
2238 uint32_t offSrcLineStart = pSrcRectl->left * pSrcDesc->bpp >> 3;
2239 uint32_t offSrcLineEnd = ((pSrcRectl->left * pSrcDesc->bpp + 7) >> 3) + ((pSrcDesc->bpp * pSrcRectl->width + 7) >> 3);
2240 uint32_t cbSrcLine = offSrcLineEnd - offSrcLineStart;
2241 uint32_t offSrcStart = pSrcDesc->pitch * pSrcRectl->top + offSrcLineStart;
2242 Assert(cbSrcLine <= pSrcDesc->pitch);
2243 uint32_t cbSrcSkip = pSrcDesc->pitch;
2244 const uint8_t * pvSrcStart = pvSrcSurf + offSrcStart;
2245
2246 Assert(cbDstLine == cbSrcLine);
2247
2248 for (uint32_t i = 0; ; ++i)
2249 {
2250 memcpy (pvDstStart, pvSrcStart, cbDstLine);
2251 if (i == pDstRectl->height)
2252 break;
2253 pvDstStart += cbDstSkip;
2254 pvSrcStart += cbSrcSkip;
2255 }
2256 }
2257 return VINF_SUCCESS;
2258}
2259
2260static void vboxVDMARectlUnite(VBOXVDMA_RECTL * pRectl1, const VBOXVDMA_RECTL * pRectl2)
2261{
2262 if (!pRectl1->width)
2263 *pRectl1 = *pRectl2;
2264 else
2265 {
2266 int16_t x21 = pRectl1->left + pRectl1->width;
2267 int16_t x22 = pRectl2->left + pRectl2->width;
2268 if (pRectl1->left > pRectl2->left)
2269 {
2270 pRectl1->left = pRectl2->left;
2271 pRectl1->width = x21 < x22 ? x22 - pRectl1->left : x21 - pRectl1->left;
2272 }
2273 else if (x21 < x22)
2274 pRectl1->width = x22 - pRectl1->left;
2275
2276 x21 = pRectl1->top + pRectl1->height;
2277 x22 = pRectl2->top + pRectl2->height;
2278 if (pRectl1->top > pRectl2->top)
2279 {
2280 pRectl1->top = pRectl2->top;
2281 pRectl1->height = x21 < x22 ? x22 - pRectl1->top : x21 - pRectl1->top;
2282 }
2283 else if (x21 < x22)
2284 pRectl1->height = x22 - pRectl1->top;
2285 }
2286}
2287
2288/*
2289 * @return on success the number of bytes the command contained, otherwise - VERR_xxx error code
2290 */
2291static int vboxVDMACmdExecBlt(PVBOXVDMAHOST pVdma, const PVBOXVDMACMD_DMA_PRESENT_BLT pBlt, uint32_t cbBuffer)
2292{
2293 const uint32_t cbBlt = VBOXVDMACMD_BODY_FIELD_OFFSET(uint32_t, VBOXVDMACMD_DMA_PRESENT_BLT, aDstSubRects[pBlt->cDstSubRects]);
2294 Assert(cbBlt <= cbBuffer);
2295 if (cbBuffer < cbBlt)
2296 return VERR_INVALID_FUNCTION;
2297
2298 /* we do not support stretching for now */
2299 Assert(pBlt->srcRectl.width == pBlt->dstRectl.width);
2300 Assert(pBlt->srcRectl.height == pBlt->dstRectl.height);
2301 if (pBlt->srcRectl.width != pBlt->dstRectl.width)
2302 return VERR_INVALID_FUNCTION;
2303 if (pBlt->srcRectl.height != pBlt->dstRectl.height)
2304 return VERR_INVALID_FUNCTION;
2305 Assert(pBlt->cDstSubRects);
2306
2307 uint8_t * pvRam = pVdma->pVGAState->vram_ptrR3;
2308 VBOXVDMA_RECTL updateRectl = {0, 0, 0, 0};
2309
2310 if (pBlt->cDstSubRects)
2311 {
2312 VBOXVDMA_RECTL dstRectl, srcRectl;
2313 const VBOXVDMA_RECTL *pDstRectl, *pSrcRectl;
2314 for (uint32_t i = 0; i < pBlt->cDstSubRects; ++i)
2315 {
2316 pDstRectl = &pBlt->aDstSubRects[i];
2317 if (pBlt->dstRectl.left || pBlt->dstRectl.top)
2318 {
2319 dstRectl.left = pDstRectl->left + pBlt->dstRectl.left;
2320 dstRectl.top = pDstRectl->top + pBlt->dstRectl.top;
2321 dstRectl.width = pDstRectl->width;
2322 dstRectl.height = pDstRectl->height;
2323 pDstRectl = &dstRectl;
2324 }
2325
2326 pSrcRectl = &pBlt->aDstSubRects[i];
2327 if (pBlt->srcRectl.left || pBlt->srcRectl.top)
2328 {
2329 srcRectl.left = pSrcRectl->left + pBlt->srcRectl.left;
2330 srcRectl.top = pSrcRectl->top + pBlt->srcRectl.top;
2331 srcRectl.width = pSrcRectl->width;
2332 srcRectl.height = pSrcRectl->height;
2333 pSrcRectl = &srcRectl;
2334 }
2335
2336 int rc = vboxVDMACmdExecBltPerform(pVdma, pvRam + pBlt->offDst, pvRam + pBlt->offSrc,
2337 &pBlt->dstDesc, &pBlt->srcDesc,
2338 pDstRectl,
2339 pSrcRectl);
2340 AssertRC(rc);
2341 if (!RT_SUCCESS(rc))
2342 return rc;
2343
2344 vboxVDMARectlUnite(&updateRectl, pDstRectl);
2345 }
2346 }
2347 else
2348 {
2349 int rc = vboxVDMACmdExecBltPerform(pVdma, pvRam + pBlt->offDst, pvRam + pBlt->offSrc,
2350 &pBlt->dstDesc, &pBlt->srcDesc,
2351 &pBlt->dstRectl,
2352 &pBlt->srcRectl);
2353 AssertRC(rc);
2354 if (!RT_SUCCESS(rc))
2355 return rc;
2356
2357 vboxVDMARectlUnite(&updateRectl, &pBlt->dstRectl);
2358 }
2359
2360 return cbBlt;
2361}
2362
2363static int vboxVDMACmdExecBpbTransfer(PVBOXVDMAHOST pVdma, const PVBOXVDMACMD_DMA_BPB_TRANSFER pTransfer, uint32_t cbBuffer)
2364{
2365 if (cbBuffer < sizeof (*pTransfer))
2366 return VERR_INVALID_PARAMETER;
2367
2368 PVGASTATE pVGAState = pVdma->pVGAState;
2369 uint8_t * pvRam = pVGAState->vram_ptrR3;
2370 PGMPAGEMAPLOCK SrcLock;
2371 PGMPAGEMAPLOCK DstLock;
2372 PPDMDEVINS pDevIns = pVdma->pVGAState->pDevInsR3;
2373 const void * pvSrc;
2374 void * pvDst;
2375 int rc = VINF_SUCCESS;
2376 uint32_t cbTransfer = pTransfer->cbTransferSize;
2377 uint32_t cbTransfered = 0;
2378 bool bSrcLocked = false;
2379 bool bDstLocked = false;
2380 do
2381 {
2382 uint32_t cbSubTransfer = cbTransfer;
2383 if (pTransfer->fFlags & VBOXVDMACMD_DMA_BPB_TRANSFER_F_SRC_VRAMOFFSET)
2384 {
2385 pvSrc = pvRam + pTransfer->Src.offVramBuf + cbTransfered;
2386 }
2387 else
2388 {
2389 RTGCPHYS phPage = pTransfer->Src.phBuf;
2390 phPage += cbTransfered;
2391 rc = PDMDevHlpPhysGCPhys2CCPtrReadOnly(pDevIns, phPage, 0, &pvSrc, &SrcLock);
2392 AssertRC(rc);
2393 if (RT_SUCCESS(rc))
2394 {
2395 bSrcLocked = true;
2396 cbSubTransfer = RT_MIN(cbSubTransfer, 0x1000);
2397 }
2398 else
2399 {
2400 break;
2401 }
2402 }
2403
2404 if (pTransfer->fFlags & VBOXVDMACMD_DMA_BPB_TRANSFER_F_DST_VRAMOFFSET)
2405 {
2406 pvDst = pvRam + pTransfer->Dst.offVramBuf + cbTransfered;
2407 }
2408 else
2409 {
2410 RTGCPHYS phPage = pTransfer->Dst.phBuf;
2411 phPage += cbTransfered;
2412 rc = PDMDevHlpPhysGCPhys2CCPtr(pDevIns, phPage, 0, &pvDst, &DstLock);
2413 AssertRC(rc);
2414 if (RT_SUCCESS(rc))
2415 {
2416 bDstLocked = true;
2417 cbSubTransfer = RT_MIN(cbSubTransfer, 0x1000);
2418 }
2419 else
2420 {
2421 break;
2422 }
2423 }
2424
2425 if (RT_SUCCESS(rc))
2426 {
2427 memcpy(pvDst, pvSrc, cbSubTransfer);
2428 cbTransfer -= cbSubTransfer;
2429 cbTransfered += cbSubTransfer;
2430 }
2431 else
2432 {
2433 cbTransfer = 0; /* to break */
2434 }
2435
2436 if (bSrcLocked)
2437 PDMDevHlpPhysReleasePageMappingLock(pDevIns, &SrcLock);
2438 if (bDstLocked)
2439 PDMDevHlpPhysReleasePageMappingLock(pDevIns, &DstLock);
2440 } while (cbTransfer);
2441
2442 if (RT_SUCCESS(rc))
2443 return sizeof (*pTransfer);
2444 return rc;
2445}
2446
2447static int vboxVDMACmdExec(PVBOXVDMAHOST pVdma, const uint8_t *pvBuffer, uint32_t cbBuffer)
2448{
2449 do
2450 {
2451 Assert(pvBuffer);
2452 Assert(cbBuffer >= VBOXVDMACMD_HEADER_SIZE());
2453
2454 if (!pvBuffer)
2455 return VERR_INVALID_PARAMETER;
2456 if (cbBuffer < VBOXVDMACMD_HEADER_SIZE())
2457 return VERR_INVALID_PARAMETER;
2458
2459 PVBOXVDMACMD pCmd = (PVBOXVDMACMD)pvBuffer;
2460 uint32_t cbCmd = 0;
2461 switch (pCmd->enmType)
2462 {
2463 case VBOXVDMACMD_TYPE_CHROMIUM_CMD:
2464 {
2465#ifdef VBOXWDDM_TEST_UHGSMI
2466 static int count = 0;
2467 static uint64_t start, end;
2468 if (count==0)
2469 {
2470 start = RTTimeNanoTS();
2471 }
2472 ++count;
2473 if (count==100000)
2474 {
2475 end = RTTimeNanoTS();
2476 float ems = (end-start)/1000000.f;
2477 LogRel(("100000 calls took %i ms, %i cps\n", (int)ems, (int)(100000.f*1000.f/ems) ));
2478 }
2479#endif
2480 /* todo: post the buffer to chromium */
2481 return VINF_SUCCESS;
2482 }
2483 case VBOXVDMACMD_TYPE_DMA_PRESENT_BLT:
2484 {
2485 const PVBOXVDMACMD_DMA_PRESENT_BLT pBlt = VBOXVDMACMD_BODY(pCmd, VBOXVDMACMD_DMA_PRESENT_BLT);
2486 int cbBlt = vboxVDMACmdExecBlt(pVdma, pBlt, cbBuffer);
2487 Assert(cbBlt >= 0);
2488 Assert((uint32_t)cbBlt <= cbBuffer);
2489 if (cbBlt >= 0)
2490 {
2491 if ((uint32_t)cbBlt == cbBuffer)
2492 return VINF_SUCCESS;
2493 else
2494 {
2495 cbBuffer -= (uint32_t)cbBlt;
2496 pvBuffer -= cbBlt;
2497 }
2498 }
2499 else
2500 return cbBlt; /* error */
2501 break;
2502 }
2503 case VBOXVDMACMD_TYPE_DMA_BPB_TRANSFER:
2504 {
2505 const PVBOXVDMACMD_DMA_BPB_TRANSFER pTransfer = VBOXVDMACMD_BODY(pCmd, VBOXVDMACMD_DMA_BPB_TRANSFER);
2506 int cbTransfer = vboxVDMACmdExecBpbTransfer(pVdma, pTransfer, cbBuffer);
2507 Assert(cbTransfer >= 0);
2508 Assert((uint32_t)cbTransfer <= cbBuffer);
2509 if (cbTransfer >= 0)
2510 {
2511 if ((uint32_t)cbTransfer == cbBuffer)
2512 return VINF_SUCCESS;
2513 else
2514 {
2515 cbBuffer -= (uint32_t)cbTransfer;
2516 pvBuffer -= cbTransfer;
2517 }
2518 }
2519 else
2520 return cbTransfer; /* error */
2521 break;
2522 }
2523 case VBOXVDMACMD_TYPE_DMA_NOP:
2524 return VINF_SUCCESS;
2525 case VBOXVDMACMD_TYPE_CHILD_STATUS_IRQ:
2526 return VINF_SUCCESS;
2527 default:
2528 AssertBreakpoint();
2529 return VERR_INVALID_FUNCTION;
2530 }
2531 } while (1);
2532
2533 /* we should not be here */
2534 AssertBreakpoint();
2535 return VERR_INVALID_STATE;
2536}
2537
2538static DECLCALLBACK(int) vboxVDMAWorkerThread(RTTHREAD ThreadSelf, void *pvUser)
2539{
2540 PVBOXVDMAHOST pVdma = (PVBOXVDMAHOST)pvUser;
2541 PVGASTATE pVGAState = pVdma->pVGAState;
2542 VBVAEXHOSTCONTEXT *pCmdVbva = &pVdma->CmdVbva;
2543 PHGSMIINSTANCE pHgsmi = pVdma->pHgsmi;
2544 uint8_t *pCmd;
2545 uint32_t cbCmd;
2546 int rc;
2547
2548 VBoxVDMAThreadNotifyConstructSucceeded(&pVdma->Thread, pvUser);
2549
2550 while (!VBoxVDMAThreadIsTerminating(&pVdma->Thread))
2551 {
2552 VBVAEXHOST_DATA_TYPE enmType = VBoxVBVAExHPDataGet(pCmdVbva, &pCmd, &cbCmd);
2553 switch (enmType)
2554 {
2555 case VBVAEXHOST_DATA_TYPE_CMD:
2556 vboxVDMACrCmdProcess(pVdma, pCmd, cbCmd);
2557 VBoxVBVAExHPDataCompleteCmd(pCmdVbva, cbCmd);
2558 VBVARaiseIrqNoWait(pVGAState, 0);
2559 break;
2560 case VBVAEXHOST_DATA_TYPE_GUESTCTL:
2561 rc = vboxVDMACrGuestCtlProcess(pVdma, (VBVAEXHOSTCTL*)pCmd);
2562 VBoxVBVAExHPDataCompleteCtl(pCmdVbva, (VBVAEXHOSTCTL*)pCmd, rc);
2563 break;
2564 case VBVAEXHOST_DATA_TYPE_HOSTCTL:
2565 {
2566 bool fContinue = true;
2567 rc = vboxVDMACrHostCtlProcess(pVdma, (VBVAEXHOSTCTL*)pCmd, &fContinue);
2568 VBoxVBVAExHPDataCompleteCtl(pCmdVbva, (VBVAEXHOSTCTL*)pCmd, rc);
2569 if (fContinue)
2570 break;
2571 }
2572 case VBVAEXHOST_DATA_TYPE_NO_DATA:
2573 rc = VBoxVDMAThreadEventWait(&pVdma->Thread, RT_INDEFINITE_WAIT);
2574 AssertRC(rc);
2575 break;
2576 default:
2577 WARN(("unexpected type %d\n", enmType));
2578 break;
2579 }
2580 }
2581
2582 VBoxVDMAThreadNotifyTerminatingSucceeded(&pVdma->Thread, pvUser);
2583
2584 return VINF_SUCCESS;
2585}
2586
2587static void vboxVDMACommandProcess(PVBOXVDMAHOST pVdma, PVBOXVDMACBUF_DR pCmd, uint32_t cbCmd)
2588{
2589 PHGSMIINSTANCE pHgsmi = pVdma->pHgsmi;
2590 const uint8_t * pvBuf;
2591 PGMPAGEMAPLOCK Lock;
2592 int rc;
2593 bool bReleaseLocked = false;
2594
2595 do
2596 {
2597 PPDMDEVINS pDevIns = pVdma->pVGAState->pDevInsR3;
2598
2599 if (pCmd->fFlags & VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR)
2600 pvBuf = VBOXVDMACBUF_DR_TAIL(pCmd, const uint8_t);
2601 else if (pCmd->fFlags & VBOXVDMACBUF_FLAG_BUF_VRAM_OFFSET)
2602 {
2603 uint8_t * pvRam = pVdma->pVGAState->vram_ptrR3;
2604 pvBuf = pvRam + pCmd->Location.offVramBuf;
2605 }
2606 else
2607 {
2608 RTGCPHYS phPage = pCmd->Location.phBuf & ~0xfffULL;
2609 uint32_t offset = pCmd->Location.phBuf & 0xfff;
2610 Assert(offset + pCmd->cbBuf <= 0x1000);
2611 if (offset + pCmd->cbBuf > 0x1000)
2612 {
2613 /* @todo: more advanced mechanism of command buffer proc is actually needed */
2614 rc = VERR_INVALID_PARAMETER;
2615 break;
2616 }
2617
2618 const void * pvPageBuf;
2619 rc = PDMDevHlpPhysGCPhys2CCPtrReadOnly(pDevIns, phPage, 0, &pvPageBuf, &Lock);
2620 AssertRC(rc);
2621 if (!RT_SUCCESS(rc))
2622 {
2623 /* @todo: if (rc == VERR_PGM_PHYS_PAGE_RESERVED) -> fall back on using PGMPhysRead ?? */
2624 break;
2625 }
2626
2627 pvBuf = (const uint8_t *)pvPageBuf;
2628 pvBuf += offset;
2629
2630 bReleaseLocked = true;
2631 }
2632
2633 rc = vboxVDMACmdExec(pVdma, pvBuf, pCmd->cbBuf);
2634 AssertRC(rc);
2635
2636 if (bReleaseLocked)
2637 PDMDevHlpPhysReleasePageMappingLock(pDevIns, &Lock);
2638 } while (0);
2639
2640 pCmd->rc = rc;
2641
2642 rc = VBoxSHGSMICommandComplete (pHgsmi, pCmd);
2643 AssertRC(rc);
2644}
2645
2646static void vboxVDMAControlProcess(PVBOXVDMAHOST pVdma, PVBOXVDMA_CTL pCmd)
2647{
2648 PHGSMIINSTANCE pHgsmi = pVdma->pHgsmi;
2649 pCmd->i32Result = VINF_SUCCESS;
2650 int rc = VBoxSHGSMICommandComplete (pHgsmi, pCmd);
2651 AssertRC(rc);
2652}
2653
2654#endif /* #ifdef VBOX_WITH_CRHGSMI */
2655
2656#ifdef VBOX_VDMA_WITH_WATCHDOG
2657static DECLCALLBACK(void) vboxVDMAWatchDogTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
2658{
2659 VBOXVDMAHOST *pVdma = (VBOXVDMAHOST *)pvUser;
2660 PVGASTATE pVGAState = pVdma->pVGAState;
2661 VBVARaiseIrq(pVGAState, HGSMIHOSTFLAGS_WATCHDOG);
2662}
2663
2664static int vboxVDMAWatchDogCtl(struct VBOXVDMAHOST *pVdma, uint32_t cMillis)
2665{
2666 PPDMDEVINS pDevIns = pVdma->pVGAState->pDevInsR3;
2667 if (cMillis)
2668 TMTimerSetMillies(pVdma->WatchDogTimer, cMillis);
2669 else
2670 TMTimerStop(pVdma->WatchDogTimer);
2671 return VINF_SUCCESS;
2672}
2673#endif
2674
2675int vboxVDMAConstruct(PVGASTATE pVGAState, uint32_t cPipeElements)
2676{
2677 int rc;
2678 PVBOXVDMAHOST pVdma = (PVBOXVDMAHOST)RTMemAllocZ(sizeof(*pVdma));
2679 Assert(pVdma);
2680 if (pVdma)
2681 {
2682 pVdma->pHgsmi = pVGAState->pHGSMI;
2683 pVdma->pVGAState = pVGAState;
2684
2685#ifdef VBOX_VDMA_WITH_WATCHDOG
2686 rc = PDMDevHlpTMTimerCreate(pVGAState->pDevInsR3, TMCLOCK_REAL, vboxVDMAWatchDogTimer,
2687 pVdma, TMTIMER_FLAGS_NO_CRIT_SECT,
2688 "VDMA WatchDog Timer", &pVdma->WatchDogTimer);
2689 AssertRC(rc);
2690#endif
2691
2692#ifdef VBOX_WITH_CRHGSMI
2693 VBoxVDMAThreadInit(&pVdma->Thread);
2694
2695 rc = RTSemEventMultiCreate(&pVdma->HostCrCtlCompleteEvent);
2696 if (RT_SUCCESS(rc))
2697 {
2698 rc = VBoxVBVAExHSInit(&pVdma->CmdVbva);
2699 if (RT_SUCCESS(rc))
2700 {
2701 pVGAState->pVdma = pVdma;
2702 int rcIgnored = vboxVDMACrCtlHgsmiSetup(pVdma); NOREF(rcIgnored); /** @todo is this ignoring intentional? */
2703 return VINF_SUCCESS;
2704
2705 VBoxVBVAExHSTerm(&pVdma->CmdVbva);
2706 }
2707 else
2708 WARN(("VBoxVBVAExHSInit failed %d\n", rc));
2709
2710 RTSemEventMultiDestroy(pVdma->HostCrCtlCompleteEvent);
2711 }
2712 else
2713 WARN(("RTSemEventMultiCreate failed %d\n", rc));
2714
2715
2716 RTMemFree(pVdma);
2717#else
2718 pVGAState->pVdma = pVdma;
2719 return VINF_SUCCESS;
2720#endif
2721 }
2722 else
2723 rc = VERR_OUT_OF_RESOURCES;
2724
2725 return rc;
2726}
2727
2728int vboxVDMAReset(struct VBOXVDMAHOST *pVdma)
2729{
2730#ifdef VBOX_WITH_CRHGSMI
2731 vdmaVBVACtlDisableSync(pVdma);
2732#endif
2733 return VINF_SUCCESS;
2734}
2735
2736int vboxVDMADestruct(struct VBOXVDMAHOST *pVdma)
2737{
2738 if (!pVdma)
2739 return VINF_SUCCESS;
2740#ifdef VBOX_WITH_CRHGSMI
2741 vdmaVBVACtlDisableSync(pVdma);
2742 VBoxVDMAThreadCleanup(&pVdma->Thread);
2743 VBoxVBVAExHSTerm(&pVdma->CmdVbva);
2744 RTSemEventMultiDestroy(pVdma->HostCrCtlCompleteEvent);
2745#endif
2746 RTMemFree(pVdma);
2747 return VINF_SUCCESS;
2748}
2749
2750void vboxVDMAControl(struct VBOXVDMAHOST *pVdma, PVBOXVDMA_CTL pCmd, uint32_t cbCmd)
2751{
2752 PHGSMIINSTANCE pIns = pVdma->pHgsmi;
2753
2754 switch (pCmd->enmCtl)
2755 {
2756 case VBOXVDMA_CTL_TYPE_ENABLE:
2757 pCmd->i32Result = VINF_SUCCESS;
2758 break;
2759 case VBOXVDMA_CTL_TYPE_DISABLE:
2760 pCmd->i32Result = VINF_SUCCESS;
2761 break;
2762 case VBOXVDMA_CTL_TYPE_FLUSH:
2763 pCmd->i32Result = VINF_SUCCESS;
2764 break;
2765#ifdef VBOX_VDMA_WITH_WATCHDOG
2766 case VBOXVDMA_CTL_TYPE_WATCHDOG:
2767 pCmd->i32Result = vboxVDMAWatchDogCtl(pVdma, pCmd->u32Offset);
2768 break;
2769#endif
2770 default:
2771 WARN(("cmd not supported"));
2772 pCmd->i32Result = VERR_NOT_SUPPORTED;
2773 }
2774
2775 int rc = VBoxSHGSMICommandComplete (pIns, pCmd);
2776 AssertRC(rc);
2777}
2778
2779void vboxVDMACommand(struct VBOXVDMAHOST *pVdma, PVBOXVDMACBUF_DR pCmd, uint32_t cbCmd)
2780{
2781 int rc = VERR_NOT_IMPLEMENTED;
2782
2783#ifdef VBOX_WITH_CRHGSMI
2784 /* chromium commands are processed by crhomium hgcm thread independently from our internal cmd processing pipeline
2785 * this is why we process them specially */
2786 rc = vboxVDMACmdCheckCrCmd(pVdma, pCmd, cbCmd);
2787 if (rc == VINF_SUCCESS)
2788 return;
2789
2790 if (RT_FAILURE(rc))
2791 {
2792 pCmd->rc = rc;
2793 rc = VBoxSHGSMICommandComplete (pVdma->pHgsmi, pCmd);
2794 AssertRC(rc);
2795 return;
2796 }
2797
2798 vboxVDMACommandProcess(pVdma, pCmd, cbCmd);
2799#else
2800 pCmd->rc = rc;
2801 rc = VBoxSHGSMICommandComplete (pVdma->pHgsmi, pCmd);
2802 AssertRC(rc);
2803#endif
2804}
2805
2806/**/
2807#ifdef VBOX_WITH_CRHGSMI
2808
2809static DECLCALLBACK(void) vdmaVBVACtlSubmitSyncCompletion(VBVAEXHOSTCONTEXT *pVbva, struct VBVAEXHOSTCTL *pCtl, int rc, void *pvContext);
2810
2811static int vdmaVBVACtlSubmit(PVBOXVDMAHOST pVdma, VBVAEXHOSTCTL* pCtl, VBVAEXHOSTCTL_SOURCE enmSource, PFNVBVAEXHOSTCTL_COMPLETE pfnComplete, void *pvComplete)
2812{
2813 int rc = VBoxVBVAExHCtlSubmit(&pVdma->CmdVbva, pCtl, enmSource, pfnComplete, pvComplete);
2814 if (RT_SUCCESS(rc))
2815 {
2816 if (rc == VINF_SUCCESS)
2817 return VBoxVDMAThreadEventNotify(&pVdma->Thread);
2818 else
2819 Assert(rc == VINF_ALREADY_INITIALIZED);
2820 }
2821 else
2822 Log(("VBoxVBVAExHCtlSubmit failed %d\n", rc));
2823
2824 return rc;
2825}
2826
2827static DECLCALLBACK(void) vboxCmdVBVACmdCtlGuestCompletion(VBVAEXHOSTCONTEXT *pVbva, struct VBVAEXHOSTCTL *pCtl, int rc, void *pvContext)
2828{
2829 PVBOXVDMAHOST pVdma = (PVBOXVDMAHOST)pvContext;
2830 VBOXCMDVBVA_CTL *pGCtl = (VBOXCMDVBVA_CTL*)(pCtl->u.cmd.pu8Cmd - sizeof (VBOXCMDVBVA_CTL));
2831 AssertRC(rc);
2832 pGCtl->i32Result = rc;
2833
2834 Assert(pVdma->pVGAState->fGuestCaps & VBVACAPS_COMPLETEGCMD_BY_IOREAD);
2835 rc = VBoxSHGSMICommandComplete(pVdma->pHgsmi, pGCtl);
2836 AssertRC(rc);
2837
2838 VBoxVBVAExHCtlFree(pVbva, pCtl);
2839}
2840
2841static int vdmaVBVACtlGenericSubmit(PVBOXVDMAHOST pVdma, VBVAEXHOSTCTL_SOURCE enmSource, VBVAEXHOSTCTL_TYPE enmType, uint8_t* pu8Cmd, uint32_t cbCmd, PFNVBVAEXHOSTCTL_COMPLETE pfnComplete, void *pvComplete)
2842{
2843 VBVAEXHOSTCTL* pHCtl = VBoxVBVAExHCtlCreate(&pVdma->CmdVbva, enmType);
2844 if (!pHCtl)
2845 {
2846 WARN(("VBoxVBVAExHCtlCreate failed\n"));
2847 return VERR_NO_MEMORY;
2848 }
2849
2850 pHCtl->u.cmd.pu8Cmd = pu8Cmd;
2851 pHCtl->u.cmd.cbCmd = cbCmd;
2852 int rc = vdmaVBVACtlSubmit(pVdma, pHCtl, enmSource, pfnComplete, pvComplete);
2853 if (RT_FAILURE(rc))
2854 {
2855 VBoxVBVAExHCtlFree(&pVdma->CmdVbva, pHCtl);
2856 Log(("vdmaVBVACtlSubmit failed rc %d\n", rc));
2857 return rc;;
2858 }
2859 return VINF_SUCCESS;
2860}
2861
2862static int vdmaVBVACtlGenericGuestSubmit(PVBOXVDMAHOST pVdma, VBVAEXHOSTCTL_TYPE enmType, VBOXCMDVBVA_CTL *pCtl, uint32_t cbCtl)
2863{
2864 Assert(cbCtl >= sizeof (VBOXCMDVBVA_CTL));
2865 VBoxSHGSMICommandMarkAsynchCompletion(pCtl);
2866 int rc = vdmaVBVACtlGenericSubmit(pVdma, VBVAEXHOSTCTL_SOURCE_GUEST, enmType, (uint8_t*)(pCtl+1), cbCtl - sizeof (VBOXCMDVBVA_CTL), vboxCmdVBVACmdCtlGuestCompletion, pVdma);
2867 if (RT_SUCCESS(rc))
2868 return VINF_SUCCESS;
2869
2870 WARN(("vdmaVBVACtlGenericSubmit failed %d\n", rc));
2871 pCtl->i32Result = rc;
2872 rc = VBoxSHGSMICommandComplete(pVdma->pHgsmi, pCtl);
2873 AssertRC(rc);
2874 return VINF_SUCCESS;
2875}
2876
2877static DECLCALLBACK(void) vboxCmdVBVACmdCtlHostCompletion(VBVAEXHOSTCONTEXT *pVbva, struct VBVAEXHOSTCTL *pCtl, int rc, void *pvCompletion)
2878{
2879 VBOXCRCMDCTL* pVboxCtl = (VBOXCRCMDCTL*)pCtl->u.cmd.pu8Cmd;
2880 if (pVboxCtl->u.pfnInternal)
2881 ((PFNCRCTLCOMPLETION)pVboxCtl->u.pfnInternal)(pVboxCtl, pCtl->u.cmd.cbCmd, rc, pvCompletion);
2882 VBoxVBVAExHCtlFree(pVbva, pCtl);
2883}
2884
2885static int vdmaVBVACtlOpaqueHostSubmit(PVBOXVDMAHOST pVdma, struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd,
2886 PFNCRCTLCOMPLETION pfnCompletion,
2887 void *pvCompletion)
2888{
2889 pCmd->u.pfnInternal = (void(*)())pfnCompletion;
2890 int rc = vdmaVBVACtlGenericSubmit(pVdma, VBVAEXHOSTCTL_SOURCE_HOST, VBVAEXHOSTCTL_TYPE_GHH_BE_OPAQUE, (uint8_t*)pCmd, cbCmd, vboxCmdVBVACmdCtlHostCompletion, pvCompletion);
2891 if (RT_FAILURE(rc))
2892 {
2893 if (rc == VERR_INVALID_STATE)
2894 {
2895 pCmd->u.pfnInternal = NULL;
2896 PVGASTATE pVGAState = pVdma->pVGAState;
2897 rc = pVGAState->pDrv->pfnCrHgcmCtlSubmit(pVGAState->pDrv, pCmd, cbCmd, pfnCompletion, pvCompletion);
2898 if (!RT_SUCCESS(rc))
2899 WARN(("pfnCrHgsmiControlProcess failed %d\n", rc));
2900
2901 return rc;
2902 }
2903 WARN(("vdmaVBVACtlGenericSubmit failed %d\n", rc));
2904 return rc;
2905 }
2906
2907 return VINF_SUCCESS;
2908}
2909
2910static DECLCALLBACK(int) vdmaVBVANotifyEnable(PVGASTATE pVGAState)
2911{
2912 for (uint32_t i = 0; i < pVGAState->cMonitors; i++)
2913 {
2914 int rc = pVGAState->pDrv->pfnVBVAEnable (pVGAState->pDrv, i, NULL, true);
2915 if (!RT_SUCCESS(rc))
2916 {
2917 WARN(("pfnVBVAEnable failed %d\n", rc));
2918 for (uint32_t j = 0; j < i; j++)
2919 {
2920 pVGAState->pDrv->pfnVBVADisable (pVGAState->pDrv, j);
2921 }
2922
2923 return rc;
2924 }
2925 }
2926 return VINF_SUCCESS;
2927}
2928
2929static DECLCALLBACK(int) vdmaVBVANotifyDisable(PVGASTATE pVGAState)
2930{
2931 for (uint32_t i = 0; i < pVGAState->cMonitors; i++)
2932 {
2933 pVGAState->pDrv->pfnVBVADisable (pVGAState->pDrv, i);
2934 }
2935 return VINF_SUCCESS;
2936}
2937
2938static DECLCALLBACK(void) vdmaVBVACtlThreadCreatedEnable(struct VBOXVDMATHREAD *pThread, int rc, void *pvThreadContext, void *pvContext)
2939{
2940 PVBOXVDMAHOST pVdma = (PVBOXVDMAHOST)pvThreadContext;
2941 VBVAEXHOSTCTL* pHCtl = (VBVAEXHOSTCTL*)pvContext;
2942
2943 if (RT_SUCCESS(rc))
2944 {
2945 rc = vboxVDMACrGuestCtlProcess(pVdma, pHCtl);
2946 /* rc == VINF_SUCCESS would mean the actual state change has occcured */
2947 if (rc == VINF_SUCCESS)
2948 {
2949 /* we need to inform Main about VBVA enable/disable
2950 * main expects notifications to be done from the main thread
2951 * submit it there */
2952 PVGASTATE pVGAState = pVdma->pVGAState;
2953
2954 if (VBoxVBVAExHSIsEnabled(&pVdma->CmdVbva))
2955 vdmaVBVANotifyEnable(pVGAState);
2956 else
2957 vdmaVBVANotifyDisable(pVGAState);
2958 }
2959 else if (RT_FAILURE(rc))
2960 WARN(("vboxVDMACrGuestCtlProcess failed %d\n", rc));
2961 }
2962 else
2963 WARN(("vdmaVBVACtlThreadCreatedEnable is passed %d\n", rc));
2964
2965 VBoxVBVAExHPDataCompleteCtl(&pVdma->CmdVbva, pHCtl, rc);
2966}
2967
2968static int vdmaVBVACtlEnableSubmitInternal(PVBOXVDMAHOST pVdma, VBVAENABLE *pEnable, bool fPaused, PFNVBVAEXHOSTCTL_COMPLETE pfnComplete, void *pvComplete)
2969{
2970 int rc;
2971 VBVAEXHOSTCTL* pHCtl = VBoxVBVAExHCtlCreate(&pVdma->CmdVbva, fPaused ? VBVAEXHOSTCTL_TYPE_GHH_ENABLE_PAUSED : VBVAEXHOSTCTL_TYPE_GHH_ENABLE);
2972 if (pHCtl)
2973 {
2974 pHCtl->u.cmd.pu8Cmd = (uint8_t*)pEnable;
2975 pHCtl->u.cmd.cbCmd = sizeof (*pEnable);
2976 pHCtl->pfnComplete = pfnComplete;
2977 pHCtl->pvComplete = pvComplete;
2978
2979 rc = VBoxVDMAThreadCreate(&pVdma->Thread, vboxVDMAWorkerThread, pVdma, vdmaVBVACtlThreadCreatedEnable, pHCtl);
2980 if (RT_SUCCESS(rc))
2981 return VINF_SUCCESS;
2982 else
2983 WARN(("VBoxVDMAThreadCreate failed %d\n", rc));
2984
2985 VBoxVBVAExHCtlFree(&pVdma->CmdVbva, pHCtl);
2986 }
2987 else
2988 {
2989 WARN(("VBoxVBVAExHCtlCreate failed\n"));
2990 rc = VERR_NO_MEMORY;
2991 }
2992
2993 return rc;
2994}
2995
2996static int vdmaVBVACtlEnableSubmitSync(PVBOXVDMAHOST pVdma, uint32_t offVram, bool fPaused)
2997{
2998 VBVAENABLE Enable = {0};
2999 Enable.u32Flags = VBVA_F_ENABLE;
3000 Enable.u32Offset = offVram;
3001
3002 VDMA_VBVA_CTL_CYNC_COMPLETION Data;
3003 Data.rc = VERR_NOT_IMPLEMENTED;
3004 int rc = RTSemEventCreate(&Data.hEvent);
3005 if (!RT_SUCCESS(rc))
3006 {
3007 WARN(("RTSemEventCreate failed %d\n", rc));
3008 return rc;
3009 }
3010
3011 rc = vdmaVBVACtlEnableSubmitInternal(pVdma, &Enable, fPaused, vdmaVBVACtlSubmitSyncCompletion, &Data);
3012 if (RT_SUCCESS(rc))
3013 {
3014 rc = RTSemEventWait(Data.hEvent, RT_INDEFINITE_WAIT);
3015 if (RT_SUCCESS(rc))
3016 {
3017 rc = Data.rc;
3018 if (!RT_SUCCESS(rc))
3019 WARN(("vdmaVBVACtlSubmitSyncCompletion returned %d\n", rc));
3020 }
3021 else
3022 WARN(("RTSemEventWait failed %d\n", rc));
3023 }
3024 else
3025 WARN(("vdmaVBVACtlSubmit failed %d\n", rc));
3026
3027 RTSemEventDestroy(Data.hEvent);
3028
3029 return rc;
3030}
3031
3032static int vdmaVBVACtlDisableSubmitInternal(PVBOXVDMAHOST pVdma, VBVAENABLE *pEnable, PFNVBVAEXHOSTCTL_COMPLETE pfnComplete, void *pvComplete)
3033{
3034 int rc;
3035 VBVAEXHOSTCTL* pHCtl;
3036 if (VBoxVBVAExHSIsDisabled(&pVdma->CmdVbva))
3037 {
3038 WARN(("VBoxVBVAExHSIsDisabled: disabled"));
3039 return VINF_SUCCESS;
3040 }
3041
3042 pHCtl = VBoxVBVAExHCtlCreate(&pVdma->CmdVbva, VBVAEXHOSTCTL_TYPE_GHH_DISABLE);
3043 if (!pHCtl)
3044 {
3045 WARN(("VBoxVBVAExHCtlCreate failed\n"));
3046 return VERR_NO_MEMORY;
3047 }
3048
3049 pHCtl->u.cmd.pu8Cmd = (uint8_t*)pEnable;
3050 pHCtl->u.cmd.cbCmd = sizeof (*pEnable);
3051 rc = vdmaVBVACtlSubmit(pVdma, pHCtl, VBVAEXHOSTCTL_SOURCE_GUEST, pfnComplete, pvComplete);
3052 if (RT_SUCCESS(rc))
3053 return VINF_SUCCESS;
3054
3055 WARN(("vdmaVBVACtlSubmit failed rc %d\n", rc));
3056 VBoxVBVAExHCtlFree(&pVdma->CmdVbva, pHCtl);
3057 return rc;
3058}
3059
3060static int vdmaVBVACtlEnableDisableSubmitInternal(PVBOXVDMAHOST pVdma, VBVAENABLE *pEnable, PFNVBVAEXHOSTCTL_COMPLETE pfnComplete, void *pvComplete)
3061{
3062 bool fEnable = ((pEnable->u32Flags & (VBVA_F_ENABLE | VBVA_F_DISABLE)) == VBVA_F_ENABLE);
3063 if (fEnable)
3064 return vdmaVBVACtlEnableSubmitInternal(pVdma, pEnable, false, pfnComplete, pvComplete);
3065 return vdmaVBVACtlDisableSubmitInternal(pVdma, pEnable, pfnComplete, pvComplete);
3066}
3067
3068static int vdmaVBVACtlEnableDisableSubmit(PVBOXVDMAHOST pVdma, VBOXCMDVBVA_CTL_ENABLE *pEnable)
3069{
3070 VBoxSHGSMICommandMarkAsynchCompletion(&pEnable->Hdr);
3071 int rc = vdmaVBVACtlEnableDisableSubmitInternal(pVdma, &pEnable->Enable, vboxCmdVBVACmdCtlGuestCompletion, pVdma);
3072 if (RT_SUCCESS(rc))
3073 return VINF_SUCCESS;
3074
3075 WARN(("vdmaVBVACtlEnableDisableSubmitInternal failed %d\n", rc));
3076 pEnable->Hdr.i32Result = rc;
3077 rc = VBoxSHGSMICommandComplete(pVdma->pHgsmi, &pEnable->Hdr);
3078 AssertRC(rc);
3079 return VINF_SUCCESS;
3080}
3081
3082static DECLCALLBACK(void) vdmaVBVACtlSubmitSyncCompletion(VBVAEXHOSTCONTEXT *pVbva, struct VBVAEXHOSTCTL *pCtl, int rc, void *pvContext)
3083{
3084 VDMA_VBVA_CTL_CYNC_COMPLETION *pData = (VDMA_VBVA_CTL_CYNC_COMPLETION*)pvContext;
3085 pData->rc = rc;
3086 rc = RTSemEventSignal(pData->hEvent);
3087 if (!RT_SUCCESS(rc))
3088 WARN(("RTSemEventSignal failed %d\n", rc));
3089}
3090
3091static int vdmaVBVACtlSubmitSync(PVBOXVDMAHOST pVdma, VBVAEXHOSTCTL* pCtl, VBVAEXHOSTCTL_SOURCE enmSource)
3092{
3093 VDMA_VBVA_CTL_CYNC_COMPLETION Data;
3094 Data.rc = VERR_NOT_IMPLEMENTED;
3095 int rc = RTSemEventCreate(&Data.hEvent);
3096 if (!RT_SUCCESS(rc))
3097 {
3098 WARN(("RTSemEventCreate failed %d\n", rc));
3099 return rc;
3100 }
3101
3102 rc = vdmaVBVACtlSubmit(pVdma, pCtl, enmSource, vdmaVBVACtlSubmitSyncCompletion, &Data);
3103 if (RT_SUCCESS(rc))
3104 {
3105 rc = RTSemEventWait(Data.hEvent, RT_INDEFINITE_WAIT);
3106 if (RT_SUCCESS(rc))
3107 {
3108 rc = Data.rc;
3109 if (!RT_SUCCESS(rc))
3110 WARN(("vdmaVBVACtlSubmitSyncCompletion returned %d\n", rc));
3111 }
3112 else
3113 WARN(("RTSemEventWait failed %d\n", rc));
3114 }
3115 else
3116 Log(("vdmaVBVACtlSubmit failed %d\n", rc));
3117
3118 RTSemEventDestroy(Data.hEvent);
3119
3120 return rc;
3121}
3122
3123static int vdmaVBVAPause(PVBOXVDMAHOST pVdma)
3124{
3125 VBVAEXHOSTCTL Ctl;
3126 Ctl.enmType = VBVAEXHOSTCTL_TYPE_HH_INTERNAL_PAUSE;
3127 return vdmaVBVACtlSubmitSync(pVdma, &Ctl, VBVAEXHOSTCTL_SOURCE_HOST);
3128}
3129
3130static int vdmaVBVAResume(PVBOXVDMAHOST pVdma)
3131{
3132 VBVAEXHOSTCTL Ctl;
3133 Ctl.enmType = VBVAEXHOSTCTL_TYPE_HH_INTERNAL_RESUME;
3134 return vdmaVBVACtlSubmitSync(pVdma, &Ctl, VBVAEXHOSTCTL_SOURCE_HOST);
3135}
3136
3137static int vboxVDMACmdSubmitPerform(struct VBOXVDMAHOST *pVdma)
3138{
3139 int rc = VBoxVBVAExHSCheckCommands(&pVdma->CmdVbva);
3140 switch (rc)
3141 {
3142 case VINF_SUCCESS:
3143 return VBoxVDMAThreadEventNotify(&pVdma->Thread);
3144 case VINF_ALREADY_INITIALIZED:
3145 case VINF_EOF:
3146 case VERR_INVALID_STATE:
3147 return VINF_SUCCESS;
3148 default:
3149 Assert(!RT_FAILURE(rc));
3150 return RT_FAILURE(rc) ? rc : VERR_INTERNAL_ERROR;
3151 }
3152}
3153
3154
3155int vboxCmdVBVACmdHostCtl(PPDMIDISPLAYVBVACALLBACKS pInterface,
3156 struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd,
3157 PFNCRCTLCOMPLETION pfnCompletion,
3158 void *pvCompletion)
3159{
3160 PVGASTATE pVGAState = PPDMIDISPLAYVBVACALLBACKS_2_PVGASTATE(pInterface);
3161 struct VBOXVDMAHOST *pVdma = pVGAState->pVdma;
3162 return vdmaVBVACtlOpaqueHostSubmit(pVdma, pCmd, cbCmd, pfnCompletion, pvCompletion);
3163}
3164
3165typedef struct VBOXCMDVBVA_CMDHOSTCTL_SYNC
3166{
3167 struct VBOXVDMAHOST *pVdma;
3168 uint32_t fProcessing;
3169 int rc;
3170} VBOXCMDVBVA_CMDHOSTCTL_SYNC;
3171
3172static DECLCALLBACK(void) vboxCmdVBVACmdHostCtlSyncCb(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd, int rc, void *pvCompletion)
3173{
3174 VBOXCMDVBVA_CMDHOSTCTL_SYNC *pData = (VBOXCMDVBVA_CMDHOSTCTL_SYNC*)pvCompletion;
3175
3176 pData->rc = rc;
3177 pData->fProcessing = 0;
3178
3179 struct VBOXVDMAHOST *pVdma = pData->pVdma;
3180
3181 ASMAtomicIncS32(&pVdma->i32cHostCrCtlCompleted);
3182
3183 RTSemEventMultiSignal(pVdma->HostCrCtlCompleteEvent);
3184}
3185
3186int vboxCmdVBVACmdHostCtlSync(PPDMIDISPLAYVBVACALLBACKS pInterface,
3187 struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd)
3188{
3189 PVGASTATE pVGAState = PPDMIDISPLAYVBVACALLBACKS_2_PVGASTATE(pInterface);
3190 struct VBOXVDMAHOST *pVdma = pVGAState->pVdma;
3191 VBOXCMDVBVA_CMDHOSTCTL_SYNC Data;
3192 Data.pVdma = pVdma;
3193 Data.fProcessing = 1;
3194 Data.rc = VERR_INTERNAL_ERROR;
3195 int rc = vdmaVBVACtlOpaqueHostSubmit(pVdma, pCmd, cbCmd, vboxCmdVBVACmdHostCtlSyncCb, &Data);
3196 if (!RT_SUCCESS(rc))
3197 {
3198 WARN(("vdmaVBVACtlOpaqueHostSubmit failed %d", rc));
3199 return rc;
3200 }
3201
3202 while (Data.fProcessing)
3203 {
3204 /* Poll infrequently to make sure no completed message has been missed. */
3205 RTSemEventMultiWait(pVdma->HostCrCtlCompleteEvent, 500);
3206
3207 if (Data.fProcessing)
3208 RTThreadYield();
3209 }
3210
3211 /* 'Our' message has been processed, so should reset the semaphore.
3212 * There is still possible that another message has been processed
3213 * and the semaphore has been signalled again.
3214 * Reset only if there are no other messages completed.
3215 */
3216 int32_t c = ASMAtomicDecS32(&pVdma->i32cHostCrCtlCompleted);
3217 Assert(c >= 0);
3218 if (!c)
3219 RTSemEventMultiReset(pVdma->HostCrCtlCompleteEvent);
3220
3221 rc = Data.rc;
3222 if (!RT_SUCCESS(rc))
3223 WARN(("host call failed %d", rc));
3224
3225 return rc;
3226}
3227
3228int vboxCmdVBVACmdCtl(PVGASTATE pVGAState, VBOXCMDVBVA_CTL *pCtl, uint32_t cbCtl)
3229{
3230 struct VBOXVDMAHOST *pVdma = pVGAState->pVdma;
3231 int rc = VINF_SUCCESS;
3232 switch (pCtl->u32Type)
3233 {
3234 case VBOXCMDVBVACTL_TYPE_3DCTL:
3235 return vdmaVBVACtlGenericGuestSubmit(pVdma, VBVAEXHOSTCTL_TYPE_GHH_BE_OPAQUE, pCtl, cbCtl);
3236 case VBOXCMDVBVACTL_TYPE_RESIZE:
3237 return vdmaVBVACtlGenericGuestSubmit(pVdma, VBVAEXHOSTCTL_TYPE_GHH_RESIZE, pCtl, cbCtl);
3238 case VBOXCMDVBVACTL_TYPE_ENABLE:
3239 if (cbCtl != sizeof (VBOXCMDVBVA_CTL_ENABLE))
3240 {
3241 WARN(("incorrect enable size\n"));
3242 rc = VERR_INVALID_PARAMETER;
3243 break;
3244 }
3245 return vdmaVBVACtlEnableDisableSubmit(pVdma, (VBOXCMDVBVA_CTL_ENABLE*)pCtl);
3246 default:
3247 WARN(("unsupported type\n"));
3248 rc = VERR_INVALID_PARAMETER;
3249 break;
3250 }
3251
3252 pCtl->i32Result = rc;
3253 rc = VBoxSHGSMICommandComplete(pVdma->pHgsmi, pCtl);
3254 AssertRC(rc);
3255 return VINF_SUCCESS;
3256}
3257
3258int vboxCmdVBVACmdSubmit(PVGASTATE pVGAState)
3259{
3260 if (!VBoxVBVAExHSIsEnabled(&pVGAState->pVdma->CmdVbva))
3261 {
3262 WARN(("vdma VBVA is disabled\n"));
3263 return VERR_INVALID_STATE;
3264 }
3265
3266 return vboxVDMACmdSubmitPerform(pVGAState->pVdma);
3267}
3268
3269int vboxCmdVBVACmdFlush(PVGASTATE pVGAState)
3270{
3271 WARN(("flush\n"));
3272 if (!VBoxVBVAExHSIsEnabled(&pVGAState->pVdma->CmdVbva))
3273 {
3274 WARN(("vdma VBVA is disabled\n"));
3275 return VERR_INVALID_STATE;
3276 }
3277 return vboxVDMACmdSubmitPerform(pVGAState->pVdma);
3278}
3279
3280void vboxCmdVBVACmdTimer(PVGASTATE pVGAState)
3281{
3282 if (!VBoxVBVAExHSIsEnabled(&pVGAState->pVdma->CmdVbva))
3283 return;
3284 vboxVDMACmdSubmitPerform(pVGAState->pVdma);
3285}
3286
3287bool vboxCmdVBVAIsEnabled(PVGASTATE pVGAState)
3288{
3289 return VBoxVBVAExHSIsEnabled(&pVGAState->pVdma->CmdVbva);
3290}
3291#endif
3292
3293int vboxVDMASaveStateExecPrep(struct VBOXVDMAHOST *pVdma, PSSMHANDLE pSSM)
3294{
3295#ifdef VBOX_WITH_CRHGSMI
3296 int rc = vdmaVBVAPause(pVdma);
3297 if (RT_SUCCESS(rc))
3298 return VINF_SUCCESS;
3299
3300 if (rc != VERR_INVALID_STATE)
3301 {
3302 WARN(("vdmaVBVAPause failed %d\n", rc));
3303 return rc;
3304 }
3305
3306#ifdef DEBUG_misha
3307 WARN(("debug prep"));
3308#endif
3309
3310 PVGASTATE pVGAState = pVdma->pVGAState;
3311 PVBOXVDMACMD_CHROMIUM_CTL pCmd = (PVBOXVDMACMD_CHROMIUM_CTL)vboxVDMACrCtlCreate(
3312 VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_BEGIN, sizeof (*pCmd));
3313 Assert(pCmd);
3314 if (pCmd)
3315 {
3316 rc = vboxVDMACrCtlPost(pVGAState, pCmd, sizeof (*pCmd));
3317 AssertRC(rc);
3318 if (RT_SUCCESS(rc))
3319 {
3320 rc = vboxVDMACrCtlGetRc(pCmd);
3321 }
3322 vboxVDMACrCtlRelease(pCmd);
3323 return rc;
3324 }
3325 return VERR_NO_MEMORY;
3326#else
3327 return VINF_SUCCESS;
3328#endif
3329}
3330
3331int vboxVDMASaveStateExecDone(struct VBOXVDMAHOST *pVdma, PSSMHANDLE pSSM)
3332{
3333#ifdef VBOX_WITH_CRHGSMI
3334 int rc = vdmaVBVAResume(pVdma);
3335 if (RT_SUCCESS(rc))
3336 return VINF_SUCCESS;
3337
3338 if (rc != VERR_INVALID_STATE)
3339 {
3340 WARN(("vdmaVBVAResume failed %d\n", rc));
3341 return rc;
3342 }
3343
3344#ifdef DEBUG_misha
3345 WARN(("debug done"));
3346#endif
3347
3348 PVGASTATE pVGAState = pVdma->pVGAState;
3349 PVBOXVDMACMD_CHROMIUM_CTL pCmd = (PVBOXVDMACMD_CHROMIUM_CTL)vboxVDMACrCtlCreate(
3350 VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_END, sizeof (*pCmd));
3351 Assert(pCmd);
3352 if (pCmd)
3353 {
3354 rc = vboxVDMACrCtlPost(pVGAState, pCmd, sizeof (*pCmd));
3355 AssertRC(rc);
3356 if (RT_SUCCESS(rc))
3357 {
3358 rc = vboxVDMACrCtlGetRc(pCmd);
3359 }
3360 vboxVDMACrCtlRelease(pCmd);
3361 return rc;
3362 }
3363 return VERR_NO_MEMORY;
3364#else
3365 return VINF_SUCCESS;
3366#endif
3367}
3368
3369int vboxVDMASaveStateExecPerform(struct VBOXVDMAHOST *pVdma, PSSMHANDLE pSSM)
3370{
3371 int rc;
3372
3373#ifdef VBOX_WITH_CRHGSMI
3374 if (!VBoxVBVAExHSIsEnabled(&pVdma->CmdVbva))
3375#endif
3376 {
3377 rc = SSMR3PutU32(pSSM, 0xffffffff);
3378 AssertRCReturn(rc, rc);
3379 return VINF_SUCCESS;
3380 }
3381
3382#ifdef VBOX_WITH_CRHGSMI
3383 PVGASTATE pVGAState = pVdma->pVGAState;
3384 uint8_t * pu8VramBase = pVGAState->vram_ptrR3;
3385
3386 rc = SSMR3PutU32(pSSM, (uint32_t)(((uint8_t*)pVdma->CmdVbva.pVBVA) - pu8VramBase));
3387 AssertRCReturn(rc, rc);
3388
3389 VBVAEXHOSTCTL HCtl;
3390 HCtl.enmType = VBVAEXHOSTCTL_TYPE_HH_SAVESTATE;
3391 HCtl.u.state.pSSM = pSSM;
3392 HCtl.u.state.u32Version = 0;
3393 return vdmaVBVACtlSubmitSync(pVdma, &HCtl, VBVAEXHOSTCTL_SOURCE_HOST);
3394#endif
3395}
3396
3397int vboxVDMASaveLoadExecPerform(struct VBOXVDMAHOST *pVdma, PSSMHANDLE pSSM, uint32_t u32Version)
3398{
3399 uint32_t u32;
3400 int rc = SSMR3GetU32(pSSM, &u32);
3401 AssertRCReturn(rc, rc);
3402
3403 if (u32 != 0xffffffff)
3404 {
3405#ifdef VBOX_WITH_CRHGSMI
3406 rc = vdmaVBVACtlEnableSubmitSync(pVdma, u32, true);
3407 AssertRCReturn(rc, rc);
3408
3409 Assert(pVdma->CmdVbva.i32State == VBVAEXHOSTCONTEXT_ESTATE_PAUSED);
3410
3411 VBVAEXHOSTCTL HCtl;
3412 HCtl.enmType = VBVAEXHOSTCTL_TYPE_HH_LOADSTATE;
3413 HCtl.u.state.pSSM = pSSM;
3414 HCtl.u.state.u32Version = u32Version;
3415 rc = vdmaVBVACtlSubmitSync(pVdma, &HCtl, VBVAEXHOSTCTL_SOURCE_HOST);
3416 AssertRCReturn(rc, rc);
3417
3418 rc = vdmaVBVAResume(pVdma);
3419 AssertRCReturn(rc, rc);
3420
3421 return VINF_SUCCESS;
3422#else
3423 WARN(("Unsupported VBVACtl info!\n"));
3424 return VERR_VERSION_MISMATCH;
3425#endif
3426 }
3427
3428 return VINF_SUCCESS;
3429}
3430
3431int vboxVDMASaveLoadDone(struct VBOXVDMAHOST *pVdma)
3432{
3433#ifdef VBOX_WITH_CRHGSMI
3434 if (!VBoxVBVAExHSIsEnabled(&pVdma->CmdVbva))
3435 return VINF_SUCCESS;
3436
3437/** @todo r=bird: BTW. would be great if you put in a couple of comments here and there explaining what
3438 * the purpose of this code is. */
3439 VBVAEXHOSTCTL* pHCtl = VBoxVBVAExHCtlCreate(&pVdma->CmdVbva, VBVAEXHOSTCTL_TYPE_HH_LOADSTATE_DONE);
3440 if (!pHCtl)
3441 {
3442 WARN(("VBoxVBVAExHCtlCreate failed\n"));
3443 return VERR_NO_MEMORY;
3444 }
3445
3446 /* sanity */
3447 pHCtl->u.cmd.pu8Cmd = NULL;
3448 pHCtl->u.cmd.cbCmd = 0;
3449
3450 /* NULL completion will just free the ctl up */
3451 int rc = vdmaVBVACtlSubmit(pVdma, pHCtl, VBVAEXHOSTCTL_SOURCE_HOST, NULL, NULL);
3452 if (RT_FAILURE(rc))
3453 {
3454 Log(("vdmaVBVACtlSubmit failed rc %d\n", rc));
3455 VBoxVBVAExHCtlFree(&pVdma->CmdVbva, pHCtl);
3456 return rc;
3457 }
3458#endif
3459 return VINF_SUCCESS;
3460}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette