VirtualBox

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

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

fixed OSE headers

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.6 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 > 0xFFFFFFFFU - 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->heap = 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}
208
209bool HGSMIHeapIsItialized (HGSMIHEAP *pHeap)
210{
211 return pHeap->heap != NIL_RTHEAPSIMPLE;
212}
213
214int HGSMIHeapRelocate (HGSMIHEAP *pHeap,
215 void *pvBase,
216 uint32_t offHeapHandle,
217 uintptr_t offDelta,
218 HGSMISIZE cbArea,
219 HGSMIOFFSET offBase
220 )
221{
222 if ( !pHeap
223 || !pvBase)
224 {
225 return VERR_INVALID_PARAMETER;
226 }
227
228 int rc = HGSMIAreaInitialize (&pHeap->area, pvBase, cbArea, offBase);
229
230 if (RT_SUCCESS (rc))
231 {
232 pHeap->heap = (RTHEAPSIMPLE)(((uint8_t*)pvBase) + offHeapHandle);
233 rc = RTHeapSimpleRelocate (pHeap->heap, offDelta); AssertRC(rc);
234 if (RT_SUCCESS (rc))
235 {
236 pHeap->cRefs = 0;
237 }
238 else
239 {
240 HGSMIAreaClear (&pHeap->area);
241 }
242 }
243
244 return rc;
245}
246
247int HGSMIHeapSetup (HGSMIHEAP *pHeap,
248 void *pvBase,
249 HGSMISIZE cbArea,
250 HGSMIOFFSET offBase)
251{
252 if ( !pHeap
253 || !pvBase)
254 {
255 return VERR_INVALID_PARAMETER;
256 }
257
258 int rc = HGSMIAreaInitialize (&pHeap->area, pvBase, cbArea, offBase);
259
260 if (RT_SUCCESS (rc))
261 {
262 rc = RTHeapSimpleInit (&pHeap->heap, pvBase, cbArea);
263
264 if (RT_SUCCESS (rc))
265 {
266 pHeap->cRefs = 0;
267 }
268 else
269 {
270 HGSMIAreaClear (&pHeap->area);
271 }
272 }
273
274 return rc;
275}
276
277void HGSMIHeapDestroy (HGSMIHEAP *pHeap)
278{
279 if (pHeap)
280 {
281 pHeap->heap = NIL_RTHEAPSIMPLE;
282 HGSMIAreaClear (&pHeap->area);
283 pHeap->cRefs = 0;
284 }
285}
286
287void *HGSMIHeapAlloc (HGSMIHEAP *pHeap,
288 HGSMISIZE cbData,
289 uint8_t u8Channel,
290 uint16_t u16ChannelInfo)
291{
292 if (pHeap->heap == NIL_RTHEAPSIMPLE)
293 {
294 return NULL;
295 }
296
297 size_t cbAlloc = HGSMIBufferRequiredSize (cbData);
298
299 HGSMIBUFFERHEADER *pHeader = (HGSMIBUFFERHEADER *)RTHeapSimpleAlloc (pHeap->heap, cbAlloc, 0);
300
301 if (!pHeader)
302 {
303 return NULL;
304 }
305
306 ++pHeap->cRefs;
307
308 hgsmiBufferInitializeSingle (&pHeap->area, pHeader, cbData, u8Channel, u16ChannelInfo);
309
310 return HGSMIBufferData (pHeader);
311}
312
313HGSMIOFFSET HGSMIHeapBufferOffset (HGSMIHEAP *pHeap,
314 void *pvData)
315{
316 HGSMIBUFFERHEADER *pHeader = HGSMIBufferHeaderFromData (pvData);
317
318 HGSMIOFFSET offBuffer = HGSMIPointerToOffset (&pHeap->area, pHeader);
319
320 return offBuffer;
321}
322
323void HGSMIHeapFree (HGSMIHEAP *pHeap,
324 void *pvData)
325{
326 if ( pvData
327 && pHeap->heap != NIL_RTHEAPSIMPLE)
328 {
329 HGSMIBUFFERHEADER *pHeader = HGSMIBufferHeaderFromData (pvData);
330
331 RTHeapSimpleFree (pHeap->heap, pHeader);
332
333 --pHeap->cRefs;
334 }
335}
336
337/* Verify that the given offBuffer points to a valid buffer, which is within the area.
338 */
339static const HGSMIBUFFERHEADER *hgsmiVerifyBuffer (const HGSMIAREA *pArea,
340 HGSMIOFFSET offBuffer)
341{
342 AssertPtr(pArea);
343
344 LogFlowFunc(("buffer 0x%x, area %p %x [0x%x;0x%x]\n", offBuffer, pArea->pu8Base, pArea->cbArea, pArea->offBase, pArea->offLast));
345
346 if ( offBuffer < pArea->offBase
347 || offBuffer > pArea->offLast)
348 {
349 LogFunc(("offset 0x%x is outside the area [0x%x;0x%x]!!!\n", offBuffer, pArea->offBase, pArea->offLast));
350 HGSMI_STRICT_ASSERT_FAILED();
351 return NULL;
352 }
353
354 const HGSMIBUFFERHEADER *pHeader = HGSMIOffsetToPointer (pArea, offBuffer);
355
356 /* Quick check of the data size, it should be less than the maximum
357 * data size for the buffer at this offset.
358 */
359 LogFlowFunc(("datasize check: pHeader->u32DataSize = 0x%x pArea->offLast - offBuffer = 0x%x\n", pHeader->u32DataSize, pArea->offLast - offBuffer));
360 if (pHeader->u32DataSize <= pArea->offLast - offBuffer)
361 {
362 HGSMIBUFFERTAIL *pTail = HGSMIBufferTail (pHeader);
363
364 /* At least both pHeader and pTail structures are in the area. Check the checksum. */
365 uint32_t u32Checksum = HGSMIChecksum (offBuffer, pHeader, pTail);
366
367 LogFlowFunc(("checksum check: u32Checksum = 0x%x pTail->u32Checksum = 0x%x\n", u32Checksum, pTail->u32Checksum));
368 if (u32Checksum == pTail->u32Checksum)
369 {
370 LogFlowFunc(("returning %p\n", pHeader));
371 return pHeader;
372 }
373 else
374 {
375 LogFunc(("invalid checksum 0x%x, expected 0x%x!!!\n", u32Checksum, pTail->u32Checksum));
376 HGSMI_STRICT_ASSERT_FAILED();
377 }
378 }
379 else
380 {
381 LogFunc(("invalid data size 0x%x, maximum is 0x%x!!!\n", pHeader->u32DataSize, pArea->offLast - offBuffer));
382 HGSMI_STRICT_ASSERT_FAILED();
383 }
384
385 LogFlowFunc(("returning NULL\n"));
386 return NULL;
387}
388
389/* A wrapper to safely call the handler.
390 */
391int HGSMIChannelHandlerCall (const HGSMICHANNELHANDLER *pHandler,
392 const HGSMIBUFFERHEADER *pHeader)
393{
394 LogFlowFunc(("pHandler %p, pHeader %p\n", pHandler, pHeader));
395
396 int rc;
397
398 Assert(pHandler && pHandler->pfnHandler);
399
400 if ( pHandler
401 && pHandler->pfnHandler)
402 {
403 void *pvBuffer = HGSMIBufferData (pHeader);
404 HGSMISIZE cbBuffer = pHeader->u32DataSize;
405
406 rc = pHandler->pfnHandler (pHandler->pvHandler, pHeader->u16ChannelInfo, pvBuffer, cbBuffer);
407 }
408 else
409 {
410 /* It is a NOOP case here. */
411 rc = VINF_SUCCESS;
412 }
413
414 LogFlowFunc(("leave rc = %Rrc\n", rc));
415
416 return rc;
417}
418
419/*
420 * Process a guest buffer.
421 * @thread EMT
422 */
423static int hgsmiBufferProcess (const HGSMICHANNEL *pChannel,
424 const HGSMIBUFFERHEADER *pHeader)
425{
426 LogFlowFunc(("pChannel %p, pHeader %p\n", pChannel, pHeader));
427
428 int rc = HGSMIChannelHandlerCall (&pChannel->handler,
429 pHeader);
430
431 return rc;
432}
433
434HGSMICHANNEL *HGSMIChannelFindById (HGSMICHANNELINFO * pChannelInfo,
435 uint8_t u8Channel)
436{
437 HGSMICHANNEL *pChannel = &pChannelInfo->Channels[u8Channel];
438
439 if (pChannel->u8Flags & HGSMI_CH_F_REGISTERED)
440 {
441 return pChannel;
442 }
443
444 return NULL;
445}
446
447int HGSMIBufferProcess (HGSMIAREA *pArea,
448 HGSMICHANNELINFO * pChannelInfo,
449 HGSMIOFFSET offBuffer)
450{
451 LogFlowFunc(("pArea %p, offBuffer 0x%x\n", pArea, offBuffer));
452
453 AssertPtr(pArea);
454 AssertPtr(pChannelInfo);
455
456 int rc = VERR_GENERAL_FAILURE;
457
458// VM_ASSERT_EMT(pIns->pVM);
459
460 /* Guest has prepared a command description at 'offBuffer'. */
461 const HGSMIBUFFERHEADER *pHeader = hgsmiVerifyBuffer (pArea, offBuffer);
462 Assert(pHeader);
463 if (pHeader)
464 {
465 /* Pass the command to the appropriate handler registered with this instance.
466 * Start with the handler list head, which is the preallocated HGSMI setup channel.
467 */
468 HGSMICHANNEL *pChannel = HGSMIChannelFindById (pChannelInfo, pHeader->u8Channel);
469 Assert(pChannel);
470 if (pChannel)
471 {
472 hgsmiBufferProcess (pChannel, pHeader);
473 HGSMI_STRICT_ASSERT(hgsmiVerifyBuffer (pArea, offBuffer) != NULL);
474 rc = VINF_SUCCESS;
475 }
476 else
477 {
478 rc = VERR_INVALID_FUNCTION;
479 }
480 }
481 else
482 {
483 rc = VERR_INVALID_HANDLE;
484// LogRel(("HGSMI[%s]: ignored invalid guest buffer 0x%08X!!!\n", pIns->pszName, offBuffer));
485 }
486 return rc;
487}
488
489/* Register a new VBVA channel by index.
490 *
491 */
492int HGSMIChannelRegister (HGSMICHANNELINFO * pChannelInfo,
493 uint8_t u8Channel,
494 const char *pszName,
495 PFNHGSMICHANNELHANDLER pfnChannelHandler,
496 void *pvChannelHandler,
497 HGSMICHANNELHANDLER *pOldHandler)
498{
499 AssertPtrReturn(pOldHandler, VERR_INVALID_PARAMETER);
500
501 /* Check whether the channel is already registered. */
502 HGSMICHANNEL *pChannel = HGSMIChannelFindById (pChannelInfo, u8Channel);
503
504 if (!pChannel)
505 {
506 /* Channel is not yet registered. */
507 pChannel = &pChannelInfo->Channels[u8Channel];
508
509 pChannel->u8Flags = HGSMI_CH_F_REGISTERED;
510 pChannel->u8Channel = u8Channel;
511
512 pChannel->handler.pfnHandler = NULL;
513 pChannel->handler.pvHandler = NULL;
514
515 pChannel->pszName = pszName;
516 }
517
518 *pOldHandler = pChannel->handler;
519
520 pChannel->handler.pfnHandler = pfnChannelHandler;
521 pChannel->handler.pvHandler = pvChannelHandler;
522
523 return VINF_SUCCESS;
524}
525
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