VirtualBox

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

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

VMM/PDMQueue: Rewrote the queue code to not use the hyper heap and be a bit safer. Added a testcase (driverless). bugref:10093

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 35.9 KB
Line 
1/* $Id: PDMR0Device.cpp 93609 2022-02-05 19:03:08Z 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 pDevIns->Internal.s.idxR0Device = idxR0Device;
426 pDevInsR3->Internal.s.idxR0Device = idxR0Device;
427
428 /*
429 * Call the early constructor if present.
430 */
431 if (pDevReg->pfnEarlyConstruct)
432 rc = pDevReg->pfnEarlyConstruct(pDevIns);
433 if (RT_SUCCESS(rc))
434 {
435 /*
436 * We're done.
437 */
438 *ppDevInsR3 = RTR0MemObjAddressR3(hMapObj);
439 return rc;
440 }
441
442 /*
443 * Bail out.
444 */
445 if (pDevIns->pReg->pfnFinalDestruct)
446 pDevIns->pReg->pfnFinalDestruct(pDevIns);
447
448 pGVM->pdmr0.s.apDevInstances[idxR0Device] = NULL;
449 Assert(pGVM->pdmr0.s.cDevInstances == idxR0Device + 1);
450 pGVM->pdmr0.s.cDevInstances = idxR0Device;
451 }
452 }
453
454 if ( hDbgfTraceEvtSrc != NIL_DBGFTRACEREVTSRC
455 && pDevIns->Internal.s.hDbgfTraceObj != NIL_RTR0MEMOBJ)
456 RTR0MemObjFree(pDevIns->Internal.s.hDbgfTraceObj, true);
457
458 RTR0MemObjFree(hMapObj, true);
459 }
460 RTR0MemObjFree(hMemObj, true);
461 return rc;
462}
463
464
465/**
466 * Used by ring-3 PDM to create a device instance that operates both in ring-3
467 * and ring-0.
468 *
469 * Creates an instance of a device (for both ring-3 and ring-0, and optionally
470 * raw-mode context).
471 *
472 * @returns VBox status code.
473 * @param pGVM The global (ring-0) VM structure.
474 * @param pReq Pointer to the request buffer.
475 * @thread EMT(0)
476 */
477VMMR0_INT_DECL(int) PDMR0DeviceCreateReqHandler(PGVM pGVM, PPDMDEVICECREATEREQ pReq)
478{
479 LogFlow(("PDMR0DeviceCreateReqHandler: %s in %s\n", pReq->szDevName, pReq->szModName));
480
481 /*
482 * Validate the request.
483 */
484 AssertReturn(pReq->Hdr.cbReq == sizeof(*pReq), VERR_INVALID_PARAMETER);
485 pReq->pDevInsR3 = NIL_RTR3PTR;
486
487 int rc = GVMMR0ValidateGVMandEMT(pGVM, 0);
488 AssertRCReturn(rc, rc);
489
490 AssertReturn(pReq->fFlags != 0, VERR_INVALID_FLAGS);
491 AssertReturn(pReq->fClass != 0, VERR_WRONG_TYPE);
492 AssertReturn(pReq->uSharedVersion != 0, VERR_INVALID_PARAMETER);
493 AssertReturn(pReq->cbInstanceShared != 0, VERR_INVALID_PARAMETER);
494 size_t const cchDevName = RTStrNLen(pReq->szDevName, sizeof(pReq->szDevName));
495 AssertReturn(cchDevName < sizeof(pReq->szDevName), VERR_NO_STRING_TERMINATOR);
496 AssertReturn(cchDevName > 0, VERR_EMPTY_STRING);
497 AssertReturn(cchDevName < RT_SIZEOFMEMB(PDMDEVREG, szName), VERR_NOT_FOUND);
498
499 size_t const cchModName = RTStrNLen(pReq->szModName, sizeof(pReq->szModName));
500 AssertReturn(cchModName < sizeof(pReq->szModName), VERR_NO_STRING_TERMINATOR);
501 AssertReturn(cchModName > 0, VERR_EMPTY_STRING);
502 AssertReturn(pReq->cbInstanceShared <= PDM_MAX_DEVICE_INSTANCE_SIZE, VERR_OUT_OF_RANGE);
503 AssertReturn(pReq->cbInstanceR3 <= PDM_MAX_DEVICE_INSTANCE_SIZE, VERR_OUT_OF_RANGE);
504 AssertReturn(pReq->cbInstanceRC <= PDM_MAX_DEVICE_INSTANCE_SIZE, VERR_OUT_OF_RANGE);
505 AssertReturn(pReq->iInstance < 1024, VERR_OUT_OF_RANGE);
506 AssertReturn(pReq->iInstance < pReq->cMaxInstances, VERR_OUT_OF_RANGE);
507 AssertReturn(pReq->cMaxPciDevices <= 8, VERR_OUT_OF_RANGE);
508 AssertReturn(pReq->cMaxMsixVectors <= VBOX_MSIX_MAX_ENTRIES, VERR_OUT_OF_RANGE);
509
510 /*
511 * Reference the module.
512 */
513 void *hMod = NULL;
514 rc = SUPR0LdrModByName(pGVM->pSession, pReq->szModName, &hMod);
515 if (RT_FAILURE(rc))
516 {
517 LogRel(("PDMR0DeviceCreateReqHandler: SUPR0LdrModByName(,%s,) failed: %Rrc\n", pReq->szModName, rc));
518 return rc;
519 }
520
521 /*
522 * Look for the the module and the device registration structure.
523 */
524 int rcLock = SUPR0LdrLock(pGVM->pSession);
525 AssertRC(rc);
526
527 rc = VERR_NOT_FOUND;
528 PPDMDEVMODREGR0 pMod;
529 RTListForEach(&g_PDMDevModList, pMod, PDMDEVMODREGR0, ListEntry)
530 {
531 if (pMod->hMod == hMod)
532 {
533 /*
534 * Found the module. We can drop the loader lock now before we
535 * search the devices it registers.
536 */
537 if (RT_SUCCESS(rcLock))
538 {
539 rcLock = SUPR0LdrUnlock(pGVM->pSession);
540 AssertRC(rcLock);
541 }
542 rcLock = VERR_ALREADY_RESET;
543
544 PCPDMDEVREGR0 *papDevRegs = pMod->papDevRegs;
545 size_t i = pMod->cDevRegs;
546 while (i-- > 0)
547 {
548 PCPDMDEVREGR0 pDevReg = papDevRegs[i];
549 LogFlow(("PDMR0DeviceCreateReqHandler: candidate #%u: %s %#x\n", i, pReq->szDevName, pDevReg->u32Version));
550 if ( PDM_VERSION_ARE_COMPATIBLE(pDevReg->u32Version, PDM_DEVREGR0_VERSION)
551 && pDevReg->szName[cchDevName] == '\0'
552 && memcmp(pDevReg->szName, pReq->szDevName, cchDevName) == 0)
553 {
554
555 /*
556 * Found the device, now check whether it matches the ring-3 registration.
557 */
558 if ( pReq->uSharedVersion == pDevReg->uSharedVersion
559 && pReq->cbInstanceShared == pDevReg->cbInstanceShared
560 && pReq->cbInstanceRC == pDevReg->cbInstanceRC
561 && pReq->fFlags == pDevReg->fFlags
562 && pReq->fClass == pDevReg->fClass
563 && pReq->cMaxInstances == pDevReg->cMaxInstances
564 && pReq->cMaxPciDevices == pDevReg->cMaxPciDevices
565 && pReq->cMaxMsixVectors == pDevReg->cMaxMsixVectors)
566 {
567 rc = pdmR0DeviceCreateWorker(pGVM, pDevReg, pReq->iInstance, pReq->cbInstanceR3, pReq->cbInstanceRC,
568 NIL_RTRCPTR /** @todo new raw-mode */, pReq->hDbgfTracerEvtSrc,
569 hMod, &pReq->pDevInsR3);
570 if (RT_SUCCESS(rc))
571 hMod = NULL; /* keep the module reference */
572 }
573 else
574 {
575 LogRel(("PDMR0DeviceCreate: Ring-3 does not match ring-0 device registration (%s):\n"
576 " uSharedVersion: %#x vs %#x\n"
577 " cbInstanceShared: %#x vs %#x\n"
578 " cbInstanceRC: %#x vs %#x\n"
579 " fFlags: %#x vs %#x\n"
580 " fClass: %#x vs %#x\n"
581 " cMaxInstances: %#x vs %#x\n"
582 " cMaxPciDevices: %#x vs %#x\n"
583 " cMaxMsixVectors: %#x vs %#x\n"
584 ,
585 pReq->szDevName,
586 pReq->uSharedVersion, pDevReg->uSharedVersion,
587 pReq->cbInstanceShared, pDevReg->cbInstanceShared,
588 pReq->cbInstanceRC, pDevReg->cbInstanceRC,
589 pReq->fFlags, pDevReg->fFlags,
590 pReq->fClass, pDevReg->fClass,
591 pReq->cMaxInstances, pDevReg->cMaxInstances,
592 pReq->cMaxPciDevices, pDevReg->cMaxPciDevices,
593 pReq->cMaxMsixVectors, pDevReg->cMaxMsixVectors));
594 rc = VERR_INCOMPATIBLE_CONFIG;
595 }
596 }
597 }
598 break;
599 }
600 }
601
602 if (RT_SUCCESS_NP(rcLock))
603 {
604 rcLock = SUPR0LdrUnlock(pGVM->pSession);
605 AssertRC(rcLock);
606 }
607 SUPR0LdrModRelease(pGVM->pSession, hMod);
608 return rc;
609}
610
611
612/**
613 * Used by ring-3 PDM to call standard ring-0 device methods.
614 *
615 * @returns VBox status code.
616 * @param pGVM The global (ring-0) VM structure.
617 * @param pReq Pointer to the request buffer.
618 * @param idCpu The ID of the calling EMT.
619 * @thread EMT(0), except for PDMDEVICEGENCALL_REQUEST which can be any EMT.
620 */
621VMMR0_INT_DECL(int) PDMR0DeviceGenCallReqHandler(PGVM pGVM, PPDMDEVICEGENCALLREQ pReq, VMCPUID idCpu)
622{
623 /*
624 * Validate the request.
625 */
626 AssertReturn(pReq->Hdr.cbReq == sizeof(*pReq), VERR_INVALID_PARAMETER);
627
628 int rc = GVMMR0ValidateGVMandEMT(pGVM, idCpu);
629 AssertRCReturn(rc, rc);
630
631 AssertReturn(pReq->idxR0Device < pGVM->pdmr0.s.cDevInstances, VERR_INVALID_HANDLE);
632 PPDMDEVINSR0 pDevIns = pGVM->pdmr0.s.apDevInstances[pReq->idxR0Device];
633 AssertPtrReturn(pDevIns, VERR_INVALID_HANDLE);
634 AssertReturn(pDevIns->pDevInsForR3 == pReq->pDevInsR3, VERR_INVALID_HANDLE);
635
636 /*
637 * Make the call.
638 */
639 rc = VINF_SUCCESS /*VINF_NOT_IMPLEMENTED*/;
640 switch (pReq->enmCall)
641 {
642 case PDMDEVICEGENCALL_CONSTRUCT:
643 AssertMsgBreakStmt(pGVM->enmVMState < VMSTATE_CREATED, ("enmVMState=%d\n", pGVM->enmVMState), rc = VERR_INVALID_STATE);
644 AssertReturn(idCpu == 0, VERR_VM_THREAD_NOT_EMT);
645 if (pDevIns->pReg->pfnConstruct)
646 rc = pDevIns->pReg->pfnConstruct(pDevIns);
647 break;
648
649 case PDMDEVICEGENCALL_DESTRUCT:
650 AssertMsgBreakStmt(pGVM->enmVMState < VMSTATE_CREATED || pGVM->enmVMState >= VMSTATE_DESTROYING,
651 ("enmVMState=%d\n", pGVM->enmVMState), rc = VERR_INVALID_STATE);
652 AssertReturn(idCpu == 0, VERR_VM_THREAD_NOT_EMT);
653 if (pDevIns->pReg->pfnDestruct)
654 {
655 pDevIns->pReg->pfnDestruct(pDevIns);
656 rc = VINF_SUCCESS;
657 }
658 break;
659
660 case PDMDEVICEGENCALL_REQUEST:
661 if (pDevIns->pReg->pfnRequest)
662 rc = pDevIns->pReg->pfnRequest(pDevIns, pReq->Params.Req.uReq, pReq->Params.Req.uArg);
663 else
664 rc = VERR_INVALID_FUNCTION;
665 break;
666
667 default:
668 AssertMsgFailed(("enmCall=%d\n", pReq->enmCall));
669 rc = VERR_INVALID_FUNCTION;
670 break;
671 }
672
673 return rc;
674}
675
676
677/**
678 * Legacy device mode compatiblity.
679 *
680 * @returns VBox status code.
681 * @param pGVM The global (ring-0) VM structure.
682 * @param pReq Pointer to the request buffer.
683 * @thread EMT(0)
684 */
685VMMR0_INT_DECL(int) PDMR0DeviceCompatSetCritSectReqHandler(PGVM pGVM, PPDMDEVICECOMPATSETCRITSECTREQ pReq)
686{
687 /*
688 * Validate the request.
689 */
690 AssertReturn(pReq->Hdr.cbReq == sizeof(*pReq), VERR_INVALID_PARAMETER);
691
692 int rc = GVMMR0ValidateGVMandEMT(pGVM, 0);
693 AssertRCReturn(rc, rc);
694
695 AssertReturn(pReq->idxR0Device < pGVM->pdmr0.s.cDevInstances, VERR_INVALID_HANDLE);
696 PPDMDEVINSR0 pDevIns = pGVM->pdmr0.s.apDevInstances[pReq->idxR0Device];
697 AssertPtrReturn(pDevIns, VERR_INVALID_HANDLE);
698 AssertReturn(pDevIns->pDevInsForR3 == pReq->pDevInsR3, VERR_INVALID_HANDLE);
699
700 AssertReturn(pGVM->enmVMState == VMSTATE_CREATING, VERR_INVALID_STATE);
701
702 /*
703 * The critical section address can be in a few different places:
704 * 1. shared data.
705 * 2. nop section.
706 * 3. pdm critsect.
707 */
708 PPDMCRITSECT pCritSect;
709 if (pReq->pCritSectR3 == pGVM->pVMR3 + RT_UOFFSETOF(VM, pdm.s.NopCritSect))
710 {
711 pCritSect = &pGVM->pdm.s.NopCritSect;
712 Log(("PDMR0DeviceCompatSetCritSectReqHandler: Nop - %p %#x\n", pCritSect, pCritSect->s.Core.u32Magic));
713 }
714 else if (pReq->pCritSectR3 == pGVM->pVMR3 + RT_UOFFSETOF(VM, pdm.s.CritSect))
715 {
716 pCritSect = &pGVM->pdm.s.CritSect;
717 Log(("PDMR0DeviceCompatSetCritSectReqHandler: PDM - %p %#x\n", pCritSect, pCritSect->s.Core.u32Magic));
718 }
719 else
720 {
721 size_t offCritSect = pReq->pCritSectR3 - pDevIns->pDevInsForR3R0->pvInstanceDataR3;
722 AssertLogRelMsgReturn( offCritSect < pDevIns->pReg->cbInstanceShared
723 && offCritSect + sizeof(PDMCRITSECT) <= pDevIns->pReg->cbInstanceShared,
724 ("offCritSect=%p pCritSectR3=%p cbInstanceShared=%#x (%s)\n",
725 offCritSect, pReq->pCritSectR3, pDevIns->pReg->cbInstanceShared, pDevIns->pReg->szName),
726 VERR_INVALID_POINTER);
727 pCritSect = (PPDMCRITSECT)((uint8_t *)pDevIns->pvInstanceDataR0 + offCritSect);
728 Log(("PDMR0DeviceCompatSetCritSectReqHandler: custom - %#x/%p %#x\n", offCritSect, pCritSect, pCritSect->s.Core.u32Magic));
729 }
730 AssertLogRelMsgReturn(pCritSect->s.Core.u32Magic == RTCRITSECT_MAGIC,
731 ("cs=%p magic=%#x dev=%s\n", pCritSect, pCritSect->s.Core.u32Magic, pDevIns->pReg->szName),
732 VERR_INVALID_MAGIC);
733
734 /*
735 * Make the update.
736 */
737 pDevIns->pCritSectRoR0 = pCritSect;
738
739 return VINF_SUCCESS;
740}
741
742
743/**
744 * Registers the device implementations living in a module.
745 *
746 * This should normally only be called during ModuleInit(). The should be a
747 * call to PDMR0DeviceDeregisterModule from the ModuleTerm() function to undo
748 * the effects of this call.
749 *
750 * @returns VBox status code.
751 * @param hMod The module handle of the module being registered.
752 * @param pModReg The module registration structure. This will be
753 * used directly so it must live as long as the module
754 * and be writable.
755 *
756 * @note Caller must own the loader lock!
757 */
758VMMR0DECL(int) PDMR0DeviceRegisterModule(void *hMod, PPDMDEVMODREGR0 pModReg)
759{
760 /*
761 * Validate the input.
762 */
763 AssertPtrReturn(hMod, VERR_INVALID_HANDLE);
764 Assert(SUPR0LdrIsLockOwnerByMod(hMod, true));
765
766 AssertPtrReturn(pModReg, VERR_INVALID_POINTER);
767 AssertLogRelMsgReturn(PDM_VERSION_ARE_COMPATIBLE(pModReg->u32Version, PDM_DEVMODREGR0_VERSION),
768 ("pModReg->u32Version=%#x vs %#x\n", pModReg->u32Version, PDM_DEVMODREGR0_VERSION),
769 VERR_VERSION_MISMATCH);
770 AssertLogRelMsgReturn(pModReg->cDevRegs <= 256 && pModReg->cDevRegs > 0, ("cDevRegs=%u\n", pModReg->cDevRegs),
771 VERR_OUT_OF_RANGE);
772 AssertLogRelMsgReturn(pModReg->hMod == NULL, ("hMod=%p\n", pModReg->hMod), VERR_INVALID_PARAMETER);
773 AssertLogRelMsgReturn(pModReg->ListEntry.pNext == NULL, ("pNext=%p\n", pModReg->ListEntry.pNext), VERR_INVALID_PARAMETER);
774 AssertLogRelMsgReturn(pModReg->ListEntry.pPrev == NULL, ("pPrev=%p\n", pModReg->ListEntry.pPrev), VERR_INVALID_PARAMETER);
775
776 for (size_t i = 0; i < pModReg->cDevRegs; i++)
777 {
778 PCPDMDEVREGR0 pDevReg = pModReg->papDevRegs[i];
779 AssertLogRelMsgReturn(RT_VALID_PTR(pDevReg), ("[%u]: %p\n", i, pDevReg), VERR_INVALID_POINTER);
780 AssertLogRelMsgReturn(PDM_VERSION_ARE_COMPATIBLE(pDevReg->u32Version, PDM_DEVREGR0_VERSION),
781 ("pDevReg->u32Version=%#x vs %#x\n", pModReg->u32Version, PDM_DEVREGR0_VERSION), VERR_VERSION_MISMATCH);
782 AssertLogRelMsgReturn(RT_VALID_PTR(pDevReg->pszDescription), ("[%u]: %p\n", i, pDevReg->pszDescription), VERR_INVALID_POINTER);
783 AssertLogRelMsgReturn(pDevReg->uReserved0 == 0, ("[%u]: %#x\n", i, pDevReg->uReserved0), VERR_INVALID_PARAMETER);
784 AssertLogRelMsgReturn(pDevReg->fClass != 0, ("[%u]: %#x\n", i, pDevReg->fClass), VERR_INVALID_PARAMETER);
785 AssertLogRelMsgReturn(pDevReg->fFlags != 0, ("[%u]: %#x\n", i, pDevReg->fFlags), VERR_INVALID_PARAMETER);
786 AssertLogRelMsgReturn(pDevReg->cMaxInstances > 0, ("[%u]: %#x\n", i, pDevReg->cMaxInstances), VERR_INVALID_PARAMETER);
787 AssertLogRelMsgReturn(pDevReg->cMaxPciDevices <= 8, ("[%u]: %#x\n", i, pDevReg->cMaxPciDevices), VERR_INVALID_PARAMETER);
788 AssertLogRelMsgReturn(pDevReg->cMaxMsixVectors <= VBOX_MSIX_MAX_ENTRIES,
789 ("[%u]: %#x\n", i, pDevReg->cMaxMsixVectors), VERR_INVALID_PARAMETER);
790
791 /* The name must be printable ascii and correctly terminated. */
792 for (size_t off = 0; off < RT_ELEMENTS(pDevReg->szName); off++)
793 {
794 char ch = pDevReg->szName[off];
795 AssertLogRelMsgReturn(RT_C_IS_PRINT(ch) || (ch == '\0' && off > 0),
796 ("[%u]: off=%u szName: %.*Rhxs\n", i, off, sizeof(pDevReg->szName), &pDevReg->szName[0]),
797 VERR_INVALID_NAME);
798 if (ch == '\0')
799 break;
800 }
801 }
802
803 /*
804 * Add it, assuming we're being called at ModuleInit/ModuleTerm time only, or
805 * that the caller has already taken the loader lock.
806 */
807 pModReg->hMod = hMod;
808 RTListAppend(&g_PDMDevModList, &pModReg->ListEntry);
809
810 return VINF_SUCCESS;
811}
812
813
814/**
815 * Deregisters the device implementations living in a module.
816 *
817 * This should normally only be called during ModuleTerm().
818 *
819 * @returns VBox status code.
820 * @param hMod The module handle of the module being registered.
821 * @param pModReg The module registration structure. This will be
822 * used directly so it must live as long as the module
823 * and be writable.
824 *
825 * @note Caller must own the loader lock!
826 */
827VMMR0DECL(int) PDMR0DeviceDeregisterModule(void *hMod, PPDMDEVMODREGR0 pModReg)
828{
829 /*
830 * Validate the input.
831 */
832 AssertPtrReturn(hMod, VERR_INVALID_HANDLE);
833 Assert(SUPR0LdrIsLockOwnerByMod(hMod, true));
834
835 AssertPtrReturn(pModReg, VERR_INVALID_POINTER);
836 AssertLogRelMsgReturn(PDM_VERSION_ARE_COMPATIBLE(pModReg->u32Version, PDM_DEVMODREGR0_VERSION),
837 ("pModReg->u32Version=%#x vs %#x\n", pModReg->u32Version, PDM_DEVMODREGR0_VERSION),
838 VERR_VERSION_MISMATCH);
839 AssertLogRelMsgReturn(pModReg->hMod == hMod || pModReg->hMod == NULL, ("pModReg->hMod=%p vs %p\n", pModReg->hMod, hMod),
840 VERR_INVALID_PARAMETER);
841
842 /*
843 * Unlink the registration record and return it to virgin conditions. Ignore
844 * the call if not registered.
845 */
846 if (pModReg->hMod)
847 {
848 pModReg->hMod = NULL;
849 RTListNodeRemove(&pModReg->ListEntry);
850 pModReg->ListEntry.pNext = NULL;
851 pModReg->ListEntry.pPrev = NULL;
852 return VINF_SUCCESS;
853 }
854 return VWRN_NOT_FOUND;
855}
856
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