VirtualBox

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

最後變更 在這個檔案從80587是 80548,由 vboxsync 提交於 6 年 前

VMM/PDMR0DeviceCompatSetCritSectReqHandler: Assertion fix. bugref:9218

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette