VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/GICR3Nem-win.cpp@ 107308

Last change on this file since 107308 was 107308, checked in by vboxsync, 5 weeks ago

VMM: bugref:10759 Refactor GIC for use with different backends.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.1 KB
Line 
1/* $Id: GICR3Nem-win.cpp 107308 2024-12-13 08:09:39Z vboxsync $ */
2/** @file
3 * GIC - Generic Interrupt Controller Architecture (GICv3) - Hyper-V interface.
4 */
5
6/*
7 * Copyright (C) 2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_DEV_APIC
33#include <iprt/nt/nt-and-windows.h>
34#include <iprt/nt/hyperv.h>
35#include <WinHvPlatform.h>
36
37#include <VBox/log.h>
38#include "GICInternal.h"
39#include "NEMInternal.h" /* Need access to the partition handle. */
40#include <VBox/vmm/pdmgic.h>
41#include <VBox/vmm/cpum.h>
42#include <VBox/vmm/hm.h>
43#include <VBox/vmm/mm.h>
44#include <VBox/vmm/pdmdev.h>
45#include <VBox/vmm/ssm.h>
46#include <VBox/vmm/vm.h>
47
48#include <iprt/armv8.h>
49
50#ifndef VBOX_DEVICE_STRUCT_TESTCASE
51
52
53/*********************************************************************************************************************************
54* Defined Constants And Macros *
55*********************************************************************************************************************************/
56
57
58/*********************************************************************************************************************************
59* Structures and Typedefs *
60*********************************************************************************************************************************/
61
62/**
63 * GICHv PDM instance data (per-VM).
64 */
65typedef struct GICHVDEV
66{
67 /** Pointer to the PDM device instance. */
68 PPDMDEVINSR3 pDevIns;
69 /** The partition handle grabbed from NEM. */
70 WHV_PARTITION_HANDLE hPartition;
71} GICHVDEV;
72/** Pointer to a GIC Hyper-V device. */
73typedef GICHVDEV *PGICHVDEV;
74/** Pointer to a const GIC Hyper-V device. */
75typedef GICHVDEV const *PCGICHVDEV;
76
77
78/*
79 * The following definitions appeared in build 27744 allow interacting with the GICv3 controller,
80 * (there is no official SDK for this yet).
81 */
82/** @todo Better way of defining these which doesn't require casting later on when calling APIs. */
83#define MY_WHV_ARM64_IINTERRUPT_TYPE_FIXED UINT32_C(0)
84
85typedef union MY_WHV_INTERRUPT_CONTROL2
86{
87 UINT64 AsUINT64;
88 struct
89 {
90 uint32_t InterruptType;
91 UINT32 Reserved1:2;
92 UINT32 Asserted:1;
93 UINT32 Retarget:1;
94 UINT32 Reserved2:28;
95 };
96} MY_WHV_INTERRUPT_CONTROL2;
97
98
99typedef struct MY_WHV_INTERRUPT_CONTROL
100{
101 UINT64 TargetPartition;
102 MY_WHV_INTERRUPT_CONTROL2 InterruptControl;
103 UINT64 DestinationAddress;
104 UINT32 RequestedVector;
105 UINT8 TargetVtl;
106 UINT8 ReservedZ0;
107 UINT16 ReservedZ1;
108} MY_WHV_INTERRUPT_CONTROL;
109AssertCompileSize(MY_WHV_INTERRUPT_CONTROL, 32);
110
111
112/*********************************************************************************************************************************
113* Global Variables *
114*********************************************************************************************************************************/
115extern decltype(WHvRequestInterrupt) * g_pfnWHvRequestInterrupt;
116
117/*
118 * Let the preprocessor alias the APIs to import variables for better autocompletion.
119 */
120#ifndef IN_SLICKEDIT
121# define WHvRequestInterrupt g_pfnWHvRequestInterrupt
122#endif
123
124
125/**
126 * Common worker for gicR3HvSetSpi() and gicR3HvSetPpi().
127 *
128 * @returns VBox status code.
129 * @param pDevIns The PDM Hyper-V GIC device instance.
130 * @param idCpu The CPU ID for which the interrupt is updated (only valid for PPIs).
131 * @param fPpi Flag whether this is a PPI or SPI.
132 * @param uIntId The interrupt ID to update.
133 * @param fAsserted Flag whether the interrupt is asserted (true) or not (false).
134 */
135DECLINLINE(int) gicR3HvSetIrq(PPDMDEVINS pDevIns, VMCPUID idCpu, bool fPpi, uint32_t uIntId, bool fAsserted)
136{
137 LogFlowFunc(("pDevIns=%p idCpu=%u fPpi=%RTbool uIntId=%u fAsserted=%RTbool\n",
138 pDevIns, idCpu, fPpi, uIntId, fAsserted));
139
140 PGICHVDEV pThis = PDMDEVINS_2_DATA(pDevIns, PGICHVDEV);
141
142 MY_WHV_INTERRUPT_CONTROL IntrCtrl;
143 IntrCtrl.TargetPartition = 0;
144 IntrCtrl.InterruptControl.InterruptType = MY_WHV_ARM64_IINTERRUPT_TYPE_FIXED;
145 IntrCtrl.InterruptControl.Reserved1 = 0;
146 IntrCtrl.InterruptControl.Asserted = fAsserted ? 1 : 0;
147 IntrCtrl.InterruptControl.Retarget = 0;
148 IntrCtrl.InterruptControl.Reserved2 = 0;
149 IntrCtrl.DestinationAddress = fPpi ? RT_BIT(idCpu) : 0; /* SGI1R_EL1 */
150 IntrCtrl.RequestedVector = fPpi ? uIntId : uIntId;
151 IntrCtrl.TargetVtl = 0;
152 IntrCtrl.ReservedZ0 = 0;
153 IntrCtrl.ReservedZ1 = 0;
154 HRESULT hrc = WHvRequestInterrupt(pThis->hPartition, (const WHV_INTERRUPT_CONTROL *)&IntrCtrl, sizeof(IntrCtrl));
155 if (SUCCEEDED(hrc))
156 return VINF_SUCCESS;
157
158 AssertFailed();
159 LogFlowFunc(("WHvRequestInterrupt() failed with %Rhrc (Last=%#x/%u)\n", hrc, RTNtLastStatusValue(), RTNtLastErrorValue()));
160 return VERR_NEM_IPE_9; /** @todo */
161}
162
163
164/**
165 * Sets the given SPI inside the in-kernel Hyper-V GIC.
166 *
167 * @returns VBox status code.
168 * @param pVM The VM instance.
169 * @param uIntId The SPI ID to update.
170 * @param fAsserted Flag whether the interrupt is asserted (true) or not (false).
171 */
172static DECLCALLBACK(int) gicR3HvSetSpi(PVMCC pVM, uint32_t uIntId, bool fAsserted)
173{
174 PGIC pGic = VM_TO_GIC(pVM);
175 PPDMDEVINS pDevIns = pGic->CTX_SUFF(pDevIns);
176
177 /* idCpu is ignored for SPI interrupts. */
178 return gicR3HvSetIrq(pDevIns, 0 /*idCpu*/, false /*fPpi*/,
179 uIntId + GIC_INTID_RANGE_SPI_START, fAsserted);
180}
181
182
183/**
184 * Sets the given PPI inside the in-kernel Hyper-V GIC.
185 *
186 * @returns VBox status code.
187 * @param pVCpu The vCPU for whih the PPI state is updated.
188 * @param uIntId The PPI ID to update.
189 * @param fAsserted Flag whether the interrupt is asserted (true) or not (false).
190 */
191static DECLCALLBACK(int) gicR3HvSetPpi(PVMCPUCC pVCpu, uint32_t uIntId, bool fAsserted)
192{
193 PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
194
195 return gicR3HvSetIrq(pDevIns, pVCpu->idCpu, true /*fPpi*/,
196 uIntId + GIC_INTID_RANGE_PPI_START, fAsserted);
197}
198
199
200/**
201 * @interface_method_impl{PDMDEVREG,pfnReset}
202 */
203DECLCALLBACK(void) gicR3HvReset(PPDMDEVINS pDevIns)
204{
205 PVM pVM = PDMDevHlpGetVM(pDevIns);
206 VM_ASSERT_EMT0(pVM);
207 VM_ASSERT_IS_NOT_RUNNING(pVM);
208
209 RT_NOREF(pVM);
210
211 LogFlow(("GIC: gicR3HvReset\n"));
212}
213
214
215/**
216 * @interface_method_impl{PDMDEVREG,pfnDestruct}
217 */
218DECLCALLBACK(int) gicR3HvDestruct(PPDMDEVINS pDevIns)
219{
220 LogFlowFunc(("pDevIns=%p\n", pDevIns));
221 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
222
223 return VINF_SUCCESS;
224}
225
226
227/**
228 * @interface_method_impl{PDMDEVREG,pfnConstruct}
229 */
230DECLCALLBACK(int) gicR3HvConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
231{
232 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
233 PGICHVDEV pThis = PDMDEVINS_2_DATA(pDevIns, PGICHVDEV);
234 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
235 PVM pVM = PDMDevHlpGetVM(pDevIns);
236 PGIC pGic = VM_TO_GIC(pVM);
237 Assert(iInstance == 0); NOREF(iInstance);
238
239 /*
240 * Init the data.
241 */
242 pGic->pDevInsR3 = pDevIns;
243 pGic->fNemGic = true;
244 pThis->pDevIns = pDevIns;
245 pThis->hPartition = pVM->nem.s.hPartition;
246
247 /*
248 * Validate GIC settings.
249 */
250 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "DistributorMmioBase|RedistributorMmioBase|ItsMmioBase", "");
251
252 /*
253 * Disable automatic PDM locking for this device.
254 */
255 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
256 AssertRCReturn(rc, rc);
257
258 /*
259 * Register the GIC with PDM.
260 */
261 rc = PDMDevHlpIcRegister(pDevIns);
262 AssertLogRelRCReturn(rc, rc);
263
264 rc = PDMGicRegisterBackend(pVM, PDMGICBACKENDTYPE_HYPERV, &g_GicHvBackend);
265 AssertLogRelRCReturn(rc, rc);
266
267 /*
268 * Query the MMIO ranges.
269 */
270 RTGCPHYS GCPhysMmioBaseDist = 0;
271 rc = pHlp->pfnCFGMQueryU64(pCfg, "DistributorMmioBase", &GCPhysMmioBaseDist);
272 if (RT_FAILURE(rc))
273 return PDMDEV_SET_ERROR(pDevIns, rc,
274 N_("Configuration error: Failed to get the \"DistributorMmioBase\" value"));
275
276 RTGCPHYS GCPhysMmioBaseReDist = 0;
277 rc = pHlp->pfnCFGMQueryU64(pCfg, "RedistributorMmioBase", &GCPhysMmioBaseReDist);
278 if (RT_FAILURE(rc))
279 return PDMDEV_SET_ERROR(pDevIns, rc,
280 N_("Configuration error: Failed to get the \"RedistributorMmioBase\" value"));
281
282 gicR3HvReset(pDevIns);
283 return VINF_SUCCESS;
284}
285
286
287/**
288 * GIC device registration structure.
289 */
290const PDMDEVREG g_DeviceGICNem =
291{
292 /* .u32Version = */ PDM_DEVREG_VERSION,
293 /* .uReserved0 = */ 0,
294 /* .szName = */ "gic-nem",
295 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_NEW_STYLE,
296 /* .fClass = */ PDM_DEVREG_CLASS_PIC,
297 /* .cMaxInstances = */ 1,
298 /* .uSharedVersion = */ 42,
299 /* .cbInstanceShared = */ sizeof(GICHVDEV),
300 /* .cbInstanceCC = */ 0,
301 /* .cbInstanceRC = */ 0,
302 /* .cMaxPciDevices = */ 0,
303 /* .cMaxMsixVectors = */ 0,
304 /* .pszDescription = */ "Generic Interrupt Controller",
305#if defined(IN_RING3)
306 /* .szRCMod = */ "VMMRC.rc",
307 /* .szR0Mod = */ "VMMR0.r0",
308 /* .pfnConstruct = */ gicR3HvConstruct,
309 /* .pfnDestruct = */ gicR3HvDestruct,
310 /* .pfnRelocate = */ NULL,
311 /* .pfnMemSetup = */ NULL,
312 /* .pfnPowerOn = */ NULL,
313 /* .pfnReset = */ gicR3HvReset,
314 /* .pfnSuspend = */ NULL,
315 /* .pfnResume = */ NULL,
316 /* .pfnAttach = */ NULL,
317 /* .pfnDetach = */ NULL,
318 /* .pfnQueryInterface = */ NULL,
319 /* .pfnInitComplete = */ NULL,
320 /* .pfnPowerOff = */ NULL,
321 /* .pfnSoftReset = */ NULL,
322 /* .pfnReserved0 = */ NULL,
323 /* .pfnReserved1 = */ NULL,
324 /* .pfnReserved2 = */ NULL,
325 /* .pfnReserved3 = */ NULL,
326 /* .pfnReserved4 = */ NULL,
327 /* .pfnReserved5 = */ NULL,
328 /* .pfnReserved6 = */ NULL,
329 /* .pfnReserved7 = */ NULL,
330#else
331# error "Not in IN_RING3!"
332#endif
333 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
334};
335
336/**
337 * The Hypervisor.Framework GIC backend.
338 */
339const PDMGICBACKEND g_GicHvfBackend =
340{
341 /* .pfnReadSysReg = */ NULL,
342 /* .pfnWriteSysReg = */ NULL,
343 /* .pfnSetSpi = */ gicR3HvSetSpi,
344 /* .pfnSetPpi = */ gicR3HvSetPpi,
345};
346
347#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
348
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