VirtualBox

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

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

Build HGSMI memory allocator (unused)

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