VirtualBox

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

Last change on this file since 99654 was 99578, checked in by vboxsync, 20 months ago

VMM/GIC: Continue implementation, bugref:10404

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.9 KB
Line 
1/* $Id: GICAll.cpp 99578 2023-05-03 10:31:20Z 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 * Reads a GIC distributor register.
55 *
56 * @returns VBox status code.
57 * @param pDevIns The device instance.
58 * @param pVCpu The cross context virtual CPU structure.
59 * @param offReg The offset of the register being read.
60 * @param puValue Where to store the register value.
61 */
62DECLINLINE(VBOXSTRICTRC) gicDistRegisterRead(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t *puValue)
63{
64 VMCPU_ASSERT_EMT(pVCpu);
65 RT_NOREF(pDevIns, pVCpu, offReg);
66
67 switch (offReg)
68 {
69 case GIC_DIST_REG_TYPER_OFF:
70 *puValue = GIC_DIST_REG_TYPER_NUM_ITLINES_SET(0) /** @todo 32 SPIs for now. */
71 | GIC_DIST_REG_TYPER_NUM_PES_SET(0) /* 1 PE */
72 /*| GIC_DIST_REG_TYPER_ESPI*/ /** @todo */
73 /*| GIC_DIST_REG_TYPER_NMI*/ /** @todo Non-maskable interrupts */
74 /*| GIC_DIST_REG_TYPER_SECURITY_EXTN */ /** @todo */
75 /*| GIC_DIST_REG_TYPER_MBIS */ /** @todo Message based interrupts */
76 /*| GIC_DIST_REG_TYPER_LPIS */ /** @todo Support LPIs */
77 | GIC_DIST_REG_TYPER_IDBITS_SET(16);
78 break;
79 case GIC_DIST_REG_PIDR2_OFF:
80 *puValue = GIC_REDIST_REG_PIDR2_ARCH_REV_SET(GIC_REDIST_REG_PIDR2_ARCH_REV_GICV3);
81 break;
82 case GIC_DIST_REG_IIDR_OFF:
83 case GIC_DIST_REG_TYPER2_OFF:
84 default:
85 *puValue = 0;
86 }
87 return VINF_SUCCESS;
88}
89
90
91/**
92 * Writes a GIC distributor register.
93 *
94 * @returns Strict VBox status code.
95 * @param pDevIns The device instance.
96 * @param pVCpu The cross context virtual CPU structure.
97 * @param offReg The offset of the register being written.
98 * @param uValue The register value.
99 */
100DECLINLINE(VBOXSTRICTRC) gicDistRegisterWrite(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue)
101{
102 VMCPU_ASSERT_EMT(pVCpu);
103 RT_NOREF(pDevIns, pVCpu, offReg, uValue);
104
105 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
106 return rcStrict;
107}
108
109
110/**
111 * Reads a GIC redistributor register.
112 *
113 * @returns VBox status code.
114 * @param pDevIns The device instance.
115 * @param pVCpu The cross context virtual CPU structure.
116 * @param offReg The offset of the register being read.
117 * @param puValue Where to store the register value.
118 */
119DECLINLINE(VBOXSTRICTRC) gicReDistRegisterRead(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t *puValue)
120{
121 VMCPU_ASSERT_EMT(pVCpu);
122 RT_NOREF(pDevIns, pVCpu, offReg);
123
124 switch (offReg)
125 {
126 case GIC_REDIST_REG_PIDR2_OFF:
127 *puValue = GIC_REDIST_REG_PIDR2_ARCH_REV_SET(GIC_REDIST_REG_PIDR2_ARCH_REV_GICV3);
128 break;
129 default:
130 *puValue = 0;
131 }
132
133 return VINF_SUCCESS;
134}
135
136
137/**
138 * Writes a GIC redistributor register.
139 *
140 * @returns Strict VBox status code.
141 * @param pDevIns The device instance.
142 * @param pVCpu The cross context virtual CPU structure.
143 * @param offReg The offset of the register being written.
144 * @param uValue The register value.
145 */
146DECLINLINE(VBOXSTRICTRC) gicReDistRegisterWrite(PPDMDEVINS pDevIns, PVMCPUCC pVCpu, uint16_t offReg, uint32_t uValue)
147{
148 VMCPU_ASSERT_EMT(pVCpu);
149 RT_NOREF(pDevIns, pVCpu, offReg, uValue);
150
151 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
152 return rcStrict;
153}
154
155
156/**
157 * Reads a GIC system register.
158 *
159 * @returns Strict VBox status code.
160 * @param pVCpu The cross context virtual CPU structure.
161 * @param u32Reg The system register being read.
162 * @param pu64Value Where to store the read value.
163 */
164VMM_INT_DECL(VBOXSTRICTRC) GICReadSysReg(PVMCPUCC pVCpu, uint32_t u32Reg, uint64_t *pu64Value)
165{
166 /*
167 * Validate.
168 */
169 VMCPU_ASSERT_EMT(pVCpu);
170 Assert(pu64Value);
171
172 *pu64Value = 0;
173 LogFlowFunc(("pVCpu=%p u32Reg=%#x pu64Value=%RX64\n", pVCpu, u32Reg, *pu64Value));
174 return VINF_SUCCESS;
175}
176
177
178/**
179 * Writes an GIC system register.
180 *
181 * @returns Strict VBox status code.
182 * @param pVCpu The cross context virtual CPU structure.
183 * @param u32Reg The system register being written (IPRT system register identifier).
184 * @param u64Value The value to write.
185 */
186VMM_INT_DECL(VBOXSTRICTRC) GICWriteSysReg(PVMCPUCC pVCpu, uint32_t u32Reg, uint64_t u64Value)
187{
188 /*
189 * Validate.
190 */
191 VMCPU_ASSERT_EMT(pVCpu);
192 RT_NOREF(pVCpu, u32Reg, u64Value);
193 LogFlowFunc(("pVCpu=%p u32Reg=%#x u64Value=%RX64\n", pVCpu, u32Reg, u64Value));
194
195 return VINF_SUCCESS;
196}
197
198
199/**
200 * Initializes per-VCPU GIC to the state following a power-up or hardware
201 * reset.
202 *
203 * @param pVCpu The cross context virtual CPU structure.
204 */
205DECLHIDDEN(void) gicResetCpu(PVMCPUCC pVCpu)
206{
207 LogFlowFunc(("GIC%u\n", pVCpu->idCpu));
208 VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu);
209}
210
211
212/**
213 * @callback_method_impl{FNIOMMMIONEWREAD}
214 */
215DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) gicDistMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
216{
217 NOREF(pvUser);
218 //Assert(!(off & 0xf));
219 //Assert(cb == 4); RT_NOREF_PV(cb);
220
221 PVMCPUCC pVCpu = PDMDevHlpGetVMCPU(pDevIns);
222 uint16_t offReg = off & 0xfffc;
223 uint32_t uValue = 0;
224
225 STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioRead));
226
227 VBOXSTRICTRC rc = VBOXSTRICTRC_VAL(gicDistRegisterRead(pDevIns, pVCpu, offReg, &uValue));
228 *(uint32_t *)pv = uValue;
229
230 Log2(("GIC%u: gicDistMmioRead: offReg=%#RX16 uValue=%#RX32\n", pVCpu->idCpu, offReg, uValue));
231 return rc;
232}
233
234
235/**
236 * @callback_method_impl{FNIOMMMIONEWWRITE}
237 */
238DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) gicDistMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
239{
240 NOREF(pvUser);
241 //Assert(!(off & 0xf));
242 //Assert(cb == 4); RT_NOREF_PV(cb);
243
244 PVMCPUCC pVCpu = PDMDevHlpGetVMCPU(pDevIns);
245 uint16_t offReg = off & 0xfffc;
246 uint32_t uValue = *(uint32_t *)pv;
247
248 STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioWrite));
249
250 Log2(("GIC%u: gicDistMmioWrite: offReg=%#RX16 uValue=%#RX32\n", pVCpu->idCpu, offReg, uValue));
251 return gicDistRegisterWrite(pDevIns, pVCpu, offReg, uValue);
252}
253
254
255/**
256 * @callback_method_impl{FNIOMMMIONEWREAD}
257 */
258DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) gicReDistMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
259{
260 NOREF(pvUser);
261 //Assert(!(off & 0xf));
262 //Assert(cb == 4); RT_NOREF_PV(cb);
263
264 PVMCPUCC pVCpu = PDMDevHlpGetVMCPU(pDevIns);
265 uint16_t offReg = off & 0xfffc;
266 uint32_t uValue = 0;
267
268 STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioRead));
269
270 VBOXSTRICTRC rc = VBOXSTRICTRC_VAL(gicReDistRegisterRead(pDevIns, pVCpu, offReg, &uValue));
271 *(uint32_t *)pv = uValue;
272
273 Log2(("GIC%u: gicReDistMmioRead: offReg=%#RX16 uValue=%#RX32\n", pVCpu->idCpu, offReg, uValue));
274 return rc;
275}
276
277
278/**
279 * @callback_method_impl{FNIOMMMIONEWWRITE}
280 */
281DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) gicReDistMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
282{
283 NOREF(pvUser);
284 //Assert(!(off & 0xf));
285 //Assert(cb == 4); RT_NOREF_PV(cb);
286
287 PVMCPUCC pVCpu = PDMDevHlpGetVMCPU(pDevIns);
288 uint16_t offReg = off & 0xfffc;
289 uint32_t uValue = *(uint32_t *)pv;
290
291 STAM_COUNTER_INC(&pVCpu->gic.s.CTX_SUFF_Z(StatMmioWrite));
292
293 Log2(("GIC%u: gicReDistMmioWrite: offReg=%#RX16 uValue=%#RX32\n", pVCpu->idCpu, offReg, uValue));
294 return gicReDistRegisterWrite(pDevIns, pVCpu, offReg, uValue);
295}
296
297
298#ifndef IN_RING3
299
300/**
301 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
302 */
303static DECLCALLBACK(int) gicRZConstruct(PPDMDEVINS pDevIns)
304{
305 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
306 AssertReleaseFailed();
307 return VINF_SUCCESS;
308}
309#endif /* !IN_RING3 */
310
311/**
312 * GIC device registration structure.
313 */
314const PDMDEVREG g_DeviceGIC =
315{
316 /* .u32Version = */ PDM_DEVREG_VERSION,
317 /* .uReserved0 = */ 0,
318 /* .szName = */ "gic",
319 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
320 /* .fClass = */ PDM_DEVREG_CLASS_PIC,
321 /* .cMaxInstances = */ 1,
322 /* .uSharedVersion = */ 42,
323 /* .cbInstanceShared = */ sizeof(GICDEV),
324 /* .cbInstanceCC = */ 0,
325 /* .cbInstanceRC = */ 0,
326 /* .cMaxPciDevices = */ 0,
327 /* .cMaxMsixVectors = */ 0,
328 /* .pszDescription = */ "Generic Interrupt Controller",
329#if defined(IN_RING3)
330 /* .szRCMod = */ "VMMRC.rc",
331 /* .szR0Mod = */ "VMMR0.r0",
332 /* .pfnConstruct = */ gicR3Construct,
333 /* .pfnDestruct = */ gicR3Destruct,
334 /* .pfnRelocate = */ gicR3Relocate,
335 /* .pfnMemSetup = */ NULL,
336 /* .pfnPowerOn = */ NULL,
337 /* .pfnReset = */ gicR3Reset,
338 /* .pfnSuspend = */ NULL,
339 /* .pfnResume = */ NULL,
340 /* .pfnAttach = */ NULL,
341 /* .pfnDetach = */ NULL,
342 /* .pfnQueryInterface = */ NULL,
343 /* .pfnInitComplete = */ NULL,
344 /* .pfnPowerOff = */ NULL,
345 /* .pfnSoftReset = */ NULL,
346 /* .pfnReserved0 = */ NULL,
347 /* .pfnReserved1 = */ NULL,
348 /* .pfnReserved2 = */ NULL,
349 /* .pfnReserved3 = */ NULL,
350 /* .pfnReserved4 = */ NULL,
351 /* .pfnReserved5 = */ NULL,
352 /* .pfnReserved6 = */ NULL,
353 /* .pfnReserved7 = */ NULL,
354#elif defined(IN_RING0)
355 /* .pfnEarlyConstruct = */ NULL,
356 /* .pfnConstruct = */ gicRZConstruct,
357 /* .pfnDestruct = */ NULL,
358 /* .pfnFinalDestruct = */ NULL,
359 /* .pfnRequest = */ NULL,
360 /* .pfnReserved0 = */ NULL,
361 /* .pfnReserved1 = */ NULL,
362 /* .pfnReserved2 = */ NULL,
363 /* .pfnReserved3 = */ NULL,
364 /* .pfnReserved4 = */ NULL,
365 /* .pfnReserved5 = */ NULL,
366 /* .pfnReserved6 = */ NULL,
367 /* .pfnReserved7 = */ NULL,
368#elif defined(IN_RC)
369 /* .pfnConstruct = */ gicRZConstruct,
370 /* .pfnReserved0 = */ NULL,
371 /* .pfnReserved1 = */ NULL,
372 /* .pfnReserved2 = */ NULL,
373 /* .pfnReserved3 = */ NULL,
374 /* .pfnReserved4 = */ NULL,
375 /* .pfnReserved5 = */ NULL,
376 /* .pfnReserved6 = */ NULL,
377 /* .pfnReserved7 = */ NULL,
378#else
379# error "Not in IN_RING3, IN_RING0 or IN_RC!"
380#endif
381 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
382};
383
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