VirtualBox

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

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

HGSMI: host command submission cleanup, removed obsolete code, comments.

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