Index: trunk/src/VBox/Devices/EFI/DevEFI-armv8.cpp
===================================================================
--- trunk/src/VBox/Devices/EFI/DevEFI-armv8.cpp	(revision 99927)
+++ trunk/src/VBox/Devices/EFI/DevEFI-armv8.cpp	(revision 99927)
@@ -0,0 +1,397 @@
+/* $Id$ */
+/** @file
+ * DevEFI - EFI <-> VirtualBox Integration Framework.
+ */
+
+/*
+ * Copyright (C) 2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_DEV_EFI
+
+#include <VBox/vmm/pdmdev.h>
+#include <VBox/vmm/pgm.h>
+#include <VBox/vmm/cpum.h>
+#include <VBox/vmm/mm.h>
+#include <VBox/log.h>
+#include <VBox/err.h>
+#include <VBox/param.h>
+#include <VBox/vmm/dbgf.h>
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/ctype.h>
+#include <iprt/file.h>
+#include <iprt/mem.h>
+#include <iprt/string.h>
+#include <iprt/uuid.h>
+#include <iprt/path.h>
+#include <iprt/string.h>
+
+#include "DevEFI.h"
+#include "VBoxDD.h"
+#include "VBoxDD2.h"
+
+
+/*********************************************************************************************************************************
+*   Structures and Typedefs                                                                                                      *
+*********************************************************************************************************************************/
+/**
+ * The EFI device shared state structure.
+ */
+typedef struct DEVEFI
+{
+    uint32_t uEmpty;
+} DEVEFI;
+/** Pointer to the shared EFI state. */
+typedef DEVEFI *PDEVEFI;
+
+
+/**
+ * The EFI device state structure for ring-3.
+ */
+typedef struct DEVEFIR3
+{
+    /** Pointer back to the device instance. */
+    PPDMDEVINS              pDevIns;
+
+    /** The system EFI ROM data. */
+    uint8_t const          *pu8EfiRom;
+    /** The system EFI ROM data pointer to be passed to RTFileReadAllFree. */
+    uint8_t                *pu8EfiRomFree;
+    /** The size of the system EFI ROM. */
+    uint64_t                cbEfiRom;
+    /** Offset into the actual ROM within EFI FW volume. */
+    uint64_t                offEfiRom;
+    /** The name of the EFI ROM file. */
+    char                   *pszEfiRomFile;
+    /** EFI firmware physical load address. */
+    RTGCPHYS                GCPhysLoadAddress;
+} DEVEFIR3;
+/** Pointer to the ring-3 EFI state. */
+typedef DEVEFIR3 *PDEVEFIR3;
+
+
+/**
+ * The EFI device state structure for ring-0.
+ */
+typedef struct DEVEFIR0
+{
+    uint32_t uEmpty;
+} DEVEFIR0;
+/** Pointer to the ring-0 EFI state.  */
+typedef DEVEFIR0 *PDEVEFIR0;
+
+
+/**
+ * The EFI device state structure for raw-mode.
+ */
+typedef struct DEVEFIRC
+{
+    uint32_t uEmpty;
+} DEVEFIRC;
+/** Pointer to the raw-mode EFI state.  */
+typedef DEVEFIRC *PDEVEFIRC;
+
+
+/** @typedef DEVEFICC
+ * The instance data for the current context. */
+/** @typedef PDEVEFICC
+ * Pointer to the instance data for the current context. */
+#ifdef IN_RING3
+typedef  DEVEFIR3  DEVEFICC;
+typedef PDEVEFIR3 PDEVEFICC;
+#elif defined(IN_RING0)
+typedef  DEVEFIR0  DEVEFICC;
+typedef PDEVEFIR0 PDEVEFICC;
+#elif defined(IN_RC)
+typedef  DEVEFIRC  DEVEFICC;
+typedef PDEVEFIRC PDEVEFICC;
+#else
+# error "Not IN_RING3, IN_RING0 or IN_RC"
+#endif
+
+
+/*********************************************************************************************************************************
+*   Defined Constants And Macros                                                                                                 *
+*********************************************************************************************************************************/
+/** The saved state version. */
+#define EFI_SSM_VERSION                  1
+
+
+/*********************************************************************************************************************************
+*   Global Variables                                                                                                             *
+*********************************************************************************************************************************/
+#ifdef IN_RING3
+
+# ifdef VBOX_WITH_EFI_IN_DD2
+/** Special file name value for indicating the 32-bit built-in EFI firmware. */
+static const char g_szEfiBuiltinAArch32[] = "VBoxEFIAArch32.fd";
+/** Special file name value for indicating the 64-bit built-in EFI firmware. */
+static const char g_szEfiBuiltinAArch64[] = "VBoxEFIAArch64.fd";
+# endif
+#endif /* IN_RING3 */
+
+
+#ifdef IN_RING3
+
+/**
+ * Destruct a device instance.
+ *
+ * Most VM resources are freed by the VM. This callback is provided so that any non-VM
+ * resources can be freed correctly.
+ *
+ * @param   pDevIns     The device instance data.
+ */
+static DECLCALLBACK(int) efiR3Destruct(PPDMDEVINS pDevIns)
+{
+    PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
+    PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
+
+    if (pThisCC->pu8EfiRomFree)
+    {
+        RTFileReadAllFree(pThisCC->pu8EfiRomFree, (size_t)pThisCC->cbEfiRom + pThisCC->offEfiRom);
+        pThisCC->pu8EfiRomFree = NULL;
+    }
+
+    /*
+     * Free MM heap pointers (waste of time, but whatever).
+     */
+    if (pThisCC->pszEfiRomFile)
+    {
+        PDMDevHlpMMHeapFree(pDevIns, pThisCC->pszEfiRomFile);
+        pThisCC->pszEfiRomFile = NULL;
+    }
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Load EFI ROM file into the memory.
+ *
+ * @returns VBox status code.
+ * @param   pDevIns     The device instance.
+ * @param   pThisCC     The device state for the current context.
+ * @param   pCfg        Configuration node handle for the device.
+ */
+static int efiR3LoadRom(PPDMDEVINS pDevIns, PDEVEFIR3 pThisCC, PCFGMNODE pCfg)
+{
+    RT_NOREF(pCfg);
+
+    /*
+     * Read the entire firmware volume into memory.
+     */
+    int     rc;
+#ifdef VBOX_WITH_EFI_IN_DD2
+    if (RTStrCmp(pThisCC->pszEfiRomFile, g_szEfiBuiltinAArch32) == 0)
+    {
+        pThisCC->pu8EfiRomFree = NULL;
+        pThisCC->pu8EfiRom = g_abEfiFirmwareAArch32;
+        pThisCC->cbEfiRom  = g_cbEfiFirmwareAArch32;
+    }
+    else if (RTStrCmp(pThisCC->pszEfiRomFile, g_szEfiBuiltinAArch64) == 0)
+    {
+        pThisCC->pu8EfiRomFree = NULL;
+        pThisCC->pu8EfiRom = g_abEfiFirmwareAArch64;
+        pThisCC->cbEfiRom  = g_cbEfiFirmwareAArch64;
+    }
+    else
+#endif
+    {
+        void   *pvFile;
+        size_t  cbFile;
+        rc = RTFileReadAllEx(pThisCC->pszEfiRomFile,
+                             0 /*off*/,
+                             RTFOFF_MAX /*cbMax*/,
+                             RTFILE_RDALL_O_DENY_WRITE,
+                             &pvFile,
+                             &cbFile);
+        if (RT_FAILURE(rc))
+            return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
+                                       N_("Loading the EFI firmware volume '%s' failed with rc=%Rrc"),
+                                       pThisCC->pszEfiRomFile, rc);
+        pThisCC->pu8EfiRomFree = (uint8_t *)pvFile;
+        pThisCC->pu8EfiRom = (uint8_t *)pvFile;
+        pThisCC->cbEfiRom  = cbFile;
+    }
+
+    rc = PDMDevHlpROMRegister(pDevIns, pThisCC->GCPhysLoadAddress, pThisCC->cbEfiRom, pThisCC->pu8EfiRom, pThisCC->cbEfiRom,
+                              PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "EFI Firmware Volume");
+    AssertRCReturn(rc, rc);
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @interface_method_impl{PDMDEVREG,pfnConstruct}
+ */
+static DECLCALLBACK(int)  efiR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
+{
+    PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
+    PDEVEFIR3       pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
+    PCPDMDEVHLPR3   pHlp    = pDevIns->pHlpR3;
+    int             rc;
+
+    RT_NOREF(iInstance);
+    Assert(iInstance == 0);
+
+    /*
+     * Initalize the basic variables so that the destructor always works.
+     */
+    pThisCC->pDevIns = pDevIns;
+
+    /*
+     * Validate and read the configuration.
+     */
+    PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "EfiRom|GCPhysLoadAddress", "");
+
+    rc = pHlp->pfnCFGMQueryU64(pCfg, "GCPhysLoadAddress", &pThisCC->GCPhysLoadAddress);
+    if (RT_FAILURE(rc))
+        return PDMDEV_SET_ERROR(pDevIns, rc,
+                                N_("Configuration error: Querying \"GCPhysLoadAddress\" as integer failed"));
+
+    /*
+     * Get the system EFI ROM file name.
+     */
+#ifdef VBOX_WITH_EFI_IN_DD2
+    rc = pHlp->pfnCFGMQueryStringAllocDef(pCfg, "EfiRom", &pThisCC->pszEfiRomFile, g_szEfiBuiltinAArch32);
+    if (RT_FAILURE(rc))
+#else
+    rc = pHlp->pfnCFGMQueryStringAlloc(pCfg, "EfiRom", &pThisCC->pszEfiRomFile);
+    if (rc == VERR_CFGM_VALUE_NOT_FOUND)
+    {
+        pThisCC->pszEfiRomFile = (char *)PDMDevHlpMMHeapAlloc(pDevIns, RTPATH_MAX);
+        AssertReturn(pThisCC->pszEfiRomFile, VERR_NO_MEMORY);
+        rc = RTPathAppPrivateArchTop(pThisCC->pszEfiRomFile, RTPATH_MAX);
+        AssertRCReturn(rc, rc);
+        rc = RTPathAppend(pThisCC->pszEfiRomFile, RTPATH_MAX, "VBoxEFIAArch32.fd");
+        AssertRCReturn(rc, rc);
+    }
+    else if (RT_FAILURE(rc))
+#endif
+        return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
+                                   N_("Configuration error: Querying \"EfiRom\" as a string failed"));
+
+    /*
+     * Load firmware volume and thunk ROM.
+     */
+    rc = efiR3LoadRom(pDevIns, pThisCC, pCfg);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    return VINF_SUCCESS;
+}
+
+#else  /* IN_RING3 */
+
+
+/**
+ * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
+ */
+static DECLCALLBACK(int)  efiRZConstruct(PPDMDEVINS pDevIns)
+{
+    PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
+    RT_NOREF(pDevIns);
+
+    return VINF_SUCCESS;
+}
+
+
+#endif /* IN_RING3 */
+
+/**
+ * The device registration structure.
+ */
+const PDMDEVREG g_DeviceEfiArmV8 =
+{
+    /* .u32Version = */             PDM_DEVREG_VERSION,
+    /* .uReserved0 = */             0,
+    /* .szName = */                 "efi-armv8",
+    /* .fFlags = */                 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
+    /* .fClass = */                 PDM_DEVREG_CLASS_ARCH_BIOS,
+    /* .cMaxInstances = */          1,
+    /* .uSharedVersion = */         42,
+    /* .cbInstanceShared = */       sizeof(DEVEFI),
+    /* .cbInstanceCC = */           sizeof(DEVEFICC),
+    /* .cbInstanceRC = */           sizeof(DEVEFIRC),
+    /* .cMaxPciDevices = */         0,
+    /* .cMaxMsixVectors = */        0,
+    /* .pszDescription = */         "Extensible Firmware Interface Device for ARMv8 platforms.\n",
+#if defined(IN_RING3)
+    /* .pszRCMod = */               "VBoxDDRC.rc",
+    /* .pszR0Mod = */               "VBoxDDR0.r0",
+    /* .pfnConstruct = */           efiR3Construct,
+    /* .pfnDestruct = */            efiR3Destruct,
+    /* .pfnRelocate = */            NULL,
+    /* .pfnMemSetup = */            NULL,
+    /* .pfnPowerOn = */             NULL,
+    /* .pfnReset = */               NULL,
+    /* .pfnSuspend = */             NULL,
+    /* .pfnResume = */              NULL,
+    /* .pfnAttach = */              NULL,
+    /* .pfnDetach = */              NULL,
+    /* .pfnQueryInterface = */      NULL,
+    /* .pfnInitComplete = */        NULL,
+    /* .pfnPowerOff = */            NULL,
+    /* .pfnSoftReset = */           NULL,
+    /* .pfnReserved0 = */           NULL,
+    /* .pfnReserved1 = */           NULL,
+    /* .pfnReserved2 = */           NULL,
+    /* .pfnReserved3 = */           NULL,
+    /* .pfnReserved4 = */           NULL,
+    /* .pfnReserved5 = */           NULL,
+    /* .pfnReserved6 = */           NULL,
+    /* .pfnReserved7 = */           NULL,
+#elif defined(IN_RING0)
+    /* .pfnEarlyConstruct = */      NULL,
+    /* .pfnConstruct = */           efiRZConstruct,
+    /* .pfnDestruct = */            NULL,
+    /* .pfnFinalDestruct = */       NULL,
+    /* .pfnRequest = */             NULL,
+    /* .pfnReserved0 = */           NULL,
+    /* .pfnReserved1 = */           NULL,
+    /* .pfnReserved2 = */           NULL,
+    /* .pfnReserved3 = */           NULL,
+    /* .pfnReserved4 = */           NULL,
+    /* .pfnReserved5 = */           NULL,
+    /* .pfnReserved6 = */           NULL,
+    /* .pfnReserved7 = */           NULL,
+#elif defined(IN_RC)
+    /* .pfnConstruct = */           efiRZConstruct,
+    /* .pfnReserved0 = */           NULL,
+    /* .pfnReserved1 = */           NULL,
+    /* .pfnReserved2 = */           NULL,
+    /* .pfnReserved3 = */           NULL,
+    /* .pfnReserved4 = */           NULL,
+    /* .pfnReserved5 = */           NULL,
+    /* .pfnReserved6 = */           NULL,
+    /* .pfnReserved7 = */           NULL,
+#else
+# error "Not in IN_RING3, IN_RING0 or IN_RC!"
+#endif
+    /* .u32VersionEnd = */          PDM_DEVREG_VERSION
+};
Index: trunk/src/VBox/Devices/EFI/DevEFI-binaries.S
===================================================================
--- trunk/src/VBox/Devices/EFI/DevEFI-binaries.S	(revision 99926)
+++ trunk/src/VBox/Devices/EFI/DevEFI-binaries.S	(revision 99927)
@@ -71,2 +71,45 @@
 .type g_cbEfiFirmware64 object
 #endif
+
+#ifdef VBOX_VMM_TARGET_ARMV8
+;
+; The ARMv8 bits
+;
+
+; 32-bit firmware:
+.p2align 6
+.globl NAME(g_abEfiFirmwareAArch32)
+NAME(g_abEfiFirmwareAArch32):
+        .incbin "VBoxEFIAArch32.fd"
+end_aarch32_firmware:
+
+.p2align 2
+.globl NAME(g_cbEfiFirmwareAArch32)
+NAME(g_cbEfiFirmwareAArch32):
+        .long end_aarch32_firmware - NAME(g_abEfiFirmwareAArch32)
+
+
+; 64-bit firmware:
+.p2align 6
+.globl NAME(g_abEfiFirmwareAArch64)
+NAME(g_abEfiFirmwareAArch64):
+        .incbin "VBoxEFIAArch64.fd"
+end_aarch64_firmware:
+
+.p2align 2
+.globl NAME(g_cbEfiFirmwareAArch64)
+NAME(g_cbEfiFirmwareAArch64):
+        .long  end_aarch64_firmware - NAME(g_abEfiFirmwareAArch64)
+
+# ifdef ASM_FORMAT_ELF
+.size g_abEfiFirmwareAArch32 end_aarch32_firmware - NAME(g_abEfiFirmwareAArch32)
+.type g_abEfiFirmwareAArch32 object
+.size g_cbEfiFirmwareAArch32 4
+.type g_cbEfiFirmwareAArch32 object
+
+.size g_abEfiFirmwareAArch64 end_aarch64_firmware - NAME(g_abEfiFirmwareAArch64)
+.type g_abEfiFirmwareAArch64 object
+.size g_cbEfiFirmwareAArch64 4
+.type g_cbEfiFirmwareAArch64 object
+# endif
+#endif
Index: trunk/src/VBox/Devices/Makefile.kmk
===================================================================
--- trunk/src/VBox/Devices/Makefile.kmk	(revision 99926)
+++ trunk/src/VBox/Devices/Makefile.kmk	(revision 99927)
@@ -926,4 +926,5 @@
   VBoxDD_SOURCES    += \
   	Bus/DevPciGenericEcam.cpp \
+  	EFI/DevEFI-armv8.cpp \
   	Gpio/DevPL061.cpp \
   	Misc/DevFlashCFI.cpp \
@@ -1212,5 +1213,6 @@
  VBoxDD2_DEFS            = \
  	IN_VBOXDD2 \
- 	$(if $(VBOX_WITH_PXE_ROM),VBOX_WITH_PXE_ROM,)
+ 	$(if $(VBOX_WITH_PXE_ROM),VBOX_WITH_PXE_ROM,) \
+ 	$(if $(VBOX_WITH_VIRT_ARMV8),VBOX_VMM_TARGET_ARMV8,)
  VBoxDD2_INCS           := \
  	build \
@@ -1243,4 +1245,9 @@
   	$(PATH_STAGE)/$(INST_BIN)VBoxEFI32.fd \
   	$(PATH_STAGE)/$(INST_BIN)VBoxEFI64.fd
+  ifdef VBOX_WITH_VIRT_ARMV8
+   EFI/DevEFI-binaries.S_DEPS   += \
+   	$(PATH_STAGE)/$(INST_BIN)VBoxEFIAArch32.fd \
+   	$(PATH_STAGE)/$(INST_BIN)VBoxEFIAArch64.fd
+  endif
  endif
 
Index: trunk/src/VBox/Devices/build/VBoxDD.cpp
===================================================================
--- trunk/src/VBox/Devices/build/VBoxDD.cpp	(revision 99926)
+++ trunk/src/VBox/Devices/build/VBoxDD.cpp	(revision 99927)
@@ -249,4 +249,8 @@
 #endif
 #ifdef VBOX_VMM_TARGET_ARMV8
+    rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceEfiArmV8);
+    if (RT_FAILURE(rc))
+        return rc;
+
     rc = pCallbacks->pfnRegister(pCallbacks, &g_DevicePl011);
     if (RT_FAILURE(rc))
Index: trunk/src/VBox/Devices/build/VBoxDD.h
===================================================================
--- trunk/src/VBox/Devices/build/VBoxDD.h	(revision 99926)
+++ trunk/src/VBox/Devices/build/VBoxDD.h	(revision 99927)
@@ -230,4 +230,5 @@
 
 #ifdef VBOX_VMM_TARGET_ARMV8
+extern const PDMDEVREG g_DeviceEfiArmV8;
 extern const PDMDEVREG g_DevicePl011;
 extern const PDMDEVREG g_DevicePl031Rtc;
Index: trunk/src/VBox/Devices/build/VBoxDD2.h
===================================================================
--- trunk/src/VBox/Devices/build/VBoxDD2.h	(revision 99926)
+++ trunk/src/VBox/Devices/build/VBoxDD2.h	(revision 99927)
@@ -60,4 +60,10 @@
 extern DECLEXPORT(const unsigned char)  g_abEfiFirmware64[];
 extern DECLEXPORT(const unsigned)       g_cbEfiFirmware64;
+#  ifdef VBOX_VMM_TARGET_ARMV8
+extern DECLEXPORT(const unsigned char)  g_abEfiFirmwareAArch32[];
+extern DECLEXPORT(const unsigned)       g_cbEfiFirmwareAArch32;
+extern DECLEXPORT(const unsigned char)  g_abEfiFirmwareAArch64[];
+extern DECLEXPORT(const unsigned)       g_cbEfiFirmwareAArch64;
+#  endif
 # endif
 #else  /* !IN_VBOXDD2 */
@@ -83,4 +89,10 @@
 extern DECLIMPORT(const unsigned char)  g_abEfiFirmware64[];
 extern DECLIMPORT(const unsigned)       g_cbEfiFirmware64;
+#  ifdef VBOX_VMM_TARGET_ARMV8
+extern DECLIMPORT(const unsigned char)  g_abEfiFirmwareAArch32[];
+extern DECLIMPORT(const unsigned)       g_cbEfiFirmwareAArch32;
+extern DECLIMPORT(const unsigned char)  g_abEfiFirmwareAArch64[];
+extern DECLIMPORT(const unsigned)       g_cbEfiFirmwareAArch64;
+#  endif
 # endif
 #endif /* !IN_VBOXDD2 */
Index: trunk/src/VBox/Main/src-client/ConsoleImplConfigArmV8.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/ConsoleImplConfigArmV8.cpp	(revision 99926)
+++ trunk/src/VBox/Main/src-client/ConsoleImplConfigArmV8.cpp	(revision 99927)
@@ -178,8 +178,4 @@
 
         PCFGMNODE pMemRegion = NULL;
-        InsertConfigNode(pMem, "Flash", &pMemRegion);
-        InsertConfigInteger(pMemRegion, "GCPhysStart", 0);
-        InsertConfigInteger(pMemRegion, "Size", 64 * _1M);
-
         InsertConfigNode(pMem, "Conventional", &pMemRegion);
         InsertConfigInteger(pMemRegion, "GCPhysStart", 0x40000000);
@@ -285,4 +281,10 @@
 
         InsertConfigNode(pRoot, "Devices", &pDevices);
+
+        InsertConfigNode(pDevices, "efi-armv8",             &pDev);
+        InsertConfigNode(pDev,     "0",                     &pInst);
+        InsertConfigNode(pInst,    "Config",                &pCfg);
+        InsertConfigInteger(pCfg,  "GCPhysLoadAddress",     0);
+        InsertConfigString(pCfg,   "EfiRom",                "VBoxEFIAArch64.fd");
 
         InsertConfigNode(pDevices, "gic",                   &pDev);
