VirtualBox

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

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

DevVGA/HGSMI: use RTList

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