VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPMisc.cpp@ 83827

Last change on this file since 83827 was 83827, checked in by vboxsync, 5 years ago

Add/NT/Graphics: VC++ 14.1 warnings. bugref:8489

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 46.4 KB
Line 
1/* $Id: VBoxMPMisc.cpp 83827 2020-04-19 02:02:30Z vboxsync $ */
2/** @file
3 * VBox WDDM Miniport driver
4 */
5
6/*
7 * Copyright (C) 2011-2020 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 "VBoxMPWddm.h"
19#include <VBoxVideoVBE.h>
20#include <iprt/param.h>
21#include <stdio.h>
22
23/* simple handle -> value table API */
24NTSTATUS vboxWddmHTableCreate(PVBOXWDDM_HTABLE pTbl, uint32_t cSize)
25{
26 memset(pTbl, 0, sizeof (*pTbl));
27 pTbl->paData = (PVOID*)vboxWddmMemAllocZero(sizeof (pTbl->paData[0]) * cSize);
28 if (pTbl->paData)
29 {
30 pTbl->cSize = cSize;
31 return STATUS_SUCCESS;
32 }
33 return STATUS_NO_MEMORY;
34}
35
36VOID vboxWddmHTableDestroy(PVBOXWDDM_HTABLE pTbl)
37{
38 if (!pTbl->paData)
39 return;
40
41 vboxWddmMemFree(pTbl->paData);
42}
43
44DECLINLINE(VBOXWDDM_HANDLE) vboxWddmHTableIndex2Handle(uint32_t iIndex)
45{
46 return iIndex+1;
47}
48
49DECLINLINE(uint32_t) vboxWddmHTableHandle2Index(VBOXWDDM_HANDLE hHandle)
50{
51 return hHandle-1;
52}
53
54NTSTATUS vboxWddmHTableRealloc(PVBOXWDDM_HTABLE pTbl, uint32_t cNewSize)
55{
56 Assert(cNewSize > pTbl->cSize);
57 if (cNewSize > pTbl->cSize)
58 {
59 PVOID *pvNewData = (PVOID*)vboxWddmMemAllocZero(sizeof (pTbl->paData[0]) * cNewSize);
60 if (!pvNewData)
61 {
62 WARN(("vboxWddmMemAllocZero failed for size (%d)", sizeof (pTbl->paData[0]) * cNewSize));
63 return STATUS_NO_MEMORY;
64 }
65 memcpy(pvNewData, pTbl->paData, sizeof (pTbl->paData[0]) * pTbl->cSize);
66 vboxWddmMemFree(pTbl->paData);
67 pTbl->iNext2Search = pTbl->cSize;
68 pTbl->cSize = cNewSize;
69 pTbl->paData = pvNewData;
70 return STATUS_SUCCESS;
71 }
72 if (cNewSize >= pTbl->cData)
73 {
74 AssertFailed();
75 return STATUS_NOT_IMPLEMENTED;
76 }
77 return STATUS_INVALID_PARAMETER;
78
79}
80VBOXWDDM_HANDLE vboxWddmHTablePut(PVBOXWDDM_HTABLE pTbl, PVOID pvData)
81{
82 if (pTbl->cSize == pTbl->cData)
83 {
84 NTSTATUS Status = vboxWddmHTableRealloc(pTbl, pTbl->cSize + RT_MAX(10, pTbl->cSize/4));
85 AssertNtStatusSuccess(Status);
86 if (Status != STATUS_SUCCESS)
87 return VBOXWDDM_HANDLE_INVALID;
88 }
89 for (UINT i = pTbl->iNext2Search; ; i = (i + 1) % pTbl->cSize)
90 {
91 Assert(i < pTbl->cSize);
92 if (!pTbl->paData[i])
93 {
94 pTbl->paData[i] = pvData;
95 ++pTbl->cData;
96 Assert(pTbl->cData <= pTbl->cSize);
97 ++pTbl->iNext2Search;
98 pTbl->iNext2Search %= pTbl->cSize;
99 return vboxWddmHTableIndex2Handle(i);
100 }
101 }
102 /* not reached */
103}
104
105PVOID vboxWddmHTableRemove(PVBOXWDDM_HTABLE pTbl, VBOXWDDM_HANDLE hHandle)
106{
107 uint32_t iIndex = vboxWddmHTableHandle2Index(hHandle);
108 Assert(iIndex < pTbl->cSize);
109 if (iIndex < pTbl->cSize)
110 {
111 PVOID pvData = pTbl->paData[iIndex];
112 pTbl->paData[iIndex] = NULL;
113 --pTbl->cData;
114 Assert(pTbl->cData <= pTbl->cSize);
115 pTbl->iNext2Search = iIndex;
116 return pvData;
117 }
118 return NULL;
119}
120
121PVOID vboxWddmHTableGet(PVBOXWDDM_HTABLE pTbl, VBOXWDDM_HANDLE hHandle)
122{
123 uint32_t iIndex = vboxWddmHTableHandle2Index(hHandle);
124 Assert(iIndex < pTbl->cSize);
125 if (iIndex < pTbl->cSize)
126 return pTbl->paData[iIndex];
127 return NULL;
128}
129
130VOID vboxWddmHTableIterInit(PVBOXWDDM_HTABLE pTbl, PVBOXWDDM_HTABLE_ITERATOR pIter)
131{
132 pIter->pTbl = pTbl;
133 pIter->iCur = ~0UL;
134 pIter->cLeft = pTbl->cData;
135}
136
137BOOL vboxWddmHTableIterHasNext(PVBOXWDDM_HTABLE_ITERATOR pIter)
138{
139 return pIter->cLeft;
140}
141
142
143PVOID vboxWddmHTableIterNext(PVBOXWDDM_HTABLE_ITERATOR pIter, VBOXWDDM_HANDLE *phHandle)
144{
145 if (vboxWddmHTableIterHasNext(pIter))
146 {
147 for (uint32_t i = pIter->iCur+1; i < pIter->pTbl->cSize ; ++i)
148 {
149 if (pIter->pTbl->paData[i])
150 {
151 pIter->iCur = i;
152 --pIter->cLeft;
153 VBOXWDDM_HANDLE hHandle = vboxWddmHTableIndex2Handle(i);
154 Assert(hHandle);
155 if (phHandle)
156 *phHandle = hHandle;
157 return pIter->pTbl->paData[i];
158 }
159 }
160 }
161
162 Assert(!vboxWddmHTableIterHasNext(pIter));
163 if (phHandle)
164 *phHandle = VBOXWDDM_HANDLE_INVALID;
165 return NULL;
166}
167
168
169PVOID vboxWddmHTableIterRemoveCur(PVBOXWDDM_HTABLE_ITERATOR pIter)
170{
171 VBOXWDDM_HANDLE hHandle = vboxWddmHTableIndex2Handle(pIter->iCur);
172 Assert(hHandle);
173 if (hHandle)
174 {
175 PVOID pRet = vboxWddmHTableRemove(pIter->pTbl, hHandle);
176 Assert(pRet);
177 return pRet;
178 }
179 return NULL;
180}
181
182NTSTATUS vboxWddmRegQueryDrvKeyName(PVBOXMP_DEVEXT pDevExt, ULONG cbBuf, PWCHAR pBuf, PULONG pcbResult)
183{
184 WCHAR fallBackBuf[2];
185 PWCHAR pSuffix;
186 bool bFallback = false;
187
188 if (cbBuf > sizeof(VBOXWDDM_REG_DRVKEY_PREFIX))
189 {
190 memcpy(pBuf, VBOXWDDM_REG_DRVKEY_PREFIX, sizeof (VBOXWDDM_REG_DRVKEY_PREFIX));
191 pSuffix = pBuf + (sizeof (VBOXWDDM_REG_DRVKEY_PREFIX)-2)/2;
192 cbBuf -= sizeof (VBOXWDDM_REG_DRVKEY_PREFIX)-2;
193 }
194 else
195 {
196 pSuffix = fallBackBuf;
197 cbBuf = sizeof (fallBackBuf);
198 bFallback = true;
199 }
200
201 NTSTATUS Status = IoGetDeviceProperty (pDevExt->pPDO,
202 DevicePropertyDriverKeyName,
203 cbBuf,
204 pSuffix,
205 &cbBuf);
206 if (Status == STATUS_SUCCESS && bFallback)
207 Status = STATUS_BUFFER_TOO_SMALL;
208 if (Status == STATUS_BUFFER_TOO_SMALL)
209 *pcbResult = cbBuf + sizeof (VBOXWDDM_REG_DRVKEY_PREFIX)-2;
210
211 return Status;
212}
213
214NTSTATUS vboxWddmRegQueryDisplaySettingsKeyName(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId,
215 ULONG cbBuf, PWCHAR pBuf, PULONG pcbResult)
216{
217 NTSTATUS Status = STATUS_SUCCESS;
218 PWCHAR pSuffix;
219 const WCHAR* pKeyPrefix;
220 UINT cbKeyPrefix;
221 UNICODE_STRING* pVGuid = vboxWddmVGuidGet(pDevExt);
222 Assert(pVGuid);
223 if (!pVGuid)
224 return STATUS_UNSUCCESSFUL;
225
226 uint32_t build;
227 vboxWinVersion_t ver = VBoxQueryWinVersion(&build);
228 if (ver == WINVERSION_VISTA)
229 {
230 pKeyPrefix = VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_VISTA;
231 cbKeyPrefix = sizeof (VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_VISTA);
232 }
233 else if (ver >= WINVERSION_10 && build >= 17763)
234 {
235 pKeyPrefix = VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_WIN10_17763;
236 cbKeyPrefix = sizeof (VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_WIN10_17763);
237 }
238 else
239 {
240 Assert(ver > WINVERSION_VISTA);
241 pKeyPrefix = VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_WIN7;
242 cbKeyPrefix = sizeof (VBOXWDDM_REG_DISPLAYSETTINGSKEY_PREFIX_WIN7);
243 }
244
245 ULONG cbResult = cbKeyPrefix + pVGuid->Length + 2 + 8; // L"\\" + "XXXX"
246 if (cbBuf >= cbResult)
247 {
248 wcscpy(pBuf, pKeyPrefix);
249 pSuffix = pBuf + (cbKeyPrefix-2)/2;
250 memcpy(pSuffix, pVGuid->Buffer, pVGuid->Length);
251 pSuffix += pVGuid->Length/2;
252 pSuffix[0] = L'\\';
253 pSuffix += 1;
254 swprintf(pSuffix, L"%04d", VidPnSourceId);
255 }
256 else
257 {
258 Status = STATUS_BUFFER_TOO_SMALL;
259 }
260
261 *pcbResult = cbResult;
262
263 return Status;
264}
265
266NTSTATUS vboxWddmRegQueryVideoGuidString(PVBOXMP_DEVEXT pDevExt, ULONG cbBuf, PWCHAR pBuf, PULONG pcbResult)
267{
268 BOOLEAN fNewMethodSucceeded = FALSE;
269 HANDLE hKey = NULL;
270 NTSTATUS Status = IoOpenDeviceRegistryKey(pDevExt->pPDO, PLUGPLAY_REGKEY_DEVICE, GENERIC_READ, &hKey);
271 if (NT_SUCCESS(Status))
272 {
273 struct
274 {
275 KEY_VALUE_PARTIAL_INFORMATION Info;
276 UCHAR Buf[1024]; /* should be enough */
277 } KeyData;
278 ULONG cbResult;
279 UNICODE_STRING RtlStr;
280 RtlInitUnicodeString(&RtlStr, L"VideoID");
281 Status = ZwQueryValueKey(hKey,
282 &RtlStr,
283 KeyValuePartialInformation,
284 &KeyData.Info,
285 sizeof(KeyData),
286 &cbResult);
287 if (NT_SUCCESS(Status))
288 {
289 if (KeyData.Info.Type == REG_SZ)
290 {
291 fNewMethodSucceeded = TRUE;
292 *pcbResult = KeyData.Info.DataLength + 2;
293 if (cbBuf >= KeyData.Info.DataLength)
294 {
295 memcpy(pBuf, KeyData.Info.Data, KeyData.Info.DataLength + 2);
296 Status = STATUS_SUCCESS;
297 }
298 else
299 Status = STATUS_BUFFER_TOO_SMALL;
300 }
301 }
302 else
303 {
304 WARN(("ZwQueryValueKey failed, Status 0x%x", Status));
305 }
306
307 NTSTATUS rcNt2 = ZwClose(hKey);
308 AssertNtStatusSuccess(rcNt2);
309 }
310 else
311 {
312 WARN(("IoOpenDeviceRegistryKey failed Status 0x%x", Status));
313 }
314
315 if (fNewMethodSucceeded)
316 return Status;
317 else
318 WARN(("failed to acquire the VideoID, falling back to the old impl"));
319
320 Status = vboxWddmRegOpenKey(&hKey, VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY, GENERIC_READ);
321 //AssertNtStatusSuccess(Status);
322 if (Status == STATUS_SUCCESS)
323 {
324 struct
325 {
326 KEY_BASIC_INFORMATION Name;
327 WCHAR Buf[256];
328 } Buf;
329 WCHAR KeyBuf[sizeof (VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY)/2 + 256 + 64];
330 wcscpy(KeyBuf, VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY);
331 ULONG ResultLength;
332 BOOL bFound = FALSE;
333 for (ULONG i = 0; !bFound; ++i)
334 {
335 RtlZeroMemory(&Buf, sizeof (Buf));
336 Status = ZwEnumerateKey(hKey, i, KeyBasicInformation, &Buf, sizeof (Buf), &ResultLength);
337 AssertNtStatusSuccess(Status);
338 /* we should not encounter STATUS_NO_MORE_ENTRIES here since this would mean we did not find our entry */
339 if (Status != STATUS_SUCCESS)
340 break;
341
342 HANDLE hSubKey;
343 PWCHAR pSubBuf = KeyBuf + (sizeof (VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY) - 2)/2;
344 memcpy(pSubBuf, Buf.Name.Name, Buf.Name.NameLength);
345 pSubBuf += Buf.Name.NameLength/2;
346 memcpy(pSubBuf, VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY_SUBKEY, sizeof (VBOXWDDM_REG_DISPLAYSETTINGSVIDEOKEY_SUBKEY));
347 Status = vboxWddmRegOpenKey(&hSubKey, KeyBuf, GENERIC_READ);
348 //AssertNtStatusSuccess(Status);
349 if (Status == STATUS_SUCCESS)
350 {
351 struct
352 {
353 KEY_VALUE_PARTIAL_INFORMATION Info;
354 UCHAR Buf[sizeof (VBOX_WDDM_DRIVERNAME)]; /* should be enough */
355 } KeyData;
356 ULONG cbResult;
357 UNICODE_STRING RtlStr;
358 RtlInitUnicodeString(&RtlStr, L"Service");
359 Status = ZwQueryValueKey(hSubKey,
360 &RtlStr,
361 KeyValuePartialInformation,
362 &KeyData.Info,
363 sizeof(KeyData),
364 &cbResult);
365 Assert(Status == STATUS_SUCCESS || STATUS_BUFFER_TOO_SMALL || STATUS_BUFFER_OVERFLOW);
366 if (Status == STATUS_SUCCESS)
367 {
368 if (KeyData.Info.Type == REG_SZ)
369 {
370 if (KeyData.Info.DataLength == sizeof (VBOX_WDDM_DRIVERNAME))
371 {
372 if (!wcscmp(VBOX_WDDM_DRIVERNAME, (PWCHAR)KeyData.Info.Data))
373 {
374 bFound = TRUE;
375 *pcbResult = Buf.Name.NameLength + 2;
376 if (cbBuf >= Buf.Name.NameLength + 2)
377 {
378 memcpy(pBuf, Buf.Name.Name, Buf.Name.NameLength + 2);
379 }
380 else
381 {
382 Status = STATUS_BUFFER_TOO_SMALL;
383 }
384 }
385 }
386 }
387 }
388
389 NTSTATUS rcNt2 = ZwClose(hSubKey);
390 AssertNtStatusSuccess(rcNt2);
391 }
392 else
393 break;
394 }
395 NTSTATUS rcNt2 = ZwClose(hKey);
396 AssertNtStatusSuccess(rcNt2);
397 }
398
399 return Status;
400}
401
402NTSTATUS vboxWddmRegOpenKeyEx(OUT PHANDLE phKey, IN HANDLE hRootKey, IN PWCHAR pName, IN ACCESS_MASK fAccess)
403{
404 OBJECT_ATTRIBUTES ObjAttr;
405 UNICODE_STRING RtlStr;
406
407 RtlInitUnicodeString(&RtlStr, pName);
408 InitializeObjectAttributes(&ObjAttr, &RtlStr, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, hRootKey, NULL);
409
410 return ZwOpenKey(phKey, fAccess, &ObjAttr);
411}
412
413NTSTATUS vboxWddmRegOpenKey(OUT PHANDLE phKey, IN PWCHAR pName, IN ACCESS_MASK fAccess)
414{
415 return vboxWddmRegOpenKeyEx(phKey, NULL, pName, fAccess);
416}
417
418NTSTATUS vboxWddmRegOpenDisplaySettingsKey(IN PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId,
419 OUT PHANDLE phKey)
420{
421 WCHAR Buf[512];
422 ULONG cbBuf = sizeof(Buf);
423 NTSTATUS Status = vboxWddmRegQueryDisplaySettingsKeyName(pDevExt, VidPnSourceId, cbBuf, Buf, &cbBuf);
424 AssertNtStatusSuccess(Status);
425 if (Status == STATUS_SUCCESS)
426 {
427 Status = vboxWddmRegOpenKey(phKey, Buf, GENERIC_READ);
428 AssertNtStatusSuccess(Status);
429 if(Status == STATUS_SUCCESS)
430 return STATUS_SUCCESS;
431 }
432
433 /* fall-back to make the subsequent VBoxVideoCmnRegXxx calls treat the fail accordingly
434 * basically needed to make as less modifications to the current XPDM code as possible */
435 *phKey = NULL;
436
437 return Status;
438}
439
440NTSTATUS vboxWddmRegDisplaySettingsQueryRelX(HANDLE hKey, int * pResult)
441{
442 DWORD dwVal;
443 NTSTATUS Status = vboxWddmRegQueryValueDword(hKey, VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_RELX, &dwVal);
444 AssertNtStatusSuccess(Status);
445 if (Status == STATUS_SUCCESS)
446 {
447 *pResult = (int)dwVal;
448 }
449
450 return Status;
451}
452
453NTSTATUS vboxWddmRegDisplaySettingsQueryRelY(HANDLE hKey, int * pResult)
454{
455 DWORD dwVal;
456 NTSTATUS Status = vboxWddmRegQueryValueDword(hKey, VBOXWDDM_REG_DISPLAYSETTINGS_ATTACH_RELY, &dwVal);
457 AssertNtStatusSuccess(Status);
458 if (Status == STATUS_SUCCESS)
459 {
460 *pResult = (int)dwVal;
461 }
462
463 return Status;
464}
465
466NTSTATUS vboxWddmDisplaySettingsQueryPos(IN PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId, POINT * pPos)
467{
468 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
469 HANDLE hKey;
470 NTSTATUS Status = vboxWddmRegOpenDisplaySettingsKey(pDevExt, VidPnSourceId, &hKey);
471 //AssertNtStatusSuccess(Status);
472 if (Status == STATUS_SUCCESS)
473 {
474 int x, y;
475 Status = vboxWddmRegDisplaySettingsQueryRelX(hKey, &x);
476 AssertNtStatusSuccess(Status);
477 if (Status == STATUS_SUCCESS)
478 {
479 Status = vboxWddmRegDisplaySettingsQueryRelY(hKey, &y);
480 AssertNtStatusSuccess(Status);
481 if (Status == STATUS_SUCCESS)
482 {
483 pPos->x = x;
484 pPos->y = y;
485 }
486 }
487 NTSTATUS rcNt2 = ZwClose(hKey);
488 AssertNtStatusSuccess(rcNt2);
489 }
490
491 return Status;
492}
493
494void vboxWddmDisplaySettingsCheckPos(IN PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId)
495{
496 POINT Pos = {0};
497 NTSTATUS Status = vboxWddmDisplaySettingsQueryPos(pDevExt, VidPnSourceId, &Pos);
498 if (!NT_SUCCESS(Status))
499 {
500 Log(("vboxWddmDisplaySettingsQueryPos failed %#x", Status));
501 return;
502 }
503
504 PVBOXWDDM_SOURCE pSource = &pDevExt->aSources[VidPnSourceId];
505
506 if (!memcmp(&pSource->VScreenPos, &Pos, sizeof (Pos)))
507 return;
508
509 pSource->VScreenPos = Pos;
510 pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_DIMENSIONS;
511
512 vboxWddmGhDisplayCheckSetInfoFromSource(pDevExt, pSource);
513}
514
515NTSTATUS vboxWddmRegDrvFlagsSet(PVBOXMP_DEVEXT pDevExt, DWORD fVal)
516{
517 HANDLE hKey = NULL;
518 NTSTATUS Status = IoOpenDeviceRegistryKey(pDevExt->pPDO, PLUGPLAY_REGKEY_DRIVER, GENERIC_WRITE, &hKey);
519 if (!NT_SUCCESS(Status))
520 {
521 WARN(("IoOpenDeviceRegistryKey failed, Status = 0x%x", Status));
522 return Status;
523 }
524
525 Status = vboxWddmRegSetValueDword(hKey, VBOXWDDM_REG_DRV_FLAGS_NAME, fVal);
526 if (!NT_SUCCESS(Status))
527 WARN(("vboxWddmRegSetValueDword failed, Status = 0x%x", Status));
528
529 NTSTATUS rcNt2 = ZwClose(hKey);
530 AssertNtStatusSuccess(rcNt2);
531
532 return Status;
533}
534
535DWORD vboxWddmRegDrvFlagsGet(PVBOXMP_DEVEXT pDevExt, DWORD fDefault)
536{
537 HANDLE hKey = NULL;
538 NTSTATUS Status = IoOpenDeviceRegistryKey(pDevExt->pPDO, PLUGPLAY_REGKEY_DRIVER, GENERIC_READ, &hKey);
539 if (!NT_SUCCESS(Status))
540 {
541 WARN(("IoOpenDeviceRegistryKey failed, Status = 0x%x", Status));
542 return fDefault;
543 }
544
545 DWORD dwVal = 0;
546 Status = vboxWddmRegQueryValueDword(hKey, VBOXWDDM_REG_DRV_FLAGS_NAME, &dwVal);
547 if (!NT_SUCCESS(Status))
548 {
549 WARN(("vboxWddmRegQueryValueDword failed, Status = 0x%x", Status));
550 dwVal = fDefault;
551 }
552
553 NTSTATUS rcNt2 = ZwClose(hKey);
554 AssertNtStatusSuccess(rcNt2);
555
556 return dwVal;
557}
558
559NTSTATUS vboxWddmRegQueryValueDword(IN HANDLE hKey, IN PWCHAR pName, OUT PDWORD pDword)
560{
561 struct
562 {
563 KEY_VALUE_PARTIAL_INFORMATION Info;
564 UCHAR Buf[32]; /* should be enough */
565 } Buf;
566 ULONG cbBuf;
567 UNICODE_STRING RtlStr;
568 RtlInitUnicodeString(&RtlStr, pName);
569 NTSTATUS Status = ZwQueryValueKey(hKey,
570 &RtlStr,
571 KeyValuePartialInformation,
572 &Buf.Info,
573 sizeof(Buf),
574 &cbBuf);
575 if (Status == STATUS_SUCCESS)
576 {
577 if (Buf.Info.Type == REG_DWORD)
578 {
579 Assert(Buf.Info.DataLength == 4);
580 *pDword = *((PULONG)Buf.Info.Data);
581 return STATUS_SUCCESS;
582 }
583 }
584
585 return STATUS_INVALID_PARAMETER;
586}
587
588NTSTATUS vboxWddmRegSetValueDword(IN HANDLE hKey, IN PWCHAR pName, IN DWORD val)
589{
590 UNICODE_STRING RtlStr;
591 RtlInitUnicodeString(&RtlStr, pName);
592 return ZwSetValueKey(hKey, &RtlStr,
593 NULL, /* IN ULONG TitleIndex OPTIONAL, reserved */
594 REG_DWORD,
595 &val,
596 sizeof(val));
597}
598
599UNICODE_STRING* vboxWddmVGuidGet(PVBOXMP_DEVEXT pDevExt)
600{
601 if (pDevExt->VideoGuid.Buffer)
602 return &pDevExt->VideoGuid;
603
604 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
605 WCHAR VideoGuidBuf[512];
606 ULONG cbVideoGuidBuf = sizeof (VideoGuidBuf);
607 NTSTATUS Status = vboxWddmRegQueryVideoGuidString(pDevExt ,cbVideoGuidBuf, VideoGuidBuf, &cbVideoGuidBuf);
608 AssertNtStatusSuccess(Status);
609 if (Status == STATUS_SUCCESS)
610 {
611 PWCHAR pBuf = (PWCHAR)vboxWddmMemAllocZero(cbVideoGuidBuf);
612 Assert(pBuf);
613 if (pBuf)
614 {
615 memcpy(pBuf, VideoGuidBuf, cbVideoGuidBuf);
616 RtlInitUnicodeString(&pDevExt->VideoGuid, pBuf);
617 return &pDevExt->VideoGuid;
618 }
619 }
620
621 return NULL;
622}
623
624VOID vboxWddmVGuidFree(PVBOXMP_DEVEXT pDevExt)
625{
626 if (pDevExt->VideoGuid.Buffer)
627 {
628 vboxWddmMemFree(pDevExt->VideoGuid.Buffer);
629 pDevExt->VideoGuid.Buffer = NULL;
630 }
631}
632
633/* mm */
634
635NTSTATUS vboxMmInit(PVBOXWDDM_MM pMm, UINT cPages)
636{
637 UINT cbBuffer = VBOXWDDM_ROUNDBOUND(cPages, 8) >> 3;
638 cbBuffer = VBOXWDDM_ROUNDBOUND(cbBuffer, 4);
639 PULONG pBuf = (PULONG)vboxWddmMemAllocZero(cbBuffer);
640 if (!pBuf)
641 {
642 Assert(0);
643 return STATUS_NO_MEMORY;
644 }
645 RtlInitializeBitMap(&pMm->BitMap, pBuf, cPages);
646 pMm->cPages = cPages;
647 pMm->cAllocs = 0;
648 pMm->pBuffer = pBuf;
649 return STATUS_SUCCESS;
650}
651
652ULONG vboxMmAlloc(PVBOXWDDM_MM pMm, UINT cPages)
653{
654 ULONG iPage = RtlFindClearBitsAndSet(&pMm->BitMap, cPages, 0);
655 if (iPage == 0xFFFFFFFF)
656 {
657 Assert(0);
658 return VBOXWDDM_MM_VOID;
659 }
660
661 ++pMm->cAllocs;
662 return iPage;
663}
664
665VOID vboxMmFree(PVBOXWDDM_MM pMm, UINT iPage, UINT cPages)
666{
667 Assert(RtlAreBitsSet(&pMm->BitMap, iPage, cPages));
668 RtlClearBits(&pMm->BitMap, iPage, cPages);
669 --pMm->cAllocs;
670 Assert(pMm->cAllocs < UINT32_MAX);
671}
672
673NTSTATUS vboxMmTerm(PVBOXWDDM_MM pMm)
674{
675 Assert(!pMm->cAllocs);
676 vboxWddmMemFree(pMm->pBuffer);
677 pMm->pBuffer = NULL;
678 return STATUS_SUCCESS;
679}
680
681
682
683typedef struct VBOXVIDEOCM_ALLOC
684{
685 VBOXWDDM_HANDLE hGlobalHandle;
686 uint32_t offData;
687 uint32_t cbData;
688} VBOXVIDEOCM_ALLOC, *PVBOXVIDEOCM_ALLOC;
689
690typedef struct VBOXVIDEOCM_ALLOC_REF
691{
692 PVBOXVIDEOCM_ALLOC_CONTEXT pContext;
693 VBOXWDDM_HANDLE hSessionHandle;
694 PVBOXVIDEOCM_ALLOC pAlloc;
695 PKEVENT pSynchEvent;
696 VBOXUHGSMI_BUFFER_TYPE_FLAGS fUhgsmiType;
697 volatile uint32_t cRefs;
698 PVOID pvUm;
699 MDL Mdl;
700} VBOXVIDEOCM_ALLOC_REF, *PVBOXVIDEOCM_ALLOC_REF;
701
702
703NTSTATUS vboxVideoCmAllocAlloc(PVBOXVIDEOCM_ALLOC_MGR pMgr, PVBOXVIDEOCM_ALLOC pAlloc)
704{
705 NTSTATUS Status = STATUS_UNSUCCESSFUL;
706 UINT cbSize = pAlloc->cbData;
707 UINT cPages = BYTES_TO_PAGES(cbSize);
708 ExAcquireFastMutex(&pMgr->Mutex);
709 UINT iPage = vboxMmAlloc(&pMgr->Mm, cPages);
710 if (iPage != VBOXWDDM_MM_VOID)
711 {
712 uint32_t offData = pMgr->offData + (iPage << PAGE_SHIFT);
713 Assert(offData + cbSize <= pMgr->offData + pMgr->cbData);
714 pAlloc->offData = offData;
715 pAlloc->hGlobalHandle = vboxWddmHTablePut(&pMgr->AllocTable, pAlloc);
716 ExReleaseFastMutex(&pMgr->Mutex);
717 if (VBOXWDDM_HANDLE_INVALID != pAlloc->hGlobalHandle)
718 return STATUS_SUCCESS;
719
720 Assert(0);
721 Status = STATUS_NO_MEMORY;
722 vboxMmFree(&pMgr->Mm, iPage, cPages);
723 }
724 else
725 {
726 Assert(0);
727 ExReleaseFastMutex(&pMgr->Mutex);
728 Status = STATUS_INSUFFICIENT_RESOURCES;
729 }
730 return Status;
731}
732
733VOID vboxVideoCmAllocDealloc(PVBOXVIDEOCM_ALLOC_MGR pMgr, PVBOXVIDEOCM_ALLOC pAlloc)
734{
735 UINT cbSize = pAlloc->cbData;
736 UINT cPages = BYTES_TO_PAGES(cbSize);
737 UINT iPage = BYTES_TO_PAGES(pAlloc->offData - pMgr->offData);
738 ExAcquireFastMutex(&pMgr->Mutex);
739 vboxWddmHTableRemove(&pMgr->AllocTable, pAlloc->hGlobalHandle);
740 vboxMmFree(&pMgr->Mm, iPage, cPages);
741 ExReleaseFastMutex(&pMgr->Mutex);
742}
743
744
745NTSTATUS vboxVideoAMgrAllocCreate(PVBOXVIDEOCM_ALLOC_MGR pMgr, UINT cbSize, PVBOXVIDEOCM_ALLOC *ppAlloc)
746{
747 NTSTATUS Status = STATUS_SUCCESS;
748 PVBOXVIDEOCM_ALLOC pAlloc = (PVBOXVIDEOCM_ALLOC)vboxWddmMemAllocZero(sizeof (*pAlloc));
749 if (pAlloc)
750 {
751 pAlloc->cbData = cbSize;
752 Status = vboxVideoCmAllocAlloc(pMgr, pAlloc);
753 if (Status == STATUS_SUCCESS)
754 {
755 *ppAlloc = pAlloc;
756 return STATUS_SUCCESS;
757 }
758
759 Assert(0);
760 vboxWddmMemFree(pAlloc);
761 }
762 else
763 {
764 Assert(0);
765 Status = STATUS_NO_MEMORY;
766 }
767
768 return Status;
769}
770
771VOID vboxVideoAMgrAllocDestroy(PVBOXVIDEOCM_ALLOC_MGR pMgr, PVBOXVIDEOCM_ALLOC pAlloc)
772{
773 vboxVideoCmAllocDealloc(pMgr, pAlloc);
774 vboxWddmMemFree(pAlloc);
775}
776
777NTSTATUS vboxVideoAMgrCtxAllocMap(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, PVBOXVIDEOCM_ALLOC pAlloc, PVBOXVIDEOCM_UM_ALLOC pUmAlloc)
778{
779 PVBOXVIDEOCM_ALLOC_MGR pMgr = pContext->pMgr;
780 NTSTATUS Status = STATUS_SUCCESS;
781 PKEVENT pSynchEvent = NULL;
782
783 if (pUmAlloc->hSynch)
784 {
785 Status = ObReferenceObjectByHandle((HANDLE)pUmAlloc->hSynch, EVENT_MODIFY_STATE, *ExEventObjectType, UserMode,
786 (PVOID*)&pSynchEvent,
787 NULL);
788 AssertNtStatusSuccess(Status);
789 Assert(pSynchEvent);
790 }
791
792 if (Status == STATUS_SUCCESS)
793 {
794 PVOID BaseVa = pMgr->pvData + pAlloc->offData - pMgr->offData;
795 SIZE_T cbLength = pAlloc->cbData;
796
797 PVBOXVIDEOCM_ALLOC_REF pAllocRef;
798 pAllocRef = (PVBOXVIDEOCM_ALLOC_REF)vboxWddmMemAllocZero( sizeof(*pAllocRef)
799 + sizeof(PFN_NUMBER)
800 * ADDRESS_AND_SIZE_TO_SPAN_PAGES(BaseVa, cbLength));
801 if (pAllocRef)
802 {
803 pAllocRef->cRefs = 1;
804 MmInitializeMdl(&pAllocRef->Mdl, BaseVa, cbLength);
805 __try
806 {
807 MmProbeAndLockPages(&pAllocRef->Mdl, KernelMode, IoWriteAccess);
808 }
809 __except(EXCEPTION_EXECUTE_HANDLER)
810 {
811 Assert(0);
812 Status = STATUS_UNSUCCESSFUL;
813 }
814
815 if (Status == STATUS_SUCCESS)
816 {
817 PVOID pvUm = MmMapLockedPagesSpecifyCache(&pAllocRef->Mdl, UserMode, MmNonCached,
818 NULL, /* PVOID BaseAddress */
819 FALSE, /* ULONG BugCheckOnFailure */
820 NormalPagePriority);
821 if (pvUm)
822 {
823 pAllocRef->pvUm = pvUm;
824 pAllocRef->pContext = pContext;
825 pAllocRef->pAlloc = pAlloc;
826 pAllocRef->fUhgsmiType = pUmAlloc->fUhgsmiType;
827 pAllocRef->pSynchEvent = pSynchEvent;
828 ExAcquireFastMutex(&pContext->Mutex);
829 pAllocRef->hSessionHandle = vboxWddmHTablePut(&pContext->AllocTable, pAllocRef);
830 ExReleaseFastMutex(&pContext->Mutex);
831 if (VBOXWDDM_HANDLE_INVALID != pAllocRef->hSessionHandle)
832 {
833 pUmAlloc->hAlloc = pAllocRef->hSessionHandle;
834 pUmAlloc->cbData = pAlloc->cbData;
835 pUmAlloc->pvData = (uintptr_t)pvUm;
836 return STATUS_SUCCESS;
837 }
838
839 MmUnmapLockedPages(pvUm, &pAllocRef->Mdl);
840 }
841 else
842 {
843 Assert(0);
844 Status = STATUS_INSUFFICIENT_RESOURCES;
845 }
846
847 MmUnlockPages(&pAllocRef->Mdl);
848 }
849
850 vboxWddmMemFree(pAllocRef);
851 }
852 else
853 {
854 Assert(0);
855 Status = STATUS_NO_MEMORY;
856 }
857
858 if (pSynchEvent)
859 ObDereferenceObject(pSynchEvent);
860 }
861 else
862 {
863 Assert(0);
864 }
865
866
867 return Status;
868}
869
870NTSTATUS vboxVideoAMgrCtxAllocUnmap(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, VBOXDISP_KMHANDLE hSesionHandle,
871 PVBOXVIDEOCM_ALLOC *ppAlloc)
872{
873 NTSTATUS Status = STATUS_SUCCESS;
874 ExAcquireFastMutex(&pContext->Mutex);
875 PVBOXVIDEOCM_ALLOC_REF pAllocRef = (PVBOXVIDEOCM_ALLOC_REF)vboxWddmHTableRemove(&pContext->AllocTable, hSesionHandle);
876 ExReleaseFastMutex(&pContext->Mutex);
877 if (pAllocRef)
878 {
879 /* wait for the dereference, i.e. for all commands involving this allocation to complete */
880 vboxWddmCounterU32Wait(&pAllocRef->cRefs, 1);
881
882 MmUnmapLockedPages(pAllocRef->pvUm, &pAllocRef->Mdl);
883
884 MmUnlockPages(&pAllocRef->Mdl);
885 *ppAlloc = pAllocRef->pAlloc;
886 if (pAllocRef->pSynchEvent)
887 ObDereferenceObject(pAllocRef->pSynchEvent);
888 vboxWddmMemFree(pAllocRef);
889 }
890 else
891 {
892 Assert(0);
893 Status = STATUS_INVALID_PARAMETER;
894 }
895
896 return Status;
897}
898
899static PVBOXVIDEOCM_ALLOC_REF vboxVideoAMgrCtxAllocRefAcquire(PVBOXVIDEOCM_ALLOC_CONTEXT pContext,
900 VBOXDISP_KMHANDLE hSesionHandle)
901{
902 ExAcquireFastMutex(&pContext->Mutex);
903 PVBOXVIDEOCM_ALLOC_REF pAllocRef = (PVBOXVIDEOCM_ALLOC_REF)vboxWddmHTableGet(&pContext->AllocTable, hSesionHandle);
904 if (pAllocRef)
905 ASMAtomicIncU32(&pAllocRef->cRefs);
906 ExReleaseFastMutex(&pContext->Mutex);
907 return pAllocRef;
908}
909
910static VOID vboxVideoAMgrCtxAllocRefRelease(PVBOXVIDEOCM_ALLOC_REF pRef)
911{
912 uint32_t cRefs = ASMAtomicDecU32(&pRef->cRefs);
913 Assert(cRefs < UINT32_MAX/2);
914 Assert(cRefs >= 1); /* we do not do cleanup-on-zero here, instead we wait for the cRefs to reach 1 in
915 vboxVideoAMgrCtxAllocUnmap before unmapping */
916 NOREF(cRefs);
917}
918
919
920
921NTSTATUS vboxVideoAMgrCtxAllocCreate(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, PVBOXVIDEOCM_UM_ALLOC pUmAlloc)
922{
923 PVBOXVIDEOCM_ALLOC pAlloc;
924 PVBOXVIDEOCM_ALLOC_MGR pMgr = pContext->pMgr;
925 NTSTATUS Status = vboxVideoAMgrAllocCreate(pMgr, pUmAlloc->cbData, &pAlloc);
926 if (Status == STATUS_SUCCESS)
927 {
928 Status = vboxVideoAMgrCtxAllocMap(pContext, pAlloc, pUmAlloc);
929 if (Status == STATUS_SUCCESS)
930 return STATUS_SUCCESS;
931 else
932 {
933 Assert(0);
934 }
935 vboxVideoAMgrAllocDestroy(pMgr, pAlloc);
936 }
937 else
938 {
939 Assert(0);
940 }
941 return Status;
942}
943
944NTSTATUS vboxVideoAMgrCtxAllocDestroy(PVBOXVIDEOCM_ALLOC_CONTEXT pContext, VBOXDISP_KMHANDLE hSesionHandle)
945{
946 PVBOXVIDEOCM_ALLOC pAlloc;
947 PVBOXVIDEOCM_ALLOC_MGR pMgr = pContext->pMgr;
948 NTSTATUS Status = vboxVideoAMgrCtxAllocUnmap(pContext, hSesionHandle, &pAlloc);
949 if (Status == STATUS_SUCCESS)
950 {
951 vboxVideoAMgrAllocDestroy(pMgr, pAlloc);
952 }
953 else
954 {
955 Assert(0);
956 }
957 return Status;
958}
959
960NTSTATUS vboxVideoAMgrCreate(PVBOXMP_DEVEXT pDevExt, PVBOXVIDEOCM_ALLOC_MGR pMgr, uint32_t offData, uint32_t cbData)
961{
962 Assert(!(offData & (PAGE_SIZE -1)));
963 Assert(!(cbData & (PAGE_SIZE -1)));
964 offData = VBOXWDDM_ROUNDBOUND(offData, PAGE_SIZE);
965 cbData &= (~(PAGE_SIZE -1));
966 Assert(cbData);
967 if (!cbData)
968 return STATUS_INVALID_PARAMETER;
969
970 ExInitializeFastMutex(&pMgr->Mutex);
971 NTSTATUS Status = vboxWddmHTableCreate(&pMgr->AllocTable, 64);
972 AssertNtStatusSuccess(Status);
973 if (Status == STATUS_SUCCESS)
974 {
975 Status = vboxMmInit(&pMgr->Mm, BYTES_TO_PAGES(cbData));
976 AssertNtStatusSuccess(Status);
977 if (Status == STATUS_SUCCESS)
978 {
979 PHYSICAL_ADDRESS PhysicalAddress = {0};
980 PhysicalAddress.QuadPart = VBoxCommonFromDeviceExt(pDevExt)->phVRAM.QuadPart + offData;
981 pMgr->pvData = (uint8_t*)MmMapIoSpace(PhysicalAddress, cbData, MmNonCached);
982 Assert(pMgr->pvData);
983 if (pMgr->pvData)
984 {
985 pMgr->offData = offData;
986 pMgr->cbData = cbData;
987 return STATUS_SUCCESS;
988 }
989 else
990 {
991 Status = STATUS_UNSUCCESSFUL;
992 }
993 vboxMmTerm(&pMgr->Mm);
994 }
995 vboxWddmHTableDestroy(&pMgr->AllocTable);
996 }
997
998 return Status;
999}
1000
1001NTSTATUS vboxVideoAMgrDestroy(PVBOXMP_DEVEXT pDevExt, PVBOXVIDEOCM_ALLOC_MGR pMgr)
1002{
1003 RT_NOREF(pDevExt);
1004 MmUnmapIoSpace(pMgr->pvData, pMgr->cbData);
1005 vboxMmTerm(&pMgr->Mm);
1006 vboxWddmHTableDestroy(&pMgr->AllocTable);
1007 return STATUS_SUCCESS;
1008}
1009
1010NTSTATUS vboxVideoAMgrCtxCreate(PVBOXVIDEOCM_ALLOC_MGR pMgr, PVBOXVIDEOCM_ALLOC_CONTEXT pCtx)
1011{
1012 NTSTATUS Status = STATUS_NOT_SUPPORTED;
1013 if (pMgr->pvData)
1014 {
1015 ExInitializeFastMutex(&pCtx->Mutex);
1016 Status = vboxWddmHTableCreate(&pCtx->AllocTable, 32);
1017 AssertNtStatusSuccess(Status);
1018 if (Status == STATUS_SUCCESS)
1019 {
1020 pCtx->pMgr = pMgr;
1021 return STATUS_SUCCESS;
1022 }
1023 }
1024 return Status;
1025}
1026
1027NTSTATUS vboxVideoAMgrCtxDestroy(PVBOXVIDEOCM_ALLOC_CONTEXT pCtx)
1028{
1029 if (!pCtx->pMgr)
1030 return STATUS_SUCCESS;
1031
1032 VBOXWDDM_HTABLE_ITERATOR Iter;
1033 NTSTATUS Status = STATUS_SUCCESS;
1034
1035 vboxWddmHTableIterInit(&pCtx->AllocTable, &Iter);
1036 do
1037 {
1038 PVBOXVIDEOCM_ALLOC_REF pRef = (PVBOXVIDEOCM_ALLOC_REF)vboxWddmHTableIterNext(&Iter, NULL);
1039 if (!pRef)
1040 break;
1041
1042 Assert(0);
1043
1044 Status = vboxVideoAMgrCtxAllocDestroy(pCtx, pRef->hSessionHandle);
1045 AssertNtStatusSuccess(Status);
1046 if (Status != STATUS_SUCCESS)
1047 break;
1048 // vboxWddmHTableIterRemoveCur(&Iter);
1049 } while (1);
1050
1051 if (Status == STATUS_SUCCESS)
1052 {
1053 vboxWddmHTableDestroy(&pCtx->AllocTable);
1054 }
1055
1056 return Status;
1057}
1058
1059
1060VOID vboxWddmSleep(uint32_t u32Val)
1061{
1062 RT_NOREF(u32Val);
1063 LARGE_INTEGER Interval;
1064 Interval.QuadPart = -(int64_t) 2 /* ms */ * 10000;
1065
1066 KeDelayExecutionThread(KernelMode, FALSE, &Interval);
1067}
1068
1069VOID vboxWddmCounterU32Wait(uint32_t volatile * pu32, uint32_t u32Val)
1070{
1071 LARGE_INTEGER Interval;
1072 Interval.QuadPart = -(int64_t) 2 /* ms */ * 10000;
1073 uint32_t u32CurVal;
1074
1075 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
1076
1077 while ((u32CurVal = ASMAtomicReadU32(pu32)) != u32Val)
1078 {
1079 Assert(u32CurVal >= u32Val);
1080 Assert(u32CurVal < UINT32_MAX/2);
1081
1082 KeDelayExecutionThread(KernelMode, FALSE, &Interval);
1083 }
1084}
1085
1086/* dump user-mode driver debug info */
1087static char g_aVBoxUmdD3DCAPS9[304];
1088static VBOXDISPIFESCAPE_DBGDUMPBUF_FLAGS g_VBoxUmdD3DCAPS9Flags;
1089static BOOLEAN g_bVBoxUmdD3DCAPS9IsInited = FALSE;
1090
1091static void vboxUmdDumpDword(DWORD *pvData, DWORD cData)
1092{
1093 DWORD dw1, dw2, dw3, dw4;
1094 for (UINT i = 0; i < (cData & (~3)); i+=4)
1095 {
1096 dw1 = *pvData++;
1097 dw2 = *pvData++;
1098 dw3 = *pvData++;
1099 dw4 = *pvData++;
1100 LOGREL(("0x%08x, 0x%08x, 0x%08x, 0x%08x,\n", dw1, dw2, dw3, dw4));
1101 }
1102
1103 cData = cData % 4;
1104 switch (cData)
1105 {
1106 case 3:
1107 dw1 = *pvData++;
1108 dw2 = *pvData++;
1109 dw3 = *pvData++;
1110 LOGREL(("0x%08x, 0x%08x, 0x%08x\n", dw1, dw2, dw3));
1111 break;
1112 case 2:
1113 dw1 = *pvData++;
1114 dw2 = *pvData++;
1115 LOGREL(("0x%08x, 0x%08x\n", dw1, dw2));
1116 break;
1117 case 1:
1118 dw1 = *pvData++;
1119 LOGREL(("0x%8x\n", dw1));
1120 break;
1121 default:
1122 break;
1123 }
1124}
1125
1126static void vboxUmdDumpD3DCAPS9(void *pvData, PVBOXDISPIFESCAPE_DBGDUMPBUF_FLAGS pFlags)
1127{
1128 AssertCompile(!(sizeof (g_aVBoxUmdD3DCAPS9) % sizeof (DWORD)));
1129 LOGREL(("*****Start Dumping D3DCAPS9:*******"));
1130 LOGREL(("WoW64 flag(%d)", (UINT)pFlags->WoW64));
1131 vboxUmdDumpDword((DWORD*)pvData, sizeof (g_aVBoxUmdD3DCAPS9) / sizeof (DWORD));
1132 LOGREL(("*****End Dumping D3DCAPS9**********"));
1133}
1134
1135NTSTATUS vboxUmdDumpBuf(PVBOXDISPIFESCAPE_DBGDUMPBUF pBuf, uint32_t cbBuffer)
1136{
1137 if (cbBuffer < RT_UOFFSETOF(VBOXDISPIFESCAPE_DBGDUMPBUF, aBuf[0]))
1138 {
1139 WARN(("Buffer too small"));
1140 return STATUS_BUFFER_TOO_SMALL;
1141 }
1142
1143 NTSTATUS Status = STATUS_SUCCESS;
1144 uint32_t cbString = cbBuffer - RT_UOFFSETOF(VBOXDISPIFESCAPE_DBGDUMPBUF, aBuf[0]);
1145 switch (pBuf->enmType)
1146 {
1147 case VBOXDISPIFESCAPE_DBGDUMPBUF_TYPE_D3DCAPS9:
1148 {
1149 if (cbString != sizeof (g_aVBoxUmdD3DCAPS9))
1150 {
1151 WARN(("wrong caps size, expected %d, but was %d", sizeof (g_aVBoxUmdD3DCAPS9), cbString));
1152 Status = STATUS_INVALID_PARAMETER;
1153 break;
1154 }
1155
1156 if (g_bVBoxUmdD3DCAPS9IsInited)
1157 {
1158 if (!memcmp(g_aVBoxUmdD3DCAPS9, pBuf->aBuf, sizeof (g_aVBoxUmdD3DCAPS9)))
1159 break;
1160
1161 WARN(("caps do not match!"));
1162 vboxUmdDumpD3DCAPS9(pBuf->aBuf, &pBuf->Flags);
1163 break;
1164 }
1165
1166 memcpy(g_aVBoxUmdD3DCAPS9, pBuf->aBuf, sizeof (g_aVBoxUmdD3DCAPS9));
1167 g_VBoxUmdD3DCAPS9Flags = pBuf->Flags;
1168 g_bVBoxUmdD3DCAPS9IsInited = TRUE;
1169 vboxUmdDumpD3DCAPS9(pBuf->aBuf, &pBuf->Flags);
1170 }
1171 default: break; /* Shuts up MSC. */
1172 }
1173
1174 return Status;
1175}
1176
1177#if 0
1178VOID vboxShRcTreeInit(PVBOXMP_DEVEXT pDevExt)
1179{
1180 ExInitializeFastMutex(&pDevExt->ShRcTreeMutex);
1181 pDevExt->ShRcTree = NULL;
1182}
1183
1184VOID vboxShRcTreeTerm(PVBOXMP_DEVEXT pDevExt)
1185{
1186 Assert(!pDevExt->ShRcTree);
1187 pDevExt->ShRcTree = NULL;
1188}
1189
1190BOOLEAN vboxShRcTreePut(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pAlloc)
1191{
1192 HANDLE hSharedRc = pAlloc->hSharedHandle;
1193 if (!hSharedRc)
1194 {
1195 WARN(("invalid call with zero shared handle!"));
1196 return FALSE;
1197 }
1198 pAlloc->ShRcTreeEntry.Key = (AVLPVKEY)hSharedRc;
1199 ExAcquireFastMutex(&pDevExt->ShRcTreeMutex);
1200 bool bRc = RTAvlPVInsert(&pDevExt->ShRcTree, &pAlloc->ShRcTreeEntry);
1201 ExReleaseFastMutex(&pDevExt->ShRcTreeMutex);
1202 Assert(bRc);
1203 return (BOOLEAN)bRc;
1204}
1205
1206#define PVBOXWDDM_ALLOCATION_FROM_SHRCTREENODE(_p) \
1207 ((PVBOXWDDM_ALLOCATION)(((uint8_t*)(_p)) - RT_OFFSETOF(VBOXWDDM_ALLOCATION, ShRcTreeEntry)))
1208
1209PVBOXWDDM_ALLOCATION vboxShRcTreeGet(PVBOXMP_DEVEXT pDevExt, HANDLE hSharedRc)
1210{
1211 ExAcquireFastMutex(&pDevExt->ShRcTreeMutex);
1212 PAVLPVNODECORE pNode = RTAvlPVGet(&pDevExt->ShRcTree, (AVLPVKEY)hSharedRc);
1213 ExReleaseFastMutex(&pDevExt->ShRcTreeMutex);
1214 if (!pNode)
1215 return NULL;
1216 PVBOXWDDM_ALLOCATION pAlloc = PVBOXWDDM_ALLOCATION_FROM_SHRCTREENODE(pNode);
1217 return pAlloc;
1218}
1219
1220BOOLEAN vboxShRcTreeRemove(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pAlloc)
1221{
1222 HANDLE hSharedRc = pAlloc->hSharedHandle;
1223 if (!hSharedRc)
1224 {
1225 WARN(("invalid call with zero shared handle!"));
1226 return FALSE;
1227 }
1228 ExAcquireFastMutex(&pDevExt->ShRcTreeMutex);
1229 PAVLPVNODECORE pNode = RTAvlPVRemove(&pDevExt->ShRcTree, (AVLPVKEY)hSharedRc);
1230 ExReleaseFastMutex(&pDevExt->ShRcTreeMutex);
1231 if (!pNode)
1232 return NULL;
1233 PVBOXWDDM_ALLOCATION pRetAlloc = PVBOXWDDM_ALLOCATION_FROM_SHRCTREENODE(pNode);
1234 Assert(pRetAlloc == pAlloc);
1235 return !!pRetAlloc;
1236}
1237#endif
1238
1239NTSTATUS vboxWddmDrvCfgInit(PUNICODE_STRING pRegStr)
1240{
1241 HANDLE hKey;
1242 OBJECT_ATTRIBUTES ObjAttr;
1243
1244 InitializeObjectAttributes(&ObjAttr, pRegStr, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
1245
1246 NTSTATUS Status = ZwOpenKey(&hKey, GENERIC_READ, &ObjAttr);
1247 if (!NT_SUCCESS(Status))
1248 {
1249 WARN(("ZwOpenKey for settings key failed, Status 0x%x", Status));
1250 return Status;
1251 }
1252
1253 DWORD dwValue = 0;
1254 Status = vboxWddmRegQueryValueDword(hKey, VBOXWDDM_CFG_STR_LOG_UM, &dwValue);
1255 if (NT_SUCCESS(Status))
1256 g_VBoxLogUm = dwValue;
1257
1258 ZwClose(hKey);
1259
1260 return Status;
1261}
1262
1263NTSTATUS vboxWddmThreadCreate(PKTHREAD * ppThread, PKSTART_ROUTINE pStartRoutine, PVOID pStartContext)
1264{
1265 NTSTATUS fStatus;
1266 HANDLE hThread;
1267 OBJECT_ATTRIBUTES fObjectAttributes;
1268
1269 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
1270
1271 InitializeObjectAttributes(&fObjectAttributes, NULL, OBJ_KERNEL_HANDLE,
1272 NULL, NULL);
1273
1274 fStatus = PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS,
1275 &fObjectAttributes, NULL, NULL,
1276 (PKSTART_ROUTINE) pStartRoutine, pStartContext);
1277 if (!NT_SUCCESS(fStatus))
1278 return fStatus;
1279
1280 ObReferenceObjectByHandle(hThread, THREAD_ALL_ACCESS, NULL,
1281 KernelMode, (PVOID*) ppThread, NULL);
1282 ZwClose(hThread);
1283 return STATUS_SUCCESS;
1284}
1285
1286static int vboxWddmSlConfigure(PVBOXMP_DEVEXT pDevExt, uint32_t fFlags)
1287{
1288 PHGSMIGUESTCOMMANDCONTEXT pCtx = &VBoxCommonFromDeviceExt(pDevExt)->guestCtx;
1289 VBVASCANLINECFG *pCfg;
1290 int rc = VINF_SUCCESS;
1291
1292 /* Allocate the IO buffer. */
1293 pCfg = (VBVASCANLINECFG *)VBoxHGSMIBufferAlloc(pCtx,
1294 sizeof (VBVASCANLINECFG), HGSMI_CH_VBVA,
1295 VBVA_SCANLINE_CFG);
1296
1297 if (pCfg)
1298 {
1299 /* Prepare data to be sent to the host. */
1300 pCfg->rc = VERR_NOT_IMPLEMENTED;
1301 pCfg->fFlags = fFlags;
1302 rc = VBoxHGSMIBufferSubmit(pCtx, pCfg);
1303 if (RT_SUCCESS(rc))
1304 {
1305 AssertRC(pCfg->rc);
1306 rc = pCfg->rc;
1307 }
1308 /* Free the IO buffer. */
1309 VBoxHGSMIBufferFree(pCtx, pCfg);
1310 }
1311 else
1312 rc = VERR_NO_MEMORY;
1313 return rc;
1314}
1315
1316NTSTATUS VBoxWddmSlEnableVSyncNotification(PVBOXMP_DEVEXT pDevExt, BOOLEAN fEnable)
1317{
1318 if (!pDevExt->bVSyncTimerEnabled == !fEnable)
1319 return STATUS_SUCCESS;
1320
1321 if (!fEnable)
1322 {
1323 KeCancelTimer(&pDevExt->VSyncTimer);
1324 }
1325 else
1326 {
1327 KeQuerySystemTime((PLARGE_INTEGER)&pDevExt->VSyncTime);
1328
1329 LARGE_INTEGER DueTime;
1330 DueTime.QuadPart = -166666LL; /* 60 Hz */
1331 KeSetTimerEx(&pDevExt->VSyncTimer, DueTime, 16, &pDevExt->VSyncDpc);
1332 }
1333
1334 pDevExt->bVSyncTimerEnabled = !!fEnable;
1335
1336 return STATUS_SUCCESS;
1337}
1338
1339NTSTATUS VBoxWddmSlGetScanLine(PVBOXMP_DEVEXT pDevExt, DXGKARG_GETSCANLINE *pGetScanLine)
1340{
1341 Assert((UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays > pGetScanLine->VidPnTargetId);
1342 VBOXWDDM_TARGET *pTarget = &pDevExt->aTargets[pGetScanLine->VidPnTargetId];
1343 Assert(pTarget->Size.cx);
1344 Assert(pTarget->Size.cy);
1345 if (pTarget->Size.cy)
1346 {
1347 uint32_t curScanLine = 0;
1348 BOOL bVBlank = FALSE;
1349 LARGE_INTEGER DevVSyncTime;
1350 DevVSyncTime.QuadPart = ASMAtomicReadU64((volatile uint64_t*)&pDevExt->VSyncTime.QuadPart);
1351 LARGE_INTEGER VSyncTime;
1352 KeQuerySystemTime(&VSyncTime);
1353
1354 if (VSyncTime.QuadPart < DevVSyncTime.QuadPart)
1355 {
1356 WARN(("vsync time is less than the one stored in device"));
1357 bVBlank = TRUE;
1358 }
1359 else
1360 {
1361 VSyncTime.QuadPart = VSyncTime.QuadPart - DevVSyncTime.QuadPart;
1362 /*
1363 * Check whether we are in VBlank state or actively drawing a scan line
1364 * 10% of the 60Hz are dedicated to VBlank.
1365 *
1366 * Time intervals are in 100ns steps.
1367 */
1368 LARGE_INTEGER VSyncPeriod;
1369 VSyncPeriod.QuadPart = VSyncTime.QuadPart % 166666LL; /* ASSUMES 60Hz*/
1370 if (VSyncPeriod.QuadPart >= 150000LL)
1371 bVBlank = TRUE;
1372 else
1373 curScanLine = (uint32_t)((pTarget->Size.cy * VSyncPeriod.QuadPart) / 150000LL);
1374 }
1375
1376 pGetScanLine->ScanLine = curScanLine;
1377 pGetScanLine->InVerticalBlank = bVBlank;
1378 }
1379 else
1380 {
1381 pGetScanLine->InVerticalBlank = TRUE;
1382 pGetScanLine->ScanLine = 0;
1383 }
1384 return STATUS_SUCCESS;
1385}
1386
1387static BOOLEAN vboxWddmSlVSyncIrqCb(PVOID pvContext)
1388{
1389 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)pvContext;
1390 DXGKARGCB_NOTIFY_INTERRUPT_DATA notify;
1391 BOOLEAN bNeedDpc = FALSE;
1392 for (UINT i = 0; i < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
1393 {
1394 PVBOXWDDM_TARGET pTarget = &pDevExt->aTargets[i];
1395 if (pTarget->fConnected)
1396 {
1397 memset(&notify, 0, sizeof(DXGKARGCB_NOTIFY_INTERRUPT_DATA));
1398 notify.InterruptType = g_VBoxDisplayOnly?
1399 DXGK_INTERRUPT_DISPLAYONLY_VSYNC:
1400 DXGK_INTERRUPT_CRTC_VSYNC;
1401 notify.CrtcVsync.VidPnTargetId = i;
1402 pDevExt->u.primary.DxgkInterface.DxgkCbNotifyInterrupt(pDevExt->u.primary.DxgkInterface.DeviceHandle, &notify);
1403 bNeedDpc = TRUE;
1404 }
1405 }
1406
1407 if (bNeedDpc)
1408 {
1409 pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
1410 }
1411
1412 return FALSE;
1413}
1414
1415static VOID vboxWddmSlVSyncDpc(
1416 __in struct _KDPC *Dpc,
1417 __in_opt PVOID DeferredContext,
1418 __in_opt PVOID SystemArgument1,
1419 __in_opt PVOID SystemArgument2
1420)
1421{
1422 RT_NOREF(Dpc, SystemArgument1, SystemArgument2);
1423 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)DeferredContext;
1424 Assert(!pDevExt->fVSyncInVBlank);
1425 ASMAtomicWriteU32(&pDevExt->fVSyncInVBlank, 1);
1426
1427 BOOLEAN bDummy;
1428 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
1429 pDevExt->u.primary.DxgkInterface.DeviceHandle,
1430 vboxWddmSlVSyncIrqCb,
1431 pDevExt,
1432 0, /* IN ULONG MessageNumber */
1433 &bDummy);
1434 if (!NT_SUCCESS(Status))
1435 WARN(("DxgkCbSynchronizeExecution failed Status %#x", Status));
1436
1437 LARGE_INTEGER VSyncTime;
1438 KeQuerySystemTime(&VSyncTime);
1439 ASMAtomicWriteU64((volatile uint64_t*)&pDevExt->VSyncTime.QuadPart, VSyncTime.QuadPart);
1440
1441 ASMAtomicWriteU32(&pDevExt->fVSyncInVBlank, 0);
1442}
1443
1444NTSTATUS VBoxWddmSlInit(PVBOXMP_DEVEXT pDevExt)
1445{
1446 pDevExt->bVSyncTimerEnabled = FALSE;
1447 pDevExt->fVSyncInVBlank = 0;
1448 KeQuerySystemTime((PLARGE_INTEGER)&pDevExt->VSyncTime);
1449 KeInitializeTimer(&pDevExt->VSyncTimer);
1450 KeInitializeDpc(&pDevExt->VSyncDpc, vboxWddmSlVSyncDpc, pDevExt);
1451 return STATUS_SUCCESS;
1452}
1453
1454NTSTATUS VBoxWddmSlTerm(PVBOXMP_DEVEXT pDevExt)
1455{
1456 KeCancelTimer(&pDevExt->VSyncTimer);
1457 return STATUS_SUCCESS;
1458}
1459
1460void vboxWddmDiInitDefault(DXGK_DISPLAY_INFORMATION *pInfo, PHYSICAL_ADDRESS PhAddr, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId)
1461{
1462 pInfo->Width = 1024;
1463 pInfo->Height = 768;
1464 pInfo->Pitch = pInfo->Width * 4;
1465 pInfo->ColorFormat = D3DDDIFMT_A8R8G8B8;
1466 pInfo->PhysicAddress = PhAddr;
1467 pInfo->TargetId = VidPnSourceId;
1468 pInfo->AcpiId = 0;
1469}
1470
1471void vboxWddmDiToAllocData(PVBOXMP_DEVEXT pDevExt, const DXGK_DISPLAY_INFORMATION *pInfo, PVBOXWDDM_ALLOC_DATA pAllocData)
1472{
1473 pAllocData->SurfDesc.width = pInfo->Width;
1474 pAllocData->SurfDesc.height = pInfo->Height;
1475 pAllocData->SurfDesc.format = pInfo->ColorFormat;
1476 pAllocData->SurfDesc.bpp = vboxWddmCalcBitsPerPixel(pInfo->ColorFormat);
1477 pAllocData->SurfDesc.pitch = pInfo->Pitch;
1478 pAllocData->SurfDesc.depth = 1;
1479 pAllocData->SurfDesc.slicePitch = pInfo->Pitch;
1480 pAllocData->SurfDesc.cbSize = pInfo->Pitch * pInfo->Height;
1481 pAllocData->SurfDesc.VidPnSourceId = pInfo->TargetId;
1482 pAllocData->SurfDesc.RefreshRate.Numerator = 60000;
1483 pAllocData->SurfDesc.RefreshRate.Denominator = 1000;
1484
1485 /* the address here is not a VRAM offset! so convert it to offset */
1486 vboxWddmAddrSetVram(&pAllocData->Addr, 1,
1487 vboxWddmVramAddrToOffset(pDevExt, pInfo->PhysicAddress));
1488}
1489
1490void vboxWddmDmSetupDefaultVramLocation(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID ModifiedVidPnSourceId,
1491 VBOXWDDM_SOURCE *paSources)
1492{
1493 PVBOXWDDM_SOURCE pSource = &paSources[ModifiedVidPnSourceId];
1494 AssertRelease(g_VBoxDisplayOnly);
1495 ULONG offVram = vboxWddmVramCpuVisibleSegmentSize(pDevExt);
1496 offVram /= VBoxCommonFromDeviceExt(pDevExt)->cDisplays;
1497 offVram &= ~PAGE_OFFSET_MASK;
1498 offVram *= ModifiedVidPnSourceId;
1499
1500 if (vboxWddmAddrSetVram(&pSource->AllocData.Addr, 1, offVram))
1501 pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_LOCATION;
1502}
1503
1504char const *vboxWddmAllocTypeString(PVBOXWDDM_ALLOCATION pAlloc)
1505{
1506 switch (pAlloc->enmType)
1507 {
1508 case VBOXWDDM_ALLOC_TYPE_UNEFINED: return "UNEFINED";
1509 case VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE: return "SHAREDPRIMARYSURFACE";
1510 case VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE: return "SHADOWSURFACE";
1511 case VBOXWDDM_ALLOC_TYPE_STD_STAGINGSURFACE: return "STAGINGSURFACE";
1512 case VBOXWDDM_ALLOC_TYPE_STD_GDISURFACE: return "GDISURFACE";
1513 case VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC: return "UMD_RC_GENERIC";
1514 case VBOXWDDM_ALLOC_TYPE_UMD_HGSMI_BUFFER: return "UMD_HGSMI_BUFFER";
1515 default: break;
1516 }
1517 AssertFailed();
1518 return "UNKNOWN";
1519}
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