VirtualBox

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

Last change on this file since 30317 was 28800, checked in by vboxsync, 15 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette