VirtualBox

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

Last change on this file since 40026 was 39078, checked in by vboxsync, 13 years ago

VMM: -Wunused-parameter

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