VirtualBox

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

Last change on this file since 108682 was 108682, checked in by vboxsync, 4 weeks ago

VMM/GIC: bugref:10877 GITS scafolding.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 38.6 KB
Line 
1/* $Id: GICR3.cpp 108682 2025-03-21 09:38:38Z 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
45
46#ifndef VBOX_DEVICE_STRUCT_TESTCASE
47
48
49/*********************************************************************************************************************************
50* Defined Constants And Macros *
51*********************************************************************************************************************************/
52/** GIC saved state version. */
53#define GIC_SAVED_STATE_VERSION 6
54
55# define GIC_SYSREGRANGE(a_uFirst, a_uLast, a_szName) \
56 { (a_uFirst), (a_uLast), kCpumSysRegRdFn_GicIcc, kCpumSysRegWrFn_GicIcc, 0, 0, 0, 0, 0, 0, a_szName, { 0 }, { 0 }, { 0 }, { 0 } }
57
58
59/*********************************************************************************************************************************
60* Global Variables *
61*********************************************************************************************************************************/
62/**
63 * System register ranges for the GIC.
64 */
65static CPUMSYSREGRANGE const g_aSysRegRanges_GIC[] =
66{
67 GIC_SYSREGRANGE(ARMV8_AARCH64_SYSREG_ICC_PMR_EL1, ARMV8_AARCH64_SYSREG_ICC_PMR_EL1, "ICC_PMR_EL1"),
68 GIC_SYSREGRANGE(ARMV8_AARCH64_SYSREG_ICC_IAR0_EL1, ARMV8_AARCH64_SYSREG_ICC_AP0R3_EL1, "ICC_IAR0_EL1 - ICC_AP0R3_EL1"),
69 GIC_SYSREGRANGE(ARMV8_AARCH64_SYSREG_ICC_AP1R0_EL1, ARMV8_AARCH64_SYSREG_ICC_NMIAR1_EL1, "ICC_AP1R0_EL1 - ICC_NMIAR1_EL1"),
70 GIC_SYSREGRANGE(ARMV8_AARCH64_SYSREG_ICC_DIR_EL1, ARMV8_AARCH64_SYSREG_ICC_SGI0R_EL1, "ICC_DIR_EL1 - ICC_SGI0R_EL1"),
71 GIC_SYSREGRANGE(ARMV8_AARCH64_SYSREG_ICC_IAR1_EL1, ARMV8_AARCH64_SYSREG_ICC_IGRPEN1_EL1, "ICC_IAR1_EL1 - ICC_IGRPEN1_EL1"),
72 GIC_SYSREGRANGE(ARMV8_AARCH64_SYSREG_ICC_SRE_EL2, ARMV8_AARCH64_SYSREG_ICC_SRE_EL2, "ICC_SRE_EL2"),
73 GIC_SYSREGRANGE(ARMV8_AARCH64_SYSREG_ICC_SRE_EL3, ARMV8_AARCH64_SYSREG_ICC_SRE_EL3, "ICC_SRE_EL3")
74};
75
76
77/**
78 * Dumps basic GIC state.
79 *
80 * @param pVM The cross context VM structure.
81 * @param pHlp The info helpers.
82 * @param pszArgs Arguments, ignored.
83 */
84static DECLCALLBACK(void) gicR3DbgInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
85{
86 RT_NOREF(pszArgs);
87 PCGIC pGic = VM_TO_GIC(pVM);
88 PPDMDEVINS pDevIns = pGic->CTX_SUFF(pDevIns);
89 PCGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PCGICDEV);
90
91 pHlp->pfnPrintf(pHlp, "GIC:\n");
92 pHlp->pfnPrintf(pHlp, " uArchRev = %u\n", pGicDev->uArchRev);
93 pHlp->pfnPrintf(pHlp, " uMaxSpi = %u (upto IntId %u)\n", pGicDev->uMaxSpi, 32 * (pGicDev->uMaxSpi + 1));
94 pHlp->pfnPrintf(pHlp, " fExtSpi = %RTbool\n", pGicDev->fExtSpi);
95 pHlp->pfnPrintf(pHlp, " uMaxExtSpi = %u (upto IntId %u)\n", pGicDev->uMaxExtSpi,
96 GIC_INTID_RANGE_EXT_SPI_START - 1 + 32 * (pGicDev->uMaxExtSpi + 1));
97 pHlp->pfnPrintf(pHlp, " fExtPpi = %RTbool\n", pGicDev->fExtPpi);
98 pHlp->pfnPrintf(pHlp, " uMaxExtPpi = %u (upto IntId %u)\n", pGicDev->uMaxExtPpi,
99 pGicDev->uMaxExtPpi == GIC_REDIST_REG_TYPER_PPI_NUM_MAX_1087 ? 1087 : GIC_INTID_RANGE_EXT_PPI_LAST);
100 pHlp->pfnPrintf(pHlp, " fRangeSelSupport = %RTbool\n", pGicDev->fRangeSel);
101 pHlp->pfnPrintf(pHlp, " fNmi = %RTbool\n", pGicDev->fNmi);
102 pHlp->pfnPrintf(pHlp, " fMbi = %RTbool\n", pGicDev->fMbi);
103 pHlp->pfnPrintf(pHlp, " fAff3Levels = %RTbool\n", pGicDev->fAff3Levels);
104}
105
106
107/**
108 * Dumps GIC Distributor information.
109 *
110 * @param pVM The cross context VM structure.
111 * @param pHlp The info helpers.
112 * @param pszArgs Arguments, ignored.
113 */
114static DECLCALLBACK(void) gicR3DbgInfoDist(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
115{
116 RT_NOREF(pszArgs);
117
118 PGIC pGic = VM_TO_GIC(pVM);
119 PPDMDEVINS pDevIns = pGic->CTX_SUFF(pDevIns);
120 PCGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PCGICDEV);
121
122#define GIC_DBGFINFO_DIST_INTR_BITMAP(a_Name, a_bmIntr) \
123 do \
124 { \
125 pHlp->pfnPrintf(pHlp, " " a_Name " =\n"); \
126 for (uint32_t i = 0; i < RT_ELEMENTS(a_bmIntr); i += 8) \
127 pHlp->pfnPrintf(pHlp, " [%2u..%-2u] %#010x %#010x %#010x %#010x %#010x %#010x %#010x %#010x\n", i, i + 7, \
128 (a_bmIntr)[i], (a_bmIntr)[i+1], (a_bmIntr)[i+2], (a_bmIntr)[i+3], \
129 (a_bmIntr)[i+4], (a_bmIntr)[i+5], (a_bmIntr)[i+6], (a_bmIntr)[i+7]); \
130 } while (0)
131
132 pHlp->pfnPrintf(pHlp, "GIC Distributor:\n");
133 pHlp->pfnPrintf(pHlp, " fIntrGroup0Enabled = %RTbool\n", pGicDev->fIntrGroup0Enabled);
134 pHlp->pfnPrintf(pHlp, " fIntrGroup1Enabled = %RTbool\n", pGicDev->fIntrGroup1Enabled);
135 pHlp->pfnPrintf(pHlp, " fAffRoutingEnabled = %RTbool\n", pGicDev->fAffRoutingEnabled);
136 GIC_DBGFINFO_DIST_INTR_BITMAP("bmIntrGroup", pGicDev->bmIntrGroup);
137 GIC_DBGFINFO_DIST_INTR_BITMAP("bmIntrEnabled", pGicDev->bmIntrEnabled);
138 GIC_DBGFINFO_DIST_INTR_BITMAP("bmIntrPending", pGicDev->bmIntrPending);
139 GIC_DBGFINFO_DIST_INTR_BITMAP("bmIntrActive", pGicDev->bmIntrActive);
140
141 /* Interrupt priorities.*/
142 {
143 uint32_t const cPriorities = RT_ELEMENTS(pGicDev->abIntrPriority);
144 AssertCompile(!(cPriorities % 16));
145 pHlp->pfnPrintf(pHlp, " Interrupt priorities:\n");
146 for (uint32_t i = 0; i < cPriorities; i += 16)
147 pHlp->pfnPrintf(pHlp, " IntId[%4u..%-4u] = %3u %3u %3u %3u %3u %3u %3u %3u"
148 " IntId[%4u..%-4u] = %3u %3u %3u %3u %3u %3u %3u %3u\n",
149 gicDistGetIntIdFromIndex(i), gicDistGetIntIdFromIndex(i + 7),
150 pGicDev->abIntrPriority[i], pGicDev->abIntrPriority[i + 1],
151 pGicDev->abIntrPriority[i + 2], pGicDev->abIntrPriority[i + 3],
152 pGicDev->abIntrPriority[i + 4], pGicDev->abIntrPriority[i + 5],
153 pGicDev->abIntrPriority[i + 6], pGicDev->abIntrPriority[i + 7],
154 gicDistGetIntIdFromIndex(i + 8), gicDistGetIntIdFromIndex(i + 15),
155 pGicDev->abIntrPriority[i + 8], pGicDev->abIntrPriority[i + 9],
156 pGicDev->abIntrPriority[i + 10], pGicDev->abIntrPriority[i + 11],
157 pGicDev->abIntrPriority[i + 12], pGicDev->abIntrPriority[i + 13],
158 pGicDev->abIntrPriority[i + 14], pGicDev->abIntrPriority[i + 15]);
159 }
160
161 /* Interrupt routing.*/
162 {
163 /** @todo Interrupt rounting mode. */
164 uint32_t const cRouting = RT_ELEMENTS(pGicDev->au32IntrRouting);
165 AssertCompile(!(cRouting % 16));
166 pHlp->pfnPrintf(pHlp, " Interrupt routing:\n");
167 for (uint32_t i = 0; i < cRouting; i += 16)
168 pHlp->pfnPrintf(pHlp, " IntId[%4u..%-4u] = %3u %3u %3u %3u %3u %3u %3u %3u"
169 " IntId[%4u..%-4u] = %3u %3u %3u %3u %3u %3u %3u %3u\n",
170 gicDistGetIntIdFromIndex(i), gicDistGetIntIdFromIndex(i + 7),
171 pGicDev->au32IntrRouting[i], pGicDev->au32IntrRouting[i + 1],
172 pGicDev->au32IntrRouting[i + 2], pGicDev->au32IntrRouting[i + 3],
173 pGicDev->au32IntrRouting[i + 4], pGicDev->au32IntrRouting[i + 5],
174 pGicDev->au32IntrRouting[i + 6], pGicDev->au32IntrRouting[i + 7],
175 gicDistGetIntIdFromIndex(i + 8), gicDistGetIntIdFromIndex(i + 15),
176 pGicDev->au32IntrRouting[i + 8], pGicDev->au32IntrRouting[i + 9],
177 pGicDev->au32IntrRouting[i + 10], pGicDev->au32IntrRouting[i + 11],
178 pGicDev->au32IntrRouting[i + 12], pGicDev->au32IntrRouting[i + 13],
179 pGicDev->au32IntrRouting[i + 14], pGicDev->au32IntrRouting[i + 15]);
180 }
181
182#undef GIC_DBGFINFO_DIST_INTR_BITMAP
183}
184
185
186/**
187 * Dumps the GIC Redistributor information.
188 *
189 * @param pVM The cross context VM structure.
190 * @param pHlp The info helpers.
191 * @param pszArgs Arguments, ignored.
192 */
193static DECLCALLBACK(void) gicR3DbgInfoReDist(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
194{
195 NOREF(pszArgs);
196 PVMCPU pVCpu = VMMGetCpu(pVM);
197 if (!pVCpu)
198 pVCpu = pVM->apCpusR3[0];
199
200 PCGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
201
202 pHlp->pfnPrintf(pHlp, "VCPU[%u] Redistributor:\n", pVCpu->idCpu);
203 AssertCompile(RT_ELEMENTS(pGicCpu->bmIntrGroup) >= 3);
204 AssertCompile(RT_ELEMENTS(pGicCpu->bmIntrEnabled) >= 3);
205 AssertCompile(RT_ELEMENTS(pGicCpu->bmIntrPending) >= 3);
206 AssertCompile(RT_ELEMENTS(pGicCpu->bmIntrActive) >= 3);
207 pHlp->pfnPrintf(pHlp, " bmIntrGroup[0..2] = %#010x %#010x %#010x\n", pGicCpu->bmIntrGroup[0], pGicCpu->bmIntrGroup[1], pGicCpu->bmIntrGroup[2]);
208 pHlp->pfnPrintf(pHlp, " bmIntrEnabled[0..2] = %#010x %#010x %#010x\n", pGicCpu->bmIntrEnabled[0], pGicCpu->bmIntrEnabled[1], pGicCpu->bmIntrEnabled[2]);
209 pHlp->pfnPrintf(pHlp, " bmIntrPending[0..2] = %#010x %#010x %#010x\n", pGicCpu->bmIntrPending[0], pGicCpu->bmIntrPending[1], pGicCpu->bmIntrPending[2]);
210 pHlp->pfnPrintf(pHlp, " bmIntrActive[0..2] = %#010x %#010x %#010x\n", pGicCpu->bmIntrActive[0], pGicCpu->bmIntrActive[1], pGicCpu->bmIntrActive[2]);
211
212 /* Interrupt priorities. */
213 {
214 uint32_t const cPriorities = RT_ELEMENTS(pGicCpu->abIntrPriority);
215 AssertCompile(!(cPriorities % 16));
216 pHlp->pfnPrintf(pHlp, " Interrupt priorities:\n");
217 for (uint32_t i = 0; i < cPriorities; i += 16)
218 pHlp->pfnPrintf(pHlp, " IntId[%4u..%-4u] = %3u %3u %3u %3u %3u %3u %3u %3u"
219 " IntId[%4u..%-4u] = %3u %3u %3u %3u %3u %3u %3u %3u\n",
220 gicReDistGetIntIdFromIndex(i), gicReDistGetIntIdFromIndex(i + 7),
221 pGicCpu->abIntrPriority[i], pGicCpu->abIntrPriority[i + 1],
222 pGicCpu->abIntrPriority[i + 2], pGicCpu->abIntrPriority[i + 3],
223 pGicCpu->abIntrPriority[i + 4], pGicCpu->abIntrPriority[i + 5],
224 pGicCpu->abIntrPriority[i + 6], pGicCpu->abIntrPriority[i + 7],
225 gicReDistGetIntIdFromIndex(i + 8), gicReDistGetIntIdFromIndex(i + 15),
226 pGicCpu->abIntrPriority[i + 8], pGicCpu->abIntrPriority[i + 9],
227 pGicCpu->abIntrPriority[i + 10], pGicCpu->abIntrPriority[i + 11],
228 pGicCpu->abIntrPriority[i + 12], pGicCpu->abIntrPriority[i + 13],
229 pGicCpu->abIntrPriority[i + 14], pGicCpu->abIntrPriority[i + 15]);
230 }
231
232 pHlp->pfnPrintf(pHlp, "\nVCPU[%u] ICC system register state:\n", pVCpu->idCpu);
233 pHlp->pfnPrintf(pHlp, " uIccCtlr = %#RX64\n", pGicCpu->uIccCtlr);
234 pHlp->pfnPrintf(pHlp, " fIntrGroup0Enabled = %RTbool\n", pGicCpu->fIntrGroup0Enabled);
235 pHlp->pfnPrintf(pHlp, " fIntrGroup1Enabled = %RTbool\n", pGicCpu->fIntrGroup1Enabled);
236 pHlp->pfnPrintf(pHlp, " bBinaryPtGroup0 = %#x\n", pGicCpu->bBinaryPtGroup0);
237 pHlp->pfnPrintf(pHlp, " bBinaryPtGroup1 = %#x\n", pGicCpu->bBinaryPtGroup1);
238 pHlp->pfnPrintf(pHlp, " idxRunningPriority = %#x\n", pGicCpu->idxRunningPriority);
239 pHlp->pfnPrintf(pHlp, " Running priority = %#x\n", pGicCpu->abRunningPriorities[pGicCpu->idxRunningPriority]);
240
241 /* Running interrupt priorities. */
242 {
243 uint32_t const cPriorities = RT_ELEMENTS(pGicCpu->abRunningPriorities);
244 AssertCompile(!(cPriorities % 16));
245 pHlp->pfnPrintf(pHlp, " Running-interrupt priorities:\n");
246 for (uint32_t i = 0; i < cPriorities; i += 16)
247 pHlp->pfnPrintf(pHlp, " [%3u..%-3u] = %3u %3u %3u %3u %3u %3u %3u %3u"
248 " [%3u..%-3u] = %3u %3u %3u %3u %3u %3u %3u %3u\n",
249 i, i + 7,
250 pGicCpu->abRunningPriorities[i], pGicCpu->abRunningPriorities[i + 1],
251 pGicCpu->abRunningPriorities[i + 2], pGicCpu->abRunningPriorities[i + 3],
252 pGicCpu->abRunningPriorities[i + 4], pGicCpu->abRunningPriorities[i + 5],
253 pGicCpu->abRunningPriorities[i + 6], pGicCpu->abRunningPriorities[i + 7],
254 i + 8, i + 15,
255 pGicCpu->abRunningPriorities[i + 8], pGicCpu->abRunningPriorities[i + 9],
256 pGicCpu->abRunningPriorities[i + 10], pGicCpu->abRunningPriorities[i + 11],
257 pGicCpu->abRunningPriorities[i + 12], pGicCpu->abRunningPriorities[i + 13],
258 pGicCpu->abRunningPriorities[i + 14], pGicCpu->abRunningPriorities[i + 15]);
259 }
260
261 AssertCompile(RT_ELEMENTS(pGicCpu->bmActivePriorityGroup0) >= 4);
262 pHlp->pfnPrintf(pHlp, " Active-interrupt priorities Group 0:\n");
263 pHlp->pfnPrintf(pHlp, " [0..3] = %#010x %#010x %#010x %#010x\n",
264 pGicCpu->bmActivePriorityGroup0[0], pGicCpu->bmActivePriorityGroup0[1],
265 pGicCpu->bmActivePriorityGroup0[2], pGicCpu->bmActivePriorityGroup0[3]);
266 AssertCompile(RT_ELEMENTS(pGicCpu->bmActivePriorityGroup1) >= 4);
267 pHlp->pfnPrintf(pHlp, " Active-interrupt priorities Group 1:\n");
268 pHlp->pfnPrintf(pHlp, " [0..3] = %#010x %#010x %#010x %#010x\n",
269 pGicCpu->bmActivePriorityGroup1[0], pGicCpu->bmActivePriorityGroup1[1],
270 pGicCpu->bmActivePriorityGroup1[2], pGicCpu->bmActivePriorityGroup1[3]);
271}
272
273
274/**
275 * Dumps the GIC ITS information.
276 *
277 * @param pVM The cross context VM structure.
278 * @param pHlp The info helpers.
279 * @param pszArgs Arguments, ignored.
280 */
281static DECLCALLBACK(void) gicR3DbgInfoIts(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
282{
283 PGIC pGic = VM_TO_GIC(pVM);
284 PPDMDEVINS pDevIns = pGic->CTX_SUFF(pDevIns);
285 PCGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PCGICDEV);
286 if (pGicDev->hMmioGits != NIL_IOMMMIOHANDLE)
287 {
288 PCGITSDEV pGitsDev = &pGicDev->Gits;
289 gitsR3DbgInfo(pGitsDev, pHlp, pszArgs);
290 }
291 else
292 pHlp->pfnPrintf(pHlp, "GIC ITS is not mapped/configured for the VM\n");
293}
294
295
296/**
297 * @copydoc FNSSMDEVSAVEEXEC
298 */
299static DECLCALLBACK(int) gicR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
300{
301 PCVM pVM = PDMDevHlpGetVM(pDevIns);
302 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
303 PCGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PCGICDEV);
304 AssertPtrReturn(pVM, VERR_INVALID_VM_HANDLE);
305 LogFlowFunc(("\n"));
306
307 /*
308 * Save per-VM data.
309 */
310 pHlp->pfnSSMPutU32(pSSM, pVM->cCpus);
311 pHlp->pfnSSMPutU8(pSSM, pGicDev->uArchRev);
312 pHlp->pfnSSMPutU8(pSSM, pGicDev->uMaxSpi);
313 pHlp->pfnSSMPutBool(pSSM, pGicDev->fExtSpi);
314 pHlp->pfnSSMPutU8(pSSM, pGicDev->uMaxExtSpi);
315 pHlp->pfnSSMPutBool(pSSM, pGicDev->fExtPpi);
316 pHlp->pfnSSMPutU8(pSSM, pGicDev->uMaxExtPpi);
317 pHlp->pfnSSMPutBool(pSSM, pGicDev->fRangeSel);
318 pHlp->pfnSSMPutBool(pSSM, pGicDev->fNmi);
319 pHlp->pfnSSMPutBool(pSSM, pGicDev->fMbi);
320 pHlp->pfnSSMPutBool(pSSM, pGicDev->fAff3Levels);
321
322 /* Distributor state. */
323 pHlp->pfnSSMPutBool(pSSM, pGicDev->fIntrGroup0Enabled);
324 pHlp->pfnSSMPutBool(pSSM, pGicDev->fIntrGroup1Enabled);
325 pHlp->pfnSSMPutBool(pSSM, pGicDev->fAffRoutingEnabled);
326 pHlp->pfnSSMPutMem(pSSM, &pGicDev->bmIntrGroup[0], sizeof(pGicDev->bmIntrGroup));
327 pHlp->pfnSSMPutMem(pSSM, &pGicDev->bmIntrConfig[0], sizeof(pGicDev->bmIntrConfig));
328 pHlp->pfnSSMPutMem(pSSM, &pGicDev->bmIntrEnabled[0], sizeof(pGicDev->bmIntrEnabled));
329 pHlp->pfnSSMPutMem(pSSM, &pGicDev->bmIntrPending[0], sizeof(pGicDev->bmIntrPending));
330 pHlp->pfnSSMPutMem(pSSM, &pGicDev->bmIntrActive[0], sizeof(pGicDev->bmIntrActive));
331 pHlp->pfnSSMPutMem(pSSM, &pGicDev->abIntrPriority[0], sizeof(pGicDev->abIntrPriority));
332 pHlp->pfnSSMPutMem(pSSM, &pGicDev->au32IntrRouting[0], sizeof(pGicDev->au32IntrRouting));
333 pHlp->pfnSSMPutMem(pSSM, &pGicDev->bmIntrRoutingMode[0], sizeof(pGicDev->bmIntrRoutingMode));
334
335 /*
336 * Save per-VCPU data.
337 */
338 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
339 {
340 PCGICCPU pGicCpu = VMCPU_TO_GICCPU(pVM->apCpusR3[idCpu]);
341 Assert(pGicCpu);
342
343 /* Redistributor state. */
344 pHlp->pfnSSMPutMem(pSSM, &pGicCpu->bmIntrGroup[0], sizeof(pGicCpu->bmIntrGroup));
345 pHlp->pfnSSMPutMem(pSSM, &pGicCpu->bmIntrConfig[0], sizeof(pGicCpu->bmIntrConfig));
346 pHlp->pfnSSMPutMem(pSSM, &pGicCpu->bmIntrEnabled[0], sizeof(pGicCpu->bmIntrEnabled));
347 pHlp->pfnSSMPutMem(pSSM, &pGicCpu->bmIntrPending[0], sizeof(pGicCpu->bmIntrPending));
348 pHlp->pfnSSMPutMem(pSSM, &pGicCpu->bmIntrActive[0], sizeof(pGicCpu->bmIntrActive));
349 pHlp->pfnSSMPutMem(pSSM, &pGicCpu->abIntrPriority[0], sizeof(pGicCpu->abIntrPriority));
350
351 /* ICC system register state. */
352 pHlp->pfnSSMPutU64(pSSM, pGicCpu->uIccCtlr);
353 pHlp->pfnSSMPutU8(pSSM, pGicCpu->bIntrPriorityMask);
354 pHlp->pfnSSMPutU8(pSSM, pGicCpu->idxRunningPriority);
355 pHlp->pfnSSMPutMem(pSSM, &pGicCpu->abRunningPriorities[0], sizeof(pGicCpu->abRunningPriorities));
356 pHlp->pfnSSMPutMem(pSSM, &pGicCpu->bmActivePriorityGroup0[0], sizeof(pGicCpu->bmActivePriorityGroup0));
357 pHlp->pfnSSMPutMem(pSSM, &pGicCpu->bmActivePriorityGroup1[0], sizeof(pGicCpu->bmActivePriorityGroup1));
358 pHlp->pfnSSMPutU8(pSSM, pGicCpu->bBinaryPtGroup0);
359 pHlp->pfnSSMPutU8(pSSM, pGicCpu->bBinaryPtGroup1);
360 pHlp->pfnSSMPutBool(pSSM, pGicCpu->fIntrGroup0Enabled);
361 pHlp->pfnSSMPutBool(pSSM, pGicCpu->fIntrGroup1Enabled);
362 }
363
364 return pHlp->pfnSSMPutU32(pSSM, UINT32_MAX);
365}
366
367
368/**
369 * @copydoc FNSSMDEVLOADEXEC
370 */
371static DECLCALLBACK(int) gicR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
372{
373 PVM pVM = PDMDevHlpGetVM(pDevIns);
374 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
375
376 AssertPtrReturn(pVM, VERR_INVALID_VM_HANDLE);
377 AssertReturn(uPass == SSM_PASS_FINAL, VERR_WRONG_ORDER);
378 LogFlowFunc(("uVersion=%u uPass=%#x\n", uVersion, uPass));
379
380 /*
381 * Validate supported saved-state versions.
382 */
383 if (uVersion != GIC_SAVED_STATE_VERSION)
384 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Invalid saved-state version %u"), uVersion);
385
386 /*
387 * Load per-VM data.
388 */
389 uint32_t cCpus;
390 pHlp->pfnSSMGetU32(pSSM, &cCpus);
391 if (cCpus != pVM->cCpus)
392 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: cCpus: got=%u expected=%u"), cCpus, pVM->cCpus);
393
394 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
395 pHlp->pfnSSMGetU8(pSSM, &pGicDev->uArchRev);
396 pHlp->pfnSSMGetU8(pSSM, &pGicDev->uMaxSpi);
397 pHlp->pfnSSMGetBool(pSSM, &pGicDev->fExtSpi);
398 pHlp->pfnSSMGetU8(pSSM, &pGicDev->uMaxExtSpi);
399 pHlp->pfnSSMGetBool(pSSM, &pGicDev->fExtPpi);
400 pHlp->pfnSSMGetU8(pSSM, &pGicDev->uMaxExtPpi);
401 pHlp->pfnSSMGetBool(pSSM, &pGicDev->fRangeSel);
402 pHlp->pfnSSMGetBool(pSSM, &pGicDev->fNmi);
403 pHlp->pfnSSMGetBool(pSSM, &pGicDev->fMbi);
404 pHlp->pfnSSMGetBool(pSSM, &pGicDev->fAff3Levels);
405
406 /* Distributor state. */
407 pHlp->pfnSSMGetBool(pSSM, &pGicDev->fIntrGroup0Enabled);
408 pHlp->pfnSSMGetBool(pSSM, &pGicDev->fIntrGroup1Enabled);
409 pHlp->pfnSSMGetBool(pSSM, &pGicDev->fAffRoutingEnabled);
410 pHlp->pfnSSMGetMem(pSSM, &pGicDev->bmIntrGroup[0], sizeof(pGicDev->bmIntrGroup));
411 pHlp->pfnSSMGetMem(pSSM, &pGicDev->bmIntrConfig[0], sizeof(pGicDev->bmIntrConfig));
412 pHlp->pfnSSMGetMem(pSSM, &pGicDev->bmIntrEnabled[0], sizeof(pGicDev->bmIntrEnabled));
413 pHlp->pfnSSMGetMem(pSSM, &pGicDev->bmIntrPending[0], sizeof(pGicDev->bmIntrPending));
414 pHlp->pfnSSMGetMem(pSSM, &pGicDev->bmIntrActive[0], sizeof(pGicDev->bmIntrActive));
415 pHlp->pfnSSMGetMem(pSSM, &pGicDev->abIntrPriority[0], sizeof(pGicDev->abIntrPriority));
416 pHlp->pfnSSMGetMem(pSSM, &pGicDev->au32IntrRouting[0], sizeof(pGicDev->au32IntrRouting));
417 pHlp->pfnSSMGetMem(pSSM, &pGicDev->bmIntrRoutingMode[0], sizeof(pGicDev->bmIntrRoutingMode));
418
419 /*
420 * Load per-VCPU data.
421 */
422 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
423 {
424 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVM->apCpusR3[idCpu]);
425 Assert(pGicCpu);
426
427 /* Redistributor state. */
428 pHlp->pfnSSMGetMem(pSSM, &pGicCpu->bmIntrGroup[0], sizeof(pGicCpu->bmIntrGroup));
429 pHlp->pfnSSMGetMem(pSSM, &pGicCpu->bmIntrConfig[0], sizeof(pGicCpu->bmIntrConfig));
430 pHlp->pfnSSMGetMem(pSSM, &pGicCpu->bmIntrEnabled[0], sizeof(pGicCpu->bmIntrEnabled));
431 pHlp->pfnSSMGetMem(pSSM, &pGicCpu->bmIntrPending[0], sizeof(pGicCpu->bmIntrPending));
432 pHlp->pfnSSMGetMem(pSSM, &pGicCpu->bmIntrActive[0], sizeof(pGicCpu->bmIntrActive));
433 pHlp->pfnSSMGetMem(pSSM, &pGicCpu->abIntrPriority[0], sizeof(pGicCpu->abIntrPriority));
434
435 /* ICC system register state. */
436 pHlp->pfnSSMGetU64(pSSM, &pGicCpu->uIccCtlr);
437 pHlp->pfnSSMGetU8(pSSM, &pGicCpu->bIntrPriorityMask);
438 pHlp->pfnSSMGetU8(pSSM, &pGicCpu->idxRunningPriority);
439 pHlp->pfnSSMGetMem(pSSM, &pGicCpu->abRunningPriorities[0], sizeof(pGicCpu->abRunningPriorities));
440 pHlp->pfnSSMGetMem(pSSM, &pGicCpu->bmActivePriorityGroup0[0], sizeof(pGicCpu->bmActivePriorityGroup0));
441 pHlp->pfnSSMGetMem(pSSM, &pGicCpu->bmActivePriorityGroup1[0], sizeof(pGicCpu->bmActivePriorityGroup1));
442 pHlp->pfnSSMGetU8(pSSM, &pGicCpu->bBinaryPtGroup0);
443 pHlp->pfnSSMGetU8(pSSM, &pGicCpu->bBinaryPtGroup1);
444 pHlp->pfnSSMGetBool(pSSM, &pGicCpu->fIntrGroup0Enabled);
445 pHlp->pfnSSMGetBool(pSSM, &pGicCpu->fIntrGroup1Enabled);
446 }
447
448 /*
449 * Check that we're still good wrt restored data.
450 */
451 int rc = pHlp->pfnSSMHandleGetStatus(pSSM);
452 AssertRCReturn(rc, rc);
453
454 uint32_t uMarker = 0;
455 rc = pHlp->pfnSSMGetU32(pSSM, &uMarker);
456 AssertRCReturn(rc, rc);
457 if (uMarker == UINT32_MAX)
458 { /* likely */ }
459 else
460 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: Marker: got=%u expected=%u"), uMarker, UINT32_MAX);
461
462 /*
463 * Finally, perform sanity checks.
464 */
465 if (pGicDev->uArchRev <= GIC_DIST_REG_PIDR2_ARCH_REV_GICV4)
466 { /* likely */ }
467 else
468 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Invalid uArchRev, got %u expected range [1,31]"), pGicDev->uArchRev,
469 GIC_DIST_REG_PIDR2_ARCH_REV_GICV1, GIC_DIST_REG_PIDR2_ARCH_REV_GICV4);
470 if (pGicDev->uMaxSpi - 1 < 31)
471 { /* likely */ }
472 else
473 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Invalid MaxSpi, got %u expected range [1,31]"), pGicDev->uMaxSpi);
474 if (pGicDev->uMaxExtSpi <= 31)
475 { /* likely */ }
476 else
477 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Invalid MaxExtSpi, got %u expected range [0,31]"), pGicDev->uMaxExtSpi);
478 if ( pGicDev->uMaxExtPpi == GIC_REDIST_REG_TYPER_PPI_NUM_MAX_1087
479 || pGicDev->uMaxExtPpi == GIC_REDIST_REG_TYPER_PPI_NUM_MAX_1119)
480 { /* likely */ }
481 else
482 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Invalid MaxExtPpi, got %u expected range [1,2]"), pGicDev->uMaxExtPpi);
483 return rc;
484}
485
486
487/**
488 * @interface_method_impl{PDMDEVREG,pfnReset}
489 */
490DECLCALLBACK(void) gicR3Reset(PPDMDEVINS pDevIns)
491{
492 PVM pVM = PDMDevHlpGetVM(pDevIns);
493 VM_ASSERT_EMT0(pVM);
494 VM_ASSERT_IS_NOT_RUNNING(pVM);
495
496 LogFlow(("GIC: gicR3Reset\n"));
497
498 gicReset(pDevIns);
499 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
500 {
501 PVMCPU pVCpuDest = pVM->apCpusR3[idCpu];
502 gicResetCpu(pDevIns, pVCpuDest);
503 }
504}
505
506
507/**
508 * @interface_method_impl{PDMDEVREG,pfnRelocate}
509 */
510DECLCALLBACK(void) gicR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
511{
512 RT_NOREF(pDevIns, offDelta);
513}
514
515
516/**
517 * @interface_method_impl{PDMDEVREG,pfnDestruct}
518 */
519DECLCALLBACK(int) gicR3Destruct(PPDMDEVINS pDevIns)
520{
521 LogFlowFunc(("pDevIns=%p\n", pDevIns));
522 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
523
524 return VINF_SUCCESS;
525}
526
527
528/**
529 * @interface_method_impl{PDMDEVREG,pfnConstruct}
530 */
531DECLCALLBACK(int) gicR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
532{
533 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
534 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
535 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
536 PVM pVM = PDMDevHlpGetVM(pDevIns);
537 PGIC pGic = VM_TO_GIC(pVM);
538 Assert(iInstance == 0); NOREF(iInstance);
539
540 /*
541 * Init the data.
542 */
543 pGic->pDevInsR3 = pDevIns;
544
545 /*
546 * Validate GIC settings.
547 */
548 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "DistributorMmioBase|RedistributorMmioBase|ItsMmioBase"
549 "|ArchRev"
550 "|MaxSpi"
551 "|ExtSpi"
552 "|MaxExtSpi"
553 "|ExtPpi"
554 "|MaxExtPpi"
555 "|RangeSel"
556 "|Nmi"
557 "|Mbi"
558 "|Aff3Levels", "");
559
560#if 0
561 /*
562 * Disable automatic PDM locking for this device.
563 */
564 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
565 AssertRCReturn(rc, rc);
566#endif
567
568 /** @devcfgm{gic, ArchRev, uint8_t, 3}
569 * Configures the GIC architecture revision (GICD_PIDR2.ArchRev and
570 * GICR_PIDR2.ArchRev).
571 *
572 * Currently we only support GICv3. */
573 int rc = pHlp->pfnCFGMQueryU8Def(pCfg, "ArchRev", &pGicDev->uArchRev, 3);
574 AssertLogRelRCReturn(rc, rc);
575 if (pGicDev->uArchRev == 3)
576 { /* likely */ }
577 else
578 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
579 N_("Configuration error: \"ArchRev\" value %u is not supported"), pGicDev->uArchRev);
580
581 /** @devcfgm{gic, MaxSpi, uint8_t, 31}
582 * Configures GICD_TYPER.ItLinesNumber.
583 *
584 * For the IntId range [32,1023], configures the maximum SPI supported. Valid values
585 * are [1,31] which equates to interrupt IDs [63,1023]. A value of 0 implies SPIs
586 * are not supported. We don't allow configuring this value as it's expected that
587 * most guests would assume support for SPIs. */
588 AssertCompile(GIC_DIST_REG_TYPER_NUM_ITLINES == 31);
589 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "MaxSpi", &pGicDev->uMaxSpi, 31 /* Upto and incl. IntId 1023 */);
590 AssertLogRelRCReturn(rc, rc);
591 if (pGicDev->uMaxSpi - 1 < 31)
592 { /* likely */ }
593 else
594 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
595 N_("Configuration error: \"MaxSpi\" must be in the range [1,%u]"),
596 GIC_DIST_REG_TYPER_NUM_ITLINES);
597
598 /** @devcfgm{gic, ExtSpi, bool, false}
599 * Configures whether extended SPIs supported is enabled (GICD_TYPER.ESPI). */
600 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "ExtSpi", &pGicDev->fExtSpi, true);
601 AssertLogRelRCReturn(rc, rc);
602
603 /** @devcfgm{gic, MaxExtSpi, uint8_t, 31}
604 * Configures GICD_TYPER.ESPI_range.
605 *
606 * For the extended SPI range [4096,5119], configures the maximum extended SPI
607 * supported. Valid values are [0,31] which equates to extended SPI IntIds
608 * [4127,5119]. This is ignored (set to 0 in the register) when extended SPIs are
609 * disabled. */
610 AssertCompile(GIC_DIST_REG_TYPER_ESPI_RANGE >> GIC_DIST_REG_TYPER_ESPI_RANGE_BIT == 31);
611 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "MaxExtSpi", &pGicDev->uMaxExtSpi, 31);
612 AssertLogRelRCReturn(rc, rc);
613 if (pGicDev->uMaxExtSpi <= 31)
614 { /* likely */ }
615 else
616 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
617 N_("Configuration error: \"MaxExtSpi\" must be in the range [0,31]"));
618
619 /** @devcfgm{gic, ExtPpi, bool, true}
620 * Configures whether extended PPIs support is enabled. */
621 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "ExtPpi", &pGicDev->fExtPpi, true);
622 AssertLogRelRCReturn(rc, rc);
623
624 /** @devcfgm{gic, MaxExtPpi, uint8_t, 2}
625 * Configures GICR_TYPER.PPInum.
626 *
627 * For the extended PPI range [1056,5119], configures the maximum extended PPI
628 * supported. Valid values are [1,2] which equates to extended PPI IntIds
629 * [1087,1119]. This is unused when extended PPIs are disabled. */
630 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "MaxExtPpi", &pGicDev->uMaxExtPpi, 2);
631 AssertLogRelRCReturn(rc, rc);
632 if ( pGicDev->uMaxExtPpi == GIC_REDIST_REG_TYPER_PPI_NUM_MAX_1087
633 || pGicDev->uMaxExtPpi == GIC_REDIST_REG_TYPER_PPI_NUM_MAX_1119)
634 { /* likely */ }
635 else
636 return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
637 N_("Configuration error: \"MaxExtPpi\" must be in the range [0,2]"));
638
639 /** @devcfgm{gic, RangeSelSupport, bool, true}
640 * Configures whether range-selector support is enabled (GICD_TYPER.RSS and
641 * ICC_CTLR_EL1.RSS). */
642 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "RangeSel", &pGicDev->fRangeSel, true);
643 AssertLogRelRCReturn(rc, rc);
644
645 /** @devcfgm{gic, Nmi, bool, false}
646 * Configures whether non-maskable interrupts (NMIs) are supported
647 * (GICD_TYPER.NMI). */
648 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "Nmi", &pGicDev->fNmi, false);
649 AssertLogRelRCReturn(rc, rc);
650
651 /** @devcfgm{gic, Mbi, bool, true}
652 * Configures whether message-based interrupts (MBIs) are supported
653 * (GICD_TYPER.MBIS). */
654 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "Mbi", &pGicDev->fMbi, true);
655 AssertLogRelRCReturn(rc, rc);
656
657 /** @devcfgm{gic, Aff3Levels, bool, true}
658 * Configures whether non-zero affinity 3 levels (A3V) are supported
659 * (GICD_TYPER.A3V) and (ICC_CTLR.A3V). */
660 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "Aff3Levels", &pGicDev->fAff3Levels, true);
661 AssertLogRelRCReturn(rc, rc);
662
663 /*
664 * Register the GIC with PDM.
665 */
666 rc = PDMDevHlpIcRegister(pDevIns);
667 AssertLogRelRCReturn(rc, rc);
668
669 rc = PDMGicRegisterBackend(pVM, PDMGICBACKENDTYPE_VBOX, &g_GicBackend);
670 AssertLogRelRCReturn(rc, rc);
671
672 /*
673 * Insert the GIC system registers.
674 */
675 for (uint32_t i = 0; i < RT_ELEMENTS(g_aSysRegRanges_GIC); i++)
676 {
677 rc = CPUMR3SysRegRangesInsert(pVM, &g_aSysRegRanges_GIC[i]);
678 AssertLogRelRCReturn(rc, rc);
679 }
680
681 /*
682 * Register the MMIO ranges.
683 */
684 /* Distributor. */
685 {
686 RTGCPHYS GCPhysMmioBase = 0;
687 rc = pHlp->pfnCFGMQueryU64(pCfg, "DistributorMmioBase", &GCPhysMmioBase);
688 if (RT_FAILURE(rc))
689 return PDMDEV_SET_ERROR(pDevIns, rc,
690 N_("Configuration error: Failed to get the \"DistributorMmioBase\" value"));
691
692 rc = PDMDevHlpMmioCreateAndMap(pDevIns, GCPhysMmioBase, GIC_DIST_REG_FRAME_SIZE, gicDistMmioWrite, gicDistMmioRead,
693 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_DWORD_ZEROED, "GIC Distributor",
694 &pGicDev->hMmioDist);
695 AssertRCReturn(rc, rc);
696 }
697
698 /* Redistributor. */
699 {
700 RTGCPHYS GCPhysMmioBase = 0;
701 rc = pHlp->pfnCFGMQueryU64(pCfg, "RedistributorMmioBase", &GCPhysMmioBase);
702 if (RT_FAILURE(rc))
703 return PDMDEV_SET_ERROR(pDevIns, rc,
704 N_("Configuration error: Failed to get the \"RedistributorMmioBase\" value"));
705
706 RTGCPHYS const cbRegion = (RTGCPHYS)pVM->cCpus
707 * (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE); /* Adjacent and per vCPU. */
708 rc = PDMDevHlpMmioCreateAndMap(pDevIns, GCPhysMmioBase, cbRegion, gicReDistMmioWrite, gicReDistMmioRead,
709 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_DWORD_ZEROED, "GIC Redistributor",
710 &pGicDev->hMmioReDist);
711 AssertRCReturn(rc, rc);
712 }
713
714 /* ITS. */
715 {
716 RTGCPHYS GCPhysMmioBase = 0;
717 rc = pHlp->pfnCFGMQueryU64(pCfg, "ItsMmioBase", &GCPhysMmioBase);
718 if (RT_SUCCESS(rc))
719 {
720 RTGCPHYS const cbRegion = 2 * GITS_REG_FRAME_SIZE; /* 2 frames for GICv3. */
721 rc = PDMDevHlpMmioCreateAndMap(pDevIns, GCPhysMmioBase, cbRegion, gicItsMmioWrite, gicItsMmioRead,
722 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_DWORD_ZEROED, "GIC ITS",
723 &pGicDev->hMmioGits);
724 AssertRCReturn(rc, rc);
725 }
726 else
727 pGicDev->hMmioGits = NIL_IOMMMIOHANDLE;
728 }
729
730 /*
731 * Register saved state callbacks.
732 */
733 rc = PDMDevHlpSSMRegister(pDevIns, GIC_SAVED_STATE_VERSION, 0, gicR3SaveExec, gicR3LoadExec);
734 AssertRCReturn(rc, rc);
735
736 /*
737 * Register debugger info callbacks.
738 *
739 * We use separate callbacks rather than arguments so they can also be
740 * dumped in an automated fashion while collecting crash diagnostics and
741 * not just used during live debugging via the VM debugger.
742 */
743 DBGFR3InfoRegisterInternalEx(pVM, "gic", "Dumps GIC basic information.", gicR3DbgInfo, DBGFINFO_FLAGS_ALL_EMTS);
744 DBGFR3InfoRegisterInternalEx(pVM, "gicdist", "Dumps GIC distributor information.", gicR3DbgInfoDist, DBGFINFO_FLAGS_ALL_EMTS);
745 DBGFR3InfoRegisterInternalEx(pVM, "gicredist", "Dumps GIC redistributor information.", gicR3DbgInfoReDist, DBGFINFO_FLAGS_ALL_EMTS);
746 DBGFR3InfoRegisterInternalEx(pVM, "gicits", "Dumps GIC ITS information.", gicR3DbgInfoIts, DBGFINFO_FLAGS_ALL_EMTS);
747
748 /*
749 * Statistics.
750 */
751#ifdef VBOX_WITH_STATISTICS
752# define GIC_REG_COUNTER(a_pvReg, a_pszNameFmt, a_pszDesc) \
753 PDMDevHlpSTAMRegisterF(pDevIns, a_pvReg, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, \
754 a_pszDesc, a_pszNameFmt, idCpu)
755# define GIC_PROF_COUNTER(a_pvReg, a_pszNameFmt, a_pszDesc) \
756 PDMDevHlpSTAMRegisterF(pDevIns, a_pvReg, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, \
757 a_pszDesc, a_pszNameFmt, idCpu)
758
759 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
760 {
761 PVMCPU pVCpu = pVM->apCpusR3[idCpu];
762 PGICCPU pGicCpu = VMCPU_TO_GICCPU(pVCpu);
763
764 GIC_REG_COUNTER(&pGicCpu->StatMmioReadR3, "%u/MmioRead", "Number of MMIO reads in R3.");
765 GIC_REG_COUNTER(&pGicCpu->StatMmioWriteR3, "%u/MmioWrite", "Number of MMIO writes in R3.");
766 GIC_REG_COUNTER(&pGicCpu->StatSysRegReadR3, "%u/SysRegRead", "Number of system register reads in R3.");
767 GIC_REG_COUNTER(&pGicCpu->StatSysRegWriteR3, "%u/SysRegWrite", "Number of system register writes in R3.");
768 GIC_REG_COUNTER(&pGicCpu->StatSetSpiR3, "%u/SetSpi", "Number of set SPI callbacks in R3.");
769 GIC_REG_COUNTER(&pGicCpu->StatSetPpiR3, "%u/SetPpi", "Number of set PPI callbacks in R3.");
770 GIC_REG_COUNTER(&pGicCpu->StatSetSgiR3, "%u/SetSgi", "Number of SGIs generated in R3.");
771
772 GIC_PROF_COUNTER(&pGicCpu->StatProfIntrAckR3, "%u/Prof/IntrAck", "Profiling of interrupt acknowledge (IAR) in R3.");
773 GIC_PROF_COUNTER(&pGicCpu->StatProfSetSpiR3, "%u/Prof/SetSpi", "Profiling of set SPI callback in R3.");
774 GIC_PROF_COUNTER(&pGicCpu->StatProfSetPpiR3, "%u/Prof/SetPpi", "Profiling of set PPI callback in R3.");
775 GIC_PROF_COUNTER(&pGicCpu->StatProfSetSgiR3, "%u/Prof/SetSgi", "Profiling of SGIs generated in R3.");
776 }
777# undef GIC_REG_COUNTER
778# undef GIC_PROF_COUNTER
779#endif
780
781 gicR3Reset(pDevIns);
782
783 /*
784 * Log features/config.
785 */
786 uint8_t const uArchRev = pGicDev->uArchRev;
787 uint8_t const uMaxSpi = pGicDev->uMaxSpi;
788 bool const fExtSpi = pGicDev->fExtSpi;
789 uint8_t const uMaxExtSpi = pGicDev->uMaxExtSpi;
790 bool const fExtPpi = pGicDev->fExtPpi;
791 uint8_t const uMaxExtPpi = pGicDev->uMaxExtPpi;
792 bool const fRangeSel = pGicDev->fRangeSel;
793 bool const fNmi = pGicDev->fNmi;
794 bool const fMbi = pGicDev->fMbi;
795 bool const fAff3Levels = pGicDev->fAff3Levels;
796 uint16_t const uExtPpiLast = uMaxExtPpi == GIC_REDIST_REG_TYPER_PPI_NUM_MAX_1087 ? 1087 : GIC_INTID_RANGE_EXT_PPI_LAST;
797 LogRel(("GIC: ArchRev=%u RangeSel=%RTbool Nmi=%RTbool Mbi=%RTbool Aff3Levels=%RTbool\n",
798 uArchRev, fRangeSel, fNmi, fMbi, fAff3Levels));
799 LogRel(("GIC: SPIs=true (%u:32..%u) ExtSPIs=%RTbool (%u:4095..%u) ExtPPIs=%RTbool (%u:1056..%u)\n",
800 uMaxSpi, 32 * (uMaxSpi + 1),
801 fExtSpi, uMaxExtSpi, GIC_INTID_RANGE_EXT_SPI_START - 1 + 32 * (uMaxExtSpi + 1),
802 fExtPpi, uMaxExtPpi, uExtPpiLast));
803 return VINF_SUCCESS;
804}
805
806#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
807
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