VirtualBox

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

Last change on this file since 55421 was 55421, checked in by vboxsync, 10 years ago

HGSMI: cleanup, logging, comments, move legacy host heap support from common code to the host code.

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