VirtualBox

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

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

wddm: fix driver initialization

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