VirtualBox

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

Last change on this file since 99900 was 99885, checked in by vboxsync, 19 months ago

VMM/GIC: Updates to the emulation implementation, some basic SPI interrupt support, 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 99885 2023-05-22 10:31: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 break;
288 case GIC_DIST_REG_TYPER_OFF:
289 *puValue = GIC_DIST_REG_TYPER_NUM_ITLINES_SET(1) /** @todo 32 SPIs for now. */
290 | GIC_DIST_REG_TYPER_NUM_PES_SET(0) /* 1 PE */
291 /*| GIC_DIST_REG_TYPER_ESPI*/ /** @todo */
292 /*| GIC_DIST_REG_TYPER_NMI*/ /** @todo Non-maskable interrupts */
293 /*| GIC_DIST_REG_TYPER_SECURITY_EXTN */ /** @todo */
294 /*| GIC_DIST_REG_TYPER_MBIS */ /** @todo Message based interrupts */
295 /*| GIC_DIST_REG_TYPER_LPIS */ /** @todo Support LPIs */
296 | GIC_DIST_REG_TYPER_IDBITS_SET(16);
297 break;
298 case GIC_DIST_REG_STATUSR_OFF:
299 AssertReleaseFailed();
300 break;
301 case GIC_DIST_REG_IGROUPRn_OFF_START: /* Only 32 lines for now. */
302 AssertReleaseFailed();
303 break;
304 case GIC_DIST_REG_ISENABLERn_OFF_START + 4: /* Only 32 lines for now. */
305 case GIC_DIST_REG_ICENABLERn_OFF_START + 4: /* Only 32 lines for now. */
306 *puValue = ASMAtomicReadU32(&pThis->bmIntEnabled);
307 break;
308 case GIC_DIST_REG_ISPENDRn_OFF_START: /* Only 32 lines for now. */
309 AssertReleaseFailed();
310 break;
311 case GIC_DIST_REG_ICPENDRn_OFF_START: /* Only 32 lines for now. */
312 AssertReleaseFailed();
313 break;
314 case GIC_DIST_REG_ISACTIVERn_OFF_START: /* Only 32 lines for now. */
315 AssertReleaseFailed();
316 break;
317 case GIC_DIST_REG_ICACTIVERn_OFF_START: /* Only 32 lines for now. */
318 AssertReleaseFailed();
319 break;
320 case GIC_DIST_REG_IPRIORITYn_OFF_START + 32: /* Only 32 lines for now. */
321 {
322 /* Figure out the register which is written. */
323 uint8_t idxPrio = offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START - 32;
324 Assert(idxPrio <= RT_ELEMENTS(pThis->abIntPriority) - sizeof(uint32_t));
325
326 uint32_t u32Value = 0;
327 for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
328 u32Value |= pThis->abIntPriority[i] << ((i - idxPrio) * 8);
329
330 *puValue = u32Value;
331 break;
332 }
333 case GIC_DIST_REG_ITARGETSRn_OFF_START: /* Only 32 lines for now. */
334 AssertReleaseFailed();
335 break;
336 case GIC_DIST_REG_ICFGRn_OFF_START: /* Only 32 lines for now. */
337 AssertReleaseFailed();
338 break;
339 case GIC_DIST_REG_IGRPMODRn_OFF_START: /* Only 32 lines for now. */
340 AssertReleaseFailed();
341 break;
342 case GIC_DIST_REG_NSACRn_OFF_START: /* Only 32 lines for now. */
343 AssertReleaseFailed();
344 break;
345 case GIC_DIST_REG_SGIR_OFF:
346 AssertReleaseFailed();
347 break;
348 case GIC_DIST_REG_CPENDSGIRn_OFF_START:
349 AssertReleaseFailed();
350 break;
351 case GIC_DIST_REG_SPENDSGIRn_OFF_START:
352 AssertReleaseFailed();
353 break;
354 case GIC_DIST_REG_INMIn_OFF_START:
355 AssertReleaseFailed();
356 break;
357 case GIC_DIST_REG_IROUTERn_OFF_START: /* Only 32 lines for now. */
358 *puValue = 0; /** @todo */
359 break;
360 case GIC_DIST_REG_PIDR2_OFF:
361 *puValue = GIC_REDIST_REG_PIDR2_ARCH_REV_SET(GIC_REDIST_REG_PIDR2_ARCH_REV_GICV3);
362 break;
363 case GIC_DIST_REG_IIDR_OFF:
364 case GIC_DIST_REG_TYPER2_OFF:
365 *puValue = 0;
366 break;
367 default:
368 *puValue = 0;
369 }
370 return VINF_SUCCESS;
371}
372
373
374/**
375 * Writes a GIC distributor register.
376 *
377 * @returns Strict VBox status code.
378 * @param pDevIns The device instance.
379 * @param pVCpu The cross context virtual CPU structure.
380 * @param offReg The offset of the register being written.
381 * @param uValue The register value.
382 */
383DECLINLINE(VBOXSTRICTRC) gicDistRegisterWrite(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue)
384{
385 VMCPU_ASSERT_EMT(pVCpu); RT_NOREF(pVCpu);
386 PGICDEV pThis = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
387 PVMCC pVM = PDMDevHlpGetVM(pDevIns);
388
389 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
390 switch (offReg)
391 {
392 case GIC_DIST_REG_CTLR_OFF:
393 ASMAtomicWriteBool(&pThis->fIrqGrp0Enabled, RT_BOOL(uValue & GIC_DIST_REG_CTRL_ENABLE_GRP0));
394 ASMAtomicWriteBool(&pThis->fIrqGrp1Enabled, RT_BOOL(uValue & GIC_DIST_REG_CTRL_ENABLE_GRP1_NS));
395 rcStrict = gicDistUpdateIrqState(pVM, pThis);
396 break;
397 case GIC_DIST_REG_STATUSR_OFF:
398 AssertReleaseFailed();
399 break;
400 case GIC_DIST_REG_SETSPI_NSR_OFF:
401 AssertReleaseFailed();
402 break;
403 case GIC_DIST_REG_CLRSPI_NSR_OFF:
404 AssertReleaseFailed();
405 break;
406 case GIC_DIST_REG_SETSPI_SR_OFF:
407 AssertReleaseFailed();
408 break;
409 case GIC_DIST_REG_CLRSPI_SR_OFF:
410 AssertReleaseFailed();
411 break;
412 case GIC_DIST_REG_IGROUPRn_OFF_START: /* Only 32 lines for now. */
413 AssertReleaseFailed();
414 break;
415 case GIC_DIST_REG_IGROUPRn_OFF_START + 4: /* Only 32 lines for now. */
416 ASMAtomicOrU32(&pThis->u32RegIGrp0, uValue);
417 rcStrict = gicDistUpdateIrqState(pVM, pThis);
418 break;
419 case GIC_DIST_REG_ISENABLERn_OFF_START + 4: /* Only 32 lines for now. */
420 ASMAtomicOrU32(&pThis->bmIntEnabled, uValue);
421 rcStrict = gicDistUpdateIrqState(pVM, pThis);
422 break;
423 case GIC_DIST_REG_ICENABLERn_OFF_START:
424 //AssertReleaseFailed();
425 break;
426 case GIC_DIST_REG_ICENABLERn_OFF_START + 4: /* Only 32 lines for now. */
427 ASMAtomicAndU32(&pThis->bmIntEnabled, ~uValue);
428 rcStrict = gicDistUpdateIrqState(pVM, pThis);
429 break;
430 case GIC_DIST_REG_ISPENDRn_OFF_START: /* Only 32 lines for now. */
431 AssertReleaseFailed();
432 break;
433 case GIC_DIST_REG_ICPENDRn_OFF_START: /* Only 32 lines for now. */
434 AssertReleaseFailed();
435 break;
436 case GIC_DIST_REG_ISACTIVERn_OFF_START: /* Only 32 lines for now. */
437 AssertReleaseFailed();
438 break;
439 case GIC_DIST_REG_ICACTIVERn_OFF_START + 4: /* Only 32 lines for now. */
440 ASMAtomicAndU32(&pThis->bmIntActive, ~uValue);
441 rcStrict = gicDistUpdateIrqState(pVM, pThis);
442 break;
443 case GIC_DIST_REG_IPRIORITYn_OFF_START + 32: /* Only 32 lines for now. */
444 case GIC_DIST_REG_IPRIORITYn_OFF_START + 36:
445 case GIC_DIST_REG_IPRIORITYn_OFF_START + 40:
446 case GIC_DIST_REG_IPRIORITYn_OFF_START + 44:
447 case GIC_DIST_REG_IPRIORITYn_OFF_START + 48:
448 case GIC_DIST_REG_IPRIORITYn_OFF_START + 52:
449 case GIC_DIST_REG_IPRIORITYn_OFF_START + 56:
450 case GIC_DIST_REG_IPRIORITYn_OFF_START + 60:
451 {
452 /* Figure out the register whch is written. */
453 uint8_t idxPrio = offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START - 32;
454 Assert(idxPrio <= RT_ELEMENTS(pThis->abIntPriority) - sizeof(uint32_t));
455 for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
456 {
457 pThis->abIntPriority[i] = (uint8_t)(uValue & 0xff);
458 uValue >>= 8;
459 }
460 break;
461 }
462 case GIC_DIST_REG_ITARGETSRn_OFF_START: /* Only 32 lines for now. */
463 AssertReleaseFailed();
464 break;
465 case GIC_DIST_REG_ICFGRn_OFF_START + 8: /* Only 32 lines for now. */
466 ASMAtomicWriteU32(&pThis->u32RegICfg0, uValue);
467 break;
468 case GIC_DIST_REG_ICFGRn_OFF_START+ 12:
469 ASMAtomicWriteU32(&pThis->u32RegICfg1, uValue);
470 break;
471 case GIC_DIST_REG_IGRPMODRn_OFF_START: /* Only 32 lines for now. */
472 AssertReleaseFailed();
473 break;
474 case GIC_DIST_REG_NSACRn_OFF_START: /* Only 32 lines for now. */
475 AssertReleaseFailed();
476 break;
477 case GIC_DIST_REG_SGIR_OFF:
478 AssertReleaseFailed();
479 break;
480 case GIC_DIST_REG_CPENDSGIRn_OFF_START:
481 AssertReleaseFailed();
482 break;
483 case GIC_DIST_REG_SPENDSGIRn_OFF_START:
484 AssertReleaseFailed();
485 break;
486 case GIC_DIST_REG_INMIn_OFF_START:
487 AssertReleaseFailed();
488 break;
489 case GIC_DIST_REG_IROUTERn_OFF_START ... GIC_DIST_REG_IROUTERn_OFF_LAST: /* Only 32 lines for now. */
490 /** @todo Ignored for now, probably make this a MMIO2 region as it begins on 0x6000, see 12.9.22 of the GICv3 architecture
491 * reference manual. */
492 break;
493 default:
494 //AssertReleaseFailed();
495 break;
496 }
497
498 return rcStrict;
499}
500
501
502/**
503 * Reads a GIC redistributor register.
504 *
505 * @returns VBox status code.
506 * @param pDevIns The device instance.
507 * @param pVCpu The cross context virtual CPU structure.
508 * @param offReg The offset of the register being read.
509 * @param puValue Where to store the register value.
510 */
511DECLINLINE(VBOXSTRICTRC) gicReDistRegisterRead(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t *puValue)
512{
513 VMCPU_ASSERT_EMT(pVCpu);
514 RT_NOREF(pDevIns, pVCpu, offReg);
515
516 switch (offReg)
517 {
518 case GIC_REDIST_REG_PIDR2_OFF:
519 *puValue = GIC_REDIST_REG_PIDR2_ARCH_REV_SET(GIC_REDIST_REG_PIDR2_ARCH_REV_GICV3);
520 break;
521 default:
522 *puValue = 0;
523 }
524
525 return VINF_SUCCESS;
526}
527
528
529/**
530 * Reads a GIC redistributor SGI/PPI frame register.
531 *
532 * @returns VBox status code.
533 * @param pDevIns The device instance.
534 * @param pVCpu The cross context virtual CPU structure.
535 * @param offReg The offset of the register being read.
536 * @param puValue Where to store the register value.
537 */
538DECLINLINE(VBOXSTRICTRC) gicReDistSgiPpiRegisterRead(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t *puValue)
539{
540 VMCPU_ASSERT_EMT(pVCpu);
541 RT_NOREF(pDevIns);
542
543 PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
544 switch (offReg)
545 {
546 case GIC_REDIST_SGI_PPI_REG_ISENABLER0_OFF:
547 case GIC_REDIST_SGI_PPI_REG_ICENABLER0_OFF:
548 *puValue = ASMAtomicReadU32(&pThis->bmIntEnabled);
549 break;
550 case GIC_REDIST_SGI_PPI_REG_ISPENDR0_OFF:
551 case GIC_REDIST_SGI_PPI_REG_ICPENDR0_OFF:
552 *puValue = ASMAtomicReadU32(&pThis->bmIntPending);
553 break;
554 case GIC_REDIST_SGI_PPI_REG_ISACTIVER0_OFF:
555 case GIC_REDIST_SGI_PPI_REG_ICACTIVER0_OFF:
556 *puValue = ASMAtomicReadU32(&pThis->bmIntActive);
557 break;
558 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START:
559 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 4:
560 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 8:
561 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 12:
562 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 16:
563 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 20:
564 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 24:
565 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 28:
566 {
567 /* Figure out the register which is written. */
568 uint8_t idxPrio = offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START;
569 Assert(idxPrio <= RT_ELEMENTS(pThis->abIntPriority) - sizeof(uint32_t));
570
571 uint32_t u32Value = 0;
572 for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
573 u32Value |= pThis->abIntPriority[i] << ((i - idxPrio) * 8);
574
575 *puValue = u32Value;
576 break;
577 }
578 case GIC_REDIST_SGI_PPI_REG_ICFGR0_OFF:
579 *puValue = ASMAtomicReadU32(&pThis->u32RegICfg0);
580 break;
581 case GIC_REDIST_SGI_PPI_REG_ICFGR1_OFF:
582 *puValue = ASMAtomicReadU32(&pThis->u32RegICfg1);
583 break;
584 default:
585 AssertReleaseFailed();
586 *puValue = 0;
587 }
588
589 return VINF_SUCCESS;
590}
591
592
593/**
594 * Writes a GIC redistributor frame register.
595 *
596 * @returns Strict VBox status code.
597 * @param pDevIns The device instance.
598 * @param pVCpu The cross context virtual CPU structure.
599 * @param offReg The offset of the register being written.
600 * @param uValue The register value.
601 */
602DECLINLINE(VBOXSTRICTRC) gicReDistRegisterWrite(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue)
603{
604 VMCPU_ASSERT_EMT(pVCpu);
605 RT_NOREF(pDevIns, pVCpu, offReg, uValue);
606
607 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
608 return rcStrict;
609}
610
611
612/**
613 * Writes a GIC redistributor SGI/PPI frame register.
614 *
615 * @returns Strict VBox status code.
616 * @param pDevIns The device instance.
617 * @param pVCpu The cross context virtual CPU structure.
618 * @param offReg The offset of the register being written.
619 * @param uValue The register value.
620 */
621DECLINLINE(VBOXSTRICTRC) gicReDistSgiPpiRegisterWrite(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue)
622{
623 VMCPU_ASSERT_EMT(pVCpu);
624 RT_NOREF(pDevIns);
625
626 PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
627 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
628 switch (offReg)
629 {
630 case GIC_REDIST_SGI_PPI_REG_IGROUPR0_OFF:
631 ASMAtomicOrU32(&pThis->u32RegIGrp0, uValue);
632 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
633 break;
634 case GIC_REDIST_SGI_PPI_REG_ISENABLER0_OFF:
635 ASMAtomicOrU32(&pThis->bmIntEnabled, uValue);
636 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
637 break;
638 case GIC_REDIST_SGI_PPI_REG_ICENABLER0_OFF:
639 ASMAtomicAndU32(&pThis->bmIntEnabled, ~uValue);
640 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
641 break;
642 case GIC_REDIST_SGI_PPI_REG_ISPENDR0_OFF:
643 ASMAtomicOrU32(&pThis->bmIntPending, uValue);
644 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
645 break;
646 case GIC_REDIST_SGI_PPI_REG_ICPENDR0_OFF:
647 ASMAtomicAndU32(&pThis->bmIntPending, ~uValue);
648 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
649 break;
650 case GIC_REDIST_SGI_PPI_REG_ISACTIVER0_OFF:
651 ASMAtomicOrU32(&pThis->bmIntActive, uValue);
652 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
653 break;
654 case GIC_REDIST_SGI_PPI_REG_ICACTIVER0_OFF:
655 ASMAtomicAndU32(&pThis->bmIntActive, ~uValue);
656 rcStrict = gicReDistUpdateIrqState(pThis, pVCpu);
657 break;
658 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START:
659 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 4:
660 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 8:
661 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 12:
662 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 16:
663 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 20:
664 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 24:
665 case GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START + 28:
666 {
667 /* Figure out the register whch is written. */
668 uint8_t idxPrio = offReg - GIC_REDIST_SGI_PPI_REG_IPRIORITYn_OFF_START;
669 Assert(idxPrio <= RT_ELEMENTS(pThis->abIntPriority) - sizeof(uint32_t));
670 for (uint32_t i = idxPrio; i < idxPrio + sizeof(uint32_t); i++)
671 {
672 pThis->abIntPriority[i] = (uint8_t)(uValue & 0xff);
673 uValue >>= 8;
674 }
675 break;
676 }
677 case GIC_REDIST_SGI_PPI_REG_ICFGR0_OFF:
678 ASMAtomicWriteU32(&pThis->u32RegICfg0, uValue);
679 break;
680 case GIC_REDIST_SGI_PPI_REG_ICFGR1_OFF:
681 ASMAtomicWriteU32(&pThis->u32RegICfg1, uValue);
682 break;
683 default:
684 AssertReleaseFailed();
685 }
686
687 return rcStrict;
688}
689
690
691/**
692 * Reads a GIC system register.
693 *
694 * @returns Strict VBox status code.
695 * @param pVCpu The cross context virtual CPU structure.
696 * @param u32Reg The system register being read.
697 * @param pu64Value Where to store the read value.
698 */
699VMM_INT_DECL(VBOXSTRICTRC) GICReadSysReg(PVMCPUCC pVCpu, uint32_t u32Reg, uint64_t *pu64Value)
700{
701 /*
702 * Validate.
703 */
704 VMCPU_ASSERT_EMT(pVCpu);
705 Assert(pu64Value);
706
707 *pu64Value = 0;
708 PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
709 PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
710 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
711 switch (u32Reg)
712 {
713 case ARMV8_AARCH64_SYSREG_ICC_PMR_EL1:
714 *pu64Value = pThis->bInterruptPriority;
715 break;
716 case ARMV8_AARCH64_SYSREG_ICC_IAR0_EL1:
717 AssertReleaseFailed();
718 break;
719 case ARMV8_AARCH64_SYSREG_ICC_EOIR0_EL1:
720 AssertReleaseFailed();
721 break;
722 case ARMV8_AARCH64_SYSREG_ICC_HPPIR0_EL1:
723 AssertReleaseFailed();
724 break;
725 case ARMV8_AARCH64_SYSREG_ICC_BPR0_EL1:
726 *pu64Value = pThis->bBinaryPointGrp0 & 0x7;
727 break;
728 case ARMV8_AARCH64_SYSREG_ICC_AP0R0_EL1:
729 AssertReleaseFailed();
730 break;
731 case ARMV8_AARCH64_SYSREG_ICC_AP0R1_EL1:
732 AssertReleaseFailed();
733 break;
734 case ARMV8_AARCH64_SYSREG_ICC_AP0R2_EL1:
735 AssertReleaseFailed();
736 break;
737 case ARMV8_AARCH64_SYSREG_ICC_AP0R3_EL1:
738 AssertReleaseFailed();
739 break;
740 case ARMV8_AARCH64_SYSREG_ICC_AP1R0_EL1:
741 AssertReleaseFailed();
742 break;
743 case ARMV8_AARCH64_SYSREG_ICC_AP1R1_EL1:
744 AssertReleaseFailed();
745 break;
746 case ARMV8_AARCH64_SYSREG_ICC_AP1R2_EL1:
747 AssertReleaseFailed();
748 break;
749 case ARMV8_AARCH64_SYSREG_ICC_AP1R3_EL1:
750 AssertReleaseFailed();
751 break;
752 case ARMV8_AARCH64_SYSREG_ICC_NMIAR1_EL1:
753 AssertReleaseFailed();
754 break;
755 case ARMV8_AARCH64_SYSREG_ICC_DIR_EL1:
756 AssertReleaseFailed();
757 break;
758 case ARMV8_AARCH64_SYSREG_ICC_RPR_EL1:
759 AssertReleaseFailed();
760 break;
761 case ARMV8_AARCH64_SYSREG_ICC_SGI1R_EL1:
762 AssertReleaseFailed();
763 break;
764 case ARMV8_AARCH64_SYSREG_ICC_ASGI1R_EL1:
765 AssertReleaseFailed();
766 break;
767 case ARMV8_AARCH64_SYSREG_ICC_SGI0R_EL1:
768 AssertReleaseFailed();
769 break;
770 case ARMV8_AARCH64_SYSREG_ICC_IAR1_EL1:
771 {
772 /** @todo Figure out the highest priority interrupt. */
773 uint32_t bmPending = ASMAtomicReadU32(&pThis->bmIntPending);
774 int32_t idxIntPending = ASMBitFirstSet(&bmPending, sizeof(bmPending) * 8);
775 if (idxIntPending > -1)
776 {
777 /* Mark the interrupt as active. */
778 ASMAtomicOrU32(&pThis->bmIntActive, idxIntPending);
779 *pu64Value = idxIntPending;
780 }
781 else
782 {
783 /** @todo This is wrong as the guest might decide to prioritize PPIs and SPIs differently. */
784 bmPending = ASMAtomicReadU32(&pGicDev->bmIntPending);
785 idxIntPending = ASMBitFirstSet(&bmPending, sizeof(bmPending) * 8);
786 if (idxIntPending > -1)
787 {
788 /* Mark the interrupt as active. */
789 ASMAtomicOrU32(&pGicDev->bmIntActive, idxIntPending);
790 *pu64Value = idxIntPending + GIC_INTID_RANGE_SPI_START;
791 }
792 else
793 *pu64Value = GIC_INTID_RANGE_SPECIAL_NO_INTERRUPT;
794 }
795 break;
796 }
797 case ARMV8_AARCH64_SYSREG_ICC_EOIR1_EL1:
798 AssertReleaseFailed();
799 break;
800 case ARMV8_AARCH64_SYSREG_ICC_HPPIR1_EL1:
801 AssertReleaseFailed();
802 break;
803 case ARMV8_AARCH64_SYSREG_ICC_BPR1_EL1:
804 *pu64Value = pThis->bBinaryPointGrp1 & 0x7;
805 break;
806 case ARMV8_AARCH64_SYSREG_ICC_CTLR_EL1:
807 *pu64Value = ARMV8_ICC_CTLR_EL1_AARCH64_PMHE
808 | ARMV8_ICC_CTLR_EL1_AARCH64_PRIBITS_SET(4)
809 | ARMV8_ICC_CTLR_EL1_AARCH64_IDBITS_SET(ARMV8_ICC_CTLR_EL1_AARCH64_IDBITS_16BITS);
810 break;
811 case ARMV8_AARCH64_SYSREG_ICC_SRE_EL1:
812 AssertReleaseFailed();
813 break;
814 case ARMV8_AARCH64_SYSREG_ICC_IGRPEN0_EL1:
815 *pu64Value = ASMAtomicReadBool(&pThis->fIrqGrp0Enabled) ? ARMV8_ICC_IGRPEN0_EL1_AARCH64_ENABLE : 0;
816 break;
817 case ARMV8_AARCH64_SYSREG_ICC_IGRPEN1_EL1:
818 *pu64Value = ASMAtomicReadBool(&pThis->fIrqGrp1Enabled) ? ARMV8_ICC_IGRPEN1_EL1_AARCH64_ENABLE : 0;
819 break;
820 default:
821 AssertReleaseFailed();
822 break;
823 }
824
825 LogFlowFunc(("pVCpu=%p u32Reg=%#x pu64Value=%RX64\n", pVCpu, u32Reg, *pu64Value));
826 return VINF_SUCCESS;
827}
828
829
830/**
831 * Writes an GIC system register.
832 *
833 * @returns Strict VBox status code.
834 * @param pVCpu The cross context virtual CPU structure.
835 * @param u32Reg The system register being written (IPRT system register identifier).
836 * @param u64Value The value to write.
837 */
838VMM_INT_DECL(VBOXSTRICTRC) GICWriteSysReg(PVMCPUCC pVCpu, uint32_t u32Reg, uint64_t u64Value)
839{
840 /*
841 * Validate.
842 */
843 VMCPU_ASSERT_EMT(pVCpu);
844 RT_NOREF(pVCpu, u32Reg, u64Value);
845 LogFlowFunc(("pVCpu=%p u32Reg=%#x u64Value=%RX64\n", pVCpu, u32Reg, u64Value));
846
847 PGICCPU pThis = VMCPU_TO_GICCPU(pVCpu);
848 PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
849 PGICDEV pGicDev = PDMDEVINS_2_DATA(pDevIns, PGICDEV);
850 switch (u32Reg)
851 {
852 case ARMV8_AARCH64_SYSREG_ICC_PMR_EL1:
853 ASMAtomicWriteU8(&pThis->bInterruptPriority, (uint8_t)u64Value);
854 break;
855 case ARMV8_AARCH64_SYSREG_ICC_IAR0_EL1:
856 AssertReleaseFailed();
857 break;
858 case ARMV8_AARCH64_SYSREG_ICC_EOIR0_EL1:
859 AssertReleaseFailed();
860 break;
861 case ARMV8_AARCH64_SYSREG_ICC_HPPIR0_EL1:
862 AssertReleaseFailed();
863 break;
864 case ARMV8_AARCH64_SYSREG_ICC_BPR0_EL1:
865 pThis->bBinaryPointGrp0 = (uint8_t)(u64Value & 0x7);
866 break;
867 case ARMV8_AARCH64_SYSREG_ICC_AP0R0_EL1:
868 /** @todo */
869 break;
870 case ARMV8_AARCH64_SYSREG_ICC_AP0R1_EL1:
871 AssertReleaseFailed();
872 break;
873 case ARMV8_AARCH64_SYSREG_ICC_AP0R2_EL1:
874 AssertReleaseFailed();
875 break;
876 case ARMV8_AARCH64_SYSREG_ICC_AP0R3_EL1:
877 AssertReleaseFailed();
878 break;
879 case ARMV8_AARCH64_SYSREG_ICC_AP1R0_EL1:
880 /** @todo */
881 break;
882 case ARMV8_AARCH64_SYSREG_ICC_AP1R1_EL1:
883 AssertReleaseFailed();
884 break;
885 case ARMV8_AARCH64_SYSREG_ICC_AP1R2_EL1:
886 AssertReleaseFailed();
887 break;
888 case ARMV8_AARCH64_SYSREG_ICC_AP1R3_EL1:
889 AssertReleaseFailed();
890 break;
891 case ARMV8_AARCH64_SYSREG_ICC_NMIAR1_EL1:
892 AssertReleaseFailed();
893 break;
894 case ARMV8_AARCH64_SYSREG_ICC_DIR_EL1:
895 AssertReleaseFailed();
896 break;
897 case ARMV8_AARCH64_SYSREG_ICC_RPR_EL1:
898 AssertReleaseFailed();
899 break;
900 case ARMV8_AARCH64_SYSREG_ICC_SGI1R_EL1:
901 AssertReleaseFailed();
902 break;
903 case ARMV8_AARCH64_SYSREG_ICC_ASGI1R_EL1:
904 AssertReleaseFailed();
905 break;
906 case ARMV8_AARCH64_SYSREG_ICC_SGI0R_EL1:
907 AssertReleaseFailed();
908 break;
909 case ARMV8_AARCH64_SYSREG_ICC_IAR1_EL1:
910 AssertReleaseFailed();
911 break;
912 case ARMV8_AARCH64_SYSREG_ICC_EOIR1_EL1:
913 {
914 /* Mark the interrupt as not active anymore, though it might still be pending. */
915 if (u64Value < GIC_INTID_RANGE_SPI_START)
916 ASMAtomicAndU32(&pThis->bmIntActive, (uint32_t)u64Value);
917 else
918 ASMAtomicAndU32(&pGicDev->bmIntActive, (uint32_t)u64Value);
919 gicReDistUpdateIrqState(pThis, pVCpu);
920 break;
921 }
922 case ARMV8_AARCH64_SYSREG_ICC_HPPIR1_EL1:
923 AssertReleaseFailed();
924 break;
925 case ARMV8_AARCH64_SYSREG_ICC_BPR1_EL1:
926 pThis->bBinaryPointGrp0 = (uint8_t)(u64Value & 0x7);
927 break;
928 case ARMV8_AARCH64_SYSREG_ICC_CTLR_EL1:
929 u64Value &= ARMV8_ICC_CTLR_EL1_RW;
930 /** @todo */
931 break;
932 case ARMV8_AARCH64_SYSREG_ICC_SRE_EL1:
933 AssertReleaseFailed();
934 break;
935 case ARMV8_AARCH64_SYSREG_ICC_IGRPEN0_EL1:
936 ASMAtomicWriteBool(&pThis->fIrqGrp0Enabled, RT_BOOL(u64Value & ARMV8_ICC_IGRPEN0_EL1_AARCH64_ENABLE));
937 break;
938 case ARMV8_AARCH64_SYSREG_ICC_IGRPEN1_EL1:
939 ASMAtomicWriteBool(&pThis->fIrqGrp1Enabled, RT_BOOL(u64Value & ARMV8_ICC_IGRPEN1_EL1_AARCH64_ENABLE));
940 break;
941 default:
942 AssertReleaseFailed();
943 break;
944 }
945
946 return VINF_SUCCESS;
947}
948
949
950/**
951 * Sets the specified shared peripheral interrupt starting.
952 *
953 * @returns VBox status code.
954 * @param pVM The cross context virtual machine structure.
955 * @param uIntId The SPI ID (minus GIC_INTID_RANGE_SPI_START) to assert/de-assert.
956 * @param fAsserted Flag whether to mark the interrupt as asserted/de-asserted.
957 */
958VMM_INT_DECL(int) GICSpiSet(PVMCC pVM, uint32_t uIntId, bool fAsserted)
959{
960 AssertReturn(uIntId < GIC_SPI_MAX, VERR_INVALID_PARAMETER);
961
962 PGIC pGic = VM_TO_GIC(pVM);
963 PGICDEV pThis = PDMDEVINS_2_DATA(pGic->CTX_SUFF(pDevIns), PGICDEV);
964
965 /* Update the interrupts pending state. */
966 if (fAsserted)
967 ASMAtomicOrU32(&pThis->bmIntPending, RT_BIT_32(uIntId));
968 else
969 ASMAtomicAndU32(&pThis->bmIntPending, ~RT_BIT_32(uIntId));
970
971 return VBOXSTRICTRC_VAL(gicDistUpdateIrqState(pVM, pThis));
972}
973
974
975/**
976 * Sets the specified private peripheral interrupt starting.
977 *
978 * @returns VBox status code.
979 * @param pVCpu The cross context virtual CPU structure.
980 * @param uIntId The PPI ID (minus GIC_INTID_RANGE_PPI_START) to assert/de-assert.
981 * @param fAsserted Flag whether to mark the interrupt as asserted/de-asserted.
982 */
983VMM_INT_DECL(int) GICPpiSet(PVMCPUCC pVCpu, uint32_t uIntId, bool fAsserted)
984{
985 LogFlowFunc(("pVCpu=%p{.idCpu=%u} uIntId=%u fAsserted=%RTbool\n",
986 pVCpu, pVCpu->idCpu, uIntId, fAsserted));
987
988 AssertReturn(uIntId >= 0 && uIntId <= (GIC_INTID_RANGE_PPI_LAST - GIC_INTID_RANGE_PPI_START), VERR_INVALID_PARAMETER);
989 return gicReDistInterruptSet(pVCpu, uIntId + GIC_INTID_RANGE_PPI_START, fAsserted);
990}
991
992
993/**
994 * Sets the specified software generated interrupt starting.
995 *
996 * @returns VBox status code.
997 * @param pVCpu The cross context virtual CPU structure.
998 * @param uIntId The PPI ID (minus GIC_INTID_RANGE_SGI_START) to assert/de-assert.
999 * @param fAsserted Flag whether to mark the interrupt as asserted/de-asserted.
1000 */
1001VMM_INT_DECL(int) GICSgiSet(PVMCPUCC pVCpu, uint32_t uIntId, bool fAsserted)
1002{
1003 AssertReturn(uIntId >= 0 && uIntId <= (GIC_INTID_RANGE_SGI_LAST - GIC_INTID_RANGE_SGI_START), VERR_INVALID_PARAMETER);
1004 return gicReDistInterruptSet(pVCpu, uIntId + GIC_INTID_RANGE_SGI_START, fAsserted);
1005}
1006
1007
1008/**
1009 * Initializes per-VCPU GIC to the state following a power-up or hardware
1010 * reset.
1011 *
1012 * @param pVCpu The cross context virtual CPU structure.
1013 */
1014DECLHIDDEN(void) gicResetCpu(PVMCPUCC pVCpu)
1015{
1016 LogFlowFunc(("GIC%u\n", pVCpu->idCpu));
1017 VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu);
1018}
1019
1020
1021/**
1022 * @callback_method_impl{FNIOMMMIONEWREAD}
1023 */
1024DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) gicDistMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
1025{
1026 NOREF(pvUser);
1027 Assert(!(off & 0x3));
1028 Assert(cb == 4); RT_NOREF_PV(cb);
1029
1030 PVMCPUCC pVCpu = PDMDevHlpGetVMCPU(pDevIns);
1031 uint16_t offReg = off & 0xfffc;
1032 uint32_t uValue = 0;
1033
1034 STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioRead));
1035
1036 VBOXSTRICTRC rc = VBOXSTRICTRC_VAL(gicDistRegisterRead(pDevIns, pVCpu, offReg, &uValue));
1037 *(uint32_t *)pv = uValue;
1038
1039 Log2(("GIC%u: gicDistMmioRead: offReg=%#RX16 uValue=%#RX32\n", pVCpu->idCpu, offReg, uValue));
1040 return rc;
1041}
1042
1043
1044/**
1045 * @callback_method_impl{FNIOMMMIONEWWRITE}
1046 */
1047DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) gicDistMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
1048{
1049 NOREF(pvUser);
1050 Assert(!(off & 0x3));
1051 Assert(cb == 4); RT_NOREF_PV(cb);
1052
1053 PVMCPUCC pVCpu = PDMDevHlpGetVMCPU(pDevIns);
1054 uint16_t offReg = off & 0xfffc;
1055 uint32_t uValue = *(uint32_t *)pv;
1056
1057 STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioWrite));
1058
1059 Log2(("GIC%u: gicDistMmioWrite: offReg=%#RX16 uValue=%#RX32\n", pVCpu->idCpu, offReg, uValue));
1060 return gicDistRegisterWrite(pDevIns, pVCpu, offReg, uValue);
1061}
1062
1063
1064/**
1065 * @callback_method_impl{FNIOMMMIONEWREAD}
1066 */
1067DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) gicReDistMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
1068{
1069 NOREF(pvUser);
1070 Assert(!(off & 0x3));
1071 Assert(cb == 4); RT_NOREF_PV(cb);
1072
1073 PVMCPUCC pVCpu = PDMDevHlpGetVMCPU(pDevIns);
1074
1075 STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioRead));
1076
1077 /*
1078 * Determine the redistributor being targeted. Each redistributor takes GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE bytes
1079 * and the redistributors are adjacent.
1080 */
1081 uint32_t idReDist = off / (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
1082 off %= (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
1083
1084 /* Redistributor or SGI/PPI frame? */
1085 uint16_t offReg = off & 0xfffc;
1086 uint32_t uValue = 0;
1087 VBOXSTRICTRC rcStrict;
1088 if (off < GIC_REDIST_REG_FRAME_SIZE)
1089 rcStrict = gicReDistRegisterRead(pDevIns, pVCpu, offReg, &uValue);
1090 else
1091 rcStrict = gicReDistSgiPpiRegisterRead(pDevIns, pVCpu, offReg, &uValue);
1092
1093 *(uint32_t *)pv = uValue;
1094 Log2(("GICReDist%u: gicReDistMmioRead: off=%RGp idReDist=%u offReg=%#RX16 uValue=%#RX32 -> %Rrc\n",
1095 pVCpu->idCpu, off, idReDist, offReg, uValue, VBOXSTRICTRC_VAL(rcStrict)));
1096 return rcStrict;
1097}
1098
1099
1100/**
1101 * @callback_method_impl{FNIOMMMIONEWWRITE}
1102 */
1103DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) gicReDistMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
1104{
1105 NOREF(pvUser);
1106 Assert(!(off & 0x3));
1107 Assert(cb == 4); RT_NOREF_PV(cb);
1108
1109 PVMCPUCC pVCpu = PDMDevHlpGetVMCPU(pDevIns);
1110 uint32_t uValue = *(uint32_t *)pv;
1111
1112 STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioWrite));
1113
1114 /*
1115 * Determine the redistributor being targeted. Each redistributor takes GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE bytes
1116 * and the redistributors are adjacent.
1117 */
1118 uint32_t idReDist = off / (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
1119 off %= (GIC_REDIST_REG_FRAME_SIZE + GIC_REDIST_SGI_PPI_REG_FRAME_SIZE);
1120
1121 /* Redistributor or SGI/PPI frame? */
1122 uint16_t offReg = off & 0xfffc;
1123 VBOXSTRICTRC rcStrict;
1124 if (off < GIC_REDIST_REG_FRAME_SIZE)
1125 rcStrict = gicReDistRegisterWrite(pDevIns, pVCpu, offReg, uValue);
1126 else
1127 rcStrict = gicReDistSgiPpiRegisterWrite(pDevIns, pVCpu, offReg, uValue);
1128
1129 Log2(("GICReDist%u: gicReDistMmioWrite: off=%RGp idReDist=%u offReg=%#RX16 uValue=%#RX32 -> %Rrc\n",
1130 pVCpu->idCpu, off, idReDist, offReg, uValue, VBOXSTRICTRC_VAL(rcStrict)));
1131 return rcStrict;
1132}
1133
1134
1135#ifndef IN_RING3
1136
1137/**
1138 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
1139 */
1140static DECLCALLBACK(int) gicRZConstruct(PPDMDEVINS pDevIns)
1141{
1142 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1143 AssertReleaseFailed();
1144 return VINF_SUCCESS;
1145}
1146#endif /* !IN_RING3 */
1147
1148/**
1149 * GIC device registration structure.
1150 */
1151const PDMDEVREG g_DeviceGIC =
1152{
1153 /* .u32Version = */ PDM_DEVREG_VERSION,
1154 /* .uReserved0 = */ 0,
1155 /* .szName = */ "gic",
1156 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
1157 /* .fClass = */ PDM_DEVREG_CLASS_PIC,
1158 /* .cMaxInstances = */ 1,
1159 /* .uSharedVersion = */ 42,
1160 /* .cbInstanceShared = */ sizeof(GICDEV),
1161 /* .cbInstanceCC = */ 0,
1162 /* .cbInstanceRC = */ 0,
1163 /* .cMaxPciDevices = */ 0,
1164 /* .cMaxMsixVectors = */ 0,
1165 /* .pszDescription = */ "Generic Interrupt Controller",
1166#if defined(IN_RING3)
1167 /* .szRCMod = */ "VMMRC.rc",
1168 /* .szR0Mod = */ "VMMR0.r0",
1169 /* .pfnConstruct = */ gicR3Construct,
1170 /* .pfnDestruct = */ gicR3Destruct,
1171 /* .pfnRelocate = */ gicR3Relocate,
1172 /* .pfnMemSetup = */ NULL,
1173 /* .pfnPowerOn = */ NULL,
1174 /* .pfnReset = */ gicR3Reset,
1175 /* .pfnSuspend = */ NULL,
1176 /* .pfnResume = */ NULL,
1177 /* .pfnAttach = */ NULL,
1178 /* .pfnDetach = */ NULL,
1179 /* .pfnQueryInterface = */ NULL,
1180 /* .pfnInitComplete = */ NULL,
1181 /* .pfnPowerOff = */ NULL,
1182 /* .pfnSoftReset = */ NULL,
1183 /* .pfnReserved0 = */ NULL,
1184 /* .pfnReserved1 = */ NULL,
1185 /* .pfnReserved2 = */ NULL,
1186 /* .pfnReserved3 = */ NULL,
1187 /* .pfnReserved4 = */ NULL,
1188 /* .pfnReserved5 = */ NULL,
1189 /* .pfnReserved6 = */ NULL,
1190 /* .pfnReserved7 = */ NULL,
1191#elif defined(IN_RING0)
1192 /* .pfnEarlyConstruct = */ NULL,
1193 /* .pfnConstruct = */ gicRZConstruct,
1194 /* .pfnDestruct = */ NULL,
1195 /* .pfnFinalDestruct = */ NULL,
1196 /* .pfnRequest = */ NULL,
1197 /* .pfnReserved0 = */ NULL,
1198 /* .pfnReserved1 = */ NULL,
1199 /* .pfnReserved2 = */ NULL,
1200 /* .pfnReserved3 = */ NULL,
1201 /* .pfnReserved4 = */ NULL,
1202 /* .pfnReserved5 = */ NULL,
1203 /* .pfnReserved6 = */ NULL,
1204 /* .pfnReserved7 = */ NULL,
1205#elif defined(IN_RC)
1206 /* .pfnConstruct = */ gicRZConstruct,
1207 /* .pfnReserved0 = */ NULL,
1208 /* .pfnReserved1 = */ NULL,
1209 /* .pfnReserved2 = */ NULL,
1210 /* .pfnReserved3 = */ NULL,
1211 /* .pfnReserved4 = */ NULL,
1212 /* .pfnReserved5 = */ NULL,
1213 /* .pfnReserved6 = */ NULL,
1214 /* .pfnReserved7 = */ NULL,
1215#else
1216# error "Not in IN_RING3, IN_RING0 or IN_RC!"
1217#endif
1218 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
1219};
1220
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