VirtualBox

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

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

IOM: New I/O port registration code. bugref:9218

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

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