VirtualBox

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

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

wddm: 1. guest installler integration (uninstall needs additional fixing), 2. dev/vga saved state fixes, 3. better split video dma and wddm 4. separate wddm wine libs, 5. etc.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette