VirtualBox

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

Last change on this file since 106362 was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 57.3 KB
Line 
1/* $Id: GICAll.cpp 106061 2024-09-16 14:03:52Z 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 /* Is anything enabled at all? */
214 uint32_t bmIntForward = (bmIntPending & bmIntEnabled) & ~bmIntActive; /* Exclude the currently active interrupt. */
215
216 /* Only allow interrupts with higher priority than the current configured and running one. */
217 uint8_t bPriority = RT_MIN(pThis->bInterruptPriority, pThis->abRunningPriorities[pThis->idxRunningPriority]);
218
219 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->abIntPriority); i++)
220 {
221 Log4(("SGI/PPI %u, configured priority %u, running priority %u\n", i, pThis->abIntPriority[i], bPriority));
222 if ( (bmIntForward & RT_BIT_32(i))
223 && pThis->abIntPriority[i] < bPriority)
224 break;
225 else
226 bmIntForward &= ~RT_BIT_32(i);
227
228 if (!bmIntForward)
229 break;
230 }
231
232 if (bmIntForward)
233 {
234 /* Determine whether we have to assert the IRQ or FIQ line. */
235 *pfIrq = RT_BOOL(bmIntForward & u32RegIGrp0) && fIrqGrp1Enabled;
236 *pfFiq = RT_BOOL(bmIntForward & ~u32RegIGrp0) && fIrqGrp0Enabled;
237 }
238 else
239 {
240 *pfIrq = false;
241 *pfFiq = false;
242 }
243
244 LogFlowFunc(("pThis=%p bPriority=%u bmIntEnabled=%#x bmIntPending=%#x bmIntActive=%#x fIrq=%RTbool fFiq=%RTbool\n",
245 pThis, bPriority, bmIntEnabled, bmIntPending, bmIntActive, *pfIrq, *pfFiq));
246}
247
248
249DECLINLINE(void) gicDistHasIrqPendingForVCpu(PGICDEV pThis, PGICCPU pGicVCpu, bool *pfIrq, bool *pfFiq)
250{
251 /* Read the interrupt state. */
252 uint32_t u32RegIGrp0 = ASMAtomicReadU32(&pThis->u32RegIGrp0);
253 uint32_t bmIntEnabled = ASMAtomicReadU32(&pThis->bmIntEnabled);
254 uint32_t bmIntPending = ASMAtomicReadU32(&pThis->bmIntPending);
255 uint32_t bmIntActive = ASMAtomicReadU32(&pThis->bmIntActive);
256 bool fIrqGrp0Enabled = ASMAtomicReadBool(&pThis->fIrqGrp0Enabled);
257 bool fIrqGrp1Enabled = ASMAtomicReadBool(&pThis->fIrqGrp1Enabled);
258
259 /* Is anything enabled at all? */
260 uint32_t bmIntForward = (bmIntPending & bmIntEnabled) & ~bmIntActive; /* Exclude the currently active interrupt. */
261
262 /* Only allow interrupts with higher priority than the current configured and running one. */
263 uint8_t bPriority = RT_MIN(pGicVCpu->bInterruptPriority, pGicVCpu->abRunningPriorities[pGicVCpu->idxRunningPriority]);
264 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->abIntPriority); i++)
265 {
266 if ( (bmIntForward & RT_BIT_32(i))
267 && pThis->abIntPriority[i] < bPriority)
268 break;
269 else
270 bmIntForward &= ~RT_BIT_32(i);
271 }
272
273 if (bmIntForward)
274 {
275 /* Determine whether we have to assert the IRQ or FIQ line. */
276 *pfIrq = RT_BOOL(bmIntForward & u32RegIGrp0) && fIrqGrp1Enabled;
277 *pfFiq = RT_BOOL(bmIntForward & ~u32RegIGrp0) && fIrqGrp0Enabled;
278 }
279 else
280 {
281 *pfIrq = false;
282 *pfFiq = false;
283 }
284
285 LogFlowFunc(("pThis=%p bPriority=%u bmIntEnabled=%#x bmIntPending=%#x bmIntActive=%#x fIrq=%RTbool fFiq=%RTbool\n",
286 pThis, bPriority, bmIntEnabled, bmIntPending, bmIntActive, *pfIrq, *pfFiq));
287}
288
289
290/**
291 * Updates the internal IRQ state and sets or clears the appropirate force action flags.
292 *
293 * @returns Strict VBox status code.
294 * @param pThis The GIC re-distributor state for the associated vCPU.
295 * @param pVCpu The cross context virtual CPU structure.
296 */
297static VBOXSTRICTRC gicReDistUpdateIrqState(PGICCPU pThis, PVMCPUCC pVCpu)
298{
299 bool fIrq, fFiq;
300 gicReDistHasIrqPending(pThis, &fIrq, &fFiq);
301
302 PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
303 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
304 bool fIrqDist, fFiqDist;
305 gicDistHasIrqPendingForVCpu(pGicDev, pThis, &fIrqDist, &fFiqDist);
306 fIrq |= fIrqDist;
307 fFiq |= fFiqDist;
308
309 gicUpdateInterruptFF(pVCpu, fIrq, fFiq);
310 return VINF_SUCCESS;
311}
312
313
314/**
315 * Updates the internal IRQ state of the distributor and sets or clears the appropirate force action flags.
316 *
317 * @returns Strict VBox status code.
318 * @param pVM The cross context VM state.
319 * @param pThis The GIC distributor state.
320 */
321static VBOXSTRICTRC gicDistUpdateIrqState(PVMCC pVM, PGICDEV pThis)
322{
323 for (uint32_t i = 0; i < pVM->cCpus; i++)
324 {
325 PVMCPUCC pVCpu = pVM->CTX_SUFF(apCpus)[i];
326 PGICCPU pGicVCpu = VMCPU_TO_GICCPU(pVCpu);
327
328 bool fIrq, fFiq;
329 gicReDistHasIrqPending(pGicVCpu, &fIrq, &fFiq);
330
331 bool fIrqDist, fFiqDist;
332 gicDistHasIrqPendingForVCpu(pThis, pGicVCpu, &fIrqDist, &fFiqDist);
333 fIrq |= fIrqDist;
334 fFiq |= fFiqDist;
335
336 gicUpdateInterruptFF(pVCpu, fIrq, fFiq);
337 }
338 return VINF_SUCCESS;
339}
340
341
342/**
343 * Sets the given SGI/PPI interrupt ID on the re-distributor of the given vCPU.
344 *
345 * @returns VBox status code.
346 * @param pVCpu The cross context virtual CPU structure.
347 * @param uIntId The SGI/PPI interrupt identifier.
348 * @param fAsserted Flag whether the SGI/PPI interrupt is asserted or not.
349 */
350static int gicReDistInterruptSet(PVMCPUCC pVCpu, uint32_t uIntId, bool fAsserted)
351{
352 PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
353
354 /* Update the interrupts pending state. */
355 if (fAsserted)
356 ASMAtomicOrU32(&pThis->bmIntPending, RT_BIT_32(uIntId));
357 else
358 ASMAtomicAndU32(&pThis->bmIntPending, ~RT_BIT_32(uIntId));
359
360 return VBOXSTRICTRC_VAL(gicReDistUpdateIrqState(pThis, pVCpu));
361}
362
363
364/**
365 * Reads a GIC distributor register.
366 *
367 * @returns VBox status code.
368 * @param pDevIns The device instance.
369 * @param pVCpu The cross context virtual CPU structure.
370 * @param offReg The offset of the register being read.
371 * @param puValue Where to store the register value.
372 */
373DECLINLINE(VBOXSTRICTRC) gicDistRegisterRead(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t *puValue)
374{
375 VMCPU_ASSERT_EMT(pVCpu);
376 PGICDEV pThis = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
377
378 switch (offReg)
379 {
380 case GIC_DIST_REG_CTLR_OFF:
381 *puValue = (ASMAtomicReadBool(&pThis->fIrqGrp0Enabled) ? GIC_DIST_REG_CTRL_ENABLE_GRP0 : 0)
382 | (ASMAtomicReadBool(&pThis->fIrqGrp1Enabled) ? GIC_DIST_REG_CTRL_ENABLE_GRP1_NS : 0)
383 | GIC_DIST_REG_CTRL_DS;
384 break;
385 case GIC_DIST_REG_TYPER_OFF:
386 *puValue = GIC_DIST_REG_TYPER_NUM_ITLINES_SET(1) /** @todo 32 SPIs for now. */
387 | GIC_DIST_REG_TYPER_NUM_PES_SET(0) /* 1 PE */
388 /*| GIC_DIST_REG_TYPER_ESPI*/ /** @todo */
389 /*| GIC_DIST_REG_TYPER_NMI*/ /** @todo Non-maskable interrupts */
390 /*| GIC_DIST_REG_TYPER_SECURITY_EXTN */ /** @todo */
391 /*| GIC_DIST_REG_TYPER_MBIS */ /** @todo Message based interrupts */
392 /*| GIC_DIST_REG_TYPER_LPIS */ /** @todo Support LPIs */
393 | GIC_DIST_REG_TYPER_IDBITS_SET(16);
394 break;
395 case GIC_DIST_REG_STATUSR_OFF:
396 AssertReleaseFailed();
397 break;
398 case GIC_DIST_REG_IGROUPRn_OFF_START: /* Only 32 lines for now. */
399 AssertReleaseFailed();
400 break;
401 case GIC_DIST_REG_ISENABLERn_OFF_START + 4: /* Only 32 lines for now. */
402 case GIC_DIST_REG_ICENABLERn_OFF_START + 4: /* Only 32 lines for now. */
403 *puValue = ASMAtomicReadU32(&pThis->bmIntEnabled);
404 break;
405 case GIC_DIST_REG_ISPENDRn_OFF_START: /* Only 32 lines for now. */
406 AssertReleaseFailed();
407 break;
408 case GIC_DIST_REG_ICPENDRn_OFF_START: /* Only 32 lines for now. */
409 AssertReleaseFailed();
410 break;
411 case GIC_DIST_REG_ISACTIVERn_OFF_START: /* Only 32 lines for now. */
412 AssertReleaseFailed();
413 break;
414 case GIC_DIST_REG_ICACTIVERn_OFF_START: /* Only 32 lines for now. */
415 AssertReleaseFailed();
416 break;
417 case GIC_DIST_REG_IPRIORITYn_OFF_START:
418 case GIC_DIST_REG_IPRIORITYn_OFF_START + 4: /* These are banked for the PEs and access the redistributor. */
419 {
420 PGICCPU pGicVCpu = VMCPU_TO_GICCPU(pVCpu);
421
422 /* Figure out the register which is written. */
423 uint8_t idxPrio = offReg - GIC_DIST_REG_IPRIORITYn_OFF_START;
424 Assert(idxPrio <= RT_ELEMENTS(pThis->abIntPriority) - sizeof(uint32_t));
425
426 uint32_t u32Value = 0;
427 for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
428 u32Value |= pGicVCpu->abIntPriority[i] << ((i - idxPrio) * 8);
429
430 *puValue = u32Value;
431 break;
432 }
433 case GIC_DIST_REG_IPRIORITYn_OFF_START + 32: /* Only 32 lines for now. */
434 {
435 /* Figure out the register which is written. */
436 uint8_t idxPrio = offReg - GIC_DIST_REG_IPRIORITYn_OFF_START - 32;
437 Assert(idxPrio <= RT_ELEMENTS(pThis->abIntPriority) - sizeof(uint32_t));
438
439 uint32_t u32Value = 0;
440 for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
441 u32Value |= pThis->abIntPriority[i] << ((i - idxPrio) * 8);
442
443 *puValue = u32Value;
444 break;
445 }
446 case GIC_DIST_REG_ITARGETSRn_OFF_START: /* Only 32 lines for now. */
447 AssertReleaseFailed();
448 break;
449 case GIC_DIST_REG_ICFGRn_OFF_START: /* Only 32 lines for now. */
450 AssertReleaseFailed();
451 break;
452 case GIC_DIST_REG_IGRPMODRn_OFF_START: /* Only 32 lines for now. */
453 AssertReleaseFailed();
454 break;
455 case GIC_DIST_REG_NSACRn_OFF_START: /* Only 32 lines for now. */
456 AssertReleaseFailed();
457 break;
458 case GIC_DIST_REG_SGIR_OFF:
459 AssertReleaseFailed();
460 break;
461 case GIC_DIST_REG_CPENDSGIRn_OFF_START:
462 AssertReleaseFailed();
463 break;
464 case GIC_DIST_REG_SPENDSGIRn_OFF_START:
465 AssertReleaseFailed();
466 break;
467 case GIC_DIST_REG_INMIn_OFF_START:
468 AssertReleaseFailed();
469 break;
470 case GIC_DIST_REG_IROUTERn_OFF_START: /* Only 32 lines for now. */
471 *puValue = 0; /** @todo */
472 break;
473 case GIC_DIST_REG_PIDR2_OFF:
474 *puValue = GIC_REDIST_REG_PIDR2_ARCH_REV_SET(GIC_REDIST_REG_PIDR2_ARCH_REV_GICV3);
475 break;
476 case GIC_DIST_REG_IIDR_OFF:
477 case GIC_DIST_REG_TYPER2_OFF:
478 *puValue = 0;
479 break;
480 default:
481 *puValue = 0;
482 }
483 return VINF_SUCCESS;
484}
485
486
487/**
488 * Writes a GIC distributor register.
489 *
490 * @returns Strict VBox status code.
491 * @param pDevIns The device instance.
492 * @param pVCpu The cross context virtual CPU structure.
493 * @param offReg The offset of the register being written.
494 * @param uValue The register value.
495 */
496DECLINLINE(VBOXSTRICTRC) gicDistRegisterWrite(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue)
497{
498 VMCPU_ASSERT_EMT(pVCpu); RT_NOREF(pVCpu);
499 PGICDEV pThis = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
500 PVMCC pVM = PDMDevHlpGetVM(pDevIns);
501
502 if (offReg >= GIC_DIST_REG_IROUTERn_OFF_START && offReg <= GIC_DIST_REG_IROUTERn_OFF_LAST)
503 {
504 /** @todo Ignored for now, probably make this a MMIO2 region as it begins on 0x6000, see 12.9.22 of the GICv3 architecture
505 * reference manual. */
506 return VINF_SUCCESS;
507 }
508
509 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
510 switch (offReg)
511 {
512 case GIC_DIST_REG_CTLR_OFF:
513 ASMAtomicWriteBool(&pThis->fIrqGrp0Enabled, RT_BOOL(uValue & GIC_DIST_REG_CTRL_ENABLE_GRP0));
514 ASMAtomicWriteBool(&pThis->fIrqGrp1Enabled, RT_BOOL(uValue & GIC_DIST_REG_CTRL_ENABLE_GRP1_NS));
515 rcStrict = gicDistUpdateIrqState(pVM, pThis);
516 break;
517 case GIC_DIST_REG_STATUSR_OFF:
518 AssertReleaseFailed();
519 break;
520 case GIC_DIST_REG_SETSPI_NSR_OFF:
521 AssertReleaseFailed();
522 break;
523 case GIC_DIST_REG_CLRSPI_NSR_OFF:
524 AssertReleaseFailed();
525 break;
526 case GIC_DIST_REG_SETSPI_SR_OFF:
527 AssertReleaseFailed();
528 break;
529 case GIC_DIST_REG_CLRSPI_SR_OFF:
530 AssertReleaseFailed();
531 break;
532 case GIC_DIST_REG_IGROUPRn_OFF_START: /* Only 32 lines for now. */
533 AssertReleaseFailed();
534 break;
535 case GIC_DIST_REG_IGROUPRn_OFF_START + 4: /* Only 32 lines for now. */
536 ASMAtomicOrU32(&pThis->u32RegIGrp0, uValue);
537 rcStrict = gicDistUpdateIrqState(pVM, pThis);
538 break;
539 case GIC_DIST_REG_ISENABLERn_OFF_START + 4: /* Only 32 lines for now. */
540 ASMAtomicOrU32(&pThis->bmIntEnabled, uValue);
541 rcStrict = gicDistUpdateIrqState(pVM, pThis);
542 break;
543 case GIC_DIST_REG_ICENABLERn_OFF_START:
544 //AssertReleaseFailed();
545 break;
546 case GIC_DIST_REG_ICENABLERn_OFF_START + 4: /* Only 32 lines for now. */
547 ASMAtomicAndU32(&pThis->bmIntEnabled, ~uValue);
548 rcStrict = gicDistUpdateIrqState(pVM, pThis);
549 break;
550 case GIC_DIST_REG_ISPENDRn_OFF_START: /* Only 32 lines for now. */
551 AssertReleaseFailed();
552 break;
553 case GIC_DIST_REG_ICPENDRn_OFF_START: /* Only 32 lines for now. */
554 AssertReleaseFailed();
555 break;
556 case GIC_DIST_REG_ISACTIVERn_OFF_START: /* Only 32 lines for now. */
557 AssertReleaseFailed();
558 break;
559 case GIC_DIST_REG_ICACTIVERn_OFF_START + 4: /* Only 32 lines for now. */
560 ASMAtomicAndU32(&pThis->bmIntActive, ~uValue);
561 rcStrict = gicDistUpdateIrqState(pVM, pThis);
562 break;
563 case GIC_DIST_REG_IPRIORITYn_OFF_START: /* These are banked for the PEs and access the redistributor. */
564 case GIC_DIST_REG_IPRIORITYn_OFF_START + 4:
565 case GIC_DIST_REG_IPRIORITYn_OFF_START + 8:
566 case GIC_DIST_REG_IPRIORITYn_OFF_START + 12:
567 case GIC_DIST_REG_IPRIORITYn_OFF_START + 16:
568 case GIC_DIST_REG_IPRIORITYn_OFF_START + 20:
569 case GIC_DIST_REG_IPRIORITYn_OFF_START + 24:
570 case GIC_DIST_REG_IPRIORITYn_OFF_START + 28:
571 {
572 PGICCPU pGicVCpu = VMCPU_TO_GICCPU(pVCpu);
573
574 /* Figure out the register which is written. */
575 uint8_t idxPrio = offReg - GIC_DIST_REG_IPRIORITYn_OFF_START;
576 Assert(idxPrio <= RT_ELEMENTS(pGicVCpu->abIntPriority) - sizeof(uint32_t));
577 for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
578 {
579 pGicVCpu->abIntPriority[i] = (uint8_t)(uValue & 0xff);
580 uValue >>= 8;
581 }
582 break;
583 }
584 case GIC_DIST_REG_IPRIORITYn_OFF_START + 32: /* Only 32 lines for now. */
585 case GIC_DIST_REG_IPRIORITYn_OFF_START + 36:
586 case GIC_DIST_REG_IPRIORITYn_OFF_START + 40:
587 case GIC_DIST_REG_IPRIORITYn_OFF_START + 44:
588 case GIC_DIST_REG_IPRIORITYn_OFF_START + 48:
589 case GIC_DIST_REG_IPRIORITYn_OFF_START + 52:
590 case GIC_DIST_REG_IPRIORITYn_OFF_START + 56:
591 case GIC_DIST_REG_IPRIORITYn_OFF_START + 60:
592 {
593 /* Figure out the register which is written. */
594 uint8_t idxPrio = offReg - GIC_DIST_REG_IPRIORITYn_OFF_START - 32;
595 Assert(idxPrio <= RT_ELEMENTS(pThis->abIntPriority) - sizeof(uint32_t));
596 for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
597 {
598 pThis->abIntPriority[i] = (uint8_t)(uValue & 0xff);
599 uValue >>= 8;
600 }
601 break;
602 }
603 case GIC_DIST_REG_ITARGETSRn_OFF_START: /* Only 32 lines for now. */
604 AssertReleaseFailed();
605 break;
606 case GIC_DIST_REG_ICFGRn_OFF_START + 8: /* Only 32 lines for now. */
607 ASMAtomicWriteU32(&pThis->u32RegICfg0, uValue);
608 break;
609 case GIC_DIST_REG_ICFGRn_OFF_START+ 12:
610 ASMAtomicWriteU32(&pThis->u32RegICfg1, uValue);
611 break;
612 case GIC_DIST_REG_IGRPMODRn_OFF_START: /* Only 32 lines for now. */
613 AssertReleaseFailed();
614 break;
615 case GIC_DIST_REG_NSACRn_OFF_START: /* Only 32 lines for now. */
616 AssertReleaseFailed();
617 break;
618 case GIC_DIST_REG_SGIR_OFF:
619 AssertReleaseFailed();
620 break;
621 case GIC_DIST_REG_CPENDSGIRn_OFF_START:
622 AssertReleaseFailed();
623 break;
624 case GIC_DIST_REG_SPENDSGIRn_OFF_START:
625 AssertReleaseFailed();
626 break;
627 case GIC_DIST_REG_INMIn_OFF_START:
628 AssertReleaseFailed();
629 break;
630 default:
631 AssertReleaseFailed();
632 break;
633 }
634
635 return rcStrict;
636}
637
638
639/**
640 * Reads a GIC redistributor register.
641 *
642 * @returns VBox status code.
643 * @param pDevIns The device instance.
644 * @param pVCpu The cross context virtual CPU structure.
645 * @param idRedist The redistributor ID.
646 * @param offReg The offset of the register being read.
647 * @param puValue Where to store the register value.
648 */
649DECLINLINE(VBOXSTRICTRC) gicReDistRegisterRead(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint32_t idRedist, uint16_t offReg, uint32_t *puValue)
650{
651 RT_NOREF(pDevIns);
652
653 switch (offReg)
654 {
655 case GIC_REDIST_REG_TYPER_OFF:
656 {
657 PVMCC pVM = PDMDevHlpGetVM(pDevIns);
658 *puValue = ((pVCpu->idCpu == pVM->cCpus - 1) ? GIC_REDIST_REG_TYPER_LAST : 0)
659 | GIC_REDIST_REG_TYPER_CPU_NUMBER_SET(idRedist)
660 | GIC_REDIST_REG_TYPER_CMN_LPI_AFF_SET(GIC_REDIST_REG_TYPER_CMN_LPI_AFF_ALL);
661 break;
662 }
663 case GIC_REDIST_REG_TYPER_AFFINITY_OFF:
664 *puValue = idRedist;
665 break;
666 case GIC_REDIST_REG_PIDR2_OFF:
667 *puValue = GIC_REDIST_REG_PIDR2_ARCH_REV_SET(GIC_REDIST_REG_PIDR2_ARCH_REV_GICV3);
668 break;
669 default:
670 *puValue = 0;
671 }
672
673 return VINF_SUCCESS;
674}
675
676
677/**
678 * Reads a GIC redistributor SGI/PPI frame register.
679 *
680 * @returns VBox status code.
681 * @param pDevIns The device instance.
682 * @param pVCpu The cross context virtual CPU structure.
683 * @param offReg The offset of the register being read.
684 * @param puValue Where to store the register value.
685 */
686DECLINLINE(VBOXSTRICTRC) gicReDistSgiPpiRegisterRead(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t *puValue)
687{
688 VMCPU_ASSERT_EMT(pVCpu);
689 RT_NOREF(pDevIns);
690
691 PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
692 switch (offReg)
693 {
694 case GIC_REDIST_SGI_PPI_REG_ISENABLER0_OFF:
695 case GIC_REDIST_SGI_PPI_REG_ICENABLER0_OFF:
696 *puValue = ASMAtomicReadU32(&pThis->bmIntEnabled);
697 break;
698 case GIC_REDIST_SGI_PPI_REG_ISPENDR0_OFF:
699 case GIC_REDIST_SGI_PPI_REG_ICPENDR0_OFF:
700 *puValue = ASMAtomicReadU32(&pThis->bmIntPending);
701 break;
702 case GIC_REDIST_SGI_PPI_REG_ISACTIVER0_OFF:
703 case GIC_REDIST_SGI_PPI_REG_ICACTIVER0_OFF:
704 *puValue = ASMAtomicReadU32(&pThis->bmIntActive);
705 break;
706 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START:
707 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 4:
708 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 8:
709 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 12:
710 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 16:
711 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 20:
712 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 24:
713 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 28:
714 {
715 /* Figure out the register which is written. */
716 uint8_t idxPrio = offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START;
717 Assert(idxPrio <= RT_ELEMENTS(pThis->abIntPriority) - sizeof(uint32_t));
718
719 uint32_t u32Value = 0;
720 for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
721 u32Value |= pThis->abIntPriority[i] << ((i - idxPrio) * 8);
722
723 *puValue = u32Value;
724 break;
725 }
726 case GIC_REDIST_SGI_PPI_REG_ICFGR0_OFF:
727 *puValue = ASMAtomicReadU32(&pThis->u32RegICfg0);
728 break;
729 case GIC_REDIST_SGI_PPI_REG_ICFGR1_OFF:
730 *puValue = ASMAtomicReadU32(&pThis->u32RegICfg1);
731 break;
732 default:
733 AssertReleaseFailed();
734 *puValue = 0;
735 }
736
737 return VINF_SUCCESS;
738}
739
740
741/**
742 * Writes a GIC redistributor frame register.
743 *
744 * @returns Strict VBox status code.
745 * @param pDevIns The device instance.
746 * @param pVCpu The cross context virtual CPU structure.
747 * @param offReg The offset of the register being written.
748 * @param uValue The register value.
749 */
750DECLINLINE(VBOXSTRICTRC) gicReDistRegisterWrite(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue)
751{
752 VMCPU_ASSERT_EMT(pVCpu);
753 RT_NOREF(pDevIns, pVCpu, uValue);
754
755 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
756 switch (offReg)
757 {
758 case GIC_REDIST_REG_STATUSR_OFF:
759 AssertReleaseFailed();
760 break;
761 case GIC_REDIST_REG_WAKER_OFF:
762 Assert(uValue == 0);
763 break;
764 case GIC_REDIST_REG_PARTIDR_OFF:
765 AssertReleaseFailed();
766 break;
767 case GIC_REDIST_REG_SETLPIR_OFF:
768 AssertReleaseFailed();
769 break;
770 case GIC_REDIST_REG_CLRLPIR_OFF:
771 AssertReleaseFailed();
772 break;
773 case GIC_REDIST_REG_PROPBASER_OFF:
774 AssertReleaseFailed();
775 break;
776 case GIC_REDIST_REG_PENDBASER_OFF:
777 AssertReleaseFailed();
778 break;
779 case GIC_REDIST_REG_INVLPIR_OFF:
780 AssertReleaseFailed();
781 break;
782 case GIC_REDIST_REG_INVALLR_OFF:
783 AssertReleaseFailed();
784 break;
785 default:
786 AssertReleaseFailed();
787 break;
788 }
789
790 return rcStrict;
791}
792
793
794/**
795 * Writes a GIC redistributor SGI/PPI frame register.
796 *
797 * @returns Strict VBox status code.
798 * @param pDevIns The device instance.
799 * @param pVCpu The cross context virtual CPU structure.
800 * @param offReg The offset of the register being written.
801 * @param uValue The register value.
802 */
803DECLINLINE(VBOXSTRICTRC) gicReDistSgiPpiRegisterWrite(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue)
804{
805 VMCPU_ASSERT_EMT(pVCpu);
806 RT_NOREF(pDevIns);
807
808 PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
809 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
810 switch (offReg)
811 {
812 case GIC_REDIST_SGI_PPI_REG_IGROUPR0_OFF:
813 ASMAtomicOrU32(&pThis->u32RegIGrp0, uValue);
814 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
815 break;
816 case GIC_REDIST_SGI_PPI_REG_ISENABLER0_OFF:
817 ASMAtomicOrU32(&pThis->bmIntEnabled, uValue);
818 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
819 break;
820 case GIC_REDIST_SGI_PPI_REG_ICENABLER0_OFF:
821 ASMAtomicAndU32(&pThis->bmIntEnabled, ~uValue);
822 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
823 break;
824 case GIC_REDIST_SGI_PPI_REG_ISPENDR0_OFF:
825 ASMAtomicOrU32(&pThis->bmIntPending, uValue);
826 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
827 break;
828 case GIC_REDIST_SGI_PPI_REG_ICPENDR0_OFF:
829 ASMAtomicAndU32(&pThis->bmIntPending, ~uValue);
830 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
831 break;
832 case GIC_REDIST_SGI_PPI_REG_ISACTIVER0_OFF:
833 ASMAtomicOrU32(&pThis->bmIntActive, uValue);
834 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
835 break;
836 case GIC_REDIST_SGI_PPI_REG_ICACTIVER0_OFF:
837 ASMAtomicAndU32(&pThis->bmIntActive, ~uValue);
838 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
839 break;
840 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START:
841 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 4:
842 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 8:
843 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 12:
844 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 16:
845 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 20:
846 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 24:
847 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 28:
848 {
849 /* Figure out the register whch is written. */
850 uint8_t idxPrio = offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START;
851 Assert(idxPrio <= RT_ELEMENTS(pThis->abIntPriority) - sizeof(uint32_t));
852 for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
853 {
854 pThis->abIntPriority[i] = (uint8_t)(uValue & 0xff);
855 uValue >>= 8;
856 }
857 break;
858 }
859 case GIC_REDIST_SGI_PPI_REG_ICFGR0_OFF:
860 ASMAtomicWriteU32(&pThis->u32RegICfg0, uValue);
861 break;
862 case GIC_REDIST_SGI_PPI_REG_ICFGR1_OFF:
863 ASMAtomicWriteU32(&pThis->u32RegICfg1, uValue);
864 break;
865 default:
866 //AssertReleaseFailed();
867 break;
868 }
869
870 return rcStrict;
871}
872
873
874/**
875 * Reads a GIC system register.
876 *
877 * @returns Strict VBox status code.
878 * @param pVCpu The cross context virtual CPU structure.
879 * @param u32Reg The system register being read.
880 * @param pu64Value Where to store the read value.
881 */
882VMM_INT_DECL(VBOXSTRICTRC) GICReadSysReg(PVMCPUCC pVCpu, uint32_t u32Reg, uint64_t *pu64Value)
883{
884 /*
885 * Validate.
886 */
887 VMCPU_ASSERT_EMT(pVCpu);
888 Assert(pu64Value);
889
890 *pu64Value = 0;
891 PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
892 PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
893 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
894
895 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
896 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
897
898 switch (u32Reg)
899 {
900 case ARMV8_AARCH64_SYSREG_ICC_PMR_EL1:
901 *pu64Value = pThis->bInterruptPriority;
902 break;
903 case ARMV8_AARCH64_SYSREG_ICC_IAR0_EL1:
904 AssertReleaseFailed();
905 break;
906 case ARMV8_AARCH64_SYSREG_ICC_EOIR0_EL1:
907 AssertReleaseFailed();
908 break;
909 case ARMV8_AARCH64_SYSREG_ICC_HPPIR0_EL1:
910 AssertReleaseFailed();
911 break;
912 case ARMV8_AARCH64_SYSREG_ICC_BPR0_EL1:
913 *pu64Value = pThis->bBinaryPointGrp0 & 0x7;
914 break;
915 case ARMV8_AARCH64_SYSREG_ICC_AP0R0_EL1:
916 AssertReleaseFailed();
917 break;
918 case ARMV8_AARCH64_SYSREG_ICC_AP0R1_EL1:
919 AssertReleaseFailed();
920 break;
921 case ARMV8_AARCH64_SYSREG_ICC_AP0R2_EL1:
922 AssertReleaseFailed();
923 break;
924 case ARMV8_AARCH64_SYSREG_ICC_AP0R3_EL1:
925 AssertReleaseFailed();
926 break;
927 case ARMV8_AARCH64_SYSREG_ICC_AP1R0_EL1:
928 AssertReleaseFailed();
929 break;
930 case ARMV8_AARCH64_SYSREG_ICC_AP1R1_EL1:
931 AssertReleaseFailed();
932 break;
933 case ARMV8_AARCH64_SYSREG_ICC_AP1R2_EL1:
934 AssertReleaseFailed();
935 break;
936 case ARMV8_AARCH64_SYSREG_ICC_AP1R3_EL1:
937 AssertReleaseFailed();
938 break;
939 case ARMV8_AARCH64_SYSREG_ICC_NMIAR1_EL1:
940 AssertReleaseFailed();
941 break;
942 case ARMV8_AARCH64_SYSREG_ICC_DIR_EL1:
943 AssertReleaseFailed();
944 break;
945 case ARMV8_AARCH64_SYSREG_ICC_RPR_EL1:
946 *pu64Value = pThis->abRunningPriorities[pThis->idxRunningPriority];
947 break;
948 case ARMV8_AARCH64_SYSREG_ICC_SGI1R_EL1:
949 AssertReleaseFailed();
950 break;
951 case ARMV8_AARCH64_SYSREG_ICC_ASGI1R_EL1:
952 AssertReleaseFailed();
953 break;
954 case ARMV8_AARCH64_SYSREG_ICC_SGI0R_EL1:
955 AssertReleaseFailed();
956 break;
957 case ARMV8_AARCH64_SYSREG_ICC_IAR1_EL1:
958 {
959 /** @todo Figure out the highest priority interrupt. */
960 uint32_t bmIntActive = ASMAtomicReadU32(&pThis->bmIntActive);
961 uint32_t bmIntEnabled = ASMAtomicReadU32(&pThis->bmIntEnabled);
962 uint32_t bmPending = (ASMAtomicReadU32(&pThis->bmIntPending) & bmIntEnabled) & ~bmIntActive;
963 int32_t idxIntPending = ASMBitFirstSet(&bmPending, sizeof(bmPending) * 8);
964 if (idxIntPending > -1)
965 {
966 /* Mark the interrupt as active. */
967 ASMAtomicOrU32(&pThis->bmIntActive, RT_BIT_32(idxIntPending));
968 /* Drop priority. */
969 Assert((uint32_t)idxIntPending < RT_ELEMENTS(pThis->abIntPriority));
970 Assert(pThis->idxRunningPriority < RT_ELEMENTS(pThis->abRunningPriorities) - 1);
971 pThis->abRunningPriorities[++pThis->idxRunningPriority] = pThis->abIntPriority[idxIntPending];
972
973 /* Clear edge level interrupts like SGIs as pending. */
974 if (idxIntPending <= GIC_INTID_RANGE_SGI_LAST)
975 ASMAtomicBitClear(&pThis->bmIntPending, idxIntPending);
976 *pu64Value = idxIntPending;
977 gicReDistUpdateIrqState(pThis, pVCpu);
978 }
979 else
980 {
981 /** @todo This is wrong as the guest might decide to prioritize PPIs and SPIs differently. */
982 bmIntActive = ASMAtomicReadU32(&pGicDev->bmIntActive);
983 bmIntEnabled = ASMAtomicReadU32(&pGicDev->bmIntEnabled);
984 bmPending = (ASMAtomicReadU32(&pGicDev->bmIntPending) & bmIntEnabled) & ~bmIntActive;
985 idxIntPending = ASMBitFirstSet(&bmPending, sizeof(bmPending) * 8);
986 if (idxIntPending > -1)
987 {
988 /* Mark the interrupt as active. */
989 ASMAtomicOrU32(&pGicDev->bmIntActive, RT_BIT_32(idxIntPending));
990
991 /* Drop priority. */
992 Assert((uint32_t)idxIntPending < RT_ELEMENTS(pThis->abIntPriority));
993 Assert(pThis->idxRunningPriority < RT_ELEMENTS(pThis->abRunningPriorities) - 1);
994 pThis->abRunningPriorities[++pThis->idxRunningPriority] = pThis->abIntPriority[idxIntPending];
995
996 *pu64Value = idxIntPending + GIC_INTID_RANGE_SPI_START;
997 gicReDistUpdateIrqState(pThis, pVCpu);
998 }
999 else
1000 *pu64Value = GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT;
1001 }
1002 break;
1003 }
1004 case ARMV8_AARCH64_SYSREG_ICC_EOIR1_EL1:
1005 AssertReleaseFailed();
1006 break;
1007 case ARMV8_AARCH64_SYSREG_ICC_HPPIR1_EL1:
1008 AssertReleaseFailed();
1009 break;
1010 case ARMV8_AARCH64_SYSREG_ICC_BPR1_EL1:
1011 *pu64Value = pThis->bBinaryPointGrp1 & 0x7;
1012 break;
1013 case ARMV8_AARCH64_SYSREG_ICC_CTLR_EL1:
1014 *pu64Value = ARMV8_ICC_CTLR_EL1_AARCH64_PMHE
1015 | ARMV8_ICC_CTLR_EL1_AARCH64_PRIBITS_SET(4)
1016 | ARMV8_ICC_CTLR_EL1_AARCH64_IDBITS_SET(ARMV8_ICC_CTLR_EL1_AARCH64_IDBITS_16BITS);
1017 break;
1018 case ARMV8_AARCH64_SYSREG_ICC_SRE_EL1:
1019 AssertReleaseFailed();
1020 break;
1021 case ARMV8_AARCH64_SYSREG_ICC_IGRPEN0_EL1:
1022 *pu64Value = ASMAtomicReadBool(&pThis->fIrqGrp0Enabled) ? ARMV8_ICC_IGRPEN0_EL1_AARCH64_ENABLE : 0;
1023 break;
1024 case ARMV8_AARCH64_SYSREG_ICC_IGRPEN1_EL1:
1025 *pu64Value = ASMAtomicReadBool(&pThis->fIrqGrp1Enabled) ? ARMV8_ICC_IGRPEN1_EL1_AARCH64_ENABLE : 0;
1026 break;
1027 default:
1028 AssertReleaseFailed();
1029 break;
1030 }
1031
1032 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
1033
1034 LogFlowFunc(("pVCpu=%p u32Reg=%#x{%s} pu64Value=%RX64\n", pVCpu, u32Reg, gicIccRegisterStringify(u32Reg), *pu64Value));
1035 return VINF_SUCCESS;
1036}
1037
1038
1039/**
1040 * Writes an GIC system register.
1041 *
1042 * @returns Strict VBox status code.
1043 * @param pVCpu The cross context virtual CPU structure.
1044 * @param u32Reg The system register being written (IPRT system register identifier).
1045 * @param u64Value The value to write.
1046 */
1047VMM_INT_DECL(VBOXSTRICTRC) GICWriteSysReg(PVMCPUCC pVCpu, uint32_t u32Reg, uint64_t u64Value)
1048{
1049 /*
1050 * Validate.
1051 */
1052 VMCPU_ASSERT_EMT(pVCpu);
1053 LogFlowFunc(("pVCpu=%p u32Reg=%#x{%s} u64Value=%RX64\n", pVCpu, u32Reg, gicIccRegisterStringify(u32Reg), u64Value));
1054
1055 PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
1056 PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
1057 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
1058
1059 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
1060 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
1061
1062 switch (u32Reg)
1063 {
1064 case ARMV8_AARCH64_SYSREG_ICC_PMR_EL1:
1065 LogFlowFunc(("ICC_PMR_EL1: Interrupt priority now %u\n", (uint8_t)u64Value));
1066 ASMAtomicWriteU8(&pThis->bInterruptPriority, (uint8_t)u64Value);
1067 gicReDistUpdateIrqState(pThis, pVCpu);
1068 break;
1069 case ARMV8_AARCH64_SYSREG_ICC_IAR0_EL1:
1070 AssertReleaseFailed();
1071 break;
1072 case ARMV8_AARCH64_SYSREG_ICC_EOIR0_EL1:
1073 AssertReleaseFailed();
1074 break;
1075 case ARMV8_AARCH64_SYSREG_ICC_HPPIR0_EL1:
1076 AssertReleaseFailed();
1077 break;
1078 case ARMV8_AARCH64_SYSREG_ICC_BPR0_EL1:
1079 pThis->bBinaryPointGrp0 = (uint8_t)(u64Value & 0x7);
1080 break;
1081 case ARMV8_AARCH64_SYSREG_ICC_AP0R0_EL1:
1082 /** @todo */
1083 break;
1084 case ARMV8_AARCH64_SYSREG_ICC_AP0R1_EL1:
1085 AssertReleaseFailed();
1086 break;
1087 case ARMV8_AARCH64_SYSREG_ICC_AP0R2_EL1:
1088 AssertReleaseFailed();
1089 break;
1090 case ARMV8_AARCH64_SYSREG_ICC_AP0R3_EL1:
1091 AssertReleaseFailed();
1092 break;
1093 case ARMV8_AARCH64_SYSREG_ICC_AP1R0_EL1:
1094 /** @todo */
1095 break;
1096 case ARMV8_AARCH64_SYSREG_ICC_AP1R1_EL1:
1097 AssertReleaseFailed();
1098 break;
1099 case ARMV8_AARCH64_SYSREG_ICC_AP1R2_EL1:
1100 AssertReleaseFailed();
1101 break;
1102 case ARMV8_AARCH64_SYSREG_ICC_AP1R3_EL1:
1103 AssertReleaseFailed();
1104 break;
1105 case ARMV8_AARCH64_SYSREG_ICC_NMIAR1_EL1:
1106 AssertReleaseFailed();
1107 break;
1108 case ARMV8_AARCH64_SYSREG_ICC_DIR_EL1:
1109 AssertReleaseFailed();
1110 break;
1111 case ARMV8_AARCH64_SYSREG_ICC_RPR_EL1:
1112 AssertReleaseFailed();
1113 break;
1114 case ARMV8_AARCH64_SYSREG_ICC_SGI1R_EL1:
1115 {
1116 uint32_t uIntId = ARMV8_ICC_SGI1R_EL1_AARCH64_INTID_GET(u64Value) - GIC_INTID_RANGE_SGI_START;
1117 if (u64Value & ARMV8_ICC_SGI1R_EL1_AARCH64_IRM)
1118 {
1119 /* Route to all but this vCPU. */
1120 AssertReleaseFailed();
1121 }
1122 else
1123 {
1124 /* Examine target list. */
1125 /** @todo Range selector support. */
1126 VMCPUID idCpu = 0;
1127 uint16_t uTgtList = ARMV8_ICC_SGI1R_EL1_AARCH64_TARGET_LIST_GET(u64Value);
1128 /** @todo rewrite using ASMBitFirstSetU16. */
1129 while (uTgtList)
1130 {
1131 if (uTgtList & 0x1)
1132 {
1133 PVMCPUCC pVCpuDst = VMMGetCpuById(pVCpu->CTX_SUFF(pVM), idCpu);
1134 if (pVCpuDst)
1135 GICSgiSet(pVCpuDst, uIntId, true /*fAsserted*/);
1136 else
1137 AssertFailed();
1138 }
1139 uTgtList >>= 1;
1140 idCpu++;
1141 }
1142 }
1143 break;
1144 }
1145 case ARMV8_AARCH64_SYSREG_ICC_ASGI1R_EL1:
1146 AssertReleaseFailed();
1147 break;
1148 case ARMV8_AARCH64_SYSREG_ICC_SGI0R_EL1:
1149 AssertReleaseFailed();
1150 break;
1151 case ARMV8_AARCH64_SYSREG_ICC_IAR1_EL1:
1152 AssertReleaseFailed();
1153 break;
1154 case ARMV8_AARCH64_SYSREG_ICC_EOIR1_EL1:
1155 {
1156 /* Mark the interrupt as not active anymore, though it might still be pending. */
1157 if (u64Value < GIC_INTID_RANGE_SPI_START)
1158 ASMAtomicAndU32(&pThis->bmIntActive, ~RT_BIT_32((uint32_t)u64Value));
1159 else
1160 ASMAtomicAndU32(&pGicDev->bmIntActive, ~RT_BIT_32((uint32_t)(u64Value - GIC_INTID_RANGE_SPI_START)));
1161
1162 /* Restore previous interrupt priority. */
1163 Assert(pThis->idxRunningPriority > 0);
1164 if (RT_LIKELY(pThis->idxRunningPriority))
1165 pThis->idxRunningPriority--;
1166 gicReDistUpdateIrqState(pThis, pVCpu);
1167 break;
1168 }
1169 case ARMV8_AARCH64_SYSREG_ICC_HPPIR1_EL1:
1170 AssertReleaseFailed();
1171 break;
1172 case ARMV8_AARCH64_SYSREG_ICC_BPR1_EL1:
1173 pThis->bBinaryPointGrp0 = (uint8_t)(u64Value & 0x7);
1174 break;
1175 case ARMV8_AARCH64_SYSREG_ICC_CTLR_EL1:
1176 u64Value &= ARMV8_ICC_CTLR_EL1_RW;
1177 /** @todo */
1178 break;
1179 case ARMV8_AARCH64_SYSREG_ICC_SRE_EL1:
1180 AssertReleaseFailed();
1181 break;
1182 case ARMV8_AARCH64_SYSREG_ICC_IGRPEN0_EL1:
1183 ASMAtomicWriteBool(&pThis->fIrqGrp0Enabled, RT_BOOL(u64Value & ARMV8_ICC_IGRPEN0_EL1_AARCH64_ENABLE));
1184 break;
1185 case ARMV8_AARCH64_SYSREG_ICC_IGRPEN1_EL1:
1186 ASMAtomicWriteBool(&pThis->fIrqGrp1Enabled, RT_BOOL(u64Value & ARMV8_ICC_IGRPEN1_EL1_AARCH64_ENABLE));
1187 break;
1188 default:
1189 AssertReleaseFailed();
1190 break;
1191 }
1192
1193 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
1194 return VINF_SUCCESS;
1195}
1196
1197
1198/**
1199 * Sets the specified shared peripheral interrupt starting.
1200 *
1201 * @returns VBox status code.
1202 * @param pVM The cross context virtual machine structure.
1203 * @param uIntId The SPI ID (minus GIC_INTID_RANGE_SPI_START) to assert/de-assert.
1204 * @param fAsserted Flag whether to mark the interrupt as asserted/de-asserted.
1205 */
1206VMM_INT_DECL(int) GICSpiSet(PVMCC pVM, uint32_t uIntId, bool fAsserted)
1207{
1208 LogFlowFunc(("pVM=%p uIntId=%u fAsserted=%RTbool\n",
1209 pVM, uIntId, fAsserted));
1210
1211 AssertReturn(uIntId < GIC_SPI_MAX, VERR_INVALID_PARAMETER);
1212
1213 PGIC pGic = VM_TO_GIC(pVM);
1214
1215 /** @todo r=aeichner There must be another way to do this better, maybe create some callback interface
1216 * the GIC can register. */
1217#ifdef IN_RING3
1218 if (pGic->fNemGic)
1219 return GICR3NemSpiSet(pVM, uIntId, fAsserted);
1220#else
1221# error "Impossible to call the NEM in-kernel GIC from this context!"
1222#endif
1223
1224 PPDMDEVINS pDevIns = pGic->CTX_SUFF(pDevIns);
1225 PGICDEV pThis = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
1226
1227 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
1228 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
1229
1230 /* Update the interrupts pending state. */
1231 if (fAsserted)
1232 ASMAtomicOrU32(&pThis->bmIntPending, RT_BIT_32(uIntId));
1233 else
1234 ASMAtomicAndU32(&pThis->bmIntPending, ~RT_BIT_32(uIntId));
1235
1236 int rc = VBOXSTRICTRC_VAL(gicDistUpdateIrqState(pVM, pThis));
1237 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
1238 return rc;
1239}
1240
1241
1242/**
1243 * Sets the specified private peripheral interrupt starting.
1244 *
1245 * @returns VBox status code.
1246 * @param pVCpu The cross context virtual CPU structure.
1247 * @param uIntId The PPI ID (minus GIC_INTID_RANGE_PPI_START) to assert/de-assert.
1248 * @param fAsserted Flag whether to mark the interrupt as asserted/de-asserted.
1249 */
1250VMM_INT_DECL(int) GICPpiSet(PVMCPUCC pVCpu, uint32_t uIntId, bool fAsserted)
1251{
1252 LogFlowFunc(("pVCpu=%p{.idCpu=%u} uIntId=%u fAsserted=%RTbool\n",
1253 pVCpu, pVCpu->idCpu, uIntId, fAsserted));
1254
1255 PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
1256
1257 /** @todo r=aeichner There must be another way to do this better, maybe create some callback interface
1258 * the GIC can register. */
1259#ifdef IN_RING3
1260 PGIC pGic = VM_TO_GIC(pVCpu->pVMR3);
1261 if (pGic->fNemGic)
1262 return GICR3NemPpiSet(pVCpu, uIntId, fAsserted);
1263#else
1264# error "Impossible to call the NEM in-kernel GIC from this context!"
1265#endif
1266
1267 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
1268 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
1269
1270 AssertReturn(uIntId <= (GIC_INTID_RANGE_PPI_LAST - GIC_INTID_RANGE_PPI_START), VERR_INVALID_PARAMETER);
1271 int rc = gicReDistInterruptSet(pVCpu, uIntId + GIC_INTID_RANGE_PPI_START, fAsserted);
1272 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
1273
1274 return rc;
1275}
1276
1277
1278/**
1279 * Sets the specified software generated interrupt starting.
1280 *
1281 * @returns VBox status code.
1282 * @param pVCpu The cross context virtual CPU structure.
1283 * @param uIntId The PPI ID (minus GIC_INTID_RANGE_SGI_START) to assert/de-assert.
1284 * @param fAsserted Flag whether to mark the interrupt as asserted/de-asserted.
1285 */
1286VMM_INT_DECL(int) GICSgiSet(PVMCPUCC pVCpu, uint32_t uIntId, bool fAsserted)
1287{
1288 LogFlowFunc(("pVCpu=%p{.idCpu=%u} uIntId=%u fAsserted=%RTbool\n",
1289 pVCpu, pVCpu->idCpu, uIntId, fAsserted));
1290
1291 PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
1292
1293 /** @todo r=aeichner There must be another way to do this better, maybe create some callback interface
1294 * the GIC can register. */
1295#ifdef IN_RING3
1296 PGIC pGic = VM_TO_GIC(pVCpu->pVMR3);
1297 /* These should be handled in the kernel and never be set from here. */
1298 AssertReturn(!pGic->fNemGic, VERR_NEM_IPE_6);
1299#else
1300# error "Impossible to call the in-kernel GIC from this context!"
1301#endif
1302
1303 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
1304 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
1305
1306 AssertReturn(uIntId <= (GIC_INTID_RANGE_SGI_LAST - GIC_INTID_RANGE_SGI_START), VERR_INVALID_PARAMETER);
1307 int rc = gicReDistInterruptSet(pVCpu, uIntId + GIC_INTID_RANGE_SGI_START, fAsserted);
1308 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
1309
1310 return rc;
1311}
1312
1313
1314/**
1315 * Initializes per-VCPU GIC to the state following a power-up or hardware
1316 * reset.
1317 *
1318 * @param pVCpu The cross context virtual CPU structure.
1319 */
1320DECLHIDDEN(void) gicResetCpu(PVMCPUCC pVCpu)
1321{
1322 LogFlowFunc(("GIC%u\n", pVCpu->idCpu));
1323 VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu);
1324
1325 memset((void *)&pVCpu->gic.s.abRunningPriorities[0], 0xff, sizeof(pVCpu->gic.s.abRunningPriorities));
1326 pVCpu->gic.s.idxRunningPriority = 0;
1327 pVCpu->gic.s.bInterruptPriority = 0; /* Means no interrupt gets through to the PE. */
1328}
1329
1330
1331/**
1332 * @callback_method_impl{FNIOMMMIONEWREAD}
1333 */
1334DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) gicDistMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
1335{
1336 NOREF(pvUser);
1337 Assert(!(off & 0x3));
1338 Assert(cb == 4); RT_NOREF_PV(cb);
1339
1340 PVMCPUCC pVCpu = PDMDevHlpGetVMCPU(pDevIns);
1341 uint16_t offReg = off & 0xfffc;
1342 uint32_t uValue = 0;
1343
1344 STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioRead));
1345
1346 VBOXSTRICTRC rc = VBOXSTRICTRC_VAL(gicDistRegisterRead(pDevIns, pVCpu, offReg, &uValue));
1347 *(uint32_t *)pv = uValue;
1348
1349 Log2(("GIC%u: gicDistMmioRead: offReg=%#RX16 uValue=%#RX32\n", pVCpu->idCpu, offReg, uValue));
1350 return rc;
1351}
1352
1353
1354/**
1355 * @callback_method_impl{FNIOMMMIONEWWRITE}
1356 */
1357DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) gicDistMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
1358{
1359 NOREF(pvUser);
1360 Assert(!(off & 0x3));
1361 Assert(cb == 4); RT_NOREF_PV(cb);
1362
1363 PVMCPUCC pVCpu = PDMDevHlpGetVMCPU(pDevIns);
1364 uint16_t offReg = off & 0xfffc;
1365 uint32_t uValue = *(uint32_t *)pv;
1366
1367 STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioWrite));
1368
1369 Log2(("GIC%u: gicDistMmioWrite: offReg=%#RX16 uValue=%#RX32\n", pVCpu->idCpu, offReg, uValue));
1370 return gicDistRegisterWrite(pDevIns, pVCpu, offReg, uValue);
1371}
1372
1373
1374/**
1375 * @callback_method_impl{FNIOMMMIONEWREAD}
1376 */
1377DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) gicReDistMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
1378{
1379 NOREF(pvUser);
1380 Assert(!(off & 0x3));
1381 Assert(cb == 4); RT_NOREF_PV(cb);
1382
1383 /*
1384 * Determine the redistributor being targeted. Each redistributor takes GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE bytes
1385 * and the redistributors are adjacent.
1386 */
1387 uint32_t idReDist = off / (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
1388 off %= (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
1389
1390 PVMCC pVM = PDMDevHlpGetVM(pDevIns);
1391 Assert(idReDist < pVM->cCpus);
1392 PVMCPUCC pVCpu = pVM->apCpusR3[idReDist];
1393
1394 STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioRead));
1395
1396 /* Redistributor or SGI/PPI frame? */
1397 uint16_t offReg = off & 0xfffc;
1398 uint32_t uValue = 0;
1399 VBOXSTRICTRC rcStrict;
1400 if (off < GIC_REDIST_REG_FRAME_SIZE)
1401 rcStrict = gicReDistRegisterRead(pDevIns, pVCpu, idReDist, offReg, &uValue);
1402 else
1403 rcStrict = gicReDistSgiPpiRegisterRead(pDevIns, pVCpu, offReg, &uValue);
1404
1405 *(uint32_t *)pv = uValue;
1406 Log2(("GICReDist%u: gicReDistMmioRead: off=%RGp idReDist=%u offReg=%#RX16 uValue=%#RX32 -> %Rrc\n",
1407 pVCpu->idCpu, off, idReDist, offReg, uValue, VBOXSTRICTRC_VAL(rcStrict)));
1408 return rcStrict;
1409}
1410
1411
1412/**
1413 * @callback_method_impl{FNIOMMMIONEWWRITE}
1414 */
1415DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) gicReDistMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
1416{
1417 NOREF(pvUser);
1418 Assert(!(off & 0x3));
1419 Assert(cb == 4); RT_NOREF_PV(cb);
1420
1421 uint32_t uValue = *(uint32_t *)pv;
1422
1423 /*
1424 * Determine the redistributor being targeted. Each redistributor takes GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE bytes
1425 * and the redistributors are adjacent.
1426 */
1427 uint32_t idReDist = off / (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
1428 off %= (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
1429
1430 PVMCC pVM = PDMDevHlpGetVM(pDevIns);
1431 Assert(idReDist < pVM->cCpus);
1432 PVMCPUCC pVCpu = pVM->apCpusR3[idReDist];
1433
1434 STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioWrite));
1435
1436 /* Redistributor or SGI/PPI frame? */
1437 uint16_t offReg = off & 0xfffc;
1438 VBOXSTRICTRC rcStrict;
1439 if (off < GIC_REDIST_REG_FRAME_SIZE)
1440 rcStrict = gicReDistRegisterWrite(pDevIns, pVCpu, offReg, uValue);
1441 else
1442 rcStrict = gicReDistSgiPpiRegisterWrite(pDevIns, pVCpu, offReg, uValue);
1443
1444 Log2(("GICReDist%u: gicReDistMmioWrite: off=%RGp idReDist=%u offReg=%#RX16 uValue=%#RX32 -> %Rrc\n",
1445 pVCpu->idCpu, off, idReDist, offReg, uValue, VBOXSTRICTRC_VAL(rcStrict)));
1446 return rcStrict;
1447}
1448
1449
1450#ifndef IN_RING3
1451
1452/**
1453 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
1454 */
1455static DECLCALLBACK(int) gicRZConstruct(PPDMDEVINS pDevIns)
1456{
1457 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1458 AssertReleaseFailed();
1459 return VINF_SUCCESS;
1460}
1461#endif /* !IN_RING3 */
1462
1463/**
1464 * GIC device registration structure.
1465 */
1466const PDMDEVREG g_DeviceGIC =
1467{
1468 /* .u32Version = */ PDM_DEVREG_VERSION,
1469 /* .uReserved0 = */ 0,
1470 /* .szName = */ "gic",
1471 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
1472 /* .fClass = */ PDM_DEVREG_CLASS_PIC,
1473 /* .cMaxInstances = */ 1,
1474 /* .uSharedVersion = */ 42,
1475 /* .cbInstanceShared = */ sizeof(GICDEV),
1476 /* .cbInstanceCC = */ 0,
1477 /* .cbInstanceRC = */ 0,
1478 /* .cMaxPciDevices = */ 0,
1479 /* .cMaxMsixVectors = */ 0,
1480 /* .pszDescription = */ "Generic Interrupt Controller",
1481#if defined(IN_RING3)
1482 /* .szRCMod = */ "VMMRC.rc",
1483 /* .szR0Mod = */ "VMMR0.r0",
1484 /* .pfnConstruct = */ gicR3Construct,
1485 /* .pfnDestruct = */ gicR3Destruct,
1486 /* .pfnRelocate = */ gicR3Relocate,
1487 /* .pfnMemSetup = */ NULL,
1488 /* .pfnPowerOn = */ NULL,
1489 /* .pfnReset = */ gicR3Reset,
1490 /* .pfnSuspend = */ NULL,
1491 /* .pfnResume = */ NULL,
1492 /* .pfnAttach = */ NULL,
1493 /* .pfnDetach = */ NULL,
1494 /* .pfnQueryInterface = */ NULL,
1495 /* .pfnInitComplete = */ NULL,
1496 /* .pfnPowerOff = */ NULL,
1497 /* .pfnSoftReset = */ NULL,
1498 /* .pfnReserved0 = */ NULL,
1499 /* .pfnReserved1 = */ NULL,
1500 /* .pfnReserved2 = */ NULL,
1501 /* .pfnReserved3 = */ NULL,
1502 /* .pfnReserved4 = */ NULL,
1503 /* .pfnReserved5 = */ NULL,
1504 /* .pfnReserved6 = */ NULL,
1505 /* .pfnReserved7 = */ NULL,
1506#elif defined(IN_RING0)
1507 /* .pfnEarlyConstruct = */ NULL,
1508 /* .pfnConstruct = */ gicRZConstruct,
1509 /* .pfnDestruct = */ NULL,
1510 /* .pfnFinalDestruct = */ NULL,
1511 /* .pfnRequest = */ NULL,
1512 /* .pfnReserved0 = */ NULL,
1513 /* .pfnReserved1 = */ NULL,
1514 /* .pfnReserved2 = */ NULL,
1515 /* .pfnReserved3 = */ NULL,
1516 /* .pfnReserved4 = */ NULL,
1517 /* .pfnReserved5 = */ NULL,
1518 /* .pfnReserved6 = */ NULL,
1519 /* .pfnReserved7 = */ NULL,
1520#elif defined(IN_RC)
1521 /* .pfnConstruct = */ gicRZConstruct,
1522 /* .pfnReserved0 = */ NULL,
1523 /* .pfnReserved1 = */ NULL,
1524 /* .pfnReserved2 = */ NULL,
1525 /* .pfnReserved3 = */ NULL,
1526 /* .pfnReserved4 = */ NULL,
1527 /* .pfnReserved5 = */ NULL,
1528 /* .pfnReserved6 = */ NULL,
1529 /* .pfnReserved7 = */ NULL,
1530#else
1531# error "Not in IN_RING3, IN_RING0 or IN_RC!"
1532#endif
1533 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
1534};
1535
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