VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR0/PDMR0Device.cpp

Last change on this file was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 36.2 KB
Line 
1/* $Id: PDMR0Device.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device and Driver Manager, R0 Device parts.
4 */
5
6/*
7 * Copyright (C) 2006-2024 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
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_PDM_DEVICE
33#define PDMPCIDEV_INCLUDE_PRIVATE /* Hack to get pdmpcidevint.h included at the right point. */
34#include "PDMInternal.h"
35#include <VBox/vmm/pdm.h>
36#include <VBox/vmm/apic.h>
37#include <VBox/vmm/mm.h>
38#include <VBox/vmm/pgm.h>
39#include <VBox/vmm/gvm.h>
40#include <VBox/vmm/vmm.h>
41#include <VBox/vmm/hm.h>
42#include <VBox/vmm/vmcc.h>
43#include <VBox/vmm/gvmm.h>
44
45#include <VBox/log.h>
46#include <VBox/err.h>
47#include <VBox/msi.h>
48#include <VBox/sup.h>
49#include <iprt/asm.h>
50#include <iprt/assert.h>
51#include <iprt/ctype.h>
52#include <iprt/mem.h>
53#include <iprt/memobj.h>
54#include <iprt/process.h>
55#include <iprt/string.h>
56
57#include "dtrace/VBoxVMM.h"
58#include "PDMInline.h"
59
60
61/*********************************************************************************************************************************
62* Global Variables *
63*********************************************************************************************************************************/
64RT_C_DECLS_BEGIN
65extern DECLEXPORT(const PDMDEVHLPR0) g_pdmR0DevHlp;
66#ifdef VBOX_WITH_DBGF_TRACING
67extern DECLEXPORT(const PDMDEVHLPR0) g_pdmR0DevHlpTracing;
68#endif
69extern DECLEXPORT(const PDMPICHLP) g_pdmR0PicHlp;
70extern DECLEXPORT(const PDMIOAPICHLP) g_pdmR0IoApicHlp;
71extern DECLEXPORT(const PDMPCIHLPR0) g_pdmR0PciHlp;
72extern DECLEXPORT(const PDMIOMMUHLPR0) g_pdmR0IommuHlp;
73extern DECLEXPORT(const PDMHPETHLPR0) g_pdmR0HpetHlp;
74extern DECLEXPORT(const PDMPCIRAWHLPR0) g_pdmR0PciRawHlp;
75RT_C_DECLS_END
76
77/** List of PDMDEVMODREGR0 structures protected by the loader lock. */
78static RTLISTANCHOR g_PDMDevModList;
79
80
81/**
82 * Pointer to the ring-0 device registrations for VMMR0.
83 */
84static const PDMDEVREGR0 *g_apVMM0DevRegs[] =
85{
86 &g_DeviceAPIC,
87};
88
89/**
90 * Module device registration record for VMMR0.
91 */
92static PDMDEVMODREGR0 g_VBoxDDR0ModDevReg =
93{
94 /* .u32Version = */ PDM_DEVMODREGR0_VERSION,
95 /* .cDevRegs = */ RT_ELEMENTS(g_apVMM0DevRegs),
96 /* .papDevRegs = */ &g_apVMM0DevRegs[0],
97 /* .hMod = */ NULL,
98 /* .ListEntry = */ { NULL, NULL },
99};
100
101
102/*********************************************************************************************************************************
103* Internal Functions *
104*********************************************************************************************************************************/
105
106
107/**
108 * Initializes the global ring-0 PDM data.
109 */
110VMMR0_INT_DECL(void) PDMR0Init(void *hMod)
111{
112 RTListInit(&g_PDMDevModList);
113 g_VBoxDDR0ModDevReg.hMod = hMod;
114 RTListAppend(&g_PDMDevModList, &g_VBoxDDR0ModDevReg.ListEntry);
115}
116
117
118/**
119 * Used by PDMR0CleanupVM to destroy a device instance.
120 *
121 * This is done during VM cleanup so that we're sure there are no active threads
122 * inside the device code.
123 *
124 * @param pGVM The global (ring-0) VM structure.
125 * @param pDevIns The device instance.
126 * @param idxR0Device The device instance handle.
127 */
128static int pdmR0DeviceDestroy(PGVM pGVM, PPDMDEVINSR0 pDevIns, uint32_t idxR0Device)
129{
130 /*
131 * Assert sanity.
132 */
133 Assert(idxR0Device < pGVM->pdmr0.s.cDevInstances);
134 AssertPtrReturn(pDevIns, VERR_INVALID_HANDLE);
135 Assert(pDevIns->u32Version == PDM_DEVINSR0_VERSION);
136 Assert(pDevIns->Internal.s.idxR0Device == idxR0Device);
137
138 /*
139 * Call the final destructor if there is one.
140 */
141 if (pDevIns->pReg->pfnFinalDestruct)
142 pDevIns->pReg->pfnFinalDestruct(pDevIns);
143 pDevIns->u32Version = ~PDM_DEVINSR0_VERSION;
144
145 /*
146 * Remove the device from the instance table.
147 */
148 Assert(pGVM->pdmr0.s.apDevInstances[idxR0Device] == pDevIns);
149 pGVM->pdmr0.s.apDevInstances[idxR0Device] = NULL;
150 if (idxR0Device + 1 == pGVM->pdmr0.s.cDevInstances)
151 pGVM->pdmr0.s.cDevInstances = idxR0Device;
152
153 /*
154 * Free the DBGF tracing tracking structures if necessary.
155 */
156 if (pDevIns->Internal.s.hDbgfTraceEvtSrc != NIL_DBGFTRACEREVTSRC)
157 {
158 RTR0MemObjFree(pDevIns->Internal.s.hDbgfTraceObj, true);
159 pDevIns->Internal.s.hDbgfTraceObj = NIL_RTR0MEMOBJ;
160 }
161
162 /*
163 * Free the ring-3 mapping and instance memory.
164 */
165 RTR0MEMOBJ hMemObj = pDevIns->Internal.s.hMapObj;
166 pDevIns->Internal.s.hMapObj = NIL_RTR0MEMOBJ;
167 RTR0MemObjFree(hMemObj, true);
168
169 hMemObj = pDevIns->Internal.s.hMemObj;
170 pDevIns->Internal.s.hMemObj = NIL_RTR0MEMOBJ;
171 RTR0MemObjFree(hMemObj, true);
172
173 return VINF_SUCCESS;
174}
175
176
177/**
178 * Initializes the per-VM data for the PDM.
179 *
180 * This is called from under the GVMM lock, so it only need to initialize the
181 * data so PDMR0CleanupVM and others will work smoothly.
182 *
183 * @param pGVM Pointer to the global VM structure.
184 */
185VMMR0_INT_DECL(void) PDMR0InitPerVMData(PGVM pGVM)
186{
187 AssertCompile(sizeof(pGVM->pdm.s) <= sizeof(pGVM->pdm.padding));
188 AssertCompile(sizeof(pGVM->pdmr0.s) <= sizeof(pGVM->pdmr0.padding));
189
190 pGVM->pdmr0.s.cDevInstances = 0;
191}
192
193
194/**
195 * Cleans up any loose ends before the GVM structure is destroyed.
196 */
197VMMR0_INT_DECL(void) PDMR0CleanupVM(PGVM pGVM)
198{
199 uint32_t i = pGVM->pdmr0.s.cDevInstances;
200 while (i-- > 0)
201 {
202 PPDMDEVINSR0 pDevIns = pGVM->pdmr0.s.apDevInstances[i];
203 if (pDevIns)
204 pdmR0DeviceDestroy(pGVM, pDevIns, i);
205 }
206
207 i = pGVM->pdmr0.s.cQueues;
208 while (i-- > 0)
209 {
210 if (pGVM->pdmr0.s.aQueues[i].pQueue != NULL)
211 pdmR0QueueDestroy(pGVM, i);
212 }
213}
214
215
216/**
217 * Worker for PDMR0DeviceCreate that does the actual instantiation.
218 *
219 * Allocates a memory object and divides it up as follows:
220 * @verbatim
221 --------------------------------------
222 ring-0 devins
223 --------------------------------------
224 ring-0 instance data
225 --------------------------------------
226 ring-0 PCI device data (optional) ??
227 --------------------------------------
228 page alignment padding
229 --------------------------------------
230 ring-3 devins
231 --------------------------------------
232 ring-3 instance data
233 --------------------------------------
234 ring-3 PCI device data (optional) ??
235 --------------------------------------
236 [page alignment padding ] -
237 [--------------------------------------] \
238 [raw-mode devins ] \
239 [--------------------------------------] - Optional, only when raw-mode is enabled.
240 [raw-mode instance data ] /
241 [--------------------------------------] /
242 [raw-mode PCI device data (optional)?? ] -
243 --------------------------------------
244 shared instance data
245 --------------------------------------
246 default crit section
247 --------------------------------------
248 shared PCI device data (optional)
249 --------------------------------------
250 @endverbatim
251 *
252 * @returns VBox status code.
253 * @param pGVM The global (ring-0) VM structure.
254 * @param pDevReg The device registration structure.
255 * @param iInstance The device instance number.
256 * @param cbInstanceR3 The size of the ring-3 instance data.
257 * @param cbInstanceRC The size of the raw-mode instance data.
258 * @param hMod The module implementing the device.
259 * @param hDbgfTraceEvtSrc The DBGF tarcer event source handle.
260 * @param RCPtrMapping The raw-mode context mapping address, NIL_RTGCPTR if
261 * not to include raw-mode.
262 * @param ppDevInsR3 Where to return the ring-3 device instance address.
263 * @thread EMT(0)
264 */
265static int pdmR0DeviceCreateWorker(PGVM pGVM, PCPDMDEVREGR0 pDevReg, uint32_t iInstance, uint32_t cbInstanceR3,
266 uint32_t cbInstanceRC, RTRGPTR RCPtrMapping, DBGFTRACEREVTSRC hDbgfTraceEvtSrc,
267 void *hMod, PPDMDEVINSR3 *ppDevInsR3)
268{
269 /*
270 * Check that the instance number isn't a duplicate.
271 */
272 for (size_t i = 0; i < pGVM->pdmr0.s.cDevInstances; i++)
273 {
274 PPDMDEVINS pCur = pGVM->pdmr0.s.apDevInstances[i];
275 AssertLogRelReturn(!pCur || pCur->pReg != pDevReg || pCur->iInstance != iInstance, VERR_DUPLICATE);
276 }
277
278 /*
279 * Figure out how much memory we need and allocate it.
280 */
281 uint32_t const cbRing0 = RT_ALIGN_32(RT_UOFFSETOF(PDMDEVINSR0, achInstanceData) + pDevReg->cbInstanceCC, HOST_PAGE_SIZE);
282 uint32_t const cbRing3 = RT_ALIGN_32(RT_UOFFSETOF(PDMDEVINSR3, achInstanceData) + cbInstanceR3,
283 RCPtrMapping != NIL_RTRGPTR ? HOST_PAGE_SIZE : 64);
284 uint32_t const cbRC = RCPtrMapping != NIL_RTRGPTR ? 0
285 : RT_ALIGN_32(RT_UOFFSETOF(PDMDEVINSRC, achInstanceData) + cbInstanceRC, 64);
286 uint32_t const cbShared = RT_ALIGN_32(pDevReg->cbInstanceShared, 64);
287 uint32_t const cbCritSect = RT_ALIGN_32(sizeof(PDMCRITSECT), 64);
288 uint32_t const cbMsixState = RT_ALIGN_32(pDevReg->cMaxMsixVectors * 16 + (pDevReg->cMaxMsixVectors + 7) / 8, _4K);
289 uint32_t const cbPciDev = RT_ALIGN_32(RT_UOFFSETOF_DYN(PDMPCIDEV, abMsixState[cbMsixState]), 64);
290 uint32_t const cPciDevs = RT_MIN(pDevReg->cMaxPciDevices, 8);
291 uint32_t const cbPciDevs = cbPciDev * cPciDevs;
292 uint32_t const cbTotal = RT_ALIGN_32(cbRing0 + cbRing3 + cbRC + cbShared + cbCritSect + cbPciDevs, HOST_PAGE_SIZE);
293 AssertLogRelMsgReturn(cbTotal <= PDM_MAX_DEVICE_INSTANCE_SIZE,
294 ("Instance of '%s' is too big: cbTotal=%u, max %u\n",
295 pDevReg->szName, cbTotal, PDM_MAX_DEVICE_INSTANCE_SIZE),
296 VERR_OUT_OF_RANGE);
297
298 RTR0MEMOBJ hMemObj;
299 int rc = RTR0MemObjAllocPage(&hMemObj, cbTotal, false /*fExecutable*/);
300 if (RT_FAILURE(rc))
301 return rc;
302 RT_BZERO(RTR0MemObjAddress(hMemObj), cbTotal);
303
304 /* Map it. */
305 RTR0MEMOBJ hMapObj;
306 rc = RTR0MemObjMapUserEx(&hMapObj, hMemObj, (RTR3PTR)-1, 0, RTMEM_PROT_READ | RTMEM_PROT_WRITE, RTR0ProcHandleSelf(),
307 cbRing0, cbTotal - cbRing0);
308 if (RT_SUCCESS(rc))
309 {
310 PPDMDEVINSR0 pDevIns = (PPDMDEVINSR0)RTR0MemObjAddress(hMemObj);
311 struct PDMDEVINSR3 *pDevInsR3 = (struct PDMDEVINSR3 *)((uint8_t *)pDevIns + cbRing0);
312
313 /*
314 * Initialize the ring-0 instance.
315 */
316 pDevIns->u32Version = PDM_DEVINSR0_VERSION;
317 pDevIns->iInstance = iInstance;
318#ifdef VBOX_WITH_DBGF_TRACING
319 pDevIns->pHlpR0 = hDbgfTraceEvtSrc == NIL_DBGFTRACEREVTSRC ? &g_pdmR0DevHlp : &g_pdmR0DevHlpTracing;
320#else
321 pDevIns->pHlpR0 = &g_pdmR0DevHlp;
322#endif
323 pDevIns->pvInstanceDataR0 = (uint8_t *)pDevIns + cbRing0 + cbRing3 + cbRC;
324 pDevIns->pvInstanceDataForR0 = &pDevIns->achInstanceData[0];
325 pDevIns->pCritSectRoR0 = (PPDMCRITSECT)((uint8_t *)pDevIns->pvInstanceDataR0 + cbShared);
326 pDevIns->pReg = pDevReg;
327 pDevIns->pDevInsForR3 = RTR0MemObjAddressR3(hMapObj);
328 pDevIns->pDevInsForR3R0 = pDevInsR3;
329 pDevIns->pvInstanceDataForR3R0 = &pDevInsR3->achInstanceData[0];
330 pDevIns->cbPciDev = cbPciDev;
331 pDevIns->cPciDevs = cPciDevs;
332 for (uint32_t iPciDev = 0; iPciDev < cPciDevs; iPciDev++)
333 {
334 /* Note! PDMDevice.cpp has a copy of this code. Keep in sync. */
335 PPDMPCIDEV pPciDev = (PPDMPCIDEV)((uint8_t *)pDevIns->pCritSectRoR0 + cbCritSect + cbPciDev * iPciDev);
336 if (iPciDev < RT_ELEMENTS(pDevIns->apPciDevs))
337 pDevIns->apPciDevs[iPciDev] = pPciDev;
338 pPciDev->cbConfig = _4K;
339 pPciDev->cbMsixState = cbMsixState;
340 pPciDev->idxSubDev = (uint16_t)iPciDev;
341 pPciDev->Int.s.idxSubDev = (uint16_t)iPciDev;
342 pPciDev->u32Magic = PDMPCIDEV_MAGIC;
343 }
344 pDevIns->Internal.s.pGVM = pGVM;
345 pDevIns->Internal.s.pRegR0 = pDevReg;
346 pDevIns->Internal.s.hMod = hMod;
347 pDevIns->Internal.s.hMemObj = hMemObj;
348 pDevIns->Internal.s.hMapObj = hMapObj;
349 pDevIns->Internal.s.pInsR3R0 = pDevInsR3;
350 pDevIns->Internal.s.pIntR3R0 = &pDevInsR3->Internal.s;
351 pDevIns->Internal.s.hDbgfTraceEvtSrc = hDbgfTraceEvtSrc;
352
353 /*
354 * Initialize the ring-3 instance data as much as we can.
355 * Note! PDMDevice.cpp does this job for ring-3 only devices. Keep in sync.
356 */
357 pDevInsR3->u32Version = PDM_DEVINSR3_VERSION;
358 pDevInsR3->iInstance = iInstance;
359 pDevInsR3->cbRing3 = cbTotal - cbRing0;
360 pDevInsR3->fR0Enabled = true;
361 pDevInsR3->fRCEnabled = RCPtrMapping != NIL_RTRGPTR;
362 pDevInsR3->pvInstanceDataR3 = pDevIns->pDevInsForR3 + cbRing3 + cbRC;
363 pDevInsR3->pvInstanceDataForR3 = pDevIns->pDevInsForR3 + RT_UOFFSETOF(PDMDEVINSR3, achInstanceData);
364 pDevInsR3->pCritSectRoR3 = pDevIns->pDevInsForR3 + cbRing3 + cbRC + cbShared;
365 pDevInsR3->pDevInsR0RemoveMe = pDevIns;
366 pDevInsR3->pvInstanceDataR0 = pDevIns->pvInstanceDataR0;
367 pDevInsR3->pvInstanceDataRC = RCPtrMapping == NIL_RTRGPTR
368 ? NIL_RTRGPTR : pDevIns->pDevInsForRC + RT_UOFFSETOF(PDMDEVINSRC, achInstanceData);
369 pDevInsR3->pDevInsForRC = pDevIns->pDevInsForRC;
370 pDevInsR3->pDevInsForRCR3 = pDevIns->pDevInsForR3 + cbRing3;
371 pDevInsR3->pDevInsForRCR3 = pDevInsR3->pDevInsForRCR3 + RT_UOFFSETOF(PDMDEVINSRC, achInstanceData);
372 pDevInsR3->cbPciDev = cbPciDev;
373 pDevInsR3->cPciDevs = cPciDevs;
374 for (uint32_t i = 0; i < RT_MIN(cPciDevs, RT_ELEMENTS(pDevIns->apPciDevs)); i++)
375 pDevInsR3->apPciDevs[i] = pDevInsR3->pCritSectRoR3 + cbCritSect + cbPciDev * i;
376
377 pDevInsR3->Internal.s.pVMR3 = pGVM->pVMR3;
378 pDevInsR3->Internal.s.fIntFlags = RCPtrMapping == NIL_RTRGPTR ? PDMDEVINSINT_FLAGS_R0_ENABLED
379 : PDMDEVINSINT_FLAGS_R0_ENABLED | PDMDEVINSINT_FLAGS_RC_ENABLED;
380 pDevInsR3->Internal.s.hDbgfTraceEvtSrc = hDbgfTraceEvtSrc;
381
382 /*
383 * Initialize the raw-mode instance data as much as possible.
384 */
385 if (RCPtrMapping != NIL_RTRGPTR)
386 {
387 struct PDMDEVINSRC *pDevInsRC = RCPtrMapping == NIL_RTRGPTR ? NULL
388 : (struct PDMDEVINSRC *)((uint8_t *)pDevIns + cbRing0 + cbRing3);
389
390 pDevIns->pDevInsForRC = RCPtrMapping;
391 pDevIns->pDevInsForRCR0 = pDevInsRC;
392 pDevIns->pvInstanceDataForRCR0 = &pDevInsRC->achInstanceData[0];
393
394 pDevInsRC->u32Version = PDM_DEVINSRC_VERSION;
395 pDevInsRC->iInstance = iInstance;
396 pDevInsRC->pvInstanceDataRC = pDevIns->pDevInsForRC + cbRC;
397 pDevInsRC->pvInstanceDataForRC = pDevIns->pDevInsForRC + RT_UOFFSETOF(PDMDEVINSRC, achInstanceData);
398 pDevInsRC->pCritSectRoRC = pDevIns->pDevInsForRC + cbRC + cbShared;
399 pDevInsRC->cbPciDev = cbPciDev;
400 pDevInsRC->cPciDevs = cPciDevs;
401 for (uint32_t i = 0; i < RT_MIN(cPciDevs, RT_ELEMENTS(pDevIns->apPciDevs)); i++)
402 pDevInsRC->apPciDevs[i] = pDevInsRC->pCritSectRoRC + cbCritSect + cbPciDev * i;
403
404 pDevInsRC->Internal.s.pVMRC = pGVM->pVMRC;
405 }
406
407 /*
408 * If the device is being traced we have to set up a single page for tracking
409 * I/O and MMIO region registrations so we can inject our own handlers.
410 */
411 if (hDbgfTraceEvtSrc != NIL_DBGFTRACEREVTSRC)
412 {
413 pDevIns->Internal.s.hDbgfTraceObj = NIL_RTR0MEMOBJ;
414 rc = RTR0MemObjAllocPage(&pDevIns->Internal.s.hDbgfTraceObj, PDM_MAX_DEVICE_DBGF_TRACING_TRACK, false /*fExecutable*/);
415 if (RT_SUCCESS(rc))
416 {
417 pDevIns->Internal.s.paDbgfTraceTrack = (PPDMDEVINSDBGFTRACK)RTR0MemObjAddress(pDevIns->Internal.s.hDbgfTraceObj);
418 pDevIns->Internal.s.idxDbgfTraceTrackNext = 0;
419 pDevIns->Internal.s.cDbgfTraceTrackMax = PDM_MAX_DEVICE_DBGF_TRACING_TRACK / sizeof(PDMDEVINSDBGFTRACK);
420 RT_BZERO(pDevIns->Internal.s.paDbgfTraceTrack, PDM_MAX_DEVICE_DBGF_TRACING_TRACK);
421 }
422 }
423
424 if (RT_SUCCESS(rc))
425 {
426 /*
427 * Add to the device instance array and set its handle value.
428 */
429 AssertCompile(sizeof(pGVM->pdmr0.padding) == sizeof(pGVM->pdmr0));
430 uint32_t idxR0Device = pGVM->pdmr0.s.cDevInstances;
431 if (idxR0Device < RT_ELEMENTS(pGVM->pdmr0.s.apDevInstances))
432 {
433 pGVM->pdmr0.s.apDevInstances[idxR0Device] = pDevIns;
434 pGVM->pdmr0.s.cDevInstances = idxR0Device + 1;
435 pGVM->pdm.s.apDevRing0Instances[idxR0Device] = pDevIns->pDevInsForR3;
436 pDevIns->Internal.s.idxR0Device = idxR0Device;
437 pDevInsR3->Internal.s.idxR0Device = idxR0Device;
438
439 /*
440 * Call the early constructor if present.
441 */
442 if (pDevReg->pfnEarlyConstruct)
443 rc = pDevReg->pfnEarlyConstruct(pDevIns);
444 if (RT_SUCCESS(rc))
445 {
446 /*
447 * We're done.
448 */
449 *ppDevInsR3 = RTR0MemObjAddressR3(hMapObj);
450 return rc;
451 }
452
453 /*
454 * Bail out.
455 */
456 if (pDevIns->pReg->pfnFinalDestruct)
457 pDevIns->pReg->pfnFinalDestruct(pDevIns);
458
459 pGVM->pdmr0.s.apDevInstances[idxR0Device] = NULL;
460 Assert(pGVM->pdmr0.s.cDevInstances == idxR0Device + 1);
461 pGVM->pdmr0.s.cDevInstances = idxR0Device;
462 }
463 }
464
465 if ( hDbgfTraceEvtSrc != NIL_DBGFTRACEREVTSRC
466 && pDevIns->Internal.s.hDbgfTraceObj != NIL_RTR0MEMOBJ)
467 RTR0MemObjFree(pDevIns->Internal.s.hDbgfTraceObj, true);
468
469 RTR0MemObjFree(hMapObj, true);
470 }
471 RTR0MemObjFree(hMemObj, true);
472 return rc;
473}
474
475
476/**
477 * Used by ring-3 PDM to create a device instance that operates both in ring-3
478 * and ring-0.
479 *
480 * Creates an instance of a device (for both ring-3 and ring-0, and optionally
481 * raw-mode context).
482 *
483 * @returns VBox status code.
484 * @param pGVM The global (ring-0) VM structure.
485 * @param pReq Pointer to the request buffer.
486 * @thread EMT(0)
487 */
488VMMR0_INT_DECL(int) PDMR0DeviceCreateReqHandler(PGVM pGVM, PPDMDEVICECREATEREQ pReq)
489{
490 LogFlow(("PDMR0DeviceCreateReqHandler: %s in %s\n", pReq->szDevName, pReq->szModName));
491
492 /*
493 * Validate the request.
494 */
495 AssertReturn(pReq->Hdr.cbReq == sizeof(*pReq), VERR_INVALID_PARAMETER);
496 pReq->pDevInsR3 = NIL_RTR3PTR;
497
498 int rc = GVMMR0ValidateGVMandEMT(pGVM, 0);
499 AssertRCReturn(rc, rc);
500
501 AssertReturn(pReq->fFlags != 0, VERR_INVALID_FLAGS);
502 AssertReturn(pReq->fClass != 0, VERR_WRONG_TYPE);
503 AssertReturn(pReq->uSharedVersion != 0, VERR_INVALID_PARAMETER);
504 AssertReturn(pReq->cbInstanceShared != 0, VERR_INVALID_PARAMETER);
505 size_t const cchDevName = RTStrNLen(pReq->szDevName, sizeof(pReq->szDevName));
506 AssertReturn(cchDevName < sizeof(pReq->szDevName), VERR_NO_STRING_TERMINATOR);
507 AssertReturn(cchDevName > 0, VERR_EMPTY_STRING);
508 AssertReturn(cchDevName < RT_SIZEOFMEMB(PDMDEVREG, szName), VERR_NOT_FOUND);
509
510 size_t const cchModName = RTStrNLen(pReq->szModName, sizeof(pReq->szModName));
511 AssertReturn(cchModName < sizeof(pReq->szModName), VERR_NO_STRING_TERMINATOR);
512 AssertReturn(cchModName > 0, VERR_EMPTY_STRING);
513 AssertReturn(pReq->cbInstanceShared <= PDM_MAX_DEVICE_INSTANCE_SIZE, VERR_OUT_OF_RANGE);
514 AssertReturn(pReq->cbInstanceR3 <= PDM_MAX_DEVICE_INSTANCE_SIZE, VERR_OUT_OF_RANGE);
515 AssertReturn(pReq->cbInstanceRC <= PDM_MAX_DEVICE_INSTANCE_SIZE, VERR_OUT_OF_RANGE);
516 AssertReturn(pReq->iInstance < 1024, VERR_OUT_OF_RANGE);
517 AssertReturn(pReq->iInstance < pReq->cMaxInstances, VERR_OUT_OF_RANGE);
518 AssertReturn(pReq->cMaxPciDevices <= 8, VERR_OUT_OF_RANGE);
519 AssertReturn(pReq->cMaxMsixVectors <= VBOX_MSIX_MAX_ENTRIES, VERR_OUT_OF_RANGE);
520
521 /*
522 * Reference the module.
523 */
524 void *hMod = NULL;
525 rc = SUPR0LdrModByName(pGVM->pSession, pReq->szModName, &hMod);
526 if (RT_FAILURE(rc))
527 {
528 LogRel(("PDMR0DeviceCreateReqHandler: SUPR0LdrModByName(,%s,) failed: %Rrc\n", pReq->szModName, rc));
529 return rc;
530 }
531
532 /*
533 * Look for the the module and the device registration structure.
534 */
535 int rcLock = SUPR0LdrLock(pGVM->pSession);
536 AssertRC(rc);
537
538 rc = VERR_NOT_FOUND;
539 PPDMDEVMODREGR0 pMod;
540 RTListForEach(&g_PDMDevModList, pMod, PDMDEVMODREGR0, ListEntry)
541 {
542 if (pMod->hMod == hMod)
543 {
544 /*
545 * Found the module. We can drop the loader lock now before we
546 * search the devices it registers.
547 */
548 if (RT_SUCCESS(rcLock))
549 {
550 rcLock = SUPR0LdrUnlock(pGVM->pSession);
551 AssertRC(rcLock);
552 }
553 rcLock = VERR_ALREADY_RESET;
554
555 PCPDMDEVREGR0 *papDevRegs = pMod->papDevRegs;
556 size_t i = pMod->cDevRegs;
557 while (i-- > 0)
558 {
559 PCPDMDEVREGR0 pDevReg = papDevRegs[i];
560 LogFlow(("PDMR0DeviceCreateReqHandler: candidate #%u: %s %#x\n", i, pReq->szDevName, pDevReg->u32Version));
561 if ( PDM_VERSION_ARE_COMPATIBLE(pDevReg->u32Version, PDM_DEVREGR0_VERSION)
562 && pDevReg->szName[cchDevName] == '\0'
563 && memcmp(pDevReg->szName, pReq->szDevName, cchDevName) == 0)
564 {
565
566 /*
567 * Found the device, now check whether it matches the ring-3 registration.
568 */
569 if ( pReq->uSharedVersion == pDevReg->uSharedVersion
570 && pReq->cbInstanceShared == pDevReg->cbInstanceShared
571 && pReq->cbInstanceRC == pDevReg->cbInstanceRC
572 && pReq->fFlags == pDevReg->fFlags
573 && pReq->fClass == pDevReg->fClass
574 && pReq->cMaxInstances == pDevReg->cMaxInstances
575 && pReq->cMaxPciDevices == pDevReg->cMaxPciDevices
576 && pReq->cMaxMsixVectors == pDevReg->cMaxMsixVectors)
577 {
578 rc = pdmR0DeviceCreateWorker(pGVM, pDevReg, pReq->iInstance, pReq->cbInstanceR3, pReq->cbInstanceRC,
579 NIL_RTRCPTR /** @todo new raw-mode */, pReq->hDbgfTracerEvtSrc,
580 hMod, &pReq->pDevInsR3);
581 if (RT_SUCCESS(rc))
582 hMod = NULL; /* keep the module reference */
583 }
584 else
585 {
586 LogRel(("PDMR0DeviceCreate: Ring-3 does not match ring-0 device registration (%s):\n"
587 " uSharedVersion: %#x vs %#x\n"
588 " cbInstanceShared: %#x vs %#x\n"
589 " cbInstanceRC: %#x vs %#x\n"
590 " fFlags: %#x vs %#x\n"
591 " fClass: %#x vs %#x\n"
592 " cMaxInstances: %#x vs %#x\n"
593 " cMaxPciDevices: %#x vs %#x\n"
594 " cMaxMsixVectors: %#x vs %#x\n"
595 ,
596 pReq->szDevName,
597 pReq->uSharedVersion, pDevReg->uSharedVersion,
598 pReq->cbInstanceShared, pDevReg->cbInstanceShared,
599 pReq->cbInstanceRC, pDevReg->cbInstanceRC,
600 pReq->fFlags, pDevReg->fFlags,
601 pReq->fClass, pDevReg->fClass,
602 pReq->cMaxInstances, pDevReg->cMaxInstances,
603 pReq->cMaxPciDevices, pDevReg->cMaxPciDevices,
604 pReq->cMaxMsixVectors, pDevReg->cMaxMsixVectors));
605 rc = VERR_INCOMPATIBLE_CONFIG;
606 }
607 }
608 }
609 break;
610 }
611 }
612
613 if (RT_SUCCESS_NP(rcLock))
614 {
615 rcLock = SUPR0LdrUnlock(pGVM->pSession);
616 AssertRC(rcLock);
617 }
618 SUPR0LdrModRelease(pGVM->pSession, hMod);
619 return rc;
620}
621
622
623/**
624 * Used by ring-3 PDM to call standard ring-0 device methods.
625 *
626 * @returns VBox status code.
627 * @param pGVM The global (ring-0) VM structure.
628 * @param pReq Pointer to the request buffer.
629 * @param idCpu The ID of the calling EMT.
630 * @thread EMT(0), except for PDMDEVICEGENCALL_REQUEST which can be any EMT.
631 */
632VMMR0_INT_DECL(int) PDMR0DeviceGenCallReqHandler(PGVM pGVM, PPDMDEVICEGENCALLREQ pReq, VMCPUID idCpu)
633{
634 /*
635 * Validate the request.
636 */
637 AssertReturn(pReq->Hdr.cbReq == sizeof(*pReq), VERR_INVALID_PARAMETER);
638
639 int rc = GVMMR0ValidateGVMandEMT(pGVM, idCpu);
640 AssertRCReturn(rc, rc);
641
642 AssertReturn(pReq->idxR0Device < pGVM->pdmr0.s.cDevInstances, VERR_INVALID_HANDLE);
643 PPDMDEVINSR0 pDevIns = pGVM->pdmr0.s.apDevInstances[pReq->idxR0Device];
644 AssertPtrReturn(pDevIns, VERR_INVALID_HANDLE);
645 AssertReturn(pDevIns->pDevInsForR3 == pReq->pDevInsR3, VERR_INVALID_HANDLE);
646
647 /*
648 * Make the call.
649 */
650 rc = VINF_SUCCESS /*VINF_NOT_IMPLEMENTED*/;
651 switch (pReq->enmCall)
652 {
653 case PDMDEVICEGENCALL_CONSTRUCT:
654 AssertMsgBreakStmt(pGVM->enmVMState < VMSTATE_CREATED, ("enmVMState=%d\n", pGVM->enmVMState), rc = VERR_INVALID_STATE);
655 AssertReturn(idCpu == 0, VERR_VM_THREAD_NOT_EMT);
656 if (pDevIns->pReg->pfnConstruct)
657 rc = pDevIns->pReg->pfnConstruct(pDevIns);
658 break;
659
660 case PDMDEVICEGENCALL_DESTRUCT:
661 AssertMsgBreakStmt(pGVM->enmVMState < VMSTATE_CREATED || pGVM->enmVMState >= VMSTATE_DESTROYING,
662 ("enmVMState=%d\n", pGVM->enmVMState), rc = VERR_INVALID_STATE);
663 AssertReturn(idCpu == 0, VERR_VM_THREAD_NOT_EMT);
664 if (pDevIns->pReg->pfnDestruct)
665 {
666 pDevIns->pReg->pfnDestruct(pDevIns);
667 rc = VINF_SUCCESS;
668 }
669 break;
670
671 case PDMDEVICEGENCALL_REQUEST:
672 if (pDevIns->pReg->pfnRequest)
673 rc = pDevIns->pReg->pfnRequest(pDevIns, pReq->Params.Req.uReq, pReq->Params.Req.uArg);
674 else
675 rc = VERR_INVALID_FUNCTION;
676 break;
677
678 default:
679 AssertMsgFailed(("enmCall=%d\n", pReq->enmCall));
680 rc = VERR_INVALID_FUNCTION;
681 break;
682 }
683
684 return rc;
685}
686
687
688/**
689 * Legacy device mode compatiblity.
690 *
691 * @returns VBox status code.
692 * @param pGVM The global (ring-0) VM structure.
693 * @param pReq Pointer to the request buffer.
694 * @thread EMT(0)
695 */
696VMMR0_INT_DECL(int) PDMR0DeviceCompatSetCritSectReqHandler(PGVM pGVM, PPDMDEVICECOMPATSETCRITSECTREQ pReq)
697{
698 /*
699 * Validate the request.
700 */
701 AssertReturn(pReq->Hdr.cbReq == sizeof(*pReq), VERR_INVALID_PARAMETER);
702
703 int rc = GVMMR0ValidateGVMandEMT(pGVM, 0);
704 AssertRCReturn(rc, rc);
705
706 AssertReturn(pReq->idxR0Device < pGVM->pdmr0.s.cDevInstances, VERR_INVALID_HANDLE);
707 PPDMDEVINSR0 pDevIns = pGVM->pdmr0.s.apDevInstances[pReq->idxR0Device];
708 AssertPtrReturn(pDevIns, VERR_INVALID_HANDLE);
709 AssertReturn(pDevIns->pDevInsForR3 == pReq->pDevInsR3, VERR_INVALID_HANDLE);
710
711 AssertReturn(pGVM->enmVMState == VMSTATE_CREATING, VERR_INVALID_STATE);
712
713 /*
714 * The critical section address can be in a few different places:
715 * 1. shared data.
716 * 2. nop section.
717 * 3. pdm critsect.
718 */
719 PPDMCRITSECT pCritSect;
720 if (pReq->pCritSectR3 == pGVM->pVMR3 + RT_UOFFSETOF(VM, pdm.s.NopCritSect))
721 {
722 pCritSect = &pGVM->pdm.s.NopCritSect;
723 Log(("PDMR0DeviceCompatSetCritSectReqHandler: Nop - %p %#x\n", pCritSect, pCritSect->s.Core.u32Magic));
724 }
725 else if (pReq->pCritSectR3 == pGVM->pVMR3 + RT_UOFFSETOF(VM, pdm.s.CritSect))
726 {
727 pCritSect = &pGVM->pdm.s.CritSect;
728 Log(("PDMR0DeviceCompatSetCritSectReqHandler: PDM - %p %#x\n", pCritSect, pCritSect->s.Core.u32Magic));
729 }
730 else
731 {
732 size_t offCritSect = pReq->pCritSectR3 - pDevIns->pDevInsForR3R0->pvInstanceDataR3;
733 AssertLogRelMsgReturn( offCritSect < pDevIns->pReg->cbInstanceShared
734 && offCritSect + sizeof(PDMCRITSECT) <= pDevIns->pReg->cbInstanceShared,
735 ("offCritSect=%p pCritSectR3=%p cbInstanceShared=%#x (%s)\n",
736 offCritSect, pReq->pCritSectR3, pDevIns->pReg->cbInstanceShared, pDevIns->pReg->szName),
737 VERR_INVALID_POINTER);
738 pCritSect = (PPDMCRITSECT)((uint8_t *)pDevIns->pvInstanceDataR0 + offCritSect);
739 Log(("PDMR0DeviceCompatSetCritSectReqHandler: custom - %#x/%p %#x\n", offCritSect, pCritSect, pCritSect->s.Core.u32Magic));
740 }
741 AssertLogRelMsgReturn(pCritSect->s.Core.u32Magic == RTCRITSECT_MAGIC,
742 ("cs=%p magic=%#x dev=%s\n", pCritSect, pCritSect->s.Core.u32Magic, pDevIns->pReg->szName),
743 VERR_INVALID_MAGIC);
744
745 /*
746 * Make the update.
747 */
748 pDevIns->pCritSectRoR0 = pCritSect;
749
750 return VINF_SUCCESS;
751}
752
753
754/**
755 * Registers the device implementations living in a module.
756 *
757 * This should normally only be called during ModuleInit(). The should be a
758 * call to PDMR0DeviceDeregisterModule from the ModuleTerm() function to undo
759 * the effects of this call.
760 *
761 * @returns VBox status code.
762 * @param hMod The module handle of the module being registered.
763 * @param pModReg The module registration structure. This will be
764 * used directly so it must live as long as the module
765 * and be writable.
766 *
767 * @note Caller must own the loader lock!
768 */
769VMMR0DECL(int) PDMR0DeviceRegisterModule(void *hMod, PPDMDEVMODREGR0 pModReg)
770{
771 /*
772 * Validate the input.
773 */
774 AssertPtrReturn(hMod, VERR_INVALID_HANDLE);
775 Assert(SUPR0LdrIsLockOwnerByMod(hMod, true));
776
777 AssertPtrReturn(pModReg, VERR_INVALID_POINTER);
778 AssertLogRelMsgReturn(PDM_VERSION_ARE_COMPATIBLE(pModReg->u32Version, PDM_DEVMODREGR0_VERSION),
779 ("pModReg->u32Version=%#x vs %#x\n", pModReg->u32Version, PDM_DEVMODREGR0_VERSION),
780 VERR_VERSION_MISMATCH);
781 AssertLogRelMsgReturn(pModReg->cDevRegs <= 256 && pModReg->cDevRegs > 0, ("cDevRegs=%u\n", pModReg->cDevRegs),
782 VERR_OUT_OF_RANGE);
783 AssertLogRelMsgReturn(pModReg->hMod == NULL, ("hMod=%p\n", pModReg->hMod), VERR_INVALID_PARAMETER);
784 AssertLogRelMsgReturn(pModReg->ListEntry.pNext == NULL, ("pNext=%p\n", pModReg->ListEntry.pNext), VERR_INVALID_PARAMETER);
785 AssertLogRelMsgReturn(pModReg->ListEntry.pPrev == NULL, ("pPrev=%p\n", pModReg->ListEntry.pPrev), VERR_INVALID_PARAMETER);
786
787 for (size_t i = 0; i < pModReg->cDevRegs; i++)
788 {
789 PCPDMDEVREGR0 pDevReg = pModReg->papDevRegs[i];
790 AssertLogRelMsgReturn(RT_VALID_PTR(pDevReg), ("[%u]: %p\n", i, pDevReg), VERR_INVALID_POINTER);
791 AssertLogRelMsgReturn(PDM_VERSION_ARE_COMPATIBLE(pDevReg->u32Version, PDM_DEVREGR0_VERSION),
792 ("pDevReg->u32Version=%#x vs %#x\n", pModReg->u32Version, PDM_DEVREGR0_VERSION), VERR_VERSION_MISMATCH);
793 AssertLogRelMsgReturn(RT_VALID_PTR(pDevReg->pszDescription), ("[%u]: %p\n", i, pDevReg->pszDescription), VERR_INVALID_POINTER);
794 AssertLogRelMsgReturn(pDevReg->uReserved0 == 0, ("[%u]: %#x\n", i, pDevReg->uReserved0), VERR_INVALID_PARAMETER);
795 AssertLogRelMsgReturn(pDevReg->fClass != 0, ("[%u]: %#x\n", i, pDevReg->fClass), VERR_INVALID_PARAMETER);
796 AssertLogRelMsgReturn(pDevReg->fFlags != 0, ("[%u]: %#x\n", i, pDevReg->fFlags), VERR_INVALID_PARAMETER);
797 AssertLogRelMsgReturn(pDevReg->cMaxInstances > 0, ("[%u]: %#x\n", i, pDevReg->cMaxInstances), VERR_INVALID_PARAMETER);
798 AssertLogRelMsgReturn(pDevReg->cMaxPciDevices <= 8, ("[%u]: %#x\n", i, pDevReg->cMaxPciDevices), VERR_INVALID_PARAMETER);
799 AssertLogRelMsgReturn(pDevReg->cMaxMsixVectors <= VBOX_MSIX_MAX_ENTRIES,
800 ("[%u]: %#x\n", i, pDevReg->cMaxMsixVectors), VERR_INVALID_PARAMETER);
801
802 /* The name must be printable ascii and correctly terminated. */
803 for (size_t off = 0; off < RT_ELEMENTS(pDevReg->szName); off++)
804 {
805 char ch = pDevReg->szName[off];
806 AssertLogRelMsgReturn(RT_C_IS_PRINT(ch) || (ch == '\0' && off > 0),
807 ("[%u]: off=%u szName: %.*Rhxs\n", i, off, sizeof(pDevReg->szName), &pDevReg->szName[0]),
808 VERR_INVALID_NAME);
809 if (ch == '\0')
810 break;
811 }
812 }
813
814 /*
815 * Add it, assuming we're being called at ModuleInit/ModuleTerm time only, or
816 * that the caller has already taken the loader lock.
817 */
818 pModReg->hMod = hMod;
819 RTListAppend(&g_PDMDevModList, &pModReg->ListEntry);
820
821 return VINF_SUCCESS;
822}
823
824
825/**
826 * Deregisters the device implementations living in a module.
827 *
828 * This should normally only be called during ModuleTerm().
829 *
830 * @returns VBox status code.
831 * @param hMod The module handle of the module being registered.
832 * @param pModReg The module registration structure. This will be
833 * used directly so it must live as long as the module
834 * and be writable.
835 *
836 * @note Caller must own the loader lock!
837 */
838VMMR0DECL(int) PDMR0DeviceDeregisterModule(void *hMod, PPDMDEVMODREGR0 pModReg)
839{
840 /*
841 * Validate the input.
842 */
843 AssertPtrReturn(hMod, VERR_INVALID_HANDLE);
844 Assert(SUPR0LdrIsLockOwnerByMod(hMod, true));
845
846 AssertPtrReturn(pModReg, VERR_INVALID_POINTER);
847 AssertLogRelMsgReturn(PDM_VERSION_ARE_COMPATIBLE(pModReg->u32Version, PDM_DEVMODREGR0_VERSION),
848 ("pModReg->u32Version=%#x vs %#x\n", pModReg->u32Version, PDM_DEVMODREGR0_VERSION),
849 VERR_VERSION_MISMATCH);
850 AssertLogRelMsgReturn(pModReg->hMod == hMod || pModReg->hMod == NULL, ("pModReg->hMod=%p vs %p\n", pModReg->hMod, hMod),
851 VERR_INVALID_PARAMETER);
852
853 /*
854 * Unlink the registration record and return it to virgin conditions. Ignore
855 * the call if not registered.
856 */
857 if (pModReg->hMod)
858 {
859 pModReg->hMod = NULL;
860 RTListNodeRemove(&pModReg->ListEntry);
861 pModReg->ListEntry.pNext = NULL;
862 pModReg->ListEntry.pPrev = NULL;
863 return VINF_SUCCESS;
864 }
865 return VWRN_NOT_FOUND;
866}
867
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