VirtualBox

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

Last change on this file since 96407 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 52.4 KB
Line 
1/* $Id: HGSMIHost.cpp 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * VBox Host Guest Shared Memory Interface (HGSMI), host part.
4 *
5 * Host part:
6 * - virtual hardware IO handlers;
7 * - channel management;
8 * - low level interface for buffer transfer.
9 */
10
11/*
12 * Copyright (C) 2006-2022 Oracle 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 */
292void 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. */
334HGSMIOFFSET 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 */
409void 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 */
423HGSMIOFFSET 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
478void HGSMISetHostGuestFlags(HGSMIINSTANCE *pIns, uint32_t flags)
479{
480 AssertPtrReturnVoid(pIns->pHGFlags);
481 ASMAtomicOrU32(&pIns->pHGFlags->u32HostFlags, flags);
482}
483
484uint32_t HGSMIGetHostGuestFlags(HGSMIINSTANCE *pIns)
485{
486 return pIns->pHGFlags ? ASMAtomicReadU32(&pIns->pHGFlags->u32HostFlags) : 0;
487}
488
489void 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 */
831int 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 */
869int 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 */
893int 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
930int 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
1181int HGSMIHostSaveStateExec(PCPDMDEVHLPR3 pHlp, PHGSMIINSTANCE pIns, PSSMHANDLE pSSM)
1182{
1183 VBOXHGSMI_SAVE_START(pSSM);
1184
1185 int rc;
1186
1187 pHlp->pfnSSMPutU32(pSSM, pIns->hostHeap.u32HeapType);
1188
1189 HGSMIOFFSET off = pIns->pHGFlags ? HGSMIPointerToOffset(&pIns->area, (const HGSMIBUFFERHEADER *)pIns->pHGFlags)
1190 : HGSMIOFFSET_VOID;
1191 pHlp->pfnSSMPutU32(pSSM, off);
1192
1193 off = pIns->hostHeap.u32HeapType == HGSMI_HEAP_TYPE_MA ? 0 : hgsmiHostHeapHandleLocationOffset(&pIns->hostHeap);
1194 rc = pHlp->pfnSSMPutU32 (pSSM, off);
1195 if (off != HGSMIOFFSET_VOID)
1196 {
1197 pHlp->pfnSSMPutU32(pSSM, hgsmiHostHeapOffset(&pIns->hostHeap));
1198 pHlp->pfnSSMPutU32(pSSM, hgsmiHostHeapSize(&pIns->hostHeap));
1199 /* need save mem pointer to calculate offset on restore */
1200 pHlp->pfnSSMPutU64(pSSM, (uint64_t)(uintptr_t)pIns->area.pu8Base);
1201 rc = hgsmiFIFOLock (pIns);
1202 if (RT_SUCCESS(rc))
1203 {
1204 rc = hgsmiHostSaveFifoLocked(pHlp, &pIns->hostFIFO, pSSM); AssertRC(rc);
1205 rc = hgsmiHostSaveFifoLocked(pHlp, &pIns->hostFIFORead, pSSM); AssertRC(rc);
1206 rc = hgsmiHostSaveFifoLocked(pHlp, &pIns->hostFIFOProcessed, pSSM); AssertRC(rc);
1207#ifdef VBOX_WITH_WDDM
1208 rc = hgsmiHostSaveGuestCmdCompletedFifoLocked(pHlp, &pIns->guestCmdCompleted, pSSM); AssertRC(rc);
1209#endif
1210
1211 hgsmiFIFOUnlock(pIns);
1212 }
1213
1214 if (RT_SUCCESS(rc))
1215 if (pIns->hostHeap.u32HeapType == HGSMI_HEAP_TYPE_MA)
1216 rc = hgsmiHostSaveMA(pHlp, pSSM, &pIns->hostHeap.u.ma);
1217 }
1218
1219 VBOXHGSMI_SAVE_STOP(pSSM);
1220
1221 return rc;
1222}
1223
1224int HGSMIHostLoadStateExec(PCPDMDEVHLPR3 pHlp, PHGSMIINSTANCE pIns, PSSMHANDLE pSSM, uint32_t u32Version)
1225{
1226 if (u32Version < VGA_SAVEDSTATE_VERSION_HGSMI)
1227 return VINF_SUCCESS;
1228
1229 VBOXHGSMI_LOAD_START(pSSM);
1230
1231 int rc;
1232 uint32_t u32HeapType = HGSMI_HEAP_TYPE_NULL;
1233 if (u32Version >= VGA_SAVEDSTATE_VERSION_HGSMIMA)
1234 {
1235 rc = pHlp->pfnSSMGetU32(pSSM, &u32HeapType);
1236 AssertRCReturn(rc, rc);
1237 }
1238
1239 HGSMIOFFSET off;
1240 rc = pHlp->pfnSSMGetU32(pSSM, &off);
1241 AssertLogRelRCReturn(rc, rc);
1242 pIns->pHGFlags = off != HGSMIOFFSET_VOID ? (HGSMIHOSTFLAGS *)HGSMIOffsetToPointer(&pIns->area, off) : NULL;
1243
1244 rc = pHlp->pfnSSMGetU32(pSSM, &off);
1245 AssertLogRelRCReturn(rc, rc);
1246 if (off != HGSMIOFFSET_VOID)
1247 {
1248 /* There is a saved heap. */
1249 if (u32HeapType == HGSMI_HEAP_TYPE_NULL)
1250 u32HeapType = u32Version > VGA_SAVEDSTATE_VERSION_HOST_HEAP
1251 ? HGSMI_HEAP_TYPE_OFFSET : HGSMI_HEAP_TYPE_POINTER;
1252
1253 HGSMIOFFSET offHeap;
1254 pHlp->pfnSSMGetU32(pSSM, &offHeap);
1255 uint32_t cbHeap;
1256 pHlp->pfnSSMGetU32(pSSM, &cbHeap);
1257 uint64_t oldMem;
1258 rc = pHlp->pfnSSMGetU64(pSSM, &oldMem);
1259 AssertLogRelRCReturn(rc, rc);
1260
1261 if (RT_SUCCESS(rc))
1262 {
1263 rc = hgsmiFIFOLock(pIns);
1264 if (RT_SUCCESS(rc))
1265 {
1266 rc = hgsmiHostLoadFifoLocked(pHlp, pIns, &pIns->hostFIFO, pSSM);
1267 if (RT_SUCCESS(rc))
1268 rc = hgsmiHostLoadFifoLocked(pHlp, pIns, &pIns->hostFIFORead, pSSM);
1269 if (RT_SUCCESS(rc))
1270 rc = hgsmiHostLoadFifoLocked(pHlp, pIns, &pIns->hostFIFOProcessed, pSSM);
1271#ifdef VBOX_WITH_WDDM
1272 if (RT_SUCCESS(rc) && u32Version > VGA_SAVEDSTATE_VERSION_PRE_WDDM)
1273 rc = hgsmiHostLoadGuestCmdCompletedFifoLocked(pHlp, pIns, &pIns->guestCmdCompleted, pSSM, u32Version);
1274#endif
1275
1276 hgsmiFIFOUnlock(pIns);
1277 }
1278 }
1279
1280 if (RT_SUCCESS(rc))
1281 {
1282 if (u32HeapType == HGSMI_HEAP_TYPE_MA)
1283 {
1284 uint32_t cBlocks = 0;
1285 HGSMISIZE cbMaxBlock = 0;
1286 HGSMIOFFSET *paDescriptors = NULL;
1287 rc = hgsmiHostLoadMA(pHlp, pSSM, &cBlocks, &paDescriptors, &cbMaxBlock);
1288 if (RT_SUCCESS(rc))
1289 {
1290 rc = hgsmiHostHeapRestoreMA(&pIns->hostHeap,
1291 pIns->area.pu8Base+offHeap,
1292 cbHeap,
1293 offHeap,
1294 cBlocks,
1295 paDescriptors,
1296 cbMaxBlock,
1297 &g_hgsmiEnv);
1298
1299 RTMemFree(paDescriptors);
1300 }
1301 }
1302 else if ( u32HeapType == HGSMI_HEAP_TYPE_OFFSET
1303 || u32HeapType == HGSMI_HEAP_TYPE_POINTER)
1304 {
1305 rc = hgsmiHostHeapLock(pIns);
1306 if (RT_SUCCESS(rc))
1307 {
1308 Assert(!pIns->hostHeap.cRefs);
1309 pIns->hostHeap.cRefs = 0;
1310
1311 rc = hgsmiHostHeapRelocate(&pIns->hostHeap,
1312 u32HeapType,
1313 pIns->area.pu8Base+offHeap,
1314 off,
1315 uintptr_t(pIns->area.pu8Base) - uintptr_t(oldMem),
1316 cbHeap,
1317 offHeap);
1318
1319 hgsmiHostHeapUnlock(pIns);
1320 }
1321 }
1322 }
1323 }
1324
1325 VBOXHGSMI_LOAD_STOP(pSSM);
1326
1327 return rc;
1328}
1329
1330/*
1331 * Channels management.
1332 */
1333
1334/* Register a new HGSMI channel by a predefined index.
1335 */
1336int HGSMIHostChannelRegister(PHGSMIINSTANCE pIns, uint8_t u8Channel,
1337 PFNHGSMICHANNELHANDLER pfnChannelHandler, void *pvChannelHandler)
1338{
1339 LogFlowFunc(("pIns %p, u8Channel %x, pfnChannelHandler %p, pvChannelHandler %p\n",
1340 pIns, u8Channel, pfnChannelHandler, pvChannelHandler));
1341
1342 AssertReturn(!HGSMI_IS_DYNAMIC_CHANNEL(u8Channel), VERR_INVALID_PARAMETER);
1343 AssertPtrReturn(pIns, VERR_INVALID_PARAMETER);
1344 AssertPtrReturn(pfnChannelHandler, VERR_INVALID_PARAMETER);
1345
1346 int rc = hgsmiLock(pIns);
1347
1348 if (RT_SUCCESS(rc))
1349 {
1350 rc = HGSMIChannelRegister(&pIns->channelInfo, u8Channel, NULL, pfnChannelHandler, pvChannelHandler);
1351
1352 hgsmiUnlock(pIns);
1353 }
1354
1355 LogFlowFunc(("leave rc = %Rrc\n", rc));
1356 return rc;
1357}
1358
1359#if 0 /* unused */
1360
1361static int hgsmiChannelMapCreate(PHGSMIINSTANCE pIns, const char *pszChannel, uint8_t *pu8Channel)
1362{
1363 RT_NOREF(pIns, pszChannel, pu8Channel);
1364 /** @todo later */
1365 return VERR_NOT_SUPPORTED;
1366}
1367
1368/**
1369 * Register a new HGSMI channel by name.
1370 *
1371 * @note currently unused.
1372 */
1373int HGSMIChannelRegisterName(PHGSMIINSTANCE pIns,
1374 const char *pszChannel,
1375 PFNHGSMICHANNELHANDLER pfnChannelHandler,
1376 void *pvChannelHandler,
1377 uint8_t *pu8Channel)
1378{
1379 LogFlowFunc(("pIns %p, pszChannel %s, pfnChannelHandler %p, pvChannelHandler %p, pu8Channel %p\n",
1380 pIns, pszChannel, pfnChannelHandler, pvChannelHandler, pu8Channel));
1381
1382 AssertPtrReturn(pIns, VERR_INVALID_PARAMETER);
1383 AssertPtrReturn(pszChannel, VERR_INVALID_PARAMETER);
1384 AssertPtrReturn(pu8Channel, VERR_INVALID_PARAMETER);
1385 AssertPtrReturn(pfnChannelHandler, VERR_INVALID_PARAMETER);
1386
1387 int rc;
1388
1389 /* The pointer to the copy will be saved in the channel description. */
1390 char *pszName = RTStrDup (pszChannel);
1391
1392 if (pszName)
1393 {
1394 rc = hgsmiLock (pIns);
1395
1396 if (RT_SUCCESS (rc))
1397 {
1398 rc = hgsmiChannelMapCreate (pIns, pszName, pu8Channel);
1399
1400 if (RT_SUCCESS (rc))
1401 {
1402 rc = HGSMIChannelRegister (&pIns->channelInfo, *pu8Channel, pszName, pfnChannelHandler, pvChannelHandler);
1403 }
1404
1405 hgsmiUnlock (pIns);
1406 }
1407
1408 if (RT_FAILURE (rc))
1409 {
1410 RTStrFree (pszName);
1411 }
1412 }
1413 else
1414 {
1415 rc = VERR_NO_MEMORY;
1416 }
1417
1418 LogFlowFunc(("leave rc = %Rrc\n", rc));
1419
1420 return rc;
1421}
1422#endif
1423
1424void RT_UNTRUSTED_VOLATILE_GUEST *HGSMIOffsetToPointerHost(PHGSMIINSTANCE pIns, HGSMIOFFSET offBuffer)
1425{
1426 const HGSMIAREA *pArea = &pIns->area;
1427 HGSMIOFFSET const offArea = offBuffer - pArea->offBase;
1428 ASSERT_GUEST_MSG_RETURN(offArea < pArea->cbArea,
1429 ("offBuffer=%#x; area %#x LB %#x\n", offBuffer, pArea->offBase, pArea->cbArea),
1430 NULL);
1431 return &pArea->pu8Base[offArea];
1432}
1433
1434
1435HGSMIOFFSET HGSMIPointerToOffsetHost(PHGSMIINSTANCE pIns, const void RT_UNTRUSTED_VOLATILE_GUEST *pv)
1436{
1437 const HGSMIAREA *pArea = &pIns->area;
1438 uintptr_t const offArea = (uintptr_t)pv - (uintptr_t)pArea->pu8Base;
1439 ASSERT_GUEST_MSG_RETURN(offArea < pArea->cbArea,
1440 ("pv=%p; area %#x LB %#x\n", pv, pArea->offBase, pArea->cbArea),
1441 HGSMIOFFSET_VOID);
1442 return pArea->offBase + (HGSMIOFFSET)offArea;
1443}
1444
1445
1446/**
1447 * Checks if @a offBuffer is within the area of this instance.
1448 *
1449 * This is for use in input validations.
1450 *
1451 * @returns true / false.
1452 * @param pIns The instance.
1453 * @param offBuffer The buffer offset to check.
1454 */
1455bool HGSMIIsOffsetValid(PHGSMIINSTANCE pIns, HGSMIOFFSET offBuffer)
1456{
1457 return pIns
1458 && offBuffer - pIns->area.offBase < pIns->area.cbArea;
1459}
1460
1461
1462/**
1463 * Returns the area offset for use in logging and assertion messages.
1464 */
1465HGSMIOFFSET HGSMIGetAreaOffset(PHGSMIINSTANCE pIns)
1466{
1467 return pIns ? pIns->area.offBase : ~(HGSMIOFFSET)0;
1468}
1469
1470
1471/**
1472 * Returns the area size for use in logging and assertion messages.
1473 */
1474HGSMIOFFSET HGSMIGetAreaSize(PHGSMIINSTANCE pIns)
1475{
1476 return pIns ? pIns->area.cbArea : 0;
1477}
1478
1479
1480void *HGSMIContext(PHGSMIINSTANCE pIns)
1481{
1482 uint8_t *p = (uint8_t *)pIns;
1483 return p + sizeof(HGSMIINSTANCE);
1484}
1485
1486/* The guest submitted a buffer. */
1487static DECLCALLBACK(int) hgsmiChannelHandler(void *pvHandler, uint16_t u16ChannelInfo,
1488 RT_UNTRUSTED_VOLATILE_GUEST void *pvBuffer, HGSMISIZE cbBuffer)
1489{
1490 int rc = VINF_SUCCESS;
1491
1492 LogFlowFunc(("pvHandler %p, u16ChannelInfo %d, pvBuffer %p, cbBuffer %u\n",
1493 pvHandler, u16ChannelInfo, pvBuffer, cbBuffer));
1494
1495 PHGSMIINSTANCE pIns = (PHGSMIINSTANCE)pvHandler;
1496
1497 switch (u16ChannelInfo)
1498 {
1499 case HGSMI_CC_HOST_FLAGS_LOCATION:
1500 {
1501 ASSERT_GUEST_RETURN(cbBuffer >= sizeof(HGSMIBUFFERLOCATION), VERR_INVALID_PARAMETER);
1502 HGSMIBUFFERLOCATION RT_UNTRUSTED_VOLATILE_GUEST *pLoc = (HGSMIBUFFERLOCATION RT_UNTRUSTED_VOLATILE_GUEST *)pvBuffer;
1503 HGSMIBUFFERLOCATION LocSafe;
1504 LocSafe.cbLocation = pLoc->cbLocation;
1505 LocSafe.offLocation = pLoc->offLocation;
1506 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
1507
1508 ASSERT_GUEST_RETURN(LocSafe.cbLocation == sizeof(HGSMIHOSTFLAGS), VERR_INVALID_PARAMETER);
1509 ASSERT_GUEST_RETURN(LocSafe.offLocation + sizeof(HGSMIHOSTFLAGS) == pIns->area.cbArea, VERR_INVALID_PARAMETER);
1510 RT_UNTRUSTED_VALIDATED_FENCE();
1511
1512 pIns->pHGFlags = (HGSMIHOSTFLAGS RT_UNTRUSTED_VOLATILE_GUEST *)HGSMIOffsetToPointer(&pIns->area, LocSafe.offLocation);
1513 break;
1514 }
1515
1516 default:
1517 Log(("Unsupported HGSMI guest command %d!!!\n",
1518 u16ChannelInfo));
1519 break;
1520 }
1521
1522 return rc;
1523}
1524
1525int HGSMICreate(PHGSMIINSTANCE *ppIns,
1526 PPDMDEVINS pDevIns,
1527 const char *pszName,
1528 HGSMIOFFSET offBase,
1529 uint8_t *pu8MemBase,
1530 HGSMISIZE cbMem,
1531 PFNHGSMINOTIFYGUEST pfnNotifyGuest,
1532 void *pvNotifyGuest,
1533 size_t cbContext)
1534{
1535 LogFlowFunc(("ppIns = %p, pDevIns = %p, pszName = [%s], offBase = 0x%08X, pu8MemBase = %p, cbMem = 0x%08X, "
1536 "pfnNotifyGuest = %p, pvNotifyGuest = %p, cbContext = %d\n",
1537 ppIns,
1538 pDevIns,
1539 pszName,
1540 offBase,
1541 pu8MemBase,
1542 cbMem,
1543 pfnNotifyGuest,
1544 pvNotifyGuest,
1545 cbContext
1546 ));
1547
1548 AssertPtrReturn(ppIns, VERR_INVALID_PARAMETER);
1549 AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
1550 AssertPtrReturn(pu8MemBase, VERR_INVALID_PARAMETER);
1551
1552 int rc;
1553 PHGSMIINSTANCE pIns = (PHGSMIINSTANCE)RTMemAllocZ(sizeof(HGSMIINSTANCE) + cbContext);
1554 if (pIns)
1555 {
1556 rc = HGSMIAreaInitialize(&pIns->area, pu8MemBase, cbMem, offBase);
1557 if (RT_SUCCESS (rc))
1558 rc = RTCritSectInit(&pIns->instanceCritSect);
1559 if (RT_SUCCESS (rc))
1560 rc = RTCritSectInit(&pIns->hostHeapCritSect);
1561 if (RT_SUCCESS (rc))
1562 rc = RTCritSectInit(&pIns->hostFIFOCritSect);
1563 if (RT_SUCCESS (rc))
1564 {
1565 pIns->pDevIns = pDevIns;
1566 pIns->pszName = RT_VALID_PTR(pszName) ? pszName : "";
1567
1568 hgsmiHostHeapSetupUninitialized(&pIns->hostHeap);
1569
1570 pIns->pfnNotifyGuest = pfnNotifyGuest;
1571 pIns->pvNotifyGuest = pvNotifyGuest;
1572
1573 RTListInit(&pIns->hostFIFO);
1574 RTListInit(&pIns->hostFIFORead);
1575 RTListInit(&pIns->hostFIFOProcessed);
1576 RTListInit(&pIns->hostFIFOFree);
1577 RTListInit(&pIns->guestCmdCompleted);
1578
1579 rc = HGSMIHostChannelRegister(pIns, HGSMI_CH_HGSMI, hgsmiChannelHandler, pIns);
1580 }
1581 if (RT_SUCCESS (rc))
1582 *ppIns = pIns;
1583 else
1584 HGSMIDestroy(pIns);
1585 }
1586 else
1587 rc = VERR_NO_MEMORY;
1588
1589 LogFlowFunc(("leave rc = %Rrc, pIns = %p\n", rc, pIns));
1590 return rc;
1591}
1592
1593uint32_t HGSMIReset(PHGSMIINSTANCE pIns)
1594{
1595 uint32_t flags = 0;
1596 if (pIns->pHGFlags)
1597 {
1598 /* treat the abandoned commands as read.. */
1599 while (HGSMIHostRead(pIns) != HGSMIOFFSET_VOID)
1600 {}
1601 flags = pIns->pHGFlags->u32HostFlags;
1602 pIns->pHGFlags->u32HostFlags = 0;
1603 }
1604
1605 /* .. and complete them */
1606 while (hgsmiProcessHostCmdCompletion(pIns, 0, true))
1607 {}
1608
1609#ifdef VBOX_WITH_WDDM
1610 while (hgsmiProcessGuestCmdCompletion(pIns) != HGSMIOFFSET_VOID)
1611 {}
1612#endif
1613
1614 hgsmiHostHeapDestroy(&pIns->hostHeap);
1615
1616 return flags;
1617}
1618
1619void HGSMIDestroy(PHGSMIINSTANCE pIns)
1620{
1621 LogFlowFunc(("pIns = %p\n", pIns));
1622
1623 if (pIns)
1624 {
1625 hgsmiHostHeapDestroy(&pIns->hostHeap);
1626 if (RTCritSectIsInitialized(&pIns->hostHeapCritSect))
1627 RTCritSectDelete(&pIns->hostHeapCritSect);
1628 if (RTCritSectIsInitialized(&pIns->instanceCritSect))
1629 RTCritSectDelete(&pIns->instanceCritSect);
1630 if (RTCritSectIsInitialized(&pIns->hostFIFOCritSect))
1631 RTCritSectDelete(&pIns->hostFIFOCritSect);
1632
1633 memset(pIns, 0, sizeof (HGSMIINSTANCE));
1634 RTMemFree(pIns);
1635 }
1636
1637 LogFlowFunc(("leave\n"));
1638}
1639
1640#ifdef VBOX_WITH_WDDM
1641
1642static int hgsmiGuestCommandComplete(HGSMIINSTANCE *pIns, HGSMIOFFSET offMem)
1643{
1644 HGSMIGUESTCOMPLENTRY *pEntry = NULL;
1645
1646 AssertPtrReturn(pIns->pHGFlags, VERR_WRONG_ORDER);
1647 int rc = hgsmiGuestCompletionFIFOAlloc(pIns, &pEntry);
1648 AssertRC(rc);
1649 if (RT_SUCCESS(rc))
1650 {
1651 pEntry->offBuffer = offMem;
1652
1653 rc = hgsmiFIFOLock(pIns);
1654 AssertRC(rc);
1655 if (RT_SUCCESS(rc))
1656 {
1657 RTListAppend(&pIns->guestCmdCompleted, &pEntry->nodeEntry);
1658 ASMAtomicOrU32(&pIns->pHGFlags->u32HostFlags, HGSMIHOSTFLAGS_GCOMMAND_COMPLETED);
1659
1660 hgsmiFIFOUnlock(pIns);
1661 }
1662 else
1663 hgsmiGuestCompletionFIFOFree(pIns, pEntry);
1664 }
1665
1666 return rc;
1667}
1668
1669int hgsmiCompleteGuestCommand(PHGSMIINSTANCE pIns, HGSMIOFFSET offBuffer, bool fDoIrq)
1670{
1671 int rc = hgsmiGuestCommandComplete(pIns, offBuffer);
1672 if (RT_SUCCESS (rc))
1673 {
1674#ifdef DEBUG_misha
1675 Assert(fDoIrq);
1676#endif
1677 if (fDoIrq)
1678 {
1679 /* Now guest can read the FIFO, the notification is informational. */
1680 hgsmiNotifyGuest (pIns);
1681 }
1682 }
1683 return rc;
1684}
1685
1686int HGSMICompleteGuestCommand(PHGSMIINSTANCE pIns, void RT_UNTRUSTED_VOLATILE_GUEST *pvMem, bool fDoIrq)
1687{
1688 LogFlowFunc(("pIns = %p, pvMem = %p\n", pIns, pvMem));
1689
1690 HGSMIBUFFERHEADER RT_UNTRUSTED_VOLATILE_GUEST *pHeader = HGSMIBufferHeaderFromData(pvMem);
1691 HGSMIOFFSET offBuffer = HGSMIPointerToOffset(&pIns->area, pHeader);
1692 ASSERT_GUEST_RETURN(offBuffer != HGSMIOFFSET_VOID, VERR_INVALID_PARAMETER);
1693
1694 int rc = hgsmiCompleteGuestCommand(pIns, offBuffer, fDoIrq);
1695 AssertRC(rc);
1696
1697 LogFlowFunc(("rc = %Rrc\n", rc));
1698 return rc;
1699}
1700
1701#endif /* VBOX_WITH_WDDM */
1702
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