VirtualBox

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

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

Video hw accel: fallback for PBO allocation failure

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