VirtualBox

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

Last change on this file since 93635 was 93635, checked in by vboxsync, 3 years ago

VMM/PGM,VMM/PDM,VGA: Consolidate the user parameters of the physical access handlers into a single uint64_t value that shouldn't be a pointer, at least not for ring-0 callbacks. Special hack for devices where it's translated from a ring-0 device instance index into a current context PPDMDEVINS (not really tested yet). bugref:10094

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