VirtualBox

source: vbox/trunk/src/VBox/Devices/Graphics/HGSMI/HGSMIHost.cpp@ 95288

Last change on this file since 95288 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 52.1 KB
Line 
1/* $Id: HGSMIHost.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * VBox Host Guest Shared Memory Interface (HGSMI), host part.
4 *
5 * Host part:
6 * - virtual hardware IO handlers;
7 * - channel management;
8 * - low level interface for buffer transfer.
9 */
10
11/*
12 * Copyright (C) 2006-2022 Oracle Corporation
13 *
14 * This file is part of VirtualBox Open Source Edition (OSE), as
15 * available from http://www.virtualbox.org. This file is free software;
16 * you can redistribute it and/or modify it under the terms of the GNU
17 * General Public License (GPL) as published by the Free Software
18 * Foundation, in version 2 as it comes in the "COPYING" file of the
19 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
20 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
21 */
22
23
24/*
25 * Async host->guest calls. Completion by an IO write from the guest or a timer timeout.
26 *
27 * Sync guest->host calls. Initiated by an IO write from the guest.
28 *
29 * Guest->Host
30 * ___________
31 *
32 * Synchronous for the guest, an async result can be also reported later by a host->guest call:
33 *
34 * G: Alloc shared memory, fill the structure, issue an IO write (HGSMI_IO_GUEST) with the memory offset.
35 * H: Verify the shared memory and call the handler.
36 * G: Continue after the IO completion.
37 *
38 *
39 * Host->Guest
40 * __________
41 *
42 * H: Alloc shared memory, fill in the info.
43 * Register in the FIFO with a callback, issue IRQ (on EMT).
44 * Wait on a sem with timeout if necessary.
45 * G: Read FIFO from HGSMI_IO_HOST_COMMAND.
46 * H(EMT): Get the shared memory offset from FIFO to return to the guest.
47 * G: Get offset, process command, issue IO write to HGSMI_IO_HOST_COMMAND.
48 * H(EMT): Find registered shared mem, run callback, which could post the sem.
49 * H: Get results and free shared mem (could be freed automatically on EMT too).
50 *
51 *
52 * Implementation notes:
53 *
54 * Host->Guest
55 *
56 * * Shared memory allocation using a critsect.
57 * * FIFO manipulation with a critsect.
58 *
59 */
60
61#define LOG_GROUP LOG_GROUP_HGSMI
62#include <iprt/alloc.h>
63#include <iprt/critsect.h>
64#include <iprt/heap.h>
65#include <iprt/list.h>
66#include <iprt/semaphore.h>
67#include <iprt/string.h>
68
69#include <VBox/AssertGuest.h>
70#include <iprt/errcore.h>
71#include <VBox/log.h>
72#include <VBox/vmm/pdmdev.h>
73#include <VBox/vmm/ssm.h>
74#include <VBox/vmm/vmm.h>
75
76#include "HGSMIHost.h"
77#include <HGSMIChannels.h>
78
79#include "../DevVGASavedState.h"
80
81#ifdef DEBUG_sunlover
82#define HGSMI_STRICT 1
83#endif /* !DEBUG_sunlover */
84
85#ifdef DEBUG_misha
86//# define VBOXHGSMI_STATE_DEBUG
87#endif
88
89#ifdef VBOXHGSMI_STATE_DEBUG
90# define VBOXHGSMI_STATE_START_MAGIC UINT32_C(0x12345678)
91# define VBOXHGSMI_STATE_STOP_MAGIC UINT32_C(0x87654321)
92# define VBOXHGSMI_STATE_FIFOSTART_MAGIC UINT32_C(0x9abcdef1)
93# define VBOXHGSMI_STATE_FIFOSTOP_MAGIC UINT32_C(0x1fedcba9)
94
95# define VBOXHGSMI_SAVE_START(_pSSM) do{ int rc2 = pHlp->pfnSSMPutU32(_pSSM, VBOXHGSMI_STATE_START_MAGIC); AssertRC(rc2); }while(0)
96# define VBOXHGSMI_SAVE_STOP(_pSSM) do{ int rc2 = pHlp->pfnSSMPutU32(_pSSM, VBOXHGSMI_STATE_STOP_MAGIC); AssertRC(rc2); }while(0)
97# define VBOXHGSMI_SAVE_FIFOSTART(_pSSM) do{ int rc2 = pHlp->pfnSSMPutU32(_pSSM, VBOXHGSMI_STATE_FIFOSTART_MAGIC); AssertRC(rc2); }while(0)
98# define VBOXHGSMI_SAVE_FIFOSTOP(_pSSM) do{ int rc2 = pHlp->pfnSSMPutU32(_pSSM, VBOXHGSMI_STATE_FIFOSTOP_MAGIC); AssertRC(rc2); }while(0)
99
100# define VBOXHGSMI_LOAD_CHECK(_pSSM, _v) \
101 do { \
102 uint32_t u32; \
103 int rc2 = pHlp->pfnSSMGetU32(_pSSM, &u32); AssertRC(rc2); \
104 Assert(u32 == (_v)); \
105 } while(0)
106
107# define VBOXHGSMI_LOAD_START(_pSSM) VBOXHGSMI_LOAD_CHECK(_pSSM, VBOXHGSMI_STATE_START_MAGIC)
108# define VBOXHGSMI_LOAD_FIFOSTART(_pSSM) VBOXHGSMI_LOAD_CHECK(_pSSM, VBOXHGSMI_STATE_FIFOSTART_MAGIC)
109# define VBOXHGSMI_LOAD_FIFOSTOP(_pSSM) VBOXHGSMI_LOAD_CHECK(_pSSM, VBOXHGSMI_STATE_FIFOSTOP_MAGIC)
110# define VBOXHGSMI_LOAD_STOP(_pSSM) VBOXHGSMI_LOAD_CHECK(_pSSM, VBOXHGSMI_STATE_STOP_MAGIC)
111#else /* !VBOXHGSMI_STATE_DEBUG */
112# define VBOXHGSMI_SAVE_START(a_pSSM) do { } while(0)
113# define VBOXHGSMI_SAVE_STOP(a_pSSM) do { } while(0)
114# define VBOXHGSMI_SAVE_FIFOSTART(a_pSSM) do { } while(0)
115# define VBOXHGSMI_SAVE_FIFOSTOP(a_pSSM) do { } while(0)
116
117# define VBOXHGSMI_LOAD_START(a_pSSM) do { } while(0)
118# define VBOXHGSMI_LOAD_FIFOSTART(a_pSSM) do { } while(0)
119# define VBOXHGSMI_LOAD_FIFOSTOP(a_pSSM) do { } while(0)
120# define VBOXHGSMI_LOAD_STOP(a_pSSM) do { } while(0)
121#endif
122
123/* Assertions for situations which could happen and normally must be processed properly
124 * but must be investigated during development: guest misbehaving, etc.
125 */
126#ifdef HGSMI_STRICT
127# define HGSMI_STRICT_ASSERT_FAILED() AssertFailed()
128# define HGSMI_STRICT_ASSERT(expr) Assert(expr)
129#else
130# define HGSMI_STRICT_ASSERT_FAILED() do {} while (0)
131# define HGSMI_STRICT_ASSERT(expr) do {} while (0)
132#endif
133
134
135/** @name Host heap types.
136 * @{ */
137#define HGSMI_HEAP_TYPE_NULL 0 /**< Heap not initialized. */
138#define HGSMI_HEAP_TYPE_POINTER 1 /**< Deprecated, used only for old saved states. RTHEAPSIMPLE. */
139#define HGSMI_HEAP_TYPE_OFFSET 2 /**< Deprecated, used only for old saved states. RTHEAPOFFSET. */
140#define HGSMI_HEAP_TYPE_MA 3 /**< Memory allocator. */
141/** @} */
142
143typedef struct HGSMIHOSTHEAP
144{
145 uint32_t u32HeapType; /**< HGSMI_HEAP_TYPE_* */
146 int32_t volatile cRefs; /**< How many blocks allocated. */
147 HGSMIAREA area; /**< Host heap location. */
148 union
149 {
150 HGSMIMADATA ma; /**< Memory allocator for the default host heap implementation. */
151 struct /**< Legacy heap implementations. For old saved states. */
152 {
153 union
154 {
155 RTHEAPSIMPLE hPtr; /**< Pointer based heap. */
156 RTHEAPOFFSET hOff; /**< Offset based heap. */
157 } u;
158 } legacy;
159 } u;
160} HGSMIHOSTHEAP;
161
162typedef struct HGSMIINSTANCE
163{
164 PPDMDEVINS pDevIns; /**< The device instance. */
165
166 const char *pszName; /**< A name for the instance. Mostyl used in the log. */
167
168 RTCRITSECT instanceCritSect; /**< For updating the instance data: FIFO's, channels. */
169
170 HGSMIAREA area; /**< The shared memory description. */
171 HGSMIHOSTHEAP hostHeap; /**< Host heap instance. */
172 RTCRITSECT hostHeapCritSect; /**< Heap serialization lock. */
173
174 RTLISTANCHOR hostFIFO; /**< Pending host buffers. */
175 RTLISTANCHOR hostFIFORead; /**< Host buffers read by the guest. */
176 RTLISTANCHOR hostFIFOProcessed; /**< Processed by the guest. */
177 RTLISTANCHOR hostFIFOFree; /**< Buffers for reuse. */
178#ifdef VBOX_WITH_WDDM
179 RTLISTANCHOR guestCmdCompleted; /**< list of completed guest commands to be returned to the guest*/
180#endif
181 RTCRITSECT hostFIFOCritSect; /**< FIFO serialization lock. */
182
183 PFNHGSMINOTIFYGUEST pfnNotifyGuest; /**< Guest notification callback. */
184 void *pvNotifyGuest; /**< Guest notification callback context. */
185
186 volatile HGSMIHOSTFLAGS *pHGFlags;
187
188 HGSMICHANNELINFO channelInfo; /**< Channel handlers indexed by the channel id.
189 * The array is accessed under the instance lock.
190 */
191} HGSMIINSTANCE;
192
193
194typedef DECLCALLBACKTYPE(void, FNHGSMIHOSTFIFOCALLBACK,(void *pvCallback));
195typedef FNHGSMIHOSTFIFOCALLBACK *PFNHGSMIHOSTFIFOCALLBACK;
196
197typedef struct HGSMIHOSTFIFOENTRY
198{
199 RTLISTNODE nodeEntry;
200
201 HGSMIINSTANCE *pIns; /**< Backlink to the HGSMI instance. */
202
203 volatile uint32_t fl; /**< Status flags of the entry. */
204
205 HGSMIOFFSET offBuffer; /**< Offset of the HGSMI buffer header in the HGSMI host heap:
206 * [pIns->hostHeap.area.offBase .. offLast]. */
207} HGSMIHOSTFIFOENTRY;
208
209
210#define HGSMI_F_HOST_FIFO_ALLOCATED 0x0001
211#define HGSMI_F_HOST_FIFO_QUEUED 0x0002
212#define HGSMI_F_HOST_FIFO_READ 0x0004
213#define HGSMI_F_HOST_FIFO_PROCESSED 0x0008
214#define HGSMI_F_HOST_FIFO_FREE 0x0010
215#define HGSMI_F_HOST_FIFO_CANCELED 0x0020
216
217static DECLCALLBACK(void) hgsmiHostCommandFreeCallback(void *pvCallback);
218
219#ifdef VBOX_WITH_WDDM
220
221typedef struct HGSMIGUESTCOMPLENTRY
222{
223 RTLISTNODE nodeEntry;
224 HGSMIOFFSET offBuffer; /**< Offset of the guest command buffer. */
225} HGSMIGUESTCOMPLENTRY;
226
227
228static void hgsmiGuestCompletionFIFOFree(HGSMIINSTANCE *pIns, HGSMIGUESTCOMPLENTRY *pEntry)
229{
230 NOREF (pIns);
231 RTMemFree (pEntry);
232}
233
234static int hgsmiGuestCompletionFIFOAlloc(HGSMIINSTANCE *pIns, HGSMIGUESTCOMPLENTRY **ppEntry)
235{
236 HGSMIGUESTCOMPLENTRY *pEntry = (HGSMIGUESTCOMPLENTRY *)RTMemAllocZ(sizeof(HGSMIGUESTCOMPLENTRY));
237 if (pEntry)
238 {
239 *ppEntry = pEntry;
240 return VINF_SUCCESS;
241 }
242 NOREF(pIns);
243 return VERR_NO_MEMORY;
244}
245
246#endif /* VBOX_WITH_WDDM */
247
248static int hgsmiLock(HGSMIINSTANCE *pIns)
249{
250 int rc = RTCritSectEnter(&pIns->instanceCritSect);
251 AssertRC(rc);
252 return rc;
253}
254
255static void hgsmiUnlock(HGSMIINSTANCE *pIns)
256{
257 int rc = RTCritSectLeave(&pIns->instanceCritSect);
258 AssertRC(rc);
259}
260
261static int hgsmiFIFOLock(HGSMIINSTANCE *pIns)
262{
263 int rc = RTCritSectEnter(&pIns->hostFIFOCritSect);
264 AssertRC(rc);
265 return rc;
266}
267
268static void hgsmiFIFOUnlock(HGSMIINSTANCE *pIns)
269{
270 int rc = RTCritSectLeave(&pIns->hostFIFOCritSect);
271 AssertRC(rc);
272}
273
274/*
275 * Virtual hardware IO handlers.
276 */
277
278/* The guest submits a new buffer to the host.
279 * Called from the HGSMI_IO_GUEST write handler.
280 * @thread EMT
281 */
282void HGSMIGuestWrite(PHGSMIINSTANCE pIns, HGSMIOFFSET offBuffer)
283{
284 HGSMIBufferProcess(&pIns->area, &pIns->channelInfo, offBuffer);
285}
286
287#ifdef VBOX_WITH_WDDM
288static HGSMIOFFSET hgsmiProcessGuestCmdCompletion(HGSMIINSTANCE *pIns)
289{
290 HGSMIOFFSET offCmd = HGSMIOFFSET_VOID;
291 int rc = hgsmiFIFOLock(pIns);
292 AssertRC(rc);
293 if (RT_SUCCESS(rc))
294 {
295 HGSMIGUESTCOMPLENTRY *pEntry = RTListGetFirst(&pIns->guestCmdCompleted, HGSMIGUESTCOMPLENTRY, nodeEntry);
296 if (pEntry)
297 {
298 RTListNodeRemove(&pEntry->nodeEntry);
299 }
300
301 if (RTListIsEmpty(&pIns->guestCmdCompleted))
302 {
303 if (pIns->pHGFlags)
304 ASMAtomicAndU32(&pIns->pHGFlags->u32HostFlags, ~HGSMIHOSTFLAGS_GCOMMAND_COMPLETED);
305 }
306
307 hgsmiFIFOUnlock(pIns);
308
309 if (pEntry)
310 {
311 offCmd = pEntry->offBuffer;
312
313 LogFlowFunc(("host FIFO head %p.\n", pEntry));
314
315 hgsmiGuestCompletionFIFOFree(pIns, pEntry);
316 }
317 }
318 return offCmd;
319}
320#endif
321
322
323/* Called from HGSMI_IO_GUEST read handler. */
324HGSMIOFFSET HGSMIGuestRead(PHGSMIINSTANCE pIns)
325{
326 LogFlowFunc(("pIns %p\n", pIns));
327
328 AssertPtr(pIns);
329
330 Assert(PDMDevHlpGetVMCPU(pIns->pDevIns) != NULL);
331
332#ifndef VBOX_WITH_WDDM
333 /* Currently there is no functionality here. */
334 NOREF(pIns);
335
336 return HGSMIOFFSET_VOID;
337#else
338 /* use this to speedup guest cmd completion
339 * this mechanism is alternative to submitting H->G command for notification */
340 HGSMIOFFSET offCmd = hgsmiProcessGuestCmdCompletion(pIns);
341 return offCmd;
342#endif
343}
344
345static bool hgsmiProcessHostCmdCompletion(HGSMIINSTANCE *pIns, HGSMIOFFSET offBuffer, bool fCompleteFirst)
346{
347 Assert(PDMDevHlpGetVMCPU(pIns->pDevIns) != NULL);
348
349 int rc = hgsmiFIFOLock(pIns);
350 if (RT_SUCCESS(rc))
351 {
352 /* Search the Read list for the given buffer offset. */
353 HGSMIHOSTFIFOENTRY *pEntry = NULL;
354
355 HGSMIHOSTFIFOENTRY *pIter;
356 RTListForEach(&pIns->hostFIFORead, pIter, HGSMIHOSTFIFOENTRY, nodeEntry)
357 {
358 Assert(pIter->fl == (HGSMI_F_HOST_FIFO_ALLOCATED | HGSMI_F_HOST_FIFO_READ));
359 if (fCompleteFirst || pIter->offBuffer == offBuffer)
360 {
361 pEntry = pIter;
362 break;
363 }
364 }
365
366 LogFlowFunc(("read list entry: %p.\n", pEntry));
367
368 Assert(pEntry || fCompleteFirst);
369
370 if (pEntry)
371 {
372 RTListNodeRemove(&pEntry->nodeEntry);
373
374 pEntry->fl &= ~HGSMI_F_HOST_FIFO_READ;
375 pEntry->fl |= HGSMI_F_HOST_FIFO_PROCESSED;
376
377 RTListAppend(&pIns->hostFIFOProcessed, &pEntry->nodeEntry);
378
379 hgsmiFIFOUnlock(pIns);
380
381 hgsmiHostCommandFreeCallback(pEntry);
382 return true;
383 }
384
385 hgsmiFIFOUnlock(pIns);
386 if (!fCompleteFirst)
387 LogRel(("HGSMI[%s]: ignored invalid write to the host FIFO: 0x%08X!!!\n", pIns->pszName, offBuffer));
388 }
389 return false;
390}
391
392/**
393 * The guest has finished processing of a buffer previously submitted by the
394 * host.
395 *
396 * Called from HGSMI_IO_HOST write handler.
397 * @thread EMT
398 */
399void HGSMIHostWrite(HGSMIINSTANCE *pIns, HGSMIOFFSET offBuffer)
400{
401 LogFlowFunc(("pIns %p offBuffer 0x%x\n", pIns, offBuffer));
402
403 hgsmiProcessHostCmdCompletion(pIns, offBuffer, false);
404}
405
406/**
407 * The guest reads a new host buffer to be processed.
408 *
409 * Called from the HGSMI_IO_HOST read handler.
410 *
411 * @thread EMT
412 */
413HGSMIOFFSET HGSMIHostRead(HGSMIINSTANCE *pIns)
414{
415 LogFlowFunc(("pIns %p\n", pIns));
416
417 Assert(PDMDevHlpGetVMCPU(pIns->pDevIns) != NULL);
418
419 AssertPtrReturn(pIns->pHGFlags, HGSMIOFFSET_VOID);
420 int rc = hgsmiFIFOLock(pIns);
421 AssertRC(rc);
422 if (RT_SUCCESS(rc))
423 {
424 /* Get the host FIFO head entry. */
425 HGSMIHOSTFIFOENTRY *pEntry = RTListGetFirst(&pIns->hostFIFO, HGSMIHOSTFIFOENTRY, nodeEntry);
426
427 LogFlowFunc(("host FIFO head %p.\n", pEntry));
428
429 if (pEntry != NULL)
430 {
431 Assert(pEntry->fl == (HGSMI_F_HOST_FIFO_ALLOCATED | HGSMI_F_HOST_FIFO_QUEUED));
432
433 /*
434 * Move the entry to the Read list.
435 */
436 RTListNodeRemove(&pEntry->nodeEntry);
437
438 if (RTListIsEmpty(&pIns->hostFIFO))
439 {
440 ASMAtomicAndU32(&pIns->pHGFlags->u32HostFlags, (~HGSMIHOSTFLAGS_COMMANDS_PENDING));
441 }
442
443 pEntry->fl &= ~HGSMI_F_HOST_FIFO_QUEUED;
444 pEntry->fl |= HGSMI_F_HOST_FIFO_READ;
445
446 RTListAppend(&pIns->hostFIFORead, &pEntry->nodeEntry);
447
448 hgsmiFIFOUnlock(pIns);
449
450 /* Return the buffer offset of the host FIFO head. */
451 return pEntry->offBuffer;
452 }
453
454 hgsmiFIFOUnlock(pIns);
455 }
456 /* Special value that means there is no host buffers to be processed. */
457 return HGSMIOFFSET_VOID;
458}
459
460
461/** Tells the guest that a new buffer to be processed is available from the host. */
462static void hgsmiNotifyGuest(HGSMIINSTANCE *pIns)
463{
464 if (pIns->pfnNotifyGuest)
465 pIns->pfnNotifyGuest(pIns->pvNotifyGuest);
466}
467
468void HGSMISetHostGuestFlags(HGSMIINSTANCE *pIns, uint32_t flags)
469{
470 AssertPtrReturnVoid(pIns->pHGFlags);
471 ASMAtomicOrU32(&pIns->pHGFlags->u32HostFlags, flags);
472}
473
474uint32_t HGSMIGetHostGuestFlags(HGSMIINSTANCE *pIns)
475{
476 return pIns->pHGFlags ? ASMAtomicReadU32(&pIns->pHGFlags->u32HostFlags) : 0;
477}
478
479void HGSMIClearHostGuestFlags(HGSMIINSTANCE *pIns, uint32_t flags)
480{
481 AssertPtrReturnVoid(pIns->pHGFlags);
482 ASMAtomicAndU32(&pIns->pHGFlags->u32HostFlags, ~flags);
483}
484
485
486/*
487 * The host heap.
488 *
489 * Uses the RTHeap implementation.
490 *
491 */
492
493static int hgsmiHostHeapLock(HGSMIINSTANCE *pIns)
494{
495 int rc = RTCritSectEnter(&pIns->hostHeapCritSect);
496 AssertRC(rc);
497 return rc;
498}
499
500static void hgsmiHostHeapUnlock(HGSMIINSTANCE *pIns)
501{
502 int rc = RTCritSectLeave(&pIns->hostHeapCritSect);
503 AssertRC(rc);
504}
505
506static HGSMIOFFSET hgsmiHostHeapOffset(HGSMIHOSTHEAP *pHeap)
507{
508 return pHeap->area.offBase;
509}
510
511static HGSMISIZE hgsmiHostHeapSize(HGSMIHOSTHEAP *pHeap)
512{
513 return pHeap->area.cbArea;
514}
515
516static void RT_UNTRUSTED_VOLATILE_GUEST *hgsmiHostHeapBufferAlloc(HGSMIHOSTHEAP *pHeap, HGSMISIZE cbBuffer)
517{
518 void RT_UNTRUSTED_VOLATILE_GUEST *pvBuf = NULL;
519
520 if (pHeap->u32HeapType == HGSMI_HEAP_TYPE_MA)
521 pvBuf = HGSMIMAAlloc(&pHeap->u.ma, cbBuffer);
522 else if (pHeap->u32HeapType == HGSMI_HEAP_TYPE_POINTER)
523 pvBuf = RTHeapSimpleAlloc(pHeap->u.legacy.u.hPtr, cbBuffer, 0);
524 else if (pHeap->u32HeapType == HGSMI_HEAP_TYPE_OFFSET)
525 pvBuf = RTHeapOffsetAlloc(pHeap->u.legacy.u.hOff, cbBuffer, 0);
526 if (pvBuf)
527 ASMAtomicIncS32(&pHeap->cRefs);
528
529 return pvBuf;
530}
531
532static void hgsmiHostHeapBufferFree(HGSMIHOSTHEAP *pHeap, void RT_UNTRUSTED_VOLATILE_GUEST *pvBuf)
533{
534 if (pHeap->u32HeapType == HGSMI_HEAP_TYPE_MA)
535 HGSMIMAFree(&pHeap->u.ma, pvBuf);
536 else if (pHeap->u32HeapType == HGSMI_HEAP_TYPE_POINTER)
537 RTHeapSimpleFree(pHeap->u.legacy.u.hPtr, (void *)pvBuf);
538 else if (pHeap->u32HeapType == HGSMI_HEAP_TYPE_OFFSET)
539 RTHeapOffsetFree(pHeap->u.legacy.u.hOff, (void *)pvBuf);
540 ASMAtomicDecS32(&pHeap->cRefs);
541}
542
543static void RT_UNTRUSTED_VOLATILE_GUEST *hgsmiHostHeapDataAlloc(HGSMIHOSTHEAP *pHeap, HGSMISIZE cbData,
544 uint8_t u8Channel, uint16_t u16ChannelInfo)
545{
546 HGSMISIZE cbAlloc = HGSMIBufferRequiredSize(cbData);
547 HGSMIBUFFERHEADER *pHeader = (HGSMIBUFFERHEADER *)hgsmiHostHeapBufferAlloc(pHeap, cbAlloc);
548 if (!pHeader)
549 return NULL;
550
551 HGSMIBufferInitializeSingle(&pHeap->area, pHeader, cbAlloc, u8Channel, u16ChannelInfo);
552
553 return HGSMIBufferDataFromPtr(pHeader);
554}
555
556static void hgsmiHostHeapDataFree(HGSMIHOSTHEAP *pHeap, void RT_UNTRUSTED_VOLATILE_GUEST *pvData)
557{
558 if ( pvData
559 && pHeap->u32HeapType != HGSMI_HEAP_TYPE_NULL)
560 {
561 HGSMIBUFFERHEADER RT_UNTRUSTED_VOLATILE_GUEST *pHeader = HGSMIBufferHeaderFromData(pvData);
562 hgsmiHostHeapBufferFree(pHeap, pHeader);
563 }
564}
565
566/* Needed for heap relocation: offset of the heap handle relative to the start of heap area. */
567static HGSMIOFFSET hgsmiHostHeapHandleLocationOffset(HGSMIHOSTHEAP *pHeap)
568{
569 HGSMIOFFSET offHeapHandle;
570 if (pHeap->u32HeapType == HGSMI_HEAP_TYPE_POINTER)
571 offHeapHandle = (HGSMIOFFSET)((uintptr_t)pHeap->u.legacy.u.hPtr - (uintptr_t)pHeap->area.pu8Base);
572 else if (pHeap->u32HeapType == HGSMI_HEAP_TYPE_OFFSET)
573 offHeapHandle = (HGSMIOFFSET)((uintptr_t)pHeap->u.legacy.u.hOff - (uintptr_t)pHeap->area.pu8Base);
574 else
575 offHeapHandle = HGSMIOFFSET_VOID;
576 return offHeapHandle;
577}
578
579static int hgsmiHostHeapRelocate(HGSMIHOSTHEAP *pHeap,
580 uint32_t u32HeapType,
581 void *pvBase,
582 uint32_t offHeapHandle,
583 uintptr_t offDelta,
584 HGSMISIZE cbArea,
585 HGSMIOFFSET offBase)
586{
587 int rc = HGSMIAreaInitialize(&pHeap->area, pvBase, cbArea, offBase);
588 if (RT_SUCCESS(rc))
589 {
590 if (u32HeapType == HGSMI_HEAP_TYPE_OFFSET)
591 pHeap->u.legacy.u.hOff = (RTHEAPOFFSET)((uint8_t *)pvBase + offHeapHandle);
592 else if (u32HeapType == HGSMI_HEAP_TYPE_POINTER)
593 {
594 pHeap->u.legacy.u.hPtr = (RTHEAPSIMPLE)((uint8_t *)pvBase + offHeapHandle);
595 rc = RTHeapSimpleRelocate(pHeap->u.legacy.u.hPtr, offDelta); AssertRC(rc);
596 }
597 else
598 {
599 /* HGSMI_HEAP_TYPE_MA does not need the relocation. */
600 rc = VERR_NOT_SUPPORTED;
601 }
602
603 if (RT_SUCCESS(rc))
604 pHeap->u32HeapType = u32HeapType;
605 else
606 HGSMIAreaClear(&pHeap->area);
607 }
608
609 return rc;
610}
611
612static int hgsmiHostHeapRestoreMA(HGSMIHOSTHEAP *pHeap,
613 void *pvBase,
614 HGSMISIZE cbArea,
615 HGSMIOFFSET offBase,
616 uint32_t cBlocks,
617 HGSMIOFFSET *paDescriptors,
618 HGSMISIZE cbMaxBlock,
619 HGSMIENV *pEnv)
620{
621 int rc = HGSMIAreaInitialize(&pHeap->area, pvBase, cbArea, offBase);
622 if (RT_SUCCESS(rc))
623 {
624 rc = HGSMIMAInit(&pHeap->u.ma, &pHeap->area, paDescriptors, cBlocks, cbMaxBlock, pEnv);
625 if (RT_SUCCESS(rc))
626 pHeap->u32HeapType = HGSMI_HEAP_TYPE_MA;
627 else
628 HGSMIAreaClear(&pHeap->area);
629 }
630
631 return rc;
632}
633
634static void hgsmiHostHeapSetupUninitialized(HGSMIHOSTHEAP *pHeap)
635{
636 RT_ZERO(*pHeap);
637 pHeap->u32HeapType = HGSMI_HEAP_TYPE_NULL;
638}
639
640static void hgsmiHostHeapDestroy(HGSMIHOSTHEAP *pHeap)
641{
642 if (pHeap->u32HeapType == HGSMI_HEAP_TYPE_MA)
643 HGSMIMAUninit(&pHeap->u.ma);
644 hgsmiHostHeapSetupUninitialized(pHeap);
645}
646
647static int hgsmiHostFIFOAlloc(HGSMIHOSTFIFOENTRY **ppEntry)
648{
649 HGSMIHOSTFIFOENTRY *pEntry = (HGSMIHOSTFIFOENTRY *)RTMemAllocZ(sizeof(HGSMIHOSTFIFOENTRY));
650 if (pEntry)
651 {
652 pEntry->fl = HGSMI_F_HOST_FIFO_ALLOCATED;
653 *ppEntry = pEntry;
654 return VINF_SUCCESS;
655 }
656 return VERR_NO_MEMORY;
657}
658
659static void hgsmiHostFIFOFree(HGSMIHOSTFIFOENTRY *pEntry)
660{
661 RTMemFree(pEntry);
662}
663
664static int hgsmiHostCommandFreeByEntry (HGSMIHOSTFIFOENTRY *pEntry)
665{
666 LogFlowFunc(("offBuffer 0x%08X\n", pEntry->offBuffer));
667
668 HGSMIINSTANCE *pIns = pEntry->pIns;
669 int rc = hgsmiFIFOLock(pIns);
670 if (RT_SUCCESS(rc))
671 {
672 RTListNodeRemove(&pEntry->nodeEntry);
673 hgsmiFIFOUnlock(pIns);
674
675 void RT_UNTRUSTED_VOLATILE_GUEST *pvData = HGSMIBufferDataFromOffset(&pIns->hostHeap.area, pEntry->offBuffer);
676
677 rc = hgsmiHostHeapLock(pIns);
678 if (RT_SUCCESS(rc))
679 {
680 /* Deallocate the host heap memory. */
681 hgsmiHostHeapDataFree(&pIns->hostHeap, pvData);
682
683 hgsmiHostHeapUnlock(pIns);
684 }
685
686 hgsmiHostFIFOFree(pEntry);
687 }
688
689 LogFlowFunc(("%Rrc\n", rc));
690 return rc;
691}
692
693static int hgsmiHostCommandFree(HGSMIINSTANCE *pIns, void RT_UNTRUSTED_VOLATILE_GUEST *pvData)
694{
695 HGSMIOFFSET offBuffer = HGSMIBufferOffsetFromData(&pIns->hostHeap.area, pvData);
696 HGSMIHOSTFIFOENTRY *pEntry = NULL;
697
698 int rc = hgsmiFIFOLock(pIns);
699 if (RT_SUCCESS(rc))
700 {
701 /* Search the Processed list for the given offBuffer. */
702 HGSMIHOSTFIFOENTRY *pIter;
703 RTListForEach(&pIns->hostFIFOProcessed, pIter, HGSMIHOSTFIFOENTRY, nodeEntry)
704 {
705 Assert(pIter->fl == (HGSMI_F_HOST_FIFO_ALLOCATED | HGSMI_F_HOST_FIFO_PROCESSED));
706
707 if (pIter->offBuffer == offBuffer)
708 {
709 pEntry = pIter;
710 break;
711 }
712 }
713
714 if (pEntry)
715 RTListNodeRemove(&pEntry->nodeEntry);
716 else
717 AssertLogRelMsgFailed(("HGSMI[%s]: the host frees unprocessed FIFO entry: 0x%08X\n",
718 pIns->pszName, offBuffer));
719
720 hgsmiFIFOUnlock(pIns);
721
722 rc = hgsmiHostHeapLock(pIns);
723 if (RT_SUCCESS(rc))
724 {
725 /* Deallocate the host heap memory. */
726 hgsmiHostHeapDataFree(&pIns->hostHeap, pvData);
727
728 hgsmiHostHeapUnlock(pIns);
729 }
730
731 if (pEntry)
732 {
733 /* Deallocate the entry. */
734 hgsmiHostFIFOFree(pEntry);
735 }
736 }
737
738 return rc;
739}
740
741static DECLCALLBACK(void) hgsmiHostCommandFreeCallback(void *pvCallback)
742{
743 /* Guest has processed the command. */
744 HGSMIHOSTFIFOENTRY *pEntry = (HGSMIHOSTFIFOENTRY *)pvCallback;
745
746 Assert(pEntry->fl == (HGSMI_F_HOST_FIFO_ALLOCATED | HGSMI_F_HOST_FIFO_PROCESSED));
747
748 /* This is a simple callback, just signal the event. */
749 hgsmiHostCommandFreeByEntry(pEntry);
750}
751
752static int hgsmiHostCommandWrite(HGSMIINSTANCE *pIns, HGSMIOFFSET offBuffer)
753{
754 AssertPtrReturn(pIns->pHGFlags, VERR_WRONG_ORDER);
755
756 HGSMIHOSTFIFOENTRY *pEntry;
757 int rc = hgsmiHostFIFOAlloc(&pEntry);
758 if (RT_SUCCESS(rc))
759 {
760 /* Initialize the new entry and add it to the FIFO. */
761 pEntry->fl |= HGSMI_F_HOST_FIFO_QUEUED;
762
763 pEntry->pIns = pIns;
764 pEntry->offBuffer = offBuffer;
765
766 rc = hgsmiFIFOLock(pIns);
767 if (RT_SUCCESS(rc))
768 {
769 ASMAtomicOrU32(&pIns->pHGFlags->u32HostFlags, HGSMIHOSTFLAGS_COMMANDS_PENDING);
770 RTListAppend(&pIns->hostFIFO, &pEntry->nodeEntry);
771
772 hgsmiFIFOUnlock(pIns);
773 }
774 else
775 hgsmiHostFIFOFree(pEntry);
776 }
777
778 return rc;
779}
780
781
782/**
783 * Append the shared memory block to the FIFO, inform the guest.
784 *
785 * @param pIns Pointer to HGSMI instance.
786 * @param pvData The shared memory block data pointer.
787 * @param fDoIrq Whether the guest interrupt should be generated, i.e. if the command is not
788 * urgent (e.g. some guest command completion notification that does not require
789 * post-processing) the command could be submitted without raising an irq.
790 * @thread EMT
791 */
792static int hgsmiHostCommandSubmit(HGSMIINSTANCE *pIns, void RT_UNTRUSTED_VOLATILE_GUEST *pvData, bool fDoIrq)
793{
794 /* Append the command to FIFO. */
795 HGSMIOFFSET offBuffer = HGSMIBufferOffsetFromData(&pIns->hostHeap.area, pvData);
796 int rc = hgsmiHostCommandWrite(pIns, offBuffer);
797 if (RT_SUCCESS(rc))
798 {
799 if (fDoIrq)
800 {
801 /* Now guest can read the FIFO, the notification is informational. */
802 hgsmiNotifyGuest(pIns);
803 }
804 }
805
806 return rc;
807}
808
809/**
810 * Allocate a shared memory buffer. The host can write command/data to the memory.
811 * The allocated buffer contains the 'header', 'data' and the 'tail', but *ppvData
812 * will point to the 'data'.
813 *
814 * @return VBox status code. Pointer to the payload data in *ppvData.
815 * @param pIns HGSMI instance,
816 * @param ppvData Where to store the allocated memory pointer to data.
817 * @param cbData How many bytes of data to allocate.
818 * @param u8Channel HGSMI channel.
819 * @param u16ChannelInfo Command parameter.
820 */
821int HGSMIHostCommandAlloc(HGSMIINSTANCE *pIns, void RT_UNTRUSTED_VOLATILE_GUEST **ppvData, HGSMISIZE cbData,
822 uint8_t u8Channel, uint16_t u16ChannelInfo)
823{
824 LogFlowFunc(("pIns = %p, cbData = %d, u8Channel %d, u16ChannelInfo 0x%04X\n",
825 pIns, cbData, u8Channel, u16ChannelInfo));
826
827 int rc = hgsmiHostHeapLock(pIns);
828 if (RT_SUCCESS(rc))
829 {
830 void RT_UNTRUSTED_VOLATILE_GUEST *pvData = hgsmiHostHeapDataAlloc(&pIns->hostHeap, cbData, u8Channel, u16ChannelInfo);
831 hgsmiHostHeapUnlock(pIns);
832
833 if (pvData)
834 *ppvData = pvData;
835 else
836 {
837 LogRel(("HGSMI[%s]: host heap allocation failed %d bytes\n", pIns->pszName, cbData));
838 rc = VERR_NO_MEMORY;
839 }
840 }
841
842 LogFlowFunc(("%Rrc, pvData = %p\n", rc, *ppvData));
843 return rc;
844}
845
846/**
847 * Convenience function that allows posting the host command asynchronously
848 * and make it freed on completion.
849 * The caller does not get notified in any way on command completion,
850 * on successful return the pvData buffer can not be used after being passed to this function.
851 *
852 * @param pIns HGSMI instance,
853 * @param pvData The pointer returned by 'HGSMIHostCommandAlloc'.
854 * @param fDoIrq Specifies whether the guest interrupt should be generated.
855 * In case the command is not urgent (e.g. some guest command
856 * completion notification that does not require post-processing)
857 * the command could be posted without raising an irq.
858 */
859int HGSMIHostCommandSubmitAndFreeAsynch(PHGSMIINSTANCE pIns, void RT_UNTRUSTED_VOLATILE_GUEST *pvData, bool fDoIrq)
860{
861 LogFlowFunc(("pIns = %p, pvData = %p, fDoIrq = %d\n", pIns, pvData, fDoIrq));
862
863 int rc;
864 if (HGSMIAreaContainsPointer(&pIns->hostHeap.area, pvData))
865 rc = hgsmiHostCommandSubmit(pIns, pvData, fDoIrq);
866 else
867 {
868 AssertLogRelMsgFailed(("HGSMI[%s]: host submits invalid command %p/%p\n",
869 pIns->pszName, pvData, pIns->hostHeap.area.pu8Base));
870 rc = VERR_INVALID_POINTER;
871 }
872
873 LogFlowFunc(("rc = %Rrc\n", rc));
874 return rc;
875}
876
877/**
878 * Free the shared memory block.
879 *
880 * @param pIns Pointer to HGSMI instance,
881 * @param pvData The pointer returned by 'HGSMIHostCommandAlloc'.
882 */
883int HGSMIHostCommandFree(HGSMIINSTANCE *pIns, void RT_UNTRUSTED_VOLATILE_GUEST *pvData)
884{
885 LogFlowFunc(("pIns = %p, pvData = %p\n", pIns, pvData));
886
887 int rc;
888 if (HGSMIAreaContainsPointer(&pIns->hostHeap.area, pvData))
889 rc = hgsmiHostCommandFree(pIns, pvData);
890 else
891 {
892 AssertLogRelMsgFailed(("HGSMI[%s]: the host frees invalid FIFO entry %p/%p\n",
893 pIns->pszName, pvData, pIns->hostHeap.area.pu8Base));
894 rc = VERR_INVALID_POINTER;
895 }
896
897 LogFlowFunc(("rc = %Rrc\n", rc));
898 return rc;
899}
900
901static DECLCALLBACK(void *) hgsmiEnvAlloc(void *pvEnv, HGSMISIZE cb)
902{
903 NOREF(pvEnv);
904 return RTMemAlloc(cb);
905}
906
907static DECLCALLBACK(void) hgsmiEnvFree(void *pvEnv, void *pv)
908{
909 NOREF(pvEnv);
910 RTMemFree(pv);
911}
912
913static HGSMIENV g_hgsmiEnv =
914{
915 NULL,
916 hgsmiEnvAlloc,
917 hgsmiEnvFree
918};
919
920int HGSMIHostHeapSetup(PHGSMIINSTANCE pIns, HGSMIOFFSET RT_UNTRUSTED_GUEST offHeap, HGSMISIZE RT_UNTRUSTED_GUEST cbHeap)
921{
922 LogFlowFunc(("pIns %p, offHeap 0x%08X, cbHeap = 0x%08X\n", pIns, offHeap, cbHeap));
923
924 /*
925 * Validate input.
926 */
927 AssertPtrReturn(pIns, VERR_INVALID_PARAMETER);
928
929 ASSERT_GUEST_LOGREL_MSG_RETURN( offHeap < pIns->area.cbArea
930 && cbHeap <= pIns->area.cbArea
931 && offHeap <= pIns->area.cbArea - cbHeap,
932 ("Heap: %#x LB %#x; Area: %#x LB %#x\n", offHeap, cbHeap, pIns->area.offBase, pIns->area.cbArea),
933 VERR_INVALID_PARAMETER);
934 RT_UNTRUSTED_VALIDATED_FENCE();
935
936 /*
937 * Lock the heap and do the job.
938 */
939 int rc = hgsmiHostHeapLock(pIns);
940 AssertRCReturn(rc, rc);
941
942 /* It is possible to change the heap only if there is no pending allocations. */
943 ASSERT_GUEST_LOGREL_MSG_STMT_RETURN(pIns->hostHeap.cRefs == 0,
944 ("HGSMI[%s]: host heap setup ignored. %d allocated.\n", pIns->pszName, pIns->hostHeap.cRefs),
945 hgsmiHostHeapUnlock(pIns),
946 VERR_ACCESS_DENIED);
947 rc = HGSMIAreaInitialize(&pIns->hostHeap.area, pIns->area.pu8Base + offHeap, cbHeap, offHeap);
948 if (RT_SUCCESS(rc))
949 {
950 rc = HGSMIMAInit(&pIns->hostHeap.u.ma, &pIns->hostHeap.area, NULL, 0, 0, &g_hgsmiEnv);
951 if (RT_SUCCESS(rc))
952 pIns->hostHeap.u32HeapType = HGSMI_HEAP_TYPE_MA;
953 else
954 HGSMIAreaClear(&pIns->hostHeap.area);
955 }
956
957 hgsmiHostHeapUnlock(pIns);
958
959 LogFlowFunc(("rc = %Rrc\n", rc));
960 return rc;
961}
962
963static int hgsmiHostSaveFifoLocked(PCPDMDEVHLPR3 pHlp, RTLISTANCHOR *pList, PSSMHANDLE pSSM)
964{
965 VBOXHGSMI_SAVE_FIFOSTART(pSSM);
966
967 HGSMIHOSTFIFOENTRY *pIter;
968
969 uint32_t cEntries = 0;
970 RTListForEach(pList, pIter, HGSMIHOSTFIFOENTRY, nodeEntry)
971 {
972 ++cEntries;
973 }
974
975 int rc = pHlp->pfnSSMPutU32(pSSM, cEntries);
976 if (RT_SUCCESS(rc))
977 {
978 RTListForEach(pList, pIter, HGSMIHOSTFIFOENTRY, nodeEntry)
979 {
980 pHlp->pfnSSMPutU32(pSSM, pIter->fl);
981 rc = pHlp->pfnSSMPutU32(pSSM, pIter->offBuffer);
982 if (RT_FAILURE(rc))
983 break;
984 }
985 }
986
987 VBOXHGSMI_SAVE_FIFOSTOP(pSSM);
988
989 return rc;
990}
991
992static int hgsmiHostSaveGuestCmdCompletedFifoLocked(PCPDMDEVHLPR3 pHlp, RTLISTANCHOR *pList, PSSMHANDLE pSSM)
993{
994 VBOXHGSMI_SAVE_FIFOSTART(pSSM);
995
996 HGSMIGUESTCOMPLENTRY *pIter;
997
998 uint32_t cEntries = 0;
999 RTListForEach(pList, pIter, HGSMIGUESTCOMPLENTRY, nodeEntry)
1000 {
1001 ++cEntries;
1002 }
1003 int rc = pHlp->pfnSSMPutU32(pSSM, cEntries);
1004 if (RT_SUCCESS(rc))
1005 {
1006 RTListForEach(pList, pIter, HGSMIGUESTCOMPLENTRY, nodeEntry)
1007 {
1008 rc = pHlp->pfnSSMPutU32(pSSM, pIter->offBuffer);
1009 if (RT_FAILURE(rc))
1010 break;
1011 }
1012 }
1013
1014 VBOXHGSMI_SAVE_FIFOSTOP(pSSM);
1015
1016 return rc;
1017}
1018
1019static int hgsmiHostLoadFifoEntryLocked(PCPDMDEVHLPR3 pHlp, PHGSMIINSTANCE pIns, HGSMIHOSTFIFOENTRY **ppEntry, PSSMHANDLE pSSM)
1020{
1021 HGSMIHOSTFIFOENTRY *pEntry;
1022 int rc = hgsmiHostFIFOAlloc(&pEntry); AssertRC(rc);
1023 if (RT_SUCCESS(rc))
1024 {
1025 uint32_t u32;
1026 pEntry->pIns = pIns;
1027 rc = pHlp->pfnSSMGetU32(pSSM, &u32); AssertRC(rc);
1028 pEntry->fl = u32;
1029 rc = pHlp->pfnSSMGetU32(pSSM, &pEntry->offBuffer); AssertRC(rc);
1030 if (RT_SUCCESS(rc))
1031 *ppEntry = pEntry;
1032 else
1033 hgsmiHostFIFOFree(pEntry);
1034 }
1035
1036 return rc;
1037}
1038
1039static int hgsmiHostLoadFifoLocked(PCPDMDEVHLPR3 pHlp, PHGSMIINSTANCE pIns, RTLISTANCHOR *pList, PSSMHANDLE pSSM)
1040{
1041 VBOXHGSMI_LOAD_FIFOSTART(pSSM);
1042
1043 uint32_t cEntries = 0;
1044 int rc = pHlp->pfnSSMGetU32(pSSM, &cEntries);
1045 if (RT_SUCCESS(rc) && cEntries)
1046 {
1047 uint32_t i;
1048 for (i = 0; i < cEntries; ++i)
1049 {
1050 HGSMIHOSTFIFOENTRY *pEntry = NULL;
1051 rc = hgsmiHostLoadFifoEntryLocked(pHlp, pIns, &pEntry, pSSM);
1052 AssertRCBreak(rc);
1053
1054 RTListAppend(pList, &pEntry->nodeEntry);
1055 }
1056 }
1057
1058 VBOXHGSMI_LOAD_FIFOSTOP(pSSM);
1059
1060 return rc;
1061}
1062
1063static int hgsmiHostLoadGuestCmdCompletedFifoEntryLocked(PCPDMDEVHLPR3 pHlp, PHGSMIINSTANCE pIns,
1064 HGSMIGUESTCOMPLENTRY **ppEntry, PSSMHANDLE pSSM)
1065{
1066 HGSMIGUESTCOMPLENTRY *pEntry;
1067 int rc = hgsmiGuestCompletionFIFOAlloc(pIns, &pEntry); AssertRC(rc);
1068 if (RT_SUCCESS (rc))
1069 {
1070 rc = pHlp->pfnSSMGetU32(pSSM, &pEntry->offBuffer); AssertRC(rc);
1071 if (RT_SUCCESS(rc))
1072 *ppEntry = pEntry;
1073 else
1074 hgsmiGuestCompletionFIFOFree(pIns, pEntry);
1075 }
1076 return rc;
1077}
1078
1079static int hgsmiHostLoadGuestCmdCompletedFifoLocked(PCPDMDEVHLPR3 pHlp, PHGSMIINSTANCE pIns, RTLISTANCHOR *pList,
1080 PSSMHANDLE pSSM, uint32_t u32Version)
1081{
1082 VBOXHGSMI_LOAD_FIFOSTART(pSSM);
1083
1084 uint32_t i;
1085
1086 uint32_t cEntries = 0;
1087 int rc = pHlp->pfnSSMGetU32(pSSM, &cEntries);
1088 if (RT_SUCCESS(rc) && cEntries)
1089 {
1090 if (u32Version > VGA_SAVEDSTATE_VERSION_INV_GCMDFIFO)
1091 {
1092 for (i = 0; i < cEntries; ++i)
1093 {
1094 HGSMIGUESTCOMPLENTRY *pEntry = NULL;
1095 rc = hgsmiHostLoadGuestCmdCompletedFifoEntryLocked(pHlp, pIns, &pEntry, pSSM);
1096 AssertRCBreak(rc);
1097
1098 RTListAppend(pList, &pEntry->nodeEntry);
1099 }
1100 }
1101 else
1102 {
1103 LogRel(("WARNING: the current saved state version has some 3D support data missing, "
1104 "which may lead to some guest applications function improperly"));
1105
1106 /* Just read out all invalid data and discard it. */
1107 for (i = 0; i < cEntries; ++i)
1108 {
1109 HGSMIHOSTFIFOENTRY *pEntry = NULL;
1110 rc = hgsmiHostLoadFifoEntryLocked(pHlp, pIns, &pEntry, pSSM);
1111 AssertRCBreak(rc);
1112
1113 hgsmiHostFIFOFree(pEntry);
1114 }
1115 }
1116 }
1117
1118 VBOXHGSMI_LOAD_FIFOSTOP(pSSM);
1119
1120 return rc;
1121}
1122
1123static int hgsmiHostSaveMA(PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM, HGSMIMADATA *pMA)
1124{
1125 int rc = pHlp->pfnSSMPutU32(pSSM, pMA->cBlocks);
1126 if (RT_SUCCESS(rc))
1127 {
1128 HGSMIMABLOCK *pIter;
1129 RTListForEach(&pMA->listBlocks, pIter, HGSMIMABLOCK, nodeBlock)
1130 {
1131 pHlp->pfnSSMPutU32(pSSM, pIter->descriptor);
1132 }
1133
1134 rc = pHlp->pfnSSMPutU32(pSSM, pMA->cbMaxBlock);
1135 }
1136
1137 return rc;
1138}
1139
1140static int hgsmiHostLoadMA(PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM, uint32_t *pcBlocks,
1141 HGSMIOFFSET **ppaDescriptors, HGSMISIZE *pcbMaxBlock)
1142{
1143 int rc = pHlp->pfnSSMGetU32(pSSM, pcBlocks);
1144 if (RT_SUCCESS(rc))
1145 {
1146 HGSMIOFFSET *paDescriptors = NULL;
1147 if (*pcBlocks > 0)
1148 {
1149 paDescriptors = (HGSMIOFFSET *)RTMemAlloc(*pcBlocks * sizeof(HGSMIOFFSET));
1150 if (paDescriptors)
1151 {
1152 uint32_t i;
1153 for (i = 0; i < *pcBlocks; ++i)
1154 pHlp->pfnSSMGetU32(pSSM, &paDescriptors[i]);
1155 }
1156 else
1157 rc = VERR_NO_MEMORY;
1158 }
1159
1160 if (RT_SUCCESS(rc))
1161 rc = pHlp->pfnSSMGetU32(pSSM, pcbMaxBlock);
1162 if (RT_SUCCESS(rc))
1163 *ppaDescriptors = paDescriptors;
1164 else
1165 RTMemFree(paDescriptors);
1166 }
1167
1168 return rc;
1169}
1170
1171int HGSMIHostSaveStateExec(PCPDMDEVHLPR3 pHlp, PHGSMIINSTANCE pIns, PSSMHANDLE pSSM)
1172{
1173 VBOXHGSMI_SAVE_START(pSSM);
1174
1175 int rc;
1176
1177 pHlp->pfnSSMPutU32(pSSM, pIns->hostHeap.u32HeapType);
1178
1179 HGSMIOFFSET off = pIns->pHGFlags ? HGSMIPointerToOffset(&pIns->area, (const HGSMIBUFFERHEADER *)pIns->pHGFlags)
1180 : HGSMIOFFSET_VOID;
1181 pHlp->pfnSSMPutU32(pSSM, off);
1182
1183 off = pIns->hostHeap.u32HeapType == HGSMI_HEAP_TYPE_MA ? 0 : hgsmiHostHeapHandleLocationOffset(&pIns->hostHeap);
1184 rc = pHlp->pfnSSMPutU32 (pSSM, off);
1185 if (off != HGSMIOFFSET_VOID)
1186 {
1187 pHlp->pfnSSMPutU32(pSSM, hgsmiHostHeapOffset(&pIns->hostHeap));
1188 pHlp->pfnSSMPutU32(pSSM, hgsmiHostHeapSize(&pIns->hostHeap));
1189 /* need save mem pointer to calculate offset on restore */
1190 pHlp->pfnSSMPutU64(pSSM, (uint64_t)(uintptr_t)pIns->area.pu8Base);
1191 rc = hgsmiFIFOLock (pIns);
1192 if (RT_SUCCESS(rc))
1193 {
1194 rc = hgsmiHostSaveFifoLocked(pHlp, &pIns->hostFIFO, pSSM); AssertRC(rc);
1195 rc = hgsmiHostSaveFifoLocked(pHlp, &pIns->hostFIFORead, pSSM); AssertRC(rc);
1196 rc = hgsmiHostSaveFifoLocked(pHlp, &pIns->hostFIFOProcessed, pSSM); AssertRC(rc);
1197#ifdef VBOX_WITH_WDDM
1198 rc = hgsmiHostSaveGuestCmdCompletedFifoLocked(pHlp, &pIns->guestCmdCompleted, pSSM); AssertRC(rc);
1199#endif
1200
1201 hgsmiFIFOUnlock(pIns);
1202 }
1203
1204 if (RT_SUCCESS(rc))
1205 if (pIns->hostHeap.u32HeapType == HGSMI_HEAP_TYPE_MA)
1206 rc = hgsmiHostSaveMA(pHlp, pSSM, &pIns->hostHeap.u.ma);
1207 }
1208
1209 VBOXHGSMI_SAVE_STOP(pSSM);
1210
1211 return rc;
1212}
1213
1214int HGSMIHostLoadStateExec(PCPDMDEVHLPR3 pHlp, PHGSMIINSTANCE pIns, PSSMHANDLE pSSM, uint32_t u32Version)
1215{
1216 if (u32Version < VGA_SAVEDSTATE_VERSION_HGSMI)
1217 return VINF_SUCCESS;
1218
1219 VBOXHGSMI_LOAD_START(pSSM);
1220
1221 int rc;
1222 uint32_t u32HeapType = HGSMI_HEAP_TYPE_NULL;
1223 if (u32Version >= VGA_SAVEDSTATE_VERSION_HGSMIMA)
1224 {
1225 rc = pHlp->pfnSSMGetU32(pSSM, &u32HeapType);
1226 AssertRCReturn(rc, rc);
1227 }
1228
1229 HGSMIOFFSET off;
1230 rc = pHlp->pfnSSMGetU32(pSSM, &off);
1231 AssertLogRelRCReturn(rc, rc);
1232 pIns->pHGFlags = off != HGSMIOFFSET_VOID ? (HGSMIHOSTFLAGS *)HGSMIOffsetToPointer(&pIns->area, off) : NULL;
1233
1234 rc = pHlp->pfnSSMGetU32(pSSM, &off);
1235 AssertLogRelRCReturn(rc, rc);
1236 if (off != HGSMIOFFSET_VOID)
1237 {
1238 /* There is a saved heap. */
1239 if (u32HeapType == HGSMI_HEAP_TYPE_NULL)
1240 u32HeapType = u32Version > VGA_SAVEDSTATE_VERSION_HOST_HEAP
1241 ? HGSMI_HEAP_TYPE_OFFSET : HGSMI_HEAP_TYPE_POINTER;
1242
1243 HGSMIOFFSET offHeap;
1244 pHlp->pfnSSMGetU32(pSSM, &offHeap);
1245 uint32_t cbHeap;
1246 pHlp->pfnSSMGetU32(pSSM, &cbHeap);
1247 uint64_t oldMem;
1248 rc = pHlp->pfnSSMGetU64(pSSM, &oldMem);
1249 AssertLogRelRCReturn(rc, rc);
1250
1251 if (RT_SUCCESS(rc))
1252 {
1253 rc = hgsmiFIFOLock(pIns);
1254 if (RT_SUCCESS(rc))
1255 {
1256 rc = hgsmiHostLoadFifoLocked(pHlp, pIns, &pIns->hostFIFO, pSSM);
1257 if (RT_SUCCESS(rc))
1258 rc = hgsmiHostLoadFifoLocked(pHlp, pIns, &pIns->hostFIFORead, pSSM);
1259 if (RT_SUCCESS(rc))
1260 rc = hgsmiHostLoadFifoLocked(pHlp, pIns, &pIns->hostFIFOProcessed, pSSM);
1261#ifdef VBOX_WITH_WDDM
1262 if (RT_SUCCESS(rc) && u32Version > VGA_SAVEDSTATE_VERSION_PRE_WDDM)
1263 rc = hgsmiHostLoadGuestCmdCompletedFifoLocked(pHlp, pIns, &pIns->guestCmdCompleted, pSSM, u32Version);
1264#endif
1265
1266 hgsmiFIFOUnlock(pIns);
1267 }
1268 }
1269
1270 if (RT_SUCCESS(rc))
1271 {
1272 if (u32HeapType == HGSMI_HEAP_TYPE_MA)
1273 {
1274 uint32_t cBlocks = 0;
1275 HGSMISIZE cbMaxBlock = 0;
1276 HGSMIOFFSET *paDescriptors = NULL;
1277 rc = hgsmiHostLoadMA(pHlp, pSSM, &cBlocks, &paDescriptors, &cbMaxBlock);
1278 if (RT_SUCCESS(rc))
1279 {
1280 rc = hgsmiHostHeapRestoreMA(&pIns->hostHeap,
1281 pIns->area.pu8Base+offHeap,
1282 cbHeap,
1283 offHeap,
1284 cBlocks,
1285 paDescriptors,
1286 cbMaxBlock,
1287 &g_hgsmiEnv);
1288
1289 RTMemFree(paDescriptors);
1290 }
1291 }
1292 else if ( u32HeapType == HGSMI_HEAP_TYPE_OFFSET
1293 || u32HeapType == HGSMI_HEAP_TYPE_POINTER)
1294 {
1295 rc = hgsmiHostHeapLock(pIns);
1296 if (RT_SUCCESS(rc))
1297 {
1298 Assert(!pIns->hostHeap.cRefs);
1299 pIns->hostHeap.cRefs = 0;
1300
1301 rc = hgsmiHostHeapRelocate(&pIns->hostHeap,
1302 u32HeapType,
1303 pIns->area.pu8Base+offHeap,
1304 off,
1305 uintptr_t(pIns->area.pu8Base) - uintptr_t(oldMem),
1306 cbHeap,
1307 offHeap);
1308
1309 hgsmiHostHeapUnlock(pIns);
1310 }
1311 }
1312 }
1313 }
1314
1315 VBOXHGSMI_LOAD_STOP(pSSM);
1316
1317 return rc;
1318}
1319
1320/*
1321 * Channels management.
1322 */
1323
1324/* Register a new HGSMI channel by a predefined index.
1325 */
1326int HGSMIHostChannelRegister(PHGSMIINSTANCE pIns, uint8_t u8Channel,
1327 PFNHGSMICHANNELHANDLER pfnChannelHandler, void *pvChannelHandler)
1328{
1329 LogFlowFunc(("pIns %p, u8Channel %x, pfnChannelHandler %p, pvChannelHandler %p\n",
1330 pIns, u8Channel, pfnChannelHandler, pvChannelHandler));
1331
1332 AssertReturn(!HGSMI_IS_DYNAMIC_CHANNEL(u8Channel), VERR_INVALID_PARAMETER);
1333 AssertPtrReturn(pIns, VERR_INVALID_PARAMETER);
1334 AssertPtrReturn(pfnChannelHandler, VERR_INVALID_PARAMETER);
1335
1336 int rc = hgsmiLock(pIns);
1337
1338 if (RT_SUCCESS(rc))
1339 {
1340 rc = HGSMIChannelRegister(&pIns->channelInfo, u8Channel, NULL, pfnChannelHandler, pvChannelHandler);
1341
1342 hgsmiUnlock(pIns);
1343 }
1344
1345 LogFlowFunc(("leave rc = %Rrc\n", rc));
1346 return rc;
1347}
1348
1349#if 0 /* unused */
1350
1351static int hgsmiChannelMapCreate(PHGSMIINSTANCE pIns, const char *pszChannel, uint8_t *pu8Channel)
1352{
1353 RT_NOREF(pIns, pszChannel, pu8Channel);
1354 /** @todo later */
1355 return VERR_NOT_SUPPORTED;
1356}
1357
1358/**
1359 * Register a new HGSMI channel by name.
1360 *
1361 * @note currently unused.
1362 */
1363int HGSMIChannelRegisterName(PHGSMIINSTANCE pIns,
1364 const char *pszChannel,
1365 PFNHGSMICHANNELHANDLER pfnChannelHandler,
1366 void *pvChannelHandler,
1367 uint8_t *pu8Channel)
1368{
1369 LogFlowFunc(("pIns %p, pszChannel %s, pfnChannelHandler %p, pvChannelHandler %p, pu8Channel %p\n",
1370 pIns, pszChannel, pfnChannelHandler, pvChannelHandler, pu8Channel));
1371
1372 AssertPtrReturn(pIns, VERR_INVALID_PARAMETER);
1373 AssertPtrReturn(pszChannel, VERR_INVALID_PARAMETER);
1374 AssertPtrReturn(pu8Channel, VERR_INVALID_PARAMETER);
1375 AssertPtrReturn(pfnChannelHandler, VERR_INVALID_PARAMETER);
1376
1377 int rc;
1378
1379 /* The pointer to the copy will be saved in the channel description. */
1380 char *pszName = RTStrDup (pszChannel);
1381
1382 if (pszName)
1383 {
1384 rc = hgsmiLock (pIns);
1385
1386 if (RT_SUCCESS (rc))
1387 {
1388 rc = hgsmiChannelMapCreate (pIns, pszName, pu8Channel);
1389
1390 if (RT_SUCCESS (rc))
1391 {
1392 rc = HGSMIChannelRegister (&pIns->channelInfo, *pu8Channel, pszName, pfnChannelHandler, pvChannelHandler);
1393 }
1394
1395 hgsmiUnlock (pIns);
1396 }
1397
1398 if (RT_FAILURE (rc))
1399 {
1400 RTStrFree (pszName);
1401 }
1402 }
1403 else
1404 {
1405 rc = VERR_NO_MEMORY;
1406 }
1407
1408 LogFlowFunc(("leave rc = %Rrc\n", rc));
1409
1410 return rc;
1411}
1412#endif
1413
1414void RT_UNTRUSTED_VOLATILE_GUEST *HGSMIOffsetToPointerHost(PHGSMIINSTANCE pIns, HGSMIOFFSET offBuffer)
1415{
1416 const HGSMIAREA *pArea = &pIns->area;
1417 HGSMIOFFSET const offArea = offBuffer - pArea->offBase;
1418 ASSERT_GUEST_MSG_RETURN(offArea < pArea->cbArea,
1419 ("offBuffer=%#x; area %#x LB %#x\n", offBuffer, pArea->offBase, pArea->cbArea),
1420 NULL);
1421 return &pArea->pu8Base[offArea];
1422}
1423
1424
1425HGSMIOFFSET HGSMIPointerToOffsetHost(PHGSMIINSTANCE pIns, const void RT_UNTRUSTED_VOLATILE_GUEST *pv)
1426{
1427 const HGSMIAREA *pArea = &pIns->area;
1428 uintptr_t const offArea = (uintptr_t)pv - (uintptr_t)pArea->pu8Base;
1429 ASSERT_GUEST_MSG_RETURN(offArea < pArea->cbArea,
1430 ("pv=%p; area %#x LB %#x\n", pv, pArea->offBase, pArea->cbArea),
1431 HGSMIOFFSET_VOID);
1432 return pArea->offBase + (HGSMIOFFSET)offArea;
1433}
1434
1435
1436/**
1437 * Checks if @a offBuffer is within the area of this instance.
1438 *
1439 * This is for use in input validations.
1440 *
1441 * @returns true / false.
1442 * @param pIns The instance.
1443 * @param offBuffer The buffer offset to check.
1444 */
1445bool HGSMIIsOffsetValid(PHGSMIINSTANCE pIns, HGSMIOFFSET offBuffer)
1446{
1447 return pIns
1448 && offBuffer - pIns->area.offBase < pIns->area.cbArea;
1449}
1450
1451
1452/**
1453 * Returns the area offset for use in logging and assertion messages.
1454 */
1455HGSMIOFFSET HGSMIGetAreaOffset(PHGSMIINSTANCE pIns)
1456{
1457 return pIns ? pIns->area.offBase : ~(HGSMIOFFSET)0;
1458}
1459
1460
1461/**
1462 * Returns the area size for use in logging and assertion messages.
1463 */
1464HGSMIOFFSET HGSMIGetAreaSize(PHGSMIINSTANCE pIns)
1465{
1466 return pIns ? pIns->area.cbArea : 0;
1467}
1468
1469
1470void *HGSMIContext(PHGSMIINSTANCE pIns)
1471{
1472 uint8_t *p = (uint8_t *)pIns;
1473 return p + sizeof(HGSMIINSTANCE);
1474}
1475
1476/* The guest submitted a buffer. */
1477static DECLCALLBACK(int) hgsmiChannelHandler(void *pvHandler, uint16_t u16ChannelInfo,
1478 RT_UNTRUSTED_VOLATILE_GUEST void *pvBuffer, HGSMISIZE cbBuffer)
1479{
1480 int rc = VINF_SUCCESS;
1481
1482 LogFlowFunc(("pvHandler %p, u16ChannelInfo %d, pvBuffer %p, cbBuffer %u\n",
1483 pvHandler, u16ChannelInfo, pvBuffer, cbBuffer));
1484
1485 PHGSMIINSTANCE pIns = (PHGSMIINSTANCE)pvHandler;
1486
1487 switch (u16ChannelInfo)
1488 {
1489 case HGSMI_CC_HOST_FLAGS_LOCATION:
1490 {
1491 ASSERT_GUEST_RETURN(cbBuffer >= sizeof(HGSMIBUFFERLOCATION), VERR_INVALID_PARAMETER);
1492 HGSMIBUFFERLOCATION RT_UNTRUSTED_VOLATILE_GUEST *pLoc = (HGSMIBUFFERLOCATION RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer;
1493 HGSMIBUFFERLOCATION LocSafe;
1494 LocSafe.cbLocation = pLoc->cbLocation;
1495 LocSafe.offLocation = pLoc->offLocation;
1496 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
1497
1498 ASSERT_GUEST_RETURN(LocSafe.cbLocation == sizeof(HGSMIHOSTFLAGS), VERR_INVALID_PARAMETER);
1499 ASSERT_GUEST_RETURN(LocSafe.offLocation + sizeof(HGSMIHOSTFLAGS) == pIns->area.cbArea, VERR_INVALID_PARAMETER);
1500 RT_UNTRUSTED_VALIDATED_FENCE();
1501
1502 pIns->pHGFlags = (HGSMIHOSTFLAGS RT_UNTRUSTED_VOLATILE_GUEST *)HGSMIOffsetToPointer(&pIns->area, LocSafe.offLocation);
1503 break;
1504 }
1505
1506 default:
1507 Log(("Unsupported HGSMI guest command %d!!!\n",
1508 u16ChannelInfo));
1509 break;
1510 }
1511
1512 return rc;
1513}
1514
1515int HGSMICreate(PHGSMIINSTANCE *ppIns,
1516 PPDMDEVINS pDevIns,
1517 const char *pszName,
1518 HGSMIOFFSET offBase,
1519 uint8_t *pu8MemBase,
1520 HGSMISIZE cbMem,
1521 PFNHGSMINOTIFYGUEST pfnNotifyGuest,
1522 void *pvNotifyGuest,
1523 size_t cbContext)
1524{
1525 LogFlowFunc(("ppIns = %p, pDevIns = %p, pszName = [%s], offBase = 0x%08X, pu8MemBase = %p, cbMem = 0x%08X, "
1526 "pfnNotifyGuest = %p, pvNotifyGuest = %p, cbContext = %d\n",
1527 ppIns,
1528 pDevIns,
1529 pszName,
1530 offBase,
1531 pu8MemBase,
1532 cbMem,
1533 pfnNotifyGuest,
1534 pvNotifyGuest,
1535 cbContext
1536 ));
1537
1538 AssertPtrReturn(ppIns, VERR_INVALID_PARAMETER);
1539 AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
1540 AssertPtrReturn(pu8MemBase, VERR_INVALID_PARAMETER);
1541
1542 int rc;
1543 PHGSMIINSTANCE pIns = (PHGSMIINSTANCE)RTMemAllocZ(sizeof(HGSMIINSTANCE) + cbContext);
1544 if (pIns)
1545 {
1546 rc = HGSMIAreaInitialize(&pIns->area, pu8MemBase, cbMem, offBase);
1547 if (RT_SUCCESS (rc))
1548 rc = RTCritSectInit(&pIns->instanceCritSect);
1549 if (RT_SUCCESS (rc))
1550 rc = RTCritSectInit(&pIns->hostHeapCritSect);
1551 if (RT_SUCCESS (rc))
1552 rc = RTCritSectInit(&pIns->hostFIFOCritSect);
1553 if (RT_SUCCESS (rc))
1554 {
1555 pIns->pDevIns = pDevIns;
1556 pIns->pszName = RT_VALID_PTR(pszName) ? pszName : "";
1557
1558 hgsmiHostHeapSetupUninitialized(&pIns->hostHeap);
1559
1560 pIns->pfnNotifyGuest = pfnNotifyGuest;
1561 pIns->pvNotifyGuest = pvNotifyGuest;
1562
1563 RTListInit(&pIns->hostFIFO);
1564 RTListInit(&pIns->hostFIFORead);
1565 RTListInit(&pIns->hostFIFOProcessed);
1566 RTListInit(&pIns->hostFIFOFree);
1567 RTListInit(&pIns->guestCmdCompleted);
1568
1569 rc = HGSMIHostChannelRegister(pIns, HGSMI_CH_HGSMI, hgsmiChannelHandler, pIns);
1570 }
1571 if (RT_SUCCESS (rc))
1572 *ppIns = pIns;
1573 else
1574 HGSMIDestroy(pIns);
1575 }
1576 else
1577 rc = VERR_NO_MEMORY;
1578
1579 LogFlowFunc(("leave rc = %Rrc, pIns = %p\n", rc, pIns));
1580 return rc;
1581}
1582
1583uint32_t HGSMIReset(PHGSMIINSTANCE pIns)
1584{
1585 uint32_t flags = 0;
1586 if (pIns->pHGFlags)
1587 {
1588 /* treat the abandoned commands as read.. */
1589 while (HGSMIHostRead(pIns) != HGSMIOFFSET_VOID)
1590 {}
1591 flags = pIns->pHGFlags->u32HostFlags;
1592 pIns->pHGFlags->u32HostFlags = 0;
1593 }
1594
1595 /* .. and complete them */
1596 while (hgsmiProcessHostCmdCompletion(pIns, 0, true))
1597 {}
1598
1599#ifdef VBOX_WITH_WDDM
1600 while (hgsmiProcessGuestCmdCompletion(pIns) != HGSMIOFFSET_VOID)
1601 {}
1602#endif
1603
1604 hgsmiHostHeapDestroy(&pIns->hostHeap);
1605
1606 return flags;
1607}
1608
1609void HGSMIDestroy(PHGSMIINSTANCE pIns)
1610{
1611 LogFlowFunc(("pIns = %p\n", pIns));
1612
1613 if (pIns)
1614 {
1615 hgsmiHostHeapDestroy(&pIns->hostHeap);
1616 if (RTCritSectIsInitialized(&pIns->hostHeapCritSect))
1617 RTCritSectDelete(&pIns->hostHeapCritSect);
1618 if (RTCritSectIsInitialized(&pIns->instanceCritSect))
1619 RTCritSectDelete(&pIns->instanceCritSect);
1620 if (RTCritSectIsInitialized(&pIns->hostFIFOCritSect))
1621 RTCritSectDelete(&pIns->hostFIFOCritSect);
1622
1623 memset(pIns, 0, sizeof (HGSMIINSTANCE));
1624 RTMemFree(pIns);
1625 }
1626
1627 LogFlowFunc(("leave\n"));
1628}
1629
1630#ifdef VBOX_WITH_WDDM
1631
1632static int hgsmiGuestCommandComplete(HGSMIINSTANCE *pIns, HGSMIOFFSET offMem)
1633{
1634 HGSMIGUESTCOMPLENTRY *pEntry = NULL;
1635
1636 AssertPtrReturn(pIns->pHGFlags, VERR_WRONG_ORDER);
1637 int rc = hgsmiGuestCompletionFIFOAlloc(pIns, &pEntry);
1638 AssertRC(rc);
1639 if (RT_SUCCESS(rc))
1640 {
1641 pEntry->offBuffer = offMem;
1642
1643 rc = hgsmiFIFOLock(pIns);
1644 AssertRC(rc);
1645 if (RT_SUCCESS(rc))
1646 {
1647 RTListAppend(&pIns->guestCmdCompleted, &pEntry->nodeEntry);
1648 ASMAtomicOrU32(&pIns->pHGFlags->u32HostFlags, HGSMIHOSTFLAGS_GCOMMAND_COMPLETED);
1649
1650 hgsmiFIFOUnlock(pIns);
1651 }
1652 else
1653 hgsmiGuestCompletionFIFOFree(pIns, pEntry);
1654 }
1655
1656 return rc;
1657}
1658
1659int hgsmiCompleteGuestCommand(PHGSMIINSTANCE pIns, HGSMIOFFSET offBuffer, bool fDoIrq)
1660{
1661 int rc = hgsmiGuestCommandComplete(pIns, offBuffer);
1662 if (RT_SUCCESS (rc))
1663 {
1664#ifdef DEBUG_misha
1665 Assert(fDoIrq);
1666#endif
1667 if (fDoIrq)
1668 {
1669 /* Now guest can read the FIFO, the notification is informational. */
1670 hgsmiNotifyGuest (pIns);
1671 }
1672 }
1673 return rc;
1674}
1675
1676int HGSMICompleteGuestCommand(PHGSMIINSTANCE pIns, void RT_UNTRUSTED_VOLATILE_GUEST *pvMem, bool fDoIrq)
1677{
1678 LogFlowFunc(("pIns = %p, pvMem = %p\n", pIns, pvMem));
1679
1680 HGSMIBUFFERHEADER RT_UNTRUSTED_VOLATILE_GUEST *pHeader = HGSMIBufferHeaderFromData(pvMem);
1681 HGSMIOFFSET offBuffer = HGSMIPointerToOffset(&pIns->area, pHeader);
1682 ASSERT_GUEST_RETURN(offBuffer != HGSMIOFFSET_VOID, VERR_INVALID_PARAMETER);
1683
1684 int rc = hgsmiCompleteGuestCommand(pIns, offBuffer, fDoIrq);
1685 AssertRC(rc);
1686
1687 LogFlowFunc(("rc = %Rrc\n", rc));
1688 return rc;
1689}
1690
1691#endif /* VBOX_WITH_WDDM */
1692
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