VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/DevEFI-armv8.cpp@ 99927

Last change on this file since 99927 was 99927, checked in by vboxsync, 18 months ago

Devices/EFI,Main: Include EFI firmware images for ARMv8 in VBoxDD2 and provide a basic efi device specific for ARMv8 to get rid of the firmware loading hack by using a dedicated device implementation mapping the image as a ROM into the guest address space, bugref:10400

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.0 KB
Line 
1/* $Id: DevEFI-armv8.cpp 99927 2023-05-23 08:05:36Z vboxsync $ */
2/** @file
3 * DevEFI - EFI <-> VirtualBox Integration Framework.
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_EFI
33
34#include <VBox/vmm/pdmdev.h>
35#include <VBox/vmm/pgm.h>
36#include <VBox/vmm/cpum.h>
37#include <VBox/vmm/mm.h>
38#include <VBox/log.h>
39#include <VBox/err.h>
40#include <VBox/param.h>
41#include <VBox/vmm/dbgf.h>
42
43#include <iprt/asm.h>
44#include <iprt/assert.h>
45#include <iprt/ctype.h>
46#include <iprt/file.h>
47#include <iprt/mem.h>
48#include <iprt/string.h>
49#include <iprt/uuid.h>
50#include <iprt/path.h>
51#include <iprt/string.h>
52
53#include "DevEFI.h"
54#include "VBoxDD.h"
55#include "VBoxDD2.h"
56
57
58/*********************************************************************************************************************************
59* Structures and Typedefs *
60*********************************************************************************************************************************/
61/**
62 * The EFI device shared state structure.
63 */
64typedef struct DEVEFI
65{
66 uint32_t uEmpty;
67} DEVEFI;
68/** Pointer to the shared EFI state. */
69typedef DEVEFI *PDEVEFI;
70
71
72/**
73 * The EFI device state structure for ring-3.
74 */
75typedef struct DEVEFIR3
76{
77 /** Pointer back to the device instance. */
78 PPDMDEVINS pDevIns;
79
80 /** The system EFI ROM data. */
81 uint8_t const *pu8EfiRom;
82 /** The system EFI ROM data pointer to be passed to RTFileReadAllFree. */
83 uint8_t *pu8EfiRomFree;
84 /** The size of the system EFI ROM. */
85 uint64_t cbEfiRom;
86 /** Offset into the actual ROM within EFI FW volume. */
87 uint64_t offEfiRom;
88 /** The name of the EFI ROM file. */
89 char *pszEfiRomFile;
90 /** EFI firmware physical load address. */
91 RTGCPHYS GCPhysLoadAddress;
92} DEVEFIR3;
93/** Pointer to the ring-3 EFI state. */
94typedef DEVEFIR3 *PDEVEFIR3;
95
96
97/**
98 * The EFI device state structure for ring-0.
99 */
100typedef struct DEVEFIR0
101{
102 uint32_t uEmpty;
103} DEVEFIR0;
104/** Pointer to the ring-0 EFI state. */
105typedef DEVEFIR0 *PDEVEFIR0;
106
107
108/**
109 * The EFI device state structure for raw-mode.
110 */
111typedef struct DEVEFIRC
112{
113 uint32_t uEmpty;
114} DEVEFIRC;
115/** Pointer to the raw-mode EFI state. */
116typedef DEVEFIRC *PDEVEFIRC;
117
118
119/** @typedef DEVEFICC
120 * The instance data for the current context. */
121/** @typedef PDEVEFICC
122 * Pointer to the instance data for the current context. */
123#ifdef IN_RING3
124typedef DEVEFIR3 DEVEFICC;
125typedef PDEVEFIR3 PDEVEFICC;
126#elif defined(IN_RING0)
127typedef DEVEFIR0 DEVEFICC;
128typedef PDEVEFIR0 PDEVEFICC;
129#elif defined(IN_RC)
130typedef DEVEFIRC DEVEFICC;
131typedef PDEVEFIRC PDEVEFICC;
132#else
133# error "Not IN_RING3, IN_RING0 or IN_RC"
134#endif
135
136
137/*********************************************************************************************************************************
138* Defined Constants And Macros *
139*********************************************************************************************************************************/
140/** The saved state version. */
141#define EFI_SSM_VERSION 1
142
143
144/*********************************************************************************************************************************
145* Global Variables *
146*********************************************************************************************************************************/
147#ifdef IN_RING3
148
149# ifdef VBOX_WITH_EFI_IN_DD2
150/** Special file name value for indicating the 32-bit built-in EFI firmware. */
151static const char g_szEfiBuiltinAArch32[] = "VBoxEFIAArch32.fd";
152/** Special file name value for indicating the 64-bit built-in EFI firmware. */
153static const char g_szEfiBuiltinAArch64[] = "VBoxEFIAArch64.fd";
154# endif
155#endif /* IN_RING3 */
156
157
158#ifdef IN_RING3
159
160/**
161 * Destruct a device instance.
162 *
163 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
164 * resources can be freed correctly.
165 *
166 * @param pDevIns The device instance data.
167 */
168static DECLCALLBACK(int) efiR3Destruct(PPDMDEVINS pDevIns)
169{
170 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
171 PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
172
173 if (pThisCC->pu8EfiRomFree)
174 {
175 RTFileReadAllFree(pThisCC->pu8EfiRomFree, (size_t)pThisCC->cbEfiRom + pThisCC->offEfiRom);
176 pThisCC->pu8EfiRomFree = NULL;
177 }
178
179 /*
180 * Free MM heap pointers (waste of time, but whatever).
181 */
182 if (pThisCC->pszEfiRomFile)
183 {
184 PDMDevHlpMMHeapFree(pDevIns, pThisCC->pszEfiRomFile);
185 pThisCC->pszEfiRomFile = NULL;
186 }
187
188 return VINF_SUCCESS;
189}
190
191
192/**
193 * Load EFI ROM file into the memory.
194 *
195 * @returns VBox status code.
196 * @param pDevIns The device instance.
197 * @param pThisCC The device state for the current context.
198 * @param pCfg Configuration node handle for the device.
199 */
200static int efiR3LoadRom(PPDMDEVINS pDevIns, PDEVEFIR3 pThisCC, PCFGMNODE pCfg)
201{
202 RT_NOREF(pCfg);
203
204 /*
205 * Read the entire firmware volume into memory.
206 */
207 int rc;
208#ifdef VBOX_WITH_EFI_IN_DD2
209 if (RTStrCmp(pThisCC->pszEfiRomFile, g_szEfiBuiltinAArch32) == 0)
210 {
211 pThisCC->pu8EfiRomFree = NULL;
212 pThisCC->pu8EfiRom = g_abEfiFirmwareAArch32;
213 pThisCC->cbEfiRom = g_cbEfiFirmwareAArch32;
214 }
215 else if (RTStrCmp(pThisCC->pszEfiRomFile, g_szEfiBuiltinAArch64) == 0)
216 {
217 pThisCC->pu8EfiRomFree = NULL;
218 pThisCC->pu8EfiRom = g_abEfiFirmwareAArch64;
219 pThisCC->cbEfiRom = g_cbEfiFirmwareAArch64;
220 }
221 else
222#endif
223 {
224 void *pvFile;
225 size_t cbFile;
226 rc = RTFileReadAllEx(pThisCC->pszEfiRomFile,
227 0 /*off*/,
228 RTFOFF_MAX /*cbMax*/,
229 RTFILE_RDALL_O_DENY_WRITE,
230 &pvFile,
231 &cbFile);
232 if (RT_FAILURE(rc))
233 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
234 N_("Loading the EFI firmware volume '%s' failed with rc=%Rrc"),
235 pThisCC->pszEfiRomFile, rc);
236 pThisCC->pu8EfiRomFree = (uint8_t *)pvFile;
237 pThisCC->pu8EfiRom = (uint8_t *)pvFile;
238 pThisCC->cbEfiRom = cbFile;
239 }
240
241 rc = PDMDevHlpROMRegister(pDevIns, pThisCC->GCPhysLoadAddress, pThisCC->cbEfiRom, pThisCC->pu8EfiRom, pThisCC->cbEfiRom,
242 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "EFI Firmware Volume");
243 AssertRCReturn(rc, rc);
244
245 return VINF_SUCCESS;
246}
247
248
249/**
250 * @interface_method_impl{PDMDEVREG,pfnConstruct}
251 */
252static DECLCALLBACK(int) efiR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
253{
254 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
255 PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
256 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
257 int rc;
258
259 RT_NOREF(iInstance);
260 Assert(iInstance == 0);
261
262 /*
263 * Initalize the basic variables so that the destructor always works.
264 */
265 pThisCC->pDevIns = pDevIns;
266
267 /*
268 * Validate and read the configuration.
269 */
270 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "EfiRom|GCPhysLoadAddress", "");
271
272 rc = pHlp->pfnCFGMQueryU64(pCfg, "GCPhysLoadAddress", &pThisCC->GCPhysLoadAddress);
273 if (RT_FAILURE(rc))
274 return PDMDEV_SET_ERROR(pDevIns, rc,
275 N_("Configuration error: Querying \"GCPhysLoadAddress\" as integer failed"));
276
277 /*
278 * Get the system EFI ROM file name.
279 */
280#ifdef VBOX_WITH_EFI_IN_DD2
281 rc = pHlp->pfnCFGMQueryStringAllocDef(pCfg, "EfiRom", &pThisCC->pszEfiRomFile, g_szEfiBuiltinAArch32);
282 if (RT_FAILURE(rc))
283#else
284 rc = pHlp->pfnCFGMQueryStringAlloc(pCfg, "EfiRom", &pThisCC->pszEfiRomFile);
285 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
286 {
287 pThisCC->pszEfiRomFile = (char *)PDMDevHlpMMHeapAlloc(pDevIns, RTPATH_MAX);
288 AssertReturn(pThisCC->pszEfiRomFile, VERR_NO_MEMORY);
289 rc = RTPathAppPrivateArchTop(pThisCC->pszEfiRomFile, RTPATH_MAX);
290 AssertRCReturn(rc, rc);
291 rc = RTPathAppend(pThisCC->pszEfiRomFile, RTPATH_MAX, "VBoxEFIAArch32.fd");
292 AssertRCReturn(rc, rc);
293 }
294 else if (RT_FAILURE(rc))
295#endif
296 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
297 N_("Configuration error: Querying \"EfiRom\" as a string failed"));
298
299 /*
300 * Load firmware volume and thunk ROM.
301 */
302 rc = efiR3LoadRom(pDevIns, pThisCC, pCfg);
303 if (RT_FAILURE(rc))
304 return rc;
305
306 return VINF_SUCCESS;
307}
308
309#else /* IN_RING3 */
310
311
312/**
313 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
314 */
315static DECLCALLBACK(int) efiRZConstruct(PPDMDEVINS pDevIns)
316{
317 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
318 RT_NOREF(pDevIns);
319
320 return VINF_SUCCESS;
321}
322
323
324#endif /* IN_RING3 */
325
326/**
327 * The device registration structure.
328 */
329const PDMDEVREG g_DeviceEfiArmV8 =
330{
331 /* .u32Version = */ PDM_DEVREG_VERSION,
332 /* .uReserved0 = */ 0,
333 /* .szName = */ "efi-armv8",
334 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
335 /* .fClass = */ PDM_DEVREG_CLASS_ARCH_BIOS,
336 /* .cMaxInstances = */ 1,
337 /* .uSharedVersion = */ 42,
338 /* .cbInstanceShared = */ sizeof(DEVEFI),
339 /* .cbInstanceCC = */ sizeof(DEVEFICC),
340 /* .cbInstanceRC = */ sizeof(DEVEFIRC),
341 /* .cMaxPciDevices = */ 0,
342 /* .cMaxMsixVectors = */ 0,
343 /* .pszDescription = */ "Extensible Firmware Interface Device for ARMv8 platforms.\n",
344#if defined(IN_RING3)
345 /* .pszRCMod = */ "VBoxDDRC.rc",
346 /* .pszR0Mod = */ "VBoxDDR0.r0",
347 /* .pfnConstruct = */ efiR3Construct,
348 /* .pfnDestruct = */ efiR3Destruct,
349 /* .pfnRelocate = */ NULL,
350 /* .pfnMemSetup = */ NULL,
351 /* .pfnPowerOn = */ NULL,
352 /* .pfnReset = */ NULL,
353 /* .pfnSuspend = */ NULL,
354 /* .pfnResume = */ NULL,
355 /* .pfnAttach = */ NULL,
356 /* .pfnDetach = */ NULL,
357 /* .pfnQueryInterface = */ NULL,
358 /* .pfnInitComplete = */ NULL,
359 /* .pfnPowerOff = */ NULL,
360 /* .pfnSoftReset = */ NULL,
361 /* .pfnReserved0 = */ NULL,
362 /* .pfnReserved1 = */ NULL,
363 /* .pfnReserved2 = */ NULL,
364 /* .pfnReserved3 = */ NULL,
365 /* .pfnReserved4 = */ NULL,
366 /* .pfnReserved5 = */ NULL,
367 /* .pfnReserved6 = */ NULL,
368 /* .pfnReserved7 = */ NULL,
369#elif defined(IN_RING0)
370 /* .pfnEarlyConstruct = */ NULL,
371 /* .pfnConstruct = */ efiRZConstruct,
372 /* .pfnDestruct = */ NULL,
373 /* .pfnFinalDestruct = */ NULL,
374 /* .pfnRequest = */ NULL,
375 /* .pfnReserved0 = */ NULL,
376 /* .pfnReserved1 = */ NULL,
377 /* .pfnReserved2 = */ NULL,
378 /* .pfnReserved3 = */ NULL,
379 /* .pfnReserved4 = */ NULL,
380 /* .pfnReserved5 = */ NULL,
381 /* .pfnReserved6 = */ NULL,
382 /* .pfnReserved7 = */ NULL,
383#elif defined(IN_RC)
384 /* .pfnConstruct = */ efiRZConstruct,
385 /* .pfnReserved0 = */ NULL,
386 /* .pfnReserved1 = */ NULL,
387 /* .pfnReserved2 = */ NULL,
388 /* .pfnReserved3 = */ NULL,
389 /* .pfnReserved4 = */ NULL,
390 /* .pfnReserved5 = */ NULL,
391 /* .pfnReserved6 = */ NULL,
392 /* .pfnReserved7 = */ NULL,
393#else
394# error "Not in IN_RING3, IN_RING0 or IN_RC!"
395#endif
396 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
397};
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