VirtualBox

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

Last change on this file since 108436 was 108433, checked in by vboxsync, 2 months ago

VMM/GIC: bugref:10404 Doxygen fixes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 154.6 KB
Line 
1/* $Id: GICAll.cpp 108433 2025-03-04 09:27:30Z vboxsync $ */
2/** @file
3 * GIC - Generic Interrupt Controller Architecture (GIC) - 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.215389.xyz.
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/pdmgic.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* Defined Constants And Macros *
47*********************************************************************************************************************************/
48#define GIC_IS_INTR_SGI(a_uIntId) (a_uIntId - GIC_INTID_RANGE_SGI_START < GIC_INTID_SGI_RANGE_SIZE)
49#define GIC_IS_INTR_PPI(a_uIntId) (a_uIntId - GIC_INTID_RANGE_PPI_START < GIC_INTID_PPI_RANGE_SIZE)
50#define GIC_IS_INTR_SGI_OR_PPI(a_uIntId) (a_uIntId - GIC_INTID_RANGE_SGI_START < GIC_INTID_PPI_RANGE_SIZE)
51#define GIC_IS_INTR_SPI(a_uIntId) (a_uIntId - GIC_INTID_RANGE_SPI_START < GIC_INTID_SPI_RANGE_SIZE)
52#define GIC_IS_INTR_SPECIAL(a_uIntId) (a_uIntId - GIC_INTID_RANGE_SPECIAL_START < GIC_INTID_EXT_PPI_RANGE_SIZE)
53#define GIC_IS_INTR_EXT_PPI(a_uIntId) (a_uIntId - GIC_INTID_RANGE_EXT_PPI_START < GIC_INTID_EXT_PPI_RANGE_SIZE)
54#define GIC_IS_INTR_EXT_SPI(a_uIntId) (a_uIntId - GIC_INTID_RANGE_EXT_SPI_START < GIC_INTID_EXT_SPI_RANGE_SIZE)
55
56
57#ifdef LOG_ENABLED
58/**
59 * Gets the description of a CPU interface register.
60 *
61 * @returns The description.
62 * @param u32Reg The CPU interface register offset.
63 */
64static const char *gicIccGetRegDescription(uint32_t u32Reg)
65{
66 switch (u32Reg)
67 {
68#define GIC_ICC_REG_CASE(a_Reg) case ARMV8_AARCH64_SYSREG_ ## a_Reg: return #a_Reg
69 GIC_ICC_REG_CASE(ICC_PMR_EL1);
70 GIC_ICC_REG_CASE(ICC_IAR0_EL1);
71 GIC_ICC_REG_CASE(ICC_EOIR0_EL1);
72 GIC_ICC_REG_CASE(ICC_HPPIR0_EL1);
73 GIC_ICC_REG_CASE(ICC_BPR0_EL1);
74 GIC_ICC_REG_CASE(ICC_AP0R0_EL1);
75 GIC_ICC_REG_CASE(ICC_AP0R1_EL1);
76 GIC_ICC_REG_CASE(ICC_AP0R2_EL1);
77 GIC_ICC_REG_CASE(ICC_AP0R3_EL1);
78 GIC_ICC_REG_CASE(ICC_AP1R0_EL1);
79 GIC_ICC_REG_CASE(ICC_AP1R1_EL1);
80 GIC_ICC_REG_CASE(ICC_AP1R2_EL1);
81 GIC_ICC_REG_CASE(ICC_AP1R3_EL1);
82 GIC_ICC_REG_CASE(ICC_DIR_EL1);
83 GIC_ICC_REG_CASE(ICC_RPR_EL1);
84 GIC_ICC_REG_CASE(ICC_SGI1R_EL1);
85 GIC_ICC_REG_CASE(ICC_ASGI1R_EL1);
86 GIC_ICC_REG_CASE(ICC_SGI0R_EL1);
87 GIC_ICC_REG_CASE(ICC_IAR1_EL1);
88 GIC_ICC_REG_CASE(ICC_EOIR1_EL1);
89 GIC_ICC_REG_CASE(ICC_HPPIR1_EL1);
90 GIC_ICC_REG_CASE(ICC_BPR1_EL1);
91 GIC_ICC_REG_CASE(ICC_CTLR_EL1);
92 GIC_ICC_REG_CASE(ICC_SRE_EL1);
93 GIC_ICC_REG_CASE(ICC_IGRPEN0_EL1);
94 GIC_ICC_REG_CASE(ICC_IGRPEN1_EL1);
95#undef GIC_ICC_REG_CASE
96 default:
97 break;
98 }
99
100 return "<UNKNOWN>";
101}
102
103
104/**
105 * Gets the description of a distributor register given it's register offset.
106 *
107 * @returns The register description.
108 * @param offReg The distributor register offset.
109 */
110static const char *gicDistGetRegDescription(uint16_t offReg)
111{
112 if (offReg - GIC_DIST_REG_IGROUPRn_OFF_START < GIC_DIST_REG_IGROUPRn_RANGE_SIZE) return "GICD_IGROUPRn";
113 if (offReg - GIC_DIST_REG_IGROUPRnE_OFF_START < GIC_DIST_REG_IGROUPRnE_RANGE_SIZE) return "GICD_IGROUPRnE";
114 if (offReg - GIC_DIST_REG_IROUTERn_OFF_START < GIC_DIST_REG_IROUTERn_RANGE_SIZE) return "GICD_IROUTERn";
115 if (offReg - GIC_DIST_REG_IROUTERnE_OFF_START < GIC_DIST_REG_IROUTERnE_RANGE_SIZE) return "GICD_IROUTERnE";
116 if (offReg - GIC_DIST_REG_ISENABLERn_OFF_START < GIC_DIST_REG_ISENABLERn_RANGE_SIZE) return "GICD_ISENABLERn";
117 if (offReg - GIC_DIST_REG_ISENABLERnE_OFF_START < GIC_DIST_REG_ISENABLERnE_RANGE_SIZE) return "GICD_ISENABLERnE";
118 if (offReg - GIC_DIST_REG_ICENABLERn_OFF_START < GIC_DIST_REG_ICENABLERn_RANGE_SIZE) return "GICD_ICENABLERn";
119 if (offReg - GIC_DIST_REG_ICENABLERnE_OFF_START < GIC_DIST_REG_ICENABLERnE_RANGE_SIZE) return "GICD_ICENABLERnE";
120 if (offReg - GIC_DIST_REG_ISACTIVERn_OFF_START < GIC_DIST_REG_ISACTIVERn_RANGE_SIZE) return "GICD_ISACTIVERn";
121 if (offReg - GIC_DIST_REG_ISACTIVERnE_OFF_START < GIC_DIST_REG_ISACTIVERnE_RANGE_SIZE) return "GICD_ISACTIVERnE";
122 if (offReg - GIC_DIST_REG_ICACTIVERn_OFF_START < GIC_DIST_REG_ICACTIVERn_RANGE_SIZE) return "GICD_ICACTIVERn";
123 if (offReg - GIC_DIST_REG_ICACTIVERnE_OFF_START < GIC_DIST_REG_ICACTIVERnE_RANGE_SIZE) return "GICD_ICACTIVERnE";
124 if (offReg - GIC_DIST_REG_IPRIORITYRn_OFF_START < GIC_DIST_REG_IPRIORITYRn_RANGE_SIZE) return "GICD_IPRIORITYRn";
125 if (offReg - GIC_DIST_REG_IPRIORITYRnE_OFF_START < GIC_DIST_REG_IPRIORITYRnE_RANGE_SIZE) return "GICD_IPRIORITYRnE";
126 if (offReg - GIC_DIST_REG_ISPENDRn_OFF_START < GIC_DIST_REG_ISPENDRn_RANGE_SIZE) return "GICD_ISPENDRn";
127 if (offReg - GIC_DIST_REG_ISPENDRnE_OFF_START < GIC_DIST_REG_ISPENDRnE_RANGE_SIZE) return "GICD_ISPENDRnE";
128 if (offReg - GIC_DIST_REG_ICPENDRn_OFF_START < GIC_DIST_REG_ICPENDRn_RANGE_SIZE) return "GICD_ICPENDRn";
129 if (offReg - GIC_DIST_REG_ICPENDRnE_OFF_START < GIC_DIST_REG_ICPENDRnE_RANGE_SIZE) return "GICD_ICPENDRnE";
130 if (offReg - GIC_DIST_REG_ICFGRn_OFF_START < GIC_DIST_REG_ICFGRn_RANGE_SIZE) return "GICD_ICFGRn";
131 if (offReg - GIC_DIST_REG_ICFGRnE_OFF_START < GIC_DIST_REG_ICFGRnE_RANGE_SIZE) return "GICD_ICFGRnE";
132 switch (offReg)
133 {
134 case GIC_DIST_REG_CTLR_OFF: return "GICD_CTLR";
135 case GIC_DIST_REG_TYPER_OFF: return "GICD_TYPER";
136 case GIC_DIST_REG_STATUSR_OFF: return "GICD_STATUSR";
137 case GIC_DIST_REG_ITARGETSRn_OFF_START: return "GICD_ITARGETSRn";
138 case GIC_DIST_REG_IGRPMODRn_OFF_START: return "GICD_IGRPMODRn";
139 case GIC_DIST_REG_NSACRn_OFF_START: return "GICD_NSACRn";
140 case GIC_DIST_REG_SGIR_OFF: return "GICD_SGIR";
141 case GIC_DIST_REG_CPENDSGIRn_OFF_START: return "GICD_CSPENDSGIRn";
142 case GIC_DIST_REG_SPENDSGIRn_OFF_START: return "GICD_SPENDSGIRn";
143 case GIC_DIST_REG_INMIn_OFF_START: return "GICD_INMIn";
144 case GIC_DIST_REG_PIDR2_OFF: return "GICD_PIDR2";
145 case GIC_DIST_REG_IIDR_OFF: return "GICD_IIDR";
146 case GIC_DIST_REG_TYPER2_OFF: return "GICD_TYPER2";
147 default:
148 return "<UNKNOWN>";
149 }
150}
151
152
153/**
154 * Gets the description of a redistributor register given it's register offset.
155 *
156 * @returns The register description.
157 * @param offReg The redistributor register offset.
158 */
159static const char *gicReDistGetRegDescription(uint16_t offReg)
160{
161 if (offReg - GIC_REDIST_SGI_PPI_REG_IGROUPR0_OFF < GIC_REDIST_SGI_PPI_REG_IGROUPRnE_RANGE_SIZE) return "GICR_IGROUPn";
162 if (offReg - GIC_REDIST_SGI_PPI_REG_ISENABLER0_OFF < GIC_REDIST_SGI_PPI_REG_ISENABLERnE_RANGE_SIZE) return "GICR_ISENABLERn";
163 if (offReg - GIC_REDIST_SGI_PPI_REG_ICENABLER0_OFF < GIC_REDIST_SGI_PPI_REG_ICENABLERnE_RANGE_SIZE) return "GICR_ICENABLERn";
164 if (offReg - GIC_REDIST_SGI_PPI_REG_ISACTIVER0_OFF < GIC_REDIST_SGI_PPI_REG_ISACTIVERnE_RANGE_SIZE) return "GICR_ISACTIVERn";
165 if (offReg - GIC_REDIST_SGI_PPI_REG_ICACTIVER0_OFF < GIC_REDIST_SGI_PPI_REG_ICACTIVERnE_RANGE_SIZE) return "GICR_ICACTIVERn";
166 if (offReg - GIC_REDIST_SGI_PPI_REG_ISPENDR0_OFF < GIC_REDIST_SGI_PPI_REG_ISPENDRnE_RANGE_SIZE) return "GICR_ISPENDRn";
167 if (offReg - GIC_REDIST_SGI_PPI_REG_ICPENDR0_OFF < GIC_REDIST_SGI_PPI_REG_ICPENDRnE_RANGE_SIZE) return "GICR_ICPENDRn";
168 if (offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START < GIC_REDIST_SGI_PPI_REG_IPRIORITYRnE_RANGE_SIZE) return "GICR_IPREIORITYn";
169 if (offReg - GIC_REDIST_SGI_PPI_REG_ICFGR0_OFF < GIC_REDIST_SGI_PPI_REG_ICFGRnE_RANGE_SIZE) return "GICR_ICFGRn";
170 switch (offReg)
171 {
172 case GIC_REDIST_REG_TYPER_OFF: return "GICR_TYPER";
173 case GIC_REDIST_REG_IIDR_OFF: return "GICR_IIDR";
174 case GIC_REDIST_REG_TYPER_AFFINITY_OFF: return "GICR_TYPER_AFF";
175 case GIC_REDIST_REG_PIDR2_OFF: return "GICR_PIDR2";
176 default:
177 return "<UNKNOWN>";
178 }
179}
180#endif
181
182
183/**
184 * Gets the interrupt ID given a distributor interrupt index.
185 *
186 * @returns The interrupt ID.
187 * @param idxIntr The distributor interrupt index.
188 * @remarks A distributor interrupt is an interrupt type that belong in the
189 * distributor (e.g. SPIs, extended SPIs).
190 */
191DECLHIDDEN(uint16_t) gicDistGetIntIdFromIndex(uint16_t idxIntr)
192{
193 /*
194 * Distributor interrupts bits to interrupt ID mapping:
195 * +--------------------------------------------------------+
196 * | Range (incl) | SGI | PPI | SPI | Ext SPI |
197 * |--------------+--------+--------+----------+------------|
198 * | Bit | 0..15 | 16..31 | 32..1023 | 1024..2047 |
199 * | Int Id | 0..15 | 16..31 | 32..1023 | 4096..5119 |
200 * +--------------------------------------------------------+
201 */
202 uint16_t uIntId;
203 /* SGIs, PPIs, SPIs and specials. */
204 if (idxIntr < 1024)
205 uIntId = idxIntr;
206 /* Extended SPIs. */
207 else if (idxIntr < 2048)
208 uIntId = GIC_INTID_RANGE_EXT_SPI_START + idxIntr - 1024;
209 else
210 {
211 uIntId = 0;
212 AssertReleaseFailed();
213 }
214 Assert( GIC_IS_INTR_SGI_OR_PPI(uIntId)
215 || GIC_IS_INTR_SPI(uIntId)
216 || GIC_IS_INTR_SPECIAL(uIntId)
217 || GIC_IS_INTR_EXT_SPI(uIntId));
218 return uIntId;
219}
220
221
222/**
223 * Gets the distributor interrupt index given an interrupt ID.
224 *
225 * @returns The distributor interrupt index.
226 * @param uIntId The interrupt ID.
227 * @remarks A distributor interrupt is an interrupt type that belong in the
228 * distributor (e.g. SPIs, extended SPIs).
229 */
230static uint16_t gicDistGetIndexFromIntId(uint16_t uIntId)
231{
232 uint16_t idxIntr;
233 /* SGIs, PPIs, SPIs and specials. */
234 if (uIntId <= GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT)
235 idxIntr = uIntId;
236 /* Extended SPIs. */
237 else if (uIntId - GIC_INTID_RANGE_EXT_SPI_START < GIC_INTID_EXT_SPI_RANGE_SIZE)
238 idxIntr = 1024 + uIntId - GIC_INTID_RANGE_EXT_SPI_START;
239 else
240 {
241 idxIntr = 0;
242 AssertReleaseFailed();
243 }
244 Assert(idxIntr < sizeof(GICDEV::bmIntrPending) * 8);
245 return idxIntr;
246}
247
248
249/**
250 * Gets the interrupt ID given a redistributor interrupt index.
251 *
252 * @returns The interrupt ID.
253 * @param idxIntr The redistributor interrupt index.
254 * @remarks A redistributor interrupt is an interrupt type that belong in the
255 * redistributor (e.g. SGIs, PPIs, extended PPIs).
256 */
257DECLHIDDEN(uint16_t) gicReDistGetIntIdFromIndex(uint16_t idxIntr)
258{
259 /*
260 * Redistributor interrupts bits to interrupt ID mapping:
261 * +---------------------------------------------+
262 * | Range (incl) | SGI | PPI | Ext PPI |
263 * +---------------------------------------------+
264 * | Bit | 0..15 | 16..31 | 32..95 |
265 * | Int Id | 0..15 | 16..31 | 1056..1119 |
266 * +---------------------------------------------+
267 */
268 uint16_t uIntId;
269 /* SGIs and PPIs. */
270 if (idxIntr < 32)
271 uIntId = idxIntr;
272 /* Extended PPIs. */
273 else if (idxIntr < 96)
274 uIntId = GIC_INTID_RANGE_PPI_LAST + 1 + idxIntr - GIC_INTID_RANGE_EXT_PPI_START;
275 else
276 {
277 uIntId = 0;
278 AssertReleaseFailed();
279 }
280 Assert(GIC_IS_INTR_SGI_OR_PPI(uIntId) || GIC_IS_INTR_EXT_PPI(uIntId));
281 return uIntId;
282}
283
284
285/**
286 * Gets the redistributor interrupt index given an interrupt ID.
287 *
288 * @returns The interrupt ID.
289 * @param uIntId The interrupt ID.
290 * @remarks A redistributor interrupt is an interrupt type that belong in the
291 * redistributor (e.g. SGIs, PPIs, extended PPIs).
292 */
293static uint16_t gicReDistGetIndexFromIntId(uint16_t uIntId)
294{
295 /* SGIs and PPIs. */
296 uint16_t idxIntr;
297 if (uIntId <= GIC_INTID_RANGE_PPI_LAST)
298 idxIntr = uIntId;
299 /* Extended PPIs. */
300 else if (uIntId - GIC_INTID_RANGE_EXT_PPI_START < GIC_INTID_EXT_PPI_RANGE_SIZE)
301 idxIntr = 32 + uIntId - GIC_INTID_RANGE_EXT_PPI_START;
302 else
303 {
304 idxIntr = 0;
305 AssertReleaseFailed();
306 }
307 Assert(idxIntr < sizeof(GICCPU::bmIntrPending) * 8);
308 return idxIntr;
309}
310
311
312/**
313 * Sets the interrupt pending force-flag and pokes the EMT if required.
314 *
315 * @param pVCpu The cross context virtual CPU structure.
316 * @param fIrq Flag whether to assert the IRQ line or leave it alone.
317 * @param fFiq Flag whether to assert the FIQ line or leave it alone.
318 */
319static void gicSetInterruptFF(PVMCPUCC pVCpu, bool fIrq, bool fFiq)
320{
321 LogFlowFunc(("pVCpu=%p{.idCpu=%u} fIrq=%RTbool fFiq=%RTbool\n",
322 pVCpu, pVCpu->idCpu, fIrq, fFiq));
323
324 Assert(fIrq || fFiq);
325
326#ifdef IN_RING3
327 /* IRQ state should be loaded as-is by "LoadExec". Changes can be made from LoadDone. */
328 Assert(pVCpu->pVMR3->enmVMState != VMSTATE_LOADING || PDMR3HasLoadedState(pVCpu->pVMR3));
329#endif
330
331 if (fIrq)
332 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_IRQ);
333 if (fFiq)
334 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_FIQ);
335
336 /*
337 * We need to wake up the target CPU if we're not on EMT.
338 */
339 /** @todo We could just use RTThreadNativeSelf() here, couldn't we? */
340#if defined(IN_RING0)
341# error "Implement me!"
342#elif defined(IN_RING3)
343 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
344 VMCPUID idCpu = pVCpu->idCpu;
345 if (VMMGetCpuId(pVM) != idCpu)
346 {
347 Log7Func(("idCpu=%u enmState=%d\n", idCpu, pVCpu->enmState));
348 VMR3NotifyCpuFFU(pVCpu->pUVCpu, VMNOTIFYFF_FLAGS_POKE);
349 }
350#endif
351}
352
353
354#if 0
355/**
356 * Sets the update interrupt force-flag and pokes the EMT if required.
357 *
358 * @param pVCpu The cross context virtual CPU structure.
359 */
360static void gicSetUpdateInterruptFF(PVMCPUCC pVCpu)
361{
362#ifdef IN_RING3
363 /* IRQ state should be loaded as-is by "LoadExec". Changes can be made from LoadDone. */
364 Assert(pVCpu->pVMR3->enmVMState != VMSTATE_LOADING || PDMR3HasLoadedState(pVCpu->pVMR3));
365#endif
366
367 /* Set the update-interrupt force-flag. */
368 VMCPU_FF_SET(pVCpu, VMCPU_FF_UPDATE_GIC);
369
370 /* Wake up the target CPU if we're not currently on the target EMT. */
371#if defined(IN_RING0)
372# error "Implement me"
373#elif defined(IN_RING3)
374 if (pVCpu->hNativeThread != RTThreadNativeSelf())
375 VMR3NotifyCpuFFU(pVCpu->pUVCpu, VMNOTIFYFF_FLAGS_POKE);
376#endif
377}
378#endif
379
380
381/**
382 * Clears the interrupt pending force-flag.
383 *
384 * @param pVCpu The cross context virtual CPU structure.
385 * @param fIrq Flag whether to clear the IRQ flag.
386 * @param fFiq Flag whether to clear the FIQ flag.
387 */
388DECLINLINE(void) gicClearInterruptFF(PVMCPUCC pVCpu, bool fIrq, bool fFiq)
389{
390 Assert(fIrq || fFiq);
391 LogFlowFunc(("pVCpu=%p{.idCpu=%u} fIrq=%RTbool fFiq=%RTbool\n", pVCpu, pVCpu->idCpu, fIrq, fFiq));
392
393#ifdef IN_RING3
394 /* IRQ state should be loaded as-is by "LoadExec". Changes can be made from LoadDone. */
395 Assert(pVCpu->pVMR3->enmVMState != VMSTATE_LOADING || PDMR3HasLoadedState(pVCpu->pVMR3));
396#endif
397
398 if (fIrq)
399 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_IRQ);
400 if (fFiq)
401 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_FIQ);
402}
403
404
405/**
406 * Updates the interrupt force-flag.
407 *
408 * @param pVCpu The cross context virtual CPU structure.
409 * @param fIrq Flag whether to clear the IRQ flag.
410 * @param fFiq Flag whether to clear the FIQ flag.
411 */
412DECLINLINE(void) gicUpdateInterruptFF(PVMCPUCC pVCpu, bool fIrq, bool fFiq)
413{
414 LogFlowFunc(("pVCpu=%p{.idCpu=%u} fIrq=%RTbool fFiq=%RTbool\n", pVCpu, pVCpu->idCpu, fIrq, fFiq));
415
416 if (fIrq || fFiq)
417 gicSetInterruptFF(pVCpu, fIrq, fFiq);
418
419 if (!fIrq || !fFiq)
420 gicClearInterruptFF(pVCpu, !fIrq, !fFiq);
421}
422
423
424/**
425 * Gets whether the redistributor has pending interrupts with sufficient priority to
426 * be signalled to the PE.
427 *
428 * @param pGicCpu The GIC redistributor and CPU interface state.
429 * @param pfIrq Where to store whether IRQs can be signalled.
430 * @param pfFiq Where to store whether FIQs can be signalled.
431 */
432DECLINLINE(void) gicReDistHasIrqPending(PCGICCPU pGicCpu, bool *pfIrq, bool *pfFiq)
433{
434 LogFlowFunc(("\n"));
435#if 0
436 /* Read the interrupt state. */
437 uint32_t u32RegIGrp0 = ASMAtomicReadU32(&pThis->u32RegIGrp0);
438 uint32_t bmIntEnabled = ASMAtomicReadU32(&pThis->bmIntEnabled);
439 uint32_t bmIntPending = ASMAtomicReadU32(&pThis->bmIntPending);
440 uint32_t bmIntActive = ASMAtomicReadU32(&pThis->bmIntActive);
441 bool fIrqGrp0Enabled = ASMAtomicReadBool(&pThis->fIrqGrp0Enabled);
442 bool fIrqGrp1Enabled = ASMAtomicReadBool(&pThis->fIrqGrp1Enabled);
443
444 /* Only allow interrupts with higher priority than the current configured and running one. */
445 uint8_t bPriority = RT_MIN(pThis->bInterruptPriority, pThis->abRunningPriorities[pThis->idxRunningPriority]);
446
447 /* Is anything enabled at all? */
448 uint32_t bmIntForward = (bmIntPending & bmIntEnabled) & ~bmIntActive; /* Exclude the currently active interrupt. */
449 if (bmIntForward)
450 {
451 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->abIntPriority); i++)
452 {
453 Log4(("SGI/PPI %u, configured priority %u, running priority %u\n", i, pThis->abIntPriority[i], bPriority));
454 if ( (bmIntForward & RT_BIT_32(i))
455 && pThis->abIntPriority[i] < bPriority)
456 break;
457 else
458 bmIntForward &= ~RT_BIT_32(i);
459
460 if (!bmIntForward)
461 break;
462 }
463 }
464
465 if (bmIntForward)
466 {
467 /* Determine whether we have to assert the IRQ or FIQ line. */
468 *pfIrq = RT_BOOL(bmIntForward & u32RegIGrp0) && fIrqGrp1Enabled;
469 *pfFiq = RT_BOOL(bmIntForward & ~u32RegIGrp0) && fIrqGrp0Enabled;
470 }
471 else
472 {
473 *pfIrq = false;
474 *pfFiq = false;
475 }
476
477 LogFlowFunc(("pThis=%p bPriority=%u bmIntEnabled=%#x bmIntPending=%#x bmIntActive=%#x fIrq=%RTbool fFiq=%RTbool\n",
478 pThis, bPriority, bmIntEnabled, bmIntPending, bmIntActive, *pfIrq, *pfFiq));
479#else
480 bool const fIsGroup1Enabled = pGicCpu->fIrqGrp1Enabled;
481 bool const fIsGroup0Enabled = pGicCpu->fIrqGrp0Enabled;
482 LogFlowFunc(("fIsGroup0Enabled=%RTbool fIsGroup1Enabled=%RTbool\n", fIsGroup0Enabled, fIsGroup1Enabled));
483
484 uint32_t bmIntrs[3];
485 for (uint8_t i = 0; i < RT_ELEMENTS(bmIntrs); i++)
486 {
487 /* Collect interrupts that are pending, enabled and inactive. */
488 bmIntrs[i] = (pGicCpu->bmIntrPending[i] & pGicCpu->bmIntrEnabled[i]) & ~pGicCpu->bmIntrActive[i];
489
490 /* Discard interrupts if the group they belong to is disabled. */
491 if (!fIsGroup1Enabled)
492 bmIntrs[i] &= ~pGicCpu->bmIntrGroup[i];
493 if (!fIsGroup0Enabled)
494 bmIntrs[i] &= pGicCpu->bmIntrGroup[i];
495 }
496
497 /* Only allow interrupts with higher priority than the current configured and running one. */
498 uint8_t const bPriority = RT_MIN(pGicCpu->bInterruptPriority, pGicCpu->abRunningPriorities[pGicCpu->idxRunningPriority]);
499
500 uint32_t const cIntrs = sizeof(bmIntrs) * 8;
501 int32_t idxIntr = ASMBitFirstSet(&bmIntrs[0], cIntrs);
502 AssertCompile(!(cIntrs % 32));
503 if (idxIntr >= 0)
504 {
505 do
506 {
507 Assert((uint32_t)idxIntr < RT_ELEMENTS(pGicCpu->abIntrPriority));
508 if (pGicCpu->abIntrPriority[idxIntr] < bPriority)
509 {
510 bool const fInGroup1 = ASMBitTest(&pGicCpu->bmIntrGroup[0], idxIntr);
511 bool const fInGroup0 = !fInGroup1;
512 *pfIrq = fInGroup1 && fIsGroup1Enabled;
513 *pfFiq = fInGroup0 && fIsGroup0Enabled;
514 return;
515 }
516 idxIntr = ASMBitNextSet(&bmIntrs[0], cIntrs, idxIntr);
517 } while (idxIntr != -1);
518 }
519 *pfIrq = false;
520 *pfFiq = false;
521#endif
522}
523
524
525/**
526 * Gets whether the distributor has pending interrupts with sufficient priority to
527 * be signalled to the PE.
528 *
529 * @param pGicDev The GIC distributor state.
530 * @param pVCpu The cross context virtual CPU structure.
531 * @param idCpu The ID of the virtual CPU.
532 * @param pfIrq Where to store whether there are IRQs can be signalled.
533 * @param pfFiq Where to store whether there are FIQs can be signalled.
534 */
535DECLINLINE(void) gicDistHasIrqPendingForVCpu(PCGICDEV pGicDev, PCVMCPUCC pVCpu, VMCPUID idCpu, bool *pfIrq, bool *pfFiq)
536{
537 LogFlowFunc(("\n"));
538#if 0
539 /* Read the interrupt state. */
540 uint32_t u32RegIGrp0 = ASMAtomicReadU32(&pThis->u32RegIGrp0);
541 uint32_t bmIntEnabled = ASMAtomicReadU32(&pThis->bmIntEnabled);
542 uint32_t bmIntPending = ASMAtomicReadU32(&pThis->bmIntPending);
543 uint32_t bmIntActive = ASMAtomicReadU32(&pThis->bmIntActive);
544 bool fIrqGrp0Enabled = ASMAtomicReadBool(&pThis->fIrqGrp0Enabled);
545 bool fIrqGrp1Enabled = ASMAtomicReadBool(&pThis->fIrqGrp1Enabled);
546
547 /* Only allow interrupts with higher priority than the current configured and running one. */
548 uint8_t bPriority = RT_MIN(pGicVCpu->bInterruptPriority, pGicVCpu->abRunningPriorities[pGicVCpu->idxRunningPriority]);
549
550 /* Is anything enabled at all? */
551 uint32_t bmIntForward = (bmIntPending & bmIntEnabled) & ~bmIntActive; /* Exclude the currently active interrupt. */
552 if (bmIntForward)
553 {
554 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->abIntPriority); i++)
555 {
556 Log4(("SPI %u, configured priority %u (routing %#x), running priority %u\n", i + GIC_INTID_RANGE_SPI_START, pThis->abIntPriority[i],
557 pThis->au32IntRouting[i], bPriority));
558 if ( (bmIntForward & RT_BIT_32(i))
559 && pThis->abIntPriority[i] < bPriority
560 && pThis->au32IntRouting[i] == idCpu)
561 break;
562 else
563 bmIntForward &= ~RT_BIT_32(i);
564
565 if (!bmIntForward)
566 break;
567 }
568 }
569
570 if (bmIntForward)
571 {
572 /* Determine whether we have to assert the IRQ or FIQ line. */
573 *pfIrq = RT_BOOL(bmIntForward & u32RegIGrp0) && fIrqGrp1Enabled;
574 *pfFiq = RT_BOOL(bmIntForward & ~u32RegIGrp0) && fIrqGrp0Enabled;
575 }
576 else
577 {
578 *pfIrq = false;
579 *pfFiq = false;
580 }
581
582 LogFlowFunc(("pThis=%p bPriority=%u bmIntEnabled=%#x bmIntPending=%#x bmIntActive=%#x fIrq=%RTbool fFiq=%RTbool\n",
583 pThis, bPriority, bmIntEnabled, bmIntPending, bmIntActive, *pfIrq, *pfFiq));
584#else
585 bool const fIsGroup1Enabled = pGicDev->fIrqGrp1Enabled;
586 bool const fIsGroup0Enabled = pGicDev->fIrqGrp0Enabled;
587 LogFlowFunc(("fIsGroup1Enabled=%RTbool fIsGroup0Enabled=%RTbool\n", fIsGroup1Enabled, fIsGroup0Enabled));
588
589 uint32_t bmIntrs[64];
590 for (uint8_t i = 0; i < RT_ELEMENTS(bmIntrs); i++)
591 {
592 /* Collect interrupts that are pending, enabled and inactive. */
593 bmIntrs[i] = (pGicDev->bmIntrPending[i] & pGicDev->bmIntrEnabled[i]) & ~pGicDev->bmIntrActive[i];
594
595 /* Discard interrupts if the group they belong to is disabled. */
596 if (!fIsGroup1Enabled)
597 bmIntrs[i] &= ~pGicDev->bmIntrGroup[i];
598 if (!fIsGroup0Enabled)
599 bmIntrs[i] &= pGicDev->bmIntrGroup[i];
600 }
601
602 /* Only allow interrupts with higher priority than the current configured and running one. */
603 PCGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
604 uint8_t const bPriority = RT_MIN(pGicCpu->bInterruptPriority, pGicCpu->abRunningPriorities[pGicCpu->idxRunningPriority]);
605
606 /*
607 * The distributor's interrupt pending/enabled/active bitmaps have 2048 bits which map
608 * SGIs (16), PPIs (16), SPIs (988), reserved SPIs (4) and extended SPIs (1024).
609 * Of these, the first 16 bits corresponding to SGIs and PPIs are RAZ/WI when affinity
610 * routing is enabled (which it always is in our implementation).
611 */
612 Assert(pGicDev->fAffRoutingEnabled);
613 uint32_t const cIntrs = sizeof(bmIntrs) * 8;
614 int32_t idxIntr = ASMBitFirstSet(&bmIntrs[0], cIntrs);
615 AssertCompile(!(cIntrs % 32));
616 Assert(bmIntrs[0] == 0);
617 if (idxIntr >= 0)
618 {
619 Assert(idxIntr > GIC_INTID_RANGE_PPI_LAST);
620 do
621 {
622 AssertCompile(RT_ELEMENTS(pGicDev->abIntrPriority) == RT_ELEMENTS(pGicDev->au32IntrRouting));
623 Assert((uint32_t)idxIntr < RT_ELEMENTS(pGicDev->abIntrPriority));
624 Assert(idxIntr < GIC_INTID_RANGE_SPECIAL_START || idxIntr > GIC_INTID_RANGE_SPECIAL_LAST);
625 if ( pGicDev->abIntrPriority[idxIntr] < bPriority
626 && pGicDev->au32IntrRouting[idxIntr] == idCpu)
627 {
628 bool const fInGroup1 = ASMBitTest(&pGicDev->bmIntrGroup[0], idxIntr);
629 bool const fInGroup0 = !fInGroup1;
630 *pfFiq = fInGroup0 && fIsGroup0Enabled;
631 *pfIrq = fInGroup1 && fIsGroup1Enabled;
632 return;
633 }
634 idxIntr = ASMBitNextSet(&bmIntrs[0], cIntrs, idxIntr);
635 } while (idxIntr != -1);
636 }
637 *pfIrq = false;
638 *pfFiq = false;
639#endif
640}
641
642
643/**
644 * Updates the internal IRQ state and sets or clears the appropriate force action
645 * flags.
646 *
647 * @returns Strict VBox status code.
648 * @param pGicDev The GIC distributor state.
649 * @param pVCpu The cross context virtual CPU structure.
650 */
651static VBOXSTRICTRC gicReDistUpdateIrqState(PCGICDEV pGicDev, PVMCPUCC pVCpu)
652{
653 LogFlowFunc(("\n"));
654 bool fIrq;
655 bool fFiq;
656 gicReDistHasIrqPending(VMCPU_TO_GICCPU(pVCpu), &fIrq, &fFiq);
657 LogFlowFunc(("fIrq=%RTbool fFiq=%RTbool\n", fIrq, fFiq));
658
659 bool fIrqDist;
660 bool fFiqDist;
661 gicDistHasIrqPendingForVCpu(pGicDev, pVCpu, pVCpu->idCpu, &fIrqDist, &fFiqDist);
662 LogFlowFunc(("fIrqDist=%RTbool fFiqDist=%RTbool\n", fIrqDist, fFiqDist));
663
664 fIrq |= fIrqDist;
665 fFiq |= fFiqDist;
666 gicUpdateInterruptFF(pVCpu, fIrq, fFiq);
667 return VINF_SUCCESS;
668}
669
670
671/**
672 * Updates the internal IRQ state of the distributor and sets or clears the appropirate force action flags.
673 *
674 * @returns Strict VBox status code.
675 * @param pVM The cross context VM state.
676 * @param pGicDev The GIC distributor state.
677 */
678static VBOXSTRICTRC gicDistUpdateIrqState(PCVMCC pVM, PCGICDEV pGicDev)
679{
680 LogFlowFunc(("\n"));
681 for (uint32_t i = 0; i < pVM->cCpus; i++)
682 {
683 PVMCPUCC pVCpu = pVM->CTX_SUFF(apCpus)[i];
684 PCGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
685
686 bool fIrq, fFiq;
687 gicReDistHasIrqPending(pGicCpu, &fIrq, &fFiq);
688
689 bool fIrqDist, fFiqDist;
690 gicDistHasIrqPendingForVCpu(pGicDev, pVCpu, i, &fIrqDist, &fFiqDist);
691 fIrq |= fIrqDist;
692 fFiq |= fFiqDist;
693
694 gicUpdateInterruptFF(pVCpu, fIrq, fFiq);
695 }
696 return VINF_SUCCESS;
697}
698
699
700/**
701 * Reads the distributor's interrupt routing register (GICD_IROUTER).
702 *
703 * @returns Strict VBox status code.
704 * @param pGicDev The GIC distributor state.
705 * @param idxReg The index of the register in the GICD_IROUTER range.
706 * @param puValue Where to store the register's value.
707 */
708static VBOXSTRICTRC gicDistReadIntrRoutingReg(PCGICDEV pGicDev, uint16_t idxReg, uint32_t *puValue)
709{
710 /* When affinity routing is disabled, reads return 0. */
711 Assert(pGicDev->fAffRoutingEnabled);
712
713 /* Hardware does not map the first 32 registers (corresponding to SGIs and PPIs). */
714 idxReg += GIC_INTID_RANGE_SPI_START;
715 AssertReturn(idxReg < RT_ELEMENTS(pGicDev->au32IntrRouting), VERR_BUFFER_OVERFLOW);
716 Assert(idxReg < sizeof(pGicDev->bmIntrRoutingMode) * 8);
717 if (!(idxReg % 2))
718 {
719 /* Lower 32-bits. */
720 uint8_t const fIrm = ASMBitTest(&pGicDev->bmIntrRoutingMode[0], idxReg);
721 *puValue = GIC_DIST_REG_IROUTERn_SET(fIrm, pGicDev->au32IntrRouting[idxReg]);
722 }
723 else
724 {
725 /* Upper 32-bits. */
726 *puValue = pGicDev->au32IntrRouting[idxReg] >> 24;
727 }
728
729 LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, *puValue));
730 return VINF_SUCCESS;
731}
732
733
734/**
735 * Writes the distributor's interrupt routing register (GICD_IROUTER).
736 *
737 * @returns Strict VBox status code.
738 * @param pGicDev The GIC distributor state.
739 * @param offReg The offset of the register in the distributor register map.
740 * @param idxReg The index of the register in the GICD_IROUTER range.
741 * @param uValue The value to write to the register.
742 */
743static VBOXSTRICTRC gicDistWriteIntrRoutingReg(PGICDEV pGicDev, uint16_t offReg, uint16_t idxReg, uint32_t uValue)
744{
745 /* When affinity routing is disabled, writes are ignored. */
746 Assert(pGicDev->fAffRoutingEnabled);
747
748 /* Hardware does not map the first 32 registers (corresponding to SGIs and PPIs). */
749 idxReg += GIC_INTID_RANGE_SPI_START;
750 AssertReturn(idxReg < RT_ELEMENTS(pGicDev->au32IntrRouting), VERR_BUFFER_OVERFLOW);
751 Assert(idxReg < sizeof(pGicDev->bmIntrRoutingMode) * 8);
752 if (!(offReg & 4))
753 {
754 /* Lower 32-bits. */
755 bool const fIrm = GIC_DIST_REG_IROUTERn_IRM_GET(uValue);
756 if (fIrm)
757 ASMBitSet(&pGicDev->bmIntrRoutingMode[0], idxReg);
758 else
759 ASMBitClear(&pGicDev->bmIntrRoutingMode[0], idxReg);
760 uint32_t const fAff3 = pGicDev->au32IntrRouting[idxReg] & 0xff000000;
761 pGicDev->au32IntrRouting[idxReg] = fAff3 | (uValue & 0x00ffffff);
762 }
763 else
764 {
765 /* Upper 32-bits. */
766 uint32_t const fAffOthers = pGicDev->au32IntrRouting[idxReg] & 0x00ffffff;
767 pGicDev->au32IntrRouting[idxReg] = (uValue << 24) | fAffOthers;
768 }
769
770 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicDev->au32IntrRouting[idxReg]));
771 return VINF_SUCCESS;
772}
773
774
775/**
776 * Reads the distributor's interrupt (set/clear) enable register (GICD_ISENABLER and
777 * GICD_ICENABLER).
778 *
779 * @returns Strict VBox status code.
780 * @param pGicDev The GIC distributor state.
781 * @param idxReg The index of the register in the GICD_ISENABLER and
782 * GICD_ICENABLER range.
783 * @param puValue Where to store the register's value.
784 */
785static VBOXSTRICTRC gicDistReadIntrEnableReg(PGICDEV pGicDev, uint16_t idxReg, uint32_t *puValue)
786{
787 Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrEnabled));
788 *puValue = pGicDev->bmIntrEnabled[idxReg];
789 LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, pGicDev->bmIntrEnabled[idxReg]));
790 return VINF_SUCCESS;
791}
792
793
794/**
795 * Writes the distributor's interrupt set-enable register (GICD_ISENABLER).
796 *
797 * @returns Strict VBox status code.
798 * @param pVM The cross context VM structure.
799 * @param pGicDev The GIC distributor state.
800 * @param idxReg The index of the register in the GICD_ISENABLER range.
801 * @param uValue The value to write to the register.
802 */
803static VBOXSTRICTRC gicDistWriteIntrSetEnableReg(PVM pVM, PGICDEV pGicDev, uint16_t idxReg, uint32_t uValue)
804{
805 /* When affinity routing is enabled, writes to SGIs and PPIs are ignored. */
806 Assert(pGicDev->fAffRoutingEnabled);
807 if (idxReg > 0)
808 {
809 Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrEnabled));
810 pGicDev->bmIntrEnabled[idxReg] |= uValue;
811 return gicDistUpdateIrqState(pVM, pGicDev);
812 }
813 else
814 AssertReleaseFailed();
815 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicDev->bmIntrEnabled[idxReg]));
816 return VINF_SUCCESS;
817}
818
819
820/**
821 * Writes the distributor's interrupt clear-enable register (GICD_ICENABLER).
822 *
823 * @returns Strict VBox status code.
824 * @param pVM The cross context VM structure.
825 * @param pGicDev The GIC distributor state.
826 * @param idxReg The index of the register in the GICD_ICENABLER range.
827 * @param uValue The value to write to the register.
828 */
829static VBOXSTRICTRC gicDistWriteIntrClearEnableReg(PVM pVM, PGICDEV pGicDev, uint16_t idxReg, uint32_t uValue)
830{
831 /* When affinity routing is enabled, writes to SGIs and PPIs are ignored. */
832 Assert(pGicDev->fAffRoutingEnabled);
833 if (idxReg > 0)
834 {
835 Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrEnabled));
836 pGicDev->bmIntrEnabled[idxReg] &= ~uValue;
837 return gicDistUpdateIrqState(pVM, pGicDev);
838 }
839 else
840 AssertReleaseFailed();
841 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicDev->bmIntrEnabled[idxReg]));
842 return VINF_SUCCESS;
843}
844
845
846/**
847 * Reads the distributor's interrupt active register (GICD_ISACTIVER and
848 * GICD_ICACTIVER).
849 *
850 * @returns Strict VBox status code.
851 * @param pGicDev The GIC distributor state.
852 * @param idxReg The index of the register in the GICD_ISACTIVER and
853 * GICD_ICACTIVER range.
854 * @param puValue Where to store the register's value.
855 */
856static VBOXSTRICTRC gicDistReadIntrActiveReg(PGICDEV pGicDev, uint16_t idxReg, uint32_t *puValue)
857{
858 Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrActive));
859 *puValue = pGicDev->bmIntrActive[idxReg];
860 LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, pGicDev->bmIntrActive[idxReg]));
861 return VINF_SUCCESS;
862}
863
864
865/**
866 * Writes the distributor's interrupt set-active register (GICD_ISACTIVER).
867 *
868 * @returns Strict VBox status code.
869 * @param pVM The cross context VM structure.
870 * @param pGicDev The GIC distributor state.
871 * @param idxReg The index of the register in the GICD_ISACTIVER range.
872 * @param uValue The value to write to the register.
873 */
874static VBOXSTRICTRC gicDistWriteIntrSetActiveReg(PVM pVM, PGICDEV pGicDev, uint16_t idxReg, uint32_t uValue)
875{
876 /* When affinity routing is enabled, writes to SGIs and PPIs are ignored. */
877 Assert(pGicDev->fAffRoutingEnabled);
878 if (idxReg > 0)
879 {
880 Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrActive));
881 pGicDev->bmIntrActive[idxReg] |= uValue;
882 return gicDistUpdateIrqState(pVM, pGicDev);
883 }
884 else
885 AssertReleaseFailed();
886 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicDev->bmIntrActive[idxReg]));
887 return VINF_SUCCESS;
888}
889
890
891/**
892 * Writes the distributor's interrupt clear-active register (GICD_ICACTIVER).
893 *
894 * @returns Strict VBox status code.
895 * @param pVM The cross context VM structure.
896 * @param pGicDev The GIC distributor state.
897 * @param idxReg The index of the register in the GICD_ICACTIVER range.
898 * @param uValue The value to write to the register.
899 */
900static VBOXSTRICTRC gicDistWriteIntrClearActiveReg(PVM pVM, PGICDEV pGicDev, uint16_t idxReg, uint32_t uValue)
901{
902 /* When affinity routing is enabled, writes to SGIs and PPIs are ignored. */
903 Assert(pGicDev->fAffRoutingEnabled);
904 if (idxReg > 0)
905 {
906 Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrActive));
907 pGicDev->bmIntrActive[idxReg] &= ~uValue;
908 return gicDistUpdateIrqState(pVM, pGicDev);
909 }
910 else
911 AssertReleaseFailed();
912 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicDev->bmIntrActive[idxReg]));
913 return VINF_SUCCESS;
914}
915
916
917/**
918 * Reads the distributor's interrupt priority register (GICD_IPRIORITYR).
919 *
920 * @returns Strict VBox status code.
921 * @param pGicDev The GIC distributor state.
922 * @param idxReg The index of the register in the GICD_IPRIORITY range.
923 * @param puValue Where to store the register's value.
924 */
925static VBOXSTRICTRC gicDistReadIntrPriorityReg(PGICDEV pGicDev, uint16_t idxReg, uint32_t *puValue)
926{
927 /* When affinity routing is enabled, reads to registers 0..7 (pertaining to SGIs and PPIs) return 0. */
928 Assert(pGicDev->fAffRoutingEnabled);
929 Assert(idxReg < RT_ELEMENTS(pGicDev->abIntrPriority) / sizeof(uint32_t));
930 Assert(idxReg != 255);
931 if (idxReg > 7)
932 {
933 uint16_t const idxPriority = idxReg * sizeof(uint32_t);
934 AssertReturn(idxPriority < RT_ELEMENTS(pGicDev->abIntrPriority) - sizeof(uint32_t), VERR_BUFFER_OVERFLOW);
935 AssertCompile(sizeof(*puValue) == sizeof(uint32_t));
936 *puValue = *(uint32_t *)&pGicDev->abIntrPriority[idxPriority];
937 }
938 else
939 {
940 AssertReleaseFailed();
941 *puValue = 0;
942 }
943 LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, *puValue));
944 return VINF_SUCCESS;
945}
946
947
948/**
949 * Writes the distributor's interrupt priority register (GICD_IPRIORITYR).
950 *
951 * @returns Strict VBox status code.
952 * @param pGicDev The GIC distributor state.
953 * @param idxReg The index of the register in the GICD_IPRIORITY range.
954 * @param uValue The value to write to the register.
955 */
956static VBOXSTRICTRC gicDistWriteIntrPriorityReg(PGICDEV pGicDev, uint16_t idxReg, uint32_t uValue)
957{
958 /* When affinity routing is enabled, writes to registers 0..7 are ignored. */
959 Assert(pGicDev->fAffRoutingEnabled);
960 Assert(idxReg < RT_ELEMENTS(pGicDev->abIntrPriority) / sizeof(uint32_t));
961 Assert(idxReg != 255);
962 if (idxReg > 7)
963 {
964 uint16_t const idxPriority = idxReg * sizeof(uint32_t);
965 AssertReturn(idxPriority < RT_ELEMENTS(pGicDev->abIntrPriority) - sizeof(uint32_t), VERR_BUFFER_OVERFLOW);
966 AssertCompile(sizeof(uValue) == sizeof(uint32_t));
967 *(uint32_t *)&pGicDev->abIntrPriority[idxPriority] = uValue;
968 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, *(uint32_t *)&pGicDev->abIntrPriority[idxPriority]));
969 }
970 else
971 AssertReleaseFailed();
972 return VINF_SUCCESS;
973}
974
975
976/**
977 * Reads the distributor's interrupt pending register (GICD_ISPENDR and
978 * GICD_ICPENDR).
979 *
980 * @returns Strict VBox status code.
981 * @param pGicDev The GIC distributor state.
982 * @param idxReg The index of the register in the GICD_ISPENDR and
983 * GICD_ICPENDR range.
984 * @param puValue Where to store the register's value.
985 */
986static VBOXSTRICTRC gicDistReadIntrPendingReg(PGICDEV pGicDev, uint16_t idxReg, uint32_t *puValue)
987{
988 /* When affinity routing is enabled, reads for SGIs and PPIs return 0. */
989 Assert(pGicDev->fAffRoutingEnabled);
990 if (idxReg > 0)
991 {
992 Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrPending));
993 *puValue = pGicDev->bmIntrPending[idxReg];
994 }
995 else
996 {
997 AssertReleaseFailed();
998 *puValue = 0;
999 }
1000 LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, pGicDev->bmIntrPending[idxReg]));
1001 return VINF_SUCCESS;
1002}
1003
1004
1005/**
1006 * Write's the distributor's interrupt set-pending register (GICD_ISPENDR).
1007 *
1008 * @returns Strict VBox status code.
1009 * @param pVM The cross context VM structure.
1010 * @param pGicDev The GIC distributor state.
1011 * @param idxReg The index of the register in the GICD_ISPENDR range.
1012 * @param uValue The value to write to the register.
1013 */
1014static VBOXSTRICTRC gicDistWriteIntrSetPendingReg(PVMCC pVM, PGICDEV pGicDev, uint16_t idxReg, uint32_t uValue)
1015{
1016 /* When affinity routing is enabled, writes to SGIs and PPIs are ignored. */
1017 Assert(pGicDev->fAffRoutingEnabled);
1018 if (idxReg > 0)
1019 {
1020 Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrPending));
1021 pGicDev->bmIntrPending[idxReg] |= uValue;
1022 return gicDistUpdateIrqState(pVM, pGicDev);
1023 }
1024 else
1025 AssertReleaseFailed();
1026 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicDev->bmIntrPending[idxReg]));
1027 return VINF_SUCCESS;
1028}
1029
1030
1031/**
1032 * Write's the distributor's interrupt clear-pending register (GICD_ICPENDR).
1033 *
1034 * @returns Strict VBox status code.
1035 * @param pVM The cross context VM structure.
1036 * @param pGicDev The GIC distributor state.
1037 * @param idxReg The index of the register in the GICD_ICPENDR range.
1038 * @param uValue The value to write to the register.
1039 */
1040static VBOXSTRICTRC gicDistWriteIntrClearPendingReg(PVMCC pVM, PGICDEV pGicDev, uint16_t idxReg, uint32_t uValue)
1041{
1042 /* When affinity routing is enabled, writes to SGIs and PPIs are ignored. */
1043 Assert(pGicDev->fAffRoutingEnabled);
1044 if (idxReg > 0)
1045 {
1046 Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrPending));
1047 pGicDev->bmIntrPending[idxReg] &= ~uValue;
1048 return gicDistUpdateIrqState(pVM, pGicDev);
1049 }
1050 else
1051 AssertReleaseFailed();
1052 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicDev->bmIntrPending[idxReg]));
1053 return VINF_SUCCESS;
1054}
1055
1056
1057/**
1058 * Reads the distributor's interrupt config register (GICD_ICFGR).
1059 *
1060 * @returns Strict VBox status code.
1061 * @param pGicDev The GIC distributor state.
1062 * @param idxReg The index of the register in the GICD_ICFGR range.
1063 * @param puValue Where to store the register's value.
1064 */
1065static VBOXSTRICTRC gicDistReadIntrConfigReg(PCGICDEV pGicDev, uint16_t idxReg, uint32_t *puValue)
1066{
1067 /* SGIs are read-only and are always edge-triggered. */
1068 if (idxReg > 0)
1069 {
1070 Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrConfig));
1071 *puValue = pGicDev->bmIntrConfig[idxReg];
1072 }
1073 else
1074 *puValue = 0xaaaaaaaa;
1075 LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, pGicDev->bmIntrConfig[idxReg]));
1076 return VINF_SUCCESS;
1077}
1078
1079
1080/**
1081 * Writes the distributor's interrupt config register (GICD_ICFGR).
1082 *
1083 * @returns Strict VBox status code.
1084 * @param pGicDev The GIC distributor state.
1085 * @param idxReg The index of the register in the GICD_ICFGR range.
1086 * @param uValue The value to write to the register.
1087 */
1088static VBOXSTRICTRC gicDistWriteIntrConfigReg(PGICDEV pGicDev, uint16_t idxReg, uint32_t uValue)
1089{
1090 /* Writes to SGIs are ignored. */
1091 if (idxReg > 0)
1092 {
1093 Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrConfig));
1094 pGicDev->bmIntrConfig[idxReg] = uValue;
1095 }
1096 else
1097 AssertReleaseFailed();
1098 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicDev->bmIntrConfig[idxReg]));
1099 return VINF_SUCCESS;
1100}
1101
1102
1103/**
1104 * Reads the distributor's interrupt config register (GICD_IGROUPR).
1105 *
1106 * @returns Strict VBox status code.
1107 * @param pGicDev The GIC distributor state.
1108 * @param idxReg The index of the register in the GICD_IGROUPR range.
1109 * @param puValue Where to store the register's value.
1110 */
1111static VBOXSTRICTRC gicDistReadIntrGroupReg(PGICDEV pGicDev, uint16_t idxReg, uint32_t *puValue)
1112{
1113 /* When affinity routing is enabled, reads to SGIs and PPIs return 0. */
1114 Assert(pGicDev->fAffRoutingEnabled);
1115 if (idxReg > 0)
1116 {
1117 Assert(idxReg < RT_ELEMENTS(pGicDev->bmIntrGroup));
1118 *puValue = pGicDev->bmIntrGroup[idxReg];
1119 LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, *puValue));
1120 }
1121 else
1122 AssertReleaseFailed();
1123 return VINF_SUCCESS;
1124}
1125
1126
1127/**
1128 * Writes the distributor's interrupt config register (GICD_ICFGR).
1129 *
1130 * @returns Strict VBox status code.
1131 * @param pVM The cross context VM structure.
1132 * @param pGicDev The GIC distributor state.
1133 * @param idxReg The index of the register in the GICD_ICFGR range.
1134 * @param uValue The value to write to the register.
1135 */
1136static VBOXSTRICTRC gicDistWriteIntrGroupReg(PCVM pVM, PGICDEV pGicDev, uint16_t idxReg, uint32_t uValue)
1137{
1138 /* When affinity routing is enabled, writes to SGIs and PPIs are ignored. */
1139 Assert(pGicDev->fAffRoutingEnabled);
1140 if (idxReg > 0)
1141 {
1142 pGicDev->bmIntrGroup[idxReg] = uValue;
1143 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicDev->bmIntrGroup[idxReg]));
1144 }
1145 else
1146 AssertReleaseFailed();
1147 return gicDistUpdateIrqState(pVM, pGicDev);
1148}
1149
1150
1151/**
1152 * Reads the redistributor's interrupt priority register (GICR_IPRIORITYR).
1153 *
1154 * @returns Strict VBox status code.
1155 * @param pGicDev The GIC distributor state.
1156 * @param pGicCpu The GIC redistributor and CPU interface state.
1157 * @param idxReg The index of the register in the GICR_IPRIORITY range.
1158 * @param puValue Where to store the register's value.
1159 */
1160static VBOXSTRICTRC gicReDistReadIntrPriorityReg(PCGICDEV pGicDev, PGICCPU pGicCpu, uint16_t idxReg, uint32_t *puValue)
1161{
1162 /* When affinity routing is disabled, reads return 0. */
1163 Assert(pGicDev->fAffRoutingEnabled); RT_NOREF(pGicDev);
1164 uint16_t const idxPriority = idxReg * sizeof(uint32_t);
1165 AssertReturn(idxPriority < RT_ELEMENTS(pGicCpu->abIntrPriority) - sizeof(uint32_t), VERR_BUFFER_OVERFLOW);
1166 AssertCompile(sizeof(*puValue) == sizeof(uint32_t));
1167 *puValue = *(uint32_t *)&pGicCpu->abIntrPriority[idxPriority];
1168 LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, *puValue));
1169 return VINF_SUCCESS;
1170}
1171
1172
1173/**
1174 * Writes the redistributor's interrupt priority register (GICR_IPRIORITYR).
1175 *
1176 * @returns Strict VBox status code.
1177 * @param pGicDev The GIC distributor state.
1178 * @param pVCpu The cross context virtual CPU structure.
1179 * @param idxReg The index of the register in the GICR_IPRIORITY range.
1180 * @param uValue The value to write to the register.
1181 */
1182static VBOXSTRICTRC gicReDistWriteIntrPriorityReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint16_t idxReg, uint32_t uValue)
1183{
1184 /* When affinity routing is disabled, writes are ignored. */
1185 Assert(pGicDev->fAffRoutingEnabled); RT_NOREF(pGicDev);
1186 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
1187 uint16_t const idxPriority = idxReg * sizeof(uint32_t);
1188 AssertReturn(idxPriority < RT_ELEMENTS(pGicCpu->abIntrPriority) - sizeof(uint32_t), VERR_BUFFER_OVERFLOW);
1189 AssertCompile(sizeof(uValue) == sizeof(uint32_t));
1190 *(uint32_t *)&pGicCpu->abIntrPriority[idxPriority] = uValue;
1191 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, *(uint32_t *)&pGicCpu->abIntrPriority[idxPriority]));
1192 return VINF_SUCCESS;
1193}
1194
1195
1196/**
1197 * Reads the redistributor's interrupt pending register (GICR_ISPENDR and
1198 * GICR_ICPENDR).
1199 *
1200 * @returns Strict VBox status code.
1201 * @param pGicDev The GIC distributor state.
1202 * @param pGicCpu The GIC redistributor and CPU interface state.
1203 * @param idxReg The index of the register in the GICR_ISPENDR and
1204 * GICR_ICPENDR range.
1205 * @param puValue Where to store the register's value.
1206 */
1207static VBOXSTRICTRC gicReDistReadIntrPendingReg(PCGICDEV pGicDev, PGICCPU pGicCpu, uint16_t idxReg, uint32_t *puValue)
1208{
1209 /* When affinity routing is disabled, reads return 0. */
1210 Assert(pGicDev->fAffRoutingEnabled); RT_NOREF(pGicDev);
1211 Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrPending));
1212 *puValue = pGicCpu->bmIntrPending[idxReg];
1213 LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, pGicCpu->bmIntrPending[idxReg]));
1214 return VINF_SUCCESS;
1215}
1216
1217
1218/**
1219 * Writes the redistributor's interrupt set-pending register (GICR_ISPENDR).
1220 *
1221 * @returns Strict VBox status code.
1222 * @param pGicDev The GIC distributor state.
1223 * @param pVCpu The cross context virtual CPU structure.
1224 * @param idxReg The index of the register in the GICR_ISPENDR range.
1225 * @param uValue The value to write to the register.
1226 */
1227static VBOXSTRICTRC gicReDistWriteIntrSetPendingReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint16_t idxReg, uint32_t uValue)
1228{
1229 /* When affinity routing is disabled, writes are ignored. */
1230 Assert(pGicDev->fAffRoutingEnabled);
1231 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
1232 Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrPending));
1233 pGicCpu->bmIntrPending[idxReg] |= uValue;
1234 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicCpu->bmIntrPending[idxReg]));
1235 return gicReDistUpdateIrqState(pGicDev, pVCpu);
1236}
1237
1238
1239/**
1240 * Writes the redistributor's interrupt clear-pending register (GICR_ICPENDR).
1241 *
1242 * @returns Strict VBox status code.
1243 * @param pGicDev The GIC distributor state.
1244 * @param pVCpu The cross context virtual CPU structure.
1245 * @param idxReg The index of the register in the GICR_ICPENDR range.
1246 * @param uValue The value to write to the register.
1247 */
1248static VBOXSTRICTRC gicReDistWriteIntrClearPendingReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint16_t idxReg, uint32_t uValue)
1249{
1250 /* When affinity routing is disabled, writes are ignored. */
1251 Assert(pGicDev->fAffRoutingEnabled);
1252 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
1253 Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrPending));
1254 pGicCpu->bmIntrPending[idxReg] &= ~uValue;
1255 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicCpu->bmIntrPending[idxReg]));
1256 return gicReDistUpdateIrqState(pGicDev, pVCpu);
1257}
1258
1259
1260/**
1261 * Reads the redistributor's interrupt enable register (GICR_ISENABLER and
1262 * GICR_ICENABLER).
1263 *
1264 * @returns Strict VBox status code.
1265 * @param pGicDev The GIC distributor state.
1266 * @param pGicCpu The GIC redistributor and CPU interface state.
1267 * @param idxReg The index of the register in the GICR_ISENABLER and
1268 * GICR_ICENABLER range.
1269 * @param puValue Where to store the register's value.
1270 */
1271static VBOXSTRICTRC gicReDistReadIntrEnableReg(PCGICDEV pGicDev, PGICCPU pGicCpu, uint16_t idxReg, uint32_t *puValue)
1272{
1273 Assert(pGicDev->fAffRoutingEnabled); RT_NOREF(pGicDev);
1274 Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrEnabled));
1275 *puValue = pGicCpu->bmIntrEnabled[idxReg];
1276 LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, pGicCpu->bmIntrEnabled[idxReg]));
1277 return VINF_SUCCESS;
1278}
1279
1280
1281/**
1282 * Writes the redistributor's interrupt set-enable register (GICR_ISENABLER).
1283 *
1284 * @returns Strict VBox status code.
1285 * @param pGicDev The GIC distributor state.
1286 * @param pVCpu The cross context virtual CPU structure.
1287 * @param idxReg The index of the register in the GICR_ISENABLER range.
1288 * @param uValue The value to write to the register.
1289 */
1290static VBOXSTRICTRC gicReDistWriteIntrSetEnableReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint16_t idxReg, uint32_t uValue)
1291{
1292 Assert(pGicDev->fAffRoutingEnabled);
1293 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
1294 Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrEnabled));
1295 pGicCpu->bmIntrEnabled[idxReg] |= uValue;
1296 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicCpu->bmIntrEnabled[idxReg]));
1297 return gicReDistUpdateIrqState(pGicDev, pVCpu);
1298}
1299
1300
1301/**
1302 * Writes the redistributor's interrupt clear-enable register (GICR_ICENABLER).
1303 *
1304 * @returns Strict VBox status code.
1305 * @param pGicDev The GIC distributor state.
1306 * @param pVCpu The cross context virtual CPU structure.
1307 * @param idxReg The index of the register in the GICR_ICENABLER range.
1308 * @param uValue The value to write to the register.
1309 */
1310static VBOXSTRICTRC gicReDistWriteIntrClearEnableReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint16_t idxReg, uint32_t uValue)
1311{
1312 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
1313 Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrEnabled));
1314 pGicCpu->bmIntrEnabled[idxReg] &= ~uValue;
1315 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicCpu->bmIntrEnabled[idxReg]));
1316 return gicReDistUpdateIrqState(pGicDev, pVCpu);
1317}
1318
1319
1320/**
1321 * Reads the redistributor's interrupt active register (GICR_ISACTIVER and
1322 * GICR_ICACTIVER).
1323 *
1324 * @returns Strict VBox status code.
1325 * @param pGicCpu The GIC redistributor and CPU interface state.
1326 * @param idxReg The index of the register in the GICR_ISACTIVER and
1327 * GICR_ICACTIVER range.
1328 * @param puValue Where to store the register's value.
1329 */
1330static VBOXSTRICTRC gicReDistReadIntrActiveReg(PGICCPU pGicCpu, uint16_t idxReg, uint32_t *puValue)
1331{
1332 Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrActive));
1333 *puValue = pGicCpu->bmIntrActive[idxReg];
1334 LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, pGicCpu->bmIntrActive[idxReg]));
1335 return VINF_SUCCESS;
1336}
1337
1338
1339/**
1340 * Writes the redistributor's interrupt set-active register (GICR_ISACTIVER).
1341 *
1342 * @returns Strict VBox status code.
1343 * @param pGicDev The GIC distributor state.
1344 * @param pVCpu The cross context virtual CPU structure.
1345 * @param idxReg The index of the register in the GICR_ISACTIVER range.
1346 * @param uValue The value to write to the register.
1347 */
1348static VBOXSTRICTRC gicReDistWriteIntrSetActiveReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint16_t idxReg, uint32_t uValue)
1349{
1350 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
1351 Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrActive));
1352 pGicCpu->bmIntrActive[idxReg] |= uValue;
1353 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicCpu->bmIntrActive[idxReg]));
1354 return gicReDistUpdateIrqState(pGicDev, pVCpu);
1355}
1356
1357
1358/**
1359 * Writes the redistributor's interrupt clear-active register (GICR_ICACTIVER).
1360 *
1361 * @returns Strict VBox status code.
1362 * @param pGicDev The GIC distributor state.
1363 * @param pVCpu The cross context virtual CPU structure.
1364 * @param idxReg The index of the register in the GICR_ICACTIVER range.
1365 * @param uValue The value to write to the register.
1366 */
1367static VBOXSTRICTRC gicReDistWriteIntrClearActiveReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint16_t idxReg, uint32_t uValue)
1368{
1369 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
1370 Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrActive));
1371 pGicCpu->bmIntrActive[idxReg] &= ~uValue;
1372 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicCpu->bmIntrActive[idxReg]));
1373 return gicReDistUpdateIrqState(pGicDev, pVCpu);
1374}
1375
1376
1377/**
1378 * Reads the redistributor's interrupt config register (GICR_ICFGR).
1379 *
1380 * @returns Strict VBox status code.
1381 * @param pGicDev The GIC distributor state.
1382 * @param pGicCpu The GIC redistributor and CPU interface state.
1383 * @param idxReg The index of the register in the GICR_ICFGR range.
1384 * @param puValue Where to store the register's value.
1385 */
1386static VBOXSTRICTRC gicReDistReadIntrConfigReg(PCGICDEV pGicDev, PGICCPU pGicCpu, uint16_t idxReg, uint32_t *puValue)
1387{
1388 /* When affinity routing is disabled, reads return 0. */
1389 Assert(pGicDev->fAffRoutingEnabled); RT_NOREF(pGicDev);
1390 if (idxReg > 0)
1391 {
1392 Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrConfig));
1393 *puValue = pGicCpu->bmIntrConfig[idxReg];
1394 }
1395 else
1396 {
1397 /* SGIs are read-only and are always edge-triggered. */
1398 *puValue = 0xaaaaaaaa;
1399 }
1400 LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, *puValue));
1401 return VINF_SUCCESS;
1402}
1403
1404
1405/**
1406 * Writes the redistributor's interrupt config register (GICR_ICFGR).
1407 *
1408 * @returns Strict VBox status code.
1409 * @param pGicDev The GIC distributor state.
1410 * @param pVCpu The cross context virtual CPU structure.
1411 * @param idxReg The index of the register in the GICR_ICFGR range.
1412 * @param uValue The value to write to the register.
1413 */
1414static VBOXSTRICTRC gicReDistWriteIntrConfigReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint16_t idxReg, uint32_t uValue)
1415{
1416 /* When affinity routing is disabled, writes are ignored. */
1417 Assert(pGicDev->fAffRoutingEnabled); RT_NOREF(pGicDev);
1418 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
1419 if (idxReg > 0)
1420 {
1421 Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrConfig));
1422 pGicCpu->bmIntrConfig[idxReg] = uValue;
1423 }
1424 else
1425 {
1426 /* SGIs are always edge triggered ignore writes, verify value on strict builds (e.g. aarch64 Win11 writes this). */
1427 Assert(uValue == 0xaaaaaaaa);
1428 Assert(pGicCpu->bmIntrConfig[0] == uValue);
1429 }
1430 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicCpu->bmIntrConfig[idxReg]));
1431 return VINF_SUCCESS;
1432}
1433
1434
1435/**
1436 * Reads the redistributor's interrupt group register (GICD_IGROUPR).
1437 *
1438 * @returns Strict VBox status code.
1439 * @param pGicDev The GIC distributor state.
1440 * @param pGicCpu The GIC redistributor and CPU interface state.
1441 * @param idxReg The index of the register in the GICR_IGROUPR range.
1442 * @param puValue Where to store the register's value.
1443 */
1444static VBOXSTRICTRC gicReDistReadIntrGroupReg(PCGICDEV pGicDev, PGICCPU pGicCpu, uint16_t idxReg, uint32_t *puValue)
1445{
1446 /* When affinity routing is disabled, reads return 0. */
1447 Assert(pGicDev->fAffRoutingEnabled); RT_NOREF(pGicDev);
1448 Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrGroup));
1449 *puValue = pGicCpu->bmIntrGroup[idxReg];
1450 LogFlowFunc(("idxReg=%#x read %#x\n", idxReg, pGicCpu->bmIntrGroup[idxReg]));
1451 return VINF_SUCCESS;
1452}
1453
1454
1455/**
1456 * Writes the redistributor's interrupt group register (GICR_IGROUPR).
1457 *
1458 * @returns Strict VBox status code.
1459 * @param pGicDev The GIC distributor state.
1460 * @param pVCpu The cross context virtual CPU structure.
1461 * @param idxReg The index of the register in the GICR_IGROUPR range.
1462 * @param uValue The value to write to the register.
1463 */
1464static VBOXSTRICTRC gicReDistWriteIntrGroupReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint16_t idxReg, uint32_t uValue)
1465{
1466 /* When affinity routing is disabled, writes are ignored. */
1467 Assert(pGicDev->fAffRoutingEnabled);
1468 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
1469 Assert(idxReg < RT_ELEMENTS(pGicCpu->bmIntrGroup));
1470 pGicCpu->bmIntrGroup[idxReg] = uValue;
1471 LogFlowFunc(("idxReg=%#x written %#x\n", idxReg, pGicCpu->bmIntrGroup[idxReg]));
1472 return gicReDistUpdateIrqState(pGicDev, pVCpu);
1473}
1474
1475
1476#if 0
1477/**
1478 * Gets the IDB index for a given interrupt ID.
1479 *
1480 * @returns UINT16_MAX is the interrupt ID is invalid or does not map to an index,
1481 * otherwise returns a valid index.
1482 * @param uIntId The interrupt ID.
1483 */
1484static uint16_t gicIntIdToIdbIndex(uint16_t uIntId)
1485{
1486 /*
1487 * Interrupt Delivery Bitmap (IDB) format; bits to interrupt ID mapping:
1488 * +---------------------------------------------------------------------+
1489 * | Incl ranges | SGI | PPI | SPI | Ext PPI | Ext SPI |
1490 * +---------------------------------------------------------------------+
1491 * | Int Id | 0..15 | 16..31 | 32..1019 | 1056..1119 | 4096..5119 |
1492 * | Bit Index | 0..15 | 16..31 | 32..1019 | 1020..1083 | 1084..2107 |
1493 * +---------------------------------------------------------------------+
1494 */
1495 uint16_t const idxIdb;
1496 if (uIntId <= GIC_INTID_RANGE_SPI_LAST)
1497 return uIntId;
1498 if (uIntId - GIC_INTID_RANGE_EXT_PPI_START < GIC_INTID_RANGE_EXT_PPI_RANGE_SIZE)
1499 return GIC_INTID_RANGE_EXT_PPI_START + uIntId - GIC_INTID_RANGE_EXT_PPI_START;
1500 if (uIntId - GIC_INTID_RANGE_EXT_SPI_START < GIC_INTID_RANGE_EXT_SPI_RANGE_SIZE)
1501 return GIC_INTID_RANGE_EXT_SPI_START + uIntId - GIC_INTID_RANGE_EXT_SPI_START;
1502 return UINT16_MAX;
1503}
1504
1505static bool gicIsIntIdValid(uint16_t uIntId)
1506{
1507 if (uIntId <= GIC_INTID_RANGE_SPI_LAST)
1508 return true;
1509 if (uIntIt - GIC_INTID_RANGE_EXT_PPI_START < GIC_INTID_RANGE_EXT_PPI_RANGE_SIZE)
1510 return true;
1511 if (uIntIt - GIC_INTID_RANGE_EXT_SPI_START < GIC_INTID_RANGE_EXT_SPI_RANGE_SIZE)
1512 return true;
1513 return false;
1514}
1515
1516
1517static void gicSetIdxInIdb(PGICIDB pGicIdb, uint16_t idxIdb)
1518{
1519 if (RT_LIKELY(idxIdb < sizeof(pGicIdb->au64IntIdBitmap) * 8))
1520 ASMAtomicBitSet(&pGicIdb->au64IntIdBitmap[0], idxIdb);
1521 else
1522 AssertMsgFailed(("Invalid IDB index %u for INTID %u\n" idxIdb, uIntId));
1523}
1524
1525
1526/**
1527 * Sets an interrupt ID in an Interrupt-Delivery Bitmap (IDB).
1528 *
1529 * @param pGicIdb Pointer to the IDB.
1530 * @param uIntId The interrupt ID.
1531 */
1532static void gicSetIntIdInIdb(PGICIDB pGicIdb, uint16_t uIntId)
1533{
1534 uint16_t const idxIdb = gicIntIdToIdbIndex(uIntId);
1535 gicSetIdxInIdb(pGicIdb, idxIdb);
1536}
1537
1538
1539/**
1540 * Clears an interrupt ID in an Interrupt-Delivery Bitmap (IDB).
1541 *
1542 * @param pGicIdb Pointer to the IDB.
1543 * @param uIntId The interrupt ID.
1544 */
1545static void gicClearIntIdInIdb(PGICIDB pGicIdb, uint16_t uIntId)
1546{
1547 uint16_t const idxIdb = gicIntIdToIdbIndex(uIntId);
1548 if (RT_LIKELY(idxIdb < sizeof(pGicIdb->au64IntIdBitmap) * 8))
1549 ASMAtomicBitClear(&pGicIdb->au64IntIdBitmap[0], idxIdb);
1550 else
1551 AssertMsgFailed(("Invalid IDB index %u for INTID %u\n" idxIdb, uIntId));
1552}
1553
1554
1555/**
1556 * Atomically sets the IDB notification bit.
1557 *
1558 * @returns non-zero if the bit was already set, 0 otherwise.
1559 * @param pGicIdb Pointer to the IDB.
1560 */
1561static uint32_t gicSetNotificationBitInIdb(PGICIDB pGicIdb)
1562{
1563 return ASMAtomicXchgU32(&pGicIdb->fOutstandingNotification, RT_BIT_32(31));
1564}
1565
1566
1567/**
1568 * Atomically tests and clears the IDB notification bit.
1569 *
1570 * @returns non-zero if the bit was already set, 0 otherwise.
1571 * @param pGicIdb Pointer to the IDB.
1572 */
1573static uint32_t gicClearNotificationBitInIdb(PGICIDB pGicIdb)
1574{
1575 return ASMAtomicXchgU32(&pGicIdb->fOutstandingNotification, UINT32_C(0));
1576}
1577
1578
1579static VBOXSTRICTRC gicPostInterrupt(PVMCPUCC pVCpu, PVMCPUSET pCpuSet, uint16_t idxIdb)
1580{
1581 Assert(gicIntIdToIdbIndex(idxIdb) != UINT16_MAX);
1582 for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
1583 {
1584 if (VMCPUSET_IS_PRESENT(&DestCpuSet, idCpu))
1585 {
1586 PVMCPUCC pTargetVCpu = pVCpu->pVMR3->CTX_SUFF(apCpus)[idCpu];
1587 VMCPU_ASSERT_VALID_EXT_RETURN(pVCpu, VERR_INVALID_HANDLE);
1588
1589 PGICCPU pTargetGicCpu = VMCPU_TO_GICCPU(pTargetVCpu);
1590 PGICIDB pTargetGicIdb = &pTargetGicCpu->IntrDeliveryBitmap;
1591 gicSetIdxInIdb(pTargetGicIdb, idxIdb);
1592 uint32_t const fAlreadySet = gicSetNotificationBitInIdb(pTargetGicIdb);
1593 if (!fAlreadySet)
1594 gicSetUpdateInterruptFF(pVCpu);
1595 }
1596 }
1597}
1598#endif
1599
1600
1601/**
1602 * Gets the virtual CPUID given the affinity values.
1603 *
1604 * @returns The virtual CPUID.
1605 * @param idCpuInterface The virtual CPUID within the PE cluster (0..15).
1606 * @param uAff1 The affinity 1 value.
1607 * @param uAff2 The affinity 2 value.
1608 * @param uAff3 The affinity 3 value.
1609 */
1610DECL_FORCE_INLINE(VMCPUID) gicGetCpuIdFromAffinity(uint8_t idCpuInterface, uint8_t uAff1, uint8_t uAff2, uint8_t uAff3)
1611{
1612 AssertReturn(idCpuInterface < 16, 0);
1613 return (uAff3 * 1048576) + (uAff2 * 4096) + (uAff1 * 16) + idCpuInterface;
1614}
1615
1616
1617#if 0
1618/**
1619 * @interface_method_impl{PDMGICBACKEND,pfnUpdatePendingInterrupts}
1620 */
1621static DECLCALLBACK(void) gicUpdatePendingInterrupts(PVMCPUCC pVCpu)
1622{
1623 VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu);
1624
1625 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
1626
1627 /*
1628 * Delivery interrupts pending in the interrupt-delivery bitmap to the PE.
1629 */
1630 bool fHasPendingIntrs = false;
1631 PGICIDB pIdb = (PGICIDB)pGicCpu->IntrDeliveryBitmap;
1632 for (;;)
1633 {
1634 uint32_t const fAlreadySet = gicClearNotificationBitInIdb(pIdb);
1635 if (!fAlreadySet)
1636 break;
1637
1638 /* SGI and PPIs */
1639 uint32_t const uSgiPpi = ASMAtomicXchgU32(&pIdb->au64IntIdBitmap[0], 0);
1640 if (uSgiPpi)
1641
1642 }
1643
1644 STAM_PROFILE_STOP(&pApicCpu->StatUpdatePendingIntrs, a);
1645 Log3(("APIC%u: apicUpdatePendingInterrupts: fHasPendingIntrs=%RTbool\n", pVCpu->idCpu, fHasPendingIntrs));
1646
1647 if ( fHasPendingIntrs
1648 && !VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC))
1649 apicSignalNextPendingIntr(pVCpu);
1650}
1651#endif
1652
1653
1654/**
1655 * Gets the highest priority pending distributor interrupt that can be forwarded to
1656 * the redistributor.
1657 *
1658 * @returns The interrupt ID or GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT if no interrupt
1659 * is pending or not in a state to be forwarded to the redistributor.
1660 * @param pGicDev The GIC distributor state.
1661 * @param fGroup0 Whether to consider group 0 interrupts.
1662 * @param fGroup1 Whether to consider group 1 interrupts.
1663 * @param pidxIntr Where to store the distributor interrupt index for the
1664 * returned interrupt ID. UINT16_MAX if this function returns
1665 * GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT. Optional, can be
1666 * NULL.
1667 * @param pbPriority Where to store the priority of the returned interrupt ID.
1668 * UINT8_MAX if this function returns
1669 * GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT.
1670 */
1671static uint16_t gicDistGetHighestPrioPendingIntr(PCGICDEV pGicDev, bool fGroup0, bool fGroup1, uint16_t *pidxIntr,
1672 uint8_t *pbPriority)
1673{
1674 /*
1675 * Figure out the highest priority pending interrupt in the distributor.
1676 * We can skip SGIs, PPIs in the distributor as we don't support legacy operation.
1677 *
1678 * See ARM GIC spec. 4.7.2 "Interaction of group and individual interrupt enables".
1679 * See ARM GIC spec. 1.3.5 "GICv3 with no legacy operation".
1680 */
1681 Assert(pGicDev->fAffRoutingEnabled);
1682 uint32_t bmIntrPending[64]; /** @todo SGIs, PPIs: iterate from 1 and initialize bmIntrPending[0] = 0. */
1683 for (uint8_t i = 0; i < RT_ELEMENTS(bmIntrPending); i++)
1684 {
1685 /* Collect interrupts that are pending, enabled and inactive. */
1686 bmIntrPending[i] = (pGicDev->bmIntrPending[i] & pGicDev->bmIntrEnabled[i]) & ~pGicDev->bmIntrActive[i];
1687
1688 /* Discard interrupts if the group they belong to is disabled. */
1689 if (!fGroup1)
1690 bmIntrPending[i] &= ~pGicDev->bmIntrGroup[i];
1691 if (!fGroup0)
1692 bmIntrPending[i] &= pGicDev->bmIntrGroup[i];
1693 }
1694
1695 /* Among the collected interrupts, pick the one with the highest priority. */
1696 uint16_t uIntId = GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT;
1697 uint16_t idxHighest = UINT16_MAX;
1698 uint16_t uPriority = UINT16_MAX;
1699 void const *pvIntrs = &bmIntrPending[0];
1700 uint32_t const cIntrs = sizeof(bmIntrPending) * 8;
1701 int32_t idxIntr = ASMBitFirstSet(pvIntrs, cIntrs);
1702 AssertCompile(!(cIntrs % 32));
1703 if (idxIntr >= 0)
1704 {
1705 Assert(idxIntr >= 32); /* We don't support legacy operation. */
1706 do
1707 {
1708 Assert((uint32_t)idxIntr < RT_ELEMENTS(pGicDev->abIntrPriority));
1709 if ((uint16_t)pGicDev->abIntrPriority[idxIntr] < uPriority)
1710 {
1711 idxHighest = (uint16_t)idxIntr;
1712 uPriority = pGicDev->abIntrPriority[idxIntr];
1713 uIntId = gicDistGetIntIdFromIndex(idxIntr);
1714 }
1715 idxIntr = ASMBitNextSet(pvIntrs, cIntrs, idxIntr);
1716 } while (idxIntr != -1);
1717 }
1718
1719 *pbPriority = uPriority;
1720 if (pidxIntr)
1721 *pidxIntr = idxHighest;
1722
1723 /* Sanity check if the interrupt ID is within known ranges. */
1724 Assert( GIC_IS_INTR_SPI(uIntId)
1725 || GIC_IS_INTR_EXT_PPI(uIntId)
1726 || GIC_IS_INTR_EXT_SPI(uIntId)
1727 || uIntId == GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT);
1728 /* Ensure that if no interrupt is pending, the priority is appropriate. */
1729 Assert(uIntId != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT || *pbPriority == UINT8_MAX);
1730
1731 LogFlowFunc(("uIntId=%u [idxIntr=%u uPriority=%u]\n", uIntId, idxIntr, uPriority));
1732 return uIntId;
1733}
1734
1735
1736/**
1737 * Gets the highest priority pending redistributor interrupt that can be signalled
1738 * to the PE.
1739 *
1740 * @returns The interrupt ID or GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT if no interrupt
1741 * is pending or not in a state to be signalled to the PE.
1742 * @param pGicCpu The GIC redistributor and CPU interface state.
1743 * @param fGroup0 Whether to consider group 0 interrupts.
1744 * @param fGroup1 Whether to consider group 1 interrupts.
1745 * @param pidxIntr Where to store the distributor interrupt index for the
1746 * returned interrupt ID. UINT16_MAX if this function returns
1747 * GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT. Optional, can be
1748 * NULL.
1749 * @param pbPriority Where to store the priority of the returned interrupt ID.
1750 * UINT8_MAX if this function returns
1751 * GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT.
1752 */
1753static uint16_t gicReDistGetHighestPrioPendingIntr(PCGICCPU pGicCpu, bool fGroup0, bool fGroup1, uint16_t *pidxIntr,
1754 uint8_t *pbPriority)
1755{
1756 /*
1757 * Figure out the highest priority pending interrupt in the redistributor.
1758 * See ARM GIC spec. 4.7.2 "Interaction of group and individual interrupt enables".
1759 */
1760 uint32_t bmIntrPending[3];
1761 for (uint8_t i = 0 ; i < RT_ELEMENTS(bmIntrPending); i++)
1762 {
1763 /* Collect interrupts that are pending, enabled and inactive. */
1764 bmIntrPending[i] = (pGicCpu->bmIntrPending[i] & pGicCpu->bmIntrEnabled[i]) & ~pGicCpu->bmIntrActive[i];
1765
1766 /* Discard interrupts if the group they belong to is disabled. */
1767 if (!fGroup1)
1768 bmIntrPending[i] &= ~pGicCpu->bmIntrGroup[i];
1769 if (!fGroup0)
1770 bmIntrPending[i] &= pGicCpu->bmIntrGroup[i];
1771 }
1772
1773 /* Among the collected interrupts, pick the one with the highest priority. */
1774 uint16_t uIntId = GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT;
1775 uint16_t idxHighest = UINT16_MAX;
1776 uint16_t uPriority = UINT16_MAX;
1777 const void *pvIntrs = &bmIntrPending[0];
1778 uint32_t const cIntrs = sizeof(bmIntrPending) * 8;
1779 int32_t idxIntr = ASMBitFirstSet(pvIntrs, cIntrs);
1780 AssertCompile(!(cIntrs % 32));
1781 if (idxIntr >= 0)
1782 {
1783 do
1784 {
1785 Assert((uint32_t)idxIntr < RT_ELEMENTS(pGicCpu->abIntrPriority));
1786 if ((uint16_t)pGicCpu->abIntrPriority[idxIntr] < uPriority)
1787 {
1788 idxHighest = (uint16_t)idxIntr;
1789 uPriority = pGicCpu->abIntrPriority[idxIntr];
1790 uIntId = gicReDistGetIntIdFromIndex(idxIntr);
1791 }
1792 idxIntr = ASMBitNextSet(pvIntrs, cIntrs, idxIntr);
1793 } while (idxIntr != -1);
1794 }
1795
1796 *pbPriority = uPriority;
1797 if (pidxIntr)
1798 *pidxIntr = idxHighest;
1799
1800 /* Sanity check if the interrupt ID is within known ranges. */
1801 Assert( GIC_IS_INTR_SGI_OR_PPI(uIntId)
1802 || GIC_IS_INTR_EXT_PPI(uIntId)
1803 || uIntId == GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT);
1804 /* Ensure that if no interrupt is pending, the priority is appropriate. */
1805 Assert(uIntId != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT || *pbPriority == UINT8_MAX);
1806
1807 LogFlowFunc(("uIntId=%u [idxIntr=%u uPriority=%u]\n", uIntId, idxIntr, uPriority));
1808 return uIntId;
1809}
1810
1811
1812/**
1813 * Gets the highest priority pending interrupt that can be signalled to the PE.
1814 *
1815 * @returns The interrupt ID or GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT if no interrupt
1816 * is pending or not in a state to be signalled to the PE.
1817 * @param pVM The cross context VM state.
1818 * @param pGicDev The GIC distributor state.
1819 * @param fGroup0 Whether to consider group 0 interrupts.
1820 * @param fGroup1 Whether to consider group 1 interrupts.
1821 */
1822static uint16_t gicGetHighestPrioPendingIntr(PCVM pVM, PCGICDEV pGicDev, bool fGroup0, bool fGroup1)
1823{
1824 /* Get highest priority pending interrupt from the distributor. */
1825 uint8_t bPriority;
1826 uint16_t uIntId = gicDistGetHighestPrioPendingIntr(pGicDev, fGroup0, fGroup1, NULL /*pidxIntr*/, &bPriority);
1827
1828 /* Compare with the highest priority pending interrupt from each redistributor. */
1829 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1830 {
1831 PCVMCPUCC pVCpu = pVM->CTX_SUFF(apCpus)[idCpu];
1832 PCGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
1833
1834 uint8_t bPriorityRedist;
1835 uint16_t const uIntIdRedist = gicReDistGetHighestPrioPendingIntr(pGicCpu, fGroup0, fGroup1, NULL /*pidxIntr*/,
1836 &bPriorityRedist);
1837 if ( uIntIdRedist != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT
1838 && bPriorityRedist < bPriority)
1839 {
1840 bPriority = bPriorityRedist;
1841 uIntId = uIntIdRedist;
1842 }
1843 }
1844
1845 /* Sanity check if the interrupt ID is within known ranges. */
1846 Assert( GIC_IS_INTR_SGI_OR_PPI(uIntId)
1847 || GIC_IS_INTR_SPI(uIntId)
1848 || GIC_IS_INTR_EXT_PPI(uIntId)
1849 || GIC_IS_INTR_EXT_SPI(uIntId)
1850 || uIntId == GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT);
1851 /* Ensure that if no interrupt is pending, the priority is appropriate. */
1852 Assert(uIntId != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT || bPriority == UINT8_MAX);
1853
1854 LogFlowFunc(("uIntId=%u [bPriority=%u]\n", uIntId, bPriority));
1855 return uIntId;
1856}
1857
1858
1859/**
1860 * Get and acknowledge the interrupt ID of a signalled interrupt.
1861 *
1862 * @returns The interrupt ID or GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT no interrupts
1863 * are pending or not in a state to be signalled.
1864 * @param pGicDev The GIC distributor state.
1865 * @param pVCpu The cross context virtual CPU structure.
1866 * @param fGroup0 Whether to consider group 0 interrupts.
1867 * @param fGroup1 Whether to consider group 1 interrupts.
1868 */
1869static uint16_t gicAckHighestPrioPendingIntr(PGICDEV pGicDev, PVMCPUCC pVCpu, bool fGroup0, bool fGroup1)
1870{
1871 Assert(fGroup0 || fGroup1);
1872 LogFlowFunc(("fGroup0=%RTbool fGroup1=%RTbool\n", fGroup0, fGroup1));
1873
1874 /* Get highest priority pending interrupt from the distributor. */
1875 uint8_t bPriority;
1876 uint16_t idxIntr;
1877 uint16_t uIntId = gicDistGetHighestPrioPendingIntr(pGicDev, fGroup0, fGroup1, &idxIntr, &bPriority);
1878
1879 /* Compare with the highest priority pending interrupt from each redistributor. */
1880 bool fIntrInRedist = false;
1881 uint32_t const cCpus = pVCpu->CTX_SUFF(pVM)->cCpus;
1882 for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
1883 {
1884 PCVMCPUCC pVCpuCur = pVCpu->CTX_SUFF(pVM)->CTX_SUFF(apCpus)[idCpu];
1885 PCGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpuCur);
1886
1887 uint8_t bPriorityRedist;
1888 uint16_t idxRedistIntr;
1889 uint16_t const uIntIdRedist = gicReDistGetHighestPrioPendingIntr(pGicCpu, fGroup0, fGroup1, &idxRedistIntr,
1890 &bPriorityRedist);
1891 if ( uIntIdRedist != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT
1892 && bPriorityRedist < bPriority)
1893 {
1894 fIntrInRedist = true;
1895 bPriority = bPriorityRedist;
1896 uIntId = uIntIdRedist;
1897 idxIntr = idxRedistIntr;
1898 }
1899 }
1900
1901 /* Sanity check if the interrupt ID is within known ranges. */
1902 Assert( GIC_IS_INTR_SGI_OR_PPI(uIntId)
1903 || GIC_IS_INTR_SPI(uIntId)
1904 || GIC_IS_INTR_EXT_PPI(uIntId)
1905 || GIC_IS_INTR_EXT_SPI(uIntId)
1906 || uIntId == GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT);
1907 /* Ensure that if no interrupt is pending, the priority is appropriate. */
1908 Assert(uIntId != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT || bPriority == UINT8_MAX);
1909
1910 /* Acknowledge the interrupt. */
1911 if (uIntId != GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT)
1912 {
1913 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
1914 if (fIntrInRedist)
1915 {
1916 /* Mark the interrupt as active. */
1917 AssertMsg(idxIntr < sizeof(pGicCpu->bmIntrActive) * 8, ("idxIntr=%u\n", idxIntr));
1918 ASMBitSet(&pGicCpu->bmIntrActive[0], idxIntr);
1919
1920 /* Drop priority. */
1921 Assert(pGicCpu->idxRunningPriority < RT_ELEMENTS(pGicCpu->abRunningPriorities) - 1);
1922
1923 LogFlowFunc(("Dropping interrupt priority from %u -> %u (idxRunningPriority: %u -> %u)\n",
1924 pGicCpu->abRunningPriorities[pGicCpu->idxRunningPriority],
1925 bPriority,
1926 pGicCpu->idxRunningPriority, pGicCpu->idxRunningPriority + 1));
1927 pGicCpu->abRunningPriorities[++pGicCpu->idxRunningPriority] = bPriority;
1928
1929 /* Clear edge level interrupts like SGIs as pending. */
1930 /** @todo do this for all edge-triggered? */
1931 if (idxIntr <= GIC_INTID_RANGE_SGI_LAST)
1932 ASMBitClear(&pGicCpu->bmIntrPending[0], idxIntr);
1933
1934 /* Update the redistributor IRQ state to reflect change in active interrupt. */
1935 gicReDistUpdateIrqState(pGicDev, pVCpu);
1936 }
1937 else
1938 {
1939 /* Mark the interrupt as active. */
1940 Assert(idxIntr < sizeof(pGicDev->bmIntrActive) * 8);
1941 ASMBitSet(&pGicDev->bmIntrActive[0], idxIntr);
1942
1943 /* Drop priority. */
1944 Assert(pGicCpu->idxRunningPriority < RT_ELEMENTS(pGicCpu->abRunningPriorities) - 1);
1945
1946 LogFlowFunc(("Dropping interrupt priority from %u -> %u (idxRunningPriority: %u -> %u)\n",
1947 pGicCpu->abRunningPriorities[pGicCpu->idxRunningPriority],
1948 bPriority,
1949 pGicCpu->idxRunningPriority, pGicCpu->idxRunningPriority + 1));
1950 pGicCpu->abRunningPriorities[++pGicCpu->idxRunningPriority] = bPriority;
1951
1952 /* Update the distributor IRQ state to reflect change in active interrupt. */
1953 gicDistUpdateIrqState(pVCpu->CTX_SUFF(pVM), pGicDev);
1954 }
1955 }
1956
1957 LogFlowFunc(("uIntId=%u\n", uIntId));
1958 return uIntId;
1959}
1960
1961
1962/**
1963 * Reads a distributor register.
1964 *
1965 * @returns VBox status code.
1966 * @param pDevIns The device instance.
1967 * @param pVCpu The cross context virtual CPU structure.
1968 * @param offReg The offset of the register being read.
1969 * @param puValue Where to store the register value.
1970 */
1971DECLINLINE(VBOXSTRICTRC) gicDistReadRegister(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t *puValue)
1972{
1973 VMCPU_ASSERT_EMT(pVCpu); RT_NOREF(pVCpu);
1974 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
1975 uint16_t const cbReg = sizeof(uint32_t);
1976
1977 /*
1978 * GICD_IGROUPR<n> and GICD_IGROUPR<n>E.
1979 */
1980 {
1981 if (offReg - GIC_DIST_REG_IGROUPRn_OFF_START < GIC_DIST_REG_IGROUPRn_RANGE_SIZE)
1982 {
1983 uint16_t const idxReg = (offReg - GIC_DIST_REG_IGROUPRn_OFF_START) / cbReg;
1984 return gicDistReadIntrGroupReg(pGicDev, idxReg, puValue);
1985 }
1986 if (offReg - GIC_DIST_REG_IGROUPRnE_OFF_START < GIC_DIST_REG_IGROUPRnE_RANGE_SIZE)
1987 {
1988 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrGroup) / 2;
1989 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_IGROUPRnE_OFF_START) / cbReg;
1990 return gicDistReadIntrGroupReg(pGicDev, idxReg, puValue);
1991 }
1992 }
1993
1994 /*
1995 * GICD_IROUTER<n> and GICD_IROUTER<n>E.
1996 */
1997 {
1998 if (offReg - GIC_DIST_REG_IROUTERn_OFF_START < GIC_DIST_REG_IROUTERn_RANGE_SIZE)
1999 {
2000 uint16_t const idxReg = (offReg - GIC_DIST_REG_IROUTERn_OFF_START) / cbReg;
2001 return gicDistReadIntrRoutingReg(pGicDev, idxReg, puValue);
2002 }
2003 if (offReg - GIC_DIST_REG_IROUTERnE_OFF_START < GIC_DIST_REG_IROUTERnE_RANGE_SIZE)
2004 {
2005 uint16_t const idxExt = RT_ELEMENTS(pGicDev->au32IntrRouting) / 2;
2006 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_IROUTERnE_OFF_START) / cbReg;
2007 return gicDistReadIntrRoutingReg(pGicDev, idxReg, puValue);
2008 }
2009 }
2010
2011 /*
2012 * GICD_ISENABLER<n> and GICD_ISENABLER<n>E.
2013 * GICD_ICENABLER<n> and GICD_ICENABLER<n>E.
2014 */
2015 {
2016 if (offReg - GIC_DIST_REG_ISENABLERn_OFF_START < GIC_DIST_REG_ISENABLERn_RANGE_SIZE)
2017 {
2018 uint16_t const idxReg = (offReg - GIC_DIST_REG_ISENABLERn_OFF_START) / cbReg;
2019 return gicDistReadIntrEnableReg(pGicDev, idxReg, puValue);
2020 }
2021 if (offReg - GIC_DIST_REG_ISENABLERnE_OFF_START < GIC_DIST_REG_ISENABLERnE_RANGE_SIZE)
2022 {
2023 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrEnabled) / 2;
2024 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ISENABLERnE_OFF_START) / cbReg;
2025 return gicDistReadIntrEnableReg(pGicDev, idxReg, puValue);
2026 }
2027
2028 if (offReg - GIC_DIST_REG_ICENABLERn_OFF_START < GIC_DIST_REG_ICENABLERn_RANGE_SIZE)
2029 {
2030 uint16_t const idxReg = (offReg - GIC_DIST_REG_ICENABLERn_OFF_START) / cbReg;
2031 return gicDistReadIntrEnableReg(pGicDev, idxReg, puValue);
2032 }
2033 if (offReg - GIC_DIST_REG_ICENABLERnE_OFF_START < GIC_DIST_REG_ICENABLERnE_RANGE_SIZE)
2034 {
2035 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrEnabled) / 2;
2036 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ICENABLERnE_OFF_START) / cbReg;
2037 return gicDistReadIntrEnableReg(pGicDev, idxReg, puValue);
2038 }
2039 }
2040
2041 /*
2042 * GICD_ISACTIVER<n> and GICD_ISACTIVER<n>E.
2043 * GICD_ICACTIVER<n> and GICD_ICACTIVER<n>E.
2044 */
2045 {
2046 if (offReg - GIC_DIST_REG_ISACTIVERn_OFF_START < GIC_DIST_REG_ISACTIVERn_RANGE_SIZE)
2047 {
2048 uint16_t const idxReg = (offReg - GIC_DIST_REG_ISACTIVERn_OFF_START) / cbReg;
2049 return gicDistReadIntrActiveReg(pGicDev, idxReg, puValue);
2050 }
2051 if (offReg - GIC_DIST_REG_ISACTIVERnE_OFF_START < GIC_DIST_REG_ISACTIVERnE_RANGE_SIZE)
2052 {
2053 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrActive) / 2;
2054 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ISACTIVERnE_OFF_START) / cbReg;
2055 return gicDistReadIntrActiveReg(pGicDev, idxReg, puValue);
2056 }
2057
2058 if (offReg - GIC_DIST_REG_ICACTIVERn_OFF_START < GIC_DIST_REG_ICACTIVERn_RANGE_SIZE)
2059 {
2060 uint16_t const idxReg = (offReg - GIC_DIST_REG_ICENABLERn_OFF_START) / cbReg;
2061 return gicDistReadIntrActiveReg(pGicDev, idxReg, puValue);
2062 }
2063 if (offReg - GIC_DIST_REG_ICACTIVERnE_OFF_START < GIC_DIST_REG_ICACTIVERnE_RANGE_SIZE)
2064 {
2065 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrActive) / 2;
2066 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ICACTIVERnE_OFF_START) / cbReg;
2067 return gicDistReadIntrActiveReg(pGicDev, idxReg, puValue);
2068 }
2069 }
2070
2071 /*
2072 * GICD_IPRIORITYR<n> and GICD_IPRIORITYR<n>E.
2073 */
2074 {
2075 if (offReg - GIC_DIST_REG_IPRIORITYRn_OFF_START < GIC_DIST_REG_IPRIORITYRn_RANGE_SIZE)
2076 {
2077 uint16_t const idxReg = (offReg - GIC_DIST_REG_IPRIORITYRn_OFF_START) / cbReg;
2078 return gicDistReadIntrPriorityReg(pGicDev, idxReg, puValue);
2079 }
2080 if (offReg - GIC_DIST_REG_IPRIORITYRnE_OFF_START < GIC_DIST_REG_IPRIORITYRnE_RANGE_SIZE)
2081 {
2082 uint16_t const idxExt = RT_ELEMENTS(pGicDev->abIntrPriority) / (2 * sizeof(uint32_t));
2083 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_IPRIORITYRnE_OFF_START) / cbReg;
2084 return gicDistReadIntrPriorityReg(pGicDev, idxReg, puValue);
2085 }
2086 }
2087
2088 /*
2089 * GICD_ISPENDR<n> and GICD_ISPENDR<n>E.
2090 * GICD_ICPENDR<n> and GICD_ICPENDR<n>E.
2091 */
2092 {
2093 if (offReg - GIC_DIST_REG_ISPENDRn_OFF_START < GIC_DIST_REG_ISPENDRn_RANGE_SIZE)
2094 {
2095 uint16_t const idxReg = (offReg - GIC_DIST_REG_ISPENDRn_OFF_START) / cbReg;
2096 return gicDistReadIntrPendingReg(pGicDev, idxReg, puValue);
2097 }
2098 if (offReg - GIC_DIST_REG_ISPENDRnE_OFF_START < GIC_DIST_REG_ISPENDRnE_RANGE_SIZE)
2099 {
2100 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrPending) / 2;
2101 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ISPENDRnE_OFF_START) / cbReg;
2102 return gicDistReadIntrPendingReg(pGicDev, idxReg, puValue);
2103 }
2104
2105 if (offReg - GIC_DIST_REG_ICPENDRn_OFF_START < GIC_DIST_REG_ICPENDRn_RANGE_SIZE)
2106 {
2107 uint16_t const idxReg = (offReg - GIC_DIST_REG_ICPENDRn_OFF_START) / cbReg;
2108 return gicDistReadIntrPendingReg(pGicDev, idxReg, puValue);
2109 }
2110 if (offReg - GIC_DIST_REG_ICPENDRnE_OFF_START < GIC_DIST_REG_ICPENDRnE_RANGE_SIZE)
2111 {
2112 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrPending) / 2;
2113 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ICPENDRnE_OFF_START) / cbReg;
2114 return gicDistReadIntrPendingReg(pGicDev, idxReg, puValue);
2115 }
2116 }
2117
2118 /*
2119 * GICD_ICFGR<n> and GICD_ICFGR<n>E.
2120 */
2121 {
2122 if (offReg - GIC_DIST_REG_ICFGRn_OFF_START < GIC_DIST_REG_ICFGRn_RANGE_SIZE)
2123 {
2124 uint16_t const idxReg = (offReg - GIC_DIST_REG_ICFGRn_OFF_START) / cbReg;
2125 return gicDistReadIntrConfigReg(pGicDev, idxReg, puValue);
2126 }
2127 if (offReg - GIC_DIST_REG_ICFGRnE_OFF_START < GIC_DIST_REG_ICFGRnE_RANGE_SIZE)
2128 {
2129 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrConfig) / 2;
2130 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ICFGRnE_OFF_START) / cbReg;
2131 return gicDistReadIntrConfigReg(pGicDev, idxReg, puValue);
2132 }
2133 }
2134
2135 switch (offReg)
2136 {
2137 case GIC_DIST_REG_CTLR_OFF:
2138 Assert(pGicDev->fAffRoutingEnabled); /* We don't support GICv2 backwards compatibility, so ARE bit must be set. */
2139 *puValue = (pGicDev->fIrqGrp0Enabled ? GIC_DIST_REG_CTRL_ENABLE_GRP0 : 0)
2140 | (pGicDev->fIrqGrp1Enabled ? GIC_DIST_REG_CTRL_ENABLE_GRP1_NS : 0)
2141 | GIC_DIST_REG_CTRL_DS
2142 | (pGicDev->fAffRoutingEnabled ? GIC_DIST_REG_CTRL_ARE_S : 0);
2143 break;
2144 case GIC_DIST_REG_TYPER_OFF:
2145 Assert(pGicDev->uMaxSpi > 0 && pGicDev->uMaxSpi < GIC_DIST_REG_TYPER_NUM_ITLINES);
2146 *puValue = GIC_DIST_REG_TYPER_NUM_ITLINES_SET(pGicDev->uMaxSpi)
2147 | GIC_DIST_REG_TYPER_NUM_PES_SET(0) /* 1 PE */ /** @todo r=ramshankar: Should this be pVCpu->cCpus? Currently it means 'ARE' must always be used? */
2148 /*| GIC_DIST_REG_TYPER_ESPI*/ /** @todo */
2149 /*| GIC_DIST_REG_TYPER_NMI*/ /** @todo Non-maskable interrupts */
2150 /*| GIC_DIST_REG_TYPER_SECURITY_EXTN */ /** @todo */
2151 /*| GIC_DIST_REG_TYPER_MBIS */ /** @todo Message based interrupts */
2152 /*| GIC_DIST_REG_TYPER_LPIS */ /** @todo Support LPIs */
2153 | (pGicDev->fRangeSelSupport ? GIC_DIST_REG_TYPER_RSS : 0)
2154 | GIC_DIST_REG_TYPER_IDBITS_SET(16);
2155 break;
2156 case GIC_DIST_REG_STATUSR_OFF:
2157 AssertReleaseFailed();
2158 break;
2159#if 0
2160 case GIC_DIST_REG_IGROUPRn_OFF_START: /* Only 32 lines for now. */
2161 AssertReleaseFailed();
2162 break;
2163 case GIC_DIST_REG_ISENABLERn_OFF_START + 4: /* Only 32 lines for now. */
2164 case GIC_DIST_REG_ICENABLERn_OFF_START + 4: /* Only 32 lines for now. */
2165 *puValue = ASMAtomicReadU32(&pThis->bmIntEnabled);
2166 break;
2167#endif
2168 case GIC_DIST_REG_ISPENDRn_OFF_START: /* Only 32 lines for now. */
2169 AssertReleaseFailed();
2170 break;
2171 case GIC_DIST_REG_ICPENDRn_OFF_START: /* Only 32 lines for now. */
2172 AssertReleaseFailed();
2173 break;
2174 case GIC_DIST_REG_ISACTIVERn_OFF_START: /* Only 32 lines for now. */
2175 AssertReleaseFailed();
2176 break;
2177 case GIC_DIST_REG_ICACTIVERn_OFF_START: /* Only 32 lines for now. */
2178 AssertReleaseFailed();
2179 break;
2180#if 0
2181 case GIC_DIST_REG_IPRIORITYRn_OFF_START:
2182 case GIC_DIST_REG_IPRIORITYRn_OFF_START + 4: /* These are banked for the PEs and access the redistributor. */
2183 {
2184 PGICCPU pGicVCpu = VMCPU_TO_GICCPU(pVCpu);
2185
2186 /* Figure out the register which is written. */
2187 uint8_t idxPrio = offReg - GIC_DIST_REG_IPRIORITYRn_OFF_START;
2188 Assert(idxPrio <= RT_ELEMENTS(pThis->abIntPriority) - sizeof(uint32_t));
2189
2190 uint32_t u32Value = 0;
2191 for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
2192 u32Value |= pGicVCpu->abIntPriority[i] << ((i - idxPrio) * 8);
2193
2194 *puValue = u32Value;
2195 break;
2196 }
2197 case GIC_DIST_REG_IPRIORITYRn_OFF_START + 32: /* Only 32 lines for now. */
2198 {
2199 /* Figure out the register which is written. */
2200 uint8_t idxPrio = offReg - GIC_DIST_REG_IPRIORITYRn_OFF_START - 32;
2201 Assert(idxPrio <= RT_ELEMENTS(pThis->abIntPriority) - sizeof(uint32_t));
2202
2203 uint32_t u32Value = 0;
2204 for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
2205 u32Value |= pThis->abIntPriority[i] << ((i - idxPrio) * 8);
2206
2207 *puValue = u32Value;
2208 break;
2209 }
2210#endif
2211 case GIC_DIST_REG_ITARGETSRn_OFF_START: /* Only 32 lines for now. */
2212 AssertReleaseFailed();
2213 break;
2214 case GIC_DIST_REG_ICFGRn_OFF_START: /* Only 32 lines for now. */
2215 AssertReleaseFailed();
2216 break;
2217 case GIC_DIST_REG_IGRPMODRn_OFF_START: /* Only 32 lines for now. */
2218 AssertReleaseFailed();
2219 break;
2220 case GIC_DIST_REG_NSACRn_OFF_START: /* Only 32 lines for now. */
2221 AssertReleaseFailed();
2222 break;
2223 case GIC_DIST_REG_SGIR_OFF:
2224 AssertReleaseFailed();
2225 break;
2226 case GIC_DIST_REG_CPENDSGIRn_OFF_START:
2227 AssertReleaseFailed();
2228 break;
2229 case GIC_DIST_REG_SPENDSGIRn_OFF_START:
2230 AssertReleaseFailed();
2231 break;
2232 case GIC_DIST_REG_INMIn_OFF_START:
2233 AssertReleaseFailed();
2234 break;
2235 case GIC_DIST_REG_PIDR2_OFF:
2236#if 0
2237 Assert(pThis->uArchRev <= GIC_DIST_REG_PIDR2_ARCH_REV_GICV4);
2238 *puValue = GIC_DIST_REG_PIDR2_ARCH_REV_SET(pThis->uArchRev);
2239#else
2240 Assert(pGicDev->uArchRev <= GIC_DIST_REG_PIDR2_ARCH_REV_GICV4);
2241 *puValue = GIC_DIST_REG_PIDR2_ARCH_REV_SET(pGicDev->uArchRev);
2242#endif
2243 break;
2244 case GIC_DIST_REG_IIDR_OFF:
2245 *puValue = 0x43b; /* JEP106 code 0x43b is an ARM implementation. */
2246 break;
2247 case GIC_DIST_REG_TYPER2_OFF:
2248 *puValue = 0;
2249 break;
2250#if 0
2251 case GIC_DIST_REG_IROUTERn_OFF_START:
2252 AssertFailed();
2253 break;
2254#endif
2255 default:
2256 *puValue = 0;
2257 }
2258 return VINF_SUCCESS;
2259}
2260
2261
2262/**
2263 * Writes a distributor register.
2264 *
2265 * @returns Strict VBox status code.
2266 * @param pDevIns The device instance.
2267 * @param pVCpu The cross context virtual CPU structure.
2268 * @param offReg The offset of the register being written.
2269 * @param uValue The register value.
2270 */
2271DECLINLINE(VBOXSTRICTRC) gicDistWriteRegister(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue)
2272{
2273 VMCPU_ASSERT_EMT(pVCpu); RT_NOREF(pVCpu);
2274 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
2275 PVMCC pVM = PDMDevHlpGetVM(pDevIns);
2276 uint16_t const cbReg = sizeof(uint32_t);
2277
2278 /*
2279 * GICD_IGROUPR<n> and GICD_IGROUPR<n>E.
2280 */
2281 {
2282 if (offReg - GIC_DIST_REG_IGROUPRn_OFF_START < GIC_DIST_REG_IGROUPRn_RANGE_SIZE)
2283 {
2284 uint16_t const idxReg = (offReg - GIC_DIST_REG_IGROUPRn_OFF_START) / cbReg;
2285 return gicDistWriteIntrGroupReg(pVM, pGicDev, idxReg, uValue);
2286 }
2287 if (offReg - GIC_DIST_REG_IGROUPRnE_OFF_START < GIC_DIST_REG_IGROUPRnE_RANGE_SIZE)
2288 {
2289 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrGroup) / 2;
2290 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_IGROUPRnE_OFF_START) / cbReg;
2291 return gicDistWriteIntrGroupReg(pVM, pGicDev, idxReg, uValue);
2292 }
2293 }
2294
2295 /*
2296 * GICD_IROUTER<n> and GICD_IROUTER<n>E.
2297 */
2298 {
2299 if (offReg - GIC_DIST_REG_IROUTERn_OFF_START < GIC_DIST_REG_IROUTERn_RANGE_SIZE)
2300 {
2301 uint16_t const idxReg = (offReg - GIC_DIST_REG_IROUTERn_OFF_START) / cbReg;
2302 return gicDistWriteIntrRoutingReg(pGicDev, offReg, idxReg, uValue);
2303 }
2304 if (offReg - GIC_DIST_REG_IROUTERnE_OFF_START < GIC_DIST_REG_IROUTERnE_RANGE_SIZE)
2305 {
2306 uint16_t const idxExt = RT_ELEMENTS(pGicDev->au32IntrRouting) / 2;
2307 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_IROUTERnE_OFF_START) / cbReg;
2308 return gicDistWriteIntrRoutingReg(pGicDev, offReg, idxReg, uValue);
2309 }
2310 }
2311
2312 /*
2313 * GICD_ISENABLER<n> and GICD_ISENABLER<n>E.
2314 * GICD_ICENABLER<n> and GICD_ICENABLER<n>E.
2315 */
2316 {
2317 if (offReg - GIC_DIST_REG_ISENABLERn_OFF_START < GIC_DIST_REG_ISENABLERn_RANGE_SIZE)
2318 {
2319 uint16_t const idxReg = (offReg - GIC_DIST_REG_ISENABLERn_OFF_START) / cbReg;
2320 return gicDistWriteIntrSetEnableReg(pVM, pGicDev, idxReg, uValue);
2321 }
2322 if (offReg - GIC_DIST_REG_ISENABLERnE_OFF_START < GIC_DIST_REG_ISENABLERnE_RANGE_SIZE)
2323 {
2324 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrEnabled) / 2;
2325 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ISENABLERnE_OFF_START) / cbReg;
2326 return gicDistWriteIntrSetEnableReg(pVM, pGicDev, idxReg, uValue);
2327 }
2328
2329 if (offReg - GIC_DIST_REG_ICENABLERn_OFF_START < GIC_DIST_REG_ICENABLERn_RANGE_SIZE)
2330 {
2331 uint16_t const idxReg = (offReg - GIC_DIST_REG_ICENABLERn_OFF_START) / cbReg;
2332 return gicDistWriteIntrClearEnableReg(pVM, pGicDev, idxReg, uValue);
2333 }
2334 if (offReg - GIC_DIST_REG_ICENABLERnE_OFF_START < GIC_DIST_REG_ICENABLERnE_RANGE_SIZE)
2335 {
2336 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrEnabled) / 2;
2337 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ICENABLERnE_OFF_START) / cbReg;
2338 return gicDistWriteIntrClearEnableReg(pVM, pGicDev, idxReg, uValue);
2339 }
2340 }
2341
2342 /*
2343 * GICD_ISACTIVER<n> and GICD_ISACTIVER<n>E.
2344 * GICD_ICACTIVER<n> and GICD_ICACTIVER<n>E.
2345 */
2346 {
2347 if (offReg - GIC_DIST_REG_ISACTIVERn_OFF_START < GIC_DIST_REG_ISACTIVERn_RANGE_SIZE)
2348 {
2349 uint16_t const idxReg = (offReg - GIC_DIST_REG_ISACTIVERn_OFF_START) / cbReg;
2350 return gicDistWriteIntrSetActiveReg(pVM, pGicDev, idxReg, uValue);
2351 }
2352 if (offReg - GIC_DIST_REG_ISACTIVERnE_OFF_START < GIC_DIST_REG_ISACTIVERnE_RANGE_SIZE)
2353 {
2354 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrActive) / 2;
2355 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ISACTIVERnE_OFF_START) / cbReg;
2356 return gicDistWriteIntrSetActiveReg(pVM, pGicDev, idxReg, uValue);
2357 }
2358
2359 if (offReg - GIC_DIST_REG_ICACTIVERn_OFF_START < GIC_DIST_REG_ICACTIVERn_RANGE_SIZE)
2360 {
2361 uint16_t const idxReg = (offReg - GIC_DIST_REG_ICACTIVERn_OFF_START) / cbReg;
2362 return gicDistWriteIntrClearActiveReg(pVM, pGicDev, idxReg, uValue);
2363 }
2364 if (offReg - GIC_DIST_REG_ICACTIVERnE_OFF_START < GIC_DIST_REG_ICACTIVERnE_RANGE_SIZE)
2365 {
2366 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrActive) / 2;
2367 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ICACTIVERnE_OFF_START) / cbReg;
2368 return gicDistWriteIntrClearActiveReg(pVM, pGicDev, idxReg, uValue);
2369 }
2370 }
2371
2372 /*
2373 * GICD_IPRIORITYR<n> and GICD_IPRIORITYR<n>E.
2374 */
2375 {
2376 if (offReg - GIC_DIST_REG_IPRIORITYRn_OFF_START < GIC_DIST_REG_IPRIORITYRn_RANGE_SIZE)
2377 {
2378 uint16_t const idxReg = (offReg - GIC_DIST_REG_IPRIORITYRn_OFF_START) / cbReg;
2379 return gicDistWriteIntrPriorityReg(pGicDev, idxReg, uValue);
2380 }
2381 if (offReg - GIC_DIST_REG_IPRIORITYRnE_OFF_START < GIC_DIST_REG_IPRIORITYRnE_RANGE_SIZE)
2382 {
2383 uint16_t const idxExt = RT_ELEMENTS(pGicDev->abIntrPriority) / (2 * sizeof(uint32_t));
2384 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_IPRIORITYRnE_OFF_START) / cbReg;
2385 return gicDistWriteIntrPriorityReg(pGicDev, idxReg, uValue);
2386 }
2387 }
2388
2389 /*
2390 * GICD_ISPENDR<n> and GICD_ISPENDR<n>E.
2391 * GICD_ICPENDR<n> and GICD_ICPENDR<n>E.
2392 */
2393 {
2394 if (offReg - GIC_DIST_REG_ISPENDRn_OFF_START < GIC_DIST_REG_ISPENDRn_RANGE_SIZE)
2395 {
2396 uint16_t const idxReg = (offReg - GIC_DIST_REG_ISPENDRn_OFF_START) / cbReg;
2397 return gicDistWriteIntrSetPendingReg(pVM, pGicDev, idxReg, uValue);
2398 }
2399 if (offReg - GIC_DIST_REG_ISPENDRnE_OFF_START < GIC_DIST_REG_ISPENDRnE_RANGE_SIZE)
2400 {
2401 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrPending) / 2;
2402 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ISPENDRnE_OFF_START) / cbReg;
2403 return gicDistWriteIntrSetPendingReg(pVM, pGicDev, idxReg, uValue);
2404 }
2405
2406 if (offReg - GIC_DIST_REG_ICPENDRn_OFF_START < GIC_DIST_REG_ICPENDRn_RANGE_SIZE)
2407 {
2408 uint16_t const idxReg = (offReg - GIC_DIST_REG_ICPENDRn_OFF_START) / cbReg;
2409 return gicDistWriteIntrClearPendingReg(pVM, pGicDev, idxReg, uValue);
2410 }
2411 if (offReg - GIC_DIST_REG_ICPENDRnE_OFF_START < GIC_DIST_REG_ICPENDRnE_RANGE_SIZE)
2412 {
2413 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrPending) / 2;
2414 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ICPENDRnE_OFF_START) / cbReg;
2415 return gicDistWriteIntrClearPendingReg(pVM, pGicDev, idxReg, uValue);
2416 }
2417 }
2418
2419 /*
2420 * GICD_ICFGR<n> and GICD_ICFGR<n>E.
2421 */
2422 {
2423 if (offReg - GIC_DIST_REG_ICFGRn_OFF_START + cbReg < GIC_DIST_REG_ICFGRn_RANGE_SIZE)
2424 {
2425 uint16_t const idxReg = (offReg - GIC_DIST_REG_ICFGRn_OFF_START) / cbReg;
2426 return gicDistWriteIntrConfigReg(pGicDev, idxReg, uValue);
2427 }
2428 if (offReg - GIC_DIST_REG_ICFGRnE_OFF_START < GIC_DIST_REG_ICFGRnE_RANGE_SIZE)
2429 {
2430 uint16_t const idxExt = RT_ELEMENTS(pGicDev->bmIntrConfig) / 2;
2431 uint16_t const idxReg = idxExt + (offReg - GIC_DIST_REG_ICFGRnE_OFF_START) / cbReg;
2432 return gicDistWriteIntrConfigReg(pGicDev, idxReg, uValue);
2433 }
2434 }
2435
2436 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
2437 switch (offReg)
2438 {
2439 case GIC_DIST_REG_CTLR_OFF:
2440#if 0
2441 ASMAtomicWriteBool(&pThis->fIrqGrp0Enabled, RT_BOOL(uValue & GIC_DIST_REG_CTRL_ENABLE_GRP0));
2442 ASMAtomicWriteBool(&pThis->fIrqGrp1Enabled, RT_BOOL(uValue & GIC_DIST_REG_CTRL_ENABLE_GRP1_NS));
2443 Assert(!(uValue & GIC_DIST_REG_CTRL_ARE_NS));
2444 rcStrict = gicDistUpdateIrqState(pVM, pThis);
2445#else
2446 Assert(!(uValue & GIC_DIST_REG_CTRL_ARE_NS));
2447 pGicDev->fIrqGrp0Enabled = RT_BOOL(uValue & GIC_DIST_REG_CTRL_ENABLE_GRP0);
2448 pGicDev->fIrqGrp1Enabled = RT_BOOL(uValue & GIC_DIST_REG_CTRL_ENABLE_GRP1_NS);
2449 rcStrict = gicDistUpdateIrqState(pVM, pGicDev);
2450#endif
2451 break;
2452 case GIC_DIST_REG_STATUSR_OFF:
2453 AssertReleaseFailed();
2454 break;
2455 case GIC_DIST_REG_SETSPI_NSR_OFF:
2456 AssertReleaseFailed();
2457 break;
2458 case GIC_DIST_REG_CLRSPI_NSR_OFF:
2459 AssertReleaseFailed();
2460 break;
2461 case GIC_DIST_REG_SETSPI_SR_OFF:
2462 AssertReleaseFailed();
2463 break;
2464 case GIC_DIST_REG_CLRSPI_SR_OFF:
2465 AssertReleaseFailed();
2466 break;
2467#if 0
2468 case GIC_DIST_REG_IGROUPRn_OFF_START: /* Only 32 lines for now. */
2469 AssertReleaseFailed();
2470 break;
2471 case GIC_DIST_REG_IGROUPRn_OFF_START + 4: /* Only 32 lines for now. */
2472 ASMAtomicOrU32(&pThis->u32RegIGrp0, uValue);
2473 rcStrict = gicDistUpdateIrqState(pVM, pThis);
2474 break;
2475 case GIC_DIST_REG_ISENABLERn_OFF_START + 4: /* Only 32 lines for now. */
2476 ASMAtomicOrU32(&pThis->bmIntEnabled, uValue);
2477 rcStrict = gicDistUpdateIrqState(pVM, pThis);
2478 break;
2479 case GIC_DIST_REG_ICENABLERn_OFF_START:
2480 AssertReleaseFailed();
2481 break;
2482 case GIC_DIST_REG_ICENABLERn_OFF_START + 4: /* Only 32 lines for now. */
2483 ASMAtomicAndU32(&pThis->bmIntEnabled, ~uValue);
2484 rcStrict = gicDistUpdateIrqState(pVM, pThis);
2485 break;
2486 case GIC_DIST_REG_ISPENDRn_OFF_START: /* Only 32 lines for now. */
2487 AssertReleaseFailed();
2488 break;
2489 case GIC_DIST_REG_ICPENDRn_OFF_START: /* Only 32 lines for now. */
2490 AssertReleaseFailed();
2491 break;
2492 case GIC_DIST_REG_ISACTIVERn_OFF_START: /* Only 32 lines for now. */
2493 AssertReleaseFailed();
2494 break;
2495 case GIC_DIST_REG_ICACTIVERn_OFF_START + 4: /* Only 32 lines for now. */
2496 ASMAtomicAndU32(&pThis->bmIntActive, ~uValue);
2497 rcStrict = gicDistUpdateIrqState(pVM, pThis);
2498 break;
2499 case GIC_DIST_REG_IPRIORITYRn_OFF_START: /* These are banked for the PEs and access the redistributor. */
2500 case GIC_DIST_REG_IPRIORITYRn_OFF_START + 4:
2501 case GIC_DIST_REG_IPRIORITYRn_OFF_START + 8:
2502 case GIC_DIST_REG_IPRIORITYRn_OFF_START + 12:
2503 case GIC_DIST_REG_IPRIORITYRn_OFF_START + 16:
2504 case GIC_DIST_REG_IPRIORITYRn_OFF_START + 20:
2505 case GIC_DIST_REG_IPRIORITYRn_OFF_START + 24:
2506 case GIC_DIST_REG_IPRIORITYRn_OFF_START + 28:
2507 {
2508 PGICCPU pGicVCpu = VMCPU_TO_GICCPU(pVCpu);
2509
2510 /* Figure out the register which is written. */
2511 uint8_t idxPrio = offReg - GIC_DIST_REG_IPRIORITYRn_OFF_START;
2512 Assert(idxPrio <= RT_ELEMENTS(pGicVCpu->abIntPriority) - sizeof(uint32_t));
2513 for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
2514 {
2515 pGicVCpu->abIntPriority[i] = (uint8_t)(uValue & 0xff);
2516 uValue >>= 8;
2517 }
2518 break;
2519 }
2520 case GIC_DIST_REG_IPRIORITYRn_OFF_START + 32: /* Only 32 lines for now. */
2521 case GIC_DIST_REG_IPRIORITYRn_OFF_START + 36:
2522 case GIC_DIST_REG_IPRIORITYRn_OFF_START + 40:
2523 case GIC_DIST_REG_IPRIORITYRn_OFF_START + 44:
2524 case GIC_DIST_REG_IPRIORITYRn_OFF_START + 48:
2525 case GIC_DIST_REG_IPRIORITYRn_OFF_START + 52:
2526 case GIC_DIST_REG_IPRIORITYRn_OFF_START + 56:
2527 case GIC_DIST_REG_IPRIORITYRn_OFF_START + 60:
2528 {
2529 /* Figure out the register which is written. */
2530 uint8_t idxPrio = offReg - GIC_DIST_REG_IPRIORITYRn_OFF_START - 32;
2531 Assert(idxPrio <= RT_ELEMENTS(pThis->abIntPriority) - sizeof(uint32_t));
2532 for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
2533 {
2534#if 1
2535 /** @todo r=aeichner This gross hack prevents Windows from hanging during boot because
2536 * it tries to set the interrupt priority for PCI interrupt lines to 0 which will cause an interrupt
2537 * storm later on because the lowest interrupt priority Windows seems to use is 32 for the per vCPU
2538 * timer.
2539 */
2540 if ((uValue & 0xff) == 0)
2541 {
2542 uValue >>= 8;
2543 continue;
2544 }
2545#endif
2546 pThis->abIntPriority[i] = (uint8_t)(uValue & 0xff);
2547 uValue >>= 8;
2548 }
2549 break;
2550 }
2551#endif
2552 case GIC_DIST_REG_ITARGETSRn_OFF_START: /* Only 32 lines for now. */
2553 AssertReleaseFailed();
2554 break;
2555#if 0
2556 case GIC_DIST_REG_ICFGRn_OFF_START + 8: /* Only 32 lines for now. */
2557 ASMAtomicWriteU32(&pThis->u32RegICfg0, uValue);
2558 break;
2559 case GIC_DIST_REG_ICFGRn_OFF_START+ 12:
2560 ASMAtomicWriteU32(&pThis->u32RegICfg1, uValue);
2561 break;
2562#endif
2563 case GIC_DIST_REG_IGRPMODRn_OFF_START: /* Only 32 lines for now. */
2564 AssertReleaseFailed();
2565 break;
2566 case GIC_DIST_REG_NSACRn_OFF_START: /* Only 32 lines for now. */
2567 AssertReleaseFailed();
2568 break;
2569 case GIC_DIST_REG_SGIR_OFF:
2570 AssertReleaseFailed();
2571 break;
2572 case GIC_DIST_REG_CPENDSGIRn_OFF_START:
2573 AssertReleaseFailed();
2574 break;
2575 case GIC_DIST_REG_SPENDSGIRn_OFF_START:
2576 AssertReleaseFailed();
2577 break;
2578 case GIC_DIST_REG_INMIn_OFF_START:
2579 AssertReleaseFailed();
2580 break;
2581 default:
2582 //AssertReleaseFailed();
2583 break;
2584 }
2585
2586 return rcStrict;
2587}
2588
2589
2590/**
2591 * Reads a GIC redistributor register.
2592 *
2593 * @returns VBox status code.
2594 * @param pDevIns The device instance.
2595 * @param pVCpu The cross context virtual CPU structure.
2596 * @param idRedist The redistributor ID.
2597 * @param offReg The offset of the register being read.
2598 * @param puValue Where to store the register value.
2599 */
2600DECLINLINE(VBOXSTRICTRC) gicReDistReadRegister(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint32_t idRedist, uint16_t offReg, uint32_t *puValue)
2601{
2602 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
2603 Assert(idRedist == pVCpu->idCpu); /* Assert for now, maybe remove function parameter later. */
2604 switch (offReg)
2605 {
2606 case GIC_REDIST_REG_TYPER_OFF:
2607 {
2608 PCVMCC pVM = PDMDevHlpGetVM(pDevIns);
2609 *puValue = ((pVCpu->idCpu == pVM->cCpus - 1) ? GIC_REDIST_REG_TYPER_LAST : 0)
2610 | GIC_REDIST_REG_TYPER_CPU_NUMBER_SET(idRedist)
2611 | GIC_REDIST_REG_TYPER_CMN_LPI_AFF_SET(GIC_REDIST_REG_TYPER_CMN_LPI_AFF_ALL);
2612 break;
2613 }
2614 case GIC_REDIST_REG_IIDR_OFF:
2615 *puValue = 0x43b; /* JEP106 code 0x43b is an ARM implementation. */
2616 break;
2617 case GIC_REDIST_REG_TYPER_AFFINITY_OFF:
2618 *puValue = idRedist;
2619 break;
2620 case GIC_REDIST_REG_PIDR2_OFF:
2621 Assert(pGicDev->uArchRev <= GIC_DIST_REG_PIDR2_ARCH_REV_GICV4);
2622 *puValue = GIC_REDIST_REG_PIDR2_ARCH_REV_SET(pGicDev->uArchRev);
2623 break;
2624 default:
2625 *puValue = 0;
2626 }
2627 return VINF_SUCCESS;
2628}
2629
2630
2631/**
2632 * Reads a GIC redistributor SGI/PPI frame register.
2633 *
2634 * @returns VBox status code.
2635 * @param pDevIns The device instance.
2636 * @param pVCpu The cross context virtual CPU structure.
2637 * @param offReg The offset of the register being read.
2638 * @param puValue Where to store the register value.
2639 */
2640DECLINLINE(VBOXSTRICTRC) gicReDistReadSgiPpiRegister(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t *puValue)
2641{
2642 VMCPU_ASSERT_EMT(pVCpu);
2643 RT_NOREF(pDevIns);
2644
2645 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
2646 PCGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
2647 uint16_t const cbReg = sizeof(uint32_t);
2648
2649#if 1
2650 /*
2651 * GICR_IGROUPR0 and GICR_IGROUPR<n>E.
2652 */
2653 {
2654 if (offReg - GIC_REDIST_SGI_PPI_REG_IGROUPR0_OFF < GIC_REDIST_SGI_PPI_REG_IGROUPRnE_RANGE_SIZE)
2655 {
2656 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_IGROUPR0_OFF) / cbReg;
2657 return gicReDistReadIntrGroupReg(pGicDev, pGicCpu, idxReg, puValue);
2658 }
2659 }
2660
2661 /*
2662 * GICR_ISENABLER0 and GICR_ISENABLER<n>E.
2663 * GICR_ICENABLER0 and GICR_ICENABLER<n>E.
2664 */
2665 {
2666 if (offReg - GIC_REDIST_SGI_PPI_REG_ISENABLER0_OFF < GIC_REDIST_SGI_PPI_REG_ISENABLERnE_RANGE_SIZE)
2667 {
2668 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ISENABLER0_OFF) / cbReg;
2669 return gicReDistReadIntrEnableReg(pGicDev, pGicCpu, idxReg, puValue);
2670 }
2671 if (offReg - GIC_REDIST_SGI_PPI_REG_ICENABLER0_OFF < GIC_REDIST_SGI_PPI_REG_ICENABLERnE_RANGE_SIZE)
2672 {
2673 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ICENABLERnE_OFF_START) / cbReg;
2674 return gicReDistReadIntrEnableReg(pGicDev, pGicCpu, idxReg, puValue);
2675 }
2676 }
2677
2678 /*
2679 * GICR_ISACTIVER0 and GICR_ISACTIVER<n>E.
2680 * GICR_ICACTIVER0 and GICR_ICACTIVER<n>E.
2681 */
2682 {
2683 if (offReg - GIC_REDIST_SGI_PPI_REG_ISACTIVER0_OFF < GIC_REDIST_SGI_PPI_REG_ISACTIVERnE_RANGE_SIZE)
2684 {
2685 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ISACTIVER0_OFF) / cbReg;
2686 return gicReDistReadIntrActiveReg(pGicCpu, idxReg, puValue);
2687 }
2688 if (offReg - GIC_REDIST_SGI_PPI_REG_ICACTIVER0_OFF < GIC_REDIST_SGI_PPI_REG_ICACTIVERnE_RANGE_SIZE)
2689 {
2690 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ICACTIVER0_OFF) / cbReg;
2691 return gicReDistReadIntrActiveReg(pGicCpu, idxReg, puValue);
2692 }
2693 }
2694
2695 /*
2696 * GICR_ISPENDR0 and GICR_ISPENDR<n>E.
2697 * GICR_ICPENDR0 and GICR_ICPENDR<n>E.
2698 */
2699 {
2700 if (offReg - GIC_REDIST_SGI_PPI_REG_ISPENDR0_OFF < GIC_REDIST_SGI_PPI_REG_ISPENDRnE_RANGE_SIZE)
2701 {
2702 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ISPENDR0_OFF) / cbReg;
2703 return gicReDistReadIntrPendingReg(pGicDev, pGicCpu, idxReg, puValue);
2704 }
2705 if (offReg - GIC_REDIST_SGI_PPI_REG_ICPENDR0_OFF < GIC_REDIST_SGI_PPI_REG_ICPENDRnE_RANGE_SIZE)
2706 {
2707 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ICPENDR0_OFF) / cbReg;
2708 return gicReDistReadIntrPendingReg(pGicDev, pGicCpu, idxReg, puValue);
2709 }
2710 }
2711
2712 /*
2713 * GICR_IPRIORITYR<n> and GICR_IPRIORITYR<n>E.
2714 */
2715 {
2716 if (offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START < GIC_REDIST_SGI_PPI_REG_IPRIORITYRnE_RANGE_SIZE)
2717 {
2718 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START) / cbReg;
2719 return gicReDistReadIntrPriorityReg(pGicDev, pGicCpu, idxReg, puValue);
2720 }
2721 }
2722
2723 /*
2724 * GICR_ICFGR0, GICR_ICFGR1 and GICR_ICFGR<n>E.
2725 */
2726 {
2727 if (offReg - GIC_REDIST_SGI_PPI_REG_ICFGR0_OFF < GIC_REDIST_SGI_PPI_REG_ICFGRnE_RANGE_SIZE)
2728 {
2729 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ICFGR0_OFF) / cbReg;
2730 return gicReDistReadIntrConfigReg(pGicDev, pGicCpu, idxReg, puValue);
2731 }
2732 }
2733
2734 AssertReleaseFailed();
2735 *puValue = 0;
2736 return VINF_SUCCESS;
2737#else
2738 switch (offReg)
2739 {
2740 case GIC_REDIST_SGI_PPI_REG_ISENABLER0_OFF:
2741 case GIC_REDIST_SGI_PPI_REG_ICENABLER0_OFF:
2742 *puValue = ASMAtomicReadU32(&pThis->bmIntEnabled);
2743 break;
2744 case GIC_REDIST_SGI_PPI_REG_ISPENDR0_OFF:
2745 case GIC_REDIST_SGI_PPI_REG_ICPENDR0_OFF:
2746 *puValue = ASMAtomicReadU32(&pThis->bmIntPending);
2747 break;
2748 case GIC_REDIST_SGI_PPI_REG_ISACTIVER0_OFF:
2749 case GIC_REDIST_SGI_PPI_REG_ICACTIVER0_OFF:
2750 *puValue = ASMAtomicReadU32(&pThis->bmIntActive);
2751 break;
2752 case GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START:
2753 case GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START + 4:
2754 case GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START + 8:
2755 case GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START + 12:
2756 case GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START + 16:
2757 case GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START + 20:
2758 case GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START + 24:
2759 case GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START + 28:
2760 {
2761 /* Figure out the register which is written. */
2762 uint8_t idxPrio = offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START;
2763 Assert(idxPrio <= RT_ELEMENTS(pThis->abIntPriority) - sizeof(uint32_t));
2764
2765 uint32_t u32Value = 0;
2766 for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
2767 u32Value |= pThis->abIntPriority[i] << ((i - idxPrio) * 8);
2768
2769 *puValue = u32Value;
2770 break;
2771 }
2772 case GIC_REDIST_SGI_PPI_REG_ICFGR0_OFF:
2773 *puValue = ASMAtomicReadU32(&pThis->u32RegICfg0);
2774 break;
2775 case GIC_REDIST_SGI_PPI_REG_ICFGR1_OFF:
2776 *puValue = ASMAtomicReadU32(&pThis->u32RegICfg1);
2777 break;
2778 default:
2779 AssertReleaseFailed();
2780 *puValue = 0;
2781 }
2782
2783 return VINF_SUCCESS;
2784#endif
2785}
2786
2787
2788/**
2789 * Writes a GIC redistributor frame register.
2790 *
2791 * @returns Strict VBox status code.
2792 * @param pDevIns The device instance.
2793 * @param pVCpu The cross context virtual CPU structure.
2794 * @param offReg The offset of the register being written.
2795 * @param uValue The register value.
2796 */
2797DECLINLINE(VBOXSTRICTRC) gicReDistWriteRegister(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue)
2798{
2799 VMCPU_ASSERT_EMT(pVCpu);
2800 RT_NOREF(pDevIns, pVCpu, uValue);
2801
2802 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
2803 switch (offReg)
2804 {
2805 case GIC_REDIST_REG_STATUSR_OFF:
2806 AssertReleaseFailed();
2807 break;
2808 case GIC_REDIST_REG_WAKER_OFF:
2809 Assert(uValue == 0);
2810 break;
2811 case GIC_REDIST_REG_PARTIDR_OFF:
2812 AssertReleaseFailed();
2813 break;
2814 case GIC_REDIST_REG_SETLPIR_OFF:
2815 AssertReleaseFailed();
2816 break;
2817 case GIC_REDIST_REG_CLRLPIR_OFF:
2818 AssertReleaseFailed();
2819 break;
2820 case GIC_REDIST_REG_PROPBASER_OFF:
2821 AssertReleaseFailed();
2822 break;
2823 case GIC_REDIST_REG_PENDBASER_OFF:
2824 AssertReleaseFailed();
2825 break;
2826 case GIC_REDIST_REG_INVLPIR_OFF:
2827 AssertReleaseFailed();
2828 break;
2829 case GIC_REDIST_REG_INVALLR_OFF:
2830 AssertReleaseFailed();
2831 break;
2832 default:
2833 AssertReleaseFailed();
2834 break;
2835 }
2836
2837 return rcStrict;
2838}
2839
2840
2841/**
2842 * Writes a GIC redistributor SGI/PPI frame register.
2843 *
2844 * @returns Strict VBox status code.
2845 * @param pDevIns The device instance.
2846 * @param pVCpu The cross context virtual CPU structure.
2847 * @param offReg The offset of the register being written.
2848 * @param uValue The register value.
2849 */
2850DECLINLINE(VBOXSTRICTRC) gicReDistWriteSgiPpiRegister(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue)
2851{
2852 VMCPU_ASSERT_EMT(pVCpu);
2853
2854#if 1
2855 PCGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PCGICDEV);
2856
2857 /*
2858 * GICR_IGROUPR0 and GICR_IGROUPR<n>E.
2859 */
2860 {
2861 uint16_t const cbReg = sizeof(uint32_t);
2862 if (offReg - GIC_REDIST_SGI_PPI_REG_IGROUPR0_OFF < GIC_REDIST_SGI_PPI_REG_IGROUPRnE_RANGE_SIZE)
2863 {
2864 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_IGROUPR0_OFF) / cbReg;
2865 return gicReDistWriteIntrGroupReg(pGicDev, pVCpu, idxReg, uValue);
2866 }
2867 }
2868
2869 /*
2870 * GICR_ISENABLER0 and GICR_ISENABLER<n>E.
2871 * GICR_ICENABLER0 and GICR_ICENABLER<n>E.
2872 */
2873 {
2874 uint16_t const cbReg = sizeof(uint32_t);
2875 if (offReg - GIC_REDIST_SGI_PPI_REG_ISENABLER0_OFF < GIC_REDIST_SGI_PPI_REG_ISENABLERnE_RANGE_SIZE)
2876 {
2877 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ISENABLER0_OFF) / cbReg;
2878 return gicReDistWriteIntrSetEnableReg(pGicDev, pVCpu, idxReg, uValue);
2879 }
2880 if (offReg - GIC_REDIST_SGI_PPI_REG_ICENABLER0_OFF < GIC_REDIST_SGI_PPI_REG_ICENABLERnE_RANGE_SIZE)
2881 {
2882 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ICENABLER0_OFF) / cbReg;
2883 return gicReDistWriteIntrClearEnableReg(pGicDev, pVCpu, idxReg, uValue);
2884 }
2885 }
2886
2887 /*
2888 * GICR_ISACTIVER0 and GICR_ISACTIVER<n>E.
2889 * GICR_ICACTIVER0 and GICR_ICACTIVER<n>E.
2890 */
2891 {
2892 uint16_t const cbReg = sizeof(uint32_t);
2893 if (offReg - GIC_REDIST_SGI_PPI_REG_ISACTIVER0_OFF < GIC_REDIST_SGI_PPI_REG_ISACTIVERnE_RANGE_SIZE)
2894 {
2895 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ISACTIVER0_OFF) / cbReg;
2896 return gicReDistWriteIntrSetActiveReg(pGicDev, pVCpu, idxReg, uValue);
2897 }
2898 if (offReg - GIC_REDIST_SGI_PPI_REG_ICACTIVER0_OFF < GIC_REDIST_SGI_PPI_REG_ICACTIVERnE_RANGE_SIZE)
2899 {
2900 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ICACTIVER0_OFF) / cbReg;
2901 return gicReDistWriteIntrClearActiveReg(pGicDev, pVCpu, idxReg, uValue);
2902 }
2903 }
2904
2905 /*
2906 * GICR_ISPENDR0 and GICR_ISPENDR<n>E.
2907 * GICR_ICPENDR0 and GICR_ICPENDR<n>E.
2908 */
2909 {
2910 uint16_t const cbReg = sizeof(uint32_t);
2911 if (offReg - GIC_REDIST_SGI_PPI_REG_ISPENDR0_OFF < GIC_REDIST_SGI_PPI_REG_ISPENDRnE_RANGE_SIZE)
2912 {
2913 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ISPENDR0_OFF) / cbReg;
2914 return gicReDistWriteIntrSetPendingReg(pGicDev, pVCpu, idxReg, uValue);
2915 }
2916 if (offReg - GIC_REDIST_SGI_PPI_REG_ICPENDR0_OFF < GIC_REDIST_SGI_PPI_REG_ICPENDRnE_RANGE_SIZE)
2917 {
2918 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ICPENDR0_OFF) / cbReg;
2919 return gicReDistWriteIntrClearPendingReg(pGicDev, pVCpu, idxReg, uValue);
2920 }
2921 }
2922
2923 /*
2924 * GICR_IPRIORITYR<n> and GICR_IPRIORITYR<n>E.
2925 */
2926 {
2927 uint16_t const cbReg = sizeof(uint32_t);
2928 if (offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START < GIC_REDIST_SGI_PPI_REG_IPRIORITYRnE_RANGE_SIZE)
2929 {
2930 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START) / cbReg;
2931 return gicReDistWriteIntrPriorityReg(pGicDev, pVCpu, idxReg, uValue);
2932 }
2933 }
2934
2935 /*
2936 * GICR_ICFGR0, GIC_ICFGR1 and GICR_ICFGR<n>E.
2937 */
2938 {
2939 uint16_t const cbReg = sizeof(uint32_t);
2940 if (offReg - GIC_REDIST_SGI_PPI_REG_ICFGR0_OFF < GIC_REDIST_SGI_PPI_REG_ICFGRnE_RANGE_SIZE)
2941 {
2942 uint16_t const idxReg = (offReg - GIC_REDIST_SGI_PPI_REG_ICFGR0_OFF) / cbReg;
2943 return gicReDistWriteIntrConfigReg(pGicDev, pVCpu, idxReg, uValue);
2944 }
2945 }
2946
2947 AssertReleaseFailed();
2948 return VERR_INTERNAL_ERROR_2;
2949#else
2950 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
2951 switch (offReg)
2952 {
2953 case GIC_REDIST_SGI_PPI_REG_IGROUPR0_OFF:
2954 ASMAtomicOrU32(&pThis->u32RegIGrp0, uValue);
2955 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
2956 break;
2957 case GIC_REDIST_SGI_PPI_REG_ISENABLER0_OFF:
2958 ASMAtomicOrU32(&pThis->bmIntEnabled, uValue);
2959 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
2960 break;
2961 case GIC_REDIST_SGI_PPI_REG_ICENABLER0_OFF:
2962 ASMAtomicAndU32(&pThis->bmIntEnabled, ~uValue);
2963 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
2964 break;
2965 case GIC_REDIST_SGI_PPI_REG_ISPENDR0_OFF:
2966 ASMAtomicOrU32(&pThis->bmIntPending, uValue);
2967 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
2968 break;
2969 case GIC_REDIST_SGI_PPI_REG_ICPENDR0_OFF:
2970 ASMAtomicAndU32(&pThis->bmIntPending, ~uValue);
2971 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
2972 break;
2973 case GIC_REDIST_SGI_PPI_REG_ISACTIVER0_OFF:
2974 ASMAtomicOrU32(&pThis->bmIntActive, uValue);
2975 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
2976 break;
2977 case GIC_REDIST_SGI_PPI_REG_ICACTIVER0_OFF:
2978 ASMAtomicAndU32(&pThis->bmIntActive, ~uValue);
2979 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
2980 break;
2981 case GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START:
2982 case GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START + 4:
2983 case GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START + 8:
2984 case GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START + 12:
2985 case GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START + 16:
2986 case GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START + 20:
2987 case GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START + 24:
2988 case GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START + 28:
2989 {
2990 /* Figure out the register which is written. */
2991 uint8_t idxPrio = offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYRn_OFF_START;
2992 Assert(idxPrio <= RT_ELEMENTS(pThis->abIntPriority) - sizeof(uint32_t));
2993 for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
2994 {
2995 pThis->abIntPriority[i] = (uint8_t)(uValue & 0xff);
2996 uValue >>= 8;
2997 }
2998 break;
2999 }
3000 case GIC_REDIST_SGI_PPI_REG_ICFGR0_OFF:
3001 ASMAtomicWriteU32(&pThis->u32RegICfg0, uValue);
3002 break;
3003 case GIC_REDIST_SGI_PPI_REG_ICFGR1_OFF:
3004 ASMAtomicWriteU32(&pThis->u32RegICfg1, uValue);
3005 break;
3006 default:
3007 //AssertReleaseFailed();
3008 break;
3009 }
3010 return rcStrict;
3011#endif
3012}
3013
3014
3015/**
3016 * @interface_method_impl{PDMGICBACKEND,pfnSetSpi}
3017 */
3018static DECLCALLBACK(int) gicSetSpi(PVMCC pVM, uint32_t uSpiIntId, bool fAsserted)
3019{
3020 LogFlowFunc(("pVM=%p uSpiIntId=%u fAsserted=%RTbool\n",
3021 pVM, uSpiIntId, fAsserted));
3022
3023 PGIC pGic = VM_TO_GIC(pVM);
3024 PPDMDEVINS pDevIns = pGic->CTX_SUFF(pDevIns);
3025 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
3026
3027 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
3028 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
3029
3030#if 0
3031 /* Update the interrupts pending state. */
3032 if (fAsserted)
3033 ASMAtomicOrU32(&pThis->bmIntPending, RT_BIT_32(uIntId));
3034 else
3035 ASMAtomicAndU32(&pThis->bmIntPending, ~RT_BIT_32(uIntId));
3036
3037 int rc = VBOXSTRICTRC_VAL(gicDistUpdateIrqState(pVM, pThis));
3038#else
3039 uint16_t const uIntId = GIC_INTID_RANGE_SPI_START + uSpiIntId;
3040 uint16_t const idxIntr = gicDistGetIndexFromIntId(uIntId);
3041
3042 Assert(idxIntr >= GIC_INTID_RANGE_SPI_START);
3043 AssertMsgReturnStmt(idxIntr < sizeof(pGicDev->bmIntrPending) * 8,
3044 ("out-of-range SPI interrupt ID %RU32 (%RU32)\n", uIntId, uSpiIntId),
3045 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3),
3046 VERR_INVALID_PARAMETER);
3047
3048 /* Update the interrupt pending state. */
3049 if (fAsserted)
3050 ASMBitSet(&pGicDev->bmIntrPending[0], idxIntr);
3051 else
3052 ASMBitClear(&pGicDev->bmIntrPending[0], idxIntr);
3053 int const rc = VBOXSTRICTRC_VAL(gicDistUpdateIrqState(pVM, pGicDev));
3054#endif
3055
3056 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
3057 return rc;
3058}
3059
3060
3061/**
3062 * @interface_method_impl{PDMGICBACKEND,pfnSetPpi}
3063 */
3064static DECLCALLBACK(int) gicSetPpi(PVMCPUCC pVCpu, uint32_t uPpiIntId, bool fAsserted)
3065{
3066 LogFlowFunc(("pVCpu=%p{.idCpu=%u} uPpiIntId=%u fAsserted=%RTbool\n", pVCpu, pVCpu->idCpu, uPpiIntId, fAsserted));
3067
3068 PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
3069 PCGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PCGICDEV);
3070 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
3071 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
3072 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
3073
3074#if 0
3075 AssertReturn(uIntId <= (GIC_INTID_RANGE_PPI_LAST - GIC_INTID_RANGE_PPI_START), VERR_INVALID_PARAMETER);
3076 int rc = gicReDistInterruptSet(pVCpu, uIntId + GIC_INTID_RANGE_PPI_START, fAsserted);
3077#else
3078 uint32_t const uIntId = GIC_INTID_RANGE_PPI_START + uPpiIntId;
3079 uint16_t const idxIntr = gicReDistGetIndexFromIntId(uIntId);
3080
3081 Assert(idxIntr >= GIC_INTID_RANGE_PPI_START);
3082 AssertMsgReturnStmt(idxIntr < sizeof(pGicCpu->bmIntrPending) * 8,
3083 ("out-of-range PPI interrupt ID %RU32 (%RU32)\n", uIntId, uPpiIntId),
3084 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3),
3085 VERR_INVALID_PARAMETER);
3086
3087 /* Update the interrupt pending state. */
3088 if (fAsserted)
3089 ASMBitSet(&pGicCpu->bmIntrPending[0], idxIntr);
3090 else
3091 ASMBitClear(&pGicCpu->bmIntrPending[0], idxIntr);
3092 int const rc = VBOXSTRICTRC_VAL(gicReDistUpdateIrqState(pGicDev, pVCpu));
3093#endif
3094
3095 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
3096
3097 return rc;
3098}
3099
3100
3101/**
3102 * Sets the specified software generated interrupt (SGI).
3103 *
3104 * @returns VBox status code.
3105 * @param pGicDev The GIC distributor state.
3106 * @param pVCpu The cross context virtual CPU structure.
3107 * @param pDestCpuSet Which CPUs to deliver the SGI to.
3108 * @param uIntId The SGI interrupt ID.
3109 */
3110static int gicSetSgi(PCGICDEV pGicDev, PVMCPUCC pVCpu, PCVMCPUSET pDestCpuSet, uint8_t uIntId)
3111{
3112#if 0
3113 LogFlowFunc(("pVCpu=%p{.idCpu=%u} uIntId=%u fAsserted=%RTbool\n",
3114 pVCpu, pVCpu->idCpu, uIntId, fAsserted));
3115
3116 PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
3117 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
3118 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
3119
3120 AssertReturn(uIntId <= (GIC_INTID_RANGE_SGI_LAST - GIC_INTID_RANGE_SGI_START), VERR_INVALID_PARAMETER);
3121 int rc = gicReDistInterruptSet(pVCpu, uIntId + GIC_INTID_RANGE_SGI_START, fAsserted);
3122 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
3123#else
3124 LogFlowFunc(("pVCpu=%p{.idCpu=%u} uIntId=%u\n", pVCpu, pVCpu->idCpu, uIntId));
3125
3126 PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
3127 PCVMCC pVM = pVCpu->CTX_SUFF(pVM);
3128 uint32_t const cCpus = pVM->cCpus;
3129 AssertReturn(uIntId <= GIC_INTID_RANGE_SGI_LAST, VERR_INVALID_PARAMETER);
3130
3131 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
3132 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
3133
3134 for (VMCPUID idCpu = 0; idCpu < cCpus; idCpu++)
3135 if (VMCPUSET_IS_PRESENT(pDestCpuSet, idCpu))
3136 {
3137 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVM->CTX_SUFF(apCpus)[idCpu]);
3138 pGicCpu->bmIntrPending[0] |= RT_BIT_32(uIntId);
3139 }
3140
3141 int const rc = VBOXSTRICTRC_VAL(gicDistUpdateIrqState(pVM, pGicDev));
3142 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
3143#endif
3144 return rc;
3145}
3146
3147
3148/**
3149 * Writes to the redistributor's SGI group 1 register (ICC_SGI1R_EL1).
3150 *
3151 * @returns Strict VBox status code.
3152 * @param pGicDev The GIC distributor state.
3153 * @param pVCpu The cross context virtual CPU structure.
3154 * @param uValue The value being written to the ICC_SGI1R_EL1 register.
3155 */
3156static VBOXSTRICTRC gicReDistWriteSgiReg(PCGICDEV pGicDev, PVMCPUCC pVCpu, uint64_t uValue)
3157{
3158 PCGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
3159 VMCPUSET DestCpuSet;
3160 if (uValue & ARMV8_ICC_SGI1R_EL1_AARCH64_IRM)
3161 {
3162 /*
3163 * Deliver to all VCPUs but this one.
3164 */
3165 VMCPUSET_FILL(&DestCpuSet);
3166 VMCPUSET_DEL(&DestCpuSet, pVCpu->idCpu);
3167 }
3168 else
3169 {
3170 /*
3171 * Target specific VCPUs.
3172 * See ARM GICv3 and GICv4 Software Overview spec 3.3 "Affinity routing".
3173 */
3174 VMCPUSET_EMPTY(&DestCpuSet);
3175 bool const fRangeSelSupport = RT_BOOL(pGicCpu->uIccCtlr & ARMV8_ICC_CTLR_EL1_AARCH64_RSS);
3176 uint8_t const idRangeStart = ARMV8_ICC_SGI1R_EL1_AARCH64_RS_GET(uValue) * 16;
3177 uint16_t const bmCpuInterfaces = ARMV8_ICC_SGI1R_EL1_AARCH64_TARGET_LIST_GET(uValue);
3178 uint8_t const uAff1 = ARMV8_ICC_SGI1R_EL1_AARCH64_AFF1_GET(uValue);
3179 uint8_t const uAff2 = ARMV8_ICC_SGI1R_EL1_AARCH64_AFF2_GET(uValue);
3180 uint8_t const uAff3 = ARMV8_ICC_SGI1R_EL1_AARCH64_AFF3_GET(uValue);
3181 uint32_t const cCpus = pVCpu->CTX_SUFF(pVM)->cCpus;
3182 for (uint8_t idCpuInterface = 0; idCpuInterface < 16; idCpuInterface++)
3183 {
3184 if (bmCpuInterfaces & RT_BIT(idCpuInterface))
3185 {
3186 VMCPUID idCpuTarget;
3187 if (fRangeSelSupport)
3188 idCpuTarget = RT_MAKE_U32_FROM_U8(idRangeStart + idCpuInterface, uAff1, uAff2, uAff3);
3189 else
3190 idCpuTarget = gicGetCpuIdFromAffinity(idCpuInterface, uAff1, uAff2, uAff3);
3191 if (RT_LIKELY(idCpuTarget < cCpus))
3192 VMCPUSET_ADD(&DestCpuSet, idCpuTarget);
3193 else
3194 AssertReleaseFailed();
3195 }
3196 }
3197 }
3198
3199 if (!VMCPUSET_IS_EMPTY(&DestCpuSet))
3200 {
3201 uint8_t const uSgiIntId = ARMV8_ICC_SGI1R_EL1_AARCH64_INTID_GET(uValue);
3202 Assert(GIC_IS_INTR_SGI(uSgiIntId));
3203#if 0
3204 uint16_t const idxIdb = uSgiIntId;
3205 gicPostInterrupt(pVCpu, &DestCpuSet, idxIdb);
3206#else
3207 gicSetSgi(pGicDev, pVCpu, &DestCpuSet, uSgiIntId);
3208#endif
3209 }
3210 return VINF_SUCCESS;
3211}
3212
3213
3214/**
3215 * @interface_method_impl{PDMGICBACKEND,pfnReadSysReg}
3216 */
3217static DECLCALLBACK(VBOXSTRICTRC) gicReadSysReg(PVMCPUCC pVCpu, uint32_t u32Reg, uint64_t *pu64Value)
3218{
3219 /*
3220 * Validate.
3221 */
3222 VMCPU_ASSERT_EMT(pVCpu);
3223 Assert(pu64Value);
3224
3225 *pu64Value = 0;
3226 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
3227 PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
3228 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
3229
3230 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
3231 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
3232
3233 switch (u32Reg)
3234 {
3235 case ARMV8_AARCH64_SYSREG_ICC_PMR_EL1:
3236 *pu64Value = pGicCpu->bInterruptPriority;
3237 break;
3238 case ARMV8_AARCH64_SYSREG_ICC_IAR0_EL1:
3239 AssertReleaseFailed();
3240 break;
3241 case ARMV8_AARCH64_SYSREG_ICC_EOIR0_EL1:
3242 AssertReleaseFailed();
3243 break;
3244 case ARMV8_AARCH64_SYSREG_ICC_HPPIR0_EL1:
3245 AssertReleaseFailed();
3246 break;
3247 case ARMV8_AARCH64_SYSREG_ICC_BPR0_EL1:
3248 *pu64Value = ARMV8_ICC_BPR0_EL1_AARCH64_BINARYPOINT_SET(pGicCpu->bBinaryPointGrp0);
3249 break;
3250 case ARMV8_AARCH64_SYSREG_ICC_AP0R0_EL1:
3251 AssertReleaseFailed();
3252 break;
3253 case ARMV8_AARCH64_SYSREG_ICC_AP0R1_EL1:
3254 AssertReleaseFailed();
3255 break;
3256 case ARMV8_AARCH64_SYSREG_ICC_AP0R2_EL1:
3257 AssertReleaseFailed();
3258 break;
3259 case ARMV8_AARCH64_SYSREG_ICC_AP0R3_EL1:
3260 AssertReleaseFailed();
3261 break;
3262 case ARMV8_AARCH64_SYSREG_ICC_AP1R0_EL1:
3263 AssertReleaseFailed();
3264 break;
3265 case ARMV8_AARCH64_SYSREG_ICC_AP1R1_EL1:
3266 AssertReleaseFailed();
3267 break;
3268 case ARMV8_AARCH64_SYSREG_ICC_AP1R2_EL1:
3269 AssertReleaseFailed();
3270 break;
3271 case ARMV8_AARCH64_SYSREG_ICC_AP1R3_EL1:
3272 AssertReleaseFailed();
3273 break;
3274 case ARMV8_AARCH64_SYSREG_ICC_NMIAR1_EL1:
3275 AssertReleaseFailed();
3276 break;
3277 case ARMV8_AARCH64_SYSREG_ICC_DIR_EL1:
3278 AssertReleaseFailed();
3279 break;
3280 case ARMV8_AARCH64_SYSREG_ICC_RPR_EL1:
3281 *pu64Value = pGicCpu->abRunningPriorities[pGicCpu->idxRunningPriority];
3282 break;
3283 case ARMV8_AARCH64_SYSREG_ICC_SGI1R_EL1:
3284 AssertReleaseFailed();
3285 break;
3286 case ARMV8_AARCH64_SYSREG_ICC_ASGI1R_EL1:
3287 AssertReleaseFailed();
3288 break;
3289 case ARMV8_AARCH64_SYSREG_ICC_SGI0R_EL1:
3290 AssertReleaseFailed();
3291 break;
3292 case ARMV8_AARCH64_SYSREG_ICC_IAR1_EL1:
3293 {
3294#if 0
3295 /** @todo Figure out the highest priority interrupt. */
3296 uint32_t bmIntActive = ASMAtomicReadU32(&pThis->bmIntActive);
3297 uint32_t bmIntEnabled = ASMAtomicReadU32(&pThis->bmIntEnabled);
3298 uint32_t bmPending = (ASMAtomicReadU32(&pThis->bmIntPending) & bmIntEnabled) & ~bmIntActive;
3299 int32_t idxIntPending = ASMBitFirstSet(&bmPending, sizeof(bmPending) * 8);
3300 if (idxIntPending > -1)
3301 {
3302 /* Mark the interrupt as active. */
3303 ASMAtomicOrU32(&pThis->bmIntActive, RT_BIT_32(idxIntPending));
3304 /* Drop priority. */
3305 Assert((uint32_t)idxIntPending < RT_ELEMENTS(pThis->abIntPriority));
3306 Assert(pThis->idxRunningPriority < RT_ELEMENTS(pThis->abRunningPriorities) - 1);
3307
3308 LogFlowFunc(("Dropping interrupt priority from %u -> %u (idxRunningPriority: %u -> %u)\n",
3309 pThis->abRunningPriorities[pThis->idxRunningPriority],
3310 pThis->abIntPriority[idxIntPending],
3311 pThis->idxRunningPriority, pThis->idxRunningPriority + 1));
3312
3313 pThis->abRunningPriorities[++pThis->idxRunningPriority] = pThis->abIntPriority[idxIntPending];
3314
3315 /* Clear edge level interrupts like SGIs as pending. */
3316 if (idxIntPending <= GIC_INTID_RANGE_SGI_LAST)
3317 ASMAtomicBitClear(&pThis->bmIntPending, idxIntPending);
3318 *pu64Value = idxIntPending;
3319 gicReDistUpdateIrqState(pThis, pVCpu);
3320 }
3321 else
3322 {
3323 /** @todo This is wrong as the guest might decide to prioritize PPIs and SPIs differently. */
3324 bmIntActive = ASMAtomicReadU32(&pGicDev->bmIntActive);
3325 bmIntEnabled = ASMAtomicReadU32(&pGicDev->bmIntEnabled);
3326 bmPending = (ASMAtomicReadU32(&pGicDev->bmIntPending) & bmIntEnabled) & ~bmIntActive;
3327 idxIntPending = ASMBitFirstSet(&bmPending, sizeof(bmPending) * 8);
3328 if ( idxIntPending > -1
3329 && pGicDev->abIntPriority[idxIntPending] < pThis->bInterruptPriority)
3330 {
3331 /* Mark the interrupt as active. */
3332 ASMAtomicOrU32(&pGicDev->bmIntActive, RT_BIT_32(idxIntPending));
3333
3334 /* Drop priority. */
3335 Assert((uint32_t)idxIntPending < RT_ELEMENTS(pGicDev->abIntPriority));
3336 Assert(pThis->idxRunningPriority < RT_ELEMENTS(pThis->abRunningPriorities) - 1);
3337
3338 LogFlowFunc(("Dropping interrupt priority from %u -> %u (idxRunningPriority: %u -> %u)\n",
3339 pThis->abRunningPriorities[pThis->idxRunningPriority],
3340 pThis->abIntPriority[idxIntPending],
3341 pThis->idxRunningPriority, pThis->idxRunningPriority + 1));
3342
3343 pThis->abRunningPriorities[++pThis->idxRunningPriority] = pGicDev->abIntPriority[idxIntPending];
3344
3345 *pu64Value = idxIntPending + GIC_INTID_RANGE_SPI_START;
3346 gicReDistUpdateIrqState(pThis, pVCpu);
3347 }
3348 else
3349 *pu64Value = GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT;
3350 }
3351#else
3352 *pu64Value = gicAckHighestPrioPendingIntr(pGicDev, pVCpu, false /*fGroup0*/, true /*fGroup1*/);
3353#endif
3354 break;
3355 }
3356 case ARMV8_AARCH64_SYSREG_ICC_EOIR1_EL1:
3357 AssertReleaseFailed();
3358 break;
3359 case ARMV8_AARCH64_SYSREG_ICC_HPPIR1_EL1:
3360 {
3361#if 0
3362 /** @todo Figure out the highest priority interrupt. */
3363 uint32_t bmIntActive = ASMAtomicReadU32(&pThis->bmIntActive);
3364 uint32_t bmIntEnabled = ASMAtomicReadU32(&pThis->bmIntEnabled);
3365 uint32_t bmPending = (ASMAtomicReadU32(&pThis->bmIntPending) & bmIntEnabled) & ~bmIntActive;
3366 int32_t idxIntPending = ASMBitFirstSet(&bmPending, sizeof(bmPending) * 8);
3367 if (idxIntPending > -1)
3368 *pu64Value = idxIntPending;
3369 else
3370 {
3371 /** @todo This is wrong as the guest might decide to prioritize PPIs and SPIs differently. */
3372 bmIntActive = ASMAtomicReadU32(&pGicDev->bmIntActive);
3373 bmIntEnabled = ASMAtomicReadU32(&pGicDev->bmIntEnabled);
3374 bmPending = (ASMAtomicReadU32(&pGicDev->bmIntPending) & bmIntEnabled) & ~bmIntActive;
3375 idxIntPending = ASMBitFirstSet(&bmPending, sizeof(bmPending) * 8);
3376 if (idxIntPending > -1)
3377 *pu64Value = idxIntPending + GIC_INTID_RANGE_SPI_START;
3378 else
3379 *pu64Value = GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT;
3380 }
3381#else
3382 AssertReleaseFailed();
3383 *pu64Value = gicGetHighestPrioPendingIntr(pVCpu->pVMR3, pGicDev, false /*fGroup0*/, true /*fGroup1*/);
3384#endif
3385 break;
3386 }
3387 case ARMV8_AARCH64_SYSREG_ICC_BPR1_EL1:
3388 *pu64Value = ARMV8_ICC_BPR1_EL1_AARCH64_BINARYPOINT_SET(pGicCpu->bBinaryPointGrp1);
3389 break;
3390 case ARMV8_AARCH64_SYSREG_ICC_CTLR_EL1:
3391 *pu64Value = pGicCpu->uIccCtlr;
3392 break;
3393 case ARMV8_AARCH64_SYSREG_ICC_SRE_EL1:
3394 AssertReleaseFailed();
3395 break;
3396 case ARMV8_AARCH64_SYSREG_ICC_IGRPEN0_EL1:
3397 *pu64Value = pGicCpu->fIrqGrp0Enabled ? ARMV8_ICC_IGRPEN0_EL1_AARCH64_ENABLE : 0;
3398 break;
3399 case ARMV8_AARCH64_SYSREG_ICC_IGRPEN1_EL1:
3400 *pu64Value = pGicCpu->fIrqGrp1Enabled ? ARMV8_ICC_IGRPEN1_EL1_AARCH64_ENABLE : 0;
3401 break;
3402 default:
3403 AssertReleaseFailed();
3404 break;
3405 }
3406
3407 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
3408
3409 LogFlowFunc(("pVCpu=%p u32Reg=%#x{%s} pu64Value=%RX64\n", pVCpu, u32Reg, gicIccGetRegDescription(u32Reg), *pu64Value));
3410 return VINF_SUCCESS;
3411}
3412
3413
3414/**
3415 * @interface_method_impl{PDMGICBACKEND,pfnWriteSysReg}
3416 */
3417static DECLCALLBACK(VBOXSTRICTRC) gicWriteSysReg(PVMCPUCC pVCpu, uint32_t u32Reg, uint64_t u64Value)
3418{
3419 /*
3420 * Validate.
3421 */
3422 VMCPU_ASSERT_EMT(pVCpu);
3423 LogFlowFunc(("pVCpu=%p u32Reg=%#x{%s} u64Value=%RX64\n", pVCpu, u32Reg, gicIccGetRegDescription(u32Reg), u64Value));
3424
3425 PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
3426 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
3427 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
3428
3429 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
3430 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
3431
3432 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
3433 switch (u32Reg)
3434 {
3435 case ARMV8_AARCH64_SYSREG_ICC_PMR_EL1:
3436 LogFlowFunc(("ICC_PMR_EL1: Interrupt priority now %u\n", (uint8_t)u64Value));
3437#if 0
3438 ASMAtomicWriteU8(&pThis->bInterruptPriority, (uint8_t)u64Value);
3439 gicReDistUpdateIrqState(pThis, pVCpu);
3440#else
3441 pGicCpu->bInterruptPriority = (uint8_t)u64Value;
3442 rcStrict = gicReDistUpdateIrqState(pGicDev, pVCpu);
3443#endif
3444 break;
3445 case ARMV8_AARCH64_SYSREG_ICC_IAR0_EL1:
3446 AssertReleaseFailed();
3447 break;
3448 case ARMV8_AARCH64_SYSREG_ICC_EOIR0_EL1:
3449 AssertReleaseFailed();
3450 break;
3451 case ARMV8_AARCH64_SYSREG_ICC_HPPIR0_EL1:
3452 AssertReleaseFailed();
3453 break;
3454 case ARMV8_AARCH64_SYSREG_ICC_BPR0_EL1:
3455#if 0
3456 pThis->bBinaryPointGrp0 = (uint8_t)ARMV8_ICC_BPR0_EL1_AARCH64_BINARYPOINT_GET(u64Value);
3457#else
3458 pGicCpu->bBinaryPointGrp0 = (uint8_t)ARMV8_ICC_BPR0_EL1_AARCH64_BINARYPOINT_GET(u64Value);
3459#endif
3460 break;
3461 case ARMV8_AARCH64_SYSREG_ICC_AP0R0_EL1:
3462 /** @todo */
3463 break;
3464 case ARMV8_AARCH64_SYSREG_ICC_AP0R1_EL1:
3465 AssertReleaseFailed();
3466 break;
3467 case ARMV8_AARCH64_SYSREG_ICC_AP0R2_EL1:
3468 AssertReleaseFailed();
3469 break;
3470 case ARMV8_AARCH64_SYSREG_ICC_AP0R3_EL1:
3471 AssertReleaseFailed();
3472 break;
3473 case ARMV8_AARCH64_SYSREG_ICC_AP1R0_EL1:
3474 /** @todo */
3475 break;
3476 case ARMV8_AARCH64_SYSREG_ICC_AP1R1_EL1:
3477 AssertReleaseFailed();
3478 break;
3479 case ARMV8_AARCH64_SYSREG_ICC_AP1R2_EL1:
3480 AssertReleaseFailed();
3481 break;
3482 case ARMV8_AARCH64_SYSREG_ICC_AP1R3_EL1:
3483 AssertReleaseFailed();
3484 break;
3485 case ARMV8_AARCH64_SYSREG_ICC_NMIAR1_EL1:
3486 AssertReleaseFailed();
3487 break;
3488 case ARMV8_AARCH64_SYSREG_ICC_DIR_EL1:
3489 AssertReleaseFailed();
3490 break;
3491 case ARMV8_AARCH64_SYSREG_ICC_RPR_EL1:
3492 AssertReleaseFailed();
3493 break;
3494 case ARMV8_AARCH64_SYSREG_ICC_SGI1R_EL1:
3495 {
3496#if 0
3497 uint32_t uIntId = ARMV8_ICC_SGI1R_EL1_AARCH64_INTID_GET(u64Value) - GIC_INTID_RANGE_SGI_START;
3498 if (u64Value & ARMV8_ICC_SGI1R_EL1_AARCH64_IRM)
3499 {
3500 /* Route to all but this vCPU. */
3501 for (uint32_t i = 0; i < pVCpu->pVMR3->cCpus; i++)
3502 {
3503 if (i != pVCpu->idCpu)
3504 {
3505 PVMCPUCC pVCpuDst = VMMGetCpuById(pVCpu->CTX_SUFF(pVM), i);
3506 if (pVCpuDst)
3507 gicSetSgi(pVCpuDst, uIntId, true /*fAsserted*/);
3508 else
3509 AssertFailed();
3510 }
3511 }
3512 }
3513 else
3514 {
3515 /* Examine target list. */
3516 /** @todo Range selector support. */
3517 VMCPUID idCpu = 0;
3518 uint16_t uTgtList = ARMV8_ICC_SGI1R_EL1_AARCH64_TARGET_LIST_GET(u64Value);
3519 /** @todo rewrite using ASMBitFirstSetU16. */
3520 while (uTgtList)
3521 {
3522 if (uTgtList & 0x1)
3523 {
3524 PVMCPUCC pVCpuDst = VMMGetCpuById(pVCpu->CTX_SUFF(pVM), idCpu);
3525 if (pVCpuDst)
3526 gicSetSgi(pVCpuDst, uIntId, true /*fAsserted*/);
3527 else
3528 AssertFailed();
3529 }
3530 uTgtList >>= 1;
3531 idCpu++;
3532 }
3533 }
3534#else
3535 gicReDistWriteSgiReg(pGicDev, pVCpu, u64Value);
3536#endif
3537 break;
3538 }
3539 case ARMV8_AARCH64_SYSREG_ICC_ASGI1R_EL1:
3540 AssertReleaseFailed();
3541 break;
3542 case ARMV8_AARCH64_SYSREG_ICC_SGI0R_EL1:
3543 AssertReleaseFailed();
3544 break;
3545 case ARMV8_AARCH64_SYSREG_ICC_IAR1_EL1:
3546 AssertReleaseFailed();
3547 break;
3548 case ARMV8_AARCH64_SYSREG_ICC_EOIR1_EL1:
3549 {
3550#if 0
3551 /* Mark the interrupt as not active anymore, though it might still be pending. */
3552 if (u64Value < GIC_INTID_RANGE_SPI_START)
3553 ASMAtomicAndU32(&pThis->bmIntActive, ~RT_BIT_32((uint32_t)u64Value));
3554 else
3555 ASMAtomicAndU32(&pGicDev->bmIntActive, ~RT_BIT_32((uint32_t)(u64Value - GIC_INTID_RANGE_SPI_START)));
3556
3557 /* Restore previous interrupt priority. */
3558 Assert(pThis->idxRunningPriority > 0);
3559 if (RT_LIKELY(pThis->idxRunningPriority))
3560 {
3561 LogFlowFunc(("Restoring interrupt priority from %u -> %u (idxRunningPriority: %u -> %u)\n",
3562 pThis->abRunningPriorities[pThis->idxRunningPriority],
3563 pThis->abRunningPriorities[pThis->idxRunningPriority - 1],
3564 pThis->idxRunningPriority, pThis->idxRunningPriority - 1));
3565 pThis->idxRunningPriority--;
3566 }
3567 gicReDistUpdateIrqState(pThis, pVCpu);
3568#else
3569 /*
3570 * We only support priority drop + interrupt deactivation with writes to this register.
3571 * This avoids an extra access which would be required by software for deactivation.
3572 */
3573 Assert(!(pGicCpu->uIccCtlr & ARMV8_ICC_CTLR_EL1_AARCH64_EOIMODE));
3574
3575 /*
3576 * Mark the interrupt as inactive, though it might still be pending.
3577 * WARNING! The order of the 'if' checks below are crucial.
3578 */
3579 uint16_t const uIntId = (uint16_t)u64Value;
3580 if (uIntId <= GIC_INTID_RANGE_PPI_LAST)
3581 {
3582 /* SGIs and PPIs. */
3583 AssertCompile(GIC_INTID_RANGE_PPI_LAST < 8 * sizeof(pGicDev->bmIntrActive[0]));
3584 Assert(pGicDev->fAffRoutingEnabled);
3585 pGicCpu->bmIntrActive[0] &= ~RT_BIT_32(uIntId);
3586 }
3587 else if (uIntId <= GIC_INTID_RANGE_SPI_LAST)
3588 {
3589 /* SPIs. */
3590 uint16_t const idxIntr = /*gicDistGetIndexFromIntId*/(uIntId);
3591 AssertReturn(idxIntr < sizeof(pGicDev->bmIntrActive) * 8, VERR_BUFFER_OVERFLOW);
3592 ASMBitClear(&pGicDev->bmIntrActive[0], idxIntr);
3593 }
3594 else if (uIntId <= GIC_INTID_RANGE_EXT_PPI_LAST)
3595 {
3596 /* Extended PPIs. */
3597 uint16_t const idxIntr = gicReDistGetIndexFromIntId(uIntId);
3598 AssertReturn(idxIntr < sizeof(pGicCpu->bmIntrActive) * 8, VERR_BUFFER_OVERFLOW);
3599 ASMBitClear(&pGicCpu->bmIntrActive[0], idxIntr);
3600 }
3601 else if (uIntId <= GIC_INTID_RANGE_EXT_SPI_LAST)
3602 {
3603 /* Extended SPIs. */
3604 uint16_t const idxIntr = gicDistGetIndexFromIntId(uIntId);
3605 AssertReturn(idxIntr < sizeof(pGicDev->bmIntrActive) * 8, VERR_BUFFER_OVERFLOW);
3606 ASMBitClear(&pGicDev->bmIntrActive[0], idxIntr);
3607 }
3608 else
3609 {
3610 AssertMsgFailed(("Invalid INTID %u\n", uIntId));
3611 break;
3612 }
3613
3614 /*
3615 * Restore previous interrupt priority.
3616 */
3617 Assert(pGicCpu->idxRunningPriority > 0);
3618 if (RT_LIKELY(pGicCpu->idxRunningPriority))
3619 {
3620 LogFlowFunc(("Restoring interrupt priority from %u -> %u (idxRunningPriority: %u -> %u)\n",
3621 pGicCpu->abRunningPriorities[pGicCpu->idxRunningPriority],
3622 pGicCpu->abRunningPriorities[pGicCpu->idxRunningPriority - 1],
3623 pGicCpu->idxRunningPriority, pGicCpu->idxRunningPriority - 1));
3624 pGicCpu->idxRunningPriority--;
3625 }
3626 rcStrict = gicReDistUpdateIrqState(pGicDev, pVCpu);
3627#endif
3628 break;
3629 }
3630 case ARMV8_AARCH64_SYSREG_ICC_HPPIR1_EL1:
3631 AssertReleaseFailed();
3632 break;
3633 case ARMV8_AARCH64_SYSREG_ICC_BPR1_EL1:
3634 pGicCpu->bBinaryPointGrp1 = (uint8_t)ARMV8_ICC_BPR1_EL1_AARCH64_BINARYPOINT_GET(u64Value);
3635 break;
3636 case ARMV8_AARCH64_SYSREG_ICC_CTLR_EL1:
3637 pGicCpu->uIccCtlr &= ARMV8_ICC_CTLR_EL1_RW;
3638 /** @todo */
3639 break;
3640 case ARMV8_AARCH64_SYSREG_ICC_SRE_EL1:
3641 AssertReleaseFailed();
3642 break;
3643 case ARMV8_AARCH64_SYSREG_ICC_IGRPEN0_EL1:
3644 pGicCpu->fIrqGrp0Enabled = RT_BOOL(u64Value & ARMV8_ICC_IGRPEN0_EL1_AARCH64_ENABLE);
3645 break;
3646 case ARMV8_AARCH64_SYSREG_ICC_IGRPEN1_EL1:
3647 pGicCpu->fIrqGrp1Enabled = RT_BOOL(u64Value & ARMV8_ICC_IGRPEN1_EL1_AARCH64_ENABLE);
3648 break;
3649 default:
3650 AssertReleaseFailed();
3651 break;
3652 }
3653
3654 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
3655 return rcStrict;
3656}
3657
3658
3659/**
3660 * Initializes the GIC distributor state.
3661 *
3662 * @param pDevIns The device instance.
3663 */
3664DECLHIDDEN(void) gicInit(PPDMDEVINS pDevIns)
3665{
3666 LogFlowFunc(("\n"));
3667 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
3668 RT_ZERO(pGicDev->bmIntrGroup);
3669 RT_ZERO(pGicDev->bmIntrConfig);
3670 RT_ZERO(pGicDev->bmIntrEnabled);
3671 RT_ZERO(pGicDev->bmIntrPending);
3672 RT_ZERO(pGicDev->bmIntrActive);
3673 RT_ZERO(pGicDev->abIntrPriority);
3674 RT_ZERO(pGicDev->au32IntrRouting);
3675 RT_ZERO(pGicDev->bmIntrRoutingMode);
3676 pGicDev->fIrqGrp0Enabled = false;
3677 pGicDev->fIrqGrp1Enabled = false;
3678 pGicDev->fAffRoutingEnabled = true; /* GICv2 backwards compatibility is not implemented, so this is RA1/WI. */
3679}
3680
3681
3682/**
3683 * Initialies the GIC redistributor and CPU interface state.
3684 *
3685 * @param pDevIns The device instance.
3686 * @param pVCpu The cross context virtual CPU structure.
3687 */
3688DECLHIDDEN(void) gicInitCpu(PPDMDEVINS pDevIns, PVMCPUCC pVCpu)
3689{
3690 LogFlowFunc(("[%u]\n", pVCpu->idCpu));
3691 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
3692 PGICCPU pGicCpu = &pVCpu->gic.s;
3693 RT_ZERO(pGicCpu->bmIntrGroup);
3694 RT_ZERO(pGicCpu->bmIntrConfig);
3695 RT_ZERO(pGicCpu->bmIntrEnabled);
3696 RT_ZERO(pGicCpu->bmIntrPending);
3697 RT_ZERO(pGicCpu->bmIntrActive);
3698 RT_ZERO(pGicCpu->abIntrPriority);
3699 pGicCpu->fRegWritePending = false;
3700
3701 /* SGIs are always edge-triggered, writes to GICR_ICFGR0 are to be ignored. */
3702 pGicCpu->bmIntrConfig[0] = 0xaaaaaaaa;
3703
3704 pGicCpu->uIccCtlr = ARMV8_ICC_CTLR_EL1_AARCH64_PMHE
3705 | ARMV8_ICC_CTLR_EL1_AARCH64_PRIBITS_SET(4)
3706 | ARMV8_ICC_CTLR_EL1_AARCH64_IDBITS_SET(ARMV8_ICC_CTLR_EL1_AARCH64_IDBITS_16BITS)
3707 | (pGicDev->fRangeSelSupport ? ARMV8_ICC_CTLR_EL1_AARCH64_RSS : 0);
3708
3709 memset((void *)&pGicCpu->abRunningPriorities[0], 0xff, sizeof(pGicCpu->abRunningPriorities));
3710 pGicCpu->idxRunningPriority = 0;
3711 pGicCpu->bInterruptPriority = 0; /* Means no interrupt gets through to the PE. */
3712 pGicCpu->fIrqGrp0Enabled = false;
3713 pGicCpu->fIrqGrp1Enabled = false;
3714
3715 /* The binary point register are undefined on reset, initialized
3716 with arbitrarily chosen values in our implementation. */
3717 pGicCpu->bBinaryPointGrp0 = 3;
3718 pGicCpu->bBinaryPointGrp1 = 3;
3719}
3720
3721
3722/**
3723 * Initializes per-VM GIC to the state following a power-up or hardware
3724 * reset.
3725 *
3726 * @param pDevIns The device instance.
3727 */
3728DECLHIDDEN(void) gicReset(PPDMDEVINS pDevIns)
3729{
3730 LogFlowFunc(("\n"));
3731 gicInit(pDevIns);
3732}
3733
3734
3735/**
3736 * Initializes per-VCPU GIC to the state following a power-up or hardware
3737 * reset.
3738 *
3739 * @param pVCpu The cross context virtual CPU structure.
3740 */
3741DECLHIDDEN(void) gicResetCpu(PPDMDEVINS pDevIns, PVMCPUCC pVCpu)
3742{
3743 LogFlowFunc(("[%u]\n", pVCpu->idCpu));
3744 VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu);
3745 gicInitCpu(pDevIns, pVCpu);
3746}
3747
3748
3749/**
3750 * @callback_method_impl{FNIOMMMIONEWREAD}
3751 */
3752DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) gicDistMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
3753{
3754 NOREF(pvUser);
3755 Assert(!(off & 0x3));
3756 Assert(cb == 4); RT_NOREF_PV(cb);
3757
3758 PVMCPUCC pVCpu = PDMDevHlpGetVMCPU(pDevIns);
3759 uint16_t offReg = off & 0xfffc;
3760 uint32_t uValue = 0;
3761
3762 STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioRead));
3763
3764 VBOXSTRICTRC rc = VBOXSTRICTRC_VAL(gicDistReadRegister(pDevIns, pVCpu, offReg, &uValue));
3765 *(uint32_t *)pv = uValue;
3766
3767 LogFlowFunc(("[%u]: offReg=%#RX16 (%s) uValue=%#RX32\n", pVCpu->idCpu, offReg, gicDistGetRegDescription(offReg), uValue));
3768 return rc;
3769}
3770
3771
3772/**
3773 * @callback_method_impl{FNIOMMMIONEWWRITE}
3774 */
3775DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) gicDistMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
3776{
3777 NOREF(pvUser);
3778 Assert(!(off & 0x3));
3779 Assert(cb == 4); RT_NOREF_PV(cb);
3780
3781 PVMCPUCC pVCpu = PDMDevHlpGetVMCPU(pDevIns);
3782 uint16_t offReg = off & 0xfffc;
3783 uint32_t uValue = *(uint32_t *)pv;
3784
3785 STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioWrite));
3786 LogFlowFunc(("[%u]: offReg=%#RX16 (%s) uValue=%#RX32\n", pVCpu->idCpu, offReg, gicDistGetRegDescription(offReg), uValue));
3787
3788 return gicDistWriteRegister(pDevIns, pVCpu, offReg, uValue);
3789}
3790
3791
3792/**
3793 * @callback_method_impl{FNIOMMMIONEWREAD}
3794 */
3795DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) gicReDistMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
3796{
3797 NOREF(pvUser);
3798 Assert(!(off & 0x3));
3799 Assert(cb == 4); RT_NOREF_PV(cb);
3800
3801 /*
3802 * Determine the redistributor being targeted. Each redistributor takes
3803 * GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE bytes
3804 * and the redistributors are adjacent.
3805 */
3806 uint32_t const idReDist = off / (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
3807 off %= (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
3808
3809 PVMCC pVM = PDMDevHlpGetVM(pDevIns);
3810 Assert(idReDist < pVM->cCpus);
3811 PVMCPUCC pVCpu = pVM->CTX_SUFF(apCpus)[idReDist];
3812
3813 STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioRead));
3814
3815 /* Redistributor or SGI/PPI frame? */
3816 uint16_t const offReg = off & 0xfffc;
3817 uint32_t uValue = 0;
3818 VBOXSTRICTRC rcStrict;
3819 if (off < GIC_REDIST_REG_FRAME_SIZE)
3820 rcStrict = gicReDistReadRegister(pDevIns, pVCpu, idReDist, offReg, &uValue);
3821 else
3822 rcStrict = gicReDistReadSgiPpiRegister(pDevIns, pVCpu, offReg, &uValue);
3823
3824 *(uint32_t *)pv = uValue;
3825 LogFlowFunc(("[%u]: off=%RGp idReDist=%u offReg=%#RX16 (%s) uValue=%#RX32 -> %Rrc\n", pVCpu->idCpu, off, idReDist, offReg,
3826 gicReDistGetRegDescription(offReg), uValue, VBOXSTRICTRC_VAL(rcStrict)));
3827 return rcStrict;
3828}
3829
3830
3831/**
3832 * @callback_method_impl{FNIOMMMIONEWWRITE}
3833 */
3834DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) gicReDistMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
3835{
3836 NOREF(pvUser);
3837 Assert(!(off & 0x3));
3838 Assert(cb == 4); RT_NOREF_PV(cb);
3839
3840 uint32_t uValue = *(uint32_t *)pv;
3841
3842 /*
3843 * Determine the redistributor being targeted. Each redistributor takes
3844 * GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE bytes
3845 * and the redistributors are adjacent.
3846 */
3847 uint32_t const idReDist = off / (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
3848 off %= (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
3849
3850 PCVMCC pVM = PDMDevHlpGetVM(pDevIns);
3851 Assert(idReDist < pVM->cCpus);
3852 PVMCPUCC pVCpu = pVM->CTX_SUFF(apCpus)[idReDist];
3853
3854 STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioWrite));
3855
3856 /* Redistributor or SGI/PPI frame? */
3857 uint16_t const offReg = off & 0xfffc;
3858 VBOXSTRICTRC rcStrict;
3859 if (off < GIC_REDIST_REG_FRAME_SIZE)
3860 rcStrict = gicReDistWriteRegister(pDevIns, pVCpu, offReg, uValue);
3861 else
3862 rcStrict = gicReDistWriteSgiPpiRegister(pDevIns, pVCpu, offReg, uValue);
3863
3864 LogFlowFunc(("[%u]: off=%RGp idReDist=%u offReg=%#RX16 (%s) uValue=%#RX32 -> %Rrc\n", pVCpu->idCpu, off, idReDist, offReg,
3865 gicReDistGetRegDescription(offReg), uValue, VBOXSTRICTRC_VAL(rcStrict)));
3866 return rcStrict;
3867}
3868
3869
3870#ifndef IN_RING3
3871/**
3872 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
3873 */
3874static DECLCALLBACK(int) gicRZConstruct(PPDMDEVINS pDevIns)
3875{
3876 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
3877 AssertReleaseFailed();
3878 return VINF_SUCCESS;
3879}
3880#endif /* !IN_RING3 */
3881
3882
3883/**
3884 * GIC device registration structure.
3885 */
3886const PDMDEVREG g_DeviceGIC =
3887{
3888 /* .u32Version = */ PDM_DEVREG_VERSION,
3889 /* .uReserved0 = */ 0,
3890 /* .szName = */ "gic",
3891 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
3892 /* .fClass = */ PDM_DEVREG_CLASS_PIC,
3893 /* .cMaxInstances = */ 1,
3894 /* .uSharedVersion = */ 42,
3895 /* .cbInstanceShared = */ sizeof(GICDEV),
3896 /* .cbInstanceCC = */ 0,
3897 /* .cbInstanceRC = */ 0,
3898 /* .cMaxPciDevices = */ 0,
3899 /* .cMaxMsixVectors = */ 0,
3900 /* .pszDescription = */ "Generic Interrupt Controller",
3901#if defined(IN_RING3)
3902 /* .szRCMod = */ "VMMRC.rc",
3903 /* .szR0Mod = */ "VMMR0.r0",
3904 /* .pfnConstruct = */ gicR3Construct,
3905 /* .pfnDestruct = */ gicR3Destruct,
3906 /* .pfnRelocate = */ gicR3Relocate,
3907 /* .pfnMemSetup = */ NULL,
3908 /* .pfnPowerOn = */ NULL,
3909 /* .pfnReset = */ gicR3Reset,
3910 /* .pfnSuspend = */ NULL,
3911 /* .pfnResume = */ NULL,
3912 /* .pfnAttach = */ NULL,
3913 /* .pfnDetach = */ NULL,
3914 /* .pfnQueryInterface = */ NULL,
3915 /* .pfnInitComplete = */ NULL,
3916 /* .pfnPowerOff = */ NULL,
3917 /* .pfnSoftReset = */ NULL,
3918 /* .pfnReserved0 = */ NULL,
3919 /* .pfnReserved1 = */ NULL,
3920 /* .pfnReserved2 = */ NULL,
3921 /* .pfnReserved3 = */ NULL,
3922 /* .pfnReserved4 = */ NULL,
3923 /* .pfnReserved5 = */ NULL,
3924 /* .pfnReserved6 = */ NULL,
3925 /* .pfnReserved7 = */ NULL,
3926#elif defined(IN_RING0)
3927 /* .pfnEarlyConstruct = */ NULL,
3928 /* .pfnConstruct = */ gicRZConstruct,
3929 /* .pfnDestruct = */ NULL,
3930 /* .pfnFinalDestruct = */ NULL,
3931 /* .pfnRequest = */ NULL,
3932 /* .pfnReserved0 = */ NULL,
3933 /* .pfnReserved1 = */ NULL,
3934 /* .pfnReserved2 = */ NULL,
3935 /* .pfnReserved3 = */ NULL,
3936 /* .pfnReserved4 = */ NULL,
3937 /* .pfnReserved5 = */ NULL,
3938 /* .pfnReserved6 = */ NULL,
3939 /* .pfnReserved7 = */ NULL,
3940#elif defined(IN_RC)
3941 /* .pfnConstruct = */ gicRZConstruct,
3942 /* .pfnReserved0 = */ NULL,
3943 /* .pfnReserved1 = */ NULL,
3944 /* .pfnReserved2 = */ NULL,
3945 /* .pfnReserved3 = */ NULL,
3946 /* .pfnReserved4 = */ NULL,
3947 /* .pfnReserved5 = */ NULL,
3948 /* .pfnReserved6 = */ NULL,
3949 /* .pfnReserved7 = */ NULL,
3950#else
3951# error "Not in IN_RING3, IN_RING0 or IN_RC!"
3952#endif
3953 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
3954};
3955
3956
3957/**
3958 * The VirtualBox GIC backend.
3959 */
3960const PDMGICBACKEND g_GicBackend =
3961{
3962 /* .pfnReadSysReg = */ gicReadSysReg,
3963 /* .pfnWriteSysReg = */ gicWriteSysReg,
3964 /* .pfnSetSpi = */ gicSetSpi,
3965 /* .pfnSetPpi = */ gicSetPpi,
3966};
3967
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette