VirtualBox

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

Last change on this file since 10700 was 10661, checked in by vboxsync, 16 years ago

Reduce the number of world switches caused by cr8 writes by checking if we really need to be notified. (only when
an interrupt is pending and masked by the TRP value)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 8.2 KB
Line 
1/* $Id: PDMAll.cpp 10661 2008-07-15 14:21:04Z 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 pVM VM handle.
43 * @param pu8Interrupt Where to store the interrupt on success.
44 */
45PDMDECL(int) PDMGetInterrupt(PVM pVM, uint8_t *pu8Interrupt)
46{
47 pdmLock(pVM);
48
49 /*
50 * The local APIC has a higer priority than the PIC.
51 */
52 if (VM_FF_ISSET(pVM, VM_FF_INTERRUPT_APIC))
53 {
54 VM_FF_CLEAR(pVM, VM_FF_INTERRUPT_APIC);
55 Assert(pVM->pdm.s.Apic.CTXALLSUFF(pDevIns));
56 Assert(pVM->pdm.s.Apic.CTXALLSUFF(pfnGetInterrupt));
57 int i = pVM->pdm.s.Apic.CTXALLSUFF(pfnGetInterrupt)(pVM->pdm.s.Apic.CTXALLSUFF(pDevIns));
58 AssertMsg(i <= 255 && i >= 0, ("i=%d\n", i));
59 if (i >= 0)
60 {
61 pdmUnlock(pVM);
62 *pu8Interrupt = (uint8_t)i;
63 return VINF_SUCCESS;
64 }
65 }
66
67 /*
68 * Check the PIC.
69 */
70 if (VM_FF_ISSET(pVM, VM_FF_INTERRUPT_PIC))
71 {
72 VM_FF_CLEAR(pVM, VM_FF_INTERRUPT_PIC);
73 Assert(pVM->pdm.s.Pic.CTXALLSUFF(pDevIns));
74 Assert(pVM->pdm.s.Pic.CTXALLSUFF(pfnGetInterrupt));
75 int i = pVM->pdm.s.Pic.CTXALLSUFF(pfnGetInterrupt)(pVM->pdm.s.Pic.CTXALLSUFF(pDevIns));
76 AssertMsg(i <= 255 && i >= 0, ("i=%d\n", i));
77 if (i >= 0)
78 {
79 pdmUnlock(pVM);
80 *pu8Interrupt = (uint8_t)i;
81 return VINF_SUCCESS;
82 }
83 }
84
85 /** @todo Figure out exactly why we can get here without anything being set. (REM) */
86
87 pdmUnlock(pVM);
88 return VERR_NO_DATA;
89}
90
91
92/**
93 * Sets the pending interrupt.
94 *
95 * @returns VBox status code.
96 * @param pVM VM handle.
97 * @param u8Irq The IRQ line.
98 * @param u8Level The new level.
99 */
100PDMDECL(int) PDMIsaSetIrq(PVM pVM, uint8_t u8Irq, uint8_t u8Level)
101{
102 pdmLock(pVM);
103
104 int rc = VERR_PDM_NO_PIC_INSTANCE;
105 if (pVM->pdm.s.Pic.CTXALLSUFF(pDevIns))
106 {
107 Assert(pVM->pdm.s.Pic.CTXALLSUFF(pfnSetIrq));
108 pVM->pdm.s.Pic.CTXALLSUFF(pfnSetIrq)(pVM->pdm.s.Pic.CTXALLSUFF(pDevIns), u8Irq, u8Level);
109 rc = VINF_SUCCESS;
110 }
111
112 if (pVM->pdm.s.IoApic.CTXALLSUFF(pDevIns))
113 {
114 Assert(pVM->pdm.s.IoApic.CTXALLSUFF(pfnSetIrq));
115 pVM->pdm.s.IoApic.CTXALLSUFF(pfnSetIrq)(pVM->pdm.s.IoApic.CTXALLSUFF(pDevIns), u8Irq, u8Level);
116 rc = VINF_SUCCESS;
117 }
118
119 pdmUnlock(pVM);
120 return rc;
121}
122
123
124/**
125 * Sets the pending I/O APIC interrupt.
126 *
127 * @returns VBox status code.
128 * @param pVM VM handle.
129 * @param u8Irq The IRQ line.
130 * @param u8Level The new level.
131 */
132PDMDECL(int) PDMIoApicSetIrq(PVM pVM, uint8_t u8Irq, uint8_t u8Level)
133{
134 if (pVM->pdm.s.IoApic.CTXALLSUFF(pDevIns))
135 {
136 Assert(pVM->pdm.s.IoApic.CTXALLSUFF(pfnSetIrq));
137 pdmLock(pVM);
138 pVM->pdm.s.IoApic.CTXALLSUFF(pfnSetIrq)(pVM->pdm.s.IoApic.CTXALLSUFF(pDevIns), u8Irq, u8Level);
139 pdmUnlock(pVM);
140 return VINF_SUCCESS;
141 }
142 return VERR_PDM_NO_PIC_INSTANCE;
143}
144
145
146/**
147 * Set the APIC base.
148 *
149 * @returns VBox status code.
150 * @param pVM VM handle.
151 * @param u64Base The new base.
152 */
153PDMDECL(int) PDMApicSetBase(PVM pVM, uint64_t u64Base)
154{
155 if (pVM->pdm.s.Apic.CTXALLSUFF(pDevIns))
156 {
157 Assert(pVM->pdm.s.Apic.CTXALLSUFF(pfnSetBase));
158 pdmLock(pVM);
159 pVM->pdm.s.Apic.CTXALLSUFF(pfnSetBase)(pVM->pdm.s.Apic.CTXALLSUFF(pDevIns), u64Base);
160 pdmUnlock(pVM);
161 return VINF_SUCCESS;
162 }
163 return VERR_PDM_NO_APIC_INSTANCE;
164}
165
166
167/**
168 * Get the APIC base.
169 *
170 * @returns VBox status code.
171 * @param pVM VM handle.
172 * @param pu64Base Where to store the APIC base.
173 */
174PDMDECL(int) PDMApicGetBase(PVM pVM, uint64_t *pu64Base)
175{
176 if (pVM->pdm.s.Apic.CTXALLSUFF(pDevIns))
177 {
178 Assert(pVM->pdm.s.Apic.CTXALLSUFF(pfnGetBase));
179 pdmLock(pVM);
180 *pu64Base = pVM->pdm.s.Apic.CTXALLSUFF(pfnGetBase)(pVM->pdm.s.Apic.CTXALLSUFF(pDevIns));
181 pdmUnlock(pVM);
182 return VINF_SUCCESS;
183 }
184 *pu64Base = 0;
185 return VERR_PDM_NO_APIC_INSTANCE;
186}
187
188
189/**
190 * Check if the APIC has a pending interrupt/if a TPR change would active one.
191 *
192 * @returns VINF_SUCCESS or VERR_PDM_NO_APIC_INSTANCE.
193 * @param pDevIns Device instance of the APIC.
194 * @param pfPending Pending state (out).
195 */
196PDMDECL(int) PDMApicHasPendingIrq(PVM pVM, bool *pfPending)
197{
198 if (pVM->pdm.s.Apic.CTXALLSUFF(pDevIns))
199 {
200 Assert(pVM->pdm.s.Apic.CTXALLSUFF(pfnSetTPR));
201 pdmLock(pVM);
202 *pfPending = pVM->pdm.s.Apic.CTXALLSUFF(pfnHasPendingIrq)(pVM->pdm.s.Apic.CTXALLSUFF(pDevIns));
203 pdmUnlock(pVM);
204 return VINF_SUCCESS;
205 }
206 return VERR_PDM_NO_APIC_INSTANCE;
207}
208
209
210/**
211 * Set the TPR (task priority register?).
212 *
213 * @returns VBox status code.
214 * @param pVM VM handle.
215 * @param u8TPR The new TPR.
216 */
217PDMDECL(int) PDMApicSetTPR(PVM pVM, uint8_t u8TPR)
218{
219 if (pVM->pdm.s.Apic.CTXALLSUFF(pDevIns))
220 {
221 Assert(pVM->pdm.s.Apic.CTXALLSUFF(pfnSetTPR));
222 pdmLock(pVM);
223 pVM->pdm.s.Apic.CTXALLSUFF(pfnSetTPR)(pVM->pdm.s.Apic.CTXALLSUFF(pDevIns), u8TPR);
224 pdmUnlock(pVM);
225 return VINF_SUCCESS;
226 }
227 return VERR_PDM_NO_APIC_INSTANCE;
228}
229
230
231/**
232 * Get the TPR (task priority register).
233 *
234 * @returns The current TPR.
235 * @param pVM VM handle.
236 * @param pu8TPR Where to store the TRP.
237 * @param pfPending Pending interrupt state (out).
238*/
239PDMDECL(int) PDMApicGetTPR(PVM pVM, uint8_t *pu8TPR, bool *pfPending)
240{
241 if (pVM->pdm.s.Apic.CTXALLSUFF(pDevIns))
242 {
243 Assert(pVM->pdm.s.Apic.CTXALLSUFF(pfnGetTPR));
244 pdmLock(pVM);
245 *pu8TPR = pVM->pdm.s.Apic.CTXALLSUFF(pfnGetTPR)(pVM->pdm.s.Apic.CTXALLSUFF(pDevIns));
246 if (pfPending)
247 *pfPending = pVM->pdm.s.Apic.CTXALLSUFF(pfnHasPendingIrq)(pVM->pdm.s.Apic.CTXALLSUFF(pDevIns));
248 pdmUnlock(pVM);
249 return VINF_SUCCESS;
250 }
251 *pu8TPR = 0;
252 return VERR_PDM_NO_APIC_INSTANCE;
253}
254
255
256/**
257 * Locks PDM.
258 * This might call back to Ring-3 in order to deal with lock contention in GC and R3.
259 *
260 * @param pVM The VM handle.
261 */
262void pdmLock(PVM pVM)
263{
264#ifdef IN_RING3
265 int rc = PDMCritSectEnter(&pVM->pdm.s.CritSect, VERR_INTERNAL_ERROR);
266#else
267 int rc = PDMCritSectEnter(&pVM->pdm.s.CritSect, VERR_GENERAL_FAILURE);
268 if (rc == VERR_GENERAL_FAILURE)
269 {
270# ifdef IN_GC
271 rc = VMMGCCallHost(pVM, VMMCALLHOST_PDM_LOCK, 0);
272# else
273 rc = VMMR0CallHost(pVM, VMMCALLHOST_PDM_LOCK, 0);
274# endif
275 }
276#endif
277 AssertRC(rc);
278}
279
280
281/**
282 * Locks PDM but don't go to ring-3 if it's owned by someone.
283 *
284 * @returns VINF_SUCCESS on success.
285 * @returns rc if we're in GC or R0 and can't get the lock.
286 * @param pVM The VM handle.
287 * @param rc The RC to return in GC or R0 when we can't get the lock.
288 */
289int pdmLockEx(PVM pVM, int rc)
290{
291 return PDMCritSectEnter(&pVM->pdm.s.CritSect, rc);
292}
293
294
295/**
296 * Unlocks PDM.
297 *
298 * @param pVM The VM handle.
299 */
300void pdmUnlock(PVM pVM)
301{
302 PDMCritSectLeave(&pVM->pdm.s.CritSect);
303}
304
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