VirtualBox

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

Last change on this file since 64373 was 64373, checked in by vboxsync, 8 years ago

PDM,Devices: Support for multiple PCI devices/function in a single PDM device.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 35.3 KB
Line 
1/* $Id: PDMR0Device.cpp 64373 2016-10-23 19:03:39Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device and Driver Manager, R0 Device parts.
4 */
5
6/*
7 * Copyright (C) 2006-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_PDM_DEVICE
23#define PDMPCIDEV_INCLUDE_PRIVATE /* Hack to get pdmpcidevint.h included at the right point. */
24#include "PDMInternal.h"
25#include <VBox/vmm/pdm.h>
26#include <VBox/vmm/pgm.h>
27#include <VBox/vmm/mm.h>
28#include <VBox/vmm/vm.h>
29#include <VBox/vmm/vmm.h>
30#include <VBox/vmm/patm.h>
31#include <VBox/vmm/hm.h>
32
33#include <VBox/log.h>
34#include <VBox/err.h>
35#include <VBox/vmm/gvmm.h>
36#include <iprt/asm.h>
37#include <iprt/assert.h>
38#include <iprt/string.h>
39
40#include "dtrace/VBoxVMM.h"
41#include "PDMInline.h"
42
43
44/*********************************************************************************************************************************
45* Global Variables *
46*********************************************************************************************************************************/
47RT_C_DECLS_BEGIN
48extern DECLEXPORT(const PDMDEVHLPR0) g_pdmR0DevHlp;
49extern DECLEXPORT(const PDMPICHLPR0) g_pdmR0PicHlp;
50extern DECLEXPORT(const PDMAPICHLPR0) g_pdmR0ApicHlp;
51extern DECLEXPORT(const PDMIOAPICHLPR0) g_pdmR0IoApicHlp;
52extern DECLEXPORT(const PDMPCIHLPR0) g_pdmR0PciHlp;
53extern DECLEXPORT(const PDMHPETHLPR0) g_pdmR0HpetHlp;
54extern DECLEXPORT(const PDMPCIRAWHLPR0) g_pdmR0PciRawHlp;
55extern DECLEXPORT(const PDMDRVHLPR0) g_pdmR0DrvHlp;
56RT_C_DECLS_END
57
58
59/*********************************************************************************************************************************
60* Internal Functions *
61*********************************************************************************************************************************/
62static bool pdmR0IsaSetIrq(PVM pVM, int iIrq, int iLevel, uint32_t uTagSrc);
63
64
65
66/** @name Ring-0 Device Helpers
67 * @{
68 */
69
70/** @interface_method_impl{PDMDEVHLPR0,pfnPCIPhysRead} */
71static DECLCALLBACK(int) pdmR0DevHlp_PCIPhysRead(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, RTGCPHYS GCPhys,
72 void *pvBuf, size_t cbRead)
73{
74 PDMDEV_ASSERT_DEVINS(pDevIns);
75 if (!pPciDev) /* NULL is an alias for the default PCI device. */
76 pPciDev = pDevIns->Internal.s.pHeadPciDevR0;
77 AssertReturn(pPciDev, VERR_PDM_NOT_PCI_DEVICE);
78
79#ifndef PDM_DO_NOT_RESPECT_PCI_BM_BIT
80 /*
81 * Just check the busmaster setting here and forward the request to the generic read helper.
82 */
83 if (PCIDevIsBusmaster(pPciDev))
84 { /* likely */ }
85 else
86 {
87 Log(("pdmRCDevHlp_PCIPhysRead: caller=%p/%d: returns %Rrc - Not bus master! GCPhys=%RGp cbRead=%#zx\n",
88 pDevIns, pDevIns->iInstance, VERR_PDM_NOT_PCI_BUS_MASTER, GCPhys, cbRead));
89 return VERR_PDM_NOT_PCI_BUS_MASTER;
90 }
91#endif
92
93 return pDevIns->pHlpR0->pfnPhysRead(pDevIns, GCPhys, pvBuf, cbRead);
94}
95
96
97/** @interface_method_impl{PDMDEVHLPR0,pfnPCIPhysWrite} */
98static DECLCALLBACK(int) pdmR0DevHlp_PCIPhysWrite(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, RTGCPHYS GCPhys,
99 const void *pvBuf, size_t cbWrite)
100{
101 PDMDEV_ASSERT_DEVINS(pDevIns);
102 if (!pPciDev) /* NULL is an alias for the default PCI device. */
103 pPciDev = pDevIns->Internal.s.pHeadPciDevR0;
104 AssertReturn(pPciDev, VERR_PDM_NOT_PCI_DEVICE);
105
106#ifndef PDM_DO_NOT_RESPECT_PCI_BM_BIT
107 /*
108 * Just check the busmaster setting here and forward the request to the generic read helper.
109 */
110 if (PCIDevIsBusmaster(pPciDev))
111 { /* likely */ }
112 else
113 {
114 Log(("pdmRCDevHlp_PCIPhysWrite: caller=%p/%d: returns %Rrc - Not bus master! GCPhys=%RGp cbWrite=%#zx\n",
115 pDevIns, pDevIns->iInstance, VERR_PDM_NOT_PCI_BUS_MASTER, GCPhys, cbWrite));
116 return VERR_PDM_NOT_PCI_BUS_MASTER;
117 }
118#endif
119
120 return pDevIns->pHlpR0->pfnPhysWrite(pDevIns, GCPhys, pvBuf, cbWrite);
121}
122
123
124/** @interface_method_impl{PDMDEVHLPR0,pfnPCISetIrq} */
125static DECLCALLBACK(void) pdmR0DevHlp_PCISetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel)
126{
127 PDMDEV_ASSERT_DEVINS(pDevIns);
128 if (!pPciDev) /* NULL is an alias for the default PCI device. */
129 pPciDev = pDevIns->Internal.s.pHeadPciDevR0;
130 AssertReturnVoid(pPciDev);
131 LogFlow(("pdmR0DevHlp_PCISetIrq: caller=%p/%d: pPciDev=%p:{%#x} iIrq=%d iLevel=%d\n",
132 pDevIns, pDevIns->iInstance, pPciDev, pPciDev->devfn, iIrq, iLevel));
133 PVM pVM = pDevIns->Internal.s.pVMR0;
134 PPDMPCIBUS pPciBus = pPciDev->Int.s.pPdmBusR0;
135
136 pdmLock(pVM);
137 uint32_t uTagSrc;
138 if (iLevel & PDM_IRQ_LEVEL_HIGH)
139 {
140 pDevIns->Internal.s.uLastIrqTag = uTagSrc = pdmCalcIrqTag(pVM, pDevIns->idTracing);
141 if (iLevel == PDM_IRQ_LEVEL_HIGH)
142 VBOXVMM_PDM_IRQ_HIGH(VMMGetCpu(pVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc));
143 else
144 VBOXVMM_PDM_IRQ_HILO(VMMGetCpu(pVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc));
145 }
146 else
147 uTagSrc = pDevIns->Internal.s.uLastIrqTag;
148
149 if ( pPciBus
150 && pPciBus->pDevInsR0)
151 {
152 pPciBus->pfnSetIrqR0(pPciBus->pDevInsR0, pPciDev, iIrq, iLevel, uTagSrc);
153
154 pdmUnlock(pVM);
155
156 if (iLevel == PDM_IRQ_LEVEL_LOW)
157 VBOXVMM_PDM_IRQ_LOW(VMMGetCpu(pVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc));
158 }
159 else
160 {
161 pdmUnlock(pVM);
162
163 /* queue for ring-3 execution. */
164 PPDMDEVHLPTASK pTask = (PPDMDEVHLPTASK)PDMQueueAlloc(pVM->pdm.s.pDevHlpQueueR0);
165 AssertReturnVoid(pTask);
166
167 pTask->enmOp = PDMDEVHLPTASKOP_PCI_SET_IRQ;
168 pTask->pDevInsR3 = PDMDEVINS_2_R3PTR(pDevIns);
169 pTask->u.PciSetIRQ.iIrq = iIrq;
170 pTask->u.PciSetIRQ.iLevel = iLevel;
171 pTask->u.PciSetIRQ.uTagSrc = uTagSrc;
172 pTask->u.PciSetIRQ.pPciDevR3 = MMHyperR0ToR3(pVM, pPciDev);
173
174 PDMQueueInsertEx(pVM->pdm.s.pDevHlpQueueR0, &pTask->Core, 0);
175 }
176
177 LogFlow(("pdmR0DevHlp_PCISetIrq: caller=%p/%d: returns void; uTagSrc=%#x\n", pDevIns, pDevIns->iInstance, uTagSrc));
178}
179
180
181/** @interface_method_impl{PDMDEVHLPR0,pfnPCISetIrq} */
182static DECLCALLBACK(void) pdmR0DevHlp_ISASetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel)
183{
184 PDMDEV_ASSERT_DEVINS(pDevIns);
185 LogFlow(("pdmR0DevHlp_ISASetIrq: caller=%p/%d: iIrq=%d iLevel=%d\n", pDevIns, pDevIns->iInstance, iIrq, iLevel));
186 PVM pVM = pDevIns->Internal.s.pVMR0;
187
188 pdmLock(pVM);
189 uint32_t uTagSrc;
190 if (iLevel & PDM_IRQ_LEVEL_HIGH)
191 {
192 pDevIns->Internal.s.uLastIrqTag = uTagSrc = pdmCalcIrqTag(pVM, pDevIns->idTracing);
193 if (iLevel == PDM_IRQ_LEVEL_HIGH)
194 VBOXVMM_PDM_IRQ_HIGH(VMMGetCpu(pVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc));
195 else
196 VBOXVMM_PDM_IRQ_HILO(VMMGetCpu(pVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc));
197 }
198 else
199 uTagSrc = pDevIns->Internal.s.uLastIrqTag;
200
201 bool fRc = pdmR0IsaSetIrq(pVM, iIrq, iLevel, uTagSrc);
202
203 if (iLevel == PDM_IRQ_LEVEL_LOW && fRc)
204 VBOXVMM_PDM_IRQ_LOW(VMMGetCpu(pVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc));
205 pdmUnlock(pVM);
206 LogFlow(("pdmR0DevHlp_ISASetIrq: caller=%p/%d: returns void; uTagSrc=%#x\n", pDevIns, pDevIns->iInstance, uTagSrc));
207}
208
209
210/** @interface_method_impl{PDMDEVHLPR0,pfnPhysRead} */
211static DECLCALLBACK(int) pdmR0DevHlp_PhysRead(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead)
212{
213 PDMDEV_ASSERT_DEVINS(pDevIns);
214 LogFlow(("pdmR0DevHlp_PhysRead: caller=%p/%d: GCPhys=%RGp pvBuf=%p cbRead=%#x\n",
215 pDevIns, pDevIns->iInstance, GCPhys, pvBuf, cbRead));
216
217 VBOXSTRICTRC rcStrict = PGMPhysRead(pDevIns->Internal.s.pVMR0, GCPhys, pvBuf, cbRead, PGMACCESSORIGIN_DEVICE);
218 AssertMsg(rcStrict == VINF_SUCCESS, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict))); /** @todo track down the users for this bugger. */
219
220 Log(("pdmR0DevHlp_PhysRead: caller=%p/%d: returns %Rrc\n", pDevIns, pDevIns->iInstance, VBOXSTRICTRC_VAL(rcStrict) ));
221 return VBOXSTRICTRC_VAL(rcStrict);
222}
223
224
225/** @interface_method_impl{PDMDEVHLPR0,pfnPhysWrite} */
226static DECLCALLBACK(int) pdmR0DevHlp_PhysWrite(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite)
227{
228 PDMDEV_ASSERT_DEVINS(pDevIns);
229 LogFlow(("pdmR0DevHlp_PhysWrite: caller=%p/%d: GCPhys=%RGp pvBuf=%p cbWrite=%#x\n",
230 pDevIns, pDevIns->iInstance, GCPhys, pvBuf, cbWrite));
231
232 VBOXSTRICTRC rcStrict = PGMPhysWrite(pDevIns->Internal.s.pVMR0, GCPhys, pvBuf, cbWrite, PGMACCESSORIGIN_DEVICE);
233 AssertMsg(rcStrict == VINF_SUCCESS, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict))); /** @todo track down the users for this bugger. */
234
235 Log(("pdmR0DevHlp_PhysWrite: caller=%p/%d: returns %Rrc\n", pDevIns, pDevIns->iInstance, VBOXSTRICTRC_VAL(rcStrict) ));
236 return VBOXSTRICTRC_VAL(rcStrict);
237}
238
239
240/** @interface_method_impl{PDMDEVHLPR0,pfnA20IsEnabled} */
241static DECLCALLBACK(bool) pdmR0DevHlp_A20IsEnabled(PPDMDEVINS pDevIns)
242{
243 PDMDEV_ASSERT_DEVINS(pDevIns);
244 LogFlow(("pdmR0DevHlp_A20IsEnabled: caller=%p/%d:\n", pDevIns, pDevIns->iInstance));
245
246 bool fEnabled = PGMPhysIsA20Enabled(VMMGetCpu(pDevIns->Internal.s.pVMR0));
247
248 Log(("pdmR0DevHlp_A20IsEnabled: caller=%p/%d: returns %RTbool\n", pDevIns, pDevIns->iInstance, fEnabled));
249 return fEnabled;
250}
251
252
253/** @interface_method_impl{PDMDEVHLPR0,pfnVMState} */
254static DECLCALLBACK(VMSTATE) pdmR0DevHlp_VMState(PPDMDEVINS pDevIns)
255{
256 PDMDEV_ASSERT_DEVINS(pDevIns);
257
258 VMSTATE enmVMState = pDevIns->Internal.s.pVMR0->enmVMState;
259
260 LogFlow(("pdmR0DevHlp_VMState: caller=%p/%d: returns %d\n", pDevIns, pDevIns->iInstance, enmVMState));
261 return enmVMState;
262}
263
264
265/** @interface_method_impl{PDMDEVHLPR0,pfnVMSetError} */
266static DECLCALLBACK(int) pdmR0DevHlp_VMSetError(PPDMDEVINS pDevIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...)
267{
268 PDMDEV_ASSERT_DEVINS(pDevIns);
269 va_list args;
270 va_start(args, pszFormat);
271 int rc2 = VMSetErrorV(pDevIns->Internal.s.pVMR0, rc, RT_SRC_POS_ARGS, pszFormat, args); Assert(rc2 == rc); NOREF(rc2);
272 va_end(args);
273 return rc;
274}
275
276
277/** @interface_method_impl{PDMDEVHLPR0,pfnVMSetErrorV} */
278static DECLCALLBACK(int) pdmR0DevHlp_VMSetErrorV(PPDMDEVINS pDevIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
279{
280 PDMDEV_ASSERT_DEVINS(pDevIns);
281 int rc2 = VMSetErrorV(pDevIns->Internal.s.pVMR0, rc, RT_SRC_POS_ARGS, pszFormat, va); Assert(rc2 == rc); NOREF(rc2);
282 return rc;
283}
284
285
286/** @interface_method_impl{PDMDEVHLPR0,pfnVMSetRuntimeError} */
287static DECLCALLBACK(int) pdmR0DevHlp_VMSetRuntimeError(PPDMDEVINS pDevIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
288{
289 PDMDEV_ASSERT_DEVINS(pDevIns);
290 va_list va;
291 va_start(va, pszFormat);
292 int rc = VMSetRuntimeErrorV(pDevIns->Internal.s.pVMR0, fFlags, pszErrorId, pszFormat, va);
293 va_end(va);
294 return rc;
295}
296
297
298/** @interface_method_impl{PDMDEVHLPR0,pfnVMSetRuntimeErrorV} */
299static DECLCALLBACK(int) pdmR0DevHlp_VMSetRuntimeErrorV(PPDMDEVINS pDevIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va)
300{
301 PDMDEV_ASSERT_DEVINS(pDevIns);
302 int rc = VMSetRuntimeErrorV(pDevIns->Internal.s.pVMR0, fFlags, pszErrorId, pszFormat, va);
303 return rc;
304}
305
306
307/** @interface_method_impl{PDMDEVHLPR0,pfnPATMSetMMIOPatchInfo} */
308static DECLCALLBACK(int) pdmR0DevHlp_PATMSetMMIOPatchInfo(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPTR pCachedData)
309{
310 PDMDEV_ASSERT_DEVINS(pDevIns);
311 LogFlow(("pdmR0DevHlp_PATMSetMMIOPatchInfo: caller=%p/%d:\n", pDevIns, pDevIns->iInstance));
312
313 AssertFailed();
314 NOREF(GCPhys); NOREF(pCachedData); NOREF(pDevIns);
315
316/* return PATMSetMMIOPatchInfo(pDevIns->Internal.s.pVMR0, GCPhys, pCachedData); */
317 return VINF_SUCCESS;
318}
319
320
321/** @interface_method_impl{PDMDEVHLPR0,pfnGetVM} */
322static DECLCALLBACK(PVM) pdmR0DevHlp_GetVM(PPDMDEVINS pDevIns)
323{
324 PDMDEV_ASSERT_DEVINS(pDevIns);
325 LogFlow(("pdmR0DevHlp_GetVM: caller='%p'/%d\n", pDevIns, pDevIns->iInstance));
326 return pDevIns->Internal.s.pVMR0;
327}
328
329
330/** @interface_method_impl{PDMDEVHLPR0,pfnGetVMCPU} */
331static DECLCALLBACK(PVMCPU) pdmR0DevHlp_GetVMCPU(PPDMDEVINS pDevIns)
332{
333 PDMDEV_ASSERT_DEVINS(pDevIns);
334 LogFlow(("pdmR0DevHlp_GetVMCPU: caller='%p'/%d\n", pDevIns, pDevIns->iInstance));
335 return VMMGetCpu(pDevIns->Internal.s.pVMR0);
336}
337
338
339/** @interface_method_impl{PDMDEVHLPRC,pfnGetCurrentCpuId} */
340static DECLCALLBACK(VMCPUID) pdmR0DevHlp_GetCurrentCpuId(PPDMDEVINS pDevIns)
341{
342 PDMDEV_ASSERT_DEVINS(pDevIns);
343 VMCPUID idCpu = VMMGetCpuId(pDevIns->Internal.s.pVMR0);
344 LogFlow(("pdmR0DevHlp_GetCurrentCpuId: caller='%p'/%d for CPU %u\n", pDevIns, pDevIns->iInstance, idCpu));
345 return idCpu;
346}
347
348
349/** @interface_method_impl{PDMDEVHLPR0,pfnTMTimeVirtGet} */
350static DECLCALLBACK(uint64_t) pdmR0DevHlp_TMTimeVirtGet(PPDMDEVINS pDevIns)
351{
352 PDMDEV_ASSERT_DEVINS(pDevIns);
353 LogFlow(("pdmR0DevHlp_TMTimeVirtGet: caller='%p'/%d\n", pDevIns, pDevIns->iInstance));
354 return TMVirtualGet(pDevIns->Internal.s.pVMR0);
355}
356
357
358/** @interface_method_impl{PDMDEVHLPR0,pfnTMTimeVirtGetFreq} */
359static DECLCALLBACK(uint64_t) pdmR0DevHlp_TMTimeVirtGetFreq(PPDMDEVINS pDevIns)
360{
361 PDMDEV_ASSERT_DEVINS(pDevIns);
362 LogFlow(("pdmR0DevHlp_TMTimeVirtGetFreq: caller='%p'/%d\n", pDevIns, pDevIns->iInstance));
363 return TMVirtualGetFreq(pDevIns->Internal.s.pVMR0);
364}
365
366
367/** @interface_method_impl{PDMDEVHLPR0,pfnTMTimeVirtGetNano} */
368static DECLCALLBACK(uint64_t) pdmR0DevHlp_TMTimeVirtGetNano(PPDMDEVINS pDevIns)
369{
370 PDMDEV_ASSERT_DEVINS(pDevIns);
371 LogFlow(("pdmR0DevHlp_TMTimeVirtGetNano: caller='%p'/%d\n", pDevIns, pDevIns->iInstance));
372 return TMVirtualToNano(pDevIns->Internal.s.pVMR0, TMVirtualGet(pDevIns->Internal.s.pVMR0));
373}
374
375
376/** @interface_method_impl{PDMDEVHLPR0,pfnDBGFTraceBuf} */
377static DECLCALLBACK(RTTRACEBUF) pdmR0DevHlp_DBGFTraceBuf(PPDMDEVINS pDevIns)
378{
379 PDMDEV_ASSERT_DEVINS(pDevIns);
380 RTTRACEBUF hTraceBuf = pDevIns->Internal.s.pVMR0->hTraceBufR0;
381 LogFlow(("pdmR3DevHlp_DBGFTraceBuf: caller='%p'/%d: returns %p\n", pDevIns, pDevIns->iInstance, hTraceBuf));
382 return hTraceBuf;
383}
384
385
386/** @interface_method_impl{PDMDEVHLPR0,pfnCanEmulateIoBlock} */
387static DECLCALLBACK(bool) pdmR0DevHlp_CanEmulateIoBlock(PPDMDEVINS pDevIns)
388{
389 PDMDEV_ASSERT_DEVINS(pDevIns);
390 LogFlow(("pdmR0DevHlp_GetVM: caller='%p'/%d\n", pDevIns, pDevIns->iInstance));
391 return HMCanEmulateIoBlock(VMMGetCpu(pDevIns->Internal.s.pVMR0));
392}
393
394
395/**
396 * The Ring-0 Device Helper Callbacks.
397 */
398extern DECLEXPORT(const PDMDEVHLPR0) g_pdmR0DevHlp =
399{
400 PDM_DEVHLPR0_VERSION,
401 pdmR0DevHlp_PCIPhysRead,
402 pdmR0DevHlp_PCIPhysWrite,
403 pdmR0DevHlp_PCISetIrq,
404 pdmR0DevHlp_ISASetIrq,
405 pdmR0DevHlp_PhysRead,
406 pdmR0DevHlp_PhysWrite,
407 pdmR0DevHlp_A20IsEnabled,
408 pdmR0DevHlp_VMState,
409 pdmR0DevHlp_VMSetError,
410 pdmR0DevHlp_VMSetErrorV,
411 pdmR0DevHlp_VMSetRuntimeError,
412 pdmR0DevHlp_VMSetRuntimeErrorV,
413 pdmR0DevHlp_PATMSetMMIOPatchInfo,
414 pdmR0DevHlp_GetVM,
415 pdmR0DevHlp_CanEmulateIoBlock,
416 pdmR0DevHlp_GetVMCPU,
417 pdmR0DevHlp_GetCurrentCpuId,
418 pdmR0DevHlp_TMTimeVirtGet,
419 pdmR0DevHlp_TMTimeVirtGetFreq,
420 pdmR0DevHlp_TMTimeVirtGetNano,
421 pdmR0DevHlp_DBGFTraceBuf,
422 NULL,
423 NULL,
424 NULL,
425 NULL,
426 NULL,
427 NULL,
428 NULL,
429 NULL,
430 NULL,
431 NULL,
432 PDM_DEVHLPR0_VERSION
433};
434
435/** @} */
436
437
438
439
440/** @name PIC Ring-0 Helpers
441 * @{
442 */
443
444/** @interface_method_impl{PDMPICHLPR0,pfnSetInterruptFF} */
445static DECLCALLBACK(void) pdmR0PicHlp_SetInterruptFF(PPDMDEVINS pDevIns)
446{
447 PDMDEV_ASSERT_DEVINS(pDevIns);
448 PVM pVM = pDevIns->Internal.s.pVMR0;
449 PVMCPU pVCpu = &pVM->aCpus[0]; /* for PIC we always deliver to CPU 0, MP use APIC */
450
451 if (pVM->pdm.s.Apic.pfnLocalInterruptR0)
452 {
453 LogFlow(("pdmR0PicHlp_SetInterruptFF: caller='%p'/%d: Setting local interrupt on LAPIC\n",
454 pDevIns, pDevIns->iInstance));
455 /* Raise the LAPIC's LINT0 line instead of signaling the CPU directly. */
456 /** @todo rcRZ propagation to pfnLocalInterrupt from caller. */
457 pVM->pdm.s.Apic.pfnLocalInterruptR0(pVM->pdm.s.Apic.pDevInsR0, pVCpu, 0 /* u8Pin */, 1 /* u8Level */,
458 VINF_SUCCESS /* rcRZ */);
459 return;
460 }
461
462 LogFlow(("pdmR0PicHlp_SetInterruptFF: caller=%p/%d: VMCPU_FF_INTERRUPT_PIC %d -> 1\n",
463 pDevIns, pDevIns->iInstance, VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC)));
464
465 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC);
466}
467
468
469/** @interface_method_impl{PDMPICHLPR0,pfnClearInterruptFF} */
470static DECLCALLBACK(void) pdmR0PicHlp_ClearInterruptFF(PPDMDEVINS pDevIns)
471{
472 PDMDEV_ASSERT_DEVINS(pDevIns);
473 PVM pVM = pDevIns->Internal.s.pVMR0;
474 PVMCPU pVCpu = &pVM->aCpus[0]; /* for PIC we always deliver to CPU 0, MP use APIC */
475
476 if (pVM->pdm.s.Apic.pfnLocalInterruptR0)
477 {
478 /* Raise the LAPIC's LINT0 line instead of signaling the CPU directly. */
479 LogFlow(("pdmR0PicHlp_ClearInterruptFF: caller='%s'/%d: Clearing local interrupt on LAPIC\n",
480 pDevIns, pDevIns->iInstance));
481 /* Lower the LAPIC's LINT0 line instead of signaling the CPU directly. */
482 /** @todo rcRZ propagation to pfnLocalInterrupt from caller. */
483 pVM->pdm.s.Apic.pfnLocalInterruptR0(pVM->pdm.s.Apic.pDevInsR0, pVCpu, 0 /* u8Pin */, 0 /* u8Level */,
484 VINF_SUCCESS /* rcRZ */);
485 return;
486 }
487
488 LogFlow(("pdmR0PicHlp_ClearInterruptFF: caller=%p/%d: VMCPU_FF_INTERRUPT_PIC %d -> 0\n",
489 pDevIns, pDevIns->iInstance, VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC)));
490
491 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_PIC);
492}
493
494
495/** @interface_method_impl{PDMPICHLPR0,pfnLock} */
496static DECLCALLBACK(int) pdmR0PicHlp_Lock(PPDMDEVINS pDevIns, int rc)
497{
498 PDMDEV_ASSERT_DEVINS(pDevIns);
499 return pdmLockEx(pDevIns->Internal.s.pVMR0, rc);
500}
501
502
503/** @interface_method_impl{PDMPICHLPR0,pfnUnlock} */
504static DECLCALLBACK(void) pdmR0PicHlp_Unlock(PPDMDEVINS pDevIns)
505{
506 PDMDEV_ASSERT_DEVINS(pDevIns);
507 pdmUnlock(pDevIns->Internal.s.pVMR0);
508}
509
510
511/**
512 * The Ring-0 PIC Helper Callbacks.
513 */
514extern DECLEXPORT(const PDMPICHLPR0) g_pdmR0PicHlp =
515{
516 PDM_PICHLPR0_VERSION,
517 pdmR0PicHlp_SetInterruptFF,
518 pdmR0PicHlp_ClearInterruptFF,
519 pdmR0PicHlp_Lock,
520 pdmR0PicHlp_Unlock,
521 PDM_PICHLPR0_VERSION
522};
523
524/** @} */
525
526
527
528
529/** @name APIC Ring-0 Helpers
530 * @{
531 */
532
533/** @interface_method_impl{PDMAPICHLPR0,pfnSetInterruptFF} */
534static DECLCALLBACK(void) pdmR0ApicHlp_SetInterruptFF(PPDMDEVINS pDevIns, PDMAPICIRQ enmType, VMCPUID idCpu)
535{
536 PDMDEV_ASSERT_DEVINS(pDevIns);
537 PVM pVM = pDevIns->Internal.s.pVMR0;
538 PVMCPU pVCpu = &pVM->aCpus[idCpu];
539
540 AssertReturnVoid(idCpu < pVM->cCpus);
541
542 LogFlow(("pdmR0ApicHlp_SetInterruptFF: CPU%d=caller=%p/%d: VM_FF_INTERRUPT %d -> 1 (CPU%d)\n",
543 VMMGetCpuId(pVM), pDevIns, pDevIns->iInstance, VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC), idCpu));
544
545 switch (enmType)
546 {
547 case PDMAPICIRQ_UPDATE_PENDING:
548 VMCPU_FF_SET(pVCpu, VMCPU_FF_UPDATE_APIC);
549 break;
550 case PDMAPICIRQ_HARDWARE:
551#ifdef VBOX_WITH_NEW_APIC
552 VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu);
553#endif
554 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC);
555 break;
556 case PDMAPICIRQ_NMI:
557 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI);
558 break;
559 case PDMAPICIRQ_SMI:
560 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_SMI);
561 break;
562 case PDMAPICIRQ_EXTINT:
563 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC);
564 break;
565 default:
566 AssertMsgFailed(("enmType=%d\n", enmType));
567 break;
568 }
569
570 /* We need to wake up the target CPU. */
571 if (
572#ifdef VBOX_WITH_NEW_APIC
573 /* We are already on EMT if enmType is PDMAPICIRQ_HARDWARE. Don't bother with poking! */
574 enmType != PDMAPICIRQ_HARDWARE &&
575#endif
576 VMMGetCpuId(pVM) != idCpu)
577 {
578 switch (VMCPU_GET_STATE(pVCpu))
579 {
580 case VMCPUSTATE_STARTED_EXEC:
581 GVMMR0SchedPokeEx(pVM, pVCpu->idCpu, false /* don't take the used lock */);
582 break;
583
584 case VMCPUSTATE_STARTED_HALTED:
585 GVMMR0SchedWakeUpEx(pVM, pVCpu->idCpu, false /* don't take the used lock */);
586 break;
587
588 default:
589 break; /* nothing to do in other states. */
590 }
591 }
592}
593
594
595/** @interface_method_impl{PDMAPICHLPR0,pfnClearInterruptFF} */
596static DECLCALLBACK(void) pdmR0ApicHlp_ClearInterruptFF(PPDMDEVINS pDevIns, PDMAPICIRQ enmType, VMCPUID idCpu)
597{
598 PDMDEV_ASSERT_DEVINS(pDevIns);
599 PVM pVM = pDevIns->Internal.s.pVMR0;
600 PVMCPU pVCpu = &pVM->aCpus[idCpu];
601
602 AssertReturnVoid(idCpu < pVM->cCpus);
603
604 LogFlow(("pdmR0ApicHlp_ClearInterruptFF: caller=%p/%d: VM_FF_INTERRUPT %d -> 0\n",
605 pDevIns, pDevIns->iInstance, VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC)));
606
607 /* Note: NMI/SMI can't be cleared. */
608 switch (enmType)
609 {
610 case PDMAPICIRQ_HARDWARE:
611 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_APIC);
612 break;
613 case PDMAPICIRQ_EXTINT:
614 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_PIC);
615 break;
616 case PDMAPICIRQ_UPDATE_PENDING:
617 VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu);
618 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_UPDATE_APIC);
619 break;
620 default:
621 AssertMsgFailed(("enmType=%d\n", enmType));
622 break;
623 }
624}
625
626
627/** @interface_method_impl{PDMAPICHLPR0,pfnBusBroadcastEoi} */
628static DECLCALLBACK(int) pdmR0ApicHlp_BusBroadcastEoi(PPDMDEVINS pDevIns, uint8_t u8Vector)
629{
630 /* pfnSetEoi will be NULL in the old IOAPIC code as it's not implemented. */
631#ifdef VBOX_WITH_NEW_IOAPIC
632 PDMDEV_ASSERT_DEVINS(pDevIns);
633 PVM pVM = pDevIns->Internal.s.CTX_SUFF(pVM);
634
635 /* At present, we support only a maximum of one I/O APIC per-VM. If we ever implement having
636 multiple I/O APICs per-VM, we'll have to broadcast this EOI to all of the I/O APICs. */
637 if (pVM->pdm.s.IoApic.CTX_SUFF(pDevIns))
638 {
639 Assert(pVM->pdm.s.IoApic.CTX_SUFF(pfnSetEoi));
640 return pVM->pdm.s.IoApic.CTX_SUFF(pfnSetEoi)(pVM->pdm.s.IoApic.CTX_SUFF(pDevIns), u8Vector);
641 }
642#endif
643 return VINF_SUCCESS;
644}
645
646
647/** @interface_method_impl{PDMAPICHLPR0,pfnCalcIrqTag} */
648static DECLCALLBACK(uint32_t) pdmR0ApicHlp_CalcIrqTag(PPDMDEVINS pDevIns, uint8_t u8Level)
649{
650 PDMDEV_ASSERT_DEVINS(pDevIns);
651 PVM pVM = pDevIns->Internal.s.pVMR0;
652
653 pdmLock(pVM);
654
655 uint32_t uTagSrc = pdmCalcIrqTag(pVM, pDevIns->idTracing);
656 if (u8Level == PDM_IRQ_LEVEL_HIGH)
657 VBOXVMM_PDM_IRQ_HIGH(VMMGetCpu(pVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc));
658 else
659 VBOXVMM_PDM_IRQ_HILO(VMMGetCpu(pVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc));
660
661
662 pdmUnlock(pVM);
663 LogFlow(("pdmR0ApicHlp_CalcIrqTag: caller=%p/%d: returns %#x (u8Level=%d)\n",
664 pDevIns, pDevIns->iInstance, uTagSrc, u8Level));
665 return uTagSrc;
666}
667
668
669/** @interface_method_impl{PDMAPICHLPR0,pfnLock} */
670static DECLCALLBACK(int) pdmR0ApicHlp_Lock(PPDMDEVINS pDevIns, int rc)
671{
672 PDMDEV_ASSERT_DEVINS(pDevIns);
673 return pdmLockEx(pDevIns->Internal.s.pVMR0, rc);
674}
675
676
677/** @interface_method_impl{PDMAPICHLPR0,pfnUnlock} */
678static DECLCALLBACK(void) pdmR0ApicHlp_Unlock(PPDMDEVINS pDevIns)
679{
680 PDMDEV_ASSERT_DEVINS(pDevIns);
681 pdmUnlock(pDevIns->Internal.s.pVMR0);
682}
683
684
685/** @interface_method_impl{PDMAPICHLPR0,pfnGetCpuId} */
686static DECLCALLBACK(VMCPUID) pdmR0ApicHlp_GetCpuId(PPDMDEVINS pDevIns)
687{
688 PDMDEV_ASSERT_DEVINS(pDevIns);
689 return VMMGetCpuId(pDevIns->Internal.s.pVMR0);
690}
691
692
693/**
694 * The Ring-0 APIC Helper Callbacks.
695 */
696extern DECLEXPORT(const PDMAPICHLPR0) g_pdmR0ApicHlp =
697{
698 PDM_APICHLPR0_VERSION,
699 pdmR0ApicHlp_SetInterruptFF,
700 pdmR0ApicHlp_ClearInterruptFF,
701 pdmR0ApicHlp_BusBroadcastEoi,
702 pdmR0ApicHlp_CalcIrqTag,
703 pdmR0ApicHlp_Lock,
704 pdmR0ApicHlp_Unlock,
705 pdmR0ApicHlp_GetCpuId,
706 PDM_APICHLPR0_VERSION
707};
708
709/** @} */
710
711
712
713
714/** @name I/O APIC Ring-0 Helpers
715 * @{
716 */
717
718/** @interface_method_impl{PDMIOAPICHLPR0,pfnApicBusDeliver} */
719static DECLCALLBACK(int) pdmR0IoApicHlp_ApicBusDeliver(PPDMDEVINS pDevIns, uint8_t u8Dest, uint8_t u8DestMode, uint8_t u8DeliveryMode,
720 uint8_t iVector, uint8_t u8Polarity, uint8_t u8TriggerMode, uint32_t uTagSrc)
721{
722 PDMDEV_ASSERT_DEVINS(pDevIns);
723 PVM pVM = pDevIns->Internal.s.pVMR0;
724 LogFlow(("pdmR0IoApicHlp_ApicBusDeliver: caller=%p/%d: u8Dest=%RX8 u8DestMode=%RX8 u8DeliveryMode=%RX8 iVector=%RX8 u8Polarity=%RX8 u8TriggerMode=%RX8 uTagSrc=%#x\n",
725 pDevIns, pDevIns->iInstance, u8Dest, u8DestMode, u8DeliveryMode, iVector, u8Polarity, u8TriggerMode, uTagSrc));
726 Assert(pVM->pdm.s.Apic.pDevInsR0);
727 if (pVM->pdm.s.Apic.pfnBusDeliverR0)
728 return pVM->pdm.s.Apic.pfnBusDeliverR0(pVM->pdm.s.Apic.pDevInsR0, u8Dest, u8DestMode, u8DeliveryMode, iVector,
729 u8Polarity, u8TriggerMode, uTagSrc);
730 return VINF_SUCCESS;
731}
732
733
734/** @interface_method_impl{PDMIOAPICHLPR0,pfnLock} */
735static DECLCALLBACK(int) pdmR0IoApicHlp_Lock(PPDMDEVINS pDevIns, int rc)
736{
737 PDMDEV_ASSERT_DEVINS(pDevIns);
738 return pdmLockEx(pDevIns->Internal.s.pVMR0, rc);
739}
740
741
742/** @interface_method_impl{PDMIOAPICHLPR0,pfnUnlock} */
743static DECLCALLBACK(void) pdmR0IoApicHlp_Unlock(PPDMDEVINS pDevIns)
744{
745 PDMDEV_ASSERT_DEVINS(pDevIns);
746 pdmUnlock(pDevIns->Internal.s.pVMR0);
747}
748
749
750/**
751 * The Ring-0 I/O APIC Helper Callbacks.
752 */
753extern DECLEXPORT(const PDMIOAPICHLPR0) g_pdmR0IoApicHlp =
754{
755 PDM_IOAPICHLPR0_VERSION,
756 pdmR0IoApicHlp_ApicBusDeliver,
757 pdmR0IoApicHlp_Lock,
758 pdmR0IoApicHlp_Unlock,
759 PDM_IOAPICHLPR0_VERSION
760};
761
762/** @} */
763
764
765
766
767/** @name PCI Bus Ring-0 Helpers
768 * @{
769 */
770
771/** @interface_method_impl{PDMPCIHLPR0,pfnIsaSetIrq} */
772static DECLCALLBACK(void) pdmR0PciHlp_IsaSetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t uTagSrc)
773{
774 PDMDEV_ASSERT_DEVINS(pDevIns);
775 Log4(("pdmR0PciHlp_IsaSetIrq: iIrq=%d iLevel=%d uTagSrc=%#x\n", iIrq, iLevel, uTagSrc));
776 PVM pVM = pDevIns->Internal.s.pVMR0;
777
778 pdmLock(pVM);
779 pdmR0IsaSetIrq(pVM, iIrq, iLevel, uTagSrc);
780 pdmUnlock(pVM);
781}
782
783
784/** @interface_method_impl{PDMPCIHLPR0,pfnIoApicSetIrq} */
785static DECLCALLBACK(void) pdmR0PciHlp_IoApicSetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t uTagSrc)
786{
787 PDMDEV_ASSERT_DEVINS(pDevIns);
788 Log4(("pdmR0PciHlp_IoApicSetIrq: iIrq=%d iLevel=%d uTagSrc=%#x\n", iIrq, iLevel, uTagSrc));
789 PVM pVM = pDevIns->Internal.s.pVMR0;
790
791 if (pVM->pdm.s.IoApic.pDevInsR0)
792 {
793#ifdef VBOX_WITH_NEW_IOAPIC
794 pVM->pdm.s.IoApic.pfnSetIrqR0(pVM->pdm.s.IoApic.pDevInsR0, iIrq, iLevel, uTagSrc);
795#else
796 pdmLock(pVM);
797 pVM->pdm.s.IoApic.pfnSetIrqR0(pVM->pdm.s.IoApic.pDevInsR0, iIrq, iLevel, uTagSrc);
798 pdmUnlock(pVM);
799#endif
800 }
801 else if (pVM->pdm.s.IoApic.pDevInsR3)
802 {
803 /* queue for ring-3 execution. */
804 PPDMDEVHLPTASK pTask = (PPDMDEVHLPTASK)PDMQueueAlloc(pVM->pdm.s.pDevHlpQueueR0);
805 if (pTask)
806 {
807 pTask->enmOp = PDMDEVHLPTASKOP_IOAPIC_SET_IRQ;
808 pTask->pDevInsR3 = NIL_RTR3PTR; /* not required */
809 pTask->u.IoApicSetIRQ.iIrq = iIrq;
810 pTask->u.IoApicSetIRQ.iLevel = iLevel;
811 pTask->u.IoApicSetIRQ.uTagSrc = uTagSrc;
812
813 PDMQueueInsertEx(pVM->pdm.s.pDevHlpQueueR0, &pTask->Core, 0);
814 }
815 else
816 AssertMsgFailed(("We're out of devhlp queue items!!!\n"));
817 }
818}
819
820
821/** @interface_method_impl{PDMPCIHLPR0,pfnIoApicSendMsi} */
822static DECLCALLBACK(void) pdmR0PciHlp_IoApicSendMsi(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint32_t uValue, uint32_t uTagSrc)
823{
824 PDMDEV_ASSERT_DEVINS(pDevIns);
825 Log4(("pdmR0PciHlp_IoApicSendMsi: GCPhys=%p uValue=%d uTagSrc=%#x\n", GCPhys, uValue, uTagSrc));
826 PVM pVM = pDevIns->Internal.s.pVMR0;
827 if (pVM->pdm.s.IoApic.pDevInsR0)
828 {
829#ifdef VBOX_WITH_NEW_IOAPIC
830 pVM->pdm.s.IoApic.pfnSendMsiR0(pVM->pdm.s.IoApic.pDevInsR0, GCPhys, uValue, uTagSrc);
831#else
832 pdmLock(pVM);
833 pVM->pdm.s.IoApic.pfnSendMsiR0(pVM->pdm.s.IoApic.pDevInsR0, GCPhys, uValue, uTagSrc);
834 pdmUnlock(pVM);
835#endif
836 }
837 else
838 AssertFatalMsgFailed(("Lazy bastards!"));
839}
840
841
842/** @interface_method_impl{PDMPCIHLPR0,pfnLock} */
843static DECLCALLBACK(int) pdmR0PciHlp_Lock(PPDMDEVINS pDevIns, int rc)
844{
845 PDMDEV_ASSERT_DEVINS(pDevIns);
846 return pdmLockEx(pDevIns->Internal.s.pVMR0, rc);
847}
848
849
850/** @interface_method_impl{PDMPCIHLPR0,pfnUnlock} */
851static DECLCALLBACK(void) pdmR0PciHlp_Unlock(PPDMDEVINS pDevIns)
852{
853 PDMDEV_ASSERT_DEVINS(pDevIns);
854 pdmUnlock(pDevIns->Internal.s.pVMR0);
855}
856
857
858/**
859 * The Ring-0 PCI Bus Helper Callbacks.
860 */
861extern DECLEXPORT(const PDMPCIHLPR0) g_pdmR0PciHlp =
862{
863 PDM_PCIHLPR0_VERSION,
864 pdmR0PciHlp_IsaSetIrq,
865 pdmR0PciHlp_IoApicSetIrq,
866 pdmR0PciHlp_IoApicSendMsi,
867 pdmR0PciHlp_Lock,
868 pdmR0PciHlp_Unlock,
869 PDM_PCIHLPR0_VERSION, /* the end */
870};
871
872/** @} */
873
874
875
876
877/** @name HPET Ring-0 Helpers
878 * @{
879 */
880/* none */
881
882/**
883 * The Ring-0 HPET Helper Callbacks.
884 */
885extern DECLEXPORT(const PDMHPETHLPR0) g_pdmR0HpetHlp =
886{
887 PDM_HPETHLPR0_VERSION,
888 PDM_HPETHLPR0_VERSION, /* the end */
889};
890
891/** @} */
892
893
894/** @name Raw PCI Ring-0 Helpers
895 * @{
896 */
897/* none */
898
899/**
900 * The Ring-0 PCI raw Helper Callbacks.
901 */
902extern DECLEXPORT(const PDMPCIRAWHLPR0) g_pdmR0PciRawHlp =
903{
904 PDM_PCIRAWHLPR0_VERSION,
905 PDM_PCIRAWHLPR0_VERSION, /* the end */
906};
907
908/** @} */
909
910
911/** @name Ring-0 Context Driver Helpers
912 * @{
913 */
914
915/** @interface_method_impl{PDMDRVHLPR0,pfnVMSetError} */
916static DECLCALLBACK(int) pdmR0DrvHlp_VMSetError(PPDMDRVINS pDrvIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...)
917{
918 PDMDRV_ASSERT_DRVINS(pDrvIns);
919 va_list args;
920 va_start(args, pszFormat);
921 int rc2 = VMSetErrorV(pDrvIns->Internal.s.pVMR0, rc, RT_SRC_POS_ARGS, pszFormat, args); Assert(rc2 == rc); NOREF(rc2);
922 va_end(args);
923 return rc;
924}
925
926
927/** @interface_method_impl{PDMDRVHLPR0,pfnVMSetErrorV} */
928static DECLCALLBACK(int) pdmR0DrvHlp_VMSetErrorV(PPDMDRVINS pDrvIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
929{
930 PDMDRV_ASSERT_DRVINS(pDrvIns);
931 int rc2 = VMSetErrorV(pDrvIns->Internal.s.pVMR0, rc, RT_SRC_POS_ARGS, pszFormat, va); Assert(rc2 == rc); NOREF(rc2);
932 return rc;
933}
934
935
936/** @interface_method_impl{PDMDRVHLPR0,pfnVMSetRuntimeError} */
937static DECLCALLBACK(int) pdmR0DrvHlp_VMSetRuntimeError(PPDMDRVINS pDrvIns, uint32_t fFlags, const char *pszErrorId,
938 const char *pszFormat, ...)
939{
940 PDMDRV_ASSERT_DRVINS(pDrvIns);
941 va_list va;
942 va_start(va, pszFormat);
943 int rc = VMSetRuntimeErrorV(pDrvIns->Internal.s.pVMR0, fFlags, pszErrorId, pszFormat, va);
944 va_end(va);
945 return rc;
946}
947
948
949/** @interface_method_impl{PDMDRVHLPR0,pfnVMSetRuntimeErrorV} */
950static DECLCALLBACK(int) pdmR0DrvHlp_VMSetRuntimeErrorV(PPDMDRVINS pDrvIns, uint32_t fFlags, const char *pszErrorId,
951 const char *pszFormat, va_list va)
952{
953 PDMDRV_ASSERT_DRVINS(pDrvIns);
954 int rc = VMSetRuntimeErrorV(pDrvIns->Internal.s.pVMR0, fFlags, pszErrorId, pszFormat, va);
955 return rc;
956}
957
958
959/** @interface_method_impl{PDMDRVHLPR0,pfnAssertEMT} */
960static DECLCALLBACK(bool) pdmR0DrvHlp_AssertEMT(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)
961{
962 PDMDRV_ASSERT_DRVINS(pDrvIns);
963 if (VM_IS_EMT(pDrvIns->Internal.s.pVMR0))
964 return true;
965
966 RTAssertMsg1Weak("AssertEMT", iLine, pszFile, pszFunction);
967 RTAssertPanic();
968 return false;
969}
970
971
972/** @interface_method_impl{PDMDRVHLPR0,pfnAssertOther} */
973static DECLCALLBACK(bool) pdmR0DrvHlp_AssertOther(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)
974{
975 PDMDRV_ASSERT_DRVINS(pDrvIns);
976 if (!VM_IS_EMT(pDrvIns->Internal.s.pVMR0))
977 return true;
978
979 RTAssertMsg1Weak("AssertOther", iLine, pszFile, pszFunction);
980 RTAssertPanic();
981 return false;
982}
983
984
985/** @interface_method_impl{PDMDRVHLPR0,pfnFTSetCheckpoint} */
986static DECLCALLBACK(int) pdmR0DrvHlp_FTSetCheckpoint(PPDMDRVINS pDrvIns, FTMCHECKPOINTTYPE enmType)
987{
988 PDMDRV_ASSERT_DRVINS(pDrvIns);
989 return FTMSetCheckpoint(pDrvIns->Internal.s.pVMR0, enmType);
990}
991
992
993/**
994 * The Ring-0 Context Driver Helper Callbacks.
995 */
996extern DECLEXPORT(const PDMDRVHLPR0) g_pdmR0DrvHlp =
997{
998 PDM_DRVHLPRC_VERSION,
999 pdmR0DrvHlp_VMSetError,
1000 pdmR0DrvHlp_VMSetErrorV,
1001 pdmR0DrvHlp_VMSetRuntimeError,
1002 pdmR0DrvHlp_VMSetRuntimeErrorV,
1003 pdmR0DrvHlp_AssertEMT,
1004 pdmR0DrvHlp_AssertOther,
1005 pdmR0DrvHlp_FTSetCheckpoint,
1006 PDM_DRVHLPRC_VERSION
1007};
1008
1009/** @} */
1010
1011
1012
1013
1014/**
1015 * Sets an irq on the PIC and I/O APIC.
1016 *
1017 * @returns true if delivered, false if postponed.
1018 * @param pVM The cross context VM structure.
1019 * @param iIrq The irq.
1020 * @param iLevel The new level.
1021 * @param uTagSrc The IRQ tag and source.
1022 *
1023 * @remarks The caller holds the PDM lock.
1024 */
1025static bool pdmR0IsaSetIrq(PVM pVM, int iIrq, int iLevel, uint32_t uTagSrc)
1026{
1027 if (RT_LIKELY( ( pVM->pdm.s.IoApic.pDevInsR0
1028 || !pVM->pdm.s.IoApic.pDevInsR3)
1029 && ( pVM->pdm.s.Pic.pDevInsR0
1030 || !pVM->pdm.s.Pic.pDevInsR3)))
1031 {
1032 if (pVM->pdm.s.Pic.pDevInsR0)
1033 pVM->pdm.s.Pic.pfnSetIrqR0(pVM->pdm.s.Pic.pDevInsR0, iIrq, iLevel, uTagSrc);
1034 if (pVM->pdm.s.IoApic.pDevInsR0)
1035 pVM->pdm.s.IoApic.pfnSetIrqR0(pVM->pdm.s.IoApic.pDevInsR0, iIrq, iLevel, uTagSrc);
1036 return true;
1037 }
1038
1039 /* queue for ring-3 execution. */
1040 PPDMDEVHLPTASK pTask = (PPDMDEVHLPTASK)PDMQueueAlloc(pVM->pdm.s.pDevHlpQueueR0);
1041 AssertReturn(pTask, false);
1042
1043 pTask->enmOp = PDMDEVHLPTASKOP_ISA_SET_IRQ;
1044 pTask->pDevInsR3 = NIL_RTR3PTR; /* not required */
1045 pTask->u.IsaSetIRQ.iIrq = iIrq;
1046 pTask->u.IsaSetIRQ.iLevel = iLevel;
1047 pTask->u.IsaSetIRQ.uTagSrc = uTagSrc;
1048
1049 PDMQueueInsertEx(pVM->pdm.s.pDevHlpQueueR0, &pTask->Core, 0);
1050 return false;
1051}
1052
1053
1054/**
1055 * PDMDevHlpCallR0 helper.
1056 *
1057 * @returns See PFNPDMDEVREQHANDLERR0.
1058 * @param pVM The cross context VM structure. (For validation.)
1059 * @param pReq Pointer to the request buffer.
1060 */
1061VMMR0_INT_DECL(int) PDMR0DeviceCallReqHandler(PVM pVM, PPDMDEVICECALLREQHANDLERREQ pReq)
1062{
1063 /*
1064 * Validate input and make the call.
1065 */
1066 AssertPtrReturn(pVM, VERR_INVALID_POINTER);
1067 AssertPtrReturn(pReq, VERR_INVALID_POINTER);
1068 AssertMsgReturn(pReq->Hdr.cbReq == sizeof(*pReq), ("%#x != %#x\n", pReq->Hdr.cbReq, sizeof(*pReq)), VERR_INVALID_PARAMETER);
1069
1070 PPDMDEVINS pDevIns = pReq->pDevInsR0;
1071 AssertPtrReturn(pDevIns, VERR_INVALID_POINTER);
1072 AssertReturn(pDevIns->Internal.s.pVMR0 == pVM, VERR_INVALID_PARAMETER);
1073
1074 PFNPDMDEVREQHANDLERR0 pfnReqHandlerR0 = pReq->pfnReqHandlerR0;
1075 AssertPtrReturn(pfnReqHandlerR0, VERR_INVALID_POINTER);
1076
1077 return pfnReqHandlerR0(pDevIns, pReq->uOperation, pReq->u64Arg);
1078}
1079
Note: See TracBrowser for help on using the repository browser.

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