VirtualBox

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

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

Devices/PCI: Device model refactoring, part I. bugref:9218

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 72.6 KB
Line 
1/* $Id: PDMR0Device.cpp 80943 2019-09-23 09:36:14Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device and Driver Manager, R0 Device parts.
4 */
5
6/*
7 * Copyright (C) 2006-2019 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;
56extern DECLEXPORT(const PDMPICHLPR0) g_pdmR0PicHlp;
57extern DECLEXPORT(const PDMIOAPICHLPR0) g_pdmR0IoApicHlp;
58extern DECLEXPORT(const PDMPCIHLPR0) g_pdmR0PciHlp;
59extern DECLEXPORT(const PDMHPETHLPR0) g_pdmR0HpetHlp;
60extern DECLEXPORT(const PDMPCIRAWHLPR0) g_pdmR0PciRawHlp;
61extern DECLEXPORT(const PDMDRVHLPR0) g_pdmR0DrvHlp;
62RT_C_DECLS_END
63
64/** List of PDMDEVMODREGR0 structures protected by the loader lock. */
65static RTLISTANCHOR g_PDMDevModList;
66
67
68/**
69 * Pointer to the ring-0 device registrations for VMMR0.
70 */
71static const PDMDEVREGR0 *g_apVMM0DevRegs[] =
72{
73 &g_DeviceAPIC,
74};
75
76/**
77 * Module device registration record for VMMR0.
78 */
79static PDMDEVMODREGR0 g_VBoxDDR0ModDevReg =
80{
81 /* .u32Version = */ PDM_DEVMODREGR0_VERSION,
82 /* .cDevRegs = */ RT_ELEMENTS(g_apVMM0DevRegs),
83 /* .papDevRegs = */ &g_apVMM0DevRegs[0],
84 /* .hMod = */ NULL,
85 /* .ListEntry = */ { NULL, NULL },
86};
87
88
89/*********************************************************************************************************************************
90* Internal Functions *
91*********************************************************************************************************************************/
92static bool pdmR0IsaSetIrq(PGVM pGVM, int iIrq, int iLevel, uint32_t uTagSrc);
93
94
95/**
96 * Initializes the global ring-0 PDM data.
97 */
98VMMR0_INT_DECL(void) PDMR0Init(void *hMod)
99{
100 RTListInit(&g_PDMDevModList);
101 g_VBoxDDR0ModDevReg.hMod = hMod;
102 RTListAppend(&g_PDMDevModList, &g_VBoxDDR0ModDevReg.ListEntry);
103}
104
105
106/**
107 * Used by PDMR0CleanupVM to destroy a device instance.
108 *
109 * This is done during VM cleanup so that we're sure there are no active threads
110 * inside the device code.
111 *
112 * @param pGVM The global (ring-0) VM structure.
113 * @param pDevIns The device instance.
114 * @param idxR0Device The device instance handle.
115 */
116static int pdmR0DeviceDestroy(PGVM pGVM, PPDMDEVINSR0 pDevIns, uint32_t idxR0Device)
117{
118 /*
119 * Assert sanity.
120 */
121 Assert(idxR0Device < pGVM->pdmr0.s.cDevInstances);
122 AssertPtrReturn(pDevIns, VERR_INVALID_HANDLE);
123 Assert(pDevIns->u32Version == PDM_DEVINSR0_VERSION);
124 Assert(pDevIns->Internal.s.idxR0Device == idxR0Device);
125
126 /*
127 * Call the final destructor if there is one.
128 */
129 if (pDevIns->pReg->pfnFinalDestruct)
130 pDevIns->pReg->pfnFinalDestruct(pDevIns);
131 pDevIns->u32Version = ~PDM_DEVINSR0_VERSION;
132
133 /*
134 * Remove the device from the instance table.
135 */
136 Assert(pGVM->pdmr0.s.apDevInstances[idxR0Device] == pDevIns);
137 pGVM->pdmr0.s.apDevInstances[idxR0Device] = NULL;
138 if (idxR0Device + 1 == pGVM->pdmr0.s.cDevInstances)
139 pGVM->pdmr0.s.cDevInstances = idxR0Device;
140
141 /*
142 * Free the ring-3 mapping and instance memory.
143 */
144 RTR0MEMOBJ hMemObj = pDevIns->Internal.s.hMapObj;
145 pDevIns->Internal.s.hMapObj = NIL_RTR0MEMOBJ;
146 RTR0MemObjFree(hMemObj, true);
147
148 hMemObj = pDevIns->Internal.s.hMemObj;
149 pDevIns->Internal.s.hMemObj = NIL_RTR0MEMOBJ;
150 RTR0MemObjFree(hMemObj, true);
151
152 return VINF_SUCCESS;
153}
154
155
156/**
157 * Initializes the per-VM data for the PDM.
158 *
159 * This is called from under the GVMM lock, so it only need to initialize the
160 * data so PDMR0CleanupVM and others will work smoothly.
161 *
162 * @param pGVM Pointer to the global VM structure.
163 */
164VMMR0_INT_DECL(void) PDMR0InitPerVMData(PGVM pGVM)
165{
166 AssertCompile(sizeof(pGVM->pdm.s) <= sizeof(pGVM->pdm.padding));
167 AssertCompile(sizeof(pGVM->pdmr0.s) <= sizeof(pGVM->pdmr0.padding));
168
169 pGVM->pdmr0.s.cDevInstances = 0;
170}
171
172
173/**
174 * Cleans up any loose ends before the GVM structure is destroyed.
175 */
176VMMR0_INT_DECL(void) PDMR0CleanupVM(PGVM pGVM)
177{
178 uint32_t i = pGVM->pdmr0.s.cDevInstances;
179 while (i-- > 0)
180 {
181 PPDMDEVINSR0 pDevIns = pGVM->pdmr0.s.apDevInstances[i];
182 if (pDevIns)
183 pdmR0DeviceDestroy(pGVM, pDevIns, i);
184 }
185}
186
187
188/** @name Ring-0 Device Helpers
189 * @{
190 */
191
192/** @interface_method_impl{PDMDEVHLPR0,pfnIoPortSetUpContextEx} */
193static DECLCALLBACK(int) pdmR0DevHlp_IoPortSetUpContextEx(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts,
194 PFNIOMIOPORTOUT pfnOut, PFNIOMIOPORTIN pfnIn,
195 PFNIOMIOPORTOUTSTRING pfnOutStr, PFNIOMIOPORTINSTRING pfnInStr,
196 void *pvUser)
197{
198 PDMDEV_ASSERT_DEVINS(pDevIns);
199 LogFlow(("pdmR0DevHlp_IoPortSetUpContextEx: caller='%s'/%d: hIoPorts=%#x pfnOut=%p pfnIn=%p pfnOutStr=%p pfnInStr=%p pvUser=%p\n",
200 pDevIns->pReg->szName, pDevIns->iInstance, hIoPorts, pfnOut, pfnIn, pfnOutStr, pfnInStr, pvUser));
201 PGVM pGVM = pDevIns->Internal.s.pGVM;
202 VM_ASSERT_EMT0_RETURN(pGVM, VERR_VM_THREAD_NOT_EMT);
203 VM_ASSERT_STATE_RETURN(pGVM, VMSTATE_CREATING, VERR_VM_INVALID_VM_STATE);
204
205 int rc = IOMR0IoPortSetUpContext(pGVM, pDevIns, hIoPorts, pfnOut, pfnIn, pfnOutStr, pfnInStr, pvUser);
206
207 LogFlow(("pdmR0DevHlp_IoPortSetUpContextEx: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
208 return rc;
209}
210
211
212/** @interface_method_impl{PDMDEVHLPR0,pfnMmioSetUpContextEx} */
213static DECLCALLBACK(int) pdmR0DevHlp_MmioSetUpContextEx(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, PFNIOMMMIOWRITE pfnWrite,
214 PFNIOMMMIOREAD pfnRead, PFNIOMMMIOFILL pfnFill, void *pvUser)
215{
216 RT_NOREF(pDevIns, hRegion, pfnWrite, pfnRead, pfnFill, pvUser);
217 return VERR_NOT_IMPLEMENTED;
218}
219
220
221/** @interface_method_impl{PDMDEVHLPR0,pfnPCIPhysRead} */
222static DECLCALLBACK(int) pdmR0DevHlp_PCIPhysRead(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys,
223 void *pvBuf, size_t cbRead)
224{
225 PDMDEV_ASSERT_DEVINS(pDevIns);
226 if (!pPciDev) /* NULL is an alias for the default PCI device. */
227 pPciDev = pDevIns->Internal.s.pHeadPciDevR0;
228 AssertReturn(pPciDev, VERR_PDM_NOT_PCI_DEVICE);
229
230#ifndef PDM_DO_NOT_RESPECT_PCI_BM_BIT
231 /*
232 * Just check the busmaster setting here and forward the request to the generic read helper.
233 */
234 if (PCIDevIsBusmaster(pPciDev))
235 { /* likely */ }
236 else
237 {
238 Log(("pdmRCDevHlp_PCIPhysRead: caller=%p/%d: returns %Rrc - Not bus master! GCPhys=%RGp cbRead=%#zx\n",
239 pDevIns, pDevIns->iInstance, VERR_PDM_NOT_PCI_BUS_MASTER, GCPhys, cbRead));
240 memset(pvBuf, 0xff, cbRead);
241 return VERR_PDM_NOT_PCI_BUS_MASTER;
242 }
243#endif
244
245 return pDevIns->pHlpR0->pfnPhysRead(pDevIns, GCPhys, pvBuf, cbRead);
246}
247
248
249/** @interface_method_impl{PDMDEVHLPR0,pfnPCIPhysWrite} */
250static DECLCALLBACK(int) pdmR0DevHlp_PCIPhysWrite(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys,
251 const void *pvBuf, size_t cbWrite)
252{
253 PDMDEV_ASSERT_DEVINS(pDevIns);
254 if (!pPciDev) /* NULL is an alias for the default PCI device. */
255 pPciDev = pDevIns->Internal.s.pHeadPciDevR0;
256 AssertReturn(pPciDev, VERR_PDM_NOT_PCI_DEVICE);
257
258#ifndef PDM_DO_NOT_RESPECT_PCI_BM_BIT
259 /*
260 * Just check the busmaster setting here and forward the request to the generic read helper.
261 */
262 if (PCIDevIsBusmaster(pPciDev))
263 { /* likely */ }
264 else
265 {
266 Log(("pdmRCDevHlp_PCIPhysWrite: caller=%p/%d: returns %Rrc - Not bus master! GCPhys=%RGp cbWrite=%#zx\n",
267 pDevIns, pDevIns->iInstance, VERR_PDM_NOT_PCI_BUS_MASTER, GCPhys, cbWrite));
268 return VERR_PDM_NOT_PCI_BUS_MASTER;
269 }
270#endif
271
272 return pDevIns->pHlpR0->pfnPhysWrite(pDevIns, GCPhys, pvBuf, cbWrite);
273}
274
275
276/** @interface_method_impl{PDMDEVHLPR0,pfnPCISetIrq} */
277static DECLCALLBACK(void) pdmR0DevHlp_PCISetIrq(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel)
278{
279 PDMDEV_ASSERT_DEVINS(pDevIns);
280 if (!pPciDev) /* NULL is an alias for the default PCI device. */
281 pPciDev = pDevIns->Internal.s.pHeadPciDevR0;
282 AssertReturnVoid(pPciDev);
283 LogFlow(("pdmR0DevHlp_PCISetIrq: caller=%p/%d: pPciDev=%p:{%#x} iIrq=%d iLevel=%d\n",
284 pDevIns, pDevIns->iInstance, pPciDev, pPciDev->uDevFn, iIrq, iLevel));
285 PGVM pGVM = pDevIns->Internal.s.pGVM;
286 size_t const idxBus = pPciDev->Int.s.idxPdmBus;
287 AssertReturnVoid(idxBus < RT_ELEMENTS(pGVM->pdmr0.s.aPciBuses));
288 PPDMPCIBUSR0 pPciBusR0 = &pGVM->pdmr0.s.aPciBuses[idxBus];
289
290 pdmLock(pGVM);
291
292 uint32_t uTagSrc;
293 if (iLevel & PDM_IRQ_LEVEL_HIGH)
294 {
295 pDevIns->Internal.s.pIntR3R0->uLastIrqTag = uTagSrc = pdmCalcIrqTag(pGVM, pDevIns->Internal.s.pInsR3R0->idTracing);
296 if (iLevel == PDM_IRQ_LEVEL_HIGH)
297 VBOXVMM_PDM_IRQ_HIGH(VMMGetCpu(pGVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc));
298 else
299 VBOXVMM_PDM_IRQ_HILO(VMMGetCpu(pGVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc));
300 }
301 else
302 uTagSrc = pDevIns->Internal.s.pIntR3R0->uLastIrqTag;
303
304 if (pPciBusR0->pDevInsR0)
305 {
306 pPciBusR0->pfnSetIrqR0(pPciBusR0->pDevInsR0, pPciDev, iIrq, iLevel, uTagSrc);
307
308 pdmUnlock(pGVM);
309
310 if (iLevel == PDM_IRQ_LEVEL_LOW)
311 VBOXVMM_PDM_IRQ_LOW(VMMGetCpu(pGVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc));
312 }
313 else
314 {
315 pdmUnlock(pGVM);
316
317 /* queue for ring-3 execution. */
318 PPDMDEVHLPTASK pTask = (PPDMDEVHLPTASK)PDMQueueAlloc(pGVM->pdm.s.pDevHlpQueueR0);
319 AssertReturnVoid(pTask);
320
321 pTask->enmOp = PDMDEVHLPTASKOP_PCI_SET_IRQ;
322 pTask->pDevInsR3 = PDMDEVINS_2_R3PTR(pDevIns);
323 pTask->u.PciSetIRQ.iIrq = iIrq;
324 pTask->u.PciSetIRQ.iLevel = iLevel;
325 pTask->u.PciSetIRQ.uTagSrc = uTagSrc;
326 pTask->u.PciSetIRQ.pPciDevR3 = MMHyperR0ToR3(pGVM, pPciDev);
327
328 PDMQueueInsertEx(pGVM->pdm.s.pDevHlpQueueR0, &pTask->Core, 0);
329 }
330
331 LogFlow(("pdmR0DevHlp_PCISetIrq: caller=%p/%d: returns void; uTagSrc=%#x\n", pDevIns, pDevIns->iInstance, uTagSrc));
332}
333
334
335/** @interface_method_impl{PDMDEVHLPR0,pfnISASetIrq} */
336static DECLCALLBACK(void) pdmR0DevHlp_ISASetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel)
337{
338 PDMDEV_ASSERT_DEVINS(pDevIns);
339 LogFlow(("pdmR0DevHlp_ISASetIrq: caller=%p/%d: iIrq=%d iLevel=%d\n", pDevIns, pDevIns->iInstance, iIrq, iLevel));
340 PGVM pGVM = pDevIns->Internal.s.pGVM;
341
342 pdmLock(pGVM);
343 uint32_t uTagSrc;
344 if (iLevel & PDM_IRQ_LEVEL_HIGH)
345 {
346 pDevIns->Internal.s.pIntR3R0->uLastIrqTag = uTagSrc = pdmCalcIrqTag(pGVM, pDevIns->Internal.s.pInsR3R0->idTracing);
347 if (iLevel == PDM_IRQ_LEVEL_HIGH)
348 VBOXVMM_PDM_IRQ_HIGH(VMMGetCpu(pGVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc));
349 else
350 VBOXVMM_PDM_IRQ_HILO(VMMGetCpu(pGVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc));
351 }
352 else
353 uTagSrc = pDevIns->Internal.s.pIntR3R0->uLastIrqTag;
354
355 bool fRc = pdmR0IsaSetIrq(pGVM, iIrq, iLevel, uTagSrc);
356
357 if (iLevel == PDM_IRQ_LEVEL_LOW && fRc)
358 VBOXVMM_PDM_IRQ_LOW(VMMGetCpu(pGVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc));
359 pdmUnlock(pGVM);
360 LogFlow(("pdmR0DevHlp_ISASetIrq: caller=%p/%d: returns void; uTagSrc=%#x\n", pDevIns, pDevIns->iInstance, uTagSrc));
361}
362
363
364/** @interface_method_impl{PDMDEVHLPR0,pfnIoApicSendMsi} */
365static DECLCALLBACK(void) pdmR0DevHlp_IoApicSendMsi(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint32_t uValue)
366{
367 PDMDEV_ASSERT_DEVINS(pDevIns);
368 LogFlow(("pdmR0DevHlp_IoApicSendMsi: caller=%p/%d: GCPhys=%RGp uValue=%#x\n", pDevIns, pDevIns->iInstance, GCPhys, uValue));
369 PGVM pGVM = pDevIns->Internal.s.pGVM;
370
371 uint32_t uTagSrc;
372 pDevIns->Internal.s.pIntR3R0->uLastIrqTag = uTagSrc = pdmCalcIrqTag(pGVM, pDevIns->Internal.s.pInsR3R0->idTracing);
373 VBOXVMM_PDM_IRQ_HILO(VMMGetCpu(pGVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc));
374
375 if (pGVM->pdm.s.IoApic.pDevInsR0)
376 pGVM->pdm.s.IoApic.pfnSendMsiR0(pGVM->pdm.s.IoApic.pDevInsR0, GCPhys, uValue, uTagSrc);
377 else
378 AssertFatalMsgFailed(("Lazy bastards!"));
379
380 LogFlow(("pdmR0DevHlp_IoApicSendMsi: caller=%p/%d: returns void; uTagSrc=%#x\n", pDevIns, pDevIns->iInstance, uTagSrc));
381}
382
383
384/** @interface_method_impl{PDMDEVHLPR0,pfnPhysRead} */
385static DECLCALLBACK(int) pdmR0DevHlp_PhysRead(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead)
386{
387 PDMDEV_ASSERT_DEVINS(pDevIns);
388 LogFlow(("pdmR0DevHlp_PhysRead: caller=%p/%d: GCPhys=%RGp pvBuf=%p cbRead=%#x\n",
389 pDevIns, pDevIns->iInstance, GCPhys, pvBuf, cbRead));
390
391 VBOXSTRICTRC rcStrict = PGMPhysRead(pDevIns->Internal.s.pGVM, GCPhys, pvBuf, cbRead, PGMACCESSORIGIN_DEVICE);
392 AssertMsg(rcStrict == VINF_SUCCESS, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict))); /** @todo track down the users for this bugger. */
393
394 Log(("pdmR0DevHlp_PhysRead: caller=%p/%d: returns %Rrc\n", pDevIns, pDevIns->iInstance, VBOXSTRICTRC_VAL(rcStrict) ));
395 return VBOXSTRICTRC_VAL(rcStrict);
396}
397
398
399/** @interface_method_impl{PDMDEVHLPR0,pfnPhysWrite} */
400static DECLCALLBACK(int) pdmR0DevHlp_PhysWrite(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite)
401{
402 PDMDEV_ASSERT_DEVINS(pDevIns);
403 LogFlow(("pdmR0DevHlp_PhysWrite: caller=%p/%d: GCPhys=%RGp pvBuf=%p cbWrite=%#x\n",
404 pDevIns, pDevIns->iInstance, GCPhys, pvBuf, cbWrite));
405
406 VBOXSTRICTRC rcStrict = PGMPhysWrite(pDevIns->Internal.s.pGVM, GCPhys, pvBuf, cbWrite, PGMACCESSORIGIN_DEVICE);
407 AssertMsg(rcStrict == VINF_SUCCESS, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict))); /** @todo track down the users for this bugger. */
408
409 Log(("pdmR0DevHlp_PhysWrite: caller=%p/%d: returns %Rrc\n", pDevIns, pDevIns->iInstance, VBOXSTRICTRC_VAL(rcStrict) ));
410 return VBOXSTRICTRC_VAL(rcStrict);
411}
412
413
414/** @interface_method_impl{PDMDEVHLPR0,pfnA20IsEnabled} */
415static DECLCALLBACK(bool) pdmR0DevHlp_A20IsEnabled(PPDMDEVINS pDevIns)
416{
417 PDMDEV_ASSERT_DEVINS(pDevIns);
418 LogFlow(("pdmR0DevHlp_A20IsEnabled: caller=%p/%d:\n", pDevIns, pDevIns->iInstance));
419
420 bool fEnabled = PGMPhysIsA20Enabled(VMMGetCpu(pDevIns->Internal.s.pGVM));
421
422 Log(("pdmR0DevHlp_A20IsEnabled: caller=%p/%d: returns %RTbool\n", pDevIns, pDevIns->iInstance, fEnabled));
423 return fEnabled;
424}
425
426
427/** @interface_method_impl{PDMDEVHLPR0,pfnVMState} */
428static DECLCALLBACK(VMSTATE) pdmR0DevHlp_VMState(PPDMDEVINS pDevIns)
429{
430 PDMDEV_ASSERT_DEVINS(pDevIns);
431
432 VMSTATE enmVMState = pDevIns->Internal.s.pGVM->enmVMState;
433
434 LogFlow(("pdmR0DevHlp_VMState: caller=%p/%d: returns %d\n", pDevIns, pDevIns->iInstance, enmVMState));
435 return enmVMState;
436}
437
438
439/** @interface_method_impl{PDMDEVHLPR0,pfnVMSetError} */
440static DECLCALLBACK(int) pdmR0DevHlp_VMSetError(PPDMDEVINS pDevIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...)
441{
442 PDMDEV_ASSERT_DEVINS(pDevIns);
443 va_list args;
444 va_start(args, pszFormat);
445 int rc2 = VMSetErrorV(pDevIns->Internal.s.pGVM, rc, RT_SRC_POS_ARGS, pszFormat, args); Assert(rc2 == rc); NOREF(rc2);
446 va_end(args);
447 return rc;
448}
449
450
451/** @interface_method_impl{PDMDEVHLPR0,pfnVMSetErrorV} */
452static DECLCALLBACK(int) pdmR0DevHlp_VMSetErrorV(PPDMDEVINS pDevIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
453{
454 PDMDEV_ASSERT_DEVINS(pDevIns);
455 int rc2 = VMSetErrorV(pDevIns->Internal.s.pGVM, rc, RT_SRC_POS_ARGS, pszFormat, va); Assert(rc2 == rc); NOREF(rc2);
456 return rc;
457}
458
459
460/** @interface_method_impl{PDMDEVHLPR0,pfnVMSetRuntimeError} */
461static DECLCALLBACK(int) pdmR0DevHlp_VMSetRuntimeError(PPDMDEVINS pDevIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
462{
463 PDMDEV_ASSERT_DEVINS(pDevIns);
464 va_list va;
465 va_start(va, pszFormat);
466 int rc = VMSetRuntimeErrorV(pDevIns->Internal.s.pGVM, fFlags, pszErrorId, pszFormat, va);
467 va_end(va);
468 return rc;
469}
470
471
472/** @interface_method_impl{PDMDEVHLPR0,pfnVMSetRuntimeErrorV} */
473static DECLCALLBACK(int) pdmR0DevHlp_VMSetRuntimeErrorV(PPDMDEVINS pDevIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va)
474{
475 PDMDEV_ASSERT_DEVINS(pDevIns);
476 int rc = VMSetRuntimeErrorV(pDevIns->Internal.s.pGVM, fFlags, pszErrorId, pszFormat, va);
477 return rc;
478}
479
480
481
482/** @interface_method_impl{PDMDEVHLPR0,pfnGetVM} */
483static DECLCALLBACK(PVMCC) pdmR0DevHlp_GetVM(PPDMDEVINS pDevIns)
484{
485 PDMDEV_ASSERT_DEVINS(pDevIns);
486 LogFlow(("pdmR0DevHlp_GetVM: caller='%p'/%d\n", pDevIns, pDevIns->iInstance));
487 return pDevIns->Internal.s.pGVM;
488}
489
490
491/** @interface_method_impl{PDMDEVHLPR0,pfnGetVMCPU} */
492static DECLCALLBACK(PVMCPUCC) pdmR0DevHlp_GetVMCPU(PPDMDEVINS pDevIns)
493{
494 PDMDEV_ASSERT_DEVINS(pDevIns);
495 LogFlow(("pdmR0DevHlp_GetVMCPU: caller='%p'/%d\n", pDevIns, pDevIns->iInstance));
496 return VMMGetCpu(pDevIns->Internal.s.pGVM);
497}
498
499
500/** @interface_method_impl{PDMDEVHLPRC,pfnGetCurrentCpuId} */
501static DECLCALLBACK(VMCPUID) pdmR0DevHlp_GetCurrentCpuId(PPDMDEVINS pDevIns)
502{
503 PDMDEV_ASSERT_DEVINS(pDevIns);
504 VMCPUID idCpu = VMMGetCpuId(pDevIns->Internal.s.pGVM);
505 LogFlow(("pdmR0DevHlp_GetCurrentCpuId: caller='%p'/%d for CPU %u\n", pDevIns, pDevIns->iInstance, idCpu));
506 return idCpu;
507}
508
509
510/** @interface_method_impl{PDMDEVHLPR0,pfnTimerToPtr} */
511static DECLCALLBACK(PTMTIMERR0) pdmR0DevHlp_TimerToPtr(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)
512{
513 PDMDEV_ASSERT_DEVINS(pDevIns);
514 RT_NOREF(pDevIns);
515 return (PTMTIMERR0)MMHyperR3ToCC(pDevIns->Internal.s.pGVM, hTimer);
516}
517
518
519/** @interface_method_impl{PDMDEVHLPR0,pfnTimerFromMicro} */
520static DECLCALLBACK(uint64_t) pdmR0DevHlp_TimerFromMicro(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMicroSecs)
521{
522 return TMTimerFromMicro(pdmR0DevHlp_TimerToPtr(pDevIns, hTimer), cMicroSecs);
523}
524
525
526/** @interface_method_impl{PDMDEVHLPR0,pfnTimerFromMilli} */
527static DECLCALLBACK(uint64_t) pdmR0DevHlp_TimerFromMilli(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMilliSecs)
528{
529 return TMTimerFromMilli(pdmR0DevHlp_TimerToPtr(pDevIns, hTimer), cMilliSecs);
530}
531
532
533/** @interface_method_impl{PDMDEVHLPR0,pfnTimerFromNano} */
534static DECLCALLBACK(uint64_t) pdmR0DevHlp_TimerFromNano(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cNanoSecs)
535{
536 return TMTimerFromNano(pdmR0DevHlp_TimerToPtr(pDevIns, hTimer), cNanoSecs);
537}
538
539/** @interface_method_impl{PDMDEVHLPR0,pfnTimerGet} */
540static DECLCALLBACK(uint64_t) pdmR0DevHlp_TimerGet(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)
541{
542 return TMTimerGet(pdmR0DevHlp_TimerToPtr(pDevIns, hTimer));
543}
544
545
546/** @interface_method_impl{PDMDEVHLPR0,pfnTimerGetFreq} */
547static DECLCALLBACK(uint64_t) pdmR0DevHlp_TimerGetFreq(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)
548{
549 return TMTimerGetFreq(pdmR0DevHlp_TimerToPtr(pDevIns, hTimer));
550}
551
552
553/** @interface_method_impl{PDMDEVHLPR0,pfnTimerGetNano} */
554static DECLCALLBACK(uint64_t) pdmR0DevHlp_TimerGetNano(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)
555{
556 return TMTimerGetNano(pdmR0DevHlp_TimerToPtr(pDevIns, hTimer));
557}
558
559
560/** @interface_method_impl{PDMDEVHLPR0,pfnTimerIsActive} */
561static DECLCALLBACK(bool) pdmR0DevHlp_TimerIsActive(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)
562{
563 return TMTimerIsActive(pdmR0DevHlp_TimerToPtr(pDevIns, hTimer));
564}
565
566
567/** @interface_method_impl{PDMDEVHLPR0,pfnTimerIsLockOwner} */
568static DECLCALLBACK(bool) pdmR0DevHlp_TimerIsLockOwner(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)
569{
570 return TMTimerIsLockOwner(pdmR0DevHlp_TimerToPtr(pDevIns, hTimer));
571}
572
573
574/** @interface_method_impl{PDMDEVHLPR0,pfnTimerLock} */
575static DECLCALLBACK(int) pdmR0DevHlp_TimerLock(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, int rcBusy)
576{
577 return TMTimerLock(pdmR0DevHlp_TimerToPtr(pDevIns, hTimer), rcBusy);
578}
579
580
581/** @interface_method_impl{PDMDEVHLPR0,pfnTimerSet} */
582static DECLCALLBACK(int) pdmR0DevHlp_TimerSet(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t uExpire)
583{
584 return TMTimerSet(pdmR0DevHlp_TimerToPtr(pDevIns, hTimer), uExpire);
585}
586
587
588/** @interface_method_impl{PDMDEVHLPR0,pfnTimerSetFrequencyHint} */
589static DECLCALLBACK(int) pdmR0DevHlp_TimerSetFrequencyHint(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint32_t uHz)
590{
591 return TMTimerSetFrequencyHint(pdmR0DevHlp_TimerToPtr(pDevIns, hTimer), uHz);
592}
593
594
595/** @interface_method_impl{PDMDEVHLPR0,pfnTimerSetMicro} */
596static DECLCALLBACK(int) pdmR0DevHlp_TimerSetMicro(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMicrosToNext)
597{
598 return TMTimerSetMicro(pdmR0DevHlp_TimerToPtr(pDevIns, hTimer), cMicrosToNext);
599}
600
601
602/** @interface_method_impl{PDMDEVHLPR0,pfnTimerSetMillies} */
603static DECLCALLBACK(int) pdmR0DevHlp_TimerSetMillies(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMilliesToNext)
604{
605 return TMTimerSetMillies(pdmR0DevHlp_TimerToPtr(pDevIns, hTimer), cMilliesToNext);
606}
607
608
609/** @interface_method_impl{PDMDEVHLPR0,pfnTimerSetNano} */
610static DECLCALLBACK(int) pdmR0DevHlp_TimerSetNano(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cNanosToNext)
611{
612 return TMTimerSetNano(pdmR0DevHlp_TimerToPtr(pDevIns, hTimer), cNanosToNext);
613}
614
615
616/** @interface_method_impl{PDMDEVHLPR0,pfnTimerSetRelative} */
617static DECLCALLBACK(int) pdmR0DevHlp_TimerSetRelative(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cTicksToNext, uint64_t *pu64Now)
618{
619 return TMTimerSetRelative(pdmR0DevHlp_TimerToPtr(pDevIns, hTimer), cTicksToNext, pu64Now);
620}
621
622
623/** @interface_method_impl{PDMDEVHLPR0,pfnTimerStop} */
624static DECLCALLBACK(int) pdmR0DevHlp_TimerStop(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)
625{
626 return TMTimerStop(pdmR0DevHlp_TimerToPtr(pDevIns, hTimer));
627}
628
629
630/** @interface_method_impl{PDMDEVHLPR0,pfnTimerUnlock} */
631static DECLCALLBACK(void) pdmR0DevHlp_TimerUnlock(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)
632{
633 TMTimerUnlock(pdmR0DevHlp_TimerToPtr(pDevIns, hTimer));
634}
635
636
637/** @interface_method_impl{PDMDEVHLPR0,pfnTMTimeVirtGet} */
638static DECLCALLBACK(uint64_t) pdmR0DevHlp_TMTimeVirtGet(PPDMDEVINS pDevIns)
639{
640 PDMDEV_ASSERT_DEVINS(pDevIns);
641 LogFlow(("pdmR0DevHlp_TMTimeVirtGet: caller='%p'/%d\n", pDevIns, pDevIns->iInstance));
642 return TMVirtualGet(pDevIns->Internal.s.pGVM);
643}
644
645
646/** @interface_method_impl{PDMDEVHLPR0,pfnTMTimeVirtGetFreq} */
647static DECLCALLBACK(uint64_t) pdmR0DevHlp_TMTimeVirtGetFreq(PPDMDEVINS pDevIns)
648{
649 PDMDEV_ASSERT_DEVINS(pDevIns);
650 LogFlow(("pdmR0DevHlp_TMTimeVirtGetFreq: caller='%p'/%d\n", pDevIns, pDevIns->iInstance));
651 return TMVirtualGetFreq(pDevIns->Internal.s.pGVM);
652}
653
654
655/** @interface_method_impl{PDMDEVHLPR0,pfnTMTimeVirtGetNano} */
656static DECLCALLBACK(uint64_t) pdmR0DevHlp_TMTimeVirtGetNano(PPDMDEVINS pDevIns)
657{
658 PDMDEV_ASSERT_DEVINS(pDevIns);
659 LogFlow(("pdmR0DevHlp_TMTimeVirtGetNano: caller='%p'/%d\n", pDevIns, pDevIns->iInstance));
660 return TMVirtualToNano(pDevIns->Internal.s.pGVM, TMVirtualGet(pDevIns->Internal.s.pGVM));
661}
662
663
664/** @interface_method_impl{PDMDEVHLPR0,pfnCritSectGetNop} */
665static DECLCALLBACK(PPDMCRITSECT) pdmR0DevHlp_CritSectGetNop(PPDMDEVINS pDevIns)
666{
667 PDMDEV_ASSERT_DEVINS(pDevIns);
668 PGVM pGVM = pDevIns->Internal.s.pGVM;
669
670 PPDMCRITSECT pCritSect = &pGVM->pdm.s.NopCritSect;
671 LogFlow(("pdmR0DevHlp_CritSectGetNop: caller='%s'/%d: return %p\n", pDevIns->pReg->szName, pDevIns->iInstance, pCritSect));
672 return pCritSect;
673}
674
675
676/** @interface_method_impl{PDMDEVHLPR0,pfnSetDeviceCritSect} */
677static DECLCALLBACK(int) pdmR0DevHlp_SetDeviceCritSect(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)
678{
679 /*
680 * Validate input.
681 *
682 * Note! We only allow the automatically created default critical section
683 * to be replaced by this API.
684 */
685 PDMDEV_ASSERT_DEVINS(pDevIns);
686 AssertPtrReturn(pCritSect, VERR_INVALID_POINTER);
687 LogFlow(("pdmR0DevHlp_SetDeviceCritSect: caller='%s'/%d: pCritSect=%p (%s)\n",
688 pDevIns->pReg->szName, pDevIns->iInstance, pCritSect, pCritSect->s.pszName));
689 AssertReturn(PDMCritSectIsInitialized(pCritSect), VERR_INVALID_PARAMETER);
690 PGVM pGVM = pDevIns->Internal.s.pGVM;
691 AssertReturn(pCritSect->s.pVMR0 == pGVM, VERR_INVALID_PARAMETER);
692
693 VM_ASSERT_EMT(pGVM);
694 VM_ASSERT_STATE_RETURN(pGVM, VMSTATE_CREATING, VERR_WRONG_ORDER);
695
696 /*
697 * Check that ring-3 has already done this, then effect the change.
698 */
699 AssertReturn(pDevIns->pDevInsForR3R0->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_CHANGED_CRITSECT, VERR_WRONG_ORDER);
700 pDevIns->pCritSectRoR0 = pCritSect;
701
702 LogFlow(("pdmR0DevHlp_SetDeviceCritSect: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, VINF_SUCCESS));
703 return VINF_SUCCESS;
704}
705
706
707/** @interface_method_impl{PDMDEVHLPR0,pfnCritSectEnter} */
708static DECLCALLBACK(int) pdmR0DevHlp_CritSectEnter(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, int rcBusy)
709{
710 PDMDEV_ASSERT_DEVINS(pDevIns);
711 RT_NOREF(pDevIns); /** @todo pass pDevIns->Internal.s.pGVM to the crit sect code. */
712 return PDMCritSectEnter(pCritSect, rcBusy);
713}
714
715
716/** @interface_method_impl{PDMDEVHLPR0,pfnCritSectEnterDebug} */
717static DECLCALLBACK(int) pdmR0DevHlp_CritSectEnterDebug(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)
718{
719 PDMDEV_ASSERT_DEVINS(pDevIns);
720 RT_NOREF(pDevIns); /** @todo pass pDevIns->Internal.s.pGVM to the crit sect code. */
721 return PDMCritSectEnterDebug(pCritSect, rcBusy, uId, RT_SRC_POS_ARGS);
722}
723
724
725/** @interface_method_impl{PDMDEVHLPR0,pfnCritSectTryEnter} */
726static DECLCALLBACK(int) pdmR0DevHlp_CritSectTryEnter(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)
727{
728 PDMDEV_ASSERT_DEVINS(pDevIns);
729 RT_NOREF(pDevIns); /** @todo pass pDevIns->Internal.s.pGVM to the crit sect code. */
730 return PDMCritSectTryEnter(pCritSect);
731}
732
733
734/** @interface_method_impl{PDMDEVHLPR0,pfnCritSectTryEnterDebug} */
735static DECLCALLBACK(int) pdmR0DevHlp_CritSectTryEnterDebug(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)
736{
737 PDMDEV_ASSERT_DEVINS(pDevIns);
738 RT_NOREF(pDevIns); /** @todo pass pDevIns->Internal.s.pGVM to the crit sect code. */
739 return PDMCritSectTryEnterDebug(pCritSect, uId, RT_SRC_POS_ARGS);
740}
741
742
743/** @interface_method_impl{PDMDEVHLPR0,pfnCritSectLeave} */
744static DECLCALLBACK(int) pdmR0DevHlp_CritSectLeave(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)
745{
746 PDMDEV_ASSERT_DEVINS(pDevIns);
747 RT_NOREF(pDevIns); /** @todo pass pDevIns->Internal.s.pGVM to the crit sect code. */
748 return PDMCritSectLeave(pCritSect);
749}
750
751
752/** @interface_method_impl{PDMDEVHLPR0,pfnCritSectIsOwner} */
753static DECLCALLBACK(bool) pdmR0DevHlp_CritSectIsOwner(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)
754{
755 PDMDEV_ASSERT_DEVINS(pDevIns);
756 RT_NOREF(pDevIns); /** @todo pass pDevIns->Internal.s.pGVM to the crit sect code. */
757 return PDMCritSectIsOwner(pCritSect);
758}
759
760
761/** @interface_method_impl{PDMDEVHLPR0,pfnCritSectIsInitialized} */
762static DECLCALLBACK(bool) pdmR0DevHlp_CritSectIsInitialized(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)
763{
764 PDMDEV_ASSERT_DEVINS(pDevIns);
765 RT_NOREF(pDevIns);
766 return PDMCritSectIsInitialized(pCritSect);
767}
768
769
770/** @interface_method_impl{PDMDEVHLPR0,pfnCritSectHasWaiters} */
771static DECLCALLBACK(bool) pdmR0DevHlp_CritSectHasWaiters(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)
772{
773 PDMDEV_ASSERT_DEVINS(pDevIns);
774 RT_NOREF(pDevIns);
775 return PDMCritSectHasWaiters(pCritSect);
776}
777
778
779/** @interface_method_impl{PDMDEVHLPR0,pfnCritSectGetRecursion} */
780static DECLCALLBACK(uint32_t) pdmR0DevHlp_CritSectGetRecursion(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)
781{
782 PDMDEV_ASSERT_DEVINS(pDevIns);
783 RT_NOREF(pDevIns);
784 return PDMCritSectGetRecursion(pCritSect);
785}
786
787
788/** @interface_method_impl{PDMDEVHLPR0,pfnDBGFTraceBuf} */
789static DECLCALLBACK(RTTRACEBUF) pdmR0DevHlp_DBGFTraceBuf(PPDMDEVINS pDevIns)
790{
791 PDMDEV_ASSERT_DEVINS(pDevIns);
792 RTTRACEBUF hTraceBuf = pDevIns->Internal.s.pGVM->hTraceBufR0;
793 LogFlow(("pdmR0DevHlp_DBGFTraceBuf: caller='%p'/%d: returns %p\n", pDevIns, pDevIns->iInstance, hTraceBuf));
794 return hTraceBuf;
795}
796
797
798/** @interface_method_impl{PDMDEVHLPR0,pfnPCIBusSetUpContext} */
799static DECLCALLBACK(int) pdmR0DevHlp_PCIBusSetUpContext(PPDMDEVINS pDevIns, PPDMPCIBUSREGR0 pPciBusReg, PCPDMPCIHLPR0 *ppPciHlp)
800{
801 PDMDEV_ASSERT_DEVINS(pDevIns);
802 LogFlow(("pdmR0DevHlp_PCIBusSetUpContext: caller='%p'/%d: pPciBusReg=%p{.u32Version=%#x, .iBus=%#u, .pfnSetIrq=%p, u32EnvVersion=%#x} ppPciHlp=%p\n",
803 pDevIns, pDevIns->iInstance, pPciBusReg, pPciBusReg->u32Version, pPciBusReg->iBus, pPciBusReg->pfnSetIrq,
804 pPciBusReg->u32EndVersion, ppPciHlp));
805 PGVM pGVM = pDevIns->Internal.s.pGVM;
806
807 /*
808 * Validate input.
809 */
810 AssertPtrReturn(pPciBusReg, VERR_INVALID_POINTER);
811 AssertLogRelMsgReturn(pPciBusReg->u32Version == PDM_PCIBUSREGCC_VERSION,
812 ("%#x vs %#x\n", pPciBusReg->u32Version, PDM_PCIBUSREGCC_VERSION), VERR_VERSION_MISMATCH);
813 AssertPtrReturn(pPciBusReg->pfnSetIrq, VERR_INVALID_POINTER);
814 AssertLogRelMsgReturn(pPciBusReg->u32EndVersion == PDM_PCIBUSREGCC_VERSION,
815 ("%#x vs %#x\n", pPciBusReg->u32EndVersion, PDM_PCIBUSREGCC_VERSION), VERR_VERSION_MISMATCH);
816
817 AssertPtrReturn(ppPciHlp, VERR_INVALID_POINTER);
818
819 VM_ASSERT_STATE_RETURN(pGVM, VMSTATE_CREATING, VERR_WRONG_ORDER);
820 VM_ASSERT_EMT0_RETURN(pGVM, VERR_VM_THREAD_NOT_EMT);
821
822 /* Check the shared bus data (registered earlier from ring-3): */
823 uint32_t iBus = pPciBusReg->iBus;
824 ASMCompilerBarrier();
825 AssertLogRelMsgReturn(iBus < RT_ELEMENTS(pGVM->pdm.s.aPciBuses), ("iBus=%#x\n", iBus), VERR_OUT_OF_RANGE);
826 PPDMPCIBUS pPciBusShared = &pGVM->pdm.s.aPciBuses[iBus];
827 AssertLogRelMsgReturn(pPciBusShared->iBus == iBus, ("%u vs %u\n", pPciBusShared->iBus, iBus), VERR_INVALID_PARAMETER);
828 AssertLogRelMsgReturn(pPciBusShared->pDevInsR3 == pDevIns->pDevInsForR3,
829 ("%p vs %p (iBus=%u)\n", pPciBusShared->pDevInsR3, pDevIns->pDevInsForR3, iBus), VERR_NOT_OWNER);
830
831 /* Check that the bus isn't already registered in ring-0: */
832 AssertCompile(RT_ELEMENTS(pGVM->pdm.s.aPciBuses) == RT_ELEMENTS(pGVM->pdmr0.s.aPciBuses));
833 PPDMPCIBUSR0 pPciBusR0 = &pGVM->pdmr0.s.aPciBuses[iBus];
834 AssertLogRelMsgReturn(pPciBusR0->pDevInsR0 == NULL,
835 ("%p (caller pDevIns=%p, iBus=%u)\n", pPciBusR0->pDevInsR0, pDevIns, iBus),
836 VERR_ALREADY_EXISTS);
837
838 /*
839 * Do the registering.
840 */
841 pPciBusR0->iBus = iBus;
842 pPciBusR0->uPadding0 = 0xbeefbeef;
843 pPciBusR0->pfnSetIrqR0 = pPciBusReg->pfnSetIrq;
844 pPciBusR0->pDevInsR0 = pDevIns;
845
846 *ppPciHlp = &g_pdmR0PciHlp;
847
848 LogFlow(("pdmR0DevHlp_PCIBusSetUpContext: caller='%p'/%d: returns VINF_SUCCESS\n", pDevIns, pDevIns->iInstance));
849 return VINF_SUCCESS;
850}
851
852
853/**
854 * The Ring-0 Device Helper Callbacks.
855 */
856extern DECLEXPORT(const PDMDEVHLPR0) g_pdmR0DevHlp =
857{
858 PDM_DEVHLPR0_VERSION,
859 pdmR0DevHlp_IoPortSetUpContextEx,
860 pdmR0DevHlp_MmioSetUpContextEx,
861 pdmR0DevHlp_PCIPhysRead,
862 pdmR0DevHlp_PCIPhysWrite,
863 pdmR0DevHlp_PCISetIrq,
864 pdmR0DevHlp_ISASetIrq,
865 pdmR0DevHlp_IoApicSendMsi,
866 pdmR0DevHlp_PhysRead,
867 pdmR0DevHlp_PhysWrite,
868 pdmR0DevHlp_A20IsEnabled,
869 pdmR0DevHlp_VMState,
870 pdmR0DevHlp_VMSetError,
871 pdmR0DevHlp_VMSetErrorV,
872 pdmR0DevHlp_VMSetRuntimeError,
873 pdmR0DevHlp_VMSetRuntimeErrorV,
874 pdmR0DevHlp_GetVM,
875 pdmR0DevHlp_GetVMCPU,
876 pdmR0DevHlp_GetCurrentCpuId,
877 pdmR0DevHlp_TimerToPtr,
878 pdmR0DevHlp_TimerFromMicro,
879 pdmR0DevHlp_TimerFromMilli,
880 pdmR0DevHlp_TimerFromNano,
881 pdmR0DevHlp_TimerGet,
882 pdmR0DevHlp_TimerGetFreq,
883 pdmR0DevHlp_TimerGetNano,
884 pdmR0DevHlp_TimerIsActive,
885 pdmR0DevHlp_TimerIsLockOwner,
886 pdmR0DevHlp_TimerLock,
887 pdmR0DevHlp_TimerSet,
888 pdmR0DevHlp_TimerSetFrequencyHint,
889 pdmR0DevHlp_TimerSetMicro,
890 pdmR0DevHlp_TimerSetMillies,
891 pdmR0DevHlp_TimerSetNano,
892 pdmR0DevHlp_TimerSetRelative,
893 pdmR0DevHlp_TimerStop,
894 pdmR0DevHlp_TimerUnlock,
895 pdmR0DevHlp_TMTimeVirtGet,
896 pdmR0DevHlp_TMTimeVirtGetFreq,
897 pdmR0DevHlp_TMTimeVirtGetNano,
898 pdmR0DevHlp_CritSectGetNop,
899 pdmR0DevHlp_SetDeviceCritSect,
900 pdmR0DevHlp_CritSectEnter,
901 pdmR0DevHlp_CritSectEnterDebug,
902 pdmR0DevHlp_CritSectTryEnter,
903 pdmR0DevHlp_CritSectTryEnterDebug,
904 pdmR0DevHlp_CritSectLeave,
905 pdmR0DevHlp_CritSectIsOwner,
906 pdmR0DevHlp_CritSectIsInitialized,
907 pdmR0DevHlp_CritSectHasWaiters,
908 pdmR0DevHlp_CritSectGetRecursion,
909 pdmR0DevHlp_DBGFTraceBuf,
910 pdmR0DevHlp_PCIBusSetUpContext,
911 NULL /*pfnReserved1*/,
912 NULL /*pfnReserved2*/,
913 NULL /*pfnReserved3*/,
914 NULL /*pfnReserved4*/,
915 NULL /*pfnReserved5*/,
916 NULL /*pfnReserved6*/,
917 NULL /*pfnReserved7*/,
918 NULL /*pfnReserved8*/,
919 NULL /*pfnReserved9*/,
920 NULL /*pfnReserved10*/,
921 PDM_DEVHLPR0_VERSION
922};
923
924/** @} */
925
926
927
928
929/** @name PIC Ring-0 Helpers
930 * @{
931 */
932
933/** @interface_method_impl{PDMPICHLPR0,pfnSetInterruptFF} */
934static DECLCALLBACK(void) pdmR0PicHlp_SetInterruptFF(PPDMDEVINS pDevIns)
935{
936 PDMDEV_ASSERT_DEVINS(pDevIns);
937 PGVM pGVM = (PGVM)pDevIns->Internal.s.pGVM;
938 PVMCPUCC pVCpu = &pGVM->aCpus[0]; /* for PIC we always deliver to CPU 0, MP use APIC */
939 /** @todo r=ramshankar: Propagating rcRZ and make all callers handle it? */
940 APICLocalInterrupt(pVCpu, 0 /* u8Pin */, 1 /* u8Level */, VINF_SUCCESS /* rcRZ */);
941}
942
943
944/** @interface_method_impl{PDMPICHLPR0,pfnClearInterruptFF} */
945static DECLCALLBACK(void) pdmR0PicHlp_ClearInterruptFF(PPDMDEVINS pDevIns)
946{
947 PDMDEV_ASSERT_DEVINS(pDevIns);
948 PGVM pGVM = (PGVM)pDevIns->Internal.s.pGVM;
949 PVMCPUCC pVCpu = &pGVM->aCpus[0]; /* for PIC we always deliver to CPU 0, MP use APIC */
950 /** @todo r=ramshankar: Propagating rcRZ and make all callers handle it? */
951 APICLocalInterrupt(pVCpu, 0 /* u8Pin */, 0 /* u8Level */, VINF_SUCCESS /* rcRZ */);
952}
953
954
955/** @interface_method_impl{PDMPICHLPR0,pfnLock} */
956static DECLCALLBACK(int) pdmR0PicHlp_Lock(PPDMDEVINS pDevIns, int rc)
957{
958 PDMDEV_ASSERT_DEVINS(pDevIns);
959 return pdmLockEx(pDevIns->Internal.s.pGVM, rc);
960}
961
962
963/** @interface_method_impl{PDMPICHLPR0,pfnUnlock} */
964static DECLCALLBACK(void) pdmR0PicHlp_Unlock(PPDMDEVINS pDevIns)
965{
966 PDMDEV_ASSERT_DEVINS(pDevIns);
967 pdmUnlock(pDevIns->Internal.s.pGVM);
968}
969
970
971/**
972 * The Ring-0 PIC Helper Callbacks.
973 */
974extern DECLEXPORT(const PDMPICHLPR0) g_pdmR0PicHlp =
975{
976 PDM_PICHLPR0_VERSION,
977 pdmR0PicHlp_SetInterruptFF,
978 pdmR0PicHlp_ClearInterruptFF,
979 pdmR0PicHlp_Lock,
980 pdmR0PicHlp_Unlock,
981 PDM_PICHLPR0_VERSION
982};
983
984/** @} */
985
986
987/** @name I/O APIC Ring-0 Helpers
988 * @{
989 */
990
991/** @interface_method_impl{PDMIOAPICHLPR0,pfnApicBusDeliver} */
992static DECLCALLBACK(int) pdmR0IoApicHlp_ApicBusDeliver(PPDMDEVINS pDevIns, uint8_t u8Dest, uint8_t u8DestMode,
993 uint8_t u8DeliveryMode, uint8_t uVector, uint8_t u8Polarity,
994 uint8_t u8TriggerMode, uint32_t uTagSrc)
995{
996 PDMDEV_ASSERT_DEVINS(pDevIns);
997 PGVM pGVM = pDevIns->Internal.s.pGVM;
998 LogFlow(("pdmR0IoApicHlp_ApicBusDeliver: caller=%p/%d: u8Dest=%RX8 u8DestMode=%RX8 u8DeliveryMode=%RX8 uVector=%RX8 u8Polarity=%RX8 u8TriggerMode=%RX8 uTagSrc=%#x\n",
999 pDevIns, pDevIns->iInstance, u8Dest, u8DestMode, u8DeliveryMode, uVector, u8Polarity, u8TriggerMode, uTagSrc));
1000 return APICBusDeliver(pGVM, u8Dest, u8DestMode, u8DeliveryMode, uVector, u8Polarity, u8TriggerMode, uTagSrc);
1001}
1002
1003
1004/** @interface_method_impl{PDMIOAPICHLPR0,pfnLock} */
1005static DECLCALLBACK(int) pdmR0IoApicHlp_Lock(PPDMDEVINS pDevIns, int rc)
1006{
1007 PDMDEV_ASSERT_DEVINS(pDevIns);
1008 return pdmLockEx(pDevIns->Internal.s.pGVM, rc);
1009}
1010
1011
1012/** @interface_method_impl{PDMIOAPICHLPR0,pfnUnlock} */
1013static DECLCALLBACK(void) pdmR0IoApicHlp_Unlock(PPDMDEVINS pDevIns)
1014{
1015 PDMDEV_ASSERT_DEVINS(pDevIns);
1016 pdmUnlock(pDevIns->Internal.s.pGVM);
1017}
1018
1019
1020/**
1021 * The Ring-0 I/O APIC Helper Callbacks.
1022 */
1023extern DECLEXPORT(const PDMIOAPICHLPR0) g_pdmR0IoApicHlp =
1024{
1025 PDM_IOAPICHLPR0_VERSION,
1026 pdmR0IoApicHlp_ApicBusDeliver,
1027 pdmR0IoApicHlp_Lock,
1028 pdmR0IoApicHlp_Unlock,
1029 PDM_IOAPICHLPR0_VERSION
1030};
1031
1032/** @} */
1033
1034
1035
1036
1037/** @name PCI Bus Ring-0 Helpers
1038 * @{
1039 */
1040
1041/** @interface_method_impl{PDMPCIHLPR0,pfnIsaSetIrq} */
1042static DECLCALLBACK(void) pdmR0PciHlp_IsaSetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t uTagSrc)
1043{
1044 PDMDEV_ASSERT_DEVINS(pDevIns);
1045 Log4(("pdmR0PciHlp_IsaSetIrq: iIrq=%d iLevel=%d uTagSrc=%#x\n", iIrq, iLevel, uTagSrc));
1046 PGVM pGVM = pDevIns->Internal.s.pGVM;
1047
1048 pdmLock(pGVM);
1049 pdmR0IsaSetIrq(pGVM, iIrq, iLevel, uTagSrc);
1050 pdmUnlock(pGVM);
1051}
1052
1053
1054/** @interface_method_impl{PDMPCIHLPR0,pfnIoApicSetIrq} */
1055static DECLCALLBACK(void) pdmR0PciHlp_IoApicSetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t uTagSrc)
1056{
1057 PDMDEV_ASSERT_DEVINS(pDevIns);
1058 Log4(("pdmR0PciHlp_IoApicSetIrq: iIrq=%d iLevel=%d uTagSrc=%#x\n", iIrq, iLevel, uTagSrc));
1059 PGVM pGVM = pDevIns->Internal.s.pGVM;
1060
1061 if (pGVM->pdm.s.IoApic.pDevInsR0)
1062 pGVM->pdm.s.IoApic.pfnSetIrqR0(pGVM->pdm.s.IoApic.pDevInsR0, iIrq, iLevel, uTagSrc);
1063 else if (pGVM->pdm.s.IoApic.pDevInsR3)
1064 {
1065 /* queue for ring-3 execution. */
1066 PPDMDEVHLPTASK pTask = (PPDMDEVHLPTASK)PDMQueueAlloc(pGVM->pdm.s.pDevHlpQueueR0);
1067 if (pTask)
1068 {
1069 pTask->enmOp = PDMDEVHLPTASKOP_IOAPIC_SET_IRQ;
1070 pTask->pDevInsR3 = NIL_RTR3PTR; /* not required */
1071 pTask->u.IoApicSetIRQ.iIrq = iIrq;
1072 pTask->u.IoApicSetIRQ.iLevel = iLevel;
1073 pTask->u.IoApicSetIRQ.uTagSrc = uTagSrc;
1074
1075 PDMQueueInsertEx(pGVM->pdm.s.pDevHlpQueueR0, &pTask->Core, 0);
1076 }
1077 else
1078 AssertMsgFailed(("We're out of devhlp queue items!!!\n"));
1079 }
1080}
1081
1082
1083/** @interface_method_impl{PDMPCIHLPR0,pfnIoApicSendMsi} */
1084static DECLCALLBACK(void) pdmR0PciHlp_IoApicSendMsi(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint32_t uValue, uint32_t uTagSrc)
1085{
1086 PDMDEV_ASSERT_DEVINS(pDevIns);
1087 Log4(("pdmR0PciHlp_IoApicSendMsi: GCPhys=%p uValue=%d uTagSrc=%#x\n", GCPhys, uValue, uTagSrc));
1088 PGVM pGVM = pDevIns->Internal.s.pGVM;
1089 if (pGVM->pdm.s.IoApic.pDevInsR0)
1090 pGVM->pdm.s.IoApic.pfnSendMsiR0(pGVM->pdm.s.IoApic.pDevInsR0, GCPhys, uValue, uTagSrc);
1091 else
1092 AssertFatalMsgFailed(("Lazy bastards!"));
1093}
1094
1095
1096/** @interface_method_impl{PDMPCIHLPR0,pfnLock} */
1097static DECLCALLBACK(int) pdmR0PciHlp_Lock(PPDMDEVINS pDevIns, int rc)
1098{
1099 PDMDEV_ASSERT_DEVINS(pDevIns);
1100 return pdmLockEx(pDevIns->Internal.s.pGVM, rc);
1101}
1102
1103
1104/** @interface_method_impl{PDMPCIHLPR0,pfnUnlock} */
1105static DECLCALLBACK(void) pdmR0PciHlp_Unlock(PPDMDEVINS pDevIns)
1106{
1107 PDMDEV_ASSERT_DEVINS(pDevIns);
1108 pdmUnlock(pDevIns->Internal.s.pGVM);
1109}
1110
1111
1112/**
1113 * The Ring-0 PCI Bus Helper Callbacks.
1114 */
1115extern DECLEXPORT(const PDMPCIHLPR0) g_pdmR0PciHlp =
1116{
1117 PDM_PCIHLPR0_VERSION,
1118 pdmR0PciHlp_IsaSetIrq,
1119 pdmR0PciHlp_IoApicSetIrq,
1120 pdmR0PciHlp_IoApicSendMsi,
1121 pdmR0PciHlp_Lock,
1122 pdmR0PciHlp_Unlock,
1123 PDM_PCIHLPR0_VERSION, /* the end */
1124};
1125
1126/** @} */
1127
1128
1129
1130
1131/** @name HPET Ring-0 Helpers
1132 * @{
1133 */
1134/* none */
1135
1136/**
1137 * The Ring-0 HPET Helper Callbacks.
1138 */
1139extern DECLEXPORT(const PDMHPETHLPR0) g_pdmR0HpetHlp =
1140{
1141 PDM_HPETHLPR0_VERSION,
1142 PDM_HPETHLPR0_VERSION, /* the end */
1143};
1144
1145/** @} */
1146
1147
1148/** @name Raw PCI Ring-0 Helpers
1149 * @{
1150 */
1151/* none */
1152
1153/**
1154 * The Ring-0 PCI raw Helper Callbacks.
1155 */
1156extern DECLEXPORT(const PDMPCIRAWHLPR0) g_pdmR0PciRawHlp =
1157{
1158 PDM_PCIRAWHLPR0_VERSION,
1159 PDM_PCIRAWHLPR0_VERSION, /* the end */
1160};
1161
1162/** @} */
1163
1164
1165/** @name Ring-0 Context Driver Helpers
1166 * @{
1167 */
1168
1169/** @interface_method_impl{PDMDRVHLPR0,pfnVMSetError} */
1170static DECLCALLBACK(int) pdmR0DrvHlp_VMSetError(PPDMDRVINS pDrvIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...)
1171{
1172 PDMDRV_ASSERT_DRVINS(pDrvIns);
1173 va_list args;
1174 va_start(args, pszFormat);
1175 int rc2 = VMSetErrorV(pDrvIns->Internal.s.pVMR0, rc, RT_SRC_POS_ARGS, pszFormat, args); Assert(rc2 == rc); NOREF(rc2);
1176 va_end(args);
1177 return rc;
1178}
1179
1180
1181/** @interface_method_impl{PDMDRVHLPR0,pfnVMSetErrorV} */
1182static DECLCALLBACK(int) pdmR0DrvHlp_VMSetErrorV(PPDMDRVINS pDrvIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
1183{
1184 PDMDRV_ASSERT_DRVINS(pDrvIns);
1185 int rc2 = VMSetErrorV(pDrvIns->Internal.s.pVMR0, rc, RT_SRC_POS_ARGS, pszFormat, va); Assert(rc2 == rc); NOREF(rc2);
1186 return rc;
1187}
1188
1189
1190/** @interface_method_impl{PDMDRVHLPR0,pfnVMSetRuntimeError} */
1191static DECLCALLBACK(int) pdmR0DrvHlp_VMSetRuntimeError(PPDMDRVINS pDrvIns, uint32_t fFlags, const char *pszErrorId,
1192 const char *pszFormat, ...)
1193{
1194 PDMDRV_ASSERT_DRVINS(pDrvIns);
1195 va_list va;
1196 va_start(va, pszFormat);
1197 int rc = VMSetRuntimeErrorV(pDrvIns->Internal.s.pVMR0, fFlags, pszErrorId, pszFormat, va);
1198 va_end(va);
1199 return rc;
1200}
1201
1202
1203/** @interface_method_impl{PDMDRVHLPR0,pfnVMSetRuntimeErrorV} */
1204static DECLCALLBACK(int) pdmR0DrvHlp_VMSetRuntimeErrorV(PPDMDRVINS pDrvIns, uint32_t fFlags, const char *pszErrorId,
1205 const char *pszFormat, va_list va)
1206{
1207 PDMDRV_ASSERT_DRVINS(pDrvIns);
1208 int rc = VMSetRuntimeErrorV(pDrvIns->Internal.s.pVMR0, fFlags, pszErrorId, pszFormat, va);
1209 return rc;
1210}
1211
1212
1213/** @interface_method_impl{PDMDRVHLPR0,pfnAssertEMT} */
1214static DECLCALLBACK(bool) pdmR0DrvHlp_AssertEMT(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)
1215{
1216 PDMDRV_ASSERT_DRVINS(pDrvIns);
1217 if (VM_IS_EMT(pDrvIns->Internal.s.pVMR0))
1218 return true;
1219
1220 RTAssertMsg1Weak("AssertEMT", iLine, pszFile, pszFunction);
1221 RTAssertPanic();
1222 return false;
1223}
1224
1225
1226/** @interface_method_impl{PDMDRVHLPR0,pfnAssertOther} */
1227static DECLCALLBACK(bool) pdmR0DrvHlp_AssertOther(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)
1228{
1229 PDMDRV_ASSERT_DRVINS(pDrvIns);
1230 if (!VM_IS_EMT(pDrvIns->Internal.s.pVMR0))
1231 return true;
1232
1233 RTAssertMsg1Weak("AssertOther", iLine, pszFile, pszFunction);
1234 RTAssertPanic();
1235 return false;
1236}
1237
1238
1239/**
1240 * The Ring-0 Context Driver Helper Callbacks.
1241 */
1242extern DECLEXPORT(const PDMDRVHLPR0) g_pdmR0DrvHlp =
1243{
1244 PDM_DRVHLPRC_VERSION,
1245 pdmR0DrvHlp_VMSetError,
1246 pdmR0DrvHlp_VMSetErrorV,
1247 pdmR0DrvHlp_VMSetRuntimeError,
1248 pdmR0DrvHlp_VMSetRuntimeErrorV,
1249 pdmR0DrvHlp_AssertEMT,
1250 pdmR0DrvHlp_AssertOther,
1251 PDM_DRVHLPRC_VERSION
1252};
1253
1254/** @} */
1255
1256
1257
1258
1259/**
1260 * Sets an irq on the PIC and I/O APIC.
1261 *
1262 * @returns true if delivered, false if postponed.
1263 * @param pGVM The global (ring-0) VM structure.
1264 * @param iIrq The irq.
1265 * @param iLevel The new level.
1266 * @param uTagSrc The IRQ tag and source.
1267 *
1268 * @remarks The caller holds the PDM lock.
1269 */
1270static bool pdmR0IsaSetIrq(PGVM pGVM, int iIrq, int iLevel, uint32_t uTagSrc)
1271{
1272 if (RT_LIKELY( ( pGVM->pdm.s.IoApic.pDevInsR0
1273 || !pGVM->pdm.s.IoApic.pDevInsR3)
1274 && ( pGVM->pdm.s.Pic.pDevInsR0
1275 || !pGVM->pdm.s.Pic.pDevInsR3)))
1276 {
1277 if (pGVM->pdm.s.Pic.pDevInsR0)
1278 pGVM->pdm.s.Pic.pfnSetIrqR0(pGVM->pdm.s.Pic.pDevInsR0, iIrq, iLevel, uTagSrc);
1279 if (pGVM->pdm.s.IoApic.pDevInsR0)
1280 pGVM->pdm.s.IoApic.pfnSetIrqR0(pGVM->pdm.s.IoApic.pDevInsR0, iIrq, iLevel, uTagSrc);
1281 return true;
1282 }
1283
1284 /* queue for ring-3 execution. */
1285 PPDMDEVHLPTASK pTask = (PPDMDEVHLPTASK)PDMQueueAlloc(pGVM->pdm.s.pDevHlpQueueR0);
1286 AssertReturn(pTask, false);
1287
1288 pTask->enmOp = PDMDEVHLPTASKOP_ISA_SET_IRQ;
1289 pTask->pDevInsR3 = NIL_RTR3PTR; /* not required */
1290 pTask->u.IsaSetIRQ.iIrq = iIrq;
1291 pTask->u.IsaSetIRQ.iLevel = iLevel;
1292 pTask->u.IsaSetIRQ.uTagSrc = uTagSrc;
1293
1294 PDMQueueInsertEx(pGVM->pdm.s.pDevHlpQueueR0, &pTask->Core, 0);
1295 return false;
1296}
1297
1298
1299/**
1300 * PDMDevHlpCallR0 helper.
1301 *
1302 * @returns See PFNPDMDEVREQHANDLERR0.
1303 * @param pGVM The global (ring-0) VM structure. (For validation.)
1304 * @param pReq Pointer to the request buffer.
1305 */
1306VMMR0_INT_DECL(int) PDMR0DeviceCallReqHandler(PGVM pGVM, PPDMDEVICECALLREQHANDLERREQ pReq)
1307{
1308 /*
1309 * Validate input and make the call.
1310 */
1311 int rc = GVMMR0ValidateGVM(pGVM);
1312 if (RT_SUCCESS(rc))
1313 {
1314 AssertPtrReturn(pReq, VERR_INVALID_POINTER);
1315 AssertMsgReturn(pReq->Hdr.cbReq == sizeof(*pReq), ("%#x != %#x\n", pReq->Hdr.cbReq, sizeof(*pReq)), VERR_INVALID_PARAMETER);
1316
1317 PPDMDEVINS pDevIns = pReq->pDevInsR0;
1318 AssertPtrReturn(pDevIns, VERR_INVALID_POINTER);
1319 AssertReturn(pDevIns->Internal.s.pGVM == pGVM, VERR_INVALID_PARAMETER);
1320
1321 PFNPDMDEVREQHANDLERR0 pfnReqHandlerR0 = pReq->pfnReqHandlerR0;
1322 AssertPtrReturn(pfnReqHandlerR0, VERR_INVALID_POINTER);
1323
1324 rc = pfnReqHandlerR0(pDevIns, pReq->uOperation, pReq->u64Arg);
1325 }
1326 return rc;
1327}
1328
1329
1330/**
1331 * Worker for PDMR0DeviceCreate that does the actual instantiation.
1332 *
1333 * Allocates a memory object and divides it up as follows:
1334 * @verbatim
1335 -----------------------------------
1336 ring-0 devins
1337 -----------------------------------
1338 ring-0 instance data
1339 -----------------------------------
1340 ring-0 PCI device data (optional) ?
1341 -----------------------------------
1342 page alignment padding
1343 -----------------------------------
1344 ring-3 devins
1345 -----------------------------------
1346 ring-3 instance data
1347 -----------------------------------
1348 ring-3 PCI device data (optional) ?
1349 -----------------------------------
1350 [page alignment padding ] -
1351 [-----------------------------------] \
1352 [raw-mode devins ] \
1353 [-----------------------------------] - Optional, only when raw-mode is enabled.
1354 [raw-mode instance data ] /
1355 [-----------------------------------] /
1356 [raw-mode PCI device data (optional)] -
1357 -----------------------------------
1358 shared instance data
1359 -----------------------------------
1360 default crit section
1361 -----------------------------------
1362 shared PCI device data (optional)
1363 -----------------------------------
1364 @endverbatim
1365 *
1366 * @returns VBox status code.
1367 * @param pGVM The global (ring-0) VM structure.
1368 * @param pDevReg The device registration structure.
1369 * @param iInstance The device instance number.
1370 * @param cbInstanceR3 The size of the ring-3 instance data.
1371 * @param cbInstanceRC The size of the raw-mode instance data.
1372 * @param hMod The module implementing the device. On success, the
1373 * @param RCPtrMapping The raw-mode context mapping address, NIL_RTGCPTR if
1374 * not to include raw-mode.
1375 * @param ppDevInsR3 Where to return the ring-3 device instance address.
1376 * @thread EMT(0)
1377 */
1378static int pdmR0DeviceCreateWorker(PGVM pGVM, PCPDMDEVREGR0 pDevReg, uint32_t iInstance, uint32_t cbInstanceR3,
1379 uint32_t cbInstanceRC, RTRGPTR RCPtrMapping, void *hMod, PPDMDEVINSR3 *ppDevInsR3)
1380{
1381 /*
1382 * Check that the instance number isn't a duplicate.
1383 */
1384 for (size_t i = 0; i < pGVM->pdmr0.s.cDevInstances; i++)
1385 {
1386 PPDMDEVINS pCur = pGVM->pdmr0.s.apDevInstances[i];
1387 AssertLogRelReturn(!pCur || pCur->pReg != pDevReg || pCur->iInstance != iInstance, VERR_DUPLICATE);
1388 }
1389
1390 /*
1391 * Figure out how much memory we need and allocate it.
1392 */
1393 uint32_t const cbRing0 = RT_ALIGN_32(RT_UOFFSETOF(PDMDEVINSR0, achInstanceData) + pDevReg->cbInstanceCC, PAGE_SIZE);
1394 uint32_t const cbRing3 = RT_ALIGN_32(RT_UOFFSETOF(PDMDEVINSR3, achInstanceData) + cbInstanceR3,
1395 RCPtrMapping != NIL_RTRGPTR ? PAGE_SIZE : 64);
1396 uint32_t const cbRC = RCPtrMapping != NIL_RTRGPTR ? 0
1397 : RT_ALIGN_32(RT_UOFFSETOF(PDMDEVINSRC, achInstanceData) + cbInstanceRC, 64);
1398 uint32_t const cbShared = RT_ALIGN_32(pDevReg->cbInstanceShared, 64);
1399 uint32_t const cbTotal = RT_ALIGN_32(cbRing0 + cbRing3 + cbRC + cbShared + sizeof(PDMCRITSECT), PAGE_SIZE);
1400
1401 RTR0MEMOBJ hMemObj;
1402 int rc = RTR0MemObjAllocPage(&hMemObj, cbTotal, false /*fExecutable*/);
1403 if (RT_FAILURE(rc))
1404 return rc;
1405 RT_BZERO(RTR0MemObjAddress(hMemObj), cbTotal);
1406
1407 /* Map it. */
1408 RTR0MEMOBJ hMapObj;
1409 rc = RTR0MemObjMapUserEx(&hMapObj, hMemObj, (RTR3PTR)-1, 0, RTMEM_PROT_READ | RTMEM_PROT_WRITE, RTR0ProcHandleSelf(),
1410 cbRing0, cbTotal - cbRing0);
1411 if (RT_SUCCESS(rc))
1412 {
1413 PPDMDEVINSR0 pDevIns = (PPDMDEVINSR0)RTR0MemObjAddress(hMemObj);
1414 struct PDMDEVINSR3 *pDevInsR3 = (struct PDMDEVINSR3 *)((uint8_t *)pDevIns + cbRing0);
1415
1416 /*
1417 * Initialize the ring-0 instance.
1418 */
1419 pDevIns->u32Version = PDM_DEVINSR0_VERSION;
1420 pDevIns->iInstance = iInstance;
1421 pDevIns->pHlpR0 = &g_pdmR0DevHlp;
1422 pDevIns->pvInstanceDataR0 = (uint8_t *)pDevIns + cbRing0 + cbRing3 + cbRC;
1423 pDevIns->pvInstanceDataForR0 = &pDevIns->achInstanceData[0];
1424 pDevIns->pCritSectRoR0 = (PPDMCRITSECT)( (uint8_t *)pDevIns->pvInstanceDataR0
1425 + RT_ALIGN_32(pDevReg->cbInstanceShared, 64));
1426 pDevIns->pReg = pDevReg;
1427 pDevIns->pDevInsForR3 = RTR0MemObjAddressR3(hMapObj);
1428 pDevIns->pDevInsForR3R0 = pDevInsR3;
1429 pDevIns->pvInstanceDataForR3R0 = &pDevInsR3->achInstanceData[0];
1430 pDevIns->Internal.s.pGVM = pGVM;
1431 pDevIns->Internal.s.pRegR0 = pDevReg;
1432 pDevIns->Internal.s.hMod = hMod;
1433 pDevIns->Internal.s.hMemObj = hMemObj;
1434 pDevIns->Internal.s.hMapObj = hMapObj;
1435 pDevIns->Internal.s.pInsR3R0 = pDevInsR3;
1436 pDevIns->Internal.s.pIntR3R0 = &pDevInsR3->Internal.s;
1437
1438 /*
1439 * Initialize the ring-3 instance data as much as we can.
1440 */
1441 pDevInsR3->u32Version = PDM_DEVINSR3_VERSION;
1442 pDevInsR3->iInstance = iInstance;
1443 pDevInsR3->cbRing3 = cbTotal - cbRing0;
1444 pDevInsR3->fR0Enabled = true;
1445 pDevInsR3->fRCEnabled = RCPtrMapping != NIL_RTRGPTR;
1446 pDevInsR3->pvInstanceDataR3 = pDevIns->pDevInsForR3 + cbRing3 + cbRC;
1447 pDevInsR3->pvInstanceDataForR3 = pDevIns->pDevInsForR3 + RT_UOFFSETOF(PDMDEVINSR3, achInstanceData);
1448 pDevInsR3->pCritSectRoR3 = pDevIns->pDevInsForR3 + cbRing3 + cbRC + cbShared;
1449 pDevInsR3->pDevInsR0RemoveMe = pDevIns;
1450 pDevInsR3->pvInstanceDataR0 = pDevIns->pvInstanceDataR0;
1451 pDevInsR3->pvInstanceDataRC = RCPtrMapping == NIL_RTRGPTR
1452 ? NIL_RTRGPTR : pDevIns->pDevInsForRC + RT_UOFFSETOF(PDMDEVINSRC, achInstanceData);
1453 pDevInsR3->pDevInsForRC = pDevIns->pDevInsForRC;
1454 pDevInsR3->pDevInsForRCR3 = pDevIns->pDevInsForR3 + cbRing3;
1455 pDevInsR3->pDevInsForRCR3 = pDevInsR3->pDevInsForRCR3 + RT_UOFFSETOF(PDMDEVINSRC, achInstanceData);
1456
1457 pDevInsR3->Internal.s.pVMR3 = pGVM->pVMR3;
1458 pDevInsR3->Internal.s.fIntFlags = RCPtrMapping == NIL_RTRGPTR ? PDMDEVINSINT_FLAGS_R0_ENABLED
1459 : PDMDEVINSINT_FLAGS_R0_ENABLED | PDMDEVINSINT_FLAGS_RC_ENABLED;
1460
1461 /*
1462 * Initialize the raw-mode instance data as much as possible.
1463 */
1464 if (RCPtrMapping != NIL_RTRGPTR)
1465 {
1466 struct PDMDEVINSRC *pDevInsRC = RCPtrMapping == NIL_RTRGPTR ? NULL
1467 : (struct PDMDEVINSRC *)((uint8_t *)pDevIns + cbRing0 + cbRing3);
1468
1469 pDevIns->pDevInsForRC = RCPtrMapping;
1470 pDevIns->pDevInsForRCR0 = pDevInsRC;
1471 pDevIns->pvInstanceDataForRCR0 = &pDevInsRC->achInstanceData[0];
1472
1473 pDevInsRC->u32Version = PDM_DEVINSRC_VERSION;
1474 pDevInsRC->iInstance = iInstance;
1475 pDevInsRC->pvInstanceDataRC = pDevIns->pDevInsForRC + cbRC;
1476 pDevInsRC->pvInstanceDataForRC = pDevIns->pDevInsForRC + RT_UOFFSETOF(PDMDEVINSRC, achInstanceData);
1477 pDevInsRC->pCritSectRoRC = pDevIns->pDevInsForRC + cbRC + cbShared;
1478 pDevInsRC->Internal.s.pVMRC = pGVM->pVMRC;
1479 }
1480
1481 /*
1482 * Add to the device instance array and set its handle value.
1483 */
1484 AssertCompile(sizeof(pGVM->pdmr0.padding) == sizeof(pGVM->pdmr0));
1485 uint32_t idxR0Device = pGVM->pdmr0.s.cDevInstances;
1486 if (idxR0Device < RT_ELEMENTS(pGVM->pdmr0.s.apDevInstances))
1487 {
1488 pGVM->pdmr0.s.apDevInstances[idxR0Device] = pDevIns;
1489 pGVM->pdmr0.s.cDevInstances = idxR0Device + 1;
1490 pDevIns->Internal.s.idxR0Device = idxR0Device;
1491 pDevInsR3->Internal.s.idxR0Device = idxR0Device;
1492
1493 /*
1494 * Call the early constructor if present.
1495 */
1496 if (pDevReg->pfnEarlyConstruct)
1497 rc = pDevReg->pfnEarlyConstruct(pDevIns);
1498 if (RT_SUCCESS(rc))
1499 {
1500 /*
1501 * We're done.
1502 */
1503 *ppDevInsR3 = RTR0MemObjAddressR3(hMapObj);
1504 return rc;
1505 }
1506
1507 /*
1508 * Bail out.
1509 */
1510 if (pDevIns->pReg->pfnFinalDestruct)
1511 pDevIns->pReg->pfnFinalDestruct(pDevIns);
1512
1513 pGVM->pdmr0.s.apDevInstances[idxR0Device] = NULL;
1514 Assert(pGVM->pdmr0.s.cDevInstances == idxR0Device + 1);
1515 pGVM->pdmr0.s.cDevInstances = idxR0Device;
1516 }
1517
1518 RTR0MemObjFree(hMapObj, true);
1519 }
1520 RTR0MemObjFree(hMemObj, true);
1521 return rc;
1522}
1523
1524
1525/**
1526 * Used by ring-3 PDM to create a device instance that operates both in ring-3
1527 * and ring-0.
1528 *
1529 * Creates an instance of a device (for both ring-3 and ring-0, and optionally
1530 * raw-mode context).
1531 *
1532 * @returns VBox status code.
1533 * @param pGVM The global (ring-0) VM structure.
1534 * @param pReq Pointer to the request buffer.
1535 * @thread EMT(0)
1536 */
1537VMMR0_INT_DECL(int) PDMR0DeviceCreateReqHandler(PGVM pGVM, PPDMDEVICECREATEREQ pReq)
1538{
1539 LogFlow(("PDMR0DeviceCreateReqHandler: %s in %s\n", pReq->szDevName, pReq->szModName));
1540
1541 /*
1542 * Validate the request.
1543 */
1544 AssertReturn(pReq->Hdr.cbReq == sizeof(*pReq), VERR_INVALID_PARAMETER);
1545 pReq->pDevInsR3 = NIL_RTR3PTR;
1546
1547 int rc = GVMMR0ValidateGVMandEMT(pGVM, 0);
1548 AssertRCReturn(rc, rc);
1549
1550 AssertReturn(pReq->fFlags != 0, VERR_INVALID_FLAGS);
1551 AssertReturn(pReq->fClass != 0, VERR_WRONG_TYPE);
1552 AssertReturn(pReq->uSharedVersion != 0, VERR_INVALID_PARAMETER);
1553 AssertReturn(pReq->cbInstanceShared != 0, VERR_INVALID_PARAMETER);
1554 size_t const cchDevName = RTStrNLen(pReq->szDevName, sizeof(pReq->szDevName));
1555 AssertReturn(cchDevName < sizeof(pReq->szDevName), VERR_NO_STRING_TERMINATOR);
1556 AssertReturn(cchDevName > 0, VERR_EMPTY_STRING);
1557 AssertReturn(cchDevName < RT_SIZEOFMEMB(PDMDEVREG, szName), VERR_NOT_FOUND);
1558
1559 size_t const cchModName = RTStrNLen(pReq->szModName, sizeof(pReq->szModName));
1560 AssertReturn(cchModName < sizeof(pReq->szModName), VERR_NO_STRING_TERMINATOR);
1561 AssertReturn(cchModName > 0, VERR_EMPTY_STRING);
1562 AssertReturn(pReq->cbInstanceR3 <= _2M, VERR_OUT_OF_RANGE);
1563 AssertReturn(pReq->cbInstanceRC <= _512K, VERR_OUT_OF_RANGE);
1564 AssertReturn(pReq->iInstance < 1024, VERR_OUT_OF_RANGE);
1565 AssertReturn(pReq->iInstance < pReq->cMaxInstances, VERR_OUT_OF_RANGE);
1566 AssertReturn(pReq->cMaxPciDevices <= 8, VERR_OUT_OF_RANGE);
1567 AssertReturn(pReq->cMaxMsixVectors <= VBOX_MSIX_MAX_ENTRIES, VERR_OUT_OF_RANGE);
1568
1569 /*
1570 * Reference the module.
1571 */
1572 void *hMod = NULL;
1573 rc = SUPR0LdrModByName(pGVM->pSession, pReq->szModName, &hMod);
1574 if (RT_FAILURE(rc))
1575 {
1576 LogRel(("PDMR0DeviceCreateReqHandler: SUPR0LdrModByName(,%s,) failed: %Rrc\n", pReq->szModName, rc));
1577 return rc;
1578 }
1579
1580 /*
1581 * Look for the the module and the device registration structure.
1582 */
1583 int rcLock = SUPR0LdrLock(pGVM->pSession);
1584 AssertRC(rc);
1585
1586 rc = VERR_NOT_FOUND;
1587 PPDMDEVMODREGR0 pMod;
1588 RTListForEach(&g_PDMDevModList, pMod, PDMDEVMODREGR0, ListEntry)
1589 {
1590 if (pMod->hMod == hMod)
1591 {
1592 /*
1593 * Found the module. We can drop the loader lock now before we
1594 * search the devices it registers.
1595 */
1596 if (RT_SUCCESS(rcLock))
1597 {
1598 rcLock = SUPR0LdrUnlock(pGVM->pSession);
1599 AssertRC(rcLock);
1600 }
1601 rcLock = VERR_ALREADY_RESET;
1602
1603 PCPDMDEVREGR0 *papDevRegs = pMod->papDevRegs;
1604 size_t i = pMod->cDevRegs;
1605 while (i-- > 0)
1606 {
1607 PCPDMDEVREGR0 pDevReg = papDevRegs[i];
1608 LogFlow(("PDMR0DeviceCreateReqHandler: candidate #%u: %s %#x\n", i, pReq->szDevName, pDevReg->u32Version));
1609 if ( PDM_VERSION_ARE_COMPATIBLE(pDevReg->u32Version, PDM_DEVREGR0_VERSION)
1610 && pDevReg->szName[cchDevName] == '\0'
1611 && memcmp(pDevReg->szName, pReq->szDevName, cchDevName) == 0)
1612 {
1613
1614 /*
1615 * Found the device, now check whether it matches the ring-3 registration.
1616 */
1617 if ( pReq->uSharedVersion == pDevReg->uSharedVersion
1618 && pReq->cbInstanceShared == pDevReg->cbInstanceShared
1619 && pReq->cbInstanceRC == pDevReg->cbInstanceRC
1620 && pReq->fFlags == pDevReg->fFlags
1621 && pReq->fClass == pDevReg->fClass
1622 && pReq->cMaxInstances == pDevReg->cMaxInstances
1623 && pReq->cMaxPciDevices == pDevReg->cMaxPciDevices
1624 && pReq->cMaxMsixVectors == pDevReg->cMaxMsixVectors)
1625 {
1626 rc = pdmR0DeviceCreateWorker(pGVM, pDevReg, pReq->iInstance, pReq->cbInstanceR3, pReq->cbInstanceRC,
1627 NIL_RTRCPTR /** @todo new raw-mode */, hMod, &pReq->pDevInsR3);
1628 if (RT_SUCCESS(rc))
1629 hMod = NULL; /* keep the module reference */
1630 }
1631 else
1632 {
1633 LogRel(("PDMR0DeviceCreate: Ring-3 does not match ring-0 device registration (%s):\n"
1634 " uSharedVersion: %#x vs %#x\n"
1635 " cbInstanceShared: %#x vs %#x\n"
1636 " cbInstanceRC: %#x vs %#x\n"
1637 " fFlags: %#x vs %#x\n"
1638 " fClass: %#x vs %#x\n"
1639 " cMaxInstances: %#x vs %#x\n"
1640 " cMaxPciDevices: %#x vs %#x\n"
1641 " cMaxMsixVectors: %#x vs %#x\n"
1642 ,
1643 pReq->szDevName,
1644 pReq->uSharedVersion, pDevReg->uSharedVersion,
1645 pReq->cbInstanceShared, pDevReg->cbInstanceShared,
1646 pReq->cbInstanceRC, pDevReg->cbInstanceRC,
1647 pReq->fFlags, pDevReg->fFlags,
1648 pReq->fClass, pDevReg->fClass,
1649 pReq->cMaxInstances, pDevReg->cMaxInstances,
1650 pReq->cMaxPciDevices, pDevReg->cMaxPciDevices,
1651 pReq->cMaxMsixVectors, pDevReg->cMaxMsixVectors));
1652 rc = VERR_INCOMPATIBLE_CONFIG;
1653 }
1654 }
1655 }
1656 break;
1657 }
1658 }
1659
1660 if (RT_SUCCESS_NP(rcLock))
1661 {
1662 rcLock = SUPR0LdrUnlock(pGVM->pSession);
1663 AssertRC(rcLock);
1664 }
1665 SUPR0LdrModRelease(pGVM->pSession, hMod);
1666 return rc;
1667}
1668
1669
1670/**
1671 * Used by ring-3 PDM to call standard ring-0 device methods.
1672 *
1673 * @returns VBox status code.
1674 * @param pGVM The global (ring-0) VM structure.
1675 * @param pReq Pointer to the request buffer.
1676 * @thread EMT(0)
1677 */
1678VMMR0_INT_DECL(int) PDMR0DeviceGenCallReqHandler(PGVM pGVM, PPDMDEVICEGENCALLREQ pReq)
1679{
1680 /*
1681 * Validate the request.
1682 */
1683 AssertReturn(pReq->Hdr.cbReq == sizeof(*pReq), VERR_INVALID_PARAMETER);
1684
1685 int rc = GVMMR0ValidateGVMandEMT(pGVM, 0);
1686 AssertRCReturn(rc, rc);
1687
1688 AssertReturn(pReq->idxR0Device < pGVM->pdmr0.s.cDevInstances, VERR_INVALID_HANDLE);
1689 PPDMDEVINSR0 pDevIns = pGVM->pdmr0.s.apDevInstances[pReq->idxR0Device];
1690 AssertPtrReturn(pDevIns, VERR_INVALID_HANDLE);
1691 AssertReturn(pDevIns->pDevInsForR3 == pReq->pDevInsR3, VERR_INVALID_HANDLE);
1692
1693 /*
1694 * Make the call.
1695 */
1696 rc = VINF_SUCCESS /*VINF_NOT_IMPLEMENTED*/;
1697 switch (pReq->enmCall)
1698 {
1699 case PDMDEVICEGENCALL_CONSTRUCT:
1700 AssertMsgBreakStmt(pGVM->enmVMState < VMSTATE_CREATED, ("enmVMState=%d\n", pGVM->enmVMState), rc = VERR_INVALID_STATE);
1701 if (pDevIns->pReg->pfnConstruct)
1702 rc = pDevIns->pReg->pfnConstruct(pDevIns);
1703 break;
1704
1705 case PDMDEVICEGENCALL_DESTRUCT:
1706 AssertMsgBreakStmt(pGVM->enmVMState < VMSTATE_CREATED || pGVM->enmVMState >= VMSTATE_DESTROYING,
1707 ("enmVMState=%d\n", pGVM->enmVMState), rc = VERR_INVALID_STATE);
1708 if (pDevIns->pReg->pfnDestruct)
1709 {
1710 pDevIns->pReg->pfnDestruct(pDevIns);
1711 rc = VINF_SUCCESS;
1712 }
1713 break;
1714
1715 default:
1716 AssertMsgFailed(("enmCall=%d\n", pReq->enmCall));
1717 rc = VERR_INVALID_FUNCTION;
1718 break;
1719 }
1720
1721 return rc;
1722}
1723
1724
1725/**
1726 * Legacy device mode compatiblity.
1727 *
1728 * @returns VBox status code.
1729 * @param pGVM The global (ring-0) VM structure.
1730 * @param pReq Pointer to the request buffer.
1731 * @thread EMT(0)
1732 */
1733VMMR0_INT_DECL(int) PDMR0DeviceCompatSetCritSectReqHandler(PGVM pGVM, PPDMDEVICECOMPATSETCRITSECTREQ pReq)
1734{
1735 /*
1736 * Validate the request.
1737 */
1738 AssertReturn(pReq->Hdr.cbReq == sizeof(*pReq), VERR_INVALID_PARAMETER);
1739
1740 int rc = GVMMR0ValidateGVMandEMT(pGVM, 0);
1741 AssertRCReturn(rc, rc);
1742
1743 AssertReturn(pReq->idxR0Device < pGVM->pdmr0.s.cDevInstances, VERR_INVALID_HANDLE);
1744 PPDMDEVINSR0 pDevIns = pGVM->pdmr0.s.apDevInstances[pReq->idxR0Device];
1745 AssertPtrReturn(pDevIns, VERR_INVALID_HANDLE);
1746 AssertReturn(pDevIns->pDevInsForR3 == pReq->pDevInsR3, VERR_INVALID_HANDLE);
1747
1748 AssertReturn(pGVM->enmVMState == VMSTATE_CREATING, VERR_INVALID_STATE);
1749
1750 /*
1751 * The critical section address can be in a few different places:
1752 * 1. shared data.
1753 * 2. nop section.
1754 * 3. pdm critsect.
1755 */
1756 PPDMCRITSECT pCritSect;
1757 if (pReq->pCritSectR3 == pGVM->pVMR3 + RT_UOFFSETOF(VM, pdm.s.NopCritSect))
1758 {
1759 pCritSect = &pGVM->pdm.s.NopCritSect;
1760 Log(("PDMR0DeviceCompatSetCritSectReqHandler: Nop - %p %#x\n", pCritSect, pCritSect->s.Core.u32Magic));
1761 }
1762 else if (pReq->pCritSectR3 == pGVM->pVMR3 + RT_UOFFSETOF(VM, pdm.s.CritSect))
1763 {
1764 pCritSect = &pGVM->pdm.s.CritSect;
1765 Log(("PDMR0DeviceCompatSetCritSectReqHandler: PDM - %p %#x\n", pCritSect, pCritSect->s.Core.u32Magic));
1766 }
1767 else
1768 {
1769 size_t offCritSect = pReq->pCritSectR3 - pDevIns->pDevInsForR3R0->pvInstanceDataR3;
1770 AssertLogRelMsgReturn( offCritSect < pDevIns->pReg->cbInstanceShared
1771 && offCritSect + sizeof(PDMCRITSECT) <= pDevIns->pReg->cbInstanceShared,
1772 ("offCritSect=%p pCritSectR3=%p cbInstanceShared=%#x (%s)\n",
1773 offCritSect, pReq->pCritSectR3, pDevIns->pReg->cbInstanceShared, pDevIns->pReg->szName),
1774 VERR_INVALID_POINTER);
1775 pCritSect = (PPDMCRITSECT)((uint8_t *)pDevIns->pvInstanceDataR0 + offCritSect);
1776 Log(("PDMR0DeviceCompatSetCritSectReqHandler: custom - %#x/%p %#x\n", offCritSect, pCritSect, pCritSect->s.Core.u32Magic));
1777 }
1778 AssertLogRelMsgReturn(pCritSect->s.Core.u32Magic == RTCRITSECT_MAGIC,
1779 ("cs=%p magic=%#x dev=%s\n", pCritSect, pCritSect->s.Core.u32Magic, pDevIns->pReg->szName),
1780 VERR_INVALID_MAGIC);
1781
1782 /*
1783 * Make the update.
1784 */
1785 pDevIns->pCritSectRoR0 = pCritSect;
1786
1787 return VINF_SUCCESS;
1788}
1789
1790
1791/**
1792 * Legacy device mode compatiblity.
1793 *
1794 * @returns VBox status code.
1795 * @param pGVM The global (ring-0) VM structure.
1796 * @param pReq Pointer to the request buffer.
1797 * @thread EMT(0)
1798 */
1799VMMR0_INT_DECL(int) PDMR0DeviceCompatRegPciDevReqHandler(PGVM pGVM, PPDMDEVICECOMPATREGPCIDEVREQ pReq)
1800{
1801 /*
1802 * Validate the request.
1803 */
1804 AssertReturn(pReq->Hdr.cbReq == sizeof(*pReq), VERR_INVALID_PARAMETER);
1805
1806 int rc = GVMMR0ValidateGVMandEMT(pGVM, 0);
1807 AssertRCReturn(rc, rc);
1808
1809 AssertReturn(pReq->idxR0Device < pGVM->pdmr0.s.cDevInstances, VERR_INVALID_HANDLE);
1810 PPDMDEVINSR0 pDevIns = pGVM->pdmr0.s.apDevInstances[pReq->idxR0Device];
1811 AssertPtrReturn(pDevIns, VERR_INVALID_HANDLE);
1812 AssertReturn(pDevIns->pDevInsForR3 == pReq->pDevInsR3, VERR_INVALID_HANDLE);
1813
1814 AssertReturn(pGVM->enmVMState == VMSTATE_CREATING, VERR_INVALID_STATE);
1815
1816 /*
1817 * The address must be within the shared instance data.
1818 */
1819 size_t offPciDev = pReq->pPciDevR3 - pDevIns->pDevInsForR3R0->pvInstanceDataR3;
1820 AssertLogRelMsgReturn( offPciDev < pDevIns->pReg->cbInstanceShared
1821 && offPciDev + sizeof(PDMPCIDEV) <= pDevIns->pReg->cbInstanceShared,
1822 ("offPciDev=%p pPciDevR3=%p cbInstanceShared=%#x (%s)\n",
1823 offPciDev, pReq->pPciDevR3, pDevIns->pReg->cbInstanceShared, pDevIns->pReg->szName),
1824 VERR_INVALID_POINTER);
1825 PPDMPCIDEV pPciDev = (PPDMPCIDEV)((uint8_t *)pDevIns->pvInstanceDataR0 + offPciDev);
1826 AssertReturn(pPciDev->Int.s.pDevInsR3 == pReq->pDevInsR3, VERR_MISMATCH);
1827
1828 /*
1829 * Append the pci device to the list.
1830 */
1831 PPDMPCIDEV pPciDevPrev = pDevIns->Internal.s.pHeadPciDevR0;
1832 if (!pPciDevPrev)
1833 pDevIns->Internal.s.pHeadPciDevR0 = pPciDev;
1834 else
1835 {
1836 while (pPciDevPrev->Int.s.pNextR0)
1837 pPciDevPrev = pPciDevPrev->Int.s.pNextR0;
1838 pPciDevPrev->Int.s.pNextR0 = pPciDev;
1839 }
1840 pPciDev->Int.s.pNextR0 = NULL;
1841
1842 return VINF_SUCCESS;
1843}
1844
1845
1846/**
1847 * Registers the device implementations living in a module.
1848 *
1849 * This should normally only be called during ModuleInit(). The should be a
1850 * call to PDMR0DeviceDeregisterModule from the ModuleTerm() function to undo
1851 * the effects of this call.
1852 *
1853 * @returns VBox status code.
1854 * @param hMod The module handle of the module being registered.
1855 * @param pModReg The module registration structure. This will be
1856 * used directly so it must live as long as the module
1857 * and be writable.
1858 *
1859 * @note Caller must own the loader lock!
1860 */
1861VMMR0DECL(int) PDMR0DeviceRegisterModule(void *hMod, PPDMDEVMODREGR0 pModReg)
1862{
1863 /*
1864 * Validate the input.
1865 */
1866 AssertPtrReturn(hMod, VERR_INVALID_HANDLE);
1867 Assert(SUPR0LdrIsLockOwnerByMod(hMod, true));
1868
1869 AssertPtrReturn(pModReg, VERR_INVALID_POINTER);
1870 AssertLogRelMsgReturn(PDM_VERSION_ARE_COMPATIBLE(pModReg->u32Version, PDM_DEVMODREGR0_VERSION),
1871 ("pModReg->u32Version=%#x vs %#x\n", pModReg->u32Version, PDM_DEVMODREGR0_VERSION),
1872 VERR_VERSION_MISMATCH);
1873 AssertLogRelMsgReturn(pModReg->cDevRegs <= 256 && pModReg->cDevRegs > 0, ("cDevRegs=%u\n", pModReg->cDevRegs),
1874 VERR_OUT_OF_RANGE);
1875 AssertLogRelMsgReturn(pModReg->hMod == NULL, ("hMod=%p\n", pModReg->hMod), VERR_INVALID_PARAMETER);
1876 AssertLogRelMsgReturn(pModReg->ListEntry.pNext == NULL, ("pNext=%p\n", pModReg->ListEntry.pNext), VERR_INVALID_PARAMETER);
1877 AssertLogRelMsgReturn(pModReg->ListEntry.pPrev == NULL, ("pPrev=%p\n", pModReg->ListEntry.pPrev), VERR_INVALID_PARAMETER);
1878
1879 for (size_t i = 0; i < pModReg->cDevRegs; i++)
1880 {
1881 PCPDMDEVREGR0 pDevReg = pModReg->papDevRegs[i];
1882 AssertLogRelMsgReturn(RT_VALID_PTR(pDevReg), ("[%u]: %p\n", i, pDevReg), VERR_INVALID_POINTER);
1883 AssertLogRelMsgReturn(PDM_VERSION_ARE_COMPATIBLE(pDevReg->u32Version, PDM_DEVREGR0_VERSION),
1884 ("pDevReg->u32Version=%#x vs %#x\n", pModReg->u32Version, PDM_DEVREGR0_VERSION), VERR_VERSION_MISMATCH);
1885 AssertLogRelMsgReturn(RT_VALID_PTR(pDevReg->pszDescription), ("[%u]: %p\n", i, pDevReg->pszDescription), VERR_INVALID_POINTER);
1886 AssertLogRelMsgReturn(pDevReg->uReserved0 == 0, ("[%u]: %#x\n", i, pDevReg->uReserved0), VERR_INVALID_PARAMETER);
1887 AssertLogRelMsgReturn(pDevReg->fClass != 0, ("[%u]: %#x\n", i, pDevReg->fClass), VERR_INVALID_PARAMETER);
1888 AssertLogRelMsgReturn(pDevReg->fFlags != 0, ("[%u]: %#x\n", i, pDevReg->fFlags), VERR_INVALID_PARAMETER);
1889 AssertLogRelMsgReturn(pDevReg->cMaxInstances > 0, ("[%u]: %#x\n", i, pDevReg->cMaxInstances), VERR_INVALID_PARAMETER);
1890 AssertLogRelMsgReturn(pDevReg->cMaxPciDevices <= 8, ("[%u]: %#x\n", i, pDevReg->cMaxPciDevices), VERR_INVALID_PARAMETER);
1891 AssertLogRelMsgReturn(pDevReg->cMaxMsixVectors <= VBOX_MSIX_MAX_ENTRIES,
1892 ("[%u]: %#x\n", i, pDevReg->cMaxMsixVectors), VERR_INVALID_PARAMETER);
1893
1894 /* The name must be printable ascii and correctly terminated. */
1895 for (size_t off = 0; off < RT_ELEMENTS(pDevReg->szName); off++)
1896 {
1897 char ch = pDevReg->szName[off];
1898 AssertLogRelMsgReturn(RT_C_IS_PRINT(ch) || (ch == '\0' && off > 0),
1899 ("[%u]: off=%u szName: %.*Rhxs\n", i, off, sizeof(pDevReg->szName), &pDevReg->szName[0]),
1900 VERR_INVALID_NAME);
1901 if (ch == '\0')
1902 break;
1903 }
1904 }
1905
1906 /*
1907 * Add it, assuming we're being called at ModuleInit/ModuleTerm time only, or
1908 * that the caller has already taken the loader lock.
1909 */
1910 pModReg->hMod = hMod;
1911 RTListAppend(&g_PDMDevModList, &pModReg->ListEntry);
1912
1913 return VINF_SUCCESS;
1914}
1915
1916
1917/**
1918 * Deregisters the device implementations living in a module.
1919 *
1920 * This should normally only be called during ModuleTerm().
1921 *
1922 * @returns VBox status code.
1923 * @param hMod The module handle of the module being registered.
1924 * @param pModReg The module registration structure. This will be
1925 * used directly so it must live as long as the module
1926 * and be writable.
1927 *
1928 * @note Caller must own the loader lock!
1929 */
1930VMMR0DECL(int) PDMR0DeviceDeregisterModule(void *hMod, PPDMDEVMODREGR0 pModReg)
1931{
1932 /*
1933 * Validate the input.
1934 */
1935 AssertPtrReturn(hMod, VERR_INVALID_HANDLE);
1936 Assert(SUPR0LdrIsLockOwnerByMod(hMod, true));
1937
1938 AssertPtrReturn(pModReg, VERR_INVALID_POINTER);
1939 AssertLogRelMsgReturn(PDM_VERSION_ARE_COMPATIBLE(pModReg->u32Version, PDM_DEVMODREGR0_VERSION),
1940 ("pModReg->u32Version=%#x vs %#x\n", pModReg->u32Version, PDM_DEVMODREGR0_VERSION),
1941 VERR_VERSION_MISMATCH);
1942 AssertLogRelMsgReturn(pModReg->hMod == hMod || pModReg->hMod == NULL, ("pModReg->hMod=%p vs %p\n", pModReg->hMod, hMod),
1943 VERR_INVALID_PARAMETER);
1944
1945 /*
1946 * Unlink the registration record and return it to virgin conditions. Ignore
1947 * the call if not registered.
1948 */
1949 if (pModReg->hMod)
1950 {
1951 pModReg->hMod = NULL;
1952 RTListNodeRemove(&pModReg->ListEntry);
1953 pModReg->ListEntry.pNext = NULL;
1954 pModReg->ListEntry.pPrev = NULL;
1955 return VINF_SUCCESS;
1956 }
1957 return VWRN_NOT_FOUND;
1958}
1959
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