VirtualBox

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

Last change on this file since 108484 was 108484, checked in by vboxsync, 8 weeks ago

VMM/GIC: bugref:10404 Validate uArchRev on saved-state load.

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