VirtualBox

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

Last change on this file since 50518 was 50518, checked in by vboxsync, 11 years ago

HGSMI memory allocator: saved state

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