VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/GICAll.cpp@ 107211

Last change on this file since 107211 was 107109, checked in by vboxsync, 3 months ago

VMM/GIC: Don try reading past the interrupt routing table, bugref:3409 bugref:10404

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 61.6 KB
Line 
1/* $Id: GICAll.cpp 107109 2024-11-22 09:51:05Z vboxsync $ */
2/** @file
3 * GIC - Generic Interrupt Controller Architecture (GICv3) - All Contexts.
4 */
5
6/*
7 * Copyright (C) 2023-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_DEV_APIC
33#include "GICInternal.h"
34#include <VBox/vmm/gic.h>
35#include <VBox/vmm/pdmdev.h>
36#include <VBox/vmm/pdmapi.h>
37#include <VBox/vmm/vmcc.h>
38#include <VBox/vmm/vmm.h>
39#include <VBox/vmm/vmcpuset.h>
40#ifdef IN_RING0
41# include <VBox/vmm/gvmm.h>
42#endif
43
44
45/*********************************************************************************************************************************
46* Internal Functions *
47*********************************************************************************************************************************/
48
49
50/*********************************************************************************************************************************
51* Global Variables *
52*********************************************************************************************************************************/
53
54#ifdef LOG_ENABLED
55/**
56 * Returns a human readable string of the given exception class.
57 *
58 * @returns Pointer to the string matching the given EC.
59 * @param u32Ec The exception class to return the string for.
60 */
61static const char *gicIccRegisterStringify(uint32_t u32Reg)
62{
63 switch (u32Reg)
64 {
65#define GIC_ICC_REG_CASE(a_Reg) case ARMV8_AARCH64_SYSREG_ ## a_Reg: return #a_Reg
66 GIC_ICC_REG_CASE(ICC_PMR_EL1);
67 GIC_ICC_REG_CASE(ICC_IAR0_EL1);
68 GIC_ICC_REG_CASE(ICC_EOIR0_EL1);
69 GIC_ICC_REG_CASE(ICC_HPPIR0_EL1);
70 GIC_ICC_REG_CASE(ICC_BPR0_EL1);
71 GIC_ICC_REG_CASE(ICC_AP0R0_EL1);
72 GIC_ICC_REG_CASE(ICC_AP0R1_EL1);
73 GIC_ICC_REG_CASE(ICC_AP0R2_EL1);
74 GIC_ICC_REG_CASE(ICC_AP0R3_EL1);
75 GIC_ICC_REG_CASE(ICC_AP1R0_EL1);
76 GIC_ICC_REG_CASE(ICC_AP1R1_EL1);
77 GIC_ICC_REG_CASE(ICC_AP1R2_EL1);
78 GIC_ICC_REG_CASE(ICC_AP1R3_EL1);
79 GIC_ICC_REG_CASE(ICC_DIR_EL1);
80 GIC_ICC_REG_CASE(ICC_RPR_EL1);
81 GIC_ICC_REG_CASE(ICC_SGI1R_EL1);
82 GIC_ICC_REG_CASE(ICC_ASGI1R_EL1);
83 GIC_ICC_REG_CASE(ICC_SGI0R_EL1);
84 GIC_ICC_REG_CASE(ICC_IAR1_EL1);
85 GIC_ICC_REG_CASE(ICC_EOIR1_EL1);
86 GIC_ICC_REG_CASE(ICC_HPPIR1_EL1);
87 GIC_ICC_REG_CASE(ICC_BPR1_EL1);
88 GIC_ICC_REG_CASE(ICC_CTLR_EL1);
89 GIC_ICC_REG_CASE(ICC_SRE_EL1);
90 GIC_ICC_REG_CASE(ICC_IGRPEN0_EL1);
91 GIC_ICC_REG_CASE(ICC_IGRPEN1_EL1);
92#undef GIC_ICC_REG_CASE
93 default:
94 break;
95 }
96
97 return "<UNKNOWN>";
98}
99#endif
100
101
102/**
103 * Sets the interrupt pending force-flag and pokes the EMT if required.
104 *
105 * @param pVCpu The cross context virtual CPU structure.
106 * @param fIrq Flag whether to assert the IRQ line or leave it alone.
107 * @param fFiq Flag whether to assert the FIQ line or leave it alone.
108 */
109static void gicSetInterruptFF(PVMCPUCC pVCpu, bool fIrq, bool fFiq)
110{
111 LogFlowFunc(("pVCpu=%p{.idCpu=%u} fIrq=%RTbool fFiq=%RTbool\n",
112 pVCpu, pVCpu->idCpu, fIrq, fFiq));
113
114 Assert(fIrq || fFiq);
115
116#ifdef IN_RING3
117 /* IRQ state should be loaded as-is by "LoadExec". Changes can be made from LoadDone. */
118 Assert(pVCpu->pVMR3->enmVMState != VMSTATE_LOADING || PDMR3HasLoadedState(pVCpu->pVMR3));
119#endif
120
121 if (fIrq)
122 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_IRQ);
123 if (fFiq)
124 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_FIQ);
125
126 /*
127 * We need to wake up the target CPU if we're not on EMT.
128 */
129 /** @todo We could just use RTThreadNativeSelf() here, couldn't we? */
130#if defined(IN_RING0)
131 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
132 VMCPUID idCpu = pVCpu->idCpu;
133 if (VMMGetCpuId(pVM) != idCpu)
134 {
135 switch (VMCPU_GET_STATE(pVCpu))
136 {
137 case VMCPUSTATE_STARTED_EXEC:
138 Log7Func(("idCpu=%u VMCPUSTATE_STARTED_EXEC\n", idCpu));
139 GVMMR0SchedPokeNoGVMNoLock(pVM, idCpu);
140 break;
141
142 case VMCPUSTATE_STARTED_HALTED:
143 Log7Func(("idCpu=%u VMCPUSTATE_STARTED_HALTED\n", idCpu));
144 GVMMR0SchedWakeUpNoGVMNoLock(pVM, idCpu);
145 break;
146
147 default:
148 Log7Func(("idCpu=%u enmState=%d\n", idCpu, pVCpu->enmState));
149 break; /* nothing to do in other states. */
150 }
151 }
152#elif defined(IN_RING3)
153 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
154 VMCPUID idCpu = pVCpu->idCpu;
155 if (VMMGetCpuId(pVM) != idCpu)
156 {
157 Log7Func(("idCpu=%u enmState=%d\n", idCpu, pVCpu->enmState));
158 VMR3NotifyCpuFFU(pVCpu->pUVCpu, VMNOTIFYFF_FLAGS_POKE);
159 }
160#endif
161}
162
163
164/**
165 * Clears the interrupt pending force-flag.
166 *
167 * @param pVCpu The cross context virtual CPU structure.
168 * @param fIrq Flag whether to clear the IRQ flag.
169 * @param fFiq Flag whether to clear the FIQ flag.
170 */
171DECLINLINE(void) gicClearInterruptFF(PVMCPUCC pVCpu, bool fIrq, bool fFiq)
172{
173 LogFlowFunc(("pVCpu=%p{.idCpu=%u} fIrq=%RTbool fFiq=%RTbool\n",
174 pVCpu, pVCpu->idCpu, fIrq, fFiq));
175
176 Assert(fIrq || fFiq);
177
178#ifdef IN_RING3
179 /* IRQ state should be loaded as-is by "LoadExec". Changes can be made from LoadDone. */
180 Assert(pVCpu->pVMR3->enmVMState != VMSTATE_LOADING || PDMR3HasLoadedState(pVCpu->pVMR3));
181#endif
182
183 if (fIrq)
184 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_IRQ);
185 if (fFiq)
186 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_FIQ);
187}
188
189
190DECLINLINE(void) gicUpdateInterruptFF(PVMCPUCC pVCpu, bool fIrq, bool fFiq)
191{
192 LogFlowFunc(("pVCpu=%p{.idCpu=%u} fIrq=%RTbool fFiq=%RTbool\n",
193 pVCpu, pVCpu->idCpu, fIrq, fFiq));
194
195 if (fIrq || fFiq)
196 gicSetInterruptFF(pVCpu, fIrq, fFiq);
197
198 if (!fIrq || !fFiq)
199 gicClearInterruptFF(pVCpu, !fIrq, !fFiq);
200}
201
202
203DECLINLINE(void) gicReDistHasIrqPending(PGICCPU pThis, bool *pfIrq, bool *pfFiq)
204{
205 /* Read the interrupt state. */
206 uint32_t u32RegIGrp0 = ASMAtomicReadU32(&pThis->u32RegIGrp0);
207 uint32_t bmIntEnabled = ASMAtomicReadU32(&pThis->bmIntEnabled);
208 uint32_t bmIntPending = ASMAtomicReadU32(&pThis->bmIntPending);
209 uint32_t bmIntActive = ASMAtomicReadU32(&pThis->bmIntActive);
210 bool fIrqGrp0Enabled = ASMAtomicReadBool(&pThis->fIrqGrp0Enabled);
211 bool fIrqGrp1Enabled = ASMAtomicReadBool(&pThis->fIrqGrp1Enabled);
212
213 /* Only allow interrupts with higher priority than the current configured and running one. */
214 uint8_t bPriority = RT_MIN(pThis->bInterruptPriority, pThis->abRunningPriorities[pThis->idxRunningPriority]);
215
216 /* Is anything enabled at all? */
217 uint32_t bmIntForward = (bmIntPending & bmIntEnabled) & ~bmIntActive; /* Exclude the currently active interrupt. */
218 if (bmIntForward)
219 {
220 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->abIntPriority); i++)
221 {
222 Log4(("SGI/PPI %u, configured priority %u, running priority %u\n", i, pThis->abIntPriority[i], bPriority));
223 if ( (bmIntForward & RT_BIT_32(i))
224 && pThis->abIntPriority[i] < bPriority)
225 break;
226 else
227 bmIntForward &= ~RT_BIT_32(i);
228
229 if (!bmIntForward)
230 break;
231 }
232 }
233
234 if (bmIntForward)
235 {
236 /* Determine whether we have to assert the IRQ or FIQ line. */
237 *pfIrq = RT_BOOL(bmIntForward & u32RegIGrp0) && fIrqGrp1Enabled;
238 *pfFiq = RT_BOOL(bmIntForward & ~u32RegIGrp0) && fIrqGrp0Enabled;
239 }
240 else
241 {
242 *pfIrq = false;
243 *pfFiq = false;
244 }
245
246 LogFlowFunc(("pThis=%p bPriority=%u bmIntEnabled=%#x bmIntPending=%#x bmIntActive=%#x fIrq=%RTbool fFiq=%RTbool\n",
247 pThis, bPriority, bmIntEnabled, bmIntPending, bmIntActive, *pfIrq, *pfFiq));
248}
249
250
251DECLINLINE(void) gicDistHasIrqPendingForVCpu(PGICDEV pThis, PGICCPU pGicVCpu, VMCPUID idCpu, bool *pfIrq, bool *pfFiq)
252{
253 /* Read the interrupt state. */
254 uint32_t u32RegIGrp0 = ASMAtomicReadU32(&pThis->u32RegIGrp0);
255 uint32_t bmIntEnabled = ASMAtomicReadU32(&pThis->bmIntEnabled);
256 uint32_t bmIntPending = ASMAtomicReadU32(&pThis->bmIntPending);
257 uint32_t bmIntActive = ASMAtomicReadU32(&pThis->bmIntActive);
258 bool fIrqGrp0Enabled = ASMAtomicReadBool(&pThis->fIrqGrp0Enabled);
259 bool fIrqGrp1Enabled = ASMAtomicReadBool(&pThis->fIrqGrp1Enabled);
260
261 /* Only allow interrupts with higher priority than the current configured and running one. */
262 uint8_t bPriority = RT_MIN(pGicVCpu->bInterruptPriority, pGicVCpu->abRunningPriorities[pGicVCpu->idxRunningPriority]);
263
264 /* Is anything enabled at all? */
265 uint32_t bmIntForward = (bmIntPending & bmIntEnabled) & ~bmIntActive; /* Exclude the currently active interrupt. */
266 if (bmIntForward)
267 {
268 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->abIntPriority); i++)
269 {
270 Log4(("SPI %u, configured priority %u (routing %#x), running priority %u\n", i + GIC_INTID_RANGE_SPI_START, pThis->abIntPriority[i],
271 pThis->au32IntRouting[i], bPriority));
272 if ( (bmIntForward & RT_BIT_32(i))
273 && pThis->abIntPriority[i] < bPriority
274 && pThis->au32IntRouting[i] == idCpu)
275 break;
276 else
277 bmIntForward &= ~RT_BIT_32(i);
278
279 if (!bmIntForward)
280 break;
281 }
282 }
283
284 if (bmIntForward)
285 {
286 /* Determine whether we have to assert the IRQ or FIQ line. */
287 *pfIrq = RT_BOOL(bmIntForward & u32RegIGrp0) && fIrqGrp1Enabled;
288 *pfFiq = RT_BOOL(bmIntForward & ~u32RegIGrp0) && fIrqGrp0Enabled;
289 }
290 else
291 {
292 *pfIrq = false;
293 *pfFiq = false;
294 }
295
296 LogFlowFunc(("pThis=%p bPriority=%u bmIntEnabled=%#x bmIntPending=%#x bmIntActive=%#x fIrq=%RTbool fFiq=%RTbool\n",
297 pThis, bPriority, bmIntEnabled, bmIntPending, bmIntActive, *pfIrq, *pfFiq));
298}
299
300
301/**
302 * Updates the internal IRQ state and sets or clears the appropirate force action flags.
303 *
304 * @returns Strict VBox status code.
305 * @param pThis The GIC re-distributor state for the associated vCPU.
306 * @param pVCpu The cross context virtual CPU structure.
307 */
308static VBOXSTRICTRC gicReDistUpdateIrqState(PGICCPU pThis, PVMCPUCC pVCpu)
309{
310 bool fIrq, fFiq;
311 gicReDistHasIrqPending(pThis, &fIrq, &fFiq);
312
313 PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
314 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
315 bool fIrqDist, fFiqDist;
316 gicDistHasIrqPendingForVCpu(pGicDev, pThis, pVCpu->idCpu, &fIrqDist, &fFiqDist);
317 fIrq |= fIrqDist;
318 fFiq |= fFiqDist;
319
320 gicUpdateInterruptFF(pVCpu, fIrq, fFiq);
321 return VINF_SUCCESS;
322}
323
324
325/**
326 * Updates the internal IRQ state of the distributor and sets or clears the appropirate force action flags.
327 *
328 * @returns Strict VBox status code.
329 * @param pVM The cross context VM state.
330 * @param pThis The GIC distributor state.
331 */
332static VBOXSTRICTRC gicDistUpdateIrqState(PVMCC pVM, PGICDEV pThis)
333{
334 for (uint32_t i = 0; i < pVM->cCpus; i++)
335 {
336 PVMCPUCC pVCpu = pVM->CTX_SUFF(apCpus)[i];
337 PGICCPU pGicVCpu = VMCPU_TO_GICCPU(pVCpu);
338
339 bool fIrq, fFiq;
340 gicReDistHasIrqPending(pGicVCpu, &fIrq, &fFiq);
341
342 bool fIrqDist, fFiqDist;
343 gicDistHasIrqPendingForVCpu(pThis, pGicVCpu, i, &fIrqDist, &fFiqDist);
344 fIrq |= fIrqDist;
345 fFiq |= fFiqDist;
346
347 gicUpdateInterruptFF(pVCpu, fIrq, fFiq);
348 }
349 return VINF_SUCCESS;
350}
351
352
353/**
354 * Sets the given SGI/PPI interrupt ID on the re-distributor of the given vCPU.
355 *
356 * @returns VBox status code.
357 * @param pVCpu The cross context virtual CPU structure.
358 * @param uIntId The SGI/PPI interrupt identifier.
359 * @param fAsserted Flag whether the SGI/PPI interrupt is asserted or not.
360 */
361static int gicReDistInterruptSet(PVMCPUCC pVCpu, uint32_t uIntId, bool fAsserted)
362{
363 PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
364
365 /* Update the interrupts pending state. */
366 if (fAsserted)
367 ASMAtomicOrU32(&pThis->bmIntPending, RT_BIT_32(uIntId));
368 else
369 ASMAtomicAndU32(&pThis->bmIntPending, ~RT_BIT_32(uIntId));
370
371 return VBOXSTRICTRC_VAL(gicReDistUpdateIrqState(pThis, pVCpu));
372}
373
374
375/**
376 * Reads a GIC distributor register.
377 *
378 * @returns VBox status code.
379 * @param pDevIns The device instance.
380 * @param pVCpu The cross context virtual CPU structure.
381 * @param offReg The offset of the register being read.
382 * @param puValue Where to store the register value.
383 */
384DECLINLINE(VBOXSTRICTRC) gicDistRegisterRead(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t *puValue)
385{
386 VMCPU_ASSERT_EMT(pVCpu);
387 PGICDEV pThis = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
388
389 if (offReg >= GIC_DIST_REG_IROUTERn_OFF_START && offReg <= GIC_DIST_REG_IROUTERn_OFF_LAST)
390 {
391 uint32_t idxEntry = (offReg - GIC_DIST_REG_IROUTERn_OFF_START) / 4;
392 if (RT_LIKELY(idxEntry < RT_ELEMENTS(pThis->au32IntRouting)))
393 *puValue = pThis->au32IntRouting[idxEntry];
394 else
395 *puValue = 0;
396 return VINF_SUCCESS;
397 }
398
399 switch (offReg)
400 {
401 case GIC_DIST_REG_CTLR_OFF:
402 *puValue = (ASMAtomicReadBool(&pThis->fIrqGrp0Enabled) ? GIC_DIST_REG_CTRL_ENABLE_GRP0 : 0)
403 | (ASMAtomicReadBool(&pThis->fIrqGrp1Enabled) ? GIC_DIST_REG_CTRL_ENABLE_GRP1_NS : 0)
404 | GIC_DIST_REG_CTRL_DS
405 | GIC_DIST_REG_CTRL_ARE_S;
406 break;
407 case GIC_DIST_REG_TYPER_OFF:
408 *puValue = GIC_DIST_REG_TYPER_NUM_ITLINES_SET(1) /** @todo 32 SPIs for now. */
409 | GIC_DIST_REG_TYPER_NUM_PES_SET(0) /* 1 PE */
410 /*| GIC_DIST_REG_TYPER_ESPI*/ /** @todo */
411 /*| GIC_DIST_REG_TYPER_NMI*/ /** @todo Non-maskable interrupts */
412 /*| GIC_DIST_REG_TYPER_SECURITY_EXTN */ /** @todo */
413 /*| GIC_DIST_REG_TYPER_MBIS */ /** @todo Message based interrupts */
414 /*| GIC_DIST_REG_TYPER_LPIS */ /** @todo Support LPIs */
415 | GIC_DIST_REG_TYPER_IDBITS_SET(16);
416 break;
417 case GIC_DIST_REG_STATUSR_OFF:
418 AssertReleaseFailed();
419 break;
420 case GIC_DIST_REG_IGROUPRn_OFF_START: /* Only 32 lines for now. */
421 AssertReleaseFailed();
422 break;
423 case GIC_DIST_REG_ISENABLERn_OFF_START + 4: /* Only 32 lines for now. */
424 case GIC_DIST_REG_ICENABLERn_OFF_START + 4: /* Only 32 lines for now. */
425 *puValue = ASMAtomicReadU32(&pThis->bmIntEnabled);
426 break;
427 case GIC_DIST_REG_ISPENDRn_OFF_START: /* Only 32 lines for now. */
428 AssertReleaseFailed();
429 break;
430 case GIC_DIST_REG_ICPENDRn_OFF_START: /* Only 32 lines for now. */
431 AssertReleaseFailed();
432 break;
433 case GIC_DIST_REG_ISACTIVERn_OFF_START: /* Only 32 lines for now. */
434 AssertReleaseFailed();
435 break;
436 case GIC_DIST_REG_ICACTIVERn_OFF_START: /* Only 32 lines for now. */
437 AssertReleaseFailed();
438 break;
439 case GIC_DIST_REG_IPRIORITYn_OFF_START:
440 case GIC_DIST_REG_IPRIORITYn_OFF_START + 4: /* These are banked for the PEs and access the redistributor. */
441 {
442 PGICCPU pGicVCpu = VMCPU_TO_GICCPU(pVCpu);
443
444 /* Figure out the register which is written. */
445 uint8_t idxPrio = offReg - GIC_DIST_REG_IPRIORITYn_OFF_START;
446 Assert(idxPrio <= RT_ELEMENTS(pThis->abIntPriority) - sizeof(uint32_t));
447
448 uint32_t u32Value = 0;
449 for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
450 u32Value |= pGicVCpu->abIntPriority[i] << ((i - idxPrio) * 8);
451
452 *puValue = u32Value;
453 break;
454 }
455 case GIC_DIST_REG_IPRIORITYn_OFF_START + 32: /* Only 32 lines for now. */
456 {
457 /* Figure out the register which is written. */
458 uint8_t idxPrio = offReg - GIC_DIST_REG_IPRIORITYn_OFF_START - 32;
459 Assert(idxPrio <= RT_ELEMENTS(pThis->abIntPriority) - sizeof(uint32_t));
460
461 uint32_t u32Value = 0;
462 for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
463 u32Value |= pThis->abIntPriority[i] << ((i - idxPrio) * 8);
464
465 *puValue = u32Value;
466 break;
467 }
468 case GIC_DIST_REG_ITARGETSRn_OFF_START: /* Only 32 lines for now. */
469 AssertReleaseFailed();
470 break;
471 case GIC_DIST_REG_ICFGRn_OFF_START: /* Only 32 lines for now. */
472 AssertReleaseFailed();
473 break;
474 case GIC_DIST_REG_IGRPMODRn_OFF_START: /* Only 32 lines for now. */
475 AssertReleaseFailed();
476 break;
477 case GIC_DIST_REG_NSACRn_OFF_START: /* Only 32 lines for now. */
478 AssertReleaseFailed();
479 break;
480 case GIC_DIST_REG_SGIR_OFF:
481 AssertReleaseFailed();
482 break;
483 case GIC_DIST_REG_CPENDSGIRn_OFF_START:
484 AssertReleaseFailed();
485 break;
486 case GIC_DIST_REG_SPENDSGIRn_OFF_START:
487 AssertReleaseFailed();
488 break;
489 case GIC_DIST_REG_INMIn_OFF_START:
490 AssertReleaseFailed();
491 break;
492 case GIC_DIST_REG_PIDR2_OFF:
493 *puValue = GIC_REDIST_REG_PIDR2_ARCH_REV_SET(GIC_REDIST_REG_PIDR2_ARCH_REV_GICV3);
494 break;
495 case GIC_DIST_REG_IIDR_OFF:
496 case GIC_DIST_REG_TYPER2_OFF:
497 *puValue = 0;
498 break;
499 case GIC_DIST_REG_IROUTERn_OFF_START:
500 AssertFailed();
501 break;
502 default:
503 *puValue = 0;
504 }
505 return VINF_SUCCESS;
506}
507
508
509/**
510 * Writes a GIC distributor register.
511 *
512 * @returns Strict VBox status code.
513 * @param pDevIns The device instance.
514 * @param pVCpu The cross context virtual CPU structure.
515 * @param offReg The offset of the register being written.
516 * @param uValue The register value.
517 */
518DECLINLINE(VBOXSTRICTRC) gicDistRegisterWrite(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue)
519{
520 VMCPU_ASSERT_EMT(pVCpu); RT_NOREF(pVCpu);
521 PGICDEV pThis = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
522 PVMCC pVM = PDMDevHlpGetVM(pDevIns);
523
524 if (offReg >= GIC_DIST_REG_IROUTERn_OFF_START && offReg <= GIC_DIST_REG_IROUTERn_OFF_LAST)
525 {
526 uint32_t idxReg = (offReg - GIC_DIST_REG_IROUTERn_OFF_START) / 4;
527 LogFlowFunc(("GicDist: idxIRouter=%u uValue=%#x\n", idxReg, uValue));
528 if (idxReg < RT_ELEMENTS(pThis->au32IntRouting))
529 pThis->au32IntRouting[idxReg] = uValue;
530 return VINF_SUCCESS;
531 }
532
533 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
534 switch (offReg)
535 {
536 case GIC_DIST_REG_CTLR_OFF:
537 ASMAtomicWriteBool(&pThis->fIrqGrp0Enabled, RT_BOOL(uValue & GIC_DIST_REG_CTRL_ENABLE_GRP0));
538 ASMAtomicWriteBool(&pThis->fIrqGrp1Enabled, RT_BOOL(uValue & GIC_DIST_REG_CTRL_ENABLE_GRP1_NS));
539 Assert(!(uValue & GIC_DIST_REG_CTRL_ARE_NS));
540 rcStrict = gicDistUpdateIrqState(pVM, pThis);
541 break;
542 case GIC_DIST_REG_STATUSR_OFF:
543 AssertReleaseFailed();
544 break;
545 case GIC_DIST_REG_SETSPI_NSR_OFF:
546 AssertReleaseFailed();
547 break;
548 case GIC_DIST_REG_CLRSPI_NSR_OFF:
549 AssertReleaseFailed();
550 break;
551 case GIC_DIST_REG_SETSPI_SR_OFF:
552 AssertReleaseFailed();
553 break;
554 case GIC_DIST_REG_CLRSPI_SR_OFF:
555 AssertReleaseFailed();
556 break;
557 case GIC_DIST_REG_IGROUPRn_OFF_START: /* Only 32 lines for now. */
558 AssertReleaseFailed();
559 break;
560 case GIC_DIST_REG_IGROUPRn_OFF_START + 4: /* Only 32 lines for now. */
561 ASMAtomicOrU32(&pThis->u32RegIGrp0, uValue);
562 rcStrict = gicDistUpdateIrqState(pVM, pThis);
563 break;
564 case GIC_DIST_REG_ISENABLERn_OFF_START + 4: /* Only 32 lines for now. */
565 ASMAtomicOrU32(&pThis->bmIntEnabled, uValue);
566 rcStrict = gicDistUpdateIrqState(pVM, pThis);
567 break;
568 case GIC_DIST_REG_ICENABLERn_OFF_START:
569 AssertReleaseFailed();
570 break;
571 case GIC_DIST_REG_ICENABLERn_OFF_START + 4: /* Only 32 lines for now. */
572 ASMAtomicAndU32(&pThis->bmIntEnabled, ~uValue);
573 rcStrict = gicDistUpdateIrqState(pVM, pThis);
574 break;
575 case GIC_DIST_REG_ISPENDRn_OFF_START: /* Only 32 lines for now. */
576 AssertReleaseFailed();
577 break;
578 case GIC_DIST_REG_ICPENDRn_OFF_START: /* Only 32 lines for now. */
579 AssertReleaseFailed();
580 break;
581 case GIC_DIST_REG_ISACTIVERn_OFF_START: /* Only 32 lines for now. */
582 AssertReleaseFailed();
583 break;
584 case GIC_DIST_REG_ICACTIVERn_OFF_START + 4: /* Only 32 lines for now. */
585 ASMAtomicAndU32(&pThis->bmIntActive, ~uValue);
586 rcStrict = gicDistUpdateIrqState(pVM, pThis);
587 break;
588 case GIC_DIST_REG_IPRIORITYn_OFF_START: /* These are banked for the PEs and access the redistributor. */
589 case GIC_DIST_REG_IPRIORITYn_OFF_START + 4:
590 case GIC_DIST_REG_IPRIORITYn_OFF_START + 8:
591 case GIC_DIST_REG_IPRIORITYn_OFF_START + 12:
592 case GIC_DIST_REG_IPRIORITYn_OFF_START + 16:
593 case GIC_DIST_REG_IPRIORITYn_OFF_START + 20:
594 case GIC_DIST_REG_IPRIORITYn_OFF_START + 24:
595 case GIC_DIST_REG_IPRIORITYn_OFF_START + 28:
596 {
597 PGICCPU pGicVCpu = VMCPU_TO_GICCPU(pVCpu);
598
599 /* Figure out the register which is written. */
600 uint8_t idxPrio = offReg - GIC_DIST_REG_IPRIORITYn_OFF_START;
601 Assert(idxPrio <= RT_ELEMENTS(pGicVCpu->abIntPriority) - sizeof(uint32_t));
602 for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
603 {
604 pGicVCpu->abIntPriority[i] = (uint8_t)(uValue & 0xff);
605 uValue >>= 8;
606 }
607 break;
608 }
609 case GIC_DIST_REG_IPRIORITYn_OFF_START + 32: /* Only 32 lines for now. */
610 case GIC_DIST_REG_IPRIORITYn_OFF_START + 36:
611 case GIC_DIST_REG_IPRIORITYn_OFF_START + 40:
612 case GIC_DIST_REG_IPRIORITYn_OFF_START + 44:
613 case GIC_DIST_REG_IPRIORITYn_OFF_START + 48:
614 case GIC_DIST_REG_IPRIORITYn_OFF_START + 52:
615 case GIC_DIST_REG_IPRIORITYn_OFF_START + 56:
616 case GIC_DIST_REG_IPRIORITYn_OFF_START + 60:
617 {
618 /* Figure out the register which is written. */
619 uint8_t idxPrio = offReg - GIC_DIST_REG_IPRIORITYn_OFF_START - 32;
620 Assert(idxPrio <= RT_ELEMENTS(pThis->abIntPriority) - sizeof(uint32_t));
621 for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
622 {
623#if 1
624 /** @todo r=aeichner This gross hack prevents Windows from hanging during boot because
625 * it tries to set the interrupt priority for PCI interrupt lines to 0 which will cause an interrupt
626 * storm later on because the lowest interrupt priority Windows seems to use is 32 for the per vCPU
627 * timer.
628 */
629 if ((uValue & 0xff) == 0)
630 {
631 uValue >>= 8;
632 continue;
633 }
634#endif
635 pThis->abIntPriority[i] = (uint8_t)(uValue & 0xff);
636 uValue >>= 8;
637 }
638 break;
639 }
640 case GIC_DIST_REG_ITARGETSRn_OFF_START: /* Only 32 lines for now. */
641 AssertReleaseFailed();
642 break;
643 case GIC_DIST_REG_ICFGRn_OFF_START + 8: /* Only 32 lines for now. */
644 ASMAtomicWriteU32(&pThis->u32RegICfg0, uValue);
645 break;
646 case GIC_DIST_REG_ICFGRn_OFF_START+ 12:
647 ASMAtomicWriteU32(&pThis->u32RegICfg1, uValue);
648 break;
649 case GIC_DIST_REG_IGRPMODRn_OFF_START: /* Only 32 lines for now. */
650 AssertReleaseFailed();
651 break;
652 case GIC_DIST_REG_NSACRn_OFF_START: /* Only 32 lines for now. */
653 AssertReleaseFailed();
654 break;
655 case GIC_DIST_REG_SGIR_OFF:
656 AssertReleaseFailed();
657 break;
658 case GIC_DIST_REG_CPENDSGIRn_OFF_START:
659 AssertReleaseFailed();
660 break;
661 case GIC_DIST_REG_SPENDSGIRn_OFF_START:
662 AssertReleaseFailed();
663 break;
664 case GIC_DIST_REG_INMIn_OFF_START:
665 AssertReleaseFailed();
666 break;
667 default:
668 //AssertReleaseFailed();
669 break;
670 }
671
672 return rcStrict;
673}
674
675
676/**
677 * Reads a GIC redistributor register.
678 *
679 * @returns VBox status code.
680 * @param pDevIns The device instance.
681 * @param pVCpu The cross context virtual CPU structure.
682 * @param idRedist The redistributor ID.
683 * @param offReg The offset of the register being read.
684 * @param puValue Where to store the register value.
685 */
686DECLINLINE(VBOXSTRICTRC) gicReDistRegisterRead(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint32_t idRedist, uint16_t offReg, uint32_t *puValue)
687{
688 RT_NOREF(pDevIns);
689
690 switch (offReg)
691 {
692 case GIC_REDIST_REG_TYPER_OFF:
693 {
694 PVMCC pVM = PDMDevHlpGetVM(pDevIns);
695 *puValue = ((pVCpu->idCpu == pVM->cCpus - 1) ? GIC_REDIST_REG_TYPER_LAST : 0)
696 | GIC_REDIST_REG_TYPER_CPU_NUMBER_SET(idRedist)
697 | GIC_REDIST_REG_TYPER_CMN_LPI_AFF_SET(GIC_REDIST_REG_TYPER_CMN_LPI_AFF_ALL);
698 break;
699 }
700 case GIC_REDIST_REG_TYPER_AFFINITY_OFF:
701 *puValue = idRedist;
702 break;
703 case GIC_REDIST_REG_PIDR2_OFF:
704 *puValue = GIC_REDIST_REG_PIDR2_ARCH_REV_SET(GIC_REDIST_REG_PIDR2_ARCH_REV_GICV3);
705 break;
706 default:
707 *puValue = 0;
708 }
709
710 return VINF_SUCCESS;
711}
712
713
714/**
715 * Reads a GIC redistributor SGI/PPI frame register.
716 *
717 * @returns VBox status code.
718 * @param pDevIns The device instance.
719 * @param pVCpu The cross context virtual CPU structure.
720 * @param offReg The offset of the register being read.
721 * @param puValue Where to store the register value.
722 */
723DECLINLINE(VBOXSTRICTRC) gicReDistSgiPpiRegisterRead(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t *puValue)
724{
725 VMCPU_ASSERT_EMT(pVCpu);
726 RT_NOREF(pDevIns);
727
728 PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
729 switch (offReg)
730 {
731 case GIC_REDIST_SGI_PPI_REG_ISENABLER0_OFF:
732 case GIC_REDIST_SGI_PPI_REG_ICENABLER0_OFF:
733 *puValue = ASMAtomicReadU32(&pThis->bmIntEnabled);
734 break;
735 case GIC_REDIST_SGI_PPI_REG_ISPENDR0_OFF:
736 case GIC_REDIST_SGI_PPI_REG_ICPENDR0_OFF:
737 *puValue = ASMAtomicReadU32(&pThis->bmIntPending);
738 break;
739 case GIC_REDIST_SGI_PPI_REG_ISACTIVER0_OFF:
740 case GIC_REDIST_SGI_PPI_REG_ICACTIVER0_OFF:
741 *puValue = ASMAtomicReadU32(&pThis->bmIntActive);
742 break;
743 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START:
744 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 4:
745 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 8:
746 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 12:
747 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 16:
748 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 20:
749 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 24:
750 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 28:
751 {
752 /* Figure out the register which is written. */
753 uint8_t idxPrio = offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START;
754 Assert(idxPrio <= RT_ELEMENTS(pThis->abIntPriority) - sizeof(uint32_t));
755
756 uint32_t u32Value = 0;
757 for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
758 u32Value |= pThis->abIntPriority[i] << ((i - idxPrio) * 8);
759
760 *puValue = u32Value;
761 break;
762 }
763 case GIC_REDIST_SGI_PPI_REG_ICFGR0_OFF:
764 *puValue = ASMAtomicReadU32(&pThis->u32RegICfg0);
765 break;
766 case GIC_REDIST_SGI_PPI_REG_ICFGR1_OFF:
767 *puValue = ASMAtomicReadU32(&pThis->u32RegICfg1);
768 break;
769 default:
770 AssertReleaseFailed();
771 *puValue = 0;
772 }
773
774 return VINF_SUCCESS;
775}
776
777
778/**
779 * Writes a GIC redistributor frame register.
780 *
781 * @returns Strict VBox status code.
782 * @param pDevIns The device instance.
783 * @param pVCpu The cross context virtual CPU structure.
784 * @param offReg The offset of the register being written.
785 * @param uValue The register value.
786 */
787DECLINLINE(VBOXSTRICTRC) gicReDistRegisterWrite(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue)
788{
789 VMCPU_ASSERT_EMT(pVCpu);
790 RT_NOREF(pDevIns, pVCpu, uValue);
791
792 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
793 switch (offReg)
794 {
795 case GIC_REDIST_REG_STATUSR_OFF:
796 AssertReleaseFailed();
797 break;
798 case GIC_REDIST_REG_WAKER_OFF:
799 Assert(uValue == 0);
800 break;
801 case GIC_REDIST_REG_PARTIDR_OFF:
802 AssertReleaseFailed();
803 break;
804 case GIC_REDIST_REG_SETLPIR_OFF:
805 AssertReleaseFailed();
806 break;
807 case GIC_REDIST_REG_CLRLPIR_OFF:
808 AssertReleaseFailed();
809 break;
810 case GIC_REDIST_REG_PROPBASER_OFF:
811 AssertReleaseFailed();
812 break;
813 case GIC_REDIST_REG_PENDBASER_OFF:
814 AssertReleaseFailed();
815 break;
816 case GIC_REDIST_REG_INVLPIR_OFF:
817 AssertReleaseFailed();
818 break;
819 case GIC_REDIST_REG_INVALLR_OFF:
820 AssertReleaseFailed();
821 break;
822 default:
823 AssertReleaseFailed();
824 break;
825 }
826
827 return rcStrict;
828}
829
830
831/**
832 * Writes a GIC redistributor SGI/PPI frame register.
833 *
834 * @returns Strict VBox status code.
835 * @param pDevIns The device instance.
836 * @param pVCpu The cross context virtual CPU structure.
837 * @param offReg The offset of the register being written.
838 * @param uValue The register value.
839 */
840DECLINLINE(VBOXSTRICTRC) gicReDistSgiPpiRegisterWrite(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue)
841{
842 VMCPU_ASSERT_EMT(pVCpu);
843 RT_NOREF(pDevIns);
844
845 PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
846 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
847 switch (offReg)
848 {
849 case GIC_REDIST_SGI_PPI_REG_IGROUPR0_OFF:
850 ASMAtomicOrU32(&pThis->u32RegIGrp0, uValue);
851 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
852 break;
853 case GIC_REDIST_SGI_PPI_REG_ISENABLER0_OFF:
854 ASMAtomicOrU32(&pThis->bmIntEnabled, uValue);
855 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
856 break;
857 case GIC_REDIST_SGI_PPI_REG_ICENABLER0_OFF:
858 ASMAtomicAndU32(&pThis->bmIntEnabled, ~uValue);
859 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
860 break;
861 case GIC_REDIST_SGI_PPI_REG_ISPENDR0_OFF:
862 ASMAtomicOrU32(&pThis->bmIntPending, uValue);
863 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
864 break;
865 case GIC_REDIST_SGI_PPI_REG_ICPENDR0_OFF:
866 ASMAtomicAndU32(&pThis->bmIntPending, ~uValue);
867 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
868 break;
869 case GIC_REDIST_SGI_PPI_REG_ISACTIVER0_OFF:
870 ASMAtomicOrU32(&pThis->bmIntActive, uValue);
871 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
872 break;
873 case GIC_REDIST_SGI_PPI_REG_ICACTIVER0_OFF:
874 ASMAtomicAndU32(&pThis->bmIntActive, ~uValue);
875 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
876 break;
877 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START:
878 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 4:
879 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 8:
880 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 12:
881 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 16:
882 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 20:
883 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 24:
884 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 28:
885 {
886 /* Figure out the register whch is written. */
887 uint8_t idxPrio = offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START;
888 Assert(idxPrio <= RT_ELEMENTS(pThis->abIntPriority) - sizeof(uint32_t));
889 for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
890 {
891 pThis->abIntPriority[i] = (uint8_t)(uValue & 0xff);
892 uValue >>= 8;
893 }
894 break;
895 }
896 case GIC_REDIST_SGI_PPI_REG_ICFGR0_OFF:
897 ASMAtomicWriteU32(&pThis->u32RegICfg0, uValue);
898 break;
899 case GIC_REDIST_SGI_PPI_REG_ICFGR1_OFF:
900 ASMAtomicWriteU32(&pThis->u32RegICfg1, uValue);
901 break;
902 default:
903 //AssertReleaseFailed();
904 break;
905 }
906
907 return rcStrict;
908}
909
910
911/**
912 * Reads a GIC system register.
913 *
914 * @returns Strict VBox status code.
915 * @param pVCpu The cross context virtual CPU structure.
916 * @param u32Reg The system register being read.
917 * @param pu64Value Where to store the read value.
918 */
919VMM_INT_DECL(VBOXSTRICTRC) GICReadSysReg(PVMCPUCC pVCpu, uint32_t u32Reg, uint64_t *pu64Value)
920{
921 /*
922 * Validate.
923 */
924 VMCPU_ASSERT_EMT(pVCpu);
925 Assert(pu64Value);
926
927 *pu64Value = 0;
928 PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
929 PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
930 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
931
932 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
933 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
934
935 switch (u32Reg)
936 {
937 case ARMV8_AARCH64_SYSREG_ICC_PMR_EL1:
938 *pu64Value = pThis->bInterruptPriority;
939 break;
940 case ARMV8_AARCH64_SYSREG_ICC_IAR0_EL1:
941 AssertReleaseFailed();
942 break;
943 case ARMV8_AARCH64_SYSREG_ICC_EOIR0_EL1:
944 AssertReleaseFailed();
945 break;
946 case ARMV8_AARCH64_SYSREG_ICC_HPPIR0_EL1:
947 AssertReleaseFailed();
948 break;
949 case ARMV8_AARCH64_SYSREG_ICC_BPR0_EL1:
950 *pu64Value = pThis->bBinaryPointGrp0 & 0x7;
951 break;
952 case ARMV8_AARCH64_SYSREG_ICC_AP0R0_EL1:
953 AssertReleaseFailed();
954 break;
955 case ARMV8_AARCH64_SYSREG_ICC_AP0R1_EL1:
956 AssertReleaseFailed();
957 break;
958 case ARMV8_AARCH64_SYSREG_ICC_AP0R2_EL1:
959 AssertReleaseFailed();
960 break;
961 case ARMV8_AARCH64_SYSREG_ICC_AP0R3_EL1:
962 AssertReleaseFailed();
963 break;
964 case ARMV8_AARCH64_SYSREG_ICC_AP1R0_EL1:
965 AssertReleaseFailed();
966 break;
967 case ARMV8_AARCH64_SYSREG_ICC_AP1R1_EL1:
968 AssertReleaseFailed();
969 break;
970 case ARMV8_AARCH64_SYSREG_ICC_AP1R2_EL1:
971 AssertReleaseFailed();
972 break;
973 case ARMV8_AARCH64_SYSREG_ICC_AP1R3_EL1:
974 AssertReleaseFailed();
975 break;
976 case ARMV8_AARCH64_SYSREG_ICC_NMIAR1_EL1:
977 AssertReleaseFailed();
978 break;
979 case ARMV8_AARCH64_SYSREG_ICC_DIR_EL1:
980 AssertReleaseFailed();
981 break;
982 case ARMV8_AARCH64_SYSREG_ICC_RPR_EL1:
983 *pu64Value = pThis->abRunningPriorities[pThis->idxRunningPriority];
984 break;
985 case ARMV8_AARCH64_SYSREG_ICC_SGI1R_EL1:
986 AssertReleaseFailed();
987 break;
988 case ARMV8_AARCH64_SYSREG_ICC_ASGI1R_EL1:
989 AssertReleaseFailed();
990 break;
991 case ARMV8_AARCH64_SYSREG_ICC_SGI0R_EL1:
992 AssertReleaseFailed();
993 break;
994 case ARMV8_AARCH64_SYSREG_ICC_IAR1_EL1:
995 {
996 /** @todo Figure out the highest priority interrupt. */
997 uint32_t bmIntActive = ASMAtomicReadU32(&pThis->bmIntActive);
998 uint32_t bmIntEnabled = ASMAtomicReadU32(&pThis->bmIntEnabled);
999 uint32_t bmPending = (ASMAtomicReadU32(&pThis->bmIntPending) & bmIntEnabled) & ~bmIntActive;
1000 int32_t idxIntPending = ASMBitFirstSet(&bmPending, sizeof(bmPending) * 8);
1001 if (idxIntPending > -1)
1002 {
1003 /* Mark the interrupt as active. */
1004 ASMAtomicOrU32(&pThis->bmIntActive, RT_BIT_32(idxIntPending));
1005 /* Drop priority. */
1006 Assert((uint32_t)idxIntPending < RT_ELEMENTS(pThis->abIntPriority));
1007 Assert(pThis->idxRunningPriority < RT_ELEMENTS(pThis->abRunningPriorities) - 1);
1008
1009 LogFlowFunc(("Dropping interrupt priority from %u -> %u (idxRunningPriority: %u -> %u)\n",
1010 pThis->abRunningPriorities[pThis->idxRunningPriority],
1011 pThis->abIntPriority[idxIntPending],
1012 pThis->idxRunningPriority, pThis->idxRunningPriority + 1));
1013
1014 pThis->abRunningPriorities[++pThis->idxRunningPriority] = pThis->abIntPriority[idxIntPending];
1015
1016 /* Clear edge level interrupts like SGIs as pending. */
1017 if (idxIntPending <= GIC_INTID_RANGE_SGI_LAST)
1018 ASMAtomicBitClear(&pThis->bmIntPending, idxIntPending);
1019 *pu64Value = idxIntPending;
1020 gicReDistUpdateIrqState(pThis, pVCpu);
1021 }
1022 else
1023 {
1024 /** @todo This is wrong as the guest might decide to prioritize PPIs and SPIs differently. */
1025 bmIntActive = ASMAtomicReadU32(&pGicDev->bmIntActive);
1026 bmIntEnabled = ASMAtomicReadU32(&pGicDev->bmIntEnabled);
1027 bmPending = (ASMAtomicReadU32(&pGicDev->bmIntPending) & bmIntEnabled) & ~bmIntActive;
1028 idxIntPending = ASMBitFirstSet(&bmPending, sizeof(bmPending) * 8);
1029 if ( idxIntPending > -1
1030 && pGicDev->abIntPriority[idxIntPending] < pThis->bInterruptPriority)
1031 {
1032 /* Mark the interrupt as active. */
1033 ASMAtomicOrU32(&pGicDev->bmIntActive, RT_BIT_32(idxIntPending));
1034
1035 /* Drop priority. */
1036 Assert((uint32_t)idxIntPending < RT_ELEMENTS(pGicDev->abIntPriority));
1037 Assert(pThis->idxRunningPriority < RT_ELEMENTS(pThis->abRunningPriorities) - 1);
1038
1039 LogFlowFunc(("Dropping interrupt priority from %u -> %u (idxRunningPriority: %u -> %u)\n",
1040 pThis->abRunningPriorities[pThis->idxRunningPriority],
1041 pThis->abIntPriority[idxIntPending],
1042 pThis->idxRunningPriority, pThis->idxRunningPriority + 1));
1043
1044 pThis->abRunningPriorities[++pThis->idxRunningPriority] = pGicDev->abIntPriority[idxIntPending];
1045
1046 *pu64Value = idxIntPending + GIC_INTID_RANGE_SPI_START;
1047 gicReDistUpdateIrqState(pThis, pVCpu);
1048 }
1049 else
1050 *pu64Value = GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT;
1051 }
1052 break;
1053 }
1054 case ARMV8_AARCH64_SYSREG_ICC_EOIR1_EL1:
1055 AssertReleaseFailed();
1056 break;
1057 case ARMV8_AARCH64_SYSREG_ICC_HPPIR1_EL1:
1058 {
1059 /** @todo Figure out the highest priority interrupt. */
1060 uint32_t bmIntActive = ASMAtomicReadU32(&pThis->bmIntActive);
1061 uint32_t bmIntEnabled = ASMAtomicReadU32(&pThis->bmIntEnabled);
1062 uint32_t bmPending = (ASMAtomicReadU32(&pThis->bmIntPending) & bmIntEnabled) & ~bmIntActive;
1063 int32_t idxIntPending = ASMBitFirstSet(&bmPending, sizeof(bmPending) * 8);
1064 if (idxIntPending > -1)
1065 *pu64Value = idxIntPending;
1066 else
1067 {
1068 /** @todo This is wrong as the guest might decide to prioritize PPIs and SPIs differently. */
1069 bmIntActive = ASMAtomicReadU32(&pGicDev->bmIntActive);
1070 bmIntEnabled = ASMAtomicReadU32(&pGicDev->bmIntEnabled);
1071 bmPending = (ASMAtomicReadU32(&pGicDev->bmIntPending) & bmIntEnabled) & ~bmIntActive;
1072 idxIntPending = ASMBitFirstSet(&bmPending, sizeof(bmPending) * 8);
1073 if (idxIntPending > -1)
1074 *pu64Value = idxIntPending + GIC_INTID_RANGE_SPI_START;
1075 else
1076 *pu64Value = GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT;
1077 }
1078 break;
1079 }
1080 case ARMV8_AARCH64_SYSREG_ICC_BPR1_EL1:
1081 *pu64Value = pThis->bBinaryPointGrp1 & 0x7;
1082 break;
1083 case ARMV8_AARCH64_SYSREG_ICC_CTLR_EL1:
1084 *pu64Value = ARMV8_ICC_CTLR_EL1_AARCH64_PMHE
1085 | ARMV8_ICC_CTLR_EL1_AARCH64_PRIBITS_SET(4)
1086 | ARMV8_ICC_CTLR_EL1_AARCH64_IDBITS_SET(ARMV8_ICC_CTLR_EL1_AARCH64_IDBITS_16BITS);
1087 break;
1088 case ARMV8_AARCH64_SYSREG_ICC_SRE_EL1:
1089 AssertReleaseFailed();
1090 break;
1091 case ARMV8_AARCH64_SYSREG_ICC_IGRPEN0_EL1:
1092 *pu64Value = ASMAtomicReadBool(&pThis->fIrqGrp0Enabled) ? ARMV8_ICC_IGRPEN0_EL1_AARCH64_ENABLE : 0;
1093 break;
1094 case ARMV8_AARCH64_SYSREG_ICC_IGRPEN1_EL1:
1095 *pu64Value = ASMAtomicReadBool(&pThis->fIrqGrp1Enabled) ? ARMV8_ICC_IGRPEN1_EL1_AARCH64_ENABLE : 0;
1096 break;
1097 default:
1098 AssertReleaseFailed();
1099 break;
1100 }
1101
1102 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
1103
1104 LogFlowFunc(("pVCpu=%p u32Reg=%#x{%s} pu64Value=%RX64\n", pVCpu, u32Reg, gicIccRegisterStringify(u32Reg), *pu64Value));
1105 return VINF_SUCCESS;
1106}
1107
1108
1109/**
1110 * Writes an GIC system register.
1111 *
1112 * @returns Strict VBox status code.
1113 * @param pVCpu The cross context virtual CPU structure.
1114 * @param u32Reg The system register being written (IPRT system register identifier).
1115 * @param u64Value The value to write.
1116 */
1117VMM_INT_DECL(VBOXSTRICTRC) GICWriteSysReg(PVMCPUCC pVCpu, uint32_t u32Reg, uint64_t u64Value)
1118{
1119 /*
1120 * Validate.
1121 */
1122 VMCPU_ASSERT_EMT(pVCpu);
1123 LogFlowFunc(("pVCpu=%p u32Reg=%#x{%s} u64Value=%RX64\n", pVCpu, u32Reg, gicIccRegisterStringify(u32Reg), u64Value));
1124
1125 PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
1126 PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
1127 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
1128
1129 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
1130 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
1131
1132 switch (u32Reg)
1133 {
1134 case ARMV8_AARCH64_SYSREG_ICC_PMR_EL1:
1135 LogFlowFunc(("ICC_PMR_EL1: Interrupt priority now %u\n", (uint8_t)u64Value));
1136 ASMAtomicWriteU8(&pThis->bInterruptPriority, (uint8_t)u64Value);
1137 gicReDistUpdateIrqState(pThis, pVCpu);
1138 break;
1139 case ARMV8_AARCH64_SYSREG_ICC_IAR0_EL1:
1140 AssertReleaseFailed();
1141 break;
1142 case ARMV8_AARCH64_SYSREG_ICC_EOIR0_EL1:
1143 AssertReleaseFailed();
1144 break;
1145 case ARMV8_AARCH64_SYSREG_ICC_HPPIR0_EL1:
1146 AssertReleaseFailed();
1147 break;
1148 case ARMV8_AARCH64_SYSREG_ICC_BPR0_EL1:
1149 pThis->bBinaryPointGrp0 = (uint8_t)(u64Value & 0x7);
1150 break;
1151 case ARMV8_AARCH64_SYSREG_ICC_AP0R0_EL1:
1152 /** @todo */
1153 break;
1154 case ARMV8_AARCH64_SYSREG_ICC_AP0R1_EL1:
1155 AssertReleaseFailed();
1156 break;
1157 case ARMV8_AARCH64_SYSREG_ICC_AP0R2_EL1:
1158 AssertReleaseFailed();
1159 break;
1160 case ARMV8_AARCH64_SYSREG_ICC_AP0R3_EL1:
1161 AssertReleaseFailed();
1162 break;
1163 case ARMV8_AARCH64_SYSREG_ICC_AP1R0_EL1:
1164 /** @todo */
1165 break;
1166 case ARMV8_AARCH64_SYSREG_ICC_AP1R1_EL1:
1167 AssertReleaseFailed();
1168 break;
1169 case ARMV8_AARCH64_SYSREG_ICC_AP1R2_EL1:
1170 AssertReleaseFailed();
1171 break;
1172 case ARMV8_AARCH64_SYSREG_ICC_AP1R3_EL1:
1173 AssertReleaseFailed();
1174 break;
1175 case ARMV8_AARCH64_SYSREG_ICC_NMIAR1_EL1:
1176 AssertReleaseFailed();
1177 break;
1178 case ARMV8_AARCH64_SYSREG_ICC_DIR_EL1:
1179 AssertReleaseFailed();
1180 break;
1181 case ARMV8_AARCH64_SYSREG_ICC_RPR_EL1:
1182 AssertReleaseFailed();
1183 break;
1184 case ARMV8_AARCH64_SYSREG_ICC_SGI1R_EL1:
1185 {
1186 uint32_t uIntId = ARMV8_ICC_SGI1R_EL1_AARCH64_INTID_GET(u64Value) - GIC_INTID_RANGE_SGI_START;
1187 if (u64Value & ARMV8_ICC_SGI1R_EL1_AARCH64_IRM)
1188 {
1189 /* Route to all but this vCPU. */
1190 for (uint32_t i = 0; i < pVCpu->pVMR3->cCpus; i++)
1191 {
1192 if (i != pVCpu->idCpu)
1193 {
1194 PVMCPUCC pVCpuDst = VMMGetCpuById(pVCpu->CTX_SUFF(pVM), i);
1195 if (pVCpuDst)
1196 GICSgiSet(pVCpuDst, uIntId, true /*fAsserted*/);
1197 else
1198 AssertFailed();
1199 }
1200 }
1201 }
1202 else
1203 {
1204 /* Examine target list. */
1205 /** @todo Range selector support. */
1206 VMCPUID idCpu = 0;
1207 uint16_t uTgtList = ARMV8_ICC_SGI1R_EL1_AARCH64_TARGET_LIST_GET(u64Value);
1208 /** @todo rewrite using ASMBitFirstSetU16. */
1209 while (uTgtList)
1210 {
1211 if (uTgtList & 0x1)
1212 {
1213 PVMCPUCC pVCpuDst = VMMGetCpuById(pVCpu->CTX_SUFF(pVM), idCpu);
1214 if (pVCpuDst)
1215 GICSgiSet(pVCpuDst, uIntId, true /*fAsserted*/);
1216 else
1217 AssertFailed();
1218 }
1219 uTgtList >>= 1;
1220 idCpu++;
1221 }
1222 }
1223 break;
1224 }
1225 case ARMV8_AARCH64_SYSREG_ICC_ASGI1R_EL1:
1226 AssertReleaseFailed();
1227 break;
1228 case ARMV8_AARCH64_SYSREG_ICC_SGI0R_EL1:
1229 AssertReleaseFailed();
1230 break;
1231 case ARMV8_AARCH64_SYSREG_ICC_IAR1_EL1:
1232 AssertReleaseFailed();
1233 break;
1234 case ARMV8_AARCH64_SYSREG_ICC_EOIR1_EL1:
1235 {
1236 /* Mark the interrupt as not active anymore, though it might still be pending. */
1237 if (u64Value < GIC_INTID_RANGE_SPI_START)
1238 ASMAtomicAndU32(&pThis->bmIntActive, ~RT_BIT_32((uint32_t)u64Value));
1239 else
1240 ASMAtomicAndU32(&pGicDev->bmIntActive, ~RT_BIT_32((uint32_t)(u64Value - GIC_INTID_RANGE_SPI_START)));
1241
1242 /* Restore previous interrupt priority. */
1243 Assert(pThis->idxRunningPriority > 0);
1244 if (RT_LIKELY(pThis->idxRunningPriority))
1245 {
1246 LogFlowFunc(("Restoring interrupt priority from %u -> %u (idxRunningPriority: %u -> %u)\n",
1247 pThis->abRunningPriorities[pThis->idxRunningPriority],
1248 pThis->abRunningPriorities[pThis->idxRunningPriority - 1],
1249 pThis->idxRunningPriority, pThis->idxRunningPriority - 1));
1250 pThis->idxRunningPriority--;
1251 }
1252 gicReDistUpdateIrqState(pThis, pVCpu);
1253 break;
1254 }
1255 case ARMV8_AARCH64_SYSREG_ICC_HPPIR1_EL1:
1256 AssertReleaseFailed();
1257 break;
1258 case ARMV8_AARCH64_SYSREG_ICC_BPR1_EL1:
1259 pThis->bBinaryPointGrp0 = (uint8_t)(u64Value & 0x7);
1260 break;
1261 case ARMV8_AARCH64_SYSREG_ICC_CTLR_EL1:
1262 u64Value &= ARMV8_ICC_CTLR_EL1_RW;
1263 /** @todo */
1264 break;
1265 case ARMV8_AARCH64_SYSREG_ICC_SRE_EL1:
1266 AssertReleaseFailed();
1267 break;
1268 case ARMV8_AARCH64_SYSREG_ICC_IGRPEN0_EL1:
1269 ASMAtomicWriteBool(&pThis->fIrqGrp0Enabled, RT_BOOL(u64Value & ARMV8_ICC_IGRPEN0_EL1_AARCH64_ENABLE));
1270 break;
1271 case ARMV8_AARCH64_SYSREG_ICC_IGRPEN1_EL1:
1272 ASMAtomicWriteBool(&pThis->fIrqGrp1Enabled, RT_BOOL(u64Value & ARMV8_ICC_IGRPEN1_EL1_AARCH64_ENABLE));
1273 break;
1274 default:
1275 AssertReleaseFailed();
1276 break;
1277 }
1278
1279 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
1280 return VINF_SUCCESS;
1281}
1282
1283
1284/**
1285 * Sets the specified shared peripheral interrupt starting.
1286 *
1287 * @returns VBox status code.
1288 * @param pVM The cross context virtual machine structure.
1289 * @param uIntId The SPI ID (minus GIC_INTID_RANGE_SPI_START) to assert/de-assert.
1290 * @param fAsserted Flag whether to mark the interrupt as asserted/de-asserted.
1291 */
1292VMM_INT_DECL(int) GICSpiSet(PVMCC pVM, uint32_t uIntId, bool fAsserted)
1293{
1294 LogFlowFunc(("pVM=%p uIntId=%u fAsserted=%RTbool\n",
1295 pVM, uIntId, fAsserted));
1296
1297 AssertReturn(uIntId < GIC_SPI_MAX, VERR_INVALID_PARAMETER);
1298
1299 PGIC pGic = VM_TO_GIC(pVM);
1300
1301 /** @todo r=aeichner There must be another way to do this better, maybe create some callback interface
1302 * the GIC can register. */
1303#ifdef IN_RING3
1304 if (pGic->fNemGic)
1305 return GICR3NemSpiSet(pVM, uIntId, fAsserted);
1306#else
1307# error "Impossible to call the NEM in-kernel GIC from this context!"
1308#endif
1309
1310 PPDMDEVINS pDevIns = pGic->CTX_SUFF(pDevIns);
1311 PGICDEV pThis = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
1312
1313 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
1314 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
1315
1316 /* Update the interrupts pending state. */
1317 if (fAsserted)
1318 ASMAtomicOrU32(&pThis->bmIntPending, RT_BIT_32(uIntId));
1319 else
1320 ASMAtomicAndU32(&pThis->bmIntPending, ~RT_BIT_32(uIntId));
1321
1322 int rc = VBOXSTRICTRC_VAL(gicDistUpdateIrqState(pVM, pThis));
1323 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
1324 return rc;
1325}
1326
1327
1328/**
1329 * Sets the specified private peripheral interrupt starting.
1330 *
1331 * @returns VBox status code.
1332 * @param pVCpu The cross context virtual CPU structure.
1333 * @param uIntId The PPI ID (minus GIC_INTID_RANGE_PPI_START) to assert/de-assert.
1334 * @param fAsserted Flag whether to mark the interrupt as asserted/de-asserted.
1335 */
1336VMM_INT_DECL(int) GICPpiSet(PVMCPUCC pVCpu, uint32_t uIntId, bool fAsserted)
1337{
1338 LogFlowFunc(("pVCpu=%p{.idCpu=%u} uIntId=%u fAsserted=%RTbool\n",
1339 pVCpu, pVCpu->idCpu, uIntId, fAsserted));
1340
1341 PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
1342
1343 /** @todo r=aeichner There must be another way to do this better, maybe create some callback interface
1344 * the GIC can register. */
1345#ifdef IN_RING3
1346 PGIC pGic = VM_TO_GIC(pVCpu->pVMR3);
1347 if (pGic->fNemGic)
1348 return GICR3NemPpiSet(pVCpu, uIntId, fAsserted);
1349#else
1350# error "Impossible to call the NEM in-kernel GIC from this context!"
1351#endif
1352
1353 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
1354 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
1355
1356 AssertReturn(uIntId <= (GIC_INTID_RANGE_PPI_LAST - GIC_INTID_RANGE_PPI_START), VERR_INVALID_PARAMETER);
1357 int rc = gicReDistInterruptSet(pVCpu, uIntId + GIC_INTID_RANGE_PPI_START, fAsserted);
1358 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
1359
1360 return rc;
1361}
1362
1363
1364/**
1365 * Sets the specified software generated interrupt starting.
1366 *
1367 * @returns VBox status code.
1368 * @param pVCpu The cross context virtual CPU structure.
1369 * @param uIntId The PPI ID (minus GIC_INTID_RANGE_SGI_START) to assert/de-assert.
1370 * @param fAsserted Flag whether to mark the interrupt as asserted/de-asserted.
1371 */
1372VMM_INT_DECL(int) GICSgiSet(PVMCPUCC pVCpu, uint32_t uIntId, bool fAsserted)
1373{
1374 LogFlowFunc(("pVCpu=%p{.idCpu=%u} uIntId=%u fAsserted=%RTbool\n",
1375 pVCpu, pVCpu->idCpu, uIntId, fAsserted));
1376
1377 PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
1378
1379 /** @todo r=aeichner There must be another way to do this better, maybe create some callback interface
1380 * the GIC can register. */
1381#ifdef IN_RING3
1382 PGIC pGic = VM_TO_GIC(pVCpu->pVMR3);
1383 /* These should be handled in the kernel and never be set from here. */
1384 AssertReturn(!pGic->fNemGic, VERR_NEM_IPE_6);
1385#else
1386# error "Impossible to call the in-kernel GIC from this context!"
1387#endif
1388
1389 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
1390 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
1391
1392 AssertReturn(uIntId <= (GIC_INTID_RANGE_SGI_LAST - GIC_INTID_RANGE_SGI_START), VERR_INVALID_PARAMETER);
1393 int rc = gicReDistInterruptSet(pVCpu, uIntId + GIC_INTID_RANGE_SGI_START, fAsserted);
1394 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
1395
1396 return rc;
1397}
1398
1399
1400/**
1401 * Initializes per-VCPU GIC to the state following a power-up or hardware
1402 * reset.
1403 *
1404 * @param pVCpu The cross context virtual CPU structure.
1405 */
1406DECLHIDDEN(void) gicResetCpu(PVMCPUCC pVCpu)
1407{
1408 LogFlowFunc(("GIC%u\n", pVCpu->idCpu));
1409 VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu);
1410
1411 memset((void *)&pVCpu->gic.s.abRunningPriorities[0], 0xff, sizeof(pVCpu->gic.s.abRunningPriorities));
1412 pVCpu->gic.s.idxRunningPriority = 0;
1413 pVCpu->gic.s.bInterruptPriority = 0; /* Means no interrupt gets through to the PE. */
1414}
1415
1416
1417/**
1418 * @callback_method_impl{FNIOMMMIONEWREAD}
1419 */
1420DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) gicDistMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
1421{
1422 NOREF(pvUser);
1423 Assert(!(off & 0x3));
1424 Assert(cb == 4); RT_NOREF_PV(cb);
1425
1426 PVMCPUCC pVCpu = PDMDevHlpGetVMCPU(pDevIns);
1427 uint16_t offReg = off & 0xfffc;
1428 uint32_t uValue = 0;
1429
1430 STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioRead));
1431
1432 VBOXSTRICTRC rc = VBOXSTRICTRC_VAL(gicDistRegisterRead(pDevIns, pVCpu, offReg, &uValue));
1433 *(uint32_t *)pv = uValue;
1434
1435 Log2(("GIC%u: gicDistMmioRead: offReg=%#RX16 uValue=%#RX32\n", pVCpu->idCpu, offReg, uValue));
1436 return rc;
1437}
1438
1439
1440/**
1441 * @callback_method_impl{FNIOMMMIONEWWRITE}
1442 */
1443DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) gicDistMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
1444{
1445 NOREF(pvUser);
1446 Assert(!(off & 0x3));
1447 Assert(cb == 4); RT_NOREF_PV(cb);
1448
1449 PVMCPUCC pVCpu = PDMDevHlpGetVMCPU(pDevIns);
1450 uint16_t offReg = off & 0xfffc;
1451 uint32_t uValue = *(uint32_t *)pv;
1452
1453 STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioWrite));
1454
1455 Log2(("GIC%u: gicDistMmioWrite: offReg=%#RX16 uValue=%#RX32\n", pVCpu->idCpu, offReg, uValue));
1456 return gicDistRegisterWrite(pDevIns, pVCpu, offReg, uValue);
1457}
1458
1459
1460/**
1461 * @callback_method_impl{FNIOMMMIONEWREAD}
1462 */
1463DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) gicReDistMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
1464{
1465 NOREF(pvUser);
1466 Assert(!(off & 0x3));
1467 Assert(cb == 4); RT_NOREF_PV(cb);
1468
1469 /*
1470 * Determine the redistributor being targeted. Each redistributor takes GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE bytes
1471 * and the redistributors are adjacent.
1472 */
1473 uint32_t idReDist = off / (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
1474 off %= (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
1475
1476 PVMCC pVM = PDMDevHlpGetVM(pDevIns);
1477 Assert(idReDist < pVM->cCpus);
1478 PVMCPUCC pVCpu = pVM->apCpusR3[idReDist];
1479
1480 STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioRead));
1481
1482 /* Redistributor or SGI/PPI frame? */
1483 uint16_t offReg = off & 0xfffc;
1484 uint32_t uValue = 0;
1485 VBOXSTRICTRC rcStrict;
1486 if (off < GIC_REDIST_REG_FRAME_SIZE)
1487 rcStrict = gicReDistRegisterRead(pDevIns, pVCpu, idReDist, offReg, &uValue);
1488 else
1489 rcStrict = gicReDistSgiPpiRegisterRead(pDevIns, pVCpu, offReg, &uValue);
1490
1491 *(uint32_t *)pv = uValue;
1492 Log2(("GICReDist%u: gicReDistMmioRead: off=%RGp idReDist=%u offReg=%#RX16 uValue=%#RX32 -> %Rrc\n",
1493 pVCpu->idCpu, off, idReDist, offReg, uValue, VBOXSTRICTRC_VAL(rcStrict)));
1494 return rcStrict;
1495}
1496
1497
1498/**
1499 * @callback_method_impl{FNIOMMMIONEWWRITE}
1500 */
1501DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) gicReDistMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
1502{
1503 NOREF(pvUser);
1504 Assert(!(off & 0x3));
1505 Assert(cb == 4); RT_NOREF_PV(cb);
1506
1507 uint32_t uValue = *(uint32_t *)pv;
1508
1509 /*
1510 * Determine the redistributor being targeted. Each redistributor takes GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE bytes
1511 * and the redistributors are adjacent.
1512 */
1513 uint32_t idReDist = off / (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
1514 off %= (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
1515
1516 PVMCC pVM = PDMDevHlpGetVM(pDevIns);
1517 Assert(idReDist < pVM->cCpus);
1518 PVMCPUCC pVCpu = pVM->apCpusR3[idReDist];
1519
1520 STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioWrite));
1521
1522 /* Redistributor or SGI/PPI frame? */
1523 uint16_t offReg = off & 0xfffc;
1524 VBOXSTRICTRC rcStrict;
1525 if (off < GIC_REDIST_REG_FRAME_SIZE)
1526 rcStrict = gicReDistRegisterWrite(pDevIns, pVCpu, offReg, uValue);
1527 else
1528 rcStrict = gicReDistSgiPpiRegisterWrite(pDevIns, pVCpu, offReg, uValue);
1529
1530 Log2(("GICReDist%u: gicReDistMmioWrite: off=%RGp idReDist=%u offReg=%#RX16 uValue=%#RX32 -> %Rrc\n",
1531 pVCpu->idCpu, off, idReDist, offReg, uValue, VBOXSTRICTRC_VAL(rcStrict)));
1532 return rcStrict;
1533}
1534
1535
1536#ifndef IN_RING3
1537
1538/**
1539 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
1540 */
1541static DECLCALLBACK(int) gicRZConstruct(PPDMDEVINS pDevIns)
1542{
1543 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1544 AssertReleaseFailed();
1545 return VINF_SUCCESS;
1546}
1547#endif /* !IN_RING3 */
1548
1549/**
1550 * GIC device registration structure.
1551 */
1552const PDMDEVREG g_DeviceGIC =
1553{
1554 /* .u32Version = */ PDM_DEVREG_VERSION,
1555 /* .uReserved0 = */ 0,
1556 /* .szName = */ "gic",
1557 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
1558 /* .fClass = */ PDM_DEVREG_CLASS_PIC,
1559 /* .cMaxInstances = */ 1,
1560 /* .uSharedVersion = */ 42,
1561 /* .cbInstanceShared = */ sizeof(GICDEV),
1562 /* .cbInstanceCC = */ 0,
1563 /* .cbInstanceRC = */ 0,
1564 /* .cMaxPciDevices = */ 0,
1565 /* .cMaxMsixVectors = */ 0,
1566 /* .pszDescription = */ "Generic Interrupt Controller",
1567#if defined(IN_RING3)
1568 /* .szRCMod = */ "VMMRC.rc",
1569 /* .szR0Mod = */ "VMMR0.r0",
1570 /* .pfnConstruct = */ gicR3Construct,
1571 /* .pfnDestruct = */ gicR3Destruct,
1572 /* .pfnRelocate = */ gicR3Relocate,
1573 /* .pfnMemSetup = */ NULL,
1574 /* .pfnPowerOn = */ NULL,
1575 /* .pfnReset = */ gicR3Reset,
1576 /* .pfnSuspend = */ NULL,
1577 /* .pfnResume = */ NULL,
1578 /* .pfnAttach = */ NULL,
1579 /* .pfnDetach = */ NULL,
1580 /* .pfnQueryInterface = */ NULL,
1581 /* .pfnInitComplete = */ NULL,
1582 /* .pfnPowerOff = */ NULL,
1583 /* .pfnSoftReset = */ NULL,
1584 /* .pfnReserved0 = */ NULL,
1585 /* .pfnReserved1 = */ NULL,
1586 /* .pfnReserved2 = */ NULL,
1587 /* .pfnReserved3 = */ NULL,
1588 /* .pfnReserved4 = */ NULL,
1589 /* .pfnReserved5 = */ NULL,
1590 /* .pfnReserved6 = */ NULL,
1591 /* .pfnReserved7 = */ NULL,
1592#elif defined(IN_RING0)
1593 /* .pfnEarlyConstruct = */ NULL,
1594 /* .pfnConstruct = */ gicRZConstruct,
1595 /* .pfnDestruct = */ NULL,
1596 /* .pfnFinalDestruct = */ NULL,
1597 /* .pfnRequest = */ NULL,
1598 /* .pfnReserved0 = */ NULL,
1599 /* .pfnReserved1 = */ NULL,
1600 /* .pfnReserved2 = */ NULL,
1601 /* .pfnReserved3 = */ NULL,
1602 /* .pfnReserved4 = */ NULL,
1603 /* .pfnReserved5 = */ NULL,
1604 /* .pfnReserved6 = */ NULL,
1605 /* .pfnReserved7 = */ NULL,
1606#elif defined(IN_RC)
1607 /* .pfnConstruct = */ gicRZConstruct,
1608 /* .pfnReserved0 = */ NULL,
1609 /* .pfnReserved1 = */ NULL,
1610 /* .pfnReserved2 = */ NULL,
1611 /* .pfnReserved3 = */ NULL,
1612 /* .pfnReserved4 = */ NULL,
1613 /* .pfnReserved5 = */ NULL,
1614 /* .pfnReserved6 = */ NULL,
1615 /* .pfnReserved7 = */ NULL,
1616#else
1617# error "Not in IN_RING3, IN_RING0 or IN_RC!"
1618#endif
1619 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
1620};
1621
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