VirtualBox

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

Last change on this file since 62514 was 62514, checked in by vboxsync, 8 years ago

(C) 2016

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