VirtualBox

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

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

HGSMI,DevVGA: Use the offset based heap for the hostHeap (resides in VRAM). New staved state version for DevVGA for indicating this change.

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