VirtualBox

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

Last change on this file since 41783 was 41783, checked in by vboxsync, 12 years ago

Doxygen, comment typos.

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