VirtualBox

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

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

VMM: bugref:10759 Refactor GIC for use with different backends. [windows build fix]

  • 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 107313 2024-12-13 08:54:06Z 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 pThis->pDevIns = pDevIns;
244 pThis->hPartition = pVM->nem.s.hPartition;
245
246 /*
247 * Validate GIC settings.
248 */
249 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "DistributorMmioBase|RedistributorMmioBase|ItsMmioBase", "");
250
251 /*
252 * Disable automatic PDM locking for this device.
253 */
254 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
255 AssertRCReturn(rc, rc);
256
257 /*
258 * Register the GIC with PDM.
259 */
260 rc = PDMDevHlpIcRegister(pDevIns);
261 AssertLogRelRCReturn(rc, rc);
262
263 rc = PDMGicRegisterBackend(pVM, PDMGICBACKENDTYPE_HYPERV, &g_GicHvBackend);
264 AssertLogRelRCReturn(rc, rc);
265
266 /*
267 * Query the MMIO ranges.
268 */
269 RTGCPHYS GCPhysMmioBaseDist = 0;
270 rc = pHlp->pfnCFGMQueryU64(pCfg, "DistributorMmioBase", &GCPhysMmioBaseDist);
271 if (RT_FAILURE(rc))
272 return PDMDEV_SET_ERROR(pDevIns, rc,
273 N_("Configuration error: Failed to get the \"DistributorMmioBase\" value"));
274
275 RTGCPHYS GCPhysMmioBaseReDist = 0;
276 rc = pHlp->pfnCFGMQueryU64(pCfg, "RedistributorMmioBase", &GCPhysMmioBaseReDist);
277 if (RT_FAILURE(rc))
278 return PDMDEV_SET_ERROR(pDevIns, rc,
279 N_("Configuration error: Failed to get the \"RedistributorMmioBase\" value"));
280
281 gicR3HvReset(pDevIns);
282 return VINF_SUCCESS;
283}
284
285
286/**
287 * GIC device registration structure.
288 */
289const PDMDEVREG g_DeviceGICNem =
290{
291 /* .u32Version = */ PDM_DEVREG_VERSION,
292 /* .uReserved0 = */ 0,
293 /* .szName = */ "gic-nem",
294 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_NEW_STYLE,
295 /* .fClass = */ PDM_DEVREG_CLASS_PIC,
296 /* .cMaxInstances = */ 1,
297 /* .uSharedVersion = */ 42,
298 /* .cbInstanceShared = */ sizeof(GICHVDEV),
299 /* .cbInstanceCC = */ 0,
300 /* .cbInstanceRC = */ 0,
301 /* .cMaxPciDevices = */ 0,
302 /* .cMaxMsixVectors = */ 0,
303 /* .pszDescription = */ "Generic Interrupt Controller",
304#if defined(IN_RING3)
305 /* .szRCMod = */ "VMMRC.rc",
306 /* .szR0Mod = */ "VMMR0.r0",
307 /* .pfnConstruct = */ gicR3HvConstruct,
308 /* .pfnDestruct = */ gicR3HvDestruct,
309 /* .pfnRelocate = */ NULL,
310 /* .pfnMemSetup = */ NULL,
311 /* .pfnPowerOn = */ NULL,
312 /* .pfnReset = */ gicR3HvReset,
313 /* .pfnSuspend = */ NULL,
314 /* .pfnResume = */ NULL,
315 /* .pfnAttach = */ NULL,
316 /* .pfnDetach = */ NULL,
317 /* .pfnQueryInterface = */ NULL,
318 /* .pfnInitComplete = */ NULL,
319 /* .pfnPowerOff = */ NULL,
320 /* .pfnSoftReset = */ NULL,
321 /* .pfnReserved0 = */ NULL,
322 /* .pfnReserved1 = */ NULL,
323 /* .pfnReserved2 = */ NULL,
324 /* .pfnReserved3 = */ NULL,
325 /* .pfnReserved4 = */ NULL,
326 /* .pfnReserved5 = */ NULL,
327 /* .pfnReserved6 = */ NULL,
328 /* .pfnReserved7 = */ NULL,
329#else
330# error "Not in IN_RING3!"
331#endif
332 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
333};
334
335/**
336 * The Hyper-V GIC backend.
337 */
338const PDMGICBACKEND g_GicHvBackend =
339{
340 /* .pfnReadSysReg = */ NULL,
341 /* .pfnWriteSysReg = */ NULL,
342 /* .pfnSetSpi = */ gicR3HvSetSpi,
343 /* .pfnSetPpi = */ gicR3HvSetPpi,
344};
345
346#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
347
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