VirtualBox

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

最後變更 在這個檔案從66506是 66506,由 vboxsync 提交於 8 年 前

bugref:8524: Additions/linux: play nicely with distribution-installed Additions
Based on a patch series by Hans de Goede/Red Hat with minor adjustments by Oracle.
Graphics: Add VBoxVideoIPRT.h header
Add a VBoxVideoIPRT.h header, this adds 2 versions of this file:
1) Generic include/VBox/Graphics/VBoxVideoIPRT.h which includes all the header

files needed by files shared with the linux drm driver

2) src/VBox/Additions/linux/drm/VBoxVideoIPRT.h, which replaces the generic

gfx-common.h when building the linux drm driver


The purpose of this is to eventually redefines various iprt and HGSMI bits
in the linux drm driver version to use more linux kernel infrastructure.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 14.2 KB
 
1/* $Id: HGSMICommon.cpp 66506 2017-04-11 09:59:29Z 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-2016 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/** @note commented out all logging statements to avoid pulling the logging
20 * sub-system into places like the Linux kernel driver. Perhaps the best
21 * thing would be to use return enough information for callers to log what
22 * is needed. */
23#define LOG_GROUP LOG_GROUP_HGSMI
24
25#include <VBoxVideoIPRT.h>
26
27#include <HGSMI.h>
28// #include <VBox/log.h>
29
30
31/* Channel flags. */
32#define HGSMI_CH_F_REGISTERED 0x01
33
34/* Assertions for situations which could happen and normally must be processed properly
35 * but must be investigated during development: guest misbehaving, etc.
36 */
37#ifdef HGSMI_STRICT
38#define HGSMI_STRICT_ASSERT_FAILED() AssertFailed()
39#define HGSMI_STRICT_ASSERT(expr) Assert(expr)
40#else
41#define HGSMI_STRICT_ASSERT_FAILED() do {} while (0)
42#define HGSMI_STRICT_ASSERT(expr) do {} while (0)
43#endif /* !HGSMI_STRICT */
44
45/*
46 * We do not want assertions in Linux kernel code to reduce symbol dependencies.
47 */
48#if defined(IN_RING0) && defined(RT_OS_LINUX)
49# define HGSMI_ASSERT_PTR_RETURN(a, b) if (!(a)) return (b)
50#else
51# define HGSMI_ASSERT_PTR_RETURN(a, b) if (!(a)) return (b)
52#endif /* !IN_RING0 && RT_OS_LINUX */
53
54/* One-at-a-Time Hash from
55 * http://www.burtleburtle.net/bob/hash/doobs.html
56 *
57 * ub4 one_at_a_time(char *key, ub4 len)
58 * {
59 * ub4 hash, i;
60 * for (hash=0, i=0; i<len; ++i)
61 * {
62 * hash += key[i];
63 * hash += (hash << 10);
64 * hash ^= (hash >> 6);
65 * }
66 * hash += (hash << 3);
67 * hash ^= (hash >> 11);
68 * hash += (hash << 15);
69 * return hash;
70 * }
71 */
72
73static uint32_t hgsmiHashBegin(void)
74{
75 return 0;
76}
77
78static uint32_t hgsmiHashProcess(uint32_t hash,
79 const void *pvData,
80 size_t cbData)
81{
82 const uint8_t *pu8Data = (const uint8_t *)pvData;
83
84 while (cbData--)
85 {
86 hash += *pu8Data++;
87 hash += (hash << 10);
88 hash ^= (hash >> 6);
89 }
90
91 return hash;
92}
93
94static uint32_t hgsmiHashEnd(uint32_t hash)
95{
96 hash += (hash << 3);
97 hash ^= (hash >> 11);
98 hash += (hash << 15);
99
100 return hash;
101}
102
103uint32_t HGSMIChecksum(HGSMIOFFSET offBuffer,
104 const HGSMIBUFFERHEADER *pHeader,
105 const HGSMIBUFFERTAIL *pTail)
106{
107 uint32_t u32Checksum = hgsmiHashBegin();
108
109 u32Checksum = hgsmiHashProcess(u32Checksum, &offBuffer, sizeof(offBuffer));
110 u32Checksum = hgsmiHashProcess(u32Checksum, pHeader, sizeof(HGSMIBUFFERHEADER));
111 u32Checksum = hgsmiHashProcess(u32Checksum, pTail, RT_OFFSETOF(HGSMIBUFFERTAIL, u32Checksum));
112
113 return hgsmiHashEnd(u32Checksum);
114}
115
116int HGSMIAreaInitialize(HGSMIAREA *pArea,
117 void *pvBase,
118 HGSMISIZE cbArea,
119 HGSMIOFFSET offBase)
120{
121 uint8_t *pu8Base = (uint8_t *)pvBase;
122
123 if ( !pArea /* Check that the area: */
124 || cbArea < HGSMIBufferMinimumSize() /* large enough; */
125 || pu8Base + cbArea < pu8Base /* no address space wrap; */
126 || offBase > UINT32_C(0xFFFFFFFF) - cbArea /* area within the 32 bit space: offBase + cbMem <= 0xFFFFFFFF. */
127 )
128 {
129 return VERR_INVALID_PARAMETER;
130 }
131
132 pArea->pu8Base = pu8Base;
133 pArea->offBase = offBase;
134 pArea->offLast = cbArea - HGSMIBufferMinimumSize() + offBase;
135 pArea->cbArea = cbArea;
136
137 return VINF_SUCCESS;
138}
139
140void HGSMIAreaClear(HGSMIAREA *pArea)
141{
142 if (pArea)
143 {
144 RT_ZERO(*pArea);
145 }
146}
147
148/* Initialize the memory buffer including its checksum.
149 * No changes alloed to the header and the tail after that.
150 */
151HGSMIOFFSET HGSMIBufferInitializeSingle(const HGSMIAREA *pArea,
152 HGSMIBUFFERHEADER *pHeader,
153 HGSMISIZE cbBuffer,
154 uint8_t u8Channel,
155 uint16_t u16ChannelInfo)
156{
157 if ( !pArea
158 || !pHeader
159 || cbBuffer < HGSMIBufferMinimumSize())
160 {
161 return HGSMIOFFSET_VOID;
162 }
163
164 /* Buffer must be within the area:
165 * * header data size do not exceed the maximum data size;
166 * * buffer address is greater than the area base address;
167 * * buffer address is lower than the maximum allowed for the given data size.
168 */
169 HGSMISIZE cbMaximumDataSize = pArea->offLast - pArea->offBase;
170 uint32_t u32DataSize = cbBuffer - HGSMIBufferMinimumSize();
171
172 if ( u32DataSize > cbMaximumDataSize
173 || (uint8_t *)pHeader < pArea->pu8Base
174 || (uint8_t *)pHeader > pArea->pu8Base + cbMaximumDataSize - u32DataSize)
175 {
176 return HGSMIOFFSET_VOID;
177 }
178
179 HGSMIOFFSET offBuffer = HGSMIPointerToOffset(pArea, pHeader);
180
181 pHeader->u8Flags = HGSMI_BUFFER_HEADER_F_SEQ_SINGLE;
182 pHeader->u32DataSize = u32DataSize;
183 pHeader->u8Channel = u8Channel;
184 pHeader->u16ChannelInfo = u16ChannelInfo;
185 RT_ZERO(pHeader->u.au8Union);
186
187 HGSMIBUFFERTAIL *pTail = HGSMIBufferTailFromPtr(pHeader, u32DataSize);
188 pTail->u32Reserved = 0;
189 pTail->u32Checksum = HGSMIChecksum(offBuffer, pHeader, pTail);
190
191 return offBuffer;
192}
193
194int HGSMIHeapSetup(HGSMIHEAP *pHeap,
195 void *pvBase,
196 HGSMISIZE cbArea,
197 HGSMIOFFSET offBase,
198 const HGSMIENV *pEnv)
199{
200 HGSMI_ASSERT_PTR_RETURN(pHeap, VERR_INVALID_PARAMETER);
201 HGSMI_ASSERT_PTR_RETURN(pvBase, VERR_INVALID_PARAMETER);
202
203 int rc = HGSMIAreaInitialize(&pHeap->area, pvBase, cbArea, offBase);
204 if (RT_SUCCESS(rc))
205 {
206 rc = HGSMIMAInit(&pHeap->ma, &pHeap->area, NULL, 0, 0, pEnv);
207 if (RT_FAILURE(rc))
208 {
209 HGSMIAreaClear(&pHeap->area);
210 }
211 }
212
213 return rc;
214}
215
216void HGSMIHeapDestroy(HGSMIHEAP *pHeap)
217{
218 if (pHeap)
219 {
220 HGSMIMAUninit(&pHeap->ma);
221 RT_ZERO(*pHeap);
222 }
223}
224
225void *HGSMIHeapAlloc(HGSMIHEAP *pHeap,
226 HGSMISIZE cbData,
227 uint8_t u8Channel,
228 uint16_t u16ChannelInfo)
229{
230 HGSMISIZE cbAlloc = HGSMIBufferRequiredSize(cbData);
231 HGSMIBUFFERHEADER *pHeader = (HGSMIBUFFERHEADER *)HGSMIHeapBufferAlloc(pHeap, cbAlloc);
232 if (pHeader)
233 {
234 HGSMIOFFSET offBuffer = HGSMIBufferInitializeSingle(HGSMIHeapArea(pHeap), pHeader,
235 cbAlloc, u8Channel, u16ChannelInfo);
236 if (offBuffer == HGSMIOFFSET_VOID)
237 {
238 HGSMIHeapBufferFree(pHeap, pHeader);
239 pHeader = NULL;
240 }
241 }
242
243 return pHeader? HGSMIBufferDataFromPtr(pHeader): NULL;
244}
245
246void HGSMIHeapFree(HGSMIHEAP *pHeap,
247 void *pvData)
248{
249 if (pvData)
250 {
251 HGSMIBUFFERHEADER *pHeader = HGSMIBufferHeaderFromData(pvData);
252 HGSMIHeapBufferFree(pHeap, pHeader);
253 }
254}
255
256void *HGSMIHeapBufferAlloc(HGSMIHEAP *pHeap,
257 HGSMISIZE cbBuffer)
258{
259 void *pvBuf = HGSMIMAAlloc(&pHeap->ma, cbBuffer);
260 return pvBuf;
261}
262
263void HGSMIHeapBufferFree(HGSMIHEAP *pHeap,
264 void *pvBuf)
265{
266 HGSMIMAFree(&pHeap->ma, pvBuf);
267}
268
269typedef struct HGSMIBUFFERCONTEXT
270{
271 const HGSMIBUFFERHEADER *pHeader; /* The original buffer header. */
272 void *pvData; /* Payload data in the buffer./ */
273 uint32_t cbData; /* Size of data */
274} HGSMIBUFFERCONTEXT;
275
276/** Verify that the given offBuffer points to a valid buffer, which is within the area.
277 *
278 * @returns VBox status and the buffer information in pBufferContext.
279 * @param pArea Area which supposed to contain the buffer.
280 * @param offBuffer The buffer location in the area.
281 * @param pBufferContext Where to write information about the buffer.
282 */
283static int hgsmiVerifyBuffer(const HGSMIAREA *pArea,
284 HGSMIOFFSET offBuffer,
285 HGSMIBUFFERCONTEXT *pBufferContext)
286{
287 // LogFlowFunc(("buffer 0x%x, area %p %x [0x%x;0x%x]\n",
288 // offBuffer, pArea->pu8Base, pArea->cbArea, pArea->offBase, pArea->offLast));
289
290 int rc = VINF_SUCCESS;
291
292 if ( offBuffer < pArea->offBase
293 || offBuffer > pArea->offLast)
294 {
295 // LogFunc(("offset 0x%x is outside the area [0x%x;0x%x]!!!\n",
296 // offBuffer, pArea->offBase, pArea->offLast));
297 rc = VERR_INVALID_PARAMETER;
298 HGSMI_STRICT_ASSERT_FAILED();
299 }
300 else
301 {
302 void *pvBuffer = HGSMIOffsetToPointer(pArea, offBuffer);
303 HGSMIBUFFERHEADER header = *HGSMIBufferHeaderFromPtr(pvBuffer);
304
305 /* Quick check of the data size, it should be less than the maximum
306 * data size for the buffer at this offset.
307 */
308 // LogFlowFunc(("datasize check: header.u32DataSize = 0x%x pArea->offLast - offBuffer = 0x%x\n",
309 // header.u32DataSize, pArea->offLast - offBuffer));
310
311 if (header.u32DataSize <= pArea->offLast - offBuffer)
312 {
313 HGSMIBUFFERTAIL tail = *HGSMIBufferTailFromPtr(pvBuffer, header.u32DataSize);
314
315 /* At least both header and tail structures are in the area. Check the checksum. */
316 uint32_t u32Checksum = HGSMIChecksum(offBuffer, &header, &tail);
317 // LogFlowFunc(("checksum check: u32Checksum = 0x%x pTail->u32Checksum = 0x%x\n",
318 // u32Checksum, tail.u32Checksum));
319 if (u32Checksum == tail.u32Checksum)
320 {
321 /* Success. */
322 pBufferContext->pHeader = HGSMIBufferHeaderFromPtr(pvBuffer);
323 pBufferContext->pvData = HGSMIBufferDataFromPtr(pvBuffer);
324 pBufferContext->cbData = header.u32DataSize;
325 }
326 else
327 {
328 // LogFunc(("invalid checksum 0x%x, expected 0x%x!!!\n",
329 // u32Checksum, tail.u32Checksum));
330 rc = VERR_INVALID_STATE;
331 HGSMI_STRICT_ASSERT_FAILED();
332 }
333 }
334 else
335 {
336 // LogFunc(("invalid data size 0x%x, maximum is 0x%x!!!\n",
337 // header.u32DataSize, pArea->offLast - offBuffer));
338 rc = VERR_TOO_MUCH_DATA;
339 HGSMI_STRICT_ASSERT_FAILED();
340 }
341 }
342
343 return rc;
344}
345
346/** Helper to convert HGSMI channel index to the channel structure pointer.
347 *
348 * @returns Pointer to the channel data.
349 * @param pChannelInfo The channel pool.
350 * @param u8Channel The channel index.
351 */
352HGSMICHANNEL *HGSMIChannelFindById(HGSMICHANNELINFO *pChannelInfo,
353 uint8_t u8Channel)
354{
355 AssertCompile(RT_ELEMENTS(pChannelInfo->Channels) >= 0x100);
356 HGSMICHANNEL *pChannel = &pChannelInfo->Channels[u8Channel];
357
358 if (pChannel->u8Flags & HGSMI_CH_F_REGISTERED)
359 {
360 return pChannel;
361 }
362
363 return NULL;
364}
365
366/** Process a guest buffer.
367 *
368 * @returns VBox status code.
369 * @param pArea Area which supposed to contain the buffer.
370 * @param pChannelInfo The channel pool.
371 * @param offBuffer The buffer location in the area.
372 */
373int HGSMIBufferProcess(const HGSMIAREA *pArea,
374 HGSMICHANNELINFO *pChannelInfo,
375 HGSMIOFFSET offBuffer)
376{
377 // LogFlowFunc(("pArea %p, offBuffer 0x%x\n", pArea, offBuffer));
378
379 HGSMI_ASSERT_PTR_RETURN(pArea, VERR_INVALID_PARAMETER);
380 HGSMI_ASSERT_PTR_RETURN(pChannelInfo, VERR_INVALID_PARAMETER);
381
382 /* Guest has prepared a command description at 'offBuffer'. */
383 HGSMIBUFFERCONTEXT bufferContext = { NULL, NULL, 0 }; /* Makes old GCC happier. */
384 int rc = hgsmiVerifyBuffer(pArea, offBuffer, &bufferContext);
385 if (RT_SUCCESS(rc))
386 {
387 /* Pass the command to the appropriate handler registered with this instance.
388 * Start with the handler list head, which is the preallocated HGSMI setup channel.
389 */
390 const HGSMICHANNEL *pChannel = HGSMIChannelFindById(pChannelInfo, bufferContext.pHeader->u8Channel);
391 if (pChannel)
392 {
393 const HGSMICHANNELHANDLER *pHandler = &pChannel->handler;
394 if (pHandler->pfnHandler)
395 {
396 pHandler->pfnHandler(pHandler->pvHandler, bufferContext.pHeader->u16ChannelInfo,
397 bufferContext.pvData, bufferContext.cbData);
398 }
399 HGSMI_STRICT_ASSERT(RT_SUCCESS(hgsmiVerifyBuffer(pArea, offBuffer, &bufferContext)));
400 }
401 else
402 {
403 rc = VERR_INVALID_FUNCTION;
404 HGSMI_STRICT_ASSERT_FAILED();
405 }
406 }
407
408 return rc;
409}
410
411/** Register a new HGSMI channel by index.
412 *
413 * @returns VBox status code.
414 * @param pChannelInfo The channel pool managed by the caller.
415 * @param u8Channel Index of the channel.
416 * @param pszName Name of the channel (optional, allocated by the caller).
417 * @param pfnChannelHandler The channel callback.
418 * @param pvChannelHandler The callback pointer.
419 */
420int HGSMIChannelRegister(HGSMICHANNELINFO *pChannelInfo,
421 uint8_t u8Channel,
422 const char *pszName,
423 PFNHGSMICHANNELHANDLER pfnChannelHandler,
424 void *pvChannelHandler)
425{
426 /* Check whether the channel is already registered. */
427 HGSMICHANNEL *pChannel = HGSMIChannelFindById(pChannelInfo, u8Channel);
428 if (pChannel)
429 {
430 HGSMI_STRICT_ASSERT_FAILED();
431 return VERR_ALREADY_EXISTS;
432 }
433
434 /* Channel is not yet registered. */
435 pChannel = &pChannelInfo->Channels[u8Channel];
436
437 pChannel->u8Flags = HGSMI_CH_F_REGISTERED;
438 pChannel->u8Channel = u8Channel;
439
440 pChannel->handler.pfnHandler = pfnChannelHandler;
441 pChannel->handler.pvHandler = pvChannelHandler;
442
443 pChannel->pszName = pszName;
444
445 return VINF_SUCCESS;
446}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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