VirtualBox

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

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

VMM: Changed PAGE_SIZE -> GUEST_PAGE_SIZE / HOST_PAGE_SIZE, PAGE_SHIFT -> GUEST_PAGE_SHIFT / HOST_PAGE_SHIFT, and PAGE_OFFSET_MASK -> GUEST_PAGE_OFFSET_MASK / HOST_PAGE_OFFSET_MASK. Also removed most usage of ASMMemIsZeroPage and ASMMemZeroPage since the host and guest page size doesn't need to be the same any more. Some work left to do in the page pool code. bugref:9898

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 35.7 KB
Line 
1/* $Id: PDMR0Device.cpp 93554 2022-02-02 22:57:02Z 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
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, HOST_PAGE_SIZE);
265 uint32_t const cbRing3 = RT_ALIGN_32(RT_UOFFSETOF(PDMDEVINSR3, achInstanceData) + cbInstanceR3,
266 RCPtrMapping != NIL_RTRGPTR ? HOST_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, HOST_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