VirtualBox

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

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

HGSMI,DevVGA: Use the offset based heap for the hostHeap (resides in VRAM). New staved state version for DevVGA for indicating this change.

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