VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Miniport/wddm/VBoxVideoMisc.cpp@ 33879

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

adds burn fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 42.1 KB
Line 
1/*
2 * Copyright (C) 2010 Oracle Corporation
3 *
4 * This file is part of VirtualBox Open Source Edition (OSE), as
5 * available from http://www.virtualbox.org. This file is free software;
6 * you can redistribute it and/or modify it under the terms of the GNU
7 * General Public License (GPL) as published by the Free Software
8 * Foundation, in version 2 as it comes in the "COPYING" file of the
9 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
10 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
11 */
12
13#include "../VBoxVideo.h"
14#include "../Helper.h"
15
16#include <iprt/asm.h>
17
18#include <stdio.h>
19
20NTSTATUS vboxWddmHTableCreate(PVBOXWDDM_HTABLE pTbl, uint32_t cSize)
21{
22 memset(pTbl, 0, sizeof (*pTbl));
23 pTbl->paData = (PVOID*)vboxWddmMemAllocZero(sizeof (pTbl->paData[0]) * cSize);
24 if (pTbl->paData)
25 {
26 pTbl->cSize = cSize;
27 return STATUS_SUCCESS;
28 }
29 return STATUS_NO_MEMORY;
30}
31
32VOID vboxWddmHTableDestroy(PVBOXWDDM_HTABLE pTbl)
33{
34 vboxWddmMemFree(pTbl->paData);
35}
36
37DECLINLINE(VBOXWDDM_HANDLE) vboxWddmHTableIndex2Handle(uint32_t iIndex)
38{
39 return iIndex+1;
40}
41
42DECLINLINE(uint32_t) vboxWddmHTableHandle2Index(VBOXWDDM_HANDLE hHandle)
43{
44 return hHandle-1;
45}
46
47NTSTATUS vboxWddmHTableRealloc(PVBOXWDDM_HTABLE pTbl, uint32_t cNewSize)
48{
49 Assert(cNewSize > pTbl->cSize);
50 if (cNewSize > pTbl->cSize)
51 {
52 PVOID *pvNewData = (PVOID*)vboxWddmMemAllocZero(sizeof (pTbl->paData[0]) * cNewSize);
53 memcpy(pvNewData, pTbl->paData, sizeof (pTbl->paData[0]) * pTbl->cSize);
54 pTbl->iNext2Search = pTbl->cSize;
55 pTbl->cSize = cNewSize;
56 pTbl->paData = pvNewData;
57 return STATUS_SUCCESS;
58 }
59 else if (cNewSize >= pTbl->cData)
60 return STATUS_NOT_IMPLEMENTED;
61 return STATUS_INVALID_PARAMETER;
62
63}
64VBOXWDDM_HANDLE vboxWddmHTablePut(PVBOXWDDM_HTABLE pTbl, PVOID pvData)
65{
66 if (pTbl->cSize == pTbl->cData)
67 {
68 Assert(0);
69 NTSTATUS Status = vboxWddmHTableRealloc(pTbl, pTbl->cSize + RT_MAX(10, pTbl->cSize/4));
70 Assert(Status == STATUS_SUCCESS);
71 if (Status != STATUS_SUCCESS)
72 return VBOXWDDM_HANDLE_INVALID;
73 }
74 for (UINT i = pTbl->iNext2Search; ; ++i, i %= pTbl->cSize)
75 {
76 Assert(i < pTbl->cSize);
77 if (!pTbl->paData[i])
78 {
79 pTbl->paData[i] = pvData;
80 ++pTbl->cData;
81 Assert(pTbl->cData <= pTbl->cSize);
82 ++pTbl->iNext2Search;
83 pTbl->iNext2Search %= pTbl->cSize;
84 return vboxWddmHTableIndex2Handle(i);
85 }
86 }
87 Assert(0);
88 return VBOXWDDM_HANDLE_INVALID;
89}
90
91PVOID vboxWddmHTableRemove(PVBOXWDDM_HTABLE pTbl, VBOXWDDM_HANDLE hHandle)
92{
93 uint32_t iIndex = vboxWddmHTableHandle2Index(hHandle);
94 Assert(iIndex < pTbl->cSize);
95 if (iIndex < pTbl->cSize)
96 {
97 PVOID pvData = pTbl->paData[iIndex];
98 pTbl->paData[iIndex] = NULL;
99 --pTbl->cData;
100 Assert(pTbl->cData <= pTbl->cSize);
101 pTbl->iNext2Search = iIndex;
102 return pvData;
103 }
104 return NULL;
105}
106
107PVOID vboxWddmHTableGet(PVBOXWDDM_HTABLE pTbl, VBOXWDDM_HANDLE hHandle)
108{
109 uint32_t iIndex = vboxWddmHTableHandle2Index(hHandle);
110 Assert(iIndex < pTbl->cSize);
111 if (iIndex < pTbl->cSize)
112 return pTbl->paData[iIndex];
113 return NULL;
114}
115
116VOID vboxWddmHTableIterInit(PVBOXWDDM_HTABLE pTbl, PVBOXWDDM_HTABLE_ITERATOR pIter)
117{
118 pIter->pTbl = pTbl;
119 pIter->iCur = ~0UL;
120 pIter->cLeft = pTbl->cData;
121}
122
123BOOL vboxWddmHTableIterHasNext(PVBOXWDDM_HTABLE_ITERATOR pIter)
124{
125 return pIter->cLeft;
126}
127
128
129PVOID vboxWddmHTableIterNext(PVBOXWDDM_HTABLE_ITERATOR pIter, VBOXWDDM_HANDLE *phHandle)
130{
131 if (vboxWddmHTableIterHasNext(pIter))
132 {
133 for (uint32_t i = pIter->iCur+1; i < pIter->pTbl->cSize ; ++i)
134 {
135 if (pIter->pTbl->paData[i])
136 {
137 pIter->iCur = i;
138 --pIter->cLeft;
139 VBOXWDDM_HANDLE hHandle = vboxWddmHTableIndex2Handle(i);
140 Assert(hHandle);
141 if (phHandle)
142 *phHandle = hHandle;
143 return pIter->pTbl->paData[i];
144 }
145 }
146 }
147
148 Assert(!vboxWddmHTableIterHasNext(pIter));
149 if (phHandle)
150 *phHandle = VBOXWDDM_HANDLE_INVALID;
151 return NULL;
152}
153
154
155PVOID vboxWddmHTableIterRemoveCur(PVBOXWDDM_HTABLE_ITERATOR pIter)
156{
157 VBOXWDDM_HANDLE hHandle = vboxWddmHTableIndex2Handle(pIter->iCur);
158 Assert(hHandle);
159 if (hHandle)
160 {
161 PVOID pRet = vboxWddmHTableRemove(pIter->pTbl, hHandle);
162 Assert(pRet);
163 return pRet;
164 }
165 return NULL;
166}
167
168PVBOXWDDM_SWAPCHAIN vboxWddmSwapchainCreate()
169{
170 PVBOXWDDM_SWAPCHAIN pSwapchain = (PVBOXWDDM_SWAPCHAIN)vboxWddmMemAllocZero(sizeof (VBOXWDDM_SWAPCHAIN));
171 Assert(pSwapchain);
172 if (pSwapchain)
173 {
174 InitializeListHead(&pSwapchain->AllocList);
175 pSwapchain->enmState = VBOXWDDM_OBJSTATE_TYPE_INITIALIZED;
176 pSwapchain->cRefs = 1;
177 }
178 return pSwapchain;
179}
180
181DECLINLINE(BOOLEAN) vboxWddmSwapchainRetainLocked(PVBOXWDDM_SWAPCHAIN pSwapchain)
182{
183 if (pSwapchain->enmState == VBOXWDDM_OBJSTATE_TYPE_INITIALIZED)
184 {
185 ASMAtomicIncU32(&pSwapchain->cRefs);
186 return TRUE;
187 }
188 return FALSE;
189}
190
191DECLINLINE(BOOLEAN) vboxWddmSwapchainRetain(PDEVICE_EXTENSION pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain)
192{
193 KIRQL OldIrql;
194 BOOLEAN bRc;
195 KeAcquireSpinLock(&pDevExt->SynchLock, &OldIrql);
196 bRc = vboxWddmSwapchainRetainLocked(pSwapchain);
197 KeReleaseSpinLock(&pDevExt->SynchLock, OldIrql);
198 return bRc;
199}
200
201DECLINLINE(VOID) vboxWddmSwapchainRelease(PVBOXWDDM_SWAPCHAIN pSwapchain)
202{
203 uint32_t cRefs = ASMAtomicDecU32(&pSwapchain->cRefs);
204 Assert(cRefs < UINT32_MAX/2);
205 if (!cRefs)
206 vboxWddmMemFree(pSwapchain);
207}
208
209PVBOXWDDM_SWAPCHAIN vboxWddmSwapchainRetainByAlloc(PDEVICE_EXTENSION pDevExt, PVBOXWDDM_ALLOCATION pAlloc)
210{
211 KIRQL OldIrql;
212 PVBOXWDDM_SWAPCHAIN pSwapchain;
213 KeAcquireSpinLock(&pDevExt->SynchLock, &OldIrql);
214 pSwapchain = pAlloc->pSwapchain;
215 if (pSwapchain && !vboxWddmSwapchainRetainLocked(pSwapchain))
216 pSwapchain = NULL;
217 KeReleaseSpinLock(&pDevExt->SynchLock, OldIrql);
218 return pSwapchain;
219}
220
221VOID vboxWddmSwapchainAllocRemove(PDEVICE_EXTENSION pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain, PVBOXWDDM_ALLOCATION pAlloc)
222{
223 KIRQL OldIrql;
224 KeAcquireSpinLock(&pDevExt->SynchLock, &OldIrql);
225 Assert(pAlloc->pSwapchain == pSwapchain);
226 pAlloc->pSwapchain = NULL;
227 RemoveEntryList(&pAlloc->SwapchainEntry);
228 KeReleaseSpinLock(&pDevExt->SynchLock, OldIrql);
229 vboxWddmSwapchainRelease(pSwapchain);
230}
231
232BOOLEAN vboxWddmSwapchainAllocAdd(PDEVICE_EXTENSION pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain, PVBOXWDDM_ALLOCATION pAlloc)
233{
234 KIRQL OldIrql;
235 BOOLEAN bRc;
236 Assert(!pAlloc->pSwapchain);
237 KeAcquireSpinLock(&pDevExt->SynchLock, &OldIrql);
238 bRc = vboxWddmSwapchainRetainLocked(pSwapchain);
239 if (bRc)
240 {
241 if (pAlloc->pSwapchain)
242 {
243 RemoveEntryList(&pAlloc->SwapchainEntry);
244 }
245 InsertTailList(&pSwapchain->AllocList, &pAlloc->SwapchainEntry);
246 pAlloc->pSwapchain = pSwapchain;
247 }
248 KeReleaseSpinLock(&pDevExt->SynchLock, OldIrql);
249 return bRc;
250}
251
252#define VBOXSCENTRY_2_ALLOC(_pE) ((PVBOXWDDM_ALLOCATION)((uint8_t*)(_pE) - RT_OFFSETOF(VBOXWDDM_ALLOCATION, SwapchainEntry)))
253
254static VOID vboxWddmSwapchainAllocRemoveAllInternal(PDEVICE_EXTENSION pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain, BOOLEAN bOnDestroy)
255{
256 KIRQL OldIrql;
257 UINT cRemoved = 0;
258 KeAcquireSpinLock(&pDevExt->SynchLock, &OldIrql);
259 PLIST_ENTRY pEntry = pSwapchain->AllocList.Flink;
260 do
261 {
262 if (pEntry != &pSwapchain->AllocList)
263 {
264 PVBOXWDDM_ALLOCATION pAlloc = VBOXSCENTRY_2_ALLOC(pEntry);
265 pEntry = pEntry->Flink;
266 Assert(pAlloc->pSwapchain == pSwapchain);
267 pAlloc->pSwapchain = NULL;
268 RemoveEntryList(&pAlloc->SwapchainEntry);
269 ++cRemoved;
270 }
271 else
272 break;
273 } while (1);
274
275 if (bOnDestroy)
276 pSwapchain->enmState = VBOXWDDM_OBJSTATE_TYPE_TERMINATED;
277 KeReleaseSpinLock(&pDevExt->SynchLock, OldIrql);
278
279 for (UINT i = 0; i < cRemoved; ++i)
280 vboxWddmSwapchainRelease(pSwapchain);
281}
282
283VOID vboxWddmSwapchainAllocRemoveAll(PDEVICE_EXTENSION pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain)
284{
285 vboxWddmSwapchainAllocRemoveAllInternal(pDevExt, pSwapchain, FALSE);
286}
287
288VOID vboxWddmSwapchainDestroy(PDEVICE_EXTENSION pDevExt, PVBOXWDDM_SWAPCHAIN pSwapchain)
289{
290 vboxWddmSwapchainAllocRemoveAllInternal(pDevExt, pSwapchain, TRUE);
291 vboxWddmSwapchainRelease(pSwapchain);
292}
293
294static BOOLEAN vboxWddmSwapchainCtxAddLocked(PDEVICE_EXTENSION pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXWDDM_SWAPCHAIN pSwapchain)
295{
296 if (vboxWddmSwapchainRetain(pDevExt, pSwapchain))
297 {
298 Assert(!pSwapchain->hSwapchainKm);
299 Assert(!pSwapchain->pContext);
300 pSwapchain->pContext = pContext;
301 pSwapchain->hSwapchainKm = vboxWddmHTablePut(&pContext->Swapchains, pSwapchain);
302 InsertHeadList(&pDevExt->SwapchainList3D, &pSwapchain->DevExtListEntry);
303 return TRUE;
304 }
305 return FALSE;
306}
307
308static VOID vboxWddmSwapchainCtxRemoveLocked(PDEVICE_EXTENSION pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXWDDM_SWAPCHAIN pSwapchain)
309{
310 Assert(pSwapchain->hSwapchainKm);
311 Assert(pSwapchain->pContext);
312 void * pTst = vboxWddmHTableRemove(&pContext->Swapchains, pSwapchain->hSwapchainKm);
313 Assert(pTst == pSwapchain);
314 RemoveEntryList(&pSwapchain->DevExtListEntry);
315 pSwapchain->pContext = NULL;
316 pSwapchain->hSwapchainKm = NULL;
317 if (pSwapchain->pLastReportedRects)
318 {
319 vboxVideoCmCmdRelease(pSwapchain->pLastReportedRects);
320 pSwapchain->pLastReportedRects = NULL;
321 }
322 vboxWddmSwapchainRelease(pSwapchain);
323}
324
325BOOLEAN vboxWddmSwapchainCtxAdd(PDEVICE_EXTENSION pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXWDDM_SWAPCHAIN pSwapchain)
326{
327 BOOLEAN bRc;
328 ExAcquireFastMutex(&pDevExt->ContextMutex);
329 bRc = vboxWddmSwapchainCtxAddLocked(pDevExt, pContext, pSwapchain);
330 ExReleaseFastMutex(&pDevExt->ContextMutex);
331 return bRc;
332}
333
334VOID vboxWddmSwapchainCtxRemove(PDEVICE_EXTENSION pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXWDDM_SWAPCHAIN pSwapchain)
335{
336 ExAcquireFastMutex(&pDevExt->ContextMutex);
337 vboxWddmSwapchainCtxRemoveLocked(pDevExt, pContext, pSwapchain);
338 ExReleaseFastMutex(&pDevExt->ContextMutex);
339}
340
341VOID vboxWddmSwapchainCtxDestroyAll(PDEVICE_EXTENSION pDevExt, PVBOXWDDM_CONTEXT pContext)
342{
343 VBOXWDDM_HTABLE_ITERATOR Iter;
344 ExAcquireFastMutex(&pDevExt->ContextMutex);
345 vboxWddmHTableIterInit(&pContext->Swapchains, &Iter);
346 do
347 {
348 PVBOXWDDM_SWAPCHAIN pSwapchain = (PVBOXWDDM_SWAPCHAIN)vboxWddmHTableIterNext(&Iter, NULL);
349 if (!pSwapchain)
350 break;
351
352 /* yes, we can call remove locked even when using iterator */
353 vboxWddmSwapchainCtxRemoveLocked(pDevExt, pContext, pSwapchain);
354// vboxWddmHTableIterRemoveCur(&Iter);
355
356 vboxWddmSwapchainDestroy(pDevExt, pSwapchain);
357 } while (1);
358 ExReleaseFastMutex(&pDevExt->ContextMutex);
359}
360
361NTSTATUS vboxWddmSwapchainCtxEscape(PDEVICE_EXTENSION pDevExt, PVBOXWDDM_CONTEXT pContext, PVBOXDISPIFESCAPE_SWAPCHAININFO pSwapchainInfo, UINT cbSize)
362{
363 Assert((cbSize >= RT_OFFSETOF(VBOXDISPIFESCAPE_SWAPCHAININFO, SwapchainInfo.ahAllocs[0])));
364 if (cbSize < RT_OFFSETOF(VBOXDISPIFESCAPE_SWAPCHAININFO, SwapchainInfo.ahAllocs[0]))
365 return STATUS_INVALID_PARAMETER;
366 Assert(cbSize >= RT_OFFSETOF(VBOXDISPIFESCAPE_SWAPCHAININFO, SwapchainInfo.ahAllocs[pSwapchainInfo->SwapchainInfo.cAllocs]));
367 if (cbSize < RT_OFFSETOF(VBOXDISPIFESCAPE_SWAPCHAININFO, SwapchainInfo.ahAllocs[pSwapchainInfo->SwapchainInfo.cAllocs]))
368 return STATUS_INVALID_PARAMETER;
369
370 PVBOXWDDM_SWAPCHAIN pSwapchain;
371 PVBOXWDDM_ALLOCATION *apAlloc = NULL;
372 if (pSwapchainInfo->SwapchainInfo.cAllocs)
373 {
374 apAlloc = (PVBOXWDDM_ALLOCATION *)vboxWddmMemAlloc(sizeof (PVBOXWDDM_ALLOCATION) * pSwapchainInfo->SwapchainInfo.cAllocs);
375 Assert(apAlloc);
376 if (!apAlloc)
377 return STATUS_NO_MEMORY;
378 for (UINT i = 0; i < pSwapchainInfo->SwapchainInfo.cAllocs; ++i)
379 {
380 DXGKARGCB_GETHANDLEDATA GhData;
381 GhData.hObject = pSwapchainInfo->SwapchainInfo.ahAllocs[i];
382 GhData.Type = DXGK_HANDLE_ALLOCATION;
383 GhData.Flags.Value = 0;
384 PVBOXWDDM_ALLOCATION pAlloc = (PVBOXWDDM_ALLOCATION)pDevExt->u.primary.DxgkInterface.DxgkCbGetHandleData(&GhData);
385 Assert(pAlloc);
386 if (!pAlloc)
387 return STATUS_INVALID_PARAMETER;
388 apAlloc[i] = pAlloc;
389 }
390 }
391
392 if (pSwapchainInfo->SwapchainInfo.hSwapchainKm)
393 {
394// ExAcquireFastMutex(&pContext->SwapchainMutex);
395 ExAcquireFastMutex(&pDevExt->ContextMutex);
396 pSwapchain = (PVBOXWDDM_SWAPCHAIN)vboxWddmHTableGet(&pContext->Swapchains, (VBOXWDDM_HANDLE)pSwapchainInfo->SwapchainInfo.hSwapchainKm);
397 Assert(pSwapchain);
398 if (!pSwapchain)
399 {
400 ExReleaseFastMutex(&pDevExt->ContextMutex);
401 return STATUS_INVALID_PARAMETER;
402 }
403 Assert(pSwapchain->hSwapchainKm == pSwapchainInfo->SwapchainInfo.hSwapchainKm);
404 Assert(pSwapchain->pContext == pContext);
405 if (pSwapchain->pContext != pContext)
406 {
407 ExReleaseFastMutex(&pDevExt->ContextMutex);
408 return STATUS_INVALID_PARAMETER;
409 }
410 }
411 else if (pSwapchainInfo->SwapchainInfo.cAllocs)
412 {
413 pSwapchain = vboxWddmSwapchainCreate();
414 if (!pSwapchain)
415 return STATUS_NO_MEMORY;
416
417 ExAcquireFastMutex(&pDevExt->ContextMutex);
418 BOOLEAN bRc = vboxWddmSwapchainCtxAddLocked(pDevExt, pContext, pSwapchain);
419 Assert(bRc);
420 }
421 else
422 return STATUS_INVALID_PARAMETER;
423
424 memset(&pSwapchain->ViewRect, 0, sizeof (pSwapchain->ViewRect));
425 if (pSwapchain->pLastReportedRects)
426 {
427 vboxVideoCmCmdRelease(pSwapchain->pLastReportedRects);
428 pSwapchain->pLastReportedRects = NULL;
429 }
430
431 vboxWddmSwapchainAllocRemoveAll(pDevExt, pSwapchain);
432
433 if (pSwapchainInfo->SwapchainInfo.cAllocs)
434 {
435 for (UINT i = 0; i < pSwapchainInfo->SwapchainInfo.cAllocs; ++i)
436 {
437 vboxWddmSwapchainAllocAdd(pDevExt, pSwapchain, apAlloc[i]);
438 }
439 pSwapchain->hSwapchainUm = pSwapchainInfo->SwapchainInfo.hSwapchainUm;
440 }
441 else
442 {
443 vboxWddmSwapchainCtxRemoveLocked(pDevExt, pContext, pSwapchain);
444 }
445
446// ExReleaseFastMutex(&pContext->SwapchainMutex);
447 ExReleaseFastMutex(&pDevExt->ContextMutex);
448
449 if (pSwapchainInfo->SwapchainInfo.cAllocs)
450 {
451 Assert(pSwapchain->pContext);
452 Assert(pSwapchain->hSwapchainKm);
453 pSwapchainInfo->SwapchainInfo.hSwapchainKm = pSwapchain->hSwapchainKm;
454 }
455 else
456 {
457 vboxWddmSwapchainDestroy(pDevExt, pSwapchain);
458 pSwapchainInfo->SwapchainInfo.hSwapchainKm = 0;
459 }
460
461 return STATUS_SUCCESS;
462}
463
464#define VBOXWDDM_REG_DRVKEY_PREFIX L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\"
465
466NTSTATUS vboxWddmRegQueryDrvKeyName(PDEVICE_EXTENSION pDevExt, ULONG cbBuf, PWCHAR pBuf, PULONG pcbResult)
467{
468 WCHAR fallBackBuf[2];
469 PWCHAR pSuffix;
470 bool bFallback = false;
471
472 if (cbBuf > sizeof(VBOXWDDM_REG_DRVKEY_PREFIX))
473 {
474 memcpy(pBuf, VBOXWDDM_REG_DRVKEY_PREFIX, sizeof (VBOXWDDM_REG_DRVKEY_PREFIX));
475 pSuffix = pBuf + (sizeof (VBOXWDDM_REG_DRVKEY_PREFIX)-2)/2;
476 cbBuf -= sizeof (VBOXWDDM_REG_DRVKEY_PREFIX)-2;
477 }
478 else
479 {
480 pSuffix = fallBackBuf;
481 cbBuf = sizeof (fallBackBuf);
482 bFallback = true;
483 }
484
485 NTSTATUS Status = IoGetDeviceProperty (pDevExt->pPDO,
486 DevicePropertyDriverKeyName,
487 cbBuf,
488 pSuffix,
489 &cbBuf);
490 if (Status == STATUS_SUCCESS && bFallback)
491 Status = STATUS_BUFFER_TOO_SMALL;
492 if (Status == STATUS_BUFFER_TOO_SMALL)
493 *pcbResult = cbBuf + sizeof (VBOXWDDM_REG_DRVKEY_PREFIX)-2;
494
495 return Status;
496}
497
498#define VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_VISTA L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\Current\\System\\CurrentControlSet\\Control\\VIDEO\\"
499#define VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_WIN7 L"\\Registry\\Machine\\System\\CurrentControlSet\\Hardware Profiles\\UnitedVideo\\CONTROL\\VIDEO\\"
500
501#define VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_RELX L"Attach.RelativeX"
502#define VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_RELY L"Attach.RelativeY"
503#define VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_DESKTOP L"Attach.ToDesktop"
504
505NTSTATUS vboxWddmRegQueryDisplaySettingsKeyName(PDEVICE_EXTENSION pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId,
506 ULONG cbBuf, PWCHAR pBuf, PULONG pcbResult)
507{
508 NTSTATUS Status = STATUS_SUCCESS;
509 PWCHAR pSuffix;
510 bool bFallback = false;
511 const WCHAR* pKeyPrefix;
512 UINT cbKeyPrefix;
513 UNICODE_STRING* pVGuid = vboxWddmVGuidGet(pDevExt);
514 Assert(pVGuid);
515 if (!pVGuid)
516 return STATUS_UNSUCCESSFUL;
517
518 winVersion_t ver = vboxQueryWinVersion();
519 if (ver == WINVISTA)
520 {
521 pKeyPrefix = VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_VISTA;
522 cbKeyPrefix = sizeof (VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_VISTA);
523 }
524 else
525 {
526 Assert(ver == WIN7);
527 pKeyPrefix = VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_WIN7;
528 cbKeyPrefix = sizeof (VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_WIN7);
529 }
530
531 ULONG cbResult = cbKeyPrefix + pVGuid->Length + 2 + 8; // L"\\" + "XXXX"
532 if (cbBuf >= cbResult)
533 {
534 wcscpy(pBuf, pKeyPrefix);
535 pSuffix = pBuf + (cbKeyPrefix-2)/2;
536 memcpy(pSuffix, pVGuid->Buffer, pVGuid->Length);
537 pSuffix += pVGuid->Length/2;
538 pSuffix[0] = L'\\';
539 pSuffix += 1;
540 swprintf(pSuffix, L"%04d", VidPnSourceId);
541 }
542 else
543 {
544 Status = STATUS_BUFFER_TOO_SMALL;
545 }
546
547 *pcbResult = cbResult;
548
549 return Status;
550}
551
552#define VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Video\\"
553#define VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY_SUBKEY L"\\Video"
554
555NTSTATUS vboxWddmRegQueryVideoGuidString(ULONG cbBuf, PWCHAR pBuf, PULONG pcbResult)
556{
557 HANDLE hKey;
558 NTSTATUS Status = vboxWddmRegOpenKey(&hKey, VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY, GENERIC_READ);
559 Assert(Status == STATUS_SUCCESS);
560 if (Status == STATUS_SUCCESS)
561 {
562 struct
563 {
564 KEY_BASIC_INFORMATION Name;
565 WCHAR Buf[256];
566 } Buf;
567 WCHAR KeyBuf[sizeof (VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY)/2 + 256 + 64];
568 wcscpy(KeyBuf, VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY);
569 ULONG ResultLength;
570 BOOL bFound = FALSE;
571 for (ULONG i = 0; !bFound; ++i)
572 {
573 RtlZeroMemory(&Buf, sizeof (Buf));
574 Status = ZwEnumerateKey(hKey, i, KeyBasicInformation, &Buf, sizeof (Buf), &ResultLength);
575 Assert(Status == STATUS_SUCCESS);
576 /* we should not encounter STATUS_NO_MORE_ENTRIES here since this would mean we did not find our entry */
577 if (Status != STATUS_SUCCESS)
578 break;
579
580 HANDLE hSubKey;
581 PWCHAR pSubBuf = KeyBuf + (sizeof (VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY) - 2)/2;
582 memcpy(pSubBuf, Buf.Name.Name, Buf.Name.NameLength);
583 pSubBuf += Buf.Name.NameLength/2;
584 memcpy(pSubBuf, VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY_SUBKEY, sizeof (VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY_SUBKEY));
585 Status = vboxWddmRegOpenKey(&hSubKey, KeyBuf, GENERIC_READ);
586 Assert(Status == STATUS_SUCCESS);
587 if (Status == STATUS_SUCCESS)
588 {
589 struct
590 {
591 KEY_VALUE_PARTIAL_INFORMATION Info;
592 UCHAR Buf[sizeof (L"VBoxVideoWddm")]; /* should be enough */
593 } KeyData;
594 ULONG cbResult;
595 UNICODE_STRING RtlStr;
596 RtlInitUnicodeString(&RtlStr, L"Service");
597 Status = ZwQueryValueKey(hSubKey,
598 &RtlStr,
599 KeyValuePartialInformation,
600 &KeyData.Info,
601 sizeof(KeyData),
602 &cbResult);
603 Assert(Status == STATUS_SUCCESS || STATUS_BUFFER_TOO_SMALL || STATUS_BUFFER_OVERFLOW);
604 if (Status == STATUS_SUCCESS)
605 {
606 if (KeyData.Info.Type == REG_SZ)
607 {
608 if (KeyData.Info.DataLength == sizeof (L"VBoxVideoWddm"))
609 {
610 if (!wcscmp(L"VBoxVideoWddm", (PWCHAR)KeyData.Info.Data))
611 {
612 bFound = TRUE;
613 *pcbResult = Buf.Name.NameLength + 2;
614 if (cbBuf >= Buf.Name.NameLength + 2)
615 {
616 memcpy(pBuf, Buf.Name.Name, Buf.Name.NameLength + 2);
617 }
618 else
619 {
620 Status = STATUS_BUFFER_TOO_SMALL;
621 }
622 }
623 }
624 }
625 }
626
627 NTSTATUS tmpStatus = ZwClose(hSubKey);
628 Assert(tmpStatus == STATUS_SUCCESS);
629 }
630 else
631 break;
632 }
633 NTSTATUS tmpStatus = ZwClose(hKey);
634 Assert(tmpStatus == STATUS_SUCCESS);
635 }
636
637 return Status;
638}
639
640NTSTATUS vboxWddmRegOpenKey(OUT PHANDLE phKey, IN PWCHAR pName, IN ACCESS_MASK fAccess)
641{
642 OBJECT_ATTRIBUTES ObjAttr;
643 UNICODE_STRING RtlStr;
644
645 RtlInitUnicodeString(&RtlStr, pName);
646 InitializeObjectAttributes(&ObjAttr, &RtlStr, OBJ_CASE_INSENSITIVE, NULL, NULL);
647
648 return ZwOpenKey(phKey, fAccess, &ObjAttr);
649}
650
651NTSTATUS vboxWddmRegOpenDisplaySettingsKey(IN PDEVICE_EXTENSION pDeviceExtension, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId, OUT PHANDLE phKey)
652{
653 WCHAR Buf[512];
654 ULONG cbBuf = sizeof(Buf);
655 NTSTATUS Status = vboxWddmRegQueryDisplaySettingsKeyName(pDeviceExtension, VidPnSourceId, cbBuf, Buf, &cbBuf);
656 Assert(Status == STATUS_SUCCESS);
657 if (Status == STATUS_SUCCESS)
658 {
659 Status = vboxWddmRegOpenKey(phKey, Buf, GENERIC_READ);
660 Assert(Status == STATUS_SUCCESS);
661 if(Status == STATUS_SUCCESS)
662 return STATUS_SUCCESS;
663 }
664
665 /* fall-back to make the subsequent VBoxVideoCmnRegXxx calls treat the fail accordingly
666 * basically needed to make as less modifications to the current XPDM code as possible */
667 *phKey = NULL;
668
669 return Status;
670}
671
672NTSTATUS vboxWddmRegDisplaySettingsQueryRelX(HANDLE hKey, int * pResult)
673{
674 DWORD dwVal;
675 NTSTATUS Status = vboxWddmRegQueryValueDword(hKey, VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_RELX, &dwVal);
676 Assert(Status == STATUS_SUCCESS);
677 if (Status == STATUS_SUCCESS)
678 {
679 *pResult = (int)dwVal;
680 }
681
682 return Status;
683}
684
685NTSTATUS vboxWddmRegDisplaySettingsQueryRelY(HANDLE hKey, int * pResult)
686{
687 DWORD dwVal;
688 NTSTATUS Status = vboxWddmRegQueryValueDword(hKey, VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_RELY, &dwVal);
689 Assert(Status == STATUS_SUCCESS);
690 if (Status == STATUS_SUCCESS)
691 {
692 *pResult = (int)dwVal;
693 }
694
695 return Status;
696}
697
698NTSTATUS vboxWddmDisplaySettingsQueryPos(IN PDEVICE_EXTENSION pDeviceExtension, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId, POINT * pPos)
699{
700 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
701 HANDLE hKey;
702 NTSTATUS Status = vboxWddmRegOpenDisplaySettingsKey(pDeviceExtension, VidPnSourceId, &hKey);
703 Assert(Status == STATUS_SUCCESS);
704 if (Status == STATUS_SUCCESS)
705 {
706 int x, y;
707 Status = vboxWddmRegDisplaySettingsQueryRelX(hKey, &x);
708 Assert(Status == STATUS_SUCCESS);
709 if (Status == STATUS_SUCCESS)
710 {
711 Status = vboxWddmRegDisplaySettingsQueryRelY(hKey, &y);
712 Assert(Status == STATUS_SUCCESS);
713 if (Status == STATUS_SUCCESS)
714 {
715 pPos->x = x;
716 pPos->y = y;
717 }
718 }
719 NTSTATUS tmpStatus = ZwClose(hKey);
720 Assert(tmpStatus == STATUS_SUCCESS);
721 }
722 return Status;
723}
724
725NTSTATUS vboxWddmRegQueryValueDword(IN HANDLE hKey, IN PWCHAR pName, OUT PDWORD pDword)
726{
727 struct
728 {
729 KEY_VALUE_PARTIAL_INFORMATION Info;
730 UCHAR Buf[32]; /* should be enough */
731 } Buf;
732 ULONG cbBuf;
733 UNICODE_STRING RtlStr;
734 RtlInitUnicodeString(&RtlStr, pName);
735 NTSTATUS Status = ZwQueryValueKey(hKey,
736 &RtlStr,
737 KeyValuePartialInformation,
738 &Buf.Info,
739 sizeof(Buf),
740 &cbBuf);
741 if (Status == STATUS_SUCCESS)
742 {
743 if (Buf.Info.Type == REG_DWORD)
744 {
745 Assert(Buf.Info.DataLength == 4);
746 *pDword = *((PULONG)Buf.Info.Data);
747 return STATUS_SUCCESS;
748 }
749 }
750
751 return STATUS_INVALID_PARAMETER;
752}
753
754NTSTATUS vboxWddmRegSetValueDword(IN HANDLE hKey, IN PWCHAR pName, OUT DWORD val)
755{
756 UNICODE_STRING RtlStr;
757 RtlInitUnicodeString(&RtlStr, pName);
758 return ZwSetValueKey(hKey, &RtlStr,
759 NULL, /* IN ULONG TitleIndex OPTIONAL, reserved */
760 REG_DWORD,
761 &val,
762 sizeof(val));
763}
764
765UNICODE_STRING* vboxWddmVGuidGet(PDEVICE_EXTENSION pDevExt)
766{
767 if (pDevExt->VideoGuid.Buffer)
768 return &pDevExt->VideoGuid;
769
770 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
771 WCHAR VideoGuidBuf[512];
772 ULONG cbVideoGuidBuf = sizeof (VideoGuidBuf);
773 NTSTATUS Status = vboxWddmRegQueryVideoGuidString(cbVideoGuidBuf, VideoGuidBuf, &cbVideoGuidBuf);
774 Assert(Status == STATUS_SUCCESS);
775 if (Status == STATUS_SUCCESS)
776 {
777 PWCHAR pBuf = (PWCHAR)vboxWddmMemAllocZero(cbVideoGuidBuf);
778 Assert(pBuf);
779 if (pBuf)
780 {
781 memcpy(pBuf, VideoGuidBuf, cbVideoGuidBuf);
782 RtlInitUnicodeString(&pDevExt->VideoGuid, pBuf);
783 return &pDevExt->VideoGuid;
784 }
785 }
786
787 return NULL;
788}
789
790VOID vboxWddmVGuidFree(PDEVICE_EXTENSION pDevExt)
791{
792 if (pDevExt->VideoGuid.Buffer)
793 {
794 vboxWddmMemFree(pDevExt->VideoGuid.Buffer);
795 pDevExt->VideoGuid.Buffer = NULL;
796 }
797}
798
799/* mm */
800
801NTSTATUS vboxMmInit(PVBOXWDDM_MM pMm, UINT cPages)
802{
803 UINT cbBuffer = VBOXWDDM_ROUNDBOUND(cPages, 8) >> 3;
804 cbBuffer = VBOXWDDM_ROUNDBOUND(cbBuffer, 4);
805 PULONG pBuf = (PULONG)vboxWddmMemAllocZero(cbBuffer);
806 if (!pBuf)
807 {
808 Assert(0);
809 return STATUS_NO_MEMORY;
810 }
811 RtlInitializeBitMap(&pMm->BitMap, pBuf, cPages);
812 pMm->cPages = cPages;
813 pMm->cAllocs = 0;
814 pMm->pBuffer = pBuf;
815 return STATUS_SUCCESS;
816}
817
818ULONG vboxMmAlloc(PVBOXWDDM_MM pMm, UINT cPages)
819{
820 ULONG iPage = RtlFindClearBitsAndSet(&pMm->BitMap, cPages, 0);
821 if (iPage == 0xFFFFFFFF)
822 {
823 Assert(0);
824 return VBOXWDDM_MM_VOID;
825 }
826
827 ++pMm->cAllocs;
828 return iPage;
829}
830
831VOID vboxMmFree(PVBOXWDDM_MM pMm, UINT iPage, UINT cPages)
832{
833 Assert(RtlAreBitsSet(&pMm->BitMap, iPage, cPages));
834 RtlClearBits(&pMm->BitMap, iPage, cPages);
835 --pMm->cAllocs;
836 Assert(pMm->cAllocs < UINT32_MAX);
837}
838
839NTSTATUS vboxMmTerm(PVBOXWDDM_MM pMm)
840{
841 Assert(!pMm->cAllocs);
842 vboxWddmMemFree(pMm->pBuffer);
843 pMm->pBuffer = NULL;
844 return STATUS_SUCCESS;
845}
846
847
848
849typedef struct VBOXVIDEOCM_ALLOC
850{
851 VBOXWDDM_HANDLE hGlobalHandle;
852 uint32_t offData;
853 uint32_t cbData;
854} VBOXVIDEOCM_ALLOC, *PVBOXVIDEOCM_ALLOC;
855
856typedef struct VBOXVIDEOCM_ALLOC_REF
857{
858 PVBOXVIDEOCM_ALLOC_CONTEXT pContext;
859 VBOXWDDM_HANDLE hSessionHandle;
860 PVBOXVIDEOCM_ALLOC pAlloc;
861 union
862 {
863 PKEVENT pSynchEvent;
864 PRKSEMAPHORE pSynchSemaphore;
865 };
866 VBOXUHGSMI_SYNCHOBJECT_TYPE enmSynchType;
867 MDL Mdl;
868} VBOXVIDEOCM_ALLOC_REF, *PVBOXVIDEOCM_ALLOC_REF;
869
870
871NTSTATUS vboxVideoCmAllocAlloc(PVBOXVIDEOCM_ALLOC_MGR pMgr, PVBOXVIDEOCM_ALLOC pAlloc)
872{
873 NTSTATUS Status = STATUS_UNSUCCESSFUL;
874 UINT cbSize = pAlloc->cbData;
875 UINT cPages = BYTES_TO_PAGES(cbSize);
876 ExAcquireFastMutex(&pMgr->Mutex);
877 UINT iPage = vboxMmAlloc(&pMgr->Mm, cPages);
878 if (iPage != VBOXWDDM_MM_VOID)
879 {
880 uint32_t offData = pMgr->offData + (iPage << PAGE_SHIFT);
881 Assert(offData + cbSize <= pMgr->offData + pMgr->cbData);
882 pAlloc->offData = offData;
883 pAlloc->hGlobalHandle = vboxWddmHTablePut(&pMgr->AllocTable, pAlloc);
884 ExReleaseFastMutex(&pMgr->Mutex);
885 if (VBOXWDDM_HANDLE_INVALID != pAlloc->hGlobalHandle)
886 return STATUS_SUCCESS;
887
888 Assert(0);
889 Status = STATUS_NO_MEMORY;
890 vboxMmFree(&pMgr->Mm, iPage, cPages);
891 }
892 else
893 {
894 Assert(0);
895 ExReleaseFastMutex(&pMgr->Mutex);
896 Status = STATUS_INSUFFICIENT_RESOURCES;
897 }
898 return Status;
899}
900
901VOID vboxVideoCmAllocDealloc(PVBOXVIDEOCM_ALLOC_MGR pMgr, PVBOXVIDEOCM_ALLOC pAlloc)
902{
903 UINT cbSize = pAlloc->cbData;
904 UINT cPages = BYTES_TO_PAGES(cbSize);
905 UINT iPage = BYTES_TO_PAGES(pAlloc->offData - pMgr->offData);
906 ExAcquireFastMutex(&pMgr->Mutex);
907 vboxWddmHTableRemove(&pMgr->AllocTable, pAlloc->hGlobalHandle);
908 vboxMmFree(&pMgr->Mm, iPage, cPages);
909 ExReleaseFastMutex(&pMgr->Mutex);
910}
911
912
913NTSTATUS vboxVideoAMgrAllocCreate(PVBOXVIDEOCM_ALLOC_MGR pMgr, UINT cbSize, PVBOXVIDEOCM_ALLOC *ppAlloc)
914{
915 NTSTATUS Status = STATUS_SUCCESS;
916 PVBOXVIDEOCM_ALLOC pAlloc = (PVBOXVIDEOCM_ALLOC)vboxWddmMemAllocZero(sizeof (*pAlloc));
917 if (pAlloc)
918 {
919 pAlloc->cbData = cbSize;
920 Status = vboxVideoCmAllocAlloc(pMgr, pAlloc);
921 if (Status == STATUS_SUCCESS)
922 {
923 *ppAlloc = pAlloc;
924 return STATUS_SUCCESS;
925 }
926
927 Assert(0);
928 vboxWddmMemFree(pAlloc);
929 }
930 else
931 {
932 Assert(0);
933 Status = STATUS_NO_MEMORY;
934 }
935
936 return Status;
937}
938
939VOID vboxVideoAMgrAllocDestroy(PVBOXVIDEOCM_ALLOC_MGR pMgr, PVBOXVIDEOCM_ALLOC pAlloc)
940{
941 vboxVideoCmAllocDealloc(pMgr, pAlloc);
942 vboxWddmMemFree(pAlloc);
943}
944
945NTSTATUS vboxVideoAMgrCtxAllocMap(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, PVBOXVIDEOCM_ALLOC pAlloc, PVBOXVIDEOCM_UM_ALLOC pUmAlloc)
946{
947 PVBOXVIDEOCM_ALLOC_MGR pMgr = pContext->pMgr;
948 NTSTATUS Status = STATUS_SUCCESS;
949
950 union
951 {
952 PKEVENT pSynchEvent;
953 PRKSEMAPHORE pSynchSemaphore;
954 };
955
956 switch (pUmAlloc->enmSynchType)
957 {
958 case VBOXUHGSMI_SYNCHOBJECT_TYPE_EVENT:
959 Status = ObReferenceObjectByHandle(pUmAlloc->hSynch, EVENT_MODIFY_STATE, *ExEventObjectType, UserMode,
960 (PVOID*)&pSynchEvent,
961 NULL);
962 Assert(Status == STATUS_SUCCESS);
963 break;
964 case VBOXUHGSMI_SYNCHOBJECT_TYPE_SEMAPHORE:
965 Status = ObReferenceObjectByHandle(pUmAlloc->hSynch, EVENT_MODIFY_STATE, *ExSemaphoreObjectType, UserMode,
966 (PVOID*)&pSynchSemaphore,
967 NULL);
968 Assert(Status == STATUS_SUCCESS);
969 break;
970 case VBOXUHGSMI_SYNCHOBJECT_TYPE_NONE:
971 pSynchEvent = NULL;
972 Status = STATUS_SUCCESS;
973 break;
974 default:
975 drprintf((__FUNCTION__ ": ERROR: invalid synch info type(%d)\n", pUmAlloc->enmSynchType));
976 AssertBreakpoint();
977 Status = STATUS_INVALID_PARAMETER;
978 break;
979 }
980
981 if (Status == STATUS_SUCCESS)
982 {
983 PVOID BaseVa = pMgr->pvData + pAlloc->offData - pMgr->offData;
984 SIZE_T cbLength = pAlloc->cbData;
985
986 PVBOXVIDEOCM_ALLOC_REF pAllocRef = (PVBOXVIDEOCM_ALLOC_REF)vboxWddmMemAllocZero(sizeof (*pAllocRef) + sizeof (PFN_NUMBER) * ADDRESS_AND_SIZE_TO_SPAN_PAGES(BaseVa, cbLength));
987 if (pAllocRef)
988 {
989 MmInitializeMdl(&pAllocRef->Mdl, BaseVa, cbLength);
990 __try
991 {
992 MmProbeAndLockPages(&pAllocRef->Mdl, KernelMode, IoWriteAccess);
993 }
994 __except(EXCEPTION_EXECUTE_HANDLER)
995 {
996 Assert(0);
997 Status = STATUS_UNSUCCESSFUL;
998 }
999
1000 if (Status == STATUS_SUCCESS)
1001 {
1002 PVOID pvUm = MmMapLockedPagesSpecifyCache(&pAllocRef->Mdl, UserMode, MmNonCached,
1003 NULL, /* PVOID BaseAddress */
1004 FALSE, /* ULONG BugCheckOnFailure */
1005 NormalPagePriority);
1006 if (pvUm)
1007 {
1008 pAllocRef->pContext = pContext;
1009 pAllocRef->pAlloc = pAlloc;
1010 pAllocRef->enmSynchType = pUmAlloc->enmSynchType;
1011 pAllocRef->pSynchEvent = pSynchEvent;
1012 ExAcquireFastMutex(&pContext->Mutex);
1013 pAllocRef->hSessionHandle = vboxWddmHTablePut(&pContext->AllocTable, pAllocRef);
1014 ExReleaseFastMutex(&pContext->Mutex);
1015 if (VBOXWDDM_HANDLE_INVALID != pAllocRef->hSessionHandle)
1016 {
1017 pUmAlloc->hAlloc = pAllocRef->hSessionHandle;
1018 pUmAlloc->cbData = pAlloc->cbData;
1019 pUmAlloc->pvData = (uint8_t*)pvUm;
1020 return STATUS_SUCCESS;
1021 }
1022 }
1023 else
1024 {
1025 Assert(0);
1026 Status = STATUS_INSUFFICIENT_RESOURCES;
1027 }
1028
1029 MmUnlockPages(&pAllocRef->Mdl);
1030 }
1031
1032 vboxWddmMemFree(pAllocRef);
1033 }
1034 else
1035 {
1036 Assert(0);
1037 Status = STATUS_NO_MEMORY;
1038 }
1039
1040 if (pSynchEvent)
1041 {
1042 ObDereferenceObject(pSynchEvent);
1043 }
1044 }
1045 else
1046 {
1047 Assert(0);
1048 }
1049
1050
1051 return Status;
1052}
1053
1054NTSTATUS vboxVideoAMgrCtxAllocUnmap(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, VBOXDISP_KMHANDLE hSesionHandle, PVBOXVIDEOCM_ALLOC *ppAlloc)
1055{
1056 NTSTATUS Status = STATUS_SUCCESS;
1057 ExAcquireFastMutex(&pContext->Mutex);
1058 PVBOXVIDEOCM_ALLOC_REF pAllocRef = (PVBOXVIDEOCM_ALLOC_REF)vboxWddmHTableRemove(&pContext->AllocTable, hSesionHandle);
1059 ExReleaseFastMutex(&pContext->Mutex);
1060 if (pAllocRef)
1061 {
1062 MmUnlockPages(&pAllocRef->Mdl);
1063 *ppAlloc = pAllocRef->pAlloc;
1064 if (pAllocRef->pSynchEvent)
1065 {
1066 ObDereferenceObject(pAllocRef->pSynchEvent);
1067 }
1068 vboxWddmMemFree(pAllocRef);
1069 }
1070 else
1071 {
1072 Assert(0);
1073 Status = STATUS_INVALID_PARAMETER;
1074 }
1075
1076 return Status;
1077}
1078
1079static PVBOXVIDEOCM_ALLOC_REF vboxVideoAMgrCtxAllocRefAcquire(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, VBOXDISP_KMHANDLE hSesionHandle)
1080{
1081 ExAcquireFastMutex(&pContext->Mutex);
1082 PVBOXVIDEOCM_ALLOC_REF pAllocRef = (PVBOXVIDEOCM_ALLOC_REF)vboxWddmHTableGet(&pContext->AllocTable, hSesionHandle);
1083 ExReleaseFastMutex(&pContext->Mutex);
1084 return pAllocRef;
1085}
1086
1087static VOID vboxVideoCmCtxAllocRefRelease(PVBOXVIDEOCM_ALLOC_REF pRef)
1088{
1089
1090}
1091
1092
1093
1094NTSTATUS vboxVideoAMgrCtxAllocCreate(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, PVBOXVIDEOCM_UM_ALLOC pUmAlloc)
1095{
1096 PVBOXVIDEOCM_ALLOC pAlloc;
1097 PVBOXVIDEOCM_ALLOC_MGR pMgr = pContext->pMgr;
1098 NTSTATUS Status = vboxVideoAMgrAllocCreate(pMgr, pUmAlloc->cbData, &pAlloc);
1099 if (Status == STATUS_SUCCESS)
1100 {
1101 Status = vboxVideoAMgrCtxAllocMap(pContext, pAlloc, pUmAlloc);
1102 if (Status == STATUS_SUCCESS)
1103 return STATUS_SUCCESS;
1104 else
1105 {
1106 Assert(0);
1107 }
1108 vboxVideoAMgrAllocDestroy(pMgr, pAlloc);
1109 }
1110 else
1111 {
1112 Assert(0);
1113 }
1114 return Status;
1115}
1116
1117NTSTATUS vboxVideoAMgrCtxAllocDestroy(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, VBOXDISP_KMHANDLE hSesionHandle)
1118{
1119 PVBOXVIDEOCM_ALLOC pAlloc;
1120 PVBOXVIDEOCM_ALLOC_MGR pMgr = pContext->pMgr;
1121 NTSTATUS Status = vboxVideoAMgrCtxAllocUnmap(pContext, hSesionHandle, &pAlloc);
1122 if (Status == STATUS_SUCCESS)
1123 {
1124 vboxVideoAMgrAllocDestroy(pMgr, pAlloc);
1125 }
1126 else
1127 {
1128 Assert(0);
1129 }
1130 return Status;
1131}
1132
1133#ifdef VBOX_WITH_VDMA
1134static DECLCALLBACK(VOID) vboxVideoAMgrAllocSubmitCompletion(PDEVICE_EXTENSION pDevExt, PVBOXVDMADDI_CMD pCmd, PVOID pvContext)
1135{
1136 PVBOXVDMACBUF_DR pDr = (PVBOXVDMACBUF_DR)pvContext;
1137 PVBOXVDMACMD pHdr = VBOXVDMACBUF_DR_TAIL(pDr, VBOXVDMACMD);
1138 VBOXVDMACMD_CHROMIUM_CMD *pBody = VBOXVDMACMD_BODY(pHdr, VBOXVDMACMD_CHROMIUM_CMD);
1139 UINT cBufs = pBody->cBuffers;
1140 for (UINT i = 0; i < cBufs; ++i)
1141 {
1142 VBOXVDMACMD_CHROMIUM_BUFFER *pBufCmd = &pBody->aBuffers[i];
1143 PVBOXVIDEOCM_ALLOC_REF pRef = (PVBOXVIDEOCM_ALLOC_REF)pBufCmd->u64GuesData;
1144 if (!pBufCmd->u32GuesData)
1145 {
1146 /* signal completion */
1147 switch (pRef->enmSynchType)
1148 {
1149 case VBOXUHGSMI_SYNCHOBJECT_TYPE_EVENT:
1150 KeSetEvent(pRef->pSynchEvent, 3, FALSE);
1151 break;
1152 case VBOXUHGSMI_SYNCHOBJECT_TYPE_SEMAPHORE:
1153 KeReleaseSemaphore(pRef->pSynchSemaphore,
1154 3,
1155 1,
1156 FALSE);
1157 break;
1158 case VBOXUHGSMI_SYNCHOBJECT_TYPE_NONE:
1159 break;
1160 default:
1161 Assert(0);
1162 }
1163 }
1164
1165 vboxVideoCmCtxAllocRefRelease(pRef);
1166 }
1167
1168 vboxVdmaCBufDrFree(&pDevExt->u.primary.Vdma, pDr);
1169}
1170
1171NTSTATUS vboxVideoAMgrCtxAllocSubmit(PDEVICE_EXTENSION pDevExt, PVBOXVIDEOCM_ALLOC_CONTEXT pContext, UINT cBuffers, VBOXWDDM_UHGSMI_BUFFER_UI_INFO_ESCAPE *paBuffers)
1172{
1173 NTSTATUS Status = STATUS_SUCCESS;
1174 UINT cbCmd = VBOXVDMACMD_SIZE_FROMBODYSIZE(RT_OFFSETOF(VBOXVDMACMD_CHROMIUM_CMD, aBuffers[cBuffers]));
1175
1176 PVBOXVDMACBUF_DR pDr = vboxVdmaCBufDrCreate (&pDevExt->u.primary.Vdma, cbCmd);
1177 if (pDr)
1178 {
1179 // vboxVdmaCBufDrCreate zero initializes the pDr
1180 pDr->fFlags = VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR;
1181 pDr->cbBuf = cbCmd;
1182 pDr->rc = VERR_NOT_IMPLEMENTED;
1183
1184 PVBOXVDMACMD pHdr = VBOXVDMACBUF_DR_TAIL(pDr, VBOXVDMACMD);
1185 pHdr->enmType = VBOXVDMACMD_TYPE_CHROMIUM_CMD;
1186 pHdr->u32CmdSpecific = 0;
1187 VBOXVDMACMD_CHROMIUM_CMD *pBody = VBOXVDMACMD_BODY(pHdr, VBOXVDMACMD_CHROMIUM_CMD);
1188 pBody->cBuffers = cBuffers;
1189 for (UINT i = 0; i < cBuffers; ++i)
1190 {
1191 VBOXVDMACMD_CHROMIUM_BUFFER *pBufCmd = &pBody->aBuffers[i];
1192 VBOXWDDM_UHGSMI_BUFFER_UI_INFO_ESCAPE *pBufInfo = &paBuffers[i];
1193 PVBOXVIDEOCM_ALLOC_REF pRef = vboxVideoAMgrCtxAllocRefAcquire(pContext, pBufInfo->hAlloc);
1194 if (pRef)
1195 {
1196 pBufCmd->offBuffer = pRef->pAlloc->offData + pBufInfo->Info.offData;
1197 pBufCmd->cbBuffer = pBufInfo->Info.cbData;
1198 pBufCmd->u32GuesData = pBufInfo->Info.fSubFlags.bDoNotSignalCompletion;
1199 pBufCmd->u64GuesData = (uint64_t)pRef;
1200 }
1201 else
1202 {
1203 Assert(0);
1204 Status = STATUS_INVALID_PARAMETER;
1205 break;
1206 }
1207 }
1208
1209 if (Status == STATUS_SUCCESS)
1210 {
1211 PVBOXVDMADDI_CMD pDdiCmd = VBOXVDMADDI_CMD_FROM_BUF_DR(pDr);
1212 vboxVdmaDdiCmdInit(pDdiCmd, 0, NULL, vboxVideoAMgrAllocSubmitCompletion, pDr);
1213 vboxVdmaDdiCmdSubmittedNotDx(pDdiCmd);
1214 int rc = vboxVdmaCBufDrSubmit(pDevExt, &pDevExt->u.primary.Vdma, pDr);
1215 Assert(rc == VINF_SUCCESS);
1216 if (RT_SUCCESS(rc))
1217 {
1218 return STATUS_SUCCESS;
1219 }
1220 }
1221
1222 vboxVdmaCBufDrFree(&pDevExt->u.primary.Vdma, pDr);
1223 }
1224 else
1225 {
1226 Assert(0);
1227 /* @todo: try flushing.. */
1228 drprintf((__FUNCTION__": vboxVdmaCBufDrCreate returned NULL\n"));
1229 Status = STATUS_INSUFFICIENT_RESOURCES;
1230 }
1231
1232 return Status;
1233}
1234#endif
1235
1236NTSTATUS vboxVideoAMgrCreate(PDEVICE_EXTENSION pDevExt, PVBOXVIDEOCM_ALLOC_MGR pMgr, uint32_t offData, uint32_t cbData)
1237{
1238 Assert(!(offData & (PAGE_SIZE -1)));
1239 Assert(!(cbData & (PAGE_SIZE -1)));
1240 offData = VBOXWDDM_ROUNDBOUND(offData, PAGE_SIZE);
1241 cbData &= (~(PAGE_SIZE -1));
1242 Assert(cbData);
1243 if (!cbData)
1244 return STATUS_INVALID_PARAMETER;
1245
1246 ExInitializeFastMutex(&pMgr->Mutex);
1247 NTSTATUS Status = vboxWddmHTableCreate(&pMgr->AllocTable, 64);
1248 Assert(Status == STATUS_SUCCESS);
1249 if (Status == STATUS_SUCCESS)
1250 {
1251 Status = vboxMmInit(&pMgr->Mm, BYTES_TO_PAGES(cbData));
1252 Assert(Status == STATUS_SUCCESS);
1253 if (Status == STATUS_SUCCESS)
1254 {
1255 PHYSICAL_ADDRESS PhysicalAddress = {0};
1256 PhysicalAddress.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + offData;
1257 pMgr->pvData = (uint8_t*)MmMapIoSpace(PhysicalAddress, cbData, MmNonCached);
1258 Assert(pMgr->pvData);
1259 if (pMgr->pvData)
1260 {
1261 pMgr->offData = offData;
1262 pMgr->cbData = cbData;
1263 return STATUS_SUCCESS;
1264 }
1265 else
1266 {
1267 Status = STATUS_UNSUCCESSFUL;
1268 }
1269 vboxMmTerm(&pMgr->Mm);
1270 }
1271 vboxWddmHTableDestroy(&pMgr->AllocTable);
1272 }
1273
1274 return Status;
1275}
1276
1277NTSTATUS vboxVideoAMgrDestroy(PDEVICE_EXTENSION pDevExt, PVBOXVIDEOCM_ALLOC_MGR pMgr)
1278{
1279 MmUnmapIoSpace(pMgr->pvData, pMgr->cbData);
1280 vboxMmTerm(&pMgr->Mm);
1281 vboxWddmHTableDestroy(&pMgr->AllocTable);
1282 return STATUS_SUCCESS;
1283}
1284
1285NTSTATUS vboxVideoAMgrCtxCreate(PVBOXVIDEOCM_ALLOC_MGR pMgr, PVBOXVIDEOCM_ALLOC_CONTEXT pCtx)
1286{
1287 NTSTATUS Status = STATUS_NOT_SUPPORTED;
1288 if (pMgr->pvData)
1289 {
1290 ExInitializeFastMutex(&pCtx->Mutex);
1291 Status = vboxWddmHTableCreate(&pCtx->AllocTable, 32);
1292 Assert(Status == STATUS_SUCCESS);
1293 if (Status == STATUS_SUCCESS)
1294 {
1295 pCtx->pMgr = pMgr;
1296 return STATUS_SUCCESS;
1297 }
1298 }
1299 return Status;
1300}
1301
1302NTSTATUS vboxVideoAMgrCtxDestroy(PVBOXVIDEOCM_ALLOC_CONTEXT pCtx)
1303{
1304 if (!pCtx->pMgr)
1305 return STATUS_SUCCESS;
1306
1307 VBOXWDDM_HTABLE_ITERATOR Iter;
1308 NTSTATUS Status = STATUS_SUCCESS;
1309
1310 vboxWddmHTableIterInit(&pCtx->AllocTable, &Iter);
1311 do
1312 {
1313 PVBOXVIDEOCM_ALLOC_REF pRef = (PVBOXVIDEOCM_ALLOC_REF)vboxWddmHTableIterNext(&Iter, NULL);
1314 if (!pRef)
1315 break;
1316
1317 Status = vboxVideoAMgrCtxAllocDestroy(pCtx, pRef->hSessionHandle);
1318 Assert(Status == STATUS_SUCCESS);
1319 if (Status != STATUS_SUCCESS)
1320 break;
1321 // vboxWddmHTableIterRemoveCur(&Iter);
1322 } while (1);
1323
1324 if (Status == STATUS_SUCCESS)
1325 {
1326 vboxWddmHTableDestroy(&pCtx->AllocTable);
1327 }
1328
1329 return Status;
1330}
1331
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