VirtualBox

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

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

PDM: add new PDM device helper for sending a MSI directly (from all contexts, as all contexts support such interrupt delivery)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 28.9 KB
Line 
1/* $Id: PDMR0Device.cpp 68470 2017-08-18 14:05:49Z 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#include <VBox/vmm/apic.h>
33
34#include <VBox/log.h>
35#include <VBox/err.h>
36#include <VBox/vmm/gvmm.h>
37#include <iprt/asm.h>
38#include <iprt/assert.h>
39#include <iprt/string.h>
40
41#include "dtrace/VBoxVMM.h"
42#include "PDMInline.h"
43
44
45/*********************************************************************************************************************************
46* Global Variables *
47*********************************************************************************************************************************/
48RT_C_DECLS_BEGIN
49extern DECLEXPORT(const PDMDEVHLPR0) g_pdmR0DevHlp;
50extern DECLEXPORT(const PDMPICHLPR0) g_pdmR0PicHlp;
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, PPDMPCIDEV 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, PPDMPCIDEV 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, PPDMPCIDEV 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->uDevFn, 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,pfnISASetIrq} */
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,pfnIoApicSendMsi} */
211static DECLCALLBACK(void) pdmR0DevHlp_IoApicSendMsi(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint32_t uValue)
212{
213 PDMDEV_ASSERT_DEVINS(pDevIns);
214 LogFlow(("pdmR0DevHlp_IoApicSendMsi: caller=%p/%d: GCPhys=%RGp uValue=%#x\n", pDevIns, pDevIns->iInstance, GCPhys, uValue));
215 PVM pVM = pDevIns->Internal.s.pVMR0;
216
217 uint32_t uTagSrc;
218 pDevIns->Internal.s.uLastIrqTag = uTagSrc = pdmCalcIrqTag(pVM, pDevIns->idTracing);
219 VBOXVMM_PDM_IRQ_HILO(VMMGetCpu(pVM), RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc));
220
221 if (pVM->pdm.s.IoApic.pDevInsR0)
222 pVM->pdm.s.IoApic.pfnSendMsiR0(pVM->pdm.s.IoApic.pDevInsR0, GCPhys, uValue, uTagSrc);
223 else
224 AssertFatalMsgFailed(("Lazy bastards!"));
225
226 LogFlow(("pdmR0DevHlp_IoApicSendMsi: caller=%p/%d: returns void; uTagSrc=%#x\n", pDevIns, pDevIns->iInstance, uTagSrc));
227}
228
229
230/** @interface_method_impl{PDMDEVHLPR0,pfnPhysRead} */
231static DECLCALLBACK(int) pdmR0DevHlp_PhysRead(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead)
232{
233 PDMDEV_ASSERT_DEVINS(pDevIns);
234 LogFlow(("pdmR0DevHlp_PhysRead: caller=%p/%d: GCPhys=%RGp pvBuf=%p cbRead=%#x\n",
235 pDevIns, pDevIns->iInstance, GCPhys, pvBuf, cbRead));
236
237 VBOXSTRICTRC rcStrict = PGMPhysRead(pDevIns->Internal.s.pVMR0, GCPhys, pvBuf, cbRead, PGMACCESSORIGIN_DEVICE);
238 AssertMsg(rcStrict == VINF_SUCCESS, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict))); /** @todo track down the users for this bugger. */
239
240 Log(("pdmR0DevHlp_PhysRead: caller=%p/%d: returns %Rrc\n", pDevIns, pDevIns->iInstance, VBOXSTRICTRC_VAL(rcStrict) ));
241 return VBOXSTRICTRC_VAL(rcStrict);
242}
243
244
245/** @interface_method_impl{PDMDEVHLPR0,pfnPhysWrite} */
246static DECLCALLBACK(int) pdmR0DevHlp_PhysWrite(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite)
247{
248 PDMDEV_ASSERT_DEVINS(pDevIns);
249 LogFlow(("pdmR0DevHlp_PhysWrite: caller=%p/%d: GCPhys=%RGp pvBuf=%p cbWrite=%#x\n",
250 pDevIns, pDevIns->iInstance, GCPhys, pvBuf, cbWrite));
251
252 VBOXSTRICTRC rcStrict = PGMPhysWrite(pDevIns->Internal.s.pVMR0, GCPhys, pvBuf, cbWrite, PGMACCESSORIGIN_DEVICE);
253 AssertMsg(rcStrict == VINF_SUCCESS, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict))); /** @todo track down the users for this bugger. */
254
255 Log(("pdmR0DevHlp_PhysWrite: caller=%p/%d: returns %Rrc\n", pDevIns, pDevIns->iInstance, VBOXSTRICTRC_VAL(rcStrict) ));
256 return VBOXSTRICTRC_VAL(rcStrict);
257}
258
259
260/** @interface_method_impl{PDMDEVHLPR0,pfnA20IsEnabled} */
261static DECLCALLBACK(bool) pdmR0DevHlp_A20IsEnabled(PPDMDEVINS pDevIns)
262{
263 PDMDEV_ASSERT_DEVINS(pDevIns);
264 LogFlow(("pdmR0DevHlp_A20IsEnabled: caller=%p/%d:\n", pDevIns, pDevIns->iInstance));
265
266 bool fEnabled = PGMPhysIsA20Enabled(VMMGetCpu(pDevIns->Internal.s.pVMR0));
267
268 Log(("pdmR0DevHlp_A20IsEnabled: caller=%p/%d: returns %RTbool\n", pDevIns, pDevIns->iInstance, fEnabled));
269 return fEnabled;
270}
271
272
273/** @interface_method_impl{PDMDEVHLPR0,pfnVMState} */
274static DECLCALLBACK(VMSTATE) pdmR0DevHlp_VMState(PPDMDEVINS pDevIns)
275{
276 PDMDEV_ASSERT_DEVINS(pDevIns);
277
278 VMSTATE enmVMState = pDevIns->Internal.s.pVMR0->enmVMState;
279
280 LogFlow(("pdmR0DevHlp_VMState: caller=%p/%d: returns %d\n", pDevIns, pDevIns->iInstance, enmVMState));
281 return enmVMState;
282}
283
284
285/** @interface_method_impl{PDMDEVHLPR0,pfnVMSetError} */
286static DECLCALLBACK(int) pdmR0DevHlp_VMSetError(PPDMDEVINS pDevIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...)
287{
288 PDMDEV_ASSERT_DEVINS(pDevIns);
289 va_list args;
290 va_start(args, pszFormat);
291 int rc2 = VMSetErrorV(pDevIns->Internal.s.pVMR0, rc, RT_SRC_POS_ARGS, pszFormat, args); Assert(rc2 == rc); NOREF(rc2);
292 va_end(args);
293 return rc;
294}
295
296
297/** @interface_method_impl{PDMDEVHLPR0,pfnVMSetErrorV} */
298static DECLCALLBACK(int) pdmR0DevHlp_VMSetErrorV(PPDMDEVINS pDevIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
299{
300 PDMDEV_ASSERT_DEVINS(pDevIns);
301 int rc2 = VMSetErrorV(pDevIns->Internal.s.pVMR0, rc, RT_SRC_POS_ARGS, pszFormat, va); Assert(rc2 == rc); NOREF(rc2);
302 return rc;
303}
304
305
306/** @interface_method_impl{PDMDEVHLPR0,pfnVMSetRuntimeError} */
307static DECLCALLBACK(int) pdmR0DevHlp_VMSetRuntimeError(PPDMDEVINS pDevIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
308{
309 PDMDEV_ASSERT_DEVINS(pDevIns);
310 va_list va;
311 va_start(va, pszFormat);
312 int rc = VMSetRuntimeErrorV(pDevIns->Internal.s.pVMR0, fFlags, pszErrorId, pszFormat, va);
313 va_end(va);
314 return rc;
315}
316
317
318/** @interface_method_impl{PDMDEVHLPR0,pfnVMSetRuntimeErrorV} */
319static DECLCALLBACK(int) pdmR0DevHlp_VMSetRuntimeErrorV(PPDMDEVINS pDevIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va)
320{
321 PDMDEV_ASSERT_DEVINS(pDevIns);
322 int rc = VMSetRuntimeErrorV(pDevIns->Internal.s.pVMR0, fFlags, pszErrorId, pszFormat, va);
323 return rc;
324}
325
326
327/** @interface_method_impl{PDMDEVHLPR0,pfnPATMSetMMIOPatchInfo} */
328static DECLCALLBACK(int) pdmR0DevHlp_PATMSetMMIOPatchInfo(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPTR pCachedData)
329{
330 PDMDEV_ASSERT_DEVINS(pDevIns);
331 LogFlow(("pdmR0DevHlp_PATMSetMMIOPatchInfo: caller=%p/%d:\n", pDevIns, pDevIns->iInstance));
332
333 AssertFailed();
334 NOREF(GCPhys); NOREF(pCachedData); NOREF(pDevIns);
335
336/* return PATMSetMMIOPatchInfo(pDevIns->Internal.s.pVMR0, GCPhys, pCachedData); */
337 return VINF_SUCCESS;
338}
339
340
341/** @interface_method_impl{PDMDEVHLPR0,pfnGetVM} */
342static DECLCALLBACK(PVM) pdmR0DevHlp_GetVM(PPDMDEVINS pDevIns)
343{
344 PDMDEV_ASSERT_DEVINS(pDevIns);
345 LogFlow(("pdmR0DevHlp_GetVM: caller='%p'/%d\n", pDevIns, pDevIns->iInstance));
346 return pDevIns->Internal.s.pVMR0;
347}
348
349
350/** @interface_method_impl{PDMDEVHLPR0,pfnGetVMCPU} */
351static DECLCALLBACK(PVMCPU) pdmR0DevHlp_GetVMCPU(PPDMDEVINS pDevIns)
352{
353 PDMDEV_ASSERT_DEVINS(pDevIns);
354 LogFlow(("pdmR0DevHlp_GetVMCPU: caller='%p'/%d\n", pDevIns, pDevIns->iInstance));
355 return VMMGetCpu(pDevIns->Internal.s.pVMR0);
356}
357
358
359/** @interface_method_impl{PDMDEVHLPRC,pfnGetCurrentCpuId} */
360static DECLCALLBACK(VMCPUID) pdmR0DevHlp_GetCurrentCpuId(PPDMDEVINS pDevIns)
361{
362 PDMDEV_ASSERT_DEVINS(pDevIns);
363 VMCPUID idCpu = VMMGetCpuId(pDevIns->Internal.s.pVMR0);
364 LogFlow(("pdmR0DevHlp_GetCurrentCpuId: caller='%p'/%d for CPU %u\n", pDevIns, pDevIns->iInstance, idCpu));
365 return idCpu;
366}
367
368
369/** @interface_method_impl{PDMDEVHLPR0,pfnTMTimeVirtGet} */
370static DECLCALLBACK(uint64_t) pdmR0DevHlp_TMTimeVirtGet(PPDMDEVINS pDevIns)
371{
372 PDMDEV_ASSERT_DEVINS(pDevIns);
373 LogFlow(("pdmR0DevHlp_TMTimeVirtGet: caller='%p'/%d\n", pDevIns, pDevIns->iInstance));
374 return TMVirtualGet(pDevIns->Internal.s.pVMR0);
375}
376
377
378/** @interface_method_impl{PDMDEVHLPR0,pfnTMTimeVirtGetFreq} */
379static DECLCALLBACK(uint64_t) pdmR0DevHlp_TMTimeVirtGetFreq(PPDMDEVINS pDevIns)
380{
381 PDMDEV_ASSERT_DEVINS(pDevIns);
382 LogFlow(("pdmR0DevHlp_TMTimeVirtGetFreq: caller='%p'/%d\n", pDevIns, pDevIns->iInstance));
383 return TMVirtualGetFreq(pDevIns->Internal.s.pVMR0);
384}
385
386
387/** @interface_method_impl{PDMDEVHLPR0,pfnTMTimeVirtGetNano} */
388static DECLCALLBACK(uint64_t) pdmR0DevHlp_TMTimeVirtGetNano(PPDMDEVINS pDevIns)
389{
390 PDMDEV_ASSERT_DEVINS(pDevIns);
391 LogFlow(("pdmR0DevHlp_TMTimeVirtGetNano: caller='%p'/%d\n", pDevIns, pDevIns->iInstance));
392 return TMVirtualToNano(pDevIns->Internal.s.pVMR0, TMVirtualGet(pDevIns->Internal.s.pVMR0));
393}
394
395
396/** @interface_method_impl{PDMDEVHLPR0,pfnDBGFTraceBuf} */
397static DECLCALLBACK(RTTRACEBUF) pdmR0DevHlp_DBGFTraceBuf(PPDMDEVINS pDevIns)
398{
399 PDMDEV_ASSERT_DEVINS(pDevIns);
400 RTTRACEBUF hTraceBuf = pDevIns->Internal.s.pVMR0->hTraceBufR0;
401 LogFlow(("pdmR3DevHlp_DBGFTraceBuf: caller='%p'/%d: returns %p\n", pDevIns, pDevIns->iInstance, hTraceBuf));
402 return hTraceBuf;
403}
404
405
406/** @interface_method_impl{PDMDEVHLPR0,pfnCanEmulateIoBlock} */
407static DECLCALLBACK(bool) pdmR0DevHlp_CanEmulateIoBlock(PPDMDEVINS pDevIns)
408{
409 PDMDEV_ASSERT_DEVINS(pDevIns);
410 LogFlow(("pdmR0DevHlp_GetVM: caller='%p'/%d\n", pDevIns, pDevIns->iInstance));
411 return HMCanEmulateIoBlock(VMMGetCpu(pDevIns->Internal.s.pVMR0));
412}
413
414
415/**
416 * The Ring-0 Device Helper Callbacks.
417 */
418extern DECLEXPORT(const PDMDEVHLPR0) g_pdmR0DevHlp =
419{
420 PDM_DEVHLPR0_VERSION,
421 pdmR0DevHlp_PCIPhysRead,
422 pdmR0DevHlp_PCIPhysWrite,
423 pdmR0DevHlp_PCISetIrq,
424 pdmR0DevHlp_ISASetIrq,
425 pdmR0DevHlp_PhysRead,
426 pdmR0DevHlp_PhysWrite,
427 pdmR0DevHlp_A20IsEnabled,
428 pdmR0DevHlp_VMState,
429 pdmR0DevHlp_VMSetError,
430 pdmR0DevHlp_VMSetErrorV,
431 pdmR0DevHlp_VMSetRuntimeError,
432 pdmR0DevHlp_VMSetRuntimeErrorV,
433 pdmR0DevHlp_PATMSetMMIOPatchInfo,
434 pdmR0DevHlp_GetVM,
435 pdmR0DevHlp_CanEmulateIoBlock,
436 pdmR0DevHlp_GetVMCPU,
437 pdmR0DevHlp_GetCurrentCpuId,
438 pdmR0DevHlp_TMTimeVirtGet,
439 pdmR0DevHlp_TMTimeVirtGetFreq,
440 pdmR0DevHlp_TMTimeVirtGetNano,
441 pdmR0DevHlp_DBGFTraceBuf,
442 pdmR0DevHlp_IoApicSendMsi,
443 NULL,
444 NULL,
445 NULL,
446 NULL,
447 NULL,
448 NULL,
449 NULL,
450 NULL,
451 NULL,
452 PDM_DEVHLPR0_VERSION
453};
454
455/** @} */
456
457
458
459
460/** @name PIC Ring-0 Helpers
461 * @{
462 */
463
464/** @interface_method_impl{PDMPICHLPR0,pfnSetInterruptFF} */
465static DECLCALLBACK(void) pdmR0PicHlp_SetInterruptFF(PPDMDEVINS pDevIns)
466{
467 PDMDEV_ASSERT_DEVINS(pDevIns);
468 PVM pVM = pDevIns->Internal.s.pVMR0;
469 PVMCPU pVCpu = &pVM->aCpus[0]; /* for PIC we always deliver to CPU 0, MP use APIC */
470 /** @todo r=ramshankar: Propagating rcRZ and make all callers handle it? */
471 APICLocalInterrupt(pVCpu, 0 /* u8Pin */, 1 /* u8Level */, VINF_SUCCESS /* rcRZ */);
472}
473
474
475/** @interface_method_impl{PDMPICHLPR0,pfnClearInterruptFF} */
476static DECLCALLBACK(void) pdmR0PicHlp_ClearInterruptFF(PPDMDEVINS pDevIns)
477{
478 PDMDEV_ASSERT_DEVINS(pDevIns);
479 PVM pVM = pDevIns->Internal.s.pVMR0;
480 PVMCPU pVCpu = &pVM->aCpus[0]; /* for PIC we always deliver to CPU 0, MP use APIC */
481 /** @todo r=ramshankar: Propagating rcRZ and make all callers handle it? */
482 APICLocalInterrupt(pVCpu, 0 /* u8Pin */, 0 /* u8Level */, VINF_SUCCESS /* rcRZ */);
483}
484
485
486/** @interface_method_impl{PDMPICHLPR0,pfnLock} */
487static DECLCALLBACK(int) pdmR0PicHlp_Lock(PPDMDEVINS pDevIns, int rc)
488{
489 PDMDEV_ASSERT_DEVINS(pDevIns);
490 return pdmLockEx(pDevIns->Internal.s.pVMR0, rc);
491}
492
493
494/** @interface_method_impl{PDMPICHLPR0,pfnUnlock} */
495static DECLCALLBACK(void) pdmR0PicHlp_Unlock(PPDMDEVINS pDevIns)
496{
497 PDMDEV_ASSERT_DEVINS(pDevIns);
498 pdmUnlock(pDevIns->Internal.s.pVMR0);
499}
500
501
502/**
503 * The Ring-0 PIC Helper Callbacks.
504 */
505extern DECLEXPORT(const PDMPICHLPR0) g_pdmR0PicHlp =
506{
507 PDM_PICHLPR0_VERSION,
508 pdmR0PicHlp_SetInterruptFF,
509 pdmR0PicHlp_ClearInterruptFF,
510 pdmR0PicHlp_Lock,
511 pdmR0PicHlp_Unlock,
512 PDM_PICHLPR0_VERSION
513};
514
515/** @} */
516
517
518/** @name I/O APIC Ring-0 Helpers
519 * @{
520 */
521
522/** @interface_method_impl{PDMIOAPICHLPR0,pfnApicBusDeliver} */
523static DECLCALLBACK(int) pdmR0IoApicHlp_ApicBusDeliver(PPDMDEVINS pDevIns, uint8_t u8Dest, uint8_t u8DestMode,
524 uint8_t u8DeliveryMode, uint8_t uVector, uint8_t u8Polarity,
525 uint8_t u8TriggerMode, uint32_t uTagSrc)
526{
527 PDMDEV_ASSERT_DEVINS(pDevIns);
528 PVM pVM = pDevIns->Internal.s.pVMR0;
529 LogFlow(("pdmR0IoApicHlp_ApicBusDeliver: caller=%p/%d: u8Dest=%RX8 u8DestMode=%RX8 u8DeliveryMode=%RX8 uVector=%RX8 u8Polarity=%RX8 u8TriggerMode=%RX8 uTagSrc=%#x\n",
530 pDevIns, pDevIns->iInstance, u8Dest, u8DestMode, u8DeliveryMode, uVector, u8Polarity, u8TriggerMode, uTagSrc));
531 return APICBusDeliver(pVM, u8Dest, u8DestMode, u8DeliveryMode, uVector, u8Polarity, u8TriggerMode, uTagSrc);
532}
533
534
535/** @interface_method_impl{PDMIOAPICHLPR0,pfnLock} */
536static DECLCALLBACK(int) pdmR0IoApicHlp_Lock(PPDMDEVINS pDevIns, int rc)
537{
538 PDMDEV_ASSERT_DEVINS(pDevIns);
539 return pdmLockEx(pDevIns->Internal.s.pVMR0, rc);
540}
541
542
543/** @interface_method_impl{PDMIOAPICHLPR0,pfnUnlock} */
544static DECLCALLBACK(void) pdmR0IoApicHlp_Unlock(PPDMDEVINS pDevIns)
545{
546 PDMDEV_ASSERT_DEVINS(pDevIns);
547 pdmUnlock(pDevIns->Internal.s.pVMR0);
548}
549
550
551/**
552 * The Ring-0 I/O APIC Helper Callbacks.
553 */
554extern DECLEXPORT(const PDMIOAPICHLPR0) g_pdmR0IoApicHlp =
555{
556 PDM_IOAPICHLPR0_VERSION,
557 pdmR0IoApicHlp_ApicBusDeliver,
558 pdmR0IoApicHlp_Lock,
559 pdmR0IoApicHlp_Unlock,
560 PDM_IOAPICHLPR0_VERSION
561};
562
563/** @} */
564
565
566
567
568/** @name PCI Bus Ring-0 Helpers
569 * @{
570 */
571
572/** @interface_method_impl{PDMPCIHLPR0,pfnIsaSetIrq} */
573static DECLCALLBACK(void) pdmR0PciHlp_IsaSetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t uTagSrc)
574{
575 PDMDEV_ASSERT_DEVINS(pDevIns);
576 Log4(("pdmR0PciHlp_IsaSetIrq: iIrq=%d iLevel=%d uTagSrc=%#x\n", iIrq, iLevel, uTagSrc));
577 PVM pVM = pDevIns->Internal.s.pVMR0;
578
579 pdmLock(pVM);
580 pdmR0IsaSetIrq(pVM, iIrq, iLevel, uTagSrc);
581 pdmUnlock(pVM);
582}
583
584
585/** @interface_method_impl{PDMPCIHLPR0,pfnIoApicSetIrq} */
586static DECLCALLBACK(void) pdmR0PciHlp_IoApicSetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t uTagSrc)
587{
588 PDMDEV_ASSERT_DEVINS(pDevIns);
589 Log4(("pdmR0PciHlp_IoApicSetIrq: iIrq=%d iLevel=%d uTagSrc=%#x\n", iIrq, iLevel, uTagSrc));
590 PVM pVM = pDevIns->Internal.s.pVMR0;
591
592 if (pVM->pdm.s.IoApic.pDevInsR0)
593 pVM->pdm.s.IoApic.pfnSetIrqR0(pVM->pdm.s.IoApic.pDevInsR0, iIrq, iLevel, uTagSrc);
594 else if (pVM->pdm.s.IoApic.pDevInsR3)
595 {
596 /* queue for ring-3 execution. */
597 PPDMDEVHLPTASK pTask = (PPDMDEVHLPTASK)PDMQueueAlloc(pVM->pdm.s.pDevHlpQueueR0);
598 if (pTask)
599 {
600 pTask->enmOp = PDMDEVHLPTASKOP_IOAPIC_SET_IRQ;
601 pTask->pDevInsR3 = NIL_RTR3PTR; /* not required */
602 pTask->u.IoApicSetIRQ.iIrq = iIrq;
603 pTask->u.IoApicSetIRQ.iLevel = iLevel;
604 pTask->u.IoApicSetIRQ.uTagSrc = uTagSrc;
605
606 PDMQueueInsertEx(pVM->pdm.s.pDevHlpQueueR0, &pTask->Core, 0);
607 }
608 else
609 AssertMsgFailed(("We're out of devhlp queue items!!!\n"));
610 }
611}
612
613
614/** @interface_method_impl{PDMPCIHLPR0,pfnIoApicSendMsi} */
615static DECLCALLBACK(void) pdmR0PciHlp_IoApicSendMsi(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint32_t uValue, uint32_t uTagSrc)
616{
617 PDMDEV_ASSERT_DEVINS(pDevIns);
618 Log4(("pdmR0PciHlp_IoApicSendMsi: GCPhys=%p uValue=%d uTagSrc=%#x\n", GCPhys, uValue, uTagSrc));
619 PVM pVM = pDevIns->Internal.s.pVMR0;
620 if (pVM->pdm.s.IoApic.pDevInsR0)
621 pVM->pdm.s.IoApic.pfnSendMsiR0(pVM->pdm.s.IoApic.pDevInsR0, GCPhys, uValue, uTagSrc);
622 else
623 AssertFatalMsgFailed(("Lazy bastards!"));
624}
625
626
627/** @interface_method_impl{PDMPCIHLPR0,pfnLock} */
628static DECLCALLBACK(int) pdmR0PciHlp_Lock(PPDMDEVINS pDevIns, int rc)
629{
630 PDMDEV_ASSERT_DEVINS(pDevIns);
631 return pdmLockEx(pDevIns->Internal.s.pVMR0, rc);
632}
633
634
635/** @interface_method_impl{PDMPCIHLPR0,pfnUnlock} */
636static DECLCALLBACK(void) pdmR0PciHlp_Unlock(PPDMDEVINS pDevIns)
637{
638 PDMDEV_ASSERT_DEVINS(pDevIns);
639 pdmUnlock(pDevIns->Internal.s.pVMR0);
640}
641
642
643/**
644 * The Ring-0 PCI Bus Helper Callbacks.
645 */
646extern DECLEXPORT(const PDMPCIHLPR0) g_pdmR0PciHlp =
647{
648 PDM_PCIHLPR0_VERSION,
649 pdmR0PciHlp_IsaSetIrq,
650 pdmR0PciHlp_IoApicSetIrq,
651 pdmR0PciHlp_IoApicSendMsi,
652 pdmR0PciHlp_Lock,
653 pdmR0PciHlp_Unlock,
654 PDM_PCIHLPR0_VERSION, /* the end */
655};
656
657/** @} */
658
659
660
661
662/** @name HPET Ring-0 Helpers
663 * @{
664 */
665/* none */
666
667/**
668 * The Ring-0 HPET Helper Callbacks.
669 */
670extern DECLEXPORT(const PDMHPETHLPR0) g_pdmR0HpetHlp =
671{
672 PDM_HPETHLPR0_VERSION,
673 PDM_HPETHLPR0_VERSION, /* the end */
674};
675
676/** @} */
677
678
679/** @name Raw PCI Ring-0 Helpers
680 * @{
681 */
682/* none */
683
684/**
685 * The Ring-0 PCI raw Helper Callbacks.
686 */
687extern DECLEXPORT(const PDMPCIRAWHLPR0) g_pdmR0PciRawHlp =
688{
689 PDM_PCIRAWHLPR0_VERSION,
690 PDM_PCIRAWHLPR0_VERSION, /* the end */
691};
692
693/** @} */
694
695
696/** @name Ring-0 Context Driver Helpers
697 * @{
698 */
699
700/** @interface_method_impl{PDMDRVHLPR0,pfnVMSetError} */
701static DECLCALLBACK(int) pdmR0DrvHlp_VMSetError(PPDMDRVINS pDrvIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...)
702{
703 PDMDRV_ASSERT_DRVINS(pDrvIns);
704 va_list args;
705 va_start(args, pszFormat);
706 int rc2 = VMSetErrorV(pDrvIns->Internal.s.pVMR0, rc, RT_SRC_POS_ARGS, pszFormat, args); Assert(rc2 == rc); NOREF(rc2);
707 va_end(args);
708 return rc;
709}
710
711
712/** @interface_method_impl{PDMDRVHLPR0,pfnVMSetErrorV} */
713static DECLCALLBACK(int) pdmR0DrvHlp_VMSetErrorV(PPDMDRVINS pDrvIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
714{
715 PDMDRV_ASSERT_DRVINS(pDrvIns);
716 int rc2 = VMSetErrorV(pDrvIns->Internal.s.pVMR0, rc, RT_SRC_POS_ARGS, pszFormat, va); Assert(rc2 == rc); NOREF(rc2);
717 return rc;
718}
719
720
721/** @interface_method_impl{PDMDRVHLPR0,pfnVMSetRuntimeError} */
722static DECLCALLBACK(int) pdmR0DrvHlp_VMSetRuntimeError(PPDMDRVINS pDrvIns, uint32_t fFlags, const char *pszErrorId,
723 const char *pszFormat, ...)
724{
725 PDMDRV_ASSERT_DRVINS(pDrvIns);
726 va_list va;
727 va_start(va, pszFormat);
728 int rc = VMSetRuntimeErrorV(pDrvIns->Internal.s.pVMR0, fFlags, pszErrorId, pszFormat, va);
729 va_end(va);
730 return rc;
731}
732
733
734/** @interface_method_impl{PDMDRVHLPR0,pfnVMSetRuntimeErrorV} */
735static DECLCALLBACK(int) pdmR0DrvHlp_VMSetRuntimeErrorV(PPDMDRVINS pDrvIns, uint32_t fFlags, const char *pszErrorId,
736 const char *pszFormat, va_list va)
737{
738 PDMDRV_ASSERT_DRVINS(pDrvIns);
739 int rc = VMSetRuntimeErrorV(pDrvIns->Internal.s.pVMR0, fFlags, pszErrorId, pszFormat, va);
740 return rc;
741}
742
743
744/** @interface_method_impl{PDMDRVHLPR0,pfnAssertEMT} */
745static DECLCALLBACK(bool) pdmR0DrvHlp_AssertEMT(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)
746{
747 PDMDRV_ASSERT_DRVINS(pDrvIns);
748 if (VM_IS_EMT(pDrvIns->Internal.s.pVMR0))
749 return true;
750
751 RTAssertMsg1Weak("AssertEMT", iLine, pszFile, pszFunction);
752 RTAssertPanic();
753 return false;
754}
755
756
757/** @interface_method_impl{PDMDRVHLPR0,pfnAssertOther} */
758static DECLCALLBACK(bool) pdmR0DrvHlp_AssertOther(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)
759{
760 PDMDRV_ASSERT_DRVINS(pDrvIns);
761 if (!VM_IS_EMT(pDrvIns->Internal.s.pVMR0))
762 return true;
763
764 RTAssertMsg1Weak("AssertOther", iLine, pszFile, pszFunction);
765 RTAssertPanic();
766 return false;
767}
768
769
770/** @interface_method_impl{PDMDRVHLPR0,pfnFTSetCheckpoint} */
771static DECLCALLBACK(int) pdmR0DrvHlp_FTSetCheckpoint(PPDMDRVINS pDrvIns, FTMCHECKPOINTTYPE enmType)
772{
773 PDMDRV_ASSERT_DRVINS(pDrvIns);
774 return FTMSetCheckpoint(pDrvIns->Internal.s.pVMR0, enmType);
775}
776
777
778/**
779 * The Ring-0 Context Driver Helper Callbacks.
780 */
781extern DECLEXPORT(const PDMDRVHLPR0) g_pdmR0DrvHlp =
782{
783 PDM_DRVHLPRC_VERSION,
784 pdmR0DrvHlp_VMSetError,
785 pdmR0DrvHlp_VMSetErrorV,
786 pdmR0DrvHlp_VMSetRuntimeError,
787 pdmR0DrvHlp_VMSetRuntimeErrorV,
788 pdmR0DrvHlp_AssertEMT,
789 pdmR0DrvHlp_AssertOther,
790 pdmR0DrvHlp_FTSetCheckpoint,
791 PDM_DRVHLPRC_VERSION
792};
793
794/** @} */
795
796
797
798
799/**
800 * Sets an irq on the PIC and I/O APIC.
801 *
802 * @returns true if delivered, false if postponed.
803 * @param pVM The cross context VM structure.
804 * @param iIrq The irq.
805 * @param iLevel The new level.
806 * @param uTagSrc The IRQ tag and source.
807 *
808 * @remarks The caller holds the PDM lock.
809 */
810static bool pdmR0IsaSetIrq(PVM pVM, int iIrq, int iLevel, uint32_t uTagSrc)
811{
812 if (RT_LIKELY( ( pVM->pdm.s.IoApic.pDevInsR0
813 || !pVM->pdm.s.IoApic.pDevInsR3)
814 && ( pVM->pdm.s.Pic.pDevInsR0
815 || !pVM->pdm.s.Pic.pDevInsR3)))
816 {
817 if (pVM->pdm.s.Pic.pDevInsR0)
818 pVM->pdm.s.Pic.pfnSetIrqR0(pVM->pdm.s.Pic.pDevInsR0, iIrq, iLevel, uTagSrc);
819 if (pVM->pdm.s.IoApic.pDevInsR0)
820 pVM->pdm.s.IoApic.pfnSetIrqR0(pVM->pdm.s.IoApic.pDevInsR0, iIrq, iLevel, uTagSrc);
821 return true;
822 }
823
824 /* queue for ring-3 execution. */
825 PPDMDEVHLPTASK pTask = (PPDMDEVHLPTASK)PDMQueueAlloc(pVM->pdm.s.pDevHlpQueueR0);
826 AssertReturn(pTask, false);
827
828 pTask->enmOp = PDMDEVHLPTASKOP_ISA_SET_IRQ;
829 pTask->pDevInsR3 = NIL_RTR3PTR; /* not required */
830 pTask->u.IsaSetIRQ.iIrq = iIrq;
831 pTask->u.IsaSetIRQ.iLevel = iLevel;
832 pTask->u.IsaSetIRQ.uTagSrc = uTagSrc;
833
834 PDMQueueInsertEx(pVM->pdm.s.pDevHlpQueueR0, &pTask->Core, 0);
835 return false;
836}
837
838
839/**
840 * PDMDevHlpCallR0 helper.
841 *
842 * @returns See PFNPDMDEVREQHANDLERR0.
843 * @param pGVM The global (ring-0) VM structure. (For validation.)
844 * @param pVM The cross context VM structure. (For validation.)
845 * @param pReq Pointer to the request buffer.
846 */
847VMMR0_INT_DECL(int) PDMR0DeviceCallReqHandler(PGVM pGVM, PVM pVM, PPDMDEVICECALLREQHANDLERREQ pReq)
848{
849 /*
850 * Validate input and make the call.
851 */
852 int rc = GVMMR0ValidateGVMandVM(pGVM, pVM);
853 if (RT_SUCCESS(rc))
854 {
855 AssertPtrReturn(pReq, VERR_INVALID_POINTER);
856 AssertMsgReturn(pReq->Hdr.cbReq == sizeof(*pReq), ("%#x != %#x\n", pReq->Hdr.cbReq, sizeof(*pReq)), VERR_INVALID_PARAMETER);
857
858 PPDMDEVINS pDevIns = pReq->pDevInsR0;
859 AssertPtrReturn(pDevIns, VERR_INVALID_POINTER);
860 AssertReturn(pDevIns->Internal.s.pVMR0 == pVM, VERR_INVALID_PARAMETER);
861
862 PFNPDMDEVREQHANDLERR0 pfnReqHandlerR0 = pReq->pfnReqHandlerR0;
863 AssertPtrReturn(pfnReqHandlerR0, VERR_INVALID_POINTER);
864
865 rc = pfnReqHandlerR0(pDevIns, pReq->uOperation, pReq->u64Arg);
866 }
867 return rc;
868}
869
Note: See TracBrowser for help on using the repository browser.

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