VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/GICR3.cpp

Last change on this file was 109033, checked in by vboxsync, 11 days ago

VMM/GIC: bugref:10877 Some GIC, ITS cleanup.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 54.3 KB
Line 
1/* $Id: GICR3.cpp 109033 2025-04-21 07:01:04Z vboxsync $ */
2/** @file
3 * GIC - Generic Interrupt Controller Architecture (GIC).
4 */
5
6/*
7 * Copyright (C) 2023-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_DEV_GIC
33#include <VBox/log.h>
34#include "GICInternal.h"
35#include <VBox/vmm/pdmgic.h>
36#include <VBox/vmm/cpum.h>
37#include <VBox/vmm/hm.h>
38#include <VBox/vmm/mm.h>
39#include <VBox/vmm/pdmdev.h>
40#include <VBox/vmm/ssm.h>
41#include <VBox/vmm/vm.h>
42
43#include <iprt/armv8.h>
44#include <iprt/mem.h>
45
46
47#ifndef VBOX_DEVICE_STRUCT_TESTCASE
48
49
50/*********************************************************************************************************************************
51* Defined Constants And Macros *
52*********************************************************************************************************************************/
53/** GIC saved state version. */
54#define GIC_SAVED_STATE_VERSION 9
55
56# define GIC_SYSREGRANGE(a_uFirst, a_uLast, a_szName) \
57 { (a_uFirst), (a_uLast), kCpumSysRegRdFn_GicIcc, kCpumSysRegWrFn_GicIcc, 0, 0, 0, 0, 0, 0, a_szName, { 0 }, { 0 }, { 0 }, { 0 } }
58
59
60/*********************************************************************************************************************************
61* Global Variables *
62*********************************************************************************************************************************/
63/**
64 * System register ranges for the GIC.
65 */
66static CPUMSYSREGRANGE const g_aSysRegRanges_GIC[] =
67{
68 GIC_SYSREGRANGE(ARMV8_AARCH64_SYSREG_ICC_PMR_EL1, ARMV8_AARCH64_SYSREG_ICC_PMR_EL1, "ICC_PMR_EL1"),
69 GIC_SYSREGRANGE(ARMV8_AARCH64_SYSREG_ICC_IAR0_EL1, ARMV8_AARCH64_SYSREG_ICC_AP0R3_EL1, "ICC_IAR0_EL1 - ICC_AP0R3_EL1"),
70 GIC_SYSREGRANGE(ARMV8_AARCH64_SYSREG_ICC_AP1R0_EL1, ARMV8_AARCH64_SYSREG_ICC_NMIAR1_EL1, "ICC_AP1R0_EL1 - ICC_NMIAR1_EL1"),
71 GIC_SYSREGRANGE(ARMV8_AARCH64_SYSREG_ICC_DIR_EL1, ARMV8_AARCH64_SYSREG_ICC_SGI0R_EL1, "ICC_DIR_EL1 - ICC_SGI0R_EL1"),
72 GIC_SYSREGRANGE(ARMV8_AARCH64_SYSREG_ICC_IAR1_EL1, ARMV8_AARCH64_SYSREG_ICC_IGRPEN1_EL1, "ICC_IAR1_EL1 - ICC_IGRPEN1_EL1"),
73 GIC_SYSREGRANGE(ARMV8_AARCH64_SYSREG_ICC_SRE_EL2, ARMV8_AARCH64_SYSREG_ICC_SRE_EL2, "ICC_SRE_EL2"),
74 GIC_SYSREGRANGE(ARMV8_AARCH64_SYSREG_ICC_SRE_EL3, ARMV8_AARCH64_SYSREG_ICC_SRE_EL3, "ICC_SRE_EL3")
75};
76
77
78/**
79 * Dumps basic GIC state.
80 *
81 * @param pVM The cross context VM structure.
82 * @param pHlp The info helpers.
83 * @param pszArgs Arguments, ignored.
84 */
85static DECLCALLBACK(void) gicR3DbgInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
86{
87 RT_NOREF(pszArgs);
88 PCGIC pGic = VM_TO_GIC(pVM);
89 PPDMDEVINS pDevIns = pGic->CTX_SUFF(pDevIns);
90 PCGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PCGICDEV);
91
92 pHlp->pfnPrintf(pHlp, "GIC:\n");
93 pHlp->pfnPrintf(pHlp, " uArchRev = %u\n", pGicDev->uArchRev);
94 pHlp->pfnPrintf(pHlp, " uArchRevMinor = %u\n", pGicDev->uArchRevMinor);
95 pHlp->pfnPrintf(pHlp, " uMaxSpi = %u (upto IntId %u)\n", pGicDev->uMaxSpi, 32 * (pGicDev->uMaxSpi + 1));
96 pHlp->pfnPrintf(pHlp, " fExtSpi = %RTbool\n", pGicDev->fExtSpi);
97 pHlp->pfnPrintf(pHlp, " uMaxExtSpi = %u (upto IntId %u)\n", pGicDev->uMaxExtSpi,
98 GIC_INTID_RANGE_EXT_SPI_START - 1 + 32 * (pGicDev->uMaxExtSpi + 1));
99 pHlp->pfnPrintf(pHlp, " fExtPpi = %RTbool\n", pGicDev->fExtPpi);
100 pHlp->pfnPrintf(pHlp, " uMaxExtPpi = %u (upto IntId %u)\n", pGicDev->uMaxExtPpi,
101 pGicDev->uMaxExtPpi == GIC_REDIST_REG_TYPER_PPI_NUM_MAX_1087 ? 1087 : GIC_INTID_RANGE_EXT_PPI_LAST);
102 pHlp->pfnPrintf(pHlp, " fRangeSelSupport = %RTbool\n", pGicDev->fRangeSel);
103 pHlp->pfnPrintf(pHlp, " fNmi = %RTbool\n", pGicDev->fNmi);
104 pHlp->pfnPrintf(pHlp, " fMbi = %RTbool\n", pGicDev->fMbi);
105 pHlp->pfnPrintf(pHlp, " fAff3Levels = %RTbool\n", pGicDev->fAff3Levels);
106 pHlp->pfnPrintf(pHlp, " fLpi = %RTbool\n", pGicDev->fLpi);
107}
108
109
110/**
111 * Dumps GIC Distributor information.
112 *
113 * @param pVM The cross context VM structure.
114 * @param pHlp The info helpers.
115 * @param pszArgs Arguments, ignored.
116 */
117static DECLCALLBACK(void) gicR3DbgInfoDist(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
118{
119 RT_NOREF(pszArgs);
120
121 PGIC pGic = VM_TO_GIC(pVM);
122 PPDMDEVINS pDevIns = pGic->CTX_SUFF(pDevIns);
123 PCGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PCGICDEV);
124
125#define GIC_DBGFINFO_DIST_INTR_BITMAP(a_Name, a_bmIntr) \
126 do \
127 { \
128 pHlp->pfnPrintf(pHlp, " " a_Name " =\n"); \
129 for (uint32_t i = 0; i < RT_ELEMENTS(a_bmIntr); i += 8) \
130 pHlp->pfnPrintf(pHlp, " [%2u..%-2u] %#010x %#010x %#010x %#010x %#010x %#010x %#010x %#010x\n", i, i + 7, \
131 (a_bmIntr)[i], (a_bmIntr)[i+1], (a_bmIntr)[i+2], (a_bmIntr)[i+3], \
132 (a_bmIntr)[i+4], (a_bmIntr)[i+5], (a_bmIntr)[i+6], (a_bmIntr)[i+7]); \
133 } while (0)
134
135 pHlp->pfnPrintf(pHlp, "GIC Distributor:\n");
136 pHlp->pfnPrintf(pHlp, " fIntrGroup0Enabled = %RTbool\n", pGicDev->fIntrGroup0Enabled);
137 pHlp->pfnPrintf(pHlp, " fIntrGroup1Enabled = %RTbool\n", pGicDev->fIntrGroup1Enabled);
138 pHlp->pfnPrintf(pHlp, " fAffRoutingEnabled = %RTbool\n", pGicDev->fAffRoutingEnabled);
139 GIC_DBGFINFO_DIST_INTR_BITMAP("bmIntrGroup", pGicDev->bmIntrGroup);
140 GIC_DBGFINFO_DIST_INTR_BITMAP("bmIntrEnabled", pGicDev->bmIntrEnabled);
141 GIC_DBGFINFO_DIST_INTR_BITMAP("bmIntrPending", pGicDev->bmIntrPending);
142 GIC_DBGFINFO_DIST_INTR_BITMAP("bmIntrActive", pGicDev->bmIntrActive);
143
144 /* Interrupt priorities.*/
145 {
146 uint32_t const cPriorities = RT_ELEMENTS(pGicDev->abIntrPriority);
147 AssertCompile(!(cPriorities % 16));
148 pHlp->pfnPrintf(pHlp, " Interrupt priorities:\n");
149 for (uint32_t i = 0; i < cPriorities; i += 16)
150 pHlp->pfnPrintf(pHlp, " IntId[%4u..%-4u] = %3u %3u %3u %3u %3u %3u %3u %3u"
151 " IntId[%4u..%-4u] = %3u %3u %3u %3u %3u %3u %3u %3u\n",
152 gicDistGetIntIdFromIndex(i), gicDistGetIntIdFromIndex(i + 7),
153 pGicDev->abIntrPriority[i], pGicDev->abIntrPriority[i + 1],
154 pGicDev->abIntrPriority[i + 2], pGicDev->abIntrPriority[i + 3],
155 pGicDev->abIntrPriority[i + 4], pGicDev->abIntrPriority[i + 5],
156 pGicDev->abIntrPriority[i + 6], pGicDev->abIntrPriority[i + 7],
157 gicDistGetIntIdFromIndex(i + 8), gicDistGetIntIdFromIndex(i + 15),
158 pGicDev->abIntrPriority[i + 8], pGicDev->abIntrPriority[i + 9],
159 pGicDev->abIntrPriority[i + 10], pGicDev->abIntrPriority[i + 11],
160 pGicDev->abIntrPriority[i + 12], pGicDev->abIntrPriority[i + 13],
161 pGicDev->abIntrPriority[i + 14], pGicDev->abIntrPriority[i + 15]);
162 }
163
164 /* Interrupt routing.*/
165 {
166 /** @todo Interrupt rounting mode. */
167 uint32_t const cRouting = RT_ELEMENTS(pGicDev->au32IntrRouting);
168 AssertCompile(!(cRouting % 16));
169 pHlp->pfnPrintf(pHlp, " Interrupt routing:\n");
170 for (uint32_t i = 0; i < cRouting; i += 16)
171 pHlp->pfnPrintf(pHlp, " IntId[%4u..%-4u] = %3u %3u %3u %3u %3u %3u %3u %3u"
172 " IntId[%4u..%-4u] = %3u %3u %3u %3u %3u %3u %3u %3u\n",
173 gicDistGetIntIdFromIndex(i), gicDistGetIntIdFromIndex(i + 7),
174 pGicDev->au32IntrRouting[i], pGicDev->au32IntrRouting[i + 1],
175 pGicDev->au32IntrRouting[i + 2], pGicDev->au32IntrRouting[i + 3],
176 pGicDev->au32IntrRouting[i + 4], pGicDev->au32IntrRouting[i + 5],
177 pGicDev->au32IntrRouting[i + 6], pGicDev->au32IntrRouting[i + 7],
178 gicDistGetIntIdFromIndex(i + 8), gicDistGetIntIdFromIndex(i + 15),
179 pGicDev->au32IntrRouting[i + 8], pGicDev->au32IntrRouting[i + 9],
180 pGicDev->au32IntrRouting[i + 10], pGicDev->au32IntrRouting[i + 11],
181 pGicDev->au32IntrRouting[i + 12], pGicDev->au32IntrRouting[i + 13],
182 pGicDev->au32IntrRouting[i + 14], pGicDev->au32IntrRouting[i + 15]);
183 }
184
185#undef GIC_DBGFINFO_DIST_INTR_BITMAP
186}
187
188
189/**
190 * Dumps the GIC Redistributor information.
191 *
192 * @param pVM The cross context VM structure.
193 * @param pHlp The info helpers.
194 * @param pszArgs Arguments, ignored.
195 */
196static DECLCALLBACK(void) gicR3DbgInfoReDist(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
197{
198 NOREF(pszArgs);
199 PVMCPU pVCpu = VMMGetCpu(pVM);
200 if (!pVCpu)
201 pVCpu = pVM->apCpusR3[0];
202
203 PCGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
204
205 pHlp->pfnPrintf(pHlp, "VCPU[%u] Redistributor:\n", pVCpu->idCpu);
206 AssertCompile(RT_ELEMENTS(pGicCpu->bmIntrGroup) >= 3);
207 AssertCompile(RT_ELEMENTS(pGicCpu->bmIntrEnabled) >= 3);
208 AssertCompile(RT_ELEMENTS(pGicCpu->bmIntrPending) >= 3);
209 AssertCompile(RT_ELEMENTS(pGicCpu->bmIntrActive) >= 3);
210
211#define GIC_DBGFINFO_REDIST_INTR_BITMAPS_3(a_bmIntr) pGicCpu->a_bmIntr[0], pGicCpu->a_bmIntr[1], pGicCpu->a_bmIntr[2]
212 pHlp->pfnPrintf(pHlp, " bmIntrGroup[0..2] = %#010x %#010x %#010x\n", GIC_DBGFINFO_REDIST_INTR_BITMAPS_3(bmIntrGroup));
213 pHlp->pfnPrintf(pHlp, " bmIntrEnabled[0..2] = %#010x %#010x %#010x\n", GIC_DBGFINFO_REDIST_INTR_BITMAPS_3(bmIntrEnabled));
214 pHlp->pfnPrintf(pHlp, " bmIntrPending[0..2] = %#010x %#010x %#010x\n", GIC_DBGFINFO_REDIST_INTR_BITMAPS_3(bmIntrPending));
215 pHlp->pfnPrintf(pHlp, " bmIntrActive[0..2] = %#010x %#010x %#010x\n", GIC_DBGFINFO_REDIST_INTR_BITMAPS_3(bmIntrActive));
216#undef GIC_DBGFINFO_REDIST_INTR_BITMAPS
217
218 /* Interrupt priorities. */
219 {
220 uint32_t const cPriorities = RT_ELEMENTS(pGicCpu->abIntrPriority);
221 AssertCompile(!(cPriorities % 16));
222 pHlp->pfnPrintf(pHlp, " Interrupt priorities:\n");
223 for (uint32_t i = 0; i < cPriorities; i += 16)
224 pHlp->pfnPrintf(pHlp, " IntId[%4u..%-4u] = %3u %3u %3u %3u %3u %3u %3u %3u"
225 " IntId[%4u..%-4u] = %3u %3u %3u %3u %3u %3u %3u %3u\n",
226 gicReDistGetIntIdFromIndex(i), gicReDistGetIntIdFromIndex(i + 7),
227 pGicCpu->abIntrPriority[i], pGicCpu->abIntrPriority[i + 1],
228 pGicCpu->abIntrPriority[i + 2], pGicCpu->abIntrPriority[i + 3],
229 pGicCpu->abIntrPriority[i + 4], pGicCpu->abIntrPriority[i + 5],
230 pGicCpu->abIntrPriority[i + 6], pGicCpu->abIntrPriority[i + 7],
231 gicReDistGetIntIdFromIndex(i + 8), gicReDistGetIntIdFromIndex(i + 15),
232 pGicCpu->abIntrPriority[i + 8], pGicCpu->abIntrPriority[i + 9],
233 pGicCpu->abIntrPriority[i + 10], pGicCpu->abIntrPriority[i + 11],
234 pGicCpu->abIntrPriority[i + 12], pGicCpu->abIntrPriority[i + 13],
235 pGicCpu->abIntrPriority[i + 14], pGicCpu->abIntrPriority[i + 15]);
236 }
237
238 pHlp->pfnPrintf(pHlp, "\nVCPU[%u] ICC system register state:\n", pVCpu->idCpu);
239 pHlp->pfnPrintf(pHlp, " uIccCtlr = %#RX64\n", pGicCpu->uIccCtlr);
240 pHlp->pfnPrintf(pHlp, " fIntrGroup0Enabled = %RTbool\n", pGicCpu->fIntrGroup0Enabled);
241 pHlp->pfnPrintf(pHlp, " fIntrGroup1Enabled = %RTbool\n", pGicCpu->fIntrGroup1Enabled);
242 pHlp->pfnPrintf(pHlp, " bBinaryPtGroup0 = %#x\n", pGicCpu->bBinaryPtGroup0);
243 pHlp->pfnPrintf(pHlp, " bBinaryPtGroup1 = %#x\n", pGicCpu->bBinaryPtGroup1);
244 pHlp->pfnPrintf(pHlp, " idxRunningPriority = %#x\n", pGicCpu->idxRunningPriority);
245 pHlp->pfnPrintf(pHlp, " Running priority = %#x\n", pGicCpu->abRunningPriorities[pGicCpu->idxRunningPriority]);
246
247 /* Running interrupt priorities. */
248 {
249 uint32_t const cPriorities = RT_ELEMENTS(pGicCpu->abRunningPriorities);
250 AssertCompile(!(cPriorities % 16));
251 pHlp->pfnPrintf(pHlp, " Running-interrupt priorities:\n");
252 for (uint32_t i = 0; i < cPriorities; i += 16)
253 pHlp->pfnPrintf(pHlp, " [%3u..%-3u] = %3u %3u %3u %3u %3u %3u %3u %3u"
254 " [%3u..%-3u] = %3u %3u %3u %3u %3u %3u %3u %3u\n",
255 i, i + 7,
256 pGicCpu->abRunningPriorities[i], pGicCpu->abRunningPriorities[i + 1],
257 pGicCpu->abRunningPriorities[i + 2], pGicCpu->abRunningPriorities[i + 3],
258 pGicCpu->abRunningPriorities[i + 4], pGicCpu->abRunningPriorities[i + 5],
259 pGicCpu->abRunningPriorities[i + 6], pGicCpu->abRunningPriorities[i + 7],
260 i + 8, i + 15,
261 pGicCpu->abRunningPriorities[i + 8], pGicCpu->abRunningPriorities[i + 9],
262 pGicCpu->abRunningPriorities[i + 10], pGicCpu->abRunningPriorities[i + 11],
263 pGicCpu->abRunningPriorities[i + 12], pGicCpu->abRunningPriorities[i + 13],
264 pGicCpu->abRunningPriorities[i + 14], pGicCpu->abRunningPriorities[i + 15]);
265 }
266
267 AssertCompile(RT_ELEMENTS(pGicCpu->bmActivePriorityGroup0) >= 4);
268 pHlp->pfnPrintf(pHlp, " Active-interrupt priorities Group 0:\n");
269 pHlp->pfnPrintf(pHlp, " [0..3] = %#010x %#010x %#010x %#010x\n",
270 pGicCpu->bmActivePriorityGroup0[0], pGicCpu->bmActivePriorityGroup0[1],
271 pGicCpu->bmActivePriorityGroup0[2], pGicCpu->bmActivePriorityGroup0[3]);
272 AssertCompile(RT_ELEMENTS(pGicCpu->bmActivePriorityGroup1) >= 4);
273 pHlp->pfnPrintf(pHlp, " Active-interrupt priorities Group 1:\n");
274 pHlp->pfnPrintf(pHlp, " [0..3] = %#010x %#010x %#010x %#010x\n",
275 pGicCpu->bmActivePriorityGroup1[0], pGicCpu->bmActivePriorityGroup1[1],
276 pGicCpu->bmActivePriorityGroup1[2], pGicCpu->bmActivePriorityGroup1[3]);
277}
278
279
280/**
281 * Dumps the GIC ITS information.
282 *
283 * @param pVM The cross context VM structure.
284 * @param pHlp The info helpers.
285 * @param pszArgs Arguments, ignored.
286 */
287static DECLCALLBACK(void) gicR3DbgInfoIts(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
288{
289 NOREF(pszArgs);
290 PGIC pGic = VM_TO_GIC(pVM);
291 PPDMDEVINS pDevIns = pGic->CTX_SUFF(pDevIns);
292 PCGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PCGICDEV);
293 if (pGicDev->hMmioGits != NIL_IOMMMIOHANDLE)
294 gitsR3DbgInfo(&pGicDev->Gits, pHlp);
295 else
296 pHlp->pfnPrintf(pHlp, "GIC ITS is not mapped/configured for the VM\n");
297}
298
299
300/**
301 * Dumps the GIC LPI information.
302 *
303 * @param pVM The cross context VM structure.
304 * @param pHlp The info helpers.
305 * @param pszArgs Arguments, ignored.
306 */
307static DECLCALLBACK(void) gicR3DbgInfoLpi(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
308{
309 NOREF(pszArgs);
310 PGIC pGic = VM_TO_GIC(pVM);
311 PPDMDEVINS pDevIns = pGic->CTX_SUFF(pDevIns);
312 PCGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PCGICDEV);
313 if (!pGicDev->fLpi)
314 {
315 pHlp->pfnPrintf(pHlp, "GIC LPI support is not enabled for the VM\n");
316 return;
317 }
318
319 PVMCPU pVCpu = VMMGetCpu(pVM);
320 if (!pVCpu)
321 pVCpu = pVM->apCpusR3[0];
322 PCGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
323
324 pHlp->pfnPrintf(pHlp, "GIC LPIs:\n");
325 pHlp->pfnPrintf(pHlp, " Enabled = %RTbool\n", pGicDev->fEnableLpis);
326
327 /* GICR_PENDBASER. */
328 {
329 uint64_t const uReg = pGicDev->uLpiPendingBaseReg.u;
330 pHlp->pfnPrintf(pHlp, " uLpiPendingBaseReg = %#RX64\n", uReg);
331 pHlp->pfnPrintf(pHlp, " Inner cache = %#x\n", RT_BF_GET(uReg, GIC_BF_REDIST_REG_PENDBASER_INNER_CACHE));
332 pHlp->pfnPrintf(pHlp, " Shareability = %#x\n", RT_BF_GET(uReg, GIC_BF_REDIST_REG_PENDBASER_SHAREABILITY));
333 pHlp->pfnPrintf(pHlp, " Phys addr = %#RX64\n", uReg & GIC_BF_REDIST_REG_PENDBASER_PHYS_ADDR_MASK);
334 pHlp->pfnPrintf(pHlp, " Outer cache = %#x\n", RT_BF_GET(uReg, GIC_BF_REDIST_REG_PENDBASER_OUTER_CACHE));
335 pHlp->pfnPrintf(pHlp, " Pending Table Zero = %RTbool\n", RT_BF_GET(uReg, GIC_BF_REDIST_REG_PENDBASER_PTZ));
336 }
337
338 /* GICR_PROPBASER. */
339 {
340 uint64_t const uReg = pGicDev->uLpiConfigBaseReg.u;
341 uint8_t const cIdBits = RT_BF_GET(uReg, GIC_BF_REDIST_REG_PROPBASER_ID_BITS);
342 pHlp->pfnPrintf(pHlp, " uLpiConfigBaseReg = %#RX64\n", uReg);
343 pHlp->pfnPrintf(pHlp, " ID bits = %#x (%u bits)\n", cIdBits, cIdBits > 0 ? cIdBits + 1 : 0);
344 pHlp->pfnPrintf(pHlp, " Inner cache = %#x\n", RT_BF_GET(uReg, GIC_BF_REDIST_REG_PROPBASER_INNER_CACHE));
345 pHlp->pfnPrintf(pHlp, " Shareability = %#x\n", RT_BF_GET(uReg, GIC_BF_REDIST_REG_PROPBASER_SHAREABILITY));
346 pHlp->pfnPrintf(pHlp, " Phys addr = %#RX64\n", uReg & GIC_BF_REDIST_REG_PROPBASER_PHYS_ADDR_MASK);
347 pHlp->pfnPrintf(pHlp, " Outer cache = %#x\n", RT_BF_GET(uReg, GIC_BF_REDIST_REG_PROPBASER_OUTER_CACHE));
348 }
349
350 /* LPI CTE (Configuration Table Entries). */
351 {
352 uint32_t const cLpiCtes = RT_ELEMENTS(pGicDev->abLpiConfig);
353 uint32_t cLpiCtesEn = 0;
354 for (uint32_t i = 0; i < cLpiCtes; i++)
355 if (RT_BF_GET(pGicDev->abLpiConfig[i], GIC_BF_LPI_CTE_ENABLE))
356 ++cLpiCtesEn;
357
358 pHlp->pfnPrintf(pHlp, " LPI config table (capacity=%u entries, enabled=%u entries)%s\n", cLpiCtes, cLpiCtesEn,
359 cLpiCtesEn > 0 ? ":" : "");
360 for (uint32_t i = 0; i < cLpiCtesEn; i++)
361 {
362 uint8_t const uLpiCte = pGicDev->abLpiConfig[i];
363 uint8_t const uPriority = RT_BF_GET(uLpiCte, GIC_BF_LPI_CTE_PRIORITY);
364 pHlp->pfnPrintf(pHlp, " [%4u] = %#x (priority=%u)\n", uLpiCte, uPriority);
365 }
366 }
367
368 /* Pending LPI registers. */
369 pHlp->pfnPrintf(pHlp, " LPI pending bitmap:\n");
370 for (uint32_t i = 0; i < RT_ELEMENTS(pGicCpu->bmLpiPending); i += 8)
371 {
372 pHlp->pfnPrintf(pHlp, " [%3u..%-3u] = %08RX64 %08RX64 %08RX64 %08RX64 %08RX64 %08RX64 %08RX64 %08RX64\n",
373 i, i + 7,
374 pGicCpu->bmLpiPending[i], pGicCpu->bmLpiPending[i + 1],
375 pGicCpu->bmLpiPending[i + 2], pGicCpu->bmLpiPending[i + 3],
376 pGicCpu->bmLpiPending[i + 4], pGicCpu->bmLpiPending[i + 5],
377 pGicCpu->bmLpiPending[i + 6], pGicCpu->bmLpiPending[i + 7]);
378 }
379}
380
381
382/**
383 * The GIC ITS command-queue thread.
384 *
385 * @returns VBox status code.
386 * @param pDevIns The device instance.
387 * @param pThread The command thread.
388 */
389static DECLCALLBACK(int) gicItsR3CmdQueueThread(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
390{
391 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
392 return VINF_SUCCESS;
393
394 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
395 PGITSDEV pGitsDev = &pGicDev->Gits;
396 AssertPtrReturn(pGicDev, VERR_INVALID_PARAMETER);
397 LogFlowFunc(("Command-queue thread spawned and initialized\n"));
398
399 /*
400 * Pre-allocate the maximum size of the command queue allowed by the ARM GIC spec.
401 * This prevents trashing the heap as well as dealing with out-of-memory situations
402 * up-front while starting the VM. It also simplifies the code from having to
403 * dynamically grow/shrink the allocation based on how software sizes the queue.
404 * Guests normally don't alter the queue size all the time, but that's not an
405 * assumption we can make. Another benefit is that we can avoid releasing and
406 * re-acquiring the device critical section if/when guests modifies the command
407 * queue size.
408 */
409 uint16_t const cMaxPages = GITS_BF_CTRL_REG_CBASER_SIZE_MASK + 1;
410 size_t const cbCmds = cMaxPages << GITS_CMD_QUEUE_PAGE_SHIFT;
411 void *pvCmds = RTMemAllocZ(cbCmds);
412 AssertLogRelMsgReturn(pvCmds, ("Failed to alloc %.Rhcb (%zu bytes) for the GITS command queue\n", cbCmds, cbCmds),
413 VERR_NO_MEMORY);
414
415 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
416 {
417 /* Sleep until we are woken up. */
418 {
419 int const rcLock = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pGitsDev->hEvtCmdQueue, RT_INDEFINITE_WAIT);
420 AssertLogRelMsgReturnStmt(RT_SUCCESS(rcLock) || rcLock == VERR_INTERRUPTED, ("%Rrc\n", rcLock),
421 RTMemFree(pvCmds), rcLock);
422 if (pThread->enmState != PDMTHREADSTATE_RUNNING)
423 break;
424 }
425
426 /* Process the command queue. */
427 int const rc = gitsR3CmdQueueProcess(pDevIns, pGitsDev, pvCmds, cbCmds);
428 if (RT_FAILURE(rc))
429 break;
430 }
431
432 RTMemFree(pvCmds);
433
434 LogFlowFunc(("Command-queue thread terminating\n"));
435 return VINF_SUCCESS;
436}
437
438
439/**
440 * Wakes up the command-queue thread so it can respond to a state change.
441 *
442 * @return VBox status code.
443 * @param pDevIns The device instance.
444 * @param pThread The command-queue thread.
445 *
446 * @thread EMT.
447 */
448static DECLCALLBACK(int) gicItsR3CmdQueueThreadWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
449{
450 RT_NOREF(pThread);
451 LogFlowFunc(("\n"));
452 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
453 PGITSDEV pGitsDev = &pGicDev->Gits;
454 return PDMDevHlpSUPSemEventSignal(pDevIns, pGitsDev->hEvtCmdQueue);
455}
456
457
458/**
459 * @copydoc FNSSMDEVSAVEEXEC
460 */
461static DECLCALLBACK(int) gicR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
462{
463 PCVM pVM = PDMDevHlpGetVM(pDevIns);
464 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
465 PCGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PCGICDEV);
466 AssertPtrReturn(pVM, VERR_INVALID_VM_HANDLE);
467 LogFlowFunc(("\n"));
468
469 /*
470 * Save per-VM data.
471 */
472 pHlp->pfnSSMPutU32(pSSM, pVM->cCpus);
473 pHlp->pfnSSMPutU8(pSSM, pGicDev->uArchRev);
474 pHlp->pfnSSMPutU8(pSSM, pGicDev->uArchRevMinor);
475 pHlp->pfnSSMPutU8(pSSM, pGicDev->uMaxSpi);
476 pHlp->pfnSSMPutBool(pSSM, pGicDev->fExtSpi);
477 pHlp->pfnSSMPutU8(pSSM, pGicDev->uMaxExtSpi);
478 pHlp->pfnSSMPutBool(pSSM, pGicDev->fExtPpi);
479 pHlp->pfnSSMPutU8(pSSM, pGicDev->uMaxExtPpi);
480 pHlp->pfnSSMPutBool(pSSM, pGicDev->fRangeSel);
481 pHlp->pfnSSMPutBool(pSSM, pGicDev->fNmi);
482 pHlp->pfnSSMPutBool(pSSM, pGicDev->fMbi);
483 pHlp->pfnSSMPutBool(pSSM, pGicDev->fAff3Levels);
484 pHlp->pfnSSMPutBool(pSSM, pGicDev->fLpi);
485
486 /* Distributor state. */
487 pHlp->pfnSSMPutBool(pSSM, pGicDev->fIntrGroup0Enabled);
488 pHlp->pfnSSMPutBool(pSSM, pGicDev->fIntrGroup1Enabled);
489 pHlp->pfnSSMPutBool(pSSM, pGicDev->fAffRoutingEnabled);
490 pHlp->pfnSSMPutMem(pSSM, &pGicDev->bmIntrGroup[0], sizeof(pGicDev->bmIntrGroup));
491 pHlp->pfnSSMPutMem(pSSM, &pGicDev->bmIntrConfig[0], sizeof(pGicDev->bmIntrConfig));
492 pHlp->pfnSSMPutMem(pSSM, &pGicDev->bmIntrEnabled[0], sizeof(pGicDev->bmIntrEnabled));
493 pHlp->pfnSSMPutMem(pSSM, &pGicDev->bmIntrPending[0], sizeof(pGicDev->bmIntrPending));
494 pHlp->pfnSSMPutMem(pSSM, &pGicDev->bmIntrActive[0], sizeof(pGicDev->bmIntrActive));
495 pHlp->pfnSSMPutMem(pSSM, &pGicDev->abIntrPriority[0], sizeof(pGicDev->abIntrPriority));
496 pHlp->pfnSSMPutMem(pSSM, &pGicDev->au32IntrRouting[0], sizeof(pGicDev->au32IntrRouting));
497 pHlp->pfnSSMPutMem(pSSM, &pGicDev->bmIntrRoutingMode[0], sizeof(pGicDev->bmIntrRoutingMode));
498
499 /* LPI state. */
500 /* We store the size followed by the data because we currently do not support the full LPI range. */
501 pHlp->pfnSSMPutU32(pSSM, RT_SIZEOFMEMB(GICCPU, bmLpiPending));
502 pHlp->pfnSSMPutU32(pSSM, sizeof(pGicDev->abLpiConfig));
503 pHlp->pfnSSMPutMem(pSSM, &pGicDev->abLpiConfig[0], sizeof(pGicDev->abLpiConfig));
504 pHlp->pfnSSMPutU64(pSSM, pGicDev->uLpiConfigBaseReg.u);
505 pHlp->pfnSSMPutU64(pSSM, pGicDev->uLpiPendingBaseReg.u);
506 pHlp->pfnSSMPutBool(pSSM, pGicDev->fEnableLpis);
507
508 /** @todo GITS data. */
509
510 /*
511 * Save per-VCPU data.
512 */
513 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
514 {
515 PCGICCPU pGicCpu = VMCPU_TO_GICCPU(pVM->apCpusR3[idCpu]);
516 Assert(pGicCpu);
517
518 /* Redistributor state. */
519 pHlp->pfnSSMPutMem(pSSM, &pGicCpu->bmIntrGroup[0], sizeof(pGicCpu->bmIntrGroup));
520 pHlp->pfnSSMPutMem(pSSM, &pGicCpu->bmIntrConfig[0], sizeof(pGicCpu->bmIntrConfig));
521 pHlp->pfnSSMPutMem(pSSM, &pGicCpu->bmIntrEnabled[0], sizeof(pGicCpu->bmIntrEnabled));
522 pHlp->pfnSSMPutMem(pSSM, &pGicCpu->bmIntrPending[0], sizeof(pGicCpu->bmIntrPending));
523 pHlp->pfnSSMPutMem(pSSM, &pGicCpu->bmIntrActive[0], sizeof(pGicCpu->bmIntrActive));
524 pHlp->pfnSSMPutMem(pSSM, &pGicCpu->abIntrPriority[0], sizeof(pGicCpu->abIntrPriority));
525
526 /* ICC system register state. */
527 pHlp->pfnSSMPutU64(pSSM, pGicCpu->uIccCtlr);
528 pHlp->pfnSSMPutU8(pSSM, pGicCpu->bIntrPriorityMask);
529 pHlp->pfnSSMPutU8(pSSM, pGicCpu->idxRunningPriority);
530 pHlp->pfnSSMPutMem(pSSM, &pGicCpu->abRunningPriorities[0], sizeof(pGicCpu->abRunningPriorities));
531 pHlp->pfnSSMPutMem(pSSM, &pGicCpu->bmActivePriorityGroup0[0], sizeof(pGicCpu->bmActivePriorityGroup0));
532 pHlp->pfnSSMPutMem(pSSM, &pGicCpu->bmActivePriorityGroup1[0], sizeof(pGicCpu->bmActivePriorityGroup1));
533 pHlp->pfnSSMPutU8(pSSM, pGicCpu->bBinaryPtGroup0);
534 pHlp->pfnSSMPutU8(pSSM, pGicCpu->bBinaryPtGroup1);
535 pHlp->pfnSSMPutBool(pSSM, pGicCpu->fIntrGroup0Enabled);
536 pHlp->pfnSSMPutBool(pSSM, pGicCpu->fIntrGroup1Enabled);
537
538 /* LPI state. */
539 pHlp->pfnSSMPutMem(pSSM, &pGicCpu->bmLpiPending[0], sizeof(pGicCpu->bmLpiPending));
540 }
541
542 return pHlp->pfnSSMPutU32(pSSM, UINT32_MAX);
543}
544
545
546/**
547 * @copydoc FNSSMDEVLOADEXEC
548 */
549static DECLCALLBACK(int) gicR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
550{
551 PVM pVM = PDMDevHlpGetVM(pDevIns);
552 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
553
554 AssertPtrReturn(pVM, VERR_INVALID_VM_HANDLE);
555 AssertReturn(uPass == SSM_PASS_FINAL, VERR_WRONG_ORDER);
556 LogFlowFunc(("uVersion=%u uPass=%#x\n", uVersion, uPass));
557
558 /*
559 * Validate supported saved-state versions.
560 */
561 if (uVersion != GIC_SAVED_STATE_VERSION)
562 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Invalid saved-state version %u"), uVersion);
563
564 /*
565 * Load per-VM data.
566 */
567 uint32_t cCpus;
568 pHlp->pfnSSMGetU32(pSSM, &cCpus);
569 if (cCpus != pVM->cCpus)
570 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: cCpus: got=%u expected=%u"), cCpus, pVM->cCpus);
571
572 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
573 pHlp->pfnSSMGetU8(pSSM, &pGicDev->uArchRev);
574 pHlp->pfnSSMGetU8(pSSM, &pGicDev->uArchRevMinor);
575 pHlp->pfnSSMGetU8(pSSM, &pGicDev->uMaxSpi);
576 pHlp->pfnSSMGetBool(pSSM, &pGicDev->fExtSpi);
577 pHlp->pfnSSMGetU8(pSSM, &pGicDev->uMaxExtSpi);
578 pHlp->pfnSSMGetBool(pSSM, &pGicDev->fExtPpi);
579 pHlp->pfnSSMGetU8(pSSM, &pGicDev->uMaxExtPpi);
580 pHlp->pfnSSMGetBool(pSSM, &pGicDev->fRangeSel);
581 pHlp->pfnSSMGetBool(pSSM, &pGicDev->fNmi);
582 pHlp->pfnSSMGetBool(pSSM, &pGicDev->fMbi);
583 pHlp->pfnSSMGetBool(pSSM, &pGicDev->fAff3Levels);
584 pHlp->pfnSSMGetBool(pSSM, &pGicDev->fLpi);
585
586 /* Distributor state. */
587 pHlp->pfnSSMGetBool(pSSM, &pGicDev->fIntrGroup0Enabled);
588 pHlp->pfnSSMGetBool(pSSM, &pGicDev->fIntrGroup1Enabled);
589 pHlp->pfnSSMGetBool(pSSM, &pGicDev->fAffRoutingEnabled);
590 pHlp->pfnSSMGetMem(pSSM, &pGicDev->bmIntrGroup[0], sizeof(pGicDev->bmIntrGroup));
591 pHlp->pfnSSMGetMem(pSSM, &pGicDev->bmIntrConfig[0], sizeof(pGicDev->bmIntrConfig));
592 pHlp->pfnSSMGetMem(pSSM, &pGicDev->bmIntrEnabled[0], sizeof(pGicDev->bmIntrEnabled));
593 pHlp->pfnSSMGetMem(pSSM, &pGicDev->bmIntrPending[0], sizeof(pGicDev->bmIntrPending));
594 pHlp->pfnSSMGetMem(pSSM, &pGicDev->bmIntrActive[0], sizeof(pGicDev->bmIntrActive));
595 pHlp->pfnSSMGetMem(pSSM, &pGicDev->abIntrPriority[0], sizeof(pGicDev->abIntrPriority));
596 pHlp->pfnSSMGetMem(pSSM, &pGicDev->au32IntrRouting[0], sizeof(pGicDev->au32IntrRouting));
597 pHlp->pfnSSMGetMem(pSSM, &pGicDev->bmIntrRoutingMode[0], sizeof(pGicDev->bmIntrRoutingMode));
598
599 /* LPI state. */
600 /* LPI pending bitmap size. */
601 {
602 uint32_t cbData = 0;
603 int const rc = pHlp->pfnSSMGetU32(pSSM, &cbData);
604 AssertRCReturn(rc, rc);
605 if (cbData != RT_SIZEOFMEMB(GICCPU, bmLpiPending))
606 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: LPI pending bitmap size: got=%u expected=%u"),
607 cbData, RT_SIZEOFMEMB(GICCPU, bmLpiPending));
608 }
609 /* LPI config table. */
610 {
611 uint32_t cbLpiConfig = 0;
612 int const rc = pHlp->pfnSSMGetU32(pSSM, &cbLpiConfig);
613 AssertRCReturn(rc, rc);
614 if (cbLpiConfig != sizeof(pGicDev->abLpiConfig))
615 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: LPI config table size: got=%u expected=%u"),
616 cbLpiConfig, sizeof(pGicDev->abLpiConfig));
617 pHlp->pfnSSMGetMem(pSSM, &pGicDev->abLpiConfig[0], cbLpiConfig);
618 }
619 pHlp->pfnSSMGetU64(pSSM, &pGicDev->uLpiConfigBaseReg.u);
620 pHlp->pfnSSMGetU64(pSSM, &pGicDev->uLpiPendingBaseReg.u);
621 pHlp->pfnSSMGetBool(pSSM, &pGicDev->fEnableLpis);
622
623 /** @todo GITS data. */
624
625 /*
626 * Load per-VCPU data.
627 */
628 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
629 {
630 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVM->apCpusR3[idCpu]);
631 Assert(pGicCpu);
632
633 /* Redistributor state. */
634 pHlp->pfnSSMGetMem(pSSM, &pGicCpu->bmIntrGroup[0], sizeof(pGicCpu->bmIntrGroup));
635 pHlp->pfnSSMGetMem(pSSM, &pGicCpu->bmIntrConfig[0], sizeof(pGicCpu->bmIntrConfig));
636 pHlp->pfnSSMGetMem(pSSM, &pGicCpu->bmIntrEnabled[0], sizeof(pGicCpu->bmIntrEnabled));
637 pHlp->pfnSSMGetMem(pSSM, &pGicCpu->bmIntrPending[0], sizeof(pGicCpu->bmIntrPending));
638 pHlp->pfnSSMGetMem(pSSM, &pGicCpu->bmIntrActive[0], sizeof(pGicCpu->bmIntrActive));
639 pHlp->pfnSSMGetMem(pSSM, &pGicCpu->abIntrPriority[0], sizeof(pGicCpu->abIntrPriority));
640
641 /* ICC system register state. */
642 pHlp->pfnSSMGetU64(pSSM, &pGicCpu->uIccCtlr);
643 pHlp->pfnSSMGetU8(pSSM, &pGicCpu->bIntrPriorityMask);
644 pHlp->pfnSSMGetU8(pSSM, &pGicCpu->idxRunningPriority);
645 pHlp->pfnSSMGetMem(pSSM, &pGicCpu->abRunningPriorities[0], sizeof(pGicCpu->abRunningPriorities));
646 pHlp->pfnSSMGetMem(pSSM, &pGicCpu->bmActivePriorityGroup0[0], sizeof(pGicCpu->bmActivePriorityGroup0));
647 pHlp->pfnSSMGetMem(pSSM, &pGicCpu->bmActivePriorityGroup1[0], sizeof(pGicCpu->bmActivePriorityGroup1));
648 pHlp->pfnSSMGetU8(pSSM, &pGicCpu->bBinaryPtGroup0);
649 pHlp->pfnSSMGetU8(pSSM, &pGicCpu->bBinaryPtGroup1);
650 pHlp->pfnSSMGetBool(pSSM, &pGicCpu->fIntrGroup0Enabled);
651 pHlp->pfnSSMGetBool(pSSM, &pGicCpu->fIntrGroup1Enabled);
652
653 /* LPI pending. */
654 pHlp->pfnSSMGetMem(pSSM, &pGicCpu->bmLpiPending[0], sizeof(pGicCpu->bmLpiPending));
655 }
656
657 /*
658 * Check that we're still good wrt restored data.
659 */
660 int rc = pHlp->pfnSSMHandleGetStatus(pSSM);
661 AssertRCReturn(rc, rc);
662
663 uint32_t uMarker = 0;
664 rc = pHlp->pfnSSMGetU32(pSSM, &uMarker);
665 AssertRCReturn(rc, rc);
666 if (uMarker == UINT32_MAX)
667 { /* likely */ }
668 else
669 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: Marker: got=%u expected=%u"), uMarker, UINT32_MAX);
670
671 /*
672 * Finally, perform sanity checks.
673 */
674 if (pGicDev->uArchRev <= GIC_DIST_REG_PIDR2_ARCHREV_GICV4)
675 { /* likely */ }
676 else
677 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Invalid uArchRev, got %u expected range [1,31]"), pGicDev->uArchRev,
678 GIC_DIST_REG_PIDR2_ARCHREV_GICV1, GIC_DIST_REG_PIDR2_ARCHREV_GICV4);
679 if (pGicDev->uArchRevMinor == 1)
680 { /* likely */ }
681 else
682 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Invalid uArchRevMinor, got %u expected 1"), pGicDev->uArchRevMinor);
683 if (pGicDev->uMaxSpi - 1 < 31)
684 { /* likely */ }
685 else
686 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Invalid MaxSpi, got %u expected range [1,31]"), pGicDev->uMaxSpi);
687 if (pGicDev->uMaxExtSpi <= 31)
688 { /* likely */ }
689 else
690 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Invalid MaxExtSpi, got %u expected range [0,31]"), pGicDev->uMaxExtSpi);
691 if ( pGicDev->uMaxExtPpi == GIC_REDIST_REG_TYPER_PPI_NUM_MAX_1087
692 || pGicDev->uMaxExtPpi == GIC_REDIST_REG_TYPER_PPI_NUM_MAX_1119)
693 { /* likely */ }
694 else
695 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Invalid MaxExtPpi, got %u expected range [1,2]"), pGicDev->uMaxExtPpi);
696 bool const fIsGitsEnabled = RT_BOOL(pGicDev->hMmioGits != NIL_IOMMMIOHANDLE);
697 if (fIsGitsEnabled == pGicDev->fLpi)
698 { /* likely */ }
699 else
700 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: LPIs are %s when ITS is %s"),
701 fIsGitsEnabled ? "enabled" : "disabled", pGicDev->fLpi ? "enabled" : "disabled");
702 return rc;
703}
704
705
706/**
707 * @interface_method_impl{PDMDEVREG,pfnReset}
708 */
709DECLCALLBACK(void) gicR3Reset(PPDMDEVINS pDevIns)
710{
711 PVM pVM = PDMDevHlpGetVM(pDevIns);
712 VM_ASSERT_EMT0(pVM);
713 VM_ASSERT_IS_NOT_RUNNING(pVM);
714
715 LogFlow(("GIC: gicR3Reset\n"));
716
717 gicReset(pDevIns);
718 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
719 {
720 PVMCPU pVCpuDest = pVM->apCpusR3[idCpu];
721 gicResetCpu(pDevIns, pVCpuDest);
722 }
723}
724
725
726/**
727 * @interface_method_impl{PDMDEVREG,pfnDestruct}
728 */
729DECLCALLBACK(int) gicR3Destruct(PPDMDEVINS pDevIns)
730{
731 LogFlowFunc(("pDevIns=%p\n", pDevIns));
732 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
733
734 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
735 PGITSDEV pGitsDev = &pGicDev->Gits;
736 if (pGitsDev->hEvtCmdQueue != NIL_SUPSEMEVENT)
737 {
738 PDMDevHlpSUPSemEventClose(pDevIns, pGitsDev->hEvtCmdQueue);
739 pGitsDev->hEvtCmdQueue = NIL_SUPSEMEVENT;
740 }
741
742 return VINF_SUCCESS;
743}
744
745
746/**
747 * @interface_method_impl{PDMDEVREG,pfnConstruct}
748 */
749DECLCALLBACK(int) gicR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
750{
751 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
752 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
753 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
754 PVM pVM = PDMDevHlpGetVM(pDevIns);
755 PGIC pGic = VM_TO_GIC(pVM);
756 Assert(iInstance == 0);
757
758 /*
759 * Init the data.
760 */
761 pGic->pDevInsR3 = pDevIns;
762
763 /*
764 * Validate GIC settings.
765 */
766 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "DistributorMmioBase|RedistributorMmioBase|ItsMmioBase"
767 "|ArchRev"
768 "|ArchRevMinor"
769 "|MaxSpi"
770 "|ExtSpi"
771 "|MaxExtSpi"
772 "|ExtPpi"
773 "|MaxExtPpi"
774 "|RangeSel"
775 "|Nmi"
776 "|Mbi"
777 "|Aff3Levels"
778 "|Lpi"
779 "|MaxLpi", "");
780
781#if 0
782 /*
783 * Disable automatic PDM locking for this device.
784 */
785 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
786 AssertRCReturn(rc, rc);
787#endif
788
789 /** @devcfgm{gic, ArchRev, uint8_t, 3}
790 * Configures the GIC architecture revision (GICD_PIDR2.ArchRev, GICR_PIDR2.ArchRev
791 * and GITS_PIDR2.ArchRev).
792 *
793 * Currently we only support GICv3 and the architecture revision reported is the
794 * same for both the GIC and the ITS. */
795 int rc = pHlp->pfnCFGMQueryU8Def(pCfg, "ArchRev", &pGicDev->uArchRev, 3);
796 AssertLogRelRCReturn(rc, rc);
797 if (pGicDev->uArchRev == GIC_DIST_REG_PIDR2_ARCHREV_GICV3)
798 {
799 AssertCompile(GIC_DIST_REG_PIDR2_ARCHREV_GICV3 == GITS_CTRL_REG_PIDR2_ARCHREV_GICV3);
800 pGicDev->Gits.uArchRev = pGicDev->uArchRev;
801 }
802 else
803 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
804 N_("Configuration error: \"ArchRev\" must be %u, other revisions not supported"),
805 GIC_DIST_REG_PIDR2_ARCHREV_GICV3);
806
807 /** @devcfgm{gic, ArchRevMinor, uint8_t, 1}
808 * Configures the GIC architecture revision minor version.
809 *
810 * Currently we support GICv3.1 only. GICv3.1's only addition to GICv3 is supported
811 * for extended INTID ranges which we currently always support. */
812 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "ArchRevMinor", &pGicDev->uArchRevMinor, 1);
813 AssertLogRelRCReturn(rc, rc);
814 if (pGicDev->uArchRevMinor == 1)
815 { /* likely */ }
816 else
817 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
818 N_("Configuration error: \"ArchRevMinor\" must be 1, other minor revisions not supported"));
819
820 /** @devcfgm{gic, MaxSpi, uint8_t, 31}
821 * Configures GICD_TYPER.ItLinesNumber.
822 *
823 * For the IntId range [32,1023], configures the maximum SPI supported. Valid values
824 * are [1,31] which equates to interrupt IDs [63,1023]. A value of 0 implies SPIs
825 * are not supported. We don't allow configuring this value as it's expected that
826 * most guests would assume support for SPIs. */
827 AssertCompile(GIC_DIST_REG_TYPER_NUM_ITLINES == 31);
828 /** @todo This currently isn't implemented and the full range is always
829 * reported to the guest. */
830 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "MaxSpi", &pGicDev->uMaxSpi, 31 /* Upto and incl. IntId 1023 */);
831 AssertLogRelRCReturn(rc, rc);
832 if (pGicDev->uMaxSpi - 1 < 31)
833 { /* likely */ }
834 else
835 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
836 N_("Configuration error: \"MaxSpi\" must be in the range [1,%u]"),
837 GIC_DIST_REG_TYPER_NUM_ITLINES);
838
839 /** @devcfgm{gic, ExtSpi, bool, false}
840 * Configures whether extended SPIs supported is enabled (GICD_TYPER.ESPI). */
841 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "ExtSpi", &pGicDev->fExtSpi, true);
842 AssertLogRelRCReturn(rc, rc);
843
844 /** @devcfgm{gic, MaxExtSpi, uint8_t, 31}
845 * Configures GICD_TYPER.ESPI_range.
846 *
847 * For the extended SPI range [4096,5119], configures the maximum extended SPI
848 * supported. Valid values are [0,31] which equates to extended SPI IntIds
849 * [4127,5119]. This is ignored (set to 0 in the register) when extended SPIs are
850 * disabled. */
851 AssertCompile(GIC_DIST_REG_TYPER_ESPI_RANGE >> GIC_DIST_REG_TYPER_ESPI_RANGE_BIT == 31);
852 /** @todo This currently isn't implemented and the full range is always
853 * reported to the guest. */
854 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "MaxExtSpi", &pGicDev->uMaxExtSpi, 31);
855 AssertLogRelRCReturn(rc, rc);
856 if (pGicDev->uMaxExtSpi <= 31)
857 { /* likely */ }
858 else
859 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
860 N_("Configuration error: \"MaxExtSpi\" must be in the range [0,31]"));
861
862 /** @devcfgm{gic, ExtPpi, bool, true}
863 * Configures whether extended PPIs support is enabled. */
864 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "ExtPpi", &pGicDev->fExtPpi, true);
865 AssertLogRelRCReturn(rc, rc);
866
867 /** @devcfgm{gic, MaxExtPpi, uint8_t, 2}
868 * Configures GICR_TYPER.PPInum.
869 *
870 * For the extended PPI range [1056,5119], configures the maximum extended PPI
871 * supported. Valid values are [1,2] which equates to extended PPI IntIds
872 * [1087,1119]. This is unused when extended PPIs are disabled. */
873 /** @todo This currently isn't implemented and the full range is always
874 * reported to the guest. */
875 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "MaxExtPpi", &pGicDev->uMaxExtPpi, 2);
876 AssertLogRelRCReturn(rc, rc);
877 if ( pGicDev->uMaxExtPpi == GIC_REDIST_REG_TYPER_PPI_NUM_MAX_1087
878 || pGicDev->uMaxExtPpi == GIC_REDIST_REG_TYPER_PPI_NUM_MAX_1119)
879 { /* likely */ }
880 else
881 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
882 N_("Configuration error: \"MaxExtPpi\" must be in the range [0,2]"));
883
884 /** @devcfgm{gic, RangeSel, bool, true}
885 * Configures whether range-selector support is enabled (GICD_TYPER.RSS and
886 * ICC_CTLR_EL1.RSS). */
887 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "RangeSel", &pGicDev->fRangeSel, true);
888 AssertLogRelRCReturn(rc, rc);
889
890 /** @devcfgm{gic, Nmi, bool, false}
891 * Configures whether non-maskable interrupts (NMIs) are supported
892 * (GICD_TYPER.NMI). */
893 /** @todo NMIs are currently not implemented. */
894 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "Nmi", &pGicDev->fNmi, false);
895 AssertLogRelRCReturn(rc, rc);
896
897 /** @devcfgm{gic, Mbi, bool, false}
898 * Configures whether message-based interrupts (MBIs) are supported
899 * (GICD_TYPER.MBIS).
900 *
901 * Guests typically can't use MBIs without an ITS. */
902 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "Mbi", &pGicDev->fMbi, false);
903 AssertLogRelRCReturn(rc, rc);
904
905 /** @devcfgm{gic, Aff3Levels, bool, true}
906 * Configures whether non-zero affinity 3 levels (A3V) are supported
907 * (GICD_TYPER.A3V and ICC_CTLR.A3V). */
908 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "Aff3Levels", &pGicDev->fAff3Levels, true);
909 AssertLogRelRCReturn(rc, rc);
910
911 /** @devcfgm{gic, Lpi, bool, false}
912 * Configures whether physical LPIs are supported (GICD_TYPER.LPIS and
913 * GICR_TYPER.PLPIS).
914 *
915 * This currently requires an ITS as we do not support direction injection of
916 * LPIs as most guests do not use them anyway. */
917 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "Lpi", &pGicDev->fLpi, false);
918 AssertLogRelRCReturn(rc, rc);
919
920 /** @devcfgm{gic, MaxLpi, uint8_t, 14}
921 * Configures GICD_TYPER.num_LPIs.
922 *
923 * For the physical LPI range [8192,65535], configures the number of physical LPI
924 * supported. Valid values are [3,14] which equates to LPI IntIds 8192 to
925 * [8207,40959]. A value of 15 or higher would exceed the maximum INTID size of
926 * 16-bits since 8192 + 2^(NumLpi+1) is >= 73727. A value of 2 or lower support
927 * fewer than 15 LPIs which seem pointless and is hence disallowed. This value is
928 * ignored (set to 0 in the register) when LPIs are disabled. */
929 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "MaxLpi", &pGicDev->uMaxLpi, 11);
930 AssertLogRelRCReturn(rc, rc);
931
932 /* We currently support 4096 LPIs until we need to support more. */
933 if (pGicDev->uMaxLpi == 11)
934 { /* likely */ }
935 else
936 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
937 N_("Configuration error: \"MaxLpi\" must be in the range [3,14]"));
938 AssertRelease(UINT32_C(2) << pGicDev->uMaxLpi <= RT_ELEMENTS(pGicDev->abLpiConfig));
939
940 /*
941 * Register the GIC with PDM.
942 */
943 rc = PDMDevHlpIcRegister(pDevIns);
944 AssertLogRelRCReturn(rc, rc);
945
946 rc = PDMGicRegisterBackend(pVM, PDMGICBACKENDTYPE_VBOX, &g_GicBackend);
947 AssertLogRelRCReturn(rc, rc);
948
949 /*
950 * Insert the GIC system registers.
951 */
952 for (uint32_t i = 0; i < RT_ELEMENTS(g_aSysRegRanges_GIC); i++)
953 {
954 rc = CPUMR3SysRegRangesInsert(pVM, &g_aSysRegRanges_GIC[i]);
955 AssertLogRelRCReturn(rc, rc);
956 }
957
958 /*
959 * Register the MMIO ranges.
960 */
961 /* Distributor. */
962 {
963 RTGCPHYS GCPhysMmioBase = 0;
964 rc = pHlp->pfnCFGMQueryU64(pCfg, "DistributorMmioBase", &GCPhysMmioBase);
965 if (RT_FAILURE(rc))
966 return PDMDEV_SET_ERROR(pDevIns, rc,
967 N_("Configuration error: Failed to get the \"DistributorMmioBase\" value"));
968
969 rc = PDMDevHlpMmioCreateAndMap(pDevIns, GCPhysMmioBase, GIC_DIST_REG_FRAME_SIZE, gicDistMmioWrite, gicDistMmioRead,
970 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_DWORD_ZEROED, "GIC Distributor",
971 &pGicDev->hMmioDist);
972 AssertRCReturn(rc, rc);
973 }
974
975 /* Redistributor. */
976 {
977 RTGCPHYS GCPhysMmioBase = 0;
978 rc = pHlp->pfnCFGMQueryU64(pCfg, "RedistributorMmioBase", &GCPhysMmioBase);
979 if (RT_FAILURE(rc))
980 return PDMDEV_SET_ERROR(pDevIns, rc,
981 N_("Configuration error: Failed to get the \"RedistributorMmioBase\" value"));
982
983 RTGCPHYS const cbRegion = (RTGCPHYS)pVM->cCpus
984 * (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE); /* Adjacent and per vCPU. */
985 rc = PDMDevHlpMmioCreateAndMap(pDevIns, GCPhysMmioBase, cbRegion, gicReDistMmioWrite, gicReDistMmioRead,
986 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_DWORD_ZEROED, "GIC Redistributor",
987 &pGicDev->hMmioReDist);
988 AssertRCReturn(rc, rc);
989 }
990
991 /* ITS. */
992 {
993 RTGCPHYS GCPhysMmioBase = 0;
994 rc = pHlp->pfnCFGMQueryU64(pCfg, "ItsMmioBase", &GCPhysMmioBase);
995 if (RT_SUCCESS(rc))
996 {
997 Assert(pGicDev->hMmioGits != NIL_IOMMMIOHANDLE); /* paranoia, as this would be 0 here not NIL_IOMMMIOHANDLE. */
998 RTGCPHYS const cbRegion = 2 * GITS_REG_FRAME_SIZE; /* 2 frames for GICv3. */
999 rc = PDMDevHlpMmioCreateAndMap(pDevIns, GCPhysMmioBase, cbRegion, gicItsMmioWrite, gicItsMmioRead,
1000 IOMMMIO_FLAGS_READ_DWORD_QWORD
1001 | IOMMMIO_FLAGS_WRITE_DWORD_QWORD_ZEROED
1002 | IOMMMIO_FLAGS_DBGSTOP_ON_COMPLICATED_READ
1003 | IOMMMIO_FLAGS_DBGSTOP_ON_COMPLICATED_WRITE,
1004 "GIC ITS", &pGicDev->hMmioGits);
1005 AssertLogRelRCReturn(rc, rc);
1006 Assert(pGicDev->hMmioGits != NIL_IOMMMIOHANDLE);
1007
1008 /* When the ITS is enabled we must support LPIs. */
1009 if (!pGicDev->fLpi)
1010 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
1011 N_("Configuration error: \"Lpi\" must be enabled when ITS is enabled\n"));
1012
1013 /* Create ITS command-queue thread and semaphore. */
1014 PGITSDEV pGitsDev = &pGicDev->Gits;
1015 char szCmdQueueThread[32];
1016 RT_ZERO(szCmdQueueThread);
1017 RTStrPrintf(szCmdQueueThread, sizeof(szCmdQueueThread), "Gits-CmdQ-%u", iInstance);
1018 rc = PDMDevHlpThreadCreate(pDevIns, &pGitsDev->pCmdQueueThread, &pGicDev, gicItsR3CmdQueueThread,
1019 gicItsR3CmdQueueThreadWakeUp, 0 /* cbStack */, RTTHREADTYPE_IO, szCmdQueueThread);
1020 AssertLogRelRCReturn(rc, rc);
1021
1022 rc = PDMDevHlpSUPSemEventCreate(pDevIns, &pGitsDev->hEvtCmdQueue);
1023 AssertLogRelRCReturn(rc, rc);
1024 }
1025 else
1026 {
1027 pGicDev->hMmioGits = NIL_IOMMMIOHANDLE;
1028
1029 /* When the ITS is disabled we don't support LPIs as we do not support direct LPI injection (guests don't use it). */
1030 if (pGicDev->fLpi)
1031 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
1032 N_("Configuration error: \"Lpi\" must be disabled when ITS is disabled\n"));
1033 }
1034 }
1035
1036 /*
1037 * Register saved state callbacks.
1038 */
1039 rc = PDMDevHlpSSMRegister(pDevIns, GIC_SAVED_STATE_VERSION, 0, gicR3SaveExec, gicR3LoadExec);
1040 AssertRCReturn(rc, rc);
1041
1042 /*
1043 * Register debugger info callbacks.
1044 *
1045 * We use separate callbacks rather than arguments so they can also be
1046 * dumped in an automated fashion while collecting crash diagnostics and
1047 * not just used during live debugging via the VM debugger.
1048 */
1049 DBGFR3InfoRegisterInternalEx(pVM, "gic", "Dumps GIC basic information.", gicR3DbgInfo, DBGFINFO_FLAGS_ALL_EMTS);
1050 DBGFR3InfoRegisterInternalEx(pVM, "gicdist", "Dumps GIC distributor information.", gicR3DbgInfoDist, DBGFINFO_FLAGS_ALL_EMTS);
1051 DBGFR3InfoRegisterInternalEx(pVM, "gicredist", "Dumps GIC redistributor information.", gicR3DbgInfoReDist, DBGFINFO_FLAGS_ALL_EMTS);
1052 DBGFR3InfoRegisterInternalEx(pVM, "gicits", "Dumps GIC ITS information.", gicR3DbgInfoIts, DBGFINFO_FLAGS_ALL_EMTS);
1053 DBGFR3InfoRegisterInternalEx(pVM, "giclpi", "Dumps GIC LPI information.", gicR3DbgInfoLpi, DBGFINFO_FLAGS_ALL_EMTS);
1054
1055 /*
1056 * Statistics.
1057 */
1058#ifdef VBOX_WITH_STATISTICS
1059# define GICCPU_REG_COUNTER(a_pvReg, a_pszNameFmt, a_pszDesc) \
1060 PDMDevHlpSTAMRegisterF(pDevIns, a_pvReg, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, \
1061 a_pszDesc, a_pszNameFmt, idCpu)
1062# define GICCPU_PROF_COUNTER(a_pvReg, a_pszNameFmt, a_pszDesc) \
1063 PDMDevHlpSTAMRegisterF(pDevIns, a_pvReg, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, \
1064 a_pszDesc, a_pszNameFmt, idCpu)
1065# define GIC_REG_COUNTER(a_pvReg, a_pszNameFmt, a_pszDesc) \
1066 PDMDevHlpSTAMRegisterF(pDevIns, a_pvReg, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, \
1067 a_pszDesc, a_pszNameFmt)
1068
1069 /* Redistributor. */
1070 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1071 {
1072 PVMCPU pVCpu = pVM->apCpusR3[idCpu];
1073 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
1074
1075 GICCPU_REG_COUNTER(&pGicCpu->StatMmioRead, "%u/MmioRead", "Number of MMIO reads.");
1076 GICCPU_REG_COUNTER(&pGicCpu->StatMmioWrite, "%u/MmioWrite", "Number of MMIO writes.");
1077 GICCPU_REG_COUNTER(&pGicCpu->StatSysRegRead, "%u/SysRegRead", "Number of system register reads.");
1078 GICCPU_REG_COUNTER(&pGicCpu->StatSysRegWrite, "%u/SysRegWrite", "Number of system register writes.");
1079 GICCPU_REG_COUNTER(&pGicCpu->StatSetSpi, "%u/SetSpi", "Number of set SPI callbacks.");
1080 GICCPU_REG_COUNTER(&pGicCpu->StatSetPpi, "%u/SetPpi", "Number of set PPI callbacks.");
1081 GICCPU_REG_COUNTER(&pGicCpu->StatSetSgi, "%u/SetSgi", "Number of SGIs generated.");
1082
1083 GICCPU_PROF_COUNTER(&pGicCpu->StatProfIntrAck, "%u/Prof/IntrAck", "Profiling of interrupt acknowledge (IAR).");
1084 GICCPU_PROF_COUNTER(&pGicCpu->StatProfSetSpi, "%u/Prof/SetSpi", "Profiling of set SPI callback.");
1085 GICCPU_PROF_COUNTER(&pGicCpu->StatProfSetPpi, "%u/Prof/SetPpi", "Profiling of set PPI callback.");
1086 GICCPU_PROF_COUNTER(&pGicCpu->StatProfSetSgi, "%u/Prof/SetSgi", "Profiling of SGIs generated.");
1087 }
1088
1089 /* ITS. */
1090 PGITSDEV pGitsDev = &pGicDev->Gits;
1091 GIC_REG_COUNTER(&pGitsDev->StatCmdMapc, "ITS/Commands/MAPC", "Number of MAPC commands executed.");
1092 GIC_REG_COUNTER(&pGitsDev->StatCmdSync, "ITS/Commands/SYNC", "Number of SYNC commands executed.");
1093 GIC_REG_COUNTER(&pGitsDev->StatCmdInvall, "ITS/Commands/INVALL", "Number of INVALL commands executed.");
1094
1095# undef GICCPU_REG_COUNTER
1096# undef GICCPU_PROF_COUNTER
1097# undef GIC_REG_COUNTER
1098#endif /* VBOX_WITH_STATISTICS */
1099
1100 gicR3Reset(pDevIns);
1101
1102 /*
1103 * Log some of the features exposed to software.
1104 */
1105 uint8_t const uArchRev = pGicDev->uArchRev;
1106 uint8_t const uArchRevMinor = pGicDev->uArchRevMinor;
1107 uint8_t const uMaxSpi = pGicDev->uMaxSpi;
1108 bool const fExtSpi = pGicDev->fExtSpi;
1109 uint8_t const uMaxExtSpi = pGicDev->uMaxExtSpi;
1110 bool const fExtPpi = pGicDev->fExtPpi;
1111 uint8_t const uMaxExtPpi = pGicDev->uMaxExtPpi;
1112 bool const fRangeSel = pGicDev->fRangeSel;
1113 bool const fNmi = pGicDev->fNmi;
1114 bool const fMbi = pGicDev->fMbi;
1115 bool const fAff3Levels = pGicDev->fAff3Levels;
1116 bool const fLpi = pGicDev->fLpi;
1117 uint32_t const uMaxLpi = pGicDev->uMaxLpi;
1118 uint16_t const uExtPpiLast = uMaxExtPpi == GIC_REDIST_REG_TYPER_PPI_NUM_MAX_1087 ? 1087 : GIC_INTID_RANGE_EXT_PPI_LAST;
1119 LogRel(("GIC: ArchRev=%u.%u RangeSel=%RTbool Nmi=%RTbool Mbi=%RTbool Aff3Levels=%RTbool\n",
1120 uArchRev, uArchRevMinor, fRangeSel, fNmi, fMbi, fAff3Levels));
1121 LogRel(("GIC: SPIs=true (%u:32..%u) ExtSPIs=%RTbool (%u:4095..%u) ExtPPIs=%RTbool (%u:1056..%u)\n",
1122 uMaxSpi, 32 * (uMaxSpi + 1),
1123 fExtSpi, uMaxExtSpi, GIC_INTID_RANGE_EXT_SPI_START - 1 + 32 * (uMaxExtSpi + 1),
1124 fExtPpi, uMaxExtPpi, uExtPpiLast));
1125 LogRel(("GIC: ITS=%s LPIs=%s (%u:%u..%u)\n",
1126 pGicDev->hMmioGits != NIL_IOMMMIOHANDLE ? "enabled" : "disabled", fLpi ? "enabled" : "disabled",
1127 uMaxLpi, GIC_INTID_RANGE_LPI_START, GIC_INTID_RANGE_LPI_START - 1 + (UINT32_C(2) << uMaxLpi)));
1128 return VINF_SUCCESS;
1129}
1130
1131#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
1132
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