VirtualBox

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

Last change on this file since 58466 was 56972, checked in by vboxsync, 9 years ago

HGSMIHost.cpp: Use AssertLogRelRCReturn instead of AssertRCReturn when loading state so we can pinpoint errors more easily.

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