VirtualBox

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

Last change on this file since 49983 was 49430, checked in by vboxsync, 11 years ago

VHWA: forward port other fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 50.9 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-2012 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#include <iprt/asm.h>
66
67#include <VBox/err.h>
68#define LOG_GROUP LOG_GROUP_DEV_VGA
69#include <VBox/log.h>
70#include <VBox/vmm/ssm.h>
71
72#include "HGSMIHost.h"
73#include <VBox/HGSMI/HGSMIChannels.h>
74#include <VBox/HGSMI/HGSMIChSetup.h>
75
76#include "HGSMIHostHlp.h"
77#include "../DevVGASavedState.h"
78
79#ifdef DEBUG_sunlover
80#define HGSMI_STRICT 1
81#endif /* !DEBUG_sunlover */
82
83#ifdef DEBUG_misha
84//# define VBOXHGSMI_STATE_DEBUG
85#endif
86
87#ifdef VBOXHGSMI_STATE_DEBUG
88#define VBOXHGSMI_STATE_START_MAGIC 0x12345678
89#define VBOXHGSMI_STATE_STOP_MAGIC 0x87654321
90#define VBOXHGSMI_STATE_FIFOSTART_MAGIC 0x9abcdef1
91#define VBOXHGSMI_STATE_FIFOSTOP_MAGIC 0x1fedcba9
92
93#define VBOXHGSMI_SAVE_START(_pSSM) do{ int rc2 = SSMR3PutU32(_pSSM, VBOXHGSMI_STATE_START_MAGIC); AssertRC(rc2);}while(0)
94#define VBOXHGSMI_SAVE_STOP(_pSSM) do{ int rc2 = SSMR3PutU32(_pSSM, VBOXHGSMI_STATE_STOP_MAGIC); AssertRC(rc2);}while(0)
95#define VBOXHGSMI_SAVE_FIFOSTART(_pSSM) do{ int rc2 = SSMR3PutU32(_pSSM, VBOXHGSMI_STATE_FIFOSTART_MAGIC); AssertRC(rc2);}while(0)
96#define VBOXHGSMI_SAVE_FIFOSTOP(_pSSM) do{ int rc2 = SSMR3PutU32(_pSSM, VBOXHGSMI_STATE_FIFOSTOP_MAGIC); AssertRC(rc2);}while(0)
97
98#define VBOXHGSMI_LOAD_CHECK(_pSSM, _v) \
99 do{ \
100 uint32_t u32; \
101 int rc2 = SSMR3GetU32(_pSSM, &u32); AssertRC(rc2); \
102 Assert(u32 == (_v)); \
103 }while(0)
104
105#define VBOXHGSMI_LOAD_START(_pSSM) VBOXHGSMI_LOAD_CHECK(_pSSM, VBOXHGSMI_STATE_START_MAGIC)
106#define VBOXHGSMI_LOAD_FIFOSTART(_pSSM) VBOXHGSMI_LOAD_CHECK(_pSSM, VBOXHGSMI_STATE_FIFOSTART_MAGIC)
107#define VBOXHGSMI_LOAD_FIFOSTOP(_pSSM) VBOXHGSMI_LOAD_CHECK(_pSSM, VBOXHGSMI_STATE_FIFOSTOP_MAGIC)
108#define VBOXHGSMI_LOAD_STOP(_pSSM) VBOXHGSMI_LOAD_CHECK(_pSSM, VBOXHGSMI_STATE_STOP_MAGIC)
109#else
110#define VBOXHGSMI_SAVE_START(_pSSM) do{ }while(0)
111#define VBOXHGSMI_SAVE_STOP(_pSSM) do{ }while(0)
112#define VBOXHGSMI_SAVE_FIFOSTART(_pSSM) do{ }while(0)
113#define VBOXHGSMI_SAVE_FIFOSTOP(_pSSM) do{ }while(0)
114
115
116#define VBOXHGSMI_LOAD_START(_pSSM) do{ }while(0)
117#define VBOXHGSMI_LOAD_FIFOSTART(_pSSM) do{ }while(0)
118#define VBOXHGSMI_LOAD_FIFOSTOP(_pSSM) do{ }while(0)
119#define VBOXHGSMI_LOAD_STOP(_pSSM) do{ }while(0)
120
121#endif
122
123/* Assertions for situations which could happen and normally must be processed properly
124 * but must be investigated during development: guest misbehaving, etc.
125 */
126#ifdef HGSMI_STRICT
127#define HGSMI_STRICT_ASSERT_FAILED() AssertFailed()
128#define HGSMI_STRICT_ASSERT(expr) Assert(expr)
129#else
130#define HGSMI_STRICT_ASSERT_FAILED() do {} while (0)
131#define HGSMI_STRICT_ASSERT(expr) do {} while (0)
132#endif /* !HGSMI_STRICT */
133
134
135typedef struct _HGSMIINSTANCE
136{
137 PVM pVM; /* The VM. */
138
139 const char *pszName; /* A name for the instance. Mostyl used in the log. */
140
141 RTCRITSECT instanceCritSect; /* For updating the instance data: FIFO's, channels. */
142
143 HGSMIAREA area; /* The shared memory description. */
144 HGSMIHEAP hostHeap; /* Host heap instance. */
145 RTCRITSECT hostHeapCritSect; /* Heap serialization lock. */
146
147 HGSMILIST hostFIFO; /* Pending host buffers. */
148 HGSMILIST hostFIFORead; /* Host buffers read by the guest. */
149 HGSMILIST hostFIFOProcessed; /* Processed by the guest. */
150 HGSMILIST hostFIFOFree; /* Buffers for reuse. */
151#ifdef VBOX_WITH_WDDM
152 HGSMILIST guestCmdCompleted; /* list of completed guest commands to be returned to the guest*/
153#endif
154 RTCRITSECT hostFIFOCritSect; /* FIFO serialization lock. */
155
156 PFNHGSMINOTIFYGUEST pfnNotifyGuest; /* Guest notification callback. */
157 void *pvNotifyGuest; /* Guest notification callback context. */
158
159 volatile HGSMIHOSTFLAGS * pHGFlags;
160
161 HGSMICHANNELINFO channelInfo; /* Channel handlers indexed by the channel id.
162 * The array is accessed under the instance lock.
163 */
164 } HGSMIINSTANCE;
165
166
167typedef DECLCALLBACK(void) FNHGSMIHOSTFIFOCALLBACK(void *pvCallback);
168typedef FNHGSMIHOSTFIFOCALLBACK *PFNHGSMIHOSTFIFOCALLBACK;
169
170typedef struct _HGSMIHOSTFIFOENTRY
171{
172 /* The list field. Must be the first field. */
173 HGSMILISTENTRY entry;
174
175 /* Backlink to the HGSMI instance. */
176 HGSMIINSTANCE *pIns;
177
178#if 0
179 /* removed to allow saved state handling */
180 /* The event which is signalled when the command has been processed by the host. */
181 RTSEMEVENTMULTI hEvent;
182#endif
183 /* Status flags of the entry. */
184 volatile uint32_t fl;
185
186 /* Offset in the memory region of the entry data. */
187 HGSMIOFFSET offBuffer;
188
189#if 0
190 /* removed to allow saved state handling */
191 /* The command completion callback. */
192 PFNHGSMIHOSTFIFOCALLBACK pfnCallback;
193 void *pvCallback;
194#endif
195
196} HGSMIHOSTFIFOENTRY;
197
198#define HGSMILISTENTRY_2_FIFOENTRY(_pe) \
199 ( (HGSMIHOSTFIFOENTRY*)((uint8_t *)(_pe) - RT_OFFSETOF(HGSMIHOSTFIFOENTRY, entry)) )
200
201//AssertCompile(RT_OFFSETOF(HGSMIHOSTFIFOENTRY, entry) == 0);
202
203
204#define HGSMI_F_HOST_FIFO_ALLOCATED 0x0001
205#define HGSMI_F_HOST_FIFO_QUEUED 0x0002
206#define HGSMI_F_HOST_FIFO_READ 0x0004
207#define HGSMI_F_HOST_FIFO_PROCESSED 0x0008
208#define HGSMI_F_HOST_FIFO_FREE 0x0010
209#define HGSMI_F_HOST_FIFO_CANCELED 0x0020
210
211static DECLCALLBACK(void) hgsmiHostCommandFreeCallback (void *pvCallback);
212
213#ifdef VBOX_WITH_WDDM
214
215typedef struct _HGSMIGUESTCOMPLENTRY
216{
217 /* The list field. Must be the first field. */
218 HGSMILISTENTRY entry;
219 /* guest command buffer */
220 HGSMIOFFSET offBuffer;
221} HGSMIGUESTCOMPLENTRY;
222
223#define HGSMILISTENTRY_2_HGSMIGUESTCOMPLENTRY(_pe) \
224 ( (HGSMIGUESTCOMPLENTRY*)((uint8_t *)(_pe) - RT_OFFSETOF(HGSMIGUESTCOMPLENTRY, entry)) )
225
226static void hgsmiGuestCompletionFIFOFree (HGSMIINSTANCE *pIns, HGSMIGUESTCOMPLENTRY *pEntry)
227{
228 NOREF (pIns);
229 RTMemFree (pEntry);
230}
231
232static int hgsmiGuestCompletionFIFOAlloc (HGSMIINSTANCE *pIns, HGSMIGUESTCOMPLENTRY **ppEntry)
233{
234 int rc = VINF_SUCCESS;
235
236 NOREF (pIns);
237
238 HGSMIGUESTCOMPLENTRY *pEntry = (HGSMIGUESTCOMPLENTRY *)RTMemAllocZ (sizeof (HGSMIGUESTCOMPLENTRY));
239
240 if (pEntry)
241 *ppEntry = pEntry;
242 else
243 rc = VERR_NO_MEMORY;
244
245 return rc;
246}
247
248#endif
249
250static int hgsmiLock (HGSMIINSTANCE *pIns)
251{
252 int rc = RTCritSectEnter (&pIns->instanceCritSect);
253 AssertRC (rc);
254 return rc;
255}
256
257static void hgsmiUnlock (HGSMIINSTANCE *pIns)
258{
259 int rc = RTCritSectLeave (&pIns->instanceCritSect);
260 AssertRC (rc);
261}
262
263static int hgsmiFIFOLock (HGSMIINSTANCE *pIns)
264{
265 int rc = RTCritSectEnter (&pIns->hostFIFOCritSect);
266 AssertRC (rc);
267 return rc;
268}
269
270static void hgsmiFIFOUnlock (HGSMIINSTANCE *pIns)
271{
272 int rc = RTCritSectLeave (&pIns->hostFIFOCritSect);
273 AssertRC (rc);
274}
275
276//static HGSMICHANNEL *hgsmiChannelFindById (PHGSMIINSTANCE pIns,
277// uint8_t u8Channel)
278//{
279// HGSMICHANNEL *pChannel = &pIns->Channels[u8Channel];
280//
281// if (pChannel->u8Flags & HGSMI_CH_F_REGISTERED)
282// {
283// return pChannel;
284// }
285//
286// return NULL;
287//}
288
289#if 0
290/* Verify that the given offBuffer points to a valid buffer, which is within the area.
291 */
292static const HGSMIBUFFERHEADER *hgsmiVerifyBuffer (const HGSMIAREA *pArea,
293 HGSMIOFFSET offBuffer)
294{
295 AssertPtr(pArea);
296
297 LogFlowFunc(("buffer 0x%x, area %p %x [0x%x;0x%x]\n", offBuffer, pArea->pu8Base, pArea->cbArea, pArea->offBase, pArea->offLast));
298
299 if ( offBuffer < pArea->offBase
300 || offBuffer > pArea->offLast)
301 {
302 LogFunc(("offset 0x%x is outside the area [0x%x;0x%x]!!!\n", offBuffer, pArea->offBase, pArea->offLast));
303 HGSMI_STRICT_ASSERT_FAILED();
304 return NULL;
305 }
306
307 const HGSMIBUFFERHEADER *pHeader = HGSMIOffsetToPointer (pArea, offBuffer);
308
309 /* Quick check of the data size, it should be less than the maximum
310 * data size for the buffer at this offset.
311 */
312 LogFlowFunc(("datasize check: pHeader->u32DataSize = 0x%x pArea->offLast - offBuffer = 0x%x\n", pHeader->u32DataSize, pArea->offLast - offBuffer));
313 if (pHeader->u32DataSize <= pArea->offLast - offBuffer)
314 {
315 HGSMIBUFFERTAIL *pTail = HGSMIBufferTail (pHeader);
316
317 /* At least both pHeader and pTail structures are in the area. Check the checksum. */
318 uint32_t u32Checksum = HGSMIChecksum (offBuffer, pHeader, pTail);
319
320 LogFlowFunc(("checksum check: u32Checksum = 0x%x pTail->u32Checksum = 0x%x\n", u32Checksum, pTail->u32Checksum));
321 if (u32Checksum == pTail->u32Checksum)
322 {
323 LogFlowFunc(("returning %p\n", pHeader));
324 return pHeader;
325 }
326 else
327 {
328 LogFunc(("invalid checksum 0x%x, expected 0x%x!!!\n", u32Checksum, pTail->u32Checksum));
329 }
330 }
331 else
332 {
333 LogFunc(("invalid data size 0x%x, maximum is 0x%x!!!\n", pHeader->u32DataSize, pArea->offLast - offBuffer));
334 }
335
336 LogFlowFunc(("returning NULL\n"));
337 HGSMI_STRICT_ASSERT_FAILED();
338 return NULL;
339}
340
341/*
342 * Process a guest buffer.
343 * @thread EMT
344 */
345static int hgsmiGuestBufferProcess (HGSMIINSTANCE *pIns,
346 const HGSMICHANNEL *pChannel,
347 const HGSMIBUFFERHEADER *pHeader)
348{
349 LogFlowFunc(("pIns %p, pChannel %p, pHeader %p\n", pIns, pChannel, pHeader));
350
351 int rc = HGSMIChannelHandlerCall (pIns,
352 &pChannel->handler,
353 pHeader);
354
355 return rc;
356}
357#endif
358/*
359 * Virtual hardware IO handlers.
360 */
361
362/* The guest submits a new buffer to the host.
363 * Called from the HGSMI_IO_GUEST write handler.
364 * @thread EMT
365 */
366void HGSMIGuestWrite (PHGSMIINSTANCE pIns,
367 HGSMIOFFSET offBuffer)
368{
369 HGSMIBufferProcess (&pIns->area, &pIns->channelInfo, offBuffer);
370}
371
372#ifdef VBOX_WITH_WDDM
373static HGSMIOFFSET hgsmiProcessGuestCmdCompletion(HGSMIINSTANCE *pIns)
374{
375 HGSMIOFFSET offCmd = HGSMIOFFSET_VOID;
376 int rc = hgsmiFIFOLock(pIns);
377 AssertRC(rc);
378 if(RT_SUCCESS(rc))
379 {
380 /* Get the host FIFO head entry. */
381 HGSMILISTENTRY *pHead = pIns->guestCmdCompleted.pHead;
382 if(pHead)
383 hgsmiListRemove (&pIns->guestCmdCompleted, pHead, NULL);
384
385 if(!pIns->guestCmdCompleted.pHead)
386 {
387 if(pIns->pHGFlags)
388 ASMAtomicAndU32(&pIns->pHGFlags->u32HostFlags, (~HGSMIHOSTFLAGS_GCOMMAND_COMPLETED));
389 }
390
391 hgsmiFIFOUnlock(pIns);
392
393 if (pHead)
394 {
395 HGSMIGUESTCOMPLENTRY *pEntry = HGSMILISTENTRY_2_HGSMIGUESTCOMPLENTRY(pHead);
396 offCmd = pEntry->offBuffer;
397
398 LogFlowFunc(("host FIFO head %p.\n", pEntry));
399
400 hgsmiGuestCompletionFIFOFree (pIns, pEntry);
401 }
402 }
403 return offCmd;
404}
405#endif
406
407
408/* Called from HGSMI_IO_GUEST read handler. */
409HGSMIOFFSET HGSMIGuestRead (PHGSMIINSTANCE pIns)
410{
411 LogFlowFunc(("pIns %p\n", pIns));
412
413 AssertPtr(pIns);
414
415 VM_ASSERT_EMT(pIns->pVM);
416
417#ifndef VBOX_WITH_WDDM
418 /* Currently there is no functionality here. */
419 NOREF(pIns);
420
421 return HGSMIOFFSET_VOID;
422#else
423 /* use this to speedup guest cmd completion
424 * this mechanism is alternative to submitting H->G command for notification */
425 HGSMIOFFSET offCmd = hgsmiProcessGuestCmdCompletion(pIns);
426 return offCmd;
427#endif
428}
429
430static bool hgsmiProcessHostCmdCompletion (HGSMIINSTANCE *pIns,
431 HGSMIOFFSET offBuffer,
432 bool bCompleteFirst)
433{
434 VM_ASSERT_EMT(pIns->pVM);
435
436 int rc = hgsmiFIFOLock(pIns);
437 if(RT_SUCCESS(rc))
438 {
439 /* Search the Read list for the given buffer offset. Also find the previous entry. */
440 HGSMIHOSTFIFOENTRY *pEntry = HGSMILISTENTRY_2_FIFOENTRY(pIns->hostFIFORead.pHead);
441 HGSMIHOSTFIFOENTRY *pPrev = NULL;
442
443 while (pEntry)
444 {
445 Assert(pEntry->fl == (HGSMI_F_HOST_FIFO_ALLOCATED | HGSMI_F_HOST_FIFO_READ));
446
447 if (bCompleteFirst || pEntry->offBuffer == offBuffer)
448 {
449 break;
450 }
451
452#ifdef DEBUGVHWASTRICT
453 /* guest usually completes commands in the order it receives it
454 * if we're here this would typically means there is some cmd loss */
455 AssertFailed();
456#endif
457
458 pPrev = pEntry;
459 pEntry = HGSMILISTENTRY_2_FIFOENTRY(pEntry->entry.pNext);
460 }
461
462 LogFlowFunc(("read list entry: %p.\n", pEntry));
463
464 Assert(pEntry || bCompleteFirst);
465
466 if (pEntry)
467 {
468 /* Exclude from the Read list. */
469 hgsmiListRemove (&pIns->hostFIFORead, &pEntry->entry, pPrev? &pPrev->entry: NULL);
470
471 pEntry->fl &= ~HGSMI_F_HOST_FIFO_READ;
472 pEntry->fl |= HGSMI_F_HOST_FIFO_PROCESSED;
473
474 /* Save in the Processed list. */
475 hgsmiListAppend (&pIns->hostFIFOProcessed, &pEntry->entry);
476
477 hgsmiFIFOUnlock(pIns);
478#if 0
479 /* Inform the submitter. */
480 if (pEntry->pfnCallback)
481 {
482 pEntry->pfnCallback (pEntry->pvCallback);
483 }
484#else
485 hgsmiHostCommandFreeCallback(pEntry);
486#endif
487 return true;
488 }
489
490 hgsmiFIFOUnlock(pIns);
491 if(!bCompleteFirst)
492 LogRel(("HGSMI[%s]: ignored invalid write to the host FIFO: 0x%08X!!!\n", pIns->pszName, offBuffer));
493 }
494 return false;
495}
496
497/* The guest has finished processing of a buffer previously submitted by the host.
498 * Called from HGSMI_IO_HOST write handler.
499 * @thread EMT
500 */
501void HGSMIHostWrite (HGSMIINSTANCE *pIns,
502 HGSMIOFFSET offBuffer)
503{
504 LogFlowFunc(("pIns %p offBuffer 0x%x\n", pIns, offBuffer));
505
506 hgsmiProcessHostCmdCompletion (pIns, offBuffer, false);
507}
508
509/* The guest reads a new host buffer to be processed.
510 * Called from the HGSMI_IO_HOST read handler.
511 * @thread EMT
512 */
513HGSMIOFFSET HGSMIHostRead (HGSMIINSTANCE *pIns)
514{
515 LogFlowFunc(("pIns %p\n", pIns));
516
517 VM_ASSERT_EMT(pIns->pVM);
518
519 int rc = hgsmiFIFOLock(pIns);
520 AssertRC(rc);
521 if(RT_SUCCESS(rc))
522 {
523 /* Get the host FIFO head entry. */
524 HGSMIHOSTFIFOENTRY *pEntry = HGSMILISTENTRY_2_FIFOENTRY(pIns->hostFIFO.pHead);
525
526 LogFlowFunc(("host FIFO head %p.\n", pEntry));
527
528 if (pEntry != NULL)
529 {
530 Assert(pEntry->fl == (HGSMI_F_HOST_FIFO_ALLOCATED | HGSMI_F_HOST_FIFO_QUEUED));
531
532 /* Exclude from the FIFO. */
533 hgsmiListRemove (&pIns->hostFIFO, &pEntry->entry, NULL);
534
535 if(!pIns->hostFIFO.pHead)
536 {
537 ASMAtomicAndU32(&pIns->pHGFlags->u32HostFlags, (~HGSMIHOSTFLAGS_COMMANDS_PENDING));
538 }
539
540 pEntry->fl &= ~HGSMI_F_HOST_FIFO_QUEUED;
541 pEntry->fl |= HGSMI_F_HOST_FIFO_READ;
542
543 /* Save in the Read list. */
544 hgsmiListAppend (&pIns->hostFIFORead, &pEntry->entry);
545
546 hgsmiFIFOUnlock(pIns);
547 Assert(pEntry->offBuffer != HGSMIOFFSET_VOID);
548 /* Return the buffer offset of the host FIFO head. */
549 return pEntry->offBuffer;
550 }
551 hgsmiFIFOUnlock(pIns);
552 }
553 /* Special value that means there is no host buffers to be processed. */
554 return HGSMIOFFSET_VOID;
555}
556
557
558/* Tells the guest that a new buffer to be processed is available from the host. */
559static void hgsmiNotifyGuest (HGSMIINSTANCE *pIns)
560{
561 if (pIns->pfnNotifyGuest)
562 {
563 pIns->pfnNotifyGuest (pIns->pvNotifyGuest);
564 }
565}
566
567void HGSMISetHostGuestFlags(HGSMIINSTANCE *pIns, uint32_t flags)
568{
569 ASMAtomicOrU32(&pIns->pHGFlags->u32HostFlags, flags);
570}
571
572void HGSMIClearHostGuestFlags(HGSMIINSTANCE *pIns, uint32_t flags)
573{
574 ASMAtomicAndU32(&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 ASMAtomicOrU32(&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#if 0
1043 void *pvContext = NULL;
1044#endif
1045
1046 HGSMIOFFSET offBuffer = HGSMIHeapBufferOffset (&pIns->hostHeap, pvMem);
1047
1048 int rc = hgsmiHostCommandProcess (pIns, offBuffer,
1049#if 0
1050 hgsmiHostCommandFreeCallback, &pvContext,
1051#endif
1052 bDoIrq);
1053 AssertRC (rc);
1054
1055 LogFlowFunc(("rc = %Rrc\n", rc));
1056
1057 return rc;
1058}
1059#if 0
1060/**
1061 * Submit the shared memory block to the guest.
1062 *
1063 * @param pIns Pointer to HGSMI instance,
1064 * @param pvMem The pointer returned by 'HGSMIHostCommandAlloc'.
1065 */
1066int HGSMIHostCommandProcess (HGSMIINSTANCE *pIns,
1067 void *pvMem)
1068{
1069 LogFlowFunc(("pIns = %p, pvMem = %p\n", pIns, pvMem));
1070
1071 VM_ASSERT_OTHER_THREAD(pIns->pVM);
1072
1073 void *pvContext = NULL;
1074
1075 HGSMIOFFSET offBuffer = HGSMIHeapBufferOffset (&pIns->hostHeap, pvMem);
1076
1077// /* Have to forward to EMT because FIFO processing is there. */
1078// int rc = VMR3ReqCallVoid (pIns->pVM, &pReq, RT_INDEFINITE_WAIT,
1079// (PFNRT) hgsmiHostCommandProcess,
1080// 3, pIns, offBuffer, &pvContext);
1081
1082 int rc = hgsmiHostCommandProcess (pIns, offBuffer,
1083#if 0
1084 hgsmiHostCommandRaiseEventCallback, &pvContext,
1085#endif
1086 true);
1087 AssertReleaseRC (rc);
1088
1089 if (RT_SUCCESS (rc))
1090 {
1091 /* Wait for completion. */
1092 hgsmiWait (pvContext);
1093 }
1094
1095 LogFlowFunc(("rc = %Rrc\n", rc));
1096
1097 return rc;
1098}
1099#endif
1100
1101/**
1102 * Free the shared memory block.
1103 *
1104 * @param pIns Pointer to HGSMI instance,
1105 * @param pvMem The pointer returned by 'HGSMIHostCommandAlloc'.
1106 */
1107int HGSMIHostCommandFree (HGSMIINSTANCE *pIns,
1108 void *pvMem)
1109{
1110 LogFlowFunc(("pIns = %p, pvMem = %p\n", pIns, pvMem));
1111
1112 return hgsmiHostCommandFree (pIns, pvMem);
1113}
1114
1115int HGSMISetupHostHeap (PHGSMIINSTANCE pIns,
1116 HGSMIOFFSET offHeap,
1117 HGSMISIZE cbHeap)
1118{
1119 LogFlowFunc(("pIns %p, offHeap 0x%08X, cbHeap = 0x%08X\n", pIns, offHeap, cbHeap));
1120
1121 int rc = VINF_SUCCESS;
1122
1123 Assert (pIns);
1124
1125// if ( offHeap >= pIns->cbMem
1126// || cbHeap > pIns->cbMem
1127// || offHeap + cbHeap > pIns->cbMem)
1128// {
1129// rc = VERR_INVALID_PARAMETER;
1130// }
1131// else
1132 {
1133 rc = hgsmiHostHeapLock (pIns);
1134
1135 if (RT_SUCCESS (rc))
1136 {
1137 if (pIns->hostHeap.cRefs)
1138 {
1139 AssertFailed();
1140 /* It is possible to change the heap only if there is no pending allocations. */
1141 rc = VERR_ACCESS_DENIED;
1142 }
1143 else
1144 {
1145 rc = HGSMIHeapSetup (&pIns->hostHeap,
1146 pIns->area.pu8Base+offHeap,
1147 cbHeap,
1148 offHeap,
1149 true /*fOffsetBased*/);
1150 }
1151
1152 hgsmiHostHeapUnlock (pIns);
1153 }
1154 }
1155
1156 LogFlowFunc(("rc = %Rrc\n", rc));
1157
1158 return rc;
1159}
1160
1161static int hgsmiHostSaveFifoEntryLocked (HGSMIHOSTFIFOENTRY *pEntry, PSSMHANDLE pSSM)
1162{
1163 SSMR3PutU32 (pSSM, pEntry->fl);
1164 return SSMR3PutU32 (pSSM, pEntry->offBuffer);
1165}
1166
1167static int hgsmiHostSaveFifoLocked (HGSMILIST * pFifo, PSSMHANDLE pSSM)
1168{
1169 VBOXHGSMI_SAVE_FIFOSTART(pSSM);
1170 uint32_t size = 0;
1171 for(HGSMILISTENTRY * pEntry = pFifo->pHead; pEntry; pEntry = pEntry->pNext)
1172 {
1173 ++size;
1174 }
1175 int rc = SSMR3PutU32 (pSSM, size);
1176
1177 for(HGSMILISTENTRY * pEntry = pFifo->pHead; pEntry && RT_SUCCESS(rc); pEntry = pEntry->pNext)
1178 {
1179 HGSMIHOSTFIFOENTRY *pFifoEntry = HGSMILISTENTRY_2_FIFOENTRY(pEntry);
1180 rc = hgsmiHostSaveFifoEntryLocked (pFifoEntry, pSSM);
1181 }
1182
1183 VBOXHGSMI_SAVE_FIFOSTOP(pSSM);
1184
1185 return rc;
1186}
1187
1188static int hgsmiHostSaveGuestCmdCompletedFifoEntryLocked (HGSMIGUESTCOMPLENTRY *pEntry, PSSMHANDLE pSSM)
1189{
1190 return SSMR3PutU32 (pSSM, pEntry->offBuffer);
1191}
1192
1193static int hgsmiHostSaveGuestCmdCompletedFifoLocked (HGSMILIST * pFifo, PSSMHANDLE pSSM)
1194{
1195 VBOXHGSMI_SAVE_FIFOSTART(pSSM);
1196 uint32_t size = 0;
1197 for(HGSMILISTENTRY * pEntry = pFifo->pHead; pEntry; pEntry = pEntry->pNext)
1198 {
1199 ++size;
1200 }
1201 int rc = SSMR3PutU32 (pSSM, size);
1202
1203 for(HGSMILISTENTRY * pEntry = pFifo->pHead; pEntry && RT_SUCCESS(rc); pEntry = pEntry->pNext)
1204 {
1205 HGSMIGUESTCOMPLENTRY *pFifoEntry = HGSMILISTENTRY_2_HGSMIGUESTCOMPLENTRY(pEntry);
1206 rc = hgsmiHostSaveGuestCmdCompletedFifoEntryLocked (pFifoEntry, pSSM);
1207 }
1208
1209 VBOXHGSMI_SAVE_FIFOSTOP(pSSM);
1210
1211 return rc;
1212}
1213
1214static int hgsmiHostLoadFifoEntryLocked (PHGSMIINSTANCE pIns, HGSMIHOSTFIFOENTRY **ppEntry, PSSMHANDLE pSSM)
1215{
1216 HGSMIHOSTFIFOENTRY *pEntry;
1217 int rc = hgsmiHostFIFOAlloc (pIns, &pEntry); AssertRC(rc);
1218 if (RT_SUCCESS (rc))
1219 {
1220 uint32_t u32;
1221 pEntry->pIns = pIns;
1222 rc = SSMR3GetU32 (pSSM, &u32); AssertRC(rc);
1223 pEntry->fl = u32;
1224 rc = SSMR3GetU32 (pSSM, &pEntry->offBuffer); AssertRC(rc);
1225 if (RT_SUCCESS (rc))
1226 *ppEntry = pEntry;
1227 else
1228 hgsmiHostFIFOFree (pIns, pEntry);
1229 }
1230
1231 return rc;
1232}
1233
1234static int hgsmiHostLoadFifoLocked (PHGSMIINSTANCE pIns, HGSMILIST * pFifo, PSSMHANDLE pSSM)
1235{
1236 VBOXHGSMI_LOAD_FIFOSTART(pSSM);
1237
1238 uint32_t size;
1239 int rc = SSMR3GetU32 (pSSM, &size); AssertRC(rc);
1240 if(RT_SUCCESS(rc) && size)
1241 {
1242 for(uint32_t i = 0; i < size; ++i)
1243 {
1244 HGSMIHOSTFIFOENTRY *pFifoEntry = NULL; /* initialized to shut up gcc */
1245 rc = hgsmiHostLoadFifoEntryLocked (pIns, &pFifoEntry, pSSM);
1246 AssertRCBreak(rc);
1247 hgsmiListAppend (pFifo, &pFifoEntry->entry);
1248 }
1249 }
1250
1251 VBOXHGSMI_LOAD_FIFOSTOP(pSSM);
1252
1253 return rc;
1254}
1255
1256static int hgsmiHostLoadGuestCmdCompletedFifoEntryLocked (PHGSMIINSTANCE pIns, HGSMIGUESTCOMPLENTRY **ppEntry, PSSMHANDLE pSSM)
1257{
1258 HGSMIGUESTCOMPLENTRY *pEntry;
1259 int rc = hgsmiGuestCompletionFIFOAlloc (pIns, &pEntry); AssertRC(rc);
1260 if (RT_SUCCESS (rc))
1261 {
1262 rc = SSMR3GetU32 (pSSM, &pEntry->offBuffer); AssertRC(rc);
1263 if (RT_SUCCESS (rc))
1264 *ppEntry = pEntry;
1265 else
1266 hgsmiGuestCompletionFIFOFree (pIns, pEntry);
1267 }
1268 return rc;
1269}
1270
1271static int hgsmiHostLoadGuestCmdCompletedFifoLocked (PHGSMIINSTANCE pIns, HGSMILIST * pFifo, PSSMHANDLE pSSM, uint32_t u32Version)
1272{
1273 VBOXHGSMI_LOAD_FIFOSTART(pSSM);
1274
1275 uint32_t size;
1276 int rc = SSMR3GetU32 (pSSM, &size); AssertRC(rc);
1277 if(RT_SUCCESS(rc) && size)
1278 {
1279 if (u32Version > VGA_SAVEDSTATE_VERSION_INV_GCMDFIFO)
1280 {
1281 for(uint32_t i = 0; i < size; ++i)
1282 {
1283 HGSMIGUESTCOMPLENTRY *pFifoEntry = NULL; /* initialized to shut up gcc */
1284 rc = hgsmiHostLoadGuestCmdCompletedFifoEntryLocked (pIns, &pFifoEntry, pSSM);
1285 AssertRCBreak(rc);
1286 hgsmiListAppend (pFifo, &pFifoEntry->entry);
1287 }
1288 }
1289 else
1290 {
1291 LogRel(("WARNING: the current saved state version has some 3D support data missing, "
1292 "which may lead to some guest applications function improperly"));
1293 /* just read out all invalid data and discard it */
1294 for(uint32_t i = 0; i < size; ++i)
1295 {
1296 HGSMIHOSTFIFOENTRY *pFifoEntry = NULL; /* initialized to shut up gcc */
1297 rc = hgsmiHostLoadFifoEntryLocked (pIns, &pFifoEntry, pSSM);
1298 AssertRCBreak(rc);
1299 hgsmiHostFIFOFree (pIns, pFifoEntry);
1300 }
1301 }
1302 }
1303
1304 VBOXHGSMI_LOAD_FIFOSTOP(pSSM);
1305
1306 return rc;
1307}
1308
1309int HGSMIHostSaveStateExec (PHGSMIINSTANCE pIns, PSSMHANDLE pSSM)
1310{
1311 VBOXHGSMI_SAVE_START(pSSM);
1312
1313 int rc;
1314
1315 HGSMIOFFSET off = pIns->pHGFlags ? HGSMIPointerToOffset(&pIns->area, (const HGSMIBUFFERHEADER *)pIns->pHGFlags) : HGSMIOFFSET_VOID;
1316 SSMR3PutU32 (pSSM, off);
1317
1318 off = HGSMIHeapHandleLocationOffset(&pIns->hostHeap);
1319 rc = SSMR3PutU32 (pSSM, off);
1320 if(off != HGSMIOFFSET_VOID)
1321 {
1322 SSMR3PutU32 (pSSM, HGSMIHeapOffset(&pIns->hostHeap));
1323 SSMR3PutU32 (pSSM, HGSMIHeapSize(&pIns->hostHeap));
1324 /* need save mem pointer to calculate offset on restore */
1325 SSMR3PutU64 (pSSM, (uint64_t)(uintptr_t)pIns->area.pu8Base);
1326 rc = hgsmiFIFOLock (pIns);
1327 if(RT_SUCCESS(rc))
1328 {
1329 rc = hgsmiHostSaveFifoLocked (&pIns->hostFIFO, pSSM); AssertRC(rc);
1330 rc = hgsmiHostSaveFifoLocked (&pIns->hostFIFORead, pSSM); AssertRC(rc);
1331 rc = hgsmiHostSaveFifoLocked (&pIns->hostFIFOProcessed, pSSM); AssertRC(rc);
1332#ifdef VBOX_WITH_WDDM
1333 rc = hgsmiHostSaveGuestCmdCompletedFifoLocked (&pIns->guestCmdCompleted, pSSM); AssertRC(rc);
1334#endif
1335
1336 hgsmiFIFOUnlock (pIns);
1337 }
1338 }
1339
1340 VBOXHGSMI_SAVE_STOP(pSSM);
1341
1342 return rc;
1343}
1344
1345int HGSMIHostLoadStateExec (PHGSMIINSTANCE pIns, PSSMHANDLE pSSM, uint32_t u32Version)
1346{
1347 if(u32Version < VGA_SAVEDSTATE_VERSION_HGSMI)
1348 return VINF_SUCCESS;
1349
1350 VBOXHGSMI_LOAD_START(pSSM);
1351
1352 int rc;
1353 HGSMIOFFSET off;
1354 rc = SSMR3GetU32(pSSM, &off);
1355 AssertRCReturn(rc, rc);
1356 pIns->pHGFlags = (off != HGSMIOFFSET_VOID) ? (HGSMIHOSTFLAGS*)HGSMIOffsetToPointer (&pIns->area, off) : NULL;
1357
1358 HGSMIHEAP hHeap = pIns->hostHeap;
1359 rc = SSMR3GetU32(pSSM, &off);
1360 AssertRCReturn(rc, rc);
1361 if(off != HGSMIOFFSET_VOID)
1362 {
1363 HGSMIOFFSET offHeap;
1364 SSMR3GetU32(pSSM, &offHeap);
1365 uint32_t cbHeap;
1366 SSMR3GetU32(pSSM, &cbHeap);
1367 uint64_t oldMem;
1368 rc = SSMR3GetU64(pSSM, &oldMem);
1369 AssertRCReturn(rc, rc);
1370
1371 rc = hgsmiHostHeapLock (pIns);
1372 if (RT_SUCCESS (rc))
1373 {
1374 Assert(!pIns->hostHeap.cRefs);
1375 pIns->hostHeap.cRefs = 0;
1376
1377 rc = HGSMIHeapRelocate(&pIns->hostHeap,
1378 pIns->area.pu8Base+offHeap,
1379 off,
1380 uintptr_t(pIns->area.pu8Base) - uintptr_t(oldMem),
1381 cbHeap,
1382 offHeap,
1383 u32Version > VGA_SAVEDSTATE_VERSION_HOST_HEAP);
1384
1385 hgsmiHostHeapUnlock (pIns);
1386 }
1387
1388 if (RT_SUCCESS(rc))
1389 {
1390 rc = hgsmiFIFOLock (pIns);
1391 if(RT_SUCCESS(rc))
1392 {
1393 rc = hgsmiHostLoadFifoLocked (pIns, &pIns->hostFIFO, pSSM);
1394 if (RT_SUCCESS(rc))
1395 rc = hgsmiHostLoadFifoLocked (pIns, &pIns->hostFIFORead, pSSM);
1396 if (RT_SUCCESS(rc))
1397 rc = hgsmiHostLoadFifoLocked (pIns, &pIns->hostFIFOProcessed, pSSM);
1398#ifdef VBOX_WITH_WDDM
1399 if (RT_SUCCESS(rc) && u32Version > VGA_SAVEDSTATE_VERSION_PRE_WDDM)
1400 rc = hgsmiHostLoadGuestCmdCompletedFifoLocked (pIns, &pIns->guestCmdCompleted, pSSM, u32Version);
1401#endif
1402
1403 hgsmiFIFOUnlock (pIns);
1404 }
1405 }
1406 }
1407
1408 VBOXHGSMI_LOAD_STOP(pSSM);
1409
1410 return rc;
1411}
1412
1413/*
1414 * Channels management.
1415 */
1416
1417static int hgsmiChannelMapCreate (PHGSMIINSTANCE pIns,
1418 const char *pszChannel,
1419 uint8_t *pu8Channel)
1420{
1421 /* @todo later */
1422 return VERR_NOT_SUPPORTED;
1423}
1424
1425/* Register a new HGSMI channel by a predefined index.
1426 */
1427int HGSMIHostChannelRegister (PHGSMIINSTANCE pIns,
1428 uint8_t u8Channel,
1429 PFNHGSMICHANNELHANDLER pfnChannelHandler,
1430 void *pvChannelHandler,
1431 HGSMICHANNELHANDLER *pOldHandler)
1432{
1433 LogFlowFunc(("pIns %p, u8Channel %x, pfnChannelHandler %p, pvChannelHandler %p, pOldHandler %p\n",
1434 pIns, u8Channel, pfnChannelHandler, pvChannelHandler, pOldHandler));
1435
1436 AssertReturn(!HGSMI_IS_DYNAMIC_CHANNEL(u8Channel), VERR_INVALID_PARAMETER);
1437 AssertPtrReturn(pIns, VERR_INVALID_PARAMETER);
1438 AssertPtrReturn(pfnChannelHandler, VERR_INVALID_PARAMETER);
1439
1440 int rc = hgsmiLock (pIns);
1441
1442 if (RT_SUCCESS (rc))
1443 {
1444 rc = HGSMIChannelRegister (&pIns->channelInfo, u8Channel, NULL, pfnChannelHandler, pvChannelHandler, pOldHandler);
1445
1446 hgsmiUnlock (pIns);
1447 }
1448
1449 LogFlowFunc(("leave rc = %Rrc\n", rc));
1450
1451 return rc;
1452}
1453
1454/* Register a new HGSMI channel by name.
1455 */
1456int HGSMIChannelRegisterName (PHGSMIINSTANCE pIns,
1457 const char *pszChannel,
1458 PFNHGSMICHANNELHANDLER pfnChannelHandler,
1459 void *pvChannelHandler,
1460 uint8_t *pu8Channel,
1461 HGSMICHANNELHANDLER *pOldHandler)
1462{
1463 LogFlowFunc(("pIns %p, pszChannel %s, pfnChannelHandler %p, pvChannelHandler %p, pu8Channel %p, pOldHandler %p\n",
1464 pIns, pszChannel, pfnChannelHandler, pvChannelHandler, pu8Channel, pOldHandler));
1465
1466 AssertPtrReturn(pIns, VERR_INVALID_PARAMETER);
1467 AssertPtrReturn(pszChannel, VERR_INVALID_PARAMETER);
1468 AssertPtrReturn(pu8Channel, VERR_INVALID_PARAMETER);
1469 AssertPtrReturn(pfnChannelHandler, VERR_INVALID_PARAMETER);
1470
1471 int rc;
1472
1473 /* The pointer to the copy will be saved in the channel description. */
1474 char *pszName = RTStrDup (pszChannel);
1475
1476 if (pszName)
1477 {
1478 rc = hgsmiLock (pIns);
1479
1480 if (RT_SUCCESS (rc))
1481 {
1482 rc = hgsmiChannelMapCreate (pIns, pszName, pu8Channel);
1483
1484 if (RT_SUCCESS (rc))
1485 {
1486 rc = HGSMIChannelRegister (&pIns->channelInfo, *pu8Channel, pszName, pfnChannelHandler, pvChannelHandler, pOldHandler);
1487 }
1488
1489 hgsmiUnlock (pIns);
1490 }
1491
1492 if (RT_FAILURE (rc))
1493 {
1494 RTStrFree (pszName);
1495 }
1496 }
1497 else
1498 {
1499 rc = VERR_NO_MEMORY;
1500 }
1501
1502 LogFlowFunc(("leave rc = %Rrc\n", rc));
1503
1504 return rc;
1505}
1506
1507#if 0
1508/* A wrapper to safely call the handler.
1509 */
1510int HGSMIChannelHandlerCall (PHGSMIINSTANCE pIns,
1511 const HGSMICHANNELHANDLER *pHandler,
1512 const HGSMIBUFFERHEADER *pHeader)
1513{
1514 LogFlowFunc(("pHandler %p, pIns %p, pHeader %p\n", pHandler, pIns, pHeader));
1515
1516 int rc;
1517
1518 if ( pHandler
1519 && pHandler->pfnHandler)
1520 {
1521 void *pvBuffer = HGSMIBufferData (pHeader);
1522 HGSMISIZE cbBuffer = pHeader->u32DataSize;
1523
1524 rc = pHandler->pfnHandler (pIns, pHandler->pvHandler, pHeader->u16ChannelInfo, pvBuffer, cbBuffer);
1525 }
1526 else
1527 {
1528 /* It is a NOOP case here. */
1529 rc = VINF_SUCCESS;
1530 }
1531
1532 LogFlowFunc(("leave rc = %Rrc\n", rc));
1533
1534 return rc;
1535}
1536
1537#endif
1538
1539void *HGSMIOffsetToPointerHost (PHGSMIINSTANCE pIns,
1540 HGSMIOFFSET offBuffer)
1541{
1542 const HGSMIAREA *pArea = &pIns->area;
1543
1544 if ( offBuffer < pArea->offBase
1545 || offBuffer > pArea->offLast)
1546 {
1547 LogFunc(("offset 0x%x is outside the area [0x%x;0x%x]!!!\n", offBuffer, pArea->offBase, pArea->offLast));
1548 return NULL;
1549 }
1550
1551 return HGSMIOffsetToPointer (pArea, offBuffer);
1552}
1553
1554
1555HGSMIOFFSET HGSMIPointerToOffsetHost (PHGSMIINSTANCE pIns,
1556 const void *pv)
1557{
1558 const HGSMIAREA *pArea = &pIns->area;
1559
1560 uintptr_t pBegin = (uintptr_t)pArea->pu8Base;
1561 uintptr_t pEnd = (uintptr_t)pArea->pu8Base + (pArea->cbArea - 1);
1562 uintptr_t p = (uintptr_t)pv;
1563
1564 if ( p < pBegin
1565 || p > pEnd)
1566 {
1567 LogFunc(("pointer %p is outside the area [%p;%p]!!!\n", pv, pBegin, pEnd));
1568 return HGSMIOFFSET_VOID;
1569 }
1570
1571 return HGSMIPointerToOffset (pArea, (HGSMIBUFFERHEADER *)pv);
1572}
1573
1574
1575void *HGSMIContext (PHGSMIINSTANCE pIns)
1576{
1577 uint8_t *p = (uint8_t *)pIns;
1578 return p + sizeof (HGSMIINSTANCE);
1579}
1580
1581/* The guest submitted a buffer. */
1582static DECLCALLBACK(int) hgsmiChannelHandler (void *pvHandler, uint16_t u16ChannelInfo, void *pvBuffer, HGSMISIZE cbBuffer)
1583{
1584 int rc = VINF_SUCCESS;
1585
1586 LogFlowFunc(("pvHandler %p, u16ChannelInfo %d, pvBuffer %p, cbBuffer %u\n",
1587 pvHandler, u16ChannelInfo, pvBuffer, cbBuffer));
1588
1589 PHGSMIINSTANCE pIns = (PHGSMIINSTANCE)pvHandler;
1590
1591 switch (u16ChannelInfo)
1592 {
1593 case HGSMI_CC_HOST_FLAGS_LOCATION:
1594 {
1595 if (cbBuffer < sizeof (HGSMIBUFFERLOCATION))
1596 {
1597 rc = VERR_INVALID_PARAMETER;
1598 break;
1599 }
1600
1601 HGSMIBUFFERLOCATION *pLoc = (HGSMIBUFFERLOCATION *)pvBuffer;
1602 if(pLoc->cbLocation != sizeof(HGSMIHOSTFLAGS))
1603 {
1604 rc = VERR_INVALID_PARAMETER;
1605 break;
1606 }
1607
1608 pIns->pHGFlags = (HGSMIHOSTFLAGS*)HGSMIOffsetToPointer (&pIns->area, pLoc->offLocation);
1609 } break;
1610
1611 default:
1612 Log(("Unsupported HGSMI guest command %d!!!\n",
1613 u16ChannelInfo));
1614 break;
1615 }
1616
1617 return rc;
1618}
1619
1620static HGSMICHANNELHANDLER sOldChannelHandler;
1621
1622int HGSMICreate (PHGSMIINSTANCE *ppIns,
1623 PVM pVM,
1624 const char *pszName,
1625 HGSMIOFFSET offBase,
1626 uint8_t *pu8MemBase,
1627 HGSMISIZE cbMem,
1628 PFNHGSMINOTIFYGUEST pfnNotifyGuest,
1629 void *pvNotifyGuest,
1630 size_t cbContext)
1631{
1632 LogFlowFunc(("ppIns = %p, pVM = %p, pszName = [%s], pu8MemBase = %p, cbMem = 0x%08X, offMemBase = 0x%08X, "
1633 "pfnNotifyGuest = %p, pvNotifyGuest = %p, cbContext = %d\n",
1634 ppIns,
1635 pVM,
1636 pszName,
1637 pu8MemBase,
1638 cbMem,
1639 pfnNotifyGuest,
1640 pvNotifyGuest,
1641 cbContext
1642 ));
1643
1644 AssertPtrReturn(ppIns, VERR_INVALID_PARAMETER);
1645 AssertPtrReturn(pVM, VERR_INVALID_PARAMETER);
1646 AssertPtrReturn(pu8MemBase, VERR_INVALID_PARAMETER);
1647
1648 int rc = VINF_SUCCESS;
1649
1650 PHGSMIINSTANCE pIns = (PHGSMIINSTANCE)RTMemAllocZ (sizeof (HGSMIINSTANCE) + cbContext);
1651
1652 if (!pIns)
1653 {
1654 rc = VERR_NO_MEMORY;
1655 }
1656
1657 if (RT_SUCCESS (rc))
1658 {
1659 rc = HGSMIAreaInitialize (&pIns->area, pu8MemBase, cbMem, offBase);
1660 }
1661
1662 if (RT_SUCCESS (rc))
1663 {
1664 rc = RTCritSectInit (&pIns->instanceCritSect);
1665 }
1666
1667 if (RT_SUCCESS (rc))
1668 {
1669 rc = RTCritSectInit (&pIns->hostHeapCritSect);
1670 }
1671
1672 if (RT_SUCCESS (rc))
1673 {
1674 rc = RTCritSectInit (&pIns->hostFIFOCritSect);
1675 }
1676
1677 if (RT_SUCCESS (rc))
1678 {
1679 pIns->pVM = pVM;
1680
1681 pIns->pszName = VALID_PTR(pszName)? pszName: "";
1682
1683 HGSMIHeapSetupUnitialized (&pIns->hostHeap);
1684
1685 pIns->pfnNotifyGuest = pfnNotifyGuest;
1686 pIns->pvNotifyGuest = pvNotifyGuest;
1687 }
1688
1689 rc = HGSMIHostChannelRegister (pIns,
1690 HGSMI_CH_HGSMI,
1691 hgsmiChannelHandler,
1692 pIns,
1693 &sOldChannelHandler);
1694
1695 if (RT_SUCCESS (rc))
1696 {
1697 *ppIns = pIns;
1698 }
1699 else
1700 {
1701 HGSMIDestroy (pIns);
1702 }
1703
1704 LogFlowFunc(("leave rc = %Rrc, pIns = %p\n", rc, pIns));
1705
1706 return rc;
1707}
1708
1709uint32_t HGSMIReset (PHGSMIINSTANCE pIns)
1710{
1711 uint32_t flags = 0;
1712 if(pIns->pHGFlags)
1713 {
1714 /* treat the abandoned commands as read.. */
1715 while(HGSMIHostRead (pIns) != HGSMIOFFSET_VOID) {}
1716 flags = pIns->pHGFlags->u32HostFlags;
1717 pIns->pHGFlags->u32HostFlags = 0;
1718 }
1719
1720 /* .. and complete them */
1721 while(hgsmiProcessHostCmdCompletion (pIns, 0, true)) {}
1722
1723#ifdef VBOX_WITH_WDDM
1724 while(hgsmiProcessGuestCmdCompletion(pIns) != HGSMIOFFSET_VOID) {}
1725#endif
1726
1727 HGSMIHeapSetupUnitialized (&pIns->hostHeap);
1728
1729 return flags;
1730}
1731
1732void HGSMIDestroy (PHGSMIINSTANCE pIns)
1733{
1734 LogFlowFunc(("pIns = %p\n", pIns));
1735
1736 if (pIns)
1737 {
1738 if (RTCritSectIsInitialized (&pIns->hostHeapCritSect))
1739 {
1740 RTCritSectDelete (&pIns->hostHeapCritSect);
1741 }
1742
1743 if (RTCritSectIsInitialized (&pIns->instanceCritSect))
1744 {
1745 RTCritSectDelete (&pIns->instanceCritSect);
1746 }
1747
1748 if (RTCritSectIsInitialized (&pIns->hostFIFOCritSect))
1749 {
1750 RTCritSectDelete (&pIns->hostFIFOCritSect);
1751 }
1752
1753 memset (pIns, 0, sizeof (HGSMIINSTANCE));
1754
1755 RTMemFree (pIns);
1756 }
1757
1758 LogFlowFunc(("leave\n"));
1759}
1760
1761#ifdef VBOX_WITH_WDDM
1762
1763static int hgsmiGuestCommandComplete (HGSMIINSTANCE *pIns, HGSMIOFFSET offMem)
1764{
1765 HGSMIGUESTCOMPLENTRY *pEntry = NULL;
1766
1767 int rc = hgsmiGuestCompletionFIFOAlloc (pIns, &pEntry);
1768 AssertRC(rc);
1769 if (RT_SUCCESS (rc))
1770 {
1771 pEntry->offBuffer = offMem;
1772
1773 rc = hgsmiFIFOLock(pIns);
1774 AssertRC(rc);
1775 if (RT_SUCCESS (rc))
1776 {
1777 hgsmiListAppend (&pIns->guestCmdCompleted, &pEntry->entry);
1778 ASMAtomicOrU32(&pIns->pHGFlags->u32HostFlags, HGSMIHOSTFLAGS_GCOMMAND_COMPLETED);
1779
1780 hgsmiFIFOUnlock(pIns);
1781 }
1782 else
1783 {
1784 hgsmiGuestCompletionFIFOFree(pIns, pEntry);
1785 }
1786 }
1787
1788 return rc;
1789}
1790
1791int hgsmiCompleteGuestCommand(PHGSMIINSTANCE pIns,
1792 HGSMIOFFSET offBuffer,
1793 bool bDoIrq)
1794{
1795 int rc = hgsmiGuestCommandComplete (pIns, offBuffer);
1796 if (RT_SUCCESS (rc))
1797 {
1798 if(bDoIrq)
1799 {
1800 /* Now guest can read the FIFO, the notification is informational. */
1801 hgsmiNotifyGuest (pIns);
1802 }
1803#ifdef DEBUG_misha
1804 else
1805 {
1806 Assert(0);
1807 }
1808#endif
1809 }
1810 return rc;
1811}
1812
1813int HGSMICompleteGuestCommand(PHGSMIINSTANCE pIns,
1814 void *pvMem,
1815 bool bDoIrq)
1816{
1817 LogFlowFunc(("pIns = %p, pvMem = %p\n", pIns, pvMem));
1818
1819 int rc = VINF_SUCCESS;
1820 HGSMIOFFSET offBuffer = HGSMIHeapBufferOffset (&pIns->hostHeap, pvMem);
1821 Assert(offBuffer != HGSMIOFFSET_VOID);
1822 if (offBuffer != HGSMIOFFSET_VOID)
1823 {
1824 rc = hgsmiCompleteGuestCommand (pIns, offBuffer, bDoIrq);
1825 AssertRC (rc);
1826 }
1827 else
1828 {
1829 LogRel(("invalid cmd offset \n"));
1830 rc = VERR_INVALID_PARAMETER;
1831 }
1832
1833 LogFlowFunc(("rc = %Rrc\n", rc));
1834
1835 return rc;
1836}
1837#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