VirtualBox

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

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

Automated rebranding to Oracle copyright/license strings via filemuncher

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 11.3 KB
Line 
1/* $Id: PDMAll.cpp 28800 2010-04-27 08:22:32Z vboxsync $ */
2/** @file
3 * PDM Critical Sections
4 */
5
6/*
7 * Copyright (C) 2006-2007 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/pdm.h>
25#include <VBox/mm.h>
26#include <VBox/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
34/**
35 * Gets the pending interrupt.
36 *
37 * @returns VBox status code.
38 * @param pVCpu VMCPU handle.
39 * @param pu8Interrupt Where to store the interrupt on success.
40 */
41VMMDECL(int) PDMGetInterrupt(PVMCPU pVCpu, uint8_t *pu8Interrupt)
42{
43 PVM pVM = pVCpu->CTX_SUFF(pVM);
44
45 pdmLock(pVM);
46
47 /*
48 * The local APIC has a higer priority than the PIC.
49 */
50 if (VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_APIC))
51 {
52 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_APIC);
53 Assert(pVM->pdm.s.Apic.CTX_SUFF(pDevIns));
54 Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnGetInterrupt));
55 int i = pVM->pdm.s.Apic.CTX_SUFF(pfnGetInterrupt)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns));
56 AssertMsg(i <= 255 && i >= 0, ("i=%d\n", i));
57 if (i >= 0)
58 {
59 pdmUnlock(pVM);
60 *pu8Interrupt = (uint8_t)i;
61 return VINF_SUCCESS;
62 }
63 }
64
65 /*
66 * Check the PIC.
67 */
68 if (VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_PIC))
69 {
70 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_PIC);
71 Assert(pVM->pdm.s.Pic.CTX_SUFF(pDevIns));
72 Assert(pVM->pdm.s.Pic.CTX_SUFF(pfnGetInterrupt));
73 int i = pVM->pdm.s.Pic.CTX_SUFF(pfnGetInterrupt)(pVM->pdm.s.Pic.CTX_SUFF(pDevIns));
74 AssertMsg(i <= 255 && i >= 0, ("i=%d\n", i));
75 if (i >= 0)
76 {
77 pdmUnlock(pVM);
78 *pu8Interrupt = (uint8_t)i;
79 return VINF_SUCCESS;
80 }
81 }
82
83 /** @todo Figure out exactly why we can get here without anything being set. (REM) */
84
85 pdmUnlock(pVM);
86 return VERR_NO_DATA;
87}
88
89
90/**
91 * Sets the pending interrupt coming from ISA source or HPET.
92 *
93 * @returns VBox status code.
94 * @param pVM VM handle.
95 * @param u8Irq The IRQ line.
96 * @param u8Level The new level.
97 */
98VMMDECL(int) PDMIsaSetIrq(PVM pVM, uint8_t u8Irq, uint8_t u8Level)
99{
100 pdmLock(pVM);
101
102 int rc = VERR_PDM_NO_PIC_INSTANCE;
103 if (pVM->pdm.s.Pic.CTX_SUFF(pDevIns))
104 {
105 Assert(pVM->pdm.s.Pic.CTX_SUFF(pfnSetIrq));
106 pVM->pdm.s.Pic.CTX_SUFF(pfnSetIrq)(pVM->pdm.s.Pic.CTX_SUFF(pDevIns), u8Irq, u8Level);
107 rc = VINF_SUCCESS;
108 }
109
110 if (pVM->pdm.s.IoApic.CTX_SUFF(pDevIns))
111 {
112 Assert(pVM->pdm.s.IoApic.CTX_SUFF(pfnSetIrq));
113
114 /**
115 * Apply Interrupt Source Override rules.
116 * See ACPI 4.0 specification 5.2.12.4 and 5.2.12.5 for details on
117 * interrupt source override.
118 * Shortly, ISA IRQ0 is electically connected to pin 2 on IO-APIC, and some OSes,
119 * notably recent OS X rely upon this configuration.
120 * If changing, also update override rules in MADT and MPS.
121 */
122 /* ISA IRQ0 routed to pin 2, all others ISA sources are identity mapped */
123 if (u8Irq == 0)
124 u8Irq = 2;
125
126 pVM->pdm.s.IoApic.CTX_SUFF(pfnSetIrq)(pVM->pdm.s.IoApic.CTX_SUFF(pDevIns), u8Irq, u8Level);
127 rc = VINF_SUCCESS;
128 }
129
130 pdmUnlock(pVM);
131 return rc;
132}
133
134
135/**
136 * Sets the pending I/O APIC interrupt.
137 *
138 * @returns VBox status code.
139 * @param pVM VM handle.
140 * @param u8Irq The IRQ line.
141 * @param u8Level The new level.
142 */
143VMMDECL(int) PDMIoApicSetIrq(PVM pVM, uint8_t u8Irq, uint8_t u8Level)
144{
145 if (pVM->pdm.s.IoApic.CTX_SUFF(pDevIns))
146 {
147 Assert(pVM->pdm.s.IoApic.CTX_SUFF(pfnSetIrq));
148 pdmLock(pVM);
149 pVM->pdm.s.IoApic.CTX_SUFF(pfnSetIrq)(pVM->pdm.s.IoApic.CTX_SUFF(pDevIns), u8Irq, u8Level);
150 pdmUnlock(pVM);
151 return VINF_SUCCESS;
152 }
153 return VERR_PDM_NO_PIC_INSTANCE;
154}
155
156
157/**
158 * Returns presence of an IO-APIC
159 *
160 * @returns VBox true if IO-APIC is present
161 * @param pVM VM handle.
162 */
163VMMDECL(bool) PDMHasIoApic(PVM pVM)
164{
165 return pVM->pdm.s.IoApic.CTX_SUFF(pDevIns) != NULL;
166}
167
168
169/**
170 * Set the APIC base.
171 *
172 * @returns VBox status code.
173 * @param pVM VM handle.
174 * @param u64Base The new base.
175 */
176VMMDECL(int) PDMApicSetBase(PVM pVM, uint64_t u64Base)
177{
178 if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns))
179 {
180 Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnSetBase));
181 pdmLock(pVM);
182 pVM->pdm.s.Apic.CTX_SUFF(pfnSetBase)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), u64Base);
183 pdmUnlock(pVM);
184 return VINF_SUCCESS;
185 }
186 return VERR_PDM_NO_APIC_INSTANCE;
187}
188
189
190/**
191 * Get the APIC base.
192 *
193 * @returns VBox status code.
194 * @param pVM VM handle.
195 * @param pu64Base Where to store the APIC base.
196 */
197VMMDECL(int) PDMApicGetBase(PVM pVM, uint64_t *pu64Base)
198{
199 if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns))
200 {
201 Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnGetBase));
202 pdmLock(pVM);
203 *pu64Base = pVM->pdm.s.Apic.CTX_SUFF(pfnGetBase)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns));
204 pdmUnlock(pVM);
205 return VINF_SUCCESS;
206 }
207 *pu64Base = 0;
208 return VERR_PDM_NO_APIC_INSTANCE;
209}
210
211
212/**
213 * Check if the APIC has a pending interrupt/if a TPR change would active one.
214 *
215 * @returns VINF_SUCCESS or VERR_PDM_NO_APIC_INSTANCE.
216 * @param pDevIns Device instance of the APIC.
217 * @param pfPending Pending state (out).
218 */
219VMMDECL(int) PDMApicHasPendingIrq(PVM pVM, bool *pfPending)
220{
221 if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns))
222 {
223 Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnSetTPR));
224 pdmLock(pVM);
225 *pfPending = pVM->pdm.s.Apic.CTX_SUFF(pfnHasPendingIrq)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns));
226 pdmUnlock(pVM);
227 return VINF_SUCCESS;
228 }
229 return VERR_PDM_NO_APIC_INSTANCE;
230}
231
232
233/**
234 * Set the TPR (task priority register?).
235 *
236 * @returns VBox status code.
237 * @param pVCpu VMCPU handle.
238 * @param u8TPR The new TPR.
239 */
240VMMDECL(int) PDMApicSetTPR(PVMCPU pVCpu, uint8_t u8TPR)
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(pfnSetTPR));
246 pdmLock(pVM);
247 pVM->pdm.s.Apic.CTX_SUFF(pfnSetTPR)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), pVCpu->idCpu, u8TPR);
248 pdmUnlock(pVM);
249 return VINF_SUCCESS;
250 }
251 return VERR_PDM_NO_APIC_INSTANCE;
252}
253
254
255/**
256 * Get the TPR (task priority register).
257 *
258 * @returns The current TPR.
259 * @param pVCpu VMCPU handle.
260 * @param pu8TPR Where to store the TRP.
261 * @param pfPending Pending interrupt state (out).
262*/
263VMMDECL(int) PDMApicGetTPR(PVMCPU pVCpu, uint8_t *pu8TPR, bool *pfPending)
264{
265 PVM pVM = pVCpu->CTX_SUFF(pVM);
266 if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns))
267 {
268 Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnGetTPR));
269 /* We don't acquire the PDM lock here as we're just reading information. Doing so causes massive
270 * contention as this function is called very often by each and every VCPU.
271 */
272 *pu8TPR = pVM->pdm.s.Apic.CTX_SUFF(pfnGetTPR)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), pVCpu->idCpu);
273 if (pfPending)
274 *pfPending = pVM->pdm.s.Apic.CTX_SUFF(pfnHasPendingIrq)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns));
275 return VINF_SUCCESS;
276 }
277 *pu8TPR = 0;
278 return VERR_PDM_NO_APIC_INSTANCE;
279}
280
281/**
282 * Write MSR in APIC range.
283 *
284 * @returns VBox status code.
285 * @param pVM VM handle.
286 * @param iCpu Target CPU.
287 * @param u32Reg MSR to write.
288 * @param u64Value Value to write.
289 */
290VMMDECL(int) PDMApicWriteMSR(PVM pVM, VMCPUID iCpu, uint32_t u32Reg, uint64_t u64Value)
291{
292 if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns))
293 {
294 Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnWriteMSR));
295 pdmLock(pVM);
296 pVM->pdm.s.Apic.CTX_SUFF(pfnWriteMSR)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), iCpu, u32Reg, u64Value);
297 pdmUnlock(pVM);
298 return VINF_SUCCESS;
299 }
300 return VERR_PDM_NO_APIC_INSTANCE;
301}
302
303/**
304 * Read MSR in APIC range.
305 *
306 * @returns VBox status code.
307 * @param pVM VM handle.
308 * @param iCpu Target CPU.
309 * @param u32Reg MSR to read.
310 * @param pu64Value Value read.
311 */
312VMMDECL(int) PDMApicReadMSR(PVM pVM, VMCPUID iCpu, uint32_t u32Reg, uint64_t *pu64Value)
313{
314 if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns))
315 {
316 Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnReadMSR));
317 pdmLock(pVM);
318 pVM->pdm.s.Apic.CTX_SUFF(pfnReadMSR)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), iCpu, u32Reg, pu64Value);
319 pdmUnlock(pVM);
320 return VINF_SUCCESS;
321 }
322 return VERR_PDM_NO_APIC_INSTANCE;
323}
324
325
326/**
327 * Locks PDM.
328 * This might call back to Ring-3 in order to deal with lock contention in GC and R3.
329 *
330 * @param pVM The VM handle.
331 */
332void pdmLock(PVM pVM)
333{
334#ifdef IN_RING3
335 int rc = PDMCritSectEnter(&pVM->pdm.s.CritSect, VERR_INTERNAL_ERROR);
336#else
337 int rc = PDMCritSectEnter(&pVM->pdm.s.CritSect, VERR_GENERAL_FAILURE);
338 if (rc == VERR_GENERAL_FAILURE)
339 rc = VMMRZCallRing3NoCpu(pVM, VMMCALLRING3_PDM_LOCK, 0);
340#endif
341 AssertRC(rc);
342}
343
344
345/**
346 * Locks PDM but don't go to ring-3 if it's owned by someone.
347 *
348 * @returns VINF_SUCCESS on success.
349 * @returns rc if we're in GC or R0 and can't get the lock.
350 * @param pVM The VM handle.
351 * @param rc The RC to return in GC or R0 when we can't get the lock.
352 */
353int pdmLockEx(PVM pVM, int rc)
354{
355 return PDMCritSectEnter(&pVM->pdm.s.CritSect, rc);
356}
357
358
359/**
360 * Unlocks PDM.
361 *
362 * @param pVM The VM handle.
363 */
364void pdmUnlock(PVM pVM)
365{
366 PDMCritSectLeave(&pVM->pdm.s.CritSect);
367}
368
369
370/**
371 * Converts ring 3 VMM heap pointer to a guest physical address
372 *
373 * @returns VBox status code.
374 * @param pVM VM handle.
375 * @param pv Ring-3 pointer.
376 * @param pGCPhys GC phys address (out).
377 */
378VMMDECL(int) PDMVMMDevHeapR3ToGCPhys(PVM pVM, RTR3PTR pv, RTGCPHYS *pGCPhys)
379{
380 /* Don't assert here as this is called before we can catch ring-0 assertions. */
381 if (RT_UNLIKELY((RTR3UINTPTR)pv - (RTR3UINTPTR)pVM->pdm.s.pvVMMDevHeap >= pVM->pdm.s.cbVMMDevHeap))
382 {
383 Log(("PDMVMMDevHeapR3ToGCPhys: pv=%p pvVMMDevHeap=%p cbVMMDevHeap=%#x\n",
384 pv, pVM->pdm.s.pvVMMDevHeap, pVM->pdm.s.cbVMMDevHeap));
385 return VERR_INTERNAL_ERROR_3;
386 }
387
388 *pGCPhys = (pVM->pdm.s.GCPhysVMMDevHeap + ((RTR3UINTPTR)pv - (RTR3UINTPTR)pVM->pdm.s.pvVMMDevHeap));
389 return VINF_SUCCESS;
390}
391
392/**
393 * Checks if the vmm device heap is enabled (== vmm device's pci region mapped)
394 *
395 * @returns dev heap enabled status (true/false)
396 * @param pVM VM handle.
397 */
398VMMDECL(bool) PDMVMMDevHeapIsEnabled(PVM pVM)
399{
400 return (pVM->pdm.s.pvVMMDevHeap != NULL);
401}
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