VirtualBox

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

Last change on this file since 98329 was 98103, checked in by vboxsync, 2 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: 10.9 KB
Line 
1/* $Id: VBoxMPShgsmi.cpp 98103 2023-01-17 14:15:46Z 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 <iprt/semaphore.h>
30
31/* SHGSMI */
32DECLINLINE(void) vboxSHGSMICommandRetain(VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_HOST *pCmd)
33{
34 ASMAtomicIncU32(&pCmd->cRefs);
35}
36
37void vboxSHGSMICommandFree(PVBOXSHGSMI pHeap, VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_HOST *pCmd)
38{
39 VBoxSHGSMIHeapFree(pHeap, pCmd);
40}
41
42DECLINLINE(void) vboxSHGSMICommandRelease(PVBOXSHGSMI pHeap, VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_HOST *pCmd)
43{
44 uint32_t cRefs = ASMAtomicDecU32(&pCmd->cRefs);
45 Assert(cRefs < UINT32_MAX / 2);
46 if(!cRefs)
47 vboxSHGSMICommandFree(pHeap, pCmd);
48}
49
50static DECLCALLBACK(void) vboxSHGSMICompletionSetEvent(PVBOXSHGSMI pHeap, void RT_UNTRUSTED_VOLATILE_HOST *pvCmd, void *pvContext)
51{
52 RT_NOREF(pHeap, pvCmd);
53 RTSemEventSignal((RTSEMEVENT)pvContext);
54}
55
56DECLCALLBACK(void) vboxSHGSMICompletionCommandRelease(PVBOXSHGSMI pHeap, void RT_UNTRUSTED_VOLATILE_HOST *pvCmd, void *pvContext)
57{
58 RT_NOREF(pvContext);
59 vboxSHGSMICommandRelease(pHeap, VBoxSHGSMIBufferHeader(pvCmd));
60}
61
62/* do not wait for completion */
63DECLINLINE(const VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_HOST *)
64vboxSHGSMICommandPrepAsynch(PVBOXSHGSMI pHeap, VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_HOST *pHeader)
65{
66 RT_NOREF(pHeap);
67 /* ensure the command is not removed until we're processing it */
68 vboxSHGSMICommandRetain(pHeader);
69 return pHeader;
70}
71
72DECLINLINE(void) vboxSHGSMICommandDoneAsynch(PVBOXSHGSMI pHeap, const VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_HOST *pHeader)
73{
74 if(!(ASMAtomicReadU32((volatile uint32_t *)&pHeader->fFlags) & VBOXSHGSMI_FLAG_HG_ASYNCH))
75 {
76 PFNVBOXSHGSMICMDCOMPLETION pfnCompletion = (PFNVBOXSHGSMICMDCOMPLETION)pHeader->u64Info1;
77 if (pfnCompletion)
78 pfnCompletion(pHeap, VBoxSHGSMIBufferData(pHeader), (PVOID)pHeader->u64Info2);
79 }
80
81 vboxSHGSMICommandRelease(pHeap, (PVBOXSHGSMIHEADER)pHeader);
82}
83
84const VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_HOST *
85VBoxSHGSMICommandPrepAsynchEvent(PVBOXSHGSMI pHeap, void RT_UNTRUSTED_VOLATILE_HOST *pvBuff, RTSEMEVENT hEventSem)
86{
87 VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_HOST *pHeader = VBoxSHGSMIBufferHeader(pvBuff);
88 pHeader->u64Info1 = (uint64_t)vboxSHGSMICompletionSetEvent;
89 pHeader->u64Info2 = (uintptr_t)hEventSem;
90 pHeader->fFlags = VBOXSHGSMI_FLAG_GH_ASYNCH_IRQ;
91
92 return vboxSHGSMICommandPrepAsynch(pHeap, pHeader);
93}
94
95const VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_HOST *VBoxSHGSMICommandPrepSynch(PVBOXSHGSMI pHeap,
96 void RT_UNTRUSTED_VOLATILE_HOST *pCmd)
97{
98 RTSEMEVENT hEventSem;
99 int rc = RTSemEventCreate(&hEventSem);
100 Assert(RT_SUCCESS(rc));
101 if (RT_SUCCESS(rc))
102 {
103 return VBoxSHGSMICommandPrepAsynchEvent(pHeap, pCmd, hEventSem);
104 }
105 return NULL;
106}
107
108void VBoxSHGSMICommandDoneAsynch(PVBOXSHGSMI pHeap, const VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_HOST *pHeader)
109{
110 vboxSHGSMICommandDoneAsynch(pHeap, pHeader);
111}
112
113int VBoxSHGSMICommandDoneSynch(PVBOXSHGSMI pHeap, const VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_HOST *pHeader)
114{
115 VBoxSHGSMICommandDoneAsynch(pHeap, pHeader);
116 RTSEMEVENT hEventSem = (RTSEMEVENT)pHeader->u64Info2;
117 int rc = RTSemEventWait(hEventSem, RT_INDEFINITE_WAIT);
118 AssertRC(rc);
119 if (RT_SUCCESS(rc))
120 RTSemEventDestroy(hEventSem);
121 return rc;
122}
123
124void VBoxSHGSMICommandCancelAsynch(PVBOXSHGSMI pHeap, const VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_HOST *pHeader)
125{
126 vboxSHGSMICommandRelease(pHeap, (PVBOXSHGSMIHEADER)pHeader);
127}
128
129void VBoxSHGSMICommandCancelSynch(PVBOXSHGSMI pHeap, const VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_HOST *pHeader)
130{
131 VBoxSHGSMICommandCancelAsynch(pHeap, pHeader);
132 RTSEMEVENT hEventSem = (RTSEMEVENT)pHeader->u64Info2;
133 RTSemEventDestroy(hEventSem);
134}
135
136const VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_HOST *
137VBoxSHGSMICommandPrepAsynch(PVBOXSHGSMI pHeap, void RT_UNTRUSTED_VOLATILE_HOST *pvBuff,
138 PFNVBOXSHGSMICMDCOMPLETION pfnCompletion,
139 void RT_UNTRUSTED_VOLATILE_HOST *pvCompletion, uint32_t fFlags)
140{
141 fFlags &= ~VBOXSHGSMI_FLAG_GH_ASYNCH_CALLBACK_IRQ;
142 VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_HOST *pHeader = VBoxSHGSMIBufferHeader(pvBuff);
143 pHeader->u64Info1 = (uintptr_t)pfnCompletion;
144 pHeader->u64Info2 = (uintptr_t)pvCompletion;
145 pHeader->fFlags = fFlags;
146
147 return vboxSHGSMICommandPrepAsynch(pHeap, pHeader);
148}
149
150const VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_HOST *
151VBoxSHGSMICommandPrepAsynchIrq(PVBOXSHGSMI pHeap, void RT_UNTRUSTED_VOLATILE_HOST *pvBuff,
152 PFNVBOXSHGSMICMDCOMPLETION_IRQ pfnCompletion, PVOID pvCompletion, uint32_t fFlags)
153{
154 fFlags |= VBOXSHGSMI_FLAG_GH_ASYNCH_CALLBACK_IRQ | VBOXSHGSMI_FLAG_GH_ASYNCH_IRQ;
155 VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_HOST *pHeader = VBoxSHGSMIBufferHeader(pvBuff);
156 pHeader->u64Info1 = (uintptr_t)pfnCompletion;
157 pHeader->u64Info2 = (uintptr_t)pvCompletion;
158 /* we must assign rather than or because flags field does not get zeroed on command creation */
159 pHeader->fFlags = fFlags;
160
161 return vboxSHGSMICommandPrepAsynch(pHeap, pHeader);
162}
163
164void RT_UNTRUSTED_VOLATILE_HOST *VBoxSHGSMIHeapAlloc(PVBOXSHGSMI pHeap, HGSMISIZE cbData, uint8_t u8Channel, uint16_t u16ChannelInfo)
165{
166 KIRQL OldIrql;
167 void RT_UNTRUSTED_VOLATILE_HOST *pvData;
168 Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL);
169 KeAcquireSpinLock(&pHeap->HeapLock, &OldIrql);
170 pvData = HGSMIHeapAlloc(&pHeap->Heap, cbData, u8Channel, u16ChannelInfo);
171 KeReleaseSpinLock(&pHeap->HeapLock, OldIrql);
172 if (!pvData)
173 WARN(("HGSMIHeapAlloc failed!"));
174 return pvData;
175}
176
177void VBoxSHGSMIHeapFree(PVBOXSHGSMI pHeap, void RT_UNTRUSTED_VOLATILE_HOST *pvBuffer)
178{
179 KIRQL OldIrql;
180 Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL);
181 KeAcquireSpinLock(&pHeap->HeapLock, &OldIrql);
182 HGSMIHeapFree(&pHeap->Heap, pvBuffer);
183 KeReleaseSpinLock(&pHeap->HeapLock, OldIrql);
184}
185
186void RT_UNTRUSTED_VOLATILE_HOST *VBoxSHGSMIHeapBufferAlloc(PVBOXSHGSMI pHeap, HGSMISIZE cbData)
187{
188 KIRQL OldIrql;
189 void RT_UNTRUSTED_VOLATILE_HOST * pvData;
190 Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL);
191 KeAcquireSpinLock(&pHeap->HeapLock, &OldIrql);
192 pvData = HGSMIHeapBufferAlloc(&pHeap->Heap, cbData);
193 KeReleaseSpinLock(&pHeap->HeapLock, OldIrql);
194 if (!pvData)
195 WARN(("HGSMIHeapAlloc failed!"));
196 return pvData;
197}
198
199void VBoxSHGSMIHeapBufferFree(PVBOXSHGSMI pHeap, void RT_UNTRUSTED_VOLATILE_HOST *pvBuffer)
200{
201 KIRQL OldIrql;
202 Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL);
203 KeAcquireSpinLock(&pHeap->HeapLock, &OldIrql);
204 HGSMIHeapBufferFree(&pHeap->Heap, pvBuffer);
205 KeReleaseSpinLock(&pHeap->HeapLock, OldIrql);
206}
207
208int VBoxSHGSMIInit(PVBOXSHGSMI pHeap, void *pvBase, HGSMISIZE cbArea, HGSMIOFFSET offBase,
209 const HGSMIENV *pEnv)
210{
211 KeInitializeSpinLock(&pHeap->HeapLock);
212 return HGSMIHeapSetup(&pHeap->Heap, pvBase, cbArea, offBase, pEnv);
213}
214
215void VBoxSHGSMITerm(PVBOXSHGSMI pHeap)
216{
217 HGSMIHeapDestroy(&pHeap->Heap);
218}
219
220void RT_UNTRUSTED_VOLATILE_HOST *VBoxSHGSMICommandAlloc(PVBOXSHGSMI pHeap, HGSMISIZE cbData, uint8_t u8Channel,
221 uint16_t u16ChannelInfo)
222{
223 /* Issue the flush command. */
224 VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_HOST *pHeader =
225 (VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_HOST *)VBoxSHGSMIHeapAlloc(pHeap, cbData + sizeof(VBOXSHGSMIHEADER),
226 u8Channel, u16ChannelInfo);
227 Assert(pHeader);
228 if (pHeader)
229 {
230 pHeader->cRefs = 1;
231 return VBoxSHGSMIBufferData(pHeader);
232 }
233 return NULL;
234}
235
236void VBoxSHGSMICommandFree(PVBOXSHGSMI pHeap, void RT_UNTRUSTED_VOLATILE_HOST *pvBuffer)
237{
238 VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_HOST *pHeader = VBoxSHGSMIBufferHeader(pvBuffer);
239 vboxSHGSMICommandRelease(pHeap, pHeader);
240}
241
242#define VBOXSHGSMI_CMD2LISTENTRY(_pCmd) ((PVBOXVTLIST_ENTRY)&(_pCmd)->pvNext)
243#define VBOXSHGSMI_LISTENTRY2CMD(_pEntry) ( (PVBOXSHGSMIHEADER)((uint8_t *)(_pEntry) - RT_UOFFSETOF(VBOXSHGSMIHEADER, pvNext)) )
244
245int VBoxSHGSMICommandProcessCompletion(PVBOXSHGSMI pHeap, VBOXSHGSMIHEADER *pCur, bool bIrq, PVBOXVTLIST pPostProcessList)
246{
247 int rc = VINF_SUCCESS;
248
249 do
250 {
251 if (pCur->fFlags & VBOXSHGSMI_FLAG_GH_ASYNCH_CALLBACK_IRQ)
252 {
253 Assert(bIrq);
254
255 PFNVBOXSHGSMICMDCOMPLETION pfnCompletion = NULL;
256 void *pvCompletion;
257 PFNVBOXSHGSMICMDCOMPLETION_IRQ pfnCallback = (PFNVBOXSHGSMICMDCOMPLETION_IRQ)pCur->u64Info1;
258 void *pvCallback = (void*)pCur->u64Info2;
259
260 pfnCompletion = pfnCallback(pHeap, VBoxSHGSMIBufferData(pCur), pvCallback, &pvCompletion);
261 if (pfnCompletion)
262 {
263 pCur->u64Info1 = (uintptr_t)pfnCompletion;
264 pCur->u64Info2 = (uintptr_t)pvCompletion;
265 pCur->fFlags &= ~VBOXSHGSMI_FLAG_GH_ASYNCH_CALLBACK_IRQ;
266 }
267 else
268 {
269 /* nothing to do with this command */
270 break;
271 }
272 }
273
274 if (!bIrq)
275 {
276 PFNVBOXSHGSMICMDCOMPLETION pfnCallback = (PFNVBOXSHGSMICMDCOMPLETION)pCur->u64Info1;
277 void *pvCallback = (void*)pCur->u64Info2;
278 pfnCallback(pHeap, VBoxSHGSMIBufferData(pCur), pvCallback);
279 }
280 else
281 vboxVtListPut(pPostProcessList, VBOXSHGSMI_CMD2LISTENTRY(pCur), VBOXSHGSMI_CMD2LISTENTRY(pCur));
282 } while (0);
283
284
285 return rc;
286}
287
288int VBoxSHGSMICommandPostprocessCompletion (PVBOXSHGSMI pHeap, PVBOXVTLIST pPostProcessList)
289{
290 PVBOXVTLIST_ENTRY pNext, pCur;
291 for (pCur = pPostProcessList->pFirst; pCur; pCur = pNext)
292 {
293 /* need to save next since the command may be released in a pfnCallback and thus its data might be invalid */
294 pNext = pCur->pNext;
295 PVBOXSHGSMIHEADER pCmd = VBOXSHGSMI_LISTENTRY2CMD(pCur);
296 PFNVBOXSHGSMICMDCOMPLETION pfnCallback = (PFNVBOXSHGSMICMDCOMPLETION)pCmd->u64Info1;
297 void *pvCallback = (void*)pCmd->u64Info2;
298 pfnCallback(pHeap, VBoxSHGSMIBufferData(pCmd), pvCallback);
299 }
300
301 return VINF_SUCCESS;
302}
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