VirtualBox

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

Last change on this file since 41774 was 40956, checked in by vboxsync, 13 years ago

PDM,APIC,IO-APIC: More IRQ tagging.

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