VirtualBox

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

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

VMMArm: Add a GIC NEM backend skeleton for Windows, bugref:10392 [doxygen]

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.7 KB
Line 
1/* $Id: GICR3Nem-win.cpp 106404 2024-10-16 21:00:19Z 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/gic.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 KVM device. */
73typedef GICHVDEV *PGICHVDEV;
74/** Pointer to a const GIC KVM device. */
75typedef GICHVDEV const *PCGICHVDEV;
76
77
78/*********************************************************************************************************************************
79* Global Variables *
80*********************************************************************************************************************************/
81extern decltype(WHvRequestInterrupt) * g_pfnWHvRequestInterrupt;
82
83/*
84 * Let the preprocessor alias the APIs to import variables for better autocompletion.
85 */
86#ifndef IN_SLICKEDIT
87# define WHvRequestInterrupt g_pfnWHvRequestInterrupt
88#endif
89
90#if 0
91/**
92 * System register ranges for the GICv3.
93 */
94static CPUMSYSREGRANGE const g_aSysRegRanges_GICv3[] =
95{
96 GIC_SYSREGRANGE(ARMV8_AARCH64_SYSREG_ICC_PMR_EL1, ARMV8_AARCH64_SYSREG_ICC_PMR_EL1, "ICC_PMR_EL1"),
97 GIC_SYSREGRANGE(ARMV8_AARCH64_SYSREG_ICC_IAR0_EL1, ARMV8_AARCH64_SYSREG_ICC_AP0R3_EL1, "ICC_IAR0_EL1 - ICC_AP0R3_EL1"),
98 GIC_SYSREGRANGE(ARMV8_AARCH64_SYSREG_ICC_AP1R0_EL1, ARMV8_AARCH64_SYSREG_ICC_NMIAR1_EL1, "ICC_AP1R0_EL1 - ICC_NMIAR1_EL1"),
99 GIC_SYSREGRANGE(ARMV8_AARCH64_SYSREG_ICC_DIR_EL1, ARMV8_AARCH64_SYSREG_ICC_SGI0R_EL1, "ICC_DIR_EL1 - ICC_SGI0R_EL1"),
100 GIC_SYSREGRANGE(ARMV8_AARCH64_SYSREG_ICC_IAR1_EL1, ARMV8_AARCH64_SYSREG_ICC_IGRPEN1_EL1, "ICC_IAR1_EL1 - ICC_IGRPEN1_EL1"),
101};
102#endif
103
104
105/**
106 * Common worker for GICR3KvmSpiSet() and GICR3KvmPpiSet().
107 *
108 * @returns VBox status code.
109 * @param pDevIns The PDM KVM GIC device instance.
110 * @param idCpu The CPU ID for which the interrupt is updated (only valid for PPIs).
111 * @param fPpi Flag whether this is a PPI or SPI.
112 * @param uIntId The interrupt ID to update.
113 * @param fAsserted Flag whether the interrupt is asserted (true) or not (false).
114 */
115DECLINLINE(int) gicR3HvSetIrq(PPDMDEVINS pDevIns, VMCPUID idCpu, bool fPpi, uint32_t uIntId, bool fAsserted)
116{
117 LogFlowFunc(("pDevIns=%p idCpu=%u fPpi=%RTbool uIntId=%u fAsserted=%RTbool\n",
118 pDevIns, idCpu, fPpi, uIntId, fAsserted));
119
120 PGICHVDEV pThis = PDMDEVINS_2_DATA(pDevIns, PGICHVDEV);
121
122 WHV_INTERRUPT_CONTROL IntrCtrl;
123 IntrCtrl.TargetPartition = 0;
124 IntrCtrl.InterruptControl.InterruptType = WHvArm64InterruptTypeFixed;
125 IntrCtrl.InterruptControl.LevelTriggered = 1;
126 IntrCtrl.InterruptControl.LogicalDestinationMode = 0;
127 IntrCtrl.InterruptControl.Asserted = fAsserted ? 1 : 0;
128 IntrCtrl.InterruptControl.Reserved = 0;
129 IntrCtrl.DestinationAddress = fPpi ? RT_BIT(idCpu) : 0; /* SGI1R_EL1 */
130 IntrCtrl.RequestedVector = fPpi ? uIntId : uIntId;
131 IntrCtrl.TargetVtl = 0;
132 IntrCtrl.ReservedZ0 = 0;
133 IntrCtrl.ReservedZ1 = 0;
134 HRESULT hrc = WHvRequestInterrupt(pThis->hPartition, &IntrCtrl, sizeof(IntrCtrl));
135 if (SUCCEEDED(hrc))
136 return VINF_SUCCESS;
137
138 LogFlowFunc(("WHvRequestInterrupt() failed with %Rhrc (Last=%#x/%u)\n", hrc, RTNtLastStatusValue(), RTNtLastErrorValue()));
139 return VERR_NEM_IPE_9; /** @todo */
140}
141
142
143/**
144 * Sets the given SPI inside the in-kernel KVM GIC.
145 *
146 * @returns VBox status code.
147 * @param pVM The VM instance.
148 * @param uIntId The SPI ID to update.
149 * @param fAsserted Flag whether the interrupt is asserted (true) or not (false).
150 */
151VMMR3_INT_DECL(int) GICR3NemSpiSet(PVMCC pVM, uint32_t uIntId, bool fAsserted)
152{
153 PGIC pGic = VM_TO_GIC(pVM);
154 PPDMDEVINS pDevIns = pGic->CTX_SUFF(pDevIns);
155
156 /* idCpu is ignored for SPI interrupts. */
157 return gicR3HvSetIrq(pDevIns, 0 /*idCpu*/, false /*fPpi*/,
158 uIntId + GIC_INTID_RANGE_SPI_START, fAsserted);
159}
160
161
162/**
163 * Sets the given PPI inside the in-kernel KVM GIC.
164 *
165 * @returns VBox status code.
166 * @param pVCpu The vCPU for whih the PPI state is updated.
167 * @param uIntId The PPI ID to update.
168 * @param fAsserted Flag whether the interrupt is asserted (true) or not (false).
169 */
170VMMR3_INT_DECL(int) GICR3NemPpiSet(PVMCPUCC pVCpu, uint32_t uIntId, bool fAsserted)
171{
172 PPDMDEVINS pDevIns = VMCPU_TO_DEVINS(pVCpu);
173
174 return gicR3HvSetIrq(pDevIns, pVCpu->idCpu, true /*fPpi*/,
175 uIntId + GIC_INTID_RANGE_PPI_START, fAsserted);
176}
177
178
179/**
180 * @interface_method_impl{PDMDEVREG,pfnReset}
181 */
182DECLCALLBACK(void) gicR3HvReset(PPDMDEVINS pDevIns)
183{
184 PVM pVM = PDMDevHlpGetVM(pDevIns);
185 VM_ASSERT_EMT0(pVM);
186 VM_ASSERT_IS_NOT_RUNNING(pVM);
187
188 RT_NOREF(pVM);
189
190 LogFlow(("GIC: gicR3HvReset\n"));
191}
192
193
194/**
195 * @interface_method_impl{PDMDEVREG,pfnDestruct}
196 */
197DECLCALLBACK(int) gicR3HvDestruct(PPDMDEVINS pDevIns)
198{
199 LogFlowFunc(("pDevIns=%p\n", pDevIns));
200 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
201
202 return VINF_SUCCESS;
203}
204
205
206/**
207 * @interface_method_impl{PDMDEVREG,pfnConstruct}
208 */
209DECLCALLBACK(int) gicR3HvConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
210{
211 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
212 PGICHVDEV pThis = PDMDEVINS_2_DATA(pDevIns, PGICHVDEV);
213 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
214 PVM pVM = PDMDevHlpGetVM(pDevIns);
215 PGIC pGic = VM_TO_GIC(pVM);
216 Assert(iInstance == 0); NOREF(iInstance);
217
218 /*
219 * Init the data.
220 */
221 pGic->pDevInsR3 = pDevIns;
222 pGic->fNemGic = true;
223 pThis->pDevIns = pDevIns;
224 pThis->hPartition = pVM->nem.s.hPartition;
225
226 /*
227 * Validate GIC settings.
228 */
229 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "DistributorMmioBase|RedistributorMmioBase", "");
230
231 /*
232 * Disable automatic PDM locking for this device.
233 */
234 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
235 AssertRCReturn(rc, rc);
236
237 /*
238 * Register the GIC with PDM.
239 */
240 rc = PDMDevHlpApicRegister(pDevIns);
241 AssertLogRelRCReturn(rc, rc);
242
243 /*
244 * Query the MMIO ranges.
245 */
246 RTGCPHYS GCPhysMmioBaseDist = 0;
247 rc = pHlp->pfnCFGMQueryU64(pCfg, "DistributorMmioBase", &GCPhysMmioBaseDist);
248 if (RT_FAILURE(rc))
249 return PDMDEV_SET_ERROR(pDevIns, rc,
250 N_("Configuration error: Failed to get the \"DistributorMmioBase\" value"));
251
252 RTGCPHYS GCPhysMmioBaseReDist = 0;
253 rc = pHlp->pfnCFGMQueryU64(pCfg, "RedistributorMmioBase", &GCPhysMmioBaseReDist);
254 if (RT_FAILURE(rc))
255 return PDMDEV_SET_ERROR(pDevIns, rc,
256 N_("Configuration error: Failed to get the \"RedistributorMmioBase\" value"));
257
258 /** @todo Configure the MMIO bases when MS released a new SDK with support for it (currently hard coded in the FDT in the
259 * Main constructor):
260 * GICD: 0xffff0000
261 * GICR: 0xeffee000 (0x20000 per VP)
262 * GITS: 0xeff68000
263 */
264
265 gicR3HvReset(pDevIns);
266 return VINF_SUCCESS;
267}
268
269
270/**
271 * GIC device registration structure.
272 */
273const PDMDEVREG g_DeviceGICNem =
274{
275 /* .u32Version = */ PDM_DEVREG_VERSION,
276 /* .uReserved0 = */ 0,
277 /* .szName = */ "gic-nem",
278 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_NEW_STYLE,
279 /* .fClass = */ PDM_DEVREG_CLASS_PIC,
280 /* .cMaxInstances = */ 1,
281 /* .uSharedVersion = */ 42,
282 /* .cbInstanceShared = */ sizeof(GICHVDEV),
283 /* .cbInstanceCC = */ 0,
284 /* .cbInstanceRC = */ 0,
285 /* .cMaxPciDevices = */ 0,
286 /* .cMaxMsixVectors = */ 0,
287 /* .pszDescription = */ "Generic Interrupt Controller",
288#if defined(IN_RING3)
289 /* .szRCMod = */ "VMMRC.rc",
290 /* .szR0Mod = */ "VMMR0.r0",
291 /* .pfnConstruct = */ gicR3HvConstruct,
292 /* .pfnDestruct = */ gicR3HvDestruct,
293 /* .pfnRelocate = */ NULL,
294 /* .pfnMemSetup = */ NULL,
295 /* .pfnPowerOn = */ NULL,
296 /* .pfnReset = */ gicR3HvReset,
297 /* .pfnSuspend = */ NULL,
298 /* .pfnResume = */ NULL,
299 /* .pfnAttach = */ NULL,
300 /* .pfnDetach = */ NULL,
301 /* .pfnQueryInterface = */ NULL,
302 /* .pfnInitComplete = */ NULL,
303 /* .pfnPowerOff = */ NULL,
304 /* .pfnSoftReset = */ NULL,
305 /* .pfnReserved0 = */ NULL,
306 /* .pfnReserved1 = */ NULL,
307 /* .pfnReserved2 = */ NULL,
308 /* .pfnReserved3 = */ NULL,
309 /* .pfnReserved4 = */ NULL,
310 /* .pfnReserved5 = */ NULL,
311 /* .pfnReserved6 = */ NULL,
312 /* .pfnReserved7 = */ NULL,
313#else
314# error "Not in IN_RING3!"
315#endif
316 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
317};
318
319#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
320
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