VirtualBox

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

Last change on this file since 87758 was 84459, checked in by vboxsync, 5 years ago

VMM/PDM: DBGF even tracing integration, bugref:9210

Integrates the new DBGF event tracing framework into PDM
devices. The new CFGM key "TracingEnabled" for a device
instance enables tracing using DBGF. A special tracing variant
of the PDM device helper is provided.

Disabled by default for now, enable with VBOX_WITH_DBGF_TRACING

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