VirtualBox

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

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

fixed OSE headers

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