VirtualBox

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

Last change on this file since 37452 was 37452, checked in by vboxsync, 14 years ago

IOM,PDMCritSect: Extended PDMCritSectEnter to handle rcBusy=VINF_SUCCESS as a request to call ring-3 to acquire a busy lock. Implemented device level locking in the MMIO code.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 11.9 KB
Line 
1/* $Id: PDMAll.cpp 37452 2011-06-14 18:13:48Z 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/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
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 higher 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 * Send a MSI to an I/O APIC.
158 *
159 * @returns VBox status code.
160 * @param pVM VM handle.
161 * @param GCAddr Request address.
162 * @param u8Value Request value.
163 */
164VMMDECL(int) PDMIoApicSendMsi(PVM pVM, RTGCPHYS GCAddr, uint32_t uValue)
165{
166 if (pVM->pdm.s.IoApic.CTX_SUFF(pDevIns))
167 {
168 Assert(pVM->pdm.s.IoApic.CTX_SUFF(pfnSendMsi));
169 pdmLock(pVM);
170 pVM->pdm.s.IoApic.CTX_SUFF(pfnSendMsi)(pVM->pdm.s.IoApic.CTX_SUFF(pDevIns), GCAddr, uValue);
171 pdmUnlock(pVM);
172 return VINF_SUCCESS;
173 }
174 return VERR_PDM_NO_PIC_INSTANCE;
175}
176
177
178
179/**
180 * Returns presence of an IO-APIC
181 *
182 * @returns VBox true if IO-APIC is present
183 * @param pVM VM handle.
184 */
185VMMDECL(bool) PDMHasIoApic(PVM pVM)
186{
187 return pVM->pdm.s.IoApic.CTX_SUFF(pDevIns) != NULL;
188}
189
190
191/**
192 * Set the APIC base.
193 *
194 * @returns VBox status code.
195 * @param pVM VM handle.
196 * @param u64Base The new base.
197 */
198VMMDECL(int) PDMApicSetBase(PVM pVM, uint64_t u64Base)
199{
200 if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns))
201 {
202 Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnSetBase));
203 pdmLock(pVM);
204 pVM->pdm.s.Apic.CTX_SUFF(pfnSetBase)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), u64Base);
205 pdmUnlock(pVM);
206 return VINF_SUCCESS;
207 }
208 return VERR_PDM_NO_APIC_INSTANCE;
209}
210
211
212/**
213 * Get the APIC base.
214 *
215 * @returns VBox status code.
216 * @param pVM VM handle.
217 * @param pu64Base Where to store the APIC base.
218 */
219VMMDECL(int) PDMApicGetBase(PVM pVM, uint64_t *pu64Base)
220{
221 if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns))
222 {
223 Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnGetBase));
224 pdmLock(pVM);
225 *pu64Base = pVM->pdm.s.Apic.CTX_SUFF(pfnGetBase)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns));
226 pdmUnlock(pVM);
227 return VINF_SUCCESS;
228 }
229 *pu64Base = 0;
230 return VERR_PDM_NO_APIC_INSTANCE;
231}
232
233
234/**
235 * Check if the APIC has a pending interrupt/if a TPR change would active one.
236 *
237 * @returns VINF_SUCCESS or VERR_PDM_NO_APIC_INSTANCE.
238 * @param pDevIns Device instance of the APIC.
239 * @param pfPending Pending state (out).
240 */
241VMMDECL(int) PDMApicHasPendingIrq(PVM pVM, bool *pfPending)
242{
243 if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns))
244 {
245 Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnSetTPR));
246 pdmLock(pVM);
247 *pfPending = pVM->pdm.s.Apic.CTX_SUFF(pfnHasPendingIrq)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns));
248 pdmUnlock(pVM);
249 return VINF_SUCCESS;
250 }
251 return VERR_PDM_NO_APIC_INSTANCE;
252}
253
254
255/**
256 * Set the TPR (task priority register?).
257 *
258 * @returns VBox status code.
259 * @param pVCpu VMCPU handle.
260 * @param u8TPR The new TPR.
261 */
262VMMDECL(int) PDMApicSetTPR(PVMCPU pVCpu, uint8_t u8TPR)
263{
264 PVM pVM = pVCpu->CTX_SUFF(pVM);
265 if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns))
266 {
267 Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnSetTPR));
268 pdmLock(pVM);
269 pVM->pdm.s.Apic.CTX_SUFF(pfnSetTPR)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), pVCpu->idCpu, u8TPR);
270 pdmUnlock(pVM);
271 return VINF_SUCCESS;
272 }
273 return VERR_PDM_NO_APIC_INSTANCE;
274}
275
276
277/**
278 * Get the TPR (task priority register).
279 *
280 * @returns The current TPR.
281 * @param pVCpu VMCPU handle.
282 * @param pu8TPR Where to store the TRP.
283 * @param pfPending Pending interrupt state (out).
284*/
285VMMDECL(int) PDMApicGetTPR(PVMCPU pVCpu, uint8_t *pu8TPR, bool *pfPending)
286{
287 PVM pVM = pVCpu->CTX_SUFF(pVM);
288 if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns))
289 {
290 Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnGetTPR));
291 /* We don't acquire the PDM lock here as we're just reading information. Doing so causes massive
292 * contention as this function is called very often by each and every VCPU.
293 */
294 *pu8TPR = pVM->pdm.s.Apic.CTX_SUFF(pfnGetTPR)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), pVCpu->idCpu);
295 if (pfPending)
296 *pfPending = pVM->pdm.s.Apic.CTX_SUFF(pfnHasPendingIrq)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns));
297 return VINF_SUCCESS;
298 }
299 *pu8TPR = 0;
300 return VERR_PDM_NO_APIC_INSTANCE;
301}
302
303
304/**
305 * Write a MSR in APIC range.
306 *
307 * @returns VBox status code.
308 * @param pVM VM handle.
309 * @param iCpu Target CPU.
310 * @param u32Reg MSR to write.
311 * @param u64Value Value to write.
312 */
313VMMDECL(int) PDMApicWriteMSR(PVM pVM, VMCPUID iCpu, uint32_t u32Reg, uint64_t u64Value)
314{
315 if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns))
316 {
317 Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnWriteMSR));
318 pdmLock(pVM);
319 pVM->pdm.s.Apic.CTX_SUFF(pfnWriteMSR)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), iCpu, u32Reg, u64Value);
320 pdmUnlock(pVM);
321 return VINF_SUCCESS;
322 }
323 return VERR_PDM_NO_APIC_INSTANCE;
324}
325
326
327/**
328 * Read a MSR in APIC range.
329 *
330 * @returns VBox status code.
331 * @param pVM VM handle.
332 * @param iCpu Target CPU.
333 * @param u32Reg MSR to read.
334 * @param pu64Value Value read.
335 */
336VMMDECL(int) PDMApicReadMSR(PVM pVM, VMCPUID iCpu, uint32_t u32Reg, uint64_t *pu64Value)
337{
338 if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns))
339 {
340 Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnReadMSR));
341 pdmLock(pVM);
342 pVM->pdm.s.Apic.CTX_SUFF(pfnReadMSR)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), iCpu, u32Reg, pu64Value);
343 pdmUnlock(pVM);
344 return VINF_SUCCESS;
345 }
346 return VERR_PDM_NO_APIC_INSTANCE;
347}
348
349
350/**
351 * Locks PDM.
352 * This might call back to Ring-3 in order to deal with lock contention in GC and R3.
353 *
354 * @param pVM The VM handle.
355 */
356void pdmLock(PVM pVM)
357{
358#ifdef IN_RING3
359 int rc = PDMCritSectEnter(&pVM->pdm.s.CritSect, VERR_INTERNAL_ERROR);
360#else
361 int rc = PDMCritSectEnter(&pVM->pdm.s.CritSect, VERR_GENERAL_FAILURE);
362 if (rc == VERR_GENERAL_FAILURE)
363 rc = VMMRZCallRing3NoCpu(pVM, VMMCALLRING3_PDM_LOCK, 0);
364#endif
365 AssertRC(rc);
366}
367
368
369/**
370 * Locks PDM but don't go to ring-3 if it's owned by someone.
371 *
372 * @returns VINF_SUCCESS on success.
373 * @returns rc if we're in GC or R0 and can't get the lock.
374 * @param pVM The VM handle.
375 * @param rc The RC to return in GC or R0 when we can't get the lock.
376 */
377int pdmLockEx(PVM pVM, int rc)
378{
379 return PDMCritSectEnter(&pVM->pdm.s.CritSect, rc);
380}
381
382
383/**
384 * Unlocks PDM.
385 *
386 * @param pVM The VM handle.
387 */
388void pdmUnlock(PVM pVM)
389{
390 PDMCritSectLeave(&pVM->pdm.s.CritSect);
391}
392
393
394/**
395 * Converts ring 3 VMM heap pointer to a guest physical address
396 *
397 * @returns VBox status code.
398 * @param pVM VM handle.
399 * @param pv Ring-3 pointer.
400 * @param pGCPhys GC phys address (out).
401 */
402VMMDECL(int) PDMVMMDevHeapR3ToGCPhys(PVM pVM, RTR3PTR pv, RTGCPHYS *pGCPhys)
403{
404 /* Don't assert here as this is called before we can catch ring-0 assertions. */
405 if (RT_UNLIKELY((RTR3UINTPTR)pv - (RTR3UINTPTR)pVM->pdm.s.pvVMMDevHeap >= pVM->pdm.s.cbVMMDevHeap))
406 {
407 Log(("PDMVMMDevHeapR3ToGCPhys: pv=%p pvVMMDevHeap=%p cbVMMDevHeap=%#x\n",
408 pv, pVM->pdm.s.pvVMMDevHeap, pVM->pdm.s.cbVMMDevHeap));
409 return VERR_INTERNAL_ERROR_3;
410 }
411
412 *pGCPhys = (pVM->pdm.s.GCPhysVMMDevHeap + ((RTR3UINTPTR)pv - (RTR3UINTPTR)pVM->pdm.s.pvVMMDevHeap));
413 return VINF_SUCCESS;
414}
415
416/**
417 * Checks if the vmm device heap is enabled (== vmm device's pci region mapped)
418 *
419 * @returns dev heap enabled status (true/false)
420 * @param pVM VM handle.
421 */
422VMMDECL(bool) PDMVMMDevHeapIsEnabled(PVM pVM)
423{
424 return (pVM->pdm.s.pvVMMDevHeap != NULL);
425}
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