summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/VBoxPkg
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
commitf215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch)
tree6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Devices/EFI/Firmware/VBoxPkg
parentInitial commit. (diff)
downloadvirtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz
virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/VBoxPkg')
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/ComponentName.c172
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/DriverBinding.c666
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/E1kHwIo.c182
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/E1kNet.h350
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/E1kNet.inf60
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/E1kNetHw.h105
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/EntryPoint.c45
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/Events.c82
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpGetStatus.c160
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpInitialize.c321
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpMcastIpToMac.c103
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpReceive.c159
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpReceiveFilters.c100
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpSharedHelpers.c281
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpShutdown.c74
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpStart.c59
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpStop.c60
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpTransmit.c170
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpUnsupported.c155
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Include/DevEFI.h38
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Include/Guid/VBoxFsBlessedFileInfo.h58
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Include/IndustryStandard/VBoxFatImage.h64
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Include/VBoxDebugLib.h50
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Include/VBoxMemLayout.h44
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Include/VBoxPkg.h69
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugAgentLib/VBoxDebugAgentLib.c97
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugAgentLib/VBoxDebugAgentLib.inf54
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugLib/VBoxDebugLib.c227
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugLib/VBoxDebugLib.inf85
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugLib/VBoxPrintChar.c56
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugLib/VBoxPrintGuid.c73
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugLib/VBoxPrintHex.c110
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugLib/VBoxPrintHexDump.c111
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugLib/VBoxPrintString.c60
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxOemHookStatusCodeLib/VBoxOemHookStatusCodeLib.c218
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxOemHookStatusCodeLib/VBoxOemHookStatusCodeLib.inf80
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxPeCoffLib/BasePeCoff.c1647
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxPeCoffLib/BasePeCoffLibInternals.h171
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxPeCoffLib/PeCoffLoaderEx.c128
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxPeCoffLib/VBoxPeCoffLib.inf84
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/Logo.bmpbin0 -> 37878 bytes
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/Logo.c186
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/Logo.idf10
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/Logo.inf68
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/Logo.uni16
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/LogoDxe.inf95
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/LogoDxe.uni16
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/LogoDxeExtra.uni14
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/LogoExtra.uni14
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/Makefile.kup0
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxApfsJmpStartDxe/VBoxApfsJmpStartDxe.c521
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxApfsJmpStartDxe/VBoxApfsJmpStartDxe.inf89
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxAppleSim/Console.c106
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxAppleSim/ConsoleControl.h158
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxAppleSim/Cpu.c146
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxAppleSim/DataHub.c215
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxAppleSim/DataHub.h178
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxAppleSim/VBoxAppleSim.c352
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxAppleSim/VBoxAppleSim.inf78
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/ReadMe.txt5
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/VBoxFswParam.h89
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/VBoxHfs.inf95
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/VBoxIso9660.inf95
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_base.h192
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_core.c961
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_core.h554
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_efi.c1142
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_efi.h133
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_efi_base.h115
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_efi_lib.c179
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_hfs.c1451
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_hfs.h177
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_iso9660.c679
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_iso9660.h235
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_lib.c564
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_strfunc.h491
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/test/Makefile32
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/test/README2
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/test/fsw_posix.c483
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/test/fsw_posix.h120
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/test/fsw_posix_base.h90
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/test/lslr.c140
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/test/lsroot.c79
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/BootService.c41
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/README3
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/RunTime.c41
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/VBoxInterceptor.c129
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/VBoxInterceptor.h152
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/VBoxInterceptorDxe.inf86
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/boot_service_table.h103
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/interceptor.h70
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/print_types.h89
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/runtime_service_table.h69
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMimicryDxe/README4
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMimicryDxe/VBoxMimicry.c155
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMimicryDxe/VBoxMimicry.h75
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMimicryDxe/VBoxMimicryDxe.inf83
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMimicryDxe/mimic_tbl.h39
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMisc/Makefile66
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMisc/Readme.txt11
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMisc/efi-app/Readme.txt39
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxPkg.dec91
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxSysTables/LegacyBiosMpTable.h319
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxSysTables/TableConversion.c380
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxSysTables/VBoxSysTables.c178
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxSysTables/VBoxSysTables.inf83
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/ComponentName.c247
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/DriverSupportedEfiVersion.c58
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/Edid.c676
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVga.c1171
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVga.h473
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaDxe.inf133
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaGraphicsOutput.c544
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaI2c.c469
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaI2c.h106
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaUgaDraw.c417
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaMiniPortDxe/VBoxVgaFont-8x14.h243
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaMiniPortDxe/VBoxVgaFont-8x16.h275
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaMiniPortDxe/VBoxVgaFont-8x8.h275
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaMiniPortDxe/VBoxVgaFonts.h13
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaMiniPortDxe/VBoxVgaMiniPortDxe.c657
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaMiniPortDxe/VBoxVgaMiniPortDxe.inf70
122 files changed, 25326 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/ComponentName.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/ComponentName.c
new file mode 100644
index 00000000..8a716487
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/ComponentName.c
@@ -0,0 +1,172 @@
+/** @file
+
+ Component Name code for the virtio-net driver.
+
+ Copyright (c) 2021, Oracle and/or its affiliates.
+ Copyright (C) 2013, Red Hat, Inc.
+ Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/UefiLib.h>
+
+#include "E1kNet.h"
+
+STATIC
+EFI_UNICODE_STRING_TABLE mE1kNetDriverNameTable[] = {
+ { "eng;en", L"E1000 network interface card Driver" },
+ { NULL, NULL }
+};
+
+STATIC
+EFI_UNICODE_STRING_TABLE mE1kNetControllerNameTable[] = {
+ { "eng;en", L"E1000 network interface card Driver" },
+ { NULL, NULL }
+};
+
+/**
+ Retrieves a Unicode string that is the user-readable name of the EFI Driver.
+
+ @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param Language A pointer to a three-character ISO 639-2 language
+ identifier. This is the language of the driver name that
+ that the caller is requesting, and it must match one of
+ the languages specified in SupportedLanguages. The number
+ of languages supported by a driver is up to the driver
+ writer.
+ @param DriverName A pointer to the Unicode string to return. This Unicode
+ string is the name of the driver specified by This in the
+ language specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+
+STATIC
+EFI_STATUS
+EFIAPI
+E1kNetGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return (Language == NULL || DriverName == NULL) ?
+ EFI_INVALID_PARAMETER :
+ LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mE1kNetDriverNameTable,
+ DriverName,
+ (BOOLEAN) (This == &gE1kNetComponentName) // Iso639Language
+ );
+}
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by an EFI Driver.
+
+ @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL
+ instance.
+ @param ControllerHandle The handle of a controller that the driver specified
+ by This is managing. This handle specifies the
+ controller whose name is to be returned.
+ @param ChildHandle The handle of the child controller to retrieve the
+ name of. This is an optional parameter that may be
+ NULL. It will be NULL for device drivers. It will
+ also be NULL for a bus drivers that wish to retrieve
+ the name of the bus controller. It will not be NULL
+ for a bus driver that wishes to retrieve the name of
+ a child controller.
+ @param Language A pointer to a three character ISO 639-2 language
+ identifier. This is the language of the controller
+ name that the caller is requesting, and it must
+ match one of the languages specified in
+ SupportedLanguages. The number of languages
+ supported by a driver is up to the driver writer.
+ @param ControllerName A pointer to the Unicode string to return. This
+ Unicode string is the name of the controller
+ specified by ControllerHandle and ChildHandle in the
+ language specified by Language, from the point of
+ view of the driver specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user-readable name
+ in the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+
+STATIC
+EFI_STATUS
+EFIAPI
+E1kNetGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+
+ if (ControllerHandle == NULL || Language == NULL || ControllerName == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // confirm that the device is managed by this driver, using the PciIo
+ // Protocol
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gE1kNetDriverBinding.DriverBindingHandle,
+ &gEfiPciIoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // we don't give different names to the bus (= parent) handle and the
+ // child (= MAC) handle
+ //
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mE1kNetControllerNameTable,
+ ControllerName,
+ (BOOLEAN) (This == &gE1kNetComponentName) // Iso639Language
+ );
+}
+
+EFI_COMPONENT_NAME_PROTOCOL gE1kNetComponentName = {
+ &E1kNetGetDriverName,
+ &E1kNetGetControllerName,
+ "eng" // SupportedLanguages, ISO 639-2 language codes
+};
+
+EFI_COMPONENT_NAME2_PROTOCOL gE1kNetComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) &E1kNetGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &E1kNetGetControllerName,
+ "en" // SupportedLanguages, RFC 4646 language codes
+};
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/DriverBinding.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/DriverBinding.c
new file mode 100644
index 00000000..7ab92e6b
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/DriverBinding.c
@@ -0,0 +1,666 @@
+/** @file
+
+ Driver Binding code and its private helpers for the virtio-net driver.
+
+ Copyright (c) 2021, Oracle and/or its affiliates.
+ Copyright (C) 2013, Red Hat, Inc.
+ Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <IndustryStandard/Pci.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include "E1kNet.h"
+
+#define RECEIVE_FILTERS_NO_MCAST ((UINT32) ( \
+ EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | \
+ EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST | \
+ EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS \
+ ))
+
+STATIC
+EFI_STATUS
+E1kNetEepromRead (
+ IN E1K_NET_DEV *Dev,
+ IN UINT8 Offset,
+ OUT UINT16 *Data
+ )
+{
+ EFI_STATUS Status;
+ UINT32 RegEerd = 0;
+
+ Status = E1kNetRegWrite32(Dev, E1K_REG_EERD, ((UINT32)Offset << 8) | E1K_REG_EERD_START);
+ if (EFI_ERROR (Status))
+ return Status;
+
+ // Wait for the read to complete
+ while ( !EFI_ERROR (Status)
+ && !(RegEerd & E1K_REG_EERD_DONE)) {
+ gBS->Stall(1);
+ Status = E1kNetRegRead32(Dev, E1K_REG_EERD, &RegEerd);
+ }
+
+ if (!EFI_ERROR(Status))
+ *Data = E1K_REG_EERD_DATA_GET(RegEerd);
+
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+E1kNetMacAddrRead (
+ IN E1K_NET_DEV *Dev
+ )
+{
+ EFI_STATUS Status;
+ UINT8 i;
+
+ for (i = 0; i < 3; i++)
+ {
+ UINT16 MacAddr;
+ Status = E1kNetEepromRead (Dev, i, &MacAddr);
+ if (EFI_ERROR (Status))
+ return Status;
+
+ Dev->Snm.CurrentAddress.Addr[i * 2] = MacAddr & 0xff;
+ Dev->Snm.CurrentAddress.Addr[i * 2 + 1] = (MacAddr >> 8) & 0xff;
+ }
+
+ return Status;
+}
+
+/**
+ Set up the Simple Network Protocol fields, the Simple Network Mode fields,
+ and the Exit Boot Services Event of the virtio-net driver instance.
+
+ This function may only be called by E1kNetDriverBindingStart().
+
+ @param[in,out] Dev The E1K_NET_DEV driver instance being created for the
+ e1000 device.
+
+ @return Status codes from the CreateEvent().
+ @retval EFI_SUCCESS Configuration successful.
+*/
+STATIC
+EFI_STATUS
+EFIAPI
+E1kNetSnpPopulate (
+ IN OUT E1K_NET_DEV *Dev
+ )
+{
+ UINT32 RegSts;
+ EFI_STATUS Status;
+
+ //
+ // We set up a function here that is asynchronously callable by an
+ // external application to check if there are any packets available for
+ // reception. The least urgent task priority level we can specify for such a
+ // "software interrupt" is TPL_CALLBACK.
+ //
+ // TPL_CALLBACK is also the maximum TPL an SNP implementation is allowed to
+ // run at (see 6.1 Event, Timer, and Task Priority Services in the UEFI
+ // Specification 2.3.1+errC).
+ //
+ // Since we raise our TPL to TPL_CALLBACK in every single function that
+ // accesses the device, and the external application also queues its interest
+ // for received packets at the same TPL_CALLBACK, in effect the
+ // E1kNetIsPacketAvailable() function will never interrupt any
+ // device-accessing driver function, it will be scheduled in isolation.
+ //
+ // TPL_CALLBACK (which basically this entire driver runs at) is allowed
+ // for "[l]ong term operations (such as file system operations and disk
+ // I/O)". Because none of our functions block, we'd satisfy an even stronger
+ // requirement.
+ //
+ Status = gBS->CreateEvent (EVT_NOTIFY_WAIT, TPL_CALLBACK,
+ &E1kNetIsPacketAvailable, Dev, &Dev->Snp.WaitForPacket);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Dev->Snp.Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;
+ Dev->Snp.Start = &E1kNetStart;
+ Dev->Snp.Stop = &E1kNetStop;
+ Dev->Snp.Initialize = &E1kNetInitialize;
+ Dev->Snp.Reset = &E1kNetReset;
+ Dev->Snp.Shutdown = &E1kNetShutdown;
+ Dev->Snp.ReceiveFilters = &E1kNetReceiveFilters;
+ Dev->Snp.StationAddress = &E1kNetStationAddress;
+ Dev->Snp.Statistics = &E1kNetStatistics;
+ Dev->Snp.MCastIpToMac = &E1kNetMcastIpToMac;
+ Dev->Snp.NvData = &E1kNetNvData;
+ Dev->Snp.GetStatus = &E1kNetGetStatus;
+ Dev->Snp.Transmit = &E1kNetTransmit;
+ Dev->Snp.Receive = &E1kNetReceive;
+ Dev->Snp.Mode = &Dev->Snm;
+
+ Dev->Snm.State = EfiSimpleNetworkStopped;
+ Dev->Snm.HwAddressSize = sizeof (E1K_NET_MAC);
+ Dev->Snm.MediaHeaderSize = sizeof (E1K_NET_MAC) + // dst MAC
+ sizeof (E1K_NET_MAC) + // src MAC
+ 2; // Ethertype
+ Dev->Snm.MaxPacketSize = 1500;
+ Dev->Snm.NvRamSize = 0;
+ Dev->Snm.NvRamAccessSize = 0;
+ Dev->Snm.ReceiveFilterMask = RECEIVE_FILTERS_NO_MCAST;
+ Dev->Snm.ReceiveFilterSetting = RECEIVE_FILTERS_NO_MCAST;
+ Dev->Snm.MaxMCastFilterCount = 0;
+ Dev->Snm.MCastFilterCount = 0;
+ Dev->Snm.IfType = 1; // ethernet
+ Dev->Snm.MacAddressChangeable = FALSE;
+ Dev->Snm.MultipleTxSupported = TRUE;
+
+ ASSERT (sizeof (E1K_NET_MAC) <= sizeof (EFI_MAC_ADDRESS));
+
+ Dev->Snm.MediaPresentSupported = TRUE;
+ Status = E1kNetRegRead32(Dev, E1K_REG_STATUS, &RegSts);
+ if (EFI_ERROR (Status)) {
+ goto CloseWaitForPacket;
+ }
+
+ Dev->Snm.MediaPresent = (BOOLEAN)((RegSts & E1K_REG_STATUS_LU) != 0);
+
+ Status = E1kNetMacAddrRead(Dev);
+ CopyMem (&Dev->Snm.PermanentAddress, &Dev->Snm.CurrentAddress,
+ sizeof (E1K_NET_MAC));
+ SetMem (&Dev->Snm.BroadcastAddress, sizeof (E1K_NET_MAC), 0xFF);
+
+ //
+ // E1kNetExitBoot() is queued by ExitBootServices(); its purpose is to
+ // cancel any pending requests. The TPL_CALLBACK reasoning is
+ // identical to the one above. There's one difference: this kind of
+ // event is "globally visible", which means it can be signalled as soon as
+ // we create it. We haven't raised our TPL here, hence E1kNetExitBoot()
+ // could be entered immediately. E1kNetExitBoot() checks Dev->Snm.State,
+ // so we're safe.
+ //
+ Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK,
+ &E1kNetExitBoot, Dev, &Dev->ExitBoot);
+ if (EFI_ERROR (Status)) {
+ goto CloseWaitForPacket;
+ }
+
+ return EFI_SUCCESS;
+
+CloseWaitForPacket:
+ gBS->CloseEvent (Dev->Snp.WaitForPacket);
+ return Status;
+}
+
+
+/**
+ Release any resources allocated by E1kNetSnpPopulate().
+
+ This function may only be called by E1kNetDriverBindingStart(), when
+ rolling back a partial, failed driver instance creation, and by
+ E1kNetDriverBindingStop(), when disconnecting a virtio-net device from the
+ driver.
+
+ @param[in,out] Dev The E1K_NET_DEV driver instance being destroyed.
+*/
+STATIC
+VOID
+EFIAPI
+E1kNetSnpEvacuate (
+ IN OUT E1K_NET_DEV *Dev
+ )
+{
+ //
+ // This function runs either at TPL_CALLBACK already (from
+ // E1kNetDriverBindingStop()), or it is part of a teardown following
+ // a partial, failed construction in E1kNetDriverBindingStart(), when
+ // WaitForPacket was never accessible to the world.
+ //
+ gBS->CloseEvent (Dev->ExitBoot);
+ gBS->CloseEvent (Dev->Snp.WaitForPacket);
+}
+
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is
+ provided, it further tests to see if this driver supports creating a handle
+ for the specified child device.
+
+ This function checks to see if the driver specified by This supports the
+ device specified by ControllerHandle. Drivers will typically use the device
+ path attached to ControllerHandle and/or the services from the bus I/O
+ abstraction attached to ControllerHandle to determine if the driver supports
+ ControllerHandle. This function may be called many times during platform
+ initialization. In order to reduce boot times, the tests performed by this
+ function must be very small, and take as little time as possible to execute.
+ This function must not change the state of any hardware devices, and this
+ function must be aware that the device specified by ControllerHandle may
+ already be managed by the same driver or a different driver. This function
+ must match its calls to AllocatePages() with FreePages(), AllocatePool() with
+ FreePool(), and OpenProtocol() with CloseProtocol(). Because ControllerHandle
+ may have been previously started by the same driver, if a protocol is already
+ in the opened state, then it must not be closed with CloseProtocol(). This is
+ required to guarantee the state of ControllerHandle is not modified by this
+ function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
+ instance.
+ @param[in] ControllerHandle The handle of the controller to test. This
+ handle must support a protocol interface
+ that supplies an I/O abstraction to the
+ driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a
+ device path. This parameter is ignored by
+ device drivers, and is optional for bus
+ drivers. For bus drivers, if this parameter
+ is not NULL, then the bus driver must
+ determine if the bus controller specified by
+ ControllerHandle and the child controller
+ specified by RemainingDevicePath are both
+ supported by this bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the
+ driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed
+ by the driver specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed
+ by a different driver or an application that
+ requires exclusive access. Currently not
+ implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the
+ driver specified by This.
+**/
+
+STATIC
+EFI_STATUS
+EFIAPI
+E1kNetDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 Pci;
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **)&PciIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (Pci) / sizeof (UINT32),
+ &Pci
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (Pci.Hdr.VendorId == INTEL_PCI_VENDOR_ID &&
+ (Pci.Hdr.DeviceId == INTEL_82540EM_PCI_DEVICE_ID ||
+ Pci.Hdr.DeviceId == INTEL_82543GC_PCI_DEVICE_ID ||
+ Pci.Hdr.DeviceId == INTEL_82545EM_PCI_DEVICE_ID)) {
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_UNSUPPORTED;
+ }
+
+Done:
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ return Status;
+}
+
+
+/**
+ Starts a device controller or a bus controller.
+
+ The Start() function is designed to be invoked from the EFI boot service
+ ConnectController(). As a result, much of the error checking on the
+ parameters to Start() has been moved into this common boot service. It is
+ legal to call Start() from other locations, but the following calling
+ restrictions must be followed, or the system behavior will not be
+ deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE.
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a
+ naturally aligned EFI_DEVICE_PATH_PROTOCOL.
+ 3. Prior to calling Start(), the Supported() function for the driver
+ specified by This must have been called with the same calling parameters,
+ and Supported() must have returned EFI_SUCCESS.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
+ instance.
+ @param[in] ControllerHandle The handle of the controller to start. This
+ handle must support a protocol interface
+ that supplies an I/O abstraction to the
+ driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a
+ device path. This parameter is ignored by
+ device drivers, and is optional for bus
+ drivers. For a bus driver, if this parameter
+ is NULL, then handles for all the children
+ of Controller are created by this driver.
+ If this parameter is not NULL and the first
+ Device Path Node is not the End of Device
+ Path Node, then only the handle for the
+ child device specified by the first Device
+ Path Node of RemainingDevicePath is created
+ by this driver. If the first Device Path
+ Node of RemainingDevicePath is the End of
+ Device Path Node, no child handle is created
+ by this driver.
+
+ @retval EFI_SUCCESS The device was started.
+ @retval EFI_DEVICE_ERROR The device could not be started due to a
+ device error.Currently not implemented.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+ @retval Others The driver failed to start the device.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+E1kNetDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ E1K_NET_DEV *Dev;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ MAC_ADDR_DEVICE_PATH MacNode;
+
+ DEBUG((DEBUG_INFO, "E1kNetControllerStart:\n"));
+
+ Dev = AllocateZeroPool (sizeof (*Dev));
+ if (Dev == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Dev->Signature = E1K_NET_DEV_SIGNATURE;
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **)&Dev->PciIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ goto FreePool;
+ }
+
+ Status = Dev->PciIo->Attributes (
+ Dev->PciIo,
+ EfiPciIoAttributeOperationGet,
+ 0,
+ &Dev->OriginalPciAttributes
+ );
+ if (EFI_ERROR (Status)) {
+ goto CloseProtocol;
+ }
+
+ //
+ // Enable I/O Space & Bus-Mastering
+ //
+ Status = Dev->PciIo->Attributes (
+ Dev->PciIo,
+ EfiPciIoAttributeOperationEnable,
+ (EFI_PCI_IO_ATTRIBUTE_IO |
+ EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto CloseProtocol;
+ }
+
+ //
+ // Signal device supports 64-bit DMA addresses
+ //
+ Status = Dev->PciIo->Attributes (
+ Dev->PciIo,
+ EfiPciIoAttributeOperationEnable,
+ EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Warn user that device will only be using 32-bit DMA addresses.
+ //
+ // Note that this does not prevent the device/driver from working
+ // and therefore we only warn and continue as usual.
+ //
+ DEBUG ((
+ DEBUG_WARN,
+ "%a: failed to enable 64-bit DMA addresses\n",
+ __FUNCTION__
+ ));
+ }
+
+ DEBUG((DEBUG_INFO, "E1kNetControllerStart: Resetting NIC\n"));
+ Status = E1kNetDevReset (Dev);
+ if (EFI_ERROR (Status)) {
+ goto RestoreAttributes;
+ }
+
+ //
+ // now we can run a basic one-shot e1000 initialization required to
+ // retrieve the MAC address
+ //
+ DEBUG((DEBUG_INFO, "E1kNetControllerStart: Populating SNP interface\n"));
+ Status = E1kNetSnpPopulate (Dev);
+ if (EFI_ERROR (Status)) {
+ goto UninitDev;
+ }
+
+ //
+ // get the device path of the e1000 device -- one-shot open
+ //
+ Status = gBS->OpenProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid,
+ (VOID **)&DevicePath, This->DriverBindingHandle,
+ ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (EFI_ERROR (Status)) {
+ goto Evacuate;
+ }
+
+ //
+ // create another device path that has the MAC address appended
+ //
+ MacNode.Header.Type = MESSAGING_DEVICE_PATH;
+ MacNode.Header.SubType = MSG_MAC_ADDR_DP;
+ SetDevicePathNodeLength (&MacNode, sizeof MacNode);
+ CopyMem (&MacNode.MacAddress, &Dev->Snm.CurrentAddress,
+ sizeof (EFI_MAC_ADDRESS));
+ MacNode.IfType = Dev->Snm.IfType;
+
+ Dev->MacDevicePath = AppendDevicePathNode (DevicePath, &MacNode.Header);
+ if (Dev->MacDevicePath == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Evacuate;
+ }
+
+ //
+ // create a child handle with the Simple Network Protocol and the new
+ // device path installed on it
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (&Dev->MacHandle,
+ &gEfiSimpleNetworkProtocolGuid, &Dev->Snp,
+ &gEfiDevicePathProtocolGuid, Dev->MacDevicePath,
+ NULL);
+ if (EFI_ERROR (Status)) {
+ goto FreeMacDevicePath;
+ }
+
+ DEBUG((DEBUG_INFO, "E1kNetControllerStart: returns EFI_SUCCESS\n"));
+ return EFI_SUCCESS;
+
+FreeMacDevicePath:
+ FreePool (Dev->MacDevicePath);
+
+Evacuate:
+ E1kNetSnpEvacuate (Dev);
+
+UninitDev:
+ E1kNetDevReset (Dev);
+
+RestoreAttributes:
+ Dev->PciIo->Attributes (
+ Dev->PciIo,
+ EfiPciIoAttributeOperationSet,
+ Dev->OriginalPciAttributes,
+ NULL
+ );
+
+CloseProtocol:
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+FreePool:
+ FreePool (Dev);
+
+ DEBUG((DEBUG_INFO, "E1kNetControllerStart: returns %u\n", Status));
+ return Status;
+}
+
+/**
+ Stops a device controller or a bus controller.
+
+ The Stop() function is designed to be invoked from the EFI boot service
+ DisconnectController(). As a result, much of the error checking on the
+ parameters to Stop() has been moved into this common boot service. It is
+ legal to call Stop() from other locations, but the following calling
+ restrictions must be followed, or the system behavior will not be
+ deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous
+ call to this same driver's Start() function.
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a
+ valid EFI_HANDLE. In addition, all of these handles must have been created
+ in this driver's Start() function, and the Start() function must have
+ called OpenProtocol() on ControllerHandle with an Attribute of
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
+ instance.
+ @param[in] ControllerHandle A handle to the device being stopped. The
+ handle must support a bus specific I/O
+ protocol for the driver to use to stop the
+ device.
+ @param[in] NumberOfChildren The number of child device handles in
+ ChildHandleBuffer.
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be
+ NULL if NumberOfChildren is 0.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device
+ error.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+E1kNetDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ if (NumberOfChildren > 0) {
+ //
+ // free all resources for whose access we need the child handle, because
+ // the child handle is going away
+ //
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
+ E1K_NET_DEV *Dev;
+ EFI_TPL OldTpl;
+
+ ASSERT (NumberOfChildren == 1);
+
+ Status = gBS->OpenProtocol (ChildHandleBuffer[0],
+ &gEfiSimpleNetworkProtocolGuid, (VOID **)&Snp,
+ This->DriverBindingHandle, ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ ASSERT_EFI_ERROR (Status);
+ Dev = E1K_NET_FROM_SNP (Snp);
+
+ //
+ // prevent any interference with WaitForPacket
+ //
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ ASSERT (Dev->MacHandle == ChildHandleBuffer[0]);
+ if (Dev->Snm.State != EfiSimpleNetworkStopped) {
+ //
+ // device in use, cannot stop driver instance
+ //
+ Status = EFI_DEVICE_ERROR;
+ }
+ else {
+ gBS->UninstallMultipleProtocolInterfaces (Dev->MacHandle,
+ &gEfiDevicePathProtocolGuid, Dev->MacDevicePath,
+ &gEfiSimpleNetworkProtocolGuid, &Dev->Snp,
+ NULL);
+ FreePool (Dev->MacDevicePath);
+ E1kNetSnpEvacuate (Dev);
+
+ Dev->PciIo->Attributes (
+ Dev->PciIo,
+ EfiPciIoAttributeOperationSet,
+ Dev->OriginalPciAttributes,
+ NULL
+ );
+
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ FreePool (Dev);
+ }
+
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_DRIVER_BINDING_PROTOCOL gE1kNetDriverBinding = {
+ &E1kNetDriverBindingSupported,
+ &E1kNetDriverBindingStart,
+ &E1kNetDriverBindingStop,
+ 0x10,
+ NULL,
+ NULL
+};
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/E1kHwIo.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/E1kHwIo.c
new file mode 100644
index 00000000..f203048b
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/E1kHwIo.c
@@ -0,0 +1,182 @@
+/** @file
+
+ This file implements the hardware register access functions of the e1000 driver.
+
+ Copyright (c) 2021, Oracle and/or its affiliates.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <IndustryStandard/Pci.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include "E1kNet.h"
+
+EFI_STATUS
+EFIAPI
+E1kNetRegWrite32 (
+ IN E1K_NET_DEV *Dev,
+ IN UINT32 Addr,
+ IN UINT32 Data
+ )
+{
+ EFI_STATUS Status;
+
+ Status = Dev->PciIo->Io.Write (
+ Dev->PciIo,
+ EfiPciIoWidthUint32,
+ PCI_BAR_IDX2,
+ 0, // IOADDR
+ 1,
+ &Addr
+ );
+ if (!EFI_ERROR (Status))
+ {
+ Status = Dev->PciIo->Io.Write (
+ Dev->PciIo,
+ EfiPciIoWidthUint32,
+ PCI_BAR_IDX2,
+ 4, // IODATA
+ 1,
+ &Data
+ );
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+E1kNetRegRead32 (
+ IN E1K_NET_DEV *Dev,
+ IN UINT32 Addr,
+ OUT UINT32 *Data
+ )
+{
+ EFI_STATUS Status;
+
+ Status = Dev->PciIo->Io.Write (
+ Dev->PciIo,
+ EfiPciIoWidthUint32,
+ PCI_BAR_IDX2,
+ 0, // IOADDR
+ 1,
+ &Addr
+ );
+ if (!EFI_ERROR (Status))
+ {
+ return Dev->PciIo->Io.Read (
+ Dev->PciIo,
+ EfiPciIoWidthUint32,
+ PCI_BAR_IDX2,
+ 4, // IODATA
+ 1,
+ Data
+ );
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+E1kNetRegSet32 (
+ IN E1K_NET_DEV *Dev,
+ IN UINT32 Addr,
+ IN UINT32 Set)
+{
+ UINT32 Reg;
+ EFI_STATUS Status;
+
+ Status = E1kNetRegRead32 (Dev, Addr, &Reg);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Reg |= Set;
+ Status = E1kNetRegWrite32 (Dev, Addr, Reg);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+E1kNetRegClear32 (
+ IN E1K_NET_DEV *Dev,
+ IN UINT32 Addr,
+ IN UINT32 Clear)
+{
+ UINT32 Reg;
+ EFI_STATUS Status;
+
+ Status = E1kNetRegRead32 (Dev, Addr, &Reg);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Reg &= ~Clear;
+ Status = E1kNetRegWrite32 (Dev, Addr, Reg);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+E1kNetDevReset (
+ IN E1K_NET_DEV *Dev
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Reset hardware
+ //
+ Status = E1kNetRegSet32 (Dev, E1K_REG_CTRL, E1K_REG_CTRL_RST);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Wait for the reset to complete
+ //
+ for (;;)
+ {
+ UINT32 Ctrl;
+
+ Status = E1kNetRegRead32 (Dev, E1K_REG_CTRL, &Ctrl);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ /// @todo Timeout?
+ if (!(Ctrl & E1K_REG_CTRL_RST))
+ break;
+ }
+
+ //
+ // Reset the PHY.
+ //
+ Status = E1kNetRegSet32 (Dev, E1K_REG_CTRL, E1K_REG_CTRL_PHY_RST);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Wait for the specified amount of 3us and de-assert the PHY reset signal.
+ //
+ gBS->Stall(3);
+ Status = E1kNetRegClear32 (Dev, E1K_REG_CTRL, E1K_REG_CTRL_PHY_RST);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/E1kNet.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/E1kNet.h
new file mode 100644
index 00000000..ea224eff
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/E1kNet.h
@@ -0,0 +1,350 @@
+/** @file
+
+ Internal definitions for the virtio-net driver, which produces Simple Network
+ Protocol instances for virtio-net devices.
+
+ Copyright (c) 2021, Oracle and/or its affiliates.
+ Copyright (c) 2017, AMD Inc, All rights reserved.
+ Copyright (C) 2013, Red Hat, Inc.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _E1K_NET_DXE_H_
+#define _E1K_NET_DXE_H_
+
+#include <Library/DebugLib.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/PciRootBridgeIo.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/ComponentName2.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/SimpleNetwork.h>
+#include <Library/OrderedCollectionLib.h>
+
+#include "E1kNetHw.h"
+
+#define E1K_NET_DEV_SIGNATURE SIGNATURE_32 ('E','1','K','N')
+
+//
+// maximum number of pending packets, separately for each direction
+//
+#define E1K_NET_MAX_PENDING 64
+
+//
+// State diagram:
+//
+// | ^
+// | |
+// BindingStart BindingStop
+// +SnpPopulate |
+// ++GetFeatures |
+// | |
+// v |
+// +---------+ virtio-net device is reset, no resources are
+// | stopped | allocated for traffic, but MAC address has
+// +---------+ been retrieved
+// | ^
+// | |
+// SNP.Start SNP.Stop
+// | |
+// v |
+// +---------+
+// | started | functionally identical to stopped
+// +---------+
+// | ^
+// | |
+// SNP.Initialize SNP.Shutdown
+// | |
+// v |
+// +-------------+ Virtio-net setup complete, including DRIVER_OK
+// | initialized | bit. The receive queue is populated with
+// +-------------+ requests; McastIpToMac, GetStatus, Transmit,
+// Receive are callable.
+//
+
+typedef struct {
+ //
+ // Parts of this structure are initialized / torn down in various functions
+ // at various call depths. The table to the right should make it easier to
+ // track them.
+ //
+ // field init function
+ // ------------------ ------------------------------
+ UINT32 Signature; // VirtioNetDriverBindingStart
+ EFI_PCI_IO_PROTOCOL *PciIo; // VirtioNetDriverBindingStart
+ UINT64 OriginalPciAttributes; // VirtioNetDriverBindingStart
+ EFI_SIMPLE_NETWORK_PROTOCOL Snp; // VirtioNetSnpPopulate
+ EFI_SIMPLE_NETWORK_MODE Snm; // VirtioNetSnpPopulate
+ EFI_EVENT ExitBoot; // VirtioNetSnpPopulate
+ EFI_DEVICE_PATH_PROTOCOL *MacDevicePath; // VirtioNetDriverBindingStart
+ EFI_HANDLE MacHandle; // VirtioNetDriverBindingStart
+
+ E1K_RX_DESC *RxRing; // VirtioNetInitRing
+ UINT8 *RxBuf; // E1kNetInitRx
+ UINT32 RdhLastSeen; // E1kNetInitRx
+ UINTN RxBufNrPages; // E1kNetInitRx
+ EFI_PHYSICAL_ADDRESS RxBufDeviceBase; // E1kNetInitRx
+ EFI_PHYSICAL_ADDRESS RxDeviceBase; // E1kNetInitRx
+ VOID *RxMap; // E1kNetInitRx
+
+ UINT16 TxMaxPending; // E1kNetInitTx
+ UINT16 TxCurPending; // E1kNetInitTx
+ E1K_TX_DESC *TxRing; // E1kNetInitTx
+ VOID *TxRingMap; // E1kNetInitTx
+ UINT16 TxLastUsed; // E1kNetInitTx
+ UINT32 TdhLastSeen; // E1kNetInitTx
+ ORDERED_COLLECTION *TxBufCollection; // E1kNetInitTx
+} E1K_NET_DEV;
+
+
+//
+// In order to avoid duplication of interface documentation, please find all
+// leading comments near the respective function / variable definitions (not
+// the declarations here), which is where your code editor of choice takes you
+// anyway when jumping to a function.
+//
+
+//
+// utility macros
+//
+#define E1K_NET_FROM_SNP(SnpPointer) \
+ CR (SnpPointer, E1K_NET_DEV, Snp, E1K_NET_DEV_SIGNATURE)
+
+//
+// component naming
+//
+extern EFI_COMPONENT_NAME_PROTOCOL gE1kNetComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gE1kNetComponentName2;
+
+//
+// driver binding
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gE1kNetDriverBinding;
+
+//
+// member functions implementing the Simple Network Protocol
+//
+EFI_STATUS
+EFIAPI
+E1kNetStart (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ );
+
+EFI_STATUS
+EFIAPI
+E1kNetStop (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ );
+
+EFI_STATUS
+EFIAPI
+E1kNetInitialize (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINTN ExtraRxBufferSize OPTIONAL,
+ IN UINTN ExtraTxBufferSize OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+E1kNetReset (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+EFI_STATUS
+EFIAPI
+E1kNetShutdown (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ );
+
+EFI_STATUS
+EFIAPI
+E1kNetReceiveFilters (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINT32 Enable,
+ IN UINT32 Disable,
+ IN BOOLEAN ResetMCastFilter,
+ IN UINTN MCastFilterCnt OPTIONAL,
+ IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+E1kNetStationAddress (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN Reset,
+ IN EFI_MAC_ADDRESS *New OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+E1kNetStatistics (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN Reset,
+ IN OUT UINTN *StatisticsSize OPTIONAL,
+ OUT EFI_NETWORK_STATISTICS *StatisticsTable OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+E1kNetMcastIpToMac (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN IPv6,
+ IN EFI_IP_ADDRESS *Ip,
+ OUT EFI_MAC_ADDRESS *Mac
+ );
+
+EFI_STATUS
+EFIAPI
+E1kNetNvData (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN ReadWrite,
+ IN UINTN Offset,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer
+ );
+
+EFI_STATUS
+EFIAPI
+E1kNetGetStatus (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ OUT UINT32 *InterruptStatus OPTIONAL,
+ OUT VOID **TxBuf OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+E1kNetTransmit (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINTN HeaderSize,
+ IN UINTN BufferSize,
+ IN /* +OUT! */ VOID *Buffer,
+ IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
+ IN EFI_MAC_ADDRESS *DestAddr OPTIONAL,
+ IN UINT16 *Protocol OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+E1kNetReceive (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ OUT UINTN *HeaderSize OPTIONAL,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer,
+ OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
+ OUT EFI_MAC_ADDRESS *DestAddr OPTIONAL,
+ OUT UINT16 *Protocol OPTIONAL
+ );
+
+//
+// utility functions shared by various SNP member functions
+//
+VOID
+EFIAPI
+E1kNetShutdownRx (
+ IN OUT E1K_NET_DEV *Dev
+ );
+
+VOID
+EFIAPI
+E1kNetShutdownTx (
+ IN OUT E1K_NET_DEV *Dev
+ );
+
+//
+// utility functions to map caller-supplied Tx buffer system physical address
+// to a device address and vice versa
+//
+EFI_STATUS
+EFIAPI
+E1kNetMapTxBuf (
+ IN E1K_NET_DEV *Dev,
+ IN VOID *Buffer,
+ IN UINTN NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress
+ );
+
+EFI_STATUS
+EFIAPI
+E1kNetUnmapTxBuf (
+ IN E1K_NET_DEV *Dev,
+ OUT VOID **Buffer,
+ IN EFI_PHYSICAL_ADDRESS DeviceAddress
+ );
+
+INTN
+EFIAPI
+E1kNetTxBufMapInfoCompare (
+ IN CONST VOID *UserStruct1,
+ IN CONST VOID *UserStruct2
+ );
+
+INTN
+EFIAPI
+E1kNetTxBufDeviceAddressCompare (
+ IN CONST VOID *StandaloneKey,
+ IN CONST VOID *UserStruct
+ );
+
+
+//
+// event callbacks
+//
+VOID
+EFIAPI
+E1kNetIsPacketAvailable (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+VOID
+EFIAPI
+E1kNetExitBoot (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+//
+// Hardware I/O functions.
+//
+EFI_STATUS
+EFIAPI
+E1kNetRegWrite32 (
+ IN E1K_NET_DEV *Dev,
+ IN UINT32 Addr,
+ IN UINT32 Data
+ );
+
+EFI_STATUS
+EFIAPI
+E1kNetRegRead32 (
+ IN E1K_NET_DEV *Dev,
+ IN UINT32 Addr,
+ OUT UINT32 *Data
+ );
+
+EFI_STATUS
+EFIAPI
+E1kNetRegSet32 (
+ IN E1K_NET_DEV *Dev,
+ IN UINT32 Addr,
+ IN UINT32 Set
+ );
+
+EFI_STATUS
+EFIAPI
+E1kNetRegClear32 (
+ IN E1K_NET_DEV *Dev,
+ IN UINT32 Addr,
+ IN UINT32 Clear
+ );
+
+EFI_STATUS
+EFIAPI
+E1kNetDevReset (
+ IN E1K_NET_DEV *Dev
+ );
+
+#endif // _E1K_NET_DXE_H_
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/E1kNet.inf b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/E1kNet.inf
new file mode 100644
index 00000000..7c9ba681
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/E1kNet.inf
@@ -0,0 +1,60 @@
+
+## @file
+#
+# This driver produces Simple Network Protocol instances for e1000 based
+# devices.
+#
+# Copyright (C) 2021, Oracle and/or its affiliates.
+# Copyright (C) 2013, Red Hat, Inc.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = E1kNetDxe
+ FILE_GUID = FFCC3DF0-C1EC-11EB-BA2F-0800200C9A66
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = E1kNetEntryPoint
+
+[Sources]
+ ComponentName.c
+ DriverBinding.c
+ EntryPoint.c
+ Events.c
+ SnpGetStatus.c
+ SnpInitialize.c
+ SnpMcastIpToMac.c
+ SnpReceive.c
+ SnpReceiveFilters.c
+ SnpSharedHelpers.c
+ SnpShutdown.c
+ SnpStart.c
+ SnpStop.c
+ SnpTransmit.c
+ SnpUnsupported.c
+ E1kHwIo.c
+ E1kNet.h
+ E1kNetHw.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+ VBoxPkg/VBoxPkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+ MemoryAllocationLib
+ OrderedCollectionLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+
+[Protocols]
+ gEfiSimpleNetworkProtocolGuid ## BY_START
+ gEfiDevicePathProtocolGuid ## BY_START
+ gEfiPciIoProtocolGuid ## TO_START
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/E1kNetHw.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/E1kNetHw.h
new file mode 100644
index 00000000..90afcf8a
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/E1kNetHw.h
@@ -0,0 +1,105 @@
+/** @file
+
+ E1000 hardware interface definitions.
+
+ Copyright (c) 2021, Oracle and/or its affiliates.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _E1K_NET_HW_H_
+#define _E1K_NET_HW_H_
+
+#define INTEL_PCI_VENDOR_ID 0x8086
+#define INTEL_82540EM_PCI_DEVICE_ID 0x100e
+#define INTEL_82543GC_PCI_DEVICE_ID 0x1004
+#define INTEL_82545EM_PCI_DEVICE_ID 0x100f
+
+//
+// Receive descriptor.
+//
+typedef struct {
+ UINT32 AddrBufferLow;
+ UINT32 AddrBufferHigh;
+ UINT16 BufferLength;
+ UINT16 Checksum;
+ UINT8 Status;
+ UINT8 Errors;
+ UINT16 Special;
+} E1K_RX_DESC;
+
+#define E1K_RX_STATUS_DONE BIT0
+#define E1K_RX_STATUS_EOP BIT1
+
+#define E1K_RX_ERROR_CE BIT0
+#define E1K_RX_ERROR_SEQ BIT2
+#define E1K_RX_ERROR_CXE BIT4
+#define E1K_RX_ERROR_RXE BIT7
+
+//
+// Transmit descriptor.
+//
+typedef struct {
+ UINT32 AddrBufferLow;
+ UINT32 AddrBufferHigh;
+ UINT16 BufferLength;
+ UINT8 ChecksumOffset;
+ UINT8 Command;
+ UINT8 Status;
+ UINT8 ChecksumStart;
+ UINT16 Special;
+} E1K_TX_DESC;
+
+#define E1K_TX_CMD_EOP BIT0
+#define E1K_TX_CMD_FCS BIT1
+#define E1K_TX_CMD_RS BIT3
+
+#define E1K_REG_CTRL 0x00000000
+# define E1K_REG_CTRL_ASDE BIT5
+# define E1K_REG_CTRL_SLU BIT6
+# define E1K_REG_CTRL_RST BIT26
+# define E1K_REG_CTRL_PHY_RST BIT31
+#define E1K_REG_STATUS 0x00000008
+# define E1K_REG_STATUS_LU BIT1
+#define E1K_REG_EECD 0x00000010
+#define E1K_REG_EERD 0x00000014
+# define E1K_REG_EERD_START BIT0
+# define E1K_REG_EERD_DONE BIT4
+# define E1K_REG_EERD_DATA_GET(x) (((x) >> 16) & 0xffff)
+#define E1K_REG_ICR 0x000000c0
+#define E1K_REG_ITR 0x000000c4
+#define E1K_REG_ICS 0x000000c8
+#define E1K_REG_IMS 0x000000d0
+#define E1K_REG_IMC 0x000000d8
+#define E1K_REG_RCTL 0x00000100
+# define E1K_REG_RCTL_EN BIT1
+# define E1K_REG_RCTL_MPE BIT4
+# define E1K_REG_RCTL_BSIZE_MASK 0x00030000
+#define E1K_REG_RDBAL 0x00002800
+#define E1K_REG_RDBAH 0x00002804
+#define E1K_REG_RDLEN 0x00002808
+#define E1K_REG_RDH 0x00002810
+#define E1K_REG_RDT 0x00002818
+#define E1K_REG_RDTR 0x00002820
+#define E1K_REG_TCTL 0x00000400
+# define E1K_REG_TCTL_EN BIT1
+# define E1K_REG_TCTL_PSP BIT3
+#define E1K_REG_TIPG 0x00000410
+#define E1K_REG_TDBAL 0x00003800
+#define E1K_REG_TDBAH 0x00003804
+#define E1K_REG_TDLEN 0x00003808
+#define E1K_REG_TDH 0x00003810
+#define E1K_REG_TDT 0x00003818
+#define E1K_REG_RAL 0x00005400
+#define E1K_REG_RAH 0x00005404
+# define E1K_REG_RAH_AV BIT31
+
+//
+// MAC address.
+//
+typedef struct
+{
+ UINT8 Mac[6];
+} E1K_NET_MAC;
+
+#endif // _E1K_NET_HW_H_
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/EntryPoint.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/EntryPoint.c
new file mode 100644
index 00000000..d4cf35fd
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/EntryPoint.c
@@ -0,0 +1,45 @@
+/** @file
+
+ This file implements the entry point of the e1000 driver.
+
+ Copyright (c) 2021, Oracle and/or its affiliates.
+ Copyright (C) 2013, Red Hat, Inc.
+ Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/UefiLib.h>
+
+#include "E1kNet.h"
+
+/**
+ This is the declaration of an EFI image entry point. This entry point is the
+ same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including both
+ device drivers and bus drivers.
+
+ @param ImageHandle The firmware allocated handle for the UEFI
+ image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval Others An unexpected error occurred.
+**/
+
+EFI_STATUS
+EFIAPI
+E1kNetEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gE1kNetDriverBinding,
+ ImageHandle,
+ &gE1kNetComponentName,
+ &gE1kNetComponentName2
+ );
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/Events.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/Events.c
new file mode 100644
index 00000000..e51aee58
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/Events.c
@@ -0,0 +1,82 @@
+/** @file
+
+ Implements
+ - the SNM.WaitForPacket EVT_NOTIFY_WAIT event,
+ - the EVT_SIGNAL_EXIT_BOOT_SERVICES event
+ for the e1000 driver.
+
+ Copyright (c) 2021, Oracle and/or its affiliates.
+ Copyright (C) 2013, Red Hat, Inc.
+ Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include "E1kNet.h"
+
+/**
+ Invoke a notification event
+
+ @param Event Event whose notification function is being
+ invoked.
+ @param Context The pointer to the notification function's
+ context, which is implementation-dependent.
+
+**/
+
+VOID
+EFIAPI
+E1kNetIsPacketAvailable (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // This callback has been enqueued by an external application and is
+ // running at TPL_CALLBACK already.
+ //
+ // The WaitForPacket logic is similar to that of WaitForKey. The former has
+ // almost no documentation in either the UEFI-2.3.1+errC spec or the
+ // DWG-2.3.1, but WaitForKey does have some.
+ //
+ E1K_NET_DEV *Dev;
+ UINT32 RdhCur;
+
+ Dev = Context;
+ if (Dev->Snm.State != EfiSimpleNetworkInitialized) {
+ return;
+ }
+
+ E1kNetRegRead32(Dev, E1K_REG_RDH, &RdhCur);
+
+ if (Dev->RdhLastSeen != RdhCur) {
+ gBS->SignalEvent (Dev->Snp.WaitForPacket);
+ }
+}
+
+VOID
+EFIAPI
+E1kNetExitBoot (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // This callback has been enqueued by ExitBootServices() and is running at
+ // TPL_CALLBACK already.
+ //
+ // Shut down pending transfers according to DWG-2.3.1, "25.5.1 Exit Boot
+ // Services Event".
+ //
+ E1K_NET_DEV *Dev;
+
+ DEBUG ((DEBUG_VERBOSE, "%a: Context=0x%p\n", __FUNCTION__, Context));
+ Dev = Context;
+ if (Dev->Snm.State == EfiSimpleNetworkInitialized) {
+ E1kNetDevReset (Dev);
+ }
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpGetStatus.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpGetStatus.c
new file mode 100644
index 00000000..6927b46e
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpGetStatus.c
@@ -0,0 +1,160 @@
+/** @file
+
+ Implementation of the SNP.GetStatus() function and its private helpers if
+ any.
+
+ Copyright (c) 2021, Oracle and/or its affiliates.
+ Copyright (C) 2013, Red Hat, Inc.
+ Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include "E1kNet.h"
+
+/**
+ Reads the current interrupt status and recycled transmit buffer status from
+ a network interface.
+
+ @param This The protocol instance pointer.
+ @param InterruptStatus A pointer to the bit mask of the currently active
+ interrupts If this is NULL, the interrupt status will
+ not be read from the device. If this is not NULL, the
+ interrupt status will be read from the device. When
+ the interrupt status is read, it will also be
+ cleared. Clearing the transmit interrupt does not
+ empty the recycled transmit buffer array.
+ @param TxBuf Recycled transmit buffer address. The network
+ interface will not transmit if its internal recycled
+ transmit buffer array is full. Reading the transmit
+ buffer does not clear the transmit interrupt. If this
+ is NULL, then the transmit buffer status will not be
+ read. If there are no transmit buffers to recycle and
+ TxBuf is not NULL, * TxBuf will be set to NULL.
+
+ @retval EFI_SUCCESS The status of the network interface was
+ retrieved.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an
+ unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network
+ interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network
+ interface.
+
+**/
+
+EFI_STATUS
+EFIAPI
+E1kNetGetStatus (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ OUT UINT32 *InterruptStatus OPTIONAL,
+ OUT VOID **TxBuf OPTIONAL
+ )
+{
+ E1K_NET_DEV *Dev;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ UINT32 TdhCur;
+ UINT32 RdhCur;
+ EFI_PHYSICAL_ADDRESS DeviceAddress;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = E1K_NET_FROM_SNP (This);
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ switch (Dev->Snm.State) {
+ case EfiSimpleNetworkStopped:
+ Status = EFI_NOT_STARTED;
+ goto Exit;
+ case EfiSimpleNetworkStarted:
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ default:
+ break;
+ }
+
+ //
+ // update link status
+ //
+ if (Dev->Snm.MediaPresentSupported) {
+ UINT32 RegSts;
+
+ Status = E1kNetRegRead32(Dev, E1K_REG_STATUS, &RegSts);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ Dev->Snm.MediaPresent = (BOOLEAN)((RegSts & E1K_REG_STATUS_LU) != 0);
+ }
+
+ E1kNetRegRead32(Dev, E1K_REG_TDH, &TdhCur);
+ E1kNetRegRead32(Dev, E1K_REG_RDH, &RdhCur);
+
+
+ if (InterruptStatus != NULL) {
+ //
+ // report the receive interrupt if there is data available for reception,
+ // report the transmit interrupt if we have transmitted at least one buffer
+ //
+ *InterruptStatus = 0;
+ if (Dev->RdhLastSeen != RdhCur) {
+ *InterruptStatus |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
+ }
+ if (Dev->TdhLastSeen != TdhCur) {
+ ASSERT (Dev->TxCurPending > 0);
+ *InterruptStatus |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
+ }
+ }
+
+ if (TxBuf != NULL) {
+ if (Dev->TdhLastSeen == TdhCur) {
+ *TxBuf = NULL;
+ }
+ else {
+ ASSERT (Dev->TxCurPending > 0);
+ ASSERT (Dev->TxCurPending <= Dev->TxMaxPending);
+
+ //
+ // get the device address that has been enqueued for the caller's
+ // transmit buffer
+ //
+ DeviceAddress = Dev->TxRing[Dev->TdhLastSeen].AddrBufferLow;
+ DeviceAddress |= LShiftU64(Dev->TxRing[Dev->TdhLastSeen].AddrBufferHigh, 32);
+
+ Dev->TdhLastSeen = (Dev->TdhLastSeen + 1) % E1K_NET_MAX_PENDING;
+ Dev->TxCurPending--;
+
+ //
+ // Unmap the device address and perform the reverse mapping to find the
+ // caller buffer address.
+ //
+ Status = E1kNetUnmapTxBuf (
+ Dev,
+ TxBuf,
+ DeviceAddress
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // E1kNetUnmapTxBuf should never fail, if we have reached here
+ // that means our internal state has been corrupted
+ //
+ ASSERT (FALSE);
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ }
+ }
+
+ Status = EFI_SUCCESS;
+
+Exit:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpInitialize.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpInitialize.c
new file mode 100644
index 00000000..1fec91b4
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpInitialize.c
@@ -0,0 +1,321 @@
+/** @file
+
+ Implementation of the SNP.Initialize() function and its private helpers if
+ any.
+
+ Copyright (c) 2021, Oracle and/or its affiliates.
+ Copyright (c) 2017, AMD Inc, All rights reserved.
+ Copyright (C) 2013, Red Hat, Inc.
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include "E1kNet.h"
+
+/**
+ Set up static scaffolding for the E1kNetTransmit() and
+ E1kNetGetStatus() SNP methods.
+
+ This function may only be called by E1kNetInitialize().
+
+ @param[in,out] Dev The E1K_NET_DEV driver instance about to enter the
+ EfiSimpleNetworkInitialized state.
+
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate the stack to track the heads
+ of free descriptor chains or failed to init
+ TxBufCollection.
+ @return Status codes from VIRTIO_DEVICE_PROTOCOL.
+ AllocateSharedPages() or
+ VirtioMapAllBytesInSharedBuffer()
+ @retval EFI_SUCCESS TX setup successful.
+*/
+
+STATIC
+EFI_STATUS
+EFIAPI
+E1kNetInitTx (
+ IN OUT E1K_NET_DEV *Dev
+ )
+{
+ UINTN TxRingSize;
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS DeviceAddress;
+ VOID *TxRingBuffer;
+
+ Dev->TxMaxPending = E1K_NET_MAX_PENDING;
+ Dev->TxCurPending = 0;
+ Dev->TxBufCollection = OrderedCollectionInit (
+ E1kNetTxBufMapInfoCompare,
+ E1kNetTxBufDeviceAddressCompare
+ );
+ if (Dev->TxBufCollection == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ //
+ // Allocate TxRing header and map with BusMasterCommonBuffer so that it
+ // can be accessed equally by both processor and device.
+ //
+ TxRingSize = Dev->TxMaxPending * sizeof (*Dev->TxRing);
+ Status = Dev->PciIo->AllocateBuffer (
+ Dev->PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ EFI_SIZE_TO_PAGES (TxRingSize),
+ &TxRingBuffer,
+ EFI_PCI_ATTRIBUTE_MEMORY_CACHED
+ );
+ if (EFI_ERROR (Status)) {
+ goto UninitTxBufCollection;
+ }
+
+ ZeroMem (TxRingBuffer, TxRingSize);
+
+ Status = Dev->PciIo->Map (
+ Dev->PciIo,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ TxRingBuffer,
+ &TxRingSize,
+ &DeviceAddress,
+ &Dev->TxRingMap
+ );
+ if (EFI_ERROR (Status)) {
+ goto FreeTxRingBuffer;
+ }
+
+ Dev->TxRing = TxRingBuffer;
+ Dev->TdhLastSeen = 0;
+ Dev->TxLastUsed = 0;
+
+ // Program the transmit engine.
+ MemoryFence ();
+ E1kNetRegWrite32(Dev, E1K_REG_TDBAL, (UINT32)DeviceAddress);
+ E1kNetRegWrite32(Dev, E1K_REG_TDBAH, (UINT32)(RShiftU64 (DeviceAddress, 32)));
+ E1kNetRegWrite32(Dev, E1K_REG_TDLEN, (UINT32)TxRingSize);
+ E1kNetRegWrite32(Dev, E1K_REG_TDH, 0);
+ E1kNetRegWrite32(Dev, E1K_REG_TDT, 0);
+ E1kNetRegWrite32(Dev, E1K_REG_TCTL, E1K_REG_TCTL_EN | E1K_REG_TCTL_PSP);
+
+ return EFI_SUCCESS;
+
+FreeTxRingBuffer:
+ Dev->PciIo->FreeBuffer (
+ Dev->PciIo,
+ EFI_SIZE_TO_PAGES (TxRingSize),
+ TxRingBuffer
+ );
+
+UninitTxBufCollection:
+ OrderedCollectionUninit (Dev->TxBufCollection);
+
+Exit:
+ return Status;
+}
+
+
+/**
+ Set up static scaffolding for the E1kNetReceive() SNP method and enable
+ live device operation.
+
+ This function may only be called as E1kNetInitialize()'s final step.
+
+ @param[in,out] Dev The E1K_NET_DEV driver instance about to enter the
+ EfiSimpleNetworkInitialized state.
+
+ @return Status codes from VIRTIO_CFG_WRITE() or
+ VIRTIO_DEVICE_PROTOCOL.AllocateSharedPages or
+ VirtioMapAllBytesInSharedBuffer().
+ @retval EFI_SUCCESS RX setup successful. The device is live and may
+ already be writing to the receive area.
+*/
+
+STATIC
+EFI_STATUS
+EFIAPI
+E1kNetInitRx (
+ IN OUT E1K_NET_DEV *Dev
+ )
+{
+ EFI_STATUS Status;
+ UINTN RxBufSize;
+ UINTN PktIdx;
+ UINTN NumBytes;
+ EFI_PHYSICAL_ADDRESS RxBufDeviceAddress;
+ VOID *RxBuffer;
+
+ //
+ // For each incoming packet we must supply two buffers:
+ // - the recipient for the RX descriptor, plus
+ // - the recipient for the network data (which consists of Ethernet header
+ // and Ethernet payload) which is a 2KB buffer.
+ //
+ RxBufSize = sizeof(*Dev->RxRing) + 2048;
+
+ //
+ // The RxBuf is shared between guest and hypervisor, use
+ // AllocateSharedPages() to allocate this memory region and map it with
+ // BusMasterCommonBuffer so that it can be accessed by both guest and
+ // hypervisor.
+ //
+ NumBytes = E1K_NET_MAX_PENDING * RxBufSize;
+ Dev->RxBufNrPages = EFI_SIZE_TO_PAGES (NumBytes);
+ Status = Dev->PciIo->AllocateBuffer (
+ Dev->PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ Dev->RxBufNrPages,
+ &RxBuffer,
+ EFI_PCI_ATTRIBUTE_MEMORY_CACHED
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ZeroMem (RxBuffer, NumBytes);
+
+ Status = Dev->PciIo->Map (
+ Dev->PciIo,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ RxBuffer,
+ &NumBytes,
+ &Dev->RxDeviceBase,
+ &Dev->RxMap
+ );
+ if (EFI_ERROR (Status)) {
+ goto FreeSharedBuffer;
+ }
+
+ Dev->RxRing = RxBuffer;
+ Dev->RxBuf = (UINT8 *)RxBuffer + sizeof(*Dev->RxRing) * E1K_NET_MAX_PENDING;
+ Dev->RdhLastSeen = 0;
+
+ // Set up the RX descriptors.
+ Dev->RxBufDeviceBase = Dev->RxDeviceBase + sizeof(*Dev->RxRing) * E1K_NET_MAX_PENDING;
+ RxBufDeviceAddress = Dev->RxBufDeviceBase;
+ for (PktIdx = 0; PktIdx < E1K_NET_MAX_PENDING; ++PktIdx) {
+ Dev->RxRing[PktIdx].AddrBufferLow = (UINT32)RxBufDeviceAddress;
+ Dev->RxRing[PktIdx].AddrBufferHigh = (UINT32)RShiftU64(RxBufDeviceAddress, 32);
+ Dev->RxRing[PktIdx].BufferLength = 2048;
+
+ RxBufDeviceAddress += Dev->RxRing[PktIdx].BufferLength;
+ }
+
+ // Program the receive engine.
+ MemoryFence ();
+ E1kNetRegWrite32(Dev, E1K_REG_RDBAL, (UINT32)Dev->RxDeviceBase);
+ E1kNetRegWrite32(Dev, E1K_REG_RDBAH, (UINT32)(RShiftU64 (Dev->RxDeviceBase, 32)));
+ E1kNetRegWrite32(Dev, E1K_REG_RDLEN, sizeof(*Dev->RxRing) * E1K_NET_MAX_PENDING);
+ E1kNetRegWrite32(Dev, E1K_REG_RDH, 0);
+ E1kNetRegWrite32(Dev, E1K_REG_RDT, E1K_NET_MAX_PENDING - 1);
+ E1kNetRegClear32(Dev, E1K_REG_RCTL, E1K_REG_RCTL_BSIZE_MASK);
+ E1kNetRegSet32(Dev, E1K_REG_RCTL, E1K_REG_RCTL_EN | E1K_REG_RCTL_MPE);
+
+ return EFI_SUCCESS;
+
+FreeSharedBuffer:
+ Dev->PciIo->FreeBuffer (
+ Dev->PciIo,
+ Dev->RxBufNrPages,
+ RxBuffer
+ );
+ return Status;
+}
+
+/**
+ Resets a network adapter and allocates the transmit and receive buffers
+ required by the network interface; optionally, also requests allocation of
+ additional transmit and receive buffers.
+
+ @param This The protocol instance pointer.
+ @param ExtraRxBufferSize The size, in bytes, of the extra receive buffer
+ space that the driver should allocate for the
+ network interface. Some network interfaces will not
+ be able to use the extra buffer, and the caller
+ will not know if it is actually being used.
+ @param ExtraTxBufferSize The size, in bytes, of the extra transmit buffer
+ space that the driver should allocate for the
+ network interface. Some network interfaces will not
+ be able to use the extra buffer, and the caller
+ will not know if it is actually being used.
+
+ @retval EFI_SUCCESS The network interface was initialized.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_OUT_OF_RESOURCES There was not enough memory for the transmit
+ and receive buffers.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an
+ unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network
+ interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network
+ interface.
+
+**/
+
+EFI_STATUS
+EFIAPI
+E1kNetInitialize (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINTN ExtraRxBufferSize OPTIONAL,
+ IN UINTN ExtraTxBufferSize OPTIONAL
+ )
+{
+ E1K_NET_DEV *Dev;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ DEBUG((DEBUG_INFO, "E1kNetInitialize:\n"));
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (ExtraRxBufferSize > 0 || ExtraTxBufferSize > 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Dev = E1K_NET_FROM_SNP (This);
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ if (Dev->Snm.State != EfiSimpleNetworkStarted) {
+ Status = EFI_NOT_STARTED;
+ goto InitFailed;
+ }
+
+ // Program the first Receive Address Low/High register.
+ E1kNetRegSet32(Dev, E1K_REG_CTRL, E1K_REG_CTRL_ASDE | E1K_REG_CTRL_SLU);
+ E1kNetRegWrite32(Dev, E1K_REG_RAL, *(UINT32 *)&Dev->Snm.CurrentAddress.Addr[0]);
+ E1kNetRegWrite32(Dev, E1K_REG_RAH, (*(UINT32 *)&Dev->Snm.CurrentAddress.Addr[4]) | E1K_REG_RAH_AV);
+
+ Status = E1kNetInitTx (Dev);
+ if (EFI_ERROR (Status)) {
+ goto AbortDevice;
+ }
+
+ //
+ // start receiving
+ //
+ Status = E1kNetInitRx (Dev);
+ if (EFI_ERROR (Status)) {
+ goto ReleaseTxAux;
+ }
+
+ Dev->Snm.State = EfiSimpleNetworkInitialized;
+ gBS->RestoreTPL (OldTpl);
+ return EFI_SUCCESS;
+
+ReleaseTxAux:
+ E1kNetShutdownTx (Dev);
+
+AbortDevice:
+ E1kNetDevReset(Dev);
+
+InitFailed:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpMcastIpToMac.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpMcastIpToMac.c
new file mode 100644
index 00000000..01508ee9
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpMcastIpToMac.c
@@ -0,0 +1,103 @@
+/** @file
+
+ Implementation of the SNP.McastIpToMac() function and its private helpers if
+ any.
+
+ Copyright (c) 2021, Oracle and/or its affiliates.<BR>
+ Copyright (C) 2013, Red Hat, Inc.
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/UefiBootServicesTableLib.h>
+
+#include "E1kNet.h"
+
+/**
+ Converts a multicast IP address to a multicast HW MAC address.
+
+ @param This The protocol instance pointer.
+ @param IPv6 Set to TRUE if the multicast IP address is IPv6 [RFC 2460]. Set
+ to FALSE if the multicast IP address is IPv4 [RFC 791].
+ @param IP The multicast IP address that is to be converted to a multicast
+ HW MAC address.
+ @param MAC The multicast HW MAC address that is to be generated from IP.
+
+ @retval EFI_SUCCESS The multicast IP address was mapped to the
+ multicast HW MAC address.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_BUFFER_TOO_SMALL The Statistics buffer was too small. The
+ current buffer size needed to hold the
+ statistics is returned in StatisticsSize.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an
+ unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network
+ interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network
+ interface.
+
+**/
+
+EFI_STATUS
+EFIAPI
+E1kNetMcastIpToMac (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN IPv6,
+ IN EFI_IP_ADDRESS *Ip,
+ OUT EFI_MAC_ADDRESS *Mac
+ )
+{
+ E1K_NET_DEV *Dev;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ //
+ // http://en.wikipedia.org/wiki/Multicast_address
+ //
+ if (This == NULL || Ip == NULL || Mac == NULL ||
+ ( IPv6 && (Ip->v6.Addr[0] ) != 0xFF) || // invalid IPv6 mcast addr
+ (!IPv6 && (Ip->v4.Addr[0] & 0xF0) != 0xE0) // invalid IPv4 mcast addr
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = E1K_NET_FROM_SNP (This);
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ switch (Dev->Snm.State) {
+ case EfiSimpleNetworkStopped:
+ Status = EFI_NOT_STARTED;
+ goto Exit;
+ case EfiSimpleNetworkStarted:
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ default:
+ break;
+ }
+
+ //
+ // http://en.wikipedia.org/wiki/IP_multicast#Layer_2_delivery
+ //
+ if (IPv6) {
+ Mac->Addr[0] = 0x33;
+ Mac->Addr[1] = 0x33;
+ Mac->Addr[2] = Ip->v6.Addr[12];
+ Mac->Addr[3] = Ip->v6.Addr[13];
+ Mac->Addr[4] = Ip->v6.Addr[14];
+ Mac->Addr[5] = Ip->v6.Addr[15];
+ }
+ else {
+ Mac->Addr[0] = 0x01;
+ Mac->Addr[1] = 0x00;
+ Mac->Addr[2] = 0x5E;
+ Mac->Addr[3] = Ip->v4.Addr[1] & 0x7F;
+ Mac->Addr[4] = Ip->v4.Addr[2];
+ Mac->Addr[5] = Ip->v4.Addr[3];
+ }
+ Status = EFI_SUCCESS;
+
+Exit:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpReceive.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpReceive.c
new file mode 100644
index 00000000..0b8b0cbe
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpReceive.c
@@ -0,0 +1,159 @@
+/** @file
+
+ Implementation of the SNP.Receive() function and its private helpers if any.
+
+ Copyright (c) 2021, Oracle and/or its affiliates.
+ Copyright (C) 2013, Red Hat, Inc.
+ Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include "E1kNet.h"
+
+/**
+ Receives a packet from a network interface.
+
+ @param This The protocol instance pointer.
+ @param HeaderSize The size, in bytes, of the media header received on the
+ network interface. If this parameter is NULL, then the
+ media header size will not be returned.
+ @param BufferSize On entry, the size, in bytes, of Buffer. On exit, the
+ size, in bytes, of the packet that was received on the
+ network interface.
+ @param Buffer A pointer to the data buffer to receive both the media
+ header and the data.
+ @param SrcAddr The source HW MAC address. If this parameter is NULL, the
+ HW MAC source address will not be extracted from the media
+ header.
+ @param DestAddr The destination HW MAC address. If this parameter is NULL,
+ the HW MAC destination address will not be extracted from
+ the media header.
+ @param Protocol The media header type. If this parameter is NULL, then the
+ protocol will not be extracted from the media header. See
+ RFC 1700 section "Ether Types" for examples.
+
+ @retval EFI_SUCCESS The received data was stored in Buffer, and
+ BufferSize has been updated to the number of
+ bytes received.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_NOT_READY The network interface is too busy to accept
+ this transmit request.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an
+ unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network
+ interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network
+ interface.
+
+**/
+
+EFI_STATUS
+EFIAPI
+E1kNetReceive (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ OUT UINTN *HeaderSize OPTIONAL,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer,
+ OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
+ OUT EFI_MAC_ADDRESS *DestAddr OPTIONAL,
+ OUT UINT16 *Protocol OPTIONAL
+ )
+{
+ E1K_NET_DEV *Dev;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ UINT32 RdhCur;
+ UINT32 RxLen;
+ UINTN OrigBufferSize;
+ EFI_PHYSICAL_ADDRESS BufferAddress;
+ UINT8 *RxPtr;
+ UINTN RxBufOffset;
+
+ DEBUG((DEBUG_INFO, "E1kNetReceive: HeaderSize=%p BufferSize=%u Buffer=%p\n",
+ HeaderSize, *BufferSize, Buffer));
+
+ if (This == NULL || BufferSize == NULL || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = E1K_NET_FROM_SNP (This);
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ switch (Dev->Snm.State) {
+ case EfiSimpleNetworkStopped:
+ Status = EFI_NOT_STARTED;
+ goto Exit;
+ case EfiSimpleNetworkStarted:
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ default:
+ break;
+ }
+
+ E1kNetRegRead32(Dev, E1K_REG_RDH, &RdhCur);
+
+ if (Dev->RdhLastSeen == RdhCur) {
+ Status = EFI_NOT_READY;
+ goto Exit;
+ }
+
+ RxLen = Dev->RxRing[Dev->RdhLastSeen].BufferLength;
+ //
+ // the host must not have filled in more data than requested
+ //
+ ASSERT (RxLen <= 2048);
+
+ OrigBufferSize = *BufferSize;
+ *BufferSize = RxLen;
+
+ if (OrigBufferSize < RxLen) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Exit; // keep the packet
+ }
+
+ if (RxLen < Dev->Snm.MediaHeaderSize) {
+ Status = EFI_DEVICE_ERROR;
+ goto RecycleDesc; // drop useless short packet
+ }
+
+ if (HeaderSize != NULL) {
+ *HeaderSize = Dev->Snm.MediaHeaderSize;
+ }
+
+ BufferAddress = Dev->RxRing[Dev->RdhLastSeen].AddrBufferLow;
+ BufferAddress |= LShiftU64(Dev->RxRing[Dev->RdhLastSeen].AddrBufferHigh, 32);
+ RxBufOffset = (UINTN)(BufferAddress - Dev->RxBufDeviceBase);
+ RxPtr = Dev->RxBuf + RxBufOffset;
+ CopyMem (Buffer, RxPtr, RxLen);
+
+ if (DestAddr != NULL) {
+ CopyMem (DestAddr, RxPtr, sizeof (E1K_NET_MAC));
+ }
+ RxPtr += sizeof (E1K_NET_MAC);
+
+ if (SrcAddr != NULL) {
+ CopyMem (SrcAddr, RxPtr, sizeof (E1K_NET_MAC));
+ }
+ RxPtr += sizeof (E1K_NET_MAC);
+
+ if (Protocol != NULL) {
+ *Protocol = (UINT16) ((RxPtr[0] << 8) | RxPtr[1]);
+ }
+ RxPtr += sizeof (UINT16);
+
+ Status = EFI_SUCCESS;
+
+RecycleDesc:
+ Dev->RdhLastSeen = (Dev->RdhLastSeen + 1) % E1K_NET_MAX_PENDING;
+ E1kNetRegWrite32(Dev, E1K_REG_RDT, Dev->RdhLastSeen);
+
+Exit:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpReceiveFilters.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpReceiveFilters.c
new file mode 100644
index 00000000..ce559f40
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpReceiveFilters.c
@@ -0,0 +1,100 @@
+/** @file
+
+ Implementation of the SNP.ReceiveFilters() function and its private helpers
+ if any.
+
+ Copyright (c) 2021, Oracle and/or its affiliates.
+ Copyright (C) 2013, Red Hat, Inc.
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/UefiBootServicesTableLib.h>
+
+#include "E1kNet.h"
+
+/**
+ Manages the multicast receive filters of a network interface.
+
+ @param This The protocol instance pointer.
+ @param Enable A bit mask of receive filters to enable on the
+ network interface.
+ @param Disable A bit mask of receive filters to disable on the
+ network interface.
+ @param ResetMCastFilter Set to TRUE to reset the contents of the multicast
+ receive filters on the network interface to their
+ default values.
+ @param McastFilterCnt Number of multicast HW MAC addresses in the new
+ MCastFilter list. This value must be less than or
+ equal to the MCastFilterCnt field of
+ EFI_SIMPLE_NETWORK_MODE. This field is optional if
+ ResetMCastFilter is TRUE.
+ @param MCastFilter A pointer to a list of new multicast receive filter
+ HW MAC addresses. This list will replace any
+ existing multicast HW MAC address list. This field
+ is optional if ResetMCastFilter is TRUE.
+
+ @retval EFI_SUCCESS The multicast receive filter list was updated.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an
+ unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network
+ interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network
+ interface.
+
+**/
+
+EFI_STATUS
+EFIAPI
+E1kNetReceiveFilters (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINT32 Enable,
+ IN UINT32 Disable,
+ IN BOOLEAN ResetMCastFilter,
+ IN UINTN MCastFilterCnt OPTIONAL,
+ IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL
+ )
+{
+ E1K_NET_DEV *Dev;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = E1K_NET_FROM_SNP (This);
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ switch (Dev->Snm.State) {
+ case EfiSimpleNetworkStopped:
+ Status = EFI_NOT_STARTED;
+ goto Exit;
+ case EfiSimpleNetworkStarted:
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ default:
+ break;
+ }
+
+ //
+ // MNP apparently fails to initialize on top of us if we simply return
+ // EFI_UNSUPPORTED in this function.
+ //
+ // Hence we openly refuse multicast functionality, and fake the rest by
+ // selecting a no stricter filter setting than whatever is requested. The
+ // UEFI-2.3.1+errC spec allows this. In practice we don't change our current
+ // (default) filter. Additionally, receiving software is responsible for
+ // discarding any packets getting through the filter.
+ //
+ Status = (
+ ((Enable | Disable) & ~Dev->Snm.ReceiveFilterMask) != 0 ||
+ (!ResetMCastFilter && MCastFilterCnt > Dev->Snm.MaxMCastFilterCount)
+ ) ? EFI_INVALID_PARAMETER : EFI_SUCCESS;
+
+Exit:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpSharedHelpers.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpSharedHelpers.c
new file mode 100644
index 00000000..01a02d7a
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpSharedHelpers.c
@@ -0,0 +1,281 @@
+/** @file
+
+ Helper functions used by at least two Simple Network Protocol methods.
+
+ Copyright (c) 2021, Oracle and/or its affiliates.
+ Copyright (C) 2013, Red Hat, Inc.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/MemoryAllocationLib.h>
+
+#include "E1kNet.h"
+
+//
+// The user structure for the ordered collection that will track the mapping
+// info of the packets queued in TxRing
+//
+typedef struct {
+ VOID *Buffer;
+ EFI_PHYSICAL_ADDRESS DeviceAddress; // lookup key for reverse mapping
+ VOID *BufMap;
+} TX_BUF_MAP_INFO;
+
+/**
+ Release RX and TX resources on the boundary of the
+ EfiSimpleNetworkInitialized state.
+
+ These functions contribute to rolling back a partial, failed initialization
+ of the e1000 SNP driver instance, or to shutting down a fully
+ initialized, running instance.
+
+ They are only callable by the E1kNetInitialize() and the
+ E1kNetShutdown() SNP methods. See the state diagram in "E1kNet.h".
+
+ @param[in,out] Dev The E1K_NET_DEV driver instance being shut down, or whose
+ partial, failed initialization is being rolled back.
+*/
+
+VOID
+EFIAPI
+E1kNetShutdownRx (
+ IN OUT E1K_NET_DEV *Dev
+ )
+{
+ Dev->PciIo->Unmap (Dev->PciIo, Dev->RxMap);
+ Dev->PciIo->FreeBuffer (
+ Dev->PciIo,
+ Dev->RxBufNrPages,
+ Dev->RxRing
+ );
+}
+
+
+VOID
+EFIAPI
+E1kNetShutdownTx (
+ IN OUT E1K_NET_DEV *Dev
+ )
+{
+ ORDERED_COLLECTION_ENTRY *Entry, *Entry2;
+ TX_BUF_MAP_INFO *TxBufMapInfo;
+ VOID *UserStruct;
+
+ Dev->PciIo->Unmap (Dev->PciIo, Dev->TxRingMap);
+ Dev->PciIo->FreeBuffer (
+ Dev->PciIo,
+ EFI_SIZE_TO_PAGES (Dev->TxMaxPending * sizeof (*Dev->TxRing)),
+ Dev->TxRing
+ );
+
+ for (Entry = OrderedCollectionMin (Dev->TxBufCollection);
+ Entry != NULL;
+ Entry = Entry2) {
+ Entry2 = OrderedCollectionNext (Entry);
+ OrderedCollectionDelete (Dev->TxBufCollection, Entry, &UserStruct);
+ TxBufMapInfo = UserStruct;
+ Dev->PciIo->Unmap (Dev->PciIo, TxBufMapInfo->BufMap);
+ FreePool (TxBufMapInfo);
+ }
+ OrderedCollectionUninit (Dev->TxBufCollection);
+}
+
+/**
+ Map Caller-supplied TxBuf buffer to the device-mapped address
+
+ @param[in] Dev The E1K_NET_DEV driver instance which wants to
+ map the Tx packet.
+ @param[in] Buffer The system physical address of TxBuf
+ @param[in] NumberOfBytes Number of bytes to map
+ @param[out] DeviceAddress The resulting device address for the bus
+ master access.
+
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to
+ a lack of resources.
+ @return Status codes from
+ VirtioMapAllBytesInSharedBuffer()
+ @retval EFI_SUCCESS Caller-supplied buffer is successfully mapped.
+*/
+EFI_STATUS
+EFIAPI
+E1kNetMapTxBuf (
+ IN E1K_NET_DEV *Dev,
+ IN VOID *Buffer,
+ IN UINTN NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress
+ )
+{
+ EFI_STATUS Status;
+ TX_BUF_MAP_INFO *TxBufMapInfo;
+ EFI_PHYSICAL_ADDRESS Address;
+ VOID *Mapping;
+
+ TxBufMapInfo = AllocatePool (sizeof (*TxBufMapInfo));
+ if (TxBufMapInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = Dev->PciIo->Map (
+ Dev->PciIo,
+ EfiPciIoOperationBusMasterRead,
+ Buffer,
+ &NumberOfBytes,
+ &Address,
+ &Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ goto FreeTxBufMapInfo;
+ }
+
+ TxBufMapInfo->Buffer = Buffer;
+ TxBufMapInfo->DeviceAddress = Address;
+ TxBufMapInfo->BufMap = Mapping;
+
+ Status = OrderedCollectionInsert (
+ Dev->TxBufCollection,
+ NULL,
+ TxBufMapInfo
+ );
+ switch (Status) {
+ case EFI_OUT_OF_RESOURCES:
+ goto UnmapTxBuf;
+ case EFI_ALREADY_STARTED:
+ //
+ // This should never happen: it implies
+ //
+ // - an identity-mapping VIRTIO_DEVICE_PROTOCOL.MapSharedBuffer()
+ // implementation -- which is fine,
+ //
+ // - and an SNP client that queues multiple instances of the exact same
+ // buffer address with SNP.Transmit() -- which is undefined behavior,
+ // based on the TxBuf language in UEFI-2.7,
+ // EFI_SIMPLE_NETWORK.GetStatus().
+ //
+ ASSERT (FALSE);
+ Status = EFI_INVALID_PARAMETER;
+ goto UnmapTxBuf;
+ default:
+ ASSERT_EFI_ERROR (Status);
+ break;
+ }
+
+ *DeviceAddress = Address;
+ return EFI_SUCCESS;
+
+UnmapTxBuf:
+ Dev->PciIo->Unmap (Dev->PciIo, Mapping);
+
+FreeTxBufMapInfo:
+ FreePool (TxBufMapInfo);
+ return Status;
+}
+
+/**
+ Unmap (aka reverse mapping) device mapped TxBuf buffer to the system
+ physical address
+
+ @param[in] Dev The E1K_NET_DEV driver instance which wants to
+ reverse- and unmap the Tx packet.
+ @param[out] Buffer The system physical address of TxBuf
+ @param[in] DeviceAddress The device address for the TxBuf
+
+ @retval EFI_INVALID_PARAMETER The DeviceAddress is not mapped
+ @retval EFI_SUCCESS The TxBuf at DeviceAddress has been unmapped,
+ and Buffer has been set to TxBuf's system
+ physical address.
+
+*/
+EFI_STATUS
+EFIAPI
+E1kNetUnmapTxBuf (
+ IN E1K_NET_DEV *Dev,
+ OUT VOID **Buffer,
+ IN EFI_PHYSICAL_ADDRESS DeviceAddress
+ )
+{
+ ORDERED_COLLECTION_ENTRY *Entry;
+ TX_BUF_MAP_INFO *TxBufMapInfo;
+ VOID *UserStruct;
+
+ Entry = OrderedCollectionFind (Dev->TxBufCollection, &DeviceAddress);
+ if (Entry == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OrderedCollectionDelete (Dev->TxBufCollection, Entry, &UserStruct);
+
+ TxBufMapInfo = UserStruct;
+
+ *Buffer = TxBufMapInfo->Buffer;
+ Dev->PciIo->Unmap (Dev->PciIo, TxBufMapInfo->BufMap);
+ FreePool (TxBufMapInfo);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Comparator function for two TX_BUF_MAP_INFO objects.
+
+ @param[in] UserStruct1 Pointer to the first TX_BUF_MAP_INFO object.
+
+ @param[in] UserStruct2 Pointer to the second TX_BUF_MAP_INFO object.
+
+ @retval <0 If UserStruct1 compares less than UserStruct2.
+
+ @retval 0 If UserStruct1 compares equal to UserStruct2.
+
+ @retval >0 If UserStruct1 compares greater than UserStruct2.
+*/
+INTN
+EFIAPI
+E1kNetTxBufMapInfoCompare (
+ IN CONST VOID *UserStruct1,
+ IN CONST VOID *UserStruct2
+ )
+{
+ CONST TX_BUF_MAP_INFO *MapInfo1;
+ CONST TX_BUF_MAP_INFO *MapInfo2;
+
+ MapInfo1 = UserStruct1;
+ MapInfo2 = UserStruct2;
+
+ return MapInfo1->DeviceAddress < MapInfo2->DeviceAddress ? -1 :
+ MapInfo1->DeviceAddress > MapInfo2->DeviceAddress ? 1 :
+ 0;
+}
+
+/**
+ Compare a standalone DeviceAddress against a TX_BUF_MAP_INFO object
+ containing an embedded DeviceAddress.
+
+ @param[in] StandaloneKey Pointer to DeviceAddress, which has type
+ EFI_PHYSICAL_ADDRESS.
+
+ @param[in] UserStruct Pointer to the TX_BUF_MAP_INFO object with the
+ embedded DeviceAddress.
+
+ @retval <0 If StandaloneKey compares less than UserStruct's key.
+
+ @retval 0 If StandaloneKey compares equal to UserStruct's key.
+
+ @retval >0 If StandaloneKey compares greater than UserStruct's key.
+**/
+INTN
+EFIAPI
+E1kNetTxBufDeviceAddressCompare (
+ IN CONST VOID *StandaloneKey,
+ IN CONST VOID *UserStruct
+ )
+{
+ CONST EFI_PHYSICAL_ADDRESS *DeviceAddress;
+ CONST TX_BUF_MAP_INFO *MapInfo;
+
+ DeviceAddress = StandaloneKey;
+ MapInfo = UserStruct;
+
+ return *DeviceAddress < MapInfo->DeviceAddress ? -1 :
+ *DeviceAddress > MapInfo->DeviceAddress ? 1 :
+ 0;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpShutdown.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpShutdown.c
new file mode 100644
index 00000000..d4dede01
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpShutdown.c
@@ -0,0 +1,74 @@
+/** @file
+
+ Implementation of the SNP.Shutdown() function and its private helpers if any.
+
+ Copyright (c) 2021, Oracle and/or its affiliates.
+ Copyright (c) 2017, AMD Inc, All rights reserved.
+ Copyright (C) 2013, Red Hat, Inc.
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/UefiBootServicesTableLib.h>
+
+#include "E1kNet.h"
+
+/**
+ Resets a network adapter and leaves it in a state that is safe for another
+ driver to initialize.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The network interface was shutdown.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an
+ unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network
+ interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network
+ interface.
+
+**/
+
+EFI_STATUS
+EFIAPI
+E1kNetShutdown (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+{
+ E1K_NET_DEV *Dev;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ DEBUG((DEBUG_INFO, "E1kNetShutdown:\n"));
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = E1K_NET_FROM_SNP (This);
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ switch (Dev->Snm.State) {
+ case EfiSimpleNetworkStopped:
+ Status = EFI_NOT_STARTED;
+ goto Exit;
+ case EfiSimpleNetworkStarted:
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ default:
+ break;
+ }
+
+ E1kNetDevReset(Dev);
+ E1kNetShutdownRx (Dev);
+ E1kNetShutdownTx (Dev);
+
+ Dev->Snm.State = EfiSimpleNetworkStarted;
+ Status = EFI_SUCCESS;
+
+Exit:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpStart.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpStart.c
new file mode 100644
index 00000000..7dd48081
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpStart.c
@@ -0,0 +1,59 @@
+/** @file
+
+ Implementation of the SNP.Start() function and its private helpers if any.
+
+ Copyright (c) 2021, Oracle and/or its affiliates.
+ Copyright (C) 2013, Red Hat, Inc.
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/UefiBootServicesTableLib.h>
+
+#include "E1kNet.h"
+
+/**
+ Changes the state of a network interface from "stopped" to "started".
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The network interface was started.
+ @retval EFI_ALREADY_STARTED The network interface is already in the started
+ state.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an
+ unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network
+ interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network
+ interface.
+**/
+
+EFI_STATUS
+EFIAPI
+E1kNetStart (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+{
+ E1K_NET_DEV *Dev;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = E1K_NET_FROM_SNP (This);
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ if (Dev->Snm.State != EfiSimpleNetworkStopped) {
+ Status = EFI_ALREADY_STARTED;
+ }
+ else {
+ Dev->Snm.State = EfiSimpleNetworkStarted;
+ Status = EFI_SUCCESS;
+ }
+
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpStop.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpStop.c
new file mode 100644
index 00000000..8f564ebb
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpStop.c
@@ -0,0 +1,60 @@
+/** @file
+
+ Implementation of the SNP.Stop() function and its private helpers if any.
+
+ Copyright (c) 2021, Oracle and/or its affiliates.
+ Copyright (C) 2013, Red Hat, Inc.
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/UefiBootServicesTableLib.h>
+
+#include "E1kNet.h"
+
+/**
+ Changes the state of a network interface from "started" to "stopped".
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The network interface was stopped.
+ @retval EFI_ALREADY_STARTED The network interface is already in the stopped
+ state.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an
+ unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network
+ interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network
+ interface.
+
+**/
+
+EFI_STATUS
+EFIAPI
+E1kNetStop (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+{
+ E1K_NET_DEV *Dev;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = E1K_NET_FROM_SNP (This);
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ if (Dev->Snm.State != EfiSimpleNetworkStarted) {
+ Status = EFI_NOT_STARTED;
+ }
+ else {
+ Dev->Snm.State = EfiSimpleNetworkStopped;
+ Status = EFI_SUCCESS;
+ }
+
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpTransmit.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpTransmit.c
new file mode 100644
index 00000000..6dead2b0
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpTransmit.c
@@ -0,0 +1,170 @@
+/** @file
+
+ Implementation of the SNP.Transmit() function and its private helpers if any.
+
+ Copyright (c) 2021, Oracle and/or its affiliates.
+ Copyright (C) 2013, Red Hat, Inc.
+ Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include "E1kNet.h"
+
+/**
+ Places a packet in the transmit queue of a network interface.
+
+ @param This The protocol instance pointer.
+ @param HeaderSize The size, in bytes, of the media header to be filled in by
+ the Transmit() function. If HeaderSize is non-zero, then
+ it must be equal to This->Mode->MediaHeaderSize and the
+ DestAddr and Protocol parameters must not be NULL.
+ @param BufferSize The size, in bytes, of the entire packet (media header and
+ data) to be transmitted through the network interface.
+ @param Buffer A pointer to the packet (media header followed by data) to
+ be transmitted. This parameter cannot be NULL. If
+ HeaderSize is zero, then the media header in Buffer must
+ already be filled in by the caller. If HeaderSize is
+ non-zero, then the media header will be filled in by the
+ Transmit() function.
+ @param SrcAddr The source HW MAC address. If HeaderSize is zero, then
+ this parameter is ignored. If HeaderSize is non-zero and
+ SrcAddr is NULL, then This->Mode->CurrentAddress is used
+ for the source HW MAC address.
+ @param DestAddr The destination HW MAC address. If HeaderSize is zero,
+ then this parameter is ignored.
+ @param Protocol The type of header to build. If HeaderSize is zero, then
+ this parameter is ignored. See RFC 1700, section "Ether
+ Types", for examples.
+
+ @retval EFI_SUCCESS The packet was placed on the transmit queue.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_NOT_READY The network interface is too busy to accept
+ this transmit request.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an
+ unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network
+ interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network
+ interface.
+
+**/
+
+EFI_STATUS
+EFIAPI
+E1kNetTransmit (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINTN HeaderSize,
+ IN UINTN BufferSize,
+ IN /* +OUT! */ VOID *Buffer,
+ IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
+ IN EFI_MAC_ADDRESS *DestAddr OPTIONAL,
+ IN UINT16 *Protocol OPTIONAL
+ )
+{
+ E1K_NET_DEV *Dev;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS DeviceAddress;
+
+ DEBUG((DEBUG_INFO, "E1kNetTransmit: HeaderSize=%u BufferSize=%u Buffer=%p\n",
+ HeaderSize, BufferSize, Buffer));
+
+ if (This == NULL || BufferSize == 0 || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Dev = E1K_NET_FROM_SNP (This);
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ switch (Dev->Snm.State) {
+ case EfiSimpleNetworkStopped:
+ Status = EFI_NOT_STARTED;
+ goto Exit;
+ case EfiSimpleNetworkStarted:
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ default:
+ break;
+ }
+
+ if (BufferSize < Dev->Snm.MediaHeaderSize) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Exit;
+ }
+ if (BufferSize > Dev->Snm.MediaHeaderSize + Dev->Snm.MaxPacketSize) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ //
+ // check if we have room for transmission
+ //
+ ASSERT (Dev->TxCurPending <= Dev->TxMaxPending);
+ if (Dev->TxCurPending == Dev->TxMaxPending) {
+ Status = EFI_NOT_READY;
+ goto Exit;
+ }
+
+ //
+ // the caller may want us to fill in the media header:
+ // dst MAC, src MAC, Ethertype
+ //
+ if (HeaderSize != 0) {
+ UINT8 *Ptr;
+
+ if (HeaderSize != Dev->Snm.MediaHeaderSize ||
+ DestAddr == NULL || Protocol == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+ Ptr = Buffer;
+ ASSERT (sizeof (E1K_NET_MAC) <= sizeof (EFI_MAC_ADDRESS));
+
+ CopyMem (Ptr, DestAddr, sizeof (E1K_NET_MAC));
+ Ptr += sizeof (E1K_NET_MAC);
+
+ CopyMem (Ptr,
+ (SrcAddr == NULL) ? &Dev->Snm.CurrentAddress : SrcAddr,
+ sizeof (E1K_NET_MAC));
+ Ptr += sizeof (E1K_NET_MAC);
+
+ *Ptr++ = (UINT8) (*Protocol >> 8);
+ *Ptr++ = (UINT8) *Protocol;
+
+ ASSERT ((UINTN) (Ptr - (UINT8 *) Buffer) == Dev->Snm.MediaHeaderSize);
+ }
+
+ //
+ // Map the transmit buffer system physical address to device address.
+ //
+ Status = E1kNetMapTxBuf (
+ Dev,
+ Buffer,
+ BufferSize,
+ &DeviceAddress
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Dev->TxCurPending++;
+ Dev->TxRing[Dev->TxLastUsed].AddrBufferLow = (UINT32)DeviceAddress;
+ Dev->TxRing[Dev->TxLastUsed].AddrBufferHigh = (UINT32)RShiftU64(DeviceAddress, 32);
+ Dev->TxRing[Dev->TxLastUsed].BufferLength = (UINT16)BufferSize;
+ Dev->TxRing[Dev->TxLastUsed].Status = 0;
+ Dev->TxRing[Dev->TxLastUsed].Command = E1K_TX_CMD_EOP | E1K_TX_CMD_FCS | E1K_TX_CMD_RS;
+
+ Dev->TxLastUsed = (Dev->TxLastUsed + 1) % E1K_NET_MAX_PENDING;
+ E1kNetRegWrite32(Dev, E1K_REG_TDT, Dev->TxLastUsed);
+
+Exit:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpUnsupported.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpUnsupported.c
new file mode 100644
index 00000000..d66594e2
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/E1kNetDxe/SnpUnsupported.c
@@ -0,0 +1,155 @@
+/** @file
+
+ Empty implementation of the SNP methods that dependent protocols don't
+ absolutely need and the UEFI-2.3.1+errC specification allows us not to
+ support.
+
+ Copyright (c) 2021, Oracle and/or its affiliates.
+ Copyright (C) 2013, Red Hat, Inc.
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "E1kNet.h"
+
+/**
+ Resets a network adapter and re-initializes it with the parameters that were
+ provided in the previous call to Initialize().
+
+ @param This The protocol instance pointer.
+ @param ExtendedVerification Indicates that the driver may perform a more
+ exhaustive verification operation of the device
+ during reset.
+
+ @retval EFI_SUCCESS The network interface was reset.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an
+ unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network
+ interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network
+ interface.
+
+**/
+
+EFI_STATUS
+EFIAPI
+E1kNetReset (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Modifies or resets the current station address, if supported.
+
+ @param This The protocol instance pointer.
+ @param Reset Flag used to reset the station address to the network
+ interfaces permanent address.
+ @param New The new station address to be used for the network interface.
+
+ @retval EFI_SUCCESS The network interfaces station address was
+ updated.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an
+ unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network
+ interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network
+ interface.
+
+**/
+
+EFI_STATUS
+EFIAPI
+E1kNetStationAddress (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN Reset,
+ IN EFI_MAC_ADDRESS *New OPTIONAL
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Resets or collects the statistics on a network interface.
+
+ @param This Protocol instance pointer.
+ @param Reset Set to TRUE to reset the statistics for the network
+ interface.
+ @param StatisticsSize On input the size, in bytes, of StatisticsTable. On
+ output the size, in bytes, of the resulting table of
+ statistics.
+ @param StatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure
+ that contains the statistics.
+
+ @retval EFI_SUCCESS The statistics were collected from the network
+ interface.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_BUFFER_TOO_SMALL The Statistics buffer was too small. The
+ current buffer size needed to hold the
+ statistics is returned in StatisticsSize.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an
+ unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network
+ interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network
+ interface.
+
+**/
+
+EFI_STATUS
+EFIAPI
+E1kNetStatistics (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN Reset,
+ IN OUT UINTN *StatisticsSize OPTIONAL,
+ OUT EFI_NETWORK_STATISTICS *StatisticsTable OPTIONAL
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Performs read and write operations on the NVRAM device attached to a network
+ interface.
+
+ @param This The protocol instance pointer.
+ @param ReadWrite TRUE for read operations, FALSE for write operations.
+ @param Offset Byte offset in the NVRAM device at which to start the read
+ or write operation. This must be a multiple of
+ NvRamAccessSize and less than NvRamSize.
+ @param BufferSize The number of bytes to read or write from the NVRAM
+ device. This must also be a multiple of NvramAccessSize.
+ @param Buffer A pointer to the data buffer.
+
+ @retval EFI_SUCCESS The NVRAM access was performed.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an
+ unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network
+ interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network
+ interface.
+
+**/
+
+EFI_STATUS
+EFIAPI
+E1kNetNvData (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN ReadWrite,
+ IN UINTN Offset,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Include/DevEFI.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Include/DevEFI.h
new file mode 100644
index 00000000..e59e0915
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Include/DevEFI.h
@@ -0,0 +1,38 @@
+/* $Id: DevEFI.h $ */
+/** @file
+ * EFI for VirtualBox Common Definitions.
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+#include "../../../DevEFI.h"
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Include/Guid/VBoxFsBlessedFileInfo.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Include/Guid/VBoxFsBlessedFileInfo.h
new file mode 100644
index 00000000..7fd22f01
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Include/Guid/VBoxFsBlessedFileInfo.h
@@ -0,0 +1,58 @@
+/* $Id */
+/** @file
+ * Provides a GUID and a data structure that can be used with EFI_FILE_PROTOCOL.GetInfo()
+ * or EFI_FILE_PROTOCOL.SetInfo() to get or set the system's volume blessed file (for booting).
+ */
+
+/*
+ * Copyright (C) 2019-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+#ifndef __VBOX_FS_BLESSED_FILE_INFO_H__
+#define __VBOX_FS_BLESSED_FILE_INFO_H__
+
+#define VBOX_FS_BLESSED_FILE_ID \
+ { \
+ 0xCC49FEFD, 0x41B7, 0x9823, { 0x98, 0x23, 0x0E, 0x8E, 0xBF, 0x35, 0x67, 0x7D } \
+ }
+
+typedef struct {
+ ///
+ /// The Null-terminated string that is the volume's label.
+ ///
+ CHAR16 BlessedFile[1];
+} VBOX_FS_BLESSED_FILE;
+
+#define SIZE_OF_VBOX_FS_BLESSED_FILE \
+ OFFSET_OF (VBOX_FS_BLESSED_FILE, BlessedFile)
+
+extern EFI_GUID gVBoxFsBlessedFileInfoGuid;
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Include/IndustryStandard/VBoxFatImage.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Include/IndustryStandard/VBoxFatImage.h
new file mode 100644
index 00000000..7cf9f646
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Include/IndustryStandard/VBoxFatImage.h
@@ -0,0 +1,64 @@
+/** @file
+ * FAT binary definitions.
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/** @todo Rename this file and/or reintegrate the FAT changes into MdePkg. */
+#ifndef ___VBoxFatImage_h
+#define ___VBoxFatImage_h
+
+#define EFI_TE_IMAGE_HEADER_SIGNATURE SIGNATURE_16('V', 'Z')
+typedef struct _EFI_FAT_IMAGE_HEADER
+{
+ UINT32 Signature;
+ UINT32 NFatArch;
+} EFI_FAT_IMAGE_HEADER;
+
+#define EFI_FAT_IMAGE_HEADER_SIGNATURE 0xef1fab9 /* Note: it's deiffer from 0xcafebabe */
+typedef struct _EFI_FAT_IMAGE_HEADER_NLIST
+{
+ UINT32 CpuType;
+ UINT32 CpuSubType;
+ UINT32 Offset;
+ UINT32 Size;
+ UINT32 Align;
+} EFI_FAT_IMAGE_HEADER_NLIST;
+
+#define EFI_FAT_CPU_TYPE_I386 0x7
+#define EFI_FAT_CPU_TYPE_X64 0x1000007
+
+#define EFI_FAT_CPU_SUB_TYPE_PC 0x3
+
+
+#endif /* !___VBoxFatImage_h */
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Include/VBoxDebugLib.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Include/VBoxDebugLib.h
new file mode 100644
index 00000000..b4baca6d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Include/VBoxDebugLib.h
@@ -0,0 +1,50 @@
+/* $Id: VBoxDebugLib.h $ */
+/** @file
+ * VBoxDebugLib.h - Debug and logging routines implemented by VBoxDebugLib.
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+#ifndef ___VBoxPkg_VBoxDebugLib_h
+#define ___VBoxPkg_VBoxDebugLib_h
+
+#include <Uefi/UefiBaseType.h>
+#include "VBoxPkg.h"
+
+size_t VBoxPrintChar(int ch);
+size_t VBoxPrintGuid(CONST EFI_GUID *pGuid);
+size_t VBoxPrintHex(UINT64 uValue, size_t cbType);
+size_t VBoxPrintHexDump(const void *pv, size_t cb);
+size_t VBoxPrintString(const char *pszString);
+
+#endif
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Include/VBoxMemLayout.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Include/VBoxMemLayout.h
new file mode 100644
index 00000000..9c4b4cf9
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Include/VBoxMemLayout.h
@@ -0,0 +1,44 @@
+/* $Id: VBoxMemLayout.h $ */
+/** @file
+ * VBoxMemLayout.h - Constants defining the memory layout. (Merge with DevEFI?)
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+#ifndef ___VBoxMemLayout_h
+#define ___VBoxMemLayout_h
+
+#define VBOXSEC_STACK_BASE (1*1024*1024)
+#define VBOXSEC_STACK_SIZE (128*1024)
+
+#endif
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Include/VBoxPkg.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Include/VBoxPkg.h
new file mode 100644
index 00000000..9f3fb199
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Include/VBoxPkg.h
@@ -0,0 +1,69 @@
+/* $Id: VBoxPkg.h $ */
+/** @file
+ * VBoxPkg.h - Common header, must be include before IPRT and VBox headers.
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+#ifndef ___VBoxPkg_h
+#define ___VBoxPkg_h
+
+/*
+ * IPRT configuration.
+ */
+#define IN_RING0
+/** @todo detect this */
+//#include <iprt/cdefs.h>
+#if !defined(ARCH_BITS) || !defined(HC_ARCH_BITS)
+//# error "please add right bitness"
+#endif
+
+/*
+ * VBox and IPRT headers.
+ */
+#include <VBox/version.h>
+#include <iprt/types.h>
+#ifdef _MSC_VER
+# pragma warning(disable: 4389)
+# pragma warning(disable: 4245)
+# pragma warning(disable: 4244)
+#endif
+#include <iprt/asm.h>
+#include <iprt/asm-amd64-x86.h>
+#ifdef _MSC_VER
+# pragma warning(default: 4244)
+# pragma warning(default: 4245)
+# pragma warning(default: 4389)
+#endif
+
+#endif
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugAgentLib/VBoxDebugAgentLib.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugAgentLib/VBoxDebugAgentLib.c
new file mode 100644
index 00000000..94b5eee5
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugAgentLib/VBoxDebugAgentLib.c
@@ -0,0 +1,97 @@
+/* $Id: VBoxDebugAgentLib.c $ */
+/** @file
+ * VBox implementation of DebugAgentLib that reports EFI state transitions
+ * to DevEFI for debugging purposes.
+ */
+
+/*
+ * Copyright (C) 2013-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <Base.h>
+#include <Library/DebugAgentLib.h>
+#include <Library/DebugLib.h>
+#include "VBoxPkg.h"
+#include "../../../../DevEFI.h"
+
+
+VOID
+EFIAPI
+InitializeDebugAgent(
+ IN UINT32 InitFlag,
+ IN VOID *Context OPTIONAL,
+ IN DEBUG_AGENT_CONTINUE Function OPTIONAL
+ )
+{
+ /*
+ * Do the reporting.
+ */
+ EFIDBGPOINT enmDbgPoint;
+ switch (InitFlag)
+ {
+ case DEBUG_AGENT_INIT_PREMEM_SEC: enmDbgPoint = EFIDBGPOINT_SEC_PREMEM; break;
+ case DEBUG_AGENT_INIT_POSTMEM_SEC: enmDbgPoint = EFIDBGPOINT_SEC_POSTMEM; break;
+ case DEBUG_AGENT_INIT_DXE_CORE: enmDbgPoint = EFIDBGPOINT_DXE_CORE; break;
+ case DEBUG_AGENT_INIT_SMM: enmDbgPoint = EFIDBGPOINT_SMM; break;
+ case DEBUG_AGENT_INIT_ENTER_SMI: enmDbgPoint = EFIDBGPOINT_SMI_ENTER; break;
+ case DEBUG_AGENT_INIT_EXIT_SMI: enmDbgPoint = EFIDBGPOINT_SMI_EXIT; break;
+ case DEBUG_AGENT_INIT_S3: enmDbgPoint = EFIDBGPOINT_GRAPHICS; break;
+ case DEBUG_AGENT_INIT_DXE_AP: enmDbgPoint = EFIDBGPOINT_DXE_AP; break;
+ default:
+ ASSERT(false);
+ enmDbgPoint = EFIDBGPOINT_INVALID;
+ break;
+ }
+ if (enmDbgPoint != EFIDBGPOINT_INVALID)
+ ASMOutU32(EFI_PORT_DEBUG_POINT, enmDbgPoint);
+
+
+ /*
+ * Call resume function if supplied.
+ */
+ if (Function)
+ Function(Context);
+}
+
+
+BOOLEAN
+EFIAPI
+SaveAndSetDebugTimerInterrupt(
+ IN BOOLEAN EnableStatus
+ )
+{
+ NOREF(EnableStatus);
+ return FALSE;
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugAgentLib/VBoxDebugAgentLib.inf b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugAgentLib/VBoxDebugAgentLib.inf
new file mode 100644
index 00000000..5ea5091e
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugAgentLib/VBoxDebugAgentLib.inf
@@ -0,0 +1,54 @@
+# $Id: VBoxDebugAgentLib.inf $
+## @file
+# VBox implementation of DebugAgentLib that reports EFI state transitions
+# to DevEFI (for debugging purposes).
+#
+
+#
+# Copyright (C) 2013-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>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VBoxDebugAgentLib
+ FILE_GUID = A13AC320-4717-99C4-B7FF-53A7D84326B0
+ MODULE_TYPE = BASE
+ VERSION_STRING = 4.3
+ LIBRARY_CLASS = DebugAgentLib
+
+[Sources.common]
+ VBoxDebugAgentLib.c
+
+[Packages]
+ VBoxPkg/VBoxPkg.dec
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugLib/VBoxDebugLib.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugLib/VBoxDebugLib.c
new file mode 100644
index 00000000..16986bc1
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugLib/VBoxDebugLib.c
@@ -0,0 +1,227 @@
+/* $Id: VBoxDebugLib.c $ */
+/** @file
+ * VBoxDebugLib.c - Debug logging and assertions support routines using DevEFI.
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <Base.h>
+#include <Library/BaseLib.h>
+#include <Library/PrintLib.h>
+#include <Library/DebugLib.h>
+
+#include "VBoxDebugLib.h"
+#include <Protocol/DevicePath.h>
+#include <Protocol/DevicePathToText.h>
+#include <Uefi/UefiSpec.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include "DevEFI.h"
+#include "iprt/asm.h"
+
+
+VOID EFIAPI
+DebugPrint(IN UINTN ErrorLevel, IN CONST CHAR8 *Format, ...)
+{
+ CHAR8 szBuf[256];
+ VA_LIST va;
+ UINTN cch;
+ BOOLEAN InterruptState;
+
+ /* No pool noise, please. */
+ if (ErrorLevel == DEBUG_POOL)
+ return;
+
+ VA_START(va, Format);
+ cch = AsciiVSPrint(szBuf, sizeof(szBuf), Format, va);
+ VA_END(va);
+
+ /* make sure it's terminated and doesn't end with a newline */
+ if (cch >= sizeof(szBuf))
+ cch = sizeof(szBuf) - 1;
+ while (cch > 0 && (szBuf[cch - 1] == '\n' || szBuf[cch - 1] == '\r'))
+ cch--;
+ szBuf[cch] = '\0';
+
+ InterruptState = SaveAndDisableInterrupts();
+
+ /* Output the log string. */
+ VBoxPrintString("dbg/");
+ VBoxPrintHex(ErrorLevel, sizeof(ErrorLevel));
+ VBoxPrintChar(' ');
+ VBoxPrintString(szBuf);
+ VBoxPrintChar('\n');
+
+ SetInterruptState(InterruptState);
+}
+
+/**
+ * Our own log worker function, avoid the dbg/00000xxx prefix and makes it clear
+ * which log statements we added..
+ *
+ * @param pszFormat Format string. EFI style!
+ * @param ... Argument referneced in the format string.
+ */
+VOID EFIAPI
+VBoxLogWorker(const char *pszFormat, ...)
+{
+ CHAR8 szBuf[384];
+ VA_LIST va;
+ BOOLEAN InterruptState;
+
+ /* Format it. */
+ VA_START(va, pszFormat);
+ AsciiVSPrint(szBuf, sizeof(szBuf), pszFormat, va);
+ VA_END(va);
+ szBuf[sizeof(szBuf) - 1] = '\0';
+
+ InterruptState = SaveAndDisableInterrupts();
+
+ /* Output the log string. */
+ VBoxPrintString(szBuf);
+ VBoxPrintChar('\n');
+
+ SetInterruptState(InterruptState);
+}
+
+/**
+ * Adds a character to the panic message.
+ *
+ * @param ch The ASCII char to add.
+ */
+static void
+VBoxPanicMsgChar(int ch)
+{
+ ASMOutU16(EFI_PANIC_PORT, EFI_PANIC_CMD_MSG_FROM_CHAR(ch));
+}
+
+/**
+ * Adds a string to the panic message.
+ *
+ * @param pszString The string to add.
+ */
+static void
+VBoxPanicMsgString(const char *pszString)
+{
+ char ch;
+ while ((ch = *pszString++) != '\0')
+ VBoxPanicMsgChar(ch);
+}
+
+/**
+ * Adds a unsigned decimal number to the panic message.
+ *
+ * @param uValue The value.
+ */
+static void
+VBoxPanicMsgDecimalU32(uint32_t uValue)
+{
+ char szTmp[32];
+ unsigned off = sizeof(szTmp) - 1;
+
+ szTmp[off] = '\0';
+ do
+ {
+ char chDigit = uValue % 10;
+ uValue /= 10;
+ szTmp[--off] = chDigit + '0';
+ } while (uValue != 0 && off > 0);
+
+ VBoxPanicMsgString(&szTmp[off]);
+}
+
+VOID EFIAPI
+DebugAssert(IN CONST CHAR8 *FileName, IN UINTN LineNumber, IN CONST CHAR8 *Description)
+{
+ BOOLEAN InterruptState = SaveAndDisableInterrupts();
+
+ ASMOutU8(EFI_PANIC_PORT, EFI_PANIC_CMD_START_MSG);
+ VBoxPanicMsgString("EFI Assertion failed!"
+ "\nFile: ");
+ VBoxPanicMsgString(FileName ? FileName : "<NULL>");
+ VBoxPanicMsgString("\nLine: ");
+ VBoxPanicMsgDecimalU32((uint32_t)LineNumber);
+ VBoxPanicMsgString("\nDescription: ");
+ VBoxPanicMsgString(Description ? Description : "<NULL>");
+ ASMOutU8(EFI_PANIC_PORT, EFI_PANIC_CMD_END_MSG);
+
+ SetInterruptState(InterruptState);
+}
+
+
+VOID * EFIAPI
+DebugClearMemory(OUT VOID *Buffer, IN UINTN Length)
+{
+ return Buffer;
+}
+
+
+BOOLEAN EFIAPI
+DebugAssertEnabled(VOID)
+{
+ return TRUE;
+}
+
+
+BOOLEAN EFIAPI
+DebugPrintEnabled(VOID)
+{
+ /** @todo some PCD for this so we can disable it in release builds. */
+ return TRUE;
+}
+
+
+BOOLEAN EFIAPI
+DebugPrintLevelEnabled(IN CONST UINTN ErrorLevel)
+{
+ /** @todo some PCD for this so we can disable it in release builds. */
+ return TRUE;
+}
+
+
+BOOLEAN EFIAPI
+DebugCodeEnabled(VOID)
+{
+ /** @todo ditto */
+ return TRUE;
+}
+
+
+BOOLEAN EFIAPI
+DebugClearMemoryEnabled(VOID)
+{
+ return FALSE;
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugLib/VBoxDebugLib.inf b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugLib/VBoxDebugLib.inf
new file mode 100644
index 00000000..60c1b067
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugLib/VBoxDebugLib.inf
@@ -0,0 +1,85 @@
+# $Id: VBoxDebugLib.inf $
+## @file
+# VBoxDebugLib - Debug logging and assertions support routines using DevEFI.
+#
+
+
+#
+# Copyright (C) 2009-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>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VBoxDebugLib
+ FILE_GUID = 549306AB-75C1-4585-8681-556EBB34C60C
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = DebugLib
+
+[Sources.common]
+ VBoxDebugLib.c
+ VBoxPrintChar.c
+ VBoxPrintGuid.c
+ VBoxPrintHex.c
+ VBoxPrintHexDump.c
+ VBoxPrintString.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ VBoxPkg/VBoxPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ PrintLib
+
+[Protocols]
+ gEfiDevicePathToTextProtocolGuid
+
+[Guids]
+ # none
+
+[Ppis]
+ # none
+
+[Guids]
+ # none
+
+[Pcd.common]
+ # none
+
+[FixedPcd.common]
+ # none
+
+[FeaturePcd.common]
+ # none
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugLib/VBoxPrintChar.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugLib/VBoxPrintChar.c
new file mode 100644
index 00000000..feba1247
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugLib/VBoxPrintChar.c
@@ -0,0 +1,56 @@
+/* $Id: VBoxPrintChar.c $ */
+/** @file
+ * VBoxPrintChar.c - Implementation of the VBoxPrintChar() debug logging routine.
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "VBoxDebugLib.h"
+#include "DevEFI.h"
+#include "iprt/asm.h"
+
+
+/**
+ * Prints a char.
+ * @returns 1
+ * @param ch The char to print.
+ */
+size_t VBoxPrintChar(int ch)
+{
+ ASMOutU8(EFI_DEBUG_PORT, (uint8_t)ch);
+ return 1;
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugLib/VBoxPrintGuid.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugLib/VBoxPrintGuid.c
new file mode 100644
index 00000000..b1587410
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugLib/VBoxPrintGuid.c
@@ -0,0 +1,73 @@
+/* $Id: VBoxPrintGuid.c $ */
+/** @file
+ * VBoxPrintGuid.c - Implementation of the VBoxPrintGuid() debug logging routine.
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "VBoxDebugLib.h"
+#include "DevEFI.h"
+
+
+/**
+ * Prints a EFI GUID.
+ *
+ * @returns Number of bytes printed.
+ *
+ * @param pGuid The GUID to print
+ */
+size_t VBoxPrintGuid(CONST EFI_GUID *pGuid)
+{
+ VBoxPrintHex(pGuid->Data1, sizeof(pGuid->Data1));
+ VBoxPrintChar('-');
+ VBoxPrintHex(pGuid->Data2, sizeof(pGuid->Data2));
+ VBoxPrintChar('-');
+ VBoxPrintHex(pGuid->Data3, sizeof(pGuid->Data3));
+ VBoxPrintChar('-');
+ VBoxPrintHex(pGuid->Data4[0], sizeof(pGuid->Data4[0]));
+ VBoxPrintHex(pGuid->Data4[1], sizeof(pGuid->Data4[1]));
+ VBoxPrintChar('-');
+ VBoxPrintHex(pGuid->Data4[2], sizeof(pGuid->Data4[2]));
+ VBoxPrintHex(pGuid->Data4[3], sizeof(pGuid->Data4[3]));
+ VBoxPrintHex(pGuid->Data4[4], sizeof(pGuid->Data4[4]));
+ VBoxPrintHex(pGuid->Data4[5], sizeof(pGuid->Data4[5]));
+ VBoxPrintHex(pGuid->Data4[6], sizeof(pGuid->Data4[6]));
+ VBoxPrintHex(pGuid->Data4[7], sizeof(pGuid->Data4[7]));
+ return 37;
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugLib/VBoxPrintHex.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugLib/VBoxPrintHex.c
new file mode 100644
index 00000000..0a1bda49
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugLib/VBoxPrintHex.c
@@ -0,0 +1,110 @@
+/* $Id: VBoxPrintHex.c $ */
+/** @file
+ * VBoxPrintHex.c - Implementation of the VBoxPrintHex() debug logging routine.
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <Library/BaseLib.h>
+
+#include "VBoxDebugLib.h"
+#include "DevEFI.h"
+#include "iprt/asm.h"
+
+
+/**
+ * Prints a char.
+ * @param ch The char to print.
+ */
+DECLINLINE(void) vboxPrintHexChar(int ch)
+{
+ ASMOutU8(EFI_DEBUG_PORT, (uint8_t)ch);
+}
+
+
+/**
+ * Print a hex number, up to 64-bit long.
+ *
+ * @returns Number of chars printed.
+ *
+ * @param uValue The value.
+ * @param cbType The size of the value type.
+ */
+size_t VBoxPrintHex(UINT64 uValue, size_t cbType)
+{
+ static const char s_szHex[17] = "0123456789abcdef";
+ switch (cbType)
+ {
+/*
+ * We have to cast the result to UINTN before indexing into the array
+ * or cl.exe insists on generating a call to __allmul for unoptimized 32bit builds,
+ * see: https://patchew.org/EDK2/1486606121-226912-1-git-send-email-dandan.bi@intel.com/
+ */
+#define VAL_NIBBLE_EXTRACT(a_uValue, a_iNibbleStart) (s_szHex[(UINTN)(RShiftU64((a_uValue), (a_iNibbleStart)) & 0xf)])
+ case 8:
+ vboxPrintHexChar(VAL_NIBBLE_EXTRACT(uValue, 60));
+ vboxPrintHexChar(VAL_NIBBLE_EXTRACT(uValue, 56));
+ vboxPrintHexChar(VAL_NIBBLE_EXTRACT(uValue, 52));
+ vboxPrintHexChar(VAL_NIBBLE_EXTRACT(uValue, 48));
+ vboxPrintHexChar(VAL_NIBBLE_EXTRACT(uValue, 44));
+ vboxPrintHexChar(VAL_NIBBLE_EXTRACT(uValue, 40));
+ vboxPrintHexChar(VAL_NIBBLE_EXTRACT(uValue, 36));
+ vboxPrintHexChar(VAL_NIBBLE_EXTRACT(uValue, 32));
+ case 4:
+ vboxPrintHexChar(VAL_NIBBLE_EXTRACT(uValue, 28));
+ vboxPrintHexChar(VAL_NIBBLE_EXTRACT(uValue, 24));
+ vboxPrintHexChar(VAL_NIBBLE_EXTRACT(uValue, 20));
+ vboxPrintHexChar(VAL_NIBBLE_EXTRACT(uValue, 16));
+ case 2:
+ vboxPrintHexChar(VAL_NIBBLE_EXTRACT(uValue, 12));
+ vboxPrintHexChar(VAL_NIBBLE_EXTRACT(uValue, 8));
+ case 1:
+ vboxPrintHexChar(VAL_NIBBLE_EXTRACT(uValue, 4));
+ vboxPrintHexChar(VAL_NIBBLE_EXTRACT(uValue, 0));
+ break;
+#undef VAL_NIBBLE_EXTRACT
+ }
+
+#if 0 /* There is no MultU32x32 for 32bit and cl insists on emitting __allmul otherwise so we just hardcode everything here... */
+ return cbType * 2;
+#else
+ static size_t s_acbPrinted[9] = { 0, 2, 4, 0, 8, 0, 0, 0, 16};
+ if (cbType < RT_ELEMENTS(s_acbPrinted))
+ return s_acbPrinted[cbType];
+ return 0;
+#endif
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugLib/VBoxPrintHexDump.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugLib/VBoxPrintHexDump.c
new file mode 100644
index 00000000..d0ed6404
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugLib/VBoxPrintHexDump.c
@@ -0,0 +1,111 @@
+/* $Id: VBoxPrintHexDump.c $ */
+/** @file
+ * VBoxPrintHex.c - Implementation of the VBoxPrintHex() debug logging routine.
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "VBoxDebugLib.h"
+#include "DevEFI.h"
+#include "iprt/asm.h"
+#include "iprt/ctype.h"
+
+
+/**
+ * Prints a char.
+ * @returns 1.
+ * @param ch The char to print.
+ */
+DECLINLINE(int) vboxPrintHexDumpChar(int ch)
+{
+ ASMOutU8(EFI_DEBUG_PORT, (uint8_t)ch);
+ return 1;
+}
+
+
+/**
+ * Prints a hex dump the specified memory block.
+ *
+ * @returns Number of bytes printed.
+ *
+ * @param pv The memory to dump.
+ * @param cb Number of bytes to dump.
+ */
+size_t VBoxPrintHexDump(const void *pv, size_t cb)
+{
+ size_t cchPrinted = 0;
+ uint8_t const *pb = (uint8_t const *)pv;
+ while (cb > 0)
+ {
+ unsigned i;
+
+ /* the offset */
+ cchPrinted += VBoxPrintHex((uintptr_t)pb, sizeof(pb));
+ cchPrinted += VBoxPrintString(" ");
+
+ /* the hex bytes value. */
+ for (i = 0; i < 16; i++)
+ {
+ cchPrinted += vboxPrintHexDumpChar(i == 7 ? '-' : ' ');
+ if (i < cb)
+ cchPrinted += VBoxPrintHex(pb[i], 1);
+ else
+ cchPrinted += VBoxPrintString(" ");
+ }
+
+ /* the printable chars */
+ cchPrinted += VBoxPrintString(" ");
+ for (i = 0; i < 16 && i < cb; i++)
+ cchPrinted += vboxPrintHexDumpChar(RT_C_IS_PRINT(pb[i])
+ ? pb[i]
+ : '.');
+
+ /* finally, the new line. */
+ cchPrinted += vboxPrintHexDumpChar('\n');
+
+ /*
+ * Advance.
+ */
+ if (cb <= 16)
+ break;
+ cb -= 16;
+ pb += 16;
+ }
+
+ return cchPrinted;
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugLib/VBoxPrintString.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugLib/VBoxPrintString.c
new file mode 100644
index 00000000..13c10bc3
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxDebugLib/VBoxPrintString.c
@@ -0,0 +1,60 @@
+/* $Id: VBoxPrintString.c $ */
+/** @file
+ * VBoxPrintString.c - Implementation of the VBoxPrintString() debug logging routine.
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "VBoxDebugLib.h"
+#include "DevEFI.h"
+#include "iprt/asm.h"
+
+
+/**
+ * Prints a string to the EFI debug port.
+ *
+ * @returns The string length.
+ * @param pszString The string to print.
+ */
+size_t VBoxPrintString(const char *pszString)
+{
+ const char *pszEnd = pszString;
+ while (*pszEnd)
+ pszEnd++;
+ ASMOutStrU8(EFI_DEBUG_PORT, (uint8_t const *)pszString, pszEnd - pszString);
+ return pszEnd - pszString;
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxOemHookStatusCodeLib/VBoxOemHookStatusCodeLib.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxOemHookStatusCodeLib/VBoxOemHookStatusCodeLib.c
new file mode 100644
index 00000000..789eb32f
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxOemHookStatusCodeLib/VBoxOemHookStatusCodeLib.c
@@ -0,0 +1,218 @@
+/* $Id: VBoxOemHookStatusCodeLib.c $ */
+/** @file
+ * DxeVBoxOemHookStatusCodeLib.c - Logging.
+ */
+
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/OemHookStatusCodeLib.h>
+#include <Library/PrintLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Guid/StatusCodeDataTypeDebug.h>
+#if 0 /* See VBoxSecExtractDebugInfo */
+# include <DebugInfo.h>
+#endif
+
+#include "VBoxDebugLib.h"
+#include "DevEFI.h"
+
+
+
+EFI_STATUS EFIAPI
+OemHookStatusCodeInitialize(VOID)
+{
+ VBoxPrintString("OemHookStatusCodeInitialize\n");
+ return EFI_SUCCESS;
+}
+
+
+#if 0 /* vvl: With thbe new version the API changed a bit and VA_LIST isn't used any more. Before applying
+ * any changes here I would like to understand in which cases we need this help function.
+ * bird: Some components sent information in this format. Search for the UUID or EFI_DEBUG_INFO usage.
+ */
+/**
+ * Helper VBoxSecPeiReportStatusCode uses for catching some odd reports.
+ */
+static BOOLEAN
+VBoxSecExtractDebugInfo(IN CONST EFI_STATUS_CODE_DATA *pData,
+ OUT UINT32 *puErrorLevel,
+ OUT VA_LIST *pVa,
+ OUT CHAR8 **ppszFormat)
+{
+ EFI_DEBUG_INFO *pDebugInfo;
+
+ if ( !CompareGuid(&pData->Type, &gEfiStatusCodeSpecificDataGuid)
+ || pData->HeaderSize != sizeof(*pData)
+ || pData->Size <= sizeof(UINT64) * 12 + sizeof(EFI_DEBUG_INFO) + 1)
+ return FALSE;
+
+ pDebugInfo = (EFI_DEBUG_INFO *)(pData + 1);
+ *pVa = (VA_LIST)(pDebugInfo + 1);
+ *ppszFormat = (CHAR8 *)((UINT64 *)pVa + 12);
+ return TRUE;
+}
+#endif
+
+/** Worker that dumps the raw data. */
+static void
+VBoxOemHookStatusCodeReportRawDump(EFI_STATUS_CODE_TYPE Type,
+ EFI_STATUS_CODE_VALUE Value,
+ UINT32 Instance,
+ CONST EFI_GUID *CallerId)
+{
+ VBoxPrintString("Report: Type=");
+ VBoxPrintHex(Type, sizeof(Type));
+ VBoxPrintString(" Value=");
+ VBoxPrintHex(Value, sizeof(Value));
+
+ VBoxPrintString(" Instance=");
+ VBoxPrintHex(Instance, sizeof(Instance));
+ if (CallerId)
+ {
+ VBoxPrintString(" CallerId=");
+ VBoxPrintGuid(CallerId);
+ }
+
+#define CASE_PRINT(Head,Print,Tail) \
+ case Head ## Print ## Tail : VBoxPrintString(" " #Print); break
+ switch (Type & EFI_STATUS_CODE_SEVERITY_MASK) /* quick guess work... */
+ {
+ CASE_PRINT(EFI_ERROR_,MINOR,);
+ CASE_PRINT(EFI_ERROR_,MAJOR,);
+ CASE_PRINT(EFI_ERROR_,UNRECOVERED,);
+ CASE_PRINT(EFI_ERROR_,UNCONTAINED,);
+ }
+ switch (Type & EFI_STATUS_CODE_TYPE_MASK) /* quick guess work... */
+ {
+ CASE_PRINT(EFI_,PROGRESS,_CODE);
+ CASE_PRINT(EFI_,ERROR,_CODE);
+ CASE_PRINT(EFI_,DEBUG,_CODE);
+ }
+#undef CASE_PRINT
+ VBoxPrintChar('\n');
+}
+
+
+EFI_STATUS EFIAPI
+OemHookStatusCodeReport(IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN EFI_GUID *CallerId OPTIONAL,
+ IN EFI_STATUS_CODE_DATA *Data OPTIONAL)
+{
+ /*
+ * Try figure out the data payload
+ */
+ if (Data != NULL)
+ {
+ CHAR8 *pszFilename;
+ CHAR8 *pszDescription;
+ UINT32 uLine;
+ UINT32 uErrorLevel;
+ BASE_LIST bs;
+ CHAR8 *pszFormat;
+
+ if (ReportStatusCodeExtractAssertInfo(Type, Value, Data, &pszFilename,
+ &pszDescription, &uLine))
+ {
+ VBoxPrintString("Assertion Failed! Line=0x");
+ VBoxPrintHex(uLine, sizeof(uLine));
+ if (pszFilename)
+ {
+ VBoxPrintString(" File=");
+ VBoxPrintString(pszFilename);
+ }
+ if (pszDescription)
+ {
+ VBoxPrintString(" Desc=");
+ VBoxPrintString(pszDescription);
+ }
+ VBoxPrintChar('\n');
+ }
+ else if ( ReportStatusCodeExtractDebugInfo(Data, &uErrorLevel, &bs, &pszFormat)
+#if 0 /* See question at VBoxSecExtractDebugInfo. */
+ || VBoxSecExtractDebugInfo(Data, &uErrorLevel, &va, &pszFormat)
+#endif
+ )
+ {
+ CHAR8 szBuf[128];
+ UINTN cch;
+
+ cch = AsciiBSPrint(szBuf, sizeof(szBuf), pszFormat, bs);
+ if (cch >= sizeof(szBuf))
+ cch = sizeof(szBuf) - 1;
+ while ( cch > 0
+ && ( szBuf[cch - 1] == '\n'
+ || szBuf[cch - 1] == '\r'))
+ cch--;
+ szBuf[cch] = '\0';
+
+ VBoxPrintString("DBG/");
+ VBoxPrintHex(uErrorLevel, sizeof(uErrorLevel));
+ VBoxPrintString(": ");
+ VBoxPrintString(szBuf);
+ VBoxPrintChar('\n');
+ }
+ else
+ {
+ /*
+ * Unknown data, resort to raw dump of everything.
+ */
+ VBoxOemHookStatusCodeReportRawDump(Type, Value, Instance, CallerId);
+
+ VBoxPrintString("OemReport: Unknown data type ");
+ VBoxPrintGuid(&Data->Type);
+ VBoxPrintString(" (Size=");
+ VBoxPrintHex(Data->Size, sizeof(Data->Size));
+ VBoxPrintString(" HeaderSize=");
+ VBoxPrintHex(Data->HeaderSize, sizeof(Data->HeaderSize));
+ VBoxPrintString(")\n");
+ if (Data->Size > 0 && Data->Size <= 128)
+ VBoxPrintHexDump(Data + 1, Data->Size);
+ }
+ }
+ /*
+ * No data, do a raw dump.
+ */
+ else
+ VBoxOemHookStatusCodeReportRawDump(Type, Value, Instance, CallerId);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxOemHookStatusCodeLib/VBoxOemHookStatusCodeLib.inf b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxOemHookStatusCodeLib/VBoxOemHookStatusCodeLib.inf
new file mode 100644
index 00000000..d23a163e
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxOemHookStatusCodeLib/VBoxOemHookStatusCodeLib.inf
@@ -0,0 +1,80 @@
+# $Id: VBoxOemHookStatusCodeLib.inf $
+## @file
+# VBoxOemHookStatusCodeLib - Logging.
+#
+
+#
+# Copyright (C) 2009-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>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VBoxOemHookStatusCodeLib
+ FILE_GUID = 2199AC76-067A-4DFC-B09F-9E8C02CE05B3
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = OemHookStatusCodeLib
+ EDK_RELEASE_VERSION = 0x00020000
+ EFI_SPECIFICATION_VERSION = 0x00020000
+
+[Sources.common]
+ VBoxOemHookStatusCodeLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+ VBoxPkg/VBoxPkg.dec
+
+[LibraryClasses]
+ DebugLib
+ BaseLib
+ BaseMemoryLib
+ ReportStatusCodeLib
+ PrintLib
+
+[Guids]
+ # none
+
+[Ppis]
+ # none
+
+[Guids]
+ # none
+
+[Pcd.common]
+ # none
+
+[FixedPcd.common]
+ # none
+
+[FeaturePcd.common]
+ # none
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxPeCoffLib/BasePeCoff.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxPeCoffLib/BasePeCoff.c
new file mode 100644
index 00000000..7ca58909
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxPeCoffLib/BasePeCoff.c
@@ -0,0 +1,1647 @@
+/* $Id: BasePeCoff.c $ */
+/** @file
+ * BasePeCoff.c
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/*
+ This code is based on:
+
+ Base PE/COFF loader supports loading any PE32/PE32+ or TE image, but
+ only supports relocating IA32, x64, IPF, and EBC images.
+
+ Copyright (c) 2006 - 2008, Intel Corporation<BR>
+ Portions copyright (c) 2008-2009 Apple Inc. All rights reserved.<BR>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+*/
+
+#include "BasePeCoffLibInternals.h"
+#if defined(MDE_CPU_IA32)
+# define EFI_FAT_CPU_TYPE EFI_FAT_CPU_TYPE_I386
+#elif defined(MDE_CPU_X64)
+# define EFI_FAT_CPU_TYPE EFI_FAT_CPU_TYPE_X64
+#else
+# error "please define EFI_FAT_CPU_TYPE for your arch"
+#endif
+
+
+/**
+ Retrieves the magic value from the PE/COFF header.
+
+ @param Hdr The buffer in which to return the PE32, PE32+, or TE header.
+
+ @return EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC - Image is PE32
+ @return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC - Image is PE32+
+
+**/
+UINT16
+PeCoffLoaderGetPeHeaderMagicValue (
+ IN EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
+ )
+{
+ //
+ // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
+ // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the
+ // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
+ // then override the returned value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
+ //
+ if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
+ }
+ //
+ // Return the magic value from the PC/COFF Optional Header
+ //
+ return Hdr.Pe32->OptionalHeader.Magic;
+}
+
+
+/**
+ Retrieves the PE or TE Header from a PE/COFF or TE image.
+
+ @param ImageContext The context of the image being loaded.
+ @param Hdr The buffer in which to return the PE32, PE32+, or TE header.
+
+ @retval RETURN_SUCCESS The PE or TE Header is read.
+ @retval Other The error status from reading the PE/COFF or TE image using the ImageRead function.
+
+**/
+RETURN_STATUS
+PeCoffLoaderGetPeHeader (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
+ OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
+ )
+{
+ RETURN_STATUS Status;
+ EFI_IMAGE_DOS_HEADER DosHdr;
+ EFI_FAT_IMAGE_HEADER Fat;
+ UINTN Size;
+#ifndef VBOX /* VBox: 64-bit VS2010 say wrong type / loss of data. */
+ UINTN Offset = 0;
+#else
+ UINT32 Offset = 0;
+#endif
+ UINT16 Magic;
+ EFI_FAT_IMAGE_HEADER_NLIST nlist[5];
+ Size = sizeof (EFI_FAT_IMAGE_HEADER);
+ Status = ImageContext->ImageRead (
+ ImageContext->Handle,
+ 0,
+ &Size,
+ &Fat
+ );
+ if (!RETURN_ERROR(Status) && Fat.Signature == EFI_FAT_IMAGE_HEADER_SIGNATURE)
+ {
+ UINT32 i;
+ DEBUG((DEBUG_LOAD, "%a:%d - %x narches:%d\n", __FILE__, __LINE__, Fat.Signature, Fat.NFatArch));
+ /* Can't find the way to allocate here because library used in all phases */
+ ASSERT((Fat.NFatArch < 5));
+ Size = sizeof(EFI_FAT_IMAGE_HEADER_NLIST) * Fat.NFatArch;
+ Status = ImageContext->ImageRead (
+ ImageContext->Handle,
+ sizeof (EFI_FAT_IMAGE_HEADER),
+ &Size,
+ nlist
+ );
+ for (i = 0; i < Fat.NFatArch ; ++i)
+ {
+
+ if (nlist[i].CpuType == EFI_FAT_CPU_TYPE)
+ {
+ ImageContext->IsFat = TRUE;
+ ImageContext->FatOffset = Offset;
+ Offset = nlist[i].Offset;
+ break;
+ }
+ }
+ }
+ //
+ // Read the DOS image header to check for its existence
+ //
+ ImageContext->FatOffset = Offset;
+ Size = sizeof (EFI_IMAGE_DOS_HEADER);
+ Status = ImageContext->ImageRead (
+ ImageContext->Handle,
+ Offset,
+ &Size,
+ &DosHdr
+ );
+ if (RETURN_ERROR (Status)) {
+ ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
+ return Status;
+ }
+
+ ImageContext->PeCoffHeaderOffset = 0;
+ if (DosHdr.e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+ //
+ // DOS image header is present, so read the PE header after the DOS image
+ // header
+ //
+ ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew;
+ }
+
+ //
+ // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much
+ // data, but that should not hurt anything. Hdr.Pe32->OptionalHeader.Magic
+ // determines if this is a PE32 or PE32+ image. The magic is in the same
+ // location in both images.
+ //
+ Size = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
+ Status = ImageContext->ImageRead (
+ ImageContext->Handle,
+ ImageContext->PeCoffHeaderOffset + Offset,
+ &Size,
+ Hdr.Pe32
+ );
+ if (RETURN_ERROR (Status)) {
+ ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
+ return Status;
+ }
+
+ //
+ // Use Signature to figure out if we understand the image format
+ //
+ if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
+ ImageContext->IsTeImage = TRUE;
+ ImageContext->Machine = Hdr.Te->Machine;
+ ImageContext->ImageType = (UINT16)(Hdr.Te->Subsystem);
+ //
+ // For TeImage, SectionAlignment is undefined to be set to Zero
+ // ImageSize can be calculated.
+ //
+ ImageContext->ImageSize = 0;
+ ImageContext->SectionAlignment = 0;
+ ImageContext->SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN)Hdr.Te->BaseOfCode - (UINTN)Hdr.Te->StrippedSize;
+
+ } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
+ ImageContext->IsTeImage = FALSE;
+ ImageContext->Machine = Hdr.Pe32->FileHeader.Machine;
+
+ Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);
+
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset
+ //
+ ImageContext->ImageType = Hdr.Pe32->OptionalHeader.Subsystem;
+ ImageContext->ImageSize = (UINT64)Hdr.Pe32->OptionalHeader.SizeOfImage;
+ ImageContext->SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment;
+ ImageContext->SizeOfHeaders = Hdr.Pe32->OptionalHeader.SizeOfHeaders;
+
+ } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ //
+ // Use PE32+ offset
+ //
+ ImageContext->ImageType = Hdr.Pe32Plus->OptionalHeader.Subsystem;
+ ImageContext->ImageSize = (UINT64) Hdr.Pe32Plus->OptionalHeader.SizeOfImage;
+ ImageContext->SectionAlignment = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;
+ ImageContext->SizeOfHeaders = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;
+ } else {
+ ImageContext->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE;
+ DEBUG((DEBUG_LOAD, "%a:%d - %r\n", __FILE__, __LINE__, RETURN_UNSUPPORTED));
+ return RETURN_UNSUPPORTED;
+ }
+ } else {
+ ImageContext->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE;
+ return RETURN_UNSUPPORTED;
+ }
+
+ if (!PeCoffLoaderImageFormatSupported (ImageContext->Machine)) {
+ //
+ // If the PE/COFF loader does not support the image type return
+ // unsupported. This library can support lots of types of images
+ // this does not mean the user of this library can call the entry
+ // point of the image.
+ //
+ DEBUG((DEBUG_LOAD, "%a:%d - %r\n", __FILE__, __LINE__, RETURN_UNSUPPORTED));
+ return RETURN_UNSUPPORTED;
+ }
+
+ return RETURN_SUCCESS;
+}
+
+
+/**
+ Retrieves information about a PE/COFF image.
+
+ Computes the PeCoffHeaderOffset, IsTeImage, ImageType, ImageAddress, ImageSize,
+ DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and
+ DebugDirectoryEntryRva fields of the ImageContext structure.
+ If ImageContext is NULL, then return RETURN_INVALID_PARAMETER.
+ If the PE/COFF image accessed through the ImageRead service in the ImageContext
+ structure is not a supported PE/COFF image type, then return RETURN_UNSUPPORTED.
+ If any errors occur while computing the fields of ImageContext,
+ then the error status is returned in the ImageError field of ImageContext.
+ If the image is a TE image, then SectionAlignment is set to 0.
+ The ImageRead and Handle fields of ImageContext structure must be valid prior
+ to invoking this service.
+
+ @param ImageContext Pointer to the image context structure that describes the PE/COFF
+ image that needs to be examined by this function.
+
+ @retval RETURN_SUCCESS The information on the PE/COFF image was collected.
+ @retval RETURN_INVALID_PARAMETER ImageContext is NULL.
+ @retval RETURN_UNSUPPORTED The PE/COFF image is not supported.
+
+**/
+RETURN_STATUS
+EFIAPI
+PeCoffLoaderGetImageInfo (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+ RETURN_STATUS Status;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+ EFI_IMAGE_DATA_DIRECTORY *DebugDirectoryEntry;
+ UINTN Size;
+ UINTN Index;
+ UINTN DebugDirectoryEntryRva;
+ UINTN DebugDirectoryEntryFileOffset;
+ UINTN SectionHeaderOffset;
+ EFI_IMAGE_SECTION_HEADER SectionHeader;
+ EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry;
+ UINT32 NumberOfRvaAndSizes;
+ UINT16 Magic;
+ UINT32 FatOffset = 0;
+
+ if (ImageContext == NULL) {
+ return RETURN_INVALID_PARAMETER;
+ }
+ //
+ // Assume success
+ //
+ ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
+
+ Hdr.Union = &HdrData;
+ Status = PeCoffLoaderGetPeHeader (ImageContext, Hdr);
+ if (RETURN_ERROR (Status)) {
+ return Status;
+ }
+ if (ImageContext->IsFat)
+ {
+ FatOffset = ImageContext->FatOffset;
+ }
+
+ Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);
+
+ //
+ // Retrieve the base address of the image
+ //
+ if (!(ImageContext->IsTeImage)) {
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset
+ //
+ ImageContext->ImageAddress = Hdr.Pe32->OptionalHeader.ImageBase;
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ ImageContext->ImageAddress = Hdr.Pe32Plus->OptionalHeader.ImageBase;
+ }
+ } else {
+ ImageContext->ImageAddress = (PHYSICAL_ADDRESS)(Hdr.Te->ImageBase + Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));
+ }
+ ImageContext->ImageAddress += FatOffset;
+
+ //
+ // Initialize the alternate destination address to 0 indicating that it
+ // should not be used.
+ //
+ ImageContext->DestinationAddress = 0;
+
+ //
+ // Initialize the debug codeview pointer.
+ //
+ ImageContext->DebugDirectoryEntryRva = 0;
+ ImageContext->CodeView = NULL;
+ ImageContext->PdbPointer = NULL;
+
+ //
+ // Three cases with regards to relocations:
+ // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
+ // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
+ // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
+ // has no base relocs to apply
+ // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
+ //
+ // Look at the file header to determine if relocations have been stripped, and
+ // save this info in the image context for later use.
+ //
+ if ((!(ImageContext->IsTeImage)) && ((Hdr.Pe32->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) {
+ ImageContext->RelocationsStripped = TRUE;
+ } else if ((ImageContext->IsTeImage) && (Hdr.Te->DataDirectory[0].Size == 0) && (Hdr.Te->DataDirectory[0].VirtualAddress == 0)) {
+ ImageContext->RelocationsStripped = TRUE;
+ } else {
+ ImageContext->RelocationsStripped = FALSE;
+ }
+
+ if (!(ImageContext->IsTeImage)) {
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset
+ //
+ NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
+ DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
+ DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
+ }
+
+ if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
+
+ DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
+
+ //
+ // Determine the file offset of the debug directory... This means we walk
+ // the sections to find which section contains the RVA of the debug
+ // directory
+ //
+ DebugDirectoryEntryFileOffset = 0;
+
+ SectionHeaderOffset = (UINTN)(
+ ImageContext->PeCoffHeaderOffset +
+ sizeof (UINT32) +
+ sizeof (EFI_IMAGE_FILE_HEADER) +
+ Hdr.Pe32->FileHeader.SizeOfOptionalHeader
+ );
+
+ for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
+ //
+ // Read section header from file
+ //
+ Size = sizeof (EFI_IMAGE_SECTION_HEADER);
+ Status = ImageContext->ImageRead (
+ ImageContext->Handle,
+ SectionHeaderOffset,
+ &Size,
+ &SectionHeader
+ );
+ if (RETURN_ERROR (Status)) {
+ ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
+ DEBUG((DEBUG_LOAD, "%a:%d - %r\n", __FILE__, __LINE__, Status));
+ return Status;
+ }
+
+ if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&
+ DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {
+
+ DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;
+ break;
+ }
+
+ SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
+ }
+
+ if (DebugDirectoryEntryFileOffset != 0) {
+ for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {
+ //
+ // Read next debug directory entry
+ //
+ Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
+ Status = ImageContext->ImageRead (
+ ImageContext->Handle,
+ DebugDirectoryEntryFileOffset,
+ &Size,
+ &DebugEntry
+ );
+ DEBUG((DEBUG_LOAD, "%a:%d - %r\n", __FILE__, __LINE__, Status));
+ if (RETURN_ERROR (Status)) {
+ ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
+ return Status;
+ }
+ if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
+ ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);
+ if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) {
+ ImageContext->ImageSize += DebugEntry.SizeOfData;
+ }
+
+ return RETURN_SUCCESS;
+ }
+ }
+ }
+ }
+ } else {
+
+ DebugDirectoryEntry = &Hdr.Te->DataDirectory[1];
+ DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
+ SectionHeaderOffset = (UINTN)(sizeof (EFI_TE_IMAGE_HEADER)) + FatOffset;
+
+ DebugDirectoryEntryFileOffset = 0;
+
+ for (Index = 0; Index < Hdr.Te->NumberOfSections;) {
+ //
+ // Read section header from file
+ //
+ Size = sizeof (EFI_IMAGE_SECTION_HEADER);
+ Status = ImageContext->ImageRead (
+ ImageContext->Handle,
+ SectionHeaderOffset,
+ &Size,
+ &SectionHeader
+ );
+ if (RETURN_ERROR (Status)) {
+ ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
+ return Status;
+ }
+
+ if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&
+ DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {
+ DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva -
+ SectionHeader.VirtualAddress +
+ SectionHeader.PointerToRawData +
+ sizeof (EFI_TE_IMAGE_HEADER) -
+ Hdr.Te->StrippedSize;
+
+ //
+ // File offset of the debug directory was found, if this is not the last
+ // section, then skip to the last section for calculating the image size.
+ //
+ if (Index < (UINTN) Hdr.Te->NumberOfSections - 1) {
+ SectionHeaderOffset += (Hdr.Te->NumberOfSections - 1 - Index) * sizeof (EFI_IMAGE_SECTION_HEADER);
+ Index = Hdr.Te->NumberOfSections - 1;
+ continue;
+ }
+ }
+
+ //
+ // In Te image header there is not a field to describe the ImageSize.
+ // Actually, the ImageSize equals the RVA plus the VirtualSize of
+ // the last section mapped into memory (Must be rounded up to
+ // a multiple of Section Alignment). Per the PE/COFF specification, the
+ // section headers in the Section Table must appear in order of the RVA
+ // values for the corresponding sections. So the ImageSize can be determined
+ // by the RVA and the VirtualSize of the last section header in the
+ // Section Table.
+ //
+ if ((++Index) == (UINTN)Hdr.Te->NumberOfSections) {
+ ImageContext->ImageSize = (SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize);
+ }
+
+ SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
+ }
+
+ if (DebugDirectoryEntryFileOffset != 0) {
+ for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {
+ //
+ // Read next debug directory entry
+ //
+ Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
+ Status = ImageContext->ImageRead (
+ ImageContext->Handle,
+ DebugDirectoryEntryFileOffset,
+ &Size,
+ &DebugEntry
+ );
+ DEBUG((DEBUG_LOAD, "%a:%d - %r\n", __FILE__, __LINE__, Status));
+ if (RETURN_ERROR (Status)) {
+ ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
+ return Status;
+ }
+
+ if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
+ ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);
+ return RETURN_SUCCESS;
+ }
+ }
+ }
+ }
+
+ return RETURN_SUCCESS;
+}
+
+
+/**
+ Converts an image address to the loaded address.
+
+ @param ImageContext The context of the image being loaded.
+ @param Address The relative virtual address to be converted to the loaded address.
+
+ @return The converted address or NULL if the address can not be converted.
+
+**/
+VOID *
+PeCoffLoaderImageAddress (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
+ IN UINTN Address
+ )
+{
+ //
+ // Make sure that Address and ImageSize is correct for the loaded image.
+ //
+ if (Address >= ImageContext->ImageSize) {
+ ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
+ return NULL;
+ }
+
+ return (CHAR8 *)((UINTN) ImageContext->ImageAddress + Address);
+}
+
+
+/**
+ Applies relocation fixups to a PE/COFF image that was loaded with PeCoffLoaderLoadImage().
+
+ If the DestinationAddress field of ImageContext is 0, then use the ImageAddress field of
+ ImageContext as the relocation base address. Otherwise, use the DestinationAddress field
+ of ImageContext as the relocation base address. The caller must allocate the relocation
+ fixup log buffer and fill in the FixupData field of ImageContext prior to calling this function.
+
+ The ImageRead, Handle, PeCoffHeaderOffset, IsTeImage, Machine, ImageType, ImageAddress,
+ ImageSize, DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders,
+ DebugDirectoryEntryRva, EntryPoint, FixupDataSize, CodeView, PdbPointer, and FixupData of
+ the ImageContext structure must be valid prior to invoking this service.
+
+ If ImageContext is NULL, then ASSERT().
+
+ Note that if the platform does not maintain coherency between the instruction cache(s) and the data
+ cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
+ prior to transferring control to a PE/COFF image that is loaded using this library.
+
+ @param ImageContext Pointer to the image context structure that describes the PE/COFF
+ image that is being relocated.
+
+ @retval RETURN_SUCCESS The PE/COFF image was relocated.
+ Extended status information is in the ImageError field of ImageContext.
+ @retval RETURN_LOAD_ERROR The image in not a valid PE/COFF image.
+ Extended status information is in the ImageError field of ImageContext.
+ @retval RETURN_UNSUPPORTED A relocation record type is not supported.
+ Extended status information is in the ImageError field of ImageContext.
+
+**/
+RETURN_STATUS
+EFIAPI
+PeCoffLoaderRelocateImage (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+ RETURN_STATUS Status;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+ EFI_IMAGE_DATA_DIRECTORY *RelocDir;
+ UINT64 Adjust;
+ EFI_IMAGE_BASE_RELOCATION *RelocBase;
+ EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;
+ UINT16 *Reloc;
+ UINT16 *RelocEnd;
+ CHAR8 *Fixup;
+ CHAR8 *FixupBase;
+ UINT16 *Fixup16;
+ UINT32 *Fixup32;
+ UINT64 *Fixup64;
+ CHAR8 *FixupData;
+ PHYSICAL_ADDRESS BaseAddress;
+ UINT32 NumberOfRvaAndSizes;
+ UINT16 Magic;
+
+ ASSERT (ImageContext != NULL);
+
+ //
+ // Assume success
+ //
+ ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
+
+ //
+ // If there are no relocation entries, then we are done
+ //
+ if (ImageContext->RelocationsStripped) {
+ // Applies additional environment specific actions to relocate fixups
+ // to a PE/COFF image if needed
+ PeCoffLoaderRelocateImageExtraAction (ImageContext);
+ return RETURN_SUCCESS;
+ }
+
+ //
+ // If the destination address is not 0, use that rather than the
+ // image address as the relocation target.
+ //
+ if (ImageContext->DestinationAddress != 0) {
+ BaseAddress = ImageContext->DestinationAddress;
+ } else {
+ BaseAddress = ImageContext->ImageAddress;
+ }
+
+ if (!(ImageContext->IsTeImage)) {
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
+
+ Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);
+
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset
+ //
+ Adjust = (UINT64)BaseAddress - Hdr.Pe32->OptionalHeader.ImageBase;
+ Hdr.Pe32->OptionalHeader.ImageBase = (UINT32)BaseAddress;
+
+ NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
+ RelocDir = &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ Adjust = (UINT64) BaseAddress - Hdr.Pe32Plus->OptionalHeader.ImageBase;
+ Hdr.Pe32Plus->OptionalHeader.ImageBase = (UINT64)BaseAddress;
+
+ NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
+ RelocDir = &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
+ }
+
+ //
+ // Find the relocation block
+ // Per the PE/COFF spec, you can't assume that a given data directory
+ // is present in the image. You have to check the NumberOfRvaAndSizes in
+ // the optional header to verify a desired directory entry is there.
+ //
+
+ if ((NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) && (RelocDir->Size > 0)) {
+ RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);
+ RelocBaseEnd = PeCoffLoaderImageAddress (
+ ImageContext,
+ RelocDir->VirtualAddress + RelocDir->Size - 1
+ );
+ if (RelocBase == NULL || RelocBaseEnd == NULL) {
+ return RETURN_LOAD_ERROR;
+ }
+ } else {
+ //
+ // Set base and end to bypass processing below.
+ //
+ RelocBase = RelocBaseEnd = NULL;
+ }
+ } else {
+ Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);
+ Adjust = (UINT64) (BaseAddress - Hdr.Te->StrippedSize + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->ImageBase);
+ Hdr.Te->ImageBase = (UINT64) (BaseAddress - Hdr.Te->StrippedSize + sizeof (EFI_TE_IMAGE_HEADER));
+
+ //
+ // Find the relocation block
+ //
+ RelocDir = &Hdr.Te->DataDirectory[0];
+ if (RelocDir->Size > 0) {
+ RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(
+ ImageContext->ImageAddress +
+ RelocDir->VirtualAddress +
+ sizeof(EFI_TE_IMAGE_HEADER) -
+ Hdr.Te->StrippedSize
+ );
+ RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1);
+ } else {
+ //
+ // Set base and end to bypass processing below.
+ //
+ RelocBase = RelocBaseEnd = NULL;
+ }
+ }
+
+ //
+ // If Adjust is not zero, then apply fix ups to the image
+ //
+ if (Adjust != 0) {
+ //
+ // Run the relocation information and apply the fixups
+ //
+ FixupData = ImageContext->FixupData;
+ while (RelocBase < RelocBaseEnd) {
+
+ Reloc = (UINT16 *) ((CHAR8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
+ RelocEnd = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);
+
+ //
+ // Make sure RelocEnd is in the Image range.
+ //
+ if ((CHAR8 *) RelocEnd < (CHAR8 *)((UINTN) ImageContext->ImageAddress) ||
+ (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress + (UINTN)ImageContext->ImageSize)) {
+ ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
+ return RETURN_LOAD_ERROR;
+ }
+
+ if (!(ImageContext->IsTeImage)) {
+ FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress);
+ if (FixupBase == NULL) {
+ return RETURN_LOAD_ERROR;
+ }
+ } else {
+ FixupBase = (CHAR8 *)(UINTN)(ImageContext->ImageAddress +
+ RelocBase->VirtualAddress +
+ sizeof(EFI_TE_IMAGE_HEADER) -
+ Hdr.Te->StrippedSize
+ );
+ }
+
+ //
+ // Run this relocation record
+ //
+ while (Reloc < RelocEnd) {
+
+ Fixup = FixupBase + (*Reloc & 0xFFF);
+ switch ((*Reloc) >> 12) {
+ case EFI_IMAGE_REL_BASED_ABSOLUTE:
+ break;
+
+ case EFI_IMAGE_REL_BASED_HIGH:
+ Fixup16 = (UINT16 *) Fixup;
+ *Fixup16 = (UINT16) (*Fixup16 + ((UINT16) ((UINT32) Adjust >> 16)));
+ if (FixupData != NULL) {
+ *(UINT16 *) FixupData = *Fixup16;
+ FixupData = FixupData + sizeof (UINT16);
+ }
+ break;
+
+ case EFI_IMAGE_REL_BASED_LOW:
+ Fixup16 = (UINT16 *) Fixup;
+ *Fixup16 = (UINT16) (*Fixup16 + (UINT16) Adjust);
+ if (FixupData != NULL) {
+ *(UINT16 *) FixupData = *Fixup16;
+ FixupData = FixupData + sizeof (UINT16);
+ }
+ break;
+
+ case EFI_IMAGE_REL_BASED_HIGHLOW:
+ Fixup32 = (UINT32 *) Fixup;
+ *Fixup32 = *Fixup32 + (UINT32) Adjust;
+ if (FixupData != NULL) {
+ FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));
+ *(UINT32 *)FixupData = *Fixup32;
+ FixupData = FixupData + sizeof (UINT32);
+ }
+ break;
+
+ case EFI_IMAGE_REL_BASED_DIR64:
+ Fixup64 = (UINT64 *) Fixup;
+ *Fixup64 = *Fixup64 + (UINT64) Adjust;
+ if (FixupData != NULL) {
+ FixupData = ALIGN_POINTER (FixupData, sizeof(UINT64));
+ *(UINT64 *)(FixupData) = *Fixup64;
+ FixupData = FixupData + sizeof(UINT64);
+ }
+ break;
+
+ default:
+ //
+ // The common code does not handle some of the stranger IPF relocations
+ // PeCoffLoaderRelocateImageEx () adds support for these complex fixups
+ // on IPF and is a No-Op on other architectures.
+ //
+ Status = PeCoffLoaderRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);
+ if (RETURN_ERROR (Status)) {
+ ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
+ return Status;
+ }
+ }
+
+ //
+ // Next relocation record
+ //
+ Reloc += 1;
+ }
+
+ //
+ // Next reloc block
+ //
+ RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
+ }
+
+ //
+ // Adjust the EntryPoint to match the linked-to address
+ //
+ if (ImageContext->DestinationAddress != 0) {
+ ImageContext->EntryPoint -= (UINT64) ImageContext->ImageAddress;
+ ImageContext->EntryPoint += (UINT64) ImageContext->DestinationAddress;
+ }
+ }
+
+ // Applies additional environment specific actions to relocate fixups
+ // to a PE/COFF image if needed
+ PeCoffLoaderRelocateImageExtraAction (ImageContext);
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Loads a PE/COFF image into memory.
+
+ Loads the PE/COFF image accessed through the ImageRead service of ImageContext into the buffer
+ specified by the ImageAddress and ImageSize fields of ImageContext. The caller must allocate
+ the load buffer and fill in the ImageAddress and ImageSize fields prior to calling this function.
+ The EntryPoint, FixupDataSize, CodeView, PdbPointer and HiiResourceData fields of ImageContext are computed.
+ The ImageRead, Handle, PeCoffHeaderOffset, IsTeImage, Machine, ImageType, ImageAddress, ImageSize,
+ DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and DebugDirectoryEntryRva
+ fields of the ImageContext structure must be valid prior to invoking this service.
+
+ If ImageContext is NULL, then ASSERT().
+
+ Note that if the platform does not maintain coherency between the instruction cache(s) and the data
+ cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
+ prior to transferring control to a PE/COFF image that is loaded using this library.
+
+ @param ImageContext Pointer to the image context structure that describes the PE/COFF
+ image that is being loaded.
+
+ @retval RETURN_SUCCESS The PE/COFF image was loaded into the buffer specified by
+ the ImageAddress and ImageSize fields of ImageContext.
+ Extended status information is in the ImageError field of ImageContext.
+ @retval RETURN_BUFFER_TOO_SMALL The caller did not provide a large enough buffer.
+ Extended status information is in the ImageError field of ImageContext.
+ @retval RETURN_LOAD_ERROR The PE/COFF image is an EFI Runtime image with no relocations.
+ Extended status information is in the ImageError field of ImageContext.
+ @retval RETURN_INVALID_PARAMETER The image address is invalid.
+ Extended status information is in the ImageError field of ImageContext.
+
+**/
+RETURN_STATUS
+EFIAPI
+PeCoffLoaderLoadImage (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+ RETURN_STATUS Status;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+ PE_COFF_LOADER_IMAGE_CONTEXT CheckContext;
+ EFI_IMAGE_SECTION_HEADER *FirstSection;
+ EFI_IMAGE_SECTION_HEADER *Section;
+ UINTN NumberOfSections;
+ UINTN Index;
+ CHAR8 *Base;
+ CHAR8 *End;
+ CHAR8 *MaxEnd;
+ EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;
+ EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
+ UINTN Size;
+ UINT32 TempDebugEntryRva;
+ UINT32 NumberOfRvaAndSizes;
+ UINT16 Magic;
+ EFI_IMAGE_RESOURCE_DIRECTORY *ResourceDirectory;
+ EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *ResourceDirectoryEntry;
+ EFI_IMAGE_RESOURCE_DIRECTORY_STRING *ResourceDirectoryString;
+ EFI_IMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry;
+ UINT32 Offset = 0;
+
+
+ ASSERT (ImageContext != NULL);
+
+ //
+ // Assume success
+ //
+ ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
+
+ //
+ // Copy the provided context info into our local version, get what we
+ // can from the original image, and then use that to make sure everything
+ // is legit.
+ //
+ CopyMem (&CheckContext, ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
+
+ Status = PeCoffLoaderGetImageInfo (&CheckContext);
+ if (RETURN_ERROR (Status)) {
+ return Status;
+ }
+
+ if (ImageContext->IsFat)
+ {
+ Offset = ImageContext->FatOffset;
+ }
+
+ //
+ // Make sure there is enough allocated space for the image being loaded
+ //
+ if (ImageContext->ImageSize < CheckContext.ImageSize) {
+ ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE;
+ return RETURN_BUFFER_TOO_SMALL;
+ }
+ if (ImageContext->ImageAddress == 0) {
+ //
+ // Image cannot be loaded into 0 address.
+ //
+ ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
+ return RETURN_INVALID_PARAMETER;
+ }
+ //
+ // If there's no relocations, then make sure it's not a runtime driver,
+ // and that it's being loaded at the linked address.
+ //
+ if (CheckContext.RelocationsStripped) {
+ //
+ // If the image does not contain relocations and it is a runtime driver
+ // then return an error.
+ //
+ if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
+ ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;
+ return RETURN_LOAD_ERROR;
+ }
+ //
+ // If the image does not contain relocations, and the requested load address
+ // is not the linked address, then return an error.
+ //
+ if (CheckContext.ImageAddress != ImageContext->ImageAddress) {
+ ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
+ return RETURN_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Make sure the allocated space has the proper section alignment
+ //
+ if (!(ImageContext->IsTeImage)) {
+ if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {
+ ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;
+ return RETURN_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Read the entire PE/COFF or TE header into memory
+ //
+ if (!(ImageContext->IsTeImage)) {
+ Status = ImageContext->ImageRead (
+ ImageContext->Handle,
+ Offset,
+ &ImageContext->SizeOfHeaders,
+ (VOID *) (UINTN) ImageContext->ImageAddress
+ );
+
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
+
+ FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
+ (UINTN)ImageContext->ImageAddress +
+ ImageContext->PeCoffHeaderOffset +
+ sizeof(UINT32) +
+ sizeof(EFI_IMAGE_FILE_HEADER) +
+ Hdr.Pe32->FileHeader.SizeOfOptionalHeader
+ );
+ NumberOfSections = (UINTN) (Hdr.Pe32->FileHeader.NumberOfSections);
+ } else {
+ Status = ImageContext->ImageRead (
+ ImageContext->Handle,
+ Offset,
+ &ImageContext->SizeOfHeaders,
+ (void *)(UINTN)ImageContext->ImageAddress
+ );
+
+ Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);
+
+ FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
+ (UINTN)ImageContext->ImageAddress +
+ sizeof(EFI_TE_IMAGE_HEADER)
+ );
+ NumberOfSections = (UINTN) (Hdr.Te->NumberOfSections);
+
+ }
+
+ if (RETURN_ERROR (Status)) {
+ ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
+ return RETURN_LOAD_ERROR;
+ }
+
+ //
+ // Load each section of the image
+ //
+ Section = FirstSection;
+ for (Index = 0, MaxEnd = NULL; Index < NumberOfSections; Index++) {
+ //
+ // Read the section
+ //
+ Size = (UINTN) Section->Misc.VirtualSize;
+ if ((Size == 0) || (Size > Section->SizeOfRawData)) {
+ Size = (UINTN) Section->SizeOfRawData;
+ }
+
+ //
+ // Compute sections address
+ //
+ Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress);
+ End = PeCoffLoaderImageAddress (
+ ImageContext,
+ Section->VirtualAddress + Section->Misc.VirtualSize - 1
+ );
+
+ //
+ // If the size of the section is non-zero and the base address or end address resolved to 0, then fail.
+ //
+ if ((Size > 0) && ((Base == NULL) || (End == NULL))) {
+ ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;
+ return RETURN_LOAD_ERROR;
+ }
+
+ if (ImageContext->IsTeImage) {
+ Base = (CHAR8 *)((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize);
+ End = (CHAR8 *)((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize);
+ }
+
+ if (End > MaxEnd) {
+ MaxEnd = End;
+ }
+
+ if (Section->SizeOfRawData > 0) {
+ if (!(ImageContext->IsTeImage)) {
+ Status = ImageContext->ImageRead (
+ ImageContext->Handle,
+ Section->PointerToRawData + Offset,
+ &Size,
+ Base
+ );
+ } else {
+ Status = ImageContext->ImageRead (
+ ImageContext->Handle,
+ Section->PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize + Offset,
+ &Size,
+ Base
+ );
+ }
+
+ if (RETURN_ERROR (Status)) {
+ ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
+ return Status;
+ }
+ }
+
+ //
+ // If raw size is less then virtual size, zero fill the remaining
+ //
+
+ if (Size < Section->Misc.VirtualSize) {
+ ZeroMem (Base + Size, Section->Misc.VirtualSize - Size);
+ }
+
+ //
+ // Next Section
+ //
+ Section += 1;
+ }
+
+ //
+ // Get image's entry point
+ //
+ Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);
+ if (!(ImageContext->IsTeImage)) {
+ //
+ // Sizes of AddressOfEntryPoint are different so we need to do this safely
+ //
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset
+ //
+ ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (
+ ImageContext,
+ (UINTN)Hdr.Pe32->OptionalHeader.AddressOfEntryPoint
+ );
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (
+ ImageContext,
+ (UINTN)Hdr.Pe32Plus->OptionalHeader.AddressOfEntryPoint
+ );
+ }
+ } else {
+ ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (
+ (UINTN)ImageContext->ImageAddress +
+ (UINTN)Hdr.Te->AddressOfEntryPoint +
+ (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -
+ (UINTN)Hdr.Te->StrippedSize
+ );
+ }
+
+ //
+ // Determine the size of the fixup data
+ //
+ // Per the PE/COFF spec, you can't assume that a given data directory
+ // is present in the image. You have to check the NumberOfRvaAndSizes in
+ // the optional header to verify a desired directory entry is there.
+ //
+ if (!(ImageContext->IsTeImage)) {
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset
+ //
+ NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
+ DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
+ DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
+ }
+
+ if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
+ ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);
+ } else {
+ ImageContext->FixupDataSize = 0;
+ }
+ } else {
+ DirectoryEntry = &Hdr.Te->DataDirectory[0];
+ ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);
+ }
+ //
+ // Consumer must allocate a buffer for the relocation fixup log.
+ // Only used for runtime drivers.
+ //
+ ImageContext->FixupData = NULL;
+
+ //
+ // Load the Codeview info if present
+ //
+ if (ImageContext->DebugDirectoryEntryRva != 0) {
+ if (!(ImageContext->IsTeImage)) {
+ DebugEntry = PeCoffLoaderImageAddress (
+ ImageContext,
+ ImageContext->DebugDirectoryEntryRva
+ );
+ } else {
+ DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)(
+ ImageContext->ImageAddress +
+ ImageContext->DebugDirectoryEntryRva +
+ sizeof(EFI_TE_IMAGE_HEADER) -
+ Hdr.Te->StrippedSize
+ );
+ }
+
+ if (DebugEntry != NULL) {
+ TempDebugEntryRva = DebugEntry->RVA;
+ if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) {
+ Section--;
+ if ((UINTN)Section->SizeOfRawData < Section->Misc.VirtualSize) {
+ TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;
+ } else {
+ TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;
+ }
+ }
+
+ if (TempDebugEntryRva != 0) {
+ if (!(ImageContext->IsTeImage)) {
+ ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva);
+ } else {
+ ImageContext->CodeView = (VOID *)(
+ (UINTN)ImageContext->ImageAddress +
+ (UINTN)TempDebugEntryRva +
+ (UINTN)sizeof (EFI_TE_IMAGE_HEADER) -
+ (UINTN) Hdr.Te->StrippedSize + Offset
+ );
+ }
+
+ if (ImageContext->CodeView == NULL) {
+ ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
+ return RETURN_LOAD_ERROR;
+ }
+
+ if (DebugEntry->RVA == 0) {
+ Size = DebugEntry->SizeOfData;
+ if (!(ImageContext->IsTeImage)) {
+ Status = ImageContext->ImageRead (
+ ImageContext->Handle,
+ DebugEntry->FileOffset + Offset,
+ &Size,
+ ImageContext->CodeView
+ );
+ } else {
+ Status = ImageContext->ImageRead (
+ ImageContext->Handle,
+ DebugEntry->FileOffset + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize + Offset,
+ &Size,
+ ImageContext->CodeView
+ );
+ //
+ // Should we apply fix up to this field according to the size difference between PE and TE?
+ // Because now we maintain TE header fields unfixed, this field will also remain as they are
+ // in original PE image.
+ //
+ }
+
+ if (RETURN_ERROR (Status)) {
+ ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
+ return RETURN_LOAD_ERROR;
+ }
+
+ DebugEntry->RVA = TempDebugEntryRva;
+ }
+
+ switch (*(UINT32 *) ImageContext->CodeView) {
+ case CODEVIEW_SIGNATURE_NB10:
+ ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
+ break;
+
+ case CODEVIEW_SIGNATURE_RSDS:
+ ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
+ break;
+
+ case CODEVIEW_SIGNATURE_MTOC:
+ ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ //
+ // Get Image's HII resource section
+ //
+ ImageContext->HiiResourceData = 0;
+ if (!(ImageContext->IsTeImage)) {
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset
+ //
+ DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];
+ }
+
+ if (DirectoryEntry->Size != 0) {
+ Base = PeCoffLoaderImageAddress (ImageContext, DirectoryEntry->VirtualAddress);
+ if (Base != NULL) {
+ ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) Base;
+ ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);
+
+ for (Index = 0; Index < ResourceDirectory->NumberOfNamedEntries; Index++) {
+ if (ResourceDirectoryEntry->u1.s.NameIsString) {
+ ResourceDirectoryString = (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *) (Base + ResourceDirectoryEntry->u1.s.NameOffset);
+
+ if (ResourceDirectoryString->Length == 3 &&
+ ResourceDirectoryString->String[0] == L'H' &&
+ ResourceDirectoryString->String[1] == L'I' &&
+ ResourceDirectoryString->String[2] == L'I') {
+ //
+ // Resource Type "HII" found
+ //
+ if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {
+ //
+ // Move to next level - resource Name
+ //
+ ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);
+ ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);
+
+ if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {
+ //
+ // Move to next level - resource Language
+ //
+ ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);
+ ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);
+ }
+ }
+
+ //
+ // Now it ought to be resource Data
+ //
+ if (!ResourceDirectoryEntry->u2.s.DataIsDirectory) {
+ ResourceDataEntry = (EFI_IMAGE_RESOURCE_DATA_ENTRY *) (Base + ResourceDirectoryEntry->u2.OffsetToData);
+ ImageContext->HiiResourceData = (PHYSICAL_ADDRESS) (UINTN) PeCoffLoaderImageAddress (ImageContext, ResourceDataEntry->OffsetToData);
+ break;
+ }
+ }
+ }
+ ResourceDirectoryEntry++;
+ }
+ }
+ }
+ }
+
+ return Status;
+}
+
+extern VOID EFIAPI VBoxPeCoffLoaderMoveImageExtraAction(IN PHYSICAL_ADDRESS OldBase, IN PHYSICAL_ADDRESS NewBase);
+
+/**
+ Reapply fixups on a fixed up PE32/PE32+ image to allow virtual calling at EFI
+ runtime.
+
+ This function reapplies relocation fixups to the PE/COFF image specified by ImageBase
+ and ImageSize so the image will execute correctly when the PE/COFF image is mapped
+ to the address specified by VirtualImageBase. RelocationData must be identical
+ to the FiuxupData buffer from the PE_COFF_LOADER_IMAGE_CONTEXT structure
+ after this PE/COFF image was relocated with PeCoffLoaderRelocateImage().
+
+ Note that if the platform does not maintain coherency between the instruction cache(s) and the data
+ cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
+ prior to transferring control to a PE/COFF image that is loaded using this library.
+
+ @param ImageBase Base address of a PE/COFF image that has been loaded
+ and relocated into system memory.
+ @param VirtImageBase The request virtual address that the PE/COFF image is to
+ be fixed up for.
+ @param ImageSize The size, in bytes, of the PE/COFF image.
+ @param RelocationData A pointer to the relocation data that was collected when the PE/COFF
+ image was relocated using PeCoffLoaderRelocateImage().
+
+**/
+VOID
+EFIAPI
+PeCoffLoaderRelocateImageForRuntime (
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN PHYSICAL_ADDRESS VirtImageBase,
+ IN UINTN ImageSize,
+ IN VOID *RelocationData
+ )
+{
+ CHAR8 *OldBase;
+ CHAR8 *NewBase;
+ EFI_IMAGE_DOS_HEADER *DosHdr;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+ UINT32 NumberOfRvaAndSizes;
+ EFI_IMAGE_DATA_DIRECTORY *DataDirectory;
+ EFI_IMAGE_DATA_DIRECTORY *RelocDir;
+ EFI_IMAGE_BASE_RELOCATION *RelocBase;
+ EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;
+ UINT16 *Reloc;
+ UINT16 *RelocEnd;
+ CHAR8 *Fixup;
+ CHAR8 *FixupBase;
+ UINT16 *Fixup16;
+ UINT32 *Fixup32;
+ UINT64 *Fixup64;
+ CHAR8 *FixupData;
+ UINTN Adjust;
+ RETURN_STATUS Status;
+ UINT16 Magic;
+ UINT32 FatOffset = 0;
+ EFI_FAT_IMAGE_HEADER *Fat;
+
+ VBoxPeCoffLoaderMoveImageExtraAction(ImageBase, VirtImageBase);
+
+ OldBase = (CHAR8 *)((UINTN)ImageBase);
+ NewBase = (CHAR8 *)((UINTN)VirtImageBase);
+
+ Fat = (EFI_FAT_IMAGE_HEADER *)OldBase;
+ if(Fat->Signature == EFI_FAT_IMAGE_HEADER_SIGNATURE)
+ {
+ UINT32 i;
+ EFI_FAT_IMAGE_HEADER_NLIST *nlist = (EFI_FAT_IMAGE_HEADER_NLIST *)&Fat[1];
+ for (i = 0; i < Fat->NFatArch; ++i)
+ {
+ if (nlist[i].CpuType == EFI_FAT_CPU_TYPE)
+ {
+ FatOffset = nlist[i].Offset;
+ break;
+ }
+ }
+ }
+
+ OldBase += FatOffset;
+ Adjust = (UINTN) NewBase - (UINTN) OldBase;
+
+ //
+ // Find the image's relocate dir info
+ //
+ DosHdr = (EFI_IMAGE_DOS_HEADER *)(OldBase);
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+ //
+ // Valid DOS header so get address of PE header
+ //
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(((CHAR8 *)DosHdr) + DosHdr->e_lfanew);
+ } else {
+ //
+ // No Dos header so assume image starts with PE header.
+ //
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)OldBase;
+ }
+
+ if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
+ //
+ // Not a valid PE image so Exit
+ //
+ return ;
+ }
+
+ Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);
+
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset
+ //
+ NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
+ DataDirectory = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[0]);
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
+ DataDirectory = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[0]);
+ }
+
+ //
+ // Find the relocation block
+ //
+ // Per the PE/COFF spec, you can't assume that a given data directory
+ // is present in the image. You have to check the NumberOfRvaAndSizes in
+ // the optional header to verify a desired directory entry is there.
+ //
+ if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
+ RelocDir = DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC;
+ RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(ImageBase + FatOffset + RelocDir->VirtualAddress);
+ RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(ImageBase + FatOffset + RelocDir->VirtualAddress + RelocDir->Size);
+ } else {
+ //
+ // Cannot find relocations, cannot continue to relocate the image, ASSERT for this invalid image.
+ //
+ ASSERT (FALSE);
+ return ;
+ }
+
+ //
+ // ASSERT for the invalid image when RelocBase and RelocBaseEnd are both NULL.
+ //
+ ASSERT (RelocBase != NULL && RelocBaseEnd != NULL);
+
+ //
+ // Run the whole relocation block. And re-fixup data that has not been
+ // modified. The FixupData is used to see if the image has been modified
+ // since it was relocated. This is so data sections that have been updated
+ // by code will not be fixed up, since that would set them back to
+ // defaults.
+ //
+ FixupData = RelocationData;
+ while (RelocBase < RelocBaseEnd) {
+
+ Reloc = (UINT16 *) ((UINT8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
+ RelocEnd = (UINT16 *) ((UINT8 *) RelocBase + RelocBase->SizeOfBlock);
+ FixupBase = (CHAR8 *) ((UINTN)ImageBase) + FatOffset + RelocBase->VirtualAddress;
+
+ //
+ // Run this relocation record
+ //
+ while (Reloc < RelocEnd) {
+
+ Fixup = FixupBase + (*Reloc & 0xFFF);
+ switch ((*Reloc) >> 12) {
+
+ case EFI_IMAGE_REL_BASED_ABSOLUTE:
+ break;
+
+ case EFI_IMAGE_REL_BASED_HIGH:
+ Fixup16 = (UINT16 *) Fixup;
+ if (*(UINT16 *) FixupData == *Fixup16) {
+ *Fixup16 = (UINT16) (*Fixup16 + ((UINT16) ((UINT32) Adjust >> 16)));
+ }
+
+ FixupData = FixupData + sizeof (UINT16);
+ break;
+
+ case EFI_IMAGE_REL_BASED_LOW:
+ Fixup16 = (UINT16 *) Fixup;
+ if (*(UINT16 *) FixupData == *Fixup16) {
+ *Fixup16 = (UINT16) (*Fixup16 + ((UINT16) Adjust & 0xffff));
+ }
+
+ FixupData = FixupData + sizeof (UINT16);
+ break;
+
+ case EFI_IMAGE_REL_BASED_HIGHLOW:
+ Fixup32 = (UINT32 *) Fixup;
+ FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));
+ if (*(UINT32 *) FixupData == *Fixup32) {
+ *Fixup32 = *Fixup32 + (UINT32) Adjust;
+ }
+
+ FixupData = FixupData + sizeof (UINT32);
+ break;
+
+ case EFI_IMAGE_REL_BASED_DIR64:
+ Fixup64 = (UINT64 *)Fixup;
+ FixupData = ALIGN_POINTER (FixupData, sizeof (UINT64));
+ if (*(UINT64 *) FixupData == *Fixup64) {
+ *Fixup64 = *Fixup64 + (UINT64)Adjust;
+ }
+
+ FixupData = FixupData + sizeof (UINT64);
+ break;
+
+ case EFI_IMAGE_REL_BASED_HIGHADJ:
+ //
+ // Not valid Relocation type for UEFI image, ASSERT
+ //
+ ASSERT (FALSE);
+ break;
+
+ default:
+ //
+ // Only Itanium requires ConvertPeImage_Ex
+ //
+ Status = PeHotRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);
+ if (RETURN_ERROR (Status)) {
+ return ;
+ }
+ }
+ //
+ // Next relocation record
+ //
+ Reloc += 1;
+ }
+ //
+ // next reloc block
+ //
+ RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
+ }
+}
+
+
+/**
+ Reads contents of a PE/COFF image from a buffer in system memory.
+
+ This is the default implementation of a PE_COFF_LOADER_READ_FILE function
+ that assumes FileHandle pointer to the beginning of a PE/COFF image.
+ This function reads contents of the PE/COFF image that starts at the system memory
+ address specified by FileHandle. The read operation copies ReadSize bytes from the
+ PE/COFF image starting at byte offset FileOffset into the buffer specified by Buffer.
+ The size of the buffer actually read is returned in ReadSize.
+
+ If FileHandle is NULL, then ASSERT().
+ If ReadSize is NULL, then ASSERT().
+ If Buffer is NULL, then ASSERT().
+
+ @param FileHandle Pointer to base of the input stream
+ @param FileOffset Offset into the PE/COFF image to begin the read operation.
+ @param ReadSize On input, the size in bytes of the requested read operation.
+ On output, the number of bytes actually read.
+ @param Buffer Output buffer that contains the data read from the PE/COFF image.
+
+ @retval RETURN_SUCCESS Data is read from FileOffset from the Handle into
+ the buffer.
+**/
+RETURN_STATUS
+EFIAPI
+PeCoffLoaderImageReadFromMemory (
+ IN VOID *FileHandle,
+ IN UINTN FileOffset,
+ IN OUT UINTN *ReadSize,
+ OUT VOID *Buffer
+ )
+{
+ ASSERT (ReadSize != NULL);
+ ASSERT (FileHandle != NULL);
+ ASSERT (Buffer != NULL);
+
+ CopyMem (Buffer, ((UINT8 *)FileHandle) + FileOffset, *ReadSize);
+ return RETURN_SUCCESS;
+}
+
+/**
+ Unloads a loaded PE/COFF image from memory and releases its taken resource.
+ Releases any environment specific resources that were allocated when the image
+ specified by ImageContext was loaded using PeCoffLoaderLoadImage().
+
+ For NT32 emulator, the PE/COFF image loaded by system needs to release.
+ For real platform, the PE/COFF image loaded by Core doesn't needs to be unloaded,
+ this function can simply return RETURN_SUCCESS.
+
+ If ImageContext is NULL, then ASSERT().
+
+ @param ImageContext Pointer to the image context structure that describes the PE/COFF
+ image to be unloaded.
+
+ @retval RETURN_SUCCESS The PE/COFF image was unloaded successfully.
+**/
+RETURN_STATUS
+EFIAPI
+PeCoffLoaderUnloadImage (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+ //
+ // Applies additional environment specific actions to unload a
+ // PE/COFF image if needed
+ //
+ PeCoffLoaderUnloadImageExtraAction (ImageContext);
+ return RETURN_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxPeCoffLib/BasePeCoffLibInternals.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxPeCoffLib/BasePeCoffLibInternals.h
new file mode 100644
index 00000000..d474f263
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxPeCoffLib/BasePeCoffLibInternals.h
@@ -0,0 +1,171 @@
+/* $Id: BasePeCoffLibInternals.h $ */
+/** @file
+ * BasePeCoffLibInternals.h
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*
+ This code is based on:
+
+ Declaration of internal functions in PE/COFF Lib.
+
+ Copyright (c) 2006, Intel Corporation<BR>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+*/
+
+#ifndef __BASE_PECOFF_LIB_INTERNALS__
+#define __BASE_PECOFF_LIB_INTERNALS__
+
+#include <Base.h>
+#include <Library/PeCoffLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PeCoffExtraActionLib.h>
+#include <IndustryStandard/PeImage.h>
+#include <IndustryStandard/VBoxFatImage.h>
+
+
+
+/**
+ Performs an Itanium-based specific relocation fixup and is a no-op on other
+ instruction sets.
+
+ @param Reloc Pointer to the relocation record.
+ @param Fixup Pointer to the address to fix up.
+ @param FixupData Pointer to a buffer to log the fixups.
+ @param Adjust The offset to adjust the fixup.
+
+ @return Status code.
+
+**/
+RETURN_STATUS
+PeCoffLoaderRelocateImageEx (
+ IN UINT16 *Reloc,
+ IN OUT CHAR8 *Fixup,
+ IN OUT CHAR8 **FixupData,
+ IN UINT64 Adjust
+ );
+
+
+/**
+ Performs an Itanium-based specific re-relocation fixup and is a no-op on other
+ instruction sets. This is used to re-relocated the image into the EFI virtual
+ space for runtime calls.
+
+ @param Reloc Pointer to the relocation record.
+ @param Fixup Pointer to the address to fix up.
+ @param FixupData Pointer to a buffer to log the fixups.
+ @param Adjust The offset to adjust the fixup.
+
+ @return Status code.
+
+**/
+RETURN_STATUS
+PeHotRelocateImageEx (
+ IN UINT16 *Reloc,
+ IN OUT CHAR8 *Fixup,
+ IN OUT CHAR8 **FixupData,
+ IN UINT64 Adjust
+ );
+
+
+/**
+ Returns TRUE if the machine type of PE/COFF image is supported. Supported
+ does not mean the image can be executed it means the PE/COFF loader supports
+ loading and relocating of the image type. It's up to the caller to support
+ the entry point.
+
+ @param Machine Machine type from the PE Header.
+
+ @return TRUE if this PE/COFF loader can load the image
+
+**/
+BOOLEAN
+PeCoffLoaderImageFormatSupported (
+ IN UINT16 Machine
+ );
+
+/**
+ Retrieves the magic value from the PE/COFF header.
+
+ @param Hdr The buffer in which to return the PE32, PE32+, or TE header.
+
+ @return EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC - Image is PE32
+ @return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC - Image is PE32+
+
+**/
+UINT16
+PeCoffLoaderGetPeHeaderMagicValue (
+ IN EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
+ );
+
+/**
+ Retrieves the PE or TE Header from a PE/COFF or TE image.
+
+ @param ImageContext The context of the image being loaded.
+ @param Hdr The buffer in which to return the PE32, PE32+, or TE header.
+
+ @retval RETURN_SUCCESS The PE or TE Header is read.
+ @retval Other The error status from reading the PE/COFF or TE image using the ImageRead function.
+
+**/
+RETURN_STATUS
+PeCoffLoaderGetPeHeader (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
+ OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
+ );
+
+/**
+ Converts an image address to the loaded address.
+
+ @param ImageContext The context of the image being loaded.
+ @param Address The address to be converted to the loaded address.
+
+ @return The converted address or NULL if the address can not be converted.
+
+**/
+VOID *
+PeCoffLoaderImageAddress (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
+ IN UINTN Address
+ );
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxPeCoffLib/PeCoffLoaderEx.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxPeCoffLib/PeCoffLoaderEx.c
new file mode 100644
index 00000000..43a57967
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxPeCoffLib/PeCoffLoaderEx.c
@@ -0,0 +1,128 @@
+/* $Id: PeCoffLoaderEx.c $ */
+/** @file
+ * PeCoffLoaderEx.c
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/*
+ This code is based on:
+
+ Specific relocation fixups for none Itanium architecture.
+
+ Copyright (c) 2006 - 2008, Intel Corporation<BR>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+*/
+
+#include "BasePeCoffLibInternals.h"
+
+
+/**
+ Performs an Itanium-based specific relocation fixup and is a no-op on other
+ instruction sets.
+
+ @param Reloc Pointer to the relocation record.
+ @param Fixup Pointer to the address to fix up.
+ @param FixupData Pointer to a buffer to log the fixups.
+ @param Adjust The offset to adjust the fixup.
+
+ @return Status code.
+
+**/
+RETURN_STATUS
+PeCoffLoaderRelocateImageEx (
+ IN UINT16 *Reloc,
+ IN OUT CHAR8 *Fixup,
+ IN OUT CHAR8 **FixupData,
+ IN UINT64 Adjust
+ )
+{
+ return RETURN_UNSUPPORTED;
+}
+
+/**
+ Returns TRUE if the machine type of PE/COFF image is supported. Supported
+ does not mean the image can be executed it means the PE/COFF loader supports
+ loading and relocating of the image type. It's up to the caller to support
+ the entry point.
+
+ The IA32/X64 version PE/COFF loader/relocater both support IA32, X64 and EBC images.
+
+ @param Machine Machine type from the PE Header.
+
+ @return TRUE if this PE/COFF loader can load the image
+
+**/
+BOOLEAN
+PeCoffLoaderImageFormatSupported (
+ IN UINT16 Machine
+ )
+{
+ if ((Machine == IMAGE_FILE_MACHINE_I386) || (Machine == IMAGE_FILE_MACHINE_X64) ||
+ (Machine == IMAGE_FILE_MACHINE_EBC)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Performs an Itanium-based specific re-relocation fixup and is a no-op on other
+ instruction sets. This is used to re-relocated the image into the EFI virtual
+ space for runtime calls.
+
+ @param Reloc Pointer to the relocation record.
+ @param Fixup Pointer to the address to fix up.
+ @param FixupData Pointer to a buffer to log the fixups.
+ @param Adjust The offset to adjust the fixup.
+
+ @return Status code.
+
+**/
+RETURN_STATUS
+PeHotRelocateImageEx (
+ IN UINT16 *Reloc,
+ IN OUT CHAR8 *Fixup,
+ IN OUT CHAR8 **FixupData,
+ IN UINT64 Adjust
+ )
+{
+ return RETURN_UNSUPPORTED;
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxPeCoffLib/VBoxPeCoffLib.inf b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxPeCoffLib/VBoxPeCoffLib.inf
new file mode 100644
index 00000000..8508bf46
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Library/VBoxPeCoffLib/VBoxPeCoffLib.inf
@@ -0,0 +1,84 @@
+# $Id: VBoxPeCoffLib.inf $
+## @file
+# VBoxPeCoffLib.inf
+#
+
+#
+# Copyright (C) 2010-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>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+# This code is based on:
+#
+#/** @file
+# PE/COFF Loader Library implementation.
+# The IPF version library supports loading IPF and EBC PE/COFF image.
+# The IA32 version library support loading IA32, X64 and EBC PE/COFF images.
+# The X64 version library support loading IA32, X64 and EBC PE/COFF images.
+#
+# Copyright (c) 2006 - 2009, Intel Corporation.<BR>
+# Portions copyright (c) 2008-2009 Apple Inc. All rights reserved.<BR>
+#
+# All rights reserved. This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VBoxPeCoffLib
+ FILE_GUID = 92e02078-d0ca-11de-a547-fb90b709a001
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PeCoffLib
+
+
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC ARM
+#
+
+[Sources.common]
+ BasePeCoffLibInternals.h
+ BasePeCoff.c
+ PeCoffLoaderEx.c
+
+[Packages]
+ VBoxPkg/VBoxPkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ DebugLib
+ PeCoffExtraActionLib
+ BaseMemoryLib
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/Logo.bmp b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/Logo.bmp
new file mode 100644
index 00000000..91c3ba89
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/Logo.bmp
Binary files differ
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/Logo.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/Logo.c
new file mode 100644
index 00000000..e815d000
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/Logo.c
@@ -0,0 +1,186 @@
+/* $Id: Logo.c $ */
+/** @file
+ * Logo DXE Driver, install Edkii Platform Logo protocol.
+ */
+
+/*
+ * Copyright (C) 2019-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ * ---------------------------------------------------------------------------
+ * This code is based on:
+ *
+ * Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ */
+#include <Uefi.h>
+#include <Protocol/HiiDatabase.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/HiiImageEx.h>
+#include <Protocol/PlatformLogo.h>
+#include <Protocol/HiiPackageList.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+
+typedef struct {
+ EFI_IMAGE_ID ImageId;
+ EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE Attribute;
+ INTN OffsetX;
+ INTN OffsetY;
+} LOGO_ENTRY;
+
+EFI_HII_IMAGE_EX_PROTOCOL *mHiiImageEx;
+EFI_HII_HANDLE mHiiHandle;
+LOGO_ENTRY mLogos[] = {
+ {
+ IMAGE_TOKEN (IMG_LOGO),
+ EdkiiPlatformLogoDisplayAttributeCenter,
+ 0,
+ 0
+ }
+};
+
+/**
+ Load a platform logo image and return its data and attributes.
+
+ @param This The pointer to this protocol instance.
+ @param Instance The visible image instance is found.
+ @param Image Points to the image.
+ @param Attribute The display attributes of the image returned.
+ @param OffsetX The X offset of the image regarding the Attribute.
+ @param OffsetY The Y offset of the image regarding the Attribute.
+
+ @retval EFI_SUCCESS The image was fetched successfully.
+ @retval EFI_NOT_FOUND The specified image could not be found.
+**/
+EFI_STATUS
+EFIAPI
+GetImage (
+ IN EDKII_PLATFORM_LOGO_PROTOCOL *This,
+ IN OUT UINT32 *Instance,
+ OUT EFI_IMAGE_INPUT *Image,
+ OUT EDKII_PLATFORM_LOGO_DISPLAY_ATTRIBUTE *Attribute,
+ OUT INTN *OffsetX,
+ OUT INTN *OffsetY
+ )
+{
+ UINT32 Current;
+ if (Instance == NULL || Image == NULL ||
+ Attribute == NULL || OffsetX == NULL || OffsetY == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Current = *Instance;
+ if (Current >= ARRAY_SIZE (mLogos)) {
+ return EFI_NOT_FOUND;
+ }
+
+ (*Instance)++;
+ *Attribute = mLogos[Current].Attribute;
+ *OffsetX = mLogos[Current].OffsetX;
+ *OffsetY = mLogos[Current].OffsetY;
+ return mHiiImageEx->GetImageEx (mHiiImageEx, mHiiHandle, mLogos[Current].ImageId, Image);
+}
+
+EDKII_PLATFORM_LOGO_PROTOCOL mPlatformLogo = {
+ GetImage
+};
+
+/**
+ Entrypoint of this module.
+
+ This function is the entrypoint of this module. It installs the Edkii
+ Platform Logo protocol.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeLogo (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_PACKAGE_LIST_HEADER *PackageList;
+ EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
+ EFI_HANDLE Handle;
+
+ Status = gBS->LocateProtocol (
+ &gEfiHiiDatabaseProtocolGuid,
+ NULL,
+ (VOID **) &HiiDatabase
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->LocateProtocol (
+ &gEfiHiiImageExProtocolGuid,
+ NULL,
+ (VOID **) &mHiiImageEx
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Retrieve HII package list from ImageHandle
+ //
+ Status = gBS->OpenProtocol (
+ ImageHandle,
+ &gEfiHiiPackageListProtocolGuid,
+ (VOID **) &PackageList,
+ ImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "HII Image Package with logo not found in PE/COFF resource section\n"));
+ return Status;
+ }
+
+ //
+ // Publish HII package list to HII Database.
+ //
+ Status = HiiDatabase->NewPackageList (
+ HiiDatabase,
+ PackageList,
+ NULL,
+ &mHiiHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ Handle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEdkiiPlatformLogoProtocolGuid, &mPlatformLogo,
+ NULL
+ );
+ }
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/Logo.idf b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/Logo.idf
new file mode 100644
index 00000000..671ad6bc
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/Logo.idf
@@ -0,0 +1,10 @@
+// /** @file
+// Platform Logo image definition file.
+//
+// Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#image IMG_LOGO Logo.bmp
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/Logo.inf b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/Logo.inf
new file mode 100644
index 00000000..902a4e2f
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/Logo.inf
@@ -0,0 +1,68 @@
+# $Id: Logo.inf $
+## @file
+# Logo.inf
+#
+
+#
+# Copyright (C) 2019-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>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+#
+# This code is based on:
+#
+## @file
+# The default logo bitmap picture shown on setup screen, which is corresponding to gEfiDefaultBmpLogoGuid.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Logo
+ MODULE_UNI_FILE = Logo.uni
+ FILE_GUID = 7BB28B99-61BB-11D5-9A5D-0090273FC14D
+ MODULE_TYPE = USER_DEFINED
+ VERSION_STRING = 1.0
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC ARM AARCH64
+#
+
+[Binaries]
+ BIN|Logo.bmp|*
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ LogoExtra.uni
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/Logo.uni b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/Logo.uni
new file mode 100644
index 00000000..9d1bbaff
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/Logo.uni
@@ -0,0 +1,16 @@
+// /** @file
+// The default logo bitmap picture shown on setup screen, which is corresponding to gEfiDefaultBmpLogoGuid.
+//
+// This module provides the default logo bitmap picture shown on setup screen, which corresponds to gEfiDefaultBmpLogoGuid.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides the default logo bitmap picture shown on setup screen, which corresponds to gEfiDefaultBmpLogoGuid"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module provides the default logo bitmap picture shown on setup screen, which corresponds to gEfiDefaultBmpLogoGuid."
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/LogoDxe.inf b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/LogoDxe.inf
new file mode 100644
index 00000000..308fe742
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/LogoDxe.inf
@@ -0,0 +1,95 @@
+# $Id: LogoDxe.inf $
+## @file
+# LogoDxe.inf
+#
+
+#
+# Copyright (C) 2019-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>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+#
+# This code is based on:
+#
+## @file
+# The default logo bitmap picture shown on setup screen.
+#
+# Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = LogoDxe
+ MODULE_UNI_FILE = LogoDxe.uni
+ FILE_GUID = F74D20EE-37E7-48FC-97F7-9B1047749C69
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = InitializeLogo
+#
+# This flag specifies whether HII resource section is generated into PE image.
+#
+ UEFI_HII_RESOURCE_SECTION = TRUE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ Logo.bmp
+ Logo.c
+ Logo.idf
+
+[Packages]
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ DebugLib
+
+[Protocols]
+ gEfiHiiDatabaseProtocolGuid ## CONSUMES
+ gEfiHiiImageExProtocolGuid ## CONSUMES
+ gEfiHiiPackageListProtocolGuid ## PRODUCES CONSUMES
+ gEdkiiPlatformLogoProtocolGuid ## PRODUCES
+
+[Depex]
+ gEfiHiiDatabaseProtocolGuid AND
+ gEfiHiiImageExProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ LogoDxeExtra.uni
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/LogoDxe.uni b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/LogoDxe.uni
new file mode 100644
index 00000000..9635701b
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/LogoDxe.uni
@@ -0,0 +1,16 @@
+// /** @file
+// The default logo bitmap picture shown on setup screen.
+//
+// This module provides the default logo bitmap picture shown on setup screen, through EDKII Platform Logo protocol.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides the default logo bitmap picture shown on setup screen."
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module provides the default logo bitmap picture shown on setup screen, through EDKII Platform Logo protocol."
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/LogoDxeExtra.uni b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/LogoDxeExtra.uni
new file mode 100644
index 00000000..c6ea34b8
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/LogoDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// Logo Localized Strings and Content
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Logo Image File"
+
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/LogoExtra.uni b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/LogoExtra.uni
new file mode 100644
index 00000000..041179fb
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Logo/LogoExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// Logo Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Logo Image File"
+
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/Makefile.kup b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/Makefile.kup
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxApfsJmpStartDxe/VBoxApfsJmpStartDxe.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxApfsJmpStartDxe/VBoxApfsJmpStartDxe.c
new file mode 100644
index 00000000..7db37a32
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxApfsJmpStartDxe/VBoxApfsJmpStartDxe.c
@@ -0,0 +1,521 @@
+/* $Id: VBoxApfsJmpStartDxe.c $ */
+/** @file
+ * VBoxApfsJmpStartDxe.c - VirtualBox APFS jumpstart driver.
+ */
+
+/*
+ * Copyright (C) 2019-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <Protocol/ComponentName.h>
+#include <Protocol/ComponentName2.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/DiskIo.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#define IN_RING0
+#include <iprt/cdefs.h>
+#include <iprt/formats/apfs.h>
+
+/**
+ * Contains the full jump start context being worked on.
+ */
+typedef struct
+{
+ /** Block I/O protocol. */
+ EFI_BLOCK_IO *pBlockIo;
+ /** Disk I/O protocol. */
+ EFI_DISK_IO *pDiskIo;
+ /** Block size. */
+ uint32_t cbBlock;
+ /** Controller handle. */
+ EFI_HANDLE hController;
+ /** APFS UUID. */
+ APFSUUID Uuid;
+} APFSJMPSTARTCTX;
+typedef APFSJMPSTARTCTX *PAPFSJMPSTARTCTX;
+typedef const APFSJMPSTARTCTX *PCAPFSJMPSTARTCTX;
+
+static EFI_GUID g_ApfsDrvLoadedFromThisControllerGuid = { 0x01aaf8bc, 0x9c37, 0x4dc1,
+ { 0xb1, 0x68, 0xe9, 0x67, 0xd4, 0x2c, 0x79, 0x25 } };
+
+typedef struct APFS_DRV_LOADED_INFO
+{
+ EFI_HANDLE hController;
+ EFI_GUID GuidContainer;
+} APFS_DRV_LOADED_INFO;
+
+/** Driver name translation table. */
+static CONST EFI_UNICODE_STRING_TABLE g_aVBoxApfsJmpStartDriverLangAndNames[] =
+{
+ { "eng;en", L"VBox APFS Jumpstart Wrapper Driver" },
+ { NULL, NULL }
+};
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+
+/**
+ * Reads data from the given offset into the buffer.
+ *
+ * @returns EFI status code.
+ * @param pCtx The jump start context.
+ * @param offRead Where to start reading from.
+ * @param pvBuf Where to read into.
+ * @param cbRead Number of bytes to read.
+ */
+static EFI_STATUS vboxApfsJmpStartRead(IN PAPFSJMPSTARTCTX pCtx, IN APFSPADDR offRead, IN void *pvBuf, IN size_t cbRead)
+{
+ return pCtx->pDiskIo->ReadDisk(pCtx->pDiskIo, pCtx->pBlockIo->Media->MediaId, offRead * pCtx->cbBlock, cbRead, pvBuf);
+}
+
+/**
+ * Calculates the fletcher64 checksum of the given APFS block and returns TRUE if it matches the one given in the object header.
+ *
+ * @returns Flag indicating whether the checksum matched.
+ * @param pObjHdr The object header containing the checksum to check against.
+ * @param pvStruct Pointer to the struct to create the checksum of.
+ * @param cbStruct Size of the struct in bytes.
+ */
+static BOOLEAN vboxApfsObjPhysIsChksumValid(PCAPFSOBJPHYS pObjHdr, void *pvStruct, size_t cbStruct)
+{
+ if (cbStruct % sizeof(uint32_t) == 0)
+ {
+ uint32_t *pu32Data = (uint32_t *)pvStruct + 2; /* Start after the checksum field at the beginning. */
+ size_t cWordsLeft = (cbStruct >> 2) - 2;
+
+ uint64_t u64C0 = 0;
+ uint64_t u64C1 = 0;
+ uint64_t u64ChksumFletcher64 = 0;
+ uint64_t u64Check0 = 0;
+ uint64_t u64Check1 = 0;
+
+ while (cWordsLeft)
+ {
+ u64C0 += (uint64_t)*pu32Data++;
+ u64C0 %= UINT32_C(0xffffffff);
+
+ u64C1 += u64C0;
+ u64C1 %= UINT32_C(0xffffffff);
+
+ cWordsLeft--;
+ }
+
+ u64Check0 = UINT32_C(0xffffffff) - (u64C0 + u64C1) % UINT32_C(0xffffffff);
+ u64Check1 = UINT32_C(0xffffffff) - (u64C0 + u64Check0) % UINT32_C(0xffffffff);
+
+ u64ChksumFletcher64 = (uint64_t)u64Check1 << 32 | u64Check0;
+ if (!CompareMem(&u64ChksumFletcher64, &pObjHdr->abChkSum[0], sizeof(pObjHdr->abChkSum)))
+ return TRUE;
+ else
+ DEBUG((DEBUG_INFO, "vboxApfsObjPhysIsChksumValid: Checksum mismatch, expected 0x%llx got 0x%llx", u64ChksumFletcher64, *(uint64_t *)&pObjHdr->abChkSum[0]));
+ }
+ else
+ DEBUG((DEBUG_INFO, "vboxApfsObjPhysIsChksumValid: Structure not a multiple of 32bit\n"));
+
+ return FALSE;
+}
+
+/**
+ * Loads and starts the EFI driver contained in the given jump start structure.
+ *
+ * @returns EFI status code.
+ * @param pCtx APFS jump start driver context structure.
+ * @param pJmpStart APFS jump start structure describing the EFI file to load and start.
+ */
+static EFI_STATUS vboxApfsJmpStartLoadAndExecEfiDriver(IN PAPFSJMPSTARTCTX pCtx, IN PCAPFSEFIJMPSTART pJmpStart)
+{
+ PCAPFSPRANGE paExtents = (PCAPFSPRANGE)(pJmpStart + 1);
+ UINTN cbReadLeft = RT_LE2H_U32(pJmpStart->cbEfiFile);
+ EFI_STATUS rc = EFI_SUCCESS;
+
+ void *pvApfsDrv = AllocateZeroPool(cbReadLeft);
+ if (pvApfsDrv)
+ {
+ uint32_t i = 0;
+ uint8_t *pbBuf = (uint8_t *)pvApfsDrv;
+
+ for (i = 0; i < RT_LE2H_U32(pJmpStart->cExtents) && !EFI_ERROR(rc) && cbReadLeft; i++)
+ {
+ UINTN cbRead = RT_MIN(cbReadLeft, (UINTN)RT_LE2H_U64(paExtents[i].cBlocks) * pCtx->cbBlock);
+
+ rc = vboxApfsJmpStartRead(pCtx, RT_LE2H_U64(paExtents[i].PAddrStart), pbBuf, cbRead);
+ pbBuf += cbRead;
+ cbReadLeft -= cbRead;
+ }
+
+ if (!EFI_ERROR(rc))
+ {
+ /* Retrieve the parent device path. */
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+
+ rc = gBS->HandleProtocol(pCtx->hController, &gEfiDevicePathProtocolGuid, (VOID **)&ParentDevicePath);
+ if (!EFI_ERROR(rc))
+ {
+ /* Load image and execute it. */
+ EFI_HANDLE hImage;
+
+ rc = gBS->LoadImage(FALSE, gImageHandle, ParentDevicePath,
+ pvApfsDrv, RT_LE2H_U32(pJmpStart->cbEfiFile),
+ &hImage);
+ if (!EFI_ERROR(rc))
+ {
+ /* Try to start the image. */
+ rc = gBS->StartImage(hImage, NULL, NULL);
+ if (!EFI_ERROR(rc))
+ {
+ APFS_DRV_LOADED_INFO *pApfsDrvLoadedInfo = (APFS_DRV_LOADED_INFO *)AllocatePool (sizeof(APFS_DRV_LOADED_INFO));
+ if (pApfsDrvLoadedInfo)
+ {
+ pApfsDrvLoadedInfo->hController = pCtx->hController;
+ CopyMem(&pApfsDrvLoadedInfo->GuidContainer, &pCtx->Uuid, sizeof(pApfsDrvLoadedInfo->GuidContainer));
+
+ rc = gBS->InstallMultipleProtocolInterfaces(&pCtx->hController, &g_ApfsDrvLoadedFromThisControllerGuid, pApfsDrvLoadedInfo, NULL);
+ if (!EFI_ERROR(rc))
+ {
+ /* Connect the driver with the controller it came from. */
+ EFI_HANDLE ahImage[2];
+
+ ahImage[0] = hImage;
+ ahImage[1] = NULL;
+
+ gBS->ConnectController(pCtx->hController, &ahImage[0], NULL, TRUE);
+ return EFI_SUCCESS;
+ }
+ else
+ {
+ FreePool(pApfsDrvLoadedInfo);
+ DEBUG((DEBUG_INFO, "VBoxApfsJmpStart: Failed to install APFS driver loaded info protocol with %r\n", rc));
+ }
+ }
+ else
+ {
+ DEBUG((DEBUG_INFO, "VBoxApfsJmpStart: Failed to allocate %u bytes for the driver loaded structure\n", sizeof(APFS_DRV_LOADED_INFO)));
+ rc = EFI_OUT_OF_RESOURCES;
+ }
+ }
+ else
+ DEBUG((DEBUG_INFO, "VBoxApfsJmpStart: Starting APFS driver failed with %r\n", rc));
+
+ gBS->UnloadImage(hImage);
+ }
+ else
+ DEBUG((DEBUG_INFO, "VBoxApfsJmpStart: Loading read image failed with %r\n", rc));
+ }
+ else
+ DEBUG((DEBUG_INFO, "VBoxApfsJmpStart: Querying device path protocol failed with %r\n", rc));
+ }
+ else
+ DEBUG((DEBUG_INFO, "VBoxApfsJmpStart: Reading the jump start extents failed with %r\n", rc));
+
+ FreePool(pvApfsDrv);
+ }
+ else
+ {
+ DEBUG((DEBUG_INFO, "VBoxApfsJmpStart: Failed to allocate %u bytes for the APFS driver image\n", cbReadLeft));
+ rc = EFI_OUT_OF_RESOURCES;
+ }
+
+ return rc;
+}
+
+/**
+ * @copydoc EFI_DRIVER_BINDING_SUPPORTED
+ */
+static EFI_STATUS EFIAPI
+VBoxApfsJmpStart_Supported(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL)
+{
+ /* Check whether the controller supports the block I/O protocol. */
+ EFI_STATUS rc = gBS->OpenProtocol(ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL);
+ if (EFI_ERROR(rc))
+ return rc;
+
+ rc = gBS->OpenProtocol(ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL);
+ if (EFI_ERROR(rc))
+ return rc;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ * @copydoc EFI_DRIVER_BINDING_START
+ */
+static EFI_STATUS EFIAPI
+VBoxApfsJmpStart_Start(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL)
+{
+ APFSJMPSTARTCTX Ctx;
+
+ /* Check whether the driver was already loaded from this controller. */
+ EFI_STATUS rc = gBS->OpenProtocol(ControllerHandle,
+ &g_ApfsDrvLoadedFromThisControllerGuid,
+ NULL,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL);
+ if (!EFI_ERROR(rc))
+ return EFI_UNSUPPORTED;
+
+ Ctx.cbBlock = 0; /* Will get filled when the superblock was read (starting at 0 anyway). */
+ Ctx.hController = ControllerHandle;
+
+ rc = gBS->OpenProtocol(ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ (void **)&Ctx.pBlockIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (!EFI_ERROR(rc))
+ {
+ rc = gBS->OpenProtocol(ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ (void **)&Ctx.pDiskIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (!EFI_ERROR(rc))
+ {
+ /* Read the NX superblock structure from the first block and verify it. */
+ APFSNXSUPERBLOCK Sb;
+
+ rc = vboxApfsJmpStartRead(&Ctx, 0, &Sb, sizeof(Sb));
+ if ( !EFI_ERROR(rc)
+ && RT_LE2H_U32(Sb.u32Magic) == APFS_NX_SUPERBLOCK_MAGIC)
+ {
+ uint8_t *pbBlock = (uint8_t *)AllocateZeroPool(RT_LE2H_U32(Sb.cbBlock));
+
+ if (pbBlock)
+ {
+ PCAPFSNXSUPERBLOCK pSb = (PCAPFSNXSUPERBLOCK)pbBlock;
+
+ /* Read in the complete block (checksums always cover the whole block and not just the structure...). */
+ Ctx.cbBlock = RT_LE2H_U32(Sb.cbBlock);
+
+ rc = vboxApfsJmpStartRead(&Ctx, 0, pbBlock, Ctx.cbBlock);
+ if ( !EFI_ERROR(rc)
+ && RT_LE2H_U64(Sb.PAddrEfiJmpStart) > 0
+ && vboxApfsObjPhysIsChksumValid(&pSb->ObjHdr, pbBlock, Ctx.cbBlock))
+ {
+ PCAPFSEFIJMPSTART pJmpStart = (PCAPFSEFIJMPSTART)pbBlock;
+
+ DEBUG((DEBUG_INFO, "VBoxApfsJmpStart: Found APFS superblock, reading jumpstart structure from %llx\n", RT_LE2H_U64(Sb.PAddrEfiJmpStart)));
+
+ CopyMem(&Ctx.Uuid, &pSb->Uuid, sizeof(Ctx.Uuid));
+
+ rc = vboxApfsJmpStartRead(&Ctx, RT_LE2H_U64(Sb.PAddrEfiJmpStart), pbBlock, Ctx.cbBlock);
+ if ( !EFI_ERROR(rc)
+ && RT_H2LE_U32(pJmpStart->u32Magic) == APFS_EFIJMPSTART_MAGIC
+ && RT_H2LE_U32(pJmpStart->u32Version) == APFS_EFIJMPSTART_VERSION
+ && vboxApfsObjPhysIsChksumValid(&pJmpStart->ObjHdr, pbBlock, Ctx.cbBlock)
+ && RT_H2LE_U32(pJmpStart->cExtents) <= (Ctx.cbBlock - sizeof(*pJmpStart)) / sizeof(APFSPRANGE))
+ rc = vboxApfsJmpStartLoadAndExecEfiDriver(&Ctx, pJmpStart);
+ else
+ {
+ rc = EFI_UNSUPPORTED;
+ DEBUG((DEBUG_INFO, "VBoxApfsJmpStart: The APFS EFI jumpstart structure is invalid\n"));
+ }
+ }
+ else
+ {
+ DEBUG((DEBUG_INFO, "VBoxApfsJmpStart: Invalid APFS superblock -> no APFS filesystem (%r %x %llx)\n", rc, Sb.u32Magic, Sb.PAddrEfiJmpStart));
+ rc = EFI_UNSUPPORTED;
+ }
+
+ FreePool(pbBlock);
+ }
+ else
+ DEBUG((DEBUG_INFO, "VBoxApfsJmpStart: Failed to allocate memory for APFS block data (%u bytes)\n", RT_LE2H_U32(Sb.cbBlock)));
+ }
+ else
+ DEBUG((DEBUG_INFO, "VBoxApfsJmpStart: Invalid APFS superblock -> no APFS filesystem (%r %x)\n", rc, Sb.u32Magic));
+
+ gBS->CloseProtocol(ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle);
+ }
+ else
+ DEBUG((DEBUG_INFO, "VBoxApfsJmpStart: Opening the Disk I/O protocol failed with %r\n", rc));
+
+ gBS->CloseProtocol(ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle);
+ }
+ else
+ DEBUG((DEBUG_INFO, "VBoxApfsJmpStart: Opening the Block I/O protocol failed with %r\n", rc));
+
+ return rc;
+}
+
+
+/**
+ * @copydoc EFI_DRIVER_BINDING_STOP
+ */
+static EFI_STATUS EFIAPI
+VBoxApfsJmpStart_Stop(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer OPTIONAL)
+{
+ /* EFI_STATUS rc; */
+
+ return EFI_UNSUPPORTED;
+}
+
+
+/** @copydoc EFI_COMPONENT_NAME_GET_DRIVER_NAME */
+static EFI_STATUS EFIAPI
+VBoxApfsJmpStartCN_GetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language, OUT CHAR16 **DriverName)
+{
+ return LookupUnicodeString2(Language,
+ This->SupportedLanguages,
+ &g_aVBoxApfsJmpStartDriverLangAndNames[0],
+ DriverName,
+ TRUE);
+}
+
+/** @copydoc EFI_COMPONENT_NAME_GET_CONTROLLER_NAME */
+static EFI_STATUS EFIAPI
+VBoxApfsJmpStartCN_GetControllerName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language, OUT CHAR16 **ControllerName)
+{
+ /** @todo try query the protocol from the controller and forward the query. */
+ return EFI_UNSUPPORTED;
+}
+
+/** @copydoc EFI_COMPONENT_NAME2_GET_DRIVER_NAME */
+static EFI_STATUS EFIAPI
+VBoxApfsJmpStartCN2_GetDriverName(IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN CHAR8 *Language, OUT CHAR16 **DriverName)
+{
+ return LookupUnicodeString2(Language,
+ This->SupportedLanguages,
+ &g_aVBoxApfsJmpStartDriverLangAndNames[0],
+ DriverName,
+ FALSE);
+}
+
+/** @copydoc EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME */
+static EFI_STATUS EFIAPI
+VBoxApfsJmpStartCN2_GetControllerName(IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language, OUT CHAR16 **ControllerName)
+{
+ /** @todo try query the protocol from the controller and forward the query. */
+ return EFI_UNSUPPORTED;
+}
+
+
+
+/*********************************************************************************************************************************
+* Entry point and driver registration *
+*********************************************************************************************************************************/
+
+/** EFI Driver Binding Protocol. */
+static EFI_DRIVER_BINDING_PROTOCOL g_VBoxApfsJmpStartDB =
+{
+ VBoxApfsJmpStart_Supported,
+ VBoxApfsJmpStart_Start,
+ VBoxApfsJmpStart_Stop,
+ /* .Version = */ 1,
+ /* .ImageHandle = */ NULL,
+ /* .DriverBindingHandle = */ NULL
+};
+
+/** EFI Component Name Protocol. */
+static const EFI_COMPONENT_NAME_PROTOCOL g_VBoxApfsJmpStartCN =
+{
+ VBoxApfsJmpStartCN_GetDriverName,
+ VBoxApfsJmpStartCN_GetControllerName,
+ "eng"
+};
+
+/** EFI Component Name 2 Protocol. */
+static const EFI_COMPONENT_NAME2_PROTOCOL g_VBoxApfsJmpStartCN2 =
+{
+ VBoxApfsJmpStartCN2_GetDriverName,
+ VBoxApfsJmpStartCN2_GetControllerName,
+ "en"
+};
+
+
+/**
+ * VBoxApfsJmpStart entry point.
+ *
+ * @returns EFI status code.
+ *
+ * @param ImageHandle The image handle.
+ * @param SystemTable The system table pointer.
+ */
+EFI_STATUS EFIAPI
+VBoxApfsjmpStartEntryDxe(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
+{
+ EFI_STATUS rc;
+ DEBUG((DEBUG_INFO, "VBoxApfsjmpStartEntryDxe\n"));
+
+ rc = EfiLibInstallDriverBindingComponentName2(ImageHandle, SystemTable,
+ &g_VBoxApfsJmpStartDB, ImageHandle,
+ &g_VBoxApfsJmpStartCN, &g_VBoxApfsJmpStartCN2);
+ ASSERT_EFI_ERROR(rc);
+ return rc;
+}
+
+EFI_STATUS EFIAPI
+VBoxApfsjmpStartUnloadDxe(IN EFI_HANDLE ImageHandle)
+{
+ return EFI_SUCCESS;
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxApfsJmpStartDxe/VBoxApfsJmpStartDxe.inf b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxApfsJmpStartDxe/VBoxApfsJmpStartDxe.inf
new file mode 100644
index 00000000..8f0d4ea5
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxApfsJmpStartDxe/VBoxApfsJmpStartDxe.inf
@@ -0,0 +1,89 @@
+# $Id: VBoxApfsJmpStartDxe.inf $
+## @file
+# VBoxApfsJmpStartDxe - VBox wrapper for loading the APFS jump start EFI driver from an APFS volume.
+#
+
+#
+# Copyright (C) 2019-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>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VBoxApfsJmpStartDxe
+ FILE_GUID = 16cb3fd4-576d-4ec8-8a81-2176c69a1229
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ EDK_RELEASE_VERSION = 0x00020000
+ EFI_SPECIFICATION_VERSION = 0x00020000
+ ENTRY_POINT = VBoxApfsjmpStartEntryDxe
+ UNLOAD_IMAGE = VBoxApfsjmpStartUnloadDxe
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gUdfDriverBinding
+# COMPONENT_NAME = gUdfComponentName
+# COMPONENT_NAME2 = gUdfComponentName2
+#
+
+[Sources.common]
+ VBoxApfsJmpStartDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ VBoxPkg/VBoxPkg.dec
+
+[LibraryClasses]
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ BaseLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+ PcdLib
+
+[Guids]
+ gEfiFileInfoGuid
+ gEfiFileSystemInfoGuid
+ gEfiFileSystemVolumeLabelInfoIdGuid
+
+
+[Protocols]
+ gEfiDiskIoProtocolGuid
+ gEfiBlockIoProtocolGuid
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLang
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLang
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxAppleSim/Console.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxAppleSim/Console.c
new file mode 100644
index 00000000..ecb959fe
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxAppleSim/Console.c
@@ -0,0 +1,106 @@
+/* $Id: Console.c $ */
+/** @file
+ * Console.c - VirtualBox Console control emulation
+ */
+
+/*
+ * Copyright (C) 2010-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+#include <Uefi.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+
+#include "VBoxPkg.h"
+#include "ConsoleControl.h"
+
+EFI_STATUS EFIAPI
+GetModeImpl(
+ IN EFI_CONSOLE_CONTROL_PROTOCOL *This,
+ OUT EFI_CONSOLE_CONTROL_SCREEN_MODE *Mode,
+ OUT BOOLEAN *GopUgaExists, OPTIONAL
+ OUT BOOLEAN *StdInLocked OPTIONAL
+ )
+{
+ *Mode = EfiConsoleControlScreenGraphics;
+
+ if (GopUgaExists)
+ *GopUgaExists = TRUE;
+ if (StdInLocked)
+ *StdInLocked = FALSE;
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS EFIAPI
+SetModeImpl(
+ IN EFI_CONSOLE_CONTROL_PROTOCOL *This,
+ IN EFI_CONSOLE_CONTROL_SCREEN_MODE Mode
+ )
+{
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS EFIAPI
+LockStdInImpl(
+ IN EFI_CONSOLE_CONTROL_PROTOCOL *This,
+ IN CHAR16 *Password
+ )
+{
+ return EFI_SUCCESS;
+}
+
+
+EFI_CONSOLE_CONTROL_PROTOCOL gConsoleController =
+{
+ GetModeImpl,
+ SetModeImpl,
+ LockStdInImpl
+};
+
+EFI_GUID gEfiConsoleControlProtocolGuid = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
+
+EFI_STATUS
+EFIAPI
+InitializeConsoleSim (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiConsoleControlProtocolGuid,
+ &gConsoleController,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxAppleSim/ConsoleControl.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxAppleSim/ConsoleControl.h
new file mode 100644
index 00000000..842dac7d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxAppleSim/ConsoleControl.h
@@ -0,0 +1,158 @@
+/* $Id: ConsoleControl.h $ */
+/** @file
+ * ConsoleControl.h
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/*
+ * This code is based on:
+ *
+ * Copyright (c) 2004 - 2006, Intel Corporation
+ * All rights reserved. This program and the accompanying materials
+ * are licensed and made available under the terms and conditions of the BSD License
+ * which accompanies this distribution. The full text of the license may be found at
+ * http://opensource.org/licenses/bsd-license.php
+ *
+ * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ *
+ * Module Name:
+ *
+ * ConsoleControl.h
+ *
+ * Abstract:
+ *
+ * Abstraction of a Text mode or GOP/UGA screen
+ */
+
+#ifndef __CONSOLE_CONTROL_H__
+#define __CONSOLE_CONTROL_H__
+
+#define EFI_CONSOLE_CONTROL_PROTOCOL_GUID \
+ { 0xf42f7782, 0x12e, 0x4c12, {0x99, 0x56, 0x49, 0xf9, 0x43, 0x4, 0xf7, 0x21} }
+
+typedef struct _EFI_CONSOLE_CONTROL_PROTOCOL EFI_CONSOLE_CONTROL_PROTOCOL;
+
+
+typedef enum {
+ EfiConsoleControlScreenText,
+ EfiConsoleControlScreenGraphics,
+ EfiConsoleControlScreenMaxValue
+} EFI_CONSOLE_CONTROL_SCREEN_MODE;
+
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE) (
+ IN EFI_CONSOLE_CONTROL_PROTOCOL *This,
+ OUT EFI_CONSOLE_CONTROL_SCREEN_MODE *Mode,
+ OUT BOOLEAN *GopUgaExists, OPTIONAL
+ OUT BOOLEAN *StdInLocked OPTIONAL
+ )
+/*++
+
+ Routine Description:
+ Return the current video mode information. Also returns info about existence
+ of Graphics Output devices or UGA Draw devices in system, and if the Std In
+ device is locked. All the arguments are optional and only returned if a non
+ NULL pointer is passed in.
+
+ Arguments:
+ This - Protocol instance pointer.
+ Mode - Are we in text of graphics mode.
+ GopUgaExists - TRUE if Console Splitter has found a GOP or UGA device
+ StdInLocked - TRUE if StdIn device is keyboard locked
+
+ Returns:
+ EFI_SUCCESS - Mode information returned.
+
+--*/
+;
+
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE) (
+ IN EFI_CONSOLE_CONTROL_PROTOCOL *This,
+ OUT EFI_CONSOLE_CONTROL_SCREEN_MODE Mode
+ )
+/*++
+
+ Routine Description:
+ Set the current mode to either text or graphics. Graphics is
+ for Quiet Boot.
+
+ Arguments:
+ This - Protocol instance pointer.
+ Mode - Mode to set the
+
+ Returns:
+ EFI_SUCCESS - Mode information returned.
+
+--*/
+;
+
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN) (
+ IN EFI_CONSOLE_CONTROL_PROTOCOL *This,
+ IN CHAR16 *Password
+ )
+/*++
+
+ Routine Description:
+ Lock Std In devices until Password is typed.
+
+ Arguments:
+ This - Protocol instance pointer.
+ Password - Password needed to unlock screen. NULL means unlock keyboard
+
+ Returns:
+ EFI_SUCCESS - Mode information returned.
+ EFI_DEVICE_ERROR - Std In not locked
+
+--*/
+;
+
+
+
+struct _EFI_CONSOLE_CONTROL_PROTOCOL {
+ EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE GetMode;
+ EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE SetMode;
+ EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN LockStdIn;
+};
+
+extern EFI_GUID gEfiConsoleControlProtocolGuid;
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxAppleSim/Cpu.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxAppleSim/Cpu.c
new file mode 100644
index 00000000..4e91e13f
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxAppleSim/Cpu.c
@@ -0,0 +1,146 @@
+/* $Id: Cpu.c $ */
+/** @file
+ * Cpu.c - VirtualBox CPU descriptors
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiLib.h>
+#include <Library/HiiLib.h>
+#include <Library/BaseLib.h>
+
+#include <Protocol/Cpu.h>
+
+#include "DataHub.h"
+
+#define EFI_CPU_DATA_MAXIMUM_LENGTH 0x100
+
+EFI_GUID gEfiAppleMagicHubGuid = {
+ 0x64517cc8, 0x6561, 0x4051, {0xb0, 0x3c, 0x59, 0x64, 0xb6, 0x0f, 0x4c, 0x7a }
+};
+
+EFI_GUID gEfiProcessorSubClassGuid = {
+ 0x26fdeb7e, 0xb8af, 0x4ccf, { 0xaa, 0x97, 0x02, 0x63, 0x3c, 0xe4, 0x8c, 0xa7 }
+};
+
+#pragma pack(1)
+typedef struct {
+ UINT8 Pad0[0x10]; /* 0x48 */
+ UINT32 NameLen; /* 0x58 , in bytes */
+ UINT32 ValLen; /* 0x5c */
+ UINT8 Data[1]; /* 0x60 Name Value */
+} MAGIC_HUB_DATA;
+#pragma pack()
+
+UINT32
+CopyRecord(MAGIC_HUB_DATA* Rec, const CHAR16* Name, VOID* Val, UINT32 ValLen)
+{
+ Rec->NameLen = (UINT32)StrLen(Name) * sizeof(CHAR16);
+ Rec->ValLen = ValLen;
+ CopyMem(Rec->Data, Name, Rec->NameLen);
+ CopyMem(Rec->Data + Rec->NameLen, Val, ValLen);
+
+ return 0x10 + 4 + 4 + Rec->NameLen + Rec->ValLen;
+}
+
+EFI_STATUS EFIAPI
+LogData(EFI_DATA_HUB_PROTOCOL *DataHub,
+ MAGIC_HUB_DATA *MagicData,
+ CHAR16 *Name,
+ VOID *Data,
+ UINT32 DataSize)
+{
+ UINT32 RecordSize;
+ EFI_STATUS Status;
+
+ RecordSize = CopyRecord(MagicData, Name, Data, DataSize);
+ Status = DataHub->LogData (
+ DataHub,
+ &gEfiProcessorSubClassGuid, /* DataRecordGuid */
+ &gEfiAppleMagicHubGuid, /* ProducerName */
+ EFI_DATA_CLASS_DATA,
+ MagicData,
+ RecordSize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+EFI_STATUS EFIAPI
+CpuUpdateDataHub(EFI_BOOT_SERVICES * bs,
+ UINT64 FSBFrequency,
+ UINT64 TSCFrequency,
+ UINT64 CPUFrequency)
+{
+ EFI_STATUS Status;
+ EFI_DATA_HUB_PROTOCOL *DataHub;
+ MAGIC_HUB_DATA *MagicData;
+ UINT32 Supported = 1;
+ //
+ // Locate DataHub protocol.
+ //
+ Status = bs->LocateProtocol (&gEfiDataHubProtocolGuid, NULL, (VOID**)&DataHub);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ MagicData = (MAGIC_HUB_DATA*)AllocatePool (0x200);
+ if (MagicData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ // Log data in format some OSes like
+ LogData(DataHub, MagicData, L"FSBFrequency", &FSBFrequency, sizeof(FSBFrequency));
+ // do that twice, as last variable read not really accounted for
+ LogData(DataHub, MagicData, L"FSBFrequency", &FSBFrequency, sizeof(FSBFrequency));
+ LogData(DataHub, MagicData, L"TSCFrequency", &TSCFrequency, sizeof(TSCFrequency));
+ LogData(DataHub, MagicData, L"CPUFrequency", &CPUFrequency, sizeof(CPUFrequency));
+
+ // The following is required for OS X to construct a SATA boot path. UEFI 2.0 (published
+ // in Jan 2006, same time as the first Intel Macs) did not standardize SATA device paths;
+ // if DevicePathsSupported is not set, OS X will create ATA boot paths which will fail
+ // to boot
+ LogData(DataHub, MagicData, L"DevicePathsSupported", &Supported, sizeof(Supported));
+
+ FreePool (MagicData);
+
+ return EFI_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxAppleSim/DataHub.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxAppleSim/DataHub.c
new file mode 100644
index 00000000..33c2a3b2
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxAppleSim/DataHub.c
@@ -0,0 +1,215 @@
+/* $Id: DataHub.c $ */
+/** @file
+ * Console.c - VirtualBox Console control emulation
+ */
+
+/*
+ * Copyright (C) 2010-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+
+#include "VBoxPkg.h"
+#include "DataHub.h"
+
+/**
+ * Data hub logged entry.
+ */
+typedef struct
+{
+ /** List node for the linked list - must be at the top. */
+ LIST_ENTRY NdEntries;
+ /** The record header. */
+ EFI_DATA_RECORD_HEADER RecHdr;
+ /** The data logged, variable in size. */
+ UINT8 abData[1];
+} EFI_DATA_HUB_ENTRY;
+
+/**
+ * DataHub instance data.
+ */
+typedef struct
+{
+ /** Monotonic increasing counter. */
+ UINT64 cMonotonicCnt;
+ /** Linked list holding the logged entries. */
+ LIST_ENTRY LstEntries;
+ /** The lock protecting the key members above. */
+ EFI_LOCK Lck;
+} EFI_DATA_HUB_INSTANCE;
+
+
+EFI_DATA_HUB_INSTANCE mDataHubInstance;
+
+EFI_STATUS EFIAPI
+DataHubLogData (
+ IN EFI_DATA_HUB_PROTOCOL *This,
+ IN EFI_GUID *DataRecordGuid,
+ IN EFI_GUID *ProducerName,
+ IN UINT64 DataRecordClass,
+ IN VOID *RawData,
+ IN UINT32 RawDataSize
+ )
+{
+ UINT32 cbEntry = sizeof(EFI_DATA_HUB_ENTRY) + RawDataSize;
+ EFI_DATA_HUB_ENTRY *pEntry = AllocatePool(cbEntry);
+
+ if (pEntry == NULL)
+ return EFI_OUT_OF_RESOURCES;
+
+ pEntry->RecHdr.Version = EFI_DATA_RECORD_HEADER_VERSION;
+ pEntry->RecHdr.HeaderSize = sizeof(EFI_DATA_RECORD_HEADER);
+ pEntry->RecHdr.RecordSize = RawDataSize + sizeof(EFI_DATA_RECORD_HEADER);
+ CopyMem(&pEntry->RecHdr.DataRecordGuid, DataRecordGuid, sizeof(pEntry->RecHdr.DataRecordGuid));
+ CopyMem(&pEntry->RecHdr.ProducerName, ProducerName, sizeof(pEntry->RecHdr.ProducerName));
+ pEntry->RecHdr.DataRecordClass = DataRecordClass;
+ SetMem(&pEntry->RecHdr.LogTime, sizeof(pEntry->RecHdr.LogTime), 0);
+ pEntry->RecHdr.LogMonotonicCount = ++mDataHubInstance.cMonotonicCnt; /* Ensure non zero value in record. */
+ CopyMem(&pEntry->abData[0], RawData, RawDataSize);
+
+ EfiAcquireLock(&mDataHubInstance.Lck);
+ InsertTailList(&mDataHubInstance.LstEntries, &pEntry->NdEntries);
+ EfiReleaseLock(&mDataHubInstance.Lck);
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS EFIAPI
+DataHubGetNextDataRecord (
+ IN EFI_DATA_HUB_PROTOCOL *This,
+ IN OUT UINT64 *MonotonicCount,
+ IN EFI_EVENT *FilterDriver OPTIONAL,
+ OUT EFI_DATA_RECORD_HEADER **Record
+ )
+{
+ EFI_DATA_HUB_ENTRY *pEntry = NULL;
+
+ EfiAcquireLock(&mDataHubInstance.Lck);
+ if (*MonotonicCount == 0)
+ {
+ if (!IsListEmpty(&mDataHubInstance.LstEntries))
+ pEntry = (EFI_DATA_HUB_ENTRY *)GetFirstNode(&mDataHubInstance.LstEntries);
+ }
+ else
+ {
+ /* Ignore filter driver handling for now. */
+ LIST_ENTRY *pHead = &mDataHubInstance.LstEntries;
+ LIST_ENTRY *pIt = NULL;
+
+ for (pIt = GetFirstNode(pHead); pIt != pHead; pIt = GetNextNode(pHead, pIt))
+ {
+ EFI_DATA_HUB_ENTRY *pTmp = (EFI_DATA_HUB_ENTRY *)pIt;
+ if (pTmp->RecHdr.LogMonotonicCount == *MonotonicCount)
+ {
+ pEntry = pTmp;
+ break;
+ }
+ }
+ }
+ EfiReleaseLock(&mDataHubInstance.Lck);
+
+ if (pEntry == NULL)
+ return EFI_NOT_FOUND;
+
+ *Record = &pEntry->RecHdr;
+
+ /* Look for the next entry and set MonotonicCount accordingly. */
+ if (!IsNodeAtEnd(&mDataHubInstance.LstEntries, &pEntry->NdEntries))
+ {
+ pEntry = (EFI_DATA_HUB_ENTRY *)GetNextNode(&mDataHubInstance.LstEntries, &pEntry->NdEntries);
+ *MonotonicCount = pEntry->RecHdr.LogMonotonicCount;
+ }
+ else
+ *MonotonicCount = 0;
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS EFIAPI
+DataHubRegisterDataFilterDriver (
+ IN EFI_DATA_HUB_PROTOCOL *This,
+ IN EFI_EVENT FilterEvent,
+ IN EFI_TPL FilterTpl,
+ IN UINT64 FilterClass,
+ IN EFI_GUID *FilterDataRecordGui OPTIONAL
+ )
+{
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS EFIAPI
+DataHubUnregisterDataFilterDriver (
+ IN EFI_DATA_HUB_PROTOCOL *This,
+ IN EFI_EVENT FilterEvent
+ )
+{
+ return EFI_SUCCESS;
+}
+
+
+EFI_DATA_HUB_PROTOCOL gDataHub =
+{
+ DataHubLogData,
+ DataHubGetNextDataRecord,
+ DataHubRegisterDataFilterDriver,
+ DataHubUnregisterDataFilterDriver
+};
+
+EFI_GUID gEfiDataHubProtocolGuid = EFI_DATA_HUB_PROTOCOL_GUID;
+
+EFI_STATUS
+EFIAPI
+InitializeDataHub (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+
+ InitializeListHead(&mDataHubInstance.LstEntries);
+ EfiInitializeLock (&mDataHubInstance.Lck, TPL_NOTIFY);
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiDataHubProtocolGuid,
+ &gDataHub,
+ NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxAppleSim/DataHub.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxAppleSim/DataHub.h
new file mode 100644
index 00000000..40358d9b
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxAppleSim/DataHub.h
@@ -0,0 +1,178 @@
+/* $Id: DataHub.h $ */
+/** @file
+ * DataHub.h
+ */
+
+/*
+ * Copyright (C) 2019-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+#ifndef __DATA_HUB_H__
+#define __DATA_HUB_H__
+
+#define EFI_DATA_HUB_PROTOCOL_GUID \
+ { 0xae80d021, 0x618e, 0x11d4, {0xbc, 0xd7, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81} }
+
+typedef struct _EFI_DATA_HUB_PROTOCOL EFI_DATA_HUB_PROTOCOL;
+
+
+#define EFI_DATA_RECORD_HEADER_VERSION 0x0100
+
+#define EFI_DATA_CLASS_DEBUG 0x1ULL
+#define EFI_DATA_CLASS_ERROR 0x2ULL
+#define EFI_DATA_CLASS_DATA 0x4ULL
+#define EFI_DATA_CLASS_PROGRESS_CODE 0x8ULL
+
+typedef struct {
+ UINT16 Version;
+ UINT16 HeaderSize;
+ UINT32 RecordSize;
+ EFI_GUID DataRecordGuid;
+ EFI_GUID ProducerName;
+ UINT64 DataRecordClass;
+ EFI_TIME LogTime;
+ UINT64 LogMonotonicCount;
+} EFI_DATA_RECORD_HEADER;
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_DATA_HUB_LOG_DATA) (
+ IN EFI_DATA_HUB_PROTOCOL *This,
+ IN EFI_GUID *DataRecordGuid,
+ IN EFI_GUID *ProducerName,
+ IN UINT64 DataRecordClass,
+ IN VOID *RawData,
+ IN UINT32 RawDataSize
+ )
+/*++
+
+ Routine Description:
+ Logs a data record to the system event log.
+
+ Arguments:
+ This - Protocol instance pointer.
+
+
+ Returns:
+ EFI_SUCCESS - Data was logged.
+
+--*/
+;
+
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_DATA_HUB_GET_NEXT_DATA_RECORD) (
+ IN EFI_DATA_HUB_PROTOCOL *This,
+ IN OUT UINT64 *MonotonicCount,
+ IN EFI_EVENT *FilterDriver OPTIONAL,
+ OUT EFI_DATA_RECORD_HEADER **Record
+ )
+/*++
+
+ Routine Description:
+ Allows the system data log to be searched.
+
+ Arguments:
+ This - Protocol instance pointer.
+
+
+ Returns:
+ EFI_SUCCESS - Data was logged.
+
+--*/
+;
+
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_DATA_HUB_REGISTER_DATA_FILTER_DRIVER) (
+ IN EFI_DATA_HUB_PROTOCOL *This,
+ IN EFI_EVENT FilterEvent,
+ IN EFI_TPL FilterTpl,
+ IN UINT64 FilterClass,
+ IN EFI_GUID *FilterDataRecordGui OPTIONAL
+ )
+/*++
+
+ Routine Description:
+ Registers an event to be signaled evey time a data record is logged in the system.
+
+ Arguments:
+ This - Protocol instance pointer.
+
+
+ Returns:
+ EFI_SUCCESS - The filter driver event was registered.
+
+--*/
+;
+
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_DATA_HUB_UNREGISTER_DATA_FILTER_DRIVER) (
+ IN EFI_DATA_HUB_PROTOCOL *This,
+ IN EFI_EVENT FilterEvent
+ )
+/*++
+
+ Routine Description:
+ Stops a filter driver from being notified when data records are logged.
+
+ Arguments:
+ This - Protocol instance pointer.
+
+
+ Returns:
+ EFI_SUCCESS - The filter driver represented by FilterEvent was shut off.
+
+--*/
+;
+
+
+struct _EFI_DATA_HUB_PROTOCOL {
+ EFI_DATA_HUB_LOG_DATA LogData;
+ EFI_DATA_HUB_GET_NEXT_DATA_RECORD GetNextDataRecord;
+ EFI_DATA_HUB_REGISTER_DATA_FILTER_DRIVER RegisterFilterDriver;
+ EFI_DATA_HUB_UNREGISTER_DATA_FILTER_DRIVER UnregisterFilterDriver;
+};
+
+extern EFI_GUID gEfiDataHubProtocolGuid;
+
+
+EFI_STATUS
+EFIAPI
+InitializeDataHub (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxAppleSim/VBoxAppleSim.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxAppleSim/VBoxAppleSim.c
new file mode 100644
index 00000000..b4f0a6dc
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxAppleSim/VBoxAppleSim.c
@@ -0,0 +1,352 @@
+/* $Id: VBoxAppleSim.c $ */
+/** @file
+ * VBoxAppleSim.c - VirtualBox Apple Firmware simulation support
+ */
+
+/*
+ * Copyright (C) 2010-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PrintLib.h>
+
+#include <Protocol/DevicePathToText.h>
+
+#include <IndustryStandard/Acpi10.h>
+#include <IndustryStandard/Acpi20.h>
+#include <IndustryStandard/SmBios.h>
+
+#include <Guid/SmBios.h>
+#include <Guid/Acpi.h>
+#include <Guid/Mps.h>
+
+#include "DataHub.h"
+#include "VBoxPkg.h"
+#include "DevEFI.h"
+#include "iprt/asm.h"
+
+
+/*
+ * External functions
+ */
+EFI_STATUS EFIAPI
+CpuUpdateDataHub(EFI_BOOT_SERVICES * bs,
+ UINT64 FSBFrequency,
+ UINT64 TSCFrequency,
+ UINT64 CPUFrequency);
+
+EFI_STATUS EFIAPI
+InitializeConsoleSim (IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable);
+
+
+/*
+ * Internal Functions
+ */
+static UINT32
+GetVmVariable(UINT32 Variable, CHAR8 *pbBuf, UINT32 cbBuf)
+{
+ UINT32 cbVar, offBuf;
+
+ ASMOutU32(EFI_INFO_PORT, Variable);
+ cbVar = ASMInU32(EFI_INFO_PORT);
+
+ for (offBuf = 0; offBuf < cbVar && offBuf < cbBuf; offBuf++)
+ pbBuf[offBuf] = ASMInU8(EFI_INFO_PORT);
+
+ return cbVar;
+}
+
+/*
+ * GUIDs
+ */
+/** The EFI variable GUID for the 'FirmwareFeatures' and friends.
+ * Also known as AppleFirmwareVariableGuid in other sources. */
+EFI_GUID gEfiAppleNvramGuid = {
+ 0x4D1EDE05, 0x38C7, 0x4A6A, {0x9C, 0xC6, 0x4B, 0xCC, 0xA8, 0xB3, 0x8C, 0x14 }
+};
+
+/** The EFI variable GUID for the 'boot-args' variable and others.
+ * Also known as AppleNVRAMVariableGuid in other sources. */
+EFI_GUID gEfiAppleBootGuid = {
+ 0x7C436110, 0xAB2A, 0x4BBB, {0xA8, 0x80, 0xFE, 0x41, 0x99, 0x5C, 0x9F, 0x82}
+};
+
+
+/*
+ * Device Properoty protocol implementation hack.
+ */
+
+/** gEfiAppleVarGuid is aka AppleDevicePropertyProtocolGuid in other sources. */
+EFI_GUID gEfiAppleVarGuid = {
+ 0x91BD12FE, 0xF6C3, 0x44FB, {0xA5, 0xB7, 0x51, 0x22, 0xAB, 0x30, 0x3A, 0xE0}
+};
+
+/** APPLE_GETVAR_PROTOCOL is aka APPLE_DEVICE_PROPERTY_PROTOCOL in other sources. */
+typedef struct _APPLE_GETVAR_PROTOCOL APPLE_GETVAR_PROTOCOL;
+
+struct _APPLE_GETVAR_PROTOCOL
+{
+ /** Magic value or some version thingy. boot.efi doesn't check this, I think. */
+ UINT64 u64Magic;
+
+ EFI_STATUS (EFIAPI *pfnUnknown0)(IN APPLE_GETVAR_PROTOCOL *This, IN VOID *pvArg1, IN VOID *pvArg2,
+ IN VOID *pvArg3, IN VOID *pvArg4);
+ EFI_STATUS (EFIAPI *pfnUnknown1)(IN APPLE_GETVAR_PROTOCOL *This, IN VOID *pvArg1, IN VOID *pvArg2,
+ IN VOID *pvArg3, IN VOID *pvArg4);
+ EFI_STATUS (EFIAPI *pfnUnknown2)(IN APPLE_GETVAR_PROTOCOL *This, IN VOID *pvArg1, IN VOID *pvArg2);
+
+ EFI_STATUS (EFIAPI *pfnGetDevProps)(IN APPLE_GETVAR_PROTOCOL *This, IN CHAR8 *pbBuf, IN OUT UINT32 *pcbBuf);
+};
+/** The value of APPLE_GETVAR_PROTOCOL::u64Magic. */
+#define APPLE_GETVAR_PROTOCOL_MAGIC 0x10000
+
+EFI_STATUS EFIAPI
+AppleGetVar_Unknown0(IN APPLE_GETVAR_PROTOCOL *This, IN VOID *pvArg1, IN VOID *pvArg2,
+ IN VOID *pvArg3, IN VOID *pvArg4)
+{
+ CHAR8 szMsg[128];
+ AsciiSPrint(szMsg, sizeof(szMsg), "AppleGetVar_Unknown0: pvArg1=%p pvArg2=%p pvArg3=%p pvArg4=%p",
+ pvArg1, pvArg2, pvArg3, pvArg4);
+ DebugAssert(__FILE__, __LINE__, szMsg);
+ return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS EFIAPI
+AppleGetVar_Unknown1(IN APPLE_GETVAR_PROTOCOL *This, IN VOID *pvArg1, IN VOID *pvArg2,
+ IN VOID *pvArg3, IN VOID *pvArg4)
+{
+ CHAR8 szMsg[128];
+ AsciiSPrint(szMsg, sizeof(szMsg), "AppleGetVar_Unknown1: pvArg1=%p pvArg2=%p pvArg3=%p pvArg4=%p",
+ pvArg1, pvArg2, pvArg3, pvArg4);
+ DebugAssert(__FILE__, __LINE__, szMsg);
+ return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS EFIAPI
+AppleGetVar_Unknown2(IN APPLE_GETVAR_PROTOCOL *This, IN VOID *pvArg1, IN VOID *pvArg2)
+{
+ CHAR8 szMsg[80];
+ AsciiSPrint(szMsg, sizeof(szMsg), "AppleGetVar_Unknown2: pvArg1=%p pvArg2=%p", pvArg1, pvArg2);
+ DebugAssert(__FILE__, __LINE__, szMsg);
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ * This method obtains the 'device-properties' that get exposed by
+ * AppleEFIFirmware and parsed by AppleACPIPlatform.
+ *
+ * Check out the data in the IORegisteryExplorer, the device-properties property
+ * under IODeviceTree:/efi.
+ *
+ * @retval EFI_SUCCESS, check *pcbBuf or the number of bytes actually returned.
+ * @retval EFI_BUFFER_TOO_SMALL, check *pcbBuf for the necessary buffer size.
+ * @param pThis Not used.
+ * @param pbBuf The output buffer.
+ * @param pcbBuf On input, the varible pointed to contains the size of the
+ * buffer. The size is generally 4KB from what we've observed.
+ * On output, it contains the amount of data available, this
+ * is always set.
+ */
+EFI_STATUS EFIAPI
+AppleGetVar_GetDeviceProps(IN APPLE_GETVAR_PROTOCOL *pThis, OUT CHAR8 *pbBuf, IN OUT UINT32 *pcbBuf)
+{
+ UINT32 cbBuf = *pcbBuf;
+ UINT32 cbActual;
+
+ cbActual = GetVmVariable(EFI_INFO_INDEX_DEVICE_PROPS, pbBuf, cbBuf);
+ *pcbBuf = cbActual;
+
+ if (cbActual > cbBuf)
+ return EFI_BUFFER_TOO_SMALL;
+
+ return EFI_SUCCESS;
+}
+
+APPLE_GETVAR_PROTOCOL gPrivateVarHandler =
+{
+ /* Magic = */ APPLE_GETVAR_PROTOCOL_MAGIC,
+ AppleGetVar_Unknown0,
+ AppleGetVar_Unknown1,
+ AppleGetVar_Unknown2,
+ AppleGetVar_GetDeviceProps
+};
+
+
+/*
+ * Unknown Protocol #1.
+ */
+
+/** This seems to be related to graphics/display... */
+EFI_GUID gEfiUnknown1ProtocolGuid =
+{
+ 0xDD8E06AC, 0x00E2, 0x49A9, {0x88, 0x8F, 0xFA, 0x46, 0xDE, 0xD4, 0x0A, 0x52}
+};
+
+EFI_STATUS EFIAPI
+UnknownHandlerImpl()
+{
+#ifdef DEBUG
+ ASSERT(0);
+#endif
+ Print(L"Unknown called\n");
+ return EFI_SUCCESS;
+}
+
+/* array of pointers to function */
+EFI_STATUS (EFIAPI *gUnknownProtoHandler[])() =
+{
+ UnknownHandlerImpl,
+ UnknownHandlerImpl,
+ UnknownHandlerImpl,
+ UnknownHandlerImpl,
+ UnknownHandlerImpl,
+ UnknownHandlerImpl,
+ UnknownHandlerImpl,
+ UnknownHandlerImpl,
+ UnknownHandlerImpl,
+ UnknownHandlerImpl,
+ UnknownHandlerImpl,
+ UnknownHandlerImpl,
+ UnknownHandlerImpl,
+ UnknownHandlerImpl,
+ UnknownHandlerImpl,
+ UnknownHandlerImpl,
+ UnknownHandlerImpl,
+ UnknownHandlerImpl
+};
+
+EFI_STATUS EFIAPI
+SetProperVariables(IN EFI_HANDLE ImageHandle, EFI_RUNTIME_SERVICES * rs)
+{
+ EFI_STATUS rc;
+ UINT32 vBackgroundClear = 0x00000000;
+ UINT32 vFwFeatures = 0x80000015;
+ UINT32 vFwFeaturesMask = 0x800003ff;
+
+ // -legacy acpi=0xffffffff acpi_debug=0xfffffff panic_io_port=0xef11 io=0xfffffffe trace=4096 io=0xffffffef -v serial=2 serialbaud=9600
+ // 0x10 makes kdb default, thus 0x15e for kdb, 0x14e for gdb
+ // usb=0x800 is required to work around default behavior of the Apple xHCI driver which rejects high-speed
+ // USB devices and tries to force them to EHCI when running on the Intel Panther Point chipset.
+
+ //static const CHAR8 vBootArgs[] = "debug=0x15e keepsyms=1 acpi=0xffffffff acpi_debug=0xff acpi_level=7 -v -x32 -s"; // or just "debug=0x8 -legacy"
+ // 0x14e for serial output
+ //static const CHAR8 vDefBootArgs[] = "debug=0x146 usb=0x800 keepsyms=1 -v -serial=0x1";
+ static const CHAR8 vDefBootArgs[] = "usb=0x800 keepsyms=1 -v -serial=0x1";
+ CHAR8 vBootArgs[256];
+ UINT32 BootArgsLen;
+
+ BootArgsLen = GetVmVariable(EFI_INFO_INDEX_BOOT_ARGS, vBootArgs, sizeof vBootArgs);
+ if (BootArgsLen <= 1)
+ {
+ BootArgsLen = sizeof vDefBootArgs;
+ CopyMem(vBootArgs, vDefBootArgs, BootArgsLen);
+ }
+ rc = rs->SetVariable(L"BackgroundClear",
+ &gEfiAppleNvramGuid,
+ /* EFI_VARIABLE_NON_VOLATILE | */ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof(vBackgroundClear), &vBackgroundClear);
+ ASSERT_EFI_ERROR (rc);
+
+ rc = rs->SetVariable(L"FirmwareFeatures",
+ &gEfiAppleNvramGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof(vFwFeatures), &vFwFeatures);
+ ASSERT_EFI_ERROR (rc);
+
+ rc = rs->SetVariable(L"FirmwareFeaturesMask",
+ &gEfiAppleNvramGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof(vFwFeaturesMask), &vFwFeaturesMask);
+ ASSERT_EFI_ERROR (rc);
+
+ rc = rs->SetVariable(L"boot-args",
+ &gEfiAppleBootGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ BootArgsLen, &vBootArgs);
+ ASSERT_EFI_ERROR (rc);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ * VBoxInitAppleSim entry point.
+ *
+ * @returns EFI status code.
+ *
+ * @param ImageHandle The image handle.
+ * @param SystemTable The system table pointer.
+ */
+EFI_STATUS EFIAPI
+VBoxInitAppleSim(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
+{
+ EFI_STATUS rc;
+ UINT64 FSBFrequency;
+ UINT64 TSCFrequency;
+ UINT64 CPUFrequency;
+
+ rc = SetProperVariables(ImageHandle, SystemTable->RuntimeServices);
+ ASSERT_EFI_ERROR(rc);
+
+ rc = gBS->InstallMultipleProtocolInterfaces(&ImageHandle, &gEfiAppleVarGuid, &gPrivateVarHandler, NULL);
+ ASSERT_EFI_ERROR(rc);
+
+ rc = InitializeDataHub(ImageHandle, SystemTable);
+ ASSERT_EFI_ERROR(rc);
+
+ GetVmVariable(EFI_INFO_INDEX_FSB_FREQUENCY, (CHAR8 *)&FSBFrequency, sizeof(FSBFrequency));
+ GetVmVariable(EFI_INFO_INDEX_TSC_FREQUENCY, (CHAR8 *)&TSCFrequency, sizeof(TSCFrequency));
+ GetVmVariable(EFI_INFO_INDEX_CPU_FREQUENCY, (CHAR8 *)&CPUFrequency, sizeof(CPUFrequency));
+
+ rc = CpuUpdateDataHub(gBS, FSBFrequency, TSCFrequency, CPUFrequency);
+ ASSERT_EFI_ERROR(rc);
+
+ rc = InitializeConsoleSim(ImageHandle, SystemTable);
+ ASSERT_EFI_ERROR(rc);
+
+ rc = gBS->InstallMultipleProtocolInterfaces(&ImageHandle, &gEfiUnknown1ProtocolGuid, gUnknownProtoHandler, NULL);
+ ASSERT_EFI_ERROR(rc);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS EFIAPI
+VBoxDeinitAppleSim(IN EFI_HANDLE ImageHandle)
+{
+ return EFI_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxAppleSim/VBoxAppleSim.inf b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxAppleSim/VBoxAppleSim.inf
new file mode 100644
index 00000000..74725f66
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxAppleSim/VBoxAppleSim.inf
@@ -0,0 +1,78 @@
+# $Id: VBoxAppleSim.inf $
+## @file
+# VBoxAppleSim - VBox Apple interfaces simulation support.
+#
+
+#
+# Copyright (C) 2010-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>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VBoxAppleSim
+ FILE_GUID = 17795471-FD9A-46BE-8806-AE787BA73CD4
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ EDK_RELEASE_VERSION = 0x00020000
+ EFI_SPECIFICATION_VERSION = 0x00020000
+ ENTRY_POINT = VBoxInitAppleSim
+ UNLOAD_IMAGE = VBoxDeinitAppleSim
+
+[Sources.common]
+ VBoxAppleSim.c
+ Cpu.c
+ Console.c
+ DataHub.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ VBoxPkg/VBoxPkg.dec
+
+[LibraryClasses]
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ BaseLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+ PcdLib
+ DevicePathLib
+
+[Protocols]
+ gEfiDevicePathToTextProtocolGuid
+
+[BuildOptions.common]
+
+ GCC:*_*_*_CC_FLAGS =
+ INTEL:*_*_*_CC_FLAGS =
+ MSFT:*_*_*_CC_FLAGS =
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/ReadMe.txt b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/ReadMe.txt
new file mode 100644
index 00000000..871ac64f
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/ReadMe.txt
@@ -0,0 +1,5 @@
+FSW code (all fsw_* files) are based on rEFIt's FSW (filesystem wrapper)
+code, revison 448 taken from
+
+ https://refit.svn.sourceforge.net/svnroot/refit/trunk/refit
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/VBoxFswParam.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/VBoxFswParam.h
new file mode 100644
index 00000000..8dc851ad
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/VBoxFswParam.h
@@ -0,0 +1,89 @@
+/* $Id: VBoxFswParam.h $ */
+/** @file
+ * VBoxFswParam.h
+ */
+
+/*
+ * Copyright (C) 2010-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+#ifndef VBOXFSPARAM_H
+#define VBOXFSPARAM_H
+/*
+ * Here is common declarations for EDK<->EDK2 compatibility
+ */
+# include <Uefi.h>
+# include <Library/DebugLib.h>
+# include <Library/BaseLib.h>
+# include <Protocol/DriverBinding.h>
+# include <Library/BaseMemoryLib.h>
+# include <Library/UefiRuntimeServicesTableLib.h>
+# include <Library/UefiDriverEntryPoint.h>
+# include <Library/UefiBootServicesTableLib.h>
+# include <Library/MemoryAllocationLib.h>
+# include <Library/DevicePathLib.h>
+# include <Protocol/DevicePathFromText.h>
+# include <Protocol/DevicePathToText.h>
+# include <Protocol/DebugPort.h>
+# include <Protocol/DebugSupport.h>
+# include <Library/PrintLib.h>
+# include <Library/UefiLib.h>
+# include <Protocol/SimpleFileSystem.h>
+# include <Protocol/BlockIo.h>
+# include <Protocol/DiskIo.h>
+# include <Guid/FileSystemInfo.h>
+# include <Guid/FileInfo.h>
+# include <Guid/FileSystemVolumeLabelInfo.h>
+# include <Protocol/ComponentName.h>
+
+# include <Guid/VBoxFsBlessedFileInfo.h> /* For HFS blessed file support. */
+
+# define BS gBS
+# define PROTO_NAME(x) gEfi ## x ## Guid
+# define GUID_NAME(x) gEfi ## x ## Guid
+
+# define EFI_FILE_HANDLE_REVISION EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION
+# define SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL
+# define EFI_FILE_SYSTEM_VOLUME_LABEL_INFO EFI_FILE_SYSTEM_VOLUME_LABEL
+# define EFI_SIGNATURE_32(a, b, c, d) SIGNATURE_32(a, b, c, d)
+# define DivU64x32(x,y,z) DivU64x32((x),(y))
+
+
+INTN CompareGuidEdk1(
+ IN EFI_GUID *Guid1,
+ IN EFI_GUID *Guid2
+ );
+
+//#define CompareGuid(x, y) CompareGuidEdk1((x),(y))
+# define HOST_EFI 1
+//# define FSW_DEBUG_LEVEL 3
+
+int fsw_streq_ISO88591_UTF16(void *s1data, void *s2data, int len);
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/VBoxHfs.inf b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/VBoxHfs.inf
new file mode 100644
index 00000000..1ccdf80a
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/VBoxHfs.inf
@@ -0,0 +1,95 @@
+# $Id: VBoxHfs.inf $
+## @file
+# VBoxHfs - VBox HFS FS driver.
+#
+
+#
+# Copyright (C) 2010-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>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VBoxHfs
+ FILE_GUID = 6E506CC2-65E0-4814-994A-08ECDA046987
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ EDK_RELEASE_VERSION = 0x00020000
+ EFI_SPECIFICATION_VERSION = 0x00020000
+
+ ENTRY_POINT = fsw_efi_main
+
+[Sources.common]
+ fsw_hfs.c
+ fsw_core.c
+ fsw_efi_lib.c
+ fsw_efi.c
+ fsw_lib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ VBoxPkg/VBoxPkg.dec
+
+[LibraryClasses]
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ BaseLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+ PcdLib
+ DevicePathLib
+
+[Guids]
+ gEfiFileInfoGuid
+ gEfiFileSystemInfoGuid
+ gEfiFileSystemVolumeLabelInfoIdGuid
+ gVBoxFsBlessedFileInfoGuid
+
+[Protocols]
+ gEfiDiskIoProtocolGuid
+ gEfiBlockIoProtocolGuid
+ gEfiSimpleFileSystemProtocolGuid
+ gEfiUnicodeCollationProtocolGuid
+ gEfiUnicodeCollation2ProtocolGuid
+ gEfiDevicePathToTextProtocolGuid ## CONSUMED
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLang
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLang
+
+[BuildOptions.common]
+ GCC:*_*_*_CC_FLAGS = -DFSTYPE=hfs -DEFI_LOG_ENABLED=1
+# -DFSW_DEBUG_LEVEL=3
+ INTEL:*_*_*_CC_FLAGS = -DFSTYPE=hfs -DEFI_LOG_ENABLED=1
+ MSFT:*_*_*_CC_FLAGS = -DFSTYPE=hfs -DEFI_LOG_ENABLED=1
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/VBoxIso9660.inf b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/VBoxIso9660.inf
new file mode 100644
index 00000000..cb4fa4af
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/VBoxIso9660.inf
@@ -0,0 +1,95 @@
+# $Id: VBoxIso9660.inf $
+## @file
+# VBox ISO9660 FS driver
+#
+
+#
+# Copyright (C) 2010-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>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VBoxIso9600
+ FILE_GUID = B34E57EE-2E02-4DAF-867F-7F40BE6FC33D
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ EDK_RELEASE_VERSION = 0x00020000
+ EFI_SPECIFICATION_VERSION = 0x00020000
+ ENTRY_POINT = fsw_efi_main
+
+[Sources.common]
+ fsw_iso9660.c
+ fsw_core.c
+ fsw_efi_lib.c
+ fsw_efi.c
+ fsw_lib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ VBoxPkg/VBoxPkg.dec
+
+[LibraryClasses]
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ BaseLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+ PcdLib
+ DevicePathLib
+
+[Guids]
+ gEfiFileInfoGuid
+ gEfiFileSystemInfoGuid
+ gEfiFileSystemVolumeLabelInfoIdGuid
+
+
+[Protocols]
+ gEfiDiskIoProtocolGuid
+ gEfiBlockIoProtocolGuid
+ gEfiSimpleFileSystemProtocolGuid
+ gEfiUnicodeCollationProtocolGuid
+ gEfiUnicodeCollation2ProtocolGuid
+ gEfiDevicePathToTextProtocolGuid ## CONSUMED
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLang
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLang
+
+[BuildOptions.common]
+ GCC:*_*_*_CC_FLAGS = -DFSTYPE=iso9660
+
+ INTEL:*_*_*_CC_FLAGS = -DFSTYPE=iso9660
+
+ MSFT:*_*_*_CC_FLAGS = -DFSTYPE=iso9660
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_base.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_base.h
new file mode 100644
index 00000000..b8729805
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_base.h
@@ -0,0 +1,192 @@
+/* $Id: fsw_base.h $ */
+/** @file
+ * fsw_base.h - Base definitions switch.
+ */
+
+/*
+ * Copyright (C) 2010-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ * ---------------------------------------------------------------------------
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_BASE_H_
+#define _FSW_BASE_H_
+
+#ifdef VBOX
+#include "VBoxFswParam.h"
+#endif
+
+#ifndef FSW_DEBUG_LEVEL
+/**
+ * Global debugging level. Can be set locally for the scope of a single
+ * file by defining the macro before fsw_base.h is included.
+ */
+#define FSW_DEBUG_LEVEL 1
+#endif
+
+
+#ifdef HOST_EFI
+#include "fsw_efi_base.h"
+#endif
+
+#ifdef HOST_POSIX
+#include "fsw_posix_base.h"
+#endif
+
+// message printing
+
+#if FSW_DEBUG_LEVEL >= 1
+#define FSW_MSG_ASSERT(params) FSW_MSGFUNC params
+#else
+#define FSW_MSG_ASSERT(params)
+#endif
+
+#if FSW_DEBUG_LEVEL >= 2
+#define FSW_MSG_DEBUG(params) FSW_MSGFUNC params
+#else
+#define FSW_MSG_DEBUG(params)
+#endif
+
+#if FSW_DEBUG_LEVEL >= 3
+#define FSW_MSG_DEBUGV(params) FSW_MSGFUNC params
+#else
+#define FSW_MSG_DEBUGV(params)
+#endif
+
+
+// Documentation for system-dependent defines
+
+/**
+ * \typedef fsw_s8
+ * Signed 8-bit integer.
+ */
+
+/**
+ * \typedef fsw_u8
+ * Unsigned 8-bit integer.
+ */
+
+/**
+ * \typedef fsw_s16
+ * Signed 16-bit integer.
+ */
+
+/**
+ * \typedef fsw_u16
+ * Unsigned 16-bit integer.
+ */
+
+/**
+ * \typedef fsw_s32
+ * Signed 32-bit integer.
+ */
+
+/**
+ * \typedef fsw_u32
+ * Unsigned 32-bit integer.
+ */
+
+/**
+ * \typedef fsw_s64
+ * Signed 64-bit integer.
+ */
+
+/**
+ * \typedef fsw_u64
+ * Unsigned 64-bit integer.
+ */
+
+
+/**
+ * \def fsw_alloc(size,ptrptr)
+ * Allocate memory on the heap. This function or macro allocates \a size
+ * bytes of memory using host-specific methods. The address of the
+ * allocated memory block is stored into the pointer variable pointed
+ * to by \a ptrptr. A status code is returned; FSW_SUCCESS if the block
+ * was allocated or FSW_OUT_OF_MEMORY if there is not enough memory
+ * to allocated the requested block.
+ */
+
+/**
+ * \def fsw_free(ptr)
+ * Release allocated memory. This function or macro returns an allocated
+ * memory block to the heap for reuse. Does not return a status.
+ */
+
+/**
+ * \def fsw_memcpy(dest,src,size)
+ * Copies a block of memory from \a src to \a dest. The two memory blocks
+ * must not overlap, or the result of the operation will be undefined.
+ * Does not return a status.
+ */
+
+/**
+ * \def fsw_memeq(dest,src,size)
+ * Compares two blocks of memory for equality. Returns boolean true if the
+ * memory blocks are equal, boolean false if they are different.
+ */
+
+/**
+ * \def fsw_memzero(dest,size)
+ * Initializes a block of memory with zeros. Does not return a status.
+ */
+
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_core.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_core.c
new file mode 100644
index 00000000..d5cea374
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_core.c
@@ -0,0 +1,961 @@
+/* $Id: fsw_core.c $ */
+/** @file
+ * fsw_core.c - Core file system wrapper abstraction layer code.
+ */
+
+/*
+ * Copyright (C) 2010-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ * ---------------------------------------------------------------------------
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_core.h"
+
+
+// functions
+
+static void fsw_blockcache_free(struct fsw_volume *vol);
+
+#define MAX_CACHE_LEVEL (5)
+
+
+/**
+ * Mount a volume with a given file system driver. This function is called by the
+ * host driver to make a volume accessible. The file system driver to use is specified
+ * by a pointer to its dispatch table. The file system driver will look at the
+ * data on the volume to determine if it can read the format. If the volume is found
+ * unsuitable, FSW_UNSUPPORTED is returned.
+ *
+ * If this function returns FSW_SUCCESS, *vol_out points at a valid volume data
+ * structure. The caller must release it later by calling fsw_unmount.
+ *
+ * If this function returns an error status, the caller only needs to clean up its
+ * own buffers that may have been allocated through the read_block interface.
+ */
+
+fsw_status_t fsw_mount(void *host_data,
+ struct fsw_host_table *host_table,
+ struct fsw_fstype_table *fstype_table,
+ struct fsw_volume **vol_out)
+{
+ fsw_status_t status;
+ struct fsw_volume *vol;
+
+ // allocate memory for the structure
+ status = fsw_alloc_zero(fstype_table->volume_struct_size, (void **)&vol);
+ if (status)
+ return status;
+
+ // initialize fields
+ vol->phys_blocksize = 512;
+ vol->log_blocksize = 512;
+ vol->label.type = FSW_STRING_TYPE_EMPTY;
+ vol->host_data = host_data;
+ vol->host_table = host_table;
+ vol->fstype_table = fstype_table;
+ vol->host_string_type = host_table->native_string_type;
+
+ // let the fs driver mount the file system
+ status = vol->fstype_table->volume_mount(vol);
+ if (status)
+ goto errorexit;
+
+ /// @todo anything else?
+
+ *vol_out = vol;
+ return FSW_SUCCESS;
+
+errorexit:
+ fsw_unmount(vol);
+ return status;
+}
+
+/**
+ * Unmount a volume by releasing all memory associated with it. This function is
+ * called by the host driver when a volume is no longer needed. It is also called
+ * by the core after a failed mount to clean up any allocated memory.
+ *
+ * Note that all dnodes must have been released before calling this function.
+ */
+
+void fsw_unmount(struct fsw_volume *vol)
+{
+ if (vol->root)
+ fsw_dnode_release(vol->root);
+ /// @todo check that no other dnodes are still around
+
+ vol->fstype_table->volume_free(vol);
+
+ fsw_blockcache_free(vol);
+ fsw_strfree(&vol->label);
+ fsw_free(vol);
+}
+
+/**
+ * Get in-depth information on the volume. This function can be called by the host
+ * driver to get additional information on the volume.
+ */
+
+fsw_status_t fsw_volume_stat(struct fsw_volume *vol, struct fsw_volume_stat *sb)
+{
+ return vol->fstype_table->volume_stat(vol, sb);
+}
+
+/**
+ * Set the physical and logical block sizes of the volume. This functions is called by
+ * the file system driver to announce the block sizes it wants to use for accessing
+ * the disk (physical) and for addressing file contents (logical).
+ * Usually both sizes will be the same but there may be file systems that need to access
+ * metadata at a smaller block size than the allocation unit for files.
+ *
+ * Calling this function causes the block cache to be dropped. All pointers returned
+ * from fsw_block_get become invalid. This function should only be called while
+ * mounting the file system, not as a part of file access operations.
+ *
+ * Both sizes are measured in bytes, must be powers of 2, and must not be smaller
+ * than 512 bytes. The logical block size cannot be smaller than the physical block size.
+ */
+
+void fsw_set_blocksize(struct fsw_volume *vol, fsw_u32 phys_blocksize, fsw_u32 log_blocksize)
+{
+ /// @todo Check the sizes. Both must be powers of 2. log_blocksize must not be smaller than
+ // phys_blocksize.
+
+ // drop core block cache if present
+ fsw_blockcache_free(vol);
+
+ // signal host driver to drop caches etc.
+ vol->host_table->change_blocksize(vol,
+ vol->phys_blocksize, vol->log_blocksize,
+ phys_blocksize, log_blocksize);
+
+ vol->phys_blocksize = phys_blocksize;
+ vol->log_blocksize = log_blocksize;
+}
+
+/**
+ * Get a block of data from the disk. This function is called by the file system driver
+ * or by core functions. It calls through to the host driver's device access routine.
+ * Given a physical block number, it reads the block into memory (or fetches it from the
+ * block cache) and returns the address of the memory buffer. The caller should provide
+ * an indication of how important the block is in the cache_level parameter. Blocks with
+ * a low level are purged first. Some suggestions for cache levels:
+ *
+ * - 0: File data
+ * - 1: Directory data, symlink data
+ * - 2: File system metadata
+ * - 3..5: File system metadata with a high rate of access
+ *
+ * If this function returns successfully, the returned data pointer is valid until the
+ * caller calls fsw_block_release.
+ */
+
+fsw_status_t fsw_block_get(struct VOLSTRUCTNAME *vol, fsw_u32 phys_bno, fsw_u32 cache_level, void **buffer_out)
+{
+ fsw_status_t status;
+ fsw_u32 i, discard_level, new_bcache_size;
+ struct fsw_blockcache *new_bcache;
+
+ /// @todo allow the host driver to do its own caching; just call through if
+ // the appropriate function pointers are set
+
+ if (cache_level > MAX_CACHE_LEVEL)
+ cache_level = MAX_CACHE_LEVEL;
+
+ // check block cache
+ for (i = 0; i < vol->bcache_size; i++) {
+ if (vol->bcache[i].phys_bno == phys_bno) {
+ // cache hit!
+ if (vol->bcache[i].cache_level < cache_level)
+ vol->bcache[i].cache_level = cache_level; // promote the entry
+ vol->bcache[i].refcount++;
+ *buffer_out = vol->bcache[i].data;
+ return FSW_SUCCESS;
+ }
+ }
+
+ // find a free entry in the cache table
+ for (i = 0; i < vol->bcache_size; i++) {
+ if (vol->bcache[i].phys_bno == FSW_INVALID_BNO)
+ break;
+ }
+ if (i >= vol->bcache_size) {
+ for (discard_level = 0; discard_level <= MAX_CACHE_LEVEL; discard_level++) {
+ for (i = 0; i < vol->bcache_size; i++) {
+ if (vol->bcache[i].refcount == 0 && vol->bcache[i].cache_level <= discard_level)
+ break;
+ }
+ if (i < vol->bcache_size)
+ break;
+ }
+ }
+ if (i >= vol->bcache_size) {
+ // enlarge / create the cache
+ if (vol->bcache_size < 16)
+ new_bcache_size = 16;
+ else
+ new_bcache_size = vol->bcache_size << 1;
+ status = fsw_alloc(new_bcache_size * sizeof(struct fsw_blockcache), &new_bcache);
+ if (status)
+ return status;
+ if (vol->bcache_size > 0)
+ fsw_memcpy(new_bcache, vol->bcache, vol->bcache_size * sizeof(struct fsw_blockcache));
+ for (i = vol->bcache_size; i < new_bcache_size; i++) {
+ new_bcache[i].refcount = 0;
+ new_bcache[i].cache_level = 0;
+ new_bcache[i].phys_bno = FSW_INVALID_BNO;
+ new_bcache[i].data = NULL;
+ }
+ i = vol->bcache_size;
+
+ // switch caches
+ if (vol->bcache != NULL)
+ fsw_free(vol->bcache);
+ vol->bcache = new_bcache;
+ vol->bcache_size = new_bcache_size;
+ }
+ vol->bcache[i].phys_bno = FSW_INVALID_BNO;
+
+ // read the data
+ if (vol->bcache[i].data == NULL) {
+ status = fsw_alloc(vol->phys_blocksize, &vol->bcache[i].data);
+ if (status)
+ return status;
+ }
+ status = vol->host_table->read_block(vol, phys_bno, vol->bcache[i].data);
+ if (status)
+ return status;
+
+ vol->bcache[i].phys_bno = phys_bno;
+ vol->bcache[i].cache_level = cache_level;
+ vol->bcache[i].refcount = 1;
+ *buffer_out = vol->bcache[i].data;
+ return FSW_SUCCESS;
+}
+
+/**
+ * Releases a disk block. This function must be called to release disk blocks returned
+ * from fsw_block_get.
+ */
+
+void fsw_block_release(struct VOLSTRUCTNAME *vol, fsw_u32 phys_bno, void *buffer)
+{
+ fsw_u32 i;
+
+ /// @todo allow the host driver to do its own caching; just call through if
+ // the appropriate function pointers are set
+
+ // update block cache
+ for (i = 0; i < vol->bcache_size; i++) {
+ if (vol->bcache[i].phys_bno == phys_bno && vol->bcache[i].refcount > 0)
+ vol->bcache[i].refcount--;
+ }
+}
+
+/**
+ * Release the block cache. Called internally when changing block sizes and when
+ * unmounting the volume. It frees all data occupied by the generic block cache.
+ */
+
+static void fsw_blockcache_free(struct fsw_volume *vol)
+{
+ fsw_u32 i;
+
+ for (i = 0; i < vol->bcache_size; i++) {
+ if (vol->bcache[i].data != NULL)
+ fsw_free(vol->bcache[i].data);
+ }
+ if (vol->bcache != NULL) {
+ fsw_free(vol->bcache);
+ vol->bcache = NULL;
+ }
+ vol->bcache_size = 0;
+}
+
+/**
+ * Add a new dnode to the list of known dnodes. This internal function is used when a
+ * dnode is created to add it to the dnode list that is used to search for existing
+ * dnodes by id.
+ */
+
+static void fsw_dnode_register(struct fsw_volume *vol, struct fsw_dnode *dno)
+{
+ dno->next = vol->dnode_head;
+ if (vol->dnode_head != NULL)
+ vol->dnode_head->prev = dno;
+ dno->prev = NULL;
+ vol->dnode_head = dno;
+}
+
+/**
+ * Create a dnode representing the root directory. This function is called by the file system
+ * driver while mounting the file system. The root directory is special because it has no parent
+ * dnode, its name is defined to be empty, and its type is also fixed. Otherwise, this functions
+ * behaves in the same way as fsw_dnode_create.
+ */
+
+fsw_status_t fsw_dnode_create_root(struct fsw_volume *vol, fsw_u32 dnode_id, struct fsw_dnode **dno_out)
+{
+ fsw_status_t status;
+ struct fsw_dnode *dno;
+
+ // allocate memory for the structure
+ status = fsw_alloc_zero(vol->fstype_table->dnode_struct_size, (void **)&dno);
+ if (status)
+ return status;
+
+ // fill the structure
+ dno->vol = vol;
+ dno->parent = NULL;
+ dno->dnode_id = dnode_id;
+ dno->type = FSW_DNODE_TYPE_DIR;
+ dno->refcount = 1;
+ dno->name.type = FSW_STRING_TYPE_EMPTY;
+ /// @todo instead, call a function to create an empty string in the native string type
+
+ fsw_dnode_register(vol, dno);
+
+ *dno_out = dno;
+ return FSW_SUCCESS;
+}
+
+/**
+ * Create a new dnode representing a file system object. This function is called by
+ * the file system driver in response to directory lookup or read requests. Note that
+ * if there already is a dnode with the given dnode_id on record, then no new object
+ * is created. Instead, the existing dnode is returned and its reference count
+ * increased. All other parameters are ignored in this case.
+ *
+ * The type passed into this function may be FSW_DNODE_TYPE_UNKNOWN. It is sufficient
+ * to fill the type field during the dnode_fill call.
+ *
+ * The name parameter must describe a string with the object's name. A copy will be
+ * stored in the dnode structure for future reference. The name will not be used to
+ * shortcut directory lookups, but may be used to reconstruct paths.
+ *
+ * If the function returns successfully, *dno_out contains a pointer to the dnode
+ * that must be released by the caller with fsw_dnode_release.
+ */
+
+fsw_status_t fsw_dnode_create(struct fsw_dnode *parent_dno, fsw_u32 dnode_id, int type,
+ struct fsw_string *name, struct fsw_dnode **dno_out)
+{
+ fsw_status_t status;
+ struct fsw_volume *vol = parent_dno->vol;
+ struct fsw_dnode *dno;
+
+ // check if we already have a dnode with the same id
+ for (dno = vol->dnode_head; dno; dno = dno->next) {
+ if (dno->dnode_id == dnode_id) {
+ fsw_dnode_retain(dno);
+ *dno_out = dno;
+ return FSW_SUCCESS;
+ }
+ }
+
+ // allocate memory for the structure
+ status = fsw_alloc_zero(vol->fstype_table->dnode_struct_size, (void **)&dno);
+ if (status)
+ return status;
+
+ // fill the structure
+ dno->vol = vol;
+ dno->parent = parent_dno;
+ fsw_dnode_retain(dno->parent);
+ dno->dnode_id = dnode_id;
+ dno->type = type;
+ dno->refcount = 1;
+ status = fsw_strdup_coerce(&dno->name, vol->host_table->native_string_type, name);
+ if (status) {
+ fsw_free(dno);
+ return status;
+ }
+
+ fsw_dnode_register(vol, dno);
+
+ *dno_out = dno;
+ return FSW_SUCCESS;
+}
+
+/**
+ * Increases the reference count of a dnode. This must be balanced with
+ * fsw_dnode_release calls. Note that some dnode functions return a retained
+ * dnode pointer to their caller.
+ */
+
+void fsw_dnode_retain(struct fsw_dnode *dno)
+{
+ dno->refcount++;
+}
+
+/**
+ * Release a dnode pointer, deallocating it if this was the last reference.
+ * This function decrements the reference counter of the dnode. If the counter
+ * reaches zero, the dnode is freed. Since the parent dnode is released
+ * during that process, this function may cause it to be freed, too.
+ */
+
+void fsw_dnode_release(struct fsw_dnode *dno)
+{
+ struct fsw_volume *vol = dno->vol;
+ struct fsw_dnode *parent_dno;
+
+ dno->refcount--;
+
+ if (dno->refcount == 0) {
+ parent_dno = dno->parent;
+
+ // de-register from volume's list
+ if (dno->next)
+ dno->next->prev = dno->prev;
+ if (dno->prev)
+ dno->prev->next = dno->next;
+ if (vol->dnode_head == dno)
+ vol->dnode_head = dno->next;
+
+ // run fstype-specific cleanup
+ vol->fstype_table->dnode_free(vol, dno);
+
+ fsw_strfree(&dno->name);
+ fsw_free(dno);
+
+ // release our pointer to the parent, possibly deallocating it, too
+ if (parent_dno)
+ fsw_dnode_release(parent_dno);
+ }
+}
+
+/**
+ * Get full information about a dnode from disk. This function is called by the host
+ * driver as well as by the core functions. Some file systems defer reading full
+ * information on a dnode until it is actually needed (i.e. separation between
+ * directory and inode information). This function makes sure that all information
+ * is available in the dnode structure. The following fields may not have a correct
+ * value until fsw_dnode_fill has been called:
+ *
+ * type, size
+ */
+
+fsw_status_t fsw_dnode_fill(struct fsw_dnode *dno)
+{
+ /// @todo check a flag right here, call fstype's dnode_fill only once per dnode
+
+ return dno->vol->fstype_table->dnode_fill(dno->vol, dno);
+}
+
+/**
+ * Get extended information about a dnode. This function can be called by the host
+ * driver to get a full compliment of information about a dnode in addition to the
+ * fields of the fsw_dnode structure itself.
+ *
+ * Some data requires host-specific conversion to be useful (i.e. timestamps) and
+ * will be passed to callback functions instead of being written into the structure.
+ * These callbacks must be filled in by the caller.
+ */
+
+fsw_status_t fsw_dnode_stat(struct fsw_dnode *dno, struct fsw_dnode_stat *sb)
+{
+ fsw_status_t status;
+
+ status = fsw_dnode_fill(dno);
+ if (status)
+ return status;
+
+ sb->used_bytes = 0;
+ status = dno->vol->fstype_table->dnode_stat(dno->vol, dno, sb);
+ if (!status && !sb->used_bytes)
+ sb->used_bytes = FSW_U64_DIV(dno->size + dno->vol->log_blocksize - 1, dno->vol->log_blocksize);
+ return status;
+}
+
+/**
+ * Lookup a directory entry by name. This function is called by the host driver.
+ * Given a directory dnode and a file name, it looks up the named entry in the
+ * directory.
+ *
+ * If the dnode is not a directory, the call will fail. The caller is responsible for
+ * resolving symbolic links before calling this function.
+ *
+ * If the function returns FSW_SUCCESS, *child_dno_out points to the requested directory
+ * entry. The caller must call fsw_dnode_release on it.
+ */
+
+fsw_status_t fsw_dnode_lookup(struct fsw_dnode *dno,
+ struct fsw_string *lookup_name, struct fsw_dnode **child_dno_out)
+{
+ fsw_status_t status;
+
+ status = fsw_dnode_fill(dno);
+ if (status)
+ return status;
+ if (dno->type != FSW_DNODE_TYPE_DIR)
+ return FSW_UNSUPPORTED;
+
+ return dno->vol->fstype_table->dir_lookup(dno->vol, dno, lookup_name, child_dno_out);
+}
+
+/**
+ * Find a file system object by path. This function is called by the host driver.
+ * Given a directory dnode and a relative or absolute path, it walks the directory
+ * tree until it finds the target dnode. If an intermediate node turns out to be
+ * a symlink, it is resolved automatically. If the target node is a symlink, it
+ * is not resolved.
+ *
+ * If the function returns FSW_SUCCESS, *child_dno_out points to the requested directory
+ * entry. The caller must call fsw_dnode_release on it.
+ */
+
+fsw_status_t fsw_dnode_lookup_path(struct fsw_dnode *dno,
+ struct fsw_string *lookup_path, char separator,
+ struct fsw_dnode **child_dno_out)
+{
+ fsw_status_t status;
+ struct fsw_volume *vol = dno->vol;
+ struct fsw_dnode *child_dno = NULL;
+ struct fsw_string lookup_name;
+ struct fsw_string remaining_path;
+ int root_if_empty;
+
+ remaining_path = *lookup_path;
+ fsw_dnode_retain(dno);
+
+ // loop over the path
+ for (root_if_empty = 1; fsw_strlen(&remaining_path) > 0; root_if_empty = 0) {
+ // parse next path component
+ fsw_strsplit(&lookup_name, &remaining_path, separator);
+
+ FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: split into %d '%s' and %d '%s'\n"),
+ lookup_name.len, lookup_name.data,
+ remaining_path.len, remaining_path.data));
+
+ if (fsw_strlen(&lookup_name) == 0) { // empty path component
+ if (root_if_empty)
+ child_dno = vol->root;
+ else
+ child_dno = dno;
+ fsw_dnode_retain(child_dno);
+
+ } else {
+ // do an actual directory lookup
+
+ // ensure we have full information
+ status = fsw_dnode_fill(dno);
+ if (status)
+ goto errorexit;
+
+ // resolve symlink if necessary
+ if (dno->type == FSW_DNODE_TYPE_SYMLINK) {
+ status = fsw_dnode_resolve(dno, &child_dno);
+ if (status)
+ goto errorexit;
+
+ // symlink target becomes the new dno
+ fsw_dnode_release(dno);
+ dno = child_dno; // is already retained
+ child_dno = NULL;
+
+ // ensure we have full information
+ status = fsw_dnode_fill(dno);
+ if (status)
+ goto errorexit;
+ }
+
+ // make sure we operate on a directory
+ if (dno->type != FSW_DNODE_TYPE_DIR) {
+ return FSW_UNSUPPORTED;
+ goto errorexit;
+ }
+
+ // check special paths
+ if (fsw_streq_cstr(&lookup_name, ".")) { // self directory
+ child_dno = dno;
+ fsw_dnode_retain(child_dno);
+
+ } else if (fsw_streq_cstr(&lookup_name, "..")) { // parent directory
+ if (dno->parent == NULL) {
+ // We cannot go up from the root directory. Caution: Certain apps like the EFI shell
+ // rely on this behaviour!
+ status = FSW_NOT_FOUND;
+ goto errorexit;
+ }
+ child_dno = dno->parent;
+ fsw_dnode_retain(child_dno);
+
+ } else {
+ // do an actual lookup
+ status = vol->fstype_table->dir_lookup(vol, dno, &lookup_name, &child_dno);
+ if (status)
+ goto errorexit;
+ }
+ }
+
+ // child_dno becomes the new dno
+ fsw_dnode_release(dno);
+ dno = child_dno; // is already retained
+ child_dno = NULL;
+
+ FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: now at inode %d\n"), dno->dnode_id));
+ }
+
+ *child_dno_out = dno;
+ return FSW_SUCCESS;
+
+errorexit:
+ FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: leaving with error %d\n"), status));
+ fsw_dnode_release(dno);
+ if (child_dno != NULL)
+ fsw_dnode_release(child_dno);
+ return status;
+}
+
+/**
+ * Get the next directory item in sequential order. This function is called by the
+ * host driver to read the complete contents of a directory in sequential (file system
+ * defined) order. Calling this function returns the next entry. Iteration state is
+ * kept by a shandle on the directory's dnode. The caller must set up the shandle
+ * when starting the iteration.
+ *
+ * When the end of the directory is reached, this function returns FSW_NOT_FOUND.
+ * If the function returns FSW_SUCCESS, *child_dno_out points to the next directory
+ * entry. The caller must call fsw_dnode_release on it.
+ */
+
+fsw_status_t fsw_dnode_dir_read(struct fsw_shandle *shand, struct fsw_dnode **child_dno_out)
+{
+ fsw_status_t status;
+ struct fsw_dnode *dno = shand->dnode;
+ fsw_u64 saved_pos;
+
+ if (dno->type != FSW_DNODE_TYPE_DIR)
+ return FSW_UNSUPPORTED;
+
+ saved_pos = shand->pos;
+ status = dno->vol->fstype_table->dir_read(dno->vol, dno, shand, child_dno_out);
+ if (status)
+ shand->pos = saved_pos;
+ return status;
+}
+
+/**
+ * Read the target path of a symbolic link. This function is called by the host driver
+ * to read the "content" of a symbolic link, that is the relative or absolute path
+ * it points to.
+ *
+ * If the function returns FSW_SUCCESS, the string handle provided by the caller is
+ * filled with a string in the host's preferred encoding. The caller is responsible
+ * for calling fsw_strfree on the string.
+ */
+
+fsw_status_t fsw_dnode_readlink(struct fsw_dnode *dno, struct fsw_string *target_name)
+{
+ fsw_status_t status;
+
+ status = fsw_dnode_fill(dno);
+ if (status)
+ return status;
+ if (dno->type != FSW_DNODE_TYPE_SYMLINK)
+ return FSW_UNSUPPORTED;
+
+ return dno->vol->fstype_table->readlink(dno->vol, dno, target_name);
+}
+
+/**
+ * Read the target path of a symbolic link by accessing file data. This function can
+ * be called by the file system driver if the file system stores the target path
+ * as normal file data. This function will open an shandle, read the whole content
+ * of the file into a buffer, and build a string from that. Currently the encoding
+ * for the string is fixed as FSW_STRING_TYPE_ISO88591.
+ *
+ * If the function returns FSW_SUCCESS, the string handle provided by the caller is
+ * filled with a string in the host's preferred encoding. The caller is responsible
+ * for calling fsw_strfree on the string.
+ */
+
+fsw_status_t fsw_dnode_readlink_data(struct fsw_dnode *dno, struct fsw_string *link_target)
+{
+ fsw_status_t status;
+ struct fsw_shandle shand;
+ fsw_u32 buffer_size;
+ char buffer[FSW_PATH_MAX];
+
+ struct fsw_string s;
+
+ if (dno->size > FSW_PATH_MAX)
+ return FSW_VOLUME_CORRUPTED;
+
+ s.type = FSW_STRING_TYPE_ISO88591;
+ s.size = s.len = (int)dno->size;
+ s.data = buffer;
+
+ // open shandle and read the data
+ status = fsw_shandle_open(dno, &shand);
+ if (status)
+ return status;
+ buffer_size = (fsw_u32)s.size;
+ status = fsw_shandle_read(&shand, &buffer_size, buffer);
+ fsw_shandle_close(&shand);
+ if (status)
+ return status;
+ if ((int)buffer_size < s.size)
+ return FSW_VOLUME_CORRUPTED;
+
+ status = fsw_strdup_coerce(link_target, dno->vol->host_string_type, &s);
+ return status;
+}
+
+/**
+ * Resolve a symbolic link. This function can be called by the host driver to make
+ * sure the a dnode is fully resolved instead of pointing at a symlink. If the dnode
+ * passed in is not a symlink, it is returned unmodified.
+ *
+ * Note that absolute paths will be resolved relative to the root directory of the
+ * volume. If the host is an operating system with its own VFS layer, it should
+ * resolve symlinks on its own.
+ *
+ * If the function returns FSW_SUCCESS, *target_dno_out points at a dnode that is
+ * not a symlink. The caller is responsible for calling fsw_dnode_release on it.
+ */
+
+fsw_status_t fsw_dnode_resolve(struct fsw_dnode *dno, struct fsw_dnode **target_dno_out)
+{
+ fsw_status_t status;
+ struct fsw_string target_name;
+ struct fsw_dnode *target_dno;
+
+ fsw_dnode_retain(dno);
+
+ while (1) {
+ // get full information
+ status = fsw_dnode_fill(dno);
+ if (status)
+ goto errorexit;
+ if (dno->type != FSW_DNODE_TYPE_SYMLINK) {
+ // found a non-symlink target, return it
+ *target_dno_out = dno;
+ return FSW_SUCCESS;
+ }
+ if (dno->parent == NULL) { // safety measure, cannot happen in theory
+ status = FSW_NOT_FOUND;
+ goto errorexit;
+ }
+
+ // read the link's target
+ status = fsw_dnode_readlink(dno, &target_name);
+ if (status)
+ goto errorexit;
+
+ // resolve it
+ status = fsw_dnode_lookup_path(dno->parent, &target_name, '/', &target_dno);
+ fsw_strfree(&target_name);
+ if (status)
+ goto errorexit;
+
+ // target_dno becomes the new dno
+ fsw_dnode_release(dno);
+ dno = target_dno; // is already retained
+ }
+
+errorexit:
+ fsw_dnode_release(dno);
+ return status;
+}
+
+/**
+ * Set up a shandle (storage handle) to access a file's data. This function is called
+ * by the host driver and by the core when they need to access a file's data. It is also
+ * used in accessing the raw data of directories and symlinks if the file system uses
+ * the same mechanisms for storing the data of those items.
+ *
+ * The storage for the fsw_shandle structure is provided by the caller. The dnode and pos
+ * fields may be accessed, pos may also be written to to set the file pointer. The file's
+ * data size is available as shand->dnode->size.
+ *
+ * If this function returns FSW_SUCCESS, the caller must call fsw_shandle_close to release
+ * the dnode reference held by the shandle.
+ */
+
+fsw_status_t fsw_shandle_open(struct fsw_dnode *dno, struct fsw_shandle *shand)
+{
+ fsw_status_t status;
+ struct fsw_volume *vol = dno->vol;
+
+ // read full dnode information into memory
+ status = vol->fstype_table->dnode_fill(vol, dno);
+ if (status)
+ return status;
+
+ // setup shandle
+ fsw_dnode_retain(dno);
+
+ shand->dnode = dno;
+ shand->pos = 0;
+ shand->extent.type = FSW_EXTENT_TYPE_INVALID;
+
+ return FSW_SUCCESS;
+}
+
+/**
+ * Close a shandle after accessing the dnode's data. This function is called by the host
+ * driver or core functions when they are finished with accessing a file's data. It
+ * releases the dnode reference and frees any buffers associated with the shandle itself.
+ * The dnode is only released if this was the last reference using it.
+ */
+
+void fsw_shandle_close(struct fsw_shandle *shand)
+{
+ if (shand->extent.type == FSW_EXTENT_TYPE_BUFFER)
+ fsw_free(shand->extent.buffer);
+ fsw_dnode_release(shand->dnode);
+}
+
+/**
+ * Read data from a shandle (storage handle for a dnode). This function is called by the
+ * host driver or internally when data is read from a file. TODO: more
+ */
+
+fsw_status_t fsw_shandle_read(struct fsw_shandle *shand, fsw_u32 *buffer_size_inout, void *buffer_in)
+{
+ fsw_status_t status;
+ struct fsw_dnode *dno = shand->dnode;
+ struct fsw_volume *vol = dno->vol;
+ fsw_u8 *buffer, *block_buffer;
+ fsw_u32 buflen, copylen, pos;
+ fsw_u32 log_bno, pos_in_extent, phys_bno, pos_in_physblock;
+ fsw_u32 cache_level;
+
+ if (shand->pos >= dno->size) { // already at EOF
+ *buffer_size_inout = 0;
+ return FSW_SUCCESS;
+ }
+
+ // initialize vars
+ buffer = buffer_in;
+ buflen = *buffer_size_inout;
+ pos = (fsw_u32)shand->pos;
+ cache_level = (dno->type != FSW_DNODE_TYPE_FILE) ? 1 : 0;
+ // restrict read to file size
+ if (buflen > dno->size - pos)
+ buflen = (fsw_u32)(dno->size - pos);
+
+ while (buflen > 0) {
+ // get extent for the current logical block
+ log_bno = pos / vol->log_blocksize;
+ if (shand->extent.type == FSW_EXTENT_TYPE_INVALID ||
+ log_bno < shand->extent.log_start ||
+ log_bno >= shand->extent.log_start + shand->extent.log_count) {
+
+ if (shand->extent.type == FSW_EXTENT_TYPE_BUFFER)
+ fsw_free(shand->extent.buffer);
+
+ // ask the file system for the proper extent
+ shand->extent.log_start = log_bno;
+ status = vol->fstype_table->get_extent(vol, dno, &shand->extent);
+ if (status) {
+ shand->extent.type = FSW_EXTENT_TYPE_INVALID;
+ return status;
+ }
+ }
+
+ pos_in_extent = pos - shand->extent.log_start * vol->log_blocksize;
+
+ // dispatch by extent type
+ if (shand->extent.type == FSW_EXTENT_TYPE_PHYSBLOCK) {
+ // convert to physical block number and offset
+ phys_bno = shand->extent.phys_start + pos_in_extent / vol->phys_blocksize;
+ pos_in_physblock = pos_in_extent & (vol->phys_blocksize - 1);
+ copylen = vol->phys_blocksize - pos_in_physblock;
+ if (copylen > buflen)
+ copylen = buflen;
+
+ // get one physical block
+ status = fsw_block_get(vol, phys_bno, cache_level, (void **)&block_buffer);
+ if (status)
+ return status;
+
+ // copy data from it
+ fsw_memcpy(buffer, block_buffer + pos_in_physblock, copylen);
+ fsw_block_release(vol, phys_bno, block_buffer);
+
+ } else if (shand->extent.type == FSW_EXTENT_TYPE_BUFFER) {
+ copylen = shand->extent.log_count * vol->log_blocksize - pos_in_extent;
+ if (copylen > buflen)
+ copylen = buflen;
+ fsw_memcpy(buffer, (fsw_u8 *)shand->extent.buffer + pos_in_extent, copylen);
+
+ } else { // _SPARSE or _INVALID
+ copylen = shand->extent.log_count * vol->log_blocksize - pos_in_extent;
+ if (copylen > buflen)
+ copylen = buflen;
+ fsw_memzero(buffer, copylen);
+
+ }
+
+ buffer += copylen;
+ buflen -= copylen;
+ pos += copylen;
+ }
+
+ *buffer_size_inout = (fsw_u32)(pos - shand->pos);
+ shand->pos = pos;
+
+ return FSW_SUCCESS;
+}
+
+// EOF
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_core.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_core.h
new file mode 100644
index 00000000..d09ce074
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_core.h
@@ -0,0 +1,554 @@
+/* $Id: fsw_core.h $ */
+/** @file
+ * fsw_core.h - Core file system wrapper abstraction layer header.
+ */
+
+/*
+ * Copyright (C) 2010-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ * ---------------------------------------------------------------------------
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ * Portions Copyright (c) The Regents of the University of California.
+ * Portions Copyright (c) UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_CORE_H_
+#define _FSW_CORE_H_
+
+#include "fsw_base.h"
+
+
+/** Maximum size for a path, specifically symlink target paths. */
+#ifndef VBOX
+#define FSW_PATH_MAX (4096)
+#else
+/* Too big allocations are handled with alloca() */
+#define FSW_PATH_MAX (2048)
+#endif
+
+/** Helper macro for token concatenation. */
+#define FSW_CONCAT3(a,b,c) a##b##c
+/** Expands to the name of a fstype dispatch table (fsw_fstype_table) for a named file system type. */
+#define FSW_FSTYPE_TABLE_NAME(t) FSW_CONCAT3(fsw_,t,_table)
+
+/** Indicates that the block cache entry is empty. */
+#define FSW_INVALID_BNO (~0U)
+
+
+//
+// Byte-swapping macros
+//
+
+
+/**
+ * \name Byte Order Macros
+ * Implements big endian vs. little endian awareness and conversion.
+ */
+/*@{*/
+
+typedef fsw_u16 fsw_u16_le;
+typedef fsw_u16 fsw_u16_be;
+typedef fsw_u32 fsw_u32_le;
+typedef fsw_u32 fsw_u32_be;
+typedef fsw_u64 fsw_u64_le;
+typedef fsw_u64 fsw_u64_be;
+
+#define FSW_SWAPVALUE_U16(v) ((((fsw_u16)(v) & 0xff00) >> 8) | \
+ (((fsw_u16)(v) & 0x00ff) << 8))
+#define FSW_SWAPVALUE_U32(v) ((((fsw_u32)(v) & 0xff000000UL) >> 24) | \
+ (((fsw_u32)(v) & 0x00ff0000UL) >> 8) | \
+ (((fsw_u32)(v) & 0x0000ff00UL) << 8) | \
+ (((fsw_u32)(v) & 0x000000ffUL) << 24))
+#define FSW_SWAPVALUE_U64(v) ((((fsw_u64)(v) & 0xff00000000000000ULL) >> 56) | \
+ (((fsw_u64)(v) & 0x00ff000000000000ULL) >> 40) | \
+ (((fsw_u64)(v) & 0x0000ff0000000000ULL) >> 24) | \
+ (((fsw_u64)(v) & 0x000000ff00000000ULL) >> 8) | \
+ (((fsw_u64)(v) & 0x00000000ff000000ULL) << 8) | \
+ (((fsw_u64)(v) & 0x0000000000ff0000ULL) << 24) | \
+ (((fsw_u64)(v) & 0x000000000000ff00ULL) << 40) | \
+ (((fsw_u64)(v) & 0x00000000000000ffULL) << 56))
+
+#ifdef FSW_LITTLE_ENDIAN
+
+#define fsw_u16_le_swap(v) (v)
+#define fsw_u16_be_swap(v) FSW_SWAPVALUE_U16(v)
+#define fsw_u32_le_swap(v) (v)
+#define fsw_u32_be_swap(v) FSW_SWAPVALUE_U32(v)
+#define fsw_u64_le_swap(v) (v)
+#define fsw_u64_be_swap(v) FSW_SWAPVALUE_U64(v)
+
+#define fsw_u16_le_sip(var)
+#define fsw_u16_be_sip(var) (var = FSW_SWAPVALUE_U16(var))
+#define fsw_u32_le_sip(var)
+#define fsw_u32_be_sip(var) (var = FSW_SWAPVALUE_U32(var))
+#define fsw_u64_le_sip(var)
+#define fsw_u64_be_sip(var) (var = FSW_SWAPVALUE_U64(var))
+
+#else
+#ifdef FSW_BIG_ENDIAN
+
+#define fsw_u16_le_swap(v) FSW_SWAPVALUE_U16(v)
+#define fsw_u16_be_swap(v) (v)
+#define fsw_u32_le_swap(v) FSW_SWAPVALUE_U32(v)
+#define fsw_u32_be_swap(v) (v)
+#define fsw_u64_le_swap(v) FSW_SWAPVALUE_U64(v)
+#define fsw_u64_be_swap(v) (v)
+
+#define fsw_u16_le_sip(var) (var = FSW_SWAPVALUE_U16(var))
+#define fsw_u16_be_sip(var)
+#define fsw_u32_le_sip(var) (var = FSW_SWAPVALUE_U32(var))
+#define fsw_u32_be_sip(var)
+#define fsw_u64_le_sip(var) (var = FSW_SWAPVALUE_U64(var))
+#define fsw_u64_be_sip(var)
+
+#else
+#fail Neither FSW_BIG_ENDIAN nor FSW_LITTLE_ENDIAN are defined
+#endif
+#endif
+
+/*@}*/
+
+
+//
+// The following evil hack avoids a lot of casts between generic and fstype-specific
+// structures.
+//
+
+#ifndef VOLSTRUCTNAME
+#define VOLSTRUCTNAME fsw_volume
+#else
+struct VOLSTRUCTNAME;
+#endif
+#ifndef DNODESTRUCTNAME
+#define DNODESTRUCTNAME fsw_dnode
+#else
+struct DNODESTRUCTNAME;
+#endif
+
+
+/**
+ * Status code type, returned from all functions that can fail.
+ */
+typedef int fsw_status_t;
+
+/**
+ * Possible status codes.
+ */
+enum {
+ FSW_SUCCESS,
+ FSW_OUT_OF_MEMORY,
+ FSW_IO_ERROR,
+ FSW_UNSUPPORTED,
+ FSW_NOT_FOUND,
+ FSW_VOLUME_CORRUPTED,
+ FSW_UNKNOWN_ERROR
+};
+
+
+/**
+ * Core: A string with explicit length and encoding information.
+ */
+
+struct fsw_string {
+ int type; //!< Encoding of the string - empty, ISO-8859-1, UTF8, UTF16
+ int len; //!< Length in characters
+ int size; //!< Total data size in bytes
+ void *data; //!< Data pointer (may be NULL if type is EMPTY or len is zero)
+};
+
+/**
+ * Possible string types / encodings. In the case of FSW_STRING_TYPE_EMPTY,
+ * all other members of the fsw_string structure may be invalid.
+ */
+enum {
+ FSW_STRING_TYPE_EMPTY,
+ FSW_STRING_TYPE_ISO88591,
+ FSW_STRING_TYPE_UTF8,
+ FSW_STRING_TYPE_UTF16,
+ FSW_STRING_TYPE_UTF16_SWAPPED
+};
+
+#ifdef FSW_LITTLE_ENDIAN
+#define FSW_STRING_TYPE_UTF16_LE FSW_STRING_TYPE_UTF16
+#define FSW_STRING_TYPE_UTF16_BE FSW_STRING_TYPE_UTF16_SWAPPED
+#else
+#define FSW_STRING_TYPE_UTF16_LE FSW_STRING_TYPE_UTF16_SWAPPED
+#define FSW_STRING_TYPE_UTF16_BE FSW_STRING_TYPE_UTF16
+#endif
+
+/** Static initializer for an empty string. */
+#define FSW_STRING_INIT { FSW_STRING_TYPE_EMPTY, 0, 0, NULL }
+
+
+/* forward declarations */
+
+struct fsw_dnode;
+struct fsw_host_table;
+struct fsw_fstype_table;
+
+struct fsw_blockcache {
+ fsw_u32 refcount; //!< Reference count
+ fsw_u32 cache_level; //!< Level of importance of this block
+ fsw_u32 phys_bno; //!< Physical block number
+ void *data; //!< Block data buffer
+};
+
+/**
+ * Core: Represents a mounted volume.
+ */
+
+struct fsw_volume {
+ fsw_u32 phys_blocksize; //!< Block size for disk access / file system structures
+ fsw_u32 log_blocksize; //!< Block size for logical file data
+
+ struct DNODESTRUCTNAME *root; //!< Root directory dnode
+ struct fsw_string label; //!< Volume label
+
+ struct fsw_dnode *dnode_head; //!< List of all dnodes allocated for this volume
+
+ struct fsw_blockcache *bcache; //!< Array of block cache entries
+ fsw_u32 bcache_size; //!< Number of entries in the block cache array
+
+ void *host_data; //!< Hook for a host-specific data structure
+ struct fsw_host_table *host_table; //!< Dispatch table for host-specific functions
+ struct fsw_fstype_table *fstype_table; //!< Dispatch table for file system specific functions
+ int host_string_type; //!< String type used by the host environment
+};
+
+/**
+ * Core: Represents a "directory node" - a file, directory, symlink, whatever.
+ */
+
+struct fsw_dnode {
+ fsw_u32 refcount; //!< Reference count
+
+ struct VOLSTRUCTNAME *vol; //!< The volume this dnode belongs to
+ struct DNODESTRUCTNAME *parent; //!< Parent directory dnode
+ struct fsw_string name; //!< Name of this item in the parent directory
+
+ fsw_u32 dnode_id; //!< Unique id number (usually the inode number)
+ int type; //!< Type of the dnode - file, dir, symlink, special
+ fsw_u64 size; //!< Data size in bytes
+
+ struct fsw_dnode *next; //!< Doubly-linked list of all dnodes: previous dnode
+ struct fsw_dnode *prev; //!< Doubly-linked list of all dnodes: next dnode
+};
+
+/**
+ * Possible dnode types. FSW_DNODE_TYPE_UNKNOWN may only be used before
+ * fsw_dnode_fill has been called on the dnode.
+ */
+enum {
+ FSW_DNODE_TYPE_UNKNOWN,
+ FSW_DNODE_TYPE_FILE,
+ FSW_DNODE_TYPE_DIR,
+ FSW_DNODE_TYPE_SYMLINK,
+ FSW_DNODE_TYPE_SPECIAL
+};
+
+/**
+ * Core: Stores the mapping of a region of a file to the data on disk.
+ */
+
+struct fsw_extent {
+ int type; //!< Type of extent specification
+ fsw_u32 log_start; //!< Starting logical block number
+ fsw_u32 log_count; //!< Logical block count
+ fsw_u32 phys_start; //!< Starting physical block number (for FSW_EXTENT_TYPE_PHYSBLOCK only)
+ void *buffer; //!< Allocated buffer pointer (for FSW_EXTENT_TYPE_BUFFER only)
+};
+
+/**
+ * Possible extent representation types. FSW_EXTENT_TYPE_INVALID is for shandle's
+ * internal use only, it must not be returned from a get_extent function.
+ */
+enum {
+ FSW_EXTENT_TYPE_INVALID,
+ FSW_EXTENT_TYPE_SPARSE,
+ FSW_EXTENT_TYPE_PHYSBLOCK,
+ FSW_EXTENT_TYPE_BUFFER
+};
+
+/**
+ * Core: An access structure to a dnode's raw data. There can be multiple
+ * shandles per dnode, each of them has its own position pointer.
+ */
+
+struct fsw_shandle {
+ struct fsw_dnode *dnode; //!< The dnode this handle reads data from
+
+ fsw_u64 pos; //!< Current file pointer in bytes
+ struct fsw_extent extent; //!< Current extent
+};
+
+/**
+ * Core: Used in gathering detailed information on a volume.
+ */
+
+struct fsw_volume_stat {
+ fsw_u64 total_bytes; //!< Total size of data area size in bytes
+ fsw_u64 free_bytes; //!< Bytes still available for storing file data
+};
+
+/**
+ * Core: Used in gathering detailed information on a dnode.
+ */
+
+struct fsw_dnode_stat {
+ fsw_u64 used_bytes; //!< Bytes actually used by the file on disk
+ void (*store_time_posix)(struct fsw_dnode_stat *sb, int which, fsw_u32 posix_time); //!< Callback for storing a Posix-style timestamp
+ void (*store_attr_posix)(struct fsw_dnode_stat *sb, fsw_u16 posix_mode); //!< Callback for storing a Posix-style file mode
+ void *host_data; //!< Hook for a host-specific data structure
+};
+
+/**
+ * Type of the timestamp passed into store_time_posix.
+ */
+enum {
+ FSW_DNODE_STAT_CTIME,
+ FSW_DNODE_STAT_MTIME,
+ FSW_DNODE_STAT_ATIME
+};
+
+/**
+ * Core: Function table for a host environment.
+ */
+
+struct fsw_host_table
+{
+ int native_string_type; //!< String type used by the host environment
+
+ void (*change_blocksize)(struct fsw_volume *vol,
+ fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
+ fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize);
+ fsw_status_t (*read_block)(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer);
+};
+
+/**
+ * Core: Function table for a file system driver.
+ */
+
+struct fsw_fstype_table
+{
+ struct fsw_string name; //!< String giving the name of the file system
+ fsw_u32 volume_struct_size; //!< Size for allocating the fsw_volume structure
+ fsw_u32 dnode_struct_size; //!< Size for allocating the fsw_dnode structure
+
+ fsw_status_t (*volume_mount)(struct VOLSTRUCTNAME *vol);
+ void (*volume_free)(struct VOLSTRUCTNAME *vol);
+ fsw_status_t (*volume_stat)(struct VOLSTRUCTNAME *vol, struct fsw_volume_stat *sb);
+
+ fsw_status_t (*dnode_fill)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno);
+ void (*dnode_free)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno);
+ fsw_status_t (*dnode_stat)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
+ struct fsw_dnode_stat *sb);
+ fsw_status_t (*get_extent)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
+ struct fsw_extent *extent);
+
+ fsw_status_t (*dir_lookup)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
+ struct fsw_string *lookup_name, struct DNODESTRUCTNAME **child_dno);
+ fsw_status_t (*dir_read)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
+ struct fsw_shandle *shand, struct DNODESTRUCTNAME **child_dno);
+ fsw_status_t (*readlink)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
+ struct fsw_string *link_target);
+};
+
+
+/**
+ * \name Volume Functions
+ */
+/*@{*/
+
+fsw_status_t fsw_mount(void *host_data,
+ struct fsw_host_table *host_table,
+ struct fsw_fstype_table *fstype_table,
+ struct fsw_volume **vol_out);
+void fsw_unmount(struct fsw_volume *vol);
+fsw_status_t fsw_volume_stat(struct fsw_volume *vol, struct fsw_volume_stat *sb);
+
+void fsw_set_blocksize(struct VOLSTRUCTNAME *vol, fsw_u32 phys_blocksize, fsw_u32 log_blocksize);
+fsw_status_t fsw_block_get(struct VOLSTRUCTNAME *vol, fsw_u32 phys_bno, fsw_u32 cache_level, void **buffer_out);
+void fsw_block_release(struct VOLSTRUCTNAME *vol, fsw_u32 phys_bno, void *buffer);
+
+/*@}*/
+
+
+/**
+ * \name dnode Functions
+ */
+/*@{*/
+
+fsw_status_t fsw_dnode_create_root(struct VOLSTRUCTNAME *vol, fsw_u32 dnode_id, struct DNODESTRUCTNAME **dno_out);
+fsw_status_t fsw_dnode_create(struct DNODESTRUCTNAME *parent_dno, fsw_u32 dnode_id, int type,
+ struct fsw_string *name, struct DNODESTRUCTNAME **dno_out);
+void fsw_dnode_retain(struct fsw_dnode *dno);
+void fsw_dnode_release(struct fsw_dnode *dno);
+
+fsw_status_t fsw_dnode_fill(struct fsw_dnode *dno);
+fsw_status_t fsw_dnode_stat(struct fsw_dnode *dno, struct fsw_dnode_stat *sb);
+
+fsw_status_t fsw_dnode_lookup(struct fsw_dnode *dno,
+ struct fsw_string *lookup_name, struct fsw_dnode **child_dno_out);
+fsw_status_t fsw_dnode_lookup_path(struct fsw_dnode *dno,
+ struct fsw_string *lookup_path, char separator,
+ struct fsw_dnode **child_dno_out);
+fsw_status_t fsw_dnode_dir_read(struct fsw_shandle *shand, struct fsw_dnode **child_dno_out);
+fsw_status_t fsw_dnode_readlink(struct fsw_dnode *dno, struct fsw_string *link_target);
+fsw_status_t fsw_dnode_readlink_data(struct DNODESTRUCTNAME *dno, struct fsw_string *link_target);
+fsw_status_t fsw_dnode_resolve(struct fsw_dnode *dno, struct fsw_dnode **target_dno_out);
+
+/*@}*/
+
+
+/**
+ * \name shandle Functions
+ */
+/*@{*/
+
+fsw_status_t fsw_shandle_open(struct DNODESTRUCTNAME *dno, struct fsw_shandle *shand);
+void fsw_shandle_close(struct fsw_shandle *shand);
+fsw_status_t fsw_shandle_read(struct fsw_shandle *shand, fsw_u32 *buffer_size_inout, void *buffer);
+
+/*@}*/
+
+
+/**
+ * \name Memory Functions
+ */
+/*@{*/
+
+fsw_status_t fsw_alloc_zero(int len, void **ptr_out);
+fsw_status_t fsw_memdup(void **dest_out, void *src, int len);
+
+/*@}*/
+
+
+/**
+ * \name String Functions
+ */
+/*@{*/
+
+int fsw_strlen(struct fsw_string *s);
+int fsw_streq(struct fsw_string *s1, struct fsw_string *s2);
+int fsw_streq_cstr(struct fsw_string *s1, const char *s2);
+fsw_status_t fsw_strdup_coerce(struct fsw_string *dest, int type, struct fsw_string *src);
+void fsw_strsplit(struct fsw_string *lookup_name, struct fsw_string *buffer, char separator);
+
+void fsw_strfree(struct fsw_string *s);
+fsw_u16 fsw_to_lower(fsw_u16 ch);
+
+/*@}*/
+
+
+/**
+ * \name Posix Mode Macros
+ * These macros can be used globally to test fields and bits in
+ * Posix-style modes.
+ *
+ * Taken from FreeBSD sys/stat.h.
+ */
+/*@{*/
+#ifndef S_IRWXU
+
+#define S_ISUID 0004000 /* set user id on execution */
+#define S_ISGID 0002000 /* set group id on execution */
+#define S_ISTXT 0001000 /* sticky bit */
+
+#define S_IRWXU 0000700 /* RWX mask for owner */
+#define S_IRUSR 0000400 /* R for owner */
+#define S_IWUSR 0000200 /* W for owner */
+#define S_IXUSR 0000100 /* X for owner */
+
+#define S_IRWXG 0000070 /* RWX mask for group */
+#define S_IRGRP 0000040 /* R for group */
+#define S_IWGRP 0000020 /* W for group */
+#define S_IXGRP 0000010 /* X for group */
+
+#define S_IRWXO 0000007 /* RWX mask for other */
+#define S_IROTH 0000004 /* R for other */
+#define S_IWOTH 0000002 /* W for other */
+#define S_IXOTH 0000001 /* X for other */
+
+#define S_IFMT 0170000 /* type of file mask */
+#define S_IFIFO 0010000 /* named pipe (fifo) */
+#define S_IFCHR 0020000 /* character special */
+#define S_IFDIR 0040000 /* directory */
+#define S_IFBLK 0060000 /* block special */
+#define S_IFREG 0100000 /* regular */
+#define S_IFLNK 0120000 /* symbolic link */
+#define S_IFSOCK 0140000 /* socket */
+#define S_ISVTX 0001000 /* save swapped text even after use */
+#define S_IFWHT 0160000 /* whiteout */
+
+#define S_ISDIR(m) (((m) & 0170000) == 0040000) /* directory */
+#define S_ISCHR(m) (((m) & 0170000) == 0020000) /* char special */
+#define S_ISBLK(m) (((m) & 0170000) == 0060000) /* block special */
+#define S_ISREG(m) (((m) & 0170000) == 0100000) /* regular file */
+#define S_ISFIFO(m) (((m) & 0170000) == 0010000) /* fifo or socket */
+#define S_ISLNK(m) (((m) & 0170000) == 0120000) /* symbolic link */
+#define S_ISSOCK(m) (((m) & 0170000) == 0140000) /* socket */
+#define S_ISWHT(m) (((m) & 0170000) == 0160000) /* whiteout */
+
+#define S_BLKSIZE 512 /* block size used in the stat struct */
+
+#endif
+/*@}*/
+
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_efi.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_efi.c
new file mode 100644
index 00000000..9a1168c1
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_efi.c
@@ -0,0 +1,1142 @@
+/* $Id: fsw_efi.c $ */
+/** @file
+ * fsw_efi.c - EFI host environment code.
+ */
+
+/*
+ * Copyright (C) 2010-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ * ---------------------------------------------------------------------------
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_efi.h"
+
+#define DEBUG_LEVEL 0
+
+#ifndef FSTYPE
+#ifdef VBOX
+#error FSTYPE must be defined!
+#else
+#define FSTYPE ext2
+#endif
+#endif
+
+/** Helper macro for stringification. */
+#define FSW_EFI_STRINGIFY(x) L#x
+/** Expands to the EFI driver name given the file system type name. */
+#define FSW_EFI_DRIVER_NAME(t) L"Fsw " FSW_EFI_STRINGIFY(t) L" File System Driver"
+
+
+// function prototypes
+
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Supported(IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath);
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath);
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Stop(IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer);
+
+EFI_STATUS EFIAPI fsw_efi_ComponentName_GetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName);
+EFI_STATUS EFIAPI fsw_efi_ComponentName_GetControllerName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName);
+
+void fsw_efi_change_blocksize(struct fsw_volume *vol,
+ fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
+ fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize);
+fsw_status_t fsw_efi_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer);
+
+EFI_STATUS fsw_efi_map_status(fsw_status_t fsw_status, FSW_VOLUME_DATA *Volume);
+
+EFI_STATUS EFIAPI fsw_efi_FileSystem_OpenVolume(IN EFI_FILE_IO_INTERFACE *This,
+ OUT EFI_FILE **Root);
+EFI_STATUS fsw_efi_dnode_to_FileHandle(IN struct fsw_dnode *dno,
+ OUT EFI_FILE **NewFileHandle);
+
+EFI_STATUS fsw_efi_file_read(IN FSW_FILE_DATA *File,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer);
+EFI_STATUS fsw_efi_file_getpos(IN FSW_FILE_DATA *File,
+ OUT UINT64 *Position);
+EFI_STATUS fsw_efi_file_setpos(IN FSW_FILE_DATA *File,
+ IN UINT64 Position);
+
+EFI_STATUS fsw_efi_dir_open(IN FSW_FILE_DATA *File,
+ OUT EFI_FILE **NewHandle,
+ IN CHAR16 *FileName,
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes);
+EFI_STATUS fsw_efi_dir_read(IN FSW_FILE_DATA *File,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer);
+EFI_STATUS fsw_efi_dir_setpos(IN FSW_FILE_DATA *File,
+ IN UINT64 Position);
+
+EFI_STATUS fsw_efi_dnode_getinfo(IN FSW_FILE_DATA *File,
+ IN EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer);
+EFI_STATUS fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume,
+ IN struct fsw_dnode *dno,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer);
+
+#if defined(VBOX) && (FSTYPE == hfs)
+extern fsw_status_t fsw_hfs_get_blessed_file(void *vol, struct fsw_string *path);
+#endif
+
+/**
+ * Interface structure for the EFI Driver Binding protocol.
+ */
+
+EFI_DRIVER_BINDING_PROTOCOL fsw_efi_DriverBinding_table = {
+ fsw_efi_DriverBinding_Supported,
+ fsw_efi_DriverBinding_Start,
+ fsw_efi_DriverBinding_Stop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+/**
+ * Interface structure for the EFI Component Name protocol.
+ */
+
+EFI_COMPONENT_NAME_PROTOCOL fsw_efi_ComponentName_table = {
+ fsw_efi_ComponentName_GetDriverName,
+ fsw_efi_ComponentName_GetControllerName,
+ "eng"
+};
+
+/**
+ * Dispatch table for our FSW host driver.
+ */
+
+struct fsw_host_table fsw_efi_host_table = {
+ FSW_STRING_TYPE_UTF16,
+
+ fsw_efi_change_blocksize,
+ fsw_efi_read_block
+};
+
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(FSTYPE);
+
+
+
+/**
+ * Image entry point. Installs the Driver Binding and Component Name protocols
+ * on the image's handle. Actually mounting a file system is initiated through
+ * the Driver Binding protocol at the firmware's request.
+ */
+EFI_STATUS EFIAPI fsw_efi_main(IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable)
+{
+ EFI_STATUS Status;
+
+#ifndef VBOX
+ InitializeLib(ImageHandle, SystemTable);
+#endif
+
+ // complete Driver Binding protocol instance
+ fsw_efi_DriverBinding_table.ImageHandle = ImageHandle;
+ fsw_efi_DriverBinding_table.DriverBindingHandle = ImageHandle;
+ // install Driver Binding protocol
+ Status = BS->InstallProtocolInterface(&fsw_efi_DriverBinding_table.DriverBindingHandle,
+ &PROTO_NAME(DriverBindingProtocol),
+ EFI_NATIVE_INTERFACE,
+ &fsw_efi_DriverBinding_table);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // install Component Name protocol
+ Status = BS->InstallProtocolInterface(&fsw_efi_DriverBinding_table.DriverBindingHandle,
+ &PROTO_NAME(ComponentNameProtocol),
+ EFI_NATIVE_INTERFACE,
+ &fsw_efi_ComponentName_table);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ * Driver Binding EFI protocol, Supported function. This function is called by EFI
+ * to test if this driver can handle a certain device. Our implementation only checks
+ * if the device is a disk (i.e. that it supports the Block I/O and Disk I/O protocols)
+ * and implicitly checks if the disk is already in use by another driver.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Supported(IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath)
+{
+ EFI_STATUS Status;
+ EFI_DISK_IO *DiskIo;
+
+ // we check for both DiskIO and BlockIO protocols
+
+ // first, open DiskIO
+ Status = BS->OpenProtocol(ControllerHandle,
+ &PROTO_NAME(DiskIoProtocol),
+ (VOID **) &DiskIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (EFI_ERROR(Status))
+ {
+ return Status;
+ }
+
+ // we were just checking, close it again
+ BS->CloseProtocol(ControllerHandle,
+ &PROTO_NAME(DiskIoProtocol),
+ This->DriverBindingHandle,
+ ControllerHandle);
+
+ // next, check BlockIO without actually opening it
+ Status = BS->OpenProtocol(ControllerHandle,
+ &PROTO_NAME(BlockIoProtocol),
+ NULL,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL);
+ return Status;
+}
+
+static EFI_STATUS fsw_efi_ReMount(IN FSW_VOLUME_DATA *pVolume,
+ IN EFI_HANDLE ControllerHandle,
+ EFI_DISK_IO *pDiskIo,
+ EFI_BLOCK_IO *pBlockIo)
+{
+ EFI_STATUS Status;
+ pVolume->Signature = FSW_VOLUME_DATA_SIGNATURE;
+ pVolume->Handle = ControllerHandle;
+ pVolume->DiskIo = pDiskIo;
+ pVolume->MediaId = pBlockIo->Media->MediaId;
+ pVolume->LastIOStatus = EFI_SUCCESS;
+
+ // mount the filesystem
+ Status = fsw_efi_map_status(fsw_mount(pVolume, &fsw_efi_host_table,
+ &FSW_FSTYPE_TABLE_NAME(FSTYPE), &pVolume->vol),
+ pVolume);
+
+ if (!EFI_ERROR(Status)) {
+ // register the SimpleFileSystem protocol
+ pVolume->FileSystem.Revision = EFI_FILE_IO_INTERFACE_REVISION;
+ pVolume->FileSystem.OpenVolume = fsw_efi_FileSystem_OpenVolume;
+ Status = BS->InstallMultipleProtocolInterfaces(&ControllerHandle,
+ &PROTO_NAME(SimpleFileSystemProtocol), &pVolume->FileSystem,
+ NULL);
+#if DEBUG_LEVEL /* This error is always printed and destroys the boot logo. */
+ if (EFI_ERROR(Status))
+ Print(L"Fsw ERROR: InstallMultipleProtocolInterfaces returned %x\n", Status);
+#endif
+ }
+ return Status;
+}
+
+/**
+ * Driver Binding EFI protocol, Start function. This function is called by EFI
+ * to start driving the given device. It is still possible at this point to
+ * return EFI_UNSUPPORTED, and in fact we will do so if the file system driver
+ * cannot find the superblock signature (or equivalent) that it expects.
+ *
+ * This function allocates memory for a per-volume structure, opens the
+ * required protocols (just Disk I/O in our case, Block I/O is only looked
+ * at to get the MediaId field), and lets the FSW core mount the file system.
+ * If successful, an EFI Simple File System protocol is exported on the
+ * device handle.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath)
+{
+ EFI_STATUS Status;
+ EFI_BLOCK_IO *BlockIo;
+ EFI_DISK_IO *DiskIo;
+ FSW_VOLUME_DATA *Volume;
+
+ // open consumed protocols
+ Status = BS->OpenProtocol(ControllerHandle,
+ &PROTO_NAME(BlockIoProtocol),
+ (VOID **) &BlockIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL); // NOTE: we only want to look at the MediaId
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ Status = BS->OpenProtocol(ControllerHandle,
+ &PROTO_NAME(DiskIoProtocol),
+ (VOID **) &DiskIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ // allocate volume structure
+ Volume = AllocateZeroPool(sizeof(FSW_VOLUME_DATA));
+ Status = fsw_efi_ReMount(Volume, ControllerHandle, DiskIo, BlockIo);
+
+ // on errors, close the opened protocols
+ if (EFI_ERROR(Status)) {
+ if (Volume->vol != NULL)
+ fsw_unmount(Volume->vol);
+ FreePool(Volume);
+
+#if 0
+ if (Status == EFI_MEDIA_CHANGED)
+ Status = fsw_efi_ReMount(Volume, ControllerHandle, DiskIo, BlockIo);
+ else
+#endif
+ BS->CloseProtocol(ControllerHandle,
+ &PROTO_NAME(DiskIoProtocol),
+ This->DriverBindingHandle,
+ ControllerHandle);
+ }
+
+ return Status;
+}
+
+/**
+ * Driver Binding EFI protocol, Stop function. This function is called by EFI
+ * to stop the driver on the given device. This translates to an unmount
+ * call for the FSW core.
+ *
+ * We assume that all file handles on the volume have been closed before
+ * the driver is stopped. At least with the EFI shell, that is actually the
+ * case; it closes all file handles between commands.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Stop(IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer)
+{
+ EFI_STATUS Status;
+ EFI_FILE_IO_INTERFACE *FileSystem;
+ FSW_VOLUME_DATA *Volume;
+
+#if DEBUG_LEVEL
+ Print(L"fsw_efi_DriverBinding_Stop\n");
+#endif
+
+ // get the installed SimpleFileSystem interface
+ Status = BS->OpenProtocol(ControllerHandle,
+ &PROTO_NAME(SimpleFileSystemProtocol),
+ (VOID **) &FileSystem,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (EFI_ERROR(Status))
+ return EFI_UNSUPPORTED;
+
+ // get private data structure
+ Volume = FSW_VOLUME_FROM_FILE_SYSTEM(FileSystem);
+
+ // uninstall Simple File System protocol
+ Status = BS->UninstallMultipleProtocolInterfaces(ControllerHandle,
+ &PROTO_NAME(SimpleFileSystemProtocol), &Volume->FileSystem,
+ NULL);
+ if (EFI_ERROR(Status)) {
+ Print(L"Fsw ERROR: UninstallMultipleProtocolInterfaces returned %x\n", Status);
+ return Status;
+ }
+#if DEBUG_LEVEL
+ Print(L"fsw_efi_DriverBinding_Stop: protocol uninstalled successfully\n");
+#endif
+
+ // release private data structure
+ if (Volume->vol != NULL)
+ fsw_unmount(Volume->vol);
+ FreePool(Volume);
+
+ // close the consumed protocols
+ Status = BS->CloseProtocol(ControllerHandle,
+ &PROTO_NAME(DiskIoProtocol),
+ This->DriverBindingHandle,
+ ControllerHandle);
+
+ return Status;
+}
+
+/**
+ * Component Name EFI protocol, GetDriverName function. Used by the EFI
+ * environment to inquire the name of this driver. The name returned is
+ * based on the file system type actually used in compilation.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_ComponentName_GetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName)
+{
+ if (Language == NULL || DriverName == NULL)
+ return EFI_INVALID_PARAMETER;
+#if 0
+
+ if (Language[0] == 'e' && Language[1] == 'n' && Language[2] == 'g' && Language[3] == 0) {
+ *DriverName = FSW_EFI_DRIVER_NAME(FSTYPE);
+ return EFI_SUCCESS;
+ }
+#endif
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ * Component Name EFI protocol, GetControllerName function. Not implemented
+ * because this is not a "bus" driver in the sense of the EFI Driver Model.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_ComponentName_GetControllerName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName)
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ * FSW interface function for block size changes. This function is called by the FSW core
+ * when the file system driver changes the block sizes for the volume.
+ */
+
+void fsw_efi_change_blocksize(struct fsw_volume *vol,
+ fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
+ fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize)
+{
+ // nothing to do
+}
+
+/**
+ * FSW interface function to read data blocks. This function is called by the FSW core
+ * to read a block of data from the device. The buffer is allocated by the core code.
+ */
+
+fsw_status_t fsw_efi_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer)
+{
+ EFI_STATUS Status;
+ FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)vol->host_data;
+
+ FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_efi_read_block: %d (%d)\n"), phys_bno, vol->phys_blocksize));
+
+ // read from disk
+ Status = Volume->DiskIo->ReadDisk(Volume->DiskIo, Volume->MediaId,
+ (UINT64)phys_bno * vol->phys_blocksize,
+ vol->phys_blocksize,
+ buffer);
+ Volume->LastIOStatus = Status;
+ if (EFI_ERROR(Status))
+ return FSW_IO_ERROR;
+ return FSW_SUCCESS;
+}
+
+/**
+ * Map FSW status codes to EFI status codes. The FSW_IO_ERROR code is only produced
+ * by fsw_efi_read_block, so we map it back to the EFI status code remembered from
+ * the last I/O operation.
+ */
+
+EFI_STATUS fsw_efi_map_status(fsw_status_t fsw_status, FSW_VOLUME_DATA *Volume)
+{
+ switch (fsw_status) {
+ case FSW_SUCCESS:
+ return EFI_SUCCESS;
+ case FSW_OUT_OF_MEMORY:
+ return EFI_VOLUME_CORRUPTED;
+ case FSW_IO_ERROR:
+ return Volume->LastIOStatus;
+ case FSW_UNSUPPORTED:
+ return EFI_UNSUPPORTED;
+ case FSW_NOT_FOUND:
+ return EFI_NOT_FOUND;
+ case FSW_VOLUME_CORRUPTED:
+ return EFI_VOLUME_CORRUPTED;
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+}
+
+/**
+ * File System EFI protocol, OpenVolume function. Creates a file handle for
+ * the root directory and returns it. Note that this function may be called
+ * multiple times and returns a new file handle each time. Each returned
+ * handle is closed by the client using it.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileSystem_OpenVolume(IN EFI_FILE_IO_INTERFACE *This,
+ OUT EFI_FILE **Root)
+{
+ EFI_STATUS Status;
+ FSW_VOLUME_DATA *Volume = FSW_VOLUME_FROM_FILE_SYSTEM(This);
+
+#if DEBUG_LEVEL
+ Print(L"fsw_efi_FileSystem_OpenVolume\n");
+#endif
+
+ Status = fsw_efi_dnode_to_FileHandle(Volume->vol->root, Root);
+
+ return Status;
+}
+
+/**
+ * File Handle EFI protocol, Open function. Dispatches the call
+ * based on the kind of file handle.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Open(IN EFI_FILE *This,
+ OUT EFI_FILE **NewHandle,
+ IN CHAR16 *FileName,
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes)
+{
+ FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+ if (File->Type == FSW_EFI_FILE_TYPE_DIR)
+ return fsw_efi_dir_open(File, NewHandle, FileName, OpenMode, Attributes);
+ // not supported for regular files
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ * File Handle EFI protocol, Close function. Closes the FSW shandle
+ * and frees the memory used for the structure.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Close(IN EFI_FILE *This)
+{
+ FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+#if DEBUG_LEVEL
+ Print(L"fsw_efi_FileHandle_Close\n");
+#endif
+
+ fsw_shandle_close(&File->shand);
+ FreePool(File);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ * File Handle EFI protocol, Delete function. Calls through to Close
+ * and returns a warning because this driver is read-only.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Delete(IN EFI_FILE *This)
+{
+ EFI_STATUS Status;
+
+ Status = This->Close(This);
+ if (Status == EFI_SUCCESS) {
+ // this driver is read-only
+ Status = EFI_WARN_DELETE_FAILURE;
+ }
+
+ return Status;
+}
+
+/**
+ * File Handle EFI protocol, Read function. Dispatches the call
+ * based on the kind of file handle.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Read(IN EFI_FILE *This,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer)
+{
+ FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+ if (File->Type == FSW_EFI_FILE_TYPE_FILE)
+ return fsw_efi_file_read(File, BufferSize, Buffer);
+ else if (File->Type == FSW_EFI_FILE_TYPE_DIR)
+ return fsw_efi_dir_read(File, BufferSize, Buffer);
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ * File Handle EFI protocol, Write function. Returns unsupported status
+ * because this driver is read-only.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Write(IN EFI_FILE *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer)
+{
+ // this driver is read-only
+ return EFI_WRITE_PROTECTED;
+}
+
+/**
+ * File Handle EFI protocol, GetPosition function. Dispatches the call
+ * based on the kind of file handle.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_GetPosition(IN EFI_FILE *This,
+ OUT UINT64 *Position)
+{
+ FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+ if (File->Type == FSW_EFI_FILE_TYPE_FILE)
+ return fsw_efi_file_getpos(File, Position);
+ // not defined for directories
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ * File Handle EFI protocol, SetPosition function. Dispatches the call
+ * based on the kind of file handle.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_SetPosition(IN EFI_FILE *This,
+ IN UINT64 Position)
+{
+ FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+ if (File->Type == FSW_EFI_FILE_TYPE_FILE)
+ return fsw_efi_file_setpos(File, Position);
+ else if (File->Type == FSW_EFI_FILE_TYPE_DIR)
+ return fsw_efi_dir_setpos(File, Position);
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ * File Handle EFI protocol, GetInfo function. Dispatches to the common
+ * function implementing this.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_GetInfo(IN EFI_FILE *This,
+ IN EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer)
+{
+ FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+ return fsw_efi_dnode_getinfo(File, InformationType, BufferSize, Buffer);
+}
+
+/**
+ * File Handle EFI protocol, SetInfo function. Returns unsupported status
+ * because this driver is read-only.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_SetInfo(IN EFI_FILE *This,
+ IN EFI_GUID *InformationType,
+ IN UINTN BufferSize,
+ IN VOID *Buffer)
+{
+ // this driver is read-only
+ return EFI_WRITE_PROTECTED;
+}
+
+/**
+ * File Handle EFI protocol, Flush function. Returns unsupported status
+ * because this driver is read-only.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Flush(IN EFI_FILE *This)
+{
+ // this driver is read-only
+ return EFI_WRITE_PROTECTED;
+}
+
+/**
+ * Set up a file handle for a dnode. This function allocates a data structure
+ * for a file handle, opens a FSW shandle and populates the EFI_FILE structure
+ * with the interface functions.
+ */
+
+EFI_STATUS fsw_efi_dnode_to_FileHandle(IN struct fsw_dnode *dno,
+ OUT EFI_FILE **NewFileHandle)
+{
+ EFI_STATUS Status;
+ FSW_FILE_DATA *File;
+
+ // make sure the dnode has complete info
+ Status = fsw_efi_map_status(fsw_dnode_fill(dno), (FSW_VOLUME_DATA *)dno->vol->host_data);
+ if (EFI_ERROR(Status))
+ return Status;
+
+ // check type
+ if (dno->type != FSW_DNODE_TYPE_FILE && dno->type != FSW_DNODE_TYPE_DIR)
+ return EFI_UNSUPPORTED;
+
+ // allocate file structure
+ File = AllocateZeroPool(sizeof(FSW_FILE_DATA));
+ File->Signature = FSW_FILE_DATA_SIGNATURE;
+ if (dno->type == FSW_DNODE_TYPE_FILE)
+ File->Type = FSW_EFI_FILE_TYPE_FILE;
+ else if (dno->type == FSW_DNODE_TYPE_DIR)
+ File->Type = FSW_EFI_FILE_TYPE_DIR;
+
+ // open shandle
+ Status = fsw_efi_map_status(fsw_shandle_open(dno, &File->shand),
+ (FSW_VOLUME_DATA *)dno->vol->host_data);
+ if (EFI_ERROR(Status)) {
+ FreePool(File);
+ return Status;
+ }
+
+ // populate the file handle
+ File->FileHandle.Revision = EFI_FILE_HANDLE_REVISION;
+ File->FileHandle.Open = fsw_efi_FileHandle_Open;
+ File->FileHandle.Close = fsw_efi_FileHandle_Close;
+ File->FileHandle.Delete = fsw_efi_FileHandle_Delete;
+ File->FileHandle.Read = fsw_efi_FileHandle_Read;
+ File->FileHandle.Write = fsw_efi_FileHandle_Write;
+ File->FileHandle.GetPosition = fsw_efi_FileHandle_GetPosition;
+ File->FileHandle.SetPosition = fsw_efi_FileHandle_SetPosition;
+ File->FileHandle.GetInfo = fsw_efi_FileHandle_GetInfo;
+ File->FileHandle.SetInfo = fsw_efi_FileHandle_SetInfo;
+ File->FileHandle.Flush = fsw_efi_FileHandle_Flush;
+
+ *NewFileHandle = &File->FileHandle;
+ return EFI_SUCCESS;
+}
+
+/**
+ * Data read function for regular files. Calls through to fsw_shandle_read.
+ */
+
+EFI_STATUS fsw_efi_file_read(IN FSW_FILE_DATA *File,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer)
+{
+ EFI_STATUS Status;
+ fsw_u32 buffer_size;
+
+#if DEBUG_LEVEL
+ Print(L"fsw_efi_file_read %d bytes\n", *BufferSize);
+#endif
+
+ buffer_size = (fsw_u32)*BufferSize;
+ if (buffer_size != *BufferSize)
+ buffer_size = ~(fsw_u32)0;
+ Status = fsw_efi_map_status(fsw_shandle_read(&File->shand, &buffer_size, Buffer),
+ (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data);
+ *BufferSize = buffer_size;
+
+ return Status;
+}
+
+/**
+ * Get file position for regular files.
+ */
+
+EFI_STATUS fsw_efi_file_getpos(IN FSW_FILE_DATA *File,
+ OUT UINT64 *Position)
+{
+ *Position = File->shand.pos;
+ return EFI_SUCCESS;
+}
+
+/**
+ * Set file position for regular files. EFI specifies the all-ones value
+ * to be a special value for the end of the file.
+ */
+
+EFI_STATUS fsw_efi_file_setpos(IN FSW_FILE_DATA *File,
+ IN UINT64 Position)
+{
+ if (Position == 0xFFFFFFFFFFFFFFFFULL)
+ File->shand.pos = File->shand.dnode->size;
+ else
+ File->shand.pos = Position;
+ return EFI_SUCCESS;
+}
+
+/**
+ * Open function used to open new file handles relative to a directory.
+ * In EFI, the "open file" function is implemented by directory file handles
+ * and is passed a relative or volume-absolute path to the file or directory
+ * to open. We use fsw_dnode_lookup_path to find the node plus an additional
+ * call to fsw_dnode_resolve because EFI has no concept of symbolic links.
+ */
+
+EFI_STATUS fsw_efi_dir_open(IN FSW_FILE_DATA *File,
+ OUT EFI_FILE **NewHandle,
+ IN CHAR16 *FileName,
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes)
+{
+ EFI_STATUS Status;
+ FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data;
+ struct fsw_dnode *dno;
+ struct fsw_dnode *target_dno;
+ struct fsw_string lookup_path;
+
+#if DEBUG_LEVEL
+ Print(L"fsw_efi_dir_open: '%s'\n", FileName);
+#endif
+
+ if (OpenMode != EFI_FILE_MODE_READ)
+ return EFI_WRITE_PROTECTED;
+
+ lookup_path.type = FSW_STRING_TYPE_UTF16;
+ lookup_path.len = (int)StrLen(FileName);
+ lookup_path.size = lookup_path.len * sizeof(fsw_u16);
+ lookup_path.data = FileName;
+
+ // resolve the path (symlinks along the way are automatically resolved)
+ Status = fsw_efi_map_status(fsw_dnode_lookup_path(File->shand.dnode, &lookup_path, '\\', &dno),
+ Volume);
+ if (EFI_ERROR(Status))
+ return Status;
+
+ // if the final node is a symlink, also resolve it
+ Status = fsw_efi_map_status(fsw_dnode_resolve(dno, &target_dno),
+ Volume);
+ fsw_dnode_release(dno);
+ if (EFI_ERROR(Status))
+ return Status;
+ dno = target_dno;
+
+ // make a new EFI handle for the target dnode
+ Status = fsw_efi_dnode_to_FileHandle(dno, NewHandle);
+ fsw_dnode_release(dno);
+ return Status;
+}
+
+/**
+ * Read function for directories. A file handle read on a directory retrieves
+ * the next directory entry.
+ */
+
+EFI_STATUS fsw_efi_dir_read(IN FSW_FILE_DATA *File,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer)
+{
+ EFI_STATUS Status;
+ FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data;
+ struct fsw_dnode *dno;
+
+#if DEBUG_LEVEL
+ Print(L"fsw_efi_dir_read...\n");
+#endif
+
+ // read the next entry
+ Status = fsw_efi_map_status(fsw_dnode_dir_read(&File->shand, &dno),
+ Volume);
+ if (Status == EFI_NOT_FOUND) {
+ // end of directory
+ *BufferSize = 0;
+#if DEBUG_LEVEL
+ Print(L"...no more entries\n");
+#endif
+ return EFI_SUCCESS;
+ }
+ if (EFI_ERROR(Status))
+ return Status;
+
+ // get info into buffer
+ Status = fsw_efi_dnode_fill_FileInfo(Volume, dno, BufferSize, Buffer);
+ fsw_dnode_release(dno);
+ return Status;
+}
+
+/**
+ * Set file position for directories. The only allowed set position operation
+ * for directories is to rewind the directory completely by setting the
+ * position to zero.
+ */
+
+EFI_STATUS fsw_efi_dir_setpos(IN FSW_FILE_DATA *File,
+ IN UINT64 Position)
+{
+ if (Position == 0) {
+ File->shand.pos = 0;
+ return EFI_SUCCESS;
+ } else {
+ // directories can only rewind to the start
+ return EFI_UNSUPPORTED;
+ }
+}
+
+/**
+ * Get file or volume information. This function implements the GetInfo call
+ * for all file handles. Control is dispatched according to the type of information
+ * requested by the caller.
+ */
+
+EFI_STATUS fsw_efi_dnode_getinfo(IN FSW_FILE_DATA *File,
+ IN EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer)
+{
+ EFI_STATUS Status;
+ FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data;
+ EFI_FILE_SYSTEM_INFO *FSInfo;
+ UINTN RequiredSize;
+ struct fsw_volume_stat vsb;
+
+ if (CompareGuid(InformationType, &GUID_NAME(FileInfo))) {
+#if DEBUG_LEVEL
+ Print(L"fsw_efi_dnode_getinfo: FILE_INFO\n");
+#endif
+
+ Status = fsw_efi_dnode_fill_FileInfo(Volume, File->shand.dnode, BufferSize, Buffer);
+
+ } else if (CompareGuid(InformationType, &GUID_NAME(FileSystemInfo))) {
+#if DEBUG_LEVEL
+ Print(L"fsw_efi_dnode_getinfo: FILE_SYSTEM_INFO\n");
+#endif
+
+ // check buffer size
+ RequiredSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + fsw_efi_strsize(&Volume->vol->label);
+ if (*BufferSize < RequiredSize) {
+ *BufferSize = RequiredSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ // fill structure
+ FSInfo = (EFI_FILE_SYSTEM_INFO *)Buffer;
+ FSInfo->Size = RequiredSize;
+ FSInfo->ReadOnly = TRUE;
+ FSInfo->BlockSize = Volume->vol->log_blocksize;
+ fsw_efi_strcpy(FSInfo->VolumeLabel, &Volume->vol->label);
+
+ // get the missing info from the fs driver
+ ZeroMem(&vsb, sizeof(struct fsw_volume_stat));
+ Status = fsw_efi_map_status(fsw_volume_stat(Volume->vol, &vsb), Volume);
+ if (EFI_ERROR(Status))
+ return Status;
+ FSInfo->VolumeSize = vsb.total_bytes;
+ FSInfo->FreeSpace = vsb.free_bytes;
+
+ // prepare for return
+ *BufferSize = RequiredSize;
+ Status = EFI_SUCCESS;
+
+ } else if (CompareGuid(InformationType, &GUID_NAME(FileSystemVolumeLabelInfoId))) {
+#if DEBUG_LEVEL
+ Print(L"fsw_efi_dnode_getinfo: FILE_SYSTEM_VOLUME_LABEL\n");
+#endif
+
+ // check buffer size
+ RequiredSize = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO + fsw_efi_strsize(&Volume->vol->label);
+ if (*BufferSize < RequiredSize) {
+ *BufferSize = RequiredSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ // copy volume label
+ fsw_efi_strcpy(((EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *)Buffer)->VolumeLabel, &Volume->vol->label);
+
+ // prepare for return
+ *BufferSize = RequiredSize;
+ Status = EFI_SUCCESS;
+
+#ifdef VBOX
+ } else if (CompareGuid(InformationType, &gVBoxFsBlessedFileInfoGuid)) {
+
+# if FSTYPE == hfs
+ struct fsw_string StrBlessedFile;
+
+ fsw_status_t rc = fsw_hfs_get_blessed_file(Volume->vol, &StrBlessedFile);
+ if (!rc)
+ {
+ // check buffer size
+ RequiredSize = SIZE_OF_VBOX_FS_BLESSED_FILE + fsw_efi_strsize(&StrBlessedFile);
+ if (*BufferSize < RequiredSize) {
+ *BufferSize = RequiredSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ // copy volume label
+ fsw_efi_strcpy(((VBOX_FS_BLESSED_FILE *)Buffer)->BlessedFile, &StrBlessedFile);
+
+ // prepare for return
+ *BufferSize = RequiredSize;
+ Status = EFI_SUCCESS;
+ }
+ else
+# endif
+ Status = EFI_UNSUPPORTED;
+#endif
+
+ } else {
+ Status = EFI_UNSUPPORTED;
+ }
+
+ return Status;
+}
+
+/**
+ * Time mapping callback for the fsw_dnode_stat call. This function converts
+ * a Posix style timestamp into an EFI_TIME structure and writes it to the
+ * appropriate member of the EFI_FILE_INFO structure that we're filling.
+ */
+
+static void fsw_efi_store_time_posix(struct fsw_dnode_stat *sb, int which, fsw_u32 posix_time)
+{
+ EFI_FILE_INFO *FileInfo = (EFI_FILE_INFO *)sb->host_data;
+
+ if (which == FSW_DNODE_STAT_CTIME)
+ fsw_efi_decode_time(&FileInfo->CreateTime, posix_time);
+ else if (which == FSW_DNODE_STAT_MTIME)
+ fsw_efi_decode_time(&FileInfo->ModificationTime, posix_time);
+ else if (which == FSW_DNODE_STAT_ATIME)
+ fsw_efi_decode_time(&FileInfo->LastAccessTime, posix_time);
+}
+
+/**
+ * Mode mapping callback for the fsw_dnode_stat call. This function looks at
+ * the Posix mode passed by the file system driver and makes appropriate
+ * adjustments to the EFI_FILE_INFO structure that we're filling.
+ */
+
+static void fsw_efi_store_attr_posix(struct fsw_dnode_stat *sb, fsw_u16 posix_mode)
+{
+ EFI_FILE_INFO *FileInfo = (EFI_FILE_INFO *)sb->host_data;
+
+ if ((posix_mode & S_IWUSR) == 0)
+ FileInfo->Attribute |= EFI_FILE_READ_ONLY;
+}
+
+/**
+ * Common function to fill an EFI_FILE_INFO with information about a dnode.
+ */
+
+EFI_STATUS fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume,
+ IN struct fsw_dnode *dno,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer)
+{
+ EFI_STATUS Status;
+ EFI_FILE_INFO *FileInfo;
+ UINTN RequiredSize;
+ struct fsw_dnode *target_dno;
+ struct fsw_dnode_stat sb;
+
+ // make sure the dnode has complete info
+ Status = fsw_efi_map_status(fsw_dnode_fill(dno), Volume);
+ if (EFI_ERROR(Status))
+ return Status;
+
+ /// @todo check/assert that the dno's name is in UTF16
+
+ // check buffer size
+ RequiredSize = SIZE_OF_EFI_FILE_INFO + fsw_efi_strsize(&dno->name);
+ if (*BufferSize < RequiredSize) {
+ /// @todo wind back the directory in this case
+
+#if DEBUG_LEVEL
+ Print(L"...BUFFER TOO SMALL\n");
+#endif
+ *BufferSize = RequiredSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ // fill structure
+ ZeroMem(Buffer, RequiredSize);
+ FileInfo = (EFI_FILE_INFO *)Buffer;
+
+ // must preserve the original file name
+ fsw_efi_strcpy(FileInfo->FileName, &dno->name);
+
+ // if the node is a symlink, also resolve it
+ Status = fsw_efi_map_status(fsw_dnode_resolve(dno, &target_dno), Volume);
+ fsw_dnode_release(dno);
+ if (EFI_ERROR(Status))
+ return Status;
+ dno = target_dno;
+ // make sure the dnode has complete info again
+ Status = fsw_efi_map_status(fsw_dnode_fill(dno), Volume);
+ if (EFI_ERROR(Status))
+ return Status;
+
+ FileInfo->Size = RequiredSize;
+ FileInfo->FileSize = dno->size;
+ FileInfo->Attribute = 0;
+ if (dno->type == FSW_DNODE_TYPE_DIR)
+ FileInfo->Attribute |= EFI_FILE_DIRECTORY;
+
+ // get the missing info from the fs driver
+ ZeroMem(&sb, sizeof(struct fsw_dnode_stat));
+ sb.store_time_posix = fsw_efi_store_time_posix;
+ sb.store_attr_posix = fsw_efi_store_attr_posix;
+ sb.host_data = FileInfo;
+ Status = fsw_efi_map_status(fsw_dnode_stat(dno, &sb), Volume);
+ if (EFI_ERROR(Status))
+ return Status;
+ FileInfo->PhysicalSize = sb.used_bytes;
+
+ // prepare for return
+ *BufferSize = RequiredSize;
+#if DEBUG_LEVEL
+ Print(L"...returning '%s'\n", FileInfo->FileName);
+#endif
+ return EFI_SUCCESS;
+}
+
+// EOF
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_efi.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_efi.h
new file mode 100644
index 00000000..63e4c721
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_efi.h
@@ -0,0 +1,133 @@
+/* $Id: fsw_efi.h $ */
+/** @file
+ * fsw_efi.h - EFI host environment header.
+ */
+
+/*
+ * Copyright (C) 2010-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ * ---------------------------------------------------------------------------
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_EFI_H_
+#define _FSW_EFI_H_
+
+#include "fsw_core.h"
+
+
+/**
+ * EFI Host: Private per-volume structure.
+ */
+
+typedef struct {
+ UINT64 Signature; //!< Used to identify this structure
+
+ EFI_FILE_IO_INTERFACE FileSystem; //!< Published EFI protocol interface structure
+
+ EFI_HANDLE Handle; //!< The device handle the protocol is attached to
+ EFI_DISK_IO *DiskIo; //!< The Disk I/O protocol we use for disk access
+ UINT32 MediaId; //!< The media ID from the Block I/O protocol
+ EFI_STATUS LastIOStatus; //!< Last status from Disk I/O
+
+ struct fsw_volume *vol; //!< FSW volume structure
+
+} FSW_VOLUME_DATA;
+
+/** Signature for the volume structure. */
+#define FSW_VOLUME_DATA_SIGNATURE EFI_SIGNATURE_32 ('f', 's', 'w', 'V')
+/** Access macro for the volume structure. */
+#define FSW_VOLUME_FROM_FILE_SYSTEM(a) CR (a, FSW_VOLUME_DATA, FileSystem, FSW_VOLUME_DATA_SIGNATURE)
+
+/**
+ * EFI Host: Private structure for a EFI_FILE interface.
+ */
+
+typedef struct {
+ UINT64 Signature; //!< Used to identify this structure
+
+ EFI_FILE FileHandle; //!< Published EFI protocol interface structure
+
+ UINTN Type; //!< File type used for dispatching
+ struct fsw_shandle shand; //!< FSW handle for this file
+
+} FSW_FILE_DATA;
+
+/** File type: regular file. */
+#define FSW_EFI_FILE_TYPE_FILE (0)
+/** File type: directory. */
+#define FSW_EFI_FILE_TYPE_DIR (1)
+
+/** Signature for the file handle structure. */
+#define FSW_FILE_DATA_SIGNATURE EFI_SIGNATURE_32 ('f', 's', 'w', 'F')
+/** Access macro for the file handle structure. */
+#define FSW_FILE_FROM_FILE_HANDLE(a) CR (a, FSW_FILE_DATA, FileHandle, FSW_FILE_DATA_SIGNATURE)
+
+
+//
+// Library functions
+//
+
+VOID fsw_efi_decode_time(OUT EFI_TIME *EfiTime, IN UINT32 UnixTime);
+
+UINTN fsw_efi_strsize(struct fsw_string *s);
+VOID fsw_efi_strcpy(CHAR16 *Dest, struct fsw_string *src);
+
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_efi_base.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_efi_base.h
new file mode 100644
index 00000000..00581d98
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_efi_base.h
@@ -0,0 +1,115 @@
+/* $Id: fsw_efi_base.h $ */
+/** @file
+ * fsw_efi_base.h - Base definitions for the EFI host environment.
+ */
+
+/*
+ * Copyright (C) 2010-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ * ---------------------------------------------------------------------------
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_EFI_BASE_H_
+#define _FSW_EFI_BASE_H_
+
+#ifndef VBOX
+#include <efi.h>
+#include <efilib.h>
+#define PROTO_NAME(x) x
+#endif
+
+#define FSW_LITTLE_ENDIAN (1)
+
+
+// types, reuse EFI types
+
+typedef INT8 fsw_s8;
+typedef UINT8 fsw_u8;
+typedef INT16 fsw_s16;
+typedef UINT16 fsw_u16;
+typedef INT32 fsw_s32;
+typedef UINT32 fsw_u32;
+typedef INT64 fsw_s64;
+typedef UINT64 fsw_u64;
+
+
+// allocation functions
+
+#define fsw_alloc(size, ptrptr) (((*(ptrptr) = AllocatePool(size)) == NULL) ? FSW_OUT_OF_MEMORY : FSW_SUCCESS)
+#define fsw_free(ptr) FreePool(ptr)
+
+// memory functions
+
+#define fsw_memzero(dest,size) ZeroMem(dest,size)
+#define fsw_memcpy(dest,src,size) CopyMem(dest,src,size)
+#define fsw_memeq(p1,p2,size) (CompareMem(p1,p2,size) == 0)
+
+// message printing
+
+#define FSW_MSGSTR(s) DEBUG_INFO, s
+#define FSW_MSGFUNC DebugPrint
+
+// 64-bit hooks
+
+#define FSW_U64_SHR(val,shiftbits) RShiftU64((val), (shiftbits))
+#define FSW_U64_DIV(val,divisor) DivU64x32((val), (divisor), NULL)
+
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_efi_lib.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_efi_lib.c
new file mode 100644
index 00000000..db575910
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_efi_lib.c
@@ -0,0 +1,179 @@
+/* $Id: fsw_efi_lib.c $ */
+/** @file
+ * fsw_efi_lib.c - EFI host environment library functions.
+ */
+
+/*
+ * Copyright (C) 2010-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ * ---------------------------------------------------------------------------
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_efi.h"
+
+
+//
+// time conversion
+//
+// Adopted from public domain code in FreeBSD libc.
+//
+
+#define SECSPERMIN 60
+#define MINSPERHOUR 60
+#define HOURSPERDAY 24
+#define DAYSPERWEEK 7
+#define DAYSPERNYEAR 365
+#define DAYSPERLYEAR 366
+#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
+#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY)
+#define MONSPERYEAR 12
+
+#define EPOCH_YEAR 1970
+#define EPOCH_WDAY TM_THURSDAY
+
+#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
+#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
+
+static const int mon_lengths[2][MONSPERYEAR] = {
+ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+};
+static const int year_lengths[2] = {
+ DAYSPERNYEAR, DAYSPERLYEAR
+};
+
+VOID fsw_efi_decode_time(OUT EFI_TIME *EfiTime, IN UINT32 UnixTime)
+{
+ long days, rem;
+ int y, newy, yleap;
+ const int *ip;
+
+ ZeroMem(EfiTime, sizeof(EFI_TIME));
+
+ days = UnixTime / SECSPERDAY;
+ rem = UnixTime % SECSPERDAY;
+
+ EfiTime->Hour = (UINT8) (rem / SECSPERHOUR);
+ rem = rem % SECSPERHOUR;
+ EfiTime->Minute = (UINT8) (rem / SECSPERMIN);
+ EfiTime->Second = (UINT8) (rem % SECSPERMIN);
+
+ y = EPOCH_YEAR;
+ while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
+ newy = y + days / DAYSPERNYEAR;
+ if (days < 0)
+ --newy;
+ days -= (newy - y) * DAYSPERNYEAR +
+ LEAPS_THRU_END_OF(newy - 1) -
+ LEAPS_THRU_END_OF(y - 1);
+ y = newy;
+ }
+ EfiTime->Year = (UINT16)y;
+ ip = mon_lengths[yleap];
+ for (EfiTime->Month = 0; days >= (long) ip[EfiTime->Month]; ++(EfiTime->Month))
+ days = days - (long) ip[EfiTime->Month];
+ EfiTime->Month++; // adjust range to EFI conventions
+ EfiTime->Day = (UINT8) (days + 1);
+}
+
+//
+// String functions, used for file and volume info
+//
+
+UINTN fsw_efi_strsize(struct fsw_string *s)
+{
+ if (s->type == FSW_STRING_TYPE_EMPTY)
+ return sizeof(CHAR16);
+ return (s->len + 1) * sizeof(CHAR16);
+}
+
+VOID fsw_efi_strcpy(CHAR16 *Dest, struct fsw_string *src)
+{
+ if (src->type == FSW_STRING_TYPE_EMPTY) {
+ Dest[0] = 0;
+ } else if (src->type == FSW_STRING_TYPE_UTF16) {
+ CopyMem(Dest, src->data, src->size);
+ Dest[src->len] = 0;
+ } else {
+ /// @todo coerce, recurse
+ Dest[0] = 0;
+ }
+}
+
+#ifdef VBOX
+int fsw_streq_ISO88591_UTF16(void *s1data, void *s2data, int len)
+{
+ int i;
+ fsw_u8 *p1 = (fsw_u8 *)s1data;
+ fsw_u16 *p2 = (fsw_u16 *)s2data;
+
+ for (i = 0; i<len; i++)
+ {
+ if (fsw_to_lower(p1[i]) != fsw_to_lower(p2[i]))
+ {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+#endif
+
+// EOF
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_hfs.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_hfs.c
new file mode 100644
index 00000000..1ced900a
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_hfs.c
@@ -0,0 +1,1451 @@
+/* $Id: fsw_hfs.c $ */
+/** @file
+ * fsw_hfs.c - HFS file system driver code, see
+ *
+ * https://developer.apple.com/legacy/library/technotes/tn/tn1150.html
+ * (formerly http://developer.apple.com/technotes/tn/tn1150.html)
+ *
+ * Current limitations:
+ * - Doesn't support permissions
+ * - Complete Unicode case-insensitiveness disabled (large tables)
+ * - No links
+ * - Only supports pure HFS+ (i.e. no HFS, or HFS+ embedded to HFS)
+ */
+
+/*
+ * Copyright (C) 2010-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+#include "fsw_hfs.h"
+
+#ifdef HOST_POSIX
+#include <assert.h>
+#define DPRINT(x) printf(x)
+#define DPRINT2(x,y) printf(x,y)
+#define BP(msg) do { printf("ERROR: %s", msg); assert(0); } while (0)
+#elif defined DEBUG_LEVEL
+#define CONCAT(x,y) x##y
+#define DPRINT(x) Print(CONCAT(L,x))
+#define DPRINT2(x,y) Print(CONCAT(L,x), y)
+#define BP(msg) DPRINT(msg)
+#else
+#include <Library/PrintLib.h>
+#define DPRINT(x) do { } while (0)
+#define DPRINT2(x,y) do { } while (0)
+#define BP(msg) do { } while (0)
+#endif
+
+// functions
+#if 0
+void dump_str(fsw_u16* p, fsw_u32 len, int swap)
+{
+ int i;
+
+ for (i=0; i<len; i++)
+ {
+ fprintf(stderr, "%c", swap ? be16_to_cpu(p[i]) : p[i]);
+ }
+ fprintf(stderr, "\n");
+}
+#endif
+
+static fsw_status_t fsw_hfs_volume_mount(struct fsw_hfs_volume *vol);
+static void fsw_hfs_volume_free(struct fsw_hfs_volume *vol);
+static fsw_status_t fsw_hfs_volume_stat(struct fsw_hfs_volume *vol, struct fsw_volume_stat *sb);
+
+static fsw_status_t fsw_hfs_dnode_fill(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno);
+static void fsw_hfs_dnode_free(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno);
+static fsw_status_t fsw_hfs_dnode_stat(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+ struct fsw_dnode_stat *sb);
+static fsw_status_t fsw_hfs_get_extent(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+ struct fsw_extent *extent);
+
+static fsw_status_t fsw_hfs_dir_lookup(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+ struct fsw_string *lookup_name, struct fsw_hfs_dnode **child_dno);
+static fsw_status_t fsw_hfs_dir_read(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+ struct fsw_shandle *shand, struct fsw_hfs_dnode **child_dno);
+#if 0
+static fsw_status_t fsw_hfs_read_dirrec(struct fsw_shandle *shand, struct hfs_dirrec_buffer *dirrec_buffer);
+#endif
+
+static fsw_status_t fsw_hfs_readlink(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+ struct fsw_string *link);
+
+//
+// Dispatch Table
+//
+
+struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(hfs) = {
+ { FSW_STRING_TYPE_ISO88591, 4, 4, "hfs" },
+ sizeof(struct fsw_hfs_volume),
+ sizeof(struct fsw_hfs_dnode),
+
+ fsw_hfs_volume_mount,
+ fsw_hfs_volume_free,
+ fsw_hfs_volume_stat,
+ fsw_hfs_dnode_fill,
+ fsw_hfs_dnode_free,
+ fsw_hfs_dnode_stat,
+ fsw_hfs_get_extent,
+ fsw_hfs_dir_lookup,
+ fsw_hfs_dir_read,
+ fsw_hfs_readlink,
+};
+
+static fsw_s32
+fsw_hfs_read_block (struct fsw_hfs_dnode * dno,
+ fsw_u32 log_bno,
+ fsw_u32 off,
+ fsw_s32 len,
+ fsw_u8 * buf)
+{
+ fsw_status_t status;
+ struct fsw_extent extent;
+ fsw_u32 phys_bno;
+ fsw_u8* buffer;
+
+ extent.log_start = log_bno;
+ status = fsw_hfs_get_extent(dno->g.vol, dno, &extent);
+ if (status)
+ return status;
+
+ phys_bno = extent.phys_start;
+ status = fsw_block_get(dno->g.vol, phys_bno, 0, (void **)&buffer);
+ if (status)
+ return status;
+
+ fsw_memcpy(buf, buffer + off, len);
+
+ fsw_block_release(dno->g.vol, phys_bno, buffer);
+
+ return FSW_SUCCESS;
+
+}
+
+/* Read data from HFS file. */
+static fsw_s32
+fsw_hfs_read_file (struct fsw_hfs_dnode * dno,
+ fsw_u64 pos,
+ fsw_s32 len,
+ fsw_u8 * buf)
+{
+
+ fsw_status_t status;
+ fsw_u32 log_bno;
+ fsw_u32 block_size_bits = dno->g.vol->block_size_shift;
+ fsw_u32 block_size = (1 << block_size_bits);
+ fsw_u32 block_size_mask = block_size - 1;
+ fsw_s32 read = 0;
+
+ while (len > 0)
+ {
+ fsw_u32 off = (fsw_u32)(pos & block_size_mask);
+ fsw_s32 next_len = len;
+
+ log_bno = (fsw_u32)RShiftU64(pos, block_size_bits);
+
+ if ( next_len >= 0
+ && (fsw_u32)next_len > block_size)
+ next_len = block_size;
+ status = fsw_hfs_read_block(dno, log_bno, off, next_len, buf);
+ if (status)
+ return -1;
+ buf += next_len;
+ pos += next_len;
+ len -= next_len;
+ read += next_len;
+ }
+
+ return read;
+}
+
+
+static fsw_s32
+fsw_hfs_compute_shift(fsw_u32 size)
+{
+ fsw_s32 i;
+
+ for (i=0; i<32; i++)
+ {
+ if ((size >> i) == 0)
+ return i - 1;
+ }
+
+ BP("BUG\n");
+ return 0;
+}
+
+/**
+ * Mount an HFS+ volume. Reads the superblock and constructs the
+ * root directory dnode.
+ */
+
+static fsw_status_t fsw_hfs_volume_mount(struct fsw_hfs_volume *vol)
+{
+ fsw_status_t status, rv;
+ void *buffer = NULL;
+ HFSPlusVolumeHeader *voldesc;
+ fsw_u32 blockno;
+ struct fsw_string s;
+
+ rv = FSW_UNSUPPORTED;
+
+ vol->primary_voldesc = NULL;
+ fsw_set_blocksize(vol, HFS_BLOCKSIZE, HFS_BLOCKSIZE);
+ blockno = HFS_SUPERBLOCK_BLOCKNO;
+
+#define CHECK(s) \
+ if (status) { \
+ rv = status; \
+ break; \
+ }
+
+ vol->emb_block_off = 0;
+ vol->hfs_kind = 0;
+ do {
+ fsw_u16 signature;
+ BTHeaderRec tree_header;
+ fsw_s32 r;
+ fsw_u32 block_size;
+
+ status = fsw_block_get(vol, blockno, 0, &buffer);
+ CHECK(status);
+ voldesc = (HFSPlusVolumeHeader *)buffer;
+ signature = be16_to_cpu(voldesc->signature);
+
+ if ((signature == kHFSPlusSigWord) || (signature == kHFSXSigWord))
+ {
+ if (vol->hfs_kind == 0)
+ {
+ DPRINT("found HFS+\n");
+ vol->hfs_kind = FSW_HFS_PLUS;
+ }
+ }
+ else if (signature == kHFSSigWord)
+ {
+ HFSMasterDirectoryBlock* mdb = (HFSMasterDirectoryBlock*)buffer;
+
+ if (be16_to_cpu(mdb->drEmbedSigWord) == kHFSPlusSigWord)
+ {
+ DPRINT("found HFS+ inside HFS, untested\n");
+ vol->hfs_kind = FSW_HFS_PLUS_EMB;
+ vol->emb_block_off = be32_to_cpu(mdb->drEmbedExtent.startBlock);
+ blockno += vol->emb_block_off;
+ /* retry */
+ continue;
+ }
+ else
+ {
+ DPRINT("found plain HFS, unsupported\n");
+ vol->hfs_kind = FSW_HFS_PLAIN;
+ }
+ rv = FSW_UNSUPPORTED;
+ break;
+ }
+ else
+ {
+ rv = FSW_UNSUPPORTED;
+ break;
+ }
+
+ status = fsw_memdup((void **)&vol->primary_voldesc, voldesc,
+ sizeof(*voldesc));
+ CHECK(status);
+
+
+ block_size = be32_to_cpu(voldesc->blockSize);
+ vol->block_size_shift = fsw_hfs_compute_shift(block_size);
+
+ fsw_block_release(vol, blockno, buffer);
+ buffer = NULL;
+ voldesc = NULL;
+ fsw_set_blocksize(vol, block_size, block_size);
+
+ /* get volume name */
+ s.type = FSW_STRING_TYPE_ISO88591;
+ s.size = s.len = kHFSMaxVolumeNameChars;
+ s.data = "HFS+ volume\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; /* Otherwise buffer overflow reading beyond the end of the buffer. */
+ status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s);
+ CHECK(status);
+
+ /* Setup catalog dnode */
+ status = fsw_dnode_create_root(vol, kHFSCatalogFileID, &vol->catalog_tree.file);
+ CHECK(status);
+ fsw_memcpy (vol->catalog_tree.file->extents,
+ vol->primary_voldesc->catalogFile.extents,
+ sizeof vol->catalog_tree.file->extents);
+ vol->catalog_tree.file->g.size =
+ be64_to_cpu(vol->primary_voldesc->catalogFile.logicalSize);
+
+ /* Setup extents overflow file */
+ status = fsw_dnode_create_root(vol, kHFSExtentsFileID, &vol->extents_tree.file);
+ fsw_memcpy (vol->extents_tree.file->extents,
+ vol->primary_voldesc->extentsFile.extents,
+ sizeof vol->extents_tree.file->extents);
+ vol->extents_tree.file->g.size =
+ be64_to_cpu(vol->primary_voldesc->extentsFile.logicalSize);
+
+ /* Setup the root dnode */
+ status = fsw_dnode_create_root(vol, kHFSRootFolderID, &vol->g.root);
+ CHECK(status);
+
+ /*
+ * Read catalog file, we know that first record is in the first node, right after
+ * the node descriptor.
+ */
+ r = fsw_hfs_read_file(vol->catalog_tree.file,
+ sizeof (BTNodeDescriptor),
+ sizeof (BTHeaderRec), (fsw_u8 *) &tree_header);
+ if (r <= 0)
+ {
+ status = FSW_VOLUME_CORRUPTED;
+ break;
+ }
+ vol->case_sensitive =
+ (signature == kHFSXSigWord) &&
+ (tree_header.keyCompareType == kHFSBinaryCompare);
+ vol->catalog_tree.root_node = be32_to_cpu (tree_header.rootNode);
+ vol->catalog_tree.node_size = be16_to_cpu (tree_header.nodeSize);
+
+ /* Read extents overflow file */
+ r = fsw_hfs_read_file(vol->extents_tree.file,
+ sizeof (BTNodeDescriptor),
+ sizeof (BTHeaderRec), (fsw_u8 *) &tree_header);
+ if (r <= 0)
+ {
+ status = FSW_VOLUME_CORRUPTED;
+ break;
+ }
+
+ vol->extents_tree.root_node = be32_to_cpu (tree_header.rootNode);
+ vol->extents_tree.node_size = be16_to_cpu (tree_header.nodeSize);
+
+ rv = FSW_SUCCESS;
+ } while (0);
+
+#undef CHECK
+
+
+ if (buffer != NULL)
+ fsw_block_release(vol, blockno, buffer);
+
+ return rv;
+}
+
+/**
+ * Free the volume data structure. Called by the core after an unmount or after
+ * an unsuccessful mount to release the memory used by the file system type specific
+ * part of the volume structure.
+ */
+
+static void fsw_hfs_volume_free(struct fsw_hfs_volume *vol)
+{
+ if (vol->primary_voldesc)
+ {
+ fsw_free(vol->primary_voldesc);
+ vol->primary_voldesc = NULL;
+ }
+}
+
+/**
+ * Get in-depth information on a volume.
+ */
+
+static fsw_status_t fsw_hfs_volume_stat(struct fsw_hfs_volume *vol, struct fsw_volume_stat *sb)
+{
+ sb->total_bytes = be32_to_cpu(vol->primary_voldesc->totalBlocks) << vol->block_size_shift;
+ sb->free_bytes = be32_to_cpu(vol->primary_voldesc->freeBlocks) << vol->block_size_shift;
+ return FSW_SUCCESS;
+}
+
+/**
+ * Get full information on a dnode from disk. This function is called by the core
+ * whenever it needs to access fields in the dnode structure that may not
+ * be filled immediately upon creation of the dnode.
+ */
+
+static fsw_status_t fsw_hfs_dnode_fill(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno)
+{
+ return FSW_SUCCESS;
+}
+
+/**
+ * Free the dnode data structure. Called by the core when deallocating a dnode
+ * structure to release the memory used by the file system type specific part
+ * of the dnode structure.
+ */
+
+static void fsw_hfs_dnode_free(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno)
+{
+}
+
+static fsw_u32 mac_to_posix(fsw_u32 mac_time)
+{
+ /* Mac time is 1904 year based */
+ return mac_time ? mac_time - 2082844800 : 0;
+}
+
+/**
+ * Get in-depth information on a dnode. The core makes sure that fsw_hfs_dnode_fill
+ * has been called on the dnode before this function is called. Note that some
+ * data is not directly stored into the structure, but passed to a host-specific
+ * callback that converts it to the host-specific format.
+ */
+
+static fsw_status_t fsw_hfs_dnode_stat(struct fsw_hfs_volume *vol,
+ struct fsw_hfs_dnode *dno,
+ struct fsw_dnode_stat *sb)
+{
+ sb->used_bytes = dno->used_bytes;
+ sb->store_time_posix(sb, FSW_DNODE_STAT_CTIME, mac_to_posix(dno->ctime));
+ sb->store_time_posix(sb, FSW_DNODE_STAT_MTIME, mac_to_posix(dno->mtime));
+ sb->store_time_posix(sb, FSW_DNODE_STAT_ATIME, 0);
+ sb->store_attr_posix(sb, 0700);
+
+ return FSW_SUCCESS;
+}
+
+static int
+fsw_hfs_find_block(HFSPlusExtentRecord * exts,
+ fsw_u32 * lbno,
+ fsw_u32 * pbno)
+{
+ int i;
+ fsw_u32 cur_lbno = *lbno;
+
+ for (i = 0; i < 8; i++)
+ {
+ fsw_u32 start = be32_to_cpu ((*exts)[i].startBlock);
+ fsw_u32 count = be32_to_cpu ((*exts)[i].blockCount);
+
+ if (cur_lbno < count)
+ {
+ *pbno = start + cur_lbno;
+ return 1;
+ }
+
+ cur_lbno -= count;
+ }
+
+ *lbno = cur_lbno;
+
+ return 0;
+}
+
+/* Find record offset, numbering starts from the end */
+static fsw_u32
+fsw_hfs_btree_recoffset (struct fsw_hfs_btree * btree,
+ BTNodeDescriptor * node,
+ fsw_u32 index)
+{
+ fsw_u8 *cnode = (fsw_u8 *) node;
+ fsw_u16 *recptr;
+ recptr = (fsw_u16 *) (cnode+btree->node_size - index * 2 - 2);
+ return be16_to_cpu(*recptr);
+}
+
+/* Pointer to the key inside node */
+static BTreeKey *
+fsw_hfs_btree_rec (struct fsw_hfs_btree * btree,
+ BTNodeDescriptor * node,
+ fsw_u32 index)
+{
+ fsw_u8 *cnode = (fsw_u8 *) node;
+ fsw_u32 offset;
+ offset = fsw_hfs_btree_recoffset (btree, node, index);
+ return (BTreeKey *) (cnode + offset);
+}
+
+
+static fsw_status_t
+fsw_hfs_btree_search (struct fsw_hfs_btree * btree,
+ BTreeKey * key,
+ int (*compare_keys) (BTreeKey* key1, BTreeKey* key2),
+ BTNodeDescriptor ** result,
+ fsw_u32 * key_offset)
+{
+ BTNodeDescriptor* node;
+ fsw_u32 currnode;
+ fsw_u32 rec;
+ fsw_status_t status;
+ fsw_u8* buffer = NULL;
+
+ currnode = btree->root_node;
+ status = fsw_alloc(btree->node_size, &buffer);
+ if (status)
+ return status;
+ node = (BTNodeDescriptor*)buffer;
+
+ while (1)
+ {
+ int cmp = 0;
+ int match;
+ fsw_u32 count;
+
+ readnode:
+ match = 0;
+ /* Read a node. */
+ if (fsw_hfs_read_file (btree->file,
+ (fsw_u64)currnode * btree->node_size,
+ btree->node_size, buffer) <= 0)
+ {
+ status = FSW_VOLUME_CORRUPTED;
+ break;
+ }
+
+ if (be16_to_cpu(*(fsw_u16*)(buffer + btree->node_size - 2)) != sizeof(BTNodeDescriptor))
+ BP("corrupted node\n");
+
+ count = be16_to_cpu (node->numRecords);
+
+#if 1
+ for (rec = 0; rec < count; rec++)
+ {
+ BTreeKey *currkey;
+
+ currkey = fsw_hfs_btree_rec (btree, node, rec);
+ cmp = compare_keys (currkey, key);
+ //fprintf(stderr, "rec=%d cmp=%d kind=%d \n", rec, cmp, node->kind);
+
+ /* Leaf node. */
+ if (node->kind == kBTLeafNode)
+ {
+ if (cmp == 0)
+ {
+ /* Found! */
+ *result = node;
+ *key_offset = rec;
+
+ status = FSW_SUCCESS;
+ goto done;
+ }
+ }
+ else if (node->kind == kBTIndexNode)
+ {
+ fsw_u32 *pointer;
+
+ if (cmp > 0)
+ break;
+
+ pointer = (fsw_u32 *) ((char *) currkey
+ + be16_to_cpu (currkey->length16)
+ + 2);
+ currnode = be32_to_cpu (*pointer);
+ match = 1;
+ }
+ }
+
+ if (node->kind == kBTLeafNode && cmp < 0 && node->fLink)
+ {
+ currnode = be32_to_cpu(node->fLink);
+ goto readnode;
+ }
+ else if (!match)
+ {
+ status = FSW_NOT_FOUND;
+ break;
+ }
+#else
+ /* Perform binary search */
+ fsw_u32 lower = 0;
+ fsw_u32 upper = count - 1;
+ fsw_s32 cmp = -1;
+ BTreeKey *currkey = NULL;
+
+ if (count == 0)
+ {
+ status = FSW_NOT_FOUND;
+ goto done;
+ }
+
+ while (lower <= upper)
+ {
+ fsw_u32 index = (lower + upper) / 2;
+
+ currkey = fsw_hfs_btree_rec (btree, node, index);
+
+ cmp = compare_keys (currkey, key);
+ if (cmp < 0) upper = index - 1;
+ if (cmp > 0) lower = index + 1;
+ if (cmp == 0)
+ {
+ /* Found! */
+ *result = node;
+ *key_offset = rec;
+
+ status = FSW_SUCCESS;
+ goto done;
+ }
+ }
+
+ if (cmp < 0)
+ currkey = fsw_hfs_btree_rec (btree, node, upper);
+
+ if (node->kind == kBTIndexNode && currkey)
+ {
+ fsw_u32 *pointer;
+
+ pointer = (fsw_u32 *) ((char *) currkey
+ + be16_to_cpu (currkey->length16)
+ + 2);
+ currnode = be32_to_cpu (*pointer);
+ }
+ else
+ {
+ status = FSW_NOT_FOUND;
+ break;
+ }
+#endif
+ }
+
+
+ done:
+ if (buffer != NULL && status != FSW_SUCCESS)
+ fsw_free(buffer);
+
+ return status;
+}
+
+typedef struct
+{
+ fsw_u32 id;
+ fsw_u32 type;
+ struct fsw_string * name;
+ fsw_u64 size;
+ fsw_u64 used;
+ fsw_u32 ctime;
+ fsw_u32 mtime;
+ fsw_u32 node_num;
+ HFSPlusExtentRecord extents;
+} file_info_t;
+
+typedef struct
+{
+ fsw_u32 cur_pos; /* current position */
+ fsw_u32 parent;
+ struct fsw_hfs_volume * vol;
+
+ struct fsw_shandle * shandle; /* this one track iterator's state */
+ file_info_t file_info;
+} visitor_parameter_t;
+
+static void hfs_fill_info(struct fsw_hfs_volume *vol, HFSPlusCatalogKey *file_key, file_info_t *file_info)
+{
+ fsw_u8 * base;
+ fsw_u16 rec_type;
+
+ /* for plain HFS "-(keySize & 1)" would be needed */
+ base = (fsw_u8*)file_key + be16_to_cpu(file_key->keyLength) + 2;
+ rec_type = be16_to_cpu(*(fsw_u16*)base);
+
+ /** @todo read additional info */
+ switch (rec_type)
+ {
+ case kHFSPlusFolderRecord:
+ {
+ HFSPlusCatalogFolder* info = (HFSPlusCatalogFolder*)base;
+
+ file_info->id = be32_to_cpu(info->folderID);
+ file_info->type = FSW_DNODE_TYPE_DIR;
+ /** @todo return number of elements, maybe use smth else */
+ file_info->size = be32_to_cpu(info->valence);
+ file_info->used = be32_to_cpu(info->valence);
+ file_info->ctime = be32_to_cpu(info->createDate);
+ file_info->mtime = be32_to_cpu(info->contentModDate);
+ break;
+ }
+ case kHFSPlusFileRecord:
+ {
+ HFSPlusCatalogFile* info = (HFSPlusCatalogFile*)base;
+ uint32_t creator = be32_to_cpu(info->userInfo.fdCreator);
+ uint32_t crtype = be32_to_cpu(info->userInfo.fdType);
+
+ file_info->id = be32_to_cpu(info->fileID);
+ file_info->type = FSW_DNODE_TYPE_FILE;
+ file_info->size = be64_to_cpu(info->dataFork.logicalSize);
+ file_info->used = LShiftU64(be32_to_cpu(info->dataFork.totalBlocks), vol->block_size_shift);
+ file_info->ctime = be32_to_cpu(info->createDate);
+ file_info->mtime = be32_to_cpu(info->contentModDate);
+ fsw_memcpy(&file_info->extents, &info->dataFork.extents,
+ sizeof file_info->extents);
+ if (creator == kHFSPlusCreator && crtype == kHardLinkFileType)
+ {
+ /* Only hard links currently supported. */
+ file_info->type = FSW_DNODE_TYPE_SYMLINK;
+ file_info->node_num = be32_to_cpu(info->bsdInfo.special.iNodeNum);
+ }
+ break;
+ }
+ case kHFSPlusFolderThreadRecord:
+ case kHFSPlusFileThreadRecord:
+ {
+ /* Do nothing. */
+ break;
+ }
+ default:
+ BP("unknown file type\n");
+ file_info->type = FSW_DNODE_TYPE_UNKNOWN;
+
+ break;
+ }
+}
+
+static int
+fsw_hfs_btree_visit_node(BTreeKey *record, void* param)
+{
+ visitor_parameter_t* vp = (visitor_parameter_t*)param;
+ fsw_u8* base = (fsw_u8*)record->rawData + be16_to_cpu(record->length16) + 2;
+ fsw_u16 rec_type = be16_to_cpu(*(fsw_u16*)base);
+ struct HFSPlusCatalogKey* cat_key = (HFSPlusCatalogKey*)record;
+ fsw_u16 name_len;
+ fsw_u16 *name_ptr;
+ fsw_u32 i;
+ struct fsw_string * file_name;
+
+ if (be32_to_cpu(cat_key->parentID) != vp->parent)
+ return -1;
+
+ /* not smth we care about */
+ if (vp->shandle->pos != vp->cur_pos++)
+ return 0;
+
+ if (rec_type == kHFSPlusFolderThreadRecord || rec_type == kHFSPlusFileThreadRecord)
+ {
+ vp->shandle->pos++;
+ return 0;
+ }
+
+ hfs_fill_info(vp->vol, cat_key, &vp->file_info);
+
+ name_len = be16_to_cpu(cat_key->nodeName.length);
+
+ file_name = vp->file_info.name;
+ file_name->len = name_len;
+ fsw_memdup(&file_name->data, &cat_key->nodeName.unicode[0], 2*name_len);
+ file_name->size = 2*name_len;
+ file_name->type = FSW_STRING_TYPE_UTF16;
+ name_ptr = (fsw_u16*)file_name->data;
+ for (i=0; i<name_len; i++)
+ {
+ name_ptr[i] = be16_to_cpu(name_ptr[i]);
+ }
+ vp->shandle->pos++;
+
+ return 1;
+}
+
+static fsw_status_t
+fsw_hfs_btree_iterate_node (struct fsw_hfs_btree * btree,
+ BTNodeDescriptor * first_node,
+ fsw_u32 first_rec,
+ int (*callback) (BTreeKey *record, void* param),
+ void * param)
+{
+ fsw_status_t status;
+ /* We modify node, so make a copy */
+ BTNodeDescriptor* node = first_node;
+ fsw_u8* buffer = NULL;
+
+ status = fsw_alloc(btree->node_size, &buffer);
+ if (status)
+ return status;
+
+ while (1)
+ {
+ fsw_u32 i;
+ fsw_u32 count = be16_to_cpu(node->numRecords);
+ fsw_u32 next_node;
+
+ /* Iterate over all records in this node. */
+ for (i = first_rec; i < count; i++)
+ {
+ int rv = callback(fsw_hfs_btree_rec (btree, node, i), param);
+
+ switch (rv)
+ {
+ case 1:
+ status = FSW_SUCCESS;
+ goto done;
+ case -1:
+ status = FSW_NOT_FOUND;
+ goto done;
+ }
+ /* if callback returned 0 - continue */
+ }
+
+ next_node = be32_to_cpu(node->fLink);
+
+ if (!next_node)
+ {
+ status = FSW_NOT_FOUND;
+ break;
+ }
+
+ if (fsw_hfs_read_file (btree->file,
+ next_node * btree->node_size,
+ btree->node_size, buffer) <= 0)
+ {
+ status = FSW_VOLUME_CORRUPTED;
+ return 1;
+ }
+
+ node = (BTNodeDescriptor*)buffer;
+ first_rec = 0;
+ }
+ done:
+ if (buffer)
+ fsw_free(buffer);
+
+ return status;
+}
+
+#if 0
+void deb(fsw_u16* p, int len, int swap)
+{
+ int i;
+ for (i=0; i<len; i++)
+ {
+ printf("%c", swap ? be16_to_cpu(p[i]) : p[i]);
+ }
+ printf("\n");
+}
+#endif
+
+static int
+fsw_hfs_cmp_extkey(BTreeKey* key1, BTreeKey* key2)
+{
+ HFSPlusExtentKey* ekey1 = (HFSPlusExtentKey*)key1;
+ HFSPlusExtentKey* ekey2 = (HFSPlusExtentKey*)key2;
+ int result;
+
+ /* First key is read from the FS data, second is in-memory in CPU endianess */
+ result = be32_to_cpu(ekey1->fileID) - ekey2->fileID;
+
+ if (result)
+ return result;
+
+ result = ekey1->forkType - ekey2->forkType;
+
+ if (result)
+ return result;
+
+ result = be32_to_cpu(ekey1->startBlock) - ekey2->startBlock;
+ return result;
+}
+
+static int
+fsw_hfs_cmp_catkey (BTreeKey *key1, BTreeKey *key2)
+{
+ HFSPlusCatalogKey *ckey1 = (HFSPlusCatalogKey*)key1;
+ HFSPlusCatalogKey *ckey2 = (HFSPlusCatalogKey*)key2;
+
+ int apos, bpos, lc;
+ fsw_u16 ac, bc;
+ fsw_u32 parentId1;
+ int key1Len;
+ fsw_u16 *p1;
+ fsw_u16 *p2;
+
+ parentId1 = be32_to_cpu(ckey1->parentID);
+
+ if (parentId1 > ckey2->parentID)
+ return 1;
+ if (parentId1 < ckey2->parentID)
+ return -1;
+
+ p1 = &ckey1->nodeName.unicode[0];
+ p2 = &ckey2->nodeName.unicode[0];
+ key1Len = be16_to_cpu (ckey1->nodeName.length);
+ apos = bpos = 0;
+
+ while(1)
+ {
+ /* get next valid character from ckey1 */
+ for (lc = 0; lc == 0 && apos < key1Len; apos++) {
+ ac = be16_to_cpu(p1[apos]);
+ lc = ac;
+ };
+ ac = (fsw_u16)lc;
+
+ /* get next valid character from ckey2 */
+ for (lc = 0; lc == 0 && bpos < ckey2->nodeName.length; bpos++) {
+ bc = p2[bpos];
+ lc = bc;
+ };
+ bc = (fsw_u16)lc;
+
+ if (ac != bc || (ac == 0 && bc == 0))
+ return ac - bc;
+ }
+}
+
+static int
+fsw_hfs_cmpi_catkey (BTreeKey *key1, BTreeKey *key2)
+{
+ HFSPlusCatalogKey *ckey1 = (HFSPlusCatalogKey*)key1;
+ HFSPlusCatalogKey *ckey2 = (HFSPlusCatalogKey*)key2;
+
+ int apos, bpos, lc;
+ fsw_u16 ac, bc;
+ fsw_u32 parentId1;
+ int key1Len;
+ fsw_u16 *p1;
+ fsw_u16 *p2;
+
+ parentId1 = be32_to_cpu(ckey1->parentID);
+
+ if (parentId1 > ckey2->parentID)
+ return 1;
+ if (parentId1 < ckey2->parentID)
+ return -1;
+
+ key1Len = be16_to_cpu (ckey1->nodeName.length);
+
+ if (key1Len == 0 && ckey2->nodeName.length == 0)
+ return 0;
+
+ p1 = &ckey1->nodeName.unicode[0];
+ p2 = &ckey2->nodeName.unicode[0];
+
+ apos = bpos = 0;
+
+ while(1)
+ {
+ /* get next valid (non-zero) character from ckey1 */
+ for (lc = 0; lc == 0 && apos < key1Len; apos++) {
+ ac = be16_to_cpu(p1[apos]);
+ lc = fsw_to_lower(ac); /* NB: 0x0000 is translated to 0xffff */
+ };
+ ac = (fsw_u16)lc;
+
+ /* get next valid (non-zero) character from ckey2 */
+ for (lc = 0; lc == 0 && bpos < ckey2->nodeName.length; bpos++) {
+ bc = p2[bpos];
+ lc = fsw_to_lower(bc); /* NB: 0x0000 is translated to 0xffff */
+ };
+ bc = (fsw_u16)lc;
+
+ if (ac != bc || (ac == 0 && bc == 0))
+ return ac - bc;
+ }
+}
+
+/**
+ * Retrieve file data mapping information. This function is called by the core when
+ * fsw_shandle_read needs to know where on the disk the required piece of the file's
+ * data can be found. The core makes sure that fsw_hfs_dnode_fill has been called
+ * on the dnode before. Our task here is to get the physical disk block number for
+ * the requested logical block number.
+ */
+
+static fsw_status_t fsw_hfs_get_extent(struct fsw_hfs_volume * vol,
+ struct fsw_hfs_dnode * dno,
+ struct fsw_extent * extent)
+{
+ fsw_status_t status;
+ fsw_u32 lbno;
+ HFSPlusExtentRecord *exts;
+ BTNodeDescriptor *node = NULL;
+
+ extent->type = FSW_EXTENT_TYPE_PHYSBLOCK;
+ extent->log_count = 1;
+ lbno = extent->log_start;
+
+ /* we only care about data forks atm, do we? */
+ exts = &dno->extents;
+
+ while (1)
+ {
+ struct HFSPlusExtentKey* key;
+ struct HFSPlusExtentKey overflowkey;
+ fsw_u32 ptr;
+ fsw_u32 phys_bno;
+
+ if (fsw_hfs_find_block(exts, &lbno, &phys_bno))
+ {
+ extent->phys_start = phys_bno + vol->emb_block_off;
+ status = FSW_SUCCESS;
+ break;
+ }
+
+
+ /* Find appropriate overflow record */
+ overflowkey.fileID = dno->g.dnode_id;
+ overflowkey.startBlock = extent->log_start - lbno;
+
+ if (node != NULL)
+ {
+ fsw_free(node);
+ node = NULL;
+ }
+
+ status = fsw_hfs_btree_search (&vol->extents_tree,
+ (BTreeKey*)&overflowkey,
+ fsw_hfs_cmp_extkey,
+ &node, &ptr);
+ if (status)
+ break;
+
+ key = (struct HFSPlusExtentKey *)
+ fsw_hfs_btree_rec (&vol->extents_tree, node, ptr);
+ exts = (HFSPlusExtentRecord*) (key + 1);
+ }
+
+ if (node != NULL)
+ fsw_free(node);
+
+ return status;
+}
+
+static const fsw_u16* g_blacklist[] =
+{
+ //L"AppleIntelCPUPowerManagement.kext",
+ NULL
+};
+
+
+//#define HFS_FILE_INJECTION
+
+#ifdef HFS_FILE_INJECTION
+static struct
+{
+ const fsw_u16* path;
+ const fsw_u16* name;
+} g_injectList[] =
+{
+ {
+ L"/System/Library/Extensions",
+ L"ApplePS2Controller.kext"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+#endif
+
+static fsw_status_t
+create_hfs_dnode(struct fsw_hfs_dnode * dno,
+ file_info_t * file_info,
+ struct fsw_hfs_dnode ** child_dno_out)
+{
+ fsw_status_t status;
+ struct fsw_hfs_dnode * baby;
+
+ status = fsw_dnode_create(dno, file_info->id, file_info->type,
+ file_info->name, &baby);
+ if (status)
+ return status;
+
+ baby->g.size = file_info->size;
+ baby->used_bytes = file_info->used;
+ baby->ctime = file_info->ctime;
+ baby->mtime = file_info->mtime;
+ baby->node_num = file_info->node_num;
+
+
+ /* Fill-in extents info */
+ if (file_info->type == FSW_DNODE_TYPE_FILE)
+ {
+ fsw_memcpy(baby->extents, &file_info->extents, sizeof file_info->extents);
+ }
+
+ *child_dno_out = baby;
+
+ return FSW_SUCCESS;
+}
+
+
+/**
+ * Lookup a directory's child dnode by name. This function is called on a directory
+ * to retrieve the directory entry with the given name. A dnode is constructed for
+ * this entry and returned. The core makes sure that fsw_hfs_dnode_fill has been called
+ * and the dnode is actually a directory.
+ */
+
+static fsw_status_t fsw_hfs_dir_lookup(struct fsw_hfs_volume * vol,
+ struct fsw_hfs_dnode * dno,
+ struct fsw_string * lookup_name,
+ struct fsw_hfs_dnode ** child_dno_out)
+{
+ fsw_status_t status;
+ struct HFSPlusCatalogKey catkey;
+ fsw_u32 ptr;
+ BTNodeDescriptor * node = NULL;
+ struct fsw_string rec_name;
+ int free_data = 0, i;
+ HFSPlusCatalogKey* file_key;
+ file_info_t file_info;
+
+
+ fsw_memzero(&file_info, sizeof file_info);
+ file_info.name = &rec_name;
+
+ catkey.parentID = dno->g.dnode_id;
+ catkey.nodeName.length = (fsw_u16)lookup_name->len;
+
+ /* no need to allocate anything */
+ if (lookup_name->type == FSW_STRING_TYPE_UTF16)
+ {
+ fsw_memcpy(catkey.nodeName.unicode, lookup_name->data, lookup_name->size);
+ rec_name = *lookup_name;
+ } else
+ {
+ status = fsw_strdup_coerce(&rec_name, FSW_STRING_TYPE_UTF16, lookup_name);
+ /* nothing allocated so far */
+ if (status)
+ goto done;
+ free_data = 1;
+ fsw_memcpy(catkey.nodeName.unicode, rec_name.data, rec_name.size);
+ }
+
+ /* Dirty hack: blacklisting of certain files on FS driver level */
+ for (i = 0; g_blacklist[i]; i++)
+ {
+ if (fsw_memeq(g_blacklist[i], catkey.nodeName.unicode, catkey.nodeName.length*2))
+ {
+ DPRINT2("Blacklisted %s\n", g_blacklist[i]);
+ status = FSW_NOT_FOUND;
+ goto done;
+ }
+ }
+
+#ifdef HFS_FILE_INJECTION
+ if (fsw_hfs_inject(vol,
+ dno,
+ catkey.nodeName.unicode,
+ catkey.nodeName.length,
+ &file_info))
+ {
+ status = FSW_SUCCESS;
+ goto create;
+ }
+#endif
+
+ catkey.keyLength = (fsw_u16)(6 + rec_name.len);
+
+ status = fsw_hfs_btree_search (&vol->catalog_tree,
+ (BTreeKey*)&catkey,
+ vol->case_sensitive ?
+ fsw_hfs_cmp_catkey : fsw_hfs_cmpi_catkey,
+ &node, &ptr);
+ if (status)
+ goto done;
+
+ file_key = (HFSPlusCatalogKey *)fsw_hfs_btree_rec (&vol->catalog_tree, node, ptr);
+ hfs_fill_info(vol, file_key, &file_info);
+
+#ifdef HFS_FILE_INJECTION
+create:
+#endif
+ status = create_hfs_dnode(dno, &file_info, child_dno_out);
+ if (status)
+ goto done;
+
+done:
+
+ if (node != NULL)
+ fsw_free(node);
+
+ if (free_data)
+ fsw_strfree(&rec_name);
+
+ return status;
+}
+
+/**
+ * Get the next directory entry when reading a directory. This function is called during
+ * directory iteration to retrieve the next directory entry. A dnode is constructed for
+ * the entry and returned. The core makes sure that fsw_hfs_dnode_fill has been called
+ * and the dnode is actually a directory. The shandle provided by the caller is used to
+ * record the position in the directory between calls.
+ */
+
+static fsw_status_t fsw_hfs_dir_read(struct fsw_hfs_volume *vol,
+ struct fsw_hfs_dnode *dno,
+ struct fsw_shandle *shand,
+ struct fsw_hfs_dnode **child_dno_out)
+{
+ fsw_status_t status;
+ struct HFSPlusCatalogKey catkey;
+ fsw_u32 ptr;
+ BTNodeDescriptor * node = NULL;
+
+ visitor_parameter_t param;
+ struct fsw_string rec_name;
+
+ catkey.parentID = dno->g.dnode_id;
+ catkey.nodeName.length = 0;
+
+ fsw_memzero(&param, sizeof(param));
+
+ rec_name.type = FSW_STRING_TYPE_EMPTY;
+ param.file_info.name = &rec_name;
+
+ status = fsw_hfs_btree_search (&vol->catalog_tree,
+ (BTreeKey*)&catkey,
+ vol->case_sensitive ?
+ fsw_hfs_cmp_catkey : fsw_hfs_cmpi_catkey,
+ &node, &ptr);
+ if (status)
+ goto done;
+
+ /* Iterator updates shand state */
+ param.vol = vol;
+ param.shandle = shand;
+ param.parent = dno->g.dnode_id;
+ param.cur_pos = 0;
+ status = fsw_hfs_btree_iterate_node (&vol->catalog_tree,
+ node,
+ ptr,
+ fsw_hfs_btree_visit_node,
+ &param);
+ if (status)
+ goto done;
+
+ status = create_hfs_dnode(dno, &param.file_info, child_dno_out);
+
+ if (status)
+ goto done;
+
+ done:
+ fsw_strfree(&rec_name);
+
+ return status;
+}
+
+static const char hfs_priv_prefix[] = "/\0\0\0\0HFS+ Private Data/" HFS_INODE_PREFIX;
+
+/**
+ * Get the target path of a symbolic link. This function is called when a symbolic
+ * link needs to be resolved. The core makes sure that the fsw_hfs_dnode_fill has been
+ * called on the dnode and that it really is a symlink.
+ *
+ */
+static fsw_status_t fsw_hfs_readlink(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+ struct fsw_string *link_target)
+{
+ fsw_status_t status;
+
+ if (dno->node_num)
+ {
+ struct fsw_string tgt;
+
+ DPRINT2("hfs_readlink: %d\n", dno->node_num);
+ tgt.type = FSW_STRING_TYPE_ISO88591;
+ tgt.size = sizeof(hfs_priv_prefix) + 10;
+ tgt.len = tgt.size - 1;
+ status = fsw_alloc(tgt.size, &tgt.data);
+ if (!status)
+ {
+ char *str = tgt.data;
+ fsw_memcpy(tgt.data, hfs_priv_prefix, sizeof(hfs_priv_prefix)); // null chars here!
+#ifdef HOST_POSIX
+ tgt.len = sprintf(&str[sizeof(hfs_priv_prefix) - 1], "%d", dno->node_num);
+#else
+ tgt.len = (int)AsciiSPrint(&str[sizeof(hfs_priv_prefix) - 1], tgt.len, "%d", dno->node_num);
+#endif
+ tgt.len += sizeof(hfs_priv_prefix) - 1;
+ status = fsw_strdup_coerce(link_target, vol->g.host_string_type, &tgt);
+ fsw_strfree(&tgt);
+ }
+ return status;
+ }
+
+ return FSW_UNSUPPORTED;
+}
+
+static int fsw_hfs_btree_find_id(BTreeKey *record, void* param)
+{
+ visitor_parameter_t *vp = (visitor_parameter_t*)param;
+ fsw_u8 *base = (fsw_u8*)record->rawData + be16_to_cpu(record->length16) + 2;
+ fsw_u16 rec_type = be16_to_cpu(*(fsw_u16*)base);
+ struct HFSPlusCatalogKey *cat_key = (HFSPlusCatalogKey*)record;
+ fsw_u16 name_len;
+ fsw_u16 *name_ptr;
+ fsw_u16 *old_ptr;
+ int i;
+ struct fsw_string *file_name;
+ struct fsw_string new_name;
+
+ if (be32_to_cpu(cat_key->parentID) != vp->parent)
+ return -1;
+
+ if (!vp->cur_pos)
+ vp->cur_pos = be32_to_cpu(cat_key->parentID);
+
+ /* Not what we're looking for. */
+ if (vp->file_info.id != vp->cur_pos++)
+ return 0;
+
+ if (rec_type == kHFSPlusFolderThreadRecord || rec_type == kHFSPlusFileThreadRecord)
+ {
+ HFSPlusCatalogThread *thread;
+
+ thread = (HFSPlusCatalogThread *)base;
+ vp->file_info.id = be32_to_cpu(thread->parentID);
+
+ name_len = be16_to_cpu(thread->nodeName.length);
+
+ file_name = vp->file_info.name;
+
+ new_name.len = name_len + 1 + file_name->len;
+ new_name.size = sizeof(fsw_u16) * new_name.len;
+ fsw_alloc(new_name.size, &new_name.data);
+ name_ptr = (fsw_u16*)new_name.data;
+ /* Tack on path separator. */
+#ifdef HOST_POSIX
+ name_ptr[0] = L'/';
+#else
+ name_ptr[0] = L'\\';
+#endif
+ /* Copy over + swap the new path component. */
+ for (i = 0; i < name_len; i++)
+ name_ptr[i + 1] = be16_to_cpu(thread->nodeName.unicode[i]);
+ if (file_name->len) {
+ /* Tack on the previous path. */
+ old_ptr = (fsw_u16*)file_name->data;
+ for (++i; i < new_name.len; i++ )
+ name_ptr[i] = *old_ptr++;
+ }
+
+ fsw_free(file_name->data);
+ file_name->len = new_name.len;
+ file_name->size = new_name.size;
+ file_name->data = new_name.data;
+ file_name->type = FSW_STRING_TYPE_UTF16;
+
+ /* This was it, stop iterating. */
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * Obtain the full path of a file given its CNID (Catalog Node ID), i.e.
+ * file or folder ID.
+ *
+ */
+static fsw_status_t fsw_hfs_get_path_from_cnid(struct fsw_hfs_volume *vol, fsw_u32 cnid, struct fsw_string *path)
+{
+ fsw_status_t status = FSW_UNSUPPORTED;
+ fsw_u32 ptr;
+ BTNodeDescriptor *node = NULL;
+ struct HFSPlusCatalogKey catkey;
+ visitor_parameter_t param;
+ struct fsw_string rec_name;
+
+ /* The CNID must be a valid user node ID. */
+ if (cnid < kHFSFirstUserCatalogNodeID)
+ goto done;
+
+ fsw_memzero(&param, sizeof(param));
+ fsw_memzero(&rec_name, sizeof(rec_name));
+
+ catkey.parentID = cnid;
+ catkey.nodeName.length = 0;
+
+ param.vol = vol;
+ param.shandle = NULL;
+ param.file_info.id = cnid;
+ param.parent = cnid;
+ param.cur_pos = 0;
+
+ do {
+ rec_name.type = FSW_STRING_TYPE_EMPTY;
+ param.file_info.name = &rec_name;
+
+ status = fsw_hfs_btree_search(&vol->catalog_tree, (BTreeKey*)&catkey,
+ vol->case_sensitive ? fsw_hfs_cmp_catkey : fsw_hfs_cmpi_catkey,
+ &node, &ptr);
+ if (status)
+ goto done;
+
+ status = fsw_hfs_btree_iterate_node(&vol->catalog_tree, node, ptr,
+ fsw_hfs_btree_find_id, &param);
+ if (status)
+ goto done;
+
+ param.parent = param.file_info.id;
+ param.cur_pos = 0;
+
+ catkey.parentID = param.file_info.id;
+ catkey.nodeName.length = 0;
+ } while (catkey.parentID >= kHFSFirstUserCatalogNodeID);
+
+ /* If everything worked out , the final parent ID will be the root folder ID. */
+ if (catkey.parentID == kHFSRootFolderID)
+ {
+ *path = *param.file_info.name;
+ status = FSW_SUCCESS;
+ }
+ else
+ status = FSW_NOT_FOUND;
+
+done:
+ return status;
+}
+
+/**
+ * Get the path of the HFS+ blessed file, if any.
+ *
+ */
+/*static*/ fsw_status_t fsw_hfs_get_blessed_file(struct fsw_hfs_volume *vol, struct fsw_string *path)
+{
+ fsw_status_t status = FSW_UNSUPPORTED;
+ fsw_u32 bfile_id;
+ fsw_u32 *finderinfo;
+
+ finderinfo = (fsw_u32 *)&vol->primary_voldesc->finderInfo;
+ bfile_id = finderinfo[1];
+ bfile_id = be32_to_cpu(bfile_id);
+
+ DPRINT2("Blessed file ID: %u\n", bfile_id);
+
+ status = fsw_hfs_get_path_from_cnid(vol, bfile_id, path);
+#ifdef HOST_POSIX
+ if (!status)
+ {
+ fsw_u16 *name_ptr;
+ int i;
+
+ printf("Blessed file: ");
+ name_ptr = (fsw_u16*)path->data;
+ for (i = 0; i < path->len; i++)
+ printf("%c", name_ptr[i]);
+ printf("\n");
+ }
+#endif
+
+ return status;
+}
+
+// EOF
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_hfs.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_hfs.h
new file mode 100644
index 00000000..6283decb
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_hfs.h
@@ -0,0 +1,177 @@
+/* $Id: fsw_hfs.h $ */
+/** @file
+ * fsw_hfs.h - HFS file system driver header.
+ */
+
+/*
+ * Copyright (C) 2010-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+#ifndef _FSW_HFS_H_
+#define _FSW_HFS_H_
+
+#define VOLSTRUCTNAME fsw_hfs_volume
+#define DNODESTRUCTNAME fsw_hfs_dnode
+
+#include "fsw_core.h"
+
+#define IN_RING0
+#if !defined(ARCH_BITS) || !defined(HC_ARCH_BITS)
+# error "please add right bitness"
+#endif
+#include "iprt/formats/hfs.h"
+#include "iprt/asm.h" /* endian conversion */
+
+#ifndef HOST_POSIX
+#include <Library/BaseLib.h>
+#endif
+
+//! Block size for HFS volumes.
+#define HFS_BLOCKSIZE 512
+
+//! Block number where the HFS superblock resides.
+#define HFS_SUPERBLOCK_BLOCKNO 2
+
+#ifdef _MSC_VER
+/* vasily: disable warning for non-standard anonymous struct/union
+ * declarations
+ */
+# pragma warning (disable:4201)
+#endif
+
+struct hfs_dirrec {
+ fsw_u8 _dummy;
+};
+
+#pragma pack(1)
+struct fsw_hfs_key
+{
+ union
+ {
+ struct HFSPlusExtentKey ext_key;
+ struct HFSPlusCatalogKey cat_key;
+ fsw_u16 key_len; /* Length is at the beginning of all keys */
+ };
+};
+#pragma pack()
+
+typedef enum {
+ /* Regular HFS */
+ FSW_HFS_PLAIN = 0,
+ /* HFS+ */
+ FSW_HFS_PLUS,
+ /* HFS+ embedded to HFS */
+ FSW_HFS_PLUS_EMB
+} fsw_hfs_kind;
+
+/**
+ * HFS: Dnode structure with HFS-specific data.
+ */
+struct fsw_hfs_dnode
+{
+ struct fsw_dnode g; //!< Generic dnode structure
+ HFSPlusExtentRecord extents;
+ fsw_u32 ctime;
+ fsw_u32 mtime;
+ fsw_u64 used_bytes;
+ fsw_u32 node_num;
+};
+
+/**
+ * HFS: In-memory B-tree structure.
+ */
+struct fsw_hfs_btree
+{
+ fsw_u32 root_node;
+ fsw_u32 node_size;
+ struct fsw_hfs_dnode* file;
+};
+
+
+/**
+ * HFS: In-memory volume structure with HFS-specific data.
+ */
+
+struct fsw_hfs_volume
+{
+ struct fsw_volume g; //!< Generic volume structure
+
+ struct HFSPlusVolumeHeader *primary_voldesc; //!< Volume Descriptor
+ struct fsw_hfs_btree catalog_tree; // Catalog tree
+ struct fsw_hfs_btree extents_tree; // Extents overflow tree
+ struct fsw_hfs_dnode root_file;
+ int case_sensitive;
+ fsw_u32 block_size_shift;
+ fsw_hfs_kind hfs_kind;
+ fsw_u32 emb_block_off;
+};
+
+/* Endianess swappers. */
+DECLINLINE(fsw_u16)
+be16_to_cpu(fsw_u16 x)
+{
+ return RT_BE2H_U16(x);
+}
+
+DECLINLINE(fsw_u16)
+cpu_to_be16(fsw_u16 x)
+{
+ return RT_H2BE_U16(x);
+}
+
+
+DECLINLINE(fsw_u32)
+cpu_to_be32(fsw_u32 x)
+{
+ return RT_H2BE_U32(x);
+}
+
+DECLINLINE(fsw_u32)
+be32_to_cpu(fsw_u32 x)
+{
+ return RT_BE2H_U32(x);
+}
+
+DECLINLINE(fsw_u64)
+be64_to_cpu(fsw_u64 x)
+{
+#ifdef RT_LITTLE_ENDIAN
+#ifdef HOST_POSIX
+ return RT_BE2H_U64(x);
+#else
+ return SwapBytes64(x);
+#endif
+#else
+ return x;
+#endif
+}
+
+#endif
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_iso9660.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_iso9660.c
new file mode 100644
index 00000000..952eb1be
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_iso9660.c
@@ -0,0 +1,679 @@
+/* $Id: fsw_iso9660.c $ */
+/** @file
+ * fsw_iso9660.c - ISO9660 file system driver code.
+ *
+ * Current limitations:
+ * - Files must be in one extent (i.e. Level 2)
+ * - No Joliet or Rock Ridge extensions
+ * - No interleaving
+ * - inode number generation strategy fails on volumes > 2 GB
+ * - No blocksizes != 2048
+ * - No High Sierra or anything else != 'CD001'
+ * - No volume sets with directories pointing at other volumes
+ * - No extended attribute records
+ */
+
+/*
+ * Copyright (C) 2010-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ * ---------------------------------------------------------------------------
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_iso9660.h"
+
+
+// functions
+
+static fsw_status_t fsw_iso9660_volume_mount(struct fsw_iso9660_volume *vol);
+static void fsw_iso9660_volume_free(struct fsw_iso9660_volume *vol);
+static fsw_status_t fsw_iso9660_volume_stat(struct fsw_iso9660_volume *vol, struct fsw_volume_stat *sb);
+
+static fsw_status_t fsw_iso9660_dnode_fill(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno);
+static void fsw_iso9660_dnode_free(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno);
+static fsw_status_t fsw_iso9660_dnode_stat(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+ struct fsw_dnode_stat *sb);
+static fsw_status_t fsw_iso9660_get_extent(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+ struct fsw_extent *extent);
+
+static fsw_status_t fsw_iso9660_dir_lookup(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+ struct fsw_string *lookup_name, struct fsw_iso9660_dnode **child_dno);
+static fsw_status_t fsw_iso9660_dir_read(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+ struct fsw_shandle *shand, struct fsw_iso9660_dnode **child_dno);
+static fsw_status_t fsw_iso9660_read_dirrec(struct fsw_iso9660_volume *vol, struct fsw_shandle *shand, struct iso9660_dirrec_buffer *dirrec_buffer);
+
+static fsw_status_t fsw_iso9660_readlink(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+ struct fsw_string *link);
+
+static fsw_status_t rr_find_sp(struct iso9660_dirrec *dirrec, struct fsw_rock_ridge_susp_sp **psp);
+static fsw_status_t rr_find_nm(struct fsw_iso9660_volume *vol, struct iso9660_dirrec *dirrec, int off, struct fsw_string *str);
+static fsw_status_t rr_read_ce(struct fsw_iso9660_volume *vol, union fsw_rock_ridge_susp_ce *ce, fsw_u8 *begin);
+//
+// Dispatch Table
+//
+
+struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(iso9660) = {
+ { FSW_STRING_TYPE_ISO88591, 4, 4, "iso9660" },
+ sizeof(struct fsw_iso9660_volume),
+ sizeof(struct fsw_iso9660_dnode),
+
+ fsw_iso9660_volume_mount,
+ fsw_iso9660_volume_free,
+ fsw_iso9660_volume_stat,
+ fsw_iso9660_dnode_fill,
+ fsw_iso9660_dnode_free,
+ fsw_iso9660_dnode_stat,
+ fsw_iso9660_get_extent,
+ fsw_iso9660_dir_lookup,
+ fsw_iso9660_dir_read,
+ fsw_iso9660_readlink,
+};
+
+static fsw_status_t rr_find_sp(struct iso9660_dirrec *dirrec, struct fsw_rock_ridge_susp_sp **psp)
+{
+ fsw_u8 *r;
+ int off = 0;
+ struct fsw_rock_ridge_susp_sp *sp;
+ r = (fsw_u8 *)((fsw_u8 *)dirrec + sizeof(*dirrec) + dirrec->file_identifier_length);
+ off = (int)(r - (fsw_u8 *)dirrec);
+ while(off < dirrec->dirrec_length)
+ {
+ if (*r == 'S')
+ {
+ sp = (struct fsw_rock_ridge_susp_sp *)r;
+ if( sp->e.sig[0] == 'S'
+ && sp->e.sig[1] == 'P'
+ && sp->magic[0] == 0xbe
+ && sp->magic[1] == 0xef)
+ {
+ *psp = sp;
+ return FSW_SUCCESS;
+ }
+ }
+ r++;
+ off = (int)(r - (fsw_u8 *)dirrec);
+ }
+ *psp = NULL;
+ return FSW_NOT_FOUND;
+}
+
+static fsw_status_t rr_find_nm(struct fsw_iso9660_volume *vol, struct iso9660_dirrec *dirrec, int off, struct fsw_string *str)
+{
+ fsw_u8 *r, *begin;
+ int fCe = 0;
+ struct fsw_rock_ridge_susp_nm *nm;
+ int limit = dirrec->dirrec_length;
+ begin = (fsw_u8 *)dirrec;
+ r = (fsw_u8 *)dirrec + off;
+ str->data = NULL;
+ str->len = 0;
+ str->size = 0;
+ str->type = 0;
+ while(off < limit)
+ {
+ if (r[0] == 'C' && r[1] == 'E' && r[2] == 28)
+ {
+ int rc;
+ int ce_off;
+ union fsw_rock_ridge_susp_ce *ce;
+ if (fCe == 0)
+ fsw_alloc_zero(ISO9660_BLOCKSIZE, (void *)&begin);
+ fCe = 1;
+ DEBUG((DEBUG_WARN, "%a:%d we found CE before NM or its continuation\n", __FILE__, __LINE__));
+ ce = (union fsw_rock_ridge_susp_ce *)r;
+ limit = ISOINT(ce->X.len);
+ ce_off = ISOINT(ce->X.offset);
+ rc = rr_read_ce(vol, ce, begin);
+ if (rc != FSW_SUCCESS)
+ {
+ fsw_free(begin);
+ return rc;
+ }
+ begin += ce_off;
+ r = begin;
+ }
+ if (r[0] == 'N' && r[1] == 'M')
+ {
+ nm = (struct fsw_rock_ridge_susp_nm *)r;
+ if( nm->e.sig[0] == 'N'
+ && nm->e.sig[1] == 'M')
+ {
+ int len = 0;
+ fsw_u8 *tmp = NULL;
+ if (nm->flags & RR_NM_CURR)
+ {
+ fsw_memdup(str->data, ".", 1);
+ str->len = 1;
+ goto done;
+ }
+ if (nm->flags & RR_NM_PARE)
+ {
+ fsw_memdup(str->data, "..", 2);
+ str->len = 2;
+ goto done;
+ }
+ len = nm->e.len - sizeof(struct fsw_rock_ridge_susp_nm) + 1;
+ fsw_alloc_zero(str->len + len, (void **)&tmp);
+ if (str->data != NULL)
+ {
+ fsw_memcpy(tmp, str->data, str->len);
+ fsw_free(str->data);
+ }
+ DEBUG((DEBUG_INFO, "dst:%p src:%p len:%d\n", tmp + str->len, &nm->name[0], len));
+ fsw_memcpy(tmp + str->len, &nm->name[0], len);
+ str->data = tmp;
+ str->len += len;
+
+ if ((nm->flags & RR_NM_CONT) == 0)
+ goto done;
+ }
+ }
+ r++;
+ off = (int)(r - (fsw_u8 *)begin);
+ }
+ if(fCe == 1)
+ fsw_free(begin);
+ return FSW_NOT_FOUND;
+done:
+ str->type = FSW_STRING_TYPE_ISO88591;
+ str->size = str->len;
+ if(fCe == 1)
+ fsw_free(begin);
+ return FSW_SUCCESS;
+}
+
+static fsw_status_t rr_read_ce(struct fsw_iso9660_volume *vol, union fsw_rock_ridge_susp_ce *ce, fsw_u8 *begin)
+{
+ int rc;
+ rc = vol->g.host_table->read_block(&vol->g, ISOINT(ce->X.block_loc), begin);
+ if (rc != FSW_SUCCESS)
+ return rc;
+ return FSW_SUCCESS;
+}
+/**
+ * Mount an ISO9660 volume. Reads the superblock and constructs the
+ * root directory dnode.
+ */
+
+static fsw_status_t fsw_iso9660_volume_mount(struct fsw_iso9660_volume *vol)
+{
+ fsw_status_t status;
+ void *buffer;
+ fsw_u32 blockno;
+ struct iso9660_volume_descriptor *voldesc;
+ struct iso9660_primary_volume_descriptor *pvoldesc;
+ fsw_u32 voldesc_type;
+ int i;
+ struct fsw_string s;
+ struct iso9660_dirrec rootdir;
+ int sua_pos;
+ char *sig;
+ int skip;
+ struct fsw_rock_ridge_susp_entry *entry;
+
+ // read through the Volume Descriptor Set
+ fsw_set_blocksize(vol, ISO9660_BLOCKSIZE, ISO9660_BLOCKSIZE);
+ blockno = ISO9660_SUPERBLOCK_BLOCKNO;
+
+ do {
+ status = fsw_block_get(vol, blockno, 0, &buffer);
+ if (status)
+ return status;
+
+ voldesc = (struct iso9660_volume_descriptor *)buffer;
+ voldesc_type = voldesc->volume_descriptor_type;
+ if (fsw_memeq(voldesc->standard_identifier, "CD001", 5)) {
+ // descriptor follows ISO 9660 standard
+ if (voldesc_type == 1 && voldesc->volume_descriptor_version == 1) {
+ // suitable Primary Volume Descriptor found
+ if (vol->primary_voldesc) {
+ fsw_free(vol->primary_voldesc);
+ vol->primary_voldesc = NULL;
+ }
+ status = fsw_memdup((void **)&vol->primary_voldesc, voldesc, ISO9660_BLOCKSIZE);
+ }
+ } else if (!fsw_memeq(voldesc->standard_identifier, "CD", 2)) {
+ // completely alien standard identifier, stop reading
+ voldesc_type = 255;
+ }
+
+ fsw_block_release(vol, blockno, buffer);
+ blockno++;
+ } while (!status && voldesc_type != 255);
+ if (status)
+ return status;
+
+ // get information from Primary Volume Descriptor
+ if (vol->primary_voldesc == NULL)
+ return FSW_UNSUPPORTED;
+ pvoldesc = vol->primary_voldesc;
+ if (ISOINT(pvoldesc->logical_block_size) != 2048)
+ return FSW_UNSUPPORTED;
+
+ // get volume name
+ for (i = 32; i > 0; i--)
+ if (pvoldesc->volume_identifier[i-1] != ' ')
+ break;
+ s.type = FSW_STRING_TYPE_ISO88591;
+ s.size = s.len = i;
+ s.data = pvoldesc->volume_identifier;
+ status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s);
+ if (status)
+ return status;
+
+ // setup the root dnode
+ status = fsw_dnode_create_root(vol, ISO9660_SUPERBLOCK_BLOCKNO << ISO9660_BLOCKSIZE_BITS, &vol->g.root);
+ if (status)
+ return status;
+ fsw_memcpy(&vol->g.root->dirrec, &pvoldesc->root_directory, sizeof(struct iso9660_dirrec));
+
+ if ( pvoldesc->escape[0] == 0x25
+ && pvoldesc->escape[1] == 0x2f
+ && ( pvoldesc->escape[2] == 0x40
+ || pvoldesc->escape[2] == 0x43
+ || pvoldesc->escape[2] == 0x45))
+ {
+ FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success (joliet!!!)\n")));
+ vol->fJoliet = 1;
+ }
+
+
+ fsw_memcpy(&rootdir, &pvoldesc->root_directory, sizeof(rootdir));
+ sua_pos = (sizeof(struct iso9660_dirrec)) + rootdir.file_identifier_length + (rootdir.file_identifier_length % 2) - 2;
+ //int sua_size = rootdir.dirrec_length - rootdir.file_identifier_length;
+ //FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success (SUA(pos:%x, sz:%d)!!!)\n"), sua_pos, sua_size));
+
+#if 1
+ status = fsw_block_get(vol, ISOINT(rootdir.extent_location), 0, &buffer);
+ sig = (char *)buffer + sua_pos;
+ skip = 0;
+ entry = (struct fsw_rock_ridge_susp_entry *)sig;
+ if ( entry->sig[0] == 'S'
+ && entry->sig[1] == 'P')
+ {
+ struct fsw_rock_ridge_susp_sp *sp = (struct fsw_rock_ridge_susp_sp *)entry;
+ if (sp->magic[0] == 0xbe && sp->magic[1] == 0xef)
+ {
+ vol->fRockRidge = 1;
+ } else {
+ FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: SP magic isn't valid\n")));
+ }
+ skip = sp->skip;
+ }
+#endif
+ // release volume descriptors
+ fsw_free(vol->primary_voldesc);
+ vol->primary_voldesc = NULL;
+
+
+ FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success\n")));
+
+ return FSW_SUCCESS;
+}
+
+/**
+ * Free the volume data structure. Called by the core after an unmount or after
+ * an unsuccessful mount to release the memory used by the file system type specific
+ * part of the volume structure.
+ */
+
+static void fsw_iso9660_volume_free(struct fsw_iso9660_volume *vol)
+{
+ if (vol->primary_voldesc)
+ fsw_free(vol->primary_voldesc);
+}
+
+/**
+ * Get in-depth information on a volume.
+ */
+
+static fsw_status_t fsw_iso9660_volume_stat(struct fsw_iso9660_volume *vol, struct fsw_volume_stat *sb)
+{
+ sb->total_bytes = 0; //(fsw_u64)vol->sb->s_blocks_count * vol->g.log_blocksize;
+ sb->free_bytes = 0;
+ return FSW_SUCCESS;
+}
+
+/**
+ * Get full information on a dnode from disk. This function is called by the core
+ * whenever it needs to access fields in the dnode structure that may not
+ * be filled immediately upon creation of the dnode. In the case of iso9660, we
+ * delay fetching of the inode structure until dnode_fill is called. The size and
+ * type fields are invalid until this function has been called.
+ */
+
+static fsw_status_t fsw_iso9660_dnode_fill(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno)
+{
+ // get info from the directory record
+ dno->g.size = ISOINT(dno->dirrec.data_length);
+ if (dno->dirrec.file_flags & 0x02)
+ dno->g.type = FSW_DNODE_TYPE_DIR;
+ else
+ dno->g.type = FSW_DNODE_TYPE_FILE;
+
+ return FSW_SUCCESS;
+}
+
+/**
+ * Free the dnode data structure. Called by the core when deallocating a dnode
+ * structure to release the memory used by the file system type specific part
+ * of the dnode structure.
+ */
+
+static void fsw_iso9660_dnode_free(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno)
+{
+}
+
+/**
+ * Get in-depth information on a dnode. The core makes sure that fsw_iso9660_dnode_fill
+ * has been called on the dnode before this function is called. Note that some
+ * data is not directly stored into the structure, but passed to a host-specific
+ * callback that converts it to the host-specific format.
+ */
+
+static fsw_status_t fsw_iso9660_dnode_stat(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+ struct fsw_dnode_stat *sb)
+{
+ sb->used_bytes = (dno->g.size + (ISO9660_BLOCKSIZE-1)) & ~(ISO9660_BLOCKSIZE-1);
+ /*
+ sb->store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->raw->i_ctime);
+ sb->store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->raw->i_atime);
+ sb->store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->raw->i_mtime);
+ sb->store_attr_posix(sb, dno->raw->i_mode);
+ */
+
+ return FSW_SUCCESS;
+}
+
+/**
+ * Retrieve file data mapping information. This function is called by the core when
+ * fsw_shandle_read needs to know where on the disk the required piece of the file's
+ * data can be found. The core makes sure that fsw_iso9660_dnode_fill has been called
+ * on the dnode before. Our task here is to get the physical disk block number for
+ * the requested logical block number.
+ */
+
+static fsw_status_t fsw_iso9660_get_extent(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+ struct fsw_extent *extent)
+{
+ // Preconditions: The caller has checked that the requested logical block
+ // is within the file's size. The dnode has complete information, i.e.
+ // fsw_iso9660_dnode_read_info was called successfully on it.
+
+ extent->type = FSW_EXTENT_TYPE_PHYSBLOCK;
+ extent->phys_start = ISOINT(dno->dirrec.extent_location);
+ extent->log_start = 0;
+ extent->log_count = (ISOINT(dno->dirrec.data_length) + (ISO9660_BLOCKSIZE-1)) >> ISO9660_BLOCKSIZE_BITS;
+ return FSW_SUCCESS;
+}
+
+/**
+ * Lookup a directory's child dnode by name. This function is called on a directory
+ * to retrieve the directory entry with the given name. A dnode is constructed for
+ * this entry and returned. The core makes sure that fsw_iso9660_dnode_fill has been called
+ * and the dnode is actually a directory.
+ */
+
+static fsw_status_t fsw_iso9660_dir_lookup(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+ struct fsw_string *lookup_name, struct fsw_iso9660_dnode **child_dno_out)
+{
+ fsw_status_t status;
+ struct fsw_shandle shand;
+ struct iso9660_dirrec_buffer dirrec_buffer;
+ struct iso9660_dirrec *dirrec = &dirrec_buffer.dirrec;
+
+ // Preconditions: The caller has checked that dno is a directory node.
+
+ // setup handle to read the directory
+ status = fsw_shandle_open(dno, &shand);
+ if (status)
+ return status;
+
+ // scan the directory for the file
+ while (1) {
+ // read next entry
+ status = fsw_iso9660_read_dirrec(vol, &shand, &dirrec_buffer);
+ if (status)
+ goto errorexit;
+ if (dirrec->dirrec_length == 0) {
+ // end of directory reached
+ status = FSW_NOT_FOUND;
+ goto errorexit;
+ }
+
+ // skip . and ..
+ if (dirrec->file_identifier_length == 1 &&
+ (dirrec->file_identifier[0] == 0 || dirrec->file_identifier[0] == 1))
+ continue;
+
+ // compare name
+ if (fsw_streq(lookup_name, &dirrec_buffer.name)) /// @todo compare case-insensitively
+ break;
+ }
+
+ // setup a dnode for the child item
+ status = fsw_dnode_create(dno, dirrec_buffer.ino, FSW_DNODE_TYPE_UNKNOWN, &dirrec_buffer.name, child_dno_out);
+ if (status == FSW_SUCCESS)
+ fsw_memcpy(&(*child_dno_out)->dirrec, dirrec, sizeof(struct iso9660_dirrec));
+
+errorexit:
+ fsw_shandle_close(&shand);
+ return status;
+}
+
+/**
+ * Get the next directory entry when reading a directory. This function is called during
+ * directory iteration to retrieve the next directory entry. A dnode is constructed for
+ * the entry and returned. The core makes sure that fsw_iso9660_dnode_fill has been called
+ * and the dnode is actually a directory. The shandle provided by the caller is used to
+ * record the position in the directory between calls.
+ */
+
+static fsw_status_t fsw_iso9660_dir_read(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+ struct fsw_shandle *shand, struct fsw_iso9660_dnode **child_dno_out)
+{
+ fsw_status_t status;
+ struct iso9660_dirrec_buffer dirrec_buffer;
+ struct iso9660_dirrec *dirrec = &dirrec_buffer.dirrec;
+
+ // Preconditions: The caller has checked that dno is a directory node. The caller
+ // has opened a storage handle to the directory's storage and keeps it around between
+ // calls.
+ /* (vasily) directory nodes are 4096 bytes that is two logical blocks so read dir operation
+ * should read both blocks.
+ */
+
+ while (1) {
+ // read next entry
+ if (shand->pos >= dno->g.size)
+ return FSW_NOT_FOUND; // end of directory
+ status = fsw_iso9660_read_dirrec(vol, shand, &dirrec_buffer);
+ if (status)
+ return status;
+ if (dirrec->dirrec_length == 0)
+ {
+ // try the next block
+ shand->pos =(shand->pos & ~(vol->g.log_blocksize - 1)) + vol->g.log_blocksize;
+ continue;
+ }
+
+ // skip . and ..
+ if (dirrec->file_identifier_length == 1 &&
+ (dirrec->file_identifier[0] == 0 || dirrec->file_identifier[0] == 1))
+ continue;
+ break;
+ }
+
+ // setup a dnode for the child item
+ status = fsw_dnode_create(dno, dirrec_buffer.ino, FSW_DNODE_TYPE_UNKNOWN, &dirrec_buffer.name, child_dno_out);
+ if (status == FSW_SUCCESS)
+ fsw_memcpy(&(*child_dno_out)->dirrec, dirrec, sizeof(struct iso9660_dirrec));
+
+ return status;
+}
+
+/**
+ * Read a directory entry from the directory's raw data. This internal function is used
+ * to read a raw iso9660 directory entry into memory. The shandle's position pointer is adjusted
+ * to point to the next entry.
+ */
+
+static fsw_status_t fsw_iso9660_read_dirrec(struct fsw_iso9660_volume *vol, struct fsw_shandle *shand, struct iso9660_dirrec_buffer *dirrec_buffer)
+{
+ fsw_status_t status;
+ fsw_u32 i, buffer_size, remaining_size, name_len;
+ struct fsw_rock_ridge_susp_sp *sp = NULL;
+ struct iso9660_dirrec *dirrec = &dirrec_buffer->dirrec;
+ int rc;
+
+ dirrec_buffer->ino = (ISOINT(((struct fsw_iso9660_dnode *)shand->dnode)->dirrec.extent_location)
+ << ISO9660_BLOCKSIZE_BITS)
+ + (fsw_u32)shand->pos;
+
+ // read fixed size part of directory record
+ buffer_size = 33;
+ status = fsw_shandle_read(shand, &buffer_size, dirrec);
+ if (status)
+ {
+ DEBUG((DEBUG_INFO, "%a:%d \n", __FILE__, __LINE__));
+ return status;
+ }
+
+ if (buffer_size < 33 || dirrec->dirrec_length == 0) {
+ // end of directory reached
+ fsw_u8 *r;
+ r = (fsw_u8 *)dirrec;
+ DEBUG((DEBUG_INFO, "%a:%d bs:%d dl:%d\n", __FILE__, __LINE__, buffer_size, dirrec->dirrec_length));
+ for(i = 0; i < buffer_size; ++i)
+ {
+ DEBUG((DEBUG_INFO, "r[%d]:%c", i, r[i]));
+ }
+ dirrec->dirrec_length = 0;
+ return FSW_SUCCESS;
+ }
+ if (dirrec->dirrec_length < 33 ||
+ dirrec->dirrec_length < 33 + dirrec->file_identifier_length)
+ return FSW_VOLUME_CORRUPTED;
+
+ DEBUG((DEBUG_INFO, "%a:%d, dirrec_length: %d\n", __FILE__, __LINE__, dirrec->dirrec_length));
+
+ // read variable size part of directory record
+ buffer_size = remaining_size = dirrec->dirrec_length - 33;
+ status = fsw_shandle_read(shand, &buffer_size, dirrec->file_identifier);
+ if (status)
+ return status;
+ if (buffer_size < remaining_size)
+ return FSW_VOLUME_CORRUPTED;
+
+ if (vol->fRockRidge)
+ {
+ UINTN sp_off = sizeof(*dirrec) + dirrec->file_identifier_length;
+ rc = rr_find_sp(dirrec, &sp);
+ if ( rc == FSW_SUCCESS
+ && sp != NULL)
+ {
+ sp_off = (fsw_u8 *)&sp[1] - (fsw_u8 *)dirrec + sp->skip;
+ }
+ rc = rr_find_nm(vol, dirrec, (int)sp_off, &dirrec_buffer->name);
+ if (rc == FSW_SUCCESS)
+ return FSW_SUCCESS;
+ }
+
+ // setup name
+ name_len = dirrec->file_identifier_length;
+ for (i = name_len - 1; i > 0; i--) {
+ if (dirrec->file_identifier[i] == ';') {
+ name_len = i; // cut the ISO9660 version number off
+ break;
+ }
+ }
+ if (name_len > 0 && dirrec->file_identifier[name_len-1] == '.')
+ name_len--; // also cut the extension separator if the extension is empty
+ dirrec_buffer->name.type = FSW_STRING_TYPE_ISO88591;
+ dirrec_buffer->name.len = dirrec_buffer->name.size = name_len;
+ dirrec_buffer->name.data = dirrec->file_identifier;
+ DEBUG((DEBUG_INFO, "%a:%d: dirrec_buffer->name.data:%a\n", __FILE__, __LINE__, dirrec_buffer->name.data));
+ return FSW_SUCCESS;
+}
+
+/**
+ * Get the target path of a symbolic link. This function is called when a symbolic
+ * link needs to be resolved. The core makes sure that the fsw_iso9660_dnode_fill has been
+ * called on the dnode and that it really is a symlink.
+ *
+ * For iso9660, the target path can be stored inline in the inode structure (in the space
+ * otherwise occupied by the block pointers) or in the inode's data. There is no flag
+ * indicating this, only the number of blocks entry (i_blocks) can be used as an
+ * indication. The check used here comes from the Linux kernel.
+ */
+
+static fsw_status_t fsw_iso9660_readlink(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+ struct fsw_string *link_target)
+{
+ fsw_status_t status;
+
+ if (dno->g.size > FSW_PATH_MAX)
+ return FSW_VOLUME_CORRUPTED;
+
+ status = fsw_dnode_readlink_data(dno, link_target);
+
+ return status;
+}
+
+// EOF
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_iso9660.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_iso9660.h
new file mode 100644
index 00000000..371d537d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_iso9660.h
@@ -0,0 +1,235 @@
+/* $Id: fsw_iso9660.h $ */
+/** @file
+ * fsw_iso9660.h - ISO9660 file system driver header.
+ */
+
+/*
+ * Copyright (C) 2010-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ * ---------------------------------------------------------------------------
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_ISO9660_H_
+#define _FSW_ISO9660_H_
+
+#define VOLSTRUCTNAME fsw_iso9660_volume
+#define DNODESTRUCTNAME fsw_iso9660_dnode
+#include "fsw_core.h"
+
+
+//! Block size for ISO9660 volumes.
+#define ISO9660_BLOCKSIZE 2048
+#define ISO9660_BLOCKSIZE_BITS 11
+//! Block number where the ISO9660 superblock resides.
+#define ISO9660_SUPERBLOCK_BLOCKNO 16
+
+
+#pragma pack(1)
+
+typedef struct {
+ fsw_u16 lsb;
+ fsw_u16 msb;
+} iso9660_u16;
+
+typedef struct {
+ fsw_u32 lsb;
+ fsw_u32 msb;
+} iso9660_u32;
+
+#define ISOINT(lsbmsbvalue) ((lsbmsbvalue).lsb)
+
+struct iso9660_dirrec {
+ fsw_u8 dirrec_length;
+ fsw_u8 ear_length;
+ iso9660_u32 extent_location;
+ iso9660_u32 data_length;
+ fsw_u8 recording_datetime[7];
+ fsw_u8 file_flags;
+ fsw_u8 file_unit_size;
+ fsw_u8 interleave_gap_size;
+ iso9660_u16 volume_sequence_number;
+ fsw_u8 file_identifier_length;
+ char file_identifier[1];
+};
+//#if sizeof(struct fsw_iso9660_dirrec) != 34
+//#fail Structure fsw_iso9660_dirrec has wrong size
+//#endif
+
+struct iso9660_volume_descriptor {
+ fsw_u8 volume_descriptor_type;
+ char standard_identifier[5];
+ fsw_u8 volume_descriptor_version;
+};
+
+struct iso9660_primary_volume_descriptor {
+ fsw_u8 volume_descriptor_type;
+ char standard_identifier[5];
+ fsw_u8 volume_descriptor_version;
+ fsw_u8 unused1;
+ char system_identifier[32];
+ char volume_identifier[32];
+ fsw_u8 unused2[8];
+ iso9660_u32 volume_space_size;
+ fsw_u8 unused3[4];
+ fsw_u8 escape[3];
+ fsw_u8 unused4[25];
+ iso9660_u16 volume_set_size;
+ iso9660_u16 volume_sequence_number;
+ iso9660_u16 logical_block_size;
+ iso9660_u32 path_table_size;
+ fsw_u32 location_type_l_path_table;
+ fsw_u32 location_optional_type_l_path_table;
+ fsw_u32 location_type_m_path_table;
+ fsw_u32 location_optional_type_m_path_table;
+ struct iso9660_dirrec root_directory;
+ char volume_set_identifier[128];
+ char publisher_identifier[128];
+ char data_preparer_identifier[128];
+ char application_identifier[128];
+ char copyright_file_identifier[37];
+ char abstract_file_identifier[37];
+ char bibliographic_file_identifier[37];
+ char volume_creation_datetime[17];
+ char volume_modification_datetime[17];
+ char volume_expiration_datetime[17];
+ char volume_effective_datetime[17];
+ fsw_u8 file_structure_version;
+ fsw_u8 reserved1;
+ fsw_u8 application_use[512];
+ fsw_u8 reserved2[653];
+};
+//#if sizeof(struct fsw_iso9660_volume_descriptor) != 2048
+//#fail Structure fsw_iso9660_volume_descriptor has wrong size
+//#endif
+
+#pragma pack()
+
+struct iso9660_dirrec_buffer {
+ fsw_u32 ino;
+ struct fsw_string name;
+ struct iso9660_dirrec dirrec;
+ char dirrec_buffer[222];
+};
+
+
+/**
+ * ISO9660: Volume structure with ISO9660-specific data.
+ */
+
+struct fsw_iso9660_volume {
+ struct fsw_volume g; //!< Generic volume structure
+ /*Note: don't move g!*/
+ int fJoliet;
+ /*Joliet specific fields*/
+ int fRockRidge;
+ /*Rock Ridge specific fields*/
+ int rr_susp_skip;
+
+ struct iso9660_primary_volume_descriptor *primary_voldesc; //!< Full Primary Volume Descriptor
+};
+
+/**
+ * ISO9660: Dnode structure with ISO9660-specific data.
+ */
+
+struct fsw_iso9660_dnode {
+ struct fsw_dnode g; //!< Generic dnode structure
+
+ struct iso9660_dirrec dirrec; //!< Fixed part of the directory record (i.e. w/o name)
+};
+
+
+struct fsw_rock_ridge_susp_entry
+{
+ fsw_u8 sig[2];
+ fsw_u8 len;
+ fsw_u8 ver;
+};
+
+struct fsw_rock_ridge_susp_sp
+{
+ struct fsw_rock_ridge_susp_entry e;
+ fsw_u8 magic[2];
+ fsw_u8 skip;
+};
+
+struct fsw_rock_ridge_susp_nm
+{
+ struct fsw_rock_ridge_susp_entry e;
+ fsw_u8 flags;
+ fsw_u8 name[1];
+};
+
+#define RR_NM_CONT (1<<0)
+#define RR_NM_CURR (1<<1)
+#define RR_NM_PARE (1<<2)
+
+union fsw_rock_ridge_susp_ce
+{
+ struct X{
+ struct fsw_rock_ridge_susp_entry e;
+ iso9660_u32 block_loc;
+ iso9660_u32 offset;
+ iso9660_u32 len;
+ } X;
+ fsw_u8 raw[28];
+};
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_lib.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_lib.c
new file mode 100644
index 00000000..f29e5dd5
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_lib.c
@@ -0,0 +1,564 @@
+/* $Id: fsw_lib.c $ */
+/** @file
+ * fsw_lib.c - Core file system wrapper library functions.
+ */
+
+/*
+ * Copyright (C) 2010-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ * ---------------------------------------------------------------------------
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_core.h"
+
+/* Include generated string encoding specific functions */
+#include "fsw_strfunc.h"
+
+
+/**
+ * Allocate memory and clear it.
+ */
+
+fsw_status_t fsw_alloc_zero(int len, void **ptr_out)
+{
+ fsw_status_t status;
+
+ status = fsw_alloc(len, ptr_out);
+ if (status)
+ return status;
+ fsw_memzero(*ptr_out, len);
+ return FSW_SUCCESS;
+}
+
+/**
+ * Duplicate a piece of data.
+ */
+
+fsw_status_t fsw_memdup(void **dest_out, void *src, int len)
+{
+ fsw_status_t status;
+
+ status = fsw_alloc(len, dest_out);
+ if (status)
+ return status;
+ fsw_memcpy(*dest_out, src, len);
+ return FSW_SUCCESS;
+}
+
+/**
+ * Get the length of a string. Returns the number of characters in the string.
+ */
+
+int fsw_strlen(struct fsw_string *s)
+{
+ if (s->type == FSW_STRING_TYPE_EMPTY)
+ return 0;
+ return s->len;
+}
+
+#if 0
+static const fsw_u16
+fsw_lower_case_table[] =
+{
+
+ /* High-byte indices ( == 0 iff no case mapping and no ignorables ) */
+
+ /* 0 */ 0x0000, 0x0100, 0x0000, 0x0200, 0x0300, 0x0400, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* 1 */ 0x0500, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* 2 */ 0x0600, 0x0700, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* 3 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* 4 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* 5 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* 6 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* 7 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* 8 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* 9 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* A */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* B */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* C */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* D */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* E */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* F */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0800, 0x0900,
+
+ /* Table 1 (for high byte 0x01) */
+
+ /* 0 */ 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106, 0x0107, 0x0108, 0x0109, 0x010A, 0x010B, 0x010C, 0x010D, 0x010E, 0x010F,
+ /* 1 */ 0x0111, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116, 0x0117, 0x0118, 0x0119, 0x011A, 0x011B, 0x011C, 0x011D, 0x011E, 0x011F,
+ /* 2 */ 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0127, 0x0127, 0x0128, 0x0129, 0x012A, 0x012B, 0x012C, 0x012D, 0x012E, 0x012F,
+ /* 3 */ 0x0130, 0x0131, 0x0133, 0x0133, 0x0134, 0x0135, 0x0136, 0x0137, 0x0138, 0x0139, 0x013A, 0x013B, 0x013C, 0x013D, 0x013E, 0x0140,
+ /* 4 */ 0x0140, 0x0142, 0x0142, 0x0143, 0x0144, 0x0145, 0x0146, 0x0147, 0x0148, 0x0149, 0x014B, 0x014B, 0x014C, 0x014D, 0x014E, 0x014F,
+ /* 5 */ 0x0150, 0x0151, 0x0153, 0x0153, 0x0154, 0x0155, 0x0156, 0x0157, 0x0158, 0x0159, 0x015A, 0x015B, 0x015C, 0x015D, 0x015E, 0x015F,
+ /* 6 */ 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165, 0x0167, 0x0167, 0x0168, 0x0169, 0x016A, 0x016B, 0x016C, 0x016D, 0x016E, 0x016F,
+ /* 7 */ 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175, 0x0176, 0x0177, 0x0178, 0x0179, 0x017A, 0x017B, 0x017C, 0x017D, 0x017E, 0x017F,
+ /* 8 */ 0x0180, 0x0253, 0x0183, 0x0183, 0x0185, 0x0185, 0x0254, 0x0188, 0x0188, 0x0256, 0x0257, 0x018C, 0x018C, 0x018D, 0x01DD, 0x0259,
+ /* 9 */ 0x025B, 0x0192, 0x0192, 0x0260, 0x0263, 0x0195, 0x0269, 0x0268, 0x0199, 0x0199, 0x019A, 0x019B, 0x026F, 0x0272, 0x019E, 0x0275,
+ /* A */ 0x01A0, 0x01A1, 0x01A3, 0x01A3, 0x01A5, 0x01A5, 0x01A6, 0x01A8, 0x01A8, 0x0283, 0x01AA, 0x01AB, 0x01AD, 0x01AD, 0x0288, 0x01AF,
+ /* B */ 0x01B0, 0x028A, 0x028B, 0x01B4, 0x01B4, 0x01B6, 0x01B6, 0x0292, 0x01B9, 0x01B9, 0x01BA, 0x01BB, 0x01BD, 0x01BD, 0x01BE, 0x01BF,
+ /* C */ 0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C6, 0x01C6, 0x01C6, 0x01C9, 0x01C9, 0x01C9, 0x01CC, 0x01CC, 0x01CC, 0x01CD, 0x01CE, 0x01CF,
+ /* D */ 0x01D0, 0x01D1, 0x01D2, 0x01D3, 0x01D4, 0x01D5, 0x01D6, 0x01D7, 0x01D8, 0x01D9, 0x01DA, 0x01DB, 0x01DC, 0x01DD, 0x01DE, 0x01DF,
+ /* E */ 0x01E0, 0x01E1, 0x01E2, 0x01E3, 0x01E5, 0x01E5, 0x01E6, 0x01E7, 0x01E8, 0x01E9, 0x01EA, 0x01EB, 0x01EC, 0x01ED, 0x01EE, 0x01EF,
+ /* F */ 0x01F0, 0x01F3, 0x01F3, 0x01F3, 0x01F4, 0x01F5, 0x01F6, 0x01F7, 0x01F8, 0x01F9, 0x01FA, 0x01FB, 0x01FC, 0x01FD, 0x01FE, 0x01FF,
+
+ /* Table 2 (for high byte 0x03) */
+
+ /* 0 */ 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, 0x0308, 0x0309, 0x030A, 0x030B, 0x030C, 0x030D, 0x030E, 0x030F,
+ /* 1 */ 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317, 0x0318, 0x0319, 0x031A, 0x031B, 0x031C, 0x031D, 0x031E, 0x031F,
+ /* 2 */ 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327, 0x0328, 0x0329, 0x032A, 0x032B, 0x032C, 0x032D, 0x032E, 0x032F,
+ /* 3 */ 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337, 0x0338, 0x0339, 0x033A, 0x033B, 0x033C, 0x033D, 0x033E, 0x033F,
+ /* 4 */ 0x0340, 0x0341, 0x0342, 0x0343, 0x0344, 0x0345, 0x0346, 0x0347, 0x0348, 0x0349, 0x034A, 0x034B, 0x034C, 0x034D, 0x034E, 0x034F,
+ /* 5 */ 0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357, 0x0358, 0x0359, 0x035A, 0x035B, 0x035C, 0x035D, 0x035E, 0x035F,
+ /* 6 */ 0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367, 0x0368, 0x0369, 0x036A, 0x036B, 0x036C, 0x036D, 0x036E, 0x036F,
+ /* 7 */ 0x0370, 0x0371, 0x0372, 0x0373, 0x0374, 0x0375, 0x0376, 0x0377, 0x0378, 0x0379, 0x037A, 0x037B, 0x037C, 0x037D, 0x037E, 0x037F,
+ /* 8 */ 0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0386, 0x0387, 0x0388, 0x0389, 0x038A, 0x038B, 0x038C, 0x038D, 0x038E, 0x038F,
+ /* 9 */ 0x0390, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
+ /* A */ 0x03C0, 0x03C1, 0x03A2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
+ /* B */ 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
+ /* C */ 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x03CF,
+ /* D */ 0x03D0, 0x03D1, 0x03D2, 0x03D3, 0x03D4, 0x03D5, 0x03D6, 0x03D7, 0x03D8, 0x03D9, 0x03DA, 0x03DB, 0x03DC, 0x03DD, 0x03DE, 0x03DF,
+ /* E */ 0x03E0, 0x03E1, 0x03E3, 0x03E3, 0x03E5, 0x03E5, 0x03E7, 0x03E7, 0x03E9, 0x03E9, 0x03EB, 0x03EB, 0x03ED, 0x03ED, 0x03EF, 0x03EF,
+ /* F */ 0x03F0, 0x03F1, 0x03F2, 0x03F3, 0x03F4, 0x03F5, 0x03F6, 0x03F7, 0x03F8, 0x03F9, 0x03FA, 0x03FB, 0x03FC, 0x03FD, 0x03FE, 0x03FF,
+
+ /* Table 3 (for high byte 0x04) */
+
+ /* 0 */ 0x0400, 0x0401, 0x0452, 0x0403, 0x0454, 0x0455, 0x0456, 0x0407, 0x0458, 0x0459, 0x045A, 0x045B, 0x040C, 0x040D, 0x040E, 0x045F,
+ /* 1 */ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0419, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+ /* 2 */ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+ /* 3 */ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+ /* 4 */ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+ /* 5 */ 0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, 0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x045D, 0x045E, 0x045F,
+ /* 6 */ 0x0461, 0x0461, 0x0463, 0x0463, 0x0465, 0x0465, 0x0467, 0x0467, 0x0469, 0x0469, 0x046B, 0x046B, 0x046D, 0x046D, 0x046F, 0x046F,
+ /* 7 */ 0x0471, 0x0471, 0x0473, 0x0473, 0x0475, 0x0475, 0x0476, 0x0477, 0x0479, 0x0479, 0x047B, 0x047B, 0x047D, 0x047D, 0x047F, 0x047F,
+ /* 8 */ 0x0481, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, 0x0488, 0x0489, 0x048A, 0x048B, 0x048C, 0x048D, 0x048E, 0x048F,
+ /* 9 */ 0x0491, 0x0491, 0x0493, 0x0493, 0x0495, 0x0495, 0x0497, 0x0497, 0x0499, 0x0499, 0x049B, 0x049B, 0x049D, 0x049D, 0x049F, 0x049F,
+ /* A */ 0x04A1, 0x04A1, 0x04A3, 0x04A3, 0x04A5, 0x04A5, 0x04A7, 0x04A7, 0x04A9, 0x04A9, 0x04AB, 0x04AB, 0x04AD, 0x04AD, 0x04AF, 0x04AF,
+ /* B */ 0x04B1, 0x04B1, 0x04B3, 0x04B3, 0x04B5, 0x04B5, 0x04B7, 0x04B7, 0x04B9, 0x04B9, 0x04BB, 0x04BB, 0x04BD, 0x04BD, 0x04BF, 0x04BF,
+ /* C */ 0x04C0, 0x04C1, 0x04C2, 0x04C4, 0x04C4, 0x04C5, 0x04C6, 0x04C8, 0x04C8, 0x04C9, 0x04CA, 0x04CC, 0x04CC, 0x04CD, 0x04CE, 0x04CF,
+ /* D */ 0x04D0, 0x04D1, 0x04D2, 0x04D3, 0x04D4, 0x04D5, 0x04D6, 0x04D7, 0x04D8, 0x04D9, 0x04DA, 0x04DB, 0x04DC, 0x04DD, 0x04DE, 0x04DF,
+ /* E */ 0x04E0, 0x04E1, 0x04E2, 0x04E3, 0x04E4, 0x04E5, 0x04E6, 0x04E7, 0x04E8, 0x04E9, 0x04EA, 0x04EB, 0x04EC, 0x04ED, 0x04EE, 0x04EF,
+ /* F */ 0x04F0, 0x04F1, 0x04F2, 0x04F3, 0x04F4, 0x04F5, 0x04F6, 0x04F7, 0x04F8, 0x04F9, 0x04FA, 0x04FB, 0x04FC, 0x04FD, 0x04FE, 0x04FF,
+
+ /* Table 4 (for high byte 0x05) */
+
+ /* 0 */ 0x0500, 0x0501, 0x0502, 0x0503, 0x0504, 0x0505, 0x0506, 0x0507, 0x0508, 0x0509, 0x050A, 0x050B, 0x050C, 0x050D, 0x050E, 0x050F,
+ /* 1 */ 0x0510, 0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0516, 0x0517, 0x0518, 0x0519, 0x051A, 0x051B, 0x051C, 0x051D, 0x051E, 0x051F,
+ /* 2 */ 0x0520, 0x0521, 0x0522, 0x0523, 0x0524, 0x0525, 0x0526, 0x0527, 0x0528, 0x0529, 0x052A, 0x052B, 0x052C, 0x052D, 0x052E, 0x052F,
+ /* 3 */ 0x0530, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567, 0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F,
+ /* 4 */ 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577, 0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F,
+ /* 5 */ 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0557, 0x0558, 0x0559, 0x055A, 0x055B, 0x055C, 0x055D, 0x055E, 0x055F,
+ /* 6 */ 0x0560, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567, 0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F,
+ /* 7 */ 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577, 0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F,
+ /* 8 */ 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0587, 0x0588, 0x0589, 0x058A, 0x058B, 0x058C, 0x058D, 0x058E, 0x058F,
+ /* 9 */ 0x0590, 0x0591, 0x0592, 0x0593, 0x0594, 0x0595, 0x0596, 0x0597, 0x0598, 0x0599, 0x059A, 0x059B, 0x059C, 0x059D, 0x059E, 0x059F,
+ /* A */ 0x05A0, 0x05A1, 0x05A2, 0x05A3, 0x05A4, 0x05A5, 0x05A6, 0x05A7, 0x05A8, 0x05A9, 0x05AA, 0x05AB, 0x05AC, 0x05AD, 0x05AE, 0x05AF,
+ /* B */ 0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7, 0x05B8, 0x05B9, 0x05BA, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF,
+ /* C */ 0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05C4, 0x05C5, 0x05C6, 0x05C7, 0x05C8, 0x05C9, 0x05CA, 0x05CB, 0x05CC, 0x05CD, 0x05CE, 0x05CF,
+ /* D */ 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
+ /* E */ 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x05EB, 0x05EC, 0x05ED, 0x05EE, 0x05EF,
+ /* F */ 0x05F0, 0x05F1, 0x05F2, 0x05F3, 0x05F4, 0x05F5, 0x05F6, 0x05F7, 0x05F8, 0x05F9, 0x05FA, 0x05FB, 0x05FC, 0x05FD, 0x05FE, 0x05FF,
+
+ /* Table 5 (for high byte 0x10) */
+
+ /* 0 */ 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006, 0x1007, 0x1008, 0x1009, 0x100A, 0x100B, 0x100C, 0x100D, 0x100E, 0x100F,
+ /* 1 */ 0x1010, 0x1011, 0x1012, 0x1013, 0x1014, 0x1015, 0x1016, 0x1017, 0x1018, 0x1019, 0x101A, 0x101B, 0x101C, 0x101D, 0x101E, 0x101F,
+ /* 2 */ 0x1020, 0x1021, 0x1022, 0x1023, 0x1024, 0x1025, 0x1026, 0x1027, 0x1028, 0x1029, 0x102A, 0x102B, 0x102C, 0x102D, 0x102E, 0x102F,
+ /* 3 */ 0x1030, 0x1031, 0x1032, 0x1033, 0x1034, 0x1035, 0x1036, 0x1037, 0x1038, 0x1039, 0x103A, 0x103B, 0x103C, 0x103D, 0x103E, 0x103F,
+ /* 4 */ 0x1040, 0x1041, 0x1042, 0x1043, 0x1044, 0x1045, 0x1046, 0x1047, 0x1048, 0x1049, 0x104A, 0x104B, 0x104C, 0x104D, 0x104E, 0x104F,
+ /* 5 */ 0x1050, 0x1051, 0x1052, 0x1053, 0x1054, 0x1055, 0x1056, 0x1057, 0x1058, 0x1059, 0x105A, 0x105B, 0x105C, 0x105D, 0x105E, 0x105F,
+ /* 6 */ 0x1060, 0x1061, 0x1062, 0x1063, 0x1064, 0x1065, 0x1066, 0x1067, 0x1068, 0x1069, 0x106A, 0x106B, 0x106C, 0x106D, 0x106E, 0x106F,
+ /* 7 */ 0x1070, 0x1071, 0x1072, 0x1073, 0x1074, 0x1075, 0x1076, 0x1077, 0x1078, 0x1079, 0x107A, 0x107B, 0x107C, 0x107D, 0x107E, 0x107F,
+ /* 8 */ 0x1080, 0x1081, 0x1082, 0x1083, 0x1084, 0x1085, 0x1086, 0x1087, 0x1088, 0x1089, 0x108A, 0x108B, 0x108C, 0x108D, 0x108E, 0x108F,
+ /* 9 */ 0x1090, 0x1091, 0x1092, 0x1093, 0x1094, 0x1095, 0x1096, 0x1097, 0x1098, 0x1099, 0x109A, 0x109B, 0x109C, 0x109D, 0x109E, 0x109F,
+ /* A */ 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10D7, 0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10DD, 0x10DE, 0x10DF,
+ /* B */ 0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4, 0x10E5, 0x10E6, 0x10E7, 0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10EF,
+ /* C */ 0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4, 0x10F5, 0x10C6, 0x10C7, 0x10C8, 0x10C9, 0x10CA, 0x10CB, 0x10CC, 0x10CD, 0x10CE, 0x10CF,
+ /* D */ 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10D7, 0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10DD, 0x10DE, 0x10DF,
+ /* E */ 0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4, 0x10E5, 0x10E6, 0x10E7, 0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10EF,
+ /* F */ 0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4, 0x10F5, 0x10F6, 0x10F7, 0x10F8, 0x10F9, 0x10FA, 0x10FB, 0x10FC, 0x10FD, 0x10FE, 0x10FF,
+
+ /* Table 6 (for high byte 0x20) */
+
+ /* 0 */ 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x200B, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* 1 */ 0x2010, 0x2011, 0x2012, 0x2013, 0x2014, 0x2015, 0x2016, 0x2017, 0x2018, 0x2019, 0x201A, 0x201B, 0x201C, 0x201D, 0x201E, 0x201F,
+ /* 2 */ 0x2020, 0x2021, 0x2022, 0x2023, 0x2024, 0x2025, 0x2026, 0x2027, 0x2028, 0x2029, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x202F,
+ /* 3 */ 0x2030, 0x2031, 0x2032, 0x2033, 0x2034, 0x2035, 0x2036, 0x2037, 0x2038, 0x2039, 0x203A, 0x203B, 0x203C, 0x203D, 0x203E, 0x203F,
+ /* 4 */ 0x2040, 0x2041, 0x2042, 0x2043, 0x2044, 0x2045, 0x2046, 0x2047, 0x2048, 0x2049, 0x204A, 0x204B, 0x204C, 0x204D, 0x204E, 0x204F,
+ /* 5 */ 0x2050, 0x2051, 0x2052, 0x2053, 0x2054, 0x2055, 0x2056, 0x2057, 0x2058, 0x2059, 0x205A, 0x205B, 0x205C, 0x205D, 0x205E, 0x205F,
+ /* 6 */ 0x2060, 0x2061, 0x2062, 0x2063, 0x2064, 0x2065, 0x2066, 0x2067, 0x2068, 0x2069, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* 7 */ 0x2070, 0x2071, 0x2072, 0x2073, 0x2074, 0x2075, 0x2076, 0x2077, 0x2078, 0x2079, 0x207A, 0x207B, 0x207C, 0x207D, 0x207E, 0x207F,
+ /* 8 */ 0x2080, 0x2081, 0x2082, 0x2083, 0x2084, 0x2085, 0x2086, 0x2087, 0x2088, 0x2089, 0x208A, 0x208B, 0x208C, 0x208D, 0x208E, 0x208F,
+ /* 9 */ 0x2090, 0x2091, 0x2092, 0x2093, 0x2094, 0x2095, 0x2096, 0x2097, 0x2098, 0x2099, 0x209A, 0x209B, 0x209C, 0x209D, 0x209E, 0x209F,
+ /* A */ 0x20A0, 0x20A1, 0x20A2, 0x20A3, 0x20A4, 0x20A5, 0x20A6, 0x20A7, 0x20A8, 0x20A9, 0x20AA, 0x20AB, 0x20AC, 0x20AD, 0x20AE, 0x20AF,
+ /* B */ 0x20B0, 0x20B1, 0x20B2, 0x20B3, 0x20B4, 0x20B5, 0x20B6, 0x20B7, 0x20B8, 0x20B9, 0x20BA, 0x20BB, 0x20BC, 0x20BD, 0x20BE, 0x20BF,
+ /* C */ 0x20C0, 0x20C1, 0x20C2, 0x20C3, 0x20C4, 0x20C5, 0x20C6, 0x20C7, 0x20C8, 0x20C9, 0x20CA, 0x20CB, 0x20CC, 0x20CD, 0x20CE, 0x20CF,
+ /* D */ 0x20D0, 0x20D1, 0x20D2, 0x20D3, 0x20D4, 0x20D5, 0x20D6, 0x20D7, 0x20D8, 0x20D9, 0x20DA, 0x20DB, 0x20DC, 0x20DD, 0x20DE, 0x20DF,
+ /* E */ 0x20E0, 0x20E1, 0x20E2, 0x20E3, 0x20E4, 0x20E5, 0x20E6, 0x20E7, 0x20E8, 0x20E9, 0x20EA, 0x20EB, 0x20EC, 0x20ED, 0x20EE, 0x20EF,
+ /* F */ 0x20F0, 0x20F1, 0x20F2, 0x20F3, 0x20F4, 0x20F5, 0x20F6, 0x20F7, 0x20F8, 0x20F9, 0x20FA, 0x20FB, 0x20FC, 0x20FD, 0x20FE, 0x20FF,
+
+ /* Table 7 (for high byte 0x21) */
+
+ /* 0 */ 0x2100, 0x2101, 0x2102, 0x2103, 0x2104, 0x2105, 0x2106, 0x2107, 0x2108, 0x2109, 0x210A, 0x210B, 0x210C, 0x210D, 0x210E, 0x210F,
+ /* 1 */ 0x2110, 0x2111, 0x2112, 0x2113, 0x2114, 0x2115, 0x2116, 0x2117, 0x2118, 0x2119, 0x211A, 0x211B, 0x211C, 0x211D, 0x211E, 0x211F,
+ /* 2 */ 0x2120, 0x2121, 0x2122, 0x2123, 0x2124, 0x2125, 0x2126, 0x2127, 0x2128, 0x2129, 0x212A, 0x212B, 0x212C, 0x212D, 0x212E, 0x212F,
+ /* 3 */ 0x2130, 0x2131, 0x2132, 0x2133, 0x2134, 0x2135, 0x2136, 0x2137, 0x2138, 0x2139, 0x213A, 0x213B, 0x213C, 0x213D, 0x213E, 0x213F,
+ /* 4 */ 0x2140, 0x2141, 0x2142, 0x2143, 0x2144, 0x2145, 0x2146, 0x2147, 0x2148, 0x2149, 0x214A, 0x214B, 0x214C, 0x214D, 0x214E, 0x214F,
+ /* 5 */ 0x2150, 0x2151, 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159, 0x215A, 0x215B, 0x215C, 0x215D, 0x215E, 0x215F,
+ /* 6 */ 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F,
+ /* 7 */ 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F,
+ /* 8 */ 0x2180, 0x2181, 0x2182, 0x2183, 0x2184, 0x2185, 0x2186, 0x2187, 0x2188, 0x2189, 0x218A, 0x218B, 0x218C, 0x218D, 0x218E, 0x218F,
+ /* 9 */ 0x2190, 0x2191, 0x2192, 0x2193, 0x2194, 0x2195, 0x2196, 0x2197, 0x2198, 0x2199, 0x219A, 0x219B, 0x219C, 0x219D, 0x219E, 0x219F,
+ /* A */ 0x21A0, 0x21A1, 0x21A2, 0x21A3, 0x21A4, 0x21A5, 0x21A6, 0x21A7, 0x21A8, 0x21A9, 0x21AA, 0x21AB, 0x21AC, 0x21AD, 0x21AE, 0x21AF,
+ /* B */ 0x21B0, 0x21B1, 0x21B2, 0x21B3, 0x21B4, 0x21B5, 0x21B6, 0x21B7, 0x21B8, 0x21B9, 0x21BA, 0x21BB, 0x21BC, 0x21BD, 0x21BE, 0x21BF,
+ /* C */ 0x21C0, 0x21C1, 0x21C2, 0x21C3, 0x21C4, 0x21C5, 0x21C6, 0x21C7, 0x21C8, 0x21C9, 0x21CA, 0x21CB, 0x21CC, 0x21CD, 0x21CE, 0x21CF,
+ /* D */ 0x21D0, 0x21D1, 0x21D2, 0x21D3, 0x21D4, 0x21D5, 0x21D6, 0x21D7, 0x21D8, 0x21D9, 0x21DA, 0x21DB, 0x21DC, 0x21DD, 0x21DE, 0x21DF,
+ /* E */ 0x21E0, 0x21E1, 0x21E2, 0x21E3, 0x21E4, 0x21E5, 0x21E6, 0x21E7, 0x21E8, 0x21E9, 0x21EA, 0x21EB, 0x21EC, 0x21ED, 0x21EE, 0x21EF,
+ /* F */ 0x21F0, 0x21F1, 0x21F2, 0x21F3, 0x21F4, 0x21F5, 0x21F6, 0x21F7, 0x21F8, 0x21F9, 0x21FA, 0x21FB, 0x21FC, 0x21FD, 0x21FE, 0x21FF,
+
+ /* Table 8 (for high byte 0xFE) */
+
+ /* 0 */ 0xFE00, 0xFE01, 0xFE02, 0xFE03, 0xFE04, 0xFE05, 0xFE06, 0xFE07, 0xFE08, 0xFE09, 0xFE0A, 0xFE0B, 0xFE0C, 0xFE0D, 0xFE0E, 0xFE0F,
+ /* 1 */ 0xFE10, 0xFE11, 0xFE12, 0xFE13, 0xFE14, 0xFE15, 0xFE16, 0xFE17, 0xFE18, 0xFE19, 0xFE1A, 0xFE1B, 0xFE1C, 0xFE1D, 0xFE1E, 0xFE1F,
+ /* 2 */ 0xFE20, 0xFE21, 0xFE22, 0xFE23, 0xFE24, 0xFE25, 0xFE26, 0xFE27, 0xFE28, 0xFE29, 0xFE2A, 0xFE2B, 0xFE2C, 0xFE2D, 0xFE2E, 0xFE2F,
+ /* 3 */ 0xFE30, 0xFE31, 0xFE32, 0xFE33, 0xFE34, 0xFE35, 0xFE36, 0xFE37, 0xFE38, 0xFE39, 0xFE3A, 0xFE3B, 0xFE3C, 0xFE3D, 0xFE3E, 0xFE3F,
+ /* 4 */ 0xFE40, 0xFE41, 0xFE42, 0xFE43, 0xFE44, 0xFE45, 0xFE46, 0xFE47, 0xFE48, 0xFE49, 0xFE4A, 0xFE4B, 0xFE4C, 0xFE4D, 0xFE4E, 0xFE4F,
+ /* 5 */ 0xFE50, 0xFE51, 0xFE52, 0xFE53, 0xFE54, 0xFE55, 0xFE56, 0xFE57, 0xFE58, 0xFE59, 0xFE5A, 0xFE5B, 0xFE5C, 0xFE5D, 0xFE5E, 0xFE5F,
+ /* 6 */ 0xFE60, 0xFE61, 0xFE62, 0xFE63, 0xFE64, 0xFE65, 0xFE66, 0xFE67, 0xFE68, 0xFE69, 0xFE6A, 0xFE6B, 0xFE6C, 0xFE6D, 0xFE6E, 0xFE6F,
+ /* 7 */ 0xFE70, 0xFE71, 0xFE72, 0xFE73, 0xFE74, 0xFE75, 0xFE76, 0xFE77, 0xFE78, 0xFE79, 0xFE7A, 0xFE7B, 0xFE7C, 0xFE7D, 0xFE7E, 0xFE7F,
+ /* 8 */ 0xFE80, 0xFE81, 0xFE82, 0xFE83, 0xFE84, 0xFE85, 0xFE86, 0xFE87, 0xFE88, 0xFE89, 0xFE8A, 0xFE8B, 0xFE8C, 0xFE8D, 0xFE8E, 0xFE8F,
+ /* 9 */ 0xFE90, 0xFE91, 0xFE92, 0xFE93, 0xFE94, 0xFE95, 0xFE96, 0xFE97, 0xFE98, 0xFE99, 0xFE9A, 0xFE9B, 0xFE9C, 0xFE9D, 0xFE9E, 0xFE9F,
+ /* A */ 0xFEA0, 0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4, 0xFEA5, 0xFEA6, 0xFEA7, 0xFEA8, 0xFEA9, 0xFEAA, 0xFEAB, 0xFEAC, 0xFEAD, 0xFEAE, 0xFEAF,
+ /* B */ 0xFEB0, 0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4, 0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8, 0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC, 0xFEBD, 0xFEBE, 0xFEBF,
+ /* C */ 0xFEC0, 0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4, 0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8, 0xFEC9, 0xFECA, 0xFECB, 0xFECC, 0xFECD, 0xFECE, 0xFECF,
+ /* D */ 0xFED0, 0xFED1, 0xFED2, 0xFED3, 0xFED4, 0xFED5, 0xFED6, 0xFED7, 0xFED8, 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC, 0xFEDD, 0xFEDE, 0xFEDF,
+ /* E */ 0xFEE0, 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4, 0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8, 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC, 0xFEED, 0xFEEE, 0xFEEF,
+ /* F */ 0xFEF0, 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4, 0xFEF5, 0xFEF6, 0xFEF7, 0xFEF8, 0xFEF9, 0xFEFA, 0xFEFB, 0xFEFC, 0xFEFD, 0xFEFE, 0x0000,
+
+ /* Table 9 (for high byte 0xFF) */
+
+ /* 0 */ 0xFF00, 0xFF01, 0xFF02, 0xFF03, 0xFF04, 0xFF05, 0xFF06, 0xFF07, 0xFF08, 0xFF09, 0xFF0A, 0xFF0B, 0xFF0C, 0xFF0D, 0xFF0E, 0xFF0F,
+ /* 1 */ 0xFF10, 0xFF11, 0xFF12, 0xFF13, 0xFF14, 0xFF15, 0xFF16, 0xFF17, 0xFF18, 0xFF19, 0xFF1A, 0xFF1B, 0xFF1C, 0xFF1D, 0xFF1E, 0xFF1F,
+ /* 2 */ 0xFF20, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F,
+ /* 3 */ 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, 0xFF58, 0xFF59, 0xFF5A, 0xFF3B, 0xFF3C, 0xFF3D, 0xFF3E, 0xFF3F,
+ /* 4 */ 0xFF40, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F,
+ /* 5 */ 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, 0xFF58, 0xFF59, 0xFF5A, 0xFF5B, 0xFF5C, 0xFF5D, 0xFF5E, 0xFF5F,
+ /* 6 */ 0xFF60, 0xFF61, 0xFF62, 0xFF63, 0xFF64, 0xFF65, 0xFF66, 0xFF67, 0xFF68, 0xFF69, 0xFF6A, 0xFF6B, 0xFF6C, 0xFF6D, 0xFF6E, 0xFF6F,
+ /* 7 */ 0xFF70, 0xFF71, 0xFF72, 0xFF73, 0xFF74, 0xFF75, 0xFF76, 0xFF77, 0xFF78, 0xFF79, 0xFF7A, 0xFF7B, 0xFF7C, 0xFF7D, 0xFF7E, 0xFF7F,
+ /* 8 */ 0xFF80, 0xFF81, 0xFF82, 0xFF83, 0xFF84, 0xFF85, 0xFF86, 0xFF87, 0xFF88, 0xFF89, 0xFF8A, 0xFF8B, 0xFF8C, 0xFF8D, 0xFF8E, 0xFF8F,
+ /* 9 */ 0xFF90, 0xFF91, 0xFF92, 0xFF93, 0xFF94, 0xFF95, 0xFF96, 0xFF97, 0xFF98, 0xFF99, 0xFF9A, 0xFF9B, 0xFF9C, 0xFF9D, 0xFF9E, 0xFF9F,
+ /* A */ 0xFFA0, 0xFFA1, 0xFFA2, 0xFFA3, 0xFFA4, 0xFFA5, 0xFFA6, 0xFFA7, 0xFFA8, 0xFFA9, 0xFFAA, 0xFFAB, 0xFFAC, 0xFFAD, 0xFFAE, 0xFFAF,
+ /* B */ 0xFFB0, 0xFFB1, 0xFFB2, 0xFFB3, 0xFFB4, 0xFFB5, 0xFFB6, 0xFFB7, 0xFFB8, 0xFFB9, 0xFFBA, 0xFFBB, 0xFFBC, 0xFFBD, 0xFFBE, 0xFFBF,
+ /* C */ 0xFFC0, 0xFFC1, 0xFFC2, 0xFFC3, 0xFFC4, 0xFFC5, 0xFFC6, 0xFFC7, 0xFFC8, 0xFFC9, 0xFFCA, 0xFFCB, 0xFFCC, 0xFFCD, 0xFFCE, 0xFFCF,
+ /* D */ 0xFFD0, 0xFFD1, 0xFFD2, 0xFFD3, 0xFFD4, 0xFFD5, 0xFFD6, 0xFFD7, 0xFFD8, 0xFFD9, 0xFFDA, 0xFFDB, 0xFFDC, 0xFFDD, 0xFFDE, 0xFFDF,
+ /* E */ 0xFFE0, 0xFFE1, 0xFFE2, 0xFFE3, 0xFFE4, 0xFFE5, 0xFFE6, 0xFFE7, 0xFFE8, 0xFFE9, 0xFFEA, 0xFFEB, 0xFFEC, 0xFFED, 0xFFEE, 0xFFEF,
+ /* F */ 0xFFF0, 0xFFF1, 0xFFF2, 0xFFF3, 0xFFF4, 0xFFF5, 0xFFF6, 0xFFF7, 0xFFF8, 0xFFF9, 0xFFFA, 0xFFFB, 0xFFFC, 0xFFFD, 0xFFFE, 0xFFFF,
+};
+#endif
+
+static const fsw_u16 fsw_latin_case_fold[] =
+{
+ /* 0 */ 0xFFFF, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ /* 1 */ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ /* 2 */ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ /* 3 */ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ /* 4 */ 0x0040, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ /* 5 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ /* 6 */ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ /* 7 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ /* 8 */ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+ /* 9 */ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+ /* A */ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ /* B */ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ /* C */ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00E6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+ /* D */ 0x00F0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00F8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00FE, 0x00DF,
+ /* E */ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+ /* F */ 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF,
+};
+
+
+fsw_u16 fsw_to_lower(fsw_u16 ch)
+{
+#if 0
+ fsw_u16 temp = temp;
+#endif
+
+ if (ch < 0x0100)
+ return fsw_latin_case_fold[ch];
+#if 0
+ /*
+ * Uncomment this along with above huge table (fsw_lower_case_table)
+ * for full UTF-16 case insensitivity
+ */
+ temp = fsw_lower_case_table[ch>>8];
+ if (temp != 0)
+ return fsw_lower_case_table[temp + (ch & 0x00FF)];
+#endif
+
+ return ch;
+}
+
+/**
+ * Compare two strings for equality. The two strings are compared, taking their
+ * encoding into account. If they are considered equal, boolean true is returned.
+ * Otherwise, boolean false is returned.
+ */
+
+int fsw_streq(struct fsw_string *s1, struct fsw_string *s2)
+{
+ struct fsw_string temp_s;
+
+ // handle empty strings
+ if (s1->type == FSW_STRING_TYPE_EMPTY) {
+ temp_s.type = FSW_STRING_TYPE_ISO88591;
+ temp_s.size = temp_s.len = 0;
+ temp_s.data = NULL;
+ return fsw_streq(&temp_s, s2);
+ }
+ if (s2->type == FSW_STRING_TYPE_EMPTY) {
+ temp_s.type = FSW_STRING_TYPE_ISO88591;
+ temp_s.size = temp_s.len = 0;
+ temp_s.data = NULL;
+ return fsw_streq(s1, &temp_s);
+ }
+
+ // check length (count of chars)
+ if (s1->len != s2->len)
+ return 0;
+ if (s1->len == 0) // both strings are empty
+ return 1;
+
+ if (s1->type == s2->type) {
+ // same type, do a dumb memory compare
+ if (s1->size != s2->size)
+ return 0;
+ return fsw_memeq(s1->data, s2->data, s1->size);
+ }
+
+ // dispatch to type-specific functions
+ #define STREQ_DISPATCH(type1, type2) \
+ if (s1->type == FSW_STRING_TYPE_##type1 && s2->type == FSW_STRING_TYPE_##type2) \
+ return fsw_streq_##type1##_##type2(s1->data, s2->data, s1->len); \
+ if (s2->type == FSW_STRING_TYPE_##type1 && s1->type == FSW_STRING_TYPE_##type2) \
+ return fsw_streq_##type1##_##type2(s2->data, s1->data, s1->len);
+ STREQ_DISPATCH(ISO88591, UTF8);
+ STREQ_DISPATCH(ISO88591, UTF16);
+ STREQ_DISPATCH(ISO88591, UTF16_SWAPPED);
+ STREQ_DISPATCH(UTF8, UTF16);
+ STREQ_DISPATCH(UTF8, UTF16_SWAPPED);
+ STREQ_DISPATCH(UTF16, UTF16_SWAPPED);
+
+ // final fallback
+ return 0;
+}
+
+/**
+ * Compare a string with a C string constant. This sets up a string descriptor
+ * for the string constant (second argument) and runs fsw_streq on the two
+ * strings. Currently the C string is interpreted as ISO 8859-1.
+ * Returns boolean true if the strings are considered equal, boolean false otherwise.
+ */
+
+int fsw_streq_cstr(struct fsw_string *s1, const char *s2)
+{
+ struct fsw_string temp_s;
+ int i;
+
+ for (i = 0; s2[i]; i++)
+ ;
+
+ temp_s.type = FSW_STRING_TYPE_ISO88591;
+ temp_s.size = temp_s.len = i;
+ temp_s.data = (char *)s2;
+
+ return fsw_streq(s1, &temp_s);
+}
+
+/**
+ * Creates a duplicate of a string, converting it to the given encoding during the copy.
+ * If the function returns FSW_SUCCESS, the caller must free the string later with
+ * fsw_strfree.
+ */
+
+fsw_status_t fsw_strdup_coerce(struct fsw_string *dest, int type, struct fsw_string *src)
+{
+ fsw_status_t status;
+
+ if (src->type == FSW_STRING_TYPE_EMPTY || src->len == 0) {
+ dest->type = type;
+ dest->size = dest->len = 0;
+ dest->data = NULL;
+ return FSW_SUCCESS;
+ }
+
+ if (src->type == type) {
+ dest->type = type;
+ dest->len = src->len;
+ dest->size = src->size;
+ status = fsw_alloc(dest->size, &dest->data);
+ if (status)
+ return status;
+
+ fsw_memcpy(dest->data, src->data, dest->size);
+ return FSW_SUCCESS;
+ }
+
+ // dispatch to type-specific functions
+ #define STRCOERCE_DISPATCH(type1, type2) \
+ if (src->type == FSW_STRING_TYPE_##type1 && type == FSW_STRING_TYPE_##type2) \
+ return fsw_strcoerce_##type1##_##type2(src->data, src->len, dest);
+ STRCOERCE_DISPATCH(UTF8, ISO88591);
+ STRCOERCE_DISPATCH(UTF16, ISO88591);
+ STRCOERCE_DISPATCH(UTF16_SWAPPED, ISO88591);
+ STRCOERCE_DISPATCH(ISO88591, UTF8);
+ STRCOERCE_DISPATCH(UTF16, UTF8);
+ STRCOERCE_DISPATCH(UTF16_SWAPPED, UTF8);
+ STRCOERCE_DISPATCH(ISO88591, UTF16);
+ STRCOERCE_DISPATCH(UTF8, UTF16);
+ STRCOERCE_DISPATCH(UTF16_SWAPPED, UTF16);
+
+ return FSW_UNSUPPORTED;
+}
+
+/**
+ * Splits a string at the first occurrence of the separator character.
+ * The buffer string is searched for the separator character. If it is found, the
+ * element string descriptor is filled to point at the part of the buffer string
+ * before the separator. The buffer string itself is adjusted to point at the
+ * remaining part of the string (without the separator).
+ *
+ * If the separator is not found in the buffer string, then element is changed to
+ * point at the whole buffer string, and the buffer string itself is changed into
+ * an empty string.
+ *
+ * This function only manipulates the pointers and lengths in the two string descriptors,
+ * it does not change the actual string. If the buffer string is dynamically allocated,
+ * you must make a copy of it so that you can release it later.
+ */
+
+void fsw_strsplit(struct fsw_string *element, struct fsw_string *buffer, char separator)
+{
+ int i, maxlen;
+
+ if (buffer->type == FSW_STRING_TYPE_EMPTY || buffer->len == 0) {
+ element->type = FSW_STRING_TYPE_EMPTY;
+ return;
+ }
+
+ maxlen = buffer->len;
+ *element = *buffer;
+
+ if (buffer->type == FSW_STRING_TYPE_ISO88591) {
+ fsw_u8 *p;
+
+ p = (fsw_u8 *)element->data;
+ for (i = 0; i < maxlen; i++, p++) {
+ if (*p == separator) {
+ buffer->data = p + 1;
+ buffer->len -= i + 1;
+ break;
+ }
+ }
+ element->len = i;
+ if (i == maxlen) {
+ buffer->data = p;
+ buffer->len -= i;
+ }
+
+ element->size = element->len;
+ buffer->size = buffer->len;
+
+ } else if (buffer->type == FSW_STRING_TYPE_UTF16) {
+ fsw_u16 *p;
+
+ p = (fsw_u16 *)element->data;
+ for (i = 0; i < maxlen; i++, p++) {
+ if (*p == separator) {
+ buffer->data = p + 1;
+ buffer->len -= i + 1;
+ break;
+ }
+ }
+ element->len = i;
+ if (i == maxlen) {
+ buffer->data = p;
+ buffer->len -= i;
+ }
+
+ element->size = element->len * sizeof(fsw_u16);
+ buffer->size = buffer->len * sizeof(fsw_u16);
+
+ } else {
+ // fallback
+ buffer->type = FSW_STRING_TYPE_EMPTY;
+ }
+
+ /// @todo support UTF8 and UTF16_SWAPPED
+}
+
+/**
+ * Frees the memory used by a string returned from fsw_strdup_coerce.
+ */
+
+void fsw_strfree(struct fsw_string *s)
+{
+ if (s->type != FSW_STRING_TYPE_EMPTY && s->data)
+ fsw_free(s->data);
+ s->type = FSW_STRING_TYPE_EMPTY;
+}
+
+// EOF
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_strfunc.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_strfunc.h
new file mode 100644
index 00000000..2939d794
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_strfunc.h
@@ -0,0 +1,491 @@
+/* $Id: fsw_strfunc.h $ */
+/** @file
+ * fsw_strfunc.h
+ */
+
+/*
+ * Copyright (C) 2010-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/* fsw_strfunc.h generated by mk_fsw_strfunc.py */
+
+static int fsw_streq_ISO88591_UTF8(void *s1data, void *s2data, int len)
+{
+ int i;
+ fsw_u8 *p1 = (fsw_u8 *)s1data;
+ fsw_u8 *p2 = (fsw_u8 *)s2data;
+ fsw_u32 c1, c2;
+
+ for (i = 0; i < len; i++) {
+ c1 = *p1++;
+ c2 = *p2++;
+ if ((c2 & 0xe0) == 0xc0) {
+ c2 = ((c2 & 0x1f) << 6) | (*p2++ & 0x3f);
+ } else if ((c2 & 0xf0) == 0xe0) {
+ c2 = ((c2 & 0x0f) << 12) | ((*p2++ & 0x3f) << 6);
+ c2 |= (*p2++ & 0x3f);
+ } else if ((c2 & 0xf8) == 0xf0) {
+ c2 = ((c2 & 0x07) << 18) | ((*p2++ & 0x3f) << 12);
+ c2 |= ((*p2++ & 0x3f) << 6);
+ c2 |= (*p2++ & 0x3f);
+ }
+ if (c1 != c2)
+ return 0;
+ }
+ return 1;
+}
+
+#ifndef HOST_EFI
+static int fsw_streq_ISO88591_UTF16(void *s1data, void *s2data, int len)
+{
+ int i;
+ fsw_u8 *p1 = (fsw_u8 *)s1data;
+ fsw_u16 *p2 = (fsw_u16 *)s2data;
+ fsw_u32 c1, c2;
+
+ for (i = 0; i < len; i++) {
+ c1 = *p1++;
+ c2 = *p2++;
+ if (c1 != c2)
+ return 0;
+ }
+ return 1;
+}
+#endif
+
+static int fsw_streq_ISO88591_UTF16_SWAPPED(void *s1data, void *s2data, int len)
+{
+ int i;
+ fsw_u8 *p1 = (fsw_u8 *)s1data;
+ fsw_u16 *p2 = (fsw_u16 *)s2data;
+ fsw_u32 c1, c2;
+
+ for (i = 0; i < len; i++) {
+ c1 = *p1++;
+ c2 = *p2++; c2 = FSW_SWAPVALUE_U16(c2);
+ if (c1 != c2)
+ return 0;
+ }
+ return 1;
+}
+
+static int fsw_streq_UTF8_UTF16(void *s1data, void *s2data, int len)
+{
+ int i;
+ fsw_u8 *p1 = (fsw_u8 *)s1data;
+ fsw_u16 *p2 = (fsw_u16 *)s2data;
+ fsw_u32 c1, c2;
+
+ for (i = 0; i < len; i++) {
+ c1 = *p1++;
+ if ((c1 & 0xe0) == 0xc0) {
+ c1 = ((c1 & 0x1f) << 6) | (*p1++ & 0x3f);
+ } else if ((c1 & 0xf0) == 0xe0) {
+ c1 = ((c1 & 0x0f) << 12) | ((*p1++ & 0x3f) << 6);
+ c1 |= (*p1++ & 0x3f);
+ } else if ((c1 & 0xf8) == 0xf0) {
+ c1 = ((c1 & 0x07) << 18) | ((*p1++ & 0x3f) << 12);
+ c1 |= ((*p1++ & 0x3f) << 6);
+ c1 |= (*p1++ & 0x3f);
+ }
+ c2 = *p2++;
+ if (c1 != c2)
+ return 0;
+ }
+ return 1;
+}
+
+static int fsw_streq_UTF8_UTF16_SWAPPED(void *s1data, void *s2data, int len)
+{
+ int i;
+ fsw_u8 *p1 = (fsw_u8 *)s1data;
+ fsw_u16 *p2 = (fsw_u16 *)s2data;
+ fsw_u32 c1, c2;
+
+ for (i = 0; i < len; i++) {
+ c1 = *p1++;
+ if ((c1 & 0xe0) == 0xc0) {
+ c1 = ((c1 & 0x1f) << 6) | (*p1++ & 0x3f);
+ } else if ((c1 & 0xf0) == 0xe0) {
+ c1 = ((c1 & 0x0f) << 12) | ((*p1++ & 0x3f) << 6);
+ c1 |= (*p1++ & 0x3f);
+ } else if ((c1 & 0xf8) == 0xf0) {
+ c1 = ((c1 & 0x07) << 18) | ((*p1++ & 0x3f) << 12);
+ c1 |= ((*p1++ & 0x3f) << 6);
+ c1 |= (*p1++ & 0x3f);
+ }
+ c2 = *p2++; c2 = FSW_SWAPVALUE_U16(c2);
+ if (c1 != c2)
+ return 0;
+ }
+ return 1;
+}
+
+static int fsw_streq_UTF16_UTF16_SWAPPED(void *s1data, void *s2data, int len)
+{
+ int i;
+ fsw_u16 *p1 = (fsw_u16 *)s1data;
+ fsw_u16 *p2 = (fsw_u16 *)s2data;
+ fsw_u32 c1, c2;
+
+ for (i = 0; i < len; i++) {
+ c1 = *p1++;
+ c2 = *p2++; c2 = FSW_SWAPVALUE_U16(c2);
+ if (c1 != c2)
+ return 0;
+ }
+ return 1;
+}
+
+static fsw_status_t fsw_strcoerce_UTF8_ISO88591(void *srcdata, int srclen, struct fsw_string *dest)
+{
+ fsw_status_t status;
+ int i;
+ fsw_u8 *sp;
+ fsw_u8 *dp;
+ fsw_u32 c;
+
+ dest->type = FSW_STRING_TYPE_ISO88591;
+ dest->len = srclen;
+ dest->size = srclen * sizeof(fsw_u8);
+ status = fsw_alloc(dest->size, &dest->data);
+ if (status)
+ return status;
+
+ sp = (fsw_u8 *)srcdata;
+ dp = (fsw_u8 *)dest->data;
+ for (i = 0; i < srclen; i++) {
+ c = *sp++;
+ if ((c & 0xe0) == 0xc0) {
+ c = ((c & 0x1f) << 6) | (*sp++ & 0x3f);
+ } else if ((c & 0xf0) == 0xe0) {
+ c = ((c & 0x0f) << 12) | ((*sp++ & 0x3f) << 6);
+ c |= (*sp++ & 0x3f);
+ } else if ((c & 0xf8) == 0xf0) {
+ c = ((c & 0x07) << 18) | ((*sp++ & 0x3f) << 12);
+ c |= ((*sp++ & 0x3f) << 6);
+ c |= (*sp++ & 0x3f);
+ }
+ *dp++ = (fsw_u8)c;
+ }
+ return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF16_ISO88591(void *srcdata, int srclen, struct fsw_string *dest)
+{
+ fsw_status_t status;
+ int i;
+ fsw_u16 *sp;
+ fsw_u8 *dp;
+ fsw_u32 c;
+
+ dest->type = FSW_STRING_TYPE_ISO88591;
+ dest->len = srclen;
+ dest->size = srclen * sizeof(fsw_u8);
+ status = fsw_alloc(dest->size, &dest->data);
+ if (status)
+ return status;
+
+ sp = (fsw_u16 *)srcdata;
+ dp = (fsw_u8 *)dest->data;
+ for (i = 0; i < srclen; i++) {
+ c = *sp++;
+ *dp++ = (fsw_u8)c;
+ }
+ return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF16_SWAPPED_ISO88591(void *srcdata, int srclen, struct fsw_string *dest)
+{
+ fsw_status_t status;
+ int i;
+ fsw_u16 *sp;
+ fsw_u8 *dp;
+ fsw_u32 c;
+
+ dest->type = FSW_STRING_TYPE_ISO88591;
+ dest->len = srclen;
+ dest->size = srclen * sizeof(fsw_u8);
+ status = fsw_alloc(dest->size, &dest->data);
+ if (status)
+ return status;
+
+ sp = (fsw_u16 *)srcdata;
+ dp = (fsw_u8 *)dest->data;
+ for (i = 0; i < srclen; i++) {
+ c = *sp++; c = FSW_SWAPVALUE_U16(c);
+ *dp++ = (fsw_u8)c;
+ }
+ return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_ISO88591_UTF16(void *srcdata, int srclen, struct fsw_string *dest)
+{
+ fsw_status_t status;
+ int i;
+ fsw_u8 *sp;
+ fsw_u16 *dp;
+ fsw_u32 c;
+
+ dest->type = FSW_STRING_TYPE_UTF16;
+ dest->len = srclen;
+ dest->size = srclen * sizeof(fsw_u16);
+ status = fsw_alloc(dest->size, &dest->data);
+ if (status)
+ return status;
+
+ sp = (fsw_u8 *)srcdata;
+ dp = (fsw_u16 *)dest->data;
+ for (i = 0; i < srclen; i++) {
+ c = *sp++;
+ *dp++ = (fsw_u16)c;
+ }
+ return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF8_UTF16(void *srcdata, int srclen, struct fsw_string *dest)
+{
+ fsw_status_t status;
+ int i;
+ fsw_u8 *sp;
+ fsw_u16 *dp;
+ fsw_u32 c;
+
+ dest->type = FSW_STRING_TYPE_UTF16;
+ dest->len = srclen;
+ dest->size = srclen * sizeof(fsw_u16);
+ status = fsw_alloc(dest->size, &dest->data);
+ if (status)
+ return status;
+
+ sp = (fsw_u8 *)srcdata;
+ dp = (fsw_u16 *)dest->data;
+ for (i = 0; i < srclen; i++) {
+ c = *sp++;
+ if ((c & 0xe0) == 0xc0) {
+ c = ((c & 0x1f) << 6) | (*sp++ & 0x3f);
+ } else if ((c & 0xf0) == 0xe0) {
+ c = ((c & 0x0f) << 12) | ((*sp++ & 0x3f) << 6);
+ c |= (*sp++ & 0x3f);
+ } else if ((c & 0xf8) == 0xf0) {
+ c = ((c & 0x07) << 18) | ((*sp++ & 0x3f) << 12);
+ c |= ((*sp++ & 0x3f) << 6);
+ c |= (*sp++ & 0x3f);
+ }
+ *dp++ = (fsw_u16)c;
+ }
+ return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF16_SWAPPED_UTF16(void *srcdata, int srclen, struct fsw_string *dest)
+{
+ fsw_status_t status;
+ int i;
+ fsw_u16 *sp;
+ fsw_u16 *dp;
+ fsw_u32 c;
+
+ dest->type = FSW_STRING_TYPE_UTF16;
+ dest->len = srclen;
+ dest->size = srclen * sizeof(fsw_u16);
+ status = fsw_alloc(dest->size, &dest->data);
+ if (status)
+ return status;
+
+ sp = (fsw_u16 *)srcdata;
+ dp = (fsw_u16 *)dest->data;
+ for (i = 0; i < srclen; i++) {
+ c = *sp++; c = FSW_SWAPVALUE_U16(c);
+ *dp++ = (fsw_u16)c;
+ }
+ return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_ISO88591_UTF8(void *srcdata, int srclen, struct fsw_string *dest)
+{
+ fsw_status_t status;
+ int i, destsize;
+ fsw_u8 *sp;
+ fsw_u8 *dp;
+ fsw_u32 c;
+
+ sp = (fsw_u8 *)srcdata;
+ destsize = 0;
+ for (i = 0; i < srclen; i++) {
+ c = *sp++;
+
+ if (c < 0x000080)
+ destsize++;
+ else if (c < 0x000800)
+ destsize += 2;
+ else if (c < 0x010000)
+ destsize += 3;
+ else
+ destsize += 4;
+ }
+
+ dest->type = FSW_STRING_TYPE_UTF8;
+ dest->len = srclen;
+ dest->size = destsize;
+ status = fsw_alloc(dest->size, &dest->data);
+ if (status)
+ return status;
+
+ sp = (fsw_u8 *)srcdata;
+ dp = (fsw_u8 *)dest->data;
+ for (i = 0; i < srclen; i++) {
+ c = *sp++;
+
+ if (c < 0x000080) {
+ *dp++ = (fsw_u8)c;
+ } else if (c < 0x000800) {
+ *dp++ = (fsw_u8)(0xc0 | ((c >> 6) & 0x1f));
+ *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+ } else if (c < 0x010000) {
+ *dp++ = (fsw_u8)(0xe0 | ((c >> 12) & 0x0f));
+ *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+ *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+ } else {
+ *dp++ = (fsw_u8)(0xf0 | ((c >> 18) & 0x07));
+ *dp++ = (fsw_u8)(0x80 | ((c >> 12) & 0x3f));
+ *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+ *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+ }
+ }
+ return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF16_UTF8(void *srcdata, int srclen, struct fsw_string *dest)
+{
+ fsw_status_t status;
+ int i, destsize;
+ fsw_u16 *sp;
+ fsw_u8 *dp;
+ fsw_u32 c;
+
+ sp = (fsw_u16 *)srcdata;
+ destsize = 0;
+ for (i = 0; i < srclen; i++) {
+ c = *sp++;
+
+ if (c < 0x000080)
+ destsize++;
+ else if (c < 0x000800)
+ destsize += 2;
+ else if (c < 0x010000)
+ destsize += 3;
+ else
+ destsize += 4;
+ }
+
+ dest->type = FSW_STRING_TYPE_UTF8;
+ dest->len = srclen;
+ dest->size = destsize;
+ status = fsw_alloc(dest->size, &dest->data);
+ if (status)
+ return status;
+
+ sp = (fsw_u16 *)srcdata;
+ dp = (fsw_u8 *)dest->data;
+ for (i = 0; i < srclen; i++) {
+ c = *sp++;
+
+ if (c < 0x000080) {
+ *dp++ = (fsw_u8)c;
+ } else if (c < 0x000800) {
+ *dp++ = (fsw_u8)(0xc0 | ((c >> 6) & 0x1f));
+ *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+ } else if (c < 0x010000) {
+ *dp++ = (fsw_u8)(0xe0 | ((c >> 12) & 0x0f));
+ *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+ *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+ } else {
+ *dp++ = (fsw_u8)(0xf0 | ((c >> 18) & 0x07));
+ *dp++ = (fsw_u8)(0x80 | ((c >> 12) & 0x3f));
+ *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+ *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+ }
+ }
+ return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF16_SWAPPED_UTF8(void *srcdata, int srclen, struct fsw_string *dest)
+{
+ fsw_status_t status;
+ int i, destsize;
+ fsw_u16 *sp;
+ fsw_u8 *dp;
+ fsw_u32 c;
+
+ sp = (fsw_u16 *)srcdata;
+ destsize = 0;
+ for (i = 0; i < srclen; i++) {
+ c = *sp++; c = FSW_SWAPVALUE_U16(c);
+
+ if (c < 0x000080)
+ destsize++;
+ else if (c < 0x000800)
+ destsize += 2;
+ else if (c < 0x010000)
+ destsize += 3;
+ else
+ destsize += 4;
+ }
+
+ dest->type = FSW_STRING_TYPE_UTF8;
+ dest->len = srclen;
+ dest->size = destsize;
+ status = fsw_alloc(dest->size, &dest->data);
+ if (status)
+ return status;
+
+ sp = (fsw_u16 *)srcdata;
+ dp = (fsw_u8 *)dest->data;
+ for (i = 0; i < srclen; i++) {
+ c = *sp++; c = FSW_SWAPVALUE_U16(c);
+
+ if (c < 0x000080) {
+ *dp++ = (fsw_u8)c;
+ } else if (c < 0x000800) {
+ *dp++ = (fsw_u8)(0xc0 | ((c >> 6) & 0x1f));
+ *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+ } else if (c < 0x010000) {
+ *dp++ = (fsw_u8)(0xe0 | ((c >> 12) & 0x0f));
+ *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+ *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+ } else {
+ *dp++ = (fsw_u8)(0xf0 | ((c >> 18) & 0x07));
+ *dp++ = (fsw_u8)(0x80 | ((c >> 12) & 0x3f));
+ *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+ *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+ }
+ }
+ return FSW_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/test/Makefile b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/test/Makefile
new file mode 100644
index 00000000..376bbba7
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/test/Makefile
@@ -0,0 +1,32 @@
+
+FS=hfs
+
+SOURCES += ../fsw_core.c
+SOURCES += ../fsw_$(FS).c
+SOURCES += ../fsw_lib.c
+SOURCES += fsw_posix.c
+
+OBJ = ${foreach src,$(SOURCES),$(addsuffix .o, $(basename $(src)))}
+
+#lslr.c
+#lsroot.c
+CPPFLAGS += -DHOST_POSIX
+CPPFLAGS += -DFSTYPE=$(FS)
+ASFLAGS += -include asm.h
+CPPFLAGS += -I..
+CPPFLAGS += -I.
+CFLAGS += -g -gdwarf-2
+CFLAGS += -m32
+
+.PHONY: all clear
+all:lslr lsroot
+clean:
+ $(RM) $(OBJ) lslr lsroot lslr.o lsroot.o
+
+lslr: OBJ += lslr.o
+lslr: $(OBJ)
+
+lsroot: OBJ += lsroot.o
+lsroot: $(OBJ)
+
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/test/README b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/test/README
new file mode 100644
index 00000000..c7c34e4d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/test/README
@@ -0,0 +1,2 @@
+This folder contains tests for VBoxFsDxe module, allowing up
+and test filesystems without EFI environment and launching whole VBox.
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/test/fsw_posix.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/test/fsw_posix.c
new file mode 100644
index 00000000..6e8255c6
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/test/fsw_posix.c
@@ -0,0 +1,483 @@
+/**
+ * \file fsw_posix.c
+ * POSIX user space host environment code.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_posix.h"
+
+
+#ifndef FSTYPE
+/** The file system type name to use. */
+#define FSTYPE ext2
+#endif
+
+
+// function prototypes
+
+fsw_status_t fsw_posix_open_dno(struct fsw_posix_volume *pvol, const char *path, int required_type,
+ struct fsw_shandle *shand);
+
+void fsw_posix_change_blocksize(struct fsw_volume *vol,
+ fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
+ fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize);
+fsw_status_t fsw_posix_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer);
+
+/**
+ * Dispatch table for our FSW host driver.
+ */
+
+struct fsw_host_table fsw_posix_host_table = {
+ FSW_STRING_TYPE_ISO88591,
+
+ fsw_posix_change_blocksize,
+ fsw_posix_read_block
+};
+
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(FSTYPE);
+
+
+/**
+ * Mount function.
+ */
+
+struct fsw_posix_volume * fsw_posix_mount(const char *path, struct fsw_fstype_table *fstype_table)
+{
+ fsw_status_t status;
+ struct fsw_posix_volume *pvol;
+
+ // allocate volume structure
+ status = fsw_alloc_zero(sizeof(struct fsw_posix_volume), (void **)&pvol);
+ if (status)
+ return NULL;
+ pvol->fd = -1;
+
+ // open underlying file/device
+ pvol->fd = open(path, O_RDONLY | O_BINARY, 0);
+ if (pvol->fd < 0) {
+ fprintf(stderr, "fsw_posix_mount: %s: %s\n", path, strerror(errno));
+ fsw_free(pvol);
+ return NULL;
+ }
+
+ // mount the filesystem
+ if (fstype_table == NULL)
+ fstype_table = &FSW_FSTYPE_TABLE_NAME(FSTYPE);
+ status = fsw_mount(pvol, &fsw_posix_host_table, fstype_table, &pvol->vol);
+ if (status) {
+ fprintf(stderr, "fsw_posix_mount: fsw_mount returned %d\n", status);
+ fsw_free(pvol);
+ return NULL;
+ }
+
+ return pvol;
+}
+
+/**
+ * Unmount function.
+ */
+
+int fsw_posix_unmount(struct fsw_posix_volume *pvol)
+{
+ if (pvol->vol != NULL)
+ fsw_unmount(pvol->vol);
+ fsw_free(pvol);
+ return 0;
+}
+
+/**
+ * Open a named regular file.
+ */
+
+struct fsw_posix_file * fsw_posix_open(struct fsw_posix_volume *pvol, const char *path, int flags, mode_t mode)
+{
+ fsw_status_t status;
+ struct fsw_posix_file *file;
+
+ // TODO: check flags for unwanted values
+
+ // allocate file structure
+ status = fsw_alloc(sizeof(struct fsw_posix_file), &file);
+ if (status)
+ return NULL;
+ file->pvol = pvol;
+
+ // open the file
+ status = fsw_posix_open_dno(pvol, path, FSW_DNODE_TYPE_FILE, &file->shand);
+ if (status) {
+ fprintf(stderr, "fsw_posix_open: open_dno returned %d\n", status);
+ fsw_free(file);
+ return NULL;
+ }
+
+ return file;
+}
+
+/**
+ * Read data from a regular file.
+ */
+
+ssize_t fsw_posix_read(struct fsw_posix_file *file, void *buf, size_t nbytes)
+{
+ fsw_status_t status;
+ fsw_u32 buffer_size;
+
+ buffer_size = nbytes;
+ status = fsw_shandle_read(&file->shand, &buffer_size, buf);
+ if (status)
+ return -1;
+ return buffer_size;
+}
+
+/**
+ * Change position within a regular file.
+ */
+
+off_t fsw_posix_lseek(struct fsw_posix_file *file, off_t offset, int whence)
+{
+ fsw_u64 base_offset = 0;
+
+ // get base offset
+ base_offset = 0;
+ if (whence == SEEK_CUR)
+ base_offset = file->shand.pos;
+ else if (whence == SEEK_END)
+ base_offset = file->shand.dnode->size;
+
+ // calculate new offset, prevent seeks before the start of the file
+ if (offset < 0 && -offset > base_offset)
+ file->shand.pos = 0;
+ else
+ file->shand.pos = base_offset + offset;
+
+ return file->shand.pos;
+}
+
+/**
+ * Close a regular file.
+ */
+
+int fsw_posix_close(struct fsw_posix_file *file)
+{
+ fsw_shandle_close(&file->shand);
+ fsw_free(file);
+ return 0;
+}
+
+/**
+ * Open a directory for iteration.
+ */
+
+struct fsw_posix_dir * fsw_posix_opendir(struct fsw_posix_volume *pvol, const char *path)
+{
+ fsw_status_t status;
+ struct fsw_posix_dir *dir;
+
+ // allocate file structure
+ status = fsw_alloc(sizeof(struct fsw_posix_dir), &dir);
+ if (status)
+ return NULL;
+ dir->pvol = pvol;
+
+ // open the directory
+ status = fsw_posix_open_dno(pvol, path, FSW_DNODE_TYPE_DIR, &dir->shand);
+ if (status) {
+ fprintf(stderr, "fsw_posix_opendir: open_dno returned %d\n", status);
+ fsw_free(dir);
+ return NULL;
+ }
+
+ return dir;
+}
+
+/**
+ * Read the next entry from a directory.
+ */
+
+struct fsw_posix_dirent * fsw_posix_readdir(struct fsw_posix_dir *dir)
+{
+ fsw_status_t status;
+ struct fsw_dnode *dno;
+ static struct fsw_posix_dirent dent;
+
+ // get next entry from file system
+ status = fsw_dnode_dir_read(&dir->shand, &dno);
+ if (status) {
+ if (status != 4)
+ fprintf(stderr, "fsw_posix_readdir: fsw_dnode_dir_read returned %d\n", status);
+ return NULL;
+ }
+ status = fsw_dnode_fill(dno);
+ if (status) {
+ fprintf(stderr, "fsw_posix_readdir: fsw_dnode_fill returned %d\n", status);
+ fsw_dnode_release(dno);
+ return NULL;
+ }
+
+ // fill dirent structure
+ dent.d_fileno = dno->dnode_id;
+ //dent.d_reclen = 8 + dno->name.size + 1;
+ switch (dno->type) {
+ case FSW_DNODE_TYPE_FILE:
+ dent.d_type = DT_REG;
+ break;
+ case FSW_DNODE_TYPE_DIR:
+ dent.d_type = DT_DIR;
+ break;
+ case FSW_DNODE_TYPE_SYMLINK:
+ dent.d_type = DT_LNK;
+ break;
+ default:
+ dent.d_type = DT_UNKNOWN;
+ break;
+ }
+#if 0
+ dent.d_namlen = dno->name.size;
+#endif
+ memcpy(dent.d_name, dno->name.data, dno->name.size);
+ dent.d_name[dno->name.size] = 0;
+
+ return &dent;
+}
+
+/**
+ * Rewind a directory to the start.
+ */
+
+void fsw_posix_rewinddir(struct fsw_posix_dir *dir)
+{
+ dir->shand.pos = 0;
+}
+
+/**
+ * Close a directory.
+ */
+
+int fsw_posix_closedir(struct fsw_posix_dir *dir)
+{
+ fsw_shandle_close(&dir->shand);
+ fsw_free(dir);
+ return 0;
+}
+
+/**
+ * Open a shand of a required type by path.
+ */
+
+fsw_status_t fsw_posix_open_dno(struct fsw_posix_volume *pvol, const char *path, int required_type, struct fsw_shandle *shand)
+{
+ fsw_status_t status;
+ struct fsw_dnode *dno;
+ struct fsw_dnode *target_dno;
+ struct fsw_string lookup_path;
+
+ lookup_path.type = FSW_STRING_TYPE_ISO88591;
+ lookup_path.len = strlen(path);
+ lookup_path.size = lookup_path.len;
+ lookup_path.data = (void *)path;
+
+ // resolve the path (symlinks along the way are automatically resolved)
+ status = fsw_dnode_lookup_path(pvol->vol->root, &lookup_path, '/', &dno);
+ if (status) {
+ fprintf(stderr, "fsw_posix_open_dno: fsw_dnode_lookup_path returned %d\n", status);
+ return status;
+ }
+
+ // if the final node is a symlink, also resolve it
+ status = fsw_dnode_resolve(dno, &target_dno);
+ fsw_dnode_release(dno);
+ if (status) {
+ fprintf(stderr, "fsw_posix_open_dno: fsw_dnode_resolve returned %d\n", status);
+ return status;
+ }
+ dno = target_dno;
+
+ // check that it is a regular file
+ status = fsw_dnode_fill(dno);
+ if (status) {
+ fprintf(stderr, "fsw_posix_open_dno: fsw_dnode_fill returned %d\n", status);
+ fsw_dnode_release(dno);
+ return status;
+ }
+ if (dno->type != required_type) {
+ fprintf(stderr, "fsw_posix_open_dno: dnode is not of the requested type\n");
+ fsw_dnode_release(dno);
+ return FSW_UNSUPPORTED;
+ }
+
+ // open shandle
+ status = fsw_shandle_open(dno, shand);
+ if (status) {
+ fprintf(stderr, "fsw_posix_open_dno: fsw_shandle_open returned %d\n", status);
+ }
+ fsw_dnode_release(dno);
+ return status;
+}
+
+/**
+ * FSW interface function for block size changes. This function is called by the FSW core
+ * when the file system driver changes the block sizes for the volume.
+ */
+
+void fsw_posix_change_blocksize(struct fsw_volume *vol,
+ fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
+ fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize)
+{
+ // nothing to do
+}
+
+/**
+ * FSW interface function to read data blocks. This function is called by the FSW core
+ * to read a block of data from the device. The buffer is allocated by the core code.
+ */
+
+fsw_status_t fsw_posix_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer)
+{
+ struct fsw_posix_volume *pvol = (struct fsw_posix_volume *)vol->host_data;
+ off_t block_offset, seek_result;
+ ssize_t read_result;
+
+ FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_posix_read_block: %d (%d)\n"), phys_bno, vol->phys_blocksize));
+
+ // read from disk
+ block_offset = (off_t)phys_bno * vol->phys_blocksize;
+ seek_result = lseek(pvol->fd, block_offset, SEEK_SET);
+ if (seek_result != block_offset) {
+ fprintf(stderr, "fsw_posix_read_block: failed to seek to block %u (offset %u)\n", phys_bno, block_offset);
+ return FSW_IO_ERROR;
+ }
+ read_result = read(pvol->fd, buffer, vol->phys_blocksize);
+ if (read_result != vol->phys_blocksize) {
+ fprintf(stderr, "fsw_posix_read_block: failed to read %u bytes at %u\n", vol->phys_blocksize, block_offset);
+ return FSW_IO_ERROR;
+ }
+
+ return FSW_SUCCESS;
+}
+
+
+/**
+ * Time mapping callback for the fsw_dnode_stat call. This function converts
+ * a Posix style timestamp into an EFI_TIME structure and writes it to the
+ * appropriate member of the EFI_FILE_INFO structure that we're filling.
+ */
+
+/*
+static void fsw_posix_store_time_posix(struct fsw_dnode_stat *sb, int which, fsw_u32 posix_time)
+{
+ EFI_FILE_INFO *FileInfo = (EFI_FILE_INFO *)sb->host_data;
+
+ if (which == FSW_DNODE_STAT_CTIME)
+ fsw_posix_decode_time(&FileInfo->CreateTime, posix_time);
+ else if (which == FSW_DNODE_STAT_MTIME)
+ fsw_posix_decode_time(&FileInfo->ModificationTime, posix_time);
+ else if (which == FSW_DNODE_STAT_ATIME)
+ fsw_posix_decode_time(&FileInfo->LastAccessTime, posix_time);
+}
+*/
+
+/**
+ * Mode mapping callback for the fsw_dnode_stat call. This function looks at
+ * the Posix mode passed by the file system driver and makes appropriate
+ * adjustments to the EFI_FILE_INFO structure that we're filling.
+ */
+
+/*
+static void fsw_posix_store_attr_posix(struct fsw_dnode_stat *sb, fsw_u16 posix_mode)
+{
+ EFI_FILE_INFO *FileInfo = (EFI_FILE_INFO *)sb->host_data;
+
+ if ((posix_mode & S_IWUSR) == 0)
+ FileInfo->Attribute |= EFI_FILE_READ_ONLY;
+}
+*/
+
+/**
+ * Common function to fill an EFI_FILE_INFO with information about a dnode.
+ */
+
+/*
+EFI_STATUS fsw_posix_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume,
+ IN struct fsw_dnode *dno,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer)
+{
+ EFI_STATUS Status;
+ EFI_FILE_INFO *FileInfo;
+ UINTN RequiredSize;
+ struct fsw_dnode_stat sb;
+
+ // make sure the dnode has complete info
+ Status = fsw_posix_map_status(fsw_dnode_fill(dno), Volume);
+ if (EFI_ERROR(Status))
+ return Status;
+
+ // TODO: check/assert that the dno's name is in UTF16
+
+ // check buffer size
+ RequiredSize = SIZE_OF_EFI_FILE_INFO + fsw_posix_strsize(&dno->name);
+ if (*BufferSize < RequiredSize) {
+ // TODO: wind back the directory in this case
+
+ *BufferSize = RequiredSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ // fill structure
+ ZeroMem(Buffer, RequiredSize);
+ FileInfo = (EFI_FILE_INFO *)Buffer;
+ FileInfo->Size = RequiredSize;
+ FileInfo->FileSize = dno->size;
+ FileInfo->Attribute = 0;
+ if (dno->type == FSW_DNODE_TYPE_DIR)
+ FileInfo->Attribute |= EFI_FILE_DIRECTORY;
+ fsw_posix_strcpy(FileInfo->FileName, &dno->name);
+
+ // get the missing info from the fs driver
+ ZeroMem(&sb, sizeof(struct fsw_dnode_stat));
+ sb.store_time_posix = fsw_posix_store_time_posix;
+ sb.store_attr_posix = fsw_posix_store_attr_posix;
+ sb.host_data = FileInfo;
+ Status = fsw_posix_map_status(fsw_dnode_stat(dno, &sb), Volume);
+ if (EFI_ERROR(Status))
+ return Status;
+ FileInfo->PhysicalSize = sb.used_bytes;
+
+ // prepare for return
+ *BufferSize = RequiredSize;
+ return EFI_SUCCESS;
+}
+*/
+
+// EOF
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/test/fsw_posix.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/test/fsw_posix.h
new file mode 100644
index 00000000..4df2bbca
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/test/fsw_posix.h
@@ -0,0 +1,120 @@
+/**
+ * \file fsw_posix.h
+ * POSIX user space host environment header.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_POSIX_H_
+#define _FSW_POSIX_H_
+
+#include "fsw_core.h"
+
+#include <fcntl.h>
+#include <sys/types.h>
+
+
+/**
+ * POSIX Host: Private per-volume structure.
+ */
+
+struct fsw_posix_volume {
+ struct fsw_volume *vol; //!< FSW volume structure
+
+ int fd; //!< System file descriptor for data access
+
+};
+
+/**
+ * POSIX Host: Private structure for an open file.
+ */
+
+struct fsw_posix_file {
+ struct fsw_posix_volume *pvol; //!< POSIX host volume structure
+
+ struct fsw_shandle shand; //!< FSW handle for this file
+
+};
+
+/**
+ * POSIX Host: Private structure for an open directory.
+ */
+
+struct fsw_posix_dir {
+ struct fsw_posix_volume *pvol; //!< POSIX host volume structure
+
+ struct fsw_shandle shand; //!< FSW handle for this file
+
+};
+
+
+#define NAME_MAX 4096
+
+#define DT_UNKNOWN 'u'
+#define DT_REG 'r'
+#define DT_DIR 'd'
+#define DT_LNK 'l'
+
+
+/**
+ * POSIX Host: Private structure for an open directory.
+ */
+
+struct fsw_posix_dirent {
+ char d_attr; /* file's attribute */
+ unsigned d_type;
+ unsigned short int d_time; /* file's time */
+ unsigned short int d_date; /* file's date */
+ long d_size; /* file's size */
+ char d_name[NAME_MAX+1]; /* file's name */
+ unsigned d_fileno; /* file number/inode */
+};
+typedef struct fsw_posix_dirent DIR;
+
+/* functions */
+
+struct fsw_posix_volume * fsw_posix_mount(const char *path, struct fsw_fstype_table *fstype_table);
+int fsw_posix_unmount(struct fsw_posix_volume *pvol);
+
+struct fsw_posix_file * fsw_posix_open(struct fsw_posix_volume *pvol, const char *path, int flags, mode_t mode);
+ssize_t fsw_posix_read(struct fsw_posix_file *file, void *buf, size_t nbytes);
+off_t fsw_posix_lseek(struct fsw_posix_file *file, off_t offset, int whence);
+int fsw_posix_close(struct fsw_posix_file *file);
+
+struct fsw_posix_dir * fsw_posix_opendir(struct fsw_posix_volume *pvol, const char *path);
+struct fsw_posix_dirent * fsw_posix_readdir(struct fsw_posix_dir *dir);
+void fsw_posix_rewinddir(struct fsw_posix_dir *dir);
+int fsw_posix_closedir(struct fsw_posix_dir *dir);
+
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/test/fsw_posix_base.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/test/fsw_posix_base.h
new file mode 100644
index 00000000..114e21fd
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/test/fsw_posix_base.h
@@ -0,0 +1,90 @@
+/**
+ * \file fsw_posix_base.h
+ * Base definitions for the POSIX user space host environment.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_POSIX_BASE_H_
+#define _FSW_POSIX_BASE_H_
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdint.h>
+
+#define FSW_LITTLE_ENDIAN (1)
+// TODO: use info from the headers to define FSW_LITTLE_ENDIAN or FSW_BIG_ENDIAN
+
+
+// types
+
+typedef int8_t fsw_s8;
+typedef uint8_t fsw_u8;
+typedef int16_t fsw_s16;
+typedef uint16_t fsw_u16;
+typedef int32_t fsw_s32;
+typedef uint32_t fsw_u32;
+typedef int64_t fsw_s64;
+typedef uint64_t fsw_u64;
+
+
+// allocation functions
+
+#define fsw_alloc(size, ptrptr) (((*(ptrptr) = malloc(size)) == NULL) ? FSW_OUT_OF_MEMORY : FSW_SUCCESS)
+#define fsw_free(ptr) free(ptr)
+
+// memory functions
+
+#define fsw_memzero(dest,size) memset(dest,0,size)
+#define fsw_memcpy(dest,src,size) memcpy(dest,src,size)
+#define fsw_memeq(p1,p2,size) (memcmp(p1,p2,size) == 0)
+
+// message printing
+
+#define FSW_MSGSTR(s) s
+#define FSW_MSGFUNC printf
+
+// 64-bit hooks
+
+#define FSW_U64_SHR(val,shiftbits) ((val) >> (shiftbits))
+#define FSW_U64_DIV(val,divisor) ((val) / (divisor))
+#define DEBUG(x)
+
+#define RShiftU64(val, shift) ((val) >> (shift))
+#define LShiftU64(val, shift) ((val) << (shift))
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/test/lslr.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/test/lslr.c
new file mode 100644
index 00000000..19442916
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/test/lslr.c
@@ -0,0 +1,140 @@
+/**
+ * \file lslr.c
+ * Test program for the POSIX user space environment.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_posix.h"
+
+
+//extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(ext2);
+//extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(reiserfs);
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(FSTYPE);
+
+static struct fsw_fstype_table *fstypes[] = {
+ //&FSW_FSTYPE_TABLE_NAME(ext2),
+ //&FSW_FSTYPE_TABLE_NAME(reiserfs),
+ &FSW_FSTYPE_TABLE_NAME(FSTYPE ),
+ NULL
+};
+
+static int listdir(struct fsw_posix_volume *vol, char *path, int level)
+{
+ struct fsw_posix_dir *dir;
+ struct fsw_posix_dirent *dent;
+ int i;
+ char subpath[4096];
+
+ dir = fsw_posix_opendir(vol, path);
+ if (dir == NULL) {
+ printf("opendir(%s) call failed.\n", path);
+ return 1;
+ }
+ while ((dent = fsw_posix_readdir(dir)) != NULL) {
+ for (i = 0; i < level*2; i++)
+ fputc(' ', stdout);
+ printf("%c %s\n", dent->d_type, dent->d_name);
+
+ if (dent->d_type == DT_DIR) {
+ snprintf(subpath, 4095, "%s%s/", path, dent->d_name);
+ listdir(vol, subpath, level + 1);
+ }
+ }
+ fsw_posix_closedir(dir);
+
+ return 0;
+}
+
+static int catfile(struct fsw_posix_volume *vol, char *path)
+{
+ struct fsw_posix_file *file;
+ int r;
+ char buf[256];
+
+ file = fsw_posix_open(vol, path, 0, 0);
+ if (file == NULL) {
+ printf("open(%s) call failed.\n", path);
+ return 1;
+ }
+ while ((r=fsw_posix_read(file, buf, sizeof(buf))) > 0)
+ {
+ int i;
+ for (i=0; i<r; i++)
+ {
+ printf("%c", buf[i]);
+ }
+ }
+ fsw_posix_close(file);
+
+ return 0;
+}
+
+extern fsw_status_t fsw_hfs_get_blessed_file(struct fsw_hfs_volume *vol, struct fsw_string *link_target);
+
+int main(int argc, char **argv)
+{
+ struct fsw_posix_volume *vol;
+ struct fsw_string blessed;
+ int i;
+
+ if (argc != 2) {
+ printf("Usage: lslr <file/device>\n");
+ return 1;
+ }
+
+ for (i = 0; fstypes[i]; i++) {
+ vol = fsw_posix_mount(argv[1], fstypes[i]);
+ if (vol != NULL) {
+ printf("Mounted as '%s'.\n", fstypes[i]->name.data);
+ break;
+ }
+ }
+ if (vol == NULL) {
+ printf("Mounting failed.\n");
+ return 1;
+ }
+
+ listdir(vol, "/System/Library/CoreServices", 0);
+ //listdir(vol, "/System/Library/Extensions/AppleACPIPlatform.kext/", 0);
+ //listdir(vol, "/System/Library/Extensions/", 0);
+ catfile(vol, "/System/Library/CoreServices/SystemVersion.plist");
+ //listdir(vol, "/", 0);
+ fsw_hfs_get_blessed_file((struct fsw_hfs_volume *)vol->vol, &blessed);
+
+ fsw_posix_unmount(vol);
+
+ return 0;
+}
+
+// EOF
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/test/lsroot.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/test/lsroot.c
new file mode 100644
index 00000000..741ae4c2
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/test/lsroot.c
@@ -0,0 +1,79 @@
+/**
+ * \file lsroot.c
+ * Example program for the POSIX user space environment.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_posix.h"
+
+
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(ext2);
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(reiserfs);
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(iso9660);
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(hfs);
+
+int main(int argc, char **argv)
+{
+ struct fsw_posix_volume *vol;
+ struct fsw_posix_dir *dir;
+ struct fsw_posix_dirent *dent;
+
+ if (argc != 3) {
+ printf("Usage: lsroot <file/device> <directory>\n");
+ return 1;
+ }
+
+ //vol = fsw_posix_mount(argv[1], &FSW_FSTYPE_TABLE_NAME(ext2));
+ //vol = fsw_posix_mount(argv[1], &FSW_FSTYPE_TABLE_NAME(reiserfs));
+ vol = fsw_posix_mount(argv[1], &FSW_FSTYPE_TABLE_NAME(FSTYPE));
+ if (vol == NULL) {
+ printf("Mounting failed.\n");
+ return 1;
+ }
+ //dir = fsw_posix_opendir(vol, "/drivers/net/");
+ dir = fsw_posix_opendir(vol, argv[2]);
+ if (dir == NULL) {
+ printf("opendir call failed.\n");
+ return 1;
+ }
+ while ((dent = fsw_posix_readdir(dir)) != NULL) {
+ printf("%c %s %u\n", dent->d_type, dent->d_name, dent->d_fileno);
+ }
+ fsw_posix_closedir(dir);
+ fsw_posix_unmount(vol);
+
+ return 0;
+}
+
+// EOF
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/BootService.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/BootService.c
new file mode 100644
index 00000000..07c8cea8
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/BootService.c
@@ -0,0 +1,41 @@
+/* $Id: BootService.c $ */
+/** @file
+ * BootService.c - boot service intercepter.
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+#define SERVICE bs
+#define ORIG_SERVICE gBS
+
+#include "VBoxInterceptor.h"
+#define SERVICE_H "boot_service_table.h"
+#include "interceptor.h"
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/README b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/README
new file mode 100644
index 00000000..4126bc8f
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/README
@@ -0,0 +1,3 @@
+This module isn't supposed to be used in normal UEFI imulation.
+It dumps calls to EFI cores from EFI guests helping in investigation
+of EFI guests behaviour and expectations.
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/RunTime.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/RunTime.c
new file mode 100644
index 00000000..23728395
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/RunTime.c
@@ -0,0 +1,41 @@
+/* $Id: RunTime.c $ */
+/** @file
+ * Runtime.c - runtime service intercepter.
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+#define SERVICE rt
+#define ORIG_SERVICE gRT
+
+#include "VBoxInterceptor.h"
+#define SERVICE_H "runtime_service_table.h"
+#include "interceptor.h"
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/VBoxInterceptor.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/VBoxInterceptor.c
new file mode 100644
index 00000000..02c8b388
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/VBoxInterceptor.c
@@ -0,0 +1,129 @@
+/* $Id: VBoxInterceptor.c $ */
+/** @file
+ * VBoxIntercepter.c - Entry point.
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+#include "VBoxInterceptor.h"
+
+#define VBOX_INTERCEPTOR_VAR L"VBOX_INTERCEPTOR"
+/*8e7505ec-d103-11de-8dbb-678848bdcb46*/
+static EFI_GUID gVBoxInterceptorVarGuid = { 0x817505ec, 0xd103, 0x11de, {0x8d, 0xbb, 0x67, 0x88, 0x48, 0xbd, 0xcb, 0x46}};
+
+static int g_indent = 0;
+
+static char* getIndent(int count, int enter)
+{
+ static char buf[64];
+ int i;
+ char ch = enter ? '>' : '<';
+
+ for (i=0; i<count+1; i++)
+ buf[i] = ch;
+
+ buf[i++] = ' ';
+ buf[i] = 0;
+
+ return buf;
+}
+
+char* indentRight()
+{
+ return getIndent(g_indent++, 1);
+}
+
+char* indentLeft()
+{
+ return getIndent(--g_indent, 0);
+}
+
+
+EFI_STATUS
+EFIAPI
+VBoxInterceptorInit(EFI_HANDLE hImage, EFI_SYSTEM_TABLE *pSysTable)
+{
+ /* Set'n'check intercept variable */
+ EFI_STATUS r;
+ UINT32 val;
+ UINTN size = sizeof(UINT32);
+ r = gRT->GetVariable(VBOX_INTERCEPTOR_VAR, &gVBoxInterceptorVarGuid, NULL, &size, &val);
+ if ( EFI_ERROR(r)
+ && r == EFI_NOT_FOUND)
+ {
+ size = sizeof(UINT32);
+ val = 1;
+ r = gRT->SetVariable(VBOX_INTERCEPTOR_VAR, &gVBoxInterceptorVarGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, size, &val);
+ if (EFI_ERROR(r))
+ {
+ DEBUG((DEBUG_INFO, "%a:%d - %r\n", __FILE__, __LINE__, r));
+ return r;
+ }
+ /* intercept installation */
+ gThis = AllocateZeroPool(sizeof(VBOXINTERCEPTOR));
+ r = install_bs_interceptors();
+ if(EFI_ERROR(r))
+ {
+ DEBUG((DEBUG_INFO, "%a:%d - %r\n", __FILE__, __LINE__, r));
+ return r;
+ }
+
+ r = install_rt_interceptors();
+ if(EFI_ERROR(r))
+ {
+ DEBUG((DEBUG_INFO, "%a:%d - %r\n", __FILE__, __LINE__, r));
+ return r;
+ }
+ return r;
+ }
+ if (!EFI_ERROR(r))
+ {
+ return EFI_ALREADY_STARTED;
+ }
+ return r;
+}
+
+EFI_STATUS
+EFIAPI
+VBoxInterceptorFini(EFI_HANDLE hImage)
+{
+ EFI_STATUS r;
+ uninstall_rt_interceptors();
+ uninstall_bs_interceptors();
+ FreePool(gThis);
+ r = gRT->SetVariable(VBOX_INTERCEPTOR_VAR, &gVBoxInterceptorVarGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 0, NULL);
+ if (EFI_ERROR(r))
+ {
+ DEBUG((DEBUG_INFO, "%a:%d - %r\n", __FILE__, __LINE__, r));
+ return r;
+ }
+ return EFI_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/VBoxInterceptor.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/VBoxInterceptor.h
new file mode 100644
index 00000000..7c409bd0
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/VBoxInterceptor.h
@@ -0,0 +1,152 @@
+/* $Id: VBoxInterceptor.h $ */
+/** @file
+ * VBoxInterceptor.h - Helpful macrodefinitions used in the interceptor.
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+#ifndef __VBOXINTERCEPTOR_H__
+#define __VBOXINTERCEPTOR_H__
+#include <Uefi.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include "print_types.h"
+
+#define VBOXINTERCEPTOR VBoxInterceptor
+#define XCONCAT(a,b) a##b
+#define CONCAT(a,b) XCONCAT(a,b)
+#define CONCAT3(a,b,c) a ## b ## c
+
+#define SCL(type) PRNT_##type, type
+#define PTR(type) PRNT_P_##type, type *
+#define PTR2(type) PRNT_PP_##type, type **
+#define PTR3(type) PRNT_PP_##type, type ***
+#define PTRC(type) PRNT_P_##type, CONST type *
+
+#define PARAMETER1(ign0, type0) type0 a0
+#define PARAMETER2(ign0, type0, ign1, type1) type0 a0, type1 a1
+#define PARAMETER3(ign0, type0, ign1, type1, ign2, type2) type0 a0, type1 a1, type2 a2
+#define PARAMETER4(ign0, type0, ign1, type1, ign2, type2, ign3, type3) type0 a0, type1 a1, type2 a2, type3 a3
+#define PARAMETER5(ign0, type0, ign1, type1, ign2, type2, ign3, type3, ign4, type4) type0 a0, type1 a1, type2 a2, type3 a3, type4 a4
+#define PARAMETER6(ign0, type0, ign1, type1, ign2, type2, ign3, type3, ign4, type4, ign5, type5) type0 a0, type1 a1, type2 a2, type3 a3, type4 a4, type5 a5
+
+#define PARAMETER(x) PARAMETER##x
+
+#define PRNT_PARAMETER1(f0, ign0) "(" f0 ")"
+#define PRNT_PARAMETER2(f0, ign0, f1, ign1) "(" f0 "," f1 ")"
+#define PRNT_PARAMETER3(f0, ign0, f1, ign1, f2, ign2) "(" f0 "," f1 "," f2 ")"
+#define PRNT_PARAMETER4(f0, ign0, f1, ign1, f2, ign2, f3, ign3) "(" f0 "," f1 "," f2 "," f3 ")"
+#define PRNT_PARAMETER5(f0, ign0, f1, ign1, f2, ign2, f3, ign3, f4, ign4) "(" f0 "," f1 "," f2 "," f3 "," f4 ")"
+#define PRNT_PARAMETER6(f0, ign0, f1, ign1, f2, ign2, f3, ign3, f4, ign4, f5, ign5) "(" f0 "," f1 "," f2 "," f3 "," f4 "," f5 ")"
+
+#define PRNT_PARAMETERS(x) PRNT_PARAMETER##x
+
+#define ARGS1 a0
+#define ARGS2 a0, a1
+#define ARGS3 a0, a1, a2
+#define ARGS4 a0, a1, a2, a3
+#define ARGS5 a0, a1, a2, a3, a4
+#define ARGS6 a0, a1, a2, a3, a4, a5
+
+#define ARGS(x) ARGS##x
+
+char* indentRight();
+char* indentLeft();
+
+#if ARCH_BITS == 64
+# define ARCH_FRAME_POINTER "rbp"
+#elif ARCH_BITS == 32
+# define ARCH_FRAME_POINTER "ebp"
+#else
+# error "port me"
+#endif
+
+#define DUMP_STACK(depth) \
+do { \
+ int i; \
+ UINTN *bp = (UINTN *)frame_pointer; \
+ for (i = 0; i < depth; ++i) \
+ { \
+ DEBUG((DEBUG_INFO, "[%d frame pbp:%x ip: %x]\n", i, bp[0], bp[1])); \
+ if (bp == NULL || bp < (UINTN *)0x1000) \
+ break; \
+ bp = *(UINTN **)bp; \
+ } \
+} while(0)
+
+
+register volatile UINTN *frame_pointer asm(ARCH_FRAME_POINTER);
+
+#define FUNCTION(RET_TYPE) RET_TYPE ## _FUNCTION
+#define RVOID_FUNCTION(return_type, func_name, nparams, params) \
+static void EFIAPI CONCAT(VBOXINTERCEPTOR,func_name)(PARAMETER(nparams)params) \
+{ \
+ UINT32 off = (UINT32)(uintptr_t)&(((typeof(gThis))0)->CONCAT(SERVICE,Orig).func_name); \
+ DEBUG((DEBUG_INFO, "%a%a[%x] enter " PRNT_PARAMETERS(nparams)params "\n", \
+ indentRight(), #func_name, off, ARGS(nparams))); \
+ DUMP_STACK(2); \
+ gThis->CONCAT(SERVICE,Orig).func_name(ARGS(nparams)); \
+ DEBUG((DEBUG_INFO, "%a%a exit \n", indentLeft(), #func_name)); \
+}
+
+/*XXX: Assume atm that Bs and Rt if func returns smth, this smt is EFI_STATUS */
+#define NVOID_FUNCTION(return_type, func_name, nparams, params) \
+static return_type EFIAPI CONCAT(VBOXINTERCEPTOR,func_name)(PARAMETER(nparams)params) \
+{ \
+ return_type r; \
+ UINT32 off = (UINT32)(uintptr_t)&(((typeof(gThis))0)->CONCAT(SERVICE,Orig).func_name); \
+ DEBUG((DEBUG_INFO, "%a%a[%x] enter " PRNT_PARAMETERS(nparams)params "\n", \
+ indentRight(), #func_name, off, ARGS(nparams))); \
+ DUMP_STACK(2); \
+ r =gThis->CONCAT(SERVICE,Orig).func_name(ARGS(nparams)); \
+ DEBUG((DEBUG_INFO, "%a%a exit:(%r) \n", \
+ indentLeft(), #func_name, r)); \
+ return r; \
+}
+
+#define INSTALLER(x) CONCAT3(install_ ,x, _interceptors)
+#define UNINSTALLER(x) CONCAT3(uninstall_,x,_interceptors)
+
+typedef struct {
+ EFI_BOOT_SERVICES bsOrig;
+ EFI_RUNTIME_SERVICES rtOrig;
+} VBOXINTERCEPTOR, *PVBOXINTERCEPTOR;
+
+PVBOXINTERCEPTOR gThis;
+
+EFI_STATUS install_bs_interceptors();
+EFI_STATUS uninstall_bs_interceptors();
+EFI_STATUS install_rt_interceptors();
+EFI_STATUS uninstall_rt_interceptors();
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/VBoxInterceptorDxe.inf b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/VBoxInterceptorDxe.inf
new file mode 100644
index 00000000..670d2b17
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/VBoxInterceptorDxe.inf
@@ -0,0 +1,86 @@
+# $Id: VBoxInterceptorDxe.inf $
+#* @file
+# VBoxInterceptorDxe.inf - Interceptor module declaration.
+
+
+#
+# Copyright (C) 2009-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>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VBoxInterceptorDxe
+ FILE_GUID = FE3542FE-C1D3-4EF8-657C-8048606FF671
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = VBoxInterceptorInit
+ UNLOAD_IMAGE = VBoxInterceptorFini
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+ VBoxInterceptor.c
+ RunTime.c
+ BootService.c
+ boot_service_table.h
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ BaseLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ HiiLib
+ PrintLib
+
+[Guids]
+ gEfiIfrTianoGuid ## CONSUMES ## Guid
+
+[Protocols]
+ gEfiHiiStringProtocolGuid ## CONSUMES
+ gEfiHiiConfigRoutingProtocolGuid ## CONSUMES
+ gEfiHiiConfigAccessProtocolGuid ## PRODUCES
+ gEfiFormBrowser2ProtocolGuid ## CONSUMES
+ gEfiHiiDatabaseProtocolGuid ## CONSUMES
+
+
+[Depex]
+ gEfiSimpleTextOutProtocolGuid AND gEfiHiiDatabaseProtocolGuid AND gEfiVariableArchProtocolGuid AND gEfiVariableWriteArchProtocolGuid
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/boot_service_table.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/boot_service_table.h
new file mode 100644
index 00000000..3e36a0bc
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/boot_service_table.h
@@ -0,0 +1,103 @@
+/* $Id: boot_service_table.h $ */
+/** @file
+ * boot_service_table.h - boot service table declaration.
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/* NVOID - Non VOID, RVOID - Return VOID */
+/*
+ * PRINTS FLAGS
+ * SCL -type
+ * PTR, PTR2, PTR3 - type *(**)(***)
+ */
+#if 0
+/* Too much traffic */
+TBL_ENTRY(EFI_RAISE_TPL, RaiseTPL, NVOID, EFI_TPL, 1, (SCL(EFI_TPL)))
+TBL_ENTRY(EFI_RESTORE_TPL, RestoreTPL, RVOID, VOID, 1, (SCL(EFI_TPL)))
+#endif
+TBL_ENTRY(EFI_ALLOCATE_PAGES, AllocatePages, NVOID, EFI_STATUS, 4, (SCL(EFI_ALLOCATE_TYPE ), SCL(EFI_MEMORY_TYPE), SCL(UINTN), PTR(EFI_PHYSICAL_ADDRESS)))
+TBL_ENTRY(EFI_FREE_PAGES, FreePages, NVOID, EFI_STATUS, 2, (SCL(EFI_PHYSICAL_ADDRESS), SCL(UINTN)))
+TBL_ENTRY(EFI_GET_MEMORY_MAP, GetMemoryMap, NVOID, EFI_STATUS, 5, (PTR(UINTN), PTR(EFI_MEMORY_DESCRIPTOR), PTR(UINTN), PTR(UINTN), PTR(UINT32)))
+TBL_ENTRY(EFI_ALLOCATE_POOL, AllocatePool, NVOID, EFI_STATUS, 3, (SCL(EFI_MEMORY_TYPE), SCL(UINTN), PTR2(VOID)))
+TBL_ENTRY(EFI_FREE_POOL, FreePool, NVOID, EFI_STATUS, 1, (PTR(VOID)))
+TBL_ENTRY(EFI_CREATE_EVENT, CreateEvent, NVOID, EFI_STATUS, 5, (SCL(UINT32), SCL(EFI_TPL), SCL(EFI_EVENT_NOTIFY), PTR(VOID), PTR(EFI_EVENT)))
+TBL_ENTRY(EFI_SET_TIMER, SetTimer, NVOID, EFI_STATUS, 3, (SCL(EFI_EVENT), SCL(EFI_TIMER_DELAY), SCL(UINT64)))
+TBL_ENTRY(EFI_WAIT_FOR_EVENT, WaitForEvent, NVOID, EFI_STATUS, 3, (SCL(UINTN), PTR(EFI_EVENT), PTR(UINTN)))
+TBL_ENTRY(EFI_SIGNAL_EVENT, SignalEvent, NVOID, EFI_STATUS, 1, (SCL(EFI_EVENT)))
+TBL_ENTRY(EFI_CLOSE_EVENT, CloseEvent, NVOID, EFI_STATUS, 1, (SCL(EFI_EVENT)))
+#if 0
+/* Too much traffic */
+TBL_ENTRY(EFI_CHECK_EVENT, CheckEvent, NVOID, EFI_STATUS, 1, (SCL(EFI_EVENT)))
+#endif
+
+TBL_ENTRY(EFI_INSTALL_PROTOCOL_INTERFACE, InstallProtocolInterface, NVOID, EFI_STATUS, 4, (PTR(EFI_HANDLE), PTR(EFI_GUID), SCL(EFI_INTERFACE_TYPE), PTR(VOID)))
+TBL_ENTRY(EFI_REINSTALL_PROTOCOL_INTERFACE, ReinstallProtocolInterface, NVOID, EFI_STATUS, 4, (SCL(EFI_HANDLE), PTR(EFI_GUID), PTR(VOID), PTR(VOID)))
+TBL_ENTRY(EFI_UNINSTALL_PROTOCOL_INTERFACE, UninstallProtocolInterface, NVOID, EFI_STATUS, 3, (SCL(EFI_HANDLE), PTR(EFI_GUID), PTR(VOID)))
+TBL_ENTRY(EFI_HANDLE_PROTOCOL, HandleProtocol, NVOID, EFI_STATUS, 3, (SCL(EFI_HANDLE), PTR(EFI_GUID), PTR2(VOID)))
+TBL_ENTRY(EFI_REGISTER_PROTOCOL_NOTIFY, RegisterProtocolNotify, NVOID, EFI_STATUS, 3, (PTR(EFI_GUID), SCL(EFI_EVENT), PTR2(VOID)))
+
+TBL_ENTRY(EFI_LOCATE_HANDLE, LocateHandle, NVOID, EFI_STATUS, 5, (SCL(EFI_LOCATE_SEARCH_TYPE), PTR(EFI_GUID), PTR(VOID), PTR(UINTN), PTR(EFI_HANDLE)))
+
+TBL_ENTRY(EFI_LOCATE_DEVICE_PATH, LocateDevicePath, NVOID, EFI_STATUS, 3, (PTR(EFI_GUID), PTR2(EFI_DEVICE_PATH_PROTOCOL), PTR(EFI_HANDLE)))
+TBL_ENTRY(EFI_INSTALL_CONFIGURATION_TABLE, InstallConfigurationTable, NVOID, EFI_STATUS, 2, (PTR(EFI_GUID), PTR(VOID)))
+
+TBL_ENTRY(EFI_IMAGE_LOAD, LoadImage, NVOID, EFI_STATUS, 6, (SCL(BOOLEAN), SCL(EFI_HANDLE), PTR(EFI_DEVICE_PATH_PROTOCOL), PTR(VOID), SCL(UINTN), PTR(EFI_HANDLE)))
+TBL_ENTRY(EFI_IMAGE_START, StartImage, NVOID, EFI_STATUS, 3, (SCL(EFI_HANDLE), PTR(UINTN), PTR2(CHAR16)))
+
+TBL_ENTRY(EFI_EXIT, Exit, NVOID, EFI_STATUS, 4, (SCL(EFI_HANDLE), SCL(EFI_STATUS), SCL(UINTN), PTR(CHAR16)))
+TBL_ENTRY(EFI_IMAGE_UNLOAD, UnloadImage, NVOID, EFI_STATUS, 1, (SCL(EFI_HANDLE)))
+TBL_ENTRY(EFI_EXIT_BOOT_SERVICES, ExitBootServices, NVOID, EFI_STATUS, 2, (SCL(EFI_HANDLE), SCL(UINTN)))
+
+TBL_ENTRY(EFI_GET_NEXT_MONOTONIC_COUNT, GetNextMonotonicCount, NVOID, EFI_STATUS, 1, (PTR(UINT64)))
+TBL_ENTRY(EFI_STALL, Stall, NVOID, EFI_STATUS, 1, (SCL(UINTN)))
+TBL_ENTRY(EFI_SET_WATCHDOG_TIMER, SetWatchdogTimer, NVOID, EFI_STATUS, 4, (SCL(UINTN), SCL(UINT64), SCL(UINTN), PTR(CHAR16)))
+
+TBL_ENTRY(EFI_CONNECT_CONTROLLER, ConnectController, NVOID, EFI_STATUS, 4, (SCL(EFI_HANDLE), PTR(EFI_HANDLE), PTR(EFI_DEVICE_PATH_PROTOCOL), SCL(BOOLEAN)))
+TBL_ENTRY(EFI_DISCONNECT_CONTROLLER, DisconnectController, NVOID, EFI_STATUS, 3, (SCL(EFI_HANDLE), SCL(EFI_HANDLE), SCL(EFI_HANDLE)))
+
+TBL_ENTRY(EFI_OPEN_PROTOCOL, OpenProtocol, NVOID, EFI_STATUS, 6, (SCL(EFI_HANDLE), PTR(EFI_GUID), PTR2(VOID), SCL(EFI_HANDLE), SCL(EFI_HANDLE), SCL(UINT32)))
+TBL_ENTRY(EFI_CLOSE_PROTOCOL, CloseProtocol, NVOID, EFI_STATUS, 4, (SCL(EFI_HANDLE), PTR(EFI_GUID), SCL(EFI_HANDLE), SCL(EFI_HANDLE)))
+TBL_ENTRY(EFI_OPEN_PROTOCOL_INFORMATION, OpenProtocolInformation, NVOID, EFI_STATUS, 4, (SCL(EFI_HANDLE), PTR(EFI_GUID), PTR2(EFI_OPEN_PROTOCOL_INFORMATION_ENTRY), PTR(UINTN)))
+
+TBL_ENTRY(EFI_PROTOCOLS_PER_HANDLE, ProtocolsPerHandle, NVOID, EFI_STATUS, 3, (SCL(EFI_HANDLE), PTR3(EFI_GUID), PTR(UINTN)))
+TBL_ENTRY(EFI_LOCATE_HANDLE_BUFFER, LocateHandleBuffer, NVOID, EFI_STATUS, 5, (SCL(EFI_LOCATE_SEARCH_TYPE), PTR(EFI_GUID), PTR(VOID), PTR(UINTN), PTR2(EFI_HANDLE)))
+TBL_ENTRY(EFI_LOCATE_PROTOCOL, LocateProtocol, NVOID, EFI_STATUS, 3, (PTR(EFI_GUID), PTR(VOID), PTR2(VOID)))
+#if 0
+/* No var args */
+TBL_ENTRY(EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES, InstallMultipleProtocolInterfaces)
+TBL_ENTRY(EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES, UninstallMultipleProtocolInterfaces)
+#endif
+TBL_ENTRY(EFI_CALCULATE_CRC32, CalculateCrc32, NVOID, EFI_STATUS, 3, (PTR(VOID), SCL(UINTN), PTR(UINT32)))
+TBL_ENTRY(EFI_COPY_MEM, CopyMem, RVOID, VOID, 3, (PTR(VOID), PTR(VOID), SCL(UINTN)))
+TBL_ENTRY(EFI_SET_MEM, SetMem, RVOID, VOID, 3, (PTR(VOID), SCL(UINTN), SCL(UINT8)))
+TBL_ENTRY(EFI_CREATE_EVENT_EX, CreateEventEx, NVOID, EFI_STATUS, 6, (SCL(UINT32), SCL(EFI_TPL), SCL(EFI_EVENT_NOTIFY), PTRC(VOID), PTRC(EFI_GUID), PTR(EFI_EVENT)))
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/interceptor.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/interceptor.h
new file mode 100644
index 00000000..d1c2098e
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/interceptor.h
@@ -0,0 +1,70 @@
+/* $Id: interceptor.h $ */
+/** @file
+ * interceptor.h - universal interceptor builder.
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+#define TBL_ENTRY(a,b, ign, return_type, params_num, params) static return_type EFIAPI CONCAT(VBOXINTERCEPTOR,b)(PARAMETER(params_num)params);
+#include SERVICE_H
+#undef TBL_ENTRY
+
+
+#define TBL_ENTRY(a, b, voidness, return_type, nparams, params) \
+ FUNCTION(voidness)(return_type, b, nparams, params)
+#include SERVICE_H
+#undef TBL_ENTRY
+
+
+
+
+EFI_STATUS INSTALLER(SERVICE)()
+{
+#define TBL_ENTRY(a,b, ign0, ign1, ign2, ign3)\
+do { \
+ gThis->CONCAT(SERVICE, Orig).b = ORIG_SERVICE->b; \
+ ORIG_SERVICE->b = CONCAT(VBOXINTERCEPTOR, b); \
+}while (0);
+#include SERVICE_H
+#undef TBL_ENTRY
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS UNINSTALLER(SERVICE)()
+{
+#define TBL_ENTRY(a,b, ign0, ign1, ign2, ign3)\
+do { \
+ ORIG_SERVICE->b = gThis->CONCAT(SERVICE,Orig).b; \
+}while (0);
+#include SERVICE_H
+#undef TBL_ENTRY
+ return EFI_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/print_types.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/print_types.h
new file mode 100644
index 00000000..2766d7c1
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/print_types.h
@@ -0,0 +1,89 @@
+/* $Id: print_types.h $ */
+/** @file
+ * print_types.h - helper macrodifinition to convert types to right printf flags.
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+#ifndef PRINT_TYPES_H
+#define PRINT_TYPES_H
+#define PRNT_EFI_TPL PRNT_UINTN
+#define PRNT_EFI_ALLOCATE_TYPE PRNT_UINTN
+#define PRNT_EFI_MEMORY_TYPE PRNT_UINTN
+#define PRNT_EFI_TIMER_DELAY PRNT_UINTN
+#define PRNT_EFI_EVENT_NOTIFY PRNT_P_VOID
+#define PRNT_EFI_EVENT PRNT_P_VOID
+#define PRNT_EFI_INTERFACE_TYPE PRNT_UINTN
+#define PRNT_EFI_LOCATE_SEARCH_TYPE PRNT_UINTN
+#define PRNT_PP_EFI_CAPSULE_HEADER PRNT_P_VOID
+#define PRNT_P_EFI_RESET_TYPE PRNT_P_UINTN
+#define PRNT_EFI_RESET_TYPE PRNT_P_UINTN
+
+#define PRNT_EFI_HANDLE PRNT_P_VOID
+#define PRNT_P_EFI_HANDLE PRNT_P_VOID
+#define PRNT_PP_EFI_HANDLE PRNT_P_VOID
+
+#define PRNT_PP_EFI_DEVICE_PATH_PROTOCOL PRNT_P_EFI_DEVICE_PATH_PROTOCOL
+#define PRNT_P_EFI_DEVICE_PATH_PROTOCOL PRNT_P_VOID
+#define PRNT_PP_CHAR16 PRNT_P_VOID
+
+/* Pointers */
+#define PRNT_P_EFI_PHYSICAL_ADDRESS PRNT_P_UINT64
+#define PRNT_P_EFI_MEMORY_DESCRIPTOR PRNT_P_VOID
+#define PRNT_PP_VOID PRNT_P_VOID
+#define PRNT_P_EFI_EVENT PRNT_P_VOID
+#define PRNT_P_UINTN PRNT_P_VOID
+#define PRNT_PP_EFI_OPEN_PROTOCOL_INFORMATION_ENTRY PRNT_P_VOID
+#define PRNT_EFI_PHYSICAL_ADDRESS PRNT_UINT64
+#define PRNT_P_EFI_TIME PRNT_P_VOID
+#define PRNT_P_EFI_TIME_CAPABILITIES PRNT_P_VOID
+
+#define PRNT_P_VOID "%p"
+#define PRNT_P_CHAR16 "%s"
+#define PRNT_P_CHAR8 PRNT_P_VOID
+#define PRNT_P_UINT64 PRNT_P_VOID
+#define PRNT_P_UINT32 PRNT_P_VOID
+#define PRNT_P_UINTN PRNT_P_VOID
+#define PRNT_P_UINT8 PRNT_P_VOID
+#define PRNT_PP_EFI_GUID PRNT_P_VOID
+#define PRNT_PPP_EFI_GUID PRNT_P_VOID
+#define PRNT_P_EFI_GUID "%g"
+/* this is machine dependednt */
+#define PRNT_UINT64 "%llx"
+#define PRNT_UINT32 "%x"
+#define PRNT_UINTN "%x"
+#define PRNT_UINT16 "%hx"
+#define PRNT_UINT8 "%c"
+#define PRNT_EFI_STATUS "%r"
+#define PRNT_BOOLEAN PRNT_UINT8
+#define PRNT_CHAR8 PRNT_UINT8
+#define PRNT_P_BOOLEAN PRNT_P_UINT8
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/runtime_service_table.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/runtime_service_table.h
new file mode 100644
index 00000000..3681ff2c
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxInterceptorDxe/runtime_service_table.h
@@ -0,0 +1,69 @@
+/* $Id: runtime_service_table.h $ */
+/** @file
+ * runtime_service_table.h - runtime service table declaration.
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+TBL_ENTRY(EFI_GET_TIME, GetTime, NVOID, EFI_STATUS, 2, (PTR(EFI_TIME), PTR(EFI_TIME_CAPABILITIES)))
+TBL_ENTRY(EFI_SET_TIME, SetTime, NVOID, EFI_STATUS, 1, (PTR(EFI_TIME)))
+TBL_ENTRY(EFI_GET_WAKEUP_TIME, GetWakeupTime, NVOID, EFI_STATUS, 3, (PTR(BOOLEAN), PTR(BOOLEAN), PTR(EFI_TIME)))
+TBL_ENTRY(EFI_SET_WAKEUP_TIME, SetWakeupTime, NVOID, EFI_STATUS, 2, (SCL(BOOLEAN), PTR(EFI_TIME)))
+
+//
+// Virtual Memory Services
+//
+TBL_ENTRY(EFI_SET_VIRTUAL_ADDRESS_MAP, SetVirtualAddressMap, NVOID, EFI_STATUS, 4, (SCL(UINTN), SCL(UINTN), SCL(UINT32), PTR(EFI_MEMORY_DESCRIPTOR)))
+TBL_ENTRY(EFI_CONVERT_POINTER, ConvertPointer, NVOID, EFI_STATUS, 2, (SCL(UINTN), PTR2(VOID)))
+
+//
+// Variable Services
+//
+TBL_ENTRY(EFI_GET_VARIABLE, GetVariable, NVOID, EFI_STATUS, 5, (PTR(CHAR16), PTR(EFI_GUID), PTR(UINT32), PTR(UINTN), PTR(VOID)))
+TBL_ENTRY(EFI_GET_NEXT_VARIABLE_NAME, GetNextVariableName, NVOID, EFI_STATUS, 3, (PTR(UINTN), PTR(CHAR16), PTR(EFI_GUID)))
+TBL_ENTRY(EFI_SET_VARIABLE, SetVariable, NVOID, EFI_STATUS, 5, (PTR(CHAR16), PTR(EFI_GUID), SCL(UINT32), SCL(UINTN), PTR(VOID)))
+
+//
+// Miscellaneous Services
+//
+TBL_ENTRY(EFI_GET_NEXT_HIGH_MONO_COUNT, GetNextHighMonotonicCount, NVOID, EFI_STATUS, 1, (PTR(UINT32)))
+TBL_ENTRY(EFI_RESET_SYSTEM, ResetSystem, RVOID, VOID, 4, (SCL(EFI_RESET_TYPE), SCL(EFI_STATUS), SCL(UINTN), PTR(VOID)))
+
+//
+// UEFI 2.0 Capsule Services
+//
+TBL_ENTRY(EFI_UPDATE_CAPSULE, UpdateCapsule, NVOID, EFI_STATUS, 3, (PTR2(EFI_CAPSULE_HEADER), SCL(UINTN), SCL(EFI_PHYSICAL_ADDRESS)))
+TBL_ENTRY(EFI_QUERY_CAPSULE_CAPABILITIES, QueryCapsuleCapabilities, NVOID, EFI_STATUS, 4, (PTR2(EFI_CAPSULE_HEADER), SCL(UINTN), PTR(UINT64), PTR(EFI_RESET_TYPE)))
+
+//
+// Miscellaneous UEFI 2.0 Service
+//
+TBL_ENTRY(EFI_QUERY_VARIABLE_INFO, QueryVariableInfo, NVOID, EFI_STATUS, 4, (SCL(UINT32), PTR(UINT64), PTR(UINT64), PTR(UINT64)))
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMimicryDxe/README b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMimicryDxe/README
new file mode 100644
index 00000000..3b748de5
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMimicryDxe/README
@@ -0,0 +1,4 @@
+This module isn't supposed to be used in normal UEFI functioning.
+It used in case guest expects some undocumented UEFI interface and
+this module helps in stubbing and simulating these interfaces and investigation of
+guest behavior changes.
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMimicryDxe/VBoxMimicry.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMimicryDxe/VBoxMimicry.c
new file mode 100644
index 00000000..2e48bb42
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMimicryDxe/VBoxMimicry.c
@@ -0,0 +1,155 @@
+/* $Id: VBoxMimicry.c $ */
+/** @file
+ * VBoxMimicry.c - Mimic table entry.
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+#include "VBoxMimicry.h"
+#define VBOX_MIMICRY_VAR L"VBOX_MIMICRY"
+
+/*610467a0-d8a7-11de-a911-87667af93b7d*/
+static EFI_GUID gVBoxMimicryVarGuid = { 0x610467a0, 0xd8a7, 0x11de, {0xa9, 0x11, 0x87, 0x66, 0x7a, 0xf9, 0x3b, 0x7d}};
+
+#define MIM_TBL_ENTRY(name, guid) DO_9_FAKE_DECL(name)
+#include "mimic_tbl.h"
+#undef MIM_TBL_ENTRY
+
+#define MIM_TBL_ENTRY(name, guid) \
+static EFI_GUID gFake ## name = guid; \
+static void *gFuncArray_ ## name [] = \
+{ \
+ name ## _fake_impl0, \
+ name ## _fake_impl1, \
+ name ## _fake_impl2, \
+ name ## _fake_impl3, \
+ name ## _fake_impl4, \
+ name ## _fake_impl5, \
+ name ## _fake_impl6, \
+ name ## _fake_impl7, \
+ name ## _fake_impl8, \
+ name ## _fake_impl9 \
+};
+#include "mimic_tbl.h"
+#undef MIM_TBL_ENTRY
+
+#define MIM_TBL_ENTRY(name, guid) \
+FAKE_IMPL(name ## _fake_impl0, gFake ## name) \
+FAKE_IMPL(name ## _fake_impl1, gFake ## name) \
+FAKE_IMPL(name ## _fake_impl2, gFake ## name) \
+FAKE_IMPL(name ## _fake_impl3, gFake ## name) \
+FAKE_IMPL(name ## _fake_impl4, gFake ## name) \
+FAKE_IMPL(name ## _fake_impl5, gFake ## name) \
+FAKE_IMPL(name ## _fake_impl6, gFake ## name) \
+FAKE_IMPL(name ## _fake_impl7, gFake ## name) \
+FAKE_IMPL(name ## _fake_impl8, gFake ## name) \
+FAKE_IMPL(name ## _fake_impl9, gFake ## name)
+#include "mimic_tbl.h"
+#undef MIM_TBL_ENTRY
+
+
+
+EFI_STATUS
+EFIAPI
+VBoxMimicryInit(EFI_HANDLE hImage, EFI_SYSTEM_TABLE *pSysTable)
+{
+ /* Set'n'check intercept variable */
+ EFI_STATUS r;
+ UINT32 val;
+ UINTN size = sizeof(UINT32);
+ r = gRT->GetVariable(VBOX_MIMICRY_VAR, &gVBoxMimicryVarGuid, NULL, &size, &val);
+ if ( EFI_ERROR(r)
+ && r == EFI_NOT_FOUND)
+ {
+ size = sizeof(UINT32);
+ val = 1;
+ r = gRT->SetVariable(VBOX_MIMICRY_VAR, &gVBoxMimicryVarGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, size, &val);
+ if (EFI_ERROR(r))
+ {
+ DEBUG((DEBUG_INFO, "%a:%d - %r\n", __FILE__, __LINE__, r));
+ return r;
+ }
+ gThis = AllocateZeroPool(sizeof(VBOXMIMICRY));
+ r = install_mimic_interfaces();
+ if(EFI_ERROR(r))
+ {
+ DEBUG((DEBUG_INFO, "%a:%d - %r\n", __FILE__, __LINE__, r));
+ return r;
+ }
+ gThis->hImage = hImage;
+ return r;
+ }
+ if (!EFI_ERROR(r))
+ {
+ return EFI_ALREADY_STARTED;
+ }
+ return r;
+}
+
+EFI_STATUS
+EFIAPI
+VBoxMimicryFini(EFI_HANDLE hImage)
+{
+ EFI_STATUS r;
+ uninstall_mimic_interfaces();
+ FreePool(gThis);
+ r = gRT->SetVariable(VBOX_MIMICRY_VAR, &gVBoxMimicryVarGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 0, NULL);
+ if (EFI_ERROR(r))
+ {
+ DEBUG((DEBUG_INFO, "%a:%d - %r\n", __FILE__, __LINE__, r));
+ return r;
+ }
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS install_mimic_interfaces()
+{
+ EFI_STATUS Status;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &gThis->hImage,
+#define MIM_TBL_ENTRY(name, guid) gFake##name, gFuncArray_##name,
+#include "mimic_tbl.h"
+#undef MIM_TBL_ENTRY
+ NULL);
+ return Status;
+}
+EFI_STATUS uninstall_mimic_interfaces()
+{
+ EFI_STATUS Status;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &gThis->hImage,
+#define MIM_TBL_ENTRY(name, guid) gFake##name,
+#include "mimic_tbl.h"
+#undef MIM_TBL_ENTRY
+ NULL);
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMimicryDxe/VBoxMimicry.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMimicryDxe/VBoxMimicry.h
new file mode 100644
index 00000000..c14c3bf7
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMimicryDxe/VBoxMimicry.h
@@ -0,0 +1,75 @@
+/* $Id: VBoxMimicry.h $ */
+/** @file
+ * VBoxMimicry.h - Debug and logging routines implemented by VBoxDebugLib.
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+#ifndef __VBOXMIMICRY_H__
+#define __VBOXMIMICRY_H__
+#include <Uefi.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+
+#define MIMICRY_INTERFACE_COUNT 1
+#define DO_9_FAKE_DECL(name) \
+static EFI_STATUS name ## _fake_impl0(); \
+static EFI_STATUS name ## _fake_impl1(); \
+static EFI_STATUS name ## _fake_impl2(); \
+static EFI_STATUS name ## _fake_impl3(); \
+static EFI_STATUS name ## _fake_impl4(); \
+static EFI_STATUS name ## _fake_impl5(); \
+static EFI_STATUS name ## _fake_impl6(); \
+static EFI_STATUS name ## _fake_impl7(); \
+static EFI_STATUS name ## _fake_impl8(); \
+static EFI_STATUS name ## _fake_impl9();
+
+#define FAKE_IMPL(name, guid) \
+static EFI_STATUS name () \
+{ \
+ DEBUG((DEBUG_INFO, #name ": of %g called\n", &guid)); \
+ return EFI_SUCCESS; \
+}
+
+typedef struct
+{
+ EFI_HANDLE hImage;
+} VBOXMIMICRY, *PVBOXMIMICRY;
+
+PVBOXMIMICRY gThis;
+
+EFI_STATUS install_mimic_interfaces();
+EFI_STATUS uninstall_mimic_interfaces();
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMimicryDxe/VBoxMimicryDxe.inf b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMimicryDxe/VBoxMimicryDxe.inf
new file mode 100644
index 00000000..e2a473e9
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMimicryDxe/VBoxMimicryDxe.inf
@@ -0,0 +1,83 @@
+# $Id: VBoxMimicryDxe.inf $ */
+#* @file
+# VBoxMimicryDxe.inf - Mimic module declaration.
+
+
+#
+# Copyright (C) 2009-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>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VBoxMimicryDxe
+ FILE_GUID = f346c474-d8a6-11de-9504-0fc338e40fda
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = VBoxMimicryInit
+ UNLOAD_IMAGE = VBoxMimicryFini
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+ VBoxMimicry.c
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ BaseLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ HiiLib
+ PrintLib
+
+[Guids]
+ gEfiIfrTianoGuid ## CONSUMES ## Guid
+
+[Protocols]
+ gEfiHiiStringProtocolGuid ## CONSUMES
+ gEfiHiiConfigRoutingProtocolGuid ## CONSUMES
+ gEfiHiiConfigAccessProtocolGuid ## PRODUCES
+ gEfiFormBrowser2ProtocolGuid ## CONSUMES
+ gEfiHiiDatabaseProtocolGuid ## CONSUMES
+
+
+[Depex]
+ gEfiSimpleTextOutProtocolGuid AND gEfiHiiDatabaseProtocolGuid AND gEfiVariableArchProtocolGuid AND gEfiVariableWriteArchProtocolGuid
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMimicryDxe/mimic_tbl.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMimicryDxe/mimic_tbl.h
new file mode 100644
index 00000000..304c2289
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMimicryDxe/mimic_tbl.h
@@ -0,0 +1,39 @@
+/* $Id: mimic_tbl.h $ */
+/** @file
+ * mimic_tbl.h - Mimic table.
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/*4DF19259-DC71-4D46-BEF1-357BB578C418*/
+#define WIN7_0_GUID {0x4df19259, 0xdc71, 0x4d46, {0xbe, 0xf1, 0x35, 0x7b, 0xb5, 0x78, 0xc4, 0x18}}
+MIM_TBL_ENTRY(win7_0, WIN7_0_GUID)
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMisc/Makefile b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMisc/Makefile
new file mode 100644
index 00000000..ad16d8ff
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMisc/Makefile
@@ -0,0 +1,66 @@
+# $Id: Makefile $
+## @file
+# Makefile - assembling the iso image for experimenting with EFI.
+#
+
+#
+# Copyright (C) 2009-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>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+#
+# Here we add modules to be burn on iso-image
+#
+SOURCES += VBoxInterceptorDxe.efi
+SOURCES += VBoxMimicryDxe.efi
+
+ifeq ($(BUILD_ARCH), IA32)
+ARCH_SUFFIX=
+else
+ARCH_SUFFIX=$(BUILD_ARCH)
+endif
+
+BUILD_ARCH ?= IA32
+BUILD_DIR=$(WORKSPACE)/Build/VBoxPkg$(ARCH_SUFFIX)/DEBUG_UNIXGCC/$(BUILD_ARCH)
+
+ISO_DIR=efi-app
+FILES_TO_ISO=$(foreach file, $(SOURCES), $(addprefix $(ISO_DIR)/, $(file)))
+
+DEST=efi-app.iso
+all:${DEST}
+
+$(DEST):$(FILES_TO_ISO)
+ mkisofs -R -o $@ $(basename $@)
+
+$(ISO_DIR)/%.efi:$(BUILD_DIR)/%.efi
+ cp $< $@
+
+clean:
+ $(RM) -rf ${DEST} $(FILES_TO_ISO)
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMisc/Readme.txt b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMisc/Readme.txt
new file mode 100644
index 00000000..238eb7ff
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMisc/Readme.txt
@@ -0,0 +1,11 @@
+Some drivers and applications we don't wont to include into fw
+but we might want to load/run from time to time for debug reasons
+or even use on real hw. To do it it required add inf file to
+VBoxPkg/VBoxPkg.dsc and don't forget add to SOURCES variable in
+Makefile.
+
+# build
+# make -C VBoxPkg/VBoxMisc
+
+Result iso is RockRidge image attachable to VM and readable
+with our EFI.
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMisc/efi-app/Readme.txt b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMisc/efi-app/Readme.txt
new file mode 100644
index 00000000..2bc3f509
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxMisc/efi-app/Readme.txt
@@ -0,0 +1,39 @@
+# $Id: Readme.txt $ */
+#* @file
+# Readme.txt - Some description about using this module.
+
+
+#
+# Copyright (C) 2009-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>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+Here could be some help how to manage files on efi-app ISO
+
+VBoxInterceptor - intercepts calls to gBS and gRT, outputs a lot of traffics to dev_efi.e.l2, (please be patient ;))
+ Shell> load VBoxInterceptor.efi
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxPkg.dec b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxPkg.dec
new file mode 100644
index 00000000..7bd1d972
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxPkg.dec
@@ -0,0 +1,91 @@
+# $Id: VBoxPkg.dec $
+## @file
+# VBoxPkg.dec - VirtualBox Package description.
+#
+
+#
+# Copyright (C) 2009-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>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+[Defines]
+ DEC_SPECIFICATION = 0x00010005
+ PACKAGE_NAME = VBoxPkg
+ PACKAGE_GUID = D118A5AF-05C8-427E-8047-EF53092514B7
+ PACKAGE_VERSION = 0.1
+
+[Includes.common]
+ Include
+
+[Guids.common]
+# gEfiPciExpressBaseAddressGuid = {0x3677d529, 0x326f, 0x4603, {0xa9, 0x26, 0xea, 0xac, 0xe0, 0x1d, 0xcb, 0xb0 }}
+ gEfiAcpiDescriptionGuid = {0x3c699197, 0x093c, 0x4c69, {0xb0, 0x6b, 0x12, 0x8a, 0xe3, 0x48, 0x1d, 0xc9 }}
+# gEfiFlashMapHobGuid = { 0xb091e7d2, 0x5a0, 0x4198, {0x94, 0xf0, 0x74, 0xb7, 0xb8, 0xc5, 0x54, 0x59 }}
+ gVBoxVgaPkgTokenSpaceGuid = { 0xa3a8ce56, 0x4a07, 0x441f, {0xa3, 0xf5, 0x6f, 0x53, 0xdb, 0x9c, 0xb7, 0xd8}}
+ gVBoxFsBlessedFileInfoGuid = { 0xcc49fefd, 0x41b7, 0x473f, {0x98, 0x23, 0x0e, 0x8e, 0xbf, 0x35, 0x67, 0x7d } }
+
+#
+# Various types of Platform Configuration Database (PCD) items.
+#
+[PcdsFixedAtBuild.common]
+# gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase|0|UINT32|0x00001000
+# gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize|0|UINT32|0x00001001
+# gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase|0|UINT32|0x00001002
+# gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize|0|UINT32|0x00001003
+# gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase|0|UINT32|0x00001004
+# gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize|0|UINT32|0x00001005
+ gVBoxVgaPkgTokenSpaceGuid.PcdDriverSupportedEfiVersion|0x0002000a|UINT32|0x00010003
+
+## XXX - boot mode - gEfiNt32PkgTokenSpaceGuid.PcdWinNtBootMode|1|UINT32|0x00001006
+
+# gEfiNt32PkgTokenSpaceGuid.PcdWinNtFlashFvRecoveryBase|0x0|UINT32|0x00001010
+# gEfiNt32PkgTokenSpaceGuid.PcdWinNtFlashFvRecoverySize|0x0|UINT32|0x00001011
+
+# gEfiNt32PkgTokenSpaceGuid.PcdWinNtFirmwareFdSize|0x0|UINT32|0x00001012
+# gEfiNt32PkgTokenSpaceGuid.PcdWinNtFirmwareFdSize|0x0|UINT32|0x00001012
+# gEfiNt32PkgTokenSpaceGuid.PcdWinNtFirmwareBlockSize|0|UINT32|0x00001013
+
+# gEfiNt32PkgTokenSpaceGuid.PcdWinNtFlashNvStorageVariableBase|0x0|UINT32|0x00001014
+# gEfiNt32PkgTokenSpaceGuid.PcdWinNtFlashNvStorageFtwSpareBase|0x0|UINT32|0x00001015
+# gEfiNt32PkgTokenSpaceGuid.PcdWinNtFlashNvStorageFtwWorkingBase|0x0|UINT32|0x00001016
+# gEfiNt32PkgTokenSpaceGuid.PcdWinNtFdBaseAddress|0x0|UINT32|0x00001017
+
+[PcdsDynamic.common]
+ # none yet
+
+[PcdsPatchableInModule.common]
+## XXX - boot mode - gEfiNt32PkgTokenSpaceGuid.PcdWinNtBootMode|1|UINT32|0x00001006
+[PcdsFeatureFlag.common]
+ gVBoxVgaPkgTokenSpaceGuid.PcdSupportGop|TRUE|BOOLEAN|0x00010004
+ gVBoxVgaPkgTokenSpaceGuid.PcdSupportUga|FALSE|BOOLEAN|0x00010005
+
+[LibraryClasses]
+ ## @libraryclass Generic BDS library definition, include the data structure and function.
+ GenericBdsLib|Include/Library/GenericBdsLib.h
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxSysTables/LegacyBiosMpTable.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxSysTables/LegacyBiosMpTable.h
new file mode 100644
index 00000000..9b929dfe
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxSysTables/LegacyBiosMpTable.h
@@ -0,0 +1,319 @@
+/* $Id: LegacyBiosMpTable.h $ */
+/** @file
+ * LegacyBiosMpTable.h
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/*++
+
+This code is based on:
+
+Copyright (c) 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ LegacyBiosMpTable.h
+
+Abstract:
+ Defines data structures per Multi Processor Specification Ver 1.4.
+
+--*/
+
+#ifndef LEGACY_BIOS_MPTABLE_H_
+#define LEGACY_BIOS_MPTABLE_H_
+
+#define EFI_LEGACY_MP_TABLE_REV_1_4 0x04
+
+//
+// Define MP table structures. All are packed.
+//
+#pragma pack(push, 1)
+
+#define EFI_LEGACY_MP_TABLE_FLOATING_POINTER_SIGNATURE SIGNATURE_32 ('_', 'M', 'P', '_')
+typedef struct {
+ UINT32 Signature;
+ UINT32 PhysicalAddress;
+ UINT8 Length;
+ UINT8 SpecRev;
+ UINT8 Checksum;
+ UINT8 FeatureByte1;
+ struct {
+ UINT32 Reserved1 : 6;
+ UINT32 MutipleClk : 1;
+ UINT32 Imcr : 1;
+ UINT32 Reserved2 : 24;
+ } FeatureByte2_5;
+} EFI_LEGACY_MP_TABLE_FLOATING_POINTER;
+
+#define EFI_LEGACY_MP_TABLE_HEADER_SIGNATURE SIGNATURE_32 ('P', 'C', 'M', 'P')
+typedef struct {
+ UINT32 Signature;
+ UINT16 BaseTableLength;
+ UINT8 SpecRev;
+ UINT8 Checksum;
+ CHAR8 OemId[8];
+ CHAR8 OemProductId[12];
+ UINT32 OemTablePointer;
+ UINT16 OemTableSize;
+ UINT16 EntryCount;
+ UINT32 LocalApicAddress;
+ UINT16 ExtendedTableLength;
+ UINT8 ExtendedChecksum;
+ UINT8 Reserved;
+} EFI_LEGACY_MP_TABLE_HEADER;
+
+typedef struct {
+ UINT8 EntryType;
+} EFI_LEGACY_MP_TABLE_ENTRY_TYPE;
+
+//
+// Entry Type 0: Processor.
+//
+#define EFI_LEGACY_MP_TABLE_ENTRY_TYPE_PROCESSOR 0x00
+typedef struct {
+ UINT8 EntryType;
+ UINT8 Id;
+ UINT8 Ver;
+ struct {
+ UINT8 Enabled : 1;
+ UINT8 Bsp : 1;
+ UINT8 Reserved : 6;
+ } Flags;
+ struct {
+ UINT32 Stepping : 4;
+ UINT32 Model : 4;
+ UINT32 Family : 4;
+ UINT32 Reserved : 20;
+ } Signature;
+ struct {
+ UINT32 Fpu : 1;
+ UINT32 Reserved1 : 6;
+ UINT32 Mce : 1;
+ UINT32 Cx8 : 1;
+ UINT32 Apic : 1;
+ UINT32 Reserved2 : 22;
+ } Features;
+ UINT32 Reserved1;
+ UINT32 Reserved2;
+} EFI_LEGACY_MP_TABLE_ENTRY_PROCESSOR;
+
+//
+// Entry Type 1: Bus.
+//
+#define EFI_LEGACY_MP_TABLE_ENTRY_TYPE_BUS 0x01
+typedef struct {
+ UINT8 EntryType;
+ UINT8 Id;
+ CHAR8 TypeString[6];
+} EFI_LEGACY_MP_TABLE_ENTRY_BUS;
+
+#define EFI_LEGACY_MP_TABLE_ENTRY_BUS_STRING_CBUS "CBUS " // Corollary CBus
+#define EFI_LEGACY_MP_TABLE_ENTRY_BUS_STRING_CBUSII "CBUSII" // Corollary CBUS II
+#define EFI_LEGACY_MP_TABLE_ENTRY_BUS_STRING_EISA "EISA " // Extended ISA
+#define EFI_LEGACY_MP_TABLE_ENTRY_BUS_STRING_FUTURE "FUTURE" // IEEE FutureBus
+#define EFI_LEGACY_MP_TABLE_ENTRY_BUS_STRING_INTERN "INTERN" // Internal bus
+#define EFI_LEGACY_MP_TABLE_ENTRY_BUS_STRING_ISA "ISA " // Industry Standard Architecture
+#define EFI_LEGACY_MP_TABLE_ENTRY_BUS_STRING_MBI "MBI " // Multibus I
+#define EFI_LEGACY_MP_TABLE_ENTRY_BUS_STRING_MBII "MBII " // Multibus II
+#define EFI_LEGACY_MP_TABLE_ENTRY_BUS_STRING_MCA "MCA " // Micro Channel Architecture
+#define EFI_LEGACY_MP_TABLE_ENTRY_BUS_STRING_MPI "MPI " // MPI
+#define EFI_LEGACY_MP_TABLE_ENTRY_BUS_STRING_MPSA "MPSA " // MPSA
+#define EFI_LEGACY_MP_TABLE_ENTRY_BUS_STRING_NUBUS "NUBUS " // Apple Macintosh NuBus
+#define EFI_LEGACY_MP_TABLE_ENTRY_BUS_STRING_PCI "PCI " // Peripheral Component Interconnect
+#define EFI_LEGACY_MP_TABLE_ENTRY_BUS_STRING_PCMCIA "PCMCIA" // PC Memory Card International Assoc.
+#define EFI_LEGACY_MP_TABLE_ENTRY_BUS_STRING_TC "TC " // DEC TurboChannel
+#define EFI_LEGACY_MP_TABLE_ENTRY_BUS_STRING_VL "VL " // VESA Local Bus
+#define EFI_LEGACY_MP_TABLE_ENTRY_BUS_STRING_VME "VME " // VMEbus
+#define EFI_LEGACY_MP_TABLE_ENTRY_BUS_STRING_XPRESS "XPRESS" // Express System Bus
+//
+// Entry Type 2: I/O APIC.
+//
+#define EFI_LEGACY_MP_TABLE_ENTRY_TYPE_IOAPIC 0x02
+typedef struct {
+ UINT8 EntryType;
+ UINT8 Id;
+ UINT8 Ver;
+ struct {
+ UINT8 Enabled : 1;
+ UINT8 Reserved : 7;
+ } Flags;
+ UINT32 Address;
+} EFI_LEGACY_MP_TABLE_ENTRY_IOAPIC;
+
+//
+// Entry Type 3: I/O Interrupt Assignment.
+//
+#define EFI_LEGACY_MP_TABLE_ENTRY_TYPE_IO_INT 0x03
+typedef struct {
+ UINT8 EntryType;
+ UINT8 IntType;
+ struct {
+ UINT16 Polarity : 2;
+ UINT16 Trigger : 2;
+ UINT16 Reserved : 12;
+ } Flags;
+ UINT8 SourceBusId;
+ union {
+ struct {
+ UINT8 IntNo : 2;
+ UINT8 Dev : 5;
+ UINT8 Reserved : 1;
+ } fields;
+ UINT8 byte;
+ } SourceBusIrq;
+ UINT8 DestApicId;
+ UINT8 DestApicIntIn;
+} EFI_LEGACY_MP_TABLE_ENTRY_IO_INT;
+
+typedef enum {
+ EfiLegacyMpTableEntryIoIntTypeInt = 0,
+ EfiLegacyMpTableEntryIoIntTypeNmi = 1,
+ EfiLegacyMpTableEntryIoIntTypeSmi = 2,
+ EfiLegacyMpTableEntryIoIntTypeExtInt= 3,
+} EFI_LEGACY_MP_TABLE_ENTRY_IO_INT_TYPE;
+
+typedef enum {
+ EfiLegacyMpTableEntryIoIntFlagsPolaritySpec = 0x0,
+ EfiLegacyMpTableEntryIoIntFlagsPolarityActiveHigh = 0x1,
+ EfiLegacyMpTableEntryIoIntFlagsPolarityReserved = 0x2,
+ EfiLegacyMpTableEntryIoIntFlagsPolarityActiveLow = 0x3,
+} EFI_LEGACY_MP_TABLE_ENTRY_IO_INT_FLAGS_POLARITY;
+
+typedef enum {
+ EfiLegacyMpTableEntryIoIntFlagsTriggerSpec = 0x0,
+ EfiLegacyMpTableEntryIoIntFlagsTriggerEdge = 0x1,
+ EfiLegacyMpTableEntryIoIntFlagsTriggerReserved = 0x2,
+ EfiLegacyMpTableEntryIoIntFlagsTriggerLevel = 0x3,
+} EFI_LEGACY_MP_TABLE_ENTRY_IO_INT_FLAGS_TRIGGER;
+
+//
+// Entry Type 4: Local Interrupt Assignment.
+//
+#define EFI_LEGACY_MP_TABLE_ENTRY_TYPE_LOCAL_INT 0x04
+typedef struct {
+ UINT8 EntryType;
+ UINT8 IntType;
+ struct {
+ UINT16 Polarity : 2;
+ UINT16 Trigger : 2;
+ UINT16 Reserved : 12;
+ } Flags;
+ UINT8 SourceBusId;
+ UINT8 SourceBusIrq;
+ UINT8 DestApicId;
+ UINT8 DestApicIntIn;
+} EFI_LEGACY_MP_TABLE_ENTRY_LOCAL_INT;
+
+typedef enum {
+ EfiLegacyMpTableEntryLocalIntTypeInt = 0,
+ EfiLegacyMpTableEntryLocalIntTypeNmi = 1,
+ EfiLegacyMpTableEntryLocalIntTypeSmi = 2,
+ EfiLegacyMpTableEntryLocalIntTypeExtInt = 3,
+} EFI_LEGACY_MP_TABLE_ENTRY_LOCAL_INT_TYPE;
+
+typedef enum {
+ EfiLegacyMpTableEntryLocalIntFlagsPolaritySpec = 0x0,
+ EfiLegacyMpTableEntryLocalIntFlagsPolarityActiveHigh= 0x1,
+ EfiLegacyMpTableEntryLocalIntFlagsPolarityReserved = 0x2,
+ EfiLegacyMpTableEntryLocalIntFlagsPolarityActiveLow = 0x3,
+} EFI_LEGACY_MP_TABLE_ENTRY_LOCAL_INT_FLAGS_POLARITY;
+
+typedef enum {
+ EfiLegacyMpTableEntryLocalIntFlagsTriggerSpec = 0x0,
+ EfiLegacyMpTableEntryLocalIntFlagsTriggerEdge = 0x1,
+ EfiLegacyMpTableEntryLocalIntFlagsTriggerReserved = 0x2,
+ EfiLegacyMpTableEntryLocalIntFlagsTriggerLevel = 0x3,
+} EFI_LEGACY_MP_TABLE_ENTRY_LOCAL_INT_FLAGS_TRIGGER;
+
+//
+// Entry Type 128: System Address Space Mapping.
+//
+#define EFI_LEGACY_MP_TABLE_ENTRY_EXT_TYPE_SYS_ADDR_SPACE_MAPPING 0x80
+typedef struct {
+ UINT8 EntryType;
+ UINT8 Length;
+ UINT8 BusId;
+ UINT8 AddressType;
+ UINT64 AddressBase;
+ UINT64 AddressLength;
+} EFI_LEGACY_MP_TABLE_ENTRY_EXT_SYS_ADDR_SPACE_MAPPING;
+
+typedef enum {
+ EfiLegacyMpTableEntryExtSysAddrSpaceMappingIo = 0,
+ EfiLegacyMpTableEntryExtSysAddrSpaceMappingMemory = 1,
+ EfiLegacyMpTableEntryExtSysAddrSpaceMappingPrefetch = 2,
+} EFI_LEGACY_MP_TABLE_ENTRY_EXT_SYS_ADDR_SPACE_MAPPING_TYPE;
+
+//
+// Entry Type 129: Bus Hierarchy.
+//
+#define EFI_LEGACY_MP_TABLE_ENTRY_EXT_TYPE_BUS_HIERARCHY 0x81
+typedef struct {
+ UINT8 EntryType;
+ UINT8 Length;
+ UINT8 BusId;
+ struct {
+ UINT8 SubtractiveDecode : 1;
+ UINT8 Reserved : 7;
+ } BusInfo;
+ UINT8 ParentBus;
+ UINT8 Reserved1;
+ UINT8 Reserved2;
+ UINT8 Reserved3;
+} EFI_LEGACY_MP_TABLE_ENTRY_EXT_BUS_HIERARCHY;
+
+//
+// Entry Type 130: Compatibility Bus Address Space Modifier.
+//
+#define EFI_LEGACY_MP_TABLE_ENTRY_EXT_TYPE_COMPAT_BUS_ADDR_SPACE_MODIFIER 0x82
+typedef struct {
+ UINT8 EntryType;
+ UINT8 Length;
+ UINT8 BusId;
+ struct {
+ UINT8 RangeMode : 1;
+ UINT8 Reserved : 7;
+ } AddrMode;
+ UINT32 PredefinedRangeList;
+} EFI_LEGACY_MP_TABLE_ENTRY_EXT_COMPAT_BUS_ADDR_SPACE_MODIFIER;
+
+#pragma pack(pop)
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxSysTables/TableConversion.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxSysTables/TableConversion.c
new file mode 100644
index 00000000..21a65c2d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxSysTables/TableConversion.c
@@ -0,0 +1,380 @@
+/* $Id: TableConversion.c $ */
+/** @file
+ * TableConversion.c
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/*++
+
+ This code is baed on:
+
+ Copyright (c) 2006 - 2007, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ --*/
+
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/Acpi.h>
+#include <IndustryStandard/SmBios.h>
+#include "LegacyBiosMpTable.h"
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseLib.h>
+
+#include <Guid/Acpi.h>
+#include <Guid/SmBios.h>
+#include <Guid/Mps.h>
+#include <Guid/HobList.h>
+#include <Guid/GlobalVariable.h>
+
+#define SYS_TABLE_PAD(ptr) (((~ptr) +1) & 0x07 )
+#define EFI_SYSTEM_TABLE_MAX_ADDRESS 0xFFFFFFFF
+
+EFI_STATUS
+ConvertAcpiTable (
+ IN UINTN TableLen,
+ IN OUT VOID **Table
+ )
+/*++
+
+ Routine Description:
+ Convert RSDP of ACPI Table if its location is lower than Address:0x100000
+ Assumption here:
+ As in legacy Bios, ACPI table is required to place in E/F Seg,
+ So here we just check if the range is E/F seg,
+ and if Not, assume the Memory type is EfiACPIReclaimMemory/EfiACPIMemoryNVS
+
+ Arguments:
+ TableLen - Acpi RSDP length
+ Table - pointer to the table
+
+ Returns:
+ EFI_SUCCESS - Convert Table successfully
+ Other - Failed
+
+ --*/
+{
+ VOID *AcpiTableOri;
+ VOID *AcpiTableNew;
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS BufferPtr;
+
+
+ AcpiTableOri = (VOID *)(UINTN)((*Table));
+
+ BufferPtr = EFI_SYSTEM_TABLE_MAX_ADDRESS;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES(TableLen),
+ &BufferPtr
+ );
+ ASSERT_EFI_ERROR (Status);
+ AcpiTableNew = (VOID *)(UINTN)BufferPtr;
+ CopyMem (AcpiTableNew, AcpiTableOri, TableLen);
+
+ //
+ // Change configuration table Pointer
+ //
+ *Table = AcpiTableNew;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+ConvertSmbiosTable (
+ IN OUT VOID **Table
+ )
+/*++
+
+ Routine Description:
+
+ Convert Smbios Table if the Location of the SMBios Table is lower than Address 0x100000
+ Assumption here:
+ As in legacy Bios, Smbios table is required to place in E/F Seg,
+ So here we just check if the range is F seg,
+ and if Not, assume the Memory type is EfiACPIMemoryNVS/EfiRuntimeServicesData
+ Arguments:
+ Table - pointer to the table
+
+ Returns:
+ EFI_SUCCESS - Convert Table successfully
+ Other - Failed
+
+ --*/
+{
+ SMBIOS_TABLE_ENTRY_POINT *SmbiosTableNew;
+ SMBIOS_TABLE_ENTRY_POINT *SmbiosTableOri;
+ EFI_STATUS Status;
+ UINT32 SmbiosEntryLen;
+ UINT32 BufferLen;
+ EFI_PHYSICAL_ADDRESS BufferPtr;
+
+ SmbiosTableNew = NULL;
+ SmbiosTableOri = NULL;
+
+ //
+ // Get Smibos configuration Table
+ //
+ SmbiosTableOri = (SMBIOS_TABLE_ENTRY_POINT *)(UINTN)((*Table));
+
+
+ ASSERT(CalculateSum8((UINT8*)SmbiosTableOri, sizeof(SMBIOS_TABLE_ENTRY_POINT)) == 0);
+ //
+ // Relocate the Smibos memory
+ //
+ BufferPtr = EFI_SYSTEM_TABLE_MAX_ADDRESS;
+ if (SmbiosTableOri->SmbiosBcdRevision != 0x21) {
+ SmbiosEntryLen = SmbiosTableOri->EntryPointLength;
+ } else {
+ //
+ // According to Smbios Spec 2.4, we should set entry point length as 0x1F if version is 2.1
+ //
+ SmbiosEntryLen = 0x1F;
+ }
+ BufferLen = SmbiosEntryLen + SYS_TABLE_PAD(SmbiosEntryLen) + SmbiosTableOri->TableLength;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES(BufferLen),
+ &BufferPtr
+ );
+ ASSERT_EFI_ERROR (Status);
+ SmbiosTableNew = (SMBIOS_TABLE_ENTRY_POINT *)(UINTN)BufferPtr;
+ CopyMem (
+ SmbiosTableNew,
+ SmbiosTableOri,
+ SmbiosEntryLen
+ );
+ //
+ // Get Smbios Structure table address, and make sure the start address is 32-bit align
+ //
+ BufferPtr += SmbiosEntryLen + SYS_TABLE_PAD(SmbiosEntryLen);
+ CopyMem (
+ (VOID *)(UINTN)BufferPtr,
+ (VOID *)(UINTN)(SmbiosTableOri->TableAddress),
+ SmbiosTableOri->TableLength
+ );
+ SmbiosTableNew->TableAddress = (UINT32)BufferPtr;
+ SmbiosTableNew->IntermediateChecksum = 0;
+ SmbiosTableNew->IntermediateChecksum =
+ CalculateCheckSum8 ((UINT8*)SmbiosTableNew + 0x10, SmbiosEntryLen -0x10);
+ //
+ // Change the SMBIOS pointer
+ //
+ *Table = SmbiosTableNew;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+ConvertMpsTable (
+ IN OUT VOID **Table
+ )
+/*++
+
+ Routine Description:
+
+ Convert MP Table if the Location of the SMBios Table is lower than Address 0x100000
+ Assumption here:
+ As in legacy Bios, MP table is required to place in E/F Seg,
+ So here we just check if the range is E/F seg,
+ and if Not, assume the Memory type is EfiACPIMemoryNVS/EfiRuntimeServicesData
+ Arguments:
+ Table - pointer to the table
+
+ Returns:
+ EFI_SUCCESS - Convert Table successfully
+ Other - Failed
+
+ --*/
+{
+ UINT32 Data32;
+ UINT32 FPLength;
+ EFI_LEGACY_MP_TABLE_FLOATING_POINTER *MpsFloatingPointerOri;
+ EFI_LEGACY_MP_TABLE_FLOATING_POINTER *MpsFloatingPointerNew;
+ EFI_LEGACY_MP_TABLE_HEADER *MpsTableOri;
+ EFI_LEGACY_MP_TABLE_HEADER *MpsTableNew;
+ VOID *OemTableOri;
+ VOID *OemTableNew;
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS BufferPtr;
+
+ //
+ // Get MP configuration Table
+ //
+ MpsFloatingPointerOri = (EFI_LEGACY_MP_TABLE_FLOATING_POINTER *)(UINTN)(*Table);
+ //
+ // Get Floating pointer structure length
+ //
+ FPLength = MpsFloatingPointerOri->Length * 16;
+ ASSERT(CalculateSum8((UINT8*)MpsFloatingPointerOri, FPLength) == 0);
+ Data32 = FPLength + SYS_TABLE_PAD (FPLength);
+ MpsTableOri = (EFI_LEGACY_MP_TABLE_HEADER *)(UINTN)(MpsFloatingPointerOri->PhysicalAddress);
+ ASSERT(MpsTableOri != NULL);
+ ASSERT(CalculateSum8((UINT8*)MpsTableOri, MpsTableOri->BaseTableLength) == 0);
+
+ Data32 += MpsTableOri->BaseTableLength;
+ Data32 += MpsTableOri->ExtendedTableLength;
+ if (MpsTableOri->OemTablePointer != 0x00) {
+ Data32 += SYS_TABLE_PAD (Data32);
+ Data32 += MpsTableOri->OemTableSize;
+ }
+
+ //
+ // Relocate memory
+ //
+ BufferPtr = EFI_SYSTEM_TABLE_MAX_ADDRESS;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES(Data32),
+ &BufferPtr
+ );
+ ASSERT_EFI_ERROR (Status);
+ MpsFloatingPointerNew = (EFI_LEGACY_MP_TABLE_FLOATING_POINTER *)(UINTN)BufferPtr;
+ CopyMem (MpsFloatingPointerNew, MpsFloatingPointerOri, FPLength);
+ //
+ // If Mp Table exists
+ //
+ if (MpsTableOri != NULL) {
+ //
+ // Get Mps table length, including Ext table
+ //
+ BufferPtr = BufferPtr + FPLength + SYS_TABLE_PAD (FPLength);
+ MpsTableNew = (EFI_LEGACY_MP_TABLE_HEADER *)(UINTN)BufferPtr;
+ CopyMem (MpsTableNew, MpsTableOri, MpsTableOri->BaseTableLength + MpsTableOri->ExtendedTableLength);
+
+ if ((MpsTableOri->OemTableSize != 0x0000) && (MpsTableOri->OemTablePointer != 0x0000)){
+ BufferPtr += MpsTableOri->BaseTableLength + MpsTableOri->ExtendedTableLength;
+ BufferPtr += SYS_TABLE_PAD (BufferPtr);
+ OemTableNew = (VOID *)(UINTN)BufferPtr;
+ OemTableOri = (VOID *)(UINTN)MpsTableOri->OemTablePointer;
+ CopyMem (OemTableNew, OemTableOri, MpsTableOri->OemTableSize);
+ MpsTableNew->OemTablePointer = (UINT32)(UINTN)OemTableNew;
+ }
+ MpsTableNew->Checksum = 0;
+ MpsTableNew->Checksum = CalculateCheckSum8 ((UINT8*)MpsTableNew, MpsTableOri->BaseTableLength);
+ MpsFloatingPointerNew->PhysicalAddress = (UINT32)(UINTN)MpsTableNew;
+ MpsFloatingPointerNew->Checksum = 0;
+ MpsFloatingPointerNew->Checksum = CalculateCheckSum8 ((UINT8*)MpsFloatingPointerNew, FPLength);
+ }
+ //
+ // Change the pointer
+ //
+ *Table = MpsFloatingPointerNew;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+ConvertSystemTable (
+ IN EFI_GUID *TableGuid,
+ IN OUT VOID **Table
+ )
+/*++
+
+ Routine Description:
+ Convert ACPI Table /Smbios Table /MP Table if its location is lower than Address:0x100000
+ Assumption here:
+ As in legacy Bios, ACPI/Smbios/MP table is required to place in E/F Seg,
+ So here we just check if the range is E/F seg,
+ and if Not, assume the Memory type is EfiACPIReclaimMemory/EfiACPIMemoryNVS
+
+ Arguments:
+ TableGuid - Guid of the table
+ Table - pointer to the table
+
+ Returns:
+ EFI_SUCCESS - Convert Table successfully
+ Other - Failed
+
+ --*/
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ VOID *AcpiHeader;
+ UINTN AcpiTableLen;
+
+ //
+ // If match acpi guid (1.0, 2.0, or later), Convert ACPI table according to version.
+ //
+
+ if (CompareGuid(TableGuid, &gEfiAcpiTableGuid) || CompareGuid(TableGuid, &gEfiAcpi20TableGuid)){
+ AcpiHeader = (VOID*)(UINTN)(*Table);
+
+ if (((EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)AcpiHeader)->Reserved == 0x00){
+ //
+ // If Acpi 1.0 Table, then RSDP structure doesn't contain Length field, use structure size
+ //
+ AcpiTableLen = sizeof (EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER);
+ } else if (((EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)AcpiHeader)->Reserved >= 0x02){
+ //
+ // If Acpi 2.0 or later, use RSDP Length fied.
+ //
+ AcpiTableLen = ((EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)AcpiHeader)->Length;
+ } else {
+ //
+ // Invalid Acpi Version, return
+ //
+ return EFI_UNSUPPORTED;
+ }
+ Status = ConvertAcpiTable (AcpiTableLen, Table);
+ return Status;
+ }
+
+ //
+ // If matches smbios guid, convert Smbios table.
+ //
+ if (CompareGuid(TableGuid, &gEfiSmbiosTableGuid)){
+ Status = ConvertSmbiosTable (Table);
+ return Status;
+ }
+
+ //
+ // If the table is MP table?
+ //
+ if (CompareGuid(TableGuid, &gEfiMpsTableGuid)){
+ Status = ConvertMpsTable (Table);
+ return Status;
+ }
+
+ return EFI_UNSUPPORTED;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxSysTables/VBoxSysTables.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxSysTables/VBoxSysTables.c
new file mode 100644
index 00000000..7916182a
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxSysTables/VBoxSysTables.c
@@ -0,0 +1,178 @@
+/* $Id: VBoxSysTables.c $ */
+/** @file
+ * VBoxSysTables.c - VirtualBox system tables
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Protocol/DevicePathToText.h>
+
+#include <IndustryStandard/Acpi10.h>
+#include <IndustryStandard/Acpi20.h>
+#include <IndustryStandard/SmBios.h>
+
+#include <Guid/SmBios.h>
+#include <Guid/Acpi.h>
+#include <Guid/Mps.h>
+
+#include "VBoxPkg.h"
+#include "DevEFI.h"
+#include "iprt/asm.h"
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+
+
+EFI_STATUS EFIAPI
+ConvertSystemTable (
+ IN EFI_GUID *TableGuid,
+ IN OUT VOID **Table
+ );
+
+#define MPS_PTR SIGNATURE_32('_','M','P','_')
+#define SMBIOS_PTR SIGNATURE_32('_','S','M','_')
+
+#define EBDA_BASE (0x9FC0 << 4)
+
+VOID *
+FindSMBIOSPtr (
+ VOID
+ )
+{
+ UINTN Address;
+
+ //
+ // First Search 0x0e0000 - 0x0fffff for SMBIOS Ptr
+ //
+ for (Address = 0xe0000; Address < 0xfffff; Address += 0x10) {
+ if (*(UINT32 *)(Address) == SMBIOS_PTR) {
+ return (VOID *)Address;
+ }
+ }
+ return NULL;
+}
+
+VOID *
+FindMPSPtr (
+ VOID
+ )
+{
+ UINTN Address;
+ UINTN Index;
+
+ //
+ // First Search 0x0e0000 - 0x0fffff for MPS Ptr
+ //
+ for (Address = 0xe0000; Address < 0xfffff; Address += 0x10) {
+ if (*(UINT32 *)(Address) == MPS_PTR) {
+ return (VOID *)Address;
+ }
+ }
+
+ //
+ // Search EBDA
+ //
+
+ Address = EBDA_BASE;
+ for (Index = 0; Index < 0x400 ; Index += 16) {
+ if (*(UINT32 *)(Address + Index) == MPS_PTR) {
+ return (VOID *)(Address + Index);
+ }
+ }
+ return NULL;
+}
+
+EFI_STATUS EFIAPI
+ConvertAndInstallTable(EFI_GUID* Guid, VOID* Ptr)
+{
+ EFI_STATUS rc = EFI_SUCCESS;
+
+ rc = ConvertSystemTable(Guid, &Ptr);
+ //ASSERT_EFI_ERROR (rc);
+
+ rc = gBS->InstallConfigurationTable(Guid, Ptr);
+ ASSERT_EFI_ERROR (rc);
+
+ return rc;
+}
+
+
+/**
+ * VBoxSysTablesDxe entry point.
+ *
+ * @returns EFI status code.
+ *
+ * @param ImageHandle The image handle.
+ * @param SystemTable The system table pointer.
+ */
+EFI_STATUS EFIAPI
+DxeInitializeVBoxSysTables(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
+{
+ EFI_STATUS rc;
+ VOID* Ptr;
+
+ DEBUG((DEBUG_INFO, "DxeInitializeVBoxSysTables\n"));
+
+ Ptr = FindSMBIOSPtr();
+ DEBUG((DEBUG_INFO, "SMBIOS=%p\n", Ptr));
+ ASSERT(Ptr != NULL);
+ if (Ptr)
+ {
+ rc = ConvertAndInstallTable(&gEfiSmbiosTableGuid, Ptr);
+ ASSERT_EFI_ERROR (rc);
+ }
+
+ Ptr = FindMPSPtr();
+ DEBUG((DEBUG_INFO, "MPS=%p\n", Ptr));
+ // MPS can be null in non IO-APIC configs
+ if (Ptr)
+ rc = ConvertAndInstallTable(&gEfiMpsTableGuid, Ptr);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS EFIAPI
+DxeUninitializeVBoxSysTables(IN EFI_HANDLE ImageHandle)
+{
+ return EFI_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxSysTables/VBoxSysTables.inf b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxSysTables/VBoxSysTables.inf
new file mode 100644
index 00000000..10ea72c3
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxSysTables/VBoxSysTables.inf
@@ -0,0 +1,83 @@
+# $Id: VBoxSysTables.inf $
+## @file
+# VBoxSysTables - VBox system tables.
+#
+
+#
+# Copyright (C) 2010-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>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VBoxSysTables
+ FILE_GUID = 3749CF40-9086-4488-BB8E-44C9400D260F
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+# SUPPORTED_ARCHITECTURES = IA32|X64|IPF|EBC
+ EDK_RELEASE_VERSION = 0x00020000
+ EFI_SPECIFICATION_VERSION = 0x00020000
+ ENTRY_POINT = DxeInitializeVBoxSysTables
+ UNLOAD_IMAGE = DxeUninitializeVBoxSysTables
+
+[Sources.common]
+ VBoxSysTables.c
+ TableConversion.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ VBoxPkg/VBoxPkg.dec
+
+[LibraryClasses]
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ BaseLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+ PcdLib
+ DevicePathLib
+
+[Guids]
+ gEfiSmbiosTableGuid
+ gEfiAcpiTableGuid
+ gEfiAcpi20TableGuid
+ gEfiMpsTableGuid
+
+[Protocols]
+ gEfiDevicePathToTextProtocolGuid
+
+[BuildOptions.common]
+
+ GCC:*_*_*_CC_FLAGS =
+ INTEL:*_*_*_CC_FLAGS =
+ MSFT:*_*_*_CC_FLAGS =
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/ComponentName.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/ComponentName.c
new file mode 100644
index 00000000..4a5bf9e4
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/ComponentName.c
@@ -0,0 +1,247 @@
+/* $Id: ComponentName.c $ */
+/** @file
+ * ComponentName.c
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/*
+ This code is based on:
+
+ Copyright (c) 2006, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+*/
+
+#include "VBoxVga.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gVBoxVgaComponentName = {
+ VBoxVgaComponentNameGetDriverName,
+ VBoxVgaComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gVBoxVgaComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) VBoxVgaComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) VBoxVgaComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mVBoxVgaDriverNameTable[] = {
+ { "eng;en", L"VirtualBox SVGA Driver" },
+ { NULL , NULL }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mVBoxVgaControllerNameTable[] = {
+ { "eng;en", L"VirtualBox SVGA PCI Adapter" },
+ { NULL , NULL }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+VBoxVgaComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mVBoxVgaDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gVBoxVgaComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+VBoxVgaComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // This is a device driver, so ChildHandle must be NULL.
+ //
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Make sure this driver is currently managing ControllHandle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gVBoxVgaDriverBinding.DriverBindingHandle,
+ &gEfiPciIoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the Cirrus Logic 5430's Device structure
+ //
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mVBoxVgaControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gVBoxVgaComponentName)
+ );
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/DriverSupportedEfiVersion.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/DriverSupportedEfiVersion.c
new file mode 100644
index 00000000..32e23ad0
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/DriverSupportedEfiVersion.c
@@ -0,0 +1,58 @@
+/* $Id: DriverSupportedEfiVersion.c $ */
+/** @file
+ * DriverSupportedEfiVersion.c
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/*
+ This code is based on:
+
+ Copyright (c) 2007, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ Module Name: DriverSupportEfiVersion.c
+
+*/
+#include "VBoxVga.h"
+
+EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL gVBoxVgaDriverSupportedEfiVersion = {
+ sizeof (EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL), // Size of Protocol structure.
+ 0 // Version number to be filled at start up.
+};
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/Edid.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/Edid.c
new file mode 100644
index 00000000..87b9f00a
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/Edid.c
@@ -0,0 +1,676 @@
+/* $Id: Edid.c $ */
+/** @file
+ * Edid.c
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/*
+ This code is based on:
+
+ Read EDID information and parse EDID information.
+
+ Copyright (c) 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+*/
+
+#include "VBoxVga.h"
+#include "VBoxVgaI2c.h"
+
+//
+// EDID block
+//
+typedef struct {
+ UINT8 Header[8]; //EDID header "00 FF FF FF FF FF FF 00"
+ UINT16 ManufactureName; //EISA 3-character ID
+ UINT16 ProductCode; //Vendor assigned code
+ UINT32 SerialNumber; //32-bit serial number
+ UINT8 WeekOfManufacture; //Week number
+ UINT8 YearOfManufacture; //Year
+ UINT8 EdidVersion; //EDID Structure Version
+ UINT8 EdidRevision; //EDID Structure Revision
+ UINT8 VideoInputDefinition;
+ UINT8 MaxHorizontalImageSize; //cm
+ UINT8 MaxVerticalImageSize; //cm
+ UINT8 DisplayTransferCharacteristic;
+ UINT8 FeatureSupport;
+ UINT8 RedGreenLowBits; //Rx1 Rx0 Ry1 Ry0 Gx1 Gx0 Gy1Gy0
+ UINT8 BlueWhiteLowBits; //Bx1 Bx0 By1 By0 Wx1 Wx0 Wy1 Wy0
+ UINT8 RedX; //Red-x Bits 9 - 2
+ UINT8 RedY; //Red-y Bits 9 - 2
+ UINT8 GreenX; //Green-x Bits 9 - 2
+ UINT8 GreenY; //Green-y Bits 9 - 2
+ UINT8 BlueX; //Blue-x Bits 9 - 2
+ UINT8 BlueY; //Blue-y Bits 9 - 2
+ UINT8 WhiteX; //White-x Bits 9 - 2
+ UINT8 WhiteY; //White-x Bits 9 - 2
+ UINT8 EstablishedTimings[3];
+ UINT8 StandardTimingIdentification[16];
+ UINT8 DetailedTimingDescriptions[72];
+ UINT8 ExtensionFlag; //Number of (optional) 128-byte EDID extension blocks to follow
+ UINT8 Checksum;
+} EDID_BLOCK;
+
+#define EDID_BLOCK_SIZE 128
+#define VBE_EDID_ESTABLISHED_TIMING_MAX_NUMBER 17
+
+typedef struct {
+ UINT16 HorizontalResolution;
+ UINT16 VerticalResolution;
+ UINT16 RefreshRate;
+} EDID_TIMING;
+
+typedef struct {
+ UINT32 ValidNumber;
+ UINT32 Key[VBE_EDID_ESTABLISHED_TIMING_MAX_NUMBER];
+} VALID_EDID_TIMING;
+
+//
+// Standard timing defined by VESA EDID
+//
+EDID_TIMING mVbeEstablishedEdidTiming[] = {
+ //
+ // Established Timing I
+ //
+ {800, 600, 60},
+ {800, 600, 56},
+ {640, 480, 75},
+ {640, 480, 72},
+ {640, 480, 67},
+ {640, 480, 60},
+ {720, 400, 88},
+ {720, 400, 70},
+ //
+ // Established Timing II
+ //
+ {1280, 1024, 75},
+ {1024, 768, 75},
+ {1024, 768, 70},
+ {1024, 768, 60},
+ {1024, 768, 87},
+ {832, 624, 75},
+ {800, 600, 75},
+ {800, 600, 72},
+ //
+ // Established Timing III
+ //
+ {1152, 870, 75}
+};
+
+/**
+ Read EDID information from I2C Bus on CirrusLogic.
+
+ @param Private Pointer to VBOX_VGA_PRIVATE_DATA.
+ @param EdidDataBlock Pointer to EDID data block.
+ @param EdidSize Returned EDID block size.
+
+ @retval EFI_UNSUPPORTED
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+ReadEdidData (
+ VBOX_VGA_PRIVATE_DATA *Private,
+ UINT8 **EdidDataBlock,
+ UINTN *EdidSize
+ )
+{
+ UINTN Index;
+ UINT8 EdidData[EDID_BLOCK_SIZE * 2];
+ UINT8 *ValidEdid;
+ UINT64 Signature;
+
+ for (Index = 0; Index < EDID_BLOCK_SIZE * 2; Index ++) {
+ I2cReadByte (Private->PciIo, 0xa0, (UINT8)Index, &EdidData[Index]);
+ }
+
+ //
+ // Search for the EDID signature
+ //
+ ValidEdid = &EdidData[0];
+ Signature = 0x00ffffffffffff00ull;
+ for (Index = 0; Index < EDID_BLOCK_SIZE * 2; Index ++, ValidEdid ++) {
+ if (CompareMem (ValidEdid, &Signature, 8) == 0) {
+ break;
+ }
+ }
+
+ if (Index == 256) {
+ //
+ // No EDID signature found
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ *EdidDataBlock = AllocateCopyPool (
+ sizeof (EDID_BLOCK_SIZE),
+ ValidEdid
+ );
+ if (*EdidDataBlock == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Currently only support EDID 1.x
+ //
+ *EdidSize = EDID_BLOCK_SIZE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Generate a search key for a specified timing data.
+
+ @param EdidTiming Pointer to EDID timing
+
+ @return The 32 bit unique key for search.
+
+**/
+UINT32
+CalculateEdidKey (
+ EDID_TIMING *EdidTiming
+ )
+{
+ UINT32 Key;
+
+ //
+ // Be sure no conflicts for all standard timing defined by VESA.
+ //
+ Key = (EdidTiming->HorizontalResolution * 2) + EdidTiming->VerticalResolution;
+ return Key;
+}
+
+/**
+ Search a specified Timing in all the valid EDID timings.
+
+ @param ValidEdidTiming All valid EDID timing information.
+ @param EdidTiming The Timing to search for.
+
+ @retval TRUE Found.
+ @retval FALSE Not found.
+
+**/
+BOOLEAN
+SearchEdidTiming (
+ VALID_EDID_TIMING *ValidEdidTiming,
+ EDID_TIMING *EdidTiming
+ )
+{
+ UINT32 Index;
+ UINT32 Key;
+
+ Key = CalculateEdidKey (EdidTiming);
+
+ for (Index = 0; Index < ValidEdidTiming->ValidNumber; Index ++) {
+ if (Key == ValidEdidTiming->Key[Index]) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Parse the Established Timing and Standard Timing in EDID data block.
+
+ @param EdidBuffer Pointer to EDID data block
+ @param ValidEdidTiming Valid EDID timing information
+
+ @retval TRUE The EDID data is valid.
+ @retval FALSE The EDID data is invalid.
+
+**/
+BOOLEAN
+ParseEdidData (
+ UINT8 *EdidBuffer,
+ VALID_EDID_TIMING *ValidEdidTiming
+ )
+{
+ UINT8 CheckSum;
+ UINT32 Index;
+ UINT32 ValidNumber;
+ UINT32 TimingBits;
+ UINT8 *BufferIndex;
+ UINT16 HorizontalResolution;
+ UINT16 VerticalResolution;
+ UINT8 AspectRatio;
+ UINT8 RefreshRate;
+ EDID_TIMING TempTiming;
+ EDID_BLOCK *EdidDataBlock;
+
+ EdidDataBlock = (EDID_BLOCK *) EdidBuffer;
+
+ //
+ // Check the checksum of EDID data
+ //
+ CheckSum = 0;
+ for (Index = 0; Index < EDID_BLOCK_SIZE; Index ++) {
+ CheckSum = (UINT8) (CheckSum + EdidBuffer[Index]);
+ }
+ if (CheckSum != 0) {
+ return FALSE;
+ }
+
+ ValidNumber = 0;
+ SetMem (ValidEdidTiming, sizeof (VALID_EDID_TIMING), 0);
+
+ if ((EdidDataBlock->EstablishedTimings[0] != 0) ||
+ (EdidDataBlock->EstablishedTimings[1] != 0) ||
+ (EdidDataBlock->EstablishedTimings[2] != 0)
+ ) {
+ //
+ // Established timing data
+ //
+ TimingBits = EdidDataBlock->EstablishedTimings[0] |
+ (EdidDataBlock->EstablishedTimings[1] << 8) |
+ ((EdidDataBlock->EstablishedTimings[2] & 0x80) << 9) ;
+ for (Index = 0; Index < VBE_EDID_ESTABLISHED_TIMING_MAX_NUMBER; Index ++) {
+ if (TimingBits & 0x1) {
+ ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&mVbeEstablishedEdidTiming[Index]);
+ ValidNumber ++;
+ }
+ TimingBits = TimingBits >> 1;
+ }
+ } else {
+ //
+ // If no Established timing data, read the standard timing data
+ //
+ BufferIndex = &EdidDataBlock->StandardTimingIdentification[0];
+ for (Index = 0; Index < 8; Index ++) {
+ if ((BufferIndex[0] != 0x1) && (BufferIndex[1] != 0x1)){
+ //
+ // A valid Standard Timing
+ //
+ HorizontalResolution = (UINT16) (BufferIndex[0] * 8 + 248);
+ AspectRatio = (UINT8) (BufferIndex[1] >> 6);
+ switch (AspectRatio) {
+ case 0:
+ VerticalResolution = (UINT16) (HorizontalResolution / 16 * 10);
+ break;
+ case 1:
+ VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);
+ break;
+ case 2:
+ VerticalResolution = (UINT16) (HorizontalResolution / 5 * 4);
+ break;
+ case 3:
+ VerticalResolution = (UINT16) (HorizontalResolution / 16 * 9);
+ break;
+ default:
+ VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);
+ break;
+ }
+ RefreshRate = (UINT8) ((BufferIndex[1] & 0x1f) + 60);
+ TempTiming.HorizontalResolution = HorizontalResolution;
+ TempTiming.VerticalResolution = VerticalResolution;
+ TempTiming.RefreshRate = RefreshRate;
+ ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&TempTiming);
+ ValidNumber ++;
+ }
+ BufferIndex += 2;
+ }
+ }
+
+ ValidEdidTiming->ValidNumber = ValidNumber;
+ return TRUE;
+}
+
+static uint16_t in_word(uint16_t port, uint16_t addr)
+{
+ ASMOutU16(port, addr);
+ return ASMInU16(port);
+}
+
+static EFI_STATUS VBoxVgaVideoModeInitExtra(void)
+{
+ UINT16 w, cur_info_ofs, vmode, xres, yres;
+ UINTN Index;
+ VBOX_VGA_VIDEO_MODES *VideoMode;
+
+ // Read and check the VBE Extra Data magic
+ w = in_word(VBE_EXTRA_PORT, 0);
+ if (w != VBEHEADER_MAGIC) {
+ DEBUG((DEBUG_INFO, "%a:%d could not find VBE magic, got %x\n", __FILE__, __LINE__, w));
+ return EFI_NOT_FOUND;
+ }
+
+ cur_info_ofs = sizeof(VBEHeader);
+
+ Index = VBoxVgaVideoModeCount - 16;
+ VideoMode = &VBoxVgaVideoModes[Index];
+ vmode = in_word(VBE_EXTRA_PORT, cur_info_ofs + OFFSET_OF(ModeInfoListItem, mode));
+ while (vmode != VBE_VESA_MODE_END_OF_LIST)
+ {
+ xres = in_word(VBE_EXTRA_PORT, cur_info_ofs + OFFSET_OF(ModeInfoListItem, info.XResolution));
+ yres = in_word(VBE_EXTRA_PORT, cur_info_ofs + OFFSET_OF(ModeInfoListItem, info.YResolution));
+
+ if (vmode >= VBE_VBOX_MODE_CUSTOM1 && vmode <= VBE_VBOX_MODE_CUSTOM16 && xres && yres && Index < VBoxVgaVideoModeCount) {
+ VideoMode->Width = xres;
+ VideoMode->Height = yres;
+ VideoMode->ColorDepth = 32;
+ VideoMode->RefreshRate = 60;
+ VideoMode->MiscSetting = 0x01;
+ VideoMode++;
+ Index++;
+ }
+
+ cur_info_ofs += sizeof(ModeInfoListItem);
+ vmode = in_word(VBE_EXTRA_PORT, cur_info_ofs + OFFSET_OF(ModeInfoListItem, mode));
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Construct the valid video modes for VBoxVga.
+
+**/
+EFI_STATUS
+VBoxVgaVideoModeSetup (
+ VBOX_VGA_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ BOOLEAN EdidFound;
+ EFI_EDID_OVERRIDE_PROTOCOL *EdidOverride;
+ UINT32 EdidAttributes;
+ BOOLEAN EdidOverrideFound;
+ UINTN EdidOverrideDataSize;
+ UINT8 *EdidOverrideDataBlock;
+ UINTN EdidDiscoveredDataSize;
+ UINT8 *EdidDiscoveredDataBlock;
+ UINTN EdidActiveDataSize;
+ UINT8 *EdidActiveDataBlock;
+ VALID_EDID_TIMING ValidEdidTiming;
+ UINT32 ValidModeCount;
+ VBOX_VGA_MODE_DATA *ModeData;
+ BOOLEAN TimingMatch;
+ const VBOX_VGA_VIDEO_MODES *VideoMode;
+ EDID_TIMING TempTiming;
+
+ //
+ // setup EDID information
+ //
+ Private->EdidDiscovered.Edid = NULL;
+ Private->EdidDiscovered.SizeOfEdid = 0;
+ Private->EdidActive.Edid = NULL;
+ Private->EdidActive.SizeOfEdid = 0;
+
+ EdidFound = FALSE;
+ EdidOverrideFound = FALSE;
+ EdidAttributes = 0xff;
+ EdidOverrideDataSize = 0;
+ EdidOverrideDataBlock = NULL;
+ EdidActiveDataSize = 0;
+ EdidActiveDataBlock = NULL;
+ EdidDiscoveredDataBlock = NULL;
+
+ //
+ // Find EDID Override protocol firstly, this protocol is installed by platform if needed.
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiEdidOverrideProtocolGuid,
+ NULL,
+ (VOID **) &EdidOverride
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow
+ //
+ EdidOverrideDataBlock = AllocatePool (sizeof (EDID_BLOCK_SIZE * 2));
+ if (NULL == EdidOverrideDataBlock) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ Status = EdidOverride->GetEdid (
+ EdidOverride,
+ Private->Handle,
+ &EdidAttributes,
+ &EdidOverrideDataSize,
+ (UINT8 **) &EdidOverrideDataBlock
+ );
+ if (!EFI_ERROR (Status) &&
+ EdidAttributes == 0 &&
+ EdidOverrideDataSize != 0) {
+ //
+ // Succeeded to get EDID Override Data
+ //
+ EdidOverrideFound = TRUE;
+ }
+ }
+
+ if (EdidOverrideFound != TRUE || EdidAttributes == EFI_EDID_OVERRIDE_DONT_OVERRIDE) {
+ //
+ // If EDID Override data doesn't exist or EFI_EDID_OVERRIDE_DONT_OVERRIDE returned,
+ // read EDID information through I2C Bus
+ //
+ if (ReadEdidData (Private, &EdidDiscoveredDataBlock, &EdidDiscoveredDataSize) == EFI_SUCCESS) {
+ Private->EdidDiscovered.SizeOfEdid = (UINT32) EdidDiscoveredDataSize;
+ Private->EdidDiscovered.Edid = (UINT8 *) AllocateCopyPool (
+ EdidDiscoveredDataSize,
+ EdidDiscoveredDataBlock
+ );
+
+ if (NULL == Private->EdidDiscovered.Edid) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ EdidActiveDataSize = Private->EdidDiscovered.SizeOfEdid;
+ EdidActiveDataBlock = Private->EdidDiscovered.Edid;
+
+ EdidFound = TRUE;
+ }
+ }
+
+ if (EdidFound != TRUE && EdidOverrideFound == TRUE) {
+ EdidActiveDataSize = EdidOverrideDataSize;
+ EdidActiveDataBlock = EdidOverrideDataBlock;
+ EdidFound = TRUE;
+ }
+
+ if (EdidFound == TRUE) {
+ //
+ // Parse EDID data structure to retrieve modes supported by monitor
+ //
+ if (ParseEdidData ((UINT8 *) EdidActiveDataBlock, &ValidEdidTiming) == TRUE) {
+ //
+ // Copy EDID Override Data to EDID Active Data
+ //
+ Private->EdidActive.SizeOfEdid = (UINT32) EdidActiveDataSize;
+ Private->EdidActive.Edid = (UINT8 *) AllocateCopyPool (
+ EdidActiveDataSize,
+ EdidActiveDataBlock
+ );
+ if (NULL == Private->EdidActive.Edid) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ }
+ } else {
+ Private->EdidActive.SizeOfEdid = 0;
+ Private->EdidActive.Edid = NULL;
+ EdidFound = FALSE;
+ }
+
+ if (EdidFound && 0) {
+ //
+ // Initialize the private mode data with the supported modes.
+ //
+ ValidModeCount = 0;
+ Private->ModeData = AllocatePool(sizeof(VBOX_VGA_MODE_DATA) * VBoxVgaVideoModeCount);
+ ModeData = &Private->ModeData[0];
+ VideoMode = &VBoxVgaVideoModes[0];
+ for (Index = 0; Index < VBoxVgaVideoModeCount; Index++) {
+
+ TimingMatch = TRUE;
+
+ //
+ // Check whether match with VBoxVga video mode
+ //
+ TempTiming.HorizontalResolution = (UINT16) VideoMode->Width;
+ TempTiming.VerticalResolution = (UINT16) VideoMode->Height;
+ TempTiming.RefreshRate = (UINT16) VideoMode->RefreshRate;
+ if (SearchEdidTiming (&ValidEdidTiming, &TempTiming) != TRUE) {
+ TimingMatch = FALSE;
+ }
+
+ //
+ // Not export Mode 0x0 as GOP mode, this is not defined in spec.
+ //
+ if ((VideoMode->Width == 0) || (VideoMode->Height == 0)) {
+ TimingMatch = FALSE;
+ }
+
+ //
+ // Check whether the mode would be exceeding the VRAM size.
+ //
+ if (VideoMode->Width * VideoMode->Height * (VideoMode->ColorDepth / 8) > Private->VRAMSize) {
+ TimingMatch = FALSE;
+ }
+
+ if (TimingMatch) {
+ ModeData->ModeNumber = Index;
+ ModeData->HorizontalResolution = VideoMode->Width;
+ ModeData->VerticalResolution = VideoMode->Height;
+ ModeData->ColorDepth = VideoMode->ColorDepth;
+ ModeData->RefreshRate = VideoMode->RefreshRate;
+
+ ModeData ++;
+ ValidModeCount ++;
+ }
+
+ VideoMode ++;
+ }
+ } else {
+ //
+ // If EDID information wasn't found
+ //
+ VBoxVgaVideoModeInitExtra();
+ ValidModeCount = 0;
+ Private->ModeData = AllocatePool(sizeof(VBOX_VGA_MODE_DATA) * VBoxVgaVideoModeCount);
+ ModeData = &Private->ModeData[0];
+ VideoMode = &VBoxVgaVideoModes[0];
+ for (Index = 0; Index < VBoxVgaVideoModeCount; Index ++) {
+
+ TimingMatch = TRUE;
+
+ //
+ // Not export Mode 0x0 as GOP mode, this is not defined in spec.
+ //
+ if ((VideoMode->Width == 0) || (VideoMode->Height == 0)) {
+ TimingMatch = FALSE;
+ }
+
+ //
+ // Check whether the mode would be exceeding the VRAM size.
+ //
+ if (VideoMode->Width * VideoMode->Height * (VideoMode->ColorDepth / 8) > Private->VRAMSize) {
+ TimingMatch = FALSE;
+ }
+
+ if (TimingMatch) {
+ ModeData->ModeNumber = Index;
+ ModeData->HorizontalResolution = VideoMode->Width;
+ ModeData->VerticalResolution = VideoMode->Height;
+ ModeData->ColorDepth = VideoMode->ColorDepth;
+ ModeData->RefreshRate = VideoMode->RefreshRate;
+
+ ModeData ++;
+ ValidModeCount ++;
+ }
+
+ VideoMode ++;
+ }
+ }
+
+ // Sort list of video modes (keeping duplicates) by increasing X, then Y,
+ // then the mode number. This way the custom modes are not overriding the
+ // default modes if they are for the same resolution.
+ ModeData = &Private->ModeData[0];
+ for (Index = 0; Index < ValidModeCount - 1; Index ++) {
+ UINT32 Index2;
+ VBOX_VGA_MODE_DATA *ModeData2 = ModeData + 1;
+ for (Index2 = Index + 1; Index2 < ValidModeCount; Index2 ++) {
+ if ( ModeData->HorizontalResolution > ModeData2->HorizontalResolution
+ || ( ModeData->HorizontalResolution == ModeData2->HorizontalResolution
+ && ModeData->VerticalResolution > ModeData2->VerticalResolution)
+ || ( ModeData->HorizontalResolution == ModeData2->HorizontalResolution
+ && ModeData->VerticalResolution == ModeData2->VerticalResolution
+ && ModeData->ModeNumber > ModeData2->ModeNumber)) {
+ VBOX_VGA_MODE_DATA Tmp;
+ CopyMem(&Tmp, ModeData, sizeof(Tmp));
+ CopyMem(ModeData, ModeData2, sizeof(Tmp));
+ CopyMem(ModeData2, &Tmp, sizeof(Tmp));
+ DEBUG((DEBUG_INFO, "%a:%d swapped mode entries %d and %d\n", __FILE__, __LINE__, Index, Index2));
+ }
+ ModeData2++;
+ }
+ ModeData++;
+ }
+
+ // dump mode list for debugging purposes
+ ModeData = &Private->ModeData[0];
+ for (Index = 0; Index < ValidModeCount; Index ++) {
+ DEBUG((DEBUG_INFO, "%a:%d mode %d: %dx%d mode number %d\n", __FILE__, __LINE__, Index, ModeData->HorizontalResolution, ModeData->VerticalResolution, ModeData->ModeNumber));
+ ModeData++;
+ }
+
+ Private->MaxMode = ValidModeCount;
+
+ if (EdidOverrideDataBlock != NULL) {
+ FreePool (EdidOverrideDataBlock);
+ }
+
+ return EFI_SUCCESS;
+
+Done:
+ if (EdidOverrideDataBlock != NULL) {
+ FreePool (EdidOverrideDataBlock);
+ }
+ if (Private->EdidDiscovered.Edid != NULL) {
+ FreePool (Private->EdidDiscovered.Edid);
+ }
+ if (Private->EdidDiscovered.Edid != NULL) {
+ FreePool (Private->EdidActive.Edid);
+ }
+
+ return EFI_DEVICE_ERROR;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVga.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVga.c
new file mode 100644
index 00000000..b6cb464d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVga.c
@@ -0,0 +1,1171 @@
+/* $Id: VBoxVga.c $ */
+/** @file
+ * VBoxVga.c
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/*
+ This code is based on:
+
+ Cirrus Logic 5430 Controller Driver.
+ This driver is a sample implementation of the UGA Draw and Graphics Output
+ Protocols for the Cirrus Logic 5430 family of PCI video controllers.
+ This driver is only usable in the EFI pre-boot environment.
+ This sample is intended to show how the UGA Draw and Graphics output Protocol
+ is able to function.
+ The UGA I/O Protocol is not implemented in this sample.
+ A fully compliant EFI UGA driver requires both
+ the UGA Draw and the UGA I/O Protocol. Please refer to Microsoft's
+ documentation on UGA for details on how to write a UGA driver that is able
+ to function both in the EFI pre-boot environment and from the OS runtime.
+
+ Copyright (c) 2006 - 2009, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+*/
+
+//
+// VirtualBox VGA Controller Driver
+//
+#include "VBoxVga.h"
+#include <IndustryStandard/Acpi.h>
+#include "iprt/asm.h"
+
+
+#define BOUTB(storage, count, aport, dport) \
+ do { \
+ for (i = 0 ; i < (count); ++i) \
+ if ((dport) == (aport) + 1) \
+ ASMOutU16((aport), ((UINT16)storage[i] << 8) | (UINT8)i); \
+ else { \
+ ASMOutU8((aport), (UINT8)i); \
+ ASMOutU8((dport), storage[i]); \
+ } \
+ } while (0)
+
+
+
+EFI_DRIVER_BINDING_PROTOCOL gVBoxVgaDriverBinding = {
+ VBoxVgaControllerDriverSupported,
+ VBoxVgaControllerDriverStart,
+ VBoxVgaControllerDriverStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+///
+/// Generic Attribute Controller Register Settings
+///
+UINT8 AttributeController[21] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x41, 0x00, 0x0F, 0x00, 0x00
+};
+
+///
+/// Generic Graphics Controller Register Settings
+///
+UINT8 GraphicsController[9] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 0xff
+};
+
+///
+/// Generic Graphics Controller Sequencer Register Settings
+///
+UINT8 Seq_Default[5] = {
+ 0x01, 0x01, 0x0f, 0x00, 0x0a
+};
+
+#if 0 // CRTC tables not used (and not checked for correctness), as VBE is much simpler
+//
+// 640 x 480 x 256 color @ 60 Hertz
+//
+UINT8 Crtc_640_480_256_60[25] = {
+ /* r0 = */0x5f, /* r1 = */0x4f, /* r2 = */0x50, /* r3 = */0x82,
+ /* r4 = */0x54, /* r5 = */0x80, /* r6 = */0x0b, /* r7 = */0x3e,
+ /* r8 = */0x00, /* r9 = */0x40, /* r10 = */0x00, /* r11 = */0x00,
+ /* r12 = */0x00, /* r13 = */0x00, /* r14 = */0x00, /* r15 = */0x00,
+ /* r16 = */0xea, /* r17 = */0x0c, /* r18 = */0xdf, /* r19 = */0x28,
+ /* r20 = */0x4f, /* r21 = */0xe7, /* r22 = */0x04, /* r23 = */0xe3,
+ /* r24 = */0xff
+};
+
+//
+// 800 x 600 x 256 color @ 60 Hertz
+//
+UINT8 Crtc_800_600_256_60[25] = {
+ /* r0 = */0x7f, /* r1 = */0x63, /* r2 = */0x64, /* r3 = */0x82,
+ /* r4 = */0x6b, /* r5 = */0x80, /* r6 = */0x0b, /* r7 = */0x3e,
+ /* r8 = */0x00, /* r9 = */0x60, /* r10 = */0x00, /* r11 = */0x00,
+ /* r12 = */0x00, /* r13 = */0x00, /* r14 = */0x00, /* r15 = */0x00,
+ /* r16 = */0xea, /* r17 = */0x0c, /* r18 = */0xdf, /* r19 = */0x28,
+ /* r20 = */0x4f, /* r21 = */0xe7, /* r22 = */0x04, /* r23 = */0xe3,
+ /* r24 = */0xff
+
+};
+
+//
+// 1024 x 768 x 256 color @ 60 Hertz
+//
+UINT8 Crtc_1024_768_256_60[25] = {
+ /* r0 = */0xa3, /* r1 = */0x7f, /* r2 = */0x81, /* r3 = */0x90,
+ /* r4 = */0x88, /* r5 = */0x05, /* r6 = */0x28, /* r7 = */0xfd,
+ /* r8 = */0x00, /* r9 = */0x60, /* r10 = */0x00, /* r11 = */0x00,
+ /* r12 = */0x00, /* r13 = */0x00, /* r14 = */0x00, /* r15 = */0x00,
+ /* r16 = */0x06, /* r17 = */0x0f, /* r18 = */0xff, /* r19 = */0x40,
+ /* r20 = */0x4f, /* r21 = */0x05, /* r22 = */0x1a, /* r23 = */0xe3,
+ /* r24 = */0xff
+};
+#endif
+
+///
+/// Table of supported video modes (sorted by increasing horizontal, then by
+/// increasing vertical resolution)
+///
+VBOX_VGA_VIDEO_MODES VBoxVgaVideoModes[] =
+{
+ { 640, 480, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // VGA 4:3
+ { 800, 600, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // SVGA 4:3
+ { 1024, 768, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // XGA 4:3
+ { 1152, 864, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // XGA+ 4:3
+ { 1280, 720, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // HD 16:9
+ { 1280, 800, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // WXGA 16:10
+ { 1280, 1024, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // SXGA 5:4
+ { 1400, 1050, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // SXGA+ 4:3
+ { 1440, 900, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // WXGA+ 16:10
+ { 1600, 900, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // HD+ 16:9
+ { 1600, 1200, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // UXGA 4:3
+ { 1680, 1050, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // WSXGA+ 16:10
+ { 1920, 1080, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // FHD 16:9
+ { 1920, 1200, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // WUXGA 16:10
+ { 2048, 1080, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // DCI_2K 19:10
+ { 2160, 1440, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // FHD+ 3:2
+ { 2304, 1440, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // unnamed 16:10
+ { 2560, 1440, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // QHD 16:9
+ { 2560, 1600, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // WQXGA 16:10
+ { 2880, 1800, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // QWXGA+ 16:10
+ { 3200, 1800, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // QHD+ 16:9
+ { 3200, 2048, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // WQSXGA 16:10
+ { 3840, 2160, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // 4K_UHD 16:9
+ { 3840, 2400, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // WQUXGA 16:10
+ { 4096, 2160, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // DCI_4K 19:10
+ { 4096, 3072, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // HXGA 4:3
+ { 5120, 2880, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // UHD+ 16:9
+ { 5120, 3200, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // WHXGA 16:10
+ { 6400, 4096, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // WHSXGA 16:10
+ { 6400, 4800, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // HUXGA 4:3
+ { 7680, 4320, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // 8K_UHD2 16:9
+ { 0, }, // Custom video mode 0, do not delete, must be at the end!
+ { 0, }, // Custom video mode 1, do not delete, must be at the end!
+ { 0, }, // Custom video mode 2, do not delete, must be at the end!
+ { 0, }, // Custom video mode 3, do not delete, must be at the end!
+ { 0, }, // Custom video mode 4, do not delete, must be at the end!
+ { 0, }, // Custom video mode 5, do not delete, must be at the end!
+ { 0, }, // Custom video mode 6, do not delete, must be at the end!
+ { 0, }, // Custom video mode 7, do not delete, must be at the end!
+ { 0, }, // Custom video mode 8, do not delete, must be at the end!
+ { 0, }, // Custom video mode 9, do not delete, must be at the end!
+ { 0, }, // Custom video mode 10, do not delete, must be at the end!
+ { 0, }, // Custom video mode 11, do not delete, must be at the end!
+ { 0, }, // Custom video mode 12, do not delete, must be at the end!
+ { 0, }, // Custom video mode 13, do not delete, must be at the end!
+ { 0, }, // Custom video mode 14, do not delete, must be at the end!
+ { 0, } // Custom video mode 15, do not delete, must be at the end!
+};
+
+const UINT32 VBoxVgaVideoModeCount = sizeof(VBoxVgaVideoModes) / sizeof(VBoxVgaVideoModes[0]);
+
+typedef struct _APPLE_FRAMEBUFFERINFO_PROTOCOL APPLE_FRAMEBUFFERINFO_PROTOCOL;
+
+typedef
+EFI_STATUS
+(EFIAPI *APPLE_FRAMEBUFFERINFO_PROTOCOL_GET_INFO) (
+ IN APPLE_FRAMEBUFFERINFO_PROTOCOL *This,
+ OUT UINT32 *BaseAddr,
+ OUT UINT32 *Something,
+ OUT UINT32 *RowBytes,
+ OUT UINT32 *Width,
+ OUT UINT32 *Height,
+ OUT UINT32 *Depth);
+
+struct _APPLE_FRAMEBUFFERINFO_PROTOCOL {
+ APPLE_FRAMEBUFFERINFO_PROTOCOL_GET_INFO GetInfo;
+ VBOX_VGA_PRIVATE_DATA *Private;
+};
+
+EFI_STATUS EFIAPI
+GetFrameBufferInfo(IN APPLE_FRAMEBUFFERINFO_PROTOCOL *This,
+ OUT UINT32 *BaseAddr,
+ OUT UINT32 *Something,
+ OUT UINT32 *RowBytes,
+ OUT UINT32 *Width,
+ OUT UINT32 *Height,
+ OUT UINT32 *Depth);
+
+static APPLE_FRAMEBUFFERINFO_PROTOCOL gAppleFrameBufferInfo =
+{
+ GetFrameBufferInfo,
+ NULL
+};
+
+
+/*
+ * @todo move this function to the library.
+ */
+UINT32 VBoxVgaGetVmVariable(UINT32 Variable, CHAR8* Buffer, UINT32 Size)
+{
+ UINT32 VarLen, i;
+
+ ASMOutU32(EFI_INFO_PORT, Variable);
+ VarLen = ASMInU32(EFI_INFO_PORT);
+
+ for (i = 0; i < VarLen && i < Size; i++)
+ Buffer[i] = ASMInU8(EFI_INFO_PORT);
+
+ return VarLen;
+}
+
+
+/**
+ VBoxVgaControllerDriverSupported
+
+ TODO: This - add argument and description to function comment
+ TODO: Controller - add argument and description to function comment
+ TODO: RemainingDevicePath - add argument and description to function comment
+**/
+EFI_STATUS
+EFIAPI
+VBoxVgaControllerDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 Pci;
+ EFI_DEV_PATH *Node;
+
+ //
+ // Open the PCI I/O Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_INFO, "%a:%d status:%r\n", __FILE__, __LINE__, Status));
+ return Status;
+ }
+
+ //
+ // Read the PCI Configuration Header from the PCI Device
+ //
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (Pci) / sizeof (UINT32),
+ &Pci
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_INFO, "%a:%d status:%r\n", __FILE__, __LINE__, Status));
+ goto Done;
+ }
+
+ Status = EFI_UNSUPPORTED;
+ //
+ // See if the I/O enable is on. Most systems only allow one VGA device to be turned on
+ // at a time, so see if this is one that is turned on.
+ //
+ // if (((Pci.Hdr.Command & 0x01) == 0x01)) {
+ //
+ // See if this is a VirtualBox VGA or VMSVGA II PCI controller
+ //
+ if ( ((Pci.Hdr.VendorId == VBOX_VENDOR_ID) && (Pci.Hdr.DeviceId == VBOX_VGA_DEVICE_ID))
+ || ((Pci.Hdr.VendorId == VMSVGA_VENDOR_ID) && (Pci.Hdr.DeviceId == VMSVGA_II_DEVICE_ID))) {
+
+ Status = EFI_SUCCESS;
+ if (RemainingDevicePath != NULL) {
+ Node = (EFI_DEV_PATH *) RemainingDevicePath;
+ //
+ // Check if RemainingDevicePath is the End of Device Path Node,
+ // if yes, return EFI_SUCCESS
+ //
+ if (!IsDevicePathEnd (Node)) {
+ //
+ // If RemainingDevicePath isn't the End of Device Path Node,
+ // check its validation
+ //
+ if (Node->DevPath.Type != ACPI_DEVICE_PATH ||
+ Node->DevPath.SubType != ACPI_ADR_DP ||
+ DevicePathNodeLength(&Node->DevPath) != sizeof(ACPI_ADR_DEVICE_PATH)) {
+ DEBUG((DEBUG_INFO, "%a:%d status:%r\n", __FILE__, __LINE__, Status));
+ Status = EFI_UNSUPPORTED;
+ }
+ }
+ }
+ }
+
+Done:
+ //
+ // Close the PCI I/O Protocol
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ DEBUG((DEBUG_INFO, "%a:%d status:%r\n", __FILE__, __LINE__, Status));
+ return Status;
+}
+
+/**
+ VBoxVgaControllerDriverStart
+
+ TODO: This - add argument and description to function comment
+ TODO: Controller - add argument and description to function comment
+ TODO: RemainingDevicePath - add argument and description to function comment
+**/
+EFI_STATUS
+EFIAPI
+VBoxVgaControllerDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ VBOX_VGA_PRIVATE_DATA *Private;
+ BOOLEAN PciAttributesSaved;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ ACPI_ADR_DEVICE_PATH AcpiDeviceNode;
+ PCI_TYPE00 Pci;
+
+ PciAttributesSaved = FALSE;
+ //
+ // Allocate Private context data for UGA Draw interface.
+ //
+ Private = AllocateZeroPool (sizeof (VBOX_VGA_PRIVATE_DATA));
+ if (Private == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+ gAppleFrameBufferInfo.Private = Private;
+ //
+ // Set up context record
+ //
+ Private->Signature = VBOX_VGA_PRIVATE_DATA_SIGNATURE;
+ Private->Handle = NULL;
+
+ //
+ // Open PCI I/O Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &Private->PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ //
+ // Read the PCI Configuration Header from the PCI Device again to figure out the model.
+ //
+ Status = Private->PciIo->Pci.Read (
+ Private->PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (Pci) / sizeof (UINT32),
+ &Pci
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_INFO, "%a:%d status:%r\n", __FILE__, __LINE__, Status));
+ goto Error;
+ }
+
+ Private->DeviceType = Pci.Hdr.DeviceId;
+
+ //
+ // Save original PCI attributes
+ //
+ Status = Private->PciIo->Attributes (
+ Private->PciIo,
+ EfiPciIoAttributeOperationGet,
+ 0,
+ &Private->OriginalPciAttributes
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ PciAttributesSaved = TRUE;
+
+ Status = Private->PciIo->Attributes (
+ Private->PciIo,
+ EfiPciIoAttributeOperationEnable,
+ EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ //
+ // Get ParentDevicePath
+ //
+ Status = gBS->HandleProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ if (FeaturePcdGet (PcdSupportGop)) {
+ //
+ // Set Gop Device Path
+ //
+ if (RemainingDevicePath == NULL) {
+ ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH));
+ AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;
+ AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;
+ AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA, 0, 0);
+ SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH));
+
+ Private->GopDevicePath = AppendDevicePathNode (
+ ParentDevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode
+ );
+ } else if (!IsDevicePathEnd (RemainingDevicePath)) {
+ //
+ // If RemainingDevicePath isn't the End of Device Path Node,
+ // only scan the specified device by RemainingDevicePath
+ //
+ Private->GopDevicePath = AppendDevicePathNode (ParentDevicePath, RemainingDevicePath);
+ } else {
+ //
+ // If RemainingDevicePath is the End of Device Path Node,
+ // don't create child device and return EFI_SUCCESS
+ //
+ Private->GopDevicePath = NULL;
+ }
+
+ if (Private->GopDevicePath != NULL) {
+ //
+ // Create child handle and device path protocol first
+ //
+ Private->Handle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Private->Handle,
+ &gEfiDevicePathProtocolGuid,
+ Private->GopDevicePath,
+ NULL
+ );
+ }
+ }
+
+ //
+ // Now do some model-specific setup.
+ //
+ if (Private->DeviceType == VMSVGA_II_DEVICE_ID) {
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *IOPortDesc;
+
+ // VMSVGA
+ Private->BarIndexFB = 1;
+
+ Private->PciIo->GetBarAttributes (
+ Private->PciIo,
+ 0, // BAR 0 is the I/O port space
+ NULL,
+ (VOID**) &IOPortDesc
+ );
+ Private->IOBase = (UINT16)IOPortDesc->AddrRangeMin;
+
+ //
+ // Query the VRAM size (for proper mode filtering)
+ //
+ ASMOutU32(Private->IOBase + SVGA_INDEX_PORT, SVGA_REG_VRAM_SIZE);
+ Private->VRAMSize = ASMInU32(Private->IOBase + SVGA_VALUE_PORT);
+
+#if 0
+ // Not used because of buggy emulation(?) which is not fully compatible
+ // with the simple "legacy" VMSVGA II register interface.
+
+ // Enable the device, set initial mode
+ ASMOutU32(Private->IOBase + SVGA_INDEX_PORT, SVGA_REG_WIDTH);
+ ASMOutU32(Private->IOBase + SVGA_VALUE_PORT, 1024);
+ ASMOutU32(Private->IOBase + SVGA_INDEX_PORT, SVGA_REG_HEIGHT);
+ ASMOutU32(Private->IOBase + SVGA_VALUE_PORT, 768);
+ ASMOutU32(Private->IOBase + SVGA_INDEX_PORT, SVGA_REG_BYTES_PER_LINE);
+ ASMOutU32(Private->IOBase + SVGA_VALUE_PORT, 768 * 4);
+ ASMOutU32(Private->IOBase + SVGA_INDEX_PORT, SVGA_REG_BITS_PER_PIXEL);
+ ASMOutU32(Private->IOBase + SVGA_VALUE_PORT, 32);
+ ASMOutU32(Private->IOBase + SVGA_INDEX_PORT, SVGA_REG_CONFIG_DONE);
+ ASMOutU32(Private->IOBase + SVGA_VALUE_PORT, 1);
+
+ ASMOutU32(Private->IOBase + SVGA_INDEX_PORT, SVGA_REG_ENABLE);
+ ASMOutU32(Private->IOBase + SVGA_VALUE_PORT, SVGA_REG_ENABLE_ENABLE);
+#endif
+ } else {
+ // VBoxVGA / VBoxSVGA
+ Private->BarIndexFB = 0;
+ //
+ // Get VRAM size, needed for constructing a correct video mode list
+ //
+ Private->VRAMSize = ASMInU32(VBE_DISPI_IOPORT_DATA);
+ }
+
+
+ //
+ // Construct video mode list
+ //
+ Status = VBoxVgaVideoModeSetup (Private);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ if (FeaturePcdGet (PcdSupportUga)) {
+ //
+ // Start the UGA Draw software stack.
+ //
+ Status = VBoxVgaUgaDrawConstructor (Private);
+ ASSERT_EFI_ERROR (Status);
+
+ Private->UgaDevicePath = ParentDevicePath;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ //&gEfiUgaDrawProtocolGuid,
+ //&Private->UgaDraw,
+ &gEfiDevicePathProtocolGuid,
+ Private->UgaDevicePath,
+ NULL
+ );
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiUgaDrawProtocolGuid,
+ &Private->UgaDraw,
+ NULL
+ );
+
+ } else if (FeaturePcdGet (PcdSupportGop)) {
+ if (Private->GopDevicePath == NULL) {
+ //
+ // If RemainingDevicePath is the End of Device Path Node,
+ // don't create child device and return EFI_SUCCESS
+ //
+ Status = EFI_SUCCESS;
+ } else {
+
+ //
+ // Start the GOP software stack.
+ //
+ Status = VBoxVgaGraphicsOutputConstructor (Private);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Private->Handle,
+ &gEfiGraphicsOutputProtocolGuid,
+ &Private->GraphicsOutput,
+ &gEfiEdidDiscoveredProtocolGuid,
+ &Private->EdidDiscovered,
+ &gEfiEdidActiveProtocolGuid,
+ &Private->EdidActive,
+ NULL
+ );
+ }
+ } else {
+ //
+ // This driver must support eithor GOP or UGA or both.
+ //
+ ASSERT (FALSE);
+ Status = EFI_UNSUPPORTED;
+ }
+
+Error:
+ if (EFI_ERROR (Status)) {
+ if (Private) {
+ if (Private->PciIo) {
+ if (PciAttributesSaved == TRUE) {
+ //
+ // Restore original PCI attributes
+ //
+ Private->PciIo->Attributes (
+ Private->PciIo,
+ EfiPciIoAttributeOperationSet,
+ Private->OriginalPciAttributes,
+ NULL
+ );
+ }
+ //
+ // Close the PCI I/O Protocol
+ //
+ gBS->CloseProtocol (
+ Private->Handle,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Private->Handle
+ );
+ }
+
+ gBS->FreePool (Private);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ VBoxVgaControllerDriverStop
+
+ TODO: This - add argument and description to function comment
+ TODO: Controller - add argument and description to function comment
+ TODO: NumberOfChildren - add argument and description to function comment
+ TODO: ChildHandleBuffer - add argument and description to function comment
+ TODO: EFI_SUCCESS - add return value to function comment
+**/
+EFI_STATUS
+EFIAPI
+VBoxVgaControllerDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_UGA_DRAW_PROTOCOL *UgaDraw;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+
+ EFI_STATUS Status;
+ VBOX_VGA_PRIVATE_DATA *Private;
+
+ if (FeaturePcdGet (PcdSupportUga)) {
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUgaDrawProtocolGuid,
+ (VOID **) &UgaDraw,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get our private context information
+ //
+ Private = VBOX_VGA_PRIVATE_DATA_FROM_UGA_DRAW_THIS (UgaDraw);
+ VBoxVgaUgaDrawDestructor (Private);
+
+ if (FeaturePcdGet (PcdSupportGop)) {
+ VBoxVgaGraphicsOutputDestructor (Private);
+ //
+ // Remove the UGA and GOP protocol interface from the system
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Private->Handle,
+ &gEfiUgaDrawProtocolGuid,
+ &Private->UgaDraw,
+ &gEfiGraphicsOutputProtocolGuid,
+ &Private->GraphicsOutput,
+ NULL
+ );
+ } else {
+ //
+ // Remove the UGA Draw interface from the system
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Private->Handle,
+ &gEfiUgaDrawProtocolGuid,
+ &Private->UgaDraw,
+ NULL
+ );
+ }
+ } else {
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiGraphicsOutputProtocolGuid,
+ (VOID **) &GraphicsOutput,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get our private context information
+ //
+ Private = VBOX_VGA_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput);
+
+ VBoxVgaGraphicsOutputDestructor (Private);
+ //
+ // Remove the GOP protocol interface from the system
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Private->Handle,
+ &gEfiGraphicsOutputProtocolGuid,
+ &Private->GraphicsOutput,
+ NULL
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Private->ModeData) {
+ FreePool(Private->ModeData);
+ Private->ModeData = NULL;
+ }
+
+ //
+ // Restore original PCI attributes
+ //
+ Private->PciIo->Attributes (
+ Private->PciIo,
+ EfiPciIoAttributeOperationSet,
+ Private->OriginalPciAttributes,
+ NULL
+ );
+
+ //
+ // Close the PCI I/O Protocol
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Free our instance data
+ //
+ gBS->FreePool (Private);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ VBoxVgaUgaDrawDestructor
+
+ TODO: Private - add argument and description to function comment
+ TODO: EFI_SUCCESS - add return value to function comment
+**/
+EFI_STATUS
+VBoxVgaUgaDrawDestructor (
+ VBOX_VGA_PRIVATE_DATA *Private
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ TODO: Add function description
+
+ @param Private TODO: add argument description
+ @param Index TODO: add argument description
+ @param Red TODO: add argument description
+ @param Green TODO: add argument description
+ @param Blue TODO: add argument description
+
+ TODO: add return values
+
+**/
+VOID
+SetPaletteColor (
+ VBOX_VGA_PRIVATE_DATA *Private,
+ UINTN Index,
+ UINT8 Red,
+ UINT8 Green,
+ UINT8 Blue
+ )
+{
+ ASMOutU8(PALETTE_INDEX_REGISTER, (UINT8) Index);
+ ASMOutU8(PALETTE_DATA_REGISTER, (UINT8) (Red >> 2));
+ ASMOutU8(PALETTE_DATA_REGISTER, (UINT8) (Green >> 2));
+ ASMOutU8(PALETTE_DATA_REGISTER, (UINT8) (Blue >> 2));
+}
+
+/**
+ TODO: Add function description
+
+ @param Private TODO: add argument description
+
+ TODO: add return values
+
+**/
+VOID
+SetDefaultPalette (
+ VBOX_VGA_PRIVATE_DATA *Private
+ )
+{
+#if 1
+ UINTN Index;
+ UINTN RedIndex;
+ UINTN GreenIndex;
+ UINTN BlueIndex;
+ Index = 0;
+ for (RedIndex = 0; RedIndex < 8; RedIndex++) {
+ for (GreenIndex = 0; GreenIndex < 8; GreenIndex++) {
+ for (BlueIndex = 0; BlueIndex < 4; BlueIndex++) {
+ SetPaletteColor (Private, Index, (UINT8) (RedIndex << 5), (UINT8) (GreenIndex << 5), (UINT8) (BlueIndex << 6));
+ Index++;
+ }
+ }
+ }
+#else
+ {
+ int i;
+ static const UINT8 s_a3bVgaDac[64*3] =
+ {
+ 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x2A,
+ 0x00, 0x2A, 0x00,
+ 0x00, 0x2A, 0x2A,
+ 0x2A, 0x00, 0x00,
+ 0x2A, 0x00, 0x2A,
+ 0x2A, 0x2A, 0x00,
+ 0x2A, 0x2A, 0x2A,
+ 0x00, 0x00, 0x15,
+ 0x00, 0x00, 0x3F,
+ 0x00, 0x2A, 0x15,
+ 0x00, 0x2A, 0x3F,
+ 0x2A, 0x00, 0x15,
+ 0x2A, 0x00, 0x3F,
+ 0x2A, 0x2A, 0x15,
+ 0x2A, 0x2A, 0x3F,
+ 0x00, 0x15, 0x00,
+ 0x00, 0x15, 0x2A,
+ 0x00, 0x3F, 0x00,
+ 0x00, 0x3F, 0x2A,
+ 0x2A, 0x15, 0x00,
+ 0x2A, 0x15, 0x2A,
+ 0x2A, 0x3F, 0x00,
+ 0x2A, 0x3F, 0x2A,
+ 0x00, 0x15, 0x15,
+ 0x00, 0x15, 0x3F,
+ 0x00, 0x3F, 0x15,
+ 0x00, 0x3F, 0x3F,
+ 0x2A, 0x15, 0x15,
+ 0x2A, 0x15, 0x3F,
+ 0x2A, 0x3F, 0x15,
+ 0x2A, 0x3F, 0x3F,
+ 0x15, 0x00, 0x00,
+ 0x15, 0x00, 0x2A,
+ 0x15, 0x2A, 0x00,
+ 0x15, 0x2A, 0x2A,
+ 0x3F, 0x00, 0x00,
+ 0x3F, 0x00, 0x2A,
+ 0x3F, 0x2A, 0x00,
+ 0x3F, 0x2A, 0x2A,
+ 0x15, 0x00, 0x15,
+ 0x15, 0x00, 0x3F,
+ 0x15, 0x2A, 0x15,
+ 0x15, 0x2A, 0x3F,
+ 0x3F, 0x00, 0x15,
+ 0x3F, 0x00, 0x3F,
+ 0x3F, 0x2A, 0x15,
+ 0x3F, 0x2A, 0x3F,
+ 0x15, 0x15, 0x00,
+ 0x15, 0x15, 0x2A,
+ 0x15, 0x3F, 0x00,
+ 0x15, 0x3F, 0x2A,
+ 0x3F, 0x15, 0x00,
+ 0x3F, 0x15, 0x2A,
+ 0x3F, 0x3F, 0x00,
+ 0x3F, 0x3F, 0x2A,
+ 0x15, 0x15, 0x15,
+ 0x15, 0x15, 0x3F,
+ 0x15, 0x3F, 0x15,
+ 0x15, 0x3F, 0x3F,
+ 0x3F, 0x15, 0x15,
+ 0x3F, 0x15, 0x3F,
+ 0x3F, 0x3F, 0x15,
+ 0x3F, 0x3F, 0x3F
+ };
+
+ for (i = 0; i < 64; ++i)
+ {
+ ASMOutU8(PALETTE_INDEX_REGISTER, (UINT8)i);
+ ASMOutU8(PALETTE_DATA_REGISTER, s_a3bVgaDac[i*3 + 0]);
+ ASMOutU8(PALETTE_DATA_REGISTER, s_a3bVgaDac[i*3 + 1]);
+ ASMOutU8(PALETTE_DATA_REGISTER, s_a3bVgaDac[i*3 + 2]);
+ }
+ }
+
+#endif
+}
+
+/**
+ TODO: Add function description
+
+ @param Private TODO: add argument description
+
+ TODO: add return values
+
+**/
+VOID
+ClearScreen (
+ VBOX_VGA_PRIVATE_DATA *Private
+ )
+{
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL blt;
+ blt.Blue = 0;
+ blt.Green = 0;
+ blt.Red = 0;
+ blt.Reserved = 0;
+ Private->PciIo->Mem.Write (
+ Private->PciIo,
+ EfiPciIoWidthFillUint32,
+ Private->BarIndexFB,
+ 0,
+ Private->ModeData[Private->CurrentMode].HorizontalResolution
+ * Private->ModeData[Private->CurrentMode].VerticalResolution,
+ &blt
+ );
+}
+
+/**
+ TODO: Add function description
+
+ @param Private TODO: add argument description
+
+ TODO: add return values
+
+**/
+VOID
+DrawLogo (
+ VBOX_VGA_PRIVATE_DATA *Private,
+ UINTN ScreenWidth,
+ UINTN ScreenHeight
+ )
+{
+ DEBUG((DEBUG_INFO, "UGA is %a GOP is %a\n",
+ FeaturePcdGet(PcdSupportUga) ? "on" : "off",
+ FeaturePcdGet(PcdSupportGop) ? "on" : "off"
+ ));
+}
+
+/**
+ TODO: Add function description
+
+ @param Private TODO: add argument description
+ @param ModeData TODO: add argument description
+
+ TODO: add return values
+
+**/
+VOID
+InitializeGraphicsMode (
+ VBOX_VGA_PRIVATE_DATA *Private,
+ VBOX_VGA_VIDEO_MODES *ModeData
+ )
+{
+ UINT16 DeviceId;
+ EFI_STATUS Status;
+ int i;
+
+ DEBUG((DEBUG_INFO, "%a:%d InitializeGraphicsMode: %dx%d bpp:%d\n", __FILE__, __LINE__, ModeData->Width, ModeData->Height, ModeData->ColorDepth));
+
+ //
+ // Read the PCI ID from the PCI Device (dummy)
+ //
+ Status = Private->PciIo->Pci.Read (
+ Private->PciIo,
+ EfiPciIoWidthUint16,
+ PCI_DEVICE_ID_OFFSET,
+ 1,
+ &DeviceId
+ );
+ ASSERT_EFI_ERROR(Status);
+
+ ASMOutU8(MISC_OUTPUT_REGISTER, 0xc3);
+ ASMOutU16(SEQ_ADDRESS_REGISTER, 0x0204);
+
+ ASMInU8(INPUT_STATUS_1_REGISTER); // reset attribute address/data flip-flop
+ ASMOutU8(ATT_ADDRESS_REGISTER, 0); // blank screen using the attribute address register
+
+ ASMOutU16(CRTC_ADDRESS_REGISTER, 0x0011);
+
+ ASMOutU16(SEQ_ADDRESS_REGISTER, 0x0100);
+ if (ModeData->SeqSettings)
+ BOUTB(ModeData->SeqSettings, 5, SEQ_ADDRESS_REGISTER, SEQ_DATA_REGISTER);
+ else
+ BOUTB(Seq_Default, 5, SEQ_ADDRESS_REGISTER, SEQ_DATA_REGISTER);
+ ASMOutU16(SEQ_ADDRESS_REGISTER, 0x0300);
+
+ BOUTB(GraphicsController, 9, GRAPH_ADDRESS_REGISTER, GRAPH_DATA_REGISTER);
+
+ ASMInU8(INPUT_STATUS_1_REGISTER); // reset attribute address/data flip-flop
+ BOUTB(AttributeController, 21, ATT_ADDRESS_REGISTER, ATT_DATA_REGISTER);
+
+ ASMOutU8(MISC_OUTPUT_REGISTER, ModeData->MiscSetting);
+
+ if (ModeData->ColorDepth <= 8)
+ {
+ ASMOutU8(DAC_PIXEL_MASK_REGISTER, 0xff);
+ SetDefaultPalette(Private);
+ }
+
+ if (!ModeData->CrtcSettings)
+ {
+ // No CRTC settings, use VBE
+ ASMOutU16(VBE_DISPI_IOPORT_INDEX, 0x00); ASMOutU16(VBE_DISPI_IOPORT_DATA, 0xb0c0); // ID
+ ASMOutU16(VBE_DISPI_IOPORT_INDEX, 0x04); ASMOutU16(VBE_DISPI_IOPORT_DATA, 0); // ENABLE
+ ASMOutU16(VBE_DISPI_IOPORT_INDEX, 0x01); ASMOutU16(VBE_DISPI_IOPORT_DATA, (UINT16)ModeData->Width); // XRES
+ ASMOutU16(VBE_DISPI_IOPORT_INDEX, 0x02); ASMOutU16(VBE_DISPI_IOPORT_DATA, (UINT16)ModeData->Height); // YRES
+ ASMOutU16(VBE_DISPI_IOPORT_INDEX, 0x03); ASMOutU16(VBE_DISPI_IOPORT_DATA, (UINT16)ModeData->ColorDepth); // BPP
+ ASMOutU16(VBE_DISPI_IOPORT_INDEX, 0x05); ASMOutU16(VBE_DISPI_IOPORT_DATA, 0); // BANK
+ ASMOutU16(VBE_DISPI_IOPORT_INDEX, 0x06); ASMOutU16(VBE_DISPI_IOPORT_DATA, (UINT16)ModeData->Width); // VIRT_WIDTH
+ ASMOutU16(VBE_DISPI_IOPORT_INDEX, 0x07); ASMOutU16(VBE_DISPI_IOPORT_DATA, (UINT16)ModeData->Height); // VIRT_HEIGHT
+ ASMOutU16(VBE_DISPI_IOPORT_INDEX, 0x08); ASMOutU16(VBE_DISPI_IOPORT_DATA, 0); // X_OFFSET
+ ASMOutU16(VBE_DISPI_IOPORT_INDEX, 0x09); ASMOutU16(VBE_DISPI_IOPORT_DATA, 0); // Y_OFFSET
+ ASMOutU16(VBE_DISPI_IOPORT_INDEX, 0x04); ASMOutU16(VBE_DISPI_IOPORT_DATA, 1); // ENABLE
+ /// @todo enabling VBE is automatically tweaking the CRTC, GC, SC, clears the
+ // screen and at the end unblanks graphics. So make sure that nothing is done
+ // after this which needs blanking. Way too much magic, but that's how it is...
+ }
+ else
+ {
+ BOUTB(ModeData->CrtcSettings, 25, CRTC_ADDRESS_REGISTER, CRTC_DATA_REGISTER);
+ }
+
+ ASMInU8(INPUT_STATUS_1_REGISTER); // reset attribute address/data flip-flop
+ ASMOutU8(ATT_ADDRESS_REGISTER, 0x20); // unblank screen
+
+ ClearScreen(Private);
+}
+
+/** Aka know as AppleGraphInfoProtocolGuid in other sources. */
+#define EFI_UNKNOWN_2_PROTOCOL_GUID \
+ { 0xE316E100, 0x0751, 0x4C49, {0x90, 0x56, 0x48, 0x6C, 0x7E, 0x47, 0x29, 0x03} }
+
+EFI_GUID gEfiAppleFrameBufferInfoGuid = EFI_UNKNOWN_2_PROTOCOL_GUID;
+
+EFI_STATUS EFIAPI
+GetFrameBufferInfo(IN APPLE_FRAMEBUFFERINFO_PROTOCOL *This,
+ OUT UINT32 *BaseAddr,
+ OUT UINT32 *Something,
+ OUT UINT32 *RowBytes,
+ OUT UINT32 *Width,
+ OUT UINT32 *Height,
+ OUT UINT32 *Depth)
+{
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *FrameBufDesc;
+ UINT32 W, H, BPP;
+ VBOX_VGA_PRIVATE_DATA *Private = This->Private;
+ UINTN CurrentModeNumber = Private->CurrentMode;
+ VBOX_VGA_MODE_DATA const *pCurrentMode = &Private->ModeData[CurrentModeNumber];
+
+ W = pCurrentMode->HorizontalResolution;
+ H = pCurrentMode->VerticalResolution;
+ BPP = pCurrentMode->ColorDepth;
+ DEBUG((DEBUG_INFO, "%a:%d GetFrameBufferInfo: %dx%d bpp:%d\n", __FILE__, __LINE__, W, H, BPP));
+
+ Private->PciIo->GetBarAttributes (
+ Private->PciIo,
+ Private->BarIndexFB,
+ NULL,
+ (VOID**) &FrameBufDesc
+ );
+
+
+ /* EFI firmware remaps it here */
+ *BaseAddr = (UINT32)FrameBufDesc->AddrRangeMin;
+ *RowBytes = W * BPP / 8;
+ *Width = W;
+ *Height = H;
+ *Depth = BPP;
+ // what *Something shall be?
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+InitializeVBoxVga (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gVBoxVgaDriverBinding,
+ ImageHandle,
+ &gVBoxVgaComponentName,
+ &gVBoxVgaComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install EFI Driver Supported EFI Version Protocol required for
+ // EFI drivers that are on PCI and other plug in cards.
+ //
+ gVBoxVgaDriverSupportedEfiVersion.FirmwareVersion = PcdGet32 (PcdDriverSupportedEfiVersion);
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiDriverSupportedEfiVersionProtocolGuid,
+ &gVBoxVgaDriverSupportedEfiVersion,
+ &gEfiAppleFrameBufferInfoGuid,
+ &gAppleFrameBufferInfo,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVga.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVga.h
new file mode 100644
index 00000000..b4ec4700
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVga.h
@@ -0,0 +1,473 @@
+/* $Id: VBoxVga.h $ */
+/** @file
+ * VBoxVga.h
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/*
+ This code is based on:
+
+ Cirrus Logic 5430 Controller Driver
+
+ Copyright (c) 2006 - 2007, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+*/
+
+//
+// VirtualBox VGA Controller Driver
+//
+
+#ifndef _VBOX_VGA_H_
+#define _VBOX_VGA_H_
+
+
+#include <Uefi.h>
+#include <Protocol/UgaDraw.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/DriverSupportedEfiVersion.h>
+#include <Protocol/EdidOverride.h>
+#include <Protocol/EdidDiscovered.h>
+#include <Protocol/EdidActive.h>
+#include <Protocol/DevicePath.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <Library/PcdLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/TimerLib.h>
+
+#include <IndustryStandard/Pci.h>
+
+#include "VBoxPkg.h"
+#include "DevEFI.h"
+#include "VBox/Graphics/VBoxVideoVBE.h"
+#include "VBox/Graphics/VBoxVideoVBEPrivate.h"
+
+//
+// VirtualBox VGA PCI Configuration Header values
+//
+#define VBOX_VENDOR_ID 0x80ee
+#define VBOX_VGA_DEVICE_ID 0xbeef
+
+
+//
+// VMSVGA II PCI Configuration Header values
+//
+#define VMSVGA_VENDOR_ID 0x15ad
+#define VMSVGA_II_DEVICE_ID 0x0405
+
+// Port offsets relative to BAR 0
+#define SVGA_INDEX_PORT 0
+#define SVGA_VALUE_PORT 1
+
+// SVGA_REG_ENABLE bits
+#define SVGA_REG_ENABLE_DISABLE 0
+#define SVGA_REG_ENABLE_ENABLE 1
+
+// Registers
+#define SVGA_REG_ENABLE 1
+#define SVGA_REG_WIDTH 2
+#define SVGA_REG_HEIGHT 3
+#define SVGA_REG_MAX_WIDTH 4
+#define SVGA_REG_MAX_HEIGHT 5
+#define SVGA_REG_DEPTH 6
+#define SVGA_REG_BITS_PER_PIXEL 7
+#define SVGA_REG_BYTES_PER_LINE 12
+#define SVGA_REG_FB_START 13
+#define SVGA_REG_FB_OFFSET 14
+#define SVGA_REG_VRAM_SIZE 15
+#define SVGA_REG_CONFIG_DONE 20 ///@todo: Why do we need this?
+
+//
+// VirtualBox VGA Graphical Mode Data
+//
+typedef struct {
+ UINT32 ModeNumber;
+ UINT32 HorizontalResolution;
+ UINT32 VerticalResolution;
+ UINT32 ColorDepth;
+ UINT32 RefreshRate;
+} VBOX_VGA_MODE_DATA;
+
+#define GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER 0xffff
+
+//
+// VirtualBox VGA Private Data Structure
+//
+#define VBOX_VGA_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('V', 'B', 'V', 'D')
+
+typedef struct {
+ UINT64 Signature;
+ EFI_HANDLE Handle;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT64 OriginalPciAttributes;
+ EFI_UGA_DRAW_PROTOCOL UgaDraw;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL GraphicsOutput;
+ EFI_EDID_DISCOVERED_PROTOCOL EdidDiscovered;
+ EFI_EDID_ACTIVE_PROTOCOL EdidActive;
+ EFI_DEVICE_PATH_PROTOCOL *GopDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *UgaDevicePath;
+ UINTN CurrentMode;
+ UINTN MaxMode;
+ VBOX_VGA_MODE_DATA *ModeData;
+ BOOLEAN HardwareNeedsStarting;
+ UINT8 BarIndexFB;
+ UINT16 DeviceType;
+ UINT16 IOBase;
+ UINT32 VRAMSize;
+} VBOX_VGA_PRIVATE_DATA;
+
+///
+/// Video Mode structure
+///
+typedef struct {
+ UINT32 Width;
+ UINT32 Height;
+ UINT32 ColorDepth;
+ UINT32 RefreshRate;
+ /// CRTC settings are optional. If NULL then VBE is used
+ UINT8 *CrtcSettings;
+ /// Sequencer settings are optional. If NULL then defaults are used
+ UINT8 *SeqSettings;
+ UINT8 MiscSetting;
+} VBOX_VGA_VIDEO_MODES;
+
+#define VBOX_VGA_PRIVATE_DATA_FROM_UGA_DRAW_THIS(a) \
+ CR(a, VBOX_VGA_PRIVATE_DATA, UgaDraw, VBOX_VGA_PRIVATE_DATA_SIGNATURE)
+
+#define VBOX_VGA_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS(a) \
+ CR(a, VBOX_VGA_PRIVATE_DATA, GraphicsOutput, VBOX_VGA_PRIVATE_DATA_SIGNATURE)
+
+
+//
+// Global Variables
+//
+extern UINT8 AttributeController[];
+extern UINT8 GraphicsController[];
+extern UINT8 Crtc_640_480_256_60[];
+extern UINT8 Seq_640_480_256_60[];
+extern UINT8 Crtc_800_600_256_60[];
+extern UINT8 Seq_800_600_256_60[];
+extern UINT8 Crtc_1024_768_256_60[];
+extern UINT8 Seq_1024_768_256_60[];
+extern VBOX_VGA_VIDEO_MODES VBoxVgaVideoModes[];
+extern const UINT32 VBoxVgaVideoModeCount;
+extern EFI_DRIVER_BINDING_PROTOCOL gVBoxVgaDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gVBoxVgaComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gVBoxVgaComponentName2;
+extern EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL gVBoxVgaDriverSupportedEfiVersion;
+
+//
+// Io Registers defined by VGA
+//
+#define CRTC_ADDRESS_REGISTER 0x3d4
+#define CRTC_DATA_REGISTER 0x3d5
+#define SEQ_ADDRESS_REGISTER 0x3c4
+#define SEQ_DATA_REGISTER 0x3c5
+#define GRAPH_ADDRESS_REGISTER 0x3ce
+#define GRAPH_DATA_REGISTER 0x3cf
+#define ATT_ADDRESS_REGISTER 0x3c0
+#define ATT_DATA_REGISTER 0x3c1
+#define MISC_OUTPUT_REGISTER 0x3c2
+#define INPUT_STATUS_1_REGISTER 0x3da
+#define DAC_PIXEL_MASK_REGISTER 0x3c6
+#define PALETTE_INDEX_REGISTER 0x3c8
+#define PALETTE_DATA_REGISTER 0x3c9
+
+
+//
+// UGA Draw Hardware abstraction internal worker functions
+//
+EFI_STATUS
+VBoxVgaUgaDrawConstructor (
+ VBOX_VGA_PRIVATE_DATA *Private
+ );
+
+EFI_STATUS
+VBoxVgaUgaDrawDestructor (
+ VBOX_VGA_PRIVATE_DATA *Private
+ );
+
+//
+// Graphics Output Hardware abstraction internal worker functions
+//
+EFI_STATUS
+VBoxVgaGraphicsOutputConstructor (
+ VBOX_VGA_PRIVATE_DATA *Private
+ );
+
+EFI_STATUS
+VBoxVgaGraphicsOutputDestructor (
+ VBOX_VGA_PRIVATE_DATA *Private
+ );
+
+
+//
+// EFI_DRIVER_BINDING_PROTOCOL Protocol Interface
+//
+/**
+ TODO: Add function description
+
+ @param This TODO: add argument description
+ @param Controller TODO: add argument description
+ @param RemainingDevicePath TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+EFIAPI
+VBoxVgaControllerDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ TODO: Add function description
+
+ @param This TODO: add argument description
+ @param Controller TODO: add argument description
+ @param RemainingDevicePath TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+EFIAPI
+VBoxVgaControllerDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ TODO: Add function description
+
+ @param This TODO: add argument description
+ @param Controller TODO: add argument description
+ @param NumberOfChildren TODO: add argument description
+ @param ChildHandleBuffer TODO: add argument description
+
+ TODO: add return values
+
+**/
+EFI_STATUS
+EFIAPI
+VBoxVgaControllerDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+//
+// EFI Component Name Functions
+//
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+VBoxVgaComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+VBoxVgaComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+//
+// Local Function Prototypes
+//
+VOID
+InitializeGraphicsMode (
+ VBOX_VGA_PRIVATE_DATA *Private,
+ VBOX_VGA_VIDEO_MODES *ModeData
+ );
+
+VOID
+SetPaletteColor (
+ VBOX_VGA_PRIVATE_DATA *Private,
+ UINTN Index,
+ UINT8 Red,
+ UINT8 Green,
+ UINT8 Blue
+ );
+
+VOID
+SetDefaultPalette (
+ VBOX_VGA_PRIVATE_DATA *Private
+ );
+
+VOID
+DrawLogo (
+ VBOX_VGA_PRIVATE_DATA *Private,
+ UINTN ScreenWidth,
+ UINTN ScreenHeight
+ );
+
+EFI_STATUS
+VBoxVgaVideoModeSetup (
+ VBOX_VGA_PRIVATE_DATA *Private
+ );
+
+UINT32 VBoxVgaGetVmVariable(UINT32 Variable, CHAR8* Buffer, UINT32 Size);
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaDxe.inf b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaDxe.inf
new file mode 100644
index 00000000..b1f0123d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaDxe.inf
@@ -0,0 +1,133 @@
+# $Id: VBoxVgaDxe.inf $
+## @file
+# VBoxVgaDxe.inf
+#
+
+#
+# Copyright (C) 2010-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>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+#
+# This code is based on:
+#
+#/** @file
+# Component description file for CirrusLogic5430 module
+#
+# Cirrus Logic 5430 Controller Driver.This driver is a sample implementation
+# of the UGA Draw Protocol for the Cirrus Logic 5430 family of PCI video controllers.
+# This driver is only usable in the EFI pre-boot environment. This sample is
+# intended to show how the UGA Draw Protocol is able to function. The UGA I/O
+# Protocol is not implemented in this sample. A fully compliant EFI UGA driver
+# requires both the UGA Draw and the UGA I/O Protocol. Please refer to Microsoft's
+# documentation on UGA for details on how to write a UGA driver that is able
+# to function both in the EFI pre-boot environment and from the OS runtime.
+# Copyright (c) 2006 - 2009, Intel Corporation
+#
+# All rights reserved. This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VBoxVgaDxe
+ FILE_GUID = b8a784bc-af4d-4d95-bdb1-ba28236a54f4
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ EDK_RELEASE_VERSION = 0x00020000
+ EFI_SPECIFICATION_VERSION = 0x00020000
+
+ ENTRY_POINT = InitializeVBoxVga
+
+ PCI_VENDOR_ID = 0x80EE
+ PCI_DEVICE_ID = 0xBEEF
+ PCI_CLASS_CODE = 0x030000
+ PCI_REVISION = 0x00
+ COMPRESS = TRUE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+# DRIVER_BINDING = VBoxVgaDriverBinding
+# COMPONENT_NAME = VBoxVgaComponentName
+#
+
+[Sources.common]
+ ComponentName.c
+ DriverSupportedEfiVersion.c
+ VBoxVgaUgaDraw.c
+ VBoxVgaGraphicsOutput.c
+ VBoxVga.c
+ VBoxVga.h
+ Edid.c
+ VBoxVgaI2c.h
+ VBoxVgaI2c.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ VBoxPkg/VBoxPkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+ BaseMemoryLib
+ DevicePathLib
+ TimerLib
+
+[Protocols]
+ gEfiDriverSupportedEfiVersionProtocolGuid # PROTOCOL ALWAYS_PRODUCED
+ gEfiUgaDrawProtocolGuid # PROTOCOL BY_START
+ gEfiGraphicsOutputProtocolGuid # PROTOCOL BY_START
+ gEfiEdidDiscoveredProtocolGuid # PROTOCOL BY_START
+ gEfiEdidActiveProtocolGuid # PROTOCOL BY_START
+ gEfiDevicePathProtocolGuid # PROTOCOL BY_START
+ gEfiPciIoProtocolGuid # PROTOCOL TO_START
+ gEfiEdidOverrideProtocolGuid # PROTOCOL TO_START
+
+
+[FeaturePcd.common]
+ gVBoxVgaPkgTokenSpaceGuid.PcdSupportGop
+ gVBoxVgaPkgTokenSpaceGuid.PcdSupportUga
+
+[Pcd]
+ gVBoxVgaPkgTokenSpaceGuid.PcdDriverSupportedEfiVersion
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution ## PRODUCES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution ## PRODUCES
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaGraphicsOutput.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaGraphicsOutput.c
new file mode 100644
index 00000000..05bfbe06
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaGraphicsOutput.c
@@ -0,0 +1,544 @@
+/* $Id: VBoxVgaGraphicsOutput.c $ */
+/** @file
+ * VBoxVgaGraphicsOutput.c
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/*
+ This code is based on:
+
+Copyright (c) 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ UefiVBoxVgaGraphicsOutput.c
+
+Abstract:
+
+ This file produces the graphics abstraction of Graphics Output Protocol. It is called by
+ VBoxVga.c file which deals with the EFI 1.1 driver model.
+ This file just does graphics.
+
+*/
+#include "VBoxVga.h"
+#include <IndustryStandard/Acpi.h>
+
+
+STATIC
+VOID
+VBoxVgaCompleteModeInfo (
+ OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info
+ )
+{
+ Info->Version = 0;
+ Info->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
+ Info->PixelsPerScanLine = Info->HorizontalResolution;
+}
+
+
+STATIC
+EFI_STATUS
+VBoxVgaCompleteModeData (
+ IN VBOX_VGA_PRIVATE_DATA *Private,
+ OUT EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode
+ )
+{
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *FrameBufDesc;
+
+ Info = Mode->Info;
+ VBoxVgaCompleteModeInfo (Info);
+
+ Private->PciIo->GetBarAttributes (
+ Private->PciIo,
+ Private->BarIndexFB,
+ NULL,
+ (VOID**) &FrameBufDesc
+ );
+
+ DEBUG((DEBUG_INFO, "%a:%d FrameBufferBase:%x\n", __FILE__, __LINE__, FrameBufDesc->AddrRangeMin));
+ Mode->FrameBufferBase = FrameBufDesc->AddrRangeMin;
+ Mode->FrameBufferSize = Info->PixelsPerScanLine * Info->VerticalResolution
+ * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL); /* 32bpp only! */
+
+ return EFI_SUCCESS;
+}
+
+
+//
+// Graphics Output Protocol Member Functions
+//
+EFI_STATUS
+EFIAPI
+VBoxVgaGraphicsOutputQueryMode (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+ IN UINT32 ModeNumber,
+ OUT UINTN *SizeOfInfo,
+ OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
+ )
+/*++
+
+Routine Description:
+
+ Graphics Output protocol interface to query video mode
+
+ Arguments:
+ This - Protocol instance pointer.
+ ModeNumber - The mode number to return information on.
+ Info - Caller allocated buffer that returns information about ModeNumber.
+ SizeOfInfo - A pointer to the size, in bytes, of the Info buffer.
+
+ Returns:
+ EFI_SUCCESS - Mode information returned.
+ EFI_BUFFER_TOO_SMALL - The Info buffer was too small.
+ EFI_DEVICE_ERROR - A hardware error occurred trying to retrieve the video mode.
+ EFI_NOT_STARTED - Video display is not initialized. Call SetMode ()
+ EFI_INVALID_PARAMETER - One of the input args was NULL.
+
+--*/
+{
+ VBOX_VGA_PRIVATE_DATA *Private;
+
+ Private = VBOX_VGA_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This);
+
+ if (Private->HardwareNeedsStarting) {
+ return EFI_NOT_STARTED;
+ }
+
+ if (Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Info = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION));
+ if (*Info == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
+
+ (*Info)->HorizontalResolution = Private->ModeData[ModeNumber].HorizontalResolution;
+ (*Info)->VerticalResolution = Private->ModeData[ModeNumber].VerticalResolution;
+ VBoxVgaCompleteModeInfo (*Info);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+VBoxVgaGraphicsOutputSetMode (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+ IN UINT32 ModeNumber
+ )
+/*++
+
+Routine Description:
+
+ Graphics Output protocol interface to set video mode
+
+ Arguments:
+ This - Protocol instance pointer.
+ ModeNumber - The mode number to be set.
+
+ Returns:
+ EFI_SUCCESS - Graphics mode was changed.
+ EFI_DEVICE_ERROR - The device had an error and could not complete the request.
+ EFI_UNSUPPORTED - ModeNumber is not supported by this device.
+
+--*/
+{
+ VBOX_VGA_PRIVATE_DATA *Private;
+ VBOX_VGA_MODE_DATA *ModeData;
+
+ Private = VBOX_VGA_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This);
+
+ DEBUG((DEBUG_INFO, "%a:%d mode:%d\n", __FILE__, __LINE__, ModeNumber));
+ if (ModeNumber >= This->Mode->MaxMode) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ModeData = &Private->ModeData[ModeNumber];
+
+ InitializeGraphicsMode (Private, &VBoxVgaVideoModes[ModeData->ModeNumber]);
+
+ This->Mode->Mode = ModeNumber;
+ This->Mode->Info->HorizontalResolution = ModeData->HorizontalResolution;
+ This->Mode->Info->VerticalResolution = ModeData->VerticalResolution;
+ This->Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
+
+ VBoxVgaCompleteModeData (Private, This->Mode);
+
+ Private->HardwareNeedsStarting = FALSE;
+ /* update current mode */
+ Private->CurrentMode = ModeNumber;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+VBoxVgaGraphicsOutputBlt (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
+ IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
+ IN UINTN SourceX,
+ IN UINTN SourceY,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height,
+ IN UINTN Delta
+ )
+/*++
+
+Routine Description:
+
+ Graphics Output protocol instance to block transfer for CirrusLogic device
+
+Arguments:
+
+ This - Pointer to Graphics Output protocol instance
+ BltBuffer - The data to transfer to screen
+ BltOperation - The operation to perform
+ SourceX - The X coordinate of the source for BltOperation
+ SourceY - The Y coordinate of the source for BltOperation
+ DestinationX - The X coordinate of the destination for BltOperation
+ DestinationY - The Y coordinate of the destination for BltOperation
+ Width - The width of a rectangle in the blt rectangle in pixels
+ Height - The height of a rectangle in the blt rectangle in pixels
+ Delta - Not used for EfiBltVideoFill and EfiBltVideoToVideo operation.
+ If a Delta of 0 is used, the entire BltBuffer will be operated on.
+ If a subrectangle of the BltBuffer is used, then Delta represents
+ the number of bytes in a row of the BltBuffer.
+
+Returns:
+
+ EFI_INVALID_PARAMETER - Invalid parameter passed in
+ EFI_SUCCESS - Blt operation success
+
+--*/
+{
+ VBOX_VGA_PRIVATE_DATA *Private;
+ EFI_TPL OriginalTPL;
+ UINTN DstY;
+ UINTN SrcY;
+ UINT32 CurrentMode;
+ UINTN ScreenWidth;
+ UINTN ScreenHeight;
+ EFI_STATUS Status;
+
+ Private = VBOX_VGA_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This);
+ CurrentMode = This->Mode->Mode;
+ ScreenWidth = Private->ModeData[CurrentMode].HorizontalResolution;
+ ScreenHeight = Private->ModeData[CurrentMode].VerticalResolution;
+
+ if ((BltOperation < 0) || (BltOperation >= EfiGraphicsOutputBltOperationMax)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Width == 0 || Height == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If Delta is zero, then the entire BltBuffer is being used, so Delta
+ // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
+ // the number of bytes in each row can be computed.
+ //
+ if (Delta == 0) {
+ Delta = Width * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
+ }
+ // code below assumes a Delta value in pixels, not bytes
+ Delta /= sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
+
+ //
+ // Make sure the SourceX, SourceY, DestinationX, DestinationY, Width, and Height parameters
+ // are valid for the operation and the current screen geometry.
+ //
+ if (BltOperation == EfiBltVideoToBltBuffer || BltOperation == EfiBltVideoToVideo) {
+ if (SourceY + Height > ScreenHeight) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (SourceX + Width > ScreenWidth) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ if (BltOperation == EfiBltBufferToVideo || BltOperation == EfiBltVideoToVideo || BltOperation == EfiBltVideoFill) {
+ if (DestinationY + Height > ScreenHeight) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DestinationX + Width > ScreenWidth) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
+ // We would not want a timer based event (Cursor, ...) to come in while we are
+ // doing this operation.
+ //
+ OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
+
+ switch (BltOperation) {
+ case EfiBltVideoToBltBuffer:
+ //
+ // Video to BltBuffer: Source is Video, destination is BltBuffer
+ //
+ for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY) && BltBuffer; SrcY++, DstY++) {
+ /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthUint32) and format matches EFI_GRAPHICS_OUTPUT_BLT_PIXEL
+ Status = Private->PciIo->Mem.Read (
+ Private->PciIo,
+ EfiPciIoWidthUint32,
+ Private->BarIndexFB,
+ ((SrcY * ScreenWidth) + SourceX) * 4,
+ Width,
+ BltBuffer + (DstY * Delta) + DestinationX
+ );
+ ASSERT_EFI_ERROR((Status));
+ }
+ break;
+
+ case EfiBltBufferToVideo:
+ //
+ // BltBuffer to Video: Source is BltBuffer, destination is Video
+ //
+ for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
+ /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthUint32) and format matches EFI_GRAPHICS_OUTPUT_BLT_PIXEL
+ Status = Private->PciIo->Mem.Write (
+ Private->PciIo,
+ EfiPciIoWidthUint32,
+ Private->BarIndexFB,
+ ((DstY * ScreenWidth) + DestinationX) * 4,
+ Width,
+ BltBuffer + (SrcY * Delta) + SourceX
+ );
+ ASSERT_EFI_ERROR((Status));
+ }
+ break;
+
+ case EfiBltVideoToVideo:
+ //
+ // Video to Video: Source is Video, destination is Video
+ //
+ if (DestinationY <= SourceY) {
+ // forward copy
+ for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
+ /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthUint32) and format matches EFI_GRAPHICS_OUTPUT_BLT_PIXEL
+ Status = Private->PciIo->CopyMem (
+ Private->PciIo,
+ EfiPciIoWidthUint32,
+ Private->BarIndexFB,
+ ((DstY * ScreenWidth) + DestinationX) * 4,
+ Private->BarIndexFB,
+ ((SrcY * ScreenWidth) + SourceX) * 4,
+ Width
+ );
+ ASSERT_EFI_ERROR((Status));
+ }
+ } else {
+ // reverse copy
+ for (SrcY = SourceY + Height - 1, DstY = DestinationY + Height - 1; SrcY >= SourceY && SrcY <= SourceY + Height - 1; SrcY--, DstY--) {
+ /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthUint32) and format matches EFI_GRAPHICS_OUTPUT_BLT_PIXEL
+ Status = Private->PciIo->CopyMem (
+ Private->PciIo,
+ EfiPciIoWidthUint32,
+ Private->BarIndexFB,
+ ((DstY * ScreenWidth) + DestinationX) * 4,
+ Private->BarIndexFB,
+ ((SrcY * ScreenWidth) + SourceX) * 4,
+ Width
+ );
+ ASSERT_EFI_ERROR((Status));
+ }
+ }
+ break;
+
+ case EfiBltVideoFill:
+ //
+ // Video Fill: Source is BltBuffer, destination is Video
+ //
+ if (DestinationX == 0 && Width == ScreenWidth) {
+ /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthFillUint32) and format matches EFI_GRAPHICS_OUTPUT_BLT_PIXEL
+ Status = Private->PciIo->Mem.Write (
+ Private->PciIo,
+ EfiPciIoWidthFillUint32,
+ Private->BarIndexFB,
+ DestinationY * ScreenWidth * 4,
+ (Width * Height),
+ BltBuffer
+ );
+ ASSERT_EFI_ERROR((Status));
+ } else {
+ for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
+ /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthFillUint32) and format matches EFI_GRAPHICS_OUTPUT_BLT_PIXEL
+ Status = Private->PciIo->Mem.Write (
+ Private->PciIo,
+ EfiPciIoWidthFillUint32,
+ Private->BarIndexFB,
+ ((DstY * ScreenWidth) + DestinationX) * 4,
+ Width,
+ BltBuffer
+ );
+ ASSERT_EFI_ERROR((Status));
+ }
+ }
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+
+ gBS->RestoreTPL (OriginalTPL);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+VBoxVgaGraphicsOutputConstructor (
+ VBOX_VGA_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ UINT32 Index;
+ UINT32 HorizontalResolution = 1024;
+ UINT32 VerticalResolution = 768;
+ UINT32 ColorDepth = 32;
+
+ DEBUG((DEBUG_INFO, "%a:%d construct\n", __FILE__, __LINE__));
+
+ GraphicsOutput = &Private->GraphicsOutput;
+ GraphicsOutput->QueryMode = VBoxVgaGraphicsOutputQueryMode;
+ GraphicsOutput->SetMode = VBoxVgaGraphicsOutputSetMode;
+ GraphicsOutput->Blt = VBoxVgaGraphicsOutputBlt;
+
+ //
+ // Initialize the private data
+ //
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE),
+ (VOID **) &Private->GraphicsOutput.Mode
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION),
+ (VOID **) &Private->GraphicsOutput.Mode->Info
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Private->GraphicsOutput.Mode->MaxMode = (UINT32) Private->MaxMode;
+ Private->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;
+ Private->HardwareNeedsStarting = TRUE;
+
+ //
+ // Initialize the hardware
+ //
+ VBoxVgaGetVmVariable(EFI_INFO_INDEX_HORIZONTAL_RESOLUTION, (CHAR8 *)&HorizontalResolution,
+ sizeof(HorizontalResolution));
+ VBoxVgaGetVmVariable(EFI_INFO_INDEX_VERTICAL_RESOLUTION, (CHAR8 *)&VerticalResolution,
+ sizeof(VerticalResolution));
+ for (Index = 0; Index < Private->MaxMode; Index++)
+ {
+ if ( HorizontalResolution == Private->ModeData[Index].HorizontalResolution
+ && VerticalResolution == Private->ModeData[Index].VerticalResolution
+ && ColorDepth == Private->ModeData[Index].ColorDepth)
+ break;
+ }
+ // not found? try mode number
+ if (Index >= Private->MaxMode)
+ {
+ VBoxVgaGetVmVariable(EFI_INFO_INDEX_GRAPHICS_MODE, (CHAR8 *)&Index, sizeof(Index));
+ // try with mode 2 (usually 1024x768) as a fallback
+ if (Index >= Private->MaxMode)
+ Index = 2;
+ // try with mode 0 (usually 640x480) as a fallback
+ if (Index >= Private->MaxMode)
+ Index = 0;
+ }
+
+ // skip mode setting completely if there is no valid mode
+ if (Index >= Private->MaxMode)
+ return EFI_UNSUPPORTED;
+
+ GraphicsOutput->SetMode (GraphicsOutput, Index);
+
+ DrawLogo (
+ Private,
+ Private->ModeData[Private->GraphicsOutput.Mode->Mode].HorizontalResolution,
+ Private->ModeData[Private->GraphicsOutput.Mode->Mode].VerticalResolution
+ );
+
+ PcdSet32S(PcdVideoHorizontalResolution, Private->ModeData[Private->GraphicsOutput.Mode->Mode].HorizontalResolution);
+ PcdSet32S(PcdVideoVerticalResolution, Private->ModeData[Private->GraphicsOutput.Mode->Mode].VerticalResolution);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+VBoxVgaGraphicsOutputDestructor (
+ VBOX_VGA_PRIVATE_DATA *Private
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Returns:
+
+ None
+
+--*/
+{
+ if (Private->GraphicsOutput.Mode != NULL) {
+ if (Private->GraphicsOutput.Mode->Info != NULL) {
+ gBS->FreePool (Private->GraphicsOutput.Mode->Info);
+ }
+ gBS->FreePool (Private->GraphicsOutput.Mode);
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaI2c.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaI2c.c
new file mode 100644
index 00000000..b540f6d8
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaI2c.c
@@ -0,0 +1,469 @@
+/* $Id: VBoxVgaI2c.c $ */
+/** @file
+ * VBoxVgaI2c.c
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/*
+ This code is based on:
+
+ I2C Bus implementation upon CirrusLogic.
+
+ Copyright (c) 2008 - 2009, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+*/
+
+#include "VBoxVga.h"
+#include "VBoxVgaI2c.h"
+
+#define SEQ_ADDRESS_REGISTER 0x3c4
+#define SEQ_DATA_REGISTER 0x3c5
+
+#define I2C_CONTROL 0x08
+#define I2CDAT_IN 7
+#define I2CCLK_IN 2
+#define I2CDAT_OUT 1
+#define I2CCLK_OUT 0
+
+#define I2C_BUS_SPEED 100 //100kbps
+
+/**
+ PCI I/O byte write function.
+
+ @param PciIo The pointer to PCI_IO_PROTOCOL.
+ @param Address The bit map of I2C Data or I2C Clock pins.
+ @param Data The date to write.
+
+**/
+VOID
+I2cOutb (
+ EFI_PCI_IO_PROTOCOL *PciIo,
+ UINTN Address,
+ UINT8 Data
+ )
+{
+ PciIo->Io.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ Address,
+ 1,
+ &Data
+ );
+}
+/**
+ PCI I/O byte read function.
+
+ @param PciIo The pointer to PCI_IO_PROTOCOL.
+ @param Address The bit map of I2C Data or I2C Clock pins.
+
+ return byte value read from PCI I/O space.
+
+**/
+UINT8
+I2cInb (
+ EFI_PCI_IO_PROTOCOL *PciIo,
+ UINTN Address
+ )
+{
+ UINT8 Data;
+
+ PciIo->Io.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ Address,
+ 1,
+ &Data
+ );
+ return Data;
+}
+
+/**
+ Read status of I2C Data and I2C Clock Pins.
+
+ @param PciIo The pointer to PCI_IO_PROTOCOL.
+ @param Blt The bit map of I2C Data or I2C Clock pins.
+
+ @retval 0 Low on I2C Data or I2C Clock Pin.
+ @retval 1 High on I2C Data or I2C Clock Pin.
+
+**/
+UINT8
+I2cPinRead (
+ EFI_PCI_IO_PROTOCOL *PciIo,
+ UINT8 Bit
+ )
+{
+ I2cOutb (PciIo, SEQ_ADDRESS_REGISTER, I2C_CONTROL);
+ return (UINT8) ((I2cInb (PciIo, SEQ_DATA_REGISTER) >> Bit ) & 0xfe);
+}
+
+
+/**
+ Set/Clear I2C Data and I2C Clock Pins.
+
+ @param PciIo The pointer to PCI_IO_PROTOCOL.
+ @param Blt The bit map to controller I2C Data or I2C Clock pins.
+ @param Value 1 or 0 stands for Set or Clear I2C Data and I2C Clock Pins.
+
+**/
+VOID
+I2cPinWrite (
+ EFI_PCI_IO_PROTOCOL *PciIo,
+ UINT8 Bit,
+ UINT8 Value
+ )
+{
+ UINT8 Byte;
+ I2cOutb (PciIo, SEQ_ADDRESS_REGISTER, I2C_CONTROL);
+ Byte = (UINT8) (I2cInb (PciIo, SEQ_DATA_REGISTER) & (UINT8) ~(1 << Bit)) ;
+ Byte = (UINT8) (Byte | ((Value & 0x01) << Bit));
+ I2cOutb (PciIo, SEQ_DATA_REGISTER, (UINT8) (Byte | 0x40));
+ return;
+}
+
+/**
+ Read/write delay according to I2C Bus Speed.
+
+**/
+VOID
+I2cDelay (
+ VOID
+ )
+{
+ MicroSecondDelay (1000 / I2C_BUS_SPEED);
+}
+
+/**
+ Write a 8-bit data onto I2C Data Pin.
+
+ @param PciIo The pointer to PCI_IO_PROTOCOL.
+ @param Data The byte data to write.
+
+**/
+VOID
+I2cSendByte (
+ EFI_PCI_IO_PROTOCOL *PciIo,
+ UINT8 Data
+ )
+{
+ UINTN Index;
+ //
+ // Send byte data onto I2C Bus
+ //
+ for (Index = 0; Index < 8; Index --) {
+ I2cPinWrite (PciIo, I2CDAT_OUT, (UINT8) (Data >> (7 - Index)));
+ I2cPinWrite (PciIo, I2CCLK_OUT, 1);
+ I2cDelay ();
+ I2cPinWrite (PciIo, I2CCLK_OUT, 0);
+ }
+}
+
+/**
+ Read a 8-bit data from I2C Data Pin.
+
+ @param PciIo The pointer to PCI_IO_PROTOCOL.
+
+ Return the byte data read from I2C Data Pin.
+**/
+UINT8
+I2cReceiveByte (
+ EFI_PCI_IO_PROTOCOL *PciIo
+ )
+{
+ UINT8 Data;
+ UINTN Index;
+
+ Data = 0;
+ //
+ // Read byte data from I2C Bus
+ //
+ for (Index = 0; Index < 8; Index --) {
+ I2cPinWrite (PciIo, I2CCLK_OUT, 1);
+ I2cDelay ();
+ Data = (UINT8) (Data << 1);
+ Data = (UINT8) (Data | I2cPinRead (PciIo, I2CDAT_IN));
+ I2cPinWrite (PciIo, I2CCLK_OUT, 0);
+ }
+
+ return Data;
+}
+
+/**
+ Receive an ACK signal from I2C Bus.
+
+ @param PciIo The pointer to PCI_IO_PROTOCOL.
+
+**/
+BOOLEAN
+I2cWaitAck (
+ EFI_PCI_IO_PROTOCOL *PciIo
+ )
+{
+ //
+ // Wait for ACK signal
+ //
+ I2cPinWrite (PciIo, I2CDAT_OUT, 1);
+ I2cPinWrite (PciIo, I2CCLK_OUT, 1);
+ I2cDelay ();
+ if (I2cPinRead (PciIo, I2CDAT_IN) == 0) {
+ I2cPinWrite (PciIo, I2CDAT_OUT, 1);
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Send an ACK signal onto I2C Bus.
+
+ @param PciIo The pointer to PCI_IO_PROTOCOL.
+
+**/
+VOID
+I2cSendAck (
+ EFI_PCI_IO_PROTOCOL *PciIo
+ )
+{
+ I2cPinWrite (PciIo, I2CCLK_OUT, 1);
+ I2cPinWrite (PciIo, I2CDAT_OUT, 1);
+ I2cPinWrite (PciIo, I2CDAT_OUT, 0);
+ I2cPinWrite (PciIo, I2CCLK_OUT, 0);
+}
+
+/**
+ Start a I2C transfer on I2C Bus.
+
+ @param PciIo The pointer to PCI_IO_PROTOCOL.
+
+**/
+VOID
+I2cStart (
+ EFI_PCI_IO_PROTOCOL *PciIo
+ )
+{
+ //
+ // Init CLK and DAT pins
+ //
+ I2cPinWrite (PciIo, I2CCLK_OUT, 1);
+ I2cPinWrite (PciIo, I2CDAT_OUT, 1);
+ //
+ // Start a I2C transfer, set SDA low from high, when SCL is high
+ //
+ I2cPinWrite (PciIo, I2CDAT_OUT, 0);
+ I2cPinWrite (PciIo, I2CCLK_OUT, 0);
+}
+
+/**
+ Stop a I2C transfer on I2C Bus.
+
+ @param PciIo The pointer to PCI_IO_PROTOCOL.
+
+**/
+VOID
+I2cStop (
+ EFI_PCI_IO_PROTOCOL *PciIo
+ )
+{
+ //
+ // Stop a I2C transfer, set SDA high from low, when SCL is high
+ //
+ I2cPinWrite (PciIo, I2CDAT_OUT, 0);
+ I2cPinWrite (PciIo, I2CCLK_OUT, 1);
+ I2cPinWrite (PciIo, I2CDAT_OUT, 1);
+}
+
+/**
+ Read one byte data on I2C Bus.
+
+ Read one byte data from the slave device connected to I2C Bus.
+ If Data is NULL, then ASSERT().
+
+ @param PciIo The pointer to PCI_IO_PROTOCOL.
+ @param DeviceAddress Slave device's address.
+ @param RegisterAddress The register address on slave device.
+ @param Data The pointer to returned data if EFI_SUCCESS returned.
+
+ @retval EFI_DEVICE_ERROR
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+I2cReadByte (
+ EFI_PCI_IO_PROTOCOL *PciIo,
+ UINT8 DeviceAddress,
+ UINT8 RegisterAddress,
+ UINT8 *Data
+ )
+{
+ ASSERT (Data != NULL);
+
+ //
+ // Start I2C transfer
+ //
+ I2cStart (PciIo);
+
+ //
+ // Send slave address with enabling write flag
+ //
+ I2cSendByte (PciIo, (UINT8) (DeviceAddress & 0xfe));
+
+ //
+ // Wait for ACK signal
+ //
+ if (I2cWaitAck (PciIo) == FALSE) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Send register address
+ //
+ I2cSendByte (PciIo, RegisterAddress);
+
+ //
+ // Wait for ACK signal
+ //
+ if (I2cWaitAck (PciIo) == FALSE) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Send slave address with enabling read flag
+ //
+ I2cSendByte (PciIo, (UINT8) (DeviceAddress | 0x01));
+
+ //
+ // Wait for ACK signal
+ //
+ if (I2cWaitAck (PciIo) == FALSE) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Read byte data from I2C Bus
+ //
+ *Data = I2cReceiveByte (PciIo);
+
+ //
+ // Send ACK signal onto I2C Bus
+ //
+ I2cSendAck (PciIo);
+
+ //
+ // Stop a I2C transfer
+ //
+ I2cStop (PciIo);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Write one byte data onto I2C Bus.
+
+ Write one byte data to the slave device connected to I2C Bus.
+ If Data is NULL, then ASSERT().
+
+ @param PciIo The pointer to PCI_IO_PROTOCOL.
+ @param DeviceAddress Slave device's address.
+ @param RegisterAddress The register address on slave device.
+ @param Data The pointer to write data.
+
+ @retval EFI_DEVICE_ERROR
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+I2cWriteByte (
+ EFI_PCI_IO_PROTOCOL *PciIo,
+ UINT8 DeviceAddress,
+ UINT8 RegisterAddress,
+ UINT8 *Data
+ )
+{
+ ASSERT (Data != NULL);
+
+ I2cStart (PciIo);
+ //
+ // Send slave address with enabling write flag
+ //
+ I2cSendByte (PciIo, (UINT8) (DeviceAddress & 0xfe));
+
+ //
+ // Wait for ACK signal
+ //
+ if (I2cWaitAck (PciIo) == FALSE) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Send register address
+ //
+ I2cSendByte (PciIo, RegisterAddress);
+
+ //
+ // Wait for ACK signal
+ //
+ if (I2cWaitAck (PciIo) == FALSE) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Send byte data onto I2C Bus
+ //
+ I2cSendByte (PciIo, *Data);
+
+ //
+ // Wait for ACK signal
+ //
+ if (I2cWaitAck (PciIo) == FALSE) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Stop a I2C transfer
+ //
+ I2cStop (PciIo);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaI2c.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaI2c.h
new file mode 100644
index 00000000..fdac6bdf
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaI2c.h
@@ -0,0 +1,106 @@
+/* $Id: VBoxVgaI2c.h $ */
+/** @file
+ * VBoxVgaI2c.h
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/*
+ This code is based on:
+
+ I2c Bus byte read/write functions.
+
+ Copyright (c) 2008 - 2009, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+*/
+
+#ifndef _CIRRUS_LOGIC_I2C_H_
+#define _CIRRUS_LOGIC_I2C_H_
+
+#include <Protocol/PciIo.h>
+
+/**
+ Read one byte data on I2C Bus.
+
+ Read one byte data from the slave device connected to I2C Bus.
+ If Data is NULL, then ASSERT().
+
+ @param PciIo The pointer to PCI_IO_PROTOCOL.
+ @param DeviceAddress Slave device's address.
+ @param RegisterAddress The register address on slave device.
+ @param Data The pointer to returned data if EFI_SUCCESS returned.
+
+ @retval EFI_DEVICE_ERROR
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+I2cReadByte (
+ EFI_PCI_IO_PROTOCOL *PciIo,
+ UINT8 DeviceAddress,
+ UINT8 RegisterAddress,
+ UINT8 *Data
+ );
+
+/**
+ Write one byte data onto I2C Bus.
+
+ Write one byte data to the slave device connected to I2C Bus.
+ If Data is NULL, then ASSERT().
+
+ @param PciIo The pointer to PCI_IO_PROTOCOL.
+ @param DeviceAddress Slave device's address.
+ @param RegisterAddress The register address on slave device.
+ @param Data The pointer to write data.
+
+ @retval EFI_DEVICE_ERROR
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+I2cWriteByte (
+ EFI_PCI_IO_PROTOCOL *PciIo,
+ UINT8 DeviceAddress,
+ UINT8 RegisterAddress,
+ UINT8 *Data
+ );
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaUgaDraw.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaUgaDraw.c
new file mode 100644
index 00000000..410e85c5
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaUgaDraw.c
@@ -0,0 +1,417 @@
+/* $Id: VBoxVgaUgaDraw.c $ */
+/** @file
+ * VBoxVgaUgaDraw.c
+ */
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/*
+ This code is based on:
+
+ This file produces the graphics abstraction of UGA Draw. It is called by
+ VBoxVga.c file which deals with the EFI 1.1 driver model.
+ This file just does graphics.
+
+ Copyright (c) 2006, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+*/
+
+#include "VBoxVga.h"
+
+//
+// UGA Draw Protocol Member Functions
+//
+EFI_STATUS
+EFIAPI
+VBoxVgaUgaDrawGetMode (
+ IN EFI_UGA_DRAW_PROTOCOL *This,
+ OUT UINT32 *HorizontalResolution,
+ OUT UINT32 *VerticalResolution,
+ OUT UINT32 *ColorDepth,
+ OUT UINT32 *RefreshRate
+ )
+{
+ VBOX_VGA_PRIVATE_DATA *Private;
+
+ Private = VBOX_VGA_PRIVATE_DATA_FROM_UGA_DRAW_THIS (This);
+
+ if (Private->HardwareNeedsStarting) {
+ return EFI_NOT_STARTED;
+ }
+
+ if ((HorizontalResolution == NULL) ||
+ (VerticalResolution == NULL) ||
+ (ColorDepth == NULL) ||
+ (RefreshRate == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *HorizontalResolution = Private->ModeData[Private->CurrentMode].HorizontalResolution;
+ *VerticalResolution = Private->ModeData[Private->CurrentMode].VerticalResolution;
+ *ColorDepth = Private->ModeData[Private->CurrentMode].ColorDepth;
+ *RefreshRate = Private->ModeData[Private->CurrentMode].RefreshRate;
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+VBoxVgaUgaDrawSetMode (
+ IN EFI_UGA_DRAW_PROTOCOL *This,
+ IN UINT32 HorizontalResolution,
+ IN UINT32 VerticalResolution,
+ IN UINT32 ColorDepth,
+ IN UINT32 RefreshRate
+ )
+{
+ VBOX_VGA_PRIVATE_DATA *Private;
+ UINTN Index;
+
+ DEBUG((DEBUG_INFO, "%a:%d VIDEO: %dx%d %d bpp\n", __FILE__, __LINE__, HorizontalResolution, VerticalResolution, ColorDepth));
+ Private = VBOX_VGA_PRIVATE_DATA_FROM_UGA_DRAW_THIS (This);
+
+ for (Index = 0; Index < Private->MaxMode; Index++) {
+
+ if (HorizontalResolution != Private->ModeData[Index].HorizontalResolution) {
+ continue;
+ }
+
+ if (VerticalResolution != Private->ModeData[Index].VerticalResolution) {
+ continue;
+ }
+
+ if (ColorDepth != Private->ModeData[Index].ColorDepth) {
+ continue;
+ }
+
+#if 0
+ if (RefreshRate != Private->ModeData[Index].RefreshRate) {
+ continue;
+ }
+#endif
+
+ InitializeGraphicsMode (Private, &VBoxVgaVideoModes[Private->ModeData[Index].ModeNumber]);
+
+ Private->CurrentMode = Index;
+
+ Private->HardwareNeedsStarting = FALSE;
+
+ /* update current mode */
+ Private->CurrentMode = Index;
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+EFI_STATUS
+EFIAPI
+VBoxVgaUgaDrawBlt (
+ IN EFI_UGA_DRAW_PROTOCOL *This,
+ IN EFI_UGA_PIXEL *BltBuffer, OPTIONAL
+ IN EFI_UGA_BLT_OPERATION BltOperation,
+ IN UINTN SourceX,
+ IN UINTN SourceY,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height,
+ IN UINTN Delta
+ )
+{
+ VBOX_VGA_PRIVATE_DATA *Private;
+ EFI_TPL OriginalTPL;
+ UINTN DstY;
+ UINTN SrcY;
+ UINTN ScreenWidth;
+ UINTN ScreenHeight;
+ EFI_STATUS Status;
+
+ Private = VBOX_VGA_PRIVATE_DATA_FROM_UGA_DRAW_THIS (This);
+ ScreenWidth = Private->ModeData[Private->CurrentMode].HorizontalResolution;
+ ScreenHeight = Private->ModeData[Private->CurrentMode].VerticalResolution;
+
+ if ((BltOperation < 0) || (BltOperation >= EfiUgaBltMax)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Width == 0 || Height == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If Delta is zero, then the entire BltBuffer is being used, so Delta
+ // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
+ // the number of bytes in each row can be computed.
+ //
+ if (Delta == 0) {
+ Delta = Width * sizeof (EFI_UGA_PIXEL);
+ }
+ // code below assumes a Delta value in pixels, not bytes
+ Delta /= sizeof (EFI_UGA_PIXEL);
+
+ //
+ // Make sure the SourceX, SourceY, DestinationX, DestinationY, Width, and Height parameters
+ // are valid for the operation and the current screen geometry.
+ //
+ if (BltOperation == EfiUgaVideoToBltBuffer || BltOperation == EfiUgaVideoToVideo) {
+ if (SourceY + Height > ScreenHeight) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (SourceX + Width > ScreenWidth) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ if (BltOperation == EfiUgaBltBufferToVideo || BltOperation == EfiUgaVideoToVideo || BltOperation == EfiUgaVideoFill) {
+ if (DestinationY + Height > ScreenHeight) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DestinationX + Width > ScreenWidth) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
+ // We would not want a timer based event (Cursor, ...) to come in while we are
+ // doing this operation.
+ //
+ OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
+
+ switch (BltOperation) {
+ case EfiUgaVideoToBltBuffer:
+ //
+ // Video to BltBuffer: Source is Video, destination is BltBuffer
+ //
+ for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) {
+ /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthUint32) and format matches EFI_UGA_PIXEL
+ Status = Private->PciIo->Mem.Read (
+ Private->PciIo,
+ EfiPciIoWidthUint32,
+ Private->BarIndexFB,
+ ((SrcY * ScreenWidth) + SourceX) * 4,
+ Width,
+ BltBuffer + (DstY * Delta) + DestinationX
+ );
+ ASSERT_EFI_ERROR((Status));
+ }
+ break;
+
+ case EfiUgaBltBufferToVideo:
+ //
+ // BltBuffer to Video: Source is BltBuffer, destination is Video
+ //
+ for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
+ /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthUint32) and format matches EFI_UGA_PIXEL
+ Status = Private->PciIo->Mem.Write (
+ Private->PciIo,
+ EfiPciIoWidthUint32,
+ Private->BarIndexFB,
+ ((DstY * ScreenWidth) + DestinationX) * 4,
+ Width,
+ BltBuffer + (SrcY * Delta) + SourceX
+ );
+ ASSERT_EFI_ERROR((Status));
+ }
+ break;
+
+ case EfiUgaVideoToVideo:
+ //
+ // Video to Video: Source is Video, destination is Video
+ //
+ if (DestinationY <= SourceY) {
+ // forward copy
+ for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
+ /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthUint32) and format matches EFI_UGA_PIXEL
+ Status = Private->PciIo->CopyMem (
+ Private->PciIo,
+ EfiPciIoWidthUint32,
+ Private->BarIndexFB,
+ ((DstY * ScreenWidth) + DestinationX) * 4,
+ Private->BarIndexFB,
+ ((SrcY * ScreenWidth) + SourceX) * 4,
+ Width
+ );
+ ASSERT_EFI_ERROR((Status));
+ }
+ } else {
+ // reverse copy
+ for (SrcY = SourceY + Height - 1, DstY = DestinationY + Height - 1; SrcY >= SourceY && SrcY <= SourceY + Height - 1; SrcY--, DstY--) {
+ /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthUint32) and format matches EFI_UGA_PIXEL
+ Status = Private->PciIo->CopyMem (
+ Private->PciIo,
+ EfiPciIoWidthUint32,
+ Private->BarIndexFB,
+ ((DstY * ScreenWidth) + DestinationX) * 4,
+ Private->BarIndexFB,
+ ((SrcY * ScreenWidth) + SourceX) * 4,
+ Width
+ );
+ ASSERT_EFI_ERROR((Status));
+ }
+ }
+ break;
+
+ case EfiUgaVideoFill:
+ //
+ // Video Fill: Source is BltBuffer, destination is Video
+ //
+ if (DestinationX == 0 && Width == ScreenWidth) {
+ /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthFillUint32) and format matches EFI_UGA_PIXEL
+ Status = Private->PciIo->Mem.Write (
+ Private->PciIo,
+ EfiPciIoWidthFillUint32,
+ Private->BarIndexFB,
+ DestinationY * ScreenWidth * 4,
+ (Width * Height),
+ BltBuffer
+ );
+ ASSERT_EFI_ERROR((Status));
+ } else {
+ for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
+ /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthFillUint32) and format matches EFI_UGA_PIXEL
+ Private->PciIo->Mem.Write (
+ Private->PciIo,
+ EfiPciIoWidthFillUint32,
+ Private->BarIndexFB,
+ ((DstY * ScreenWidth) + DestinationX) * 4,
+ Width,
+ BltBuffer
+ );
+ }
+ }
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+
+ gBS->RestoreTPL (OriginalTPL);
+
+ return EFI_SUCCESS;
+}
+
+//
+// Construction and Destruction functions
+//
+EFI_STATUS
+VBoxVgaUgaDrawConstructor (
+ VBOX_VGA_PRIVATE_DATA *Private
+ )
+{
+ EFI_UGA_DRAW_PROTOCOL *UgaDraw;
+ UINT32 Index;
+ UINT32 HorizontalResolution = 1024;
+ UINT32 VerticalResolution = 768;
+ UINT32 ColorDepth = 32;
+
+ //
+ // Fill in Private->UgaDraw protocol
+ //
+ UgaDraw = &Private->UgaDraw;
+
+ UgaDraw->GetMode = VBoxVgaUgaDrawGetMode;
+ UgaDraw->SetMode = VBoxVgaUgaDrawSetMode;
+ UgaDraw->Blt = VBoxVgaUgaDrawBlt;
+
+ //
+ // Initialize the private data
+ //
+ Private->CurrentMode = 0;
+ Private->HardwareNeedsStarting = TRUE;
+
+ //
+ // Initialize the hardware
+ //
+ VBoxVgaGetVmVariable(EFI_INFO_INDEX_HORIZONTAL_RESOLUTION, (CHAR8 *)&HorizontalResolution,
+ sizeof(HorizontalResolution));
+ VBoxVgaGetVmVariable(EFI_INFO_INDEX_VERTICAL_RESOLUTION, (CHAR8 *)&VerticalResolution,
+ sizeof(VerticalResolution));
+ for (Index = 0; Index < Private->MaxMode; Index++)
+ {
+ if ( HorizontalResolution == Private->ModeData[Index].HorizontalResolution
+ && VerticalResolution == Private->ModeData[Index].VerticalResolution
+ && ColorDepth == Private->ModeData[Index].ColorDepth)
+ break;
+ }
+ // not found? try mode number
+ if (Index >= Private->MaxMode)
+ {
+ VBoxVgaGetVmVariable(EFI_INFO_INDEX_GRAPHICS_MODE, (CHAR8 *)&Index, sizeof(Index));
+ // try with mode 2 (usually 1024x768) as a fallback
+ if (Index >= Private->MaxMode)
+ Index = 2;
+ // try with mode 0 (usually 640x480) as a fallback
+ if (Index >= Private->MaxMode)
+ Index = 0;
+
+ // get the resolution from the mode if valid
+ if (Index < Private->MaxMode)
+ {
+ HorizontalResolution = Private->ModeData[Index].HorizontalResolution;
+ VerticalResolution = Private->ModeData[Index].VerticalResolution;
+ ColorDepth = Private->ModeData[Index].ColorDepth;
+ }
+ }
+
+ // skip mode setting completely if there is no valid mode
+ if (Index >= Private->MaxMode)
+ return EFI_UNSUPPORTED;
+
+ UgaDraw->SetMode (
+ UgaDraw,
+ HorizontalResolution,
+ VerticalResolution,
+ ColorDepth,
+ 60
+ );
+
+ DrawLogo (
+ Private,
+ Private->ModeData[Private->CurrentMode].HorizontalResolution,
+ Private->ModeData[Private->CurrentMode].VerticalResolution
+ );
+
+ PcdSet32S(PcdVideoHorizontalResolution, HorizontalResolution);
+ PcdSet32S(PcdVideoVerticalResolution, VerticalResolution);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaMiniPortDxe/VBoxVgaFont-8x14.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaMiniPortDxe/VBoxVgaFont-8x14.h
new file mode 100644
index 00000000..2342f4a5
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaMiniPortDxe/VBoxVgaFont-8x14.h
@@ -0,0 +1,243 @@
+/* $Id: VBoxVgaFont-8x14.h $ */
+/** @file
+ * VGA-ROM.F14 from ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip .
+ * The package is (C) Joseph (Yossi) Gil.
+ * The individual fonts are in the public domain.
+ */
+
+/*
+ * This file was automatically generated
+ * from VGA-ROM.F14
+ * by \coding\vbox\svn\trunk\out\win.amd64\debug\obj\bin2c\bin2c.exe.
+ */
+
+const unsigned char g_abVgaFont_8x14[] =
+{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff,
+ 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe,
+ 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c,
+ 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18,
+ 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32,
+ 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18,
+ 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x70, 0xf0,
+ 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x06, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c,
+ 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b,
+ 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38,
+ 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60,
+ 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0,
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x6c, 0xfe, 0x6c, 0x28, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66,
+ 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c,
+ 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06,
+ 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x66,
+ 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0x76, 0x00,
+ 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18,
+ 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
+ 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06,
+ 0x3c, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe,
+ 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0xc6,
+ 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+ 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30,
+ 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66,
+ 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0,
+ 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x62, 0x66,
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0x66, 0x6c, 0x6c,
+ 0x78, 0x6c, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60,
+ 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66,
+ 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60,
+ 0x38, 0x0c, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xfe, 0x7c, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x38, 0x6c, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6,
+ 0x8c, 0x18, 0x30, 0x60, 0xc2, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30,
+ 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c,
+ 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x3c, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60,
+ 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
+ 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc,
+ 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6,
+ 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06,
+ 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66,
+ 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xfe, 0xd6, 0xd6, 0xd6,
+ 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
+ 0xc6, 0x70, 0x1c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30,
+ 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc,
+ 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18,
+ 0x70, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18,
+ 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18,
+ 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, 0x00,
+ 0xcc, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30,
+ 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78,
+ 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x78, 0x0c, 0x7c,
+ 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc,
+ 0x76, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xcc, 0xcc, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18,
+ 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x00, 0x38,
+ 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18,
+ 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18,
+ 0x3c, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0x76, 0x36, 0x7e, 0xd8, 0xd8, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c,
+ 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0x00, 0x7c, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0x7c, 0x00, 0x00, 0x00, 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
+ 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, 0x00, 0xc6,
+ 0xc6, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0x00,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x3c, 0x66, 0x60,
+ 0x60, 0x66, 0x3c, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60,
+ 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x7e, 0x18,
+ 0x18, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0xcc, 0xc6, 0x00,
+ 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x0c,
+ 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60,
+ 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6,
+ 0xc6, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc6, 0xcc, 0xd8,
+ 0x30, 0x60, 0xdc, 0x86, 0x0c, 0x18, 0x3e, 0x00, 0x00, 0xc0, 0xc0, 0xc6, 0xcc, 0xd8, 0x30, 0x66,
+ 0xce, 0x9e, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x3c, 0x3c, 0x3c,
+ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x55, 0xaa,
+ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77,
+ 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+ 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xfc, 0xc6, 0xc6, 0xfc, 0xc0, 0xc0, 0x40, 0x00, 0x00, 0x00, 0xfe, 0xc6,
+ 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c,
+ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30,
+ 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8,
+ 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
+ 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c,
+ 0x3e, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb,
+ 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60,
+ 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x30, 0x1c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18,
+ 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60,
+ 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8,
+ 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0xec, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+const unsigned g_cbVgaFont_8x14 = sizeof(g_abVgaFont_8x14);
+/* end of file */
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaMiniPortDxe/VBoxVgaFont-8x16.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaMiniPortDxe/VBoxVgaFont-8x16.h
new file mode 100644
index 00000000..bb8b6b46
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaMiniPortDxe/VBoxVgaFont-8x16.h
@@ -0,0 +1,275 @@
+/* $Id: VBoxVgaFont-8x16.h $ */
+/** @file
+ * VGA-ROM.F16 from ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip .
+ * The package is (C) Joseph (Yossi) Gil.
+ * The individual fonts are in the public domain.
+ */
+
+/*
+ * This file was automatically generated
+ * from VGA-ROM.F16
+ * by \coding\vbox\svn\trunk\out\win.amd64\debug\obj\bin2c\bin2c.exe.
+ */
+
+const unsigned char g_abVgaFont_8x16[] =
+{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc3, 0xc3, 0xdb, 0xdb, 0xc3, 0xc3, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
+ 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x18, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xfc, 0x66, 0x66, 0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 0x0c, 0x1f, 0x00, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
+ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+ 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+const unsigned g_cbVgaFont_8x16 = sizeof(g_abVgaFont_8x16);
+/* end of file */
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaMiniPortDxe/VBoxVgaFont-8x8.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaMiniPortDxe/VBoxVgaFont-8x8.h
new file mode 100644
index 00000000..369fbb11
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaMiniPortDxe/VBoxVgaFont-8x8.h
@@ -0,0 +1,275 @@
+/* $Id: VBoxVgaFont-8x8.h $ */
+/** @file
+ * VGA-ROM.F8 from ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip .
+ * The package is (C) Joseph (Yossi) Gil.
+ * The individual fonts are in the public domain.
+ */
+
+/*
+ * This file was automatically generated
+ * from VGA-ROM.F8
+ * by \coding\vbox\svn\trunk\out\win.amd64\debug\obj\bin2c\bin2c.exe.
+ */
+
+const unsigned char g_abVgaFont_8x8[] =
+{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
+ 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
+ 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
+ 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
+ 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
+ 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
+ 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
+ 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
+ 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
+ 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
+ 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
+ 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
+ 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
+ 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
+ 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
+ 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
+ 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
+ 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
+ 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
+ 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
+ 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
+ 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
+ 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
+ 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
+ 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
+ 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
+ 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
+ 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
+ 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
+ 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
+ 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
+ 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
+ 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
+ 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
+ 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
+ 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
+ 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
+ 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
+ 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
+ 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
+ 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
+ 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
+ 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
+ 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
+ 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
+ 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
+ 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
+ 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
+ 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
+ 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
+ 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
+ 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
+ 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
+ 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
+ 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
+ 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
+ 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
+ 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
+ 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
+ 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
+ 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
+ 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
+ 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
+ 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+ 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
+ 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
+ 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
+ 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
+ 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
+ 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
+ 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
+ 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
+ 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
+ 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
+ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
+ 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
+ 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+ 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
+ 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
+ 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
+ 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
+ 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
+ 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
+ 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
+ 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
+ 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
+ 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+ 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
+ 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
+ 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
+ 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
+ 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
+ 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x18, 0x0c, 0x78,
+ 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x1c, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0x7e, 0xc3, 0x3c, 0x06, 0x3e, 0x66, 0x3f, 0x00,
+ 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+ 0xe0, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+ 0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+ 0x00, 0x00, 0x78, 0xc0, 0xc0, 0x78, 0x0c, 0x38,
+ 0x7e, 0xc3, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00,
+ 0xcc, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0xe0, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0xcc, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x7c, 0xc6, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00,
+ 0xe0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0xc6, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00,
+ 0x30, 0x30, 0x00, 0x78, 0xcc, 0xfc, 0xcc, 0x00,
+ 0x1c, 0x00, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00,
+ 0x00, 0x00, 0x7f, 0x0c, 0x7f, 0xcc, 0x7f, 0x00,
+ 0x3e, 0x6c, 0xcc, 0xfe, 0xcc, 0xcc, 0xce, 0x00,
+ 0x78, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0xe0, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x00, 0xe0, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+ 0xc3, 0x18, 0x3c, 0x66, 0x66, 0x3c, 0x18, 0x00,
+ 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
+ 0x18, 0x18, 0x7e, 0xc0, 0xc0, 0x7e, 0x18, 0x18,
+ 0x38, 0x6c, 0x64, 0xf0, 0x60, 0xe6, 0xfc, 0x00,
+ 0xcc, 0xcc, 0x78, 0xfc, 0x30, 0xfc, 0x30, 0x30,
+ 0xf8, 0xcc, 0xcc, 0xfa, 0xc6, 0xcf, 0xc6, 0xc7,
+ 0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70,
+ 0x1c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+ 0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x00, 0x1c, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0x1c, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x00, 0xf8, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0x00,
+ 0xfc, 0x00, 0xcc, 0xec, 0xfc, 0xdc, 0xcc, 0x00,
+ 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00,
+ 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00,
+ 0x30, 0x00, 0x30, 0x60, 0xc0, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0x00, 0xfc, 0xc0, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00,
+ 0xc3, 0xc6, 0xcc, 0xde, 0x33, 0x66, 0xcc, 0x0f,
+ 0xc3, 0xc6, 0xcc, 0xdb, 0x37, 0x6f, 0xcf, 0x03,
+ 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x00, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x00, 0x00,
+ 0x00, 0xcc, 0x66, 0x33, 0x66, 0xcc, 0x00, 0x00,
+ 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88,
+ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+ 0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0xc8, 0xdc, 0x76, 0x00,
+ 0x00, 0x78, 0xcc, 0xf8, 0xcc, 0xf8, 0xc0, 0xc0,
+ 0x00, 0xfc, 0xcc, 0xc0, 0xc0, 0xc0, 0xc0, 0x00,
+ 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00,
+ 0xfc, 0xcc, 0x60, 0x30, 0x60, 0xcc, 0xfc, 0x00,
+ 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0x70, 0x00,
+ 0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0xc0,
+ 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0xfc, 0x30, 0x78, 0xcc, 0xcc, 0x78, 0x30, 0xfc,
+ 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x6c, 0x38, 0x00,
+ 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x6c, 0xee, 0x00,
+ 0x1c, 0x30, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00,
+ 0x06, 0x0c, 0x7e, 0xdb, 0xdb, 0x7e, 0x60, 0xc0,
+ 0x38, 0x60, 0xc0, 0xf8, 0xc0, 0x60, 0x38, 0x00,
+ 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
+ 0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x00,
+ 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0xfc, 0x00,
+ 0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xfc, 0x00,
+ 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xfc, 0x00,
+ 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70,
+ 0x30, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x30, 0x00,
+ 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00,
+ 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c,
+ 0x78, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00,
+ 0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+const unsigned g_cbVgaFont_8x8 = sizeof(g_abVgaFont_8x8);
+/* end of file */
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaMiniPortDxe/VBoxVgaFonts.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaMiniPortDxe/VBoxVgaFonts.h
new file mode 100644
index 00000000..ef94497d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaMiniPortDxe/VBoxVgaFonts.h
@@ -0,0 +1,13 @@
+/* $Id: VBoxVgaFonts.h $ */
+/** @file
+ * Some of the VGA-ROM fonts from ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip .
+ * The package is (C) Joseph (Yossi) Gil.
+ * The individual fonts are in the public domain.
+ *
+ * Note. These fonts are also used by the VGA BIOS.
+ */
+
+#include "VBoxVgaFont-8x8.h"
+#include "VBoxVgaFont-8x14.h"
+#include "VBoxVgaFont-8x16.h"
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaMiniPortDxe/VBoxVgaMiniPortDxe.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaMiniPortDxe/VBoxVgaMiniPortDxe.c
new file mode 100644
index 00000000..f4a8b4af
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaMiniPortDxe/VBoxVgaMiniPortDxe.c
@@ -0,0 +1,657 @@
+/* $Id: VBoxVgaMiniPortDxe.c $ */
+/** @file
+ * VBoxVgaMiniPortDxe.c - VgaMiniPort Protocol Implementation.
+ */
+
+
+/*
+ * Copyright (C) 2009-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <Protocol/ComponentName.h>
+#include <Protocol/ComponentName2.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/VgaMiniPort.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <IndustryStandard/Pci22.h>
+
+#include "VBoxPkg.h"
+#include "VBoxVgaFonts.h"
+#include "iprt/asm.h"
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Instance data for a VGA device this driver handles.
+ */
+typedef struct VBOXVGAMINIPORT
+{
+ /** The VGA Mini Port Protocol. */
+ EFI_VGA_MINI_PORT_PROTOCOL VgaMiniPort;
+ /** Magic value, VBOX_VGA_MINI_PORT_MAGIC. */
+ UINT32 u32Magic;
+ /** The controller handle of the device. */
+ EFI_HANDLE hController;
+ /** The PciIo protocol for the device. */
+ EFI_PCI_IO_PROTOCOL *pPciIo;
+} VBOXVGAMINIPORT;
+/** Pointer to a VBOXVGAMINIPORT structure. */
+typedef VBOXVGAMINIPORT *PVBOXVGAMINIPORT;
+
+/** VBOXVGAMINIPORT::u32Magic value (Isaac Asimov). */
+#define VBOX_VGA_MINI_PORT_MAGIC 0x19200102
+/** VBOXVGAMINIPORT::u32Magic dead value. */
+#define VBOX_VGA_MINI_PORT_MAGIC_DEAD 0x19920406
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+static EFI_STATUS EFIAPI
+VBoxVgaMiniPortDB_Supported(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL);
+static EFI_STATUS EFIAPI
+VBoxVgaMiniPortDB_Start(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL);
+static EFI_STATUS EFIAPI
+VBoxVgaMiniPortDB_Stop(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer OPTIONAL);
+
+
+static EFI_STATUS EFIAPI
+VBoxVgaMiniPortVMP_SetMode(IN EFI_VGA_MINI_PORT_PROTOCOL *This, IN UINTN ModeNumber);
+
+
+static EFI_STATUS EFIAPI
+VBoxVgaMiniPortCN_GetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language, OUT CHAR16 **DriverName);
+static EFI_STATUS EFIAPI
+VBoxVgaMiniPortCN_GetControllerName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language, OUT CHAR16 **ControllerName);
+
+
+static EFI_STATUS EFIAPI
+VBoxVgaMiniPortCN2_GetDriverName(IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN CHAR8 *Language, OUT CHAR16 **DriverName);
+static EFI_STATUS EFIAPI
+VBoxVgaMiniPortCN2_GetControllerName(IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language, OUT CHAR16 **ControllerName);
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/** EFI Driver Binding Protocol. */
+static EFI_DRIVER_BINDING_PROTOCOL g_VBoxVgaMiniPortDB =
+{
+ VBoxVgaMiniPortDB_Supported,
+ VBoxVgaMiniPortDB_Start,
+ VBoxVgaMiniPortDB_Stop,
+ /* .Version = */ 1, /* One higher than Pci/VgaMiniPortDxe. */
+ /* .ImageHandle = */ NULL,
+ /* .DriverBindingHandle = */ NULL
+};
+
+/** EFI Component Name Protocol. */
+static const EFI_COMPONENT_NAME_PROTOCOL g_VBoxVgaMiniPortCN =
+{
+ VBoxVgaMiniPortCN_GetDriverName,
+ VBoxVgaMiniPortCN_GetControllerName,
+ "eng"
+};
+
+/** EFI Component Name 2 Protocol. */
+static const EFI_COMPONENT_NAME2_PROTOCOL g_VBoxVgaMiniPortCN2 =
+{
+ VBoxVgaMiniPortCN2_GetDriverName,
+ VBoxVgaMiniPortCN2_GetControllerName,
+ "en"
+};
+
+/** Driver name translation table. */
+static CONST EFI_UNICODE_STRING_TABLE g_aVBoxMiniPortDriverLangAndNames[] =
+{
+ { "eng;en", L"PCI VGA Mini Port Driver" },
+ { NULL, NULL }
+};
+
+
+
+/**
+ * VBoxVgaMiniPort entry point.
+ *
+ * @returns EFI status code.
+ *
+ * @param ImageHandle The image handle.
+ * @param SystemTable The system table pointer.
+ */
+EFI_STATUS EFIAPI
+DxeInitializeVBoxVgaMiniPort(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
+{
+ EFI_STATUS rc;
+ DEBUG((DEBUG_INFO, "DxeInitializeVBoxVgaMiniPort\n"));
+
+ rc = EfiLibInstallDriverBindingComponentName2(ImageHandle, SystemTable,
+ &g_VBoxVgaMiniPortDB, ImageHandle,
+ &g_VBoxVgaMiniPortCN, &g_VBoxVgaMiniPortCN2);
+ ASSERT_EFI_ERROR(rc);
+ return rc;
+}
+
+/**
+ * @copydoc EFI_DRIVER_BINDING_SUPPORTED
+ */
+static EFI_STATUS EFIAPI
+VBoxVgaMiniPortDB_Supported(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL)
+{
+ EFI_STATUS rcRet = EFI_UNSUPPORTED;
+ EFI_PCI_IO_PROTOCOL *pPciIo;
+ EFI_STATUS rc;
+
+ DEBUG((DEBUG_INFO, "%a: Controller=%p\n", __FUNCTION__, ControllerHandle));
+
+ /*
+ * To perform the test we need to check some PCI configuration registers,
+ * just read all the standard ones to make life simpler.
+ */
+ rc = gBS->OpenProtocol(ControllerHandle, &gEfiPciIoProtocolGuid, (VOID **)&pPciIo,
+ This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
+ if (!EFI_ERROR(rc))
+ {
+ PCI_TYPE00 CfgRegs;
+
+ rc = pPciIo->Pci.Read(pPciIo,
+ EfiPciIoWidthUint32,
+ 0 /* Offset */,
+ sizeof(CfgRegs) / sizeof(UINT32) /* Count */ ,
+ &CfgRegs);
+ if (!EFI_ERROR(rc))
+ {
+ /*
+ * Perform the test.
+ */
+ if (IS_PCI_VGA(&CfgRegs))
+ {
+#if 0 /** @todo this doesn't quite work with our DevVGA since it doesn't flag I/O access. */
+ if ( CfgRegs.Hdr.Command & (PCI_COMMAND_IOACCESS | PCI_COMMAND_MEMACCESS)
+ == (PCI_COMMAND_IOACCESS | PCI_COMMAND_MEMACCESS))
+#else
+ if (1)
+#endif
+ {
+ DEBUG((DEBUG_INFO, "%a: Found supported VGA device! (VendorId=%x DeviceId=%x)\n",
+ __FUNCTION__, CfgRegs.Hdr.VendorId, CfgRegs.Hdr.DeviceId));
+ rcRet = EFI_SUCCESS;
+ }
+ else
+ DEBUG((DEBUG_INFO, "%a: VGA device not enabled! (VendorId=%x DeviceId=%x)\n",
+ __FUNCTION__, CfgRegs.Hdr.VendorId, CfgRegs.Hdr.DeviceId));
+ }
+ else
+ DEBUG((DEBUG_INFO, "%a: Not VGA (Class=%x,%x,%x VendorId=%x DeviceId=%x)\n",
+ __FUNCTION__, CfgRegs.Hdr.ClassCode[0], CfgRegs.Hdr.ClassCode[1],
+ CfgRegs.Hdr.ClassCode[2], CfgRegs.Hdr.VendorId, CfgRegs.Hdr.DeviceId));
+ }
+ else
+ DEBUG((DEBUG_INFO, "%a: pPciIo->Pci.Read -> %r\n", __FUNCTION__, rc));
+
+ gBS->CloseProtocol(ControllerHandle, &gEfiPciIoProtocolGuid, This->DriverBindingHandle, ControllerHandle);
+ }
+ else
+ DEBUG((DEBUG_INFO, "%a: PciIoProtocol -> %r\n", __FUNCTION__, rc));
+ return rcRet;
+}
+
+/**
+ * @copydoc EFI_DRIVER_BINDING_START
+ */
+static EFI_STATUS EFIAPI
+VBoxVgaMiniPortDB_Start(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL)
+{
+ EFI_STATUS rc;
+ EFI_PCI_IO_PROTOCOL *pPciIo;
+
+ DEBUG((DEBUG_INFO, "%a\n", __FUNCTION__));
+
+ /*
+ * We need the PCI I/O abstraction protocol.
+ */
+ rc = gBS->OpenProtocol(ControllerHandle, &gEfiPciIoProtocolGuid, (VOID **)&pPciIo,
+ This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
+ if (!EFI_ERROR(rc))
+ {
+ /*
+ * Allocate and initialize the instance data.
+ */
+ PVBOXVGAMINIPORT pThisDev;
+ rc = gBS->AllocatePool(EfiBootServicesData, sizeof(*pThisDev), (VOID **)&pThisDev);
+ if (!EFI_ERROR(rc))
+ {
+ pThisDev->VgaMiniPort.SetMode = VBoxVgaMiniPortVMP_SetMode;
+ pThisDev->VgaMiniPort.VgaMemoryOffset = 0x000b8000;
+ pThisDev->VgaMiniPort.CrtcAddressRegisterOffset = 0x03d4;
+ pThisDev->VgaMiniPort.CrtcDataRegisterOffset = 0x03d5;
+ pThisDev->VgaMiniPort.VgaMemoryBar = EFI_PCI_IO_PASS_THROUGH_BAR;
+ pThisDev->VgaMiniPort.CrtcAddressRegisterBar = EFI_PCI_IO_PASS_THROUGH_BAR;
+ pThisDev->VgaMiniPort.CrtcDataRegisterBar = EFI_PCI_IO_PASS_THROUGH_BAR;
+ pThisDev->VgaMiniPort.MaxMode = 2;
+ pThisDev->u32Magic = VBOX_VGA_MINI_PORT_MAGIC;
+ pThisDev->hController = ControllerHandle;
+ pThisDev->pPciIo = pPciIo;
+
+ /*
+ * Register the VGA Mini Port Protocol.
+ */
+ rc = gBS->InstallMultipleProtocolInterfaces(&ControllerHandle,
+ &gEfiVgaMiniPortProtocolGuid, &pThisDev->VgaMiniPort,
+ NULL, NULL);
+ if (!EFI_ERROR(rc))
+ {
+ DEBUG((DEBUG_INFO, "%a: Successfully started, pThisDev=%p ControllerHandle=%p\n",
+ __FUNCTION__, pThisDev, ControllerHandle));
+ return EFI_SUCCESS;
+ }
+
+ DEBUG((DEBUG_INFO, "%a: InstallMultipleProtocolInterfaces -> %r\n", __FUNCTION__, rc));
+ gBS->FreePool(pThisDev);
+ }
+ else
+ DEBUG((DEBUG_INFO, "%a: AllocatePool -> %r\n", __FUNCTION__, rc));
+
+ gBS->CloseProtocol(ControllerHandle, &gEfiPciIoProtocolGuid, This->DriverBindingHandle, ControllerHandle);
+ }
+ else
+ DEBUG((DEBUG_INFO, "%a: PciIoProtocol -> %r\n", __FUNCTION__, rc));
+ return rc;
+}
+
+/**
+ * @copydoc EFI_DRIVER_BINDING_STOP
+ */
+static EFI_STATUS EFIAPI
+VBoxVgaMiniPortDB_Stop(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer OPTIONAL)
+{
+ EFI_STATUS rc;
+ PVBOXVGAMINIPORT pThisDev;
+
+ DEBUG((DEBUG_INFO, "%a: ControllerHandle=%p NumberOfChildren=%u\n", __FUNCTION__, ControllerHandle, NumberOfChildren));
+
+ /*
+ * Get the miniport driver instance associated with the controller.
+ */
+ rc = gBS->OpenProtocol(ControllerHandle, &gEfiVgaMiniPortProtocolGuid,
+ (VOID **)&pThisDev, This->DriverBindingHandle,
+ ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (!EFI_ERROR(rc))
+ {
+ ASSERT(pThisDev->u32Magic == VBOX_VGA_MINI_PORT_MAGIC);
+ ASSERT(pThisDev->hController == ControllerHandle);
+ if ( pThisDev->u32Magic == VBOX_VGA_MINI_PORT_MAGIC
+ && pThisDev->hController == ControllerHandle)
+ {
+ /*
+ * Uninstall the VgaMiniPort interface.
+ */
+ rc = gBS->UninstallProtocolInterface(ControllerHandle,
+ &gEfiVgaMiniPortProtocolGuid,
+ &pThisDev->VgaMiniPort);
+ if (!EFI_ERROR(rc))
+ {
+ /*
+ * Invalidate and release sources associated with the device instance.
+ */
+ pThisDev->u32Magic = VBOX_VGA_MINI_PORT_MAGIC_DEAD;
+ gBS->FreePool(pThisDev);
+
+ }
+ else
+ DEBUG((DEBUG_INFO, "%a: UninstallProtocolInterface -> %r\n", __FUNCTION__, rc));
+ }
+ else
+ {
+ DEBUG((DEBUG_INFO, "%a: magic=%x/%x hController=%x/%x\n", __FUNCTION__,
+ pThisDev->u32Magic, VBOX_VGA_MINI_PORT_MAGIC,
+ pThisDev->hController, ControllerHandle));
+ rc = EFI_DEVICE_ERROR;
+ }
+ gBS->CloseProtocol(ControllerHandle, &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle, ControllerHandle);
+ }
+ else
+ DEBUG((DEBUG_INFO, "%a: VgaMiniPortProtocol -> %r\n", __FUNCTION__, rc));
+ return rc;
+}
+
+
+
+
+
+/**
+ * @copydoc EFI_VGA_MINI_PORT_SET_MODE
+ */
+static EFI_STATUS EFIAPI
+VBoxVgaMiniPortVMP_SetMode(IN EFI_VGA_MINI_PORT_PROTOCOL *This, IN UINTN ModeNumber)
+{
+ PVBOXVGAMINIPORT pThisDev = (PVBOXVGAMINIPORT)This;
+ UINT8 r[64];
+ int i;
+
+ /*
+ * Check input.
+ */
+ if (pThisDev->u32Magic != VBOX_VGA_MINI_PORT_MAGIC)
+ {
+ DEBUG((DEBUG_INFO, "%a: u32Magic=%x/%x\n", __FUNCTION__, pThisDev->u32Magic, VBOX_VGA_MINI_PORT_MAGIC));
+ return EFI_DEVICE_ERROR;
+ }
+ if (ModeNumber >= This->MaxMode)
+ {
+ DEBUG((DEBUG_INFO, "%a: ModeNumber=%d >= MaxMode=%d\n", __FUNCTION__, ModeNumber, This->MaxMode));
+ return EFI_UNSUPPORTED;
+ }
+ DEBUG((DEBUG_INFO, "%a: ModeNumber=%d\n", __FUNCTION__, ModeNumber));
+
+ /* some initialization */
+ ASMOutU8(0x3c2, 0xc3);
+ ASMOutU16(0x3c4, 0x0204);
+
+ ASMInU8(0x3da); // reset attr F/F
+ ASMOutU8(0x3c0, 0); // disable palette
+ ASMOutU16(0x3d4, 0x0011); // unprotect crtc regs 0 - 7
+
+#define BOUTB(count, aport, dport) \
+ do { \
+ for (i = 0 ; i < (count); ++i) \
+ if ((dport) == (aport) + 1) \
+ ASMOutU16((aport), ((UINT16)r[i] << 8) | (UINT8)i); \
+ else { \
+ ASMOutU8((aport), (UINT8)i); \
+ ASMOutU8((dport), r[i]); \
+ } \
+ } while (0)
+
+ /* Reset and set sequencer registers */
+ r[0] = 0x01;
+ r[1] = 0x00;
+ r[2] = 0x03;
+ r[3] = 0x00;
+ r[4] = 0x02;
+ BOUTB(5, 0x3c4, 0x3c5);
+
+ /* set misc out register */
+ ASMOutU8(0x3c2, 0x67);
+
+ /* enable sequencer */
+ ASMOutU16(0x3c4, 0x0300);
+
+ /* set all crtc registers */
+ r[0] = 0x5f; r[1] = 0x4f; r[2] = 0x50; r[3] = 0x82;
+ r[4] = 0x55; r[5] = 0x81; r[6] = 0xbf; r[7] = 0x1f;
+ r[8] = 0x00; r[9] = 0x4f; r[10]= 0x0d; r[11]= 0x0e;
+ r[12]= 0x00; r[13]= 0x00; r[14]= 0x03; r[15]= 0xc0;
+ r[16]= 0x9c; r[17]= 0x0e; r[18]= 0x8f; r[19]= 0x28;
+ r[20]= 0x1f; r[21]= 0x96; r[22]= 0xb9; r[23]= 0xa3;
+ r[24]= 0xff;
+ BOUTB(25, 0x3d4, 0x3d5);
+
+ /* set all graphics controller registers */
+ r[0]= 0x00; r[1]= 0x00; r[2]= 0x00; r[3]= 0x00;
+ r[4]= 0x00; r[5]= 0x10; r[6]= 0x0e; r[7]= 0x00;
+ r[8]= 0xff;
+ BOUTB(9, 0x3ce, 0x3cf);
+
+ /* set all attribute registers */
+ ASMInU8(0x3da); // reset attr F/F
+ r[0] = 0x00; r[1] = 0x01; r[2] = 0x02; r[3] = 0x03;
+ r[4] = 0x04; r[5] = 0x05; r[6] = 0x14; r[7] = 0x07;
+ r[8] = 0x38; r[9] = 0x39; r[10]= 0x3a; r[11]= 0x3b;
+ r[12]= 0x3c; r[13]= 0x3d; r[14]= 0x3e; r[15]= 0x3f;
+ r[16]= 0x0c; r[17]= 0x00; r[18]= 0x0f; r[19]= 0x08;
+ r[20]= 0x00;
+ BOUTB(21, 0x3c0, 0x3c0);
+ ASMOutU8(0x3c0, 0x20); // re-enable palette
+
+ /* set all VBox extended registers */
+
+ /* enable sequencer */
+ ASMOutU16(0x3c4, 0x0100);
+
+ ASMOutU16(0x1ce, 0x04); ASMOutU16(0x1cf, 0); // ENABLE
+
+ /* enable sequencer */
+ ASMOutU16(0x3c4, 0x0300);
+
+ /* Load default values into the first 16 entries of the DAC */
+ {
+ static const UINT8 s_a3bVgaDac[64*3] =
+ {
+ 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x2A,
+ 0x00, 0x2A, 0x00,
+ 0x00, 0x2A, 0x2A,
+ 0x2A, 0x00, 0x00,
+ 0x2A, 0x00, 0x2A,
+ 0x2A, 0x2A, 0x00,
+ 0x2A, 0x2A, 0x2A,
+ 0x00, 0x00, 0x15,
+ 0x00, 0x00, 0x3F,
+ 0x00, 0x2A, 0x15,
+ 0x00, 0x2A, 0x3F,
+ 0x2A, 0x00, 0x15,
+ 0x2A, 0x00, 0x3F,
+ 0x2A, 0x2A, 0x15,
+ 0x2A, 0x2A, 0x3F,
+ 0x00, 0x15, 0x00,
+ 0x00, 0x15, 0x2A,
+ 0x00, 0x3F, 0x00,
+ 0x00, 0x3F, 0x2A,
+ 0x2A, 0x15, 0x00,
+ 0x2A, 0x15, 0x2A,
+ 0x2A, 0x3F, 0x00,
+ 0x2A, 0x3F, 0x2A,
+ 0x00, 0x15, 0x15,
+ 0x00, 0x15, 0x3F,
+ 0x00, 0x3F, 0x15,
+ 0x00, 0x3F, 0x3F,
+ 0x2A, 0x15, 0x15,
+ 0x2A, 0x15, 0x3F,
+ 0x2A, 0x3F, 0x15,
+ 0x2A, 0x3F, 0x3F,
+ 0x15, 0x00, 0x00,
+ 0x15, 0x00, 0x2A,
+ 0x15, 0x2A, 0x00,
+ 0x15, 0x2A, 0x2A,
+ 0x3F, 0x00, 0x00,
+ 0x3F, 0x00, 0x2A,
+ 0x3F, 0x2A, 0x00,
+ 0x3F, 0x2A, 0x2A,
+ 0x15, 0x00, 0x15,
+ 0x15, 0x00, 0x3F,
+ 0x15, 0x2A, 0x15,
+ 0x15, 0x2A, 0x3F,
+ 0x3F, 0x00, 0x15,
+ 0x3F, 0x00, 0x3F,
+ 0x3F, 0x2A, 0x15,
+ 0x3F, 0x2A, 0x3F,
+ 0x15, 0x15, 0x00,
+ 0x15, 0x15, 0x2A,
+ 0x15, 0x3F, 0x00,
+ 0x15, 0x3F, 0x2A,
+ 0x3F, 0x15, 0x00,
+ 0x3F, 0x15, 0x2A,
+ 0x3F, 0x3F, 0x00,
+ 0x3F, 0x3F, 0x2A,
+ 0x15, 0x15, 0x15,
+ 0x15, 0x15, 0x3F,
+ 0x15, 0x3F, 0x15,
+ 0x15, 0x3F, 0x3F,
+ 0x3F, 0x15, 0x15,
+ 0x3F, 0x15, 0x3F,
+ 0x3F, 0x3F, 0x15,
+ 0x3F, 0x3F, 0x3F
+ };
+
+ for (i = 0; i < 64; ++i)
+ {
+ ASMOutU8(0x3c8, (UINT8)i);
+ ASMOutU8(0x3c9, s_a3bVgaDac[i*3 + 0]);
+ ASMOutU8(0x3c9, s_a3bVgaDac[i*3 + 1]);
+ ASMOutU8(0x3c9, s_a3bVgaDac[i*3 + 2]);
+ }
+ }
+
+ /* Load the appropriate font into the first map */
+ {
+ UINT8 const *pabFont;
+ unsigned offBase = 0;
+ UINT16 height;
+
+ switch (ModeNumber) {
+ case 0: // 80x25 mode, uses 8x16 font
+ pabFont = g_abVgaFont_8x16;
+ height = 16;
+ break;
+ case 1: // 80x50 mode, uses 8x8 font
+ pabFont = g_abVgaFont_8x8;
+ height = 8;
+ break;
+ default:
+ ASSERT(0); // Valid mode numbers checked above
+ return EFI_UNSUPPORTED;
+ }
+ // Enable font map access
+ {
+ /* Write sequencer registers */
+ ASMOutU16(0x3c4, 0x0100);
+ ASMOutU16(0x3c4, 0x0402);
+ ASMOutU16(0x3c4, 0x0704);
+ ASMOutU16(0x3c4, 0x0300);
+ /* Write graphics controller registers */
+ ASMOutU16(0x3ce, 0x0204);
+ ASMOutU16(0x3ce, 0x0005);
+ ASMOutU16(0x3ce, 0x0406);
+ }
+
+ for (i = 0; i < 256; ++i)
+ {
+ int offChr = i * height;
+ int offDst = offBase + i * 32;
+ CopyMem((UINT8 *)(UINTN)0xA0000 + offDst, pabFont + offChr, height);
+ }
+
+ // Set the CRTC Maximum Scan Line register
+ ASMOutU16(0x3d4, 0x4009 | ((height - 1) << 8));
+
+ // Disable font map access again
+ {
+ /* Write sequencer registers */
+ ASMOutU16(0x3c4, 0x0100);
+ ASMOutU16(0x3c4, 0x0302);
+ ASMOutU16(0x3c4, 0x0304);
+ ASMOutU16(0x3c4, 0x0300);
+ /* Write graphics controller registers */
+ ASMOutU16(0x3ce, 0x0004);
+ ASMOutU16(0x3ce, 0x1005);
+ ASMOutU16(0x3ce, 0x0e06);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+
+
+/** @copydoc EFI_COMPONENT_NAME_GET_DRIVER_NAME */
+static EFI_STATUS EFIAPI
+VBoxVgaMiniPortCN_GetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language, OUT CHAR16 **DriverName)
+{
+ return LookupUnicodeString2(Language,
+ This->SupportedLanguages,
+ &g_aVBoxMiniPortDriverLangAndNames[0],
+ DriverName,
+ TRUE);
+}
+
+/** @copydoc EFI_COMPONENT_NAME_GET_CONTROLLER_NAME */
+static EFI_STATUS EFIAPI
+VBoxVgaMiniPortCN_GetControllerName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language, OUT CHAR16 **ControllerName)
+{
+ /** @todo try query the protocol from the controller and forward the query. */
+ return EFI_UNSUPPORTED;
+}
+
+
+
+
+/** @copydoc EFI_COMPONENT_NAME2_GET_DRIVER_NAME */
+static EFI_STATUS EFIAPI
+VBoxVgaMiniPortCN2_GetDriverName(IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN CHAR8 *Language, OUT CHAR16 **DriverName)
+{
+ return LookupUnicodeString2(Language,
+ This->SupportedLanguages,
+ &g_aVBoxMiniPortDriverLangAndNames[0],
+ DriverName,
+ FALSE);
+}
+
+/** @copydoc EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME */
+static EFI_STATUS EFIAPI
+VBoxVgaMiniPortCN2_GetControllerName(IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language, OUT CHAR16 **ControllerName)
+{
+ /** @todo try query the protocol from the controller and forward the query. */
+ return EFI_UNSUPPORTED;
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaMiniPortDxe/VBoxVgaMiniPortDxe.inf b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaMiniPortDxe/VBoxVgaMiniPortDxe.inf
new file mode 100644
index 00000000..5169653c
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaMiniPortDxe/VBoxVgaMiniPortDxe.inf
@@ -0,0 +1,70 @@
+# $Id: VBoxVgaMiniPortDxe.inf $
+## @file
+# VBoxVgaMiniPortDxe.inf - VgaMiniPort Protocol module declaration.
+#
+
+
+#
+# Copyright (C) 2009-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>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VBoxVgaMiniPortDxe
+ FILE_GUID = AE8558FD-9DA9-4FA1-AE16-94456C977244
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ EDK_RELEASE_VERSION = 0x00020000
+ EFI_SPECIFICATION_VERSION = 0x00020000
+ ENTRY_POINT = DxeInitializeVBoxVgaMiniPort
+
+[Sources.common]
+ VBoxVgaMiniPortDxe.c
+ VBoxVgaFonts.h
+ VBoxVgaFont-8x14.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+ VBoxPkg/VBoxPkg.dec
+
+[LibraryClasses]
+ UefiLib
+ DebugLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ MemoryAllocationLib
+
+[Protocols]
+ gEfiPciIoProtocolGuid ## TO_START
+ gEfiVgaMiniPortProtocolGuid ## BY_START