VirtualBox

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

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

VMM/GIC: bugref:10404 Profiling counters.

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