VirtualBox

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

Last change on this file since 45733 was 44528, checked in by vboxsync, 12 years ago

header (C) fixes

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