VirtualBox

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

Last change on this file since 28319 was 28319, checked in by vboxsync, 15 years ago

pdmdev: Made PDMDevHlpVMState available in R0 and RC.

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