VirtualBox

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

Last change on this file since 81002 was 80295, checked in by vboxsync, 5 years ago

Graphics/HGSMIHost.h: Avoid including vm.h just for three cases of VM_ASSERT_EMT. bugref:9217

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