VirtualBox

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

最後變更 在這個檔案從55422是 55421,由 vboxsync 提交於 10 年 前

HGSMI: cleanup, logging, comments, move legacy host heap support from common code to the host code.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 13.4 KB
 
1/* $Id: HGSMICommon.cpp 55421 2015-04-24 12:00:21Z 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-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.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
103int HGSMIAreaInitialize (HGSMIAREA *pArea, void *pvBase, HGSMISIZE cbArea, HGSMIOFFSET offBase)
104{
105 uint8_t *pu8Base = (uint8_t *)pvBase;
106
107 if ( !pArea /* Check that the area: */
108 || cbArea < HGSMIBufferMinimumSize () /* Large enough. */
109 || pu8Base + cbArea < pu8Base /* No address space wrap. */
110 || offBase > UINT32_C(0xFFFFFFFF) - cbArea /* Area within the 32 bit space: offBase + cbMem <= 0xFFFFFFFF */
111 )
112 {
113 return VERR_INVALID_PARAMETER;
114 }
115
116 pArea->pu8Base = pu8Base;
117 pArea->offBase = offBase;
118 pArea->offLast = cbArea - HGSMIBufferMinimumSize () + offBase;
119 pArea->cbArea = cbArea;
120
121 return VINF_SUCCESS;
122}
123
124void HGSMIAreaClear (HGSMIAREA *pArea)
125{
126 if (pArea)
127 {
128 memset (pArea, 0, sizeof (HGSMIAREA));
129 }
130}
131
132/* Initialize the memory buffer including its checksum.
133 * No changes alloed to the header and the tail after that.
134 */
135HGSMIOFFSET HGSMIBufferInitializeSingle(const HGSMIAREA *pArea,
136 HGSMIBUFFERHEADER *pHeader,
137 HGSMISIZE cbBuffer,
138 uint8_t u8Channel,
139 uint16_t u16ChannelInfo)
140{
141 if ( !pArea
142 || !pHeader
143 || cbBuffer < HGSMIBufferMinimumSize())
144 {
145 return HGSMIOFFSET_VOID;
146 }
147
148 /* Buffer must be within the area:
149 * * header data size do not exceed the maximum data size;
150 * * buffer address is greater than the area base address;
151 * * buffer address is lower than the maximum allowed for the given data size.
152 */
153 HGSMISIZE cbMaximumDataSize = pArea->offLast - pArea->offBase;
154 uint32_t u32DataSize = cbBuffer - HGSMIBufferMinimumSize();
155
156 if ( u32DataSize > cbMaximumDataSize
157 || (uint8_t *)pHeader < pArea->pu8Base
158 || (uint8_t *)pHeader > pArea->pu8Base + cbMaximumDataSize - u32DataSize)
159 {
160 return HGSMIOFFSET_VOID;
161 }
162
163 HGSMIOFFSET offBuffer = HGSMIPointerToOffset (pArea, pHeader);
164
165 pHeader->u8Flags = HGSMI_BUFFER_HEADER_F_SEQ_SINGLE;
166 pHeader->u32DataSize = u32DataSize;
167 pHeader->u8Channel = u8Channel;
168 pHeader->u16ChannelInfo = u16ChannelInfo;
169 memset (pHeader->u.au8Union, 0, sizeof (pHeader->u.au8Union));
170
171 HGSMIBUFFERTAIL *pTail = HGSMIBufferTail (pHeader);
172
173 pTail->u32Reserved = 0;
174 pTail->u32Checksum = HGSMIChecksum (offBuffer, pHeader, pTail);
175
176 return offBuffer;
177}
178
179int HGSMIHeapSetup (HGSMIHEAP *pHeap,
180 void *pvBase,
181 HGSMISIZE cbArea,
182 HGSMIOFFSET offBase,
183 const HGSMIENV *pEnv)
184{
185 if ( !pHeap
186 || !pvBase)
187 {
188 return VERR_INVALID_PARAMETER;
189 }
190
191 int rc = HGSMIAreaInitialize (&pHeap->area, pvBase, cbArea, offBase);
192
193 if (RT_SUCCESS (rc))
194 {
195 rc = HGSMIMAInit(&pHeap->ma, &pHeap->area, NULL, 0, 0, pEnv);
196 if (RT_FAILURE(rc))
197 {
198 HGSMIAreaClear (&pHeap->area);
199 }
200 }
201
202 return rc;
203}
204
205void HGSMIHeapDestroy (HGSMIHEAP *pHeap)
206{
207 if (pHeap)
208 {
209 HGSMIMAUninit(&pHeap->ma);
210 }
211}
212
213void *HGSMIHeapAlloc (HGSMIHEAP *pHeap,
214 HGSMISIZE cbData,
215 uint8_t u8Channel,
216 uint16_t u16ChannelInfo)
217{
218 HGSMISIZE cbAlloc = HGSMIBufferRequiredSize (cbData);
219
220 HGSMIBUFFERHEADER *pHeader = (HGSMIBUFFERHEADER *)HGSMIHeapBufferAlloc (pHeap, cbAlloc);
221 if (!pHeader)
222 return NULL;
223
224 HGSMIOFFSET offBuffer = HGSMIBufferInitializeSingle(HGSMIHeapArea(pHeap), pHeader,
225 cbAlloc, u8Channel, u16ChannelInfo);
226 if (offBuffer == HGSMIOFFSET_VOID)
227 {
228 HGSMIHeapBufferFree(pHeap, pHeader);
229 return NULL;
230 }
231
232 return HGSMIBufferData (pHeader);
233}
234
235void HGSMIHeapFree (HGSMIHEAP *pHeap,
236 void *pvData)
237{
238 if (pvData)
239 {
240 HGSMIBUFFERHEADER *pHeader = HGSMIBufferHeaderFromData (pvData);
241
242 HGSMIHeapBufferFree (pHeap, pHeader);
243 }
244}
245
246void* HGSMIHeapBufferAlloc (HGSMIHEAP *pHeap, HGSMISIZE cbBuffer)
247{
248 void *pvBuf = HGSMIMAAlloc(&pHeap->ma, cbBuffer);
249 return pvBuf;
250}
251
252void HGSMIHeapBufferFree(HGSMIHEAP *pHeap,
253 void *pvBuf)
254{
255 HGSMIMAFree(&pHeap->ma, pvBuf);
256}
257
258typedef struct HGSMIBUFFERCONTEXT
259{
260 const HGSMIBUFFERHEADER *pHeader; /* The original buffer header. */
261 void *pvData; /* Payload data in the buffer./ */
262 uint32_t cbData; /* Size of data */
263} HGSMIBUFFERCONTEXT;
264
265/* Verify that the given offBuffer points to a valid buffer, which is within the area.
266 */
267static int hgsmiVerifyBuffer(const HGSMIAREA *pArea,
268 HGSMIOFFSET offBuffer,
269 HGSMIBUFFERCONTEXT *pBufferContext)
270{
271 LogFlowFunc(("buffer 0x%x, area %p %x [0x%x;0x%x]\n",
272 offBuffer, pArea->pu8Base, pArea->cbArea, pArea->offBase, pArea->offLast));
273
274 int rc = VINF_SUCCESS;
275
276 if ( offBuffer < pArea->offBase
277 || offBuffer > pArea->offLast)
278 {
279 LogFunc(("offset 0x%x is outside the area [0x%x;0x%x]!!!\n",
280 offBuffer, pArea->offBase, pArea->offLast));
281 rc = VERR_INVALID_PARAMETER;
282 HGSMI_STRICT_ASSERT_FAILED();
283 }
284 else
285 {
286 void *pvBuffer = HGSMIOffsetToPointer(pArea, offBuffer);
287 HGSMIBUFFERHEADER header = *HGSMIBufferHeaderFromPtr(pvBuffer);
288
289 /* Quick check of the data size, it should be less than the maximum
290 * data size for the buffer at this offset.
291 */
292 LogFlowFunc(("datasize check: header.u32DataSize = 0x%x pArea->offLast - offBuffer = 0x%x\n",
293 header.u32DataSize, pArea->offLast - offBuffer));
294
295 if (header.u32DataSize <= pArea->offLast - offBuffer)
296 {
297 HGSMIBUFFERTAIL tail = *HGSMIBufferTailFromPtr(pvBuffer, header.u32DataSize);
298
299 /* At least both header and tail structures are in the area. Check the checksum. */
300 uint32_t u32Checksum = HGSMIChecksum(offBuffer, &header, &tail);
301 LogFlowFunc(("checksum check: u32Checksum = 0x%x pTail->u32Checksum = 0x%x\n",
302 u32Checksum, tail.u32Checksum));
303 if (u32Checksum == tail.u32Checksum)
304 {
305 /* Success. */
306 pBufferContext->pHeader = HGSMIBufferHeaderFromPtr(pvBuffer);
307 pBufferContext->pvData = HGSMIBufferDataFromPtr(pvBuffer);
308 pBufferContext->cbData = header.u32DataSize;
309 }
310 else
311 {
312 LogFunc(("invalid checksum 0x%x, expected 0x%x!!!\n",
313 u32Checksum, tail.u32Checksum));
314 rc = VERR_INVALID_STATE;
315 HGSMI_STRICT_ASSERT_FAILED();
316 }
317 }
318 else
319 {
320 LogFunc(("invalid data size 0x%x, maximum is 0x%x!!!\n",
321 header.u32DataSize, pArea->offLast - offBuffer));
322 rc = VERR_TOO_MUCH_DATA;
323 HGSMI_STRICT_ASSERT_FAILED();
324 }
325 }
326
327 return rc;
328}
329
330/* A wrapper to safely call the handler.
331 */
332static void hgsmiChannelHandlerCall(const HGSMICHANNELHANDLER *pHandler,
333 const HGSMIBUFFERCONTEXT *pBufferContext)
334{
335 LogFlowFunc(("pHandler %p\n", pHandler));
336
337 if ( pHandler
338 && pHandler->pfnHandler)
339 {
340 pHandler->pfnHandler(pHandler->pvHandler, pBufferContext->pHeader->u16ChannelInfo,
341 pBufferContext->pvData, pBufferContext->cbData);
342 }
343}
344
345/** Helper to convert HGSMI channel index to the channel structure pointer.
346 *
347 * @returns Pointer to the channel data.
348 * @param pChannelInfo The channel pool.
349 * @param u8Channel The channel index.
350 */
351HGSMICHANNEL *HGSMIChannelFindById(HGSMICHANNELINFO *pChannelInfo,
352 uint8_t u8Channel)
353{
354 AssertCompile(RT_ELEMENTS(pChannelInfo->Channels) >= 0x100);
355 HGSMICHANNEL *pChannel = &pChannelInfo->Channels[u8Channel];
356
357 if (pChannel->u8Flags & HGSMI_CH_F_REGISTERED)
358 {
359 return pChannel;
360 }
361
362 return NULL;
363}
364
365/** Process a guest buffer.
366 *
367 * @returns VBox status.
368 * @param pArea Area which supposed to contain the buffer.
369 * @param pChannelInfo The channel pool.
370 * @param offBuffer The buffer location in the area.
371 */
372int HGSMIBufferProcess(HGSMIAREA *pArea,
373 HGSMICHANNELINFO *pChannelInfo,
374 HGSMIOFFSET offBuffer)
375{
376 LogFlowFunc(("pArea %p, offBuffer 0x%x\n", pArea, offBuffer));
377
378 AssertPtrReturn(pArea, VERR_INVALID_PARAMETER);
379 AssertPtrReturn(pChannelInfo, VERR_INVALID_PARAMETER);
380
381 /* Guest has prepared a command description at 'offBuffer'. */
382 HGSMIBUFFERCONTEXT bufferContext;
383 int rc = hgsmiVerifyBuffer(pArea, offBuffer, &bufferContext);
384 if (RT_SUCCESS(rc))
385 {
386 /* Pass the command to the appropriate handler registered with this instance.
387 * Start with the handler list head, which is the preallocated HGSMI setup channel.
388 */
389 HGSMICHANNEL *pChannel = HGSMIChannelFindById(pChannelInfo, bufferContext.pHeader->u8Channel);
390 if (pChannel)
391 {
392 hgsmiChannelHandlerCall(&pChannel->handler, &bufferContext);
393 HGSMI_STRICT_ASSERT(RT_SUCCESS(hgsmiVerifyBuffer(pArea, offBuffer, &bufferContext)));
394 }
395 else
396 {
397 rc = VERR_INVALID_FUNCTION;
398 HGSMI_STRICT_ASSERT_FAILED();
399 }
400 }
401
402 return rc;
403}
404
405/** Register a new HGSMI channel by index.
406 *
407 * @returns VBox status.
408 * @param pChannelInfo The channel pool managed by the caller.
409 * @param u8Channel Index of the channel.
410 * @param pszName Name of the channel (optional, allocated by the caller).
411 * @param pfnChannelHandler The channel callback.
412 * @param pvChannelHandler The callback pointer.
413 */
414int HGSMIChannelRegister(HGSMICHANNELINFO *pChannelInfo,
415 uint8_t u8Channel,
416 const char *pszName,
417 PFNHGSMICHANNELHANDLER pfnChannelHandler,
418 void *pvChannelHandler)
419{
420 /* Check whether the channel is already registered. */
421 HGSMICHANNEL *pChannel = HGSMIChannelFindById(pChannelInfo, u8Channel);
422 if (pChannel)
423 {
424 HGSMI_STRICT_ASSERT_FAILED();
425 return VERR_ALREADY_EXISTS;
426 }
427
428 /* Channel is not yet registered. */
429 pChannel = &pChannelInfo->Channels[u8Channel];
430
431 pChannel->u8Flags = HGSMI_CH_F_REGISTERED;
432 pChannel->u8Channel = u8Channel;
433
434 pChannel->handler.pfnHandler = pfnChannelHandler;
435 pChannel->handler.pvHandler = pvChannelHandler;
436
437 pChannel->pszName = pszName;
438
439 return VINF_SUCCESS;
440}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette