VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/GICAll.cpp@ 99949

Last change on this file since 99949 was 99935, checked in by vboxsync, 21 months ago

VMM/GIC: Always set DS bit in the CTRL register to indicate we only support one security state, fixes UEFI receiving timer interrupts, bugref:10404

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 44.7 KB
Line 
1/* $Id: GICAll.cpp 99935 2023-05-23 13:03:37Z vboxsync $ */
2/** @file
3 * GIC - Generic Interrupt Controller Architecture (GICv3) - All Contexts.
4 */
5
6/*
7 * Copyright (C) 2023 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 "GICInternal.h"
34#include <VBox/vmm/gic.h>
35#include <VBox/vmm/pdmdev.h>
36#include <VBox/vmm/pdmapi.h>
37#include <VBox/vmm/vmcc.h>
38#include <VBox/vmm/vmm.h>
39#include <VBox/vmm/vmcpuset.h>
40#ifdef IN_RING0
41# include <VBox/vmm/gvmm.h>
42#endif
43
44
45/*********************************************************************************************************************************
46* Internal Functions *
47*********************************************************************************************************************************/
48
49
50/*********************************************************************************************************************************
51* Global Variables *
52*********************************************************************************************************************************/
53
54/**
55 * Sets the interrupt pending force-flag and pokes the EMT if required.
56 *
57 * @param pVCpu The cross context virtual CPU structure.
58 * @param fIrq Flag whether to assert the IRQ line or leave it alone.
59 * @param fFiq Flag whether to assert the FIQ line or leave it alone.
60 */
61static void gicSetInterruptFF(PVMCPUCC pVCpu, bool fIrq, bool fFiq)
62{
63 Assert(fIrq || fFiq);
64
65#ifdef IN_RING3
66 /* IRQ state should be loaded as-is by "LoadExec". Changes can be made from LoadDone. */
67 Assert(pVCpu->pVMR3->enmVMState != VMSTATE_LOADING || PDMR3HasLoadedState(pVCpu->pVMR3));
68#endif
69
70 if (fIrq)
71 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_IRQ);
72 if (fFiq)
73 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_FIQ);
74
75 /*
76 * We need to wake up the target CPU if we're not on EMT.
77 */
78 /** @todo We could just use RTThreadNativeSelf() here, couldn't we? */
79#if defined(IN_RING0)
80 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
81 VMCPUID idCpu = pVCpu->idCpu;
82 if (VMMGetCpuId(pVM) != idCpu)
83 {
84 switch (VMCPU_GET_STATE(pVCpu))
85 {
86 case VMCPUSTATE_STARTED_EXEC:
87 Log7Func(("idCpu=%u VMCPUSTATE_STARTED_EXEC\n", idCpu));
88 GVMMR0SchedPokeNoGVMNoLock(pVM, idCpu);
89 break;
90
91 case VMCPUSTATE_STARTED_HALTED:
92 Log7Func(("idCpu=%u VMCPUSTATE_STARTED_HALTED\n", idCpu));
93 GVMMR0SchedWakeUpNoGVMNoLock(pVM, idCpu);
94 break;
95
96 default:
97 Log7Func(("idCpu=%u enmState=%d\n", idCpu, pVCpu->enmState));
98 break; /* nothing to do in other states. */
99 }
100 }
101#elif defined(IN_RING3)
102 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
103 VMCPUID idCpu = pVCpu->idCpu;
104 if (VMMGetCpuId(pVM) != idCpu)
105 {
106 Log7Func(("idCpu=%u enmState=%d\n", idCpu, pVCpu->enmState));
107 VMR3NotifyCpuFFU(pVCpu->pUVCpu, VMNOTIFYFF_FLAGS_POKE);
108 }
109#endif
110}
111
112
113/**
114 * Clears the interrupt pending force-flag.
115 *
116 * @param pVCpu The cross context virtual CPU structure.
117 * @param fIrq Flag whether to clear the IRQ flag.
118 * @param fFiq Flag whether to clear the FIQ flag.
119 */
120DECLINLINE(void) gicClearInterruptFF(PVMCPUCC pVCpu, bool fIrq, bool fFiq)
121{
122 Assert(fIrq || fFiq);
123
124#ifdef IN_RING3
125 /* IRQ state should be loaded as-is by "LoadExec". Changes can be made from LoadDone. */
126 Assert(pVCpu->pVMR3->enmVMState != VMSTATE_LOADING || PDMR3HasLoadedState(pVCpu->pVMR3));
127#endif
128
129 if (fIrq)
130 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_IRQ);
131 if (fFiq)
132 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_FIQ);
133}
134
135
136DECLINLINE(void) gicUpdateInterruptFF(PVMCPUCC pVCpu, bool fIrq, bool fFiq)
137{
138 if (fIrq || fFiq)
139 gicSetInterruptFF(pVCpu, fIrq, fFiq);
140
141 if (!fIrq || !fFiq)
142 gicClearInterruptFF(pVCpu, !fIrq, !fFiq);
143}
144
145
146DECLINLINE(void) gicReDistHasIrqPending(PGICCPU pThis, bool *pfIrq, bool *pfFiq)
147{
148 /* Read the interrupt state. */
149 uint32_t u32RegIGrp0 = ASMAtomicReadU32(&pThis->u32RegIGrp0);
150 uint32_t bmIntEnabled = ASMAtomicReadU32(&pThis->bmIntEnabled);
151 uint32_t bmIntPending = ASMAtomicReadU32(&pThis->bmIntPending);
152 uint32_t bmIntActive = ASMAtomicReadU32(&pThis->bmIntActive);
153 bool fIrqGrp0Enabled = ASMAtomicReadBool(&pThis->fIrqGrp0Enabled);
154 bool fIrqGrp1Enabled = ASMAtomicReadBool(&pThis->fIrqGrp1Enabled);
155
156 /* Is anything enabled at all? */
157 uint32_t bmIntForward = (bmIntPending & bmIntEnabled) & ~bmIntActive; /* Exclude the currently active interrupt. */
158 if (bmIntForward)
159 {
160 /* Determine whether we have to assert the IRQ or FIQ line. */
161 *pfIrq = RT_BOOL(bmIntForward & u32RegIGrp0) && fIrqGrp1Enabled;
162 *pfFiq = RT_BOOL(bmIntForward & ~u32RegIGrp0) && fIrqGrp0Enabled;
163 }
164 else
165 {
166 *pfIrq = false;
167 *pfFiq = false;
168 }
169}
170
171
172DECLINLINE(void) gicDistHasIrqPendingForVCpu(PGICDEV pThis, bool *pfIrq, bool *pfFiq)
173{
174 /* Read the interrupt state. */
175 uint32_t u32RegIGrp0 = ASMAtomicReadU32(&pThis->u32RegIGrp0);
176 uint32_t bmIntEnabled = ASMAtomicReadU32(&pThis->bmIntEnabled);
177 uint32_t bmIntPending = ASMAtomicReadU32(&pThis->bmIntPending);
178 uint32_t bmIntActive = ASMAtomicReadU32(&pThis->bmIntActive);
179 bool fIrqGrp0Enabled = ASMAtomicReadBool(&pThis->fIrqGrp0Enabled);
180 bool fIrqGrp1Enabled = ASMAtomicReadBool(&pThis->fIrqGrp1Enabled);
181
182 /* Is anything enabled at all? */
183 uint32_t bmIntForward = (bmIntPending & bmIntEnabled) & ~bmIntActive; /* Exclude the currently active interrupt. */
184 if (bmIntForward)
185 {
186 /* Determine whether we have to assert the IRQ or FIQ line. */
187 *pfIrq = RT_BOOL(bmIntForward & u32RegIGrp0) && fIrqGrp1Enabled;
188 *pfFiq = RT_BOOL(bmIntForward & ~u32RegIGrp0) && fIrqGrp0Enabled;
189 }
190 else
191 {
192 *pfIrq = false;
193 *pfFiq = false;
194 }
195}
196
197
198/**
199 * Updates the internal IRQ state and sets or clears the appropirate force action flags.
200 *
201 * @returns Strict VBox status code.
202 * @param pThis The GIC re-distributor state for the associated vCPU.
203 * @param pVCpu The cross context virtual CPU structure.
204 */
205static VBOXSTRICTRC gicReDistUpdateIrqState(PGICCPU pThis, PVMCPUCC pVCpu)
206{
207 bool fIrq, fFiq;
208 gicReDistHasIrqPending(pThis, &fIrq, &fFiq);
209
210 PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
211 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
212 bool fIrqDist, fFiqDist;
213 gicDistHasIrqPendingForVCpu(pGicDev, &fIrqDist, &fFiqDist);
214 fIrq |= fIrqDist;
215 fFiq |= fFiqDist;
216
217 gicUpdateInterruptFF(pVCpu, fIrq, fFiq);
218 return VINF_SUCCESS;
219}
220
221
222/**
223 * Updates the internal IRQ state of the distributor and sets or clears the appropirate force action flags.
224 *
225 * @returns Strict VBox status code.
226 * @param pVM The cross context VM state.
227 * @param pThis The GIC distributor state.
228 */
229static VBOXSTRICTRC gicDistUpdateIrqState(PVMCC pVM, PGICDEV pThis)
230{
231 PVMCPUCC pVCpu = pVM->CTX_SUFF(apCpus)[0]; /** @todo SMP */
232
233 bool fIrq, fFiq;
234 gicReDistHasIrqPending(VMCPU_TO_GICCPU(pVCpu), &fIrq, &fFiq);
235
236 bool fIrqDist, fFiqDist;
237 gicDistHasIrqPendingForVCpu(pThis, &fIrqDist, &fFiqDist);
238 fIrq |= fIrqDist;
239 fFiq |= fFiqDist;
240
241 gicUpdateInterruptFF(pVCpu, fIrq, fFiq);
242 return VINF_SUCCESS;
243}
244
245
246/**
247 * Sets the given SGI/PPI interrupt ID on the re-distributor of the given vCPU.
248 *
249 * @returns VBox status code.
250 * @param pVCpu The cross context virtual CPU structure.
251 * @param uIntId The SGI/PPI interrupt identifier.
252 * @param fAsserted Flag whether the SGI/PPI interrupt is asserted or not.
253 */
254static int gicReDistInterruptSet(PVMCPUCC pVCpu, uint32_t uIntId, bool fAsserted)
255{
256 PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
257
258 /* Update the interrupts pending state. */
259 if (fAsserted)
260 ASMAtomicOrU32(&pThis->bmIntPending, RT_BIT_32(uIntId));
261 else
262 ASMAtomicAndU32(&pThis->bmIntPending, ~RT_BIT_32(uIntId));
263
264 return VBOXSTRICTRC_VAL(gicReDistUpdateIrqState(pThis, pVCpu));
265}
266
267
268/**
269 * Reads a GIC distributor register.
270 *
271 * @returns VBox status code.
272 * @param pDevIns The device instance.
273 * @param pVCpu The cross context virtual CPU structure.
274 * @param offReg The offset of the register being read.
275 * @param puValue Where to store the register value.
276 */
277DECLINLINE(VBOXSTRICTRC) gicDistRegisterRead(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t *puValue)
278{
279 VMCPU_ASSERT_EMT(pVCpu); RT_NOREF(pVCpu);
280 PGICDEV pThis = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
281
282 switch (offReg)
283 {
284 case GIC_DIST_REG_CTLR_OFF:
285 *puValue = (ASMAtomicReadBool(&pThis->fIrqGrp0Enabled) ? GIC_DIST_REG_CTRL_ENABLE_GRP0 : 0)
286 | (ASMAtomicReadBool(&pThis->fIrqGrp1Enabled) ? GIC_DIST_REG_CTRL_ENABLE_GRP1_NS : 0)
287 | GIC_DIST_REG_CTRL_DS;
288 break;
289 case GIC_DIST_REG_TYPER_OFF:
290 *puValue = GIC_DIST_REG_TYPER_NUM_ITLINES_SET(1) /** @todo 32 SPIs for now. */
291 | GIC_DIST_REG_TYPER_NUM_PES_SET(0) /* 1 PE */
292 /*| GIC_DIST_REG_TYPER_ESPI*/ /** @todo */
293 /*| GIC_DIST_REG_TYPER_NMI*/ /** @todo Non-maskable interrupts */
294 /*| GIC_DIST_REG_TYPER_SECURITY_EXTN */ /** @todo */
295 /*| GIC_DIST_REG_TYPER_MBIS */ /** @todo Message based interrupts */
296 /*| GIC_DIST_REG_TYPER_LPIS */ /** @todo Support LPIs */
297 | GIC_DIST_REG_TYPER_IDBITS_SET(16);
298 break;
299 case GIC_DIST_REG_STATUSR_OFF:
300 AssertReleaseFailed();
301 break;
302 case GIC_DIST_REG_IGROUPRn_OFF_START: /* Only 32 lines for now. */
303 AssertReleaseFailed();
304 break;
305 case GIC_DIST_REG_ISENABLERn_OFF_START + 4: /* Only 32 lines for now. */
306 case GIC_DIST_REG_ICENABLERn_OFF_START + 4: /* Only 32 lines for now. */
307 *puValue = ASMAtomicReadU32(&pThis->bmIntEnabled);
308 break;
309 case GIC_DIST_REG_ISPENDRn_OFF_START: /* Only 32 lines for now. */
310 AssertReleaseFailed();
311 break;
312 case GIC_DIST_REG_ICPENDRn_OFF_START: /* Only 32 lines for now. */
313 AssertReleaseFailed();
314 break;
315 case GIC_DIST_REG_ISACTIVERn_OFF_START: /* Only 32 lines for now. */
316 AssertReleaseFailed();
317 break;
318 case GIC_DIST_REG_ICACTIVERn_OFF_START: /* Only 32 lines for now. */
319 AssertReleaseFailed();
320 break;
321 case GIC_DIST_REG_IPRIORITYn_OFF_START + 32: /* Only 32 lines for now. */
322 {
323 /* Figure out the register which is written. */
324 uint8_t idxPrio = offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START - 32;
325 Assert(idxPrio <= RT_ELEMENTS(pThis->abIntPriority) - sizeof(uint32_t));
326
327 uint32_t u32Value = 0;
328 for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
329 u32Value |= pThis->abIntPriority[i] << ((i - idxPrio) * 8);
330
331 *puValue = u32Value;
332 break;
333 }
334 case GIC_DIST_REG_ITARGETSRn_OFF_START: /* Only 32 lines for now. */
335 AssertReleaseFailed();
336 break;
337 case GIC_DIST_REG_ICFGRn_OFF_START: /* Only 32 lines for now. */
338 AssertReleaseFailed();
339 break;
340 case GIC_DIST_REG_IGRPMODRn_OFF_START: /* Only 32 lines for now. */
341 AssertReleaseFailed();
342 break;
343 case GIC_DIST_REG_NSACRn_OFF_START: /* Only 32 lines for now. */
344 AssertReleaseFailed();
345 break;
346 case GIC_DIST_REG_SGIR_OFF:
347 AssertReleaseFailed();
348 break;
349 case GIC_DIST_REG_CPENDSGIRn_OFF_START:
350 AssertReleaseFailed();
351 break;
352 case GIC_DIST_REG_SPENDSGIRn_OFF_START:
353 AssertReleaseFailed();
354 break;
355 case GIC_DIST_REG_INMIn_OFF_START:
356 AssertReleaseFailed();
357 break;
358 case GIC_DIST_REG_IROUTERn_OFF_START: /* Only 32 lines for now. */
359 *puValue = 0; /** @todo */
360 break;
361 case GIC_DIST_REG_PIDR2_OFF:
362 *puValue = GIC_REDIST_REG_PIDR2_ARCH_REV_SET(GIC_REDIST_REG_PIDR2_ARCH_REV_GICV3);
363 break;
364 case GIC_DIST_REG_IIDR_OFF:
365 case GIC_DIST_REG_TYPER2_OFF:
366 *puValue = 0;
367 break;
368 default:
369 *puValue = 0;
370 }
371 return VINF_SUCCESS;
372}
373
374
375/**
376 * Writes a GIC distributor register.
377 *
378 * @returns Strict VBox status code.
379 * @param pDevIns The device instance.
380 * @param pVCpu The cross context virtual CPU structure.
381 * @param offReg The offset of the register being written.
382 * @param uValue The register value.
383 */
384DECLINLINE(VBOXSTRICTRC) gicDistRegisterWrite(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue)
385{
386 VMCPU_ASSERT_EMT(pVCpu); RT_NOREF(pVCpu);
387 PGICDEV pThis = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
388 PVMCC pVM = PDMDevHlpGetVM(pDevIns);
389
390 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
391 switch (offReg)
392 {
393 case GIC_DIST_REG_CTLR_OFF:
394 ASMAtomicWriteBool(&pThis->fIrqGrp0Enabled, RT_BOOL(uValue & GIC_DIST_REG_CTRL_ENABLE_GRP0));
395 ASMAtomicWriteBool(&pThis->fIrqGrp1Enabled, RT_BOOL(uValue & GIC_DIST_REG_CTRL_ENABLE_GRP1_NS));
396 rcStrict = gicDistUpdateIrqState(pVM, pThis);
397 break;
398 case GIC_DIST_REG_STATUSR_OFF:
399 AssertReleaseFailed();
400 break;
401 case GIC_DIST_REG_SETSPI_NSR_OFF:
402 AssertReleaseFailed();
403 break;
404 case GIC_DIST_REG_CLRSPI_NSR_OFF:
405 AssertReleaseFailed();
406 break;
407 case GIC_DIST_REG_SETSPI_SR_OFF:
408 AssertReleaseFailed();
409 break;
410 case GIC_DIST_REG_CLRSPI_SR_OFF:
411 AssertReleaseFailed();
412 break;
413 case GIC_DIST_REG_IGROUPRn_OFF_START: /* Only 32 lines for now. */
414 AssertReleaseFailed();
415 break;
416 case GIC_DIST_REG_IGROUPRn_OFF_START + 4: /* Only 32 lines for now. */
417 ASMAtomicOrU32(&pThis->u32RegIGrp0, uValue);
418 rcStrict = gicDistUpdateIrqState(pVM, pThis);
419 break;
420 case GIC_DIST_REG_ISENABLERn_OFF_START + 4: /* Only 32 lines for now. */
421 ASMAtomicOrU32(&pThis->bmIntEnabled, uValue);
422 rcStrict = gicDistUpdateIrqState(pVM, pThis);
423 break;
424 case GIC_DIST_REG_ICENABLERn_OFF_START:
425 //AssertReleaseFailed();
426 break;
427 case GIC_DIST_REG_ICENABLERn_OFF_START + 4: /* Only 32 lines for now. */
428 ASMAtomicAndU32(&pThis->bmIntEnabled, ~uValue);
429 rcStrict = gicDistUpdateIrqState(pVM, pThis);
430 break;
431 case GIC_DIST_REG_ISPENDRn_OFF_START: /* Only 32 lines for now. */
432 AssertReleaseFailed();
433 break;
434 case GIC_DIST_REG_ICPENDRn_OFF_START: /* Only 32 lines for now. */
435 AssertReleaseFailed();
436 break;
437 case GIC_DIST_REG_ISACTIVERn_OFF_START: /* Only 32 lines for now. */
438 AssertReleaseFailed();
439 break;
440 case GIC_DIST_REG_ICACTIVERn_OFF_START + 4: /* Only 32 lines for now. */
441 ASMAtomicAndU32(&pThis->bmIntActive, ~uValue);
442 rcStrict = gicDistUpdateIrqState(pVM, pThis);
443 break;
444 case GIC_DIST_REG_IPRIORITYn_OFF_START + 32: /* Only 32 lines for now. */
445 case GIC_DIST_REG_IPRIORITYn_OFF_START + 36:
446 case GIC_DIST_REG_IPRIORITYn_OFF_START + 40:
447 case GIC_DIST_REG_IPRIORITYn_OFF_START + 44:
448 case GIC_DIST_REG_IPRIORITYn_OFF_START + 48:
449 case GIC_DIST_REG_IPRIORITYn_OFF_START + 52:
450 case GIC_DIST_REG_IPRIORITYn_OFF_START + 56:
451 case GIC_DIST_REG_IPRIORITYn_OFF_START + 60:
452 {
453 /* Figure out the register whch is written. */
454 uint8_t idxPrio = offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START - 32;
455 Assert(idxPrio <= RT_ELEMENTS(pThis->abIntPriority) - sizeof(uint32_t));
456 for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
457 {
458 pThis->abIntPriority[i] = (uint8_t)(uValue & 0xff);
459 uValue >>= 8;
460 }
461 break;
462 }
463 case GIC_DIST_REG_ITARGETSRn_OFF_START: /* Only 32 lines for now. */
464 AssertReleaseFailed();
465 break;
466 case GIC_DIST_REG_ICFGRn_OFF_START + 8: /* Only 32 lines for now. */
467 ASMAtomicWriteU32(&pThis->u32RegICfg0, uValue);
468 break;
469 case GIC_DIST_REG_ICFGRn_OFF_START+ 12:
470 ASMAtomicWriteU32(&pThis->u32RegICfg1, uValue);
471 break;
472 case GIC_DIST_REG_IGRPMODRn_OFF_START: /* Only 32 lines for now. */
473 AssertReleaseFailed();
474 break;
475 case GIC_DIST_REG_NSACRn_OFF_START: /* Only 32 lines for now. */
476 AssertReleaseFailed();
477 break;
478 case GIC_DIST_REG_SGIR_OFF:
479 AssertReleaseFailed();
480 break;
481 case GIC_DIST_REG_CPENDSGIRn_OFF_START:
482 AssertReleaseFailed();
483 break;
484 case GIC_DIST_REG_SPENDSGIRn_OFF_START:
485 AssertReleaseFailed();
486 break;
487 case GIC_DIST_REG_INMIn_OFF_START:
488 AssertReleaseFailed();
489 break;
490 case GIC_DIST_REG_IROUTERn_OFF_START ... GIC_DIST_REG_IROUTERn_OFF_LAST: /* Only 32 lines for now. */
491 /** @todo Ignored for now, probably make this a MMIO2 region as it begins on 0x6000, see 12.9.22 of the GICv3 architecture
492 * reference manual. */
493 break;
494 default:
495 //AssertReleaseFailed();
496 break;
497 }
498
499 return rcStrict;
500}
501
502
503/**
504 * Reads a GIC redistributor register.
505 *
506 * @returns VBox status code.
507 * @param pDevIns The device instance.
508 * @param pVCpu The cross context virtual CPU structure.
509 * @param offReg The offset of the register being read.
510 * @param puValue Where to store the register value.
511 */
512DECLINLINE(VBOXSTRICTRC) gicReDistRegisterRead(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t *puValue)
513{
514 VMCPU_ASSERT_EMT(pVCpu);
515 RT_NOREF(pDevIns, pVCpu, offReg);
516
517 switch (offReg)
518 {
519 case GIC_REDIST_REG_PIDR2_OFF:
520 *puValue = GIC_REDIST_REG_PIDR2_ARCH_REV_SET(GIC_REDIST_REG_PIDR2_ARCH_REV_GICV3);
521 break;
522 default:
523 *puValue = 0;
524 }
525
526 return VINF_SUCCESS;
527}
528
529
530/**
531 * Reads a GIC redistributor SGI/PPI frame register.
532 *
533 * @returns VBox status code.
534 * @param pDevIns The device instance.
535 * @param pVCpu The cross context virtual CPU structure.
536 * @param offReg The offset of the register being read.
537 * @param puValue Where to store the register value.
538 */
539DECLINLINE(VBOXSTRICTRC) gicReDistSgiPpiRegisterRead(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t *puValue)
540{
541 VMCPU_ASSERT_EMT(pVCpu);
542 RT_NOREF(pDevIns);
543
544 PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
545 switch (offReg)
546 {
547 case GIC_REDIST_SGI_PPI_REG_ISENABLER0_OFF:
548 case GIC_REDIST_SGI_PPI_REG_ICENABLER0_OFF:
549 *puValue = ASMAtomicReadU32(&pThis->bmIntEnabled);
550 break;
551 case GIC_REDIST_SGI_PPI_REG_ISPENDR0_OFF:
552 case GIC_REDIST_SGI_PPI_REG_ICPENDR0_OFF:
553 *puValue = ASMAtomicReadU32(&pThis->bmIntPending);
554 break;
555 case GIC_REDIST_SGI_PPI_REG_ISACTIVER0_OFF:
556 case GIC_REDIST_SGI_PPI_REG_ICACTIVER0_OFF:
557 *puValue = ASMAtomicReadU32(&pThis->bmIntActive);
558 break;
559 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START:
560 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 4:
561 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 8:
562 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 12:
563 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 16:
564 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 20:
565 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 24:
566 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 28:
567 {
568 /* Figure out the register which is written. */
569 uint8_t idxPrio = offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START;
570 Assert(idxPrio <= RT_ELEMENTS(pThis->abIntPriority) - sizeof(uint32_t));
571
572 uint32_t u32Value = 0;
573 for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
574 u32Value |= pThis->abIntPriority[i] << ((i - idxPrio) * 8);
575
576 *puValue = u32Value;
577 break;
578 }
579 case GIC_REDIST_SGI_PPI_REG_ICFGR0_OFF:
580 *puValue = ASMAtomicReadU32(&pThis->u32RegICfg0);
581 break;
582 case GIC_REDIST_SGI_PPI_REG_ICFGR1_OFF:
583 *puValue = ASMAtomicReadU32(&pThis->u32RegICfg1);
584 break;
585 default:
586 AssertReleaseFailed();
587 *puValue = 0;
588 }
589
590 return VINF_SUCCESS;
591}
592
593
594/**
595 * Writes a GIC redistributor frame register.
596 *
597 * @returns Strict VBox status code.
598 * @param pDevIns The device instance.
599 * @param pVCpu The cross context virtual CPU structure.
600 * @param offReg The offset of the register being written.
601 * @param uValue The register value.
602 */
603DECLINLINE(VBOXSTRICTRC) gicReDistRegisterWrite(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue)
604{
605 VMCPU_ASSERT_EMT(pVCpu);
606 RT_NOREF(pDevIns, pVCpu, offReg, uValue);
607
608 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
609 return rcStrict;
610}
611
612
613/**
614 * Writes a GIC redistributor SGI/PPI frame register.
615 *
616 * @returns Strict VBox status code.
617 * @param pDevIns The device instance.
618 * @param pVCpu The cross context virtual CPU structure.
619 * @param offReg The offset of the register being written.
620 * @param uValue The register value.
621 */
622DECLINLINE(VBOXSTRICTRC) gicReDistSgiPpiRegisterWrite(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue)
623{
624 VMCPU_ASSERT_EMT(pVCpu);
625 RT_NOREF(pDevIns);
626
627 PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
628 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
629 switch (offReg)
630 {
631 case GIC_REDIST_SGI_PPI_REG_IGROUPR0_OFF:
632 ASMAtomicOrU32(&pThis->u32RegIGrp0, uValue);
633 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
634 break;
635 case GIC_REDIST_SGI_PPI_REG_ISENABLER0_OFF:
636 ASMAtomicOrU32(&pThis->bmIntEnabled, uValue);
637 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
638 break;
639 case GIC_REDIST_SGI_PPI_REG_ICENABLER0_OFF:
640 ASMAtomicAndU32(&pThis->bmIntEnabled, ~uValue);
641 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
642 break;
643 case GIC_REDIST_SGI_PPI_REG_ISPENDR0_OFF:
644 ASMAtomicOrU32(&pThis->bmIntPending, uValue);
645 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
646 break;
647 case GIC_REDIST_SGI_PPI_REG_ICPENDR0_OFF:
648 ASMAtomicAndU32(&pThis->bmIntPending, ~uValue);
649 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
650 break;
651 case GIC_REDIST_SGI_PPI_REG_ISACTIVER0_OFF:
652 ASMAtomicOrU32(&pThis->bmIntActive, uValue);
653 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
654 break;
655 case GIC_REDIST_SGI_PPI_REG_ICACTIVER0_OFF:
656 ASMAtomicAndU32(&pThis->bmIntActive, ~uValue);
657 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
658 break;
659 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START:
660 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 4:
661 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 8:
662 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 12:
663 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 16:
664 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 20:
665 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 24:
666 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 28:
667 {
668 /* Figure out the register whch is written. */
669 uint8_t idxPrio = offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START;
670 Assert(idxPrio <= RT_ELEMENTS(pThis->abIntPriority) - sizeof(uint32_t));
671 for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
672 {
673 pThis->abIntPriority[i] = (uint8_t)(uValue & 0xff);
674 uValue >>= 8;
675 }
676 break;
677 }
678 case GIC_REDIST_SGI_PPI_REG_ICFGR0_OFF:
679 ASMAtomicWriteU32(&pThis->u32RegICfg0, uValue);
680 break;
681 case GIC_REDIST_SGI_PPI_REG_ICFGR1_OFF:
682 ASMAtomicWriteU32(&pThis->u32RegICfg1, uValue);
683 break;
684 default:
685 AssertReleaseFailed();
686 }
687
688 return rcStrict;
689}
690
691
692/**
693 * Reads a GIC system register.
694 *
695 * @returns Strict VBox status code.
696 * @param pVCpu The cross context virtual CPU structure.
697 * @param u32Reg The system register being read.
698 * @param pu64Value Where to store the read value.
699 */
700VMM_INT_DECL(VBOXSTRICTRC) GICReadSysReg(PVMCPUCC pVCpu, uint32_t u32Reg, uint64_t *pu64Value)
701{
702 /*
703 * Validate.
704 */
705 VMCPU_ASSERT_EMT(pVCpu);
706 Assert(pu64Value);
707
708 *pu64Value = 0;
709 PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
710 PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
711 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
712 switch (u32Reg)
713 {
714 case ARMV8_AARCH64_SYSREG_ICC_PMR_EL1:
715 *pu64Value = pThis->bInterruptPriority;
716 break;
717 case ARMV8_AARCH64_SYSREG_ICC_IAR0_EL1:
718 AssertReleaseFailed();
719 break;
720 case ARMV8_AARCH64_SYSREG_ICC_EOIR0_EL1:
721 AssertReleaseFailed();
722 break;
723 case ARMV8_AARCH64_SYSREG_ICC_HPPIR0_EL1:
724 AssertReleaseFailed();
725 break;
726 case ARMV8_AARCH64_SYSREG_ICC_BPR0_EL1:
727 *pu64Value = pThis->bBinaryPointGrp0 & 0x7;
728 break;
729 case ARMV8_AARCH64_SYSREG_ICC_AP0R0_EL1:
730 AssertReleaseFailed();
731 break;
732 case ARMV8_AARCH64_SYSREG_ICC_AP0R1_EL1:
733 AssertReleaseFailed();
734 break;
735 case ARMV8_AARCH64_SYSREG_ICC_AP0R2_EL1:
736 AssertReleaseFailed();
737 break;
738 case ARMV8_AARCH64_SYSREG_ICC_AP0R3_EL1:
739 AssertReleaseFailed();
740 break;
741 case ARMV8_AARCH64_SYSREG_ICC_AP1R0_EL1:
742 AssertReleaseFailed();
743 break;
744 case ARMV8_AARCH64_SYSREG_ICC_AP1R1_EL1:
745 AssertReleaseFailed();
746 break;
747 case ARMV8_AARCH64_SYSREG_ICC_AP1R2_EL1:
748 AssertReleaseFailed();
749 break;
750 case ARMV8_AARCH64_SYSREG_ICC_AP1R3_EL1:
751 AssertReleaseFailed();
752 break;
753 case ARMV8_AARCH64_SYSREG_ICC_NMIAR1_EL1:
754 AssertReleaseFailed();
755 break;
756 case ARMV8_AARCH64_SYSREG_ICC_DIR_EL1:
757 AssertReleaseFailed();
758 break;
759 case ARMV8_AARCH64_SYSREG_ICC_RPR_EL1:
760 AssertReleaseFailed();
761 break;
762 case ARMV8_AARCH64_SYSREG_ICC_SGI1R_EL1:
763 AssertReleaseFailed();
764 break;
765 case ARMV8_AARCH64_SYSREG_ICC_ASGI1R_EL1:
766 AssertReleaseFailed();
767 break;
768 case ARMV8_AARCH64_SYSREG_ICC_SGI0R_EL1:
769 AssertReleaseFailed();
770 break;
771 case ARMV8_AARCH64_SYSREG_ICC_IAR1_EL1:
772 {
773 /** @todo Figure out the highest priority interrupt. */
774 uint32_t bmPending = ASMAtomicReadU32(&pThis->bmIntPending);
775 int32_t idxIntPending = ASMBitFirstSet(&bmPending, sizeof(bmPending) * 8);
776 if (idxIntPending > -1)
777 {
778 /* Mark the interrupt as active. */
779 ASMAtomicOrU32(&pThis->bmIntActive, idxIntPending);
780 *pu64Value = idxIntPending;
781 }
782 else
783 {
784 /** @todo This is wrong as the guest might decide to prioritize PPIs and SPIs differently. */
785 bmPending = ASMAtomicReadU32(&pGicDev->bmIntPending);
786 idxIntPending = ASMBitFirstSet(&bmPending, sizeof(bmPending) * 8);
787 if (idxIntPending > -1)
788 {
789 /* Mark the interrupt as active. */
790 ASMAtomicOrU32(&pGicDev->bmIntActive, idxIntPending);
791 *pu64Value = idxIntPending + GIC_INTID_RANGE_SPI_START;
792 }
793 else
794 *pu64Value = GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT;
795 }
796 break;
797 }
798 case ARMV8_AARCH64_SYSREG_ICC_EOIR1_EL1:
799 AssertReleaseFailed();
800 break;
801 case ARMV8_AARCH64_SYSREG_ICC_HPPIR1_EL1:
802 AssertReleaseFailed();
803 break;
804 case ARMV8_AARCH64_SYSREG_ICC_BPR1_EL1:
805 *pu64Value = pThis->bBinaryPointGrp1 & 0x7;
806 break;
807 case ARMV8_AARCH64_SYSREG_ICC_CTLR_EL1:
808 *pu64Value = ARMV8_ICC_CTLR_EL1_AARCH64_PMHE
809 | ARMV8_ICC_CTLR_EL1_AARCH64_PRIBITS_SET(4)
810 | ARMV8_ICC_CTLR_EL1_AARCH64_IDBITS_SET(ARMV8_ICC_CTLR_EL1_AARCH64_IDBITS_16BITS);
811 break;
812 case ARMV8_AARCH64_SYSREG_ICC_SRE_EL1:
813 AssertReleaseFailed();
814 break;
815 case ARMV8_AARCH64_SYSREG_ICC_IGRPEN0_EL1:
816 *pu64Value = ASMAtomicReadBool(&pThis->fIrqGrp0Enabled) ? ARMV8_ICC_IGRPEN0_EL1_AARCH64_ENABLE : 0;
817 break;
818 case ARMV8_AARCH64_SYSREG_ICC_IGRPEN1_EL1:
819 *pu64Value = ASMAtomicReadBool(&pThis->fIrqGrp1Enabled) ? ARMV8_ICC_IGRPEN1_EL1_AARCH64_ENABLE : 0;
820 break;
821 default:
822 AssertReleaseFailed();
823 break;
824 }
825
826 LogFlowFunc(("pVCpu=%p u32Reg=%#x pu64Value=%RX64\n", pVCpu, u32Reg, *pu64Value));
827 return VINF_SUCCESS;
828}
829
830
831/**
832 * Writes an GIC system register.
833 *
834 * @returns Strict VBox status code.
835 * @param pVCpu The cross context virtual CPU structure.
836 * @param u32Reg The system register being written (IPRT system register identifier).
837 * @param u64Value The value to write.
838 */
839VMM_INT_DECL(VBOXSTRICTRC) GICWriteSysReg(PVMCPUCC pVCpu, uint32_t u32Reg, uint64_t u64Value)
840{
841 /*
842 * Validate.
843 */
844 VMCPU_ASSERT_EMT(pVCpu);
845 RT_NOREF(pVCpu, u32Reg, u64Value);
846 LogFlowFunc(("pVCpu=%p u32Reg=%#x u64Value=%RX64\n", pVCpu, u32Reg, u64Value));
847
848 PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
849 PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
850 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
851 switch (u32Reg)
852 {
853 case ARMV8_AARCH64_SYSREG_ICC_PMR_EL1:
854 ASMAtomicWriteU8(&pThis->bInterruptPriority, (uint8_t)u64Value);
855 break;
856 case ARMV8_AARCH64_SYSREG_ICC_IAR0_EL1:
857 AssertReleaseFailed();
858 break;
859 case ARMV8_AARCH64_SYSREG_ICC_EOIR0_EL1:
860 AssertReleaseFailed();
861 break;
862 case ARMV8_AARCH64_SYSREG_ICC_HPPIR0_EL1:
863 AssertReleaseFailed();
864 break;
865 case ARMV8_AARCH64_SYSREG_ICC_BPR0_EL1:
866 pThis->bBinaryPointGrp0 = (uint8_t)(u64Value & 0x7);
867 break;
868 case ARMV8_AARCH64_SYSREG_ICC_AP0R0_EL1:
869 /** @todo */
870 break;
871 case ARMV8_AARCH64_SYSREG_ICC_AP0R1_EL1:
872 AssertReleaseFailed();
873 break;
874 case ARMV8_AARCH64_SYSREG_ICC_AP0R2_EL1:
875 AssertReleaseFailed();
876 break;
877 case ARMV8_AARCH64_SYSREG_ICC_AP0R3_EL1:
878 AssertReleaseFailed();
879 break;
880 case ARMV8_AARCH64_SYSREG_ICC_AP1R0_EL1:
881 /** @todo */
882 break;
883 case ARMV8_AARCH64_SYSREG_ICC_AP1R1_EL1:
884 AssertReleaseFailed();
885 break;
886 case ARMV8_AARCH64_SYSREG_ICC_AP1R2_EL1:
887 AssertReleaseFailed();
888 break;
889 case ARMV8_AARCH64_SYSREG_ICC_AP1R3_EL1:
890 AssertReleaseFailed();
891 break;
892 case ARMV8_AARCH64_SYSREG_ICC_NMIAR1_EL1:
893 AssertReleaseFailed();
894 break;
895 case ARMV8_AARCH64_SYSREG_ICC_DIR_EL1:
896 AssertReleaseFailed();
897 break;
898 case ARMV8_AARCH64_SYSREG_ICC_RPR_EL1:
899 AssertReleaseFailed();
900 break;
901 case ARMV8_AARCH64_SYSREG_ICC_SGI1R_EL1:
902 AssertReleaseFailed();
903 break;
904 case ARMV8_AARCH64_SYSREG_ICC_ASGI1R_EL1:
905 AssertReleaseFailed();
906 break;
907 case ARMV8_AARCH64_SYSREG_ICC_SGI0R_EL1:
908 AssertReleaseFailed();
909 break;
910 case ARMV8_AARCH64_SYSREG_ICC_IAR1_EL1:
911 AssertReleaseFailed();
912 break;
913 case ARMV8_AARCH64_SYSREG_ICC_EOIR1_EL1:
914 {
915 /* Mark the interrupt as not active anymore, though it might still be pending. */
916 if (u64Value < GIC_INTID_RANGE_SPI_START)
917 ASMAtomicAndU32(&pThis->bmIntActive, (uint32_t)u64Value);
918 else
919 ASMAtomicAndU32(&pGicDev->bmIntActive, (uint32_t)u64Value);
920 gicReDistUpdateIrqState(pThis, pVCpu);
921 break;
922 }
923 case ARMV8_AARCH64_SYSREG_ICC_HPPIR1_EL1:
924 AssertReleaseFailed();
925 break;
926 case ARMV8_AARCH64_SYSREG_ICC_BPR1_EL1:
927 pThis->bBinaryPointGrp0 = (uint8_t)(u64Value & 0x7);
928 break;
929 case ARMV8_AARCH64_SYSREG_ICC_CTLR_EL1:
930 u64Value &= ARMV8_ICC_CTLR_EL1_RW;
931 /** @todo */
932 break;
933 case ARMV8_AARCH64_SYSREG_ICC_SRE_EL1:
934 AssertReleaseFailed();
935 break;
936 case ARMV8_AARCH64_SYSREG_ICC_IGRPEN0_EL1:
937 ASMAtomicWriteBool(&pThis->fIrqGrp0Enabled, RT_BOOL(u64Value & ARMV8_ICC_IGRPEN0_EL1_AARCH64_ENABLE));
938 break;
939 case ARMV8_AARCH64_SYSREG_ICC_IGRPEN1_EL1:
940 ASMAtomicWriteBool(&pThis->fIrqGrp1Enabled, RT_BOOL(u64Value & ARMV8_ICC_IGRPEN1_EL1_AARCH64_ENABLE));
941 break;
942 default:
943 AssertReleaseFailed();
944 break;
945 }
946
947 return VINF_SUCCESS;
948}
949
950
951/**
952 * Sets the specified shared peripheral interrupt starting.
953 *
954 * @returns VBox status code.
955 * @param pVM The cross context virtual machine structure.
956 * @param uIntId The SPI ID (minus GIC_INTID_RANGE_SPI_START) to assert/de-assert.
957 * @param fAsserted Flag whether to mark the interrupt as asserted/de-asserted.
958 */
959VMM_INT_DECL(int) GICSpiSet(PVMCC pVM, uint32_t uIntId, bool fAsserted)
960{
961 AssertReturn(uIntId < GIC_SPI_MAX, VERR_INVALID_PARAMETER);
962
963 PGIC pGic = VM_TO_GIC(pVM);
964 PGICDEV pThis = PDMDEVINS_2_DATA(pGic->CTX_SUFF(pDevIns), PGICDEV);
965
966 /* Update the interrupts pending state. */
967 if (fAsserted)
968 ASMAtomicOrU32(&pThis->bmIntPending, RT_BIT_32(uIntId));
969 else
970 ASMAtomicAndU32(&pThis->bmIntPending, ~RT_BIT_32(uIntId));
971
972 return VBOXSTRICTRC_VAL(gicDistUpdateIrqState(pVM, pThis));
973}
974
975
976/**
977 * Sets the specified private peripheral interrupt starting.
978 *
979 * @returns VBox status code.
980 * @param pVCpu The cross context virtual CPU structure.
981 * @param uIntId The PPI ID (minus GIC_INTID_RANGE_PPI_START) to assert/de-assert.
982 * @param fAsserted Flag whether to mark the interrupt as asserted/de-asserted.
983 */
984VMM_INT_DECL(int) GICPpiSet(PVMCPUCC pVCpu, uint32_t uIntId, bool fAsserted)
985{
986 LogFlowFunc(("pVCpu=%p{.idCpu=%u} uIntId=%u fAsserted=%RTbool\n",
987 pVCpu, pVCpu->idCpu, uIntId, fAsserted));
988
989 AssertReturn(uIntId >= 0 && uIntId <= (GIC_INTID_RANGE_PPI_LAST - GIC_INTID_RANGE_PPI_START), VERR_INVALID_PARAMETER);
990 return gicReDistInterruptSet(pVCpu, uIntId + GIC_INTID_RANGE_PPI_START, fAsserted);
991}
992
993
994/**
995 * Sets the specified software generated interrupt starting.
996 *
997 * @returns VBox status code.
998 * @param pVCpu The cross context virtual CPU structure.
999 * @param uIntId The PPI ID (minus GIC_INTID_RANGE_SGI_START) to assert/de-assert.
1000 * @param fAsserted Flag whether to mark the interrupt as asserted/de-asserted.
1001 */
1002VMM_INT_DECL(int) GICSgiSet(PVMCPUCC pVCpu, uint32_t uIntId, bool fAsserted)
1003{
1004 AssertReturn(uIntId >= 0 && uIntId <= (GIC_INTID_RANGE_SGI_LAST - GIC_INTID_RANGE_SGI_START), VERR_INVALID_PARAMETER);
1005 return gicReDistInterruptSet(pVCpu, uIntId + GIC_INTID_RANGE_SGI_START, fAsserted);
1006}
1007
1008
1009/**
1010 * Initializes per-VCPU GIC to the state following a power-up or hardware
1011 * reset.
1012 *
1013 * @param pVCpu The cross context virtual CPU structure.
1014 */
1015DECLHIDDEN(void) gicResetCpu(PVMCPUCC pVCpu)
1016{
1017 LogFlowFunc(("GIC%u\n", pVCpu->idCpu));
1018 VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu);
1019}
1020
1021
1022/**
1023 * @callback_method_impl{FNIOMMMIONEWREAD}
1024 */
1025DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) gicDistMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
1026{
1027 NOREF(pvUser);
1028 Assert(!(off & 0x3));
1029 Assert(cb == 4); RT_NOREF_PV(cb);
1030
1031 PVMCPUCC pVCpu = PDMDevHlpGetVMCPU(pDevIns);
1032 uint16_t offReg = off & 0xfffc;
1033 uint32_t uValue = 0;
1034
1035 STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioRead));
1036
1037 VBOXSTRICTRC rc = VBOXSTRICTRC_VAL(gicDistRegisterRead(pDevIns, pVCpu, offReg, &uValue));
1038 *(uint32_t *)pv = uValue;
1039
1040 Log2(("GIC%u: gicDistMmioRead: offReg=%#RX16 uValue=%#RX32\n", pVCpu->idCpu, offReg, uValue));
1041 return rc;
1042}
1043
1044
1045/**
1046 * @callback_method_impl{FNIOMMMIONEWWRITE}
1047 */
1048DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) gicDistMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
1049{
1050 NOREF(pvUser);
1051 Assert(!(off & 0x3));
1052 Assert(cb == 4); RT_NOREF_PV(cb);
1053
1054 PVMCPUCC pVCpu = PDMDevHlpGetVMCPU(pDevIns);
1055 uint16_t offReg = off & 0xfffc;
1056 uint32_t uValue = *(uint32_t *)pv;
1057
1058 STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioWrite));
1059
1060 Log2(("GIC%u: gicDistMmioWrite: offReg=%#RX16 uValue=%#RX32\n", pVCpu->idCpu, offReg, uValue));
1061 return gicDistRegisterWrite(pDevIns, pVCpu, offReg, uValue);
1062}
1063
1064
1065/**
1066 * @callback_method_impl{FNIOMMMIONEWREAD}
1067 */
1068DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) gicReDistMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
1069{
1070 NOREF(pvUser);
1071 Assert(!(off & 0x3));
1072 Assert(cb == 4); RT_NOREF_PV(cb);
1073
1074 PVMCPUCC pVCpu = PDMDevHlpGetVMCPU(pDevIns);
1075
1076 STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioRead));
1077
1078 /*
1079 * Determine the redistributor being targeted. Each redistributor takes GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE bytes
1080 * and the redistributors are adjacent.
1081 */
1082 uint32_t idReDist = off / (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
1083 off %= (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
1084
1085 /* Redistributor or SGI/PPI frame? */
1086 uint16_t offReg = off & 0xfffc;
1087 uint32_t uValue = 0;
1088 VBOXSTRICTRC rcStrict;
1089 if (off < GIC_REDIST_REG_FRAME_SIZE)
1090 rcStrict = gicReDistRegisterRead(pDevIns, pVCpu, offReg, &uValue);
1091 else
1092 rcStrict = gicReDistSgiPpiRegisterRead(pDevIns, pVCpu, offReg, &uValue);
1093
1094 *(uint32_t *)pv = uValue;
1095 Log2(("GICReDist%u: gicReDistMmioRead: off=%RGp idReDist=%u offReg=%#RX16 uValue=%#RX32 -> %Rrc\n",
1096 pVCpu->idCpu, off, idReDist, offReg, uValue, VBOXSTRICTRC_VAL(rcStrict)));
1097 return rcStrict;
1098}
1099
1100
1101/**
1102 * @callback_method_impl{FNIOMMMIONEWWRITE}
1103 */
1104DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) gicReDistMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
1105{
1106 NOREF(pvUser);
1107 Assert(!(off & 0x3));
1108 Assert(cb == 4); RT_NOREF_PV(cb);
1109
1110 PVMCPUCC pVCpu = PDMDevHlpGetVMCPU(pDevIns);
1111 uint32_t uValue = *(uint32_t *)pv;
1112
1113 STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioWrite));
1114
1115 /*
1116 * Determine the redistributor being targeted. Each redistributor takes GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE bytes
1117 * and the redistributors are adjacent.
1118 */
1119 uint32_t idReDist = off / (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
1120 off %= (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
1121
1122 /* Redistributor or SGI/PPI frame? */
1123 uint16_t offReg = off & 0xfffc;
1124 VBOXSTRICTRC rcStrict;
1125 if (off < GIC_REDIST_REG_FRAME_SIZE)
1126 rcStrict = gicReDistRegisterWrite(pDevIns, pVCpu, offReg, uValue);
1127 else
1128 rcStrict = gicReDistSgiPpiRegisterWrite(pDevIns, pVCpu, offReg, uValue);
1129
1130 Log2(("GICReDist%u: gicReDistMmioWrite: off=%RGp idReDist=%u offReg=%#RX16 uValue=%#RX32 -> %Rrc\n",
1131 pVCpu->idCpu, off, idReDist, offReg, uValue, VBOXSTRICTRC_VAL(rcStrict)));
1132 return rcStrict;
1133}
1134
1135
1136#ifndef IN_RING3
1137
1138/**
1139 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
1140 */
1141static DECLCALLBACK(int) gicRZConstruct(PPDMDEVINS pDevIns)
1142{
1143 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1144 AssertReleaseFailed();
1145 return VINF_SUCCESS;
1146}
1147#endif /* !IN_RING3 */
1148
1149/**
1150 * GIC device registration structure.
1151 */
1152const PDMDEVREG g_DeviceGIC =
1153{
1154 /* .u32Version = */ PDM_DEVREG_VERSION,
1155 /* .uReserved0 = */ 0,
1156 /* .szName = */ "gic",
1157 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
1158 /* .fClass = */ PDM_DEVREG_CLASS_PIC,
1159 /* .cMaxInstances = */ 1,
1160 /* .uSharedVersion = */ 42,
1161 /* .cbInstanceShared = */ sizeof(GICDEV),
1162 /* .cbInstanceCC = */ 0,
1163 /* .cbInstanceRC = */ 0,
1164 /* .cMaxPciDevices = */ 0,
1165 /* .cMaxMsixVectors = */ 0,
1166 /* .pszDescription = */ "Generic Interrupt Controller",
1167#if defined(IN_RING3)
1168 /* .szRCMod = */ "VMMRC.rc",
1169 /* .szR0Mod = */ "VMMR0.r0",
1170 /* .pfnConstruct = */ gicR3Construct,
1171 /* .pfnDestruct = */ gicR3Destruct,
1172 /* .pfnRelocate = */ gicR3Relocate,
1173 /* .pfnMemSetup = */ NULL,
1174 /* .pfnPowerOn = */ NULL,
1175 /* .pfnReset = */ gicR3Reset,
1176 /* .pfnSuspend = */ NULL,
1177 /* .pfnResume = */ NULL,
1178 /* .pfnAttach = */ NULL,
1179 /* .pfnDetach = */ NULL,
1180 /* .pfnQueryInterface = */ NULL,
1181 /* .pfnInitComplete = */ NULL,
1182 /* .pfnPowerOff = */ NULL,
1183 /* .pfnSoftReset = */ NULL,
1184 /* .pfnReserved0 = */ NULL,
1185 /* .pfnReserved1 = */ NULL,
1186 /* .pfnReserved2 = */ NULL,
1187 /* .pfnReserved3 = */ NULL,
1188 /* .pfnReserved4 = */ NULL,
1189 /* .pfnReserved5 = */ NULL,
1190 /* .pfnReserved6 = */ NULL,
1191 /* .pfnReserved7 = */ NULL,
1192#elif defined(IN_RING0)
1193 /* .pfnEarlyConstruct = */ NULL,
1194 /* .pfnConstruct = */ gicRZConstruct,
1195 /* .pfnDestruct = */ NULL,
1196 /* .pfnFinalDestruct = */ NULL,
1197 /* .pfnRequest = */ NULL,
1198 /* .pfnReserved0 = */ NULL,
1199 /* .pfnReserved1 = */ NULL,
1200 /* .pfnReserved2 = */ NULL,
1201 /* .pfnReserved3 = */ NULL,
1202 /* .pfnReserved4 = */ NULL,
1203 /* .pfnReserved5 = */ NULL,
1204 /* .pfnReserved6 = */ NULL,
1205 /* .pfnReserved7 = */ NULL,
1206#elif defined(IN_RC)
1207 /* .pfnConstruct = */ gicRZConstruct,
1208 /* .pfnReserved0 = */ NULL,
1209 /* .pfnReserved1 = */ NULL,
1210 /* .pfnReserved2 = */ NULL,
1211 /* .pfnReserved3 = */ NULL,
1212 /* .pfnReserved4 = */ NULL,
1213 /* .pfnReserved5 = */ NULL,
1214 /* .pfnReserved6 = */ NULL,
1215 /* .pfnReserved7 = */ NULL,
1216#else
1217# error "Not in IN_RING3, IN_RING0 or IN_RC!"
1218#endif
1219 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
1220};
1221
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette