VirtualBox

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

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

2d accel: perform data reset VGA device reset

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