VirtualBox

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

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

Devices/Graphics: safety checks when setting IRQs.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 53.5 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 AssertPtrReturn(pIns->pHGFlags, VERR_WRONG_ORDER);
498 int rc = hgsmiFIFOLock(pIns);
499 AssertRC(rc);
500 if(RT_SUCCESS(rc))
501 {
502 /* Get the host FIFO head entry. */
503 HGSMIHOSTFIFOENTRY *pEntry = RTListGetFirst(&pIns->hostFIFO, HGSMIHOSTFIFOENTRY, nodeEntry);
504
505 LogFlowFunc(("host FIFO head %p.\n", pEntry));
506
507 if (pEntry != NULL)
508 {
509 Assert(pEntry->fl == (HGSMI_F_HOST_FIFO_ALLOCATED | HGSMI_F_HOST_FIFO_QUEUED));
510
511 /*
512 * Move the entry to the Read list.
513 */
514 RTListNodeRemove(&pEntry->nodeEntry);
515
516 if (RTListIsEmpty(&pIns->hostFIFO))
517 {
518 ASMAtomicAndU32(&pIns->pHGFlags->u32HostFlags, (~HGSMIHOSTFLAGS_COMMANDS_PENDING));
519 }
520
521 pEntry->fl &= ~HGSMI_F_HOST_FIFO_QUEUED;
522 pEntry->fl |= HGSMI_F_HOST_FIFO_READ;
523
524 RTListAppend(&pIns->hostFIFORead, &pEntry->nodeEntry);
525
526 hgsmiFIFOUnlock(pIns);
527
528 /* Return the buffer offset of the host FIFO head. */
529 return pEntry->offBuffer;
530 }
531 hgsmiFIFOUnlock(pIns);
532 }
533 /* Special value that means there is no host buffers to be processed. */
534 return HGSMIOFFSET_VOID;
535}
536
537
538/* Tells the guest that a new buffer to be processed is available from the host. */
539static void hgsmiNotifyGuest (HGSMIINSTANCE *pIns)
540{
541 if (pIns->pfnNotifyGuest)
542 {
543 pIns->pfnNotifyGuest (pIns->pvNotifyGuest);
544 }
545}
546
547void HGSMISetHostGuestFlags(HGSMIINSTANCE *pIns, uint32_t flags)
548{
549 AssertPtrReturnVoid(pIns->pHGFlags);
550 ASMAtomicOrU32(&pIns->pHGFlags->u32HostFlags, flags);
551}
552
553void HGSMIClearHostGuestFlags(HGSMIINSTANCE *pIns, uint32_t flags)
554{
555 AssertPtrReturnVoid(pIns->pHGFlags);
556 ASMAtomicAndU32(&pIns->pHGFlags->u32HostFlags, (~flags));
557}
558
559#if 0
560static void hgsmiRaiseEvent (const HGSMIHOSTFIFOENTRY *pEntry)
561{
562 int rc = RTSemEventMultiSignal (pEntry->hEvent);
563 AssertRC(rc);
564}
565
566static int hgsmiWaitEvent (const HGSMIHOSTFIFOENTRY *pEntry)
567{
568 int rc = RTSemEventMultiWait (pEntry->hEvent, RT_INDEFINITE_WAIT);
569 AssertRC(rc);
570 return rc;
571}
572#endif
573
574#if 0
575DECLINLINE(HGSMIOFFSET) hgsmiMemoryOffset (const HGSMIINSTANCE *pIns, const void *pv)
576{
577 Assert((uint8_t *)pv >= pIns->area.pu8Base);
578 Assert((uint8_t *)pv < pIns->area.pu8Base + pIns->area.cbArea);
579 return (HGSMIOFFSET)((uint8_t *)pv - pIns->area.pu8Base);
580}
581#endif
582/*
583 * The host heap.
584 *
585 * Uses the RTHeap implementation.
586 *
587 */
588static int hgsmiHostHeapLock (HGSMIINSTANCE *pIns)
589{
590 int rc = RTCritSectEnter (&pIns->hostHeapCritSect);
591 AssertRC (rc);
592 return rc;
593}
594
595static void hgsmiHostHeapUnlock (HGSMIINSTANCE *pIns)
596{
597 int rc = RTCritSectLeave (&pIns->hostHeapCritSect);
598 AssertRC (rc);
599}
600
601#if 0
602static int hgsmiHostHeapAlloc (HGSMIINSTANCE *pIns, void **ppvMem, uint32_t cb)
603{
604 int rc = hgsmiHostHeapLock (pIns);
605
606 if (RT_SUCCESS (rc))
607 {
608 if (pIns->hostHeap == NIL_RTHEAPSIMPLE)
609 {
610 rc = VERR_NOT_SUPPORTED;
611 }
612 else
613 {
614 /* A block structure: [header][data][tail].
615 * 'header' and 'tail' is used to verify memory blocks.
616 */
617 uint32_t cbAlloc = HGSMIBufferRequiredSize (cb);
618
619 void *pv = RTHeapSimpleAlloc (pIns->hostHeap, cbAlloc, 0);
620
621 if (pv)
622 {
623 HGSMIBUFFERHEADER *pHdr = (HGSMIBUFFERHEADER *)pv;
624
625 /* Store some information which will help to verify memory pointers. */
626 pHdr->u32Signature = HGSMI_MEM_SIGNATURE;
627 pHdr->cb = cb;
628 pHdr->off = hgsmiMemoryOffset (pIns, pv);
629 pHdr->u32HdrVerifyer = HGSMI_MEM_VERIFYER_HDR (pHdr);
630
631 /* Setup the tail. */
632 HGSMIBUFFERTAIL *pTail = HGSMIBufferTail (pHdr);
633
634 pTail->u32TailVerifyer = HGSMI_MEM_VERIFYER_TAIL (pHdr);
635
636 *ppvMem = pv;
637 }
638 else
639 {
640 rc = VERR_NO_MEMORY;
641 }
642 }
643
644 hgsmiHostHeapUnlock (pIns);
645 }
646
647 return rc;
648}
649
650
651static int hgsmiHostHeapCheckBlock (HGSMIINSTANCE *pIns, void *pvMem)
652{
653 int rc = hgsmiHostHeapLock (pIns);
654
655 if (RT_SUCCESS (rc))
656 {
657 rc = hgsmiVerifyBuffer (pIns, pvMem);
658
659 hgsmiHostHeapUnlock (pIns);
660 }
661
662 return rc;
663}
664
665static int hgsmiHostHeapFree (HGSMIINSTANCE *pIns, void *pvMem)
666{
667 int rc = hgsmiHostHeapLock (pIns);
668
669 if (RT_SUCCESS (rc))
670 {
671 RTHeapSimpleFree (pIns->hostHeap, pvMem);
672
673 hgsmiHostHeapUnlock (pIns);
674 }
675
676 return rc;
677}
678
679static int hgsmiCheckMemPtr (HGSMIINSTANCE *pIns, void *pvMem, HGSMIOFFSET *poffMem)
680{
681 int rc = hgsmiHostHeapCheckBlock (pIns, pvMem);
682
683 if (RT_SUCCESS (rc))
684 {
685 *poffMem = hgsmiMemoryOffset (pIns, pvMem);
686 }
687
688 return rc;
689}
690#endif
691
692static int hgsmiHostFIFOAlloc (HGSMIINSTANCE *pIns, HGSMIHOSTFIFOENTRY **ppEntry)
693{
694 int rc = VINF_SUCCESS;
695
696 NOREF (pIns);
697
698 HGSMIHOSTFIFOENTRY *pEntry = (HGSMIHOSTFIFOENTRY *)RTMemAllocZ (sizeof (HGSMIHOSTFIFOENTRY));
699
700 if (pEntry)
701 {
702 pEntry->fl = HGSMI_F_HOST_FIFO_ALLOCATED;
703#if 0
704 rc = RTSemEventMultiCreate (&pEntry->hEvent);
705
706 if (RT_FAILURE (rc))
707 {
708 RTMemFree (pEntry);
709 }
710#endif
711 }
712 else
713 {
714 rc = VERR_NO_MEMORY;
715 }
716
717 if (RT_SUCCESS (rc))
718 {
719 *ppEntry = pEntry;
720 }
721
722 return rc;
723}
724
725static void hgsmiHostFIFOFree (HGSMIINSTANCE *pIns, HGSMIHOSTFIFOENTRY *pEntry)
726{
727 NOREF (pIns);
728#if 0
729 if (pEntry->hEvent)
730 {
731 RTSemEventMultiDestroy (pEntry->hEvent);
732 }
733#endif
734 RTMemFree (pEntry);
735}
736
737static int hgsmiHostCommandFreeByEntry (HGSMIHOSTFIFOENTRY *pEntry)
738{
739 HGSMIINSTANCE *pIns = pEntry->pIns;
740 int rc = hgsmiFIFOLock (pIns);
741 if(RT_SUCCESS(rc))
742 {
743 RTListNodeRemove(&pEntry->nodeEntry);
744 hgsmiFIFOUnlock (pIns);
745
746 void *pvMem = HGSMIBufferDataFromOffset(&pIns->area, pEntry->offBuffer);
747
748 rc = hgsmiHostHeapLock (pIns);
749 if(RT_SUCCESS(rc))
750 {
751 /* Deallocate the host heap memory. */
752 HGSMIHeapFree (&pIns->hostHeap, pvMem);
753
754 hgsmiHostHeapUnlock(pIns);
755 }
756
757 hgsmiHostFIFOFree (pIns, pEntry);
758 }
759 return rc;
760}
761
762static int hgsmiHostCommandFree (HGSMIINSTANCE *pIns,
763 void *pvMem)
764{
765 HGSMIOFFSET offMem = HGSMIHeapBufferOffset (&pIns->hostHeap, pvMem);
766 int rc = VINF_SUCCESS;
767 if (offMem != HGSMIOFFSET_VOID)
768 {
769 rc = hgsmiFIFOLock (pIns);
770 if(RT_SUCCESS(rc))
771 {
772 /* Search the Processed list for the given offMem. */
773 HGSMIHOSTFIFOENTRY *pEntry = NULL;
774
775 HGSMIHOSTFIFOENTRY *pIter;
776 RTListForEach(&pIns->hostFIFOProcessed, pIter, HGSMIHOSTFIFOENTRY, nodeEntry)
777 {
778 Assert(pIter->fl == (HGSMI_F_HOST_FIFO_ALLOCATED | HGSMI_F_HOST_FIFO_PROCESSED));
779
780 if (pIter->offBuffer == offMem)
781 {
782 pEntry = pIter;
783 break;
784 }
785 }
786
787 if (pEntry)
788 {
789 RTListNodeRemove(&pEntry->nodeEntry);
790 }
791 else
792 {
793 LogRel(("HGSMI[%s]: the host frees unprocessed FIFO entry: 0x%08X\n", pIns->pszName, offMem));
794 AssertFailed ();
795 }
796
797 hgsmiFIFOUnlock (pIns);
798
799 rc = hgsmiHostHeapLock (pIns);
800 if(RT_SUCCESS(rc))
801 {
802 /* Deallocate the host heap memory. */
803 HGSMIHeapFree (&pIns->hostHeap, pvMem);
804
805 hgsmiHostHeapUnlock(pIns);
806 }
807
808 if(pEntry)
809 {
810 /* Deallocate the entry. */
811 hgsmiHostFIFOFree (pIns, pEntry);
812 }
813 }
814
815 }
816 else
817 {
818 rc = VERR_INVALID_POINTER;
819 LogRel(("HGSMI[%s]: the host frees invalid FIFO entry: %p\n", pIns->pszName, pvMem));
820 AssertFailed ();
821 }
822 return rc;
823}
824
825#if 0
826static DECLCALLBACK(void) hgsmiHostCommandRaiseEventCallback (void *pvCallback)
827{
828 /* Guest has processed the command. */
829 HGSMIHOSTFIFOENTRY *pEntry = (HGSMIHOSTFIFOENTRY *)pvCallback;
830
831 Assert(pEntry->fl == (HGSMI_F_HOST_FIFO_ALLOCATED | HGSMI_F_HOST_FIFO_PROCESSED));
832
833 /* This is a simple callback, just signal the event. */
834 hgsmiRaiseEvent (pEntry);
835}
836#endif
837
838static DECLCALLBACK(void) hgsmiHostCommandFreeCallback (void *pvCallback)
839{
840 /* Guest has processed the command. */
841 HGSMIHOSTFIFOENTRY *pEntry = (HGSMIHOSTFIFOENTRY *)pvCallback;
842
843 Assert(pEntry->fl == (HGSMI_F_HOST_FIFO_ALLOCATED | HGSMI_F_HOST_FIFO_PROCESSED));
844
845 /* This is a simple callback, just signal the event. */
846 hgsmiHostCommandFreeByEntry (pEntry);
847}
848
849static int hgsmiHostCommandWrite (HGSMIINSTANCE *pIns, HGSMIOFFSET offMem
850#if 0
851 , PFNHGSMIHOSTFIFOCALLBACK pfnCallback, void **ppvContext
852#endif
853 )
854{
855 HGSMIHOSTFIFOENTRY *pEntry;
856
857 AssertPtrReturn(pIns->pHGFlags, VERR_WRONG_ORDER);
858 int rc = hgsmiHostFIFOAlloc (pIns, &pEntry);
859
860 if (RT_SUCCESS (rc))
861 {
862 /* Initialize the new entry and add it to the FIFO. */
863 pEntry->fl |= HGSMI_F_HOST_FIFO_QUEUED;
864
865 pEntry->pIns = pIns;
866 pEntry->offBuffer = offMem;
867#if 0
868 pEntry->pfnCallback = pfnCallback;
869 pEntry->pvCallback = pEntry;
870#endif
871
872 rc = hgsmiFIFOLock(pIns);
873 if (RT_SUCCESS (rc))
874 {
875 RTListAppend(&pIns->hostFIFO, &pEntry->nodeEntry);
876 ASMAtomicOrU32(&pIns->pHGFlags->u32HostFlags, HGSMIHOSTFLAGS_COMMANDS_PENDING);
877
878 hgsmiFIFOUnlock(pIns);
879#if 0
880 *ppvContext = pEntry;
881#endif
882 }
883 else
884 {
885 hgsmiHostFIFOFree(pIns, pEntry);
886 }
887 }
888
889 return rc;
890}
891
892
893/**
894 * Append the shared memory block to the FIFO, inform the guest.
895 *
896 * @param pIns Pointer to HGSMI instance,
897 * @param pv The HC memory pointer to the information.
898 * @param ppvContext Where to store a pointer, which will allow the caller
899 * to wait for the command completion.
900 * @param bDoIrq specifies whether the guest interrupt should be generated,
901 * i.e. in case the command is not urgent(e.g. some guest command completion notification that does not require post-processing)
902 * the command could be posted without raising an irq.
903 *
904 * @thread EMT
905 */
906static int hgsmiHostCommandProcess (HGSMIINSTANCE *pIns, HGSMIOFFSET offBuffer,
907#if 0
908 PFNHGSMIHOSTFIFOCALLBACK pfnCallback, void **ppvContext,
909#endif
910 bool bDoIrq)
911{
912// HGSMIOFFSET offMem;
913//
914// int rc = hgsmiCheckMemPtr (pIns, pvMem, &offMem);
915//
916// if (RT_SUCCESS (rc))
917// {
918 /* Append the command to FIFO. */
919 int rc = hgsmiHostCommandWrite (pIns, offBuffer
920#if 0
921 , pfnCallback, ppvContext
922#endif
923 );
924
925 if (RT_SUCCESS (rc))
926 {
927 if(bDoIrq)
928 {
929 /* Now guest can read the FIFO, the notification is informational. */
930 hgsmiNotifyGuest (pIns);
931 }
932 }
933// }
934// else
935// {
936// AssertFailed ();
937// }
938
939 return rc;
940}
941#if 0
942static void hgsmiWait (void *pvContext)
943{
944 HGSMIHOSTFIFOENTRY *pEntry = (HGSMIHOSTFIFOENTRY *)pvContext;
945
946 for (;;)
947 {
948 hgsmiWaitEvent (pEntry);
949
950 if (pEntry->fl & (HGSMI_F_HOST_FIFO_PROCESSED | HGSMI_F_HOST_FIFO_CANCELED))
951 {
952 return;
953 }
954 }
955}
956#endif
957/**
958 * Allocate a shared memory block. The host can write command/data to the memory.
959 *
960 * @param pIns Pointer to HGSMI instance,
961 * @param ppvMem Where to store the allocated memory pointer to data.
962 * @param cbMem How many bytes of data to allocate.
963 */
964int HGSMIHostCommandAlloc (HGSMIINSTANCE *pIns,
965 void **ppvMem,
966 HGSMISIZE cbMem,
967 uint8_t u8Channel,
968 uint16_t u16ChannelInfo)
969{
970 LogFlowFunc (("pIns = %p, cbMem = 0x%08X(%d)\n", pIns, cbMem, cbMem));
971
972 int rc = hgsmiHostHeapLock (pIns);
973 if(RT_SUCCESS(rc))
974 {
975 void *pvMem = HGSMIHeapAlloc (&pIns->hostHeap,
976 cbMem,
977 u8Channel,
978 u16ChannelInfo);
979 hgsmiHostHeapUnlock(pIns);
980
981 if (pvMem)
982 {
983 *ppvMem = pvMem;
984 }
985 else
986 {
987 LogRel((0, "HGSMIHeapAlloc: HGSMIHeapAlloc failed\n"));
988 rc = VERR_GENERAL_FAILURE;
989 }
990 }
991
992 LogFlowFunc (("rc = %Rrc, pvMem = %p\n", rc, *ppvMem));
993
994 return rc;
995}
996
997/**
998 * Convenience function that allows posting the host command asynchronously
999 * and make it freed on completion.
1000 * The caller does not get notified in any way on command completion,
1001 * on success return the pvMem buffer can not be used after being passed to this function
1002 *
1003 * @param pIns Pointer to HGSMI instance,
1004 * @param pvMem The pointer returned by 'HGSMIHostCommandAlloc'.
1005 * @param bDoIrq specifies whether the guest interrupt should be generated,
1006 * i.e. in case the command is not urgent(e.g. some guest command completion notification that does not require post-processing)
1007 * the command could be posted without raising an irq.
1008 */
1009int HGSMIHostCommandProcessAndFreeAsynch (PHGSMIINSTANCE pIns,
1010 void *pvMem,
1011 bool bDoIrq)
1012{
1013 LogFlowFunc(("pIns = %p, pvMem = %p\n", pIns, pvMem));
1014
1015#if 0
1016 void *pvContext = NULL;
1017#endif
1018
1019 HGSMIOFFSET offBuffer = HGSMIHeapBufferOffset (&pIns->hostHeap, pvMem);
1020
1021 int rc = hgsmiHostCommandProcess (pIns, offBuffer,
1022#if 0
1023 hgsmiHostCommandFreeCallback, &pvContext,
1024#endif
1025 bDoIrq);
1026 AssertRC (rc);
1027
1028 LogFlowFunc(("rc = %Rrc\n", rc));
1029
1030 return rc;
1031}
1032#if 0
1033/**
1034 * Submit the shared memory block to the guest.
1035 *
1036 * @param pIns Pointer to HGSMI instance,
1037 * @param pvMem The pointer returned by 'HGSMIHostCommandAlloc'.
1038 */
1039int HGSMIHostCommandProcess (HGSMIINSTANCE *pIns,
1040 void *pvMem)
1041{
1042 LogFlowFunc(("pIns = %p, pvMem = %p\n", pIns, pvMem));
1043
1044 VM_ASSERT_OTHER_THREAD(pIns->pVM);
1045
1046 void *pvContext = NULL;
1047
1048 HGSMIOFFSET offBuffer = HGSMIHeapBufferOffset (&pIns->hostHeap, pvMem);
1049
1050// /* Have to forward to EMT because FIFO processing is there. */
1051// int rc = VMR3ReqCallVoid (pIns->pVM, &pReq, RT_INDEFINITE_WAIT,
1052// (PFNRT) hgsmiHostCommandProcess,
1053// 3, pIns, offBuffer, &pvContext);
1054
1055 int rc = hgsmiHostCommandProcess (pIns, offBuffer,
1056#if 0
1057 hgsmiHostCommandRaiseEventCallback, &pvContext,
1058#endif
1059 true);
1060 AssertReleaseRC (rc);
1061
1062 if (RT_SUCCESS (rc))
1063 {
1064 /* Wait for completion. */
1065 hgsmiWait (pvContext);
1066 }
1067
1068 LogFlowFunc(("rc = %Rrc\n", rc));
1069
1070 return rc;
1071}
1072#endif
1073
1074/**
1075 * Free the shared memory block.
1076 *
1077 * @param pIns Pointer to HGSMI instance,
1078 * @param pvMem The pointer returned by 'HGSMIHostCommandAlloc'.
1079 */
1080int HGSMIHostCommandFree (HGSMIINSTANCE *pIns,
1081 void *pvMem)
1082{
1083 LogFlowFunc(("pIns = %p, pvMem = %p\n", pIns, pvMem));
1084
1085 return hgsmiHostCommandFree (pIns, pvMem);
1086}
1087
1088static DECLCALLBACK(void *) hgsmiEnvAlloc(void *pvEnv, HGSMISIZE cb)
1089{
1090 NOREF(pvEnv);
1091 return RTMemAlloc(cb);
1092}
1093
1094static DECLCALLBACK(void) hgsmiEnvFree(void *pvEnv, void *pv)
1095{
1096 NOREF(pvEnv);
1097 RTMemFree(pv);
1098}
1099
1100static HGSMIENV g_hgsmiEnv =
1101{
1102 NULL,
1103 hgsmiEnvAlloc,
1104 hgsmiEnvFree
1105};
1106
1107int HGSMISetupHostHeap (PHGSMIINSTANCE pIns,
1108 HGSMIOFFSET offHeap,
1109 HGSMISIZE cbHeap)
1110{
1111 LogFlowFunc(("pIns %p, offHeap 0x%08X, cbHeap = 0x%08X\n", pIns, offHeap, cbHeap));
1112
1113 int rc = VINF_SUCCESS;
1114
1115 Assert (pIns);
1116
1117// if ( offHeap >= pIns->cbMem
1118// || cbHeap > pIns->cbMem
1119// || offHeap + cbHeap > pIns->cbMem)
1120// {
1121// rc = VERR_INVALID_PARAMETER;
1122// }
1123// else
1124 {
1125 rc = hgsmiHostHeapLock (pIns);
1126
1127 if (RT_SUCCESS (rc))
1128 {
1129 if (pIns->hostHeap.cRefs)
1130 {
1131 AssertFailed();
1132 /* It is possible to change the heap only if there is no pending allocations. */
1133 rc = VERR_ACCESS_DENIED;
1134 }
1135 else
1136 {
1137 rc = HGSMIHeapSetup (&pIns->hostHeap,
1138 HGSMI_HEAP_TYPE_MA,
1139 pIns->area.pu8Base+offHeap,
1140 cbHeap,
1141 offHeap,
1142 &g_hgsmiEnv);
1143 }
1144
1145 hgsmiHostHeapUnlock (pIns);
1146 }
1147 }
1148
1149 LogFlowFunc(("rc = %Rrc\n", rc));
1150
1151 return rc;
1152}
1153
1154static int hgsmiHostSaveFifoLocked(RTLISTANCHOR *pList, PSSMHANDLE pSSM)
1155{
1156 VBOXHGSMI_SAVE_FIFOSTART(pSSM);
1157
1158 HGSMIHOSTFIFOENTRY *pIter;
1159
1160 uint32_t cEntries = 0;
1161 RTListForEach(pList, pIter, HGSMIHOSTFIFOENTRY, nodeEntry)
1162 {
1163 ++cEntries;
1164 }
1165
1166 int rc = SSMR3PutU32(pSSM, cEntries);
1167 if (RT_SUCCESS(rc))
1168 {
1169 RTListForEach(pList, pIter, HGSMIHOSTFIFOENTRY, nodeEntry)
1170 {
1171 SSMR3PutU32(pSSM, pIter->fl);
1172 rc = SSMR3PutU32(pSSM, pIter->offBuffer);
1173 if (RT_FAILURE(rc))
1174 {
1175 break;
1176 }
1177 }
1178 }
1179
1180 VBOXHGSMI_SAVE_FIFOSTOP(pSSM);
1181
1182 return rc;
1183}
1184
1185static int hgsmiHostSaveGuestCmdCompletedFifoLocked(RTLISTANCHOR *pList, PSSMHANDLE pSSM)
1186{
1187 VBOXHGSMI_SAVE_FIFOSTART(pSSM);
1188
1189 HGSMIGUESTCOMPLENTRY *pIter;
1190
1191 uint32_t cEntries = 0;
1192 RTListForEach(pList, pIter, HGSMIGUESTCOMPLENTRY, nodeEntry)
1193 {
1194 ++cEntries;
1195 }
1196 int rc = SSMR3PutU32(pSSM, cEntries);
1197 if (RT_SUCCESS(rc))
1198 {
1199 RTListForEach(pList, pIter, HGSMIGUESTCOMPLENTRY, nodeEntry)
1200 {
1201 rc = SSMR3PutU32(pSSM, pIter->offBuffer);
1202 if (RT_FAILURE(rc))
1203 {
1204 break;
1205 }
1206 }
1207 }
1208
1209 VBOXHGSMI_SAVE_FIFOSTOP(pSSM);
1210
1211 return rc;
1212}
1213
1214static int hgsmiHostLoadFifoEntryLocked (PHGSMIINSTANCE pIns, HGSMIHOSTFIFOENTRY **ppEntry, PSSMHANDLE pSSM)
1215{
1216 HGSMIHOSTFIFOENTRY *pEntry;
1217 int rc = hgsmiHostFIFOAlloc (pIns, &pEntry); AssertRC(rc);
1218 if (RT_SUCCESS (rc))
1219 {
1220 uint32_t u32;
1221 pEntry->pIns = pIns;
1222 rc = SSMR3GetU32 (pSSM, &u32); AssertRC(rc);
1223 pEntry->fl = u32;
1224 rc = SSMR3GetU32 (pSSM, &pEntry->offBuffer); AssertRC(rc);
1225 if (RT_SUCCESS (rc))
1226 *ppEntry = pEntry;
1227 else
1228 hgsmiHostFIFOFree (pIns, pEntry);
1229 }
1230
1231 return rc;
1232}
1233
1234static int hgsmiHostLoadFifoLocked(PHGSMIINSTANCE pIns, RTLISTANCHOR *pList, PSSMHANDLE pSSM)
1235{
1236 VBOXHGSMI_LOAD_FIFOSTART(pSSM);
1237
1238 uint32_t cEntries = 0;
1239 int rc = SSMR3GetU32(pSSM, &cEntries);
1240 if (RT_SUCCESS(rc) && cEntries)
1241 {
1242 uint32_t i;
1243 for (i = 0; i < cEntries; ++i)
1244 {
1245 HGSMIHOSTFIFOENTRY *pEntry = NULL;
1246 rc = hgsmiHostLoadFifoEntryLocked(pIns, &pEntry, pSSM);
1247 AssertRCBreak(rc);
1248
1249 RTListAppend(pList, &pEntry->nodeEntry);
1250 }
1251 }
1252
1253 VBOXHGSMI_LOAD_FIFOSTOP(pSSM);
1254
1255 return rc;
1256}
1257
1258static int hgsmiHostLoadGuestCmdCompletedFifoEntryLocked (PHGSMIINSTANCE pIns, HGSMIGUESTCOMPLENTRY **ppEntry, PSSMHANDLE pSSM)
1259{
1260 HGSMIGUESTCOMPLENTRY *pEntry;
1261 int rc = hgsmiGuestCompletionFIFOAlloc (pIns, &pEntry); AssertRC(rc);
1262 if (RT_SUCCESS (rc))
1263 {
1264 rc = SSMR3GetU32 (pSSM, &pEntry->offBuffer); AssertRC(rc);
1265 if (RT_SUCCESS (rc))
1266 *ppEntry = pEntry;
1267 else
1268 hgsmiGuestCompletionFIFOFree (pIns, pEntry);
1269 }
1270 return rc;
1271}
1272
1273static int hgsmiHostLoadGuestCmdCompletedFifoLocked(PHGSMIINSTANCE pIns, RTLISTANCHOR *pList, PSSMHANDLE pSSM, uint32_t u32Version)
1274{
1275 VBOXHGSMI_LOAD_FIFOSTART(pSSM);
1276
1277 uint32_t i;
1278
1279 uint32_t cEntries = 0;
1280 int rc = SSMR3GetU32(pSSM, &cEntries);
1281 if (RT_SUCCESS(rc) && cEntries)
1282 {
1283 if (u32Version > VGA_SAVEDSTATE_VERSION_INV_GCMDFIFO)
1284 {
1285 for (i = 0; i < cEntries; ++i)
1286 {
1287 HGSMIGUESTCOMPLENTRY *pEntry = NULL;
1288 rc = hgsmiHostLoadGuestCmdCompletedFifoEntryLocked(pIns, &pEntry, pSSM);
1289 AssertRCBreak(rc);
1290
1291 RTListAppend(pList, &pEntry->nodeEntry);
1292 }
1293 }
1294 else
1295 {
1296 LogRel(("WARNING: the current saved state version has some 3D support data missing, "
1297 "which may lead to some guest applications function improperly"));
1298
1299 /* Just read out all invalid data and discard it. */
1300 for (i = 0; i < cEntries; ++i)
1301 {
1302 HGSMIHOSTFIFOENTRY *pEntry = NULL;
1303 rc = hgsmiHostLoadFifoEntryLocked(pIns, &pEntry, pSSM);
1304 AssertRCBreak(rc);
1305
1306 hgsmiHostFIFOFree(pIns, pEntry);
1307 }
1308 }
1309 }
1310
1311 VBOXHGSMI_LOAD_FIFOSTOP(pSSM);
1312
1313 return rc;
1314}
1315
1316static int hgsmiHostSaveMA(PSSMHANDLE pSSM, HGSMIMADATA *pMA)
1317{
1318 int rc = SSMR3PutU32(pSSM, pMA->cBlocks);
1319 if (RT_SUCCESS(rc))
1320 {
1321 HGSMIMABLOCK *pIter;
1322 RTListForEach(&pMA->listBlocks, pIter, HGSMIMABLOCK, nodeBlock)
1323 {
1324 SSMR3PutU32(pSSM, pIter->descriptor);
1325 }
1326
1327 rc = SSMR3PutU32(pSSM, pMA->cbMaxBlock);
1328 }
1329
1330 return rc;
1331}
1332
1333static int hgsmiHostLoadMA(PSSMHANDLE pSSM, uint32_t *pcBlocks, HGSMIOFFSET **ppaDescriptors, HGSMISIZE *pcbMaxBlock)
1334{
1335 int rc = SSMR3GetU32(pSSM, pcBlocks);
1336 if (RT_SUCCESS(rc))
1337 {
1338 HGSMIOFFSET *paDescriptors = NULL;
1339 if (*pcBlocks > 0)
1340 {
1341 paDescriptors = (HGSMIOFFSET *)RTMemAlloc(*pcBlocks * sizeof(HGSMIOFFSET));
1342 if (paDescriptors)
1343 {
1344 uint32_t i;
1345 for (i = 0; i < *pcBlocks; ++i)
1346 {
1347 SSMR3GetU32(pSSM, &paDescriptors[i]);
1348 }
1349 }
1350 else
1351 {
1352 rc = VERR_NO_MEMORY;
1353 }
1354 }
1355
1356 if (RT_SUCCESS(rc))
1357 {
1358 rc = SSMR3GetU32(pSSM, pcbMaxBlock);
1359 }
1360
1361 if (RT_SUCCESS(rc))
1362 {
1363 *ppaDescriptors = paDescriptors;
1364 }
1365 else
1366 {
1367 RTMemFree(paDescriptors);
1368 }
1369 }
1370
1371 return rc;
1372}
1373
1374int HGSMIHostSaveStateExec (PHGSMIINSTANCE pIns, PSSMHANDLE pSSM)
1375{
1376 VBOXHGSMI_SAVE_START(pSSM);
1377
1378 int rc;
1379
1380 SSMR3PutU32(pSSM, pIns->hostHeap.u32HeapType);
1381
1382 HGSMIOFFSET off = pIns->pHGFlags ? HGSMIPointerToOffset(&pIns->area, (const HGSMIBUFFERHEADER *)pIns->pHGFlags) : HGSMIOFFSET_VOID;
1383 SSMR3PutU32 (pSSM, off);
1384
1385 off = pIns->hostHeap.u32HeapType == HGSMI_HEAP_TYPE_MA?
1386 0:
1387 HGSMIHeapHandleLocationOffset(&pIns->hostHeap);
1388 rc = SSMR3PutU32 (pSSM, off);
1389 if(off != HGSMIOFFSET_VOID)
1390 {
1391 SSMR3PutU32 (pSSM, HGSMIHeapOffset(&pIns->hostHeap));
1392 SSMR3PutU32 (pSSM, HGSMIHeapSize(&pIns->hostHeap));
1393 /* need save mem pointer to calculate offset on restore */
1394 SSMR3PutU64 (pSSM, (uint64_t)(uintptr_t)pIns->area.pu8Base);
1395 rc = hgsmiFIFOLock (pIns);
1396 if(RT_SUCCESS(rc))
1397 {
1398 rc = hgsmiHostSaveFifoLocked (&pIns->hostFIFO, pSSM); AssertRC(rc);
1399 rc = hgsmiHostSaveFifoLocked (&pIns->hostFIFORead, pSSM); AssertRC(rc);
1400 rc = hgsmiHostSaveFifoLocked (&pIns->hostFIFOProcessed, pSSM); AssertRC(rc);
1401#ifdef VBOX_WITH_WDDM
1402 rc = hgsmiHostSaveGuestCmdCompletedFifoLocked (&pIns->guestCmdCompleted, pSSM); AssertRC(rc);
1403#endif
1404
1405 hgsmiFIFOUnlock (pIns);
1406 }
1407
1408 if (RT_SUCCESS(rc))
1409 {
1410 if (pIns->hostHeap.u32HeapType == HGSMI_HEAP_TYPE_MA)
1411 {
1412 rc = hgsmiHostSaveMA(pSSM, &pIns->hostHeap.u.ma);
1413 }
1414 }
1415 }
1416
1417 VBOXHGSMI_SAVE_STOP(pSSM);
1418
1419 return rc;
1420}
1421
1422int HGSMIHostLoadStateExec (PHGSMIINSTANCE pIns, PSSMHANDLE pSSM, uint32_t u32Version)
1423{
1424 if(u32Version < VGA_SAVEDSTATE_VERSION_HGSMI)
1425 return VINF_SUCCESS;
1426
1427 VBOXHGSMI_LOAD_START(pSSM);
1428
1429 int rc;
1430 HGSMIOFFSET off;
1431 uint32_t u32HeapType = HGSMI_HEAP_TYPE_NULL;
1432
1433 if (u32Version >= VGA_SAVEDSTATE_VERSION_HGSMIMA)
1434 {
1435 rc = SSMR3GetU32(pSSM, &u32HeapType);
1436 AssertRCReturn(rc, rc);
1437 }
1438
1439 rc = SSMR3GetU32(pSSM, &off);
1440 AssertRCReturn(rc, rc);
1441 pIns->pHGFlags = (off != HGSMIOFFSET_VOID) ? (HGSMIHOSTFLAGS*)HGSMIOffsetToPointer (&pIns->area, off) : NULL;
1442
1443 HGSMIHEAP hHeap = pIns->hostHeap;
1444 rc = SSMR3GetU32(pSSM, &off);
1445 AssertRCReturn(rc, rc);
1446 if(off != HGSMIOFFSET_VOID)
1447 {
1448 /* There is a saved heap. */
1449 if (u32HeapType == HGSMI_HEAP_TYPE_NULL)
1450 {
1451 u32HeapType = u32Version > VGA_SAVEDSTATE_VERSION_HOST_HEAP?
1452 HGSMI_HEAP_TYPE_OFFSET:
1453 HGSMI_HEAP_TYPE_POINTER;
1454 }
1455
1456 HGSMIOFFSET offHeap;
1457 SSMR3GetU32(pSSM, &offHeap);
1458 uint32_t cbHeap;
1459 SSMR3GetU32(pSSM, &cbHeap);
1460 uint64_t oldMem;
1461 rc = SSMR3GetU64(pSSM, &oldMem);
1462 AssertRCReturn(rc, rc);
1463
1464 if (RT_SUCCESS(rc))
1465 {
1466 rc = hgsmiFIFOLock (pIns);
1467 if(RT_SUCCESS(rc))
1468 {
1469 rc = hgsmiHostLoadFifoLocked (pIns, &pIns->hostFIFO, pSSM);
1470 if (RT_SUCCESS(rc))
1471 rc = hgsmiHostLoadFifoLocked (pIns, &pIns->hostFIFORead, pSSM);
1472 if (RT_SUCCESS(rc))
1473 rc = hgsmiHostLoadFifoLocked (pIns, &pIns->hostFIFOProcessed, pSSM);
1474#ifdef VBOX_WITH_WDDM
1475 if (RT_SUCCESS(rc) && u32Version > VGA_SAVEDSTATE_VERSION_PRE_WDDM)
1476 rc = hgsmiHostLoadGuestCmdCompletedFifoLocked (pIns, &pIns->guestCmdCompleted, pSSM, u32Version);
1477#endif
1478
1479 hgsmiFIFOUnlock (pIns);
1480 }
1481 }
1482
1483 if (RT_SUCCESS(rc))
1484 {
1485 if (u32HeapType == HGSMI_HEAP_TYPE_MA)
1486 {
1487 uint32_t cBlocks = 0;
1488 HGSMISIZE cbMaxBlock = 0;
1489 HGSMIOFFSET *paDescriptors = NULL;
1490 rc = hgsmiHostLoadMA(pSSM, &cBlocks, &paDescriptors, &cbMaxBlock);
1491 if (RT_SUCCESS(rc))
1492 {
1493 rc = HGSMIHeapRestoreMA(&pIns->hostHeap,
1494 pIns->area.pu8Base+offHeap,
1495 cbHeap,
1496 offHeap,
1497 cBlocks,
1498 paDescriptors,
1499 cbMaxBlock,
1500 &g_hgsmiEnv);
1501
1502 RTMemFree(paDescriptors);
1503 }
1504 }
1505 else if ( u32HeapType == HGSMI_HEAP_TYPE_OFFSET
1506 || u32HeapType == HGSMI_HEAP_TYPE_POINTER)
1507 {
1508 rc = hgsmiHostHeapLock (pIns);
1509 if (RT_SUCCESS (rc))
1510 {
1511 Assert(!pIns->hostHeap.cRefs);
1512 pIns->hostHeap.cRefs = 0;
1513
1514 rc = HGSMIHeapRelocate(&pIns->hostHeap,
1515 u32HeapType,
1516 pIns->area.pu8Base+offHeap,
1517 off,
1518 uintptr_t(pIns->area.pu8Base) - uintptr_t(oldMem),
1519 cbHeap,
1520 offHeap);
1521
1522 hgsmiHostHeapUnlock (pIns);
1523 }
1524 }
1525 }
1526 }
1527
1528 VBOXHGSMI_LOAD_STOP(pSSM);
1529
1530 return rc;
1531}
1532
1533/*
1534 * Channels management.
1535 */
1536
1537static int hgsmiChannelMapCreate (PHGSMIINSTANCE pIns,
1538 const char *pszChannel,
1539 uint8_t *pu8Channel)
1540{
1541 /* @todo later */
1542 return VERR_NOT_SUPPORTED;
1543}
1544
1545/* Register a new HGSMI channel by a predefined index.
1546 */
1547int HGSMIHostChannelRegister (PHGSMIINSTANCE pIns,
1548 uint8_t u8Channel,
1549 PFNHGSMICHANNELHANDLER pfnChannelHandler,
1550 void *pvChannelHandler,
1551 HGSMICHANNELHANDLER *pOldHandler)
1552{
1553 LogFlowFunc(("pIns %p, u8Channel %x, pfnChannelHandler %p, pvChannelHandler %p, pOldHandler %p\n",
1554 pIns, u8Channel, pfnChannelHandler, pvChannelHandler, pOldHandler));
1555
1556 AssertReturn(!HGSMI_IS_DYNAMIC_CHANNEL(u8Channel), VERR_INVALID_PARAMETER);
1557 AssertPtrReturn(pIns, VERR_INVALID_PARAMETER);
1558 AssertPtrReturn(pfnChannelHandler, VERR_INVALID_PARAMETER);
1559
1560 int rc = hgsmiLock (pIns);
1561
1562 if (RT_SUCCESS (rc))
1563 {
1564 rc = HGSMIChannelRegister (&pIns->channelInfo, u8Channel, NULL, pfnChannelHandler, pvChannelHandler, pOldHandler);
1565
1566 hgsmiUnlock (pIns);
1567 }
1568
1569 LogFlowFunc(("leave rc = %Rrc\n", rc));
1570
1571 return rc;
1572}
1573
1574/* Register a new HGSMI channel by name.
1575 */
1576int HGSMIChannelRegisterName (PHGSMIINSTANCE pIns,
1577 const char *pszChannel,
1578 PFNHGSMICHANNELHANDLER pfnChannelHandler,
1579 void *pvChannelHandler,
1580 uint8_t *pu8Channel,
1581 HGSMICHANNELHANDLER *pOldHandler)
1582{
1583 LogFlowFunc(("pIns %p, pszChannel %s, pfnChannelHandler %p, pvChannelHandler %p, pu8Channel %p, pOldHandler %p\n",
1584 pIns, pszChannel, pfnChannelHandler, pvChannelHandler, pu8Channel, pOldHandler));
1585
1586 AssertPtrReturn(pIns, VERR_INVALID_PARAMETER);
1587 AssertPtrReturn(pszChannel, VERR_INVALID_PARAMETER);
1588 AssertPtrReturn(pu8Channel, VERR_INVALID_PARAMETER);
1589 AssertPtrReturn(pfnChannelHandler, VERR_INVALID_PARAMETER);
1590
1591 int rc;
1592
1593 /* The pointer to the copy will be saved in the channel description. */
1594 char *pszName = RTStrDup (pszChannel);
1595
1596 if (pszName)
1597 {
1598 rc = hgsmiLock (pIns);
1599
1600 if (RT_SUCCESS (rc))
1601 {
1602 rc = hgsmiChannelMapCreate (pIns, pszName, pu8Channel);
1603
1604 if (RT_SUCCESS (rc))
1605 {
1606 rc = HGSMIChannelRegister (&pIns->channelInfo, *pu8Channel, pszName, pfnChannelHandler, pvChannelHandler, pOldHandler);
1607 }
1608
1609 hgsmiUnlock (pIns);
1610 }
1611
1612 if (RT_FAILURE (rc))
1613 {
1614 RTStrFree (pszName);
1615 }
1616 }
1617 else
1618 {
1619 rc = VERR_NO_MEMORY;
1620 }
1621
1622 LogFlowFunc(("leave rc = %Rrc\n", rc));
1623
1624 return rc;
1625}
1626
1627#if 0
1628/* A wrapper to safely call the handler.
1629 */
1630int HGSMIChannelHandlerCall (PHGSMIINSTANCE pIns,
1631 const HGSMICHANNELHANDLER *pHandler,
1632 const HGSMIBUFFERHEADER *pHeader)
1633{
1634 LogFlowFunc(("pHandler %p, pIns %p, pHeader %p\n", pHandler, pIns, pHeader));
1635
1636 int rc;
1637
1638 if ( pHandler
1639 && pHandler->pfnHandler)
1640 {
1641 void *pvBuffer = HGSMIBufferData (pHeader);
1642 HGSMISIZE cbBuffer = pHeader->u32DataSize;
1643
1644 rc = pHandler->pfnHandler (pIns, pHandler->pvHandler, pHeader->u16ChannelInfo, pvBuffer, cbBuffer);
1645 }
1646 else
1647 {
1648 /* It is a NOOP case here. */
1649 rc = VINF_SUCCESS;
1650 }
1651
1652 LogFlowFunc(("leave rc = %Rrc\n", rc));
1653
1654 return rc;
1655}
1656
1657#endif
1658
1659void *HGSMIOffsetToPointerHost (PHGSMIINSTANCE pIns,
1660 HGSMIOFFSET offBuffer)
1661{
1662 const HGSMIAREA *pArea = &pIns->area;
1663
1664 if ( offBuffer < pArea->offBase
1665 || offBuffer > pArea->offLast)
1666 {
1667 LogFunc(("offset 0x%x is outside the area [0x%x;0x%x]!!!\n", offBuffer, pArea->offBase, pArea->offLast));
1668 return NULL;
1669 }
1670
1671 return HGSMIOffsetToPointer (pArea, offBuffer);
1672}
1673
1674
1675HGSMIOFFSET HGSMIPointerToOffsetHost (PHGSMIINSTANCE pIns,
1676 const void *pv)
1677{
1678 const HGSMIAREA *pArea = &pIns->area;
1679
1680 uintptr_t pBegin = (uintptr_t)pArea->pu8Base;
1681 uintptr_t pEnd = (uintptr_t)pArea->pu8Base + (pArea->cbArea - 1);
1682 uintptr_t p = (uintptr_t)pv;
1683
1684 if ( p < pBegin
1685 || p > pEnd)
1686 {
1687 LogFunc(("pointer %p is outside the area [%p;%p]!!!\n", pv, pBegin, pEnd));
1688 return HGSMIOFFSET_VOID;
1689 }
1690
1691 return HGSMIPointerToOffset (pArea, (HGSMIBUFFERHEADER *)pv);
1692}
1693
1694
1695void *HGSMIContext (PHGSMIINSTANCE pIns)
1696{
1697 uint8_t *p = (uint8_t *)pIns;
1698 return p + sizeof (HGSMIINSTANCE);
1699}
1700
1701/* The guest submitted a buffer. */
1702static DECLCALLBACK(int) hgsmiChannelHandler (void *pvHandler, uint16_t u16ChannelInfo, void *pvBuffer, HGSMISIZE cbBuffer)
1703{
1704 int rc = VINF_SUCCESS;
1705
1706 LogFlowFunc(("pvHandler %p, u16ChannelInfo %d, pvBuffer %p, cbBuffer %u\n",
1707 pvHandler, u16ChannelInfo, pvBuffer, cbBuffer));
1708
1709 PHGSMIINSTANCE pIns = (PHGSMIINSTANCE)pvHandler;
1710
1711 switch (u16ChannelInfo)
1712 {
1713 case HGSMI_CC_HOST_FLAGS_LOCATION:
1714 {
1715 if (cbBuffer < sizeof (HGSMIBUFFERLOCATION))
1716 {
1717 rc = VERR_INVALID_PARAMETER;
1718 break;
1719 }
1720
1721 HGSMIBUFFERLOCATION *pLoc = (HGSMIBUFFERLOCATION *)pvBuffer;
1722 if(pLoc->cbLocation != sizeof(HGSMIHOSTFLAGS))
1723 {
1724 rc = VERR_INVALID_PARAMETER;
1725 break;
1726 }
1727
1728 pIns->pHGFlags = (HGSMIHOSTFLAGS*)HGSMIOffsetToPointer (&pIns->area, pLoc->offLocation);
1729 } break;
1730
1731 default:
1732 Log(("Unsupported HGSMI guest command %d!!!\n",
1733 u16ChannelInfo));
1734 break;
1735 }
1736
1737 return rc;
1738}
1739
1740static HGSMICHANNELHANDLER sOldChannelHandler;
1741
1742int HGSMICreate (PHGSMIINSTANCE *ppIns,
1743 PVM pVM,
1744 const char *pszName,
1745 HGSMIOFFSET offBase,
1746 uint8_t *pu8MemBase,
1747 HGSMISIZE cbMem,
1748 PFNHGSMINOTIFYGUEST pfnNotifyGuest,
1749 void *pvNotifyGuest,
1750 size_t cbContext)
1751{
1752 LogFlowFunc(("ppIns = %p, pVM = %p, pszName = [%s], pu8MemBase = %p, cbMem = 0x%08X, offMemBase = 0x%08X, "
1753 "pfnNotifyGuest = %p, pvNotifyGuest = %p, cbContext = %d\n",
1754 ppIns,
1755 pVM,
1756 pszName,
1757 pu8MemBase,
1758 cbMem,
1759 pfnNotifyGuest,
1760 pvNotifyGuest,
1761 cbContext
1762 ));
1763
1764 AssertPtrReturn(ppIns, VERR_INVALID_PARAMETER);
1765 AssertPtrReturn(pVM, VERR_INVALID_PARAMETER);
1766 AssertPtrReturn(pu8MemBase, VERR_INVALID_PARAMETER);
1767
1768 int rc = VINF_SUCCESS;
1769
1770 PHGSMIINSTANCE pIns = (PHGSMIINSTANCE)RTMemAllocZ (sizeof (HGSMIINSTANCE) + cbContext);
1771
1772 if (!pIns)
1773 {
1774 rc = VERR_NO_MEMORY;
1775 }
1776
1777 if (RT_SUCCESS (rc))
1778 {
1779 rc = HGSMIAreaInitialize (&pIns->area, pu8MemBase, cbMem, offBase);
1780 }
1781
1782 if (RT_SUCCESS (rc))
1783 {
1784 rc = RTCritSectInit (&pIns->instanceCritSect);
1785 }
1786
1787 if (RT_SUCCESS (rc))
1788 {
1789 rc = RTCritSectInit (&pIns->hostHeapCritSect);
1790 }
1791
1792 if (RT_SUCCESS (rc))
1793 {
1794 rc = RTCritSectInit (&pIns->hostFIFOCritSect);
1795 }
1796
1797 if (RT_SUCCESS (rc))
1798 {
1799 pIns->pVM = pVM;
1800
1801 pIns->pszName = VALID_PTR(pszName)? pszName: "";
1802
1803 HGSMIHeapSetupUninitialized(&pIns->hostHeap);
1804
1805 pIns->pfnNotifyGuest = pfnNotifyGuest;
1806 pIns->pvNotifyGuest = pvNotifyGuest;
1807
1808 RTListInit(&pIns->hostFIFO);
1809 RTListInit(&pIns->hostFIFORead);
1810 RTListInit(&pIns->hostFIFOProcessed);
1811 RTListInit(&pIns->hostFIFOFree);
1812 RTListInit(&pIns->guestCmdCompleted);
1813 }
1814
1815 rc = HGSMIHostChannelRegister (pIns,
1816 HGSMI_CH_HGSMI,
1817 hgsmiChannelHandler,
1818 pIns,
1819 &sOldChannelHandler);
1820
1821 if (RT_SUCCESS (rc))
1822 {
1823 *ppIns = pIns;
1824 }
1825 else
1826 {
1827 HGSMIDestroy (pIns);
1828 }
1829
1830 LogFlowFunc(("leave rc = %Rrc, pIns = %p\n", rc, pIns));
1831
1832 return rc;
1833}
1834
1835uint32_t HGSMIReset (PHGSMIINSTANCE pIns)
1836{
1837 uint32_t flags = 0;
1838 if(pIns->pHGFlags)
1839 {
1840 /* treat the abandoned commands as read.. */
1841 while(HGSMIHostRead (pIns) != HGSMIOFFSET_VOID) {}
1842 flags = pIns->pHGFlags->u32HostFlags;
1843 pIns->pHGFlags->u32HostFlags = 0;
1844 }
1845
1846 /* .. and complete them */
1847 while(hgsmiProcessHostCmdCompletion (pIns, 0, true)) {}
1848
1849#ifdef VBOX_WITH_WDDM
1850 while(hgsmiProcessGuestCmdCompletion(pIns) != HGSMIOFFSET_VOID) {}
1851#endif
1852
1853 HGSMIHeapDestroy(&pIns->hostHeap);
1854
1855 HGSMIHeapSetupUninitialized(&pIns->hostHeap);
1856
1857 return flags;
1858}
1859
1860void HGSMIDestroy (PHGSMIINSTANCE pIns)
1861{
1862 LogFlowFunc(("pIns = %p\n", pIns));
1863
1864 if (pIns)
1865 {
1866 HGSMIHeapDestroy(&pIns->hostHeap);
1867
1868 if (RTCritSectIsInitialized (&pIns->hostHeapCritSect))
1869 {
1870 RTCritSectDelete (&pIns->hostHeapCritSect);
1871 }
1872
1873 if (RTCritSectIsInitialized (&pIns->instanceCritSect))
1874 {
1875 RTCritSectDelete (&pIns->instanceCritSect);
1876 }
1877
1878 if (RTCritSectIsInitialized (&pIns->hostFIFOCritSect))
1879 {
1880 RTCritSectDelete (&pIns->hostFIFOCritSect);
1881 }
1882
1883 memset (pIns, 0, sizeof (HGSMIINSTANCE));
1884
1885 RTMemFree (pIns);
1886 }
1887
1888 LogFlowFunc(("leave\n"));
1889}
1890
1891#ifdef VBOX_WITH_WDDM
1892
1893static int hgsmiGuestCommandComplete (HGSMIINSTANCE *pIns, HGSMIOFFSET offMem)
1894{
1895 HGSMIGUESTCOMPLENTRY *pEntry = NULL;
1896
1897 AssertPtrReturn(pIns->pHGFlags, VERR_WRONG_ORDER);
1898 int rc = hgsmiGuestCompletionFIFOAlloc (pIns, &pEntry);
1899 AssertRC(rc);
1900 if (RT_SUCCESS (rc))
1901 {
1902 pEntry->offBuffer = offMem;
1903
1904 rc = hgsmiFIFOLock(pIns);
1905 AssertRC(rc);
1906 if (RT_SUCCESS (rc))
1907 {
1908 RTListAppend(&pIns->guestCmdCompleted, &pEntry->nodeEntry);
1909 ASMAtomicOrU32(&pIns->pHGFlags->u32HostFlags, HGSMIHOSTFLAGS_GCOMMAND_COMPLETED);
1910
1911 hgsmiFIFOUnlock(pIns);
1912 }
1913 else
1914 {
1915 hgsmiGuestCompletionFIFOFree(pIns, pEntry);
1916 }
1917 }
1918
1919 return rc;
1920}
1921
1922int hgsmiCompleteGuestCommand(PHGSMIINSTANCE pIns,
1923 HGSMIOFFSET offBuffer,
1924 bool bDoIrq)
1925{
1926 int rc = hgsmiGuestCommandComplete (pIns, offBuffer);
1927 if (RT_SUCCESS (rc))
1928 {
1929 if(bDoIrq)
1930 {
1931 /* Now guest can read the FIFO, the notification is informational. */
1932 hgsmiNotifyGuest (pIns);
1933 }
1934#ifdef DEBUG_misha
1935 else
1936 {
1937 Assert(0);
1938 }
1939#endif
1940 }
1941 return rc;
1942}
1943
1944int HGSMICompleteGuestCommand(PHGSMIINSTANCE pIns,
1945 void *pvMem,
1946 bool bDoIrq)
1947{
1948 LogFlowFunc(("pIns = %p, pvMem = %p\n", pIns, pvMem));
1949
1950 int rc = VINF_SUCCESS;
1951
1952 HGSMIBUFFERHEADER *pHeader = HGSMIBufferHeaderFromData(pvMem);
1953 HGSMIOFFSET offBuffer = HGSMIPointerToOffset(&pIns->area, pHeader);
1954
1955 Assert(offBuffer != HGSMIOFFSET_VOID);
1956 if (offBuffer != HGSMIOFFSET_VOID)
1957 {
1958 rc = hgsmiCompleteGuestCommand (pIns, offBuffer, bDoIrq);
1959 AssertRC (rc);
1960 }
1961 else
1962 {
1963 LogRel(("invalid cmd offset \n"));
1964 rc = VERR_INVALID_PARAMETER;
1965 }
1966
1967 LogFlowFunc(("rc = %Rrc\n", rc));
1968
1969 return rc;
1970}
1971#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