VirtualBox

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

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

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 46.5 KB
Line 
1/* $Id: VBoxMPMisc.cpp 82968 2020-02-04 10:35:17Z 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 char aBuf[16*4];
1094 DWORD dw1, dw2, dw3, dw4;
1095 for (UINT i = 0; i < (cData & (~3)); i+=4)
1096 {
1097 dw1 = *pvData++;
1098 dw2 = *pvData++;
1099 dw3 = *pvData++;
1100 dw4 = *pvData++;
1101 sprintf(aBuf, "0x%08x, 0x%08x, 0x%08x, 0x%08x,\n", dw1, dw2, dw3, dw4);
1102 LOGREL(("%s", aBuf));
1103 }
1104
1105 cData = cData % 4;
1106 switch (cData)
1107 {
1108 case 3:
1109 dw1 = *pvData++;
1110 dw2 = *pvData++;
1111 dw3 = *pvData++;
1112 sprintf(aBuf, "0x%08x, 0x%08x, 0x%08x\n", dw1, dw2, dw3);
1113 LOGREL(("%s", aBuf));
1114 break;
1115 case 2:
1116 dw1 = *pvData++;
1117 dw2 = *pvData++;
1118 sprintf(aBuf, "0x%08x, 0x%08x\n", dw1, dw2);
1119 LOGREL(("%s", aBuf));
1120 break;
1121 case 1:
1122 dw1 = *pvData++;
1123 sprintf(aBuf, "0x%8x\n", dw1);
1124 LOGREL(("%s", aBuf));
1125 break;
1126 default:
1127 break;
1128 }
1129}
1130
1131static void vboxUmdDumpD3DCAPS9(void *pvData, PVBOXDISPIFESCAPE_DBGDUMPBUF_FLAGS pFlags)
1132{
1133 AssertCompile(!(sizeof (g_aVBoxUmdD3DCAPS9) % sizeof (DWORD)));
1134 LOGREL(("*****Start Dumping D3DCAPS9:*******"));
1135 LOGREL(("WoW64 flag(%d)", (UINT)pFlags->WoW64));
1136 vboxUmdDumpDword((DWORD*)pvData, sizeof (g_aVBoxUmdD3DCAPS9) / sizeof (DWORD));
1137 LOGREL(("*****End Dumping D3DCAPS9**********"));
1138}
1139
1140NTSTATUS vboxUmdDumpBuf(PVBOXDISPIFESCAPE_DBGDUMPBUF pBuf, uint32_t cbBuffer)
1141{
1142 if (cbBuffer < RT_UOFFSETOF(VBOXDISPIFESCAPE_DBGDUMPBUF, aBuf[0]))
1143 {
1144 WARN(("Buffer too small"));
1145 return STATUS_BUFFER_TOO_SMALL;
1146 }
1147
1148 NTSTATUS Status = STATUS_SUCCESS;
1149 uint32_t cbString = cbBuffer - RT_UOFFSETOF(VBOXDISPIFESCAPE_DBGDUMPBUF, aBuf[0]);
1150 switch (pBuf->enmType)
1151 {
1152 case VBOXDISPIFESCAPE_DBGDUMPBUF_TYPE_D3DCAPS9:
1153 {
1154 if (cbString != sizeof (g_aVBoxUmdD3DCAPS9))
1155 {
1156 WARN(("wrong caps size, expected %d, but was %d", sizeof (g_aVBoxUmdD3DCAPS9), cbString));
1157 Status = STATUS_INVALID_PARAMETER;
1158 break;
1159 }
1160
1161 if (g_bVBoxUmdD3DCAPS9IsInited)
1162 {
1163 if (!memcmp(g_aVBoxUmdD3DCAPS9, pBuf->aBuf, sizeof (g_aVBoxUmdD3DCAPS9)))
1164 break;
1165
1166 WARN(("caps do not match!"));
1167 vboxUmdDumpD3DCAPS9(pBuf->aBuf, &pBuf->Flags);
1168 break;
1169 }
1170
1171 memcpy(g_aVBoxUmdD3DCAPS9, pBuf->aBuf, sizeof (g_aVBoxUmdD3DCAPS9));
1172 g_VBoxUmdD3DCAPS9Flags = pBuf->Flags;
1173 g_bVBoxUmdD3DCAPS9IsInited = TRUE;
1174 vboxUmdDumpD3DCAPS9(pBuf->aBuf, &pBuf->Flags);
1175 }
1176 default: break; /* Shuts up MSC. */
1177 }
1178
1179 return Status;
1180}
1181
1182#if 0
1183VOID vboxShRcTreeInit(PVBOXMP_DEVEXT pDevExt)
1184{
1185 ExInitializeFastMutex(&pDevExt->ShRcTreeMutex);
1186 pDevExt->ShRcTree = NULL;
1187}
1188
1189VOID vboxShRcTreeTerm(PVBOXMP_DEVEXT pDevExt)
1190{
1191 Assert(!pDevExt->ShRcTree);
1192 pDevExt->ShRcTree = NULL;
1193}
1194
1195BOOLEAN vboxShRcTreePut(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pAlloc)
1196{
1197 HANDLE hSharedRc = pAlloc->hSharedHandle;
1198 if (!hSharedRc)
1199 {
1200 WARN(("invalid call with zero shared handle!"));
1201 return FALSE;
1202 }
1203 pAlloc->ShRcTreeEntry.Key = (AVLPVKEY)hSharedRc;
1204 ExAcquireFastMutex(&pDevExt->ShRcTreeMutex);
1205 bool bRc = RTAvlPVInsert(&pDevExt->ShRcTree, &pAlloc->ShRcTreeEntry);
1206 ExReleaseFastMutex(&pDevExt->ShRcTreeMutex);
1207 Assert(bRc);
1208 return (BOOLEAN)bRc;
1209}
1210
1211#define PVBOXWDDM_ALLOCATION_FROM_SHRCTREENODE(_p) \
1212 ((PVBOXWDDM_ALLOCATION)(((uint8_t*)(_p)) - RT_OFFSETOF(VBOXWDDM_ALLOCATION, ShRcTreeEntry)))
1213
1214PVBOXWDDM_ALLOCATION vboxShRcTreeGet(PVBOXMP_DEVEXT pDevExt, HANDLE hSharedRc)
1215{
1216 ExAcquireFastMutex(&pDevExt->ShRcTreeMutex);
1217 PAVLPVNODECORE pNode = RTAvlPVGet(&pDevExt->ShRcTree, (AVLPVKEY)hSharedRc);
1218 ExReleaseFastMutex(&pDevExt->ShRcTreeMutex);
1219 if (!pNode)
1220 return NULL;
1221 PVBOXWDDM_ALLOCATION pAlloc = PVBOXWDDM_ALLOCATION_FROM_SHRCTREENODE(pNode);
1222 return pAlloc;
1223}
1224
1225BOOLEAN vboxShRcTreeRemove(PVBOXMP_DEVEXT pDevExt, PVBOXWDDM_ALLOCATION pAlloc)
1226{
1227 HANDLE hSharedRc = pAlloc->hSharedHandle;
1228 if (!hSharedRc)
1229 {
1230 WARN(("invalid call with zero shared handle!"));
1231 return FALSE;
1232 }
1233 ExAcquireFastMutex(&pDevExt->ShRcTreeMutex);
1234 PAVLPVNODECORE pNode = RTAvlPVRemove(&pDevExt->ShRcTree, (AVLPVKEY)hSharedRc);
1235 ExReleaseFastMutex(&pDevExt->ShRcTreeMutex);
1236 if (!pNode)
1237 return NULL;
1238 PVBOXWDDM_ALLOCATION pRetAlloc = PVBOXWDDM_ALLOCATION_FROM_SHRCTREENODE(pNode);
1239 Assert(pRetAlloc == pAlloc);
1240 return !!pRetAlloc;
1241}
1242#endif
1243
1244NTSTATUS vboxWddmDrvCfgInit(PUNICODE_STRING pRegStr)
1245{
1246 HANDLE hKey;
1247 OBJECT_ATTRIBUTES ObjAttr;
1248
1249 InitializeObjectAttributes(&ObjAttr, pRegStr, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
1250
1251 NTSTATUS Status = ZwOpenKey(&hKey, GENERIC_READ, &ObjAttr);
1252 if (!NT_SUCCESS(Status))
1253 {
1254 WARN(("ZwOpenKey for settings key failed, Status 0x%x", Status));
1255 return Status;
1256 }
1257
1258 DWORD dwValue = 0;
1259 Status = vboxWddmRegQueryValueDword(hKey, VBOXWDDM_CFG_STR_LOG_UM, &dwValue);
1260 if (NT_SUCCESS(Status))
1261 g_VBoxLogUm = dwValue;
1262
1263 ZwClose(hKey);
1264
1265 return Status;
1266}
1267
1268NTSTATUS vboxWddmThreadCreate(PKTHREAD * ppThread, PKSTART_ROUTINE pStartRoutine, PVOID pStartContext)
1269{
1270 NTSTATUS fStatus;
1271 HANDLE hThread;
1272 OBJECT_ATTRIBUTES fObjectAttributes;
1273
1274 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
1275
1276 InitializeObjectAttributes(&fObjectAttributes, NULL, OBJ_KERNEL_HANDLE,
1277 NULL, NULL);
1278
1279 fStatus = PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS,
1280 &fObjectAttributes, NULL, NULL,
1281 (PKSTART_ROUTINE) pStartRoutine, pStartContext);
1282 if (!NT_SUCCESS(fStatus))
1283 return fStatus;
1284
1285 ObReferenceObjectByHandle(hThread, THREAD_ALL_ACCESS, NULL,
1286 KernelMode, (PVOID*) ppThread, NULL);
1287 ZwClose(hThread);
1288 return STATUS_SUCCESS;
1289}
1290
1291static int vboxWddmSlConfigure(PVBOXMP_DEVEXT pDevExt, uint32_t fFlags)
1292{
1293 PHGSMIGUESTCOMMANDCONTEXT pCtx = &VBoxCommonFromDeviceExt(pDevExt)->guestCtx;
1294 VBVASCANLINECFG *pCfg;
1295 int rc = VINF_SUCCESS;
1296
1297 /* Allocate the IO buffer. */
1298 pCfg = (VBVASCANLINECFG *)VBoxHGSMIBufferAlloc(pCtx,
1299 sizeof (VBVASCANLINECFG), HGSMI_CH_VBVA,
1300 VBVA_SCANLINE_CFG);
1301
1302 if (pCfg)
1303 {
1304 /* Prepare data to be sent to the host. */
1305 pCfg->rc = VERR_NOT_IMPLEMENTED;
1306 pCfg->fFlags = fFlags;
1307 rc = VBoxHGSMIBufferSubmit(pCtx, pCfg);
1308 if (RT_SUCCESS(rc))
1309 {
1310 AssertRC(pCfg->rc);
1311 rc = pCfg->rc;
1312 }
1313 /* Free the IO buffer. */
1314 VBoxHGSMIBufferFree(pCtx, pCfg);
1315 }
1316 else
1317 rc = VERR_NO_MEMORY;
1318 return rc;
1319}
1320
1321NTSTATUS VBoxWddmSlEnableVSyncNotification(PVBOXMP_DEVEXT pDevExt, BOOLEAN fEnable)
1322{
1323 if (!pDevExt->bVSyncTimerEnabled == !fEnable)
1324 return STATUS_SUCCESS;
1325
1326 if (!fEnable)
1327 {
1328 KeCancelTimer(&pDevExt->VSyncTimer);
1329 }
1330 else
1331 {
1332 KeQuerySystemTime((PLARGE_INTEGER)&pDevExt->VSyncTime);
1333
1334 LARGE_INTEGER DueTime;
1335 DueTime.QuadPart = -166666LL; /* 60 Hz */
1336 KeSetTimerEx(&pDevExt->VSyncTimer, DueTime, 16, &pDevExt->VSyncDpc);
1337 }
1338
1339 pDevExt->bVSyncTimerEnabled = !!fEnable;
1340
1341 return STATUS_SUCCESS;
1342}
1343
1344NTSTATUS VBoxWddmSlGetScanLine(PVBOXMP_DEVEXT pDevExt, DXGKARG_GETSCANLINE *pGetScanLine)
1345{
1346 Assert((UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays > pGetScanLine->VidPnTargetId);
1347 VBOXWDDM_TARGET *pTarget = &pDevExt->aTargets[pGetScanLine->VidPnTargetId];
1348 Assert(pTarget->Size.cx);
1349 Assert(pTarget->Size.cy);
1350 if (pTarget->Size.cy)
1351 {
1352 uint32_t curScanLine = 0;
1353 BOOL bVBlank = FALSE;
1354 LARGE_INTEGER DevVSyncTime;
1355 DevVSyncTime.QuadPart = ASMAtomicReadU64((volatile uint64_t*)&pDevExt->VSyncTime.QuadPart);
1356 LARGE_INTEGER VSyncTime;
1357 KeQuerySystemTime(&VSyncTime);
1358
1359 if (VSyncTime.QuadPart < DevVSyncTime.QuadPart)
1360 {
1361 WARN(("vsync time is less than the one stored in device"));
1362 bVBlank = TRUE;
1363 }
1364 else
1365 {
1366 VSyncTime.QuadPart = VSyncTime.QuadPart - DevVSyncTime.QuadPart;
1367 /*
1368 * Check whether we are in VBlank state or actively drawing a scan line
1369 * 10% of the 60Hz are dedicated to VBlank.
1370 *
1371 * Time intervals are in 100ns steps.
1372 */
1373 LARGE_INTEGER VSyncPeriod;
1374 VSyncPeriod.QuadPart = VSyncTime.QuadPart % 166666LL; /* ASSUMES 60Hz*/
1375 if (VSyncPeriod.QuadPart >= 150000LL)
1376 bVBlank = TRUE;
1377 else
1378 curScanLine = (uint32_t)((pTarget->Size.cy * VSyncPeriod.QuadPart) / 150000LL);
1379 }
1380
1381 pGetScanLine->ScanLine = curScanLine;
1382 pGetScanLine->InVerticalBlank = bVBlank;
1383 }
1384 else
1385 {
1386 pGetScanLine->InVerticalBlank = TRUE;
1387 pGetScanLine->ScanLine = 0;
1388 }
1389 return STATUS_SUCCESS;
1390}
1391
1392static BOOLEAN vboxWddmSlVSyncIrqCb(PVOID pvContext)
1393{
1394 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)pvContext;
1395 DXGKARGCB_NOTIFY_INTERRUPT_DATA notify;
1396 BOOLEAN bNeedDpc = FALSE;
1397 for (UINT i = 0; i < (UINT)VBoxCommonFromDeviceExt(pDevExt)->cDisplays; ++i)
1398 {
1399 PVBOXWDDM_TARGET pTarget = &pDevExt->aTargets[i];
1400 if (pTarget->fConnected)
1401 {
1402 memset(&notify, 0, sizeof(DXGKARGCB_NOTIFY_INTERRUPT_DATA));
1403 notify.InterruptType = g_VBoxDisplayOnly?
1404 DXGK_INTERRUPT_DISPLAYONLY_VSYNC:
1405 DXGK_INTERRUPT_CRTC_VSYNC;
1406 notify.CrtcVsync.VidPnTargetId = i;
1407 pDevExt->u.primary.DxgkInterface.DxgkCbNotifyInterrupt(pDevExt->u.primary.DxgkInterface.DeviceHandle, &notify);
1408 bNeedDpc = TRUE;
1409 }
1410 }
1411
1412 if (bNeedDpc)
1413 {
1414 pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
1415 }
1416
1417 return FALSE;
1418}
1419
1420static VOID vboxWddmSlVSyncDpc(
1421 __in struct _KDPC *Dpc,
1422 __in_opt PVOID DeferredContext,
1423 __in_opt PVOID SystemArgument1,
1424 __in_opt PVOID SystemArgument2
1425)
1426{
1427 RT_NOREF(Dpc, SystemArgument1, SystemArgument2);
1428 PVBOXMP_DEVEXT pDevExt = (PVBOXMP_DEVEXT)DeferredContext;
1429 Assert(!pDevExt->fVSyncInVBlank);
1430 ASMAtomicWriteU32(&pDevExt->fVSyncInVBlank, 1);
1431
1432 BOOLEAN bDummy;
1433 NTSTATUS Status = pDevExt->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(
1434 pDevExt->u.primary.DxgkInterface.DeviceHandle,
1435 vboxWddmSlVSyncIrqCb,
1436 pDevExt,
1437 0, /* IN ULONG MessageNumber */
1438 &bDummy);
1439 if (!NT_SUCCESS(Status))
1440 WARN(("DxgkCbSynchronizeExecution failed Status %#x", Status));
1441
1442 LARGE_INTEGER VSyncTime;
1443 KeQuerySystemTime(&VSyncTime);
1444 ASMAtomicWriteU64((volatile uint64_t*)&pDevExt->VSyncTime.QuadPart, VSyncTime.QuadPart);
1445
1446 ASMAtomicWriteU32(&pDevExt->fVSyncInVBlank, 0);
1447}
1448
1449NTSTATUS VBoxWddmSlInit(PVBOXMP_DEVEXT pDevExt)
1450{
1451 pDevExt->bVSyncTimerEnabled = FALSE;
1452 pDevExt->fVSyncInVBlank = 0;
1453 KeQuerySystemTime((PLARGE_INTEGER)&pDevExt->VSyncTime);
1454 KeInitializeTimer(&pDevExt->VSyncTimer);
1455 KeInitializeDpc(&pDevExt->VSyncDpc, vboxWddmSlVSyncDpc, pDevExt);
1456 return STATUS_SUCCESS;
1457}
1458
1459NTSTATUS VBoxWddmSlTerm(PVBOXMP_DEVEXT pDevExt)
1460{
1461 KeCancelTimer(&pDevExt->VSyncTimer);
1462 return STATUS_SUCCESS;
1463}
1464
1465void vboxWddmDiInitDefault(DXGK_DISPLAY_INFORMATION *pInfo, PHYSICAL_ADDRESS PhAddr, D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId)
1466{
1467 pInfo->Width = 1024;
1468 pInfo->Height = 768;
1469 pInfo->Pitch = pInfo->Width * 4;
1470 pInfo->ColorFormat = D3DDDIFMT_A8R8G8B8;
1471 pInfo->PhysicAddress = PhAddr;
1472 pInfo->TargetId = VidPnSourceId;
1473 pInfo->AcpiId = 0;
1474}
1475
1476void vboxWddmDiToAllocData(PVBOXMP_DEVEXT pDevExt, const DXGK_DISPLAY_INFORMATION *pInfo, PVBOXWDDM_ALLOC_DATA pAllocData)
1477{
1478 pAllocData->SurfDesc.width = pInfo->Width;
1479 pAllocData->SurfDesc.height = pInfo->Height;
1480 pAllocData->SurfDesc.format = pInfo->ColorFormat;
1481 pAllocData->SurfDesc.bpp = vboxWddmCalcBitsPerPixel(pInfo->ColorFormat);
1482 pAllocData->SurfDesc.pitch = pInfo->Pitch;
1483 pAllocData->SurfDesc.depth = 1;
1484 pAllocData->SurfDesc.slicePitch = pInfo->Pitch;
1485 pAllocData->SurfDesc.cbSize = pInfo->Pitch * pInfo->Height;
1486 pAllocData->SurfDesc.VidPnSourceId = pInfo->TargetId;
1487 pAllocData->SurfDesc.RefreshRate.Numerator = 60000;
1488 pAllocData->SurfDesc.RefreshRate.Denominator = 1000;
1489
1490 /* the address here is not a VRAM offset! so convert it to offset */
1491 vboxWddmAddrSetVram(&pAllocData->Addr, 1,
1492 vboxWddmVramAddrToOffset(pDevExt, pInfo->PhysicAddress));
1493}
1494
1495void vboxWddmDmSetupDefaultVramLocation(PVBOXMP_DEVEXT pDevExt, D3DDDI_VIDEO_PRESENT_SOURCE_ID ModifiedVidPnSourceId,
1496 VBOXWDDM_SOURCE *paSources)
1497{
1498 PVBOXWDDM_SOURCE pSource = &paSources[ModifiedVidPnSourceId];
1499 AssertRelease(g_VBoxDisplayOnly);
1500 ULONG offVram = vboxWddmVramCpuVisibleSegmentSize(pDevExt);
1501 offVram /= VBoxCommonFromDeviceExt(pDevExt)->cDisplays;
1502 offVram &= ~PAGE_OFFSET_MASK;
1503 offVram *= ModifiedVidPnSourceId;
1504
1505 if (vboxWddmAddrSetVram(&pSource->AllocData.Addr, 1, offVram))
1506 pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_LOCATION;
1507}
1508
1509char const *vboxWddmAllocTypeString(PVBOXWDDM_ALLOCATION pAlloc)
1510{
1511 switch (pAlloc->enmType)
1512 {
1513 case VBOXWDDM_ALLOC_TYPE_UNEFINED: return "UNEFINED";
1514 case VBOXWDDM_ALLOC_TYPE_STD_SHAREDPRIMARYSURFACE: return "SHAREDPRIMARYSURFACE";
1515 case VBOXWDDM_ALLOC_TYPE_STD_SHADOWSURFACE: return "SHADOWSURFACE";
1516 case VBOXWDDM_ALLOC_TYPE_STD_STAGINGSURFACE: return "STAGINGSURFACE";
1517 case VBOXWDDM_ALLOC_TYPE_STD_GDISURFACE: return "GDISURFACE";
1518 case VBOXWDDM_ALLOC_TYPE_UMD_RC_GENERIC: return "UMD_RC_GENERIC";
1519 case VBOXWDDM_ALLOC_TYPE_UMD_HGSMI_BUFFER: return "UMD_HGSMI_BUFFER";
1520 default: break;
1521 }
1522 AssertFailed();
1523 return "UNKNOWN";
1524}
Note: See TracBrowser for help on using the repository browser.

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