VirtualBox

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

Last change on this file since 108831 was 108831, checked in by vboxsync, 2 weeks ago

VMM/GIC: bugref:10877 The GITS and GIC arch revision should be identical.

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