1 /* $Id: HGSMICommon.cpp $ */
3 * VBox Host Guest Shared Memory Interface (HGSMI) - Functions common to both host and guest.
7 * Copyright (C) 2006-2016 Oracle Corporation
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.
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>
23 #include <VBox/HGSMI/HGSMI.h>
28 #define HGSMI_CH_F_REGISTERED 0x01
30 /* Assertions for situations which could happen and normally must be processed properly
31 * but must be investigated during development: guest misbehaving, etc.
34 #define HGSMI_STRICT_ASSERT_FAILED() AssertFailed()
35 #define HGSMI_STRICT_ASSERT(expr) Assert(expr)
37 #define HGSMI_STRICT_ASSERT_FAILED() do {} while (0)
38 #define HGSMI_STRICT_ASSERT(expr) do {} while (0)
39 #endif /* !HGSMI_STRICT */
41 /* One-at-a-Time Hash from
42 * http://www.burtleburtle.net/bob/hash/doobs.html
44 * ub4 one_at_a_time(char *key, ub4 len)
47 * for (hash=0, i=0; i<len; ++i)
50 * hash += (hash << 10);
51 * hash ^= (hash >> 6);
53 * hash += (hash << 3);
54 * hash ^= (hash >> 11);
55 * hash += (hash << 15);
60 static uint32_t hgsmiHashBegin(void)
65 static uint32_t hgsmiHashProcess(uint32_t hash
,
69 const uint8_t *pu8Data
= (const uint8_t *)pvData
;
81 static uint32_t hgsmiHashEnd(uint32_t hash
)
90 uint32_t HGSMIChecksum(HGSMIOFFSET offBuffer
,
91 const HGSMIBUFFERHEADER
*pHeader
,
92 const HGSMIBUFFERTAIL
*pTail
)
94 uint32_t u32Checksum
= hgsmiHashBegin();
96 u32Checksum
= hgsmiHashProcess(u32Checksum
, &offBuffer
, sizeof(offBuffer
));
97 u32Checksum
= hgsmiHashProcess(u32Checksum
, pHeader
, sizeof(HGSMIBUFFERHEADER
));
98 u32Checksum
= hgsmiHashProcess(u32Checksum
, pTail
, RT_OFFSETOF(HGSMIBUFFERTAIL
, u32Checksum
));
100 return hgsmiHashEnd(u32Checksum
);
103 int HGSMIAreaInitialize(HGSMIAREA
*pArea
,
108 uint8_t *pu8Base
= (uint8_t *)pvBase
;
110 if ( !pArea
/* Check that the area: */
111 || cbArea
< HGSMIBufferMinimumSize() /* large enough; */
112 || pu8Base
+ cbArea
< pu8Base
/* no address space wrap; */
113 || offBase
> UINT32_C(0xFFFFFFFF) - cbArea
/* area within the 32 bit space: offBase + cbMem <= 0xFFFFFFFF. */
116 return VERR_INVALID_PARAMETER
;
119 pArea
->pu8Base
= pu8Base
;
120 pArea
->offBase
= offBase
;
121 pArea
->offLast
= cbArea
- HGSMIBufferMinimumSize() + offBase
;
122 pArea
->cbArea
= cbArea
;
127 void HGSMIAreaClear(HGSMIAREA
*pArea
)
135 /* Initialize the memory buffer including its checksum.
136 * No changes alloed to the header and the tail after that.
138 HGSMIOFFSET
HGSMIBufferInitializeSingle(const HGSMIAREA
*pArea
,
139 HGSMIBUFFERHEADER
*pHeader
,
142 uint16_t u16ChannelInfo
)
146 || cbBuffer
< HGSMIBufferMinimumSize())
148 return HGSMIOFFSET_VOID
;
151 /* Buffer must be within the area:
152 * * header data size do not exceed the maximum data size;
153 * * buffer address is greater than the area base address;
154 * * buffer address is lower than the maximum allowed for the given data size.
156 HGSMISIZE cbMaximumDataSize
= pArea
->offLast
- pArea
->offBase
;
157 uint32_t u32DataSize
= cbBuffer
- HGSMIBufferMinimumSize();
159 if ( u32DataSize
> cbMaximumDataSize
160 || (uint8_t *)pHeader
< pArea
->pu8Base
161 || (uint8_t *)pHeader
> pArea
->pu8Base
+ cbMaximumDataSize
- u32DataSize
)
163 return HGSMIOFFSET_VOID
;
166 HGSMIOFFSET offBuffer
= HGSMIPointerToOffset(pArea
, pHeader
);
168 pHeader
->u8Flags
= HGSMI_BUFFER_HEADER_F_SEQ_SINGLE
;
169 pHeader
->u32DataSize
= u32DataSize
;
170 pHeader
->u8Channel
= u8Channel
;
171 pHeader
->u16ChannelInfo
= u16ChannelInfo
;
172 RT_ZERO(pHeader
->u
.au8Union
);
174 HGSMIBUFFERTAIL
*pTail
= HGSMIBufferTailFromPtr(pHeader
, u32DataSize
);
175 pTail
->u32Reserved
= 0;
176 pTail
->u32Checksum
= HGSMIChecksum(offBuffer
, pHeader
, pTail
);
181 int HGSMIHeapSetup(HGSMIHEAP
*pHeap
,
185 const HGSMIENV
*pEnv
)
187 AssertPtrReturn(pHeap
, VERR_INVALID_PARAMETER
);
188 AssertPtrReturn(pvBase
, VERR_INVALID_PARAMETER
);
190 int rc
= HGSMIAreaInitialize(&pHeap
->area
, pvBase
, cbArea
, offBase
);
193 rc
= HGSMIMAInit(&pHeap
->ma
, &pHeap
->area
, NULL
, 0, 0, pEnv
);
196 HGSMIAreaClear(&pHeap
->area
);
203 void HGSMIHeapDestroy(HGSMIHEAP
*pHeap
)
207 HGSMIMAUninit(&pHeap
->ma
);
212 void *HGSMIHeapAlloc(HGSMIHEAP
*pHeap
,
215 uint16_t u16ChannelInfo
)
217 HGSMISIZE cbAlloc
= HGSMIBufferRequiredSize(cbData
);
218 HGSMIBUFFERHEADER
*pHeader
= (HGSMIBUFFERHEADER
*)HGSMIHeapBufferAlloc(pHeap
, cbAlloc
);
221 HGSMIOFFSET offBuffer
= HGSMIBufferInitializeSingle(HGSMIHeapArea(pHeap
), pHeader
,
222 cbAlloc
, u8Channel
, u16ChannelInfo
);
223 if (offBuffer
== HGSMIOFFSET_VOID
)
225 HGSMIHeapBufferFree(pHeap
, pHeader
);
230 return pHeader
? HGSMIBufferDataFromPtr(pHeader
): NULL
;
233 void HGSMIHeapFree(HGSMIHEAP
*pHeap
,
238 HGSMIBUFFERHEADER
*pHeader
= HGSMIBufferHeaderFromData(pvData
);
239 HGSMIHeapBufferFree(pHeap
, pHeader
);
243 void *HGSMIHeapBufferAlloc(HGSMIHEAP
*pHeap
,
246 void *pvBuf
= HGSMIMAAlloc(&pHeap
->ma
, cbBuffer
);
250 void HGSMIHeapBufferFree(HGSMIHEAP
*pHeap
,
253 HGSMIMAFree(&pHeap
->ma
, pvBuf
);
256 typedef struct HGSMIBUFFERCONTEXT
258 const HGSMIBUFFERHEADER
*pHeader
; /* The original buffer header. */
259 void *pvData
; /* Payload data in the buffer./ */
260 uint32_t cbData
; /* Size of data */
261 } HGSMIBUFFERCONTEXT
;
263 /** Verify that the given offBuffer points to a valid buffer, which is within the area.
265 * @returns VBox status and the buffer information in pBufferContext.
266 * @param pArea Area which supposed to contain the buffer.
267 * @param offBuffer The buffer location in the area.
268 * @param pBufferContext Where to write information about the buffer.
270 static int hgsmiVerifyBuffer(const HGSMIAREA
*pArea
,
271 HGSMIOFFSET offBuffer
,
272 HGSMIBUFFERCONTEXT
*pBufferContext
)
274 LogFlowFunc(("buffer 0x%x, area %p %x [0x%x;0x%x]\n",
275 offBuffer
, pArea
->pu8Base
, pArea
->cbArea
, pArea
->offBase
, pArea
->offLast
));
277 int rc
= VINF_SUCCESS
;
279 if ( offBuffer
< pArea
->offBase
280 || offBuffer
> pArea
->offLast
)
282 LogFunc(("offset 0x%x is outside the area [0x%x;0x%x]!!!\n",
283 offBuffer
, pArea
->offBase
, pArea
->offLast
));
284 rc
= VERR_INVALID_PARAMETER
;
285 HGSMI_STRICT_ASSERT_FAILED();
289 void *pvBuffer
= HGSMIOffsetToPointer(pArea
, offBuffer
);
290 HGSMIBUFFERHEADER header
= *HGSMIBufferHeaderFromPtr(pvBuffer
);
292 /* Quick check of the data size, it should be less than the maximum
293 * data size for the buffer at this offset.
295 LogFlowFunc(("datasize check: header.u32DataSize = 0x%x pArea->offLast - offBuffer = 0x%x\n",
296 header
.u32DataSize
, pArea
->offLast
- offBuffer
));
298 if (header
.u32DataSize
<= pArea
->offLast
- offBuffer
)
300 HGSMIBUFFERTAIL tail
= *HGSMIBufferTailFromPtr(pvBuffer
, header
.u32DataSize
);
302 /* At least both header and tail structures are in the area. Check the checksum. */
303 uint32_t u32Checksum
= HGSMIChecksum(offBuffer
, &header
, &tail
);
304 LogFlowFunc(("checksum check: u32Checksum = 0x%x pTail->u32Checksum = 0x%x\n",
305 u32Checksum
, tail
.u32Checksum
));
306 if (u32Checksum
== tail
.u32Checksum
)
309 pBufferContext
->pHeader
= HGSMIBufferHeaderFromPtr(pvBuffer
);
310 pBufferContext
->pvData
= HGSMIBufferDataFromPtr(pvBuffer
);
311 pBufferContext
->cbData
= header
.u32DataSize
;
315 LogFunc(("invalid checksum 0x%x, expected 0x%x!!!\n",
316 u32Checksum
, tail
.u32Checksum
));
317 rc
= VERR_INVALID_STATE
;
318 HGSMI_STRICT_ASSERT_FAILED();
323 LogFunc(("invalid data size 0x%x, maximum is 0x%x!!!\n",
324 header
.u32DataSize
, pArea
->offLast
- offBuffer
));
325 rc
= VERR_TOO_MUCH_DATA
;
326 HGSMI_STRICT_ASSERT_FAILED();
333 /** Helper to convert HGSMI channel index to the channel structure pointer.
335 * @returns Pointer to the channel data.
336 * @param pChannelInfo The channel pool.
337 * @param u8Channel The channel index.
339 HGSMICHANNEL
*HGSMIChannelFindById(HGSMICHANNELINFO
*pChannelInfo
,
342 AssertCompile(RT_ELEMENTS(pChannelInfo
->Channels
) >= 0x100);
343 HGSMICHANNEL
*pChannel
= &pChannelInfo
->Channels
[u8Channel
];
345 if (pChannel
->u8Flags
& HGSMI_CH_F_REGISTERED
)
353 /** Process a guest buffer.
355 * @returns VBox status code.
356 * @param pArea Area which supposed to contain the buffer.
357 * @param pChannelInfo The channel pool.
358 * @param offBuffer The buffer location in the area.
360 int HGSMIBufferProcess(const HGSMIAREA
*pArea
,
361 HGSMICHANNELINFO
*pChannelInfo
,
362 HGSMIOFFSET offBuffer
)
364 LogFlowFunc(("pArea %p, offBuffer 0x%x\n", pArea
, offBuffer
));
366 AssertPtrReturn(pArea
, VERR_INVALID_PARAMETER
);
367 AssertPtrReturn(pChannelInfo
, VERR_INVALID_PARAMETER
);
369 /* Guest has prepared a command description at 'offBuffer'. */
370 HGSMIBUFFERCONTEXT bufferContext
= { NULL
, NULL
, 0 }; /* Makes old GCC happier. */
371 int rc
= hgsmiVerifyBuffer(pArea
, offBuffer
, &bufferContext
);
374 /* Pass the command to the appropriate handler registered with this instance.
375 * Start with the handler list head, which is the preallocated HGSMI setup channel.
377 const HGSMICHANNEL
*pChannel
= HGSMIChannelFindById(pChannelInfo
, bufferContext
.pHeader
->u8Channel
);
380 const HGSMICHANNELHANDLER
*pHandler
= &pChannel
->handler
;
381 if (pHandler
->pfnHandler
)
383 pHandler
->pfnHandler(pHandler
->pvHandler
, bufferContext
.pHeader
->u16ChannelInfo
,
384 bufferContext
.pvData
, bufferContext
.cbData
);
386 HGSMI_STRICT_ASSERT(RT_SUCCESS(hgsmiVerifyBuffer(pArea
, offBuffer
, &bufferContext
)));
390 rc
= VERR_INVALID_FUNCTION
;
391 HGSMI_STRICT_ASSERT_FAILED();
398 /** Register a new HGSMI channel by index.
400 * @returns VBox status code.
401 * @param pChannelInfo The channel pool managed by the caller.
402 * @param u8Channel Index of the channel.
403 * @param pszName Name of the channel (optional, allocated by the caller).
404 * @param pfnChannelHandler The channel callback.
405 * @param pvChannelHandler The callback pointer.
407 int HGSMIChannelRegister(HGSMICHANNELINFO
*pChannelInfo
,
410 PFNHGSMICHANNELHANDLER pfnChannelHandler
,
411 void *pvChannelHandler
)
413 /* Check whether the channel is already registered. */
414 HGSMICHANNEL
*pChannel
= HGSMIChannelFindById(pChannelInfo
, u8Channel
);
417 HGSMI_STRICT_ASSERT_FAILED();
418 return VERR_ALREADY_EXISTS
;
421 /* Channel is not yet registered. */
422 pChannel
= &pChannelInfo
->Channels
[u8Channel
];
424 pChannel
->u8Flags
= HGSMI_CH_F_REGISTERED
;
425 pChannel
->u8Channel
= u8Channel
;
427 pChannel
->handler
.pfnHandler
= pfnChannelHandler
;
428 pChannel
->handler
.pvHandler
= pvChannelHandler
;
430 pChannel
->pszName
= pszName
;