VirtualBox

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

Last change on this file since 19602 was 19141, checked in by vboxsync, 16 years ago

Action flags breakup.
Fixed PGM saved state loading of 2.2.2 images.
Reduced hacks in PATM state loading (fixups).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 10.0 KB
Line 
1/* $Id: PDMAll.cpp 19141 2009-04-23 13:52:18Z vboxsync $ */
2/** @file
3 * PDM Critical Sections
4 */
5
6/*
7 * Copyright (C) 2006-2007 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
27#include "PDMInternal.h"
28#include <VBox/pdm.h>
29#include <VBox/mm.h>
30#include <VBox/vm.h>
31#include <VBox/err.h>
32
33#include <VBox/log.h>
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36
37
38/**
39 * Gets the pending interrupt.
40 *
41 * @returns VBox status code.
42 * @param pVCpu VMCPU handle.
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 pdmLock(pVM);
50
51 /*
52 * The local APIC has a higer priority than the PIC.
53 */
54 if (VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_APIC))
55 {
56 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_APIC);
57 Assert(pVM->pdm.s.Apic.CTX_SUFF(pDevIns));
58 Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnGetInterrupt));
59 int i = pVM->pdm.s.Apic.CTX_SUFF(pfnGetInterrupt)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns));
60 AssertMsg(i <= 255 && i >= 0, ("i=%d\n", i));
61 if (i >= 0)
62 {
63 pdmUnlock(pVM);
64 *pu8Interrupt = (uint8_t)i;
65 return VINF_SUCCESS;
66 }
67 }
68
69 /*
70 * Check the PIC.
71 */
72 if (VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_PIC))
73 {
74 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_PIC);
75 Assert(pVM->pdm.s.Pic.CTX_SUFF(pDevIns));
76 Assert(pVM->pdm.s.Pic.CTX_SUFF(pfnGetInterrupt));
77 int i = pVM->pdm.s.Pic.CTX_SUFF(pfnGetInterrupt)(pVM->pdm.s.Pic.CTX_SUFF(pDevIns));
78 AssertMsg(i <= 255 && i >= 0, ("i=%d\n", i));
79 if (i >= 0)
80 {
81 pdmUnlock(pVM);
82 *pu8Interrupt = (uint8_t)i;
83 return VINF_SUCCESS;
84 }
85 }
86
87 /** @todo Figure out exactly why we can get here without anything being set. (REM) */
88
89 pdmUnlock(pVM);
90 return VERR_NO_DATA;
91}
92
93
94/**
95 * Sets the pending interrupt.
96 *
97 * @returns VBox status code.
98 * @param pVM VM handle.
99 * @param u8Irq The IRQ line.
100 * @param u8Level The new level.
101 */
102VMMDECL(int) PDMIsaSetIrq(PVM pVM, uint8_t u8Irq, uint8_t u8Level)
103{
104 pdmLock(pVM);
105
106 int rc = VERR_PDM_NO_PIC_INSTANCE;
107 if (pVM->pdm.s.Pic.CTX_SUFF(pDevIns))
108 {
109 Assert(pVM->pdm.s.Pic.CTX_SUFF(pfnSetIrq));
110 pVM->pdm.s.Pic.CTX_SUFF(pfnSetIrq)(pVM->pdm.s.Pic.CTX_SUFF(pDevIns), u8Irq, u8Level);
111 rc = VINF_SUCCESS;
112 }
113
114 if (pVM->pdm.s.IoApic.CTX_SUFF(pDevIns))
115 {
116 Assert(pVM->pdm.s.IoApic.CTX_SUFF(pfnSetIrq));
117 pVM->pdm.s.IoApic.CTX_SUFF(pfnSetIrq)(pVM->pdm.s.IoApic.CTX_SUFF(pDevIns), u8Irq, u8Level);
118 rc = VINF_SUCCESS;
119 }
120
121 pdmUnlock(pVM);
122 return rc;
123}
124
125
126/**
127 * Sets the pending I/O APIC interrupt.
128 *
129 * @returns VBox status code.
130 * @param pVM VM handle.
131 * @param u8Irq The IRQ line.
132 * @param u8Level The new level.
133 */
134VMMDECL(int) PDMIoApicSetIrq(PVM pVM, uint8_t u8Irq, uint8_t u8Level)
135{
136 if (pVM->pdm.s.IoApic.CTX_SUFF(pDevIns))
137 {
138 Assert(pVM->pdm.s.IoApic.CTX_SUFF(pfnSetIrq));
139 pdmLock(pVM);
140 pVM->pdm.s.IoApic.CTX_SUFF(pfnSetIrq)(pVM->pdm.s.IoApic.CTX_SUFF(pDevIns), u8Irq, u8Level);
141 pdmUnlock(pVM);
142 return VINF_SUCCESS;
143 }
144 return VERR_PDM_NO_PIC_INSTANCE;
145}
146
147
148/**
149 * Set the APIC base.
150 *
151 * @returns VBox status code.
152 * @param pVM VM handle.
153 * @param u64Base The new base.
154 */
155VMMDECL(int) PDMApicSetBase(PVM pVM, uint64_t u64Base)
156{
157 if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns))
158 {
159 Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnSetBase));
160 pdmLock(pVM);
161 pVM->pdm.s.Apic.CTX_SUFF(pfnSetBase)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), u64Base);
162 pdmUnlock(pVM);
163 return VINF_SUCCESS;
164 }
165 return VERR_PDM_NO_APIC_INSTANCE;
166}
167
168
169/**
170 * Get the APIC base.
171 *
172 * @returns VBox status code.
173 * @param pVM VM handle.
174 * @param pu64Base Where to store the APIC base.
175 */
176VMMDECL(int) PDMApicGetBase(PVM pVM, uint64_t *pu64Base)
177{
178 if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns))
179 {
180 Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnGetBase));
181 pdmLock(pVM);
182 *pu64Base = pVM->pdm.s.Apic.CTX_SUFF(pfnGetBase)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns));
183 pdmUnlock(pVM);
184 return VINF_SUCCESS;
185 }
186 *pu64Base = 0;
187 return VERR_PDM_NO_APIC_INSTANCE;
188}
189
190
191/**
192 * Check if the APIC has a pending interrupt/if a TPR change would active one.
193 *
194 * @returns VINF_SUCCESS or VERR_PDM_NO_APIC_INSTANCE.
195 * @param pDevIns Device instance of the APIC.
196 * @param pfPending Pending state (out).
197 */
198VMMDECL(int) PDMApicHasPendingIrq(PVM pVM, bool *pfPending)
199{
200 if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns))
201 {
202 Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnSetTPR));
203 pdmLock(pVM);
204 *pfPending = pVM->pdm.s.Apic.CTX_SUFF(pfnHasPendingIrq)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns));
205 pdmUnlock(pVM);
206 return VINF_SUCCESS;
207 }
208 return VERR_PDM_NO_APIC_INSTANCE;
209}
210
211
212/**
213 * Set the TPR (task priority register?).
214 *
215 * @returns VBox status code.
216 * @param pVM VM handle.
217 * @param u8TPR The new TPR.
218 */
219VMMDECL(int) PDMApicSetTPR(PVM pVM, uint8_t u8TPR)
220{
221 if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns))
222 {
223 Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnSetTPR));
224 pdmLock(pVM);
225 pVM->pdm.s.Apic.CTX_SUFF(pfnSetTPR)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), u8TPR);
226 pdmUnlock(pVM);
227 return VINF_SUCCESS;
228 }
229 return VERR_PDM_NO_APIC_INSTANCE;
230}
231
232
233/**
234 * Get the TPR (task priority register).
235 *
236 * @returns The current TPR.
237 * @param pVM VM handle.
238 * @param pu8TPR Where to store the TRP.
239 * @param pfPending Pending interrupt state (out).
240*/
241VMMDECL(int) PDMApicGetTPR(PVM pVM, uint8_t *pu8TPR, bool *pfPending)
242{
243 if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns))
244 {
245 Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnGetTPR));
246 pdmLock(pVM);
247 *pu8TPR = pVM->pdm.s.Apic.CTX_SUFF(pfnGetTPR)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns));
248 if (pfPending)
249 *pfPending = pVM->pdm.s.Apic.CTX_SUFF(pfnHasPendingIrq)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns));
250 pdmUnlock(pVM);
251 return VINF_SUCCESS;
252 }
253 *pu8TPR = 0;
254 return VERR_PDM_NO_APIC_INSTANCE;
255}
256
257/**
258 * Write MSR in APIC range.
259 *
260 * @returns VBox status code.
261 * @param pVM VM handle.
262 * @param iCpu Target CPU.
263 * @param u32Reg MSR to write.
264 * @param u64Value Value to write.
265 */
266VMMDECL(int) PDMApicWriteMSR(PVM pVM, VMCPUID iCpu, uint32_t u32Reg, uint64_t u64Value)
267{
268 if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns))
269 {
270 Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnWriteMSR));
271 pdmLock(pVM);
272 pVM->pdm.s.Apic.CTX_SUFF(pfnWriteMSR)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), iCpu, u32Reg, u64Value);
273 pdmUnlock(pVM);
274 return VINF_SUCCESS;
275 }
276 return VERR_PDM_NO_APIC_INSTANCE;
277}
278
279/**
280 * Read MSR in APIC range.
281 *
282 * @returns VBox status code.
283 * @param pVM VM handle.
284 * @param iCpu Target CPU.
285 * @param u32Reg MSR to read.
286 * @param pu64Value Value read.
287 */
288VMMDECL(int) PDMApicReadMSR(PVM pVM, VMCPUID iCpu, uint32_t u32Reg, uint64_t *pu64Value)
289{
290 if (pVM->pdm.s.Apic.CTX_SUFF(pDevIns))
291 {
292 Assert(pVM->pdm.s.Apic.CTX_SUFF(pfnReadMSR));
293 pdmLock(pVM);
294 pVM->pdm.s.Apic.CTX_SUFF(pfnReadMSR)(pVM->pdm.s.Apic.CTX_SUFF(pDevIns), iCpu, u32Reg, pu64Value);
295 pdmUnlock(pVM);
296 return VINF_SUCCESS;
297 }
298 return VERR_PDM_NO_APIC_INSTANCE;
299}
300
301
302/**
303 * Locks PDM.
304 * This might call back to Ring-3 in order to deal with lock contention in GC and R3.
305 *
306 * @param pVM The VM handle.
307 */
308void pdmLock(PVM pVM)
309{
310#ifdef IN_RING3
311 int rc = PDMCritSectEnter(&pVM->pdm.s.CritSect, VERR_INTERNAL_ERROR);
312#else
313 int rc = PDMCritSectEnter(&pVM->pdm.s.CritSect, VERR_GENERAL_FAILURE);
314 if (rc == VERR_GENERAL_FAILURE)
315 {
316# ifdef IN_RC
317 rc = VMMGCCallHost(pVM, VMMCALLHOST_PDM_LOCK, 0);
318# else
319 rc = VMMR0CallHost(pVM, VMMCALLHOST_PDM_LOCK, 0);
320# endif
321 }
322#endif
323 AssertRC(rc);
324}
325
326
327/**
328 * Locks PDM but don't go to ring-3 if it's owned by someone.
329 *
330 * @returns VINF_SUCCESS on success.
331 * @returns rc if we're in GC or R0 and can't get the lock.
332 * @param pVM The VM handle.
333 * @param rc The RC to return in GC or R0 when we can't get the lock.
334 */
335int pdmLockEx(PVM pVM, int rc)
336{
337 return PDMCritSectEnter(&pVM->pdm.s.CritSect, rc);
338}
339
340
341/**
342 * Unlocks PDM.
343 *
344 * @param pVM The VM handle.
345 */
346void pdmUnlock(PVM pVM)
347{
348 PDMCritSectLeave(&pVM->pdm.s.CritSect);
349}
350
351
352/**
353 * Converts ring 3 VMM heap pointer to a guest physical address
354 *
355 * @returns VBox status code.
356 * @param pVM VM handle.
357 * @param pv Ring-3 pointer.
358 * @param pGCPhys GC phys address (out).
359 */
360VMMDECL(int) PDMVMMDevHeapR3ToGCPhys(PVM pVM, RTR3PTR pv, RTGCPHYS *pGCPhys)
361{
362 AssertReturn(pv >= pVM->pdm.s.pvVMMDevHeap && (RTR3UINTPTR)pv < (RTR3UINTPTR)pVM->pdm.s.pvVMMDevHeap + pVM->pdm.s.cbVMMDevHeap, VERR_INVALID_PARAMETER);
363
364 *pGCPhys = (pVM->pdm.s.GCPhysVMMDevHeap + ((RTR3UINTPTR)pv - (RTR3UINTPTR)pVM->pdm.s.pvVMMDevHeap));
365 return VINF_SUCCESS;
366}
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