VirtualBox

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

Last change on this file was 99828, checked in by vboxsync, 13 months ago

*: A bunch of adjustments that allows using /permissive- with Visual C++ (qt 6.x necessity).

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

© 2023 Oracle
ContactPrivacy policyTerms of Use