VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 8 weeks ago

Copyright year updates by scm.

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