VirtualBox

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

Last change on this file since 71651 was 71651, checked in by vboxsync, 7 years ago

DevVGA,VBoxC,++: Code cleanup in progress. bugref:9094

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