VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/PDMAll.cpp@ 60396

Last change on this file since 60396 was 60396, checked in by vboxsync, 9 years ago

VMMDev,PDM,HM: Changed the VMMDev heap interface a little so HM can init without the fake PCI BIOS code having run.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 16.0 KB
Line 
1/* $Id: PDMAll.cpp 60396 2016-04-08 16:17:15Z vboxsync $ */
2/** @file
3 * PDM Critical Sections
4 */
5
6/*
7 * Copyright (C) 2006-2015 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
23#include "PDMInternal.h"
24#include <VBox/vmm/pdm.h>
25#include <VBox/vmm/mm.h>
26#include <VBox/vmm/vm.h>
27#include <VBox/err.h>
28
29#include <VBox/log.h>
30#include <iprt/asm.h>
31#include <iprt/assert.h>
32
33#include "PDMInline.h"
34#include "dtrace/VBoxVMM.h"
35
36
37
38/**
39 * Gets the pending interrupt.
40 *
41 * @returns VBox status code.
42 * @param pVCpu The cross context virtual CPU structure.
43 * @param pu8Interrupt Where to store the interrupt on success.
44 */
45VMMDECL(int) PDMGetInterrupt(PVMCPU pVCpu, uint8_t *pu8Interrupt)
46{
47 PVM pVM = pVCpu->CTX_SUFF(pVM);
48
49#ifndef VBOX_WITH_NEW_APIC
50 pdmLock(pVM);
51#endif
52
53 /*
54 * The local APIC has a higher priority than the PIC.
55 */
56 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC))
57 {
58 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_APIC);
59 Assert(pVM->pdm.s.Apic.CTX_SUFF(pDevIns));
60 Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnGetInterrupt));
61 uint32_t uTagSrc;
62 int i = pVM->pdm.s.Apic.CTX_SUFF(pfnGetInterrupt)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), pVCpu, &uTagSrc);
63 AssertMsg(i <= 255 && i >= 0, ("i=%d\n", i));
64 if (i >= 0)
65 {
66#ifndef VBOX_WITH_NEW_APIC
67 pdmUnlock(pVM);
68#endif
69 *pu8Interrupt = (uint8_t)i;
70 VBOXVMM_PDM_IRQ_GET(pVCpu, RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc), i);
71 return VINF_SUCCESS;
72 }
73 }
74
75#ifdef VBOX_WITH_NEW_APIC
76 pdmLock(pVM);
77#endif
78
79 /*
80 * Check the PIC.
81 */
82 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC))
83 {
84 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_PIC);
85 Assert(pVM->pdm.s.Pic.CTX_SUFF(pDevIns));
86 Assert(pVM->pdm.s.Pic.CTX_SUFF(pfnGetInterrupt));
87 uint32_t uTagSrc;
88 int i = pVM->pdm.s.Pic.CTX_SUFF(pfnGetInterrupt)(pVM->pdm.s.Pic.CTX_SUFF(pDevIns), &uTagSrc);
89 AssertMsg(i <= 255 && i >= 0, ("i=%d\n", i));
90 if (i >= 0)
91 {
92 pdmUnlock(pVM);
93 *pu8Interrupt = (uint8_t)i;
94 VBOXVMM_PDM_IRQ_GET(pVCpu, RT_LOWORD(uTagSrc), RT_HIWORD(uTagSrc), i);
95 return VINF_SUCCESS;
96 }
97 }
98
99 /** @todo Figure out exactly why we can get here without anything being set. (REM) */
100
101 pdmUnlock(pVM);
102 return VERR_NO_DATA;
103}
104
105
106/**
107 * Sets the pending interrupt coming from ISA source or HPET.
108 *
109 * @returns VBox status code.
110 * @param pVM The cross context VM structure.
111 * @param u8Irq The IRQ line.
112 * @param u8Level The new level.
113 * @param uTagSrc The IRQ tag and source tracer ID.
114 */
115VMMDECL(int) PDMIsaSetIrq(PVM pVM, uint8_t u8Irq, uint8_t u8Level, uint32_t uTagSrc)
116{
117 pdmLock(pVM);
118
119 /** @todo put the IRQ13 code elsewhere to avoid this unnecessary bloat. */
120 if (!uTagSrc && (u8Level & PDM_IRQ_LEVEL_HIGH)) /* FPU IRQ */
121 {
122 if (u8Level == PDM_IRQ_LEVEL_HIGH)
123 VBOXVMM_PDM_IRQ_HIGH(VMMGetCpu(pVM), 0, 0);
124 else
125 VBOXVMM_PDM_IRQ_HILO(VMMGetCpu(pVM), 0, 0);
126 }
127
128 int rc = VERR_PDM_NO_PIC_INSTANCE;
129 if (pVM->pdm.s.Pic.CTX_SUFF(pDevIns))
130 {
131 Assert(pVM->pdm.s.Pic.CTX_SUFF(pfnSetIrq));
132 pVM->pdm.s.Pic.CTX_SUFF(pfnSetIrq)(pVM->pdm.s.Pic.CTX_SUFF(pDevIns), u8Irq, u8Level, uTagSrc);
133 rc = VINF_SUCCESS;
134 }
135
136 if (pVM->pdm.s.IoApic.CTX_SUFF(pDevIns))
137 {
138 Assert(pVM->pdm.s.IoApic.CTX_SUFF(pfnSetIrq));
139
140 /*
141 * Apply Interrupt Source Override rules.
142 * See ACPI 4.0 specification 5.2.12.4 and 5.2.12.5 for details on
143 * interrupt source override.
144 * Shortly, ISA IRQ0 is electically connected to pin 2 on IO-APIC, and some OSes,
145 * notably recent OS X rely upon this configuration.
146 * If changing, also update override rules in MADT and MPS.
147 */
148 /* ISA IRQ0 routed to pin 2, all others ISA sources are identity mapped */
149 if (u8Irq == 0)
150 u8Irq = 2;
151
152 pVM->pdm.s.IoApic.CTX_SUFF(pfnSetIrq)(pVM->pdm.s.IoApic.CTX_SUFF(pDevIns), u8Irq, u8Level, uTagSrc);
153 rc = VINF_SUCCESS;
154 }
155
156 if (!uTagSrc && u8Level == PDM_IRQ_LEVEL_LOW)
157 VBOXVMM_PDM_IRQ_LOW(VMMGetCpu(pVM), 0, 0);
158 pdmUnlock(pVM);
159 return rc;
160}
161
162
163/**
164 * Sets the pending I/O APIC interrupt.
165 *
166 * @returns VBox status code.
167 * @param pVM The cross context VM structure.
168 * @param u8Irq The IRQ line.
169 * @param u8Level The new level.
170 * @param uTagSrc The IRQ tag and source tracer ID.
171 */
172VMM_INT_DECL(int) PDMIoApicSetIrq(PVM pVM, uint8_t u8Irq, uint8_t u8Level, uint32_t uTagSrc)
173{
174 if (pVM->pdm.s.IoApic.CTX_SUFF(pDevIns))
175 {
176 Assert(pVM->pdm.s.IoApic.CTX_SUFF(pfnSetIrq));
177 pdmLock(pVM);
178 pVM->pdm.s.IoApic.CTX_SUFF(pfnSetIrq)(pVM->pdm.s.IoApic.CTX_SUFF(pDevIns), u8Irq, u8Level, uTagSrc);
179 pdmUnlock(pVM);
180 return VINF_SUCCESS;
181 }
182 return VERR_PDM_NO_PIC_INSTANCE;
183}
184
185/**
186 * Send a MSI to an I/O APIC.
187 *
188 * @returns VBox status code.
189 * @param pVM The cross context VM structure.
190 * @param GCAddr Request address.
191 * @param uValue Request value.
192 * @param uTagSrc The IRQ tag and source tracer ID.
193 */
194VMM_INT_DECL(int) PDMIoApicSendMsi(PVM pVM, RTGCPHYS GCAddr, uint32_t uValue, uint32_t uTagSrc)
195{
196 if (pVM->pdm.s.IoApic.CTX_SUFF(pDevIns))
197 {
198 Assert(pVM->pdm.s.IoApic.CTX_SUFF(pfnSendMsi));
199 pdmLock(pVM);
200 pVM->pdm.s.IoApic.CTX_SUFF(pfnSendMsi)(pVM->pdm.s.IoApic.CTX_SUFF(pDevIns), GCAddr, uValue, uTagSrc);
201 pdmUnlock(pVM);
202 return VINF_SUCCESS;
203 }
204 return VERR_PDM_NO_PIC_INSTANCE;
205}
206
207
208
209/**
210 * Returns the presence of an IO-APIC.
211 *
212 * @returns VBox true if an IO-APIC is present.
213 * @param pVM The cross context VM structure.
214 */
215VMM_INT_DECL(bool) PDMHasIoApic(PVM pVM)
216{
217 return pVM->pdm.s.IoApic.CTX_SUFF(pDevIns) != NULL;
218}
219
220
221/**
222 * Returns the presence of a Local APIC.
223 *
224 * @returns VBox true if a Local APIC is present.
225 * @param pVM The cross context VM structure.
226 */
227VMM_INT_DECL(bool) PDMHasApic(PVM pVM)
228{
229 return pVM->pdm.s.Apic.CTX_SUFF(pDevIns) != NULL;
230}
231
232
233/**
234 * Set the APIC base.
235 *
236 * @returns Strict VBox status code.
237 * @param pVCpu The cross context virtual CPU structure.
238 * @param u64Base The new base.
239 */
240VMMDECL(VBOXSTRICTRC) PDMApicSetBaseMsr(PVMCPU pVCpu, uint64_t u64Base)
241{
242 PVM pVM = pVCpu->CTX_SUFF(pVM);
243 if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns))
244 {
245 Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnSetBaseMsr));
246#ifndef VBOX_WITH_NEW_APIC
247 pdmLock(pVM);
248#endif
249 VBOXSTRICTRC rcStrict = pVM->pdm.s.Apic.CTX_SUFF(pfnSetBaseMsr)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), pVCpu, u64Base);
250
251 /* Update CPUM's copy of the APIC base. */
252 PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
253 Assert(pCtx);
254 pCtx->msrApicBase = pVM->pdm.s.Apic.CTX_SUFF(pfnGetBaseMsr)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), pVCpu);
255
256#ifndef VBOX_WITH_NEW_APIC
257 pdmUnlock(pVM);
258#endif
259 return rcStrict;
260 }
261
262#ifdef IN_RING3
263 LogRelMax(5, ("PDM: APIC%U: Writing APIC base MSR (%#x) invalid since there isn't an APIC -> #GP(0)\n", pVCpu->idCpu,
264 MSR_IA32_APICBASE));
265 return VERR_CPUM_RAISE_GP_0;
266#else
267 return VINF_CPUM_R3_MSR_WRITE;
268#endif
269}
270
271
272/**
273 * Get the APIC base MSR from the APIC device.
274 *
275 * @returns Strict VBox status code.
276 * @param pVCpu The cross context virtual CPU structure.
277 * @param pu64Base Where to store the APIC base.
278 * @param fIgnoreErrors Whether to ignore errors (i.e. not a real guest MSR
279 * access).
280 */
281VMMDECL(VBOXSTRICTRC) PDMApicGetBaseMsr(PVMCPU pVCpu, uint64_t *pu64Base, bool fIgnoreErrors)
282{
283 PVM pVM = pVCpu->CTX_SUFF(pVM);
284 if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns))
285 {
286 Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnGetBaseMsr));
287#ifdef VBOX_WITH_NEW_APIC
288 VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu);
289 *pu64Base = pVM->pdm.s.Apic.CTX_SUFF(pfnGetBaseMsr)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), pVCpu);
290#else
291 pdmLock(pVM);
292 *pu64Base = pVM->pdm.s.Apic.CTX_SUFF(pfnGetBaseMsr)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), pVCpu);
293 pdmUnlock(pVM);
294#endif
295 return VINF_SUCCESS;
296 }
297
298 *pu64Base = 0;
299 if (fIgnoreErrors)
300 return VINF_SUCCESS;
301
302#ifdef IN_RING3
303 LogRelMax(5, ("PDM: APIC%u: Reading APIC base MSR (%#x) invalid without an APIC instance -> #GP(0)\n", pVCpu->idCpu,
304 MSR_IA32_APICBASE));
305 return VERR_CPUM_RAISE_GP_0;
306#else
307 return VINF_CPUM_R3_MSR_WRITE;
308#endif
309}
310
311
312/**
313 * Check if the APIC has a pending interrupt/if a TPR change would active one.
314 *
315 * @returns VINF_SUCCESS or VERR_PDM_NO_APIC_INSTANCE.
316 * @param pVCpu The cross context virtual CPU structure.
317 * @param pfPending Pending state (out).
318 */
319VMM_INT_DECL(int) PDMApicHasPendingIrq(PVMCPU pVCpu, bool *pfPending)
320{
321 PVM pVM = pVCpu->CTX_SUFF(pVM);
322 if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns))
323 {
324 Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnHasPendingIrq));
325 pdmLock(pVM);
326 *pfPending = pVM->pdm.s.Apic.CTX_SUFF(pfnHasPendingIrq)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), pVCpu, NULL /*pu8PendingIrq*/);
327 pdmUnlock(pVM);
328 return VINF_SUCCESS;
329 }
330 return VERR_PDM_NO_APIC_INSTANCE;
331}
332
333
334/**
335 * Set the TPR (task priority register).
336 *
337 * @returns VBox status code.
338 * @param pVCpu The cross context virtual CPU structure.
339 * @param u8TPR The new TPR.
340 */
341VMMDECL(int) PDMApicSetTPR(PVMCPU pVCpu, uint8_t u8TPR)
342{
343 PVM pVM = pVCpu->CTX_SUFF(pVM);
344 if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns))
345 {
346 Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnSetTpr));
347 pdmLock(pVM);
348 pVM->pdm.s.Apic.CTX_SUFF(pfnSetTpr)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), pVCpu, u8TPR);
349 pdmUnlock(pVM);
350 return VINF_SUCCESS;
351 }
352 return VERR_PDM_NO_APIC_INSTANCE;
353}
354
355
356/**
357 * Get the TPR (task priority register).
358 *
359 * @returns VINF_SUCCESS or VERR_PDM_NO_APIC_INSTANCE.
360 * @param pVCpu The cross context virtual CPU structure.
361 * @param pu8TPR Where to store the TRP.
362 * @param pfPending Pending interrupt state (out, optional).
363 * @param pu8PendingIrq Where to store the highest-priority pending IRQ
364 * (out, optional).
365 *
366 * @remarks No-long-jump zone!!!
367 */
368VMMDECL(int) PDMApicGetTPR(PVMCPU pVCpu, uint8_t *pu8TPR, bool *pfPending, uint8_t *pu8PendingIrq)
369{
370 PVM pVM = pVCpu->CTX_SUFF(pVM);
371 PPDMDEVINS pApicIns = pVM->pdm.s.Apic.CTX_SUFF(pDevIns);
372 if (pApicIns)
373 {
374 /*
375 * Note! We don't acquire the PDM lock here as we're just reading
376 * information. Doing so causes massive contention as this
377 * function is called very often by each and every VCPU.
378 */
379 Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnGetTpr));
380 *pu8TPR = pVM->pdm.s.Apic.CTX_SUFF(pfnGetTpr)(pApicIns, pVCpu);
381 if (pfPending)
382 *pfPending = pVM->pdm.s.Apic.CTX_SUFF(pfnHasPendingIrq)(pApicIns, pVCpu, pu8PendingIrq);
383 return VINF_SUCCESS;
384 }
385 *pu8TPR = 0;
386 return VERR_PDM_NO_APIC_INSTANCE;
387}
388
389
390/**
391 * Write a MSR in APIC range.
392 *
393 * @returns Strict VBox status code.
394 * @param pVCpu The cross context virtual CPU structure.
395 * @param u32Reg MSR to write.
396 * @param u64Value Value to write.
397 */
398VMM_INT_DECL(VBOXSTRICTRC) PDMApicWriteMsr(PVMCPU pVCpu, uint32_t u32Reg, uint64_t u64Value)
399{
400 PVM pVM = pVCpu->CTX_SUFF(pVM);
401 if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns))
402 {
403 AssertPtr(pVM->pdm.s.Apic.CTX_SUFF(pfnWriteMsr));
404 return pVM->pdm.s.Apic.CTX_SUFF(pfnWriteMsr)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), pVCpu, u32Reg, u64Value);
405 }
406 return VERR_CPUM_RAISE_GP_0;
407}
408
409
410/**
411 * Read a MSR in APIC range.
412 *
413 * @returns Strict VBox status code.
414 * @param pVCpu The cross context virtual CPU structure.
415 * @param u32Reg MSR to read.
416 * @param pu64Value Where to store the value read.
417 */
418VMM_INT_DECL(VBOXSTRICTRC) PDMApicReadMsr(PVMCPU pVCpu, uint32_t u32Reg, uint64_t *pu64Value)
419{
420 PVM pVM = pVCpu->CTX_SUFF(pVM);
421 if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns))
422 {
423 AssertPtr(pVM->pdm.s.Apic.CTX_SUFF(pfnReadMsr));
424 return pVM->pdm.s.Apic.CTX_SUFF(pfnReadMsr)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), pVCpu, u32Reg, pu64Value);
425 }
426 return VERR_CPUM_RAISE_GP_0;
427}
428
429
430/**
431 * Gets the frequency of the APIC timer.
432 *
433 * @returns VBox status code.
434 * @param pVM The cross context VM structure.
435 * @param pu64Value Where to store the frequency.
436 */
437VMM_INT_DECL(int) PDMApicGetTimerFreq(PVM pVM, uint64_t *pu64Value)
438{
439 if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns))
440 {
441 AssertPtr(pVM->pdm.s.Apic.CTX_SUFF(pfnGetTimerFreq));
442 *pu64Value = pVM->pdm.s.Apic.CTX_SUFF(pfnGetTimerFreq)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns));
443 return VINF_SUCCESS;
444 }
445 return VERR_PDM_NO_APIC_INSTANCE;
446}
447
448
449/**
450 * Locks PDM.
451 * This might call back to Ring-3 in order to deal with lock contention in GC and R3.
452 *
453 * @param pVM The cross context VM structure.
454 */
455void pdmLock(PVM pVM)
456{
457#ifdef IN_RING3
458 int rc = PDMCritSectEnter(&pVM->pdm.s.CritSect, VERR_IGNORED);
459#else
460 int rc = PDMCritSectEnter(&pVM->pdm.s.CritSect, VERR_GENERAL_FAILURE);
461 if (rc == VERR_GENERAL_FAILURE)
462 rc = VMMRZCallRing3NoCpu(pVM, VMMCALLRING3_PDM_LOCK, 0);
463#endif
464 AssertRC(rc);
465}
466
467
468/**
469 * Locks PDM but don't go to ring-3 if it's owned by someone.
470 *
471 * @returns VINF_SUCCESS on success.
472 * @returns rc if we're in GC or R0 and can't get the lock.
473 * @param pVM The cross context VM structure.
474 * @param rc The RC to return in GC or R0 when we can't get the lock.
475 */
476int pdmLockEx(PVM pVM, int rc)
477{
478 return PDMCritSectEnter(&pVM->pdm.s.CritSect, rc);
479}
480
481
482/**
483 * Unlocks PDM.
484 *
485 * @param pVM The cross context VM structure.
486 */
487void pdmUnlock(PVM pVM)
488{
489 PDMCritSectLeave(&pVM->pdm.s.CritSect);
490}
491
492
493/**
494 * Converts ring 3 VMM heap pointer to a guest physical address
495 *
496 * @returns VBox status code.
497 * @param pVM The cross context VM structure.
498 * @param pv Ring-3 pointer.
499 * @param pGCPhys GC phys address (out).
500 */
501VMM_INT_DECL(int) PDMVmmDevHeapR3ToGCPhys(PVM pVM, RTR3PTR pv, RTGCPHYS *pGCPhys)
502{
503 if (RT_LIKELY(pVM->pdm.s.GCPhysVMMDevHeap != NIL_RTGCPHYS))
504 {
505 RTR3UINTPTR const offHeap = (RTR3UINTPTR)pv - (RTR3UINTPTR)pVM->pdm.s.pvVMMDevHeap;
506 if (RT_LIKELY(offHeap < pVM->pdm.s.cbVMMDevHeap))
507 {
508 *pGCPhys = pVM->pdm.s.GCPhysVMMDevHeap + offHeap;
509 return VINF_SUCCESS;
510 }
511
512 /* Don't assert here as this is called before we can catch ring-0 assertions. */
513 Log(("PDMVmmDevHeapR3ToGCPhys: pv=%p pvVMMDevHeap=%p cbVMMDevHeap=%#x\n",
514 pv, pVM->pdm.s.pvVMMDevHeap, pVM->pdm.s.cbVMMDevHeap));
515 }
516 else
517 Log(("PDMVmmDevHeapR3ToGCPhys: GCPhysVMMDevHeap=%RGp (pv=%p)\n", pVM->pdm.s.GCPhysVMMDevHeap, pv));
518 return VERR_PDM_DEV_HEAP_R3_TO_GCPHYS;
519}
520
521
522/**
523 * Checks if the vmm device heap is enabled (== vmm device's pci region mapped)
524 *
525 * @returns dev heap enabled status (true/false)
526 * @param pVM The cross context VM structure.
527 */
528VMM_INT_DECL(bool) PDMVmmDevHeapIsEnabled(PVM pVM)
529{
530 return pVM->pdm.s.GCPhysVMMDevHeap != NIL_RTGCPHYS;
531}
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