VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Miniport/VBoxVideoHGSMI.cpp@ 34491

Last change on this file since 34491 was 34491, checked in by vboxsync, 14 years ago

VBoxVideo: remove more leading underscores from structure names

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.7 KB
Line 
1/* $Id: VBoxVideoHGSMI.cpp 34491 2010-11-29 22:05:59Z vboxsync $ */
2/** @file
3 * VirtualBox Video miniport driver for NT/2k/XP - HGSMI related functions.
4 */
5
6/*
7 * Copyright (C) 2006-2009 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#include <string.h>
19
20#include "VBoxVideo.h"
21#include "Helper.h"
22
23#include <iprt/asm.h>
24#include <iprt/log.h>
25#include <iprt/thread.h>
26#include <VBox/VMMDev.h>
27#include <VBox/VBoxGuest.h>
28#include <VBox/VBoxVideo.h>
29
30
31/**
32 * Helper function to register secondary displays (DualView). Note that this will not
33 * be available on pre-XP versions, and some editions on XP will fail because they are
34 * intentionally crippled.
35 *
36 * HGSMI variant is a bit different because it uses only HGSMI interface (VBVA channel)
37 * to talk to the host.
38 */
39void VBoxSetupDisplaysHGSMI(PVBOXVIDEO_COMMON pCommon,
40 uint32_t AdapterMemorySize, uint32_t fCaps)
41{
42 /** @todo I simply converted this from Windows error codes. That is wrong,
43 * but we currently freely mix and match those (failure == rc > 0) and iprt
44 * ones (failure == rc < 0) anyway. This needs to be fully reviewed and
45 * fixed. */
46 int rc = VINF_SUCCESS;
47 uint32_t offVRAMBaseMapping, cbMapping, offGuestHeapMemory, cbGuestHeapMemory,
48 offHostFlags, offVRAMHostArea, cbHostArea;
49 Log(("VBoxVideo::VBoxSetupDisplays: pCommon = %p\n", pCommon));
50
51 memset(pCommon, 0, sizeof(*pCommon));
52 pCommon->cbVRAM = AdapterMemorySize;
53 pCommon->cDisplays = 1;
54 pCommon->bHGSMI = VBoxHGSMIIsSupported ();
55 /* Why does this use VBoxVideoCmnMemZero? The MSDN docs say that it should
56 * only be used on mapped display adapter memory. Done with memset above. */
57 // VBoxVideoCmnMemZero(&pCommon->areaHostHeap, sizeof(HGSMIAREA));
58 if (pCommon->bHGSMI)
59 {
60 VBoxHGSMIGetBaseMappingInfo(pCommon->cbVRAM, &offVRAMBaseMapping,
61 &cbMapping, &offGuestHeapMemory,
62 &cbGuestHeapMemory, &offHostFlags);
63
64 /* Map the adapter information. It will be needed for HGSMI IO. */
65 /** @todo all callers of VBoxMapAdapterMemory expect it to use iprt
66 * error codes, but it doesn't. */
67 rc = VBoxMapAdapterMemory (pCommon, &pCommon->pvAdapterInformation,
68 offVRAMBaseMapping, cbMapping);
69 if (RT_FAILURE(rc))
70 {
71 Log(("VBoxVideo::VBoxSetupDisplays: VBoxMapAdapterMemory pvAdapterInfoirrmation failed rc = %d\n",
72 rc));
73
74 pCommon->bHGSMI = false;
75 }
76 else
77 {
78 /* Setup an HGSMI heap within the adapter information area. */
79 rc = VBoxHGSMISetupGuestContext(&pCommon->guestCtx,
80 pCommon->pvAdapterInformation,
81 cbGuestHeapMemory,
82 offVRAMBaseMapping
83 + offGuestHeapMemory);
84
85 if (RT_FAILURE(rc))
86 {
87 Log(("VBoxVideo::VBoxSetupDisplays: HGSMIHeapSetup failed rc = %d\n",
88 rc));
89
90 pCommon->bHGSMI = false;
91 }
92 }
93 }
94
95 /* Setup the host heap and the adapter memory. */
96 if (pCommon->bHGSMI)
97 {
98 VBoxHGSMIGetHostAreaMapping(&pCommon->guestCtx, pCommon->cbVRAM,
99 offVRAMBaseMapping, &offVRAMHostArea,
100 &cbHostArea);
101 if (cbHostArea)
102 {
103
104 /* Map the heap region.
105 *
106 * Note: the heap will be used for the host buffers submitted to the guest.
107 * The miniport driver is responsible for reading FIFO and notifying
108 * display drivers.
109 */
110 pCommon->cbMiniportHeap = cbHostArea;
111 rc = VBoxMapAdapterMemory (pCommon, &pCommon->pvMiniportHeap,
112 offVRAMHostArea, cbHostArea);
113 if (RT_FAILURE(rc))
114 {
115 pCommon->pvMiniportHeap = NULL;
116 pCommon->cbMiniportHeap = 0;
117 pCommon->bHGSMI = false;
118 }
119 else
120 VBoxHGSMISetupHostContext(&pCommon->hostCtx,
121 pCommon->pvAdapterInformation,
122 offHostFlags,
123 pCommon->pvMiniportHeap,
124 offVRAMHostArea, cbHostArea);
125 }
126 else
127 {
128 /* Host has not requested a heap. */
129 pCommon->pvMiniportHeap = NULL;
130 pCommon->cbMiniportHeap = 0;
131 }
132 }
133
134 if (pCommon->bHGSMI)
135 {
136 /* Setup the information for the host. */
137 rc = VBoxHGSMISendHostCtxInfo(&pCommon->guestCtx,
138 offVRAMBaseMapping + offHostFlags,
139 fCaps, offVRAMHostArea,
140 pCommon->cbMiniportHeap);
141
142 if (RT_FAILURE(rc))
143 {
144 pCommon->bHGSMI = false;
145 }
146 }
147
148 /* Check whether the guest supports multimonitors. */
149 if (pCommon->bHGSMI)
150 /* Query the configured number of displays. */
151 pCommon->cDisplays = VBoxHGSMIGetMonitorCount(&pCommon->guestCtx);
152
153 if (!pCommon->bHGSMI)
154 VBoxFreeDisplaysHGSMI(pCommon);
155
156 Log(("VBoxVideo::VBoxSetupDisplays: finished\n"));
157}
158
159static bool VBoxUnmapAdpInfoCallback(void *pvCommon)
160{
161 PVBOXVIDEO_COMMON pCommon = (PVBOXVIDEO_COMMON)pvCommon;
162
163 pCommon->hostCtx.pfHostFlags = NULL;
164 return true;
165}
166
167void VBoxFreeDisplaysHGSMI(PVBOXVIDEO_COMMON pCommon)
168{
169 VBoxUnmapAdapterMemory(pCommon, &pCommon->pvMiniportHeap);
170 HGSMIHeapDestroy(&pCommon->guestCtx.heapCtx);
171
172 /* Unmap the adapter information needed for HGSMI IO. */
173 VBoxSyncToVideoIRQ(pCommon, VBoxUnmapAdpInfoCallback, pCommon);
174 VBoxUnmapAdapterMemory(pCommon, &pCommon->pvAdapterInformation);
175}
176
177
178#ifndef VBOX_WITH_WDDM
179typedef struct _VBVAMINIPORT_CHANNELCONTEXT
180{
181 PFNHGSMICHANNELHANDLER pfnChannelHandler;
182 void *pvChannelHandler;
183}VBVAMINIPORT_CHANNELCONTEXT;
184
185typedef struct _VBVADISP_CHANNELCONTEXT
186{
187 /** The generic command handler builds up a list of commands - in reverse
188 * order! - here */
189 VBVAHOSTCMD *pCmd;
190 bool bValid;
191}VBVADISP_CHANNELCONTEXT;
192
193typedef struct _VBVA_CHANNELCONTEXTS
194{
195 PVBOXVIDEO_COMMON pCommon;
196 uint32_t cUsed;
197 uint32_t cContexts;
198 VBVAMINIPORT_CHANNELCONTEXT mpContext;
199 VBVADISP_CHANNELCONTEXT aContexts[1];
200}VBVA_CHANNELCONTEXTS;
201
202static int vboxVBVADeleteChannelContexts(PVBOXVIDEO_COMMON pCommon,
203 VBVA_CHANNELCONTEXTS * pContext)
204{
205 VBoxVideoCmnMemFreeDriver(pCommon, pContext);
206 return VINF_SUCCESS;
207}
208
209static int vboxVBVACreateChannelContexts(PVBOXVIDEO_COMMON pCommon, VBVA_CHANNELCONTEXTS ** ppContext)
210{
211 uint32_t cDisplays = (uint32_t)pCommon->cDisplays;
212 const size_t size = RT_OFFSETOF(VBVA_CHANNELCONTEXTS, aContexts[cDisplays]);
213 VBVA_CHANNELCONTEXTS * pContext = (VBVA_CHANNELCONTEXTS*)VBoxVideoCmnMemAllocDriver(pCommon, size);
214 if(pContext)
215 {
216 memset(pContext, 0, size);
217 pContext->cContexts = cDisplays;
218 pContext->pCommon = pCommon;
219 *ppContext = pContext;
220 return VINF_SUCCESS;
221 }
222 return VERR_GENERAL_FAILURE;
223}
224
225static VBVADISP_CHANNELCONTEXT* vboxVBVAFindHandlerInfo(VBVA_CHANNELCONTEXTS *pCallbacks, int iId)
226{
227 if(iId < 0)
228 {
229 return NULL;
230 }
231 else if(pCallbacks->cContexts > (uint32_t)iId)
232 {
233 return &pCallbacks->aContexts[iId];
234 }
235 return NULL;
236}
237
238DECLCALLBACK(void) hgsmiHostCmdComplete (HVBOXVIDEOHGSMI hHGSMI, struct VBVAHOSTCMD * pCmd)
239{
240 PHGSMIHOSTCOMMANDCONTEXT pCtx = &((PVBOXVIDEO_COMMON)hHGSMI)->hostCtx;
241 VBoxHGSMIHostCmdComplete(pCtx, pCmd);
242}
243
244/** Reverses a NULL-terminated linked list of VBVAHOSTCMD structures. */
245static VBVAHOSTCMD *vboxVBVAReverseList(VBVAHOSTCMD *pList)
246{
247 VBVAHOSTCMD *pFirst = NULL;
248 while (pList)
249 {
250 VBVAHOSTCMD *pNext = pList;
251 pList = pList->u.pNext;
252 pNext->u.pNext = pFirst;
253 pFirst = pNext;
254 }
255 return pFirst;
256}
257
258DECLCALLBACK(int) hgsmiHostCmdRequest (HVBOXVIDEOHGSMI hHGSMI, uint8_t u8Channel, uint32_t iDevice, struct VBVAHOSTCMD ** ppCmd)
259{
260// if(display < 0)
261// return VERR_INVALID_PARAMETER;
262 if(!ppCmd)
263 return VERR_INVALID_PARAMETER;
264
265 PHGSMIHOSTCOMMANDCONTEXT pCtx = &((PVBOXVIDEO_COMMON)hHGSMI)->hostCtx;
266
267 /* pick up the host commands */
268 VBoxHGSMIProcessHostQueue(pCtx);
269
270 HGSMICHANNEL *pChannel = HGSMIChannelFindById (&pCtx->channels, u8Channel);
271 if(pChannel)
272 {
273 VBVA_CHANNELCONTEXTS * pContexts = (VBVA_CHANNELCONTEXTS *)pChannel->handler.pvHandler;
274 VBVADISP_CHANNELCONTEXT *pDispContext = vboxVBVAFindHandlerInfo(pContexts, iDevice);
275 Assert(pDispContext);
276 if(pDispContext)
277 {
278 VBVAHOSTCMD *pCmd;
279 do
280 pCmd = ASMAtomicReadPtrT(&pDispContext->pCmd, VBVAHOSTCMD *);
281 while (!ASMAtomicCmpXchgPtr(&pDispContext->pCmd, NULL, pCmd));
282 *ppCmd = vboxVBVAReverseList(pCmd);
283
284 return VINF_SUCCESS;
285 }
286 }
287
288 return VERR_INVALID_PARAMETER;
289}
290
291
292static DECLCALLBACK(int) vboxVBVAChannelGenericHandler(void *pvHandler, uint16_t u16ChannelInfo, void *pvBuffer, HGSMISIZE cbBuffer)
293{
294 VBVA_CHANNELCONTEXTS *pCallbacks = (VBVA_CHANNELCONTEXTS*)pvHandler;
295// Assert(0);
296 Assert(cbBuffer > VBVAHOSTCMD_HDRSIZE);
297 if(cbBuffer > VBVAHOSTCMD_HDRSIZE)
298 {
299 VBVAHOSTCMD *pHdr = (VBVAHOSTCMD*)pvBuffer;
300 Assert(pHdr->iDstID >= 0);
301 if(pHdr->iDstID >= 0)
302 {
303 VBVADISP_CHANNELCONTEXT* pHandler = vboxVBVAFindHandlerInfo(pCallbacks, pHdr->iDstID);
304 Assert(pHandler && pHandler->bValid);
305 if(pHandler && pHandler->bValid)
306 {
307 VBVAHOSTCMD *pFirst = NULL, *pLast = NULL;
308 for(VBVAHOSTCMD *pCur = pHdr; pCur; )
309 {
310 Assert(!pCur->u.Data);
311 Assert(!pFirst);
312 Assert(!pLast);
313
314 switch(u16ChannelInfo)
315 {
316 case VBVAHG_DISPLAY_CUSTOM:
317 {
318#if 0 /* Never taken */
319 if(pLast)
320 {
321 pLast->u.pNext = pCur;
322 pLast = pCur;
323 }
324 else
325#endif
326 {
327 pFirst = pCur;
328 pLast = pCur;
329 }
330 Assert(!pCur->u.Data);
331#if 0 /* Who is supposed to set pNext? */
332 //TODO: use offset here
333 pCur = pCur->u.pNext;
334 Assert(!pCur);
335#else
336 Assert(!pCur->u.pNext);
337 pCur = NULL;
338#endif
339 Assert(pFirst);
340 Assert(pFirst == pLast);
341 break;
342 }
343 case VBVAHG_EVENT:
344 {
345 VBVAHOSTCMDEVENT *pEventCmd = VBVAHOSTCMD_BODY(pCur, VBVAHOSTCMDEVENT);
346 VBoxVideoCmnSignalEvent(pCallbacks->pCommon, pEventCmd->pEvent);
347 }
348 default:
349 {
350 Assert(u16ChannelInfo==VBVAHG_EVENT);
351 Assert(!pCur->u.Data);
352#if 0 /* pLast has been asserted to be NULL, and who should set pNext? */
353 //TODO: use offset here
354 if(pLast)
355 pLast->u.pNext = pCur->u.pNext;
356 VBVAHOSTCMD * pNext = pCur->u.pNext;
357 pCur->u.pNext = NULL;
358#else
359 Assert(!pCur->u.pNext);
360#endif
361 VBoxHGSMIHostCmdComplete(&pCallbacks->pCommon->hostCtx, pCur);
362#if 0 /* pNext is NULL, and the other things have already been asserted */
363 pCur = pNext;
364 Assert(!pCur);
365 Assert(!pFirst);
366 Assert(pFirst == pLast);
367#else
368 pCur = NULL;
369#endif
370 break;
371 }
372 }
373 }
374
375 /* we do not support lists currently */
376 Assert(pFirst == pLast);
377 if(pLast)
378 {
379 Assert(pLast->u.pNext == NULL);
380 }
381
382 if(pFirst)
383 {
384 Assert(pLast);
385 VBVAHOSTCMD *pCmd;
386 do
387 {
388 pCmd = ASMAtomicReadPtrT(&pHandler->pCmd, VBVAHOSTCMD *);
389 pFirst->u.pNext = pCmd;
390 }
391 while (!ASMAtomicCmpXchgPtr(&pHandler->pCmd, pFirst, pCmd));
392 }
393 else
394 {
395 Assert(!pLast);
396 }
397 return VINF_SUCCESS;
398 }
399 }
400 else
401 {
402 //TODO: impl
403// HGSMIMINIPORT_CHANNELCONTEXT *pHandler = vboxVideoHGSMIFindHandler;
404// if(pHandler && pHandler->pfnChannelHandler)
405// {
406// pHandler->pfnChannelHandler(pHandler->pvChannelHandler, u16ChannelInfo, pHdr, cbBuffer);
407//
408// return VINF_SUCCESS;
409// }
410 }
411 }
412 /* no handlers were found, need to complete the command here */
413 VBoxHGSMIHostCmdComplete(&pCallbacks->pCommon->hostCtx, pvBuffer);
414 return VINF_SUCCESS;
415}
416
417static HGSMICHANNELHANDLER g_OldHandler;
418
419int vboxVBVAChannelDisplayEnable(PVBOXVIDEO_COMMON pCommon,
420 int iDisplay, /* negative would mean this is a miniport handler */
421 uint8_t u8Channel)
422{
423 VBVA_CHANNELCONTEXTS * pContexts;
424 HGSMICHANNEL * pChannel = HGSMIChannelFindById (&pCommon->hostCtx.channels, u8Channel);
425 if(!pChannel)
426 {
427 int rc = vboxVBVACreateChannelContexts(pCommon, &pContexts);
428 if(RT_FAILURE(rc))
429 {
430 return rc;
431 }
432 }
433 else
434 {
435 pContexts = (VBVA_CHANNELCONTEXTS *)pChannel->handler.pvHandler;
436 }
437
438 VBVADISP_CHANNELCONTEXT *pDispContext = vboxVBVAFindHandlerInfo(pContexts, iDisplay);
439 Assert(pDispContext);
440 if(pDispContext)
441 {
442#ifdef DEBUGVHWASTRICT
443 Assert(!pDispContext->bValid);
444#endif
445 Assert(!pDispContext->pCmd);
446 if(!pDispContext->bValid)
447 {
448 pDispContext->bValid = true;
449 pDispContext->pCmd = NULL;
450
451 int rc = VINF_SUCCESS;
452 if(!pChannel)
453 {
454 rc = HGSMIChannelRegister (&pCommon->hostCtx.channels,
455 u8Channel,
456 "VGA Miniport HGSMI channel",
457 vboxVBVAChannelGenericHandler,
458 pContexts,
459 &g_OldHandler);
460 }
461
462 if(RT_SUCCESS(rc))
463 {
464 pContexts->cUsed++;
465 return VINF_SUCCESS;
466 }
467 }
468 }
469
470 if(!pChannel)
471 {
472 vboxVBVADeleteChannelContexts(pCommon, pContexts);
473 }
474
475 return VERR_GENERAL_FAILURE;
476}
477#endif /* !VBOX_WITH_WDDM */
478
479/** @todo Mouse pointer position to be read from VMMDev memory, address of the memory region
480 * can be queried from VMMDev via an IOCTL. This VMMDev memory region will contain
481 * host information which is needed by the guest.
482 *
483 * Reading will not cause a switch to the host.
484 *
485 * Have to take into account:
486 * * synchronization: host must write to the memory only from EMT,
487 * large structures must be read under flag, which tells the host
488 * that the guest is currently reading the memory (OWNER flag?).
489 * * guest writes: may be allocate a page for the host info and make
490 * the page readonly for the guest.
491 * * the information should be available only for additions drivers.
492 * * VMMDev additions driver will inform the host which version of the info it expects,
493 * host must support all versions.
494 *
495 */
496
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