VirtualBox

source: vbox/trunk/src/VBox/GuestHost/HGSMI/HGSMICommon.cpp@ 30111

Last change on this file since 30111 was 29798, checked in by vboxsync, 14 years ago

wddm: driver update w/o reboot working; dummy context creation in CreateDevice

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.2 KB
Line 
1/** @file
2 *
3 * VBox Host Guest Shared Memory Interface (HGSMI).
4 * HGSMI functions common for both host and guest.
5 */
6
7/*
8 * Copyright (C) 2006-2009 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#include <iprt/heap.h>
20#include <iprt/string.h>
21
22#include <VBox/HGSMI/HGSMI.h>
23
24//#define LOG_GROUP LOG_GROUP_HGSMI
25//#include <VBox/log.h>
26#define Log(f) do{}while(0)
27#define LogFlowFunc(f) do{}while(0)
28#define LogFunc(f) do{}while(0)
29
30
31/* Channel flags. */
32#define HGSMI_CH_F_REGISTERED 0x01
33
34/* Assertions for situations which could happen and normally must be processed properly
35 * but must be investigated during development: guest misbehaving, etc.
36 */
37#ifdef HGSMI_STRICT
38#define HGSMI_STRICT_ASSERT_FAILED() AssertFailed()
39#define HGSMI_STRICT_ASSERT(expr) Assert(expr)
40#else
41#define HGSMI_STRICT_ASSERT_FAILED() do {} while (0)
42#define HGSMI_STRICT_ASSERT(expr) do {} while (0)
43#endif /* !HGSMI_STRICT */
44
45/* One-at-a-Time Hash from
46 * http://www.burtleburtle.net/bob/hash/doobs.html
47 *
48 * ub4 one_at_a_time(char *key, ub4 len)
49 * {
50 * ub4 hash, i;
51 * for (hash=0, i=0; i<len; ++i)
52 * {
53 * hash += key[i];
54 * hash += (hash << 10);
55 * hash ^= (hash >> 6);
56 * }
57 * hash += (hash << 3);
58 * hash ^= (hash >> 11);
59 * hash += (hash << 15);
60 * return hash;
61 * }
62 */
63
64static uint32_t hgsmiHashBegin (void)
65{
66 return 0;
67}
68
69static uint32_t hgsmiHashProcess (uint32_t hash,
70 const void *pvData,
71 size_t cbData)
72{
73 const uint8_t *pu8Data = (const uint8_t *)pvData;
74
75 while (cbData--)
76 {
77 hash += *pu8Data++;
78 hash += (hash << 10);
79 hash ^= (hash >> 6);
80 }
81
82 return hash;
83}
84
85static uint32_t hgsmiHashEnd (uint32_t hash)
86{
87 hash += (hash << 3);
88 hash ^= (hash >> 11);
89 hash += (hash << 15);
90
91 return hash;
92}
93
94uint32_t HGSMIChecksum (HGSMIOFFSET offBuffer,
95 const HGSMIBUFFERHEADER *pHeader,
96 const HGSMIBUFFERTAIL *pTail)
97{
98 uint32_t u32Checksum = hgsmiHashBegin ();
99
100 u32Checksum = hgsmiHashProcess (u32Checksum, &offBuffer, sizeof (offBuffer));
101 u32Checksum = hgsmiHashProcess (u32Checksum, pHeader, sizeof (HGSMIBUFFERHEADER));
102 u32Checksum = hgsmiHashProcess (u32Checksum, pTail, RT_OFFSETOF(HGSMIBUFFERTAIL, u32Checksum));
103
104 return hgsmiHashEnd (u32Checksum);
105}
106
107static HGSMIOFFSET hgsmiBufferInitializeSingle (const HGSMIAREA *pArea,
108 HGSMIBUFFERHEADER *pHeader,
109 uint32_t u32DataSize,
110 uint8_t u8Channel,
111 uint16_t u16ChannelInfo)
112{
113 if ( !pArea
114 || !pHeader)
115 {
116 return HGSMIOFFSET_VOID;
117 }
118
119 /* Buffer must be within the area:
120 * * header data size do not exceed the maximum data size;
121 * * buffer address is greater than the area base address;
122 * * buffer address is lower than the maximum allowed for the given data size.
123 */
124 HGSMISIZE cbMaximumDataSize = pArea->offLast - pArea->offBase;
125
126 if ( u32DataSize > cbMaximumDataSize
127 || (uint8_t *)pHeader < pArea->pu8Base
128 || (uint8_t *)pHeader > pArea->pu8Base + cbMaximumDataSize - u32DataSize)
129 {
130 return HGSMIOFFSET_VOID;
131 }
132
133 HGSMIOFFSET offBuffer = HGSMIPointerToOffset (pArea, pHeader);
134
135 pHeader->u8Flags = HGSMI_BUFFER_HEADER_F_SEQ_SINGLE;
136 pHeader->u32DataSize = u32DataSize;
137 pHeader->u8Channel = u8Channel;
138 pHeader->u16ChannelInfo = u16ChannelInfo;
139 memset (pHeader->u.au8Union, 0, sizeof (pHeader->u.au8Union));
140
141 HGSMIBUFFERTAIL *pTail = HGSMIBufferTail (pHeader);
142
143 pTail->u32Reserved = 0;
144 pTail->u32Checksum = HGSMIChecksum (offBuffer, pHeader, pTail);
145
146 return offBuffer;
147}
148
149int HGSMIAreaInitialize (HGSMIAREA *pArea, void *pvBase, HGSMISIZE cbArea, HGSMIOFFSET offBase)
150{
151 uint8_t *pu8Base = (uint8_t *)pvBase;
152
153 if ( !pArea /* Check that the area: */
154 || cbArea < HGSMIBufferMinimumSize () /* Large enough. */
155 || pu8Base + cbArea < pu8Base /* No address space wrap. */
156 || offBase > UINT32_C(0xFFFFFFFF) - cbArea /* Area within the 32 bit space: offBase + cbMem <= 0xFFFFFFFF */
157 )
158 {
159 return VERR_INVALID_PARAMETER;
160 }
161
162 pArea->pu8Base = pu8Base;
163 pArea->offBase = offBase;
164 pArea->offLast = cbArea - HGSMIBufferMinimumSize () + offBase;
165 pArea->cbArea = cbArea;
166
167 return VINF_SUCCESS;
168}
169
170void HGSMIAreaClear (HGSMIAREA *pArea)
171{
172 if (pArea)
173 {
174 memset (pArea, 0, sizeof (HGSMIAREA));
175 }
176}
177
178/* Initialize the memory buffer including its checksum.
179 * No changes alloed to the header and the tail after that.
180 */
181HGSMIOFFSET HGSMIBufferInitializeSingle (const HGSMIAREA *pArea,
182 HGSMIBUFFERHEADER *pHeader,
183 HGSMISIZE cbBuffer,
184 uint8_t u8Channel,
185 uint16_t u16ChannelInfo)
186{
187 if (cbBuffer < HGSMIBufferMinimumSize ())
188 {
189 return HGSMIOFFSET_VOID;
190 }
191
192 return hgsmiBufferInitializeSingle (pArea, pHeader, cbBuffer - HGSMIBufferMinimumSize (), u8Channel, u16ChannelInfo);
193}
194
195void HGSMIHeapSetupUnitialized (HGSMIHEAP *pHeap)
196{
197 pHeap->u.hPtr = NIL_RTHEAPSIMPLE;
198 pHeap->cRefs = 0;
199 pHeap->area.cbArea = 0;
200 pHeap->area.offBase = HGSMIOFFSET_VOID;
201 pHeap->area.offLast = HGSMIOFFSET_VOID;
202 pHeap->area.pu8Base = 0;
203 pHeap->fOffsetBased = false;
204}
205
206bool HGSMIHeapIsItialized (HGSMIHEAP *pHeap)
207{
208 return pHeap->u.hPtr != NIL_RTHEAPSIMPLE;
209}
210
211int HGSMIHeapRelocate (HGSMIHEAP *pHeap,
212 void *pvBase,
213 uint32_t offHeapHandle,
214 uintptr_t offDelta,
215 HGSMISIZE cbArea,
216 HGSMIOFFSET offBase,
217 bool fOffsetBased
218 )
219{
220 if ( !pHeap
221 || !pvBase)
222 {
223 return VERR_INVALID_PARAMETER;
224 }
225
226 int rc = HGSMIAreaInitialize (&pHeap->area, pvBase, cbArea, offBase);
227
228 if (RT_SUCCESS (rc))
229 {
230 if (fOffsetBased)
231 pHeap->u.hOff = (RTHEAPOFFSET)((uint8_t *)pvBase + offHeapHandle);
232 else
233 {
234 pHeap->u.hPtr = (RTHEAPSIMPLE)((uint8_t *)pvBase + offHeapHandle);
235 rc = RTHeapSimpleRelocate (pHeap->u.hPtr, offDelta); AssertRC(rc);
236 }
237 if (RT_SUCCESS (rc))
238 {
239 pHeap->cRefs = 0;
240 pHeap->fOffsetBased = fOffsetBased;
241 }
242 else
243 {
244 HGSMIAreaClear (&pHeap->area);
245 }
246 }
247
248 return rc;
249}
250
251int HGSMIHeapSetup (HGSMIHEAP *pHeap,
252 void *pvBase,
253 HGSMISIZE cbArea,
254 HGSMIOFFSET offBase,
255 bool fOffsetBased)
256{
257 if ( !pHeap
258 || !pvBase)
259 {
260 return VERR_INVALID_PARAMETER;
261 }
262
263 int rc = HGSMIAreaInitialize (&pHeap->area, pvBase, cbArea, offBase);
264
265 if (RT_SUCCESS (rc))
266 {
267 if (!fOffsetBased)
268 rc = RTHeapSimpleInit (&pHeap->u.hPtr, pvBase, cbArea);
269 else
270 rc = RTHeapOffsetInit (&pHeap->u.hOff, pvBase, cbArea);
271
272 if (RT_SUCCESS (rc))
273 {
274 pHeap->cRefs = 0;
275 pHeap->fOffsetBased = fOffsetBased;
276 }
277 else
278 {
279 HGSMIAreaClear (&pHeap->area);
280 }
281 }
282
283 return rc;
284}
285
286void HGSMIHeapDestroy (HGSMIHEAP *pHeap)
287{
288 if (pHeap)
289 {
290 Assert(!pHeap->cRefs);
291 pHeap->u.hPtr = NIL_RTHEAPSIMPLE;
292 HGSMIAreaClear (&pHeap->area);
293 pHeap->cRefs = 0;
294 }
295}
296
297void *HGSMIHeapAlloc (HGSMIHEAP *pHeap,
298 HGSMISIZE cbData,
299 uint8_t u8Channel,
300 uint16_t u16ChannelInfo)
301{
302 if (pHeap->u.hPtr == NIL_RTHEAPSIMPLE)
303 {
304 return NULL;
305 }
306
307 size_t cbAlloc = HGSMIBufferRequiredSize (cbData);
308
309 HGSMIBUFFERHEADER *pHeader;
310 if (!pHeap->fOffsetBased)
311 pHeader = (HGSMIBUFFERHEADER *)RTHeapSimpleAlloc (pHeap->u.hPtr, cbAlloc, 0);
312 else
313 pHeader = (HGSMIBUFFERHEADER *)RTHeapOffsetAlloc (pHeap->u.hOff, cbAlloc, 0);
314
315 if (!pHeader)
316 {
317 return NULL;
318 }
319
320 ++pHeap->cRefs;
321
322 hgsmiBufferInitializeSingle (&pHeap->area, pHeader, cbData, u8Channel, u16ChannelInfo);
323
324 return HGSMIBufferData (pHeader);
325}
326
327HGSMIOFFSET HGSMIHeapBufferOffset (HGSMIHEAP *pHeap,
328 void *pvData)
329{
330 HGSMIBUFFERHEADER *pHeader = HGSMIBufferHeaderFromData (pvData);
331
332 HGSMIOFFSET offBuffer = HGSMIPointerToOffset (&pHeap->area, pHeader);
333
334 return offBuffer;
335}
336
337void HGSMIHeapFree (HGSMIHEAP *pHeap,
338 void *pvData)
339{
340 if ( pvData
341 && pHeap->u.hPtr != NIL_RTHEAPSIMPLE)
342 {
343 HGSMIBUFFERHEADER *pHeader = HGSMIBufferHeaderFromData (pvData);
344
345 if (!pHeap->fOffsetBased)
346 RTHeapSimpleFree (pHeap->u.hPtr, pHeader);
347 else
348 RTHeapOffsetFree (pHeap->u.hOff, pHeader);
349
350 --pHeap->cRefs;
351 }
352}
353
354/* Verify that the given offBuffer points to a valid buffer, which is within the area.
355 */
356static const HGSMIBUFFERHEADER *hgsmiVerifyBuffer (const HGSMIAREA *pArea,
357 HGSMIOFFSET offBuffer)
358{
359 AssertPtr(pArea);
360
361 LogFlowFunc(("buffer 0x%x, area %p %x [0x%x;0x%x]\n", offBuffer, pArea->pu8Base, pArea->cbArea, pArea->offBase, pArea->offLast));
362
363 if ( offBuffer < pArea->offBase
364 || offBuffer > pArea->offLast)
365 {
366 LogFunc(("offset 0x%x is outside the area [0x%x;0x%x]!!!\n", offBuffer, pArea->offBase, pArea->offLast));
367 HGSMI_STRICT_ASSERT_FAILED();
368 return NULL;
369 }
370
371 const HGSMIBUFFERHEADER *pHeader = HGSMIOffsetToPointer (pArea, offBuffer);
372
373 /* Quick check of the data size, it should be less than the maximum
374 * data size for the buffer at this offset.
375 */
376 LogFlowFunc(("datasize check: pHeader->u32DataSize = 0x%x pArea->offLast - offBuffer = 0x%x\n", pHeader->u32DataSize, pArea->offLast - offBuffer));
377 if (pHeader->u32DataSize <= pArea->offLast - offBuffer)
378 {
379 HGSMIBUFFERTAIL *pTail = HGSMIBufferTail (pHeader);
380
381 /* At least both pHeader and pTail structures are in the area. Check the checksum. */
382 uint32_t u32Checksum = HGSMIChecksum (offBuffer, pHeader, pTail);
383
384 LogFlowFunc(("checksum check: u32Checksum = 0x%x pTail->u32Checksum = 0x%x\n", u32Checksum, pTail->u32Checksum));
385 if (u32Checksum == pTail->u32Checksum)
386 {
387 LogFlowFunc(("returning %p\n", pHeader));
388 return pHeader;
389 }
390 else
391 {
392 LogFunc(("invalid checksum 0x%x, expected 0x%x!!!\n", u32Checksum, pTail->u32Checksum));
393 HGSMI_STRICT_ASSERT_FAILED();
394 }
395 }
396 else
397 {
398 LogFunc(("invalid data size 0x%x, maximum is 0x%x!!!\n", pHeader->u32DataSize, pArea->offLast - offBuffer));
399 HGSMI_STRICT_ASSERT_FAILED();
400 }
401
402 LogFlowFunc(("returning NULL\n"));
403 return NULL;
404}
405
406/* A wrapper to safely call the handler.
407 */
408int HGSMIChannelHandlerCall (const HGSMICHANNELHANDLER *pHandler,
409 const HGSMIBUFFERHEADER *pHeader)
410{
411 LogFlowFunc(("pHandler %p, pHeader %p\n", pHandler, pHeader));
412
413 int rc;
414
415 Assert(pHandler && pHandler->pfnHandler);
416
417 if ( pHandler
418 && pHandler->pfnHandler)
419 {
420 void *pvBuffer = HGSMIBufferData (pHeader);
421 HGSMISIZE cbBuffer = pHeader->u32DataSize;
422
423 rc = pHandler->pfnHandler (pHandler->pvHandler, pHeader->u16ChannelInfo, pvBuffer, cbBuffer);
424 }
425 else
426 {
427 /* It is a NOOP case here. */
428 rc = VINF_SUCCESS;
429 }
430
431 LogFlowFunc(("leave rc = %Rrc\n", rc));
432
433 return rc;
434}
435
436/*
437 * Process a guest buffer.
438 * @thread EMT
439 */
440static int hgsmiBufferProcess (const HGSMICHANNEL *pChannel,
441 const HGSMIBUFFERHEADER *pHeader)
442{
443 LogFlowFunc(("pChannel %p, pHeader %p\n", pChannel, pHeader));
444
445 int rc = HGSMIChannelHandlerCall (&pChannel->handler,
446 pHeader);
447
448 return rc;
449}
450
451HGSMICHANNEL *HGSMIChannelFindById (HGSMICHANNELINFO * pChannelInfo,
452 uint8_t u8Channel)
453{
454 HGSMICHANNEL *pChannel = &pChannelInfo->Channels[u8Channel];
455
456 if (pChannel->u8Flags & HGSMI_CH_F_REGISTERED)
457 {
458 return pChannel;
459 }
460
461 return NULL;
462}
463
464int HGSMIBufferProcess (HGSMIAREA *pArea,
465 HGSMICHANNELINFO * pChannelInfo,
466 HGSMIOFFSET offBuffer)
467{
468 LogFlowFunc(("pArea %p, offBuffer 0x%x\n", pArea, offBuffer));
469
470 AssertPtr(pArea);
471 AssertPtr(pChannelInfo);
472
473 int rc = VERR_GENERAL_FAILURE;
474
475// VM_ASSERT_EMT(pIns->pVM);
476
477 /* Guest has prepared a command description at 'offBuffer'. */
478 const HGSMIBUFFERHEADER *pHeader = hgsmiVerifyBuffer (pArea, offBuffer);
479 Assert(pHeader);
480 if (pHeader)
481 {
482 /* Pass the command to the appropriate handler registered with this instance.
483 * Start with the handler list head, which is the preallocated HGSMI setup channel.
484 */
485 HGSMICHANNEL *pChannel = HGSMIChannelFindById (pChannelInfo, pHeader->u8Channel);
486 Assert(pChannel);
487 if (pChannel)
488 {
489 hgsmiBufferProcess (pChannel, pHeader);
490 HGSMI_STRICT_ASSERT(hgsmiVerifyBuffer (pArea, offBuffer) != NULL);
491 rc = VINF_SUCCESS;
492 }
493 else
494 {
495 rc = VERR_INVALID_FUNCTION;
496 }
497 }
498 else
499 {
500 rc = VERR_INVALID_HANDLE;
501// LogRel(("HGSMI[%s]: ignored invalid guest buffer 0x%08X!!!\n", pIns->pszName, offBuffer));
502 }
503 return rc;
504}
505
506/* Register a new VBVA channel by index.
507 *
508 */
509int HGSMIChannelRegister (HGSMICHANNELINFO * pChannelInfo,
510 uint8_t u8Channel,
511 const char *pszName,
512 PFNHGSMICHANNELHANDLER pfnChannelHandler,
513 void *pvChannelHandler,
514 HGSMICHANNELHANDLER *pOldHandler)
515{
516 AssertPtrReturn(pOldHandler, VERR_INVALID_PARAMETER);
517
518 /* Check whether the channel is already registered. */
519 HGSMICHANNEL *pChannel = HGSMIChannelFindById (pChannelInfo, u8Channel);
520
521 if (!pChannel)
522 {
523 /* Channel is not yet registered. */
524 pChannel = &pChannelInfo->Channels[u8Channel];
525
526 pChannel->u8Flags = HGSMI_CH_F_REGISTERED;
527 pChannel->u8Channel = u8Channel;
528
529 pChannel->handler.pfnHandler = NULL;
530 pChannel->handler.pvHandler = NULL;
531
532 pChannel->pszName = pszName;
533 }
534
535 *pOldHandler = pChannel->handler;
536
537 pChannel->handler.pfnHandler = pfnChannelHandler;
538 pChannel->handler.pvHandler = pvChannelHandler;
539
540 return VINF_SUCCESS;
541}
542
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