summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk')
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPei.inf68
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPei.uni18
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPeiExtra.uni14
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/CdExpressPei/PeiCdExpress.c715
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/CdExpressPei/PeiCdExpress.h292
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/ComponentName.c183
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c1262
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.h467
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf65
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.uni21
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxeExtra.uni14
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Apple.c241
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/ComponentName.c182
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/ElTorito.c275
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Gpt.c883
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Mbr.c353
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c1430
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.h514
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf86
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.uni24
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxeExtra.uni14
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c788
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDisk.asl38
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskBlockIo.c487
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDriver.c244
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.inf84
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.uni14
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskFileExplorer.c107
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskHii.vfr94
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskHiiStrings.uni41
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.c758
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.h604
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskNVData.h44
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskProtocol.c857
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UdfDxe/ComponentName.c179
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UdfDxe/File.c904
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UdfDxe/FileName.c214
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c2924
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UdfDxe/Udf.c331
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UdfDxe/Udf.h1215
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UdfDxe/UdfDxe.inf62
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf54
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.uni20
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxeExtra.uni14
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/UnicodeCollationEng.c467
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/UnicodeCollationEng.h181
46 files changed, 17846 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPei.inf b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPei.inf
new file mode 100644
index 00000000..1004adc2
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPei.inf
@@ -0,0 +1,68 @@
+## @file
+# PeiCdExpress recovery module.
+#
+# This module reads data from CDROM device by all installed block IO ppi and
+# finds whether there is Recovery data in the device. If it finds recovery
+# data, it will install Device Recovery Module PPI.
+#
+# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = CdExpressPei
+ MODULE_UNI_FILE = CdExpressPei.uni
+ FILE_GUID = 31e147a6-d39a-4147-9da3-befd4d523243
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = CdExpressPeimEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ PeiCdExpress.c
+ PeiCdExpress.h
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ PeimEntryPoint
+ DebugLib
+ PeiServicesTablePointerLib
+ PeiServicesLib
+ MemoryAllocationLib
+ PcdLib
+
+[Guids]
+ gRecoveryOnDataCdGuid ## CONSUMES ## UNDEFINED # Indicate the recovery device type
+
+
+[Ppis]
+ ## NOTIFY
+ ## CONSUMES
+ gEfiPeiVirtualBlockIoPpiGuid
+ ## NOTIFY
+ ## CONSUMES
+ gEfiPeiVirtualBlockIo2PpiGuid
+ gEfiPeiDeviceRecoveryModulePpiGuid ## PRODUCES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdRecoveryFileName ## CONSUMES
+
+[Depex]
+ gEfiPeiMemoryDiscoveredPpiGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ CdExpressPeiExtra.uni
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPei.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPei.uni
new file mode 100644
index 00000000..89f77e2a
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPei.uni
@@ -0,0 +1,18 @@
+// /** @file
+// PeiCdExpress recovery module.
+//
+// This module reads data from CDROM device by all installed block IO ppi and
+// finds whether there is Recovery data in the device. If it finds recovery
+// data, it will install Device Recovery Module PPI.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "PeiCdExpress recovery module"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module reads data from CDROM device by all installed block IO ppi and finds whether there is Recovery data in the device. If it finds recovery data, it will install Device Recovery Module PPI."
+
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPeiExtra.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPeiExtra.uni
new file mode 100644
index 00000000..d05fff83
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/CdExpressPei/CdExpressPeiExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// CdExpressPei 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
+"CD PEI Module for Recovery"
+
+
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/CdExpressPei/PeiCdExpress.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/CdExpressPei/PeiCdExpress.c
new file mode 100644
index 00000000..a3a0be4d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/CdExpressPei/PeiCdExpress.c
@@ -0,0 +1,715 @@
+/** @file
+ Source file for CD recovery PEIM
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PeiCdExpress.h"
+
+PEI_CD_EXPRESS_PRIVATE_DATA *mPrivateData = NULL;
+CHAR8 *mRecoveryFileName;
+UINTN mRecoveryFileNameSize;
+
+/**
+ Installs the Device Recovery Module PPI, Initialize BlockIo Ppi
+ installation notification
+
+ @param FileHandle The file handle of the image.
+ @param PeiServices General purpose services available to every PEIM.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory.
+
+**/
+EFI_STATUS
+EFIAPI
+CdExpressPeimEntry (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData;
+
+ if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
+ return EFI_SUCCESS;
+ }
+
+ PrivateData = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (*PrivateData)));
+ if (PrivateData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mRecoveryFileNameSize = PcdGetSize(PcdRecoveryFileName) / sizeof(CHAR16);
+ mRecoveryFileName = AllocatePool(mRecoveryFileNameSize);
+ if (mRecoveryFileName == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = UnicodeStrToAsciiStrS(PcdGetPtr(PcdRecoveryFileName), mRecoveryFileName, mRecoveryFileNameSize);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ //
+ // Initialize Private Data (to zero, as is required by subsequent operations)
+ //
+ ZeroMem (PrivateData, sizeof (*PrivateData));
+ PrivateData->Signature = PEI_CD_EXPRESS_PRIVATE_DATA_SIGNATURE;
+
+ PrivateData->BlockBuffer = AllocatePages (EFI_SIZE_TO_PAGES (PEI_CD_BLOCK_SIZE));
+ if (PrivateData->BlockBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PrivateData->CapsuleCount = 0;
+ Status = UpdateBlocksAndVolumes (PrivateData, TRUE);
+ Status = UpdateBlocksAndVolumes (PrivateData, FALSE);
+
+ //
+ // Installs Ppi
+ //
+ PrivateData->DeviceRecoveryPpi.GetNumberRecoveryCapsules = GetNumberRecoveryCapsules;
+ PrivateData->DeviceRecoveryPpi.GetRecoveryCapsuleInfo = GetRecoveryCapsuleInfo;
+ PrivateData->DeviceRecoveryPpi.LoadRecoveryCapsule = LoadRecoveryCapsule;
+
+ PrivateData->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
+ PrivateData->PpiDescriptor.Guid = &gEfiPeiDeviceRecoveryModulePpiGuid;
+ PrivateData->PpiDescriptor.Ppi = &PrivateData->DeviceRecoveryPpi;
+
+ Status = PeiServicesInstallPpi (&PrivateData->PpiDescriptor);
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // PrivateData is allocated now, set it to the module variable
+ //
+ mPrivateData = PrivateData;
+
+ //
+ // Installs Block Io Ppi notification function
+ //
+ PrivateData->NotifyDescriptor.Flags =
+ (
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
+ );
+ PrivateData->NotifyDescriptor.Guid = &gEfiPeiVirtualBlockIoPpiGuid;
+ PrivateData->NotifyDescriptor.Notify = BlockIoNotifyEntry;
+
+ PrivateData->NotifyDescriptor2.Flags =
+ (
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK |
+ EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
+ );
+ PrivateData->NotifyDescriptor2.Guid = &gEfiPeiVirtualBlockIo2PpiGuid;
+ PrivateData->NotifyDescriptor2.Notify = BlockIoNotifyEntry;
+
+ return PeiServicesNotifyPpi (&PrivateData->NotifyDescriptor);
+
+}
+
+/**
+ BlockIo installation notification function.
+
+ This function finds out all the current Block IO PPIs in the system and add them
+ into private data.
+
+ @param PeiServices Indirect reference to the PEI Services Table.
+ @param NotifyDescriptor Address of the notification descriptor data structure.
+ @param Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS The function completes successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+BlockIoNotifyEntry (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ if (CompareGuid (NotifyDescriptor->Guid, &gEfiPeiVirtualBlockIo2PpiGuid)) {
+ UpdateBlocksAndVolumes (mPrivateData, TRUE);
+ } else {
+ UpdateBlocksAndVolumes (mPrivateData, FALSE);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Finds out all the current Block IO PPIs in the system and add them into private data.
+
+ @param PrivateData The private data structure that contains recovery module information.
+ @param BlockIo2 Boolean to show whether using BlockIo2 or BlockIo.
+
+ @retval EFI_SUCCESS The blocks and volumes are updated successfully.
+
+**/
+EFI_STATUS
+UpdateBlocksAndVolumes (
+ IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData,
+ IN BOOLEAN BlockIo2
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_PPI_DESCRIPTOR *TempPpiDescriptor;
+ UINTN BlockIoPpiInstance;
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi;
+ EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi;
+ UINTN NumberBlockDevices;
+ UINTN IndexBlockDevice;
+ EFI_PEI_BLOCK_IO_MEDIA Media;
+ EFI_PEI_BLOCK_IO2_MEDIA Media2;
+ EFI_PEI_SERVICES **PeiServices;
+
+ IndexBlockDevice = 0;
+ BlockIo2Ppi = NULL;
+ BlockIoPpi = NULL;
+ //
+ // Find out all Block Io Ppi instances within the system
+ // Assuming all device Block Io Peims are dispatched already
+ //
+ for (BlockIoPpiInstance = 0; BlockIoPpiInstance < PEI_CD_EXPRESS_MAX_BLOCK_IO_PPI; BlockIoPpiInstance++) {
+ if (BlockIo2) {
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiVirtualBlockIo2PpiGuid,
+ BlockIoPpiInstance,
+ &TempPpiDescriptor,
+ (VOID **) &BlockIo2Ppi
+ );
+ } else {
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiVirtualBlockIoPpiGuid,
+ BlockIoPpiInstance,
+ &TempPpiDescriptor,
+ (VOID **) &BlockIoPpi
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ //
+ // Done with all Block Io Ppis
+ //
+ break;
+ }
+
+ PeiServices = (EFI_PEI_SERVICES **) GetPeiServicesTablePointer ();
+ if (BlockIo2) {
+ Status = BlockIo2Ppi->GetNumberOfBlockDevices (
+ PeiServices,
+ BlockIo2Ppi,
+ &NumberBlockDevices
+ );
+ } else {
+ Status = BlockIoPpi->GetNumberOfBlockDevices (
+ PeiServices,
+ BlockIoPpi,
+ &NumberBlockDevices
+ );
+ }
+ if (EFI_ERROR (Status) || (NumberBlockDevices == 0)) {
+ continue;
+ }
+ //
+ // Just retrieve the first block, should emulate all blocks.
+ //
+ for (IndexBlockDevice = 1; IndexBlockDevice <= NumberBlockDevices && PrivateData->CapsuleCount < PEI_CD_EXPRESS_MAX_CAPSULE_NUMBER; IndexBlockDevice ++) {
+ if (BlockIo2) {
+ Status = BlockIo2Ppi->GetBlockDeviceMediaInfo (
+ PeiServices,
+ BlockIo2Ppi,
+ IndexBlockDevice,
+ &Media2
+ );
+ if (EFI_ERROR (Status) ||
+ !Media2.MediaPresent ||
+ ((Media2.InterfaceType != MSG_ATAPI_DP) && (Media2.InterfaceType != MSG_USB_DP)) ||
+ (Media2.BlockSize != PEI_CD_BLOCK_SIZE)
+ ) {
+ continue;
+ }
+ DEBUG ((EFI_D_INFO, "PeiCdExpress InterfaceType is %d\n", Media2.InterfaceType));
+ DEBUG ((EFI_D_INFO, "PeiCdExpress MediaPresent is %d\n", Media2.MediaPresent));
+ DEBUG ((EFI_D_INFO, "PeiCdExpress BlockSize is 0x%x\n", Media2.BlockSize));
+ } else {
+ Status = BlockIoPpi->GetBlockDeviceMediaInfo (
+ PeiServices,
+ BlockIoPpi,
+ IndexBlockDevice,
+ &Media
+ );
+ if (EFI_ERROR (Status) ||
+ !Media.MediaPresent ||
+ ((Media.DeviceType != IdeCDROM) && (Media.DeviceType != UsbMassStorage)) ||
+ (Media.BlockSize != PEI_CD_BLOCK_SIZE)
+ ) {
+ continue;
+ }
+ DEBUG ((EFI_D_INFO, "PeiCdExpress DeviceType is %d\n", Media.DeviceType));
+ DEBUG ((EFI_D_INFO, "PeiCdExpress MediaPresent is %d\n", Media.MediaPresent));
+ DEBUG ((EFI_D_INFO, "PeiCdExpress BlockSize is 0x%x\n", Media.BlockSize));
+ }
+
+ DEBUG ((EFI_D_INFO, "PeiCdExpress Status is %d\n", Status));
+
+ DEBUG ((EFI_D_INFO, "IndexBlockDevice is %d\n", IndexBlockDevice));
+ PrivateData->CapsuleData[PrivateData->CapsuleCount].IndexBlock = IndexBlockDevice;
+ if (BlockIo2) {
+ PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo2 = BlockIo2Ppi;
+ } else {
+ PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo = BlockIoPpi;
+ }
+ Status = FindRecoveryCapsules (PrivateData);
+ DEBUG ((EFI_D_INFO, "Status is %d\n", Status));
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ PrivateData->CapsuleCount++;
+ }
+
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Finds out the recovery capsule in the current volume.
+
+ @param PrivateData The private data structure that contains recovery module information.
+
+ @retval EFI_SUCCESS The recovery capsule is successfully found in the volume.
+ @retval EFI_NOT_FOUND The recovery capsule is not found in the volume.
+
+**/
+EFI_STATUS
+EFIAPI
+FindRecoveryCapsules (
+ IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData
+ )
+{
+ EFI_STATUS Status;
+ UINTN Lba;
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi;
+ EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi;
+ UINTN BufferSize;
+ UINT8 *Buffer;
+ UINT8 Type;
+ UINT8 *StandardID;
+ UINT32 RootDirLBA;
+ PEI_CD_EXPRESS_DIR_FILE_RECORD *RoorDirRecord;
+ UINTN VolumeSpaceSize;
+ BOOLEAN StartOfVolume;
+ UINTN OriginalLBA;
+ UINTN IndexBlockDevice;
+
+ Buffer = PrivateData->BlockBuffer;
+ BufferSize = PEI_CD_BLOCK_SIZE;
+
+ Lba = 16;
+ //
+ // The volume descriptor starts on Lba 16
+ //
+ IndexBlockDevice = PrivateData->CapsuleData[PrivateData->CapsuleCount].IndexBlock;
+ BlockIoPpi = PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo;
+ BlockIo2Ppi = PrivateData->CapsuleData[PrivateData->CapsuleCount].BlockIo2;
+
+ VolumeSpaceSize = 0;
+ StartOfVolume = TRUE;
+ OriginalLBA = 16;
+
+ while (TRUE) {
+ SetMem (Buffer, BufferSize, 0);
+ if (BlockIo2Ppi != NULL) {
+ Status = BlockIo2Ppi->ReadBlocks (
+ (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
+ BlockIo2Ppi,
+ IndexBlockDevice,
+ Lba,
+ BufferSize,
+ Buffer
+ );
+ } else {
+ Status = BlockIoPpi->ReadBlocks (
+ (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
+ BlockIoPpi,
+ IndexBlockDevice,
+ Lba,
+ BufferSize,
+ Buffer
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ StandardID = (UINT8 *) (Buffer + PEI_CD_EXPRESS_STANDARD_ID_OFFSET);
+ if (!StringCmp (StandardID, (UINT8 *) PEI_CD_STANDARD_ID, PEI_CD_EXPRESS_STANDARD_ID_SIZE, TRUE)) {
+ break;
+ }
+
+ if (StartOfVolume) {
+ OriginalLBA = Lba;
+ StartOfVolume = FALSE;
+ }
+
+ Type = *(UINT8 *) (Buffer + PEI_CD_EXPRESS_VOLUME_TYPE_OFFSET);
+ if (Type == PEI_CD_EXPRESS_VOLUME_TYPE_TERMINATOR) {
+ if (VolumeSpaceSize == 0) {
+ break;
+ } else {
+ Lba = (OriginalLBA + VolumeSpaceSize);
+ VolumeSpaceSize = 0;
+ StartOfVolume = TRUE;
+ continue;
+ }
+ }
+
+ if (Type != PEI_CD_EXPRESS_VOLUME_TYPE_PRIMARY) {
+ Lba++;
+ continue;
+ }
+
+ VolumeSpaceSize = *(UINT32 *) (Buffer + PEI_CD_EXPRESS_VOLUME_SPACE_OFFSET);
+
+ RoorDirRecord = (PEI_CD_EXPRESS_DIR_FILE_RECORD *) (Buffer + PEI_CD_EXPRESS_ROOT_DIR_RECORD_OFFSET);
+ RootDirLBA = RoorDirRecord->LocationOfExtent[0];
+
+ Status = RetrieveCapsuleFileFromRoot (PrivateData, BlockIoPpi, BlockIo2Ppi, IndexBlockDevice, RootDirLBA);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Just look for the first primary descriptor
+ //
+ return EFI_SUCCESS;
+ }
+
+ Lba++;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Retrieves the recovery capsule in root directory of the current volume.
+
+ @param PrivateData The private data structure that contains recovery module information.
+ @param BlockIoPpi The Block IO PPI used to access the volume.
+ @param BlockIo2Ppi The Block IO 2 PPI used to access the volume.
+ @param IndexBlockDevice The index of current block device.
+ @param Lba The starting logic block address to retrieve capsule.
+
+ @retval EFI_SUCCESS The recovery capsule is successfully found in the volume.
+ @retval EFI_NOT_FOUND The recovery capsule is not found in the volume.
+ @retval Others
+
+**/
+EFI_STATUS
+EFIAPI
+RetrieveCapsuleFileFromRoot (
+ IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi,
+ IN UINTN IndexBlockDevice,
+ IN UINT32 Lba
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ UINT8 *Buffer;
+ PEI_CD_EXPRESS_DIR_FILE_RECORD *FileRecord;
+ UINTN Index;
+
+ Buffer = PrivateData->BlockBuffer;
+ BufferSize = PEI_CD_BLOCK_SIZE;
+
+ SetMem (Buffer, BufferSize, 0);
+
+ if (BlockIo2Ppi != NULL) {
+ Status = BlockIo2Ppi->ReadBlocks (
+ (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
+ BlockIo2Ppi,
+ IndexBlockDevice,
+ Lba,
+ BufferSize,
+ Buffer
+ );
+ } else {
+ Status = BlockIoPpi->ReadBlocks (
+ (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
+ BlockIoPpi,
+ IndexBlockDevice,
+ Lba,
+ BufferSize,
+ Buffer
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ while (1) {
+ FileRecord = (PEI_CD_EXPRESS_DIR_FILE_RECORD *) Buffer;
+
+ if (FileRecord->Length == 0) {
+ break;
+ }
+ //
+ // Not intend to check other flag now
+ //
+ if ((FileRecord->Flag & PEI_CD_EXPRESS_DIR_FILE_REC_FLAG_ISDIR) != 0) {
+ Buffer += FileRecord->Length;
+ continue;
+ }
+
+ for (Index = 0; Index < FileRecord->FileIDLength; Index++) {
+ if (FileRecord->FileID[Index] == ';') {
+ break;
+ }
+ }
+
+ if (Index != mRecoveryFileNameSize - 1) {
+ Buffer += FileRecord->Length;
+ continue;
+ }
+
+ if (!StringCmp (FileRecord->FileID, (UINT8 *)mRecoveryFileName, mRecoveryFileNameSize - 1, FALSE)) {
+ Buffer += FileRecord->Length;
+ continue;
+ }
+
+ PrivateData->CapsuleData[PrivateData->CapsuleCount].CapsuleStartLBA = FileRecord->LocationOfExtent[0];
+ PrivateData->CapsuleData[PrivateData->CapsuleCount].CapsuleBlockAlignedSize =
+ (
+ FileRecord->DataLength[0] /
+ PEI_CD_BLOCK_SIZE +
+ 1
+ ) *
+ PEI_CD_BLOCK_SIZE;
+ PrivateData->CapsuleData[PrivateData->CapsuleCount].CapsuleSize = FileRecord->DataLength[0];
+
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Returns the number of DXE capsules residing on the device.
+
+ This function searches for DXE capsules from the associated device and returns
+ the number and maximum size in bytes of the capsules discovered. Entry 1 is
+ assumed to be the highest load priority and entry N is assumed to be the lowest
+ priority.
+
+ @param[in] PeiServices General-purpose services that are available
+ to every PEIM
+ @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
+ instance.
+ @param[out] NumberRecoveryCapsules Pointer to a caller-allocated UINTN. On
+ output, *NumberRecoveryCapsules contains
+ the number of recovery capsule images
+ available for retrieval from this PEIM
+ instance.
+
+ @retval EFI_SUCCESS One or more capsules were discovered.
+ @retval EFI_DEVICE_ERROR A device error occurred.
+ @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
+
+**/
+EFI_STATUS
+EFIAPI
+GetNumberRecoveryCapsules (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,
+ OUT UINTN *NumberRecoveryCapsules
+ )
+{
+ PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData;
+
+ PrivateData = PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This);
+ UpdateBlocksAndVolumes (PrivateData, TRUE);
+ UpdateBlocksAndVolumes (PrivateData, FALSE);
+ *NumberRecoveryCapsules = PrivateData->CapsuleCount;
+
+ if (*NumberRecoveryCapsules == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Returns the size and type of the requested recovery capsule.
+
+ This function gets the size and type of the capsule specified by CapsuleInstance.
+
+ @param[in] PeiServices General-purpose services that are available to every PEIM
+ @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
+ instance.
+ @param[in] CapsuleInstance Specifies for which capsule instance to retrieve
+ the information. This parameter must be between
+ one and the value returned by GetNumberRecoveryCapsules()
+ in NumberRecoveryCapsules.
+ @param[out] Size A pointer to a caller-allocated UINTN in which
+ the size of the requested recovery module is
+ returned.
+ @param[out] CapsuleType A pointer to a caller-allocated EFI_GUID in which
+ the type of the requested recovery capsule is
+ returned. The semantic meaning of the value
+ returned is defined by the implementation.
+
+ @retval EFI_SUCCESS One or more capsules were discovered.
+ @retval EFI_DEVICE_ERROR A device error occurred.
+ @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
+
+**/
+EFI_STATUS
+EFIAPI
+GetRecoveryCapsuleInfo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,
+ IN UINTN CapsuleInstance,
+ OUT UINTN *Size,
+ OUT EFI_GUID *CapsuleType
+ )
+{
+ PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData;
+ UINTN NumberRecoveryCapsules;
+ EFI_STATUS Status;
+
+ Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) {
+ return EFI_NOT_FOUND;
+ }
+
+ PrivateData = PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This);
+
+ *Size = PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleSize;
+ CopyMem (
+ CapsuleType,
+ &gRecoveryOnDataCdGuid,
+ sizeof (EFI_GUID)
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Loads a DXE capsule from some media into memory.
+
+ This function, by whatever mechanism, retrieves a DXE capsule from some device
+ and loads it into memory. Note that the published interface is device neutral.
+
+ @param[in] PeiServices General-purpose services that are available
+ to every PEIM
+ @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
+ instance.
+ @param[in] CapsuleInstance Specifies which capsule instance to retrieve.
+ @param[out] Buffer Specifies a caller-allocated buffer in which
+ the requested recovery capsule will be returned.
+
+ @retval EFI_SUCCESS The capsule was loaded correctly.
+ @retval EFI_DEVICE_ERROR A device error occurred.
+ @retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found.
+
+**/
+EFI_STATUS
+EFIAPI
+LoadRecoveryCapsule (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,
+ IN UINTN CapsuleInstance,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData;
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi;
+ EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi;
+ UINTN NumberRecoveryCapsules;
+
+ Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) {
+ return EFI_NOT_FOUND;
+ }
+
+ PrivateData = PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS (This);
+ BlockIoPpi = PrivateData->CapsuleData[CapsuleInstance - 1].BlockIo;
+ BlockIo2Ppi = PrivateData->CapsuleData[CapsuleInstance - 1].BlockIo2;
+
+ if (BlockIo2Ppi != NULL) {
+ Status = BlockIo2Ppi->ReadBlocks (
+ PeiServices,
+ BlockIo2Ppi,
+ PrivateData->CapsuleData[CapsuleInstance - 1].IndexBlock,
+ PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleStartLBA,
+ PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleBlockAlignedSize,
+ Buffer
+ );
+ } else {
+ Status = BlockIoPpi->ReadBlocks (
+ PeiServices,
+ BlockIoPpi,
+ PrivateData->CapsuleData[CapsuleInstance - 1].IndexBlock,
+ PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleStartLBA,
+ PrivateData->CapsuleData[CapsuleInstance - 1].CapsuleBlockAlignedSize,
+ Buffer
+ );
+ }
+ return Status;
+}
+
+/**
+ This function compares two ASCII strings in case sensitive/insensitive way.
+
+ @param Source1 The first string.
+ @param Source2 The second string.
+ @param Size The maximum comparison length.
+ @param CaseSensitive Flag to indicate whether the comparison is case sensitive.
+
+ @retval TRUE The two strings are the same.
+ @retval FALSE The two string are not the same.
+
+**/
+BOOLEAN
+StringCmp (
+ IN UINT8 *Source1,
+ IN UINT8 *Source2,
+ IN UINTN Size,
+ IN BOOLEAN CaseSensitive
+ )
+{
+ UINTN Index;
+ UINT8 Dif;
+
+ for (Index = 0; Index < Size; Index++) {
+ if (Source1[Index] == Source2[Index]) {
+ continue;
+ }
+
+ if (!CaseSensitive) {
+ Dif = (UINT8) ((Source1[Index] > Source2[Index]) ? (Source1[Index] - Source2[Index]) : (Source2[Index] - Source1[Index]));
+ if (Dif == ('a' - 'A')) {
+ continue;
+ }
+ }
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/CdExpressPei/PeiCdExpress.h b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/CdExpressPei/PeiCdExpress.h
new file mode 100644
index 00000000..ed71fc55
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/CdExpressPei/PeiCdExpress.h
@@ -0,0 +1,292 @@
+/** @file
+ Header file for CD recovery PEIM
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PEI_CD_EXPRESS_H_
+#define _PEI_CD_EXPRESS_H_
+
+
+#include <PiPei.h>
+
+#include <Ppi/BlockIo.h>
+#include <Ppi/BlockIo2.h>
+#include <Guid/RecoveryDevice.h>
+#include <Ppi/DeviceRecoveryModule.h>
+
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+
+#pragma pack(1)
+
+#define PEI_CD_EXPRESS_MAX_BLOCK_IO_PPI 8
+#define PEI_CD_EXPRESS_MAX_CAPSULE_NUMBER 16
+
+#define PEI_CD_BLOCK_SIZE 0x800
+#define PEI_MEMMORY_PAGE_SIZE 0x1000
+
+//
+// Following are defined according to ISO-9660 specification
+//
+#define PEI_CD_STANDARD_ID "CD001"
+#define PEI_CD_EXPRESS_STANDARD_ID_SIZE 5
+
+#define PEI_CD_EXPRESS_VOLUME_TYPE_OFFSET 0
+#define PEI_CD_EXPRESS_STANDARD_ID_OFFSET 1
+#define PEI_CD_EXPRESS_VOLUME_SPACE_OFFSET 80
+#define PEI_CD_EXPRESS_ROOT_DIR_RECORD_OFFSET 156
+
+#define PEI_CD_EXPRESS_VOLUME_TYPE_PRIMARY 1
+#define PEI_CD_EXPRESS_VOLUME_TYPE_TERMINATOR 255
+
+#define PEI_CD_EXPRESS_DIR_FILE_REC_FLAG_ISDIR 0x02
+
+typedef struct {
+ UINTN CapsuleStartLBA;
+ UINTN CapsuleSize;
+ UINTN CapsuleBlockAlignedSize;
+ UINTN IndexBlock;
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIo;
+ EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2;
+} PEI_CD_EXPRESS_CAPSULE_DATA;
+
+#define PEI_CD_EXPRESS_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('p', 'c', 'd', 'e')
+
+typedef struct {
+
+ UINTN Signature;
+ EFI_PEI_DEVICE_RECOVERY_MODULE_PPI DeviceRecoveryPpi;
+ EFI_PEI_PPI_DESCRIPTOR PpiDescriptor;
+ EFI_PEI_NOTIFY_DESCRIPTOR NotifyDescriptor;
+ EFI_PEI_NOTIFY_DESCRIPTOR NotifyDescriptor2;
+
+ UINT8 *BlockBuffer;
+ UINTN CapsuleCount;
+ PEI_CD_EXPRESS_CAPSULE_DATA CapsuleData[PEI_CD_EXPRESS_MAX_CAPSULE_NUMBER];
+
+} PEI_CD_EXPRESS_PRIVATE_DATA;
+
+#define PEI_CD_EXPRESS_PRIVATE_DATA_FROM_THIS(a) \
+ CR (a, \
+ PEI_CD_EXPRESS_PRIVATE_DATA, \
+ DeviceRecoveryPpi, \
+ PEI_CD_EXPRESS_PRIVATE_DATA_SIGNATURE \
+ )
+
+typedef struct {
+ UINT8 Length;
+ UINT8 ExtendedAttributeRecordLength;
+ UINT32 LocationOfExtent[2];
+ UINT32 DataLength[2];
+ UINT8 DateTime[7];
+ UINT8 Flag;
+ UINT8 FileUnitSize;
+ UINT8 InterleaveGapSize;
+ UINT32 VolumeSequenceNumber;
+ UINT8 FileIDLength;
+ UINT8 FileID[1];
+} PEI_CD_EXPRESS_DIR_FILE_RECORD;
+
+/**
+ BlockIo installation notification function.
+
+ This function finds out all the current Block IO PPIs in the system and add them
+ into private data.
+
+ @param PeiServices Indirect reference to the PEI Services Table.
+ @param NotifyDescriptor Address of the notification descriptor data structure.
+ @param Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS The function completes successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+BlockIoNotifyEntry (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ );
+
+/**
+ Finds out all the current Block IO PPIs in the system and add them into private data.
+
+ @param PrivateData The private data structure that contains recovery module information.
+ @param BlockIo2 Boolean to show whether using BlockIo2 or BlockIo.
+
+ @retval EFI_SUCCESS The blocks and volumes are updated successfully.
+
+**/
+EFI_STATUS
+UpdateBlocksAndVolumes (
+ IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData,
+ IN BOOLEAN BlockIo2
+ );
+
+/**
+ Returns the number of DXE capsules residing on the device.
+
+ This function searches for DXE capsules from the associated device and returns
+ the number and maximum size in bytes of the capsules discovered. Entry 1 is
+ assumed to be the highest load priority and entry N is assumed to be the lowest
+ priority.
+
+ @param[in] PeiServices General-purpose services that are available
+ to every PEIM
+ @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
+ instance.
+ @param[out] NumberRecoveryCapsules Pointer to a caller-allocated UINTN. On
+ output, *NumberRecoveryCapsules contains
+ the number of recovery capsule images
+ available for retrieval from this PEIM
+ instance.
+
+ @retval EFI_SUCCESS One or more capsules were discovered.
+ @retval EFI_DEVICE_ERROR A device error occurred.
+ @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
+
+**/
+EFI_STATUS
+EFIAPI
+GetNumberRecoveryCapsules (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,
+ OUT UINTN *NumberRecoveryCapsules
+ );
+
+/**
+ Returns the size and type of the requested recovery capsule.
+
+ This function gets the size and type of the capsule specified by CapsuleInstance.
+
+ @param[in] PeiServices General-purpose services that are available to every PEIM
+ @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
+ instance.
+ @param[in] CapsuleInstance Specifies for which capsule instance to retrieve
+ the information. This parameter must be between
+ one and the value returned by GetNumberRecoveryCapsules()
+ in NumberRecoveryCapsules.
+ @param[out] Size A pointer to a caller-allocated UINTN in which
+ the size of the requested recovery module is
+ returned.
+ @param[out] CapsuleType A pointer to a caller-allocated EFI_GUID in which
+ the type of the requested recovery capsule is
+ returned. The semantic meaning of the value
+ returned is defined by the implementation.
+
+ @retval EFI_SUCCESS One or more capsules were discovered.
+ @retval EFI_DEVICE_ERROR A device error occurred.
+ @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
+
+**/
+EFI_STATUS
+EFIAPI
+GetRecoveryCapsuleInfo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,
+ IN UINTN CapsuleInstance,
+ OUT UINTN *Size,
+ OUT EFI_GUID *CapsuleType
+ );
+
+/**
+ Loads a DXE capsule from some media into memory.
+
+ This function, by whatever mechanism, retrieves a DXE capsule from some device
+ and loads it into memory. Note that the published interface is device neutral.
+
+ @param[in] PeiServices General-purpose services that are available
+ to every PEIM
+ @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
+ instance.
+ @param[in] CapsuleInstance Specifies which capsule instance to retrieve.
+ @param[out] Buffer Specifies a caller-allocated buffer in which
+ the requested recovery capsule will be returned.
+
+ @retval EFI_SUCCESS The capsule was loaded correctly.
+ @retval EFI_DEVICE_ERROR A device error occurred.
+ @retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found.
+
+**/
+EFI_STATUS
+EFIAPI
+LoadRecoveryCapsule (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,
+ IN UINTN CapsuleInstance,
+ OUT VOID *Buffer
+ );
+
+/**
+ Finds out the recovery capsule in the current volume.
+
+ @param PrivateData The private data structure that contains recovery module information.
+
+ @retval EFI_SUCCESS The recovery capsule is successfully found in the volume.
+ @retval EFI_NOT_FOUND The recovery capsule is not found in the volume.
+
+**/
+EFI_STATUS
+EFIAPI
+FindRecoveryCapsules (
+ IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData
+ );
+
+/**
+ Retrieves the recovery capsule in root directory of the current volume.
+
+ @param PrivateData The private data structure that contains recovery module information.
+ @param BlockIoPpi The Block IO PPI used to access the volume.
+ @param BlockIo2Ppi The Block IO 2 PPI used to access the volume.
+ @param IndexBlockDevice The index of current block device.
+ @param Lba The starting logic block address to retrieve capsule.
+
+ @retval EFI_SUCCESS The recovery capsule is successfully found in the volume.
+ @retval EFI_NOT_FOUND The recovery capsule is not found in the volume.
+ @retval Others
+
+**/
+EFI_STATUS
+EFIAPI
+RetrieveCapsuleFileFromRoot (
+ IN OUT PEI_CD_EXPRESS_PRIVATE_DATA *PrivateData,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi,
+ IN EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi,
+ IN UINTN IndexBlockDevice,
+ IN UINT32 Lba
+ );
+
+
+/**
+ This function compares two ASCII strings in case sensitive/insensitive way.
+
+ @param Source1 The first string.
+ @param Source2 The second string.
+ @param Size The maximum comparison length.
+ @param CaseSensitive Flag to indicate whether the comparison is case sensitive.
+
+ @retval TRUE The two strings are the same.
+ @retval FALSE The two string are not the same.
+
+**/
+BOOLEAN
+StringCmp (
+ IN UINT8 *Source1,
+ IN UINT8 *Source2,
+ IN UINTN Size,
+ IN BOOLEAN CaseSensitive
+ );
+
+#pragma pack()
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/ComponentName.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/ComponentName.c
new file mode 100644
index 00000000..b17b4a9c
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/ComponentName.c
@@ -0,0 +1,183 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for DiskIo driver.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DiskIo.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gDiskIoComponentName = {
+ DiskIoComponentNameGetDriverName,
+ DiskIoComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gDiskIoComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) DiskIoComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) DiskIoComponentNameGetControllerName,
+ "en"
+};
+
+//
+// Driver name table for DiskIo module.
+// It is shared by the implementation of ComponentName & ComponentName2 Protocol.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mDiskIoDriverNameTable[] = {
+ {
+ "eng;en",
+ (CHAR16 *)L"Generic Disk I/O Driver"
+ },
+ {
+ 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
+DiskIoComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mDiskIoDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gDiskIoComponentName)
+ );
+}
+
+
+
+/**
+ 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 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.
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIoComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c
new file mode 100644
index 00000000..311b9b64
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c
@@ -0,0 +1,1262 @@
+/** @file
+ DiskIo driver that lays on every BlockIo protocol in the system.
+ DiskIo converts a block oriented device to a byte oriented device.
+
+ Disk access may have to handle unaligned request about sector boundaries.
+ There are three cases:
+ UnderRun - The first byte is not on a sector boundary or the read request is
+ less than a sector in length.
+ Aligned - A read of N contiguous sectors.
+ OverRun - The last byte is not on a sector boundary.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "DiskIo.h"
+
+//
+// Driver binding protocol implementation for DiskIo driver.
+//
+EFI_DRIVER_BINDING_PROTOCOL gDiskIoDriverBinding = {
+ DiskIoDriverBindingSupported,
+ DiskIoDriverBindingStart,
+ DiskIoDriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+//
+// Template for DiskIo private data structure.
+// The pointer to BlockIo protocol interface is assigned dynamically.
+//
+DISK_IO_PRIVATE_DATA gDiskIoPrivateDataTemplate = {
+ DISK_IO_PRIVATE_DATA_SIGNATURE,
+ {
+ EFI_DISK_IO_PROTOCOL_REVISION,
+ DiskIoReadDisk,
+ DiskIoWriteDisk
+ },
+ {
+ EFI_DISK_IO2_PROTOCOL_REVISION,
+ DiskIo2Cancel,
+ DiskIo2ReadDiskEx,
+ DiskIo2WriteDiskEx,
+ DiskIo2FlushDiskEx
+ }
+};
+
+/**
+ Test to see if this driver supports ControllerHandle.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to test
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver supports this device
+ @retval EFI_ALREADY_STARTED This driver is already running on this device
+ @retval other This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIoDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test.
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test.
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Start this driver on ControllerHandle by opening a Block IO protocol and
+ installing a Disk IO protocol on ControllerHandle.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to bind driver to
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver is added to ControllerHandle
+ @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
+ @retval other This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIoDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ DISK_IO_PRIVATE_DATA *Instance;
+ EFI_TPL OldTpl;
+
+ Instance = NULL;
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // Connect to the Block IO and Block IO2 interface on ControllerHandle.
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &gDiskIoPrivateDataTemplate.BlockIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit1;
+ }
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiBlockIo2ProtocolGuid,
+ (VOID **) &gDiskIoPrivateDataTemplate.BlockIo2,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ gDiskIoPrivateDataTemplate.BlockIo2 = NULL;
+ }
+
+ //
+ // Initialize the Disk IO device instance.
+ //
+ Instance = AllocateCopyPool (sizeof (DISK_IO_PRIVATE_DATA), &gDiskIoPrivateDataTemplate);
+ if (Instance == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ //
+ // The BlockSize and IoAlign of BlockIo and BlockIo2 should equal.
+ //
+ ASSERT ((Instance->BlockIo2 == NULL) ||
+ ((Instance->BlockIo->Media->IoAlign == Instance->BlockIo2->Media->IoAlign) &&
+ (Instance->BlockIo->Media->BlockSize == Instance->BlockIo2->Media->BlockSize)
+ ));
+
+ InitializeListHead (&Instance->TaskQueue);
+ EfiInitializeLock (&Instance->TaskQueueLock, TPL_NOTIFY);
+ Instance->SharedWorkingBuffer = AllocateAlignedPages (
+ EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum) * Instance->BlockIo->Media->BlockSize),
+ Instance->BlockIo->Media->IoAlign
+ );
+ if (Instance->SharedWorkingBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ //
+ // Install protocol interfaces for the Disk IO device.
+ //
+ if (Instance->BlockIo2 != NULL) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ControllerHandle,
+ &gEfiDiskIoProtocolGuid, &Instance->DiskIo,
+ &gEfiDiskIo2ProtocolGuid, &Instance->DiskIo2,
+ NULL
+ );
+ } else {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ControllerHandle,
+ &gEfiDiskIoProtocolGuid, &Instance->DiskIo,
+ NULL
+ );
+ }
+
+ErrorExit:
+ if (EFI_ERROR (Status)) {
+ if (Instance != NULL && Instance->SharedWorkingBuffer != NULL) {
+ FreeAlignedPages (
+ Instance->SharedWorkingBuffer,
+ EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum) * Instance->BlockIo->Media->BlockSize)
+ );
+ }
+
+ if (Instance != NULL) {
+ FreePool (Instance);
+ }
+
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ }
+
+ErrorExit1:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ Stop this driver on ControllerHandle by removing Disk IO protocol and closing
+ the Block IO protocol on ControllerHandle.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to stop driver on
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCESS This driver is removed ControllerHandle
+ @retval other This driver was not removed from this device
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIoDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ EFI_DISK_IO2_PROTOCOL *DiskIo2;
+ DISK_IO_PRIVATE_DATA *Instance;
+ BOOLEAN AllTaskDone;
+
+ //
+ // Get our context back.
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ (VOID **) &DiskIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDiskIo2ProtocolGuid,
+ (VOID **) &DiskIo2,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ DiskIo2 = NULL;
+ }
+
+ Instance = DISK_IO_PRIVATE_DATA_FROM_DISK_IO (DiskIo);
+
+ if (DiskIo2 != NULL) {
+ //
+ // Call BlockIo2::Reset() to terminate any in-flight non-blocking I/O requests
+ //
+ ASSERT (Instance->BlockIo2 != NULL);
+ Status = Instance->BlockIo2->Reset (Instance->BlockIo2, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid, &Instance->DiskIo,
+ &gEfiDiskIo2ProtocolGuid, &Instance->DiskIo2,
+ NULL
+ );
+ } else {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid, &Instance->DiskIo,
+ NULL
+ );
+ }
+ if (!EFI_ERROR (Status)) {
+
+ do {
+ EfiAcquireLock (&Instance->TaskQueueLock);
+ AllTaskDone = IsListEmpty (&Instance->TaskQueue);
+ EfiReleaseLock (&Instance->TaskQueueLock);
+ } while (!AllTaskDone);
+
+ FreeAlignedPages (
+ Instance->SharedWorkingBuffer,
+ EFI_SIZE_TO_PAGES (PcdGet32 (PcdDiskIoDataBufferBlockNum) * Instance->BlockIo->Media->BlockSize)
+ );
+
+ Status = gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (DiskIo2 != NULL) {
+ Status = gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiBlockIo2ProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ FreePool (Instance);
+ }
+
+ return Status;
+}
+
+
+/**
+ Destroy the sub task.
+
+ @param Instance Pointer to the DISK_IO_PRIVATE_DATA.
+ @param Subtask Subtask.
+
+ @return LIST_ENTRY * Pointer to the next link of subtask.
+**/
+LIST_ENTRY *
+DiskIoDestroySubtask (
+ IN DISK_IO_PRIVATE_DATA *Instance,
+ IN DISK_IO_SUBTASK *Subtask
+ )
+{
+ LIST_ENTRY *Link;
+
+ if (Subtask->Task != NULL) {
+ EfiAcquireLock (&Subtask->Task->SubtasksLock);
+ }
+ Link = RemoveEntryList (&Subtask->Link);
+ if (Subtask->Task != NULL) {
+ EfiReleaseLock (&Subtask->Task->SubtasksLock);
+ }
+
+ if (!Subtask->Blocking) {
+ if (Subtask->WorkingBuffer != NULL) {
+ FreeAlignedPages (
+ Subtask->WorkingBuffer,
+ Subtask->Length < Instance->BlockIo->Media->BlockSize
+ ? EFI_SIZE_TO_PAGES (Instance->BlockIo->Media->BlockSize)
+ : EFI_SIZE_TO_PAGES (Subtask->Length)
+ );
+ }
+ if (Subtask->BlockIo2Token.Event != NULL) {
+ gBS->CloseEvent (Subtask->BlockIo2Token.Event);
+ }
+ }
+ FreePool (Subtask);
+
+ return Link;
+}
+
+/**
+ The callback for the BlockIo2 ReadBlocksEx/WriteBlocksEx.
+ @param Event Event whose notification function is being invoked.
+ @param Context The pointer to the notification function's context,
+ which points to the DISK_IO_SUBTASK instance.
+**/
+VOID
+EFIAPI
+DiskIo2OnReadWriteComplete (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ DISK_IO_SUBTASK *Subtask;
+ DISK_IO2_TASK *Task;
+ EFI_STATUS TransactionStatus;
+ DISK_IO_PRIVATE_DATA *Instance;
+
+ Subtask = (DISK_IO_SUBTASK *) Context;
+ TransactionStatus = Subtask->BlockIo2Token.TransactionStatus;
+ Task = Subtask->Task;
+ Instance = Task->Instance;
+
+ ASSERT (Subtask->Signature == DISK_IO_SUBTASK_SIGNATURE);
+ ASSERT (Instance->Signature == DISK_IO_PRIVATE_DATA_SIGNATURE);
+ ASSERT (Task->Signature == DISK_IO2_TASK_SIGNATURE);
+
+ if ((Subtask->WorkingBuffer != NULL) && !EFI_ERROR (TransactionStatus) &&
+ (Task->Token != NULL) && !Subtask->Write
+ ) {
+ CopyMem (Subtask->Buffer, Subtask->WorkingBuffer + Subtask->Offset, Subtask->Length);
+ }
+
+ DiskIoDestroySubtask (Instance, Subtask);
+
+ if (EFI_ERROR (TransactionStatus) || IsListEmpty (&Task->Subtasks)) {
+ if (Task->Token != NULL) {
+ //
+ // Signal error status once the subtask is failed.
+ // Or signal the last status once the last subtask is finished.
+ //
+ Task->Token->TransactionStatus = TransactionStatus;
+ gBS->SignalEvent (Task->Token->Event);
+
+ //
+ // Mark token to NULL indicating the Task is a dead task.
+ //
+ Task->Token = NULL;
+ }
+ }
+}
+
+/**
+ Create the subtask.
+
+ @param Write TRUE: Write request; FALSE: Read request.
+ @param Lba The starting logical block address to read from on the device.
+ @param Offset The starting byte offset to read from the LBA.
+ @param Length The number of bytes to read from the device.
+ @param WorkingBuffer The aligned buffer to hold the data for reading or writing.
+ @param Buffer The buffer to hold the data for reading or writing.
+ @param Blocking TRUE: Blocking request; FALSE: Non-blocking request.
+
+ @return A pointer to the created subtask.
+**/
+DISK_IO_SUBTASK *
+DiskIoCreateSubtask (
+ IN BOOLEAN Write,
+ IN UINT64 Lba,
+ IN UINT32 Offset,
+ IN UINTN Length,
+ IN VOID *WorkingBuffer, OPTIONAL
+ IN VOID *Buffer,
+ IN BOOLEAN Blocking
+ )
+{
+ DISK_IO_SUBTASK *Subtask;
+ EFI_STATUS Status;
+
+ Subtask = AllocateZeroPool (sizeof (DISK_IO_SUBTASK));
+ if (Subtask == NULL) {
+ return NULL;
+ }
+ Subtask->Signature = DISK_IO_SUBTASK_SIGNATURE;
+ Subtask->Write = Write;
+ Subtask->Lba = Lba;
+ Subtask->Offset = Offset;
+ Subtask->Length = Length;
+ Subtask->WorkingBuffer = WorkingBuffer;
+ Subtask->Buffer = Buffer;
+ Subtask->Blocking = Blocking;
+ if (!Blocking) {
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ DiskIo2OnReadWriteComplete,
+ Subtask,
+ &Subtask->BlockIo2Token.Event
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Subtask);
+ return NULL;
+ }
+ }
+ DEBUG ((
+ EFI_D_BLKIO,
+ " %c:Lba/Offset/Length/WorkingBuffer/Buffer = %016lx/%08x/%08x/%08x/%08x\n",
+ Write ? 'W': 'R', Lba, Offset, Length, WorkingBuffer, Buffer
+ ));
+
+ return Subtask;
+}
+
+/**
+ Create the subtask list.
+
+ @param Instance Pointer to the DISK_IO_PRIVATE_DATA.
+ @param Write TRUE: Write request; FALSE: Read request.
+ @param Offset The starting byte offset to read from the device.
+ @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.
+ @param Buffer A pointer to the buffer for the data.
+ @param Blocking TRUE: Blocking request; FALSE: Non-blocking request.
+ @param SharedWorkingBuffer The aligned buffer to hold the data for reading or writing.
+ @param Subtasks The subtask list header.
+
+ @retval TRUE The subtask list is created successfully.
+ @retval FALSE The subtask list is not created.
+**/
+BOOLEAN
+DiskIoCreateSubtaskList (
+ IN DISK_IO_PRIVATE_DATA *Instance,
+ IN BOOLEAN Write,
+ IN UINT64 Offset,
+ IN UINTN BufferSize,
+ IN VOID *Buffer,
+ IN BOOLEAN Blocking,
+ IN VOID *SharedWorkingBuffer,
+ IN OUT LIST_ENTRY *Subtasks
+ )
+{
+ UINT32 BlockSize;
+ UINT32 IoAlign;
+ UINT64 Lba;
+ UINT64 OverRunLba;
+ UINT32 UnderRun;
+ UINT32 OverRun;
+ UINT8 *BufferPtr;
+ UINTN Length;
+ UINTN DataBufferSize;
+ DISK_IO_SUBTASK *Subtask;
+ VOID *WorkingBuffer;
+ LIST_ENTRY *Link;
+
+ DEBUG ((EFI_D_BLKIO, "DiskIo: Create subtasks for task: Offset/BufferSize/Buffer = %016lx/%08x/%08x\n", Offset, BufferSize, Buffer));
+
+ BlockSize = Instance->BlockIo->Media->BlockSize;
+ IoAlign = Instance->BlockIo->Media->IoAlign;
+ if (IoAlign == 0) {
+ IoAlign = 1;
+ }
+
+ Lba = DivU64x32Remainder (Offset, BlockSize, &UnderRun);
+ BufferPtr = (UINT8 *) Buffer;
+
+ //
+ // Special handling for zero BufferSize
+ //
+ if (BufferSize == 0) {
+ Subtask = DiskIoCreateSubtask (Write, Lba, UnderRun, 0, NULL, BufferPtr, Blocking);
+ if (Subtask == NULL) {
+ goto Done;
+ }
+ InsertTailList (Subtasks, &Subtask->Link);
+ return TRUE;
+ }
+
+ if (UnderRun != 0) {
+ Length = MIN (BlockSize - UnderRun, BufferSize);
+ if (Blocking) {
+ WorkingBuffer = SharedWorkingBuffer;
+ } else {
+ WorkingBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BlockSize), IoAlign);
+ if (WorkingBuffer == NULL) {
+ goto Done;
+ }
+ }
+ if (Write) {
+ //
+ // A half write operation can be splitted to a blocking block-read and half write operation
+ // This can simplify the sub task processing logic
+ //
+ Subtask = DiskIoCreateSubtask (FALSE, Lba, 0, BlockSize, NULL, WorkingBuffer, TRUE);
+ if (Subtask == NULL) {
+ goto Done;
+ }
+ InsertTailList (Subtasks, &Subtask->Link);
+ }
+
+ Subtask = DiskIoCreateSubtask (Write, Lba, UnderRun, Length, WorkingBuffer, BufferPtr, Blocking);
+ if (Subtask == NULL) {
+ goto Done;
+ }
+ InsertTailList (Subtasks, &Subtask->Link);
+
+ BufferPtr += Length;
+ Offset += Length;
+ BufferSize -= Length;
+ Lba ++;
+ }
+
+ OverRunLba = Lba + DivU64x32Remainder (BufferSize, BlockSize, &OverRun);
+ BufferSize -= OverRun;
+
+ if (OverRun != 0) {
+ if (Blocking) {
+ WorkingBuffer = SharedWorkingBuffer;
+ } else {
+ WorkingBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BlockSize), IoAlign);
+ if (WorkingBuffer == NULL) {
+ goto Done;
+ }
+ }
+ if (Write) {
+ //
+ // A half write operation can be splitted to a blocking block-read and half write operation
+ // This can simplify the sub task processing logic
+ //
+ Subtask = DiskIoCreateSubtask (FALSE, OverRunLba, 0, BlockSize, NULL, WorkingBuffer, TRUE);
+ if (Subtask == NULL) {
+ goto Done;
+ }
+ InsertTailList (Subtasks, &Subtask->Link);
+ }
+
+ Subtask = DiskIoCreateSubtask (Write, OverRunLba, 0, OverRun, WorkingBuffer, BufferPtr + BufferSize, Blocking);
+ if (Subtask == NULL) {
+ goto Done;
+ }
+ InsertTailList (Subtasks, &Subtask->Link);
+ }
+
+ if (OverRunLba > Lba) {
+ //
+ // If the DiskIo maps directly to a BlockIo device do the read.
+ //
+ if (ALIGN_POINTER (BufferPtr, IoAlign) == BufferPtr) {
+ Subtask = DiskIoCreateSubtask (Write, Lba, 0, BufferSize, NULL, BufferPtr, Blocking);
+ if (Subtask == NULL) {
+ goto Done;
+ }
+ InsertTailList (Subtasks, &Subtask->Link);
+
+ BufferPtr += BufferSize;
+ Offset += BufferSize;
+ BufferSize -= BufferSize;
+
+ } else {
+ if (Blocking) {
+ //
+ // Use the allocated buffer instead of the original buffer
+ // to avoid alignment issue.
+ //
+ for (; Lba < OverRunLba; Lba += PcdGet32 (PcdDiskIoDataBufferBlockNum)) {
+ DataBufferSize = MIN (BufferSize, PcdGet32 (PcdDiskIoDataBufferBlockNum) * BlockSize);
+
+ Subtask = DiskIoCreateSubtask (Write, Lba, 0, DataBufferSize, SharedWorkingBuffer, BufferPtr, Blocking);
+ if (Subtask == NULL) {
+ goto Done;
+ }
+ InsertTailList (Subtasks, &Subtask->Link);
+
+ BufferPtr += DataBufferSize;
+ Offset += DataBufferSize;
+ BufferSize -= DataBufferSize;
+ }
+ } else {
+ WorkingBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), IoAlign);
+ if (WorkingBuffer == NULL) {
+ //
+ // If there is not enough memory, downgrade to blocking access
+ //
+ DEBUG ((EFI_D_VERBOSE, "DiskIo: No enough memory so downgrade to blocking access\n"));
+ if (!DiskIoCreateSubtaskList (Instance, Write, Offset, BufferSize, BufferPtr, TRUE, SharedWorkingBuffer, Subtasks)) {
+ goto Done;
+ }
+ } else {
+ Subtask = DiskIoCreateSubtask (Write, Lba, 0, BufferSize, WorkingBuffer, BufferPtr, Blocking);
+ if (Subtask == NULL) {
+ goto Done;
+ }
+ InsertTailList (Subtasks, &Subtask->Link);
+ }
+
+ BufferPtr += BufferSize;
+ Offset += BufferSize;
+ BufferSize -= BufferSize;
+ }
+ }
+ }
+
+ ASSERT (BufferSize == 0);
+
+ return TRUE;
+
+Done:
+ //
+ // Remove all the subtasks.
+ //
+ for (Link = GetFirstNode (Subtasks); !IsNull (Subtasks, Link); ) {
+ Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
+ Link = DiskIoDestroySubtask (Instance, Subtask);
+ }
+ return FALSE;
+}
+
+/**
+ Terminate outstanding asynchronous requests to a device.
+
+ @param This Indicates a pointer to the calling context.
+
+ @retval EFI_SUCCESS All outstanding requests were successfully terminated.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the cancel
+ operation.
+**/
+EFI_STATUS
+EFIAPI
+DiskIo2Cancel (
+ IN EFI_DISK_IO2_PROTOCOL *This
+ )
+{
+ DISK_IO_PRIVATE_DATA *Instance;
+ DISK_IO2_TASK *Task;
+ LIST_ENTRY *Link;
+
+ Instance = DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This);
+
+ EfiAcquireLock (&Instance->TaskQueueLock);
+
+ for (Link = GetFirstNode (&Instance->TaskQueue)
+ ; !IsNull (&Instance->TaskQueue, Link)
+ ; Link = GetNextNode (&Instance->TaskQueue, Link)
+ ) {
+ Task = CR (Link, DISK_IO2_TASK, Link, DISK_IO2_TASK_SIGNATURE);
+
+ if (Task->Token != NULL) {
+ Task->Token->TransactionStatus = EFI_ABORTED;
+ gBS->SignalEvent (Task->Token->Event);
+ //
+ // Set Token to NULL so that the further BlockIo2 responses will be ignored
+ //
+ Task->Token = NULL;
+ }
+ }
+
+ EfiReleaseLock (&Instance->TaskQueueLock);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Remove the completed tasks from Instance->TaskQueue. Completed tasks are those who don't have any subtasks.
+
+ @param Instance Pointer to the DISK_IO_PRIVATE_DATA.
+
+ @retval TRUE The Instance->TaskQueue is empty after the completed tasks are removed.
+ @retval FALSE The Instance->TaskQueue is not empty after the completed tasks are removed.
+**/
+BOOLEAN
+DiskIo2RemoveCompletedTask (
+ IN DISK_IO_PRIVATE_DATA *Instance
+ )
+{
+ BOOLEAN QueueEmpty;
+ LIST_ENTRY *Link;
+ DISK_IO2_TASK *Task;
+
+ QueueEmpty = TRUE;
+
+ EfiAcquireLock (&Instance->TaskQueueLock);
+ for (Link = GetFirstNode (&Instance->TaskQueue); !IsNull (&Instance->TaskQueue, Link); ) {
+ Task = CR (Link, DISK_IO2_TASK, Link, DISK_IO2_TASK_SIGNATURE);
+ if (IsListEmpty (&Task->Subtasks)) {
+ Link = RemoveEntryList (&Task->Link);
+ ASSERT (Task->Token == NULL);
+ FreePool (Task);
+ } else {
+ Link = GetNextNode (&Instance->TaskQueue, Link);
+ QueueEmpty = FALSE;
+ }
+ }
+ EfiReleaseLock (&Instance->TaskQueueLock);
+
+ return QueueEmpty;
+}
+
+/**
+ Common routine to access the disk.
+
+ @param Instance Pointer to the DISK_IO_PRIVATE_DATA.
+ @param Write TRUE: Write operation; FALSE: Read operation.
+ @param MediaId ID of the medium to access.
+ @param Offset The starting byte offset on the logical block I/O device to access.
+ @param Token A pointer to the token associated with the transaction.
+ If this field is NULL, synchronous/blocking IO is performed.
+ @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.
+ @param Buffer A pointer to the destination buffer for the data.
+ The caller is responsible either having implicit or explicit ownership of the buffer.
+**/
+EFI_STATUS
+DiskIo2ReadWriteDisk (
+ IN DISK_IO_PRIVATE_DATA *Instance,
+ IN BOOLEAN Write,
+ IN UINT32 MediaId,
+ IN UINT64 Offset,
+ IN EFI_DISK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN UINT8 *Buffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
+ EFI_BLOCK_IO_MEDIA *Media;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NextLink;
+ LIST_ENTRY Subtasks;
+ DISK_IO_SUBTASK *Subtask;
+ DISK_IO2_TASK *Task;
+ EFI_TPL OldTpl;
+ BOOLEAN Blocking;
+ BOOLEAN SubtaskBlocking;
+ LIST_ENTRY *SubtasksPtr;
+
+ Task = NULL;
+ BlockIo = Instance->BlockIo;
+ BlockIo2 = Instance->BlockIo2;
+ Media = BlockIo->Media;
+ Status = EFI_SUCCESS;
+ Blocking = (BOOLEAN) ((Token == NULL) || (Token->Event == NULL));
+
+ if (Blocking) {
+ //
+ // Wait till pending async task is completed.
+ //
+ while (!DiskIo2RemoveCompletedTask (Instance));
+
+ SubtasksPtr = &Subtasks;
+ } else {
+ DiskIo2RemoveCompletedTask (Instance);
+ Task = AllocatePool (sizeof (DISK_IO2_TASK));
+ if (Task == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ EfiAcquireLock (&Instance->TaskQueueLock);
+ InsertTailList (&Instance->TaskQueue, &Task->Link);
+ EfiReleaseLock (&Instance->TaskQueueLock);
+
+ Task->Signature = DISK_IO2_TASK_SIGNATURE;
+ Task->Instance = Instance;
+ Task->Token = Token;
+ EfiInitializeLock (&Task->SubtasksLock, TPL_NOTIFY);
+
+ SubtasksPtr = &Task->Subtasks;
+ }
+
+ InitializeListHead (SubtasksPtr);
+ if (!DiskIoCreateSubtaskList (Instance, Write, Offset, BufferSize, Buffer, Blocking, Instance->SharedWorkingBuffer, SubtasksPtr)) {
+ if (Task != NULL) {
+ FreePool (Task);
+ }
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ASSERT (!IsListEmpty (SubtasksPtr));
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ for ( Link = GetFirstNode (SubtasksPtr), NextLink = GetNextNode (SubtasksPtr, Link)
+ ; !IsNull (SubtasksPtr, Link)
+ ; Link = NextLink, NextLink = GetNextNode (SubtasksPtr, NextLink)
+ ) {
+ Subtask = CR (Link, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
+ Subtask->Task = Task;
+ SubtaskBlocking = Subtask->Blocking;
+
+ ASSERT ((Subtask->Length % Media->BlockSize == 0) || (Subtask->Length < Media->BlockSize));
+
+ if (Subtask->Write) {
+ //
+ // Write
+ //
+ if (Subtask->WorkingBuffer != NULL) {
+ //
+ // A sub task before this one should be a block read operation, causing the WorkingBuffer filled with the entire one block data.
+ //
+ CopyMem (Subtask->WorkingBuffer + Subtask->Offset, Subtask->Buffer, Subtask->Length);
+ }
+
+ if (SubtaskBlocking) {
+ Status = BlockIo->WriteBlocks (
+ BlockIo,
+ MediaId,
+ Subtask->Lba,
+ (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
+ (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
+ );
+ } else {
+ Status = BlockIo2->WriteBlocksEx (
+ BlockIo2,
+ MediaId,
+ Subtask->Lba,
+ &Subtask->BlockIo2Token,
+ (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
+ (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
+ );
+ }
+
+ } else {
+ //
+ // Read
+ //
+ if (SubtaskBlocking) {
+ Status = BlockIo->ReadBlocks (
+ BlockIo,
+ MediaId,
+ Subtask->Lba,
+ (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
+ (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
+ );
+ if (!EFI_ERROR (Status) && (Subtask->WorkingBuffer != NULL)) {
+ CopyMem (Subtask->Buffer, Subtask->WorkingBuffer + Subtask->Offset, Subtask->Length);
+ }
+ } else {
+ Status = BlockIo2->ReadBlocksEx (
+ BlockIo2,
+ MediaId,
+ Subtask->Lba,
+ &Subtask->BlockIo2Token,
+ (Subtask->Length % Media->BlockSize == 0) ? Subtask->Length : Media->BlockSize,
+ (Subtask->WorkingBuffer != NULL) ? Subtask->WorkingBuffer : Subtask->Buffer
+ );
+ }
+ }
+
+ if (SubtaskBlocking || EFI_ERROR (Status)) {
+ //
+ // Make sure the subtask list only contains non-blocking subtasks.
+ // Remove failed non-blocking subtasks as well because the callback won't be called.
+ //
+ DiskIoDestroySubtask (Instance, Subtask);
+ }
+
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ gBS->RaiseTPL (TPL_NOTIFY);
+
+ //
+ // Remove all the remaining subtasks when failure.
+ // We shouldn't remove all the tasks because the non-blocking requests have been submitted and cannot be canceled.
+ //
+ if (EFI_ERROR (Status)) {
+ while (!IsNull (SubtasksPtr, NextLink)) {
+ Subtask = CR (NextLink, DISK_IO_SUBTASK, Link, DISK_IO_SUBTASK_SIGNATURE);
+ NextLink = DiskIoDestroySubtask (Instance, Subtask);
+ }
+ }
+
+ //
+ // It's possible that the non-blocking subtasks finish before raising TPL to NOTIFY,
+ // so the subtasks list might be empty at this point.
+ //
+ if (!Blocking && IsListEmpty (SubtasksPtr)) {
+ EfiAcquireLock (&Instance->TaskQueueLock);
+ RemoveEntryList (&Task->Link);
+ EfiReleaseLock (&Instance->TaskQueueLock);
+
+ if (!EFI_ERROR (Status) && (Task->Token != NULL)) {
+ //
+ // Task->Token should be set to NULL by the DiskIo2OnReadWriteComplete
+ // It it's not, that means the non-blocking request was downgraded to blocking request.
+ //
+ DEBUG ((EFI_D_VERBOSE, "DiskIo: Non-blocking request was downgraded to blocking request, signal event directly.\n"));
+ Task->Token->TransactionStatus = Status;
+ gBS->SignalEvent (Task->Token->Event);
+ }
+
+ FreePool (Task);
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+/**
+ Reads a specified number of bytes from a device.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to be read.
+ @param Offset The starting byte offset on the logical block I/O device to read from.
+ @param Token A pointer to the token associated with the transaction.
+ If this field is NULL, synchronous/blocking IO is performed.
+ @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.
+ @param Buffer A pointer to the destination buffer for the data.
+ The caller is responsible either having implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was read correctly from the device.
+ If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
+ Event will be signaled upon completion.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_NO_MEDIA There is no medium in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId is not for the current medium.
+ @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not valid for the device.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIo2ReadDiskEx (
+ IN EFI_DISK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Offset,
+ IN OUT EFI_DISK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ return DiskIo2ReadWriteDisk (
+ DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This),
+ FALSE, MediaId, Offset, Token, BufferSize, (UINT8 *) Buffer
+ );
+}
+
+/**
+ Writes a specified number of bytes to a device.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to be written.
+ @param Offset The starting byte offset on the logical block I/O device to write to.
+ @param Token A pointer to the token associated with the transaction.
+ If this field is NULL, synchronous/blocking IO is performed.
+ @param BufferSize The size in bytes of Buffer. The number of bytes to write to the device.
+ @param Buffer A pointer to the buffer containing the data to be written.
+
+ @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was written correctly to the device.
+ If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
+ Event will be signaled upon completion.
+ @retval EFI_WRITE_PROTECTED The device cannot be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write operation.
+ @retval EFI_NO_MEDIA There is no medium in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId is not for the current medium.
+ @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not valid for the device.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIo2WriteDiskEx (
+ IN EFI_DISK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Offset,
+ IN OUT EFI_DISK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ return DiskIo2ReadWriteDisk (
+ DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This),
+ TRUE, MediaId, Offset, Token, BufferSize, (UINT8 *) Buffer
+ );
+}
+
+/**
+ The callback for the BlockIo2 FlushBlocksEx.
+ @param Event Event whose notification function is being invoked.
+ @param Context The pointer to the notification function's context,
+ which points to the DISK_IO2_FLUSH_TASK instance.
+**/
+VOID
+EFIAPI
+DiskIo2OnFlushComplete (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ DISK_IO2_FLUSH_TASK *Task;
+
+ gBS->CloseEvent (Event);
+
+ Task = (DISK_IO2_FLUSH_TASK *) Context;
+ ASSERT (Task->Signature == DISK_IO2_FLUSH_TASK_SIGNATURE);
+ Task->Token->TransactionStatus = Task->BlockIo2Token.TransactionStatus;
+ gBS->SignalEvent (Task->Token->Event);
+
+ FreePool (Task);
+}
+
+/**
+ Flushes all modified data to the physical device.
+
+ @param This Indicates a pointer to the calling context.
+ @param Token A pointer to the token associated with the transaction.
+ If this field is NULL, synchronous/blocking IO is performed.
+
+ @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was flushed successfully to the device.
+ If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
+ Event will be signaled upon completion.
+ @retval EFI_WRITE_PROTECTED The device cannot be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write operation.
+ @retval EFI_NO_MEDIA There is no medium in the device.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+DiskIo2FlushDiskEx (
+ IN EFI_DISK_IO2_PROTOCOL *This,
+ IN OUT EFI_DISK_IO2_TOKEN *Token
+ )
+{
+ EFI_STATUS Status;
+ DISK_IO2_FLUSH_TASK *Task;
+ DISK_IO_PRIVATE_DATA *Private;
+
+ Private = DISK_IO_PRIVATE_DATA_FROM_DISK_IO2 (This);
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Task = AllocatePool (sizeof (DISK_IO2_FLUSH_TASK));
+ if (Task == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ DiskIo2OnFlushComplete,
+ Task,
+ &Task->BlockIo2Token.Event
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Task);
+ return Status;
+ }
+ Task->Signature = DISK_IO2_FLUSH_TASK_SIGNATURE;
+ Task->Token = Token;
+ Status = Private->BlockIo2->FlushBlocksEx (Private->BlockIo2, &Task->BlockIo2Token);
+ if (EFI_ERROR (Status)) {
+ gBS->CloseEvent (Task->BlockIo2Token.Event);
+ FreePool (Task);
+ }
+ } else {
+ Status = Private->BlockIo2->FlushBlocksEx (Private->BlockIo2, NULL);
+ }
+
+ return Status;
+}
+
+/**
+ Read BufferSize bytes from Offset into Buffer.
+ Reads may support reads that are not aligned on
+ sector boundaries. There are three cases:
+ UnderRun - The first byte is not on a sector boundary or the read request is
+ less than a sector in length.
+ Aligned - A read of N contiguous sectors.
+ OverRun - The last byte is not on a sector boundary.
+
+ @param This Protocol instance pointer.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param Offset The starting byte offset to read from
+ @param BufferSize Size of Buffer
+ @param Buffer Buffer containing read data
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
+ valid for the device.
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIoReadDisk (
+ IN EFI_DISK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Offset,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ return DiskIo2ReadWriteDisk (
+ DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This),
+ FALSE, MediaId, Offset, NULL, BufferSize, (UINT8 *) Buffer
+ );
+}
+
+
+/**
+ Writes BufferSize bytes from Buffer into Offset.
+ Writes may require a read modify write to support writes that are not
+ aligned on sector boundaries. There are three cases:
+ UnderRun - The first byte is not on a sector boundary or the write request
+ is less than a sector in length. Read modify write is required.
+ Aligned - A write of N contiguous sectors.
+ OverRun - The last byte is not on a sector boundary. Read modified write
+ required.
+
+ @param This Protocol instance pointer.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param Offset The starting byte offset to read from
+ @param BufferSize Size of Buffer
+ @param Buffer Buffer containing read data
+
+ @retval EFI_SUCCESS The data was written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not
+ valid for the device.
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIoWriteDisk (
+ IN EFI_DISK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Offset,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ return DiskIo2ReadWriteDisk (
+ DISK_IO_PRIVATE_DATA_FROM_DISK_IO (This),
+ TRUE, MediaId, Offset, NULL, BufferSize, (UINT8 *) Buffer
+ );
+}
+
+/**
+ The user Entry Point for module DiskIo. The user code starts with this function.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeDiskIo (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gDiskIoDriverBinding,
+ ImageHandle,
+ &gDiskIoComponentName,
+ &gDiskIoComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.h b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.h
new file mode 100644
index 00000000..351d0ad9
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.h
@@ -0,0 +1,467 @@
+/** @file
+ Master header file for DiskIo driver. It includes the module private defininitions.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _DISK_IO_H_
+#define _DISK_IO_H_
+
+#include <Uefi.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/BlockIo2.h>
+#include <Protocol/DiskIo2.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/DiskIo.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#define DISK_IO_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('d', 's', 'k', 'I')
+typedef struct {
+ UINT32 Signature;
+
+ EFI_DISK_IO_PROTOCOL DiskIo;
+ EFI_DISK_IO2_PROTOCOL DiskIo2;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
+
+ UINT8 *SharedWorkingBuffer;
+
+ EFI_LOCK TaskQueueLock;
+ LIST_ENTRY TaskQueue;
+} DISK_IO_PRIVATE_DATA;
+#define DISK_IO_PRIVATE_DATA_FROM_DISK_IO(a) CR (a, DISK_IO_PRIVATE_DATA, DiskIo, DISK_IO_PRIVATE_DATA_SIGNATURE)
+#define DISK_IO_PRIVATE_DATA_FROM_DISK_IO2(a) CR (a, DISK_IO_PRIVATE_DATA, DiskIo2, DISK_IO_PRIVATE_DATA_SIGNATURE)
+
+#define DISK_IO2_TASK_SIGNATURE SIGNATURE_32 ('d', 'i', 'a', 't')
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link; /// < link to other task
+ EFI_LOCK SubtasksLock;
+ LIST_ENTRY Subtasks; /// < header of subtasks
+ EFI_DISK_IO2_TOKEN *Token;
+ DISK_IO_PRIVATE_DATA *Instance;
+} DISK_IO2_TASK;
+
+#define DISK_IO2_FLUSH_TASK_SIGNATURE SIGNATURE_32 ('d', 'i', 'f', 't')
+typedef struct {
+ UINT32 Signature;
+ EFI_BLOCK_IO2_TOKEN BlockIo2Token;
+ EFI_DISK_IO2_TOKEN *Token;
+} DISK_IO2_FLUSH_TASK;
+
+#define DISK_IO_SUBTASK_SIGNATURE SIGNATURE_32 ('d', 'i', 's', 't')
+typedef struct {
+ //
+ // UnderRun: Offset != 0, Length < BlockSize
+ // OverRun: Offset == 0, Length < BlockSize
+ // Middle: Offset is block aligned, Length is multiple of block size
+ //
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ BOOLEAN Write;
+ UINT64 Lba;
+ UINT32 Offset;
+ UINTN Length;
+ UINT8 *WorkingBuffer; /// < NULL indicates using "Buffer" directly
+ UINT8 *Buffer;
+ BOOLEAN Blocking;
+
+ //
+ // Following fields are for DiskIo2
+ //
+ DISK_IO2_TASK *Task;
+ EFI_BLOCK_IO2_TOKEN BlockIo2Token;
+} DISK_IO_SUBTASK;
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gDiskIoDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gDiskIoComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gDiskIoComponentName2;
+
+//
+// Prototypes
+// Driver model protocol interface
+//
+/**
+ Test to see if this driver supports ControllerHandle.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to test
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver supports this device
+ @retval EFI_ALREADY_STARTED This driver is already running on this device
+ @retval other This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIoDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Start this driver on ControllerHandle by opening a Block IO protocol and
+ installing a Disk IO protocol on ControllerHandle.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to bind driver to
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver is added to ControllerHandle
+ @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
+ @retval other This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIoDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Stop this driver on ControllerHandle by removing Disk IO protocol and closing
+ the Block IO protocol on ControllerHandle.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to stop driver on
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCESS This driver is removed ControllerHandle
+ @retval other This driver was not removed from this device
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIoDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+//
+// Disk I/O Protocol Interface
+//
+/**
+ Read BufferSize bytes from Offset into Buffer.
+ Reads may support reads that are not aligned on
+ sector boundaries. There are three cases:
+ UnderRun - The first byte is not on a sector boundary or the read request is
+ less than a sector in length.
+ Aligned - A read of N contiguous sectors.
+ OverRun - The last byte is not on a sector boundary.
+
+ @param This Protocol instance pointer.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param Offset The starting byte offset to read from
+ @param BufferSize Size of Buffer
+ @param Buffer Buffer containing read data
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
+ valid for the device.
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIoReadDisk (
+ IN EFI_DISK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Offset,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Writes BufferSize bytes from Buffer into Offset.
+ Writes may require a read modify write to support writes that are not
+ aligned on sector boundaries. There are three cases:
+ UnderRun - The first byte is not on a sector boundary or the write request
+ is less than a sector in length. Read modify write is required.
+ Aligned - A write of N contiguous sectors.
+ OverRun - The last byte is not on a sector boundary. Read modified write
+ required.
+
+ @param This Protocol instance pointer.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param Offset The starting byte offset to read from
+ @param BufferSize Size of Buffer
+ @param Buffer Buffer containing read data
+
+ @retval EFI_SUCCESS The data was written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not
+ valid for the device.
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIoWriteDisk (
+ IN EFI_DISK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Offset,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+
+/**
+ Terminate outstanding asynchronous requests to a device.
+
+ @param This Indicates a pointer to the calling context.
+
+ @retval EFI_SUCCESS All outstanding requests were successfully terminated.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the cancel
+ operation.
+**/
+EFI_STATUS
+EFIAPI
+DiskIo2Cancel (
+ IN EFI_DISK_IO2_PROTOCOL *This
+ );
+
+/**
+ Reads a specified number of bytes from a device.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to be read.
+ @param Offset The starting byte offset on the logical block I/O device to read from.
+ @param Token A pointer to the token associated with the transaction.
+ If this field is NULL, synchronous/blocking IO is performed.
+ @param BufferSize The size in bytes of Buffer. The number of bytes to read from the device.
+ @param Buffer A pointer to the destination buffer for the data.
+ The caller is responsible either having implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was read correctly from the device.
+ If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
+ Event will be signaled upon completion.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_NO_MEDIA There is no medium in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId is not for the current medium.
+ @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not valid for the device.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIo2ReadDiskEx (
+ IN EFI_DISK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Offset,
+ IN OUT EFI_DISK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Writes a specified number of bytes to a device.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to be written.
+ @param Offset The starting byte offset on the logical block I/O device to write to.
+ @param Token A pointer to the token associated with the transaction.
+ If this field is NULL, synchronous/blocking IO is performed.
+ @param BufferSize The size in bytes of Buffer. The number of bytes to write to the device.
+ @param Buffer A pointer to the buffer containing the data to be written.
+
+ @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was written correctly to the device.
+ If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
+ Event will be signaled upon completion.
+ @retval EFI_WRITE_PROTECTED The device cannot be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write operation.
+ @retval EFI_NO_MEDIA There is no medium in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId is not for the current medium.
+ @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not valid for the device.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIo2WriteDiskEx (
+ IN EFI_DISK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Offset,
+ IN EFI_DISK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+ Flushes all modified data to the physical device.
+
+ @param This Indicates a pointer to the calling context.
+ @param Token A pointer to the token associated with the transaction.
+ If this field is NULL, synchronous/blocking IO is performed.
+
+ @retval EFI_SUCCESS If Event is NULL (blocking I/O): The data was flushed successfully to the device.
+ If Event is not NULL (asynchronous I/O): The request was successfully queued for processing.
+ Event will be signaled upon completion.
+ @retval EFI_WRITE_PROTECTED The device cannot be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write operation.
+ @retval EFI_NO_MEDIA There is no medium in the device.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+DiskIo2FlushDiskEx (
+ IN EFI_DISK_IO2_PROTOCOL *This,
+ IN OUT EFI_DISK_IO2_TOKEN *Token
+ );
+
+//
+// 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
+DiskIoComponentNameGetDriverName (
+ 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 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.
+
+**/
+EFI_STATUS
+EFIAPI
+DiskIoComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf
new file mode 100644
index 00000000..b8942ce4
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf
@@ -0,0 +1,65 @@
+## @file
+# Module that lays Disk I/O protocol on every Block I/O protocol.
+#
+# This module produces Disk I/O protocol to abstract the block accesses
+# of the Block I/O protocol to a more general offset-length protocol
+# to provide byte-oriented access to block media. It adds this protocol
+# to any Block I/O interface that appears in the system that does not
+# already have a Disk I/O protocol. File systems and other disk access
+# code utilize the Disk I/O protocol.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DiskIoDxe
+ MODULE_UNI_FILE = DiskIoDxe.uni
+ FILE_GUID = 6B38F7B4-AD98-40e9-9093-ACA2B5A253C4
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeDiskIo
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gDiskIoDriverBinding
+# COMPONENT_NAME = gDiskIoComponentName
+# COMPONENT_NAME2 = gDiskIoComponentName2
+#
+
+[Sources]
+ ComponentName.c
+ DiskIo.h
+ DiskIo.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ BaseLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+ PcdLib
+
+[Protocols]
+ gEfiDiskIoProtocolGuid ## BY_START
+ gEfiDiskIo2ProtocolGuid ## BY_START
+ gEfiBlockIoProtocolGuid ## TO_START
+ gEfiBlockIo2ProtocolGuid ## TO_START
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDiskIoDataBufferBlockNum ## SOMETIMES_CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ DiskIoDxeExtra.uni
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.uni
new file mode 100644
index 00000000..3bdf78d4
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.uni
@@ -0,0 +1,21 @@
+// /** @file
+// Module that lays Disk I/O protocol on every Block I/O protocol.
+//
+// This module produces Disk I/O protocol to abstract the block accesses
+// of the Block I/O protocol to a more general offset-length protocol
+// to provide byte-oriented access to block media. It adds this protocol
+// to any Block I/O interface that appears in the system that does not
+// already have a Disk I/O protocol. File systems and other disk access
+// code utilize the Disk I/O protocol.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Lays Disk I/O protocol on every Block I/O protocol"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module produces Disk I/O protocol to abstract the block accesses of the Block I/O protocol to a more general offset-length protocol to provide byte-oriented access to block media. It adds this protocol to any Block I/O interface that appears in the system that does not already have a Disk I/O protocol. File systems and other disk access code utilize the Disk I/O protocol."
+
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxeExtra.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxeExtra.uni
new file mode 100644
index 00000000..a63822cc
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// DiskIoDxe 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
+"Disk I/O DXE Driver"
+
+
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Apple.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Apple.c
new file mode 100644
index 00000000..8881e49f
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Apple.c
@@ -0,0 +1,241 @@
+/* $Id: Apple.c $ */
+/** @file
+ * Apple.c
+ */
+
+/*
+ * Copyright (C) 2012-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 "Partition.h"
+
+#define DPISTRLEN 32
+
+#pragma pack(1)
+typedef struct APPLE_PT_HEADER {
+ UINT16 sbSig; /* must be BE 0x4552 */
+ UINT16 sbBlkSize; /* block size of device */
+ UINT32 sbBlkCount; /* number of blocks on device */
+ UINT16 sbDevType; /* device type */
+ UINT16 sbDevId; /* device id */
+ UINT32 sbData; /* not used */
+ UINT16 sbDrvrCount; /* driver descriptor count */
+ UINT16 sbMap[247]; /* descriptor map */
+} APPLE_PT_HEADER;
+
+typedef struct APPLE_PT_ENTRY {
+ UINT16 signature ; /* must be BE 0x504D for new style PT */
+ UINT16 reserved_1 ;
+ UINT32 map_entries ; /* how many PT entries are there */
+ UINT32 pblock_start ; /* first physical block */
+ UINT32 pblocks ; /* number of physical blocks */
+ char name[DPISTRLEN] ; /* name of partition */
+ char type[DPISTRLEN] ; /* type of partition */
+ /* Some more data we don't really need */
+} APPLE_PT_ENTRY;
+#pragma pack()
+
+static UINT16
+be16_to_cpu(UINT16 x)
+{
+ return SwapBytes16(x);
+}
+
+static UINT32
+be32_to_cpu(UINT32 x)
+{
+ return SwapBytes32(x);
+}
+
+
+/**
+ Install child handles if the Handle supports Apple partition table format.
+
+ @param[in] This Calling context.
+ @param[in] Handle Parent Handle
+ @param[in] DiskIo Parent DiskIo interface
+ @param[in] BlockIo Parent BlockIo interface
+ @param[in] DevicePath Parent Device Path
+
+
+ @retval EFI_SUCCESS Child handle(s) was added
+ @retval EFI_MEDIA_CHANGED Media changed Detected
+ @retval other no child handle was added
+
+**/
+EFI_STATUS
+PartitionInstallAppleChildHandles (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Lba;
+ EFI_BLOCK_IO_MEDIA *Media;
+ VOID *Block;
+ //UINTN MaxIndex;
+ /** @todo wrong, as this PT can be on both HDD or CD */
+ CDROM_DEVICE_PATH CdDev;
+ //EFI_DEVICE_PATH_PROTOCOL Dev;
+ EFI_STATUS Found;
+ UINT32 Partition;
+ UINT32 PartitionEntries;
+ UINT32 SubBlockSize;
+ UINT32 BlkPerSec;
+ EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
+
+ VBoxLogFlowFuncEnter();
+ Found = EFI_NOT_FOUND;
+ Media = BlockIo->Media;
+
+ Block = AllocatePool ((UINTN) Media->BlockSize);
+
+ if (Block == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ do {
+ APPLE_PT_HEADER * Header;
+
+ /* read PT header first */
+ Lba = 0;
+
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ Media->MediaId,
+ MultU64x32 (Lba, Media->BlockSize),
+ Media->BlockSize,
+ Block
+ );
+ if (EFI_ERROR (Status))
+ {
+ Found = Status;
+ break;
+ }
+
+ Header = (APPLE_PT_HEADER *)Block;
+ if (be16_to_cpu(Header->sbSig) != 0x4552)
+ {
+ break;
+ }
+ SubBlockSize = be16_to_cpu(Header->sbBlkSize);
+ BlkPerSec = Media->BlockSize / SubBlockSize;
+
+ /* Fail if media block size isn't an exact multiple */
+ if (Media->BlockSize != SubBlockSize * BlkPerSec)
+ {
+ break;
+ }
+
+ /* Now iterate over PT entries and install child handles */
+ PartitionEntries = 1;
+ for (Partition = 1; Partition <= PartitionEntries; Partition++)
+ {
+ APPLE_PT_ENTRY * Entry;
+ UINT32 StartLba;
+ UINT32 SizeLbs;
+
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ Media->MediaId,
+ MultU64x32 (Partition, SubBlockSize),
+ SubBlockSize,
+ Block
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_NOT_FOUND;
+ goto done; /* would break, but ... */
+ }
+
+ Entry = (APPLE_PT_ENTRY *)Block;
+
+ if (be16_to_cpu(Entry->signature) != 0x504D)
+ {
+ Print(L"Not a new PT entry: %x", Entry->signature);
+ continue;
+ }
+
+ /* First partition contains partitions count */
+ if (Partition == 1)
+ {
+ PartitionEntries = be32_to_cpu(Entry->map_entries);
+ }
+
+ StartLba = be32_to_cpu(Entry->pblock_start);
+ SizeLbs = be32_to_cpu(Entry->pblocks);
+
+ if (0 && CompareMem("Apple_HFS", Entry->type, 10) == 0)
+ Print(L"HFS partition (%d of %d) at LBA 0x%x size=%dM\n",
+ Partition, PartitionEntries, StartLba,
+ (UINT32)(DivU64x32(MultU64x32(SizeLbs, SubBlockSize), (1024 * 1024))));
+
+ ZeroMem (&CdDev, sizeof (CdDev));
+ CdDev.Header.Type = MEDIA_DEVICE_PATH;
+ CdDev.Header.SubType = MEDIA_CDROM_DP;
+ SetDevicePathNodeLength (&CdDev.Header, sizeof (CdDev));
+
+ CdDev.BootEntry = 0;
+ /* Convert from partition to media blocks */
+ CdDev.PartitionStart = StartLba / BlkPerSec; /* start, LBA */
+ CdDev.PartitionSize = SizeLbs / BlkPerSec; /* size, LBs */
+
+ Status = PartitionInstallChildHandle (
+ This,
+ Handle,
+ DiskIo,
+ DiskIo2,
+ BlockIo,
+ BlockIo2,
+ DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &CdDev,
+ &PartitionInfo,
+ CdDev.PartitionStart,
+ CdDev.PartitionStart + CdDev.PartitionSize - 1,
+ SubBlockSize,
+ NULL);
+
+ if (!EFI_ERROR (Status)) {
+ Found = EFI_SUCCESS;
+ }
+ }
+
+ } while (0);
+
+ done:
+ FreePool (Block);
+
+ return Found;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/ComponentName.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/ComponentName.c
new file mode 100644
index 00000000..0623ac3d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/ComponentName.c
@@ -0,0 +1,182 @@
+/** @file
+ UEFI Component Name protocol for Partition driver.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Partition.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gPartitionComponentName = {
+ PartitionComponentNameGetDriverName,
+ PartitionComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gPartitionComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) PartitionComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) PartitionComponentNameGetControllerName,
+ "en"
+};
+
+//
+// Driver name table for Partition module.
+// It is shared by the implementation of ComponentName & ComponentName2 Protocol.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mPartitionDriverNameTable[] = {
+ {
+ "eng;en",
+ L"Partition Driver(MBR/GPT/El Torito)"
+ },
+ {
+ 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
+PartitionComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mPartitionDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gPartitionComponentName)
+ );
+}
+
+
+/**
+ 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 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.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/ElTorito.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/ElTorito.c
new file mode 100644
index 00000000..083e7efc
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/ElTorito.c
@@ -0,0 +1,275 @@
+/** @file
+ Decode an El Torito formatted CD-ROM
+
+Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "Partition.h"
+
+
+/**
+ Install child handles if the Handle supports El Torito format.
+
+ @param[in] This Calling context.
+ @param[in] Handle Parent Handle.
+ @param[in] DiskIo Parent DiskIo interface.
+ @param[in] DiskIo2 Parent DiskIo2 interface.
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] BlockIo2 Parent BlockIo2 interface.
+ @param[in] DevicePath Parent Device Path
+
+
+ @retval EFI_SUCCESS Child handle(s) was added.
+ @retval EFI_MEDIA_CHANGED Media changed Detected.
+ @retval other no child handle was added.
+
+**/
+EFI_STATUS
+PartitionInstallElToritoChildHandles (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_STATUS Status;
+ UINT64 VolDescriptorOffset;
+ UINT32 Lba2KB;
+ EFI_BLOCK_IO_MEDIA *Media;
+ CDROM_VOLUME_DESCRIPTOR *VolDescriptor;
+ ELTORITO_CATALOG *Catalog;
+ UINTN Check;
+ UINTN Index;
+ UINTN BootEntry;
+ UINTN MaxIndex;
+ UINT16 *CheckBuffer;
+ CDROM_DEVICE_PATH CdDev;
+ UINT32 SubBlockSize;
+ UINT32 SectorCount;
+ EFI_STATUS Found;
+ UINT32 VolSpaceSize;
+ EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
+
+ Found = EFI_NOT_FOUND;
+ Media = BlockIo->Media;
+
+ VolSpaceSize = 0;
+
+ //
+ // CD_ROM has the fixed block size as 2048 bytes (SIZE_2KB)
+ //
+
+ // If the ISO image has been copied onto a different storage media
+ // then the block size might be different (eg: USB).
+ // Ensure 2048 (SIZE_2KB) is a multiple of block size
+ if (((SIZE_2KB % Media->BlockSize) != 0) || (Media->BlockSize > SIZE_2KB)) {
+ return EFI_NOT_FOUND;
+ }
+
+ VolDescriptor = AllocatePool ((UINTN)SIZE_2KB);
+
+ if (VolDescriptor == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ Catalog = (ELTORITO_CATALOG *) VolDescriptor;
+
+ //
+ // Loop: handle one volume descriptor per time
+ // The ISO-9660 volume descriptor starts at 32k on the media
+ //
+ for (VolDescriptorOffset = SIZE_32KB;
+ VolDescriptorOffset <= MultU64x32 (Media->LastBlock, Media->BlockSize);
+ VolDescriptorOffset += SIZE_2KB) {
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ Media->MediaId,
+ VolDescriptorOffset,
+ SIZE_2KB,
+ VolDescriptor
+ );
+ if (EFI_ERROR (Status)) {
+ Found = Status;
+ break;
+ }
+ //
+ // Check for valid volume descriptor signature
+ //
+ if (VolDescriptor->Unknown.Type == CDVOL_TYPE_END ||
+ CompareMem (VolDescriptor->Unknown.Id, CDVOL_ID, sizeof (VolDescriptor->Unknown.Id)) != 0
+ ) {
+ //
+ // end of Volume descriptor list
+ //
+ break;
+ }
+ //
+ // Read the Volume Space Size from Primary Volume Descriptor 81-88 byte,
+ // the 32-bit numerical values is stored in Both-byte orders
+ //
+ if (VolDescriptor->PrimaryVolume.Type == CDVOL_TYPE_CODED) {
+ VolSpaceSize = VolDescriptor->PrimaryVolume.VolSpaceSize[0];
+ }
+ //
+ // Is it an El Torito volume descriptor?
+ //
+ if (CompareMem (VolDescriptor->BootRecordVolume.SystemId, CDVOL_ELTORITO_ID, sizeof (CDVOL_ELTORITO_ID) - 1) != 0) {
+ continue;
+ }
+ //
+ // Read in the boot El Torito boot catalog
+ // The LBA unit used by El Torito boot catalog is 2KB unit
+ //
+ Lba2KB = UNPACK_INT32 (VolDescriptor->BootRecordVolume.EltCatalog);
+ // Ensure the LBA (in 2KB unit) fits into our media
+ if (Lba2KB * (SIZE_2KB / Media->BlockSize) > Media->LastBlock) {
+ continue;
+ }
+
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ Media->MediaId,
+ MultU64x32 (Lba2KB, SIZE_2KB),
+ SIZE_2KB,
+ Catalog
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "EltCheckDevice: error reading catalog %r\n", Status));
+ continue;
+ }
+ //
+ // We don't care too much about the Catalog header's contents, but we do want
+ // to make sure it looks like a Catalog header
+ //
+ if (Catalog->Catalog.Indicator != ELTORITO_ID_CATALOG || Catalog->Catalog.Id55AA != 0xAA55) {
+ DEBUG ((EFI_D_ERROR, "EltCheckBootCatalog: El Torito boot catalog header IDs not correct\n"));
+ continue;
+ }
+
+ Check = 0;
+ CheckBuffer = (UINT16 *) Catalog;
+ for (Index = 0; Index < sizeof (ELTORITO_CATALOG) / sizeof (UINT16); Index += 1) {
+ Check += CheckBuffer[Index];
+ }
+
+ if ((Check & 0xFFFF) != 0) {
+ DEBUG ((EFI_D_ERROR, "EltCheckBootCatalog: El Torito boot catalog header checksum failed\n"));
+ continue;
+ }
+
+ MaxIndex = Media->BlockSize / sizeof (ELTORITO_CATALOG);
+ for (Index = 1, BootEntry = 1; Index < MaxIndex; Index += 1) {
+ //
+ // Next entry
+ //
+ Catalog += 1;
+
+ //
+ // Check this entry
+ //
+ if (Catalog->Boot.Indicator != ELTORITO_ID_SECTION_BOOTABLE || Catalog->Boot.Lba == 0) {
+ continue;
+ }
+
+ SubBlockSize = 512;
+ SectorCount = Catalog->Boot.SectorCount;
+
+ switch (Catalog->Boot.MediaType) {
+
+ case ELTORITO_NO_EMULATION:
+ SubBlockSize = Media->BlockSize;
+ break;
+
+ case ELTORITO_HARD_DISK:
+ break;
+
+ case ELTORITO_12_DISKETTE:
+ SectorCount = 0x50 * 0x02 * 0x0F;
+ break;
+
+ case ELTORITO_14_DISKETTE:
+ SectorCount = 0x50 * 0x02 * 0x12;
+ break;
+
+ case ELTORITO_28_DISKETTE:
+ SectorCount = 0x50 * 0x02 * 0x24;
+ break;
+
+ default:
+ DEBUG ((EFI_D_INIT, "EltCheckDevice: unsupported El Torito boot media type %x\n", Catalog->Boot.MediaType));
+ SectorCount = 0;
+ SubBlockSize = Media->BlockSize;
+ break;
+ }
+ //
+ // Create child device handle
+ //
+ CdDev.Header.Type = MEDIA_DEVICE_PATH;
+ CdDev.Header.SubType = MEDIA_CDROM_DP;
+ SetDevicePathNodeLength (&CdDev.Header, sizeof (CdDev));
+
+ if (Index == 1) {
+ //
+ // This is the initial/default entry
+ //
+ BootEntry = 0;
+ }
+
+ CdDev.BootEntry = (UINT32) BootEntry;
+ BootEntry++;
+ CdDev.PartitionStart = Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize);
+ if (SectorCount < 2) {
+ //
+ // When the SectorCount < 2, set the Partition as the whole CD.
+ //
+ if (VolSpaceSize * (SIZE_2KB / Media->BlockSize) > (Media->LastBlock + 1)) {
+ CdDev.PartitionSize = (UINT32)(Media->LastBlock - Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize) + 1);
+ } else {
+ CdDev.PartitionSize = (UINT32)(VolSpaceSize - Catalog->Boot.Lba) * (SIZE_2KB / Media->BlockSize);
+ }
+ } else {
+ CdDev.PartitionSize = DivU64x32 (
+ MultU64x32 (
+ SectorCount * (SIZE_2KB / Media->BlockSize),
+ SubBlockSize
+ ) + Media->BlockSize - 1,
+ Media->BlockSize
+ );
+ }
+
+ ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
+ PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
+ PartitionInfo.Type = PARTITION_TYPE_OTHER;
+
+ Status = PartitionInstallChildHandle (
+ This,
+ Handle,
+ DiskIo,
+ DiskIo2,
+ BlockIo,
+ BlockIo2,
+ DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &CdDev,
+ &PartitionInfo,
+ Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize),
+ Catalog->Boot.Lba * (SIZE_2KB / Media->BlockSize) + CdDev.PartitionSize - 1,
+ SubBlockSize,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ Found = EFI_SUCCESS;
+ }
+ }
+ }
+
+ FreePool (VolDescriptor);
+
+ return Found;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Gpt.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Gpt.c
new file mode 100644
index 00000000..0f436987
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Gpt.c
@@ -0,0 +1,883 @@
+/** @file
+ Decode a hard disk partitioned with the GPT scheme in the UEFI 2.0
+ specification.
+
+ Caution: This file requires additional review when modified.
+ This driver will have external input - disk partition.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ PartitionInstallGptChildHandles() routine will read disk partition content and
+ do basic validation before PartitionInstallChildHandle().
+
+ PartitionValidGptTable(), PartitionCheckGptEntry() routine will accept disk
+ partition content and validate the GPT table and GPT entry.
+
+Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "Partition.h"
+
+/**
+ Install child handles if the Handle supports GPT partition structure.
+
+ Caution: This function may receive untrusted input.
+ The GPT partition table header is external input, so this routine
+ will do basic validation for GPT partition table header before return.
+
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] DiskIo Disk Io protocol.
+ @param[in] Lba The starting Lba of the Partition Table
+ @param[out] PartHeader Stores the partition table that is read
+
+ @retval TRUE The partition table is valid
+ @retval FALSE The partition table is not valid
+
+**/
+BOOLEAN
+PartitionValidGptTable (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_LBA Lba,
+ OUT EFI_PARTITION_TABLE_HEADER *PartHeader
+ );
+
+/**
+ Check if the CRC field in the Partition table header is valid
+ for Partition entry array.
+
+ @param[in] BlockIo Parent BlockIo interface
+ @param[in] DiskIo Disk Io Protocol.
+ @param[in] PartHeader Partition table header structure
+
+ @retval TRUE the CRC is valid
+ @retval FALSE the CRC is invalid
+
+**/
+BOOLEAN
+PartitionCheckGptEntryArrayCRC (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_PARTITION_TABLE_HEADER *PartHeader
+ );
+
+
+/**
+ Restore Partition Table to its alternate place
+ (Primary -> Backup or Backup -> Primary).
+
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] DiskIo Disk Io Protocol.
+ @param[in] PartHeader Partition table header structure.
+
+ @retval TRUE Restoring succeeds
+ @retval FALSE Restoring failed
+
+**/
+BOOLEAN
+PartitionRestoreGptTable (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_PARTITION_TABLE_HEADER *PartHeader
+ );
+
+
+/**
+ This routine will check GPT partition entry and return entry status.
+
+ Caution: This function may receive untrusted input.
+ The GPT partition entry is external input, so this routine
+ will do basic validation for GPT partition entry and report status.
+
+ @param[in] PartHeader Partition table header structure
+ @param[in] PartEntry The partition entry array
+ @param[out] PEntryStatus the partition entry status array
+ recording the status of each partition
+
+**/
+VOID
+PartitionCheckGptEntry (
+ IN EFI_PARTITION_TABLE_HEADER *PartHeader,
+ IN EFI_PARTITION_ENTRY *PartEntry,
+ OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus
+ );
+
+
+/**
+ Checks the CRC32 value in the table header.
+
+ @param MaxSize Max Size limit
+ @param Size The size of the table
+ @param Hdr Table to check
+
+ @return TRUE CRC Valid
+ @return FALSE CRC Invalid
+
+**/
+BOOLEAN
+PartitionCheckCrcAltSize (
+ IN UINTN MaxSize,
+ IN UINTN Size,
+ IN OUT EFI_TABLE_HEADER *Hdr
+ );
+
+
+/**
+ Checks the CRC32 value in the table header.
+
+ @param MaxSize Max Size limit
+ @param Hdr Table to check
+
+ @return TRUE CRC Valid
+ @return FALSE CRC Invalid
+
+**/
+BOOLEAN
+PartitionCheckCrc (
+ IN UINTN MaxSize,
+ IN OUT EFI_TABLE_HEADER *Hdr
+ );
+
+
+/**
+ Updates the CRC32 value in the table header.
+
+ @param Size The size of the table
+ @param Hdr Table to update
+
+**/
+VOID
+PartitionSetCrcAltSize (
+ IN UINTN Size,
+ IN OUT EFI_TABLE_HEADER *Hdr
+ );
+
+
+/**
+ Updates the CRC32 value in the table header.
+
+ @param Hdr Table to update
+
+**/
+VOID
+PartitionSetCrc (
+ IN OUT EFI_TABLE_HEADER *Hdr
+ );
+
+/**
+ Install child handles if the Handle supports GPT partition structure.
+
+ Caution: This function may receive untrusted input.
+ The GPT partition table is external input, so this routine
+ will do basic validation for GPT partition table before install
+ child handle for each GPT partition.
+
+ @param[in] This Calling context.
+ @param[in] Handle Parent Handle.
+ @param[in] DiskIo Parent DiskIo interface.
+ @param[in] DiskIo2 Parent DiskIo2 interface.
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] BlockIo2 Parent BlockIo2 interface.
+ @param[in] DevicePath Parent Device Path.
+
+ @retval EFI_SUCCESS Valid GPT disk.
+ @retval EFI_MEDIA_CHANGED Media changed Detected.
+ @retval other Not a valid GPT disk.
+
+**/
+EFI_STATUS
+PartitionInstallGptChildHandles (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ EFI_LBA LastBlock;
+ MASTER_BOOT_RECORD *ProtectiveMbr;
+ EFI_PARTITION_TABLE_HEADER *PrimaryHeader;
+ EFI_PARTITION_TABLE_HEADER *BackupHeader;
+ EFI_PARTITION_ENTRY *PartEntry;
+ EFI_PARTITION_ENTRY *Entry;
+ EFI_PARTITION_ENTRY_STATUS *PEntryStatus;
+ UINTN Index;
+ EFI_STATUS GptValidStatus;
+ HARDDRIVE_DEVICE_PATH HdDev;
+ UINT32 MediaId;
+ EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
+
+ ProtectiveMbr = NULL;
+ PrimaryHeader = NULL;
+ BackupHeader = NULL;
+ PartEntry = NULL;
+ PEntryStatus = NULL;
+
+ BlockSize = BlockIo->Media->BlockSize;
+ LastBlock = BlockIo->Media->LastBlock;
+ MediaId = BlockIo->Media->MediaId;
+
+ DEBUG ((EFI_D_INFO, " BlockSize : %d \n", BlockSize));
+ DEBUG ((EFI_D_INFO, " LastBlock : %lx \n", LastBlock));
+
+ GptValidStatus = EFI_NOT_FOUND;
+
+ //
+ // Ensure the block size can hold the MBR
+ //
+ if (BlockSize < sizeof (MASTER_BOOT_RECORD)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Allocate a buffer for the Protective MBR
+ //
+ ProtectiveMbr = AllocatePool (BlockSize);
+ if (ProtectiveMbr == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Read the Protective MBR from LBA #0
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ MediaId,
+ 0,
+ BlockSize,
+ ProtectiveMbr
+ );
+ if (EFI_ERROR (Status)) {
+ GptValidStatus = Status;
+ goto Done;
+ }
+
+ //
+ // Verify that the Protective MBR is valid
+ //
+ for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
+ if (ProtectiveMbr->Partition[Index].BootIndicator == 0x00 &&
+ ProtectiveMbr->Partition[Index].OSIndicator == PMBR_GPT_PARTITION &&
+ UNPACK_UINT32 (ProtectiveMbr->Partition[Index].StartingLBA) == 1
+ ) {
+ break;
+ }
+ }
+ if (Index == MAX_MBR_PARTITIONS) {
+ goto Done;
+ }
+
+ //
+ // Allocate the GPT structures
+ //
+ PrimaryHeader = AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER));
+ if (PrimaryHeader == NULL) {
+ goto Done;
+ }
+
+ BackupHeader = AllocateZeroPool (sizeof (EFI_PARTITION_TABLE_HEADER));
+ if (BackupHeader == NULL) {
+ goto Done;
+ }
+
+ //
+ // Check primary and backup partition tables
+ //
+ if (!PartitionValidGptTable (BlockIo, DiskIo, PRIMARY_PART_HEADER_LBA, PrimaryHeader)) {
+ DEBUG ((EFI_D_INFO, " Not Valid primary partition table\n"));
+
+ if (!PartitionValidGptTable (BlockIo, DiskIo, LastBlock, BackupHeader)) {
+ DEBUG ((EFI_D_INFO, " Not Valid backup partition table\n"));
+ goto Done;
+ } else {
+ DEBUG ((EFI_D_INFO, " Valid backup partition table\n"));
+ DEBUG ((EFI_D_INFO, " Restore primary partition table by the backup\n"));
+ if (!PartitionRestoreGptTable (BlockIo, DiskIo, BackupHeader)) {
+ DEBUG ((EFI_D_INFO, " Restore primary partition table error\n"));
+ }
+
+ if (PartitionValidGptTable (BlockIo, DiskIo, BackupHeader->AlternateLBA, PrimaryHeader)) {
+ DEBUG ((EFI_D_INFO, " Restore backup partition table success\n"));
+ }
+ }
+ } else if (!PartitionValidGptTable (BlockIo, DiskIo, PrimaryHeader->AlternateLBA, BackupHeader)) {
+ DEBUG ((EFI_D_INFO, " Valid primary and !Valid backup partition table\n"));
+ DEBUG ((EFI_D_INFO, " Restore backup partition table by the primary\n"));
+ if (!PartitionRestoreGptTable (BlockIo, DiskIo, PrimaryHeader)) {
+ DEBUG ((EFI_D_INFO, " Restore backup partition table error\n"));
+ }
+
+ if (PartitionValidGptTable (BlockIo, DiskIo, PrimaryHeader->AlternateLBA, BackupHeader)) {
+ DEBUG ((EFI_D_INFO, " Restore backup partition table success\n"));
+ }
+
+ }
+
+ DEBUG ((EFI_D_INFO, " Valid primary and Valid backup partition table\n"));
+
+ //
+ // Read the EFI Partition Entries
+ //
+ PartEntry = AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry);
+ if (PartEntry == NULL) {
+ DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
+ goto Done;
+ }
+
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ MediaId,
+ MultU64x32(PrimaryHeader->PartitionEntryLBA, BlockSize),
+ PrimaryHeader->NumberOfPartitionEntries * (PrimaryHeader->SizeOfPartitionEntry),
+ PartEntry
+ );
+ if (EFI_ERROR (Status)) {
+ GptValidStatus = Status;
+ DEBUG ((EFI_D_ERROR, " Partition Entry ReadDisk error\n"));
+ goto Done;
+ }
+
+ DEBUG ((EFI_D_INFO, " Partition entries read block success\n"));
+
+ DEBUG ((EFI_D_INFO, " Number of partition entries: %d\n", PrimaryHeader->NumberOfPartitionEntries));
+
+ PEntryStatus = AllocateZeroPool (PrimaryHeader->NumberOfPartitionEntries * sizeof (EFI_PARTITION_ENTRY_STATUS));
+ if (PEntryStatus == NULL) {
+ DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
+ goto Done;
+ }
+
+ //
+ // Check the integrity of partition entries
+ //
+ PartitionCheckGptEntry (PrimaryHeader, PartEntry, PEntryStatus);
+
+ //
+ // If we got this far the GPT layout of the disk is valid and we should return true
+ //
+ GptValidStatus = EFI_SUCCESS;
+
+ //
+ // Create child device handles
+ //
+ for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {
+ Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartEntry + Index * PrimaryHeader->SizeOfPartitionEntry);
+ if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid) ||
+ PEntryStatus[Index].OutOfRange ||
+ PEntryStatus[Index].Overlap ||
+ PEntryStatus[Index].OsSpecific
+ ) {
+ //
+ // Don't use null EFI Partition Entries, Invalid Partition Entries or OS specific
+ // partition Entries
+ //
+ continue;
+ }
+
+ ZeroMem (&HdDev, sizeof (HdDev));
+ HdDev.Header.Type = MEDIA_DEVICE_PATH;
+ HdDev.Header.SubType = MEDIA_HARDDRIVE_DP;
+ SetDevicePathNodeLength (&HdDev.Header, sizeof (HdDev));
+
+ HdDev.PartitionNumber = (UINT32) Index + 1;
+ HdDev.MBRType = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
+ HdDev.SignatureType = SIGNATURE_TYPE_GUID;
+ HdDev.PartitionStart = Entry->StartingLBA;
+ HdDev.PartitionSize = Entry->EndingLBA - Entry->StartingLBA + 1;
+ CopyMem (HdDev.Signature, &Entry->UniquePartitionGUID, sizeof (EFI_GUID));
+
+ ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
+ PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
+ PartitionInfo.Type = PARTITION_TYPE_GPT;
+ if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeSystemPartGuid)) {
+ PartitionInfo.System = 1;
+ }
+ CopyMem (&PartitionInfo.Info.Gpt, Entry, sizeof (EFI_PARTITION_ENTRY));
+
+ DEBUG ((EFI_D_INFO, " Index : %d\n", (UINT32) Index));
+ DEBUG ((EFI_D_INFO, " Start LBA : %lx\n", (UINT64) HdDev.PartitionStart));
+ DEBUG ((EFI_D_INFO, " End LBA : %lx\n", (UINT64) Entry->EndingLBA));
+ DEBUG ((EFI_D_INFO, " Partition size: %lx\n", (UINT64) HdDev.PartitionSize));
+ DEBUG ((EFI_D_INFO, " Start : %lx", MultU64x32 (Entry->StartingLBA, BlockSize)));
+ DEBUG ((EFI_D_INFO, " End : %lx\n", MultU64x32 (Entry->EndingLBA, BlockSize)));
+
+ Status = PartitionInstallChildHandle (
+ This,
+ Handle,
+ DiskIo,
+ DiskIo2,
+ BlockIo,
+ BlockIo2,
+ DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &HdDev,
+ &PartitionInfo,
+ Entry->StartingLBA,
+ Entry->EndingLBA,
+ BlockSize,
+ &Entry->PartitionTypeGUID
+ );
+ }
+
+ DEBUG ((EFI_D_INFO, "Prepare to Free Pool\n"));
+
+Done:
+ if (ProtectiveMbr != NULL) {
+ FreePool (ProtectiveMbr);
+ }
+ if (PrimaryHeader != NULL) {
+ FreePool (PrimaryHeader);
+ }
+ if (BackupHeader != NULL) {
+ FreePool (BackupHeader);
+ }
+ if (PartEntry != NULL) {
+ FreePool (PartEntry);
+ }
+ if (PEntryStatus != NULL) {
+ FreePool (PEntryStatus);
+ }
+
+ return GptValidStatus;
+}
+
+/**
+ This routine will read GPT partition table header and return it.
+
+ Caution: This function may receive untrusted input.
+ The GPT partition table header is external input, so this routine
+ will do basic validation for GPT partition table header before return.
+
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] DiskIo Disk Io protocol.
+ @param[in] Lba The starting Lba of the Partition Table
+ @param[out] PartHeader Stores the partition table that is read
+
+ @retval TRUE The partition table is valid
+ @retval FALSE The partition table is not valid
+
+**/
+BOOLEAN
+PartitionValidGptTable (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_LBA Lba,
+ OUT EFI_PARTITION_TABLE_HEADER *PartHeader
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ EFI_PARTITION_TABLE_HEADER *PartHdr;
+ UINT32 MediaId;
+
+ BlockSize = BlockIo->Media->BlockSize;
+ MediaId = BlockIo->Media->MediaId;
+ PartHdr = AllocateZeroPool (BlockSize);
+
+ if (PartHdr == NULL) {
+ DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
+ return FALSE;
+ }
+ //
+ // Read the EFI Partition Table Header
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ MediaId,
+ MultU64x32 (Lba, BlockSize),
+ BlockSize,
+ PartHdr
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (PartHdr);
+ return FALSE;
+ }
+
+ if ((PartHdr->Header.Signature != EFI_PTAB_HEADER_ID) ||
+ !PartitionCheckCrc (BlockSize, &PartHdr->Header) ||
+ PartHdr->MyLBA != Lba ||
+ (PartHdr->SizeOfPartitionEntry < sizeof (EFI_PARTITION_ENTRY))
+ ) {
+ DEBUG ((EFI_D_INFO, "Invalid efi partition table header\n"));
+ FreePool (PartHdr);
+ return FALSE;
+ }
+
+ //
+ // Ensure the NumberOfPartitionEntries * SizeOfPartitionEntry doesn't overflow.
+ //
+ if (PartHdr->NumberOfPartitionEntries > DivU64x32 (MAX_UINTN, PartHdr->SizeOfPartitionEntry)) {
+ FreePool (PartHdr);
+ return FALSE;
+ }
+
+ CopyMem (PartHeader, PartHdr, sizeof (EFI_PARTITION_TABLE_HEADER));
+ if (!PartitionCheckGptEntryArrayCRC (BlockIo, DiskIo, PartHeader)) {
+ FreePool (PartHdr);
+ return FALSE;
+ }
+
+ DEBUG ((EFI_D_INFO, " Valid efi partition table header\n"));
+ FreePool (PartHdr);
+ return TRUE;
+}
+
+/**
+ Check if the CRC field in the Partition table header is valid
+ for Partition entry array.
+
+ @param[in] BlockIo Parent BlockIo interface
+ @param[in] DiskIo Disk Io Protocol.
+ @param[in] PartHeader Partition table header structure
+
+ @retval TRUE the CRC is valid
+ @retval FALSE the CRC is invalid
+
+**/
+BOOLEAN
+PartitionCheckGptEntryArrayCRC (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_PARTITION_TABLE_HEADER *PartHeader
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Ptr;
+ UINT32 Crc;
+ UINTN Size;
+
+ //
+ // Read the EFI Partition Entries
+ //
+ Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry);
+ if (Ptr == NULL) {
+ DEBUG ((EFI_D_ERROR, " Allocate pool error\n"));
+ return FALSE;
+ }
+
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32(PartHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),
+ PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Ptr);
+ return FALSE;
+ }
+
+ Size = PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry;
+
+ Status = gBS->CalculateCrc32 (Ptr, Size, &Crc);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "CheckPEntryArrayCRC: Crc calculation failed\n"));
+ FreePool (Ptr);
+ return FALSE;
+ }
+
+ FreePool (Ptr);
+
+ return (BOOLEAN) (PartHeader->PartitionEntryArrayCRC32 == Crc);
+}
+
+
+/**
+ Restore Partition Table to its alternate place
+ (Primary -> Backup or Backup -> Primary).
+
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] DiskIo Disk Io Protocol.
+ @param[in] PartHeader Partition table header structure.
+
+ @retval TRUE Restoring succeeds
+ @retval FALSE Restoring failed
+
+**/
+BOOLEAN
+PartitionRestoreGptTable (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_PARTITION_TABLE_HEADER *PartHeader
+ )
+{
+ EFI_STATUS Status;
+ UINTN BlockSize;
+ EFI_PARTITION_TABLE_HEADER *PartHdr;
+ EFI_LBA PEntryLBA;
+ UINT8 *Ptr;
+ UINT32 MediaId;
+
+ PartHdr = NULL;
+ Ptr = NULL;
+
+ BlockSize = BlockIo->Media->BlockSize;
+ MediaId = BlockIo->Media->MediaId;
+
+ PartHdr = AllocateZeroPool (BlockSize);
+
+ if (PartHdr == NULL) {
+ DEBUG ((EFI_D_ERROR, "Allocate pool error\n"));
+ return FALSE;
+ }
+
+ PEntryLBA = (PartHeader->MyLBA == PRIMARY_PART_HEADER_LBA) ? \
+ (PartHeader->LastUsableLBA + 1) : \
+ (PRIMARY_PART_HEADER_LBA + 1);
+
+ CopyMem (PartHdr, PartHeader, sizeof (EFI_PARTITION_TABLE_HEADER));
+
+ PartHdr->MyLBA = PartHeader->AlternateLBA;
+ PartHdr->AlternateLBA = PartHeader->MyLBA;
+ PartHdr->PartitionEntryLBA = PEntryLBA;
+ PartitionSetCrc ((EFI_TABLE_HEADER *) PartHdr);
+
+ Status = DiskIo->WriteDisk (
+ DiskIo,
+ MediaId,
+ MultU64x32 (PartHdr->MyLBA, (UINT32) BlockSize),
+ BlockSize,
+ PartHdr
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry);
+ if (Ptr == NULL) {
+ DEBUG ((EFI_D_ERROR, " Allocate pool error\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ MediaId,
+ MultU64x32(PartHeader->PartitionEntryLBA, (UINT32) BlockSize),
+ PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
+ Ptr
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = DiskIo->WriteDisk (
+ DiskIo,
+ MediaId,
+ MultU64x32(PEntryLBA, (UINT32) BlockSize),
+ PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
+ Ptr
+ );
+
+Done:
+ FreePool (PartHdr);
+
+ if (Ptr != NULL) {
+ FreePool (Ptr);
+ }
+
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ This routine will check GPT partition entry and return entry status.
+
+ Caution: This function may receive untrusted input.
+ The GPT partition entry is external input, so this routine
+ will do basic validation for GPT partition entry and report status.
+
+ @param[in] PartHeader Partition table header structure
+ @param[in] PartEntry The partition entry array
+ @param[out] PEntryStatus the partition entry status array
+ recording the status of each partition
+
+**/
+VOID
+PartitionCheckGptEntry (
+ IN EFI_PARTITION_TABLE_HEADER *PartHeader,
+ IN EFI_PARTITION_ENTRY *PartEntry,
+ OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus
+ )
+{
+ EFI_LBA StartingLBA;
+ EFI_LBA EndingLBA;
+ EFI_PARTITION_ENTRY *Entry;
+ UINTN Index1;
+ UINTN Index2;
+
+ DEBUG ((EFI_D_INFO, " start check partition entries\n"));
+ for (Index1 = 0; Index1 < PartHeader->NumberOfPartitionEntries; Index1++) {
+ Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartEntry + Index1 * PartHeader->SizeOfPartitionEntry);
+ if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
+ continue;
+ }
+
+ StartingLBA = Entry->StartingLBA;
+ EndingLBA = Entry->EndingLBA;
+ if (StartingLBA > EndingLBA ||
+ StartingLBA < PartHeader->FirstUsableLBA ||
+ StartingLBA > PartHeader->LastUsableLBA ||
+ EndingLBA < PartHeader->FirstUsableLBA ||
+ EndingLBA > PartHeader->LastUsableLBA
+ ) {
+ PEntryStatus[Index1].OutOfRange = TRUE;
+ continue;
+ }
+
+ if ((Entry->Attributes & BIT1) != 0) {
+ //
+ // If Bit 1 is set, this indicate that this is an OS specific GUID partition.
+ //
+ PEntryStatus[Index1].OsSpecific = TRUE;
+ }
+
+ for (Index2 = Index1 + 1; Index2 < PartHeader->NumberOfPartitionEntries; Index2++) {
+ Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartEntry + Index2 * PartHeader->SizeOfPartitionEntry);
+ if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
+ continue;
+ }
+
+ if (Entry->EndingLBA >= StartingLBA && Entry->StartingLBA <= EndingLBA) {
+ //
+ // This region overlaps with the Index1'th region
+ //
+ PEntryStatus[Index1].Overlap = TRUE;
+ PEntryStatus[Index2].Overlap = TRUE;
+ continue;
+ }
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, " End check partition entries\n"));
+}
+
+
+/**
+ Updates the CRC32 value in the table header.
+
+ @param Hdr Table to update
+
+**/
+VOID
+PartitionSetCrc (
+ IN OUT EFI_TABLE_HEADER *Hdr
+ )
+{
+ PartitionSetCrcAltSize (Hdr->HeaderSize, Hdr);
+}
+
+
+/**
+ Updates the CRC32 value in the table header.
+
+ @param Size The size of the table
+ @param Hdr Table to update
+
+**/
+VOID
+PartitionSetCrcAltSize (
+ IN UINTN Size,
+ IN OUT EFI_TABLE_HEADER *Hdr
+ )
+{
+ UINT32 Crc;
+
+ Hdr->CRC32 = 0;
+ gBS->CalculateCrc32 ((UINT8 *) Hdr, Size, &Crc);
+ Hdr->CRC32 = Crc;
+}
+
+
+/**
+ Checks the CRC32 value in the table header.
+
+ @param MaxSize Max Size limit
+ @param Hdr Table to check
+
+ @return TRUE CRC Valid
+ @return FALSE CRC Invalid
+
+**/
+BOOLEAN
+PartitionCheckCrc (
+ IN UINTN MaxSize,
+ IN OUT EFI_TABLE_HEADER *Hdr
+ )
+{
+ return PartitionCheckCrcAltSize (MaxSize, Hdr->HeaderSize, Hdr);
+}
+
+
+/**
+ Checks the CRC32 value in the table header.
+
+ @param MaxSize Max Size limit
+ @param Size The size of the table
+ @param Hdr Table to check
+
+ @return TRUE CRC Valid
+ @return FALSE CRC Invalid
+
+**/
+BOOLEAN
+PartitionCheckCrcAltSize (
+ IN UINTN MaxSize,
+ IN UINTN Size,
+ IN OUT EFI_TABLE_HEADER *Hdr
+ )
+{
+ UINT32 Crc;
+ UINT32 OrgCrc;
+ EFI_STATUS Status;
+
+ Crc = 0;
+
+ if (Size == 0) {
+ //
+ // If header size is 0 CRC will pass so return FALSE here
+ //
+ return FALSE;
+ }
+
+ if ((MaxSize != 0) && (Size > MaxSize)) {
+ DEBUG ((EFI_D_ERROR, "CheckCrc32: Size > MaxSize\n"));
+ return FALSE;
+ }
+ //
+ // clear old crc from header
+ //
+ OrgCrc = Hdr->CRC32;
+ Hdr->CRC32 = 0;
+
+ Status = gBS->CalculateCrc32 ((UINT8 *) Hdr, Size, &Crc);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc calculation failed\n"));
+ return FALSE;
+ }
+ //
+ // set results
+ //
+ Hdr->CRC32 = Crc;
+
+ //
+ // return status
+ //
+ DEBUG_CODE_BEGIN ();
+ if (OrgCrc != Crc) {
+ DEBUG ((EFI_D_ERROR, "CheckCrc32: Crc check failed\n"));
+ }
+ DEBUG_CODE_END ();
+
+ return (BOOLEAN) (OrgCrc == Crc);
+}
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Mbr.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Mbr.c
new file mode 100644
index 00000000..6e3a85d3
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Mbr.c
@@ -0,0 +1,353 @@
+/** @file
+ Decode a hard disk partitioned with the legacy MBR found on most PC's
+
+ MBR - Master Boot Record is in the first sector of a partitioned hard disk.
+ The MBR supports four partitions per disk. The MBR also contains legacy
+ code that is not run on an EFI system. The legacy code reads the
+ first sector of the active partition into memory and
+
+ BPB - BIOS Parameter Block is in the first sector of a FAT file system.
+ The BPB contains information about the FAT file system. The BPB is
+ always on the first sector of a media. The first sector also contains
+ the legacy boot strap code.
+
+Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
+Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Partition.h"
+
+/**
+ Test to see if the Mbr buffer is a valid MBR.
+
+ @param Mbr Parent Handle.
+ @param LastLba Last Lba address on the device.
+
+ @retval TRUE Mbr is a Valid MBR.
+ @retval FALSE Mbr is not a Valid MBR.
+
+**/
+BOOLEAN
+PartitionValidMbr (
+ IN MASTER_BOOT_RECORD *Mbr,
+ IN EFI_LBA LastLba
+ )
+{
+ UINT32 StartingLBA;
+ UINT32 EndingLBA;
+ UINT32 NewEndingLBA;
+ INTN Index1;
+ INTN Index2;
+ BOOLEAN MbrValid;
+
+ if (Mbr->Signature != MBR_SIGNATURE) {
+ return FALSE;
+ }
+ //
+ // The BPB also has this signature, so it can not be used alone.
+ //
+ MbrValid = FALSE;
+ for (Index1 = 0; Index1 < MAX_MBR_PARTITIONS; Index1++) {
+ if (Mbr->Partition[Index1].OSIndicator == 0x00 || UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) == 0) {
+ continue;
+ }
+
+ MbrValid = TRUE;
+ StartingLBA = UNPACK_UINT32 (Mbr->Partition[Index1].StartingLBA);
+ EndingLBA = StartingLBA + UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) - 1;
+ if (EndingLBA > LastLba) {
+ //
+ // Compatibility Errata:
+ // Some systems try to hide drive space with their INT 13h driver
+ // This does not hide space from the OS driver. This means the MBR
+ // that gets created from DOS is smaller than the MBR created from
+ // a real OS (NT & Win98). This leads to BlockIo->LastBlock being
+ // wrong on some systems FDISKed by the OS.
+ //
+ // return FALSE since no block devices on a system are implemented
+ // with INT 13h
+ //
+
+ DEBUG((EFI_D_INFO, "PartitionValidMbr: Bad MBR partition size EndingLBA(%1x) > LastLBA(%1x)\n", EndingLBA, LastLba));
+
+ return FALSE;
+ }
+
+ for (Index2 = Index1 + 1; Index2 < MAX_MBR_PARTITIONS; Index2++) {
+ if (Mbr->Partition[Index2].OSIndicator == 0x00 || UNPACK_UINT32 (Mbr->Partition[Index2].SizeInLBA) == 0) {
+ continue;
+ }
+
+ NewEndingLBA = UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) + UNPACK_UINT32 (Mbr->Partition[Index2].SizeInLBA) - 1;
+ if (NewEndingLBA >= StartingLBA && UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) <= EndingLBA) {
+ //
+ // This region overlaps with the Index1'th region
+ //
+ return FALSE;
+ }
+ }
+ }
+ //
+ // None of the regions overlapped so MBR is O.K.
+ //
+ return MbrValid;
+}
+
+
+/**
+ Install child handles if the Handle supports MBR format.
+
+ @param[in] This Calling context.
+ @param[in] Handle Parent Handle.
+ @param[in] DiskIo Parent DiskIo interface.
+ @param[in] DiskIo2 Parent DiskIo2 interface.
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] BlockIo2 Parent BlockIo2 interface.
+ @param[in] DevicePath Parent Device Path.
+
+ @retval EFI_SUCCESS A child handle was added.
+ @retval EFI_MEDIA_CHANGED Media change was detected.
+ @retval Others MBR partition was not found.
+
+**/
+EFI_STATUS
+PartitionInstallMbrChildHandles (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_STATUS Status;
+ MASTER_BOOT_RECORD *Mbr;
+ UINT32 ExtMbrStartingLba;
+ UINT32 Index;
+ HARDDRIVE_DEVICE_PATH HdDev;
+ HARDDRIVE_DEVICE_PATH ParentHdDev;
+ EFI_STATUS Found;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
+ EFI_DEVICE_PATH_PROTOCOL *LastDevicePathNode;
+ UINT32 BlockSize;
+ UINT32 MediaId;
+ EFI_LBA LastSector;
+ EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
+
+ Found = EFI_NOT_FOUND;
+
+ BlockSize = BlockIo->Media->BlockSize;
+ MediaId = BlockIo->Media->MediaId;
+ LastSector = DivU64x32 (
+ MultU64x32 (BlockIo->Media->LastBlock + 1, BlockSize),
+ MBR_SIZE
+ ) - 1;
+
+ //
+ // Ensure the block size can hold the MBR
+ //
+ if (BlockSize < sizeof (MASTER_BOOT_RECORD)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Mbr = AllocatePool (BlockSize);
+ if (Mbr == NULL) {
+ return Found;
+ }
+
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ MediaId,
+ 0,
+ BlockSize,
+ Mbr
+ );
+ if (EFI_ERROR (Status)) {
+ Found = Status;
+ goto Done;
+ }
+ if (!PartitionValidMbr (Mbr, LastSector)) {
+ goto Done;
+ }
+ //
+ // We have a valid mbr - add each partition
+ //
+ //
+ // Get starting and ending LBA of the parent block device.
+ //
+ LastDevicePathNode = NULL;
+ ZeroMem (&ParentHdDev, sizeof (ParentHdDev));
+ DevicePathNode = DevicePath;
+ while (!IsDevicePathEnd (DevicePathNode)) {
+ LastDevicePathNode = DevicePathNode;
+ DevicePathNode = NextDevicePathNode (DevicePathNode);
+ }
+
+ if (LastDevicePathNode != NULL) {
+ if (DevicePathType (LastDevicePathNode) == MEDIA_DEVICE_PATH &&
+ DevicePathSubType (LastDevicePathNode) == MEDIA_HARDDRIVE_DP
+ ) {
+ CopyMem (&ParentHdDev, LastDevicePathNode, sizeof (ParentHdDev));
+ } else {
+ LastDevicePathNode = NULL;
+ }
+ }
+
+ ZeroMem (&HdDev, sizeof (HdDev));
+ HdDev.Header.Type = MEDIA_DEVICE_PATH;
+ HdDev.Header.SubType = MEDIA_HARDDRIVE_DP;
+ SetDevicePathNodeLength (&HdDev.Header, sizeof (HdDev));
+ HdDev.MBRType = MBR_TYPE_PCAT;
+ HdDev.SignatureType = SIGNATURE_TYPE_MBR;
+
+ if (LastDevicePathNode == NULL) {
+ //
+ // This is a MBR, add each partition
+ //
+ for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
+ if (Mbr->Partition[Index].OSIndicator == 0x00 || UNPACK_UINT32 (Mbr->Partition[Index].SizeInLBA) == 0) {
+ //
+ // Don't use null MBR entries
+ //
+ continue;
+ }
+
+ if (Mbr->Partition[Index].OSIndicator == PMBR_GPT_PARTITION) {
+ //
+ // This is the guard MBR for the GPT. If you ever see a GPT disk with zero partitions you can get here.
+ // We can not produce an MBR BlockIo for this device as the MBR spans the GPT headers. So formating
+ // this BlockIo would corrupt the GPT structures and require a recovery that would corrupt the format
+ // that corrupted the GPT partition.
+ //
+ continue;
+ }
+
+ HdDev.PartitionNumber = Index + 1;
+ HdDev.PartitionStart = UNPACK_UINT32 (Mbr->Partition[Index].StartingLBA);
+ HdDev.PartitionSize = UNPACK_UINT32 (Mbr->Partition[Index].SizeInLBA);
+ CopyMem (HdDev.Signature, &(Mbr->UniqueMbrSignature[0]), sizeof (Mbr->UniqueMbrSignature));
+
+ ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
+ PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
+ PartitionInfo.Type = PARTITION_TYPE_MBR;
+ if (Mbr->Partition[Index].OSIndicator == EFI_PARTITION) {
+ PartitionInfo.System = 1;
+ }
+ CopyMem (&PartitionInfo.Info.Mbr, &Mbr->Partition[Index], sizeof (MBR_PARTITION_RECORD));
+
+ Status = PartitionInstallChildHandle (
+ This,
+ Handle,
+ DiskIo,
+ DiskIo2,
+ BlockIo,
+ BlockIo2,
+ DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &HdDev,
+ &PartitionInfo,
+ HdDev.PartitionStart,
+ HdDev.PartitionStart + HdDev.PartitionSize - 1,
+ MBR_SIZE,
+ ((Mbr->Partition[Index].OSIndicator == EFI_PARTITION) ? &gEfiPartTypeSystemPartGuid: NULL)
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Found = EFI_SUCCESS;
+ }
+ }
+ } else {
+ //
+ // It's an extended partition. Follow the extended partition
+ // chain to get all the logical drives
+ //
+ Index = 0;
+ ExtMbrStartingLba = 0;
+
+ do {
+
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ MediaId,
+ MultU64x32 (ExtMbrStartingLba, BlockSize),
+ BlockSize,
+ Mbr
+ );
+ if (EFI_ERROR (Status)) {
+ Found = Status;
+ goto Done;
+ }
+
+ if (UNPACK_UINT32 (Mbr->Partition[0].SizeInLBA) == 0) {
+ break;
+ }
+
+ if ((Mbr->Partition[0].OSIndicator == EXTENDED_DOS_PARTITION) ||
+ (Mbr->Partition[0].OSIndicator == EXTENDED_WINDOWS_PARTITION)) {
+ ExtMbrStartingLba = UNPACK_UINT32 (Mbr->Partition[0].StartingLBA);
+ continue;
+ }
+ HdDev.PartitionNumber = ++Index;
+ HdDev.PartitionStart = UNPACK_UINT32 (Mbr->Partition[0].StartingLBA) + ExtMbrStartingLba + ParentHdDev.PartitionStart;
+ HdDev.PartitionSize = UNPACK_UINT32 (Mbr->Partition[0].SizeInLBA);
+ if ((HdDev.PartitionStart + HdDev.PartitionSize - 1 >= ParentHdDev.PartitionStart + ParentHdDev.PartitionSize) ||
+ (HdDev.PartitionStart <= ParentHdDev.PartitionStart)) {
+ break;
+ }
+
+ //
+ // The signature in EBR(Extended Boot Record) should always be 0.
+ //
+ *((UINT32 *) &HdDev.Signature[0]) = 0;
+
+ ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
+ PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
+ PartitionInfo.Type = PARTITION_TYPE_MBR;
+ if (Mbr->Partition[0].OSIndicator == EFI_PARTITION) {
+ PartitionInfo.System = 1;
+ }
+ CopyMem (&PartitionInfo.Info.Mbr, &Mbr->Partition[0], sizeof (MBR_PARTITION_RECORD));
+
+ Status = PartitionInstallChildHandle (
+ This,
+ Handle,
+ DiskIo,
+ DiskIo2,
+ BlockIo,
+ BlockIo2,
+ DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &HdDev,
+ &PartitionInfo,
+ HdDev.PartitionStart - ParentHdDev.PartitionStart,
+ HdDev.PartitionStart - ParentHdDev.PartitionStart + HdDev.PartitionSize - 1,
+ MBR_SIZE,
+ ((Mbr->Partition[0].OSIndicator == EFI_PARTITION) ? &gEfiPartTypeSystemPartGuid: NULL)
+ );
+ if (!EFI_ERROR (Status)) {
+ Found = EFI_SUCCESS;
+ }
+
+ if ((Mbr->Partition[1].OSIndicator != EXTENDED_DOS_PARTITION) &&
+ (Mbr->Partition[1].OSIndicator != EXTENDED_WINDOWS_PARTITION)
+ ) {
+ break;
+ }
+
+ ExtMbrStartingLba = UNPACK_UINT32 (Mbr->Partition[1].StartingLBA);
+ //
+ // Don't allow partition to be self referencing
+ //
+ if (ExtMbrStartingLba == 0) {
+ break;
+ }
+ } while (ExtMbrStartingLba < ParentHdDev.PartitionSize);
+ }
+
+Done:
+ FreePool (Mbr);
+
+ return Found;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c
new file mode 100644
index 00000000..f183e9c8
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.c
@@ -0,0 +1,1430 @@
+/** @file
+ Partition driver that produces logical BlockIo devices from a physical
+ BlockIo device. The logical BlockIo devices are based on the format
+ of the raw block devices media. Currently "El Torito CD-ROM", UDF, Legacy
+ MBR, and GPT partition schemes are supported.
+
+Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "Partition.h"
+
+//
+// Partition Driver Global Variables.
+//
+EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding = {
+ PartitionDriverBindingSupported,
+ PartitionDriverBindingStart,
+ PartitionDriverBindingStop,
+ //
+ // Grub4Dos copies the BPB of the first partition to the MBR. If the
+ // DriverBindingStart() of the Fat driver gets run before that of Partition
+ // driver only the first partition can be recognized.
+ // Let the driver binding version of Partition driver be higher than that of
+ // Fat driver to make sure the DriverBindingStart() of the Partition driver
+ // gets run before that of Fat driver so that all the partitions can be recognized.
+ //
+ 0xb,
+ NULL,
+ NULL
+};
+
+//
+// Prioritized function list to detect partition table.
+// Refer to UEFI Spec 13.3.2 Partition Discovery, the block device
+// should be scanned in below order:
+// 1. GPT
+// 2. ISO 9660 (El Torito) (or UDF)
+// 3. MBR
+// 4. no partiton found
+// Note: UDF is using a same method as booting from CD-ROM, so put it along
+// with CD-ROM check.
+//
+PARTITION_DETECT_ROUTINE mPartitionDetectRoutineTable[] = {
+#ifdef VBOX
+ PartitionInstallAppleChildHandles,
+#endif
+ PartitionInstallGptChildHandles,
+ PartitionInstallUdfChildHandles,
+ PartitionInstallMbrChildHandles,
+ NULL
+};
+
+/**
+ Test to see if this driver supports ControllerHandle. Any ControllerHandle
+ than contains a BlockIo and DiskIo protocol or a BlockIo2 protocol can be
+ supported.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to test.
+ @param[in] RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver supports this device
+ @retval EFI_ALREADY_STARTED This driver is already running on this device
+ @retval other This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ EFI_DEV_PATH *Node;
+#ifdef VBOX
+ VBoxLogFlowFuncEnter();
+#endif
+
+ //
+ // Check RemainingDevicePath validation
+ //
+ if (RemainingDevicePath != NULL) {
+ //
+ // Check if RemainingDevicePath is the End of Device Path Node,
+ // if yes, go on checking other conditions
+ //
+ if (!IsDevicePathEnd (RemainingDevicePath)) {
+ //
+ // If RemainingDevicePath isn't the End of Device Path Node,
+ // check its validation
+ //
+ Node = (EFI_DEV_PATH *) RemainingDevicePath;
+#ifndef VBOX
+ if (Node->DevPath.Type != MEDIA_DEVICE_PATH ||
+ Node->DevPath.SubType != MEDIA_HARDDRIVE_DP ||
+ DevicePathNodeLength (&Node->DevPath) != sizeof (HARDDRIVE_DEVICE_PATH)) {
+ return EFI_UNSUPPORTED;
+ }
+#else
+ if ( Node->DevPath.Type != MEDIA_DEVICE_PATH
+ || Node->DevPath.SubType != MEDIA_HARDDRIVE_DP
+ || DevicePathNodeLength (&Node->DevPath) != sizeof (HARDDRIVE_DEVICE_PATH)
+ || Node->DevPath.Type != MESSAGING_DEVICE_PATH
+ || Node->DevPath.SubType != MSG_SATA_DP) {
+ VBoxLogFlowFuncLeaveRC(EFI_UNSUPPORTED);
+ return EFI_UNSUPPORTED;
+ }
+#endif
+ }
+ }
+
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ (VOID **) &DiskIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+#ifdef VBOX
+ VBoxLogFlowFuncLeaveRC(EFI_SUCCESS);
+#endif
+ return EFI_SUCCESS;
+ }
+ if (EFI_ERROR (Status)) {
+#ifdef VBOX
+ VBoxLogFlowFuncLeaveRC(Status);
+#endif
+ return Status;
+ }
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ //
+ // Open the EFI Device Path protocol needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status)) {
+#ifdef VBOX
+ VBoxLogFlowFuncLeaveRC(Status);
+#endif
+ return Status;
+ }
+
+ //
+ // Close protocol, don't use device path protocol in the Support() function
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+
+#ifdef VBOX
+ VBoxLogFlowFuncLeaveRC(Status);
+#endif
+ return Status;
+}
+
+/**
+ Start this driver on ControllerHandle by opening a Block IO or a Block IO2
+ or both, and Disk IO protocol, reading Device Path, and creating a child
+ handle with a Disk IO and device path protocol.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to bind driver to
+ @param[in] RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver is added to ControllerHandle
+ @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
+ @retval other This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS OpenStatus;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ EFI_DISK_IO2_PROTOCOL *DiskIo2;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ PARTITION_DETECT_ROUTINE *Routine;
+ BOOLEAN MediaPresent;
+ EFI_TPL OldTpl;
+#ifdef VBOX
+ int idxRoutine = 0;
+
+ VBoxLogFlowFuncEnter();
+#endif
+
+ BlockIo2 = NULL;
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ //
+ // Check RemainingDevicePath validation
+ //
+ if (RemainingDevicePath != NULL) {
+ //
+ // Check if RemainingDevicePath is the End of Device Path Node,
+ // if yes, return EFI_SUCCESS
+ //
+ if (IsDevicePathEnd (RemainingDevicePath)) {
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+ }
+
+ //
+ // Try to open BlockIO and BlockIO2. If BlockIO would be opened, continue,
+ // otherwise, return error.
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+#ifdef VBOX
+ VBoxLogFlowFuncMarkRC(Status);
+#endif
+ goto Exit;
+ }
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiBlockIo2ProtocolGuid,
+ (VOID **) &BlockIo2,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ BlockIo2 = NULL;
+ }
+
+ //
+ // Get the Device Path Protocol on ControllerHandle's handle.
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
+#ifdef VBOX
+ VBoxLogFlowFuncMarkRC(Status);
+#endif
+ goto Exit;
+ }
+
+ //
+ // Get the DiskIo and DiskIo2.
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ (VOID **) &DiskIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+#ifdef VBOX
+ VBoxLogFlowFuncMarkRC(Status);
+#endif
+ goto Exit;
+ }
+
+ OpenStatus = Status;
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDiskIo2ProtocolGuid,
+ (VOID **) &DiskIo2,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
+ DiskIo2 = NULL;
+ }
+
+ //
+ // Try to read blocks when there's media or it is removable physical partition.
+ //
+ Status = EFI_UNSUPPORTED;
+ MediaPresent = BlockIo->Media->MediaPresent;
+ if (BlockIo->Media->MediaPresent ||
+ (BlockIo->Media->RemovableMedia && !BlockIo->Media->LogicalPartition)) {
+ //
+ // Try for GPT, then legacy MBR partition types, and then UDF and El Torito.
+ // If the media supports a given partition type install child handles to
+ // represent the partitions described by the media.
+ //
+ Routine = &mPartitionDetectRoutineTable[0];
+ while (*Routine != NULL) {
+ Status = (*Routine) (
+ This,
+ ControllerHandle,
+ DiskIo,
+ DiskIo2,
+ BlockIo,
+ BlockIo2,
+ ParentDevicePath
+ );
+#ifdef VBOX
+ VBoxLogFlowFuncMarkRC(Status);
+#endif
+ if (!EFI_ERROR (Status) || Status == EFI_MEDIA_CHANGED || Status == EFI_NO_MEDIA) {
+#ifdef VBOX
+ VBoxLogFlowFuncMarkVar(idxRoutine, "%d");
+#endif
+ break;
+ }
+ Routine++;
+#ifdef VBOX
+ idxRoutine++;
+#endif
+ }
+ }
+ //
+ // In the case that the driver is already started (OpenStatus == EFI_ALREADY_STARTED),
+ // the DevicePathProtocol and the DiskIoProtocol are not actually opened by the
+ // driver. So don't try to close them. Otherwise, we will break the dependency
+ // between the controller and the driver set up before.
+ //
+ // In the case that when the media changes on a device it will Reinstall the
+ // BlockIo interaface. This will cause a call to our Stop(), and a subsequent
+ // reentrant call to our Start() successfully. We should leave the device open
+ // when this happen. The "media change" case includes either the status is
+ // EFI_MEDIA_CHANGED or it is a "media" to "no media" change.
+ //
+ if (EFI_ERROR (Status) &&
+ !EFI_ERROR (OpenStatus) &&
+ Status != EFI_MEDIA_CHANGED &&
+ !(MediaPresent && Status == EFI_NO_MEDIA)) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ //
+ // Close Parent DiskIo2 if has.
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDiskIo2ProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ }
+
+Exit:
+ gBS->RestoreTPL (OldTpl);
+#ifdef VBOX
+ VBoxLogFlowFuncLeaveRC(Status);
+#endif
+ return Status;
+}
+
+/**
+ Stop this driver on ControllerHandle. Support stopping any child handles
+ created by this driver.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to stop driver on
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCESS This driver is removed ControllerHandle
+ @retval other This driver was not removed from this device
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
+ BOOLEAN AllChildrenStopped;
+ PARTITION_PRIVATE_DATA *Private;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ EFI_GUID *TypeGuid;
+
+ BlockIo = NULL;
+ BlockIo2 = NULL;
+ Private = NULL;
+
+ if (NumberOfChildren == 0) {
+ //
+ // In the case of re-entry of the PartitionDriverBindingStop, the
+ // NumberOfChildren may not reflect the actual number of children on the
+ // bus driver. Hence, additional check is needed here.
+ //
+ if (HasChildren (ControllerHandle)) {
+ DEBUG((EFI_D_ERROR, "PartitionDriverBindingStop: Still has child.\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Close the bus driver
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ //
+ // Close Parent BlockIO2 if has.
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDiskIo2ProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ return EFI_SUCCESS;
+ }
+
+ AllChildrenStopped = TRUE;
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+ gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ //
+ // Try to locate BlockIo2.
+ //
+ gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiBlockIo2ProtocolGuid,
+ (VOID **) &BlockIo2,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo);
+ if (Private->InStop) {
+ //
+ // If the child handle is going to be stopped again during the re-entry
+ // of DriverBindingStop, just do nothing.
+ //
+ break;
+ }
+ Private->InStop = TRUE;
+
+ BlockIo->FlushBlocks (BlockIo);
+
+ if (BlockIo2 != NULL) {
+ Status = BlockIo2->FlushBlocksEx (BlockIo2, NULL);
+ DEBUG((EFI_D_ERROR, "PartitionDriverBindingStop: FlushBlocksEx returned with %r\n", Status));
+ } else {
+ Status = EFI_SUCCESS;
+ }
+
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index]
+ );
+
+ if (IsZeroGuid (&Private->TypeGuid)) {
+ TypeGuid = NULL;
+ } else {
+ TypeGuid = &Private->TypeGuid;
+ }
+
+ //
+ // All Software protocols have be freed from the handle so remove it.
+ // Remove the BlockIo Protocol if has.
+ // Remove the BlockIo2 Protocol if has.
+ //
+ if (BlockIo2 != NULL) {
+ //
+ // Some device drivers might re-install the BlockIO(2) protocols for a
+ // media change condition. Therefore, if the FlushBlocksEx returned with
+ // EFI_MEDIA_CHANGED, just let the BindingStop fail to avoid potential
+ // reference of already stopped child handle.
+ //
+ if (Status != EFI_MEDIA_CHANGED) {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ Private->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &Private->BlockIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &Private->BlockIo2,
+ &gEfiPartitionInfoProtocolGuid,
+ &Private->PartitionInfo,
+ TypeGuid,
+ NULL,
+ NULL
+ );
+ }
+ } else {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ Private->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &Private->BlockIo,
+ &gEfiPartitionInfoProtocolGuid,
+ &Private->PartitionInfo,
+ TypeGuid,
+ NULL,
+ NULL
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ Private->InStop = FALSE;
+ gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ (VOID **) &DiskIo,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ } else {
+ FreePool (Private->DevicePath);
+ FreePool (Private);
+ }
+
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ if (Status == EFI_MEDIA_CHANGED) {
+ break;
+ }
+ }
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Reset the Block Device.
+
+ @param This Protocol instance pointer.
+ @param ExtendedVerification Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could
+ not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ PARTITION_PRIVATE_DATA *Private;
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
+
+ return Private->ParentBlockIo->Reset (
+ Private->ParentBlockIo,
+ ExtendedVerification
+ );
+}
+
+/**
+ Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED
+ for no media or media change case. Otherwise DefaultStatus is returned.
+
+ @param DiskIo Pointer to the DiskIo instance.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param DefaultStatus The default status to return when it's not the no media
+ or media change case.
+
+ @retval EFI_NO_MEDIA There is no media.
+ @retval EFI_MEDIA_CHANGED The media was changed.
+ @retval others The default status to return.
+**/
+EFI_STATUS
+ProbeMediaStatus (
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UINT32 MediaId,
+ IN EFI_STATUS DefaultStatus
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Buffer[1];
+
+ //
+ // Read 1 byte from offset 0 to check if the MediaId is still valid.
+ // The reading operation is synchronious thus it is not worth it to
+ // allocate a buffer from the pool. The destination buffer for the
+ // data is in the stack.
+ //
+ Status = DiskIo->ReadDisk (DiskIo, MediaId, 0, 1, (VOID*)Buffer);
+ if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {
+ return Status;
+ }
+ return DefaultStatus;
+}
+
+/**
+ Read by using the Disk IO protocol on the parent device. Lba addresses
+ must be converted to byte offsets.
+
+ @param This Protocol instance pointer.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param Lba The starting Logical Block Address to read from
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer Buffer containing read data
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
+ valid for the device.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ PARTITION_PRIVATE_DATA *Private;
+ UINT64 Offset;
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
+
+ if (BufferSize % Private->BlockSize != 0) {
+ return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE);
+ }
+
+ Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
+ if (Offset + BufferSize > Private->End) {
+ return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER);
+ }
+ //
+ // Because some kinds of partition have different block size from their parent
+ // device, we call the Disk IO protocol on the parent device, not the Block IO
+ // protocol
+ //
+ return Private->DiskIo->ReadDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer);
+}
+
+/**
+ Write by using the Disk IO protocol on the parent device. Lba addresses
+ must be converted to byte offsets.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] MediaId Id of the media, changes every time the media is replaced.
+ @param[in] Lba The starting Logical Block Address to read from
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[in] Buffer Buffer containing data to be written to device.
+
+ @retval EFI_SUCCESS The data was written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains a LBA that is not
+ valid for the device.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ PARTITION_PRIVATE_DATA *Private;
+ UINT64 Offset;
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
+
+ if (BufferSize % Private->BlockSize != 0) {
+ return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_BAD_BUFFER_SIZE);
+ }
+
+ Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
+ if (Offset + BufferSize > Private->End) {
+ return ProbeMediaStatus (Private->DiskIo, MediaId, EFI_INVALID_PARAMETER);
+ }
+ //
+ // Because some kinds of partition have different block size from their parent
+ // device, we call the Disk IO protocol on the parent device, not the Block IO
+ // protocol
+ //
+ return Private->DiskIo->WriteDisk (Private->DiskIo, MediaId, Offset, BufferSize, Buffer);
+}
+
+
+/**
+ Flush the parent Block Device.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS All outstanding data was written to the device
+ @retval EFI_DEVICE_ERROR The device reported an error while writting back the data
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ )
+{
+ PARTITION_PRIVATE_DATA *Private;
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (This);
+
+ return Private->ParentBlockIo->FlushBlocks (Private->ParentBlockIo);
+}
+
+/**
+ Probe the media status and return EFI_NO_MEDIA or EFI_MEDIA_CHANGED
+ for no media or media change case. Otherwise DefaultStatus is returned.
+
+ @param DiskIo2 Pointer to the DiskIo2 instance.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param DefaultStatus The default status to return when it's not the no media
+ or media change case.
+
+ @retval EFI_NO_MEDIA There is no media.
+ @retval EFI_MEDIA_CHANGED The media was changed.
+ @retval others The default status to return.
+**/
+EFI_STATUS
+ProbeMediaStatusEx (
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN UINT32 MediaId,
+ IN EFI_STATUS DefaultStatus
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Buffer[1];
+
+ //
+ // Read 1 byte from offset 0 to check if the MediaId is still valid.
+ // The reading operation is synchronious thus it is not worth it to
+ // allocate a buffer from the pool. The destination buffer for the
+ // data is in the stack.
+ //
+ Status = DiskIo2->ReadDiskEx (DiskIo2, MediaId, 0, NULL, 1, (VOID*)Buffer);
+ if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {
+ return Status;
+ }
+ return DefaultStatus;
+}
+
+/**
+ Reset the Block Device throught Block I/O2 protocol.
+
+ @param This Protocol instance pointer.
+ @param ExtendedVerification Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could
+ not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionResetEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ PARTITION_PRIVATE_DATA *Private;
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
+
+ return Private->ParentBlockIo2->Reset (
+ Private->ParentBlockIo2,
+ ExtendedVerification
+ );
+}
+
+/**
+ The general callback for the DiskIo2 interfaces.
+ @param Event Event whose notification function is being invoked.
+ @param Context The pointer to the notification function's context,
+ which points to the PARTITION_ACCESS_TASK instance.
+**/
+VOID
+EFIAPI
+PartitionOnAccessComplete (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ PARTITION_ACCESS_TASK *Task;
+
+ Task = (PARTITION_ACCESS_TASK *) Context;
+
+ gBS->CloseEvent (Event);
+
+ Task->BlockIo2Token->TransactionStatus = Task->DiskIo2Token.TransactionStatus;
+ gBS->SignalEvent (Task->BlockIo2Token->Event);
+
+ FreePool (Task);
+}
+
+/**
+ Create a new PARTITION_ACCESS_TASK instance.
+
+ @param Token Pointer to the EFI_BLOCK_IO2_TOKEN.
+
+ @return Pointer to the created PARTITION_ACCESS_TASK instance or NULL upon failure.
+**/
+PARTITION_ACCESS_TASK *
+PartitionCreateAccessTask (
+ IN EFI_BLOCK_IO2_TOKEN *Token
+ )
+{
+ EFI_STATUS Status;
+ PARTITION_ACCESS_TASK *Task;
+
+ Task = AllocatePool (sizeof (*Task));
+ if (Task == NULL) {
+ return NULL;
+ }
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ PartitionOnAccessComplete,
+ Task,
+ &Task->DiskIo2Token.Event
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Task);
+ return NULL;
+ }
+
+ Task->BlockIo2Token = Token;
+
+ return Task;
+}
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ This function reads the requested number of blocks from the device. All the
+ blocks are read, or an error is returned.
+ If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
+ non-blocking I/O is being used, the Event associated with this request will
+ not be signaled.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId Id of the media, changes every time the media is
+ replaced.
+ @param[in] Lba The starting Logical Block Address to read from.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[out] Buffer A pointer to the destination buffer for the data. The
+ caller is responsible for either having implicit or
+ explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The read request was queued if Token->Event is
+ not NULL.The data was read correctly from the
+ device if the Token->Event is NULL.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing
+ the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
+ intrinsic block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
+ of resources.
+**/
+EFI_STATUS
+EFIAPI
+PartitionReadBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ PARTITION_PRIVATE_DATA *Private;
+ UINT64 Offset;
+ PARTITION_ACCESS_TASK *Task;
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
+
+ if (BufferSize % Private->BlockSize != 0) {
+ return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_BAD_BUFFER_SIZE);
+ }
+
+ Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
+ if (Offset + BufferSize > Private->End) {
+ return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_INVALID_PARAMETER);
+ }
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Task = PartitionCreateAccessTask (Token);
+ if (Task == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = Private->DiskIo2->ReadDiskEx (Private->DiskIo2, MediaId, Offset, &Task->DiskIo2Token, BufferSize, Buffer);
+ if (EFI_ERROR (Status)) {
+ gBS->CloseEvent (Task->DiskIo2Token.Event);
+ FreePool (Task);
+ }
+ } else {
+ Status = Private->DiskIo2->ReadDiskEx (Private->DiskIo2, MediaId, Offset, NULL, BufferSize, Buffer);
+ }
+
+ return Status;
+}
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ This function writes the requested number of blocks to the device. All blocks
+ are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
+ EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
+ being used, the Event associated with this request will not be signaled.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the write request is for.
+ @param[in] Lba The starting logical block address to be written. The
+ caller is responsible for writing to only legitimate
+ locations.
+ @param[in, out] Token A pointer to the token associated with the transaction.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
+ @param[in] Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The write request was queued if Event is not NULL.
+ The data was written correctly to the device if
+ the Event is NULL.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
+ of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionWriteBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ PARTITION_PRIVATE_DATA *Private;
+ UINT64 Offset;
+ PARTITION_ACCESS_TASK *Task;
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
+
+ if (BufferSize % Private->BlockSize != 0) {
+ return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_BAD_BUFFER_SIZE);
+ }
+
+ Offset = MultU64x32 (Lba, Private->BlockSize) + Private->Start;
+ if (Offset + BufferSize > Private->End) {
+ return ProbeMediaStatusEx (Private->DiskIo2, MediaId, EFI_INVALID_PARAMETER);
+ }
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Task = PartitionCreateAccessTask (Token);
+ if (Task == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = Private->DiskIo2->WriteDiskEx (Private->DiskIo2, MediaId, Offset, &Task->DiskIo2Token, BufferSize, Buffer);
+ if (EFI_ERROR (Status)) {
+ gBS->CloseEvent (Task->DiskIo2Token.Event);
+ FreePool (Task);
+ }
+ } else {
+ Status = Private->DiskIo2->WriteDiskEx (Private->DiskIo2, MediaId, Offset, NULL, BufferSize, Buffer);
+ }
+ return Status;
+}
+
+/**
+ Flush the Block Device.
+
+ If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
+ is returned and non-blocking I/O is being used, the Event associated with
+ this request will not be signaled.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in, out] Token A pointer to the token associated with the transaction
+
+ @retval EFI_SUCCESS The flush request was queued if Event is not NULL.
+ All outstanding data was written correctly to the
+ device if the Event is NULL.
+ @retval EFI_DEVICE_ERROR The device reported an error while writting back
+ the data.
+ @retval EFI_WRITE_PROTECTED The device cannot be written to.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
+ of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionFlushBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token
+ )
+{
+ EFI_STATUS Status;
+ PARTITION_PRIVATE_DATA *Private;
+ PARTITION_ACCESS_TASK *Task;
+
+ Private = PARTITION_DEVICE_FROM_BLOCK_IO2_THIS (This);
+
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Task = PartitionCreateAccessTask (Token);
+ if (Task == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = Private->DiskIo2->FlushDiskEx (Private->DiskIo2, &Task->DiskIo2Token);
+ if (EFI_ERROR (Status)) {
+ gBS->CloseEvent (Task->DiskIo2Token.Event);
+ FreePool (Task);
+ }
+ } else {
+ Status = Private->DiskIo2->FlushDiskEx (Private->DiskIo2, NULL);
+ }
+ return Status;
+}
+
+
+/**
+ Create a child handle for a logical block device that represents the
+ bytes Start to End of the Parent Block IO device.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ParentHandle Parent Handle for new child.
+ @param[in] ParentDiskIo Parent DiskIo interface.
+ @param[in] ParentDiskIo2 Parent DiskIo2 interface.
+ @param[in] ParentBlockIo Parent BlockIo interface.
+ @param[in] ParentBlockIo2 Parent BlockIo2 interface.
+ @param[in] ParentDevicePath Parent Device Path.
+ @param[in] DevicePathNode Child Device Path node.
+ @param[in] PartitionInfo Child Partition Information interface.
+ @param[in] Start Start Block.
+ @param[in] End End Block.
+ @param[in] BlockSize Child block size.
+ @param[in] TypeGuid Partition GUID Type.
+
+ @retval EFI_SUCCESS A child handle was added.
+ @retval other A child handle was not added.
+
+**/
+EFI_STATUS
+PartitionInstallChildHandle (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ParentHandle,
+ IN EFI_DISK_IO_PROTOCOL *ParentDiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *ParentDiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode,
+ IN EFI_PARTITION_INFO_PROTOCOL *PartitionInfo,
+ IN EFI_LBA Start,
+ IN EFI_LBA End,
+ IN UINT32 BlockSize,
+ IN EFI_GUID *TypeGuid
+ )
+{
+ EFI_STATUS Status;
+ PARTITION_PRIVATE_DATA *Private;
+
+ Status = EFI_SUCCESS;
+ Private = AllocateZeroPool (sizeof (PARTITION_PRIVATE_DATA));
+ if (Private == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Private->Signature = PARTITION_PRIVATE_DATA_SIGNATURE;
+
+ Private->Start = MultU64x32 (Start, ParentBlockIo->Media->BlockSize);
+ Private->End = MultU64x32 (End + 1, ParentBlockIo->Media->BlockSize);
+
+ Private->BlockSize = BlockSize;
+ Private->ParentBlockIo = ParentBlockIo;
+ Private->ParentBlockIo2 = ParentBlockIo2;
+ Private->DiskIo = ParentDiskIo;
+ Private->DiskIo2 = ParentDiskIo2;
+
+ //
+ // Set the BlockIO into Private Data.
+ //
+ Private->BlockIo.Revision = ParentBlockIo->Revision;
+
+ Private->BlockIo.Media = &Private->Media;
+ CopyMem (Private->BlockIo.Media, ParentBlockIo->Media, sizeof (EFI_BLOCK_IO_MEDIA));
+
+ Private->BlockIo.Reset = PartitionReset;
+ Private->BlockIo.ReadBlocks = PartitionReadBlocks;
+ Private->BlockIo.WriteBlocks = PartitionWriteBlocks;
+ Private->BlockIo.FlushBlocks = PartitionFlushBlocks;
+
+ //
+ // Set the BlockIO2 into Private Data.
+ //
+ if (Private->DiskIo2 != NULL) {
+ ASSERT (Private->ParentBlockIo2 != NULL);
+ Private->BlockIo2.Media = &Private->Media2;
+ CopyMem (Private->BlockIo2.Media, ParentBlockIo2->Media, sizeof (EFI_BLOCK_IO_MEDIA));
+
+ Private->BlockIo2.Reset = PartitionResetEx;
+ Private->BlockIo2.ReadBlocksEx = PartitionReadBlocksEx;
+ Private->BlockIo2.WriteBlocksEx = PartitionWriteBlocksEx;
+ Private->BlockIo2.FlushBlocksEx = PartitionFlushBlocksEx;
+ }
+
+ Private->Media.IoAlign = 0;
+ Private->Media.LogicalPartition = TRUE;
+ Private->Media.LastBlock = DivU64x32 (
+ MultU64x32 (
+ End - Start + 1,
+ ParentBlockIo->Media->BlockSize
+ ),
+ BlockSize
+ ) - 1;
+
+ Private->Media.BlockSize = (UINT32) BlockSize;
+
+ Private->Media2.IoAlign = 0;
+ Private->Media2.LogicalPartition = TRUE;
+ Private->Media2.LastBlock = Private->Media.LastBlock;
+ Private->Media2.BlockSize = (UINT32) BlockSize;
+
+ //
+ // Per UEFI Spec, LowestAlignedLba, LogicalBlocksPerPhysicalBlock and OptimalTransferLengthGranularity must be 0
+ // for logical partitions.
+ //
+ if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION2) {
+ Private->Media.LowestAlignedLba = 0;
+ Private->Media.LogicalBlocksPerPhysicalBlock = 0;
+ Private->Media2.LowestAlignedLba = 0;
+ Private->Media2.LogicalBlocksPerPhysicalBlock = 0;
+ if (Private->BlockIo.Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION3) {
+ Private->Media.OptimalTransferLengthGranularity = 0;
+ Private->Media2.OptimalTransferLengthGranularity = 0;
+ }
+ }
+
+ Private->DevicePath = AppendDevicePathNode (ParentDevicePath, DevicePathNode);
+
+ if (Private->DevicePath == NULL) {
+ FreePool (Private);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Set the PartitionInfo into Private Data.
+ //
+ CopyMem (&Private->PartitionInfo, PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
+
+ if (TypeGuid != NULL) {
+ CopyGuid(&(Private->TypeGuid), TypeGuid);
+ } else {
+ ZeroMem ((VOID *)&(Private->TypeGuid), sizeof (EFI_GUID));
+ }
+
+ //
+ // Create the new handle.
+ //
+ Private->Handle = NULL;
+ if (Private->DiskIo2 != NULL) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Private->Handle,
+ &gEfiDevicePathProtocolGuid,
+ Private->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &Private->BlockIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &Private->BlockIo2,
+ &gEfiPartitionInfoProtocolGuid,
+ &Private->PartitionInfo,
+ TypeGuid,
+ NULL,
+ NULL
+ );
+ } else {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Private->Handle,
+ &gEfiDevicePathProtocolGuid,
+ Private->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &Private->BlockIo,
+ &gEfiPartitionInfoProtocolGuid,
+ &Private->PartitionInfo,
+ TypeGuid,
+ NULL,
+ NULL
+ );
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Open the Parent Handle for the child
+ //
+ Status = gBS->OpenProtocol (
+ ParentHandle,
+ &gEfiDiskIoProtocolGuid,
+ (VOID **) &ParentDiskIo,
+ This->DriverBindingHandle,
+ Private->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ } else {
+ FreePool (Private->DevicePath);
+ FreePool (Private);
+
+ //
+ // if the Status == EFI_ALREADY_STARTED, it means the child handles
+ // are already installed. So return EFI_SUCCESS to avoid do the next
+ // partition type check.
+ //
+ if (Status == EFI_ALREADY_STARTED) {
+ Status = EFI_SUCCESS;
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ The user Entry Point for module Partition. The user code starts with this function.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializePartition (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gPartitionDriverBinding,
+ ImageHandle,
+ &gPartitionComponentName,
+ &gPartitionComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+
+ return Status;
+}
+
+
+/**
+ Test to see if there is any child on ControllerHandle.
+
+ @param[in] ControllerHandle Handle of device to test.
+
+ @retval TRUE There are children on the ControllerHandle.
+ @retval FALSE No child is on the ControllerHandle.
+
+**/
+BOOLEAN
+HasChildren (
+ IN EFI_HANDLE ControllerHandle
+ )
+{
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
+ UINTN EntryCount;
+ EFI_STATUS Status;
+ UINTN Index;
+
+ Status = gBS->OpenProtocolInformation (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ &OpenInfoBuffer,
+ &EntryCount
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ for (Index = 0; Index < EntryCount; Index++) {
+ if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
+ break;
+ }
+ }
+ FreePool (OpenInfoBuffer);
+
+ return (BOOLEAN) (Index < EntryCount);
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.h b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.h
new file mode 100644
index 00000000..5b225b07
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Partition.h
@@ -0,0 +1,514 @@
+/** @file
+ Partition driver that produces logical BlockIo devices from a physical
+ BlockIo device. The logical BlockIo devices are based on the format
+ of the raw block devices media. Currently "El Torito CD-ROM", UDF, Legacy
+ MBR, and GPT partition schemes are supported.
+
+Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _PARTITION_H_
+#define _PARTITION_H_
+
+#include <Uefi.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/BlockIo2.h>
+#include <Guid/Gpt.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/DiskIo.h>
+#include <Protocol/DiskIo2.h>
+#include <Protocol/PartitionInfo.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+
+#include <IndustryStandard/Mbr.h>
+#include <IndustryStandard/ElTorito.h>
+#include <IndustryStandard/Udf.h>
+
+//
+// Partition private data
+//
+#define PARTITION_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('P', 'a', 'r', 't')
+typedef struct {
+ UINT64 Signature;
+
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_BLOCK_IO_PROTOCOL BlockIo;
+ EFI_BLOCK_IO2_PROTOCOL BlockIo2;
+ EFI_BLOCK_IO_MEDIA Media;
+ EFI_BLOCK_IO_MEDIA Media2;//For BlockIO2
+ EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
+
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ EFI_DISK_IO2_PROTOCOL *DiskIo2;
+ EFI_BLOCK_IO_PROTOCOL *ParentBlockIo;
+ EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2;
+ UINT64 Start;
+ UINT64 End;
+ UINT32 BlockSize;
+ BOOLEAN InStop;
+
+ EFI_GUID TypeGuid;
+
+} PARTITION_PRIVATE_DATA;
+
+typedef struct {
+ EFI_DISK_IO2_TOKEN DiskIo2Token;
+ EFI_BLOCK_IO2_TOKEN *BlockIo2Token;
+} PARTITION_ACCESS_TASK;
+
+#define PARTITION_DEVICE_FROM_BLOCK_IO_THIS(a) CR (a, PARTITION_PRIVATE_DATA, BlockIo, PARTITION_PRIVATE_DATA_SIGNATURE)
+#define PARTITION_DEVICE_FROM_BLOCK_IO2_THIS(a) CR (a, PARTITION_PRIVATE_DATA, BlockIo2, PARTITION_PRIVATE_DATA_SIGNATURE)
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gPartitionDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gPartitionComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gPartitionComponentName2;
+
+//
+// Extract INT32 from char array
+//
+#define UNPACK_INT32(a) (INT32)( (((UINT8 *) a)[0] << 0) | \
+ (((UINT8 *) a)[1] << 8) | \
+ (((UINT8 *) a)[2] << 16) | \
+ (((UINT8 *) a)[3] << 24) )
+
+//
+// Extract UINT32 from char array
+//
+#define UNPACK_UINT32(a) (UINT32)( (((UINT8 *) a)[0] << 0) | \
+ (((UINT8 *) a)[1] << 8) | \
+ (((UINT8 *) a)[2] << 16) | \
+ (((UINT8 *) a)[3] << 24) )
+
+
+//
+// GPT Partition Entry Status
+//
+typedef struct {
+ BOOLEAN OutOfRange;
+ BOOLEAN Overlap;
+ BOOLEAN OsSpecific;
+} EFI_PARTITION_ENTRY_STATUS;
+
+//
+// Function Prototypes
+//
+/**
+ Test to see if this driver supports ControllerHandle. Any ControllerHandle
+ than contains a BlockIo and DiskIo protocol can be supported.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to test
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver supports this device
+ @retval EFI_ALREADY_STARTED This driver is already running on this device
+ @retval other This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Start this driver on ControllerHandle by opening a Block IO and Disk IO
+ protocol, reading Device Path, and creating a child handle with a
+ Disk IO and device path protocol.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to bind driver to
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver is added to ControllerHandle
+ @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
+ @retval other This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop this driver on ControllerHandle. Support stopping any child handles
+ created by this driver.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to stop driver on
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCESS This driver is removed ControllerHandle
+ @retval other This driver was not removed from this device
+
+**/
+EFI_STATUS
+EFIAPI
+PartitionDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ 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
+PartitionComponentNameGetDriverName (
+ 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
+PartitionComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+/**
+ Create a child handle for a logical block device that represents the
+ bytes Start to End of the Parent Block IO device.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ParentHandle Parent Handle for new child.
+ @param[in] ParentDiskIo Parent DiskIo interface.
+ @param[in] ParentDiskIo2 Parent DiskIo2 interface.
+ @param[in] ParentBlockIo Parent BlockIo interface.
+ @param[in] ParentBlockIo2 Parent BlockIo2 interface.
+ @param[in] ParentDevicePath Parent Device Path.
+ @param[in] DevicePathNode Child Device Path node.
+ @param[in] PartitionInfo Child Partition Information interface.
+ @param[in] Start Start Block.
+ @param[in] End End Block.
+ @param[in] BlockSize Child block size.
+ @param[in] TypeGuid Parition Type Guid.
+
+ @retval EFI_SUCCESS A child handle was added.
+ @retval other A child handle was not added.
+
+**/
+EFI_STATUS
+PartitionInstallChildHandle (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ParentHandle,
+ IN EFI_DISK_IO_PROTOCOL *ParentDiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *ParentDiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *ParentBlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *ParentBlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePathNode,
+ IN EFI_PARTITION_INFO_PROTOCOL *PartitionInfo,
+ IN EFI_LBA Start,
+ IN EFI_LBA End,
+ IN UINT32 BlockSize,
+ IN EFI_GUID *TypeGuid
+ );
+
+/**
+ Test to see if there is any child on ControllerHandle.
+
+ @param[in] ControllerHandle Handle of device to test.
+
+ @retval TRUE There are children on the ControllerHandle.
+ @retval FALSE No child is on the ControllerHandle.
+
+**/
+BOOLEAN
+HasChildren (
+ IN EFI_HANDLE ControllerHandle
+ );
+
+/**
+ Install child handles if the Handle supports GPT partition structure.
+
+ @param[in] This Calling context.
+ @param[in] Handle Parent Handle.
+ @param[in] DiskIo Parent DiskIo interface.
+ @param[in] DiskIo2 Parent DiskIo2 interface.
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] BlockIo2 Parent BlockIo2 interface.
+ @param[in] DevicePath Parent Device Path.
+
+ @retval EFI_SUCCESS Valid GPT disk.
+ @retval EFI_MEDIA_CHANGED Media changed Detected.
+ @retval EFI_INVALID_PARAMETER If both BlockIo and BlockIo2 are NULL;
+ @retval other Not a valid GPT disk.
+
+**/
+EFI_STATUS
+PartitionInstallGptChildHandles (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+/**
+ Install child handles if the Handle supports El Torito format.
+
+ @param[in] This Calling context.
+ @param[in] Handle Parent Handle.
+ @param[in] DiskIo Parent DiskIo interface.
+ @param[in] DiskIo2 Parent DiskIo2 interface.
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] BlockIo2 Parent BlockIo2 interface.
+ @param[in] DevicePath Parent Device Path
+
+
+ @retval EFI_SUCCESS Child handle(s) was added.
+ @retval EFI_MEDIA_CHANGED Media changed Detected.
+ @retval other no child handle was added.
+
+**/
+EFI_STATUS
+PartitionInstallElToritoChildHandles (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+/**
+ Install child handles if the Handle supports MBR format.
+
+ @param[in] This Calling context.
+ @param[in] Handle Parent Handle.
+ @param[in] DiskIo Parent DiskIo interface.
+ @param[in] DiskIo2 Parent DiskIo2 interface.
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] BlockIo2 Parent BlockIo2 interface.
+ @param[in] DevicePath Parent Device Path.
+
+ @retval EFI_SUCCESS A child handle was added.
+ @retval EFI_MEDIA_CHANGED Media change was detected.
+ @retval Others MBR partition was not found.
+
+**/
+EFI_STATUS
+PartitionInstallMbrChildHandles (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+/**
+ Install child handles if the Handle supports UDF/ECMA-167 volume format.
+
+ @param[in] This Calling context.
+ @param[in] Handle Parent Handle.
+ @param[in] DiskIo Parent DiskIo interface.
+ @param[in] DiskIo2 Parent DiskIo2 interface.
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] BlockIo2 Parent BlockIo2 interface.
+ @param[in] DevicePath Parent Device Path
+
+
+ @retval EFI_SUCCESS Child handle(s) was added.
+ @retval EFI_MEDIA_CHANGED Media changed Detected.
+ @retval other no child handle was added.
+
+**/
+EFI_STATUS
+PartitionInstallUdfChildHandles (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+#ifdef VBOX
+/**
+ Install child handles if the Handle supports Apple format.
+
+ @param[in] This Calling context.
+ @param[in] Handle Parent Handle.
+ @param[in] DiskIo Parent DiskIo interface.
+ @param[in] DiskIo2 Parent DiskIo2 interface.
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] BlockIo2 Parent BlockIo2 interface.
+ @param[in] DevicePath Parent Device Path.
+
+ @retval EFI_SUCCESS A child handle was added.
+ @retval EFI_MEDIA_CHANGED Media change was detected.
+ @retval Others Apple partition was not found.
+
+**/
+EFI_STATUS
+PartitionInstallAppleChildHandles (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+#endif
+
+typedef
+EFI_STATUS
+(*PARTITION_DETECT_ROUTINE) (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf
new file mode 100644
index 00000000..392d19de
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf
@@ -0,0 +1,86 @@
+## @file
+# Modules that produces the logic Block I/O protocol for every partition via the physical Block I/O.
+#
+# This module produces the logical Block I/O device that represents
+# the bytes from Start to End of the Parent Block I/O device.
+# The partition of physical BlockIo device supported is one of legacy MBR, GPT,
+# UDF and "El Torito" partitions.
+#
+# Caution: This module requires additional review when modified.
+# This driver will have external input - disk partition.
+# This external input must be validated carefully to avoid security issue like
+# buffer overflow, integer overflow.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PartitionDxe
+ MODULE_UNI_FILE = PartitionDxe.uni
+ FILE_GUID = 1FA1F39E-FEFF-4aae-BD7B-38A070A3B609
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializePartition
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# DRIVER_BINDING = gPartitionDriverBinding
+# COMPONENT_NAME = gPartitionComponentName
+# COMPONENT_NAME2 = gPartitionComponentName2
+#
+
+[Sources]
+ ComponentName.c
+ Mbr.c
+ Gpt.c
+ ElTorito.c
+ Udf.c
+ Apple.c # VBox specific
+ Partition.c
+ Partition.h
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+
+[LibraryClasses]
+ DevicePathLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ UefiLib
+ BaseLib
+ UefiDriverEntryPoint
+ DebugLib
+
+
+[Guids]
+ gEfiPartTypeUnusedGuid ## SOMETIMES_CONSUMES ## GUID
+ ## SOMETIMES_CONSUMES ## GUID
+ ## SOMETIMES_CONSUMES ## GUID # Install protocol
+ gEfiPartTypeSystemPartGuid
+
+
+[Protocols]
+ ## BY_START
+ ## TO_START
+ gEfiBlockIoProtocolGuid
+ ## BY_START
+ ## TO_START
+ gEfiBlockIo2ProtocolGuid
+ ## BY_START
+ ## TO_START
+ gEfiDevicePathProtocolGuid
+ gEfiPartitionInfoProtocolGuid ## BY_START
+ gEfiDiskIoProtocolGuid ## TO_START
+ gEfiDiskIo2ProtocolGuid ## TO_START
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ PartitionDxeExtra.uni
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.uni
new file mode 100644
index 00000000..e22c47bb
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.uni
@@ -0,0 +1,24 @@
+// /** @file
+// Modules that produces the logic Block I/O protocol for every partition via the physical Block I/O.
+//
+// This module produces the logical Block I/O device that represents
+// the bytes from Start to End of the Parent Block I/O device.
+// The partition of physical BlockIo device supported is one of legacy MBR, GPT,
+// and "El Torito" partitions.
+//
+// Caution: This module requires additional review when modified.
+// This driver will have external input - disk partition.
+// This external input must be validated carefully to avoid security issue like
+// buffer overflow, integer overflow.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces the logic Block I/O protocol for every partition via the physical Block I/O."
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module produces the logical Block I/O device that represents the bytes from Start to End of the Parent Block I/O device. The partition of physical BlockIO device supported is one of legacy MBR, GPT, and \"El Torito\" partitions.<BR><BR>"
+
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxeExtra.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxeExtra.uni
new file mode 100644
index 00000000..f92d2e53
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// PartitionDxe 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
+"Partition DXE Driver"
+
+
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c
new file mode 100644
index 00000000..b321bf71
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/PartitionDxe/Udf.c
@@ -0,0 +1,788 @@
+/** @file
+ Scan for an UDF file system on a formatted media.
+
+ Caution: This file requires additional review when modified.
+ This driver will have external input - CD/DVD media.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ FindUdfFileSystem() routine will consume the media properties and do basic
+ validation.
+
+ Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
+ Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
+ Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "Partition.h"
+
+#define MAX_CORRECTION_BLOCKS_NUM 512u
+
+//
+// C5BD4D42-1A76-4996-8956-73CDA326CD0A
+//
+#define EFI_UDF_DEVICE_PATH_GUID \
+ { 0xC5BD4D42, 0x1A76, 0x4996, \
+ { 0x89, 0x56, 0x73, 0xCD, 0xA3, 0x26, 0xCD, 0x0A } \
+ }
+
+typedef struct {
+ VENDOR_DEVICE_PATH DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} UDF_DEVICE_PATH;
+
+//
+// Vendor-Defined Device Path GUID for UDF file system
+//
+EFI_GUID gUdfDevPathGuid = EFI_UDF_DEVICE_PATH_GUID;
+
+//
+// Vendor-Defined Media Device Path for UDF file system
+//
+UDF_DEVICE_PATH gUdfDevicePath = {
+ { { MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP,
+ { sizeof (VENDOR_DEVICE_PATH), 0 } },
+ EFI_UDF_DEVICE_PATH_GUID
+ },
+ { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
+ }
+};
+
+/**
+ Find the anchor volume descriptor pointer.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[out] AnchorPoint Anchor volume descriptor pointer.
+ @param[out] LastRecordedBlock Last recorded block.
+
+ @retval EFI_SUCCESS Anchor volume descriptor pointer found.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval other Anchor volume descriptor pointer not found.
+
+**/
+EFI_STATUS
+FindAnchorVolumeDescriptorPointer (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ OUT UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoint,
+ OUT EFI_LBA *LastRecordedBlock
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ EFI_LBA EndLBA;
+ UDF_DESCRIPTOR_TAG *DescriptorTag;
+ UINTN AvdpsCount;
+ UINTN Size;
+ UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoints;
+ INTN Index;
+ UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPointPtr;
+ EFI_LBA LastAvdpBlockNum;
+
+ //
+ // UDF 2.60, 2.2.3 Anchor Volume Descriptor Pointer
+ //
+ // An Anchor Volume Descriptor Pointer structure shall be recorded in at
+ // least 2 of the following 3 locations on the media: Logical Sector 256,
+ // N - 256 or N, where N is the last *addressable* sector of a volume.
+ //
+ // To figure out what logical sector N is, the SCSI commands READ CAPACITY and
+ // READ TRACK INFORMATION are used, however many drives or medias report their
+ // "last recorded block" wrongly. Although, READ CAPACITY returns the last
+ // readable data block but there might be unwritten blocks, which are located
+ // outside any track and therefore AVDP will not be found at block N.
+ //
+ // That said, we define a magic number of 512 blocks to be used as correction
+ // when attempting to find AVDP and define last block number.
+ //
+ BlockSize = BlockIo->Media->BlockSize;
+ EndLBA = BlockIo->Media->LastBlock;
+ *LastRecordedBlock = EndLBA;
+ AvdpsCount = 0;
+
+ //
+ // Check if the block size of the underlying media can hold the data of an
+ // Anchor Volume Descriptor Pointer
+ //
+ if (BlockSize < sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Media block size 0x%x unable to hold an AVDP.\n",
+ __FUNCTION__,
+ BlockSize
+ ));
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Find AVDP at block 256
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 (256, BlockSize),
+ sizeof (*AnchorPoint),
+ AnchorPoint
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DescriptorTag = &AnchorPoint->DescriptorTag;
+
+ //
+ // Check if read block is a valid AVDP descriptor
+ //
+ if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {
+ DEBUG ((DEBUG_INFO, "%a: found AVDP at block %d\n", __FUNCTION__, 256));
+ AvdpsCount++;
+ }
+
+ //
+ // Find AVDP at block N - 256
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 ((UINT64)EndLBA - 256, BlockSize),
+ sizeof (*AnchorPoint),
+ AnchorPoint
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check if read block is a valid AVDP descriptor
+ //
+ if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer &&
+ ++AvdpsCount == 2) {
+ DEBUG ((DEBUG_INFO, "%a: found AVDP at block %Ld\n", __FUNCTION__,
+ EndLBA - 256));
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Check if at least one AVDP was found in previous locations
+ //
+ if (AvdpsCount == 0) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ //
+ // Find AVDP at block N
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 ((UINT64)EndLBA, BlockSize),
+ sizeof (*AnchorPoint),
+ AnchorPoint
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check if read block is a valid AVDP descriptor
+ //
+ if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // No AVDP found at block N. Possibly drive/media returned bad last recorded
+ // block, or it is part of unwritten data blocks and outside any track.
+ //
+ // Search backwards for an AVDP from block N-1 through
+ // N-MAX_CORRECTION_BLOCKS_NUM. If any AVDP is found, then correct last block
+ // number for the new UDF partition child handle.
+ //
+ Size = MAX_CORRECTION_BLOCKS_NUM * BlockSize;
+
+ AnchorPoints = AllocateZeroPool (Size);
+ if (AnchorPoints == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Read consecutive MAX_CORRECTION_BLOCKS_NUM disk blocks
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 ((UINT64)EndLBA - MAX_CORRECTION_BLOCKS_NUM, BlockSize),
+ Size,
+ AnchorPoints
+ );
+ if (EFI_ERROR (Status)) {
+ goto Out_Free;
+ }
+
+ Status = EFI_VOLUME_CORRUPTED;
+
+ //
+ // Search for AVDP from blocks N-1 through N-MAX_CORRECTION_BLOCKS_NUM
+ //
+ for (Index = MAX_CORRECTION_BLOCKS_NUM - 2; Index >= 0; Index--) {
+ AnchorPointPtr = (VOID *)((UINTN)AnchorPoints + Index * BlockSize);
+
+ DescriptorTag = &AnchorPointPtr->DescriptorTag;
+
+ //
+ // Check if read block is a valid AVDP descriptor
+ //
+ if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {
+ //
+ // Calculate last recorded block number
+ //
+ LastAvdpBlockNum = EndLBA - (MAX_CORRECTION_BLOCKS_NUM - Index);
+ DEBUG ((DEBUG_WARN, "%a: found AVDP at block %Ld\n", __FUNCTION__,
+ LastAvdpBlockNum));
+ DEBUG ((DEBUG_WARN, "%a: correcting last block from %Ld to %Ld\n",
+ __FUNCTION__, EndLBA, LastAvdpBlockNum));
+ //
+ // Save read AVDP from last block
+ //
+ CopyMem (AnchorPoint, AnchorPointPtr, sizeof (*AnchorPointPtr));
+ //
+ // Set last recorded block number
+ //
+ *LastRecordedBlock = LastAvdpBlockNum;
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+
+Out_Free:
+ FreePool (AnchorPoints);
+ return Status;
+}
+
+/**
+ Find UDF volume identifiers in a Volume Recognition Sequence.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+
+ @retval EFI_SUCCESS UDF volume identifiers were found.
+ @retval EFI_NOT_FOUND UDF volume identifiers were not found.
+ @retval other Failed to perform disk I/O.
+
+**/
+EFI_STATUS
+FindUdfVolumeIdentifiers (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Offset;
+ UINT64 EndDiskOffset;
+ CDROM_VOLUME_DESCRIPTOR VolDescriptor;
+ CDROM_VOLUME_DESCRIPTOR TerminatingVolDescriptor;
+
+ ZeroMem ((VOID *)&TerminatingVolDescriptor, sizeof (CDROM_VOLUME_DESCRIPTOR));
+
+ //
+ // Start Volume Recognition Sequence
+ //
+ EndDiskOffset = MultU64x32 (BlockIo->Media->LastBlock,
+ BlockIo->Media->BlockSize);
+
+ for (Offset = UDF_VRS_START_OFFSET; Offset < EndDiskOffset;
+ Offset += UDF_LOGICAL_SECTOR_SIZE) {
+ //
+ // Check if block device has a Volume Structure Descriptor and an Extended
+ // Area.
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ Offset,
+ sizeof (CDROM_VOLUME_DESCRIPTOR),
+ (VOID *)&VolDescriptor
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (CompareMem ((VOID *)VolDescriptor.Unknown.Id,
+ (VOID *)UDF_BEA_IDENTIFIER,
+ sizeof (VolDescriptor.Unknown.Id)) == 0) {
+ break;
+ }
+
+ if ((CompareMem ((VOID *)VolDescriptor.Unknown.Id,
+ (VOID *)CDVOL_ID,
+ sizeof (VolDescriptor.Unknown.Id)) != 0) ||
+ (CompareMem ((VOID *)&VolDescriptor,
+ (VOID *)&TerminatingVolDescriptor,
+ sizeof (CDROM_VOLUME_DESCRIPTOR)) == 0)) {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ //
+ // Look for "NSR0{2,3}" identifiers in the Extended Area.
+ //
+ Offset += UDF_LOGICAL_SECTOR_SIZE;
+ if (Offset >= EndDiskOffset) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ Offset,
+ sizeof (CDROM_VOLUME_DESCRIPTOR),
+ (VOID *)&VolDescriptor
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((CompareMem ((VOID *)VolDescriptor.Unknown.Id,
+ (VOID *)UDF_NSR2_IDENTIFIER,
+ sizeof (VolDescriptor.Unknown.Id)) != 0) &&
+ (CompareMem ((VOID *)VolDescriptor.Unknown.Id,
+ (VOID *)UDF_NSR3_IDENTIFIER,
+ sizeof (VolDescriptor.Unknown.Id)) != 0)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Look for "TEA01" identifier in the Extended Area
+ //
+ Offset += UDF_LOGICAL_SECTOR_SIZE;
+ if (Offset >= EndDiskOffset) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ Offset,
+ sizeof (CDROM_VOLUME_DESCRIPTOR),
+ (VOID *)&VolDescriptor
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (CompareMem ((VOID *)VolDescriptor.Unknown.Id,
+ (VOID *)UDF_TEA_IDENTIFIER,
+ sizeof (VolDescriptor.Unknown.Id)) != 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if Logical Volume Descriptor is supported by current EDK2 UDF file
+ system implementation.
+
+ @param[in] LogicalVolDesc Logical Volume Descriptor pointer.
+
+ @retval TRUE Logical Volume Descriptor is supported.
+ @retval FALSE Logical Volume Descriptor is not supported.
+
+**/
+BOOLEAN
+IsLogicalVolumeDescriptorSupported (
+ UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc
+ )
+{
+ //
+ // Check for a valid UDF revision range
+ //
+ switch (LogicalVolDesc->DomainIdentifier.Suffix.Domain.UdfRevision) {
+ case 0x0102:
+ case 0x0150:
+ case 0x0200:
+ case 0x0201:
+ case 0x0250:
+ case 0x0260:
+ break;
+ default:
+ return FALSE;
+ }
+
+ //
+ // Check for a single Partition Map
+ //
+ if (LogicalVolDesc->NumberOfPartitionMaps > 1) {
+ return FALSE;
+ }
+ //
+ // UDF 1.02 revision supports only Type 1 (Physical) partitions, but
+ // let's check it any way.
+ //
+ // PartitionMap[0] -> type
+ // PartitionMap[1] -> length (in bytes)
+ //
+ if (LogicalVolDesc->PartitionMaps[0] != 1 ||
+ LogicalVolDesc->PartitionMaps[1] != 6) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Find UDF logical volume location and whether it is supported by current EDK2
+ UDF file system implementation.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] AnchorPoint Anchor volume descriptor pointer.
+ @param[in] LastRecordedBlock Last recorded block in media.
+ @param[out] MainVdsStartBlock Main VDS starting block number.
+ @param[out] MainVdsEndBlock Main VDS ending block number.
+
+ @retval EFI_SUCCESS UDF logical volume was found.
+ @retval EFI_VOLUME_CORRUPTED UDF file system structures are corrupted.
+ @retval EFI_UNSUPPORTED UDF logical volume is not supported.
+ @retval other Failed to perform disk I/O.
+
+**/
+EFI_STATUS
+FindLogicalVolumeLocation (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoint,
+ IN EFI_LBA LastRecordedBlock,
+ OUT UINT64 *MainVdsStartBlock,
+ OUT UINT64 *MainVdsEndBlock
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ UDF_EXTENT_AD *ExtentAd;
+ UINT64 SeqBlocksNum;
+ UINT64 SeqStartBlock;
+ UINT64 GuardMainVdsStartBlock;
+ VOID *Buffer;
+ UINT64 SeqEndBlock;
+ BOOLEAN StopSequence;
+ UINTN LvdsCount;
+ UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc;
+ UDF_DESCRIPTOR_TAG *DescriptorTag;
+
+ BlockSize = BlockIo->Media->BlockSize;
+ ExtentAd = &AnchorPoint->MainVolumeDescriptorSequenceExtent;
+
+ //
+ // UDF 2.60, 2.2.3.1 struct MainVolumeDescriptorSequenceExtent
+ //
+ // The Main Volume Descriptor Sequence Extent shall have a minimum length of
+ // 16 logical sectors.
+ //
+ // Also make sure it does not exceed maximum number of blocks in the disk.
+ //
+ SeqBlocksNum = DivU64x32 ((UINT64)ExtentAd->ExtentLength, BlockSize);
+ if (SeqBlocksNum < 16 || (EFI_LBA)SeqBlocksNum > LastRecordedBlock + 1) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ //
+ // Check for valid Volume Descriptor Sequence starting block number
+ //
+ SeqStartBlock = (UINT64)ExtentAd->ExtentLocation;
+ if (SeqStartBlock > LastRecordedBlock ||
+ SeqStartBlock + SeqBlocksNum - 1 > LastRecordedBlock) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ GuardMainVdsStartBlock = SeqStartBlock;
+
+ //
+ // Allocate buffer for reading disk blocks
+ //
+ Buffer = AllocateZeroPool ((UINTN)BlockSize);
+ if (Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SeqEndBlock = SeqStartBlock + SeqBlocksNum;
+ StopSequence = FALSE;
+ LvdsCount = 0;
+ Status = EFI_VOLUME_CORRUPTED;
+ //
+ // Start Main Volume Descriptor Sequence
+ //
+ for (; SeqStartBlock < SeqEndBlock && !StopSequence; SeqStartBlock++) {
+ //
+ // Read disk block
+ //
+ Status = BlockIo->ReadBlocks (
+ BlockIo,
+ BlockIo->Media->MediaId,
+ SeqStartBlock,
+ BlockSize,
+ Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ goto Out_Free;
+ }
+
+ DescriptorTag = Buffer;
+
+ //
+ // ECMA 167, 8.4.1 Contents of a Volume Descriptor Sequence
+ //
+ // - A Volume Descriptor Sequence shall contain one or more Primary Volume
+ // Descriptors.
+ // - A Volume Descriptor Sequence shall contain zero or more Implementation
+ // Use Volume Descriptors.
+ // - A Volume Descriptor Sequence shall contain zero or more Partition
+ // Descriptors.
+ // - A Volume Descriptor Sequence shall contain zero or more Logical Volume
+ // Descriptors.
+ // - A Volume Descriptor Sequence shall contain zero or more Unallocated
+ // Space Descriptors.
+ //
+ switch (DescriptorTag->TagIdentifier) {
+ case UdfPrimaryVolumeDescriptor:
+ case UdfImplemenationUseVolumeDescriptor:
+ case UdfPartitionDescriptor:
+ case UdfUnallocatedSpaceDescriptor:
+ break;
+
+ case UdfLogicalVolumeDescriptor:
+ LogicalVolDesc = Buffer;
+
+ //
+ // Check for existence of a single LVD and whether it is supported by
+ // current EDK2 UDF file system implementation.
+ //
+ if (++LvdsCount > 1 ||
+ !IsLogicalVolumeDescriptorSupported (LogicalVolDesc)) {
+ Status = EFI_UNSUPPORTED;
+ StopSequence = TRUE;
+ }
+
+ break;
+
+ case UdfTerminatingDescriptor:
+ //
+ // Stop the sequence when we find a Terminating Descriptor
+ // (aka Unallocated Sector), se we don't have to walk all the unallocated
+ // area unnecessarily.
+ //
+ StopSequence = TRUE;
+ break;
+
+ default:
+ //
+ // An invalid Volume Descriptor has been found in the sequece. Volume is
+ // corrupted.
+ //
+ Status = EFI_VOLUME_CORRUPTED;
+ goto Out_Free;
+ }
+ }
+
+ //
+ // Check if LVD was found
+ //
+ if (!EFI_ERROR (Status) && LvdsCount == 1) {
+ *MainVdsStartBlock = GuardMainVdsStartBlock;
+ //
+ // We do not need to read either LVD or PD descriptors to know the last
+ // valid block in the found UDF file system. It's already
+ // LastRecordedBlock.
+ //
+ *MainVdsEndBlock = LastRecordedBlock;
+
+ Status = EFI_SUCCESS;
+ }
+
+Out_Free:
+ //
+ // Free block read buffer
+ //
+ FreePool (Buffer);
+
+ return Status;
+}
+
+/**
+ Find a supported UDF file system in block device.
+
+ @attention This is boundary function that may receive untrusted input.
+ @attention The input is from Partition.
+
+ The CD/DVD media is the external input, so this routine will do basic
+ validation for the media.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[out] StartingLBA UDF file system starting LBA.
+ @param[out] EndingLBA UDF file system starting LBA.
+
+ @retval EFI_SUCCESS UDF file system was found.
+ @retval other UDF file system was not found.
+
+**/
+EFI_STATUS
+FindUdfFileSystem (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ OUT EFI_LBA *StartingLBA,
+ OUT EFI_LBA *EndingLBA
+ )
+{
+ EFI_STATUS Status;
+ UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER AnchorPoint;
+ EFI_LBA LastRecordedBlock;
+
+ //
+ // Find UDF volume identifiers
+ //
+ Status = FindUdfVolumeIdentifiers (BlockIo, DiskIo);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Find Anchor Volume Descriptor Pointer
+ //
+ Status = FindAnchorVolumeDescriptorPointer (
+ BlockIo,
+ DiskIo,
+ &AnchorPoint,
+ &LastRecordedBlock
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Find Logical Volume location
+ //
+ Status = FindLogicalVolumeLocation (
+ BlockIo,
+ DiskIo,
+ &AnchorPoint,
+ LastRecordedBlock,
+ (UINT64 *)StartingLBA,
+ (UINT64 *)EndingLBA
+ );
+
+ return Status;
+}
+
+/**
+ Install child handles if the Handle supports UDF/ECMA-167 volume format.
+
+ @param[in] This Calling context.
+ @param[in] Handle Parent Handle.
+ @param[in] DiskIo Parent DiskIo interface.
+ @param[in] DiskIo2 Parent DiskIo2 interface.
+ @param[in] BlockIo Parent BlockIo interface.
+ @param[in] BlockIo2 Parent BlockIo2 interface.
+ @param[in] DevicePath Parent Device Path
+
+
+ @retval EFI_SUCCESS Child handle(s) was added.
+ @retval EFI_MEDIA_CHANGED Media changed Detected.
+ @retval other no child handle was added.
+
+**/
+EFI_STATUS
+PartitionInstallUdfChildHandles (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ UINT32 RemainderByMediaBlockSize;
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
+ EFI_LBA StartingLBA;
+ EFI_LBA EndingLBA;
+ BOOLEAN ChildCreated;
+
+ Media = BlockIo->Media;
+ ChildCreated = FALSE;
+
+ //
+ // Check if UDF logical block size is multiple of underlying device block size
+ //
+ DivU64x32Remainder (
+ UDF_LOGICAL_SECTOR_SIZE, // Dividend
+ Media->BlockSize, // Divisor
+ &RemainderByMediaBlockSize // Remainder
+ );
+ if (RemainderByMediaBlockSize != 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Detect El Torito feature first.
+ // And always continue to search for UDF.
+ //
+ Status = PartitionInstallElToritoChildHandles (
+ This,
+ Handle,
+ DiskIo,
+ DiskIo2,
+ BlockIo,
+ BlockIo2,
+ DevicePath
+ );
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "PartitionDxe: El Torito standard found on handle 0x%p.\n", Handle));
+ ChildCreated = TRUE;
+ }
+
+ //
+ // Search for an UDF file system on block device
+ //
+ Status = FindUdfFileSystem (BlockIo, DiskIo, &StartingLBA, &EndingLBA);
+ if (EFI_ERROR (Status)) {
+ return (ChildCreated ? EFI_SUCCESS : EFI_NOT_FOUND);
+ }
+
+ //
+ // Create Partition Info protocol for UDF file system
+ //
+ ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
+ PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
+ PartitionInfo.Type = PARTITION_TYPE_OTHER;
+
+ //
+ // Install partition child handle for UDF file system
+ //
+ Status = PartitionInstallChildHandle (
+ This,
+ Handle,
+ DiskIo,
+ DiskIo2,
+ BlockIo,
+ BlockIo2,
+ DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *)&gUdfDevicePath,
+ &PartitionInfo,
+ StartingLBA,
+ EndingLBA,
+ Media->BlockSize,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return (ChildCreated ? EFI_SUCCESS : Status);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDisk.asl b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDisk.asl
new file mode 100644
index 00000000..2213204b
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDisk.asl
@@ -0,0 +1,38 @@
+/** @file
+ The definition block in ACPI table for NVDIMM root device.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+DefinitionBlock (
+ "RamDisk.aml",
+ "SSDT",
+ 2,
+ "INTEL ",
+ "RamDisk ",
+ 0x1000
+ )
+{
+ Scope (\_SB)
+ {
+ Device (NVDR)
+ {
+ //
+ // Define _HID, "ACPI0012" NVDIMM Root Device
+ //
+ Name (_HID, "ACPI0012")
+
+ //
+ // Readable name of this device
+ //
+ Name (_STR, Unicode ("NVDIMM Root Device"))
+
+ Method (_STA, 0)
+ {
+ Return (0x0f)
+ }
+ }
+ }
+}
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskBlockIo.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskBlockIo.c
new file mode 100644
index 00000000..370fa096
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskBlockIo.c
@@ -0,0 +1,487 @@
+/** @file
+ Produce EFI_BLOCK_IO_PROTOCOL on a RAM disk device.
+
+ Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RamDiskImpl.h"
+
+//
+// The EFI_BLOCK_IO_PROTOCOL instances that is installed onto the handle
+// for newly registered RAM disks
+//
+EFI_BLOCK_IO_PROTOCOL mRamDiskBlockIoTemplate = {
+ EFI_BLOCK_IO_PROTOCOL_REVISION,
+ (EFI_BLOCK_IO_MEDIA *) 0,
+ RamDiskBlkIoReset,
+ RamDiskBlkIoReadBlocks,
+ RamDiskBlkIoWriteBlocks,
+ RamDiskBlkIoFlushBlocks
+};
+
+//
+// The EFI_BLOCK_IO_PROTOCOL2 instances that is installed onto the handle
+// for newly registered RAM disks
+//
+EFI_BLOCK_IO2_PROTOCOL mRamDiskBlockIo2Template = {
+ (EFI_BLOCK_IO_MEDIA *) 0,
+ RamDiskBlkIo2Reset,
+ RamDiskBlkIo2ReadBlocksEx,
+ RamDiskBlkIo2WriteBlocksEx,
+ RamDiskBlkIo2FlushBlocksEx
+};
+
+
+/**
+ Initialize the BlockIO & BlockIO2 protocol of a RAM disk device.
+
+ @param[in] PrivateData Points to RAM disk private data.
+
+**/
+VOID
+RamDiskInitBlockIo (
+ IN RAM_DISK_PRIVATE_DATA *PrivateData
+ )
+{
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_BLOCK_IO2_PROTOCOL *BlockIo2;
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINT32 Remainder;
+
+ BlockIo = &PrivateData->BlockIo;
+ BlockIo2 = &PrivateData->BlockIo2;
+ Media = &PrivateData->Media;
+
+ CopyMem (BlockIo, &mRamDiskBlockIoTemplate, sizeof (EFI_BLOCK_IO_PROTOCOL));
+ CopyMem (BlockIo2, &mRamDiskBlockIo2Template, sizeof (EFI_BLOCK_IO2_PROTOCOL));
+
+ BlockIo->Media = Media;
+ BlockIo2->Media = Media;
+ Media->RemovableMedia = FALSE;
+ Media->MediaPresent = TRUE;
+ Media->LogicalPartition = FALSE;
+ Media->ReadOnly = FALSE;
+ Media->WriteCaching = FALSE;
+
+ for (Media->BlockSize = RAM_DISK_DEFAULT_BLOCK_SIZE;
+ Media->BlockSize >= 1;
+ Media->BlockSize = Media->BlockSize >> 1) {
+ Media->LastBlock = DivU64x32Remainder (PrivateData->Size, Media->BlockSize, &Remainder) - 1;
+ if (Remainder == 0) {
+ break;
+ }
+ }
+ ASSERT (Media->BlockSize != 0);
+
+ return;
+}
+
+
+/**
+ Reset the Block Device.
+
+ @param This Indicates a pointer to the calling context.
+ @param ExtendedVerification Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could
+ not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskBlkIoReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId Id of the media, changes every time the media is
+ replaced.
+ @param[in] Lba The starting Logical Block Address to read from.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block
+ size.
+ @param[out] Buffer A pointer to the destination buffer for the data.
+ The caller is responsible for either having
+ implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing
+ the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not matched the current
+ device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block
+ size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
+ valid, or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskBlkIoReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ RAM_DISK_PRIVATE_DATA *PrivateData;
+ UINTN NumberOfBlocks;
+
+ PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO (This);
+
+ if (MediaId != PrivateData->Media.MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ if ((BufferSize % PrivateData->Media.BlockSize) != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (Lba > PrivateData->Media.LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ NumberOfBlocks = BufferSize / PrivateData->Media.BlockSize;
+ if ((Lba + NumberOfBlocks - 1) > PrivateData->Media.LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CopyMem (
+ Buffer,
+ (VOID *)(UINTN)(PrivateData->StartingAddr + MultU64x32 (Lba, PrivateData->Media.BlockSize)),
+ BufferSize
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the write request is for.
+ @param[in] Lba The starting logical block address to be written.
+ The caller is responsible for writing to only
+ legitimate locations.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block
+ size.
+ @param[in] Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The data was written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing
+ the write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current
+ device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block
+ size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not
+ valid, or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskBlkIoWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ RAM_DISK_PRIVATE_DATA *PrivateData;
+ UINTN NumberOfBlocks;
+
+ PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO (This);
+
+ if (MediaId != PrivateData->Media.MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (TRUE == PrivateData->Media.ReadOnly) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ if ((BufferSize % PrivateData->Media.BlockSize) != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (Lba > PrivateData->Media.LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ NumberOfBlocks = BufferSize / PrivateData->Media.BlockSize;
+ if ((Lba + NumberOfBlocks - 1) > PrivateData->Media.LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CopyMem (
+ (VOID *)(UINTN)(PrivateData->StartingAddr + MultU64x32 (Lba, PrivateData->Media.BlockSize)),
+ Buffer,
+ BufferSize
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Flush the Block Device.
+
+ @param[in] This Indicates a pointer to the calling context.
+
+ @retval EFI_SUCCESS All outstanding data was written to the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while writting
+ back the data
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskBlkIoFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ )
+{
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Resets the block device hardware.
+
+ @param[in] This The pointer of EFI_BLOCK_IO2_PROTOCOL.
+ @param[in] ExtendedVerification The flag about if extend verificate.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The block device is not functioning correctly
+ and could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskBlkIo2Reset (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Reads the requested number of blocks from the device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the read request is for.
+ @param[in] Lba The starting logical block address to read
+ from on the device.
+ @param[in, out] Token A pointer to the token associated with the
+ transaction.
+ @param[in] BufferSize The size of the Buffer in bytes. This must be
+ a multiple of the intrinsic block size of the
+ device.
+ @param[out] Buffer A pointer to the destination buffer for the
+ data. The caller is responsible for either
+ having implicit or explicit ownership of the
+ buffer.
+
+ @retval EFI_SUCCESS The read request was queued if Token->Event
+ is not NULL. The data was read correctly from
+ the device if the Token->Event is NULL.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting
+ to perform the read operation.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
+ the intrinsic block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
+ valid, or the buffer is not on proper
+ alignment.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskBlkIo2ReadBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ RAM_DISK_PRIVATE_DATA *PrivateData;
+ EFI_STATUS Status;
+
+ PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO2 (This);
+
+ Status = RamDiskBlkIoReadBlocks (
+ &PrivateData->BlockIo,
+ MediaId,
+ Lba,
+ BufferSize,
+ Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // If caller's event is given, signal it after the memory read completes.
+ //
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ gBS->SignalEvent (Token->Event);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Writes a specified number of blocks to the device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the write request is for.
+ @param[in] Lba The starting logical block address to be
+ written. The caller is responsible for
+ writing to only legitimate locations.
+ @param[in, out] Token A pointer to the token associated with the
+ transaction.
+ @param[in] BufferSize The size in bytes of Buffer. This must be a
+ multiple of the intrinsic block size of the
+ device.
+ @param[in] Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The write request was queued if Event is not
+ NULL. The data was written correctly to the
+ device if the Event is NULL.
+ @retval EFI_WRITE_PROTECTED The device cannot be written to.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting
+ to perform the write operation.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
+ the intrinsic block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not
+ valid, or the buffer is not on proper
+ alignment.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskBlkIo2WriteBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ RAM_DISK_PRIVATE_DATA *PrivateData;
+ EFI_STATUS Status;
+
+ PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO2 (This);
+
+ Status = RamDiskBlkIoWriteBlocks (
+ &PrivateData->BlockIo,
+ MediaId,
+ Lba,
+ BufferSize,
+ Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // If caller's event is given, signal it after the memory write completes.
+ //
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ gBS->SignalEvent (Token->Event);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Flushes all modified data to a physical block device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in, out] Token A pointer to the token associated with the
+ transaction.
+
+ @retval EFI_SUCCESS The flush request was queued if Event is not
+ NULL. All outstanding data was written
+ correctly to the device if the Event is NULL.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting
+ to write data.
+ @retval EFI_WRITE_PROTECTED The device cannot be written to.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskBlkIo2FlushBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token
+ )
+{
+ RAM_DISK_PRIVATE_DATA *PrivateData;
+
+ PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO2 (This);
+
+ if (TRUE == PrivateData->Media.ReadOnly) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ //
+ // If caller's event is given, signal it directly.
+ //
+ if ((Token != NULL) && (Token->Event != NULL)) {
+ Token->TransactionStatus = EFI_SUCCESS;
+ gBS->SignalEvent (Token->Event);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDriver.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDriver.c
new file mode 100644
index 00000000..8c632ebc
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDriver.c
@@ -0,0 +1,244 @@
+/** @file
+ The driver entry point for RamDiskDxe driver.
+
+ Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) Microsoft Corporation.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RamDiskImpl.h"
+
+//
+// Handle for the EFI_RAM_DISK_PROTOCOL instance
+//
+EFI_HANDLE mRamDiskHandle = NULL;
+
+//
+// The EFI_RAM_DISK_PROTOCOL instances that is installed onto the driver
+// handle
+//
+EFI_RAM_DISK_PROTOCOL mRamDiskProtocol = {
+ RamDiskRegister,
+ RamDiskUnregister
+};
+
+//
+// RamDiskDxe driver maintains a list of registered RAM disks.
+//
+LIST_ENTRY RegisteredRamDisks;
+
+//
+// Pointers to the EFI_ACPI_TABLE_PROTOCOL and EFI_ACPI_SDT_PROTOCOL.
+//
+EFI_ACPI_TABLE_PROTOCOL *mAcpiTableProtocol = NULL;
+EFI_ACPI_SDT_PROTOCOL *mAcpiSdtProtocol = NULL;
+
+
+/**
+ Check whether EFI_ACPI_TABLE_PROTOCOL and EFI_ACPI_SDT_PROTOCOL are produced.
+ If both protocols are produced, publish all the reserved memory type RAM
+ disks to the NVDIMM Firmware Interface Table (NFIT).
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context The pointer to the notification function's context,
+ which is implementation-dependent.
+
+**/
+VOID
+EFIAPI
+RamDiskAcpiCheck (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Entry;
+ RAM_DISK_PRIVATE_DATA *PrivateData;
+
+ gBS->CloseEvent (Event);
+
+ //
+ // Locate the EFI_ACPI_TABLE_PROTOCOL.
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiAcpiTableProtocolGuid,
+ NULL,
+ (VOID **)&mAcpiTableProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ EFI_D_INFO,
+ "RamDiskAcpiCheck: Cannot locate the EFI ACPI Table Protocol, "
+ "unable to publish RAM disks to NFIT.\n"
+ ));
+ return;
+ }
+
+ //
+ // Locate the EFI_ACPI_SDT_PROTOCOL.
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiAcpiSdtProtocolGuid,
+ NULL,
+ (VOID **)&mAcpiSdtProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ EFI_D_INFO,
+ "RamDiskAcpiCheck: Cannot locate the EFI ACPI Sdt Protocol, "
+ "unable to publish RAM disks to NFIT.\n"
+ ));
+ mAcpiTableProtocol = NULL;
+ return;
+ }
+
+ BASE_LIST_FOR_EACH (Entry, &RegisteredRamDisks) {
+ PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry);
+ RamDiskPublishNfit (PrivateData);
+ }
+}
+
+
+/**
+ The entry point for RamDiskDxe driver.
+
+ @param[in] ImageHandle The image handle of the driver.
+ @param[in] SystemTable The system table.
+
+ @retval EFI_ALREADY_STARTED The driver already exists in system.
+ @retval EFI_OUT_OF_RESOURCES Fail to execute entry point due to lack of
+ resources.
+ @retval EFI_SUCCES All the related protocols are installed on
+ the driver.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskDxeEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivate;
+ VOID *DummyInterface;
+ EFI_EVENT Event;
+
+ //
+ // If already started, return.
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiRamDiskProtocolGuid,
+ NULL,
+ &DummyInterface
+ );
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "Driver already started!\n"));
+ return EFI_ALREADY_STARTED;
+ }
+
+ //
+ // Create a private data structure.
+ //
+ ConfigPrivate = AllocateCopyPool (sizeof (RAM_DISK_CONFIG_PRIVATE_DATA), &mRamDiskConfigPrivateDataTemplate);
+ if (ConfigPrivate == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Install RAM disk configuration form
+ //
+ Status = InstallRamDiskConfigForm (ConfigPrivate);
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ //
+ // Install the EFI_RAM_DISK_PROTOCOL and RAM disk private data onto a
+ // new handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mRamDiskHandle,
+ &gEfiRamDiskProtocolGuid,
+ &mRamDiskProtocol,
+ &gEfiCallerIdGuid,
+ ConfigPrivate,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ //
+ // Initialize the list of registered RAM disks maintained by the driver
+ //
+ InitializeListHead (&RegisteredRamDisks);
+
+ Status = EfiCreateEventReadyToBootEx (
+ TPL_CALLBACK,
+ RamDiskAcpiCheck,
+ NULL,
+ &Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+
+ErrorExit:
+ if (ConfigPrivate != NULL) {
+ UninstallRamDiskConfigForm (ConfigPrivate);
+ }
+
+ return Status;
+}
+
+
+/**
+ Unload the RamDiskDxe driver and its configuration form.
+
+ @param[in] ImageHandle The driver's image handle.
+
+ @retval EFI_SUCCESS The RamDiskDxe driver and its configuration
+ form is unloaded.
+ @retval Others Failed to unload the form.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskDxeUnload (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivate;
+
+ Status = gBS->HandleProtocol (
+ mRamDiskHandle,
+ &gEfiCallerIdGuid,
+ (VOID **) &ConfigPrivate
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ASSERT (ConfigPrivate->Signature == RAM_DISK_CONFIG_PRIVATE_DATA_SIGNATURE);
+
+ //
+ // Unregister all registered RAM disks
+ //
+ UnregisterAllRamDisks ();
+
+ gBS->UninstallMultipleProtocolInterfaces (
+ mRamDiskHandle,
+ &gEfiRamDiskProtocolGuid,
+ &mRamDiskProtocol,
+ &gEfiCallerIdGuid,
+ ConfigPrivate,
+ NULL
+ );
+
+ UninstallRamDiskConfigForm (ConfigPrivate);
+
+ return EFI_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.inf b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.inf
new file mode 100644
index 00000000..5e71b6c8
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.inf
@@ -0,0 +1,84 @@
+## @file
+# Produces EFI_RAM_DISK_PROTOCOL and provides the capability to
+# create/remove RAM disks in a setup browser.
+#
+# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = RamDiskDxe
+ MODULE_UNI_FILE = RamDiskDxe.uni
+ FILE_GUID = 28A03FF4-12B3-4305-A417-BB1A4F94081E
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = RamDiskDxeEntryPoint
+ UNLOAD_IMAGE = RamDiskDxeUnload
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64
+#
+
+[Sources]
+ RamDiskDriver.c
+ RamDiskImpl.c
+ RamDiskBlockIo.c
+ RamDiskProtocol.c
+ RamDiskFileExplorer.c
+ RamDiskImpl.h
+ RamDiskHii.vfr
+ RamDiskHiiStrings.uni
+ RamDiskNVData.h
+ RamDisk.asl
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ UefiLib
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ UefiHiiServicesLib
+ MemoryAllocationLib
+ HiiLib
+ FileExplorerLib
+ DevicePathLib
+ PrintLib
+ PcdLib
+ DxeServicesLib
+
+[Guids]
+ gEfiIfrTianoGuid ## PRODUCES ## GUID # HII opcode
+ ## PRODUCES ## HII
+ ## CONSUMES ## HII
+ gRamDiskFormSetGuid
+ gEfiVirtualDiskGuid ## SOMETIMES_CONSUMES ## GUID
+ gEfiFileInfoGuid ## SOMETIMES_CONSUMES ## GUID # Indicate the information type
+
+[Protocols]
+ gEfiRamDiskProtocolGuid ## PRODUCES
+ gEfiHiiConfigAccessProtocolGuid ## PRODUCES
+ gEfiDevicePathProtocolGuid ## PRODUCES
+ gEfiBlockIoProtocolGuid ## PRODUCES
+ gEfiBlockIo2ProtocolGuid ## PRODUCES
+ gEfiAcpiTableProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiAcpiSdtProtocolGuid ## SOMETIMES_CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision ## SOMETIMES_CONSUMES
+
+[Depex]
+ gEfiHiiConfigRoutingProtocolGuid AND
+ gEfiHiiDatabaseProtocolGuid
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.uni
new file mode 100644
index 00000000..edf35ea1
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.uni
@@ -0,0 +1,14 @@
+// /** @file
+// Produces EFI_RAM_DISK_PROTOCOL and provides the capability to
+// create/remove RAM disks in a setup browser.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces EFI_RAM_DISK_PROTOCOL and provides the capability to create/remove RAM disks in a setup browser."
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module produces EFI_RAM_DISK_PROTOCOL and provides the capability to create/remove RAM disks in a setup browser."
+
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskFileExplorer.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskFileExplorer.c
new file mode 100644
index 00000000..3205c114
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskFileExplorer.c
@@ -0,0 +1,107 @@
+/** @file
+ Internal file explorer helper functions for RamDiskDxe driver.
+
+ Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RamDiskImpl.h"
+
+
+/**
+ Helper function called as part of the code needed to allocate the proper
+ sized buffer for various EFI interfaces.
+
+ @param[in, out] Status Current status.
+ @param[in, out] Buffer Current allocated buffer, or NULL.
+ @param[in] BufferSize Current buffer size needed.
+
+ @retval TRUE If the buffer was reallocated and the caller should
+ try the API again.
+ @retval FALSE The caller should not call this function again.
+
+**/
+BOOLEAN
+GrowBuffer (
+ IN OUT EFI_STATUS *Status,
+ IN OUT VOID **Buffer,
+ IN UINTN BufferSize
+ )
+{
+ BOOLEAN TryAgain;
+
+ //
+ // If this is an initial request, buffer will be null with a new buffer size
+ //
+ if ((*Buffer == NULL) && (BufferSize != 0)) {
+ *Status = EFI_BUFFER_TOO_SMALL;
+ }
+ //
+ // If the status code is "buffer too small", resize the buffer
+ //
+ TryAgain = FALSE;
+ if (*Status == EFI_BUFFER_TOO_SMALL) {
+
+ if (*Buffer != NULL) {
+ FreePool (*Buffer);
+ }
+
+ *Buffer = AllocateZeroPool (BufferSize);
+
+ if (*Buffer != NULL) {
+ TryAgain = TRUE;
+ } else {
+ *Status = EFI_OUT_OF_RESOURCES;
+ }
+ }
+ //
+ // If there's an error, free the buffer
+ //
+ if (!TryAgain && EFI_ERROR (*Status) && (*Buffer != NULL)) {
+ FreePool (*Buffer);
+ *Buffer = NULL;
+ }
+
+ return TryAgain;
+}
+
+
+/**
+ This function gets the file information from an open file descriptor,
+ and stores it in a buffer allocated from pool.
+
+ @param[in] FHand File Handle.
+
+ @return A pointer to a buffer with file information or NULL is returned.
+
+**/
+EFI_FILE_INFO *
+FileInfo (
+ IN EFI_FILE_HANDLE FHand
+ )
+{
+ EFI_STATUS Status;
+ EFI_FILE_INFO *Buffer;
+ UINTN BufferSize;
+
+ //
+ // Initialize for GrowBuffer loop
+ //
+ Buffer = NULL;
+ BufferSize = SIZE_OF_EFI_FILE_INFO + 200;
+
+ //
+ // Call the real function
+ //
+ while (GrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {
+ Status = FHand->GetInfo (
+ FHand,
+ &gEfiFileInfoGuid,
+ &BufferSize,
+ Buffer
+ );
+ }
+
+ return Buffer;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskHii.vfr b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskHii.vfr
new file mode 100644
index 00000000..a6bee275
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskHii.vfr
@@ -0,0 +1,94 @@
+///** @file
+// VFR file used by the RamDiskDxe driver.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+// (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+//**/
+
+#include "RamDiskNVData.h"
+
+formset
+ guid = RAM_DISK_FORM_SET_GUID,
+ title = STRING_TOKEN(STR_FORM_SET_TITLE),
+ help = STRING_TOKEN(STR_FORM_SET_TITLE_HELP),
+ classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID,
+
+ //
+ // Form #1 "Main Form - Add/Remove/Show RAM Disks"
+ //
+ form formid = MAIN_FORM_ID,
+ title = STRING_TOKEN(STR_MAIN_FORM_TITLE);
+
+ oneof
+ questionid = CREATE_RAW_MEMORY_TYPE_QUESTION_ID,
+ prompt = STRING_TOKEN(STR_MEMORY_TYPE_PROMPT),
+ help = STRING_TOKEN(STR_MEMORY_TYPE_HELP),
+ flags = NUMERIC_SIZE_1 | INTERACTIVE,
+ option text = STRING_TOKEN(STR_RAM_DISK_BOOT_SERVICE_DATA_MEMORY), value = RAM_DISK_BOOT_SERVICE_DATA_MEMORY, flags = DEFAULT;
+ option text = STRING_TOKEN(STR_RAM_DISK_RESERVED_MEMORY), value = RAM_DISK_RESERVED_MEMORY, flags = 0;
+ endoneof;
+
+ subtitle text = STRING_TOKEN(STR_RAM_DISK_NULL_STRING);
+
+ goto CREATE_RAW_RAM_DISK_FORM_ID,
+ prompt = STRING_TOKEN(STR_GOTO_ADD_RAW_FORM),
+ help = STRING_TOKEN(STR_GOTO_ADD_RAW_FORM_HELP);
+
+ goto MAIN_FORM_ID,
+ prompt = STRING_TOKEN(STR_GOTO_ADD_FROM_FILE_FORM),
+ help = STRING_TOKEN(STR_GOTO_ADD_FROM_FILE_FORM_HELP),
+ flags = INTERACTIVE,
+ key = MAIN_GOTO_FILE_EXPLORER_ID;
+
+ subtitle text = STRING_TOKEN(STR_RAM_DISK_NULL_STRING);
+ subtitle text = STRING_TOKEN(STR_RAM_DISK_LIST_TEXT);
+
+ label MAIN_LABEL_LIST_START;
+ label MAIN_LABEL_LIST_END;
+
+ subtitle text = STRING_TOKEN(STR_RAM_DISK_NULL_STRING);
+
+ text
+ help = STRING_TOKEN(STR_REMOVE_SEL_HELP),
+ text = STRING_TOKEN(STR_REMOVE_SEL_TEXT),
+ flags = INTERACTIVE,
+ key = MAIN_REMOVE_RD_QUESTION_ID;
+
+ endform;
+
+ //
+ // Form #2 "Add New Raw RAM Disk"
+ //
+ form formid = CREATE_RAW_RAM_DISK_FORM_ID,
+ title = STRING_TOKEN(STR_ADD_RAW_FORM_TITLE);
+
+ subtitle text = STRING_TOKEN(STR_RAM_DISK_NULL_STRING);
+
+ numeric
+ questionid = CREATE_RAW_SIZE_QUESTION_ID,
+ prompt = STRING_TOKEN(STR_SIZE_PROMPT),
+ help = STRING_TOKEN(STR_SIZE_HELP),
+ flags = NUMERIC_SIZE_8 | DISPLAY_UINT_HEX | INTERACTIVE,
+ minimum = 1,
+ maximum = 0xFFFFFFFFFFFFFFFF,
+ endnumeric;
+
+ subtitle text = STRING_TOKEN(STR_RAM_DISK_NULL_STRING);
+
+ text
+ help = STRING_TOKEN(STR_CREATE_AND_EXIT_HELP),
+ text = STRING_TOKEN(STR_CREATE_AND_EXIT_PROMPT),
+ flags = INTERACTIVE,
+ key = CREATE_RAW_SUBMIT_QUESTION_ID;
+
+ text
+ help = STRING_TOKEN(STR_DISCARD_AND_EXIT_HELP),
+ text = STRING_TOKEN(STR_DISCARD_AND_EXIT_PROMPT),
+ flags = INTERACTIVE,
+ key = CREATE_RAW_DISCARD_QUESTION_ID;
+
+ endform;
+
+endformset;
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskHiiStrings.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskHiiStrings.uni
new file mode 100644
index 00000000..5ee1172c
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskHiiStrings.uni
@@ -0,0 +1,41 @@
+// /** @file
+// String definitions for RamDiskDxe driver form.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+// (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#langdef en-US "English"
+
+#string STR_FORM_SET_TITLE #language en-US "RAM Disk Configuration"
+#string STR_FORM_SET_TITLE_HELP #language en-US "Press <Enter> to add/remove RAM disks."
+
+#string STR_MAIN_FORM_TITLE #language en-US "RAM Disk HII Main Screen"
+#string STR_RAM_DISK_NULL_STRING #language en-US ""
+
+#string STR_RAM_DISK_LIST_TEXT #language en-US "Created RAM disk list:"
+#string STR_RAM_DISK_LIST_HELP #language en-US "Select for remove"
+#string STR_GOTO_ADD_RAW_FORM #language en-US "Create raw"
+#string STR_GOTO_ADD_RAW_FORM_HELP #language en-US "Create a raw RAM disk."
+#string STR_GOTO_ADD_FROM_FILE_FORM #language en-US "Create from file"
+#string STR_GOTO_ADD_FROM_FILE_FORM_HELP #language en-US "Create a RAM disk from a given file."
+#string STR_REMOVE_SEL_HELP #language en-US "Remove selected RAM disk(s)"
+#string STR_REMOVE_SEL_TEXT #language en-US "Remove selected RAM disk(s)."
+
+#string STR_ADD_RAW_FORM_TITLE #language en-US "Add A Raw RAM Disk"
+#string STR_ADD_RAW_FORM_SUBTITLE_TEXT #language en-US " "
+
+#string STR_SIZE_PROMPT #language en-US "Size (Hex):"
+#string STR_SIZE_HELP #language en-US "The valid RAM disk size should be multiples of the RAM disk block size."
+
+#string STR_MEMORY_TYPE_PROMPT #language en-US "Disk Memory Type:"
+#string STR_MEMORY_TYPE_HELP #language en-US "Specifies type of memory to use from available memory pool in system to create a disk."
+#string STR_RAM_DISK_BOOT_SERVICE_DATA_MEMORY #language en-US "Boot Service Data"
+#string STR_RAM_DISK_RESERVED_MEMORY #language en-US "Reserved"
+
+#string STR_CREATE_AND_EXIT_HELP #language en-US "Create a new RAM disk with the given starting and ending address."
+#string STR_CREATE_AND_EXIT_PROMPT #language en-US "Create & Exit"
+#string STR_DISCARD_AND_EXIT_HELP #language en-US "Discard and exit."
+#string STR_DISCARD_AND_EXIT_PROMPT #language en-US "Discard & Exit"
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.c
new file mode 100644
index 00000000..42a22781
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.c
@@ -0,0 +1,758 @@
+/** @file
+ HII Config Access protocol implementation of RamDiskDxe driver.
+
+ Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+ (C) Copyright 2016-2018 Hewlett Packard Enterprise Development LP<BR>
+ Copyright (c) Microsoft Corporation.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RamDiskImpl.h"
+
+CHAR16 mRamDiskStorageName[] = L"RAM_DISK_CONFIGURATION";
+
+RAM_DISK_CONFIG_PRIVATE_DATA mRamDiskConfigPrivateDataTemplate = {
+ RAM_DISK_CONFIG_PRIVATE_DATA_SIGNATURE,
+ {
+ EFI_PAGE_SIZE,
+ RAM_DISK_BOOT_SERVICE_DATA_MEMORY
+ },
+ {
+ RamDiskExtractConfig,
+ RamDiskRouteConfig,
+ RamDiskCallback
+ }
+};
+
+HII_VENDOR_DEVICE_PATH mRamDiskHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ RAM_DISK_FORM_SET_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+
+/**
+ This function publish the RAM disk configuration Form.
+
+ @param[in, out] ConfigPrivateData
+ Points to RAM disk configuration private data.
+
+ @retval EFI_SUCCESS HII Form is installed successfully.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource for HII Form installation.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+InstallRamDiskConfigForm (
+ IN OUT RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivateData
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
+
+ DriverHandle = NULL;
+ ConfigAccess = &ConfigPrivateData->ConfigAccess;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mRamDiskHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ ConfigAccess,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ConfigPrivateData->DriverHandle = DriverHandle;
+
+ //
+ // Publish the HII package list
+ //
+ HiiHandle = HiiAddPackages (
+ &gRamDiskFormSetGuid,
+ DriverHandle,
+ RamDiskDxeStrings,
+ RamDiskHiiBin,
+ NULL
+ );
+ if (HiiHandle == NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mRamDiskHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ ConfigAccess,
+ NULL
+ );
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ConfigPrivateData->HiiHandle = HiiHandle;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function removes RAM disk configuration Form.
+
+ @param[in, out] ConfigPrivateData
+ Points to RAM disk configuration private data.
+
+**/
+VOID
+UninstallRamDiskConfigForm (
+ IN OUT RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivateData
+ )
+{
+ //
+ // Uninstall HII package list
+ //
+ if (ConfigPrivateData->HiiHandle != NULL) {
+ HiiRemovePackages (ConfigPrivateData->HiiHandle);
+ ConfigPrivateData->HiiHandle = NULL;
+ }
+
+ //
+ // Uninstall HII Config Access Protocol
+ //
+ if (ConfigPrivateData->DriverHandle != NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ ConfigPrivateData->DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mRamDiskHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &ConfigPrivateData->ConfigAccess,
+ NULL
+ );
+ ConfigPrivateData->DriverHandle = NULL;
+ }
+
+ FreePool (ConfigPrivateData);
+}
+
+
+/**
+ Unregister all registered RAM disks.
+
+**/
+VOID
+UnregisterAllRamDisks (
+ VOID
+ )
+{
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *NextEntry;
+ RAM_DISK_PRIVATE_DATA *PrivateData;
+
+ if (!IsListEmpty(&RegisteredRamDisks)) {
+ BASE_LIST_FOR_EACH_SAFE (Entry, NextEntry, &RegisteredRamDisks) {
+ PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry);
+
+ gBS->UninstallMultipleProtocolInterfaces (
+ PrivateData->Handle,
+ &gEfiBlockIoProtocolGuid,
+ &PrivateData->BlockIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &PrivateData->BlockIo2,
+ &gEfiDevicePathProtocolGuid,
+ (EFI_DEVICE_PATH_PROTOCOL *) PrivateData->DevicePath,
+ NULL
+ );
+
+ RemoveEntryList (&PrivateData->ThisInstance);
+
+ if (RamDiskCreateHii == PrivateData->CreateMethod) {
+ //
+ // If a RAM disk is created within HII, then the RamDiskDxe driver
+ // driver is responsible for freeing the allocated memory for the
+ // RAM disk.
+ //
+ FreePool ((VOID *)(UINTN) PrivateData->StartingAddr);
+ }
+
+ FreePool (PrivateData->DevicePath);
+ FreePool (PrivateData);
+ }
+ }
+}
+
+
+/**
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Request A null-terminated Unicode string in
+ <ConfigRequest> format.
+ @param[out] Progress On return, points to a character in the Request
+ string. Points to the string's null terminator if
+ request was successful. Points to the most recent
+ '&' before the first failing name/value pair (or
+ the beginning of the string if the failure is in
+ the first name/value pair) if the request was not
+ successful.
+ @param[out] Results A null-terminated Unicode string in
+ <ConfigAltResp> format which has all values filled
+ in for the names in the Request string. String to
+ be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested
+ values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in
+ this driver.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ )
+{
+ if (Progress == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *Progress = Request;
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Configuration A null-terminated Unicode string in <ConfigResp>
+ format.
+ @param[out] Progress A pointer to a string filled in with the offset of
+ the most recent '&' before the first failing
+ name/value pair (or the beginning of the string if
+ the failure is in the first name/value pair) or
+ the terminating NULL if all was successful.
+
+ @retval EFI_SUCCESS The Results is processed successfully.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in
+ this driver.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+{
+ if (Configuration == NULL || Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Progress = Configuration;
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Allocate memory and register the RAM disk created within RamDiskDxe
+ driver HII.
+
+ @param[in] Size If creating raw, size of the RAM disk to create.
+ If creating from file, zero.
+ @param[in] FileHandle If creating raw, NULL. If creating from file, the
+ file handle.
+ @param[in] MemoryType Type of memory to be used to create RAM Disk.
+
+ @retval EFI_SUCCESS RAM disk is created and registered.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to match the
+ size required.
+
+**/
+EFI_STATUS
+HiiCreateRamDisk (
+ IN UINT64 Size,
+ IN EFI_FILE_HANDLE FileHandle,
+ IN UINT8 MemoryType
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ UINT64 *StartingAddr;
+ EFI_INPUT_KEY Key;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ RAM_DISK_PRIVATE_DATA *PrivateData;
+ EFI_FILE_INFO *FileInformation;
+
+ FileInformation = NULL;
+ StartingAddr = NULL;
+
+ if (FileHandle != NULL) {
+ //
+ // Create from file.
+ //
+ FileInformation = FileInfo (FileHandle);
+ if (NULL == FileInformation) {
+ do {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"",
+ L"Not enough memory to get the file information!",
+ L"Press ENTER to continue ...",
+ L"",
+ NULL
+ );
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Update the size of RAM disk according to the file size.
+ //
+ Size = FileInformation->FileSize;
+ }
+
+ if (Size > (UINTN) -1) {
+ do {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"",
+ L"The given RAM disk size is too large!",
+ L"Press ENTER to continue ...",
+ L"",
+ NULL
+ );
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (MemoryType == RAM_DISK_BOOT_SERVICE_DATA_MEMORY) {
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ (UINTN)Size,
+ (VOID**)&StartingAddr
+ );
+ } else if (MemoryType == RAM_DISK_RESERVED_MEMORY) {
+ Status = gBS->AllocatePool (
+ EfiReservedMemoryType,
+ (UINTN)Size,
+ (VOID**)&StartingAddr
+ );
+ } else {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ if ((StartingAddr == NULL) || EFI_ERROR(Status)) {
+ do {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"",
+ L"Not enough memory to create the RAM disk!",
+ L"Press ENTER to continue ...",
+ L"",
+ NULL
+ );
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (FileHandle != NULL) {
+ //
+ // Copy the file content to the RAM disk.
+ //
+ BufferSize = (UINTN) Size;
+ FileHandle->Read (
+ FileHandle,
+ &BufferSize,
+ (VOID *)(UINTN) StartingAddr
+ );
+ if (BufferSize != FileInformation->FileSize) {
+ do {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"",
+ L"File content read error!",
+ L"Press ENTER to continue ...",
+ L"",
+ NULL
+ );
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ //
+ // Register the newly created RAM disk.
+ //
+ Status = RamDiskRegister (
+ ((UINT64)(UINTN) StartingAddr),
+ Size,
+ &gEfiVirtualDiskGuid,
+ NULL,
+ &DevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ do {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"",
+ L"Fail to register the newly created RAM disk!",
+ L"Press ENTER to continue ...",
+ L"",
+ NULL
+ );
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+
+ return Status;
+ }
+
+ //
+ // If RAM disk is created within HII, memory should be freed when the
+ // RAM disk is unregisterd.
+ //
+ PrivateData = RAM_DISK_PRIVATE_FROM_THIS (RegisteredRamDisks.BackLink);
+ PrivateData->CreateMethod = RamDiskCreateHii;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function updates the registered RAM disks list on the main form.
+
+ @param[in, out] ConfigPrivate
+ Private data for configurating hii data for RAM
+ disks.
+
+**/
+VOID
+UpdateMainForm (
+ IN OUT RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivate
+ )
+{
+ VOID *StartOpCodeHandle;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ EFI_IFR_GUID_LABEL *EndLabel;
+ LIST_ENTRY *Entry;
+ UINTN Index;
+ RAM_DISK_PRIVATE_DATA *PrivateData;
+ CHAR16 *String;
+ CHAR16 RamDiskStr[128];
+ EFI_STRING_ID StringId;
+
+ //
+ // Init OpCode Handle
+ //
+ StartOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (StartOpCodeHandle != NULL);
+
+ EndOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (EndOpCodeHandle != NULL);
+
+ //
+ // Create Hii Extend Label OpCode as the start opcode
+ //
+ StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
+ StartOpCodeHandle,
+ &gEfiIfrTianoGuid,
+ NULL,
+ sizeof (EFI_IFR_GUID_LABEL)
+ );
+ StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ StartLabel->Number = MAIN_LABEL_LIST_START;
+
+ //
+ // Create Hii Extend Label OpCode as the end opcode
+ //
+ EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
+ EndOpCodeHandle,
+ &gEfiIfrTianoGuid,
+ NULL,
+ sizeof (EFI_IFR_GUID_LABEL)
+ );
+ EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ EndLabel->Number = MAIN_LABEL_LIST_END;
+
+ Index = 0;
+ BASE_LIST_FOR_EACH (Entry, &RegisteredRamDisks) {
+ PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry);
+ PrivateData->CheckBoxId = (EFI_QUESTION_ID)
+ (MAIN_CHECKBOX_QUESTION_ID_START + Index);
+ //
+ // CheckBox is unchecked by default.
+ //
+ PrivateData->CheckBoxChecked = FALSE;
+ String = RamDiskStr;
+
+ UnicodeSPrint (
+ String,
+ sizeof (RamDiskStr),
+ L" RAM Disk %d: [0x%lx, 0x%lx]\n",
+ Index,
+ PrivateData->StartingAddr,
+ PrivateData->StartingAddr + PrivateData->Size - 1
+ );
+
+ StringId = HiiSetString (ConfigPrivate->HiiHandle, 0, RamDiskStr, NULL);
+ ASSERT (StringId != 0);
+
+ HiiCreateCheckBoxOpCode (
+ StartOpCodeHandle,
+ PrivateData->CheckBoxId,
+ 0,
+ 0,
+ StringId,
+ STRING_TOKEN (STR_RAM_DISK_LIST_HELP),
+ EFI_IFR_FLAG_CALLBACK,
+ 0,
+ NULL
+ );
+
+ Index++;
+ }
+
+ HiiUpdateForm (
+ ConfigPrivate->HiiHandle,
+ &gRamDiskFormSetGuid,
+ MAIN_FORM_ID,
+ StartOpCodeHandle,
+ EndOpCodeHandle
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+}
+
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Action Specifies the type of action taken by the browser.
+ @param[in] QuestionId A unique value which is sent to the original
+ exporting driver so that it can identify the type
+ of data to expect.
+ @param[in] Type The type of value for the question.
+ @param[in] Value A pointer to the data being sent to the original
+ exporting driver.
+ @param[out] ActionRequest On return, points to the action requested by the
+ callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the
+ variable and its data.
+ @retval EFI_DEVICE_ERROR The variable could not be saved.
+ @retval EFI_UNSUPPORTED The specified Action is not supported by the
+ callback.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+{
+ EFI_STATUS Status;
+ RAM_DISK_PRIVATE_DATA *PrivateData;
+ RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivate;
+ EFI_DEVICE_PATH_PROTOCOL *FileDevPath;
+ EFI_FILE_HANDLE FileHandle;
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *NextEntry;
+
+ if ((This == NULL) || (Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ConfigPrivate = RAM_DISK_CONFIG_PRIVATE_FROM_THIS (This);
+
+ if (Action == EFI_BROWSER_ACTION_RETRIEVE) {
+ Status = EFI_UNSUPPORTED;
+ if (QuestionId == CREATE_RAW_SIZE_QUESTION_ID) {
+ Value->u64 = EFI_PAGE_SIZE;
+ ConfigPrivate->ConfigStore.Size = EFI_PAGE_SIZE;
+ Status = EFI_SUCCESS;
+ } else if (QuestionId == CREATE_RAW_MEMORY_TYPE_QUESTION_ID) {
+ Value->u8 = RAM_DISK_BOOT_SERVICE_DATA_MEMORY;
+ ConfigPrivate->ConfigStore.MemType = RAM_DISK_BOOT_SERVICE_DATA_MEMORY;
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+ }
+
+ if ((Action != EFI_BROWSER_ACTION_CHANGED) &&
+ (Action != EFI_BROWSER_ACTION_CHANGING) &&
+ (Action != EFI_BROWSER_ACTION_FORM_OPEN)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Update the RAM disk list show at the main form first.
+ //
+ if (Action == EFI_BROWSER_ACTION_FORM_OPEN) {
+ Status = EFI_UNSUPPORTED;
+ if (QuestionId == MAIN_GOTO_FILE_EXPLORER_ID) {
+ UpdateMainForm (ConfigPrivate);
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+ }
+
+ Status = EFI_SUCCESS;
+
+ if (Action == EFI_BROWSER_ACTION_CHANGING) {
+ switch (QuestionId) {
+ case MAIN_GOTO_FILE_EXPLORER_ID:
+ Status = ChooseFile (NULL, NULL, NULL, &FileDevPath);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (FileDevPath != NULL) {
+ //
+ // Open the file.
+ //
+ Status = EfiOpenFileByDevicePath (
+ &FileDevPath,
+ &FileHandle,
+ EFI_FILE_MODE_READ,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ //
+ // Create from file, RAM disk size is zero. It will be updated
+ // according to the file size.
+ //
+ Status = HiiCreateRamDisk (
+ 0,
+ FileHandle,
+ ConfigPrivate->ConfigStore.MemType
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ //
+ // Refresh the registered RAM disks list.
+ //
+ UpdateMainForm (ConfigPrivate);
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else if (Action == EFI_BROWSER_ACTION_CHANGED) {
+ switch (QuestionId) {
+ case MAIN_REMOVE_RD_QUESTION_ID:
+ //
+ // Remove the selected RAM disks
+ //
+ BASE_LIST_FOR_EACH_SAFE (Entry, NextEntry, &RegisteredRamDisks) {
+ PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry);
+ if (PrivateData->CheckBoxChecked) {
+ RamDiskUnregister (
+ (EFI_DEVICE_PATH_PROTOCOL *) PrivateData->DevicePath
+ );
+ }
+ }
+
+ UpdateMainForm (ConfigPrivate);
+
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
+ break;
+
+ case CREATE_RAW_SIZE_QUESTION_ID:
+ ConfigPrivate->ConfigStore.Size = Value->u64;
+ break;
+
+ case CREATE_RAW_MEMORY_TYPE_QUESTION_ID:
+ ConfigPrivate->ConfigStore.MemType = Value->u8;
+ break;
+
+ case CREATE_RAW_SUBMIT_QUESTION_ID:
+ //
+ // Create raw, FileHandle is NULL.
+ //
+ Status = HiiCreateRamDisk (
+ ConfigPrivate->ConfigStore.Size,
+ NULL,
+ ConfigPrivate->ConfigStore.MemType
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ //
+ // Refresh the registered RAM disks list.
+ //
+ UpdateMainForm (ConfigPrivate);
+
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
+ break;
+
+ case CREATE_RAW_DISCARD_QUESTION_ID:
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
+ break;
+
+ default:
+ //
+ // QuestionIds for checkboxes
+ //
+ if ((QuestionId >= MAIN_CHECKBOX_QUESTION_ID_START) &&
+ (QuestionId < CREATE_RAW_RAM_DISK_FORM_ID)) {
+ BASE_LIST_FOR_EACH (Entry, &RegisteredRamDisks) {
+ PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry);
+ if (PrivateData->CheckBoxId == QuestionId) {
+ PrivateData->CheckBoxChecked = (BOOLEAN) (Value->u8 != 0);
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.h b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.h
new file mode 100644
index 00000000..c29c38d1
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskImpl.h
@@ -0,0 +1,604 @@
+/** @file
+ The header file of RamDiskDxe driver.
+
+ Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) Microsoft Corporation.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _RAM_DISK_IMPL_H_
+#define _RAM_DISK_IMPL_H_
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiHiiServicesLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/HiiLib.h>
+#include <Library/FileExplorerLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PrintLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Protocol/RamDisk.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/BlockIo2.h>
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/AcpiTable.h>
+#include <Protocol/AcpiSystemDescriptionTable.h>
+#include <Guid/MdeModuleHii.h>
+#include <Guid/RamDiskHii.h>
+#include <Guid/FileInfo.h>
+#include <IndustryStandard/Acpi61.h>
+
+#include "RamDiskNVData.h"
+
+///
+/// RAM disk general definitions and declarations
+///
+
+//
+// Default block size for RAM disk
+//
+#define RAM_DISK_DEFAULT_BLOCK_SIZE 512
+
+//
+// RamDiskDxe driver maintains a list of registered RAM disks.
+//
+extern LIST_ENTRY RegisteredRamDisks;
+
+//
+// Pointers to the EFI_ACPI_TABLE_PROTOCOL and EFI_ACPI_SDT_PROTOCOL.
+//
+extern EFI_ACPI_TABLE_PROTOCOL *mAcpiTableProtocol;
+extern EFI_ACPI_SDT_PROTOCOL *mAcpiSdtProtocol;
+
+//
+// RAM Disk create method.
+//
+typedef enum _RAM_DISK_CREATE_METHOD {
+ RamDiskCreateOthers = 0,
+ RamDiskCreateHii
+} RAM_DISK_CREATE_METHOD;
+
+//
+// RamDiskDxe driver maintains a list of registered RAM disks.
+// The struct contains the list entry and the information of each RAM
+// disk
+//
+typedef struct {
+ UINTN Signature;
+
+ EFI_HANDLE Handle;
+
+ EFI_BLOCK_IO_PROTOCOL BlockIo;
+ EFI_BLOCK_IO2_PROTOCOL BlockIo2;
+ EFI_BLOCK_IO_MEDIA Media;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ UINT64 StartingAddr;
+ UINT64 Size;
+ EFI_GUID TypeGuid;
+ UINT16 InstanceNumber;
+ RAM_DISK_CREATE_METHOD CreateMethod;
+ BOOLEAN InNfit;
+ EFI_QUESTION_ID CheckBoxId;
+ BOOLEAN CheckBoxChecked;
+
+ LIST_ENTRY ThisInstance;
+} RAM_DISK_PRIVATE_DATA;
+
+#define RAM_DISK_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('R', 'D', 'S', 'K')
+#define RAM_DISK_PRIVATE_FROM_BLKIO(a) CR (a, RAM_DISK_PRIVATE_DATA, BlockIo, RAM_DISK_PRIVATE_DATA_SIGNATURE)
+#define RAM_DISK_PRIVATE_FROM_BLKIO2(a) CR (a, RAM_DISK_PRIVATE_DATA, BlockIo2, RAM_DISK_PRIVATE_DATA_SIGNATURE)
+#define RAM_DISK_PRIVATE_FROM_THIS(a) CR (a, RAM_DISK_PRIVATE_DATA, ThisInstance, RAM_DISK_PRIVATE_DATA_SIGNATURE)
+
+///
+/// RAM disk HII-related definitions and declarations
+///
+
+//
+// Tool generated IFR binary data and String package data
+//
+extern UINT8 RamDiskHiiBin[];
+extern UINT8 RamDiskDxeStrings[];
+
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} HII_VENDOR_DEVICE_PATH;
+
+typedef struct {
+ UINTN Signature;
+
+ RAM_DISK_CONFIGURATION ConfigStore;
+
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_HANDLE HiiHandle;
+} RAM_DISK_CONFIG_PRIVATE_DATA;
+
+extern RAM_DISK_CONFIG_PRIVATE_DATA mRamDiskConfigPrivateDataTemplate;
+
+#define RAM_DISK_CONFIG_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('R', 'C', 'F', 'G')
+#define RAM_DISK_CONFIG_PRIVATE_FROM_THIS(a) CR (a, RAM_DISK_CONFIG_PRIVATE_DATA, ConfigAccess, RAM_DISK_CONFIG_PRIVATE_DATA_SIGNATURE)
+
+/**
+ Register a RAM disk with specified address, size and type.
+
+ @param[in] RamDiskBase The base address of registered RAM disk.
+ @param[in] RamDiskSize The size of registered RAM disk.
+ @param[in] RamDiskType The type of registered RAM disk. The GUID can be
+ any of the values defined in section 9.3.6.9, or a
+ vendor defined GUID.
+ @param[in] ParentDevicePath
+ Pointer to the parent device path. If there is no
+ parent device path then ParentDevicePath is NULL.
+ @param[out] DevicePath On return, points to a pointer to the device path
+ of the RAM disk device.
+ If ParentDevicePath is not NULL, the returned
+ DevicePath is created by appending a RAM disk node
+ to the parent device path. If ParentDevicePath is
+ NULL, the returned DevicePath is a RAM disk device
+ path without appending. This function is
+ responsible for allocating the buffer DevicePath
+ with the boot service AllocatePool().
+
+ @retval EFI_SUCCESS The RAM disk is registered successfully.
+ @retval EFI_INVALID_PARAMETER DevicePath or RamDiskType is NULL.
+ RamDiskSize is 0.
+ @retval EFI_ALREADY_STARTED A Device Path Protocol instance to be created
+ is already present in the handle database.
+ @retval EFI_OUT_OF_RESOURCES The RAM disk register operation fails due to
+ resource limitation.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskRegister (
+ IN UINT64 RamDiskBase,
+ IN UINT64 RamDiskSize,
+ IN EFI_GUID *RamDiskType,
+ IN EFI_DEVICE_PATH *ParentDevicePath OPTIONAL,
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ );
+
+/**
+ Unregister a RAM disk specified by DevicePath.
+
+ @param[in] DevicePath A pointer to the device path that describes a RAM
+ Disk device.
+
+ @retval EFI_SUCCESS The RAM disk is unregistered successfully.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.
+ @retval EFI_UNSUPPORTED The device specified by DevicePath is not a
+ valid ramdisk device path and not supported
+ by the driver.
+ @retval EFI_NOT_FOUND The RAM disk pointed by DevicePath doesn't
+ exist.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskUnregister (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+/**
+ Initialize the BlockIO protocol of a RAM disk device.
+
+ @param[in] PrivateData Points to RAM disk private data.
+
+**/
+VOID
+RamDiskInitBlockIo (
+ IN RAM_DISK_PRIVATE_DATA *PrivateData
+ );
+
+/**
+ Reset the Block Device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] ExtendedVerification
+ Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and
+ could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskBlkIoReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId Id of the media, changes every time the media is
+ replaced.
+ @param[in] Lba The starting Logical Block Address to read from.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block
+ size.
+ @param[out] Buffer A pointer to the destination buffer for the data.
+ The caller is responsible for either having
+ implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing
+ the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not matched the current
+ device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block
+ size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
+ valid, or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskBlkIoReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the write request is for.
+ @param[in] Lba The starting logical block address to be written.
+ The caller is responsible for writing to only
+ legitimate locations.
+ @param[in] BufferSize Size of Buffer, must be a multiple of device block
+ size.
+ @param[in] Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The data was written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing
+ the write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current
+ device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block
+ size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not
+ valid, or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskBlkIoWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+ Flush the Block Device.
+
+ @param[in] This Indicates a pointer to the calling context.
+
+ @retval EFI_SUCCESS All outstanding data was written to the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while writting
+ back the data
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskBlkIoFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ );
+
+/**
+ Resets the block device hardware.
+
+ @param[in] This The pointer of EFI_BLOCK_IO2_PROTOCOL.
+ @param[in] ExtendedVerification The flag about if extend verificate.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The block device is not functioning correctly
+ and could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskBlkIo2Reset (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Reads the requested number of blocks from the device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the read request is for.
+ @param[in] Lba The starting logical block address to read
+ from on the device.
+ @param[in, out] Token A pointer to the token associated with the
+ transaction.
+ @param[in] BufferSize The size of the Buffer in bytes. This must be
+ a multiple of the intrinsic block size of the
+ device.
+ @param[out] Buffer A pointer to the destination buffer for the
+ data. The caller is responsible for either
+ having implicit or explicit ownership of the
+ buffer.
+
+ @retval EFI_SUCCESS The read request was queued if Token->Event
+ is not NULL. The data was read correctly from
+ the device if the Token->Event is NULL.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting
+ to perform the read operation.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
+ the intrinsic block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
+ valid, or the buffer is not on proper
+ alignment.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskBlkIo2ReadBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Writes a specified number of blocks to the device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] MediaId The media ID that the write request is for.
+ @param[in] Lba The starting logical block address to be
+ written. The caller is responsible for
+ writing to only legitimate locations.
+ @param[in, out] Token A pointer to the token associated with the
+ transaction.
+ @param[in] BufferSize The size in bytes of Buffer. This must be a
+ multiple of the intrinsic block size of the
+ device.
+ @param[in] Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The write request was queued if Event is not
+ NULL. The data was written correctly to the
+ device if the Event is NULL.
+ @retval EFI_WRITE_PROTECTED The device cannot be written to.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting
+ to perform the write operation.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
+ the intrinsic block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not
+ valid, or the buffer is not on proper
+ alignment.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskBlkIo2WriteBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+ Flushes all modified data to a physical block device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in, out] Token A pointer to the token associated with the
+ transaction.
+
+ @retval EFI_SUCCESS The flush request was queued if Event is not
+ NULL. All outstanding data was written
+ correctly to the device if the Event is NULL.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting
+ to write data.
+ @retval EFI_WRITE_PROTECTED The device cannot be written to.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskBlkIo2FlushBlocksEx (
+ IN EFI_BLOCK_IO2_PROTOCOL *This,
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token
+ );
+
+/**
+ This function publish the RAM disk configuration Form.
+
+ @param[in, out] ConfigPrivateData
+ Points to RAM disk configuration private data.
+
+ @retval EFI_SUCCESS HII Form is installed successfully.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource for HII Form installation.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+InstallRamDiskConfigForm (
+ IN OUT RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivateData
+ );
+
+/**
+ This function removes RAM disk configuration Form.
+
+ @param[in, out] ConfigPrivateData
+ Points to RAM disk configuration private data.
+
+**/
+VOID
+UninstallRamDiskConfigForm (
+ IN OUT RAM_DISK_CONFIG_PRIVATE_DATA *ConfigPrivateData
+ );
+
+/**
+ Unregister all registered RAM disks.
+
+**/
+VOID
+UnregisterAllRamDisks (
+ VOID
+ );
+
+/**
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Request A null-terminated Unicode string in
+ <ConfigRequest> format.
+ @param[out] Progress On return, points to a character in the Request
+ string. Points to the string's null terminator if
+ request was successful. Points to the most recent
+ '&' before the first failing name/value pair (or
+ the beginning of the string if the failure is in
+ the first name/value pair) if the request was not
+ successful.
+ @param[out] Results A null-terminated Unicode string in
+ <ConfigAltResp> format which has all values filled
+ in for the names in the Request string. String to
+ be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested
+ values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in
+ this driver.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ );
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Configuration A null-terminated Unicode string in <ConfigResp>
+ format.
+ @param[out] Progress A pointer to a string filled in with the offset of
+ the most recent '&' before the first failing
+ name/value pair (or the beginning of the string if
+ the failure is in the first name/value pair) or
+ the terminating NULL if all was successful.
+
+ @retval EFI_SUCCESS The Results is processed successfully.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in
+ this driver.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ );
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Action Specifies the type of action taken by the browser.
+ @param[in] QuestionId A unique value which is sent to the original
+ exporting driver so that it can identify the type
+ of data to expect.
+ @param[in] Type The type of value for the question.
+ @param[in] Value A pointer to the data being sent to the original
+ exporting driver.
+ @param[out] ActionRequest On return, points to the action requested by the
+ callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the
+ variable and its data.
+ @retval EFI_DEVICE_ERROR The variable could not be saved.
+ @retval EFI_UNSUPPORTED The specified Action is not supported by the
+ callback.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ );
+
+
+/**
+ This function gets the file information from an open file descriptor,
+ and stores it in a buffer allocated from pool.
+
+ @param[in] FHand File Handle.
+
+ @return A pointer to a buffer with file information or NULL is returned.
+
+**/
+EFI_FILE_INFO *
+FileInfo (
+ IN EFI_FILE_HANDLE FHand
+ );
+
+
+/**
+ Publish the RAM disk NVDIMM Firmware Interface Table (NFIT) to the ACPI
+ table.
+
+ @param[in] PrivateData Points to RAM disk private data.
+
+ @retval EFI_SUCCESS The RAM disk NFIT has been published.
+ @retval others The RAM disk NFIT has not been published.
+
+**/
+EFI_STATUS
+RamDiskPublishNfit (
+ IN RAM_DISK_PRIVATE_DATA *PrivateData
+ );
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskNVData.h b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskNVData.h
new file mode 100644
index 00000000..6ffcc0eb
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskNVData.h
@@ -0,0 +1,44 @@
+/** @file
+ Header file for NV data structure definition.
+
+ Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _RAM_DISK_NVDATA_H_
+#define _RAM_DISK_NVDATA_H_
+
+#include <Guid/HiiPlatformSetupFormset.h>
+#include <Guid/RamDiskHii.h>
+
+#define MAIN_FORM_ID 0x1000
+#define MAIN_GOTO_FILE_EXPLORER_ID 0x1001
+#define MAIN_REMOVE_RD_QUESTION_ID 0x1002
+#define MAIN_LABEL_LIST_START 0x1003
+#define MAIN_LABEL_LIST_END 0x1004
+#define MAIN_CHECKBOX_QUESTION_ID_START 0x1100
+
+#define CREATE_RAW_RAM_DISK_FORM_ID 0x2000
+#define CREATE_RAW_SIZE_QUESTION_ID 0x2001
+#define CREATE_RAW_SUBMIT_QUESTION_ID 0x2002
+#define CREATE_RAW_DISCARD_QUESTION_ID 0x2003
+#define CREATE_RAW_MEMORY_TYPE_QUESTION_ID 0x2004
+
+#define RAM_DISK_BOOT_SERVICE_DATA_MEMORY 0x00
+#define RAM_DISK_RESERVED_MEMORY 0x01
+#define RAM_DISK_MEMORY_TYPE_MAX 0x02
+
+typedef struct {
+ //
+ // The size of the RAM disk to be created.
+ //
+ UINT64 Size;
+ //
+ // Selected RAM Disk Memory Type
+ //
+ UINT8 MemType;
+} RAM_DISK_CONFIGURATION;
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskProtocol.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskProtocol.c
new file mode 100644
index 00000000..22cbfb84
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskProtocol.c
@@ -0,0 +1,857 @@
+/** @file
+ The realization of EFI_RAM_DISK_PROTOCOL.
+
+ Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+ Copyright (c) Microsoft Corporation.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RamDiskImpl.h"
+
+RAM_DISK_PRIVATE_DATA mRamDiskPrivateDataTemplate = {
+ RAM_DISK_PRIVATE_DATA_SIGNATURE,
+ NULL
+};
+
+MEDIA_RAM_DISK_DEVICE_PATH mRamDiskDeviceNodeTemplate = {
+ {
+ MEDIA_DEVICE_PATH,
+ MEDIA_RAM_DISK_DP,
+ {
+ (UINT8) (sizeof (MEDIA_RAM_DISK_DEVICE_PATH)),
+ (UINT8) ((sizeof (MEDIA_RAM_DISK_DEVICE_PATH)) >> 8)
+ }
+ }
+};
+
+BOOLEAN mRamDiskSsdtTableKeyValid = FALSE;
+UINTN mRamDiskSsdtTableKey;
+
+
+/**
+ Initialize the RAM disk device node.
+
+ @param[in] PrivateData Points to RAM disk private data.
+ @param[in, out] RamDiskDevNode Points to the RAM disk device node.
+
+**/
+VOID
+RamDiskInitDeviceNode (
+ IN RAM_DISK_PRIVATE_DATA *PrivateData,
+ IN OUT MEDIA_RAM_DISK_DEVICE_PATH *RamDiskDevNode
+ )
+{
+ WriteUnaligned64 (
+ (UINT64 *) &(RamDiskDevNode->StartingAddr[0]),
+ (UINT64) PrivateData->StartingAddr
+ );
+ WriteUnaligned64 (
+ (UINT64 *) &(RamDiskDevNode->EndingAddr[0]),
+ (UINT64) PrivateData->StartingAddr + PrivateData->Size - 1
+ );
+ CopyGuid (&RamDiskDevNode->TypeGuid, &PrivateData->TypeGuid);
+ RamDiskDevNode->Instance = PrivateData->InstanceNumber;
+}
+
+
+/**
+ Initialize and publish NVDIMM root device SSDT in ACPI table.
+
+ @retval EFI_SUCCESS The NVDIMM root device SSDT is published.
+ @retval Others The NVDIMM root device SSDT is not published.
+
+**/
+EFI_STATUS
+RamDiskPublishSsdt (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_DESCRIPTION_HEADER *Table;
+ UINTN SectionInstance;
+ UINTN TableSize;
+
+ Status = EFI_SUCCESS;
+ SectionInstance = 0;
+
+ //
+ // Scan all the EFI raw section instances in FV to find the NVDIMM root
+ // device SSDT.
+ //
+ while (TRUE) {
+ Status = GetSectionFromFv (
+ &gEfiCallerIdGuid,
+ EFI_SECTION_RAW,
+ SectionInstance,
+ (VOID **) &Table,
+ &TableSize
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (Table->OemTableId == SIGNATURE_64 ('R', 'a', 'm', 'D', 'i', 's', 'k', ' ')) {
+ Status = mAcpiTableProtocol->InstallAcpiTable (
+ mAcpiTableProtocol,
+ Table,
+ TableSize,
+ &mRamDiskSsdtTableKey
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (!EFI_ERROR (Status)) {
+ mRamDiskSsdtTableKeyValid = TRUE;
+ }
+
+ FreePool (Table);
+ return Status;
+ } else {
+ FreePool (Table);
+ SectionInstance++;
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Publish the RAM disk NVDIMM Firmware Interface Table (NFIT) to the ACPI
+ table.
+
+ @param[in] PrivateData Points to RAM disk private data.
+
+ @retval EFI_SUCCESS The RAM disk NFIT has been published.
+ @retval others The RAM disk NFIT has not been published.
+
+**/
+EFI_STATUS
+RamDiskPublishNfit (
+ IN RAM_DISK_PRIVATE_DATA *PrivateData
+ )
+{
+ EFI_STATUS Status;
+ EFI_MEMORY_DESCRIPTOR *MemoryMap;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
+ EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
+ UINTN TableIndex;
+ VOID *TableHeader;
+ EFI_ACPI_TABLE_VERSION TableVersion;
+ UINTN TableKey;
+ EFI_ACPI_DESCRIPTION_HEADER *NfitHeader;
+ EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE
+ *SpaRange;
+ VOID *Nfit;
+ UINT32 NfitLen;
+ UINTN MemoryMapSize;
+ UINTN MapKey;
+ UINTN DescriptorSize;
+ UINT32 DescriptorVersion;
+ UINT64 CurrentData;
+ UINT8 Checksum;
+ BOOLEAN MemoryFound;
+
+ //
+ // Get the EFI memory map.
+ //
+ MemoryMapSize = 0;
+ MemoryMap = NULL;
+ MemoryFound = FALSE;
+
+ Status = gBS->GetMemoryMap (
+ &MemoryMapSize,
+ MemoryMap,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion
+ );
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);
+ do {
+ MemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (MemoryMapSize);
+ ASSERT (MemoryMap != NULL);
+ Status = gBS->GetMemoryMap (
+ &MemoryMapSize,
+ MemoryMap,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (MemoryMap);
+ }
+ } while (Status == EFI_BUFFER_TOO_SMALL);
+ ASSERT_EFI_ERROR (Status);
+
+ MemoryMapEntry = MemoryMap;
+ MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);
+ while ((UINTN) MemoryMapEntry < (UINTN) MemoryMapEnd) {
+ if ((MemoryMapEntry->Type == EfiReservedMemoryType) &&
+ (MemoryMapEntry->PhysicalStart <= PrivateData->StartingAddr) &&
+ (MemoryMapEntry->PhysicalStart +
+ MultU64x32 (MemoryMapEntry->NumberOfPages, EFI_PAGE_SIZE)
+ >= PrivateData->StartingAddr + PrivateData->Size)) {
+ MemoryFound = TRUE;
+ DEBUG ((
+ EFI_D_INFO,
+ "RamDiskPublishNfit: RAM disk with reserved meomry type, will publish to NFIT.\n"
+ ));
+ break;
+ }
+ MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
+ }
+ FreePool (MemoryMap);
+
+ if (!MemoryFound) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Determine whether there is a NFIT already in the ACPI table.
+ //
+ Status = EFI_SUCCESS;
+ TableIndex = 0;
+ TableKey = 0;
+ TableHeader = NULL;
+
+ while (!EFI_ERROR (Status)) {
+ Status = mAcpiSdtProtocol->GetAcpiTable (
+ TableIndex,
+ (EFI_ACPI_SDT_HEADER **)&TableHeader,
+ &TableVersion,
+ &TableKey
+ );
+ if (!EFI_ERROR (Status)) {
+ TableIndex++;
+
+ if (((EFI_ACPI_SDT_HEADER *)TableHeader)->Signature ==
+ EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_STRUCTURE_SIGNATURE) {
+ break;
+ }
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // A NFIT is already in the ACPI table.
+ //
+ DEBUG ((
+ EFI_D_INFO,
+ "RamDiskPublishNfit: A NFIT is already exist in the ACPI Table.\n"
+ ));
+
+ NfitHeader = (EFI_ACPI_DESCRIPTION_HEADER *)TableHeader;
+ NfitLen = NfitHeader->Length + sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE);
+ Nfit = AllocateZeroPool (NfitLen);
+ if (Nfit == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (Nfit, TableHeader, NfitHeader->Length);
+
+ //
+ // Update the NFIT head pointer.
+ //
+ NfitHeader = (EFI_ACPI_DESCRIPTION_HEADER *)Nfit;
+
+ //
+ // Uninstall the origin NFIT from the ACPI table.
+ //
+ Status = mAcpiTableProtocol->UninstallAcpiTable (
+ mAcpiTableProtocol,
+ TableKey
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (EFI_ERROR (Status)) {
+ FreePool (Nfit);
+ return Status;
+ }
+
+ //
+ // Append the System Physical Address (SPA) Range Structure at the end
+ // of the origin NFIT.
+ //
+ SpaRange = (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE *)
+ ((UINT8 *)Nfit + NfitHeader->Length);
+
+ //
+ // Update the length field of the NFIT
+ //
+ NfitHeader->Length = NfitLen;
+
+ //
+ // The checksum will be updated after the new contents are appended.
+ //
+ NfitHeader->Checksum = 0;
+ } else {
+ //
+ // Assumption is made that if no NFIT is in the ACPI table, there is no
+ // NVDIMM root device in the \SB scope.
+ // Therefore, a NVDIMM root device will be reported via Secondary System
+ // Description Table (SSDT).
+ //
+ Status = RamDiskPublishSsdt ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // No NFIT is in the ACPI table, we will create one here.
+ //
+ DEBUG ((
+ EFI_D_INFO,
+ "RamDiskPublishNfit: No NFIT is in the ACPI Table, will create one.\n"
+ ));
+
+ NfitLen = sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE) +
+ sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE);
+ Nfit = AllocateZeroPool (NfitLen);
+ if (Nfit == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SpaRange = (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE *)
+ ((UINT8 *)Nfit + sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE));
+
+ NfitHeader = (EFI_ACPI_DESCRIPTION_HEADER *)Nfit;
+ NfitHeader->Signature = EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_STRUCTURE_SIGNATURE;
+ NfitHeader->Length = NfitLen;
+ NfitHeader->Revision = EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_REVISION;
+ NfitHeader->Checksum = 0;
+ NfitHeader->OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
+ NfitHeader->CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
+ NfitHeader->CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
+ CurrentData = PcdGet64 (PcdAcpiDefaultOemTableId);
+ CopyMem (NfitHeader->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (NfitHeader->OemId));
+ CopyMem (&NfitHeader->OemTableId, &CurrentData, sizeof (UINT64));
+ }
+
+ //
+ // Fill in the content of the SPA Range Structure.
+ //
+ SpaRange->Type = EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE_TYPE;
+ SpaRange->Length = sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE);
+ SpaRange->SystemPhysicalAddressRangeBase = PrivateData->StartingAddr;
+ SpaRange->SystemPhysicalAddressRangeLength = PrivateData->Size;
+ CopyGuid (&SpaRange->AddressRangeTypeGUID, &PrivateData->TypeGuid);
+
+ Checksum = CalculateCheckSum8((UINT8 *)Nfit, NfitHeader->Length);
+ NfitHeader->Checksum = Checksum;
+
+ //
+ // Publish the NFIT to the ACPI table.
+ // Note, since the NFIT might be modified by other driver, therefore, we
+ // do not track the returning TableKey from the InstallAcpiTable().
+ //
+ Status = mAcpiTableProtocol->InstallAcpiTable (
+ mAcpiTableProtocol,
+ Nfit,
+ NfitHeader->Length,
+ &TableKey
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ FreePool (Nfit);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PrivateData->InNfit = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Unpublish the RAM disk NVDIMM Firmware Interface Table (NFIT) from the
+ ACPI table.
+
+ @param[in] PrivateData Points to RAM disk private data.
+
+ @retval EFI_SUCCESS The RAM disk NFIT has been unpublished.
+ @retval others The RAM disk NFIT has not been unpublished.
+
+**/
+EFI_STATUS
+RamDiskUnpublishNfit (
+ IN RAM_DISK_PRIVATE_DATA *PrivateData
+ )
+{
+ EFI_STATUS Status;
+ UINTN TableIndex;
+ VOID *TableHeader;
+ EFI_ACPI_TABLE_VERSION TableVersion;
+ UINTN TableKey;
+ EFI_ACPI_DESCRIPTION_HEADER *NewNfitHeader;
+ EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE
+ *SpaRange;
+ VOID *NewNfit;
+ VOID *NewNfitPtr;
+ EFI_ACPI_6_1_NFIT_STRUCTURE_HEADER *NfitStructHeader;
+ UINT32 NewNfitLen;
+ UINT32 RemainLen;
+ UINT8 Checksum;
+
+ //
+ // Find the NFIT in the ACPI table.
+ //
+ Status = EFI_SUCCESS;
+ TableIndex = 0;
+ TableKey = 0;
+ TableHeader = NULL;
+
+ while (!EFI_ERROR (Status)) {
+ Status = mAcpiSdtProtocol->GetAcpiTable (
+ TableIndex,
+ (EFI_ACPI_SDT_HEADER **)&TableHeader,
+ &TableVersion,
+ &TableKey
+ );
+ if (!EFI_ERROR (Status)) {
+ TableIndex++;
+
+ if (((EFI_ACPI_SDT_HEADER *)TableHeader)->Signature ==
+ EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE_STRUCTURE_SIGNATURE) {
+ break;
+ }
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // No NFIT is found in the ACPI table.
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ NewNfitLen = ((EFI_ACPI_DESCRIPTION_HEADER *)TableHeader)->Length -
+ sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE);
+
+ //
+ // After removing this RAM disk from the NFIT, if no other structure is in
+ // the NFIT, we just remove the NFIT and the SSDT which is used to report
+ // the NVDIMM root device.
+ //
+ if (NewNfitLen == sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE)) {
+ //
+ // Remove the NFIT.
+ //
+ Status = mAcpiTableProtocol->UninstallAcpiTable (
+ mAcpiTableProtocol,
+ TableKey
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Remove the SSDT which is used by RamDiskDxe driver to report the NVDIMM
+ // root device.
+ // We do not care the return status since this SSDT might already be
+ // uninstalled by other drivers to update the information of the NVDIMM
+ // root device.
+ //
+ if (mRamDiskSsdtTableKeyValid) {
+ mRamDiskSsdtTableKeyValid = FALSE;
+
+ mAcpiTableProtocol->UninstallAcpiTable (
+ mAcpiTableProtocol,
+ mRamDiskSsdtTableKey
+ );
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ NewNfit = AllocateZeroPool (NewNfitLen);
+ if (NewNfit == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Get a copy of the old NFIT header content.
+ //
+ CopyMem (NewNfit, TableHeader, sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE));
+ NewNfitHeader = (EFI_ACPI_DESCRIPTION_HEADER *)NewNfit;
+ NewNfitHeader->Length = NewNfitLen;
+ NewNfitHeader->Checksum = 0;
+
+ //
+ // Copy the content of required NFIT structures.
+ //
+ NewNfitPtr = (UINT8 *)NewNfit + sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE);
+ RemainLen = NewNfitLen - sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE);
+ NfitStructHeader = (EFI_ACPI_6_1_NFIT_STRUCTURE_HEADER *)
+ ((UINT8 *)TableHeader + sizeof (EFI_ACPI_6_1_NVDIMM_FIRMWARE_INTERFACE_TABLE));
+ while (RemainLen > 0) {
+ if ((NfitStructHeader->Type == EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE_TYPE) &&
+ (NfitStructHeader->Length == sizeof (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE))) {
+ SpaRange = (EFI_ACPI_6_1_NFIT_SYSTEM_PHYSICAL_ADDRESS_RANGE_STRUCTURE *)NfitStructHeader;
+
+ if ((SpaRange->SystemPhysicalAddressRangeBase == PrivateData->StartingAddr) &&
+ (SpaRange->SystemPhysicalAddressRangeLength == PrivateData->Size) &&
+ (CompareGuid (&SpaRange->AddressRangeTypeGUID, &PrivateData->TypeGuid))) {
+ //
+ // Skip the SPA Range Structure for the RAM disk to be unpublished
+ // from NFIT.
+ //
+ NfitStructHeader = (EFI_ACPI_6_1_NFIT_STRUCTURE_HEADER *)
+ ((UINT8 *)NfitStructHeader + NfitStructHeader->Length);
+ continue;
+ }
+ }
+
+ //
+ // Copy the content of origin NFIT.
+ //
+ CopyMem (NewNfitPtr, NfitStructHeader, NfitStructHeader->Length);
+ NewNfitPtr = (UINT8 *)NewNfitPtr + NfitStructHeader->Length;
+
+ //
+ // Move to the header of next NFIT structure.
+ //
+ RemainLen -= NfitStructHeader->Length;
+ NfitStructHeader = (EFI_ACPI_6_1_NFIT_STRUCTURE_HEADER *)
+ ((UINT8 *)NfitStructHeader + NfitStructHeader->Length);
+ }
+
+ Checksum = CalculateCheckSum8((UINT8 *)NewNfit, NewNfitHeader->Length);
+ NewNfitHeader->Checksum = Checksum;
+
+ Status = mAcpiTableProtocol->UninstallAcpiTable (
+ mAcpiTableProtocol,
+ TableKey
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (EFI_ERROR (Status)) {
+ FreePool (NewNfit);
+ return Status;
+ }
+
+ //
+ // Publish the NFIT to the ACPI table.
+ // Note, since the NFIT might be modified by other driver, therefore, we
+ // do not track the returning TableKey from the InstallAcpiTable().
+ //
+ Status = mAcpiTableProtocol->InstallAcpiTable (
+ mAcpiTableProtocol,
+ NewNfit,
+ NewNfitLen,
+ &TableKey
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ FreePool (NewNfit);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Register a RAM disk with specified address, size and type.
+
+ @param[in] RamDiskBase The base address of registered RAM disk.
+ @param[in] RamDiskSize The size of registered RAM disk.
+ @param[in] RamDiskType The type of registered RAM disk. The GUID can be
+ any of the values defined in section 9.3.6.9, or a
+ vendor defined GUID.
+ @param[in] ParentDevicePath
+ Pointer to the parent device path. If there is no
+ parent device path then ParentDevicePath is NULL.
+ @param[out] DevicePath On return, points to a pointer to the device path
+ of the RAM disk device.
+ If ParentDevicePath is not NULL, the returned
+ DevicePath is created by appending a RAM disk node
+ to the parent device path. If ParentDevicePath is
+ NULL, the returned DevicePath is a RAM disk device
+ path without appending. This function is
+ responsible for allocating the buffer DevicePath
+ with the boot service AllocatePool().
+
+ @retval EFI_SUCCESS The RAM disk is registered successfully.
+ @retval EFI_INVALID_PARAMETER DevicePath or RamDiskType is NULL.
+ RamDiskSize is 0.
+ @retval EFI_ALREADY_STARTED A Device Path Protocol instance to be created
+ is already present in the handle database.
+ @retval EFI_OUT_OF_RESOURCES The RAM disk register operation fails due to
+ resource limitation.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskRegister (
+ IN UINT64 RamDiskBase,
+ IN UINT64 RamDiskSize,
+ IN EFI_GUID *RamDiskType,
+ IN EFI_DEVICE_PATH *ParentDevicePath OPTIONAL,
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ EFI_STATUS Status;
+ RAM_DISK_PRIVATE_DATA *PrivateData;
+ RAM_DISK_PRIVATE_DATA *RegisteredPrivateData;
+ MEDIA_RAM_DISK_DEVICE_PATH *RamDiskDevNode;
+ UINTN DevicePathSize;
+ LIST_ENTRY *Entry;
+
+ if ((0 == RamDiskSize) || (NULL == RamDiskType) || (NULL == DevicePath)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Add check to prevent data read across the memory boundary
+ //
+ if ((RamDiskSize > MAX_UINTN) ||
+ (RamDiskBase > MAX_UINTN - RamDiskSize + 1)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RamDiskDevNode = NULL;
+
+ //
+ // Create a new RAM disk instance and initialize its private data
+ //
+ PrivateData = AllocateCopyPool (
+ sizeof (RAM_DISK_PRIVATE_DATA),
+ &mRamDiskPrivateDataTemplate
+ );
+ if (NULL == PrivateData) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PrivateData->StartingAddr = RamDiskBase;
+ PrivateData->Size = RamDiskSize;
+ CopyGuid (&PrivateData->TypeGuid, RamDiskType);
+ InitializeListHead (&PrivateData->ThisInstance);
+
+ //
+ // Generate device path information for the registered RAM disk
+ //
+ RamDiskDevNode = AllocateCopyPool (
+ sizeof (MEDIA_RAM_DISK_DEVICE_PATH),
+ &mRamDiskDeviceNodeTemplate
+ );
+ if (NULL == RamDiskDevNode) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ RamDiskInitDeviceNode (PrivateData, RamDiskDevNode);
+
+ *DevicePath = AppendDevicePathNode (
+ ParentDevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) RamDiskDevNode
+ );
+ if (NULL == *DevicePath) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ PrivateData->DevicePath = *DevicePath;
+
+ //
+ // Check whether the created device path is already present in the handle
+ // database
+ //
+ if (!IsListEmpty(&RegisteredRamDisks)) {
+ DevicePathSize = GetDevicePathSize (PrivateData->DevicePath);
+
+ BASE_LIST_FOR_EACH (Entry, &RegisteredRamDisks) {
+ RegisteredPrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry);
+ if (DevicePathSize == GetDevicePathSize (RegisteredPrivateData->DevicePath)) {
+ //
+ // Compare device path
+ //
+ if ((CompareMem (
+ PrivateData->DevicePath,
+ RegisteredPrivateData->DevicePath,
+ DevicePathSize)) == 0) {
+ *DevicePath = NULL;
+ Status = EFI_ALREADY_STARTED;
+ goto ErrorExit;
+ }
+ }
+ }
+ }
+
+ //
+ // Fill Block IO protocol informations for the RAM disk
+ //
+ RamDiskInitBlockIo (PrivateData);
+
+ //
+ // Install EFI_DEVICE_PATH_PROTOCOL & EFI_BLOCK_IO(2)_PROTOCOL on a new
+ // handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &PrivateData->Handle,
+ &gEfiBlockIoProtocolGuid,
+ &PrivateData->BlockIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &PrivateData->BlockIo2,
+ &gEfiDevicePathProtocolGuid,
+ PrivateData->DevicePath,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ //
+ // Insert the newly created one to the registered RAM disk list
+ //
+ InsertTailList (&RegisteredRamDisks, &PrivateData->ThisInstance);
+
+ gBS->ConnectController (PrivateData->Handle, NULL, NULL, TRUE);
+
+ FreePool (RamDiskDevNode);
+
+ if ((mAcpiTableProtocol != NULL) && (mAcpiSdtProtocol != NULL)) {
+ RamDiskPublishNfit (PrivateData);
+ }
+
+ return EFI_SUCCESS;
+
+ErrorExit:
+ if (RamDiskDevNode != NULL) {
+ FreePool (RamDiskDevNode);
+ }
+
+ if (PrivateData != NULL) {
+ if (PrivateData->DevicePath) {
+ FreePool (PrivateData->DevicePath);
+ }
+
+ FreePool (PrivateData);
+ }
+
+ return Status;
+}
+
+
+/**
+ Unregister a RAM disk specified by DevicePath.
+
+ @param[in] DevicePath A pointer to the device path that describes a RAM
+ Disk device.
+
+ @retval EFI_SUCCESS The RAM disk is unregistered successfully.
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.
+ @retval EFI_UNSUPPORTED The device specified by DevicePath is not a
+ valid ramdisk device path and not supported
+ by the driver.
+ @retval EFI_NOT_FOUND The RAM disk pointed by DevicePath doesn't
+ exist.
+
+**/
+EFI_STATUS
+EFIAPI
+RamDiskUnregister (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *NextEntry;
+ BOOLEAN Found;
+ UINT64 StartingAddr;
+ UINT64 EndingAddr;
+ EFI_DEVICE_PATH_PROTOCOL *Header;
+ MEDIA_RAM_DISK_DEVICE_PATH *RamDiskDevNode;
+ RAM_DISK_PRIVATE_DATA *PrivateData;
+
+ if (NULL == DevicePath) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Locate the RAM disk device node.
+ //
+ RamDiskDevNode = NULL;
+ Header = DevicePath;
+ do {
+ //
+ // Test if the current device node is a RAM disk.
+ //
+ if ((MEDIA_DEVICE_PATH == Header->Type) &&
+ (MEDIA_RAM_DISK_DP == Header->SubType)) {
+ RamDiskDevNode = (MEDIA_RAM_DISK_DEVICE_PATH *) Header;
+
+ break;
+ }
+
+ Header = NextDevicePathNode (Header);
+ } while ((Header->Type != END_DEVICE_PATH_TYPE));
+
+ if (NULL == RamDiskDevNode) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Found = FALSE;
+ StartingAddr = ReadUnaligned64 ((UINT64 *) &(RamDiskDevNode->StartingAddr[0]));
+ EndingAddr = ReadUnaligned64 ((UINT64 *) &(RamDiskDevNode->EndingAddr[0]));
+
+ if (!IsListEmpty(&RegisteredRamDisks)) {
+ BASE_LIST_FOR_EACH_SAFE (Entry, NextEntry, &RegisteredRamDisks) {
+ PrivateData = RAM_DISK_PRIVATE_FROM_THIS (Entry);
+
+ //
+ // Unregister the RAM disk given by its starting address, ending address
+ // and type guid.
+ //
+ if ((StartingAddr == PrivateData->StartingAddr) &&
+ (EndingAddr == PrivateData->StartingAddr + PrivateData->Size - 1) &&
+ (CompareGuid (&RamDiskDevNode->TypeGuid, &PrivateData->TypeGuid))) {
+ //
+ // Remove the content for this RAM disk in NFIT.
+ //
+ if (PrivateData->InNfit) {
+ RamDiskUnpublishNfit (PrivateData);
+ }
+
+ //
+ // Uninstall the EFI_DEVICE_PATH_PROTOCOL & EFI_BLOCK_IO(2)_PROTOCOL
+ //
+ gBS->UninstallMultipleProtocolInterfaces (
+ PrivateData->Handle,
+ &gEfiBlockIoProtocolGuid,
+ &PrivateData->BlockIo,
+ &gEfiBlockIo2ProtocolGuid,
+ &PrivateData->BlockIo2,
+ &gEfiDevicePathProtocolGuid,
+ (EFI_DEVICE_PATH_PROTOCOL *) PrivateData->DevicePath,
+ NULL
+ );
+
+ RemoveEntryList (&PrivateData->ThisInstance);
+
+ if (RamDiskCreateHii == PrivateData->CreateMethod) {
+ //
+ // If a RAM disk is created within HII, then the RamDiskDxe driver
+ // driver is responsible for freeing the allocated memory for the
+ // RAM disk.
+ //
+ FreePool ((VOID *)(UINTN) PrivateData->StartingAddr);
+ }
+
+ FreePool (PrivateData->DevicePath);
+ FreePool (PrivateData);
+ Found = TRUE;
+
+ break;
+ }
+ }
+ }
+
+ if (TRUE == Found) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+}
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UdfDxe/ComponentName.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UdfDxe/ComponentName.c
new file mode 100644
index 00000000..c194c48a
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UdfDxe/ComponentName.c
@@ -0,0 +1,179 @@
+/** @file
+ UEFI Component Name protocol for UDF/ECMA-167 file system driver.
+
+ Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "Udf.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gUdfComponentName = {
+ UdfComponentNameGetDriverName,
+ UdfComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gUdfComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) UdfComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) UdfComponentNameGetControllerName,
+ "en"
+};
+
+//
+// Driver name table for Udf module.
+// It is shared by the implementation of ComponentName & ComponentName2 Protocol.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mUdfDriverNameTable[] = {
+ {
+ "eng;en",
+ L"UDF File System Driver"
+ },
+ {
+ 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
+UdfComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mUdfDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gUdfComponentName)
+ );
+}
+
+/**
+ 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 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.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UdfDxe/File.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UdfDxe/File.c
new file mode 100644
index 00000000..3966e091
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UdfDxe/File.c
@@ -0,0 +1,904 @@
+/** @file
+ Handle operations in files and directories from UDF/ECMA-167 file systems.
+
+ Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
+ Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "Udf.h"
+
+EFI_FILE_PROTOCOL gUdfFileIoOps = {
+ EFI_FILE_PROTOCOL_REVISION,
+ UdfOpen,
+ UdfClose,
+ UdfDelete,
+ UdfRead,
+ UdfWrite,
+ UdfGetPosition,
+ UdfSetPosition,
+ UdfGetInfo,
+ UdfSetInfo,
+ UdfFlush,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+#define _ROOT_FILE(_PrivData) (_PrivData)->Root
+#define _PARENT_FILE(_PrivData) \
+ ((_PrivData)->IsRootDirectory ? (_PrivData)->Root : &(_PrivData)->File)
+#define _FILE(_PrivData) _PARENT_FILE(_PrivData)
+
+/**
+ Open the root directory on a volume.
+
+ @param This Protocol instance pointer.
+ @param Root Returns an Open file handle for the root directory
+
+ @retval EFI_SUCCESS The device was opened.
+ @retval EFI_UNSUPPORTED This volume does not support the file system.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_ACCESS_DENIED The service denied access to the file.
+ @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of
+ resources.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfOpenVolume (
+ IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
+ OUT EFI_FILE_PROTOCOL **Root
+ )
+{
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;
+ PRIVATE_UDF_FILE_DATA *PrivFileData;
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ if (This == NULL || Root == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Error_Invalid_Params;
+ }
+
+ PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (This);
+
+ if (PrivFsData->OpenFiles == 0) {
+ //
+ // There is no more open files. Read volume information again since it was
+ // cleaned up on the last UdfClose() call.
+ //
+ Status = ReadUdfVolumeInformation (
+ PrivFsData->BlockIo,
+ PrivFsData->DiskIo,
+ &PrivFsData->Volume
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error_Read_Udf_Volume;
+ }
+ }
+
+ CleanupFileInformation (&PrivFsData->Root);
+
+ //
+ // Find root directory file.
+ //
+ Status = FindRootDirectory (
+ PrivFsData->BlockIo,
+ PrivFsData->DiskIo,
+ &PrivFsData->Volume,
+ &PrivFsData->Root
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error_Find_Root_Dir;
+ }
+
+ PrivFileData =
+ (PRIVATE_UDF_FILE_DATA *) AllocateZeroPool (sizeof (PRIVATE_UDF_FILE_DATA));
+ if (PrivFileData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error_Alloc_Priv_File_Data;
+ }
+
+ PrivFileData->Signature = PRIVATE_UDF_FILE_DATA_SIGNATURE;
+ PrivFileData->SimpleFs = This;
+ PrivFileData->Root = &PrivFsData->Root;
+ PrivFileData->IsRootDirectory = TRUE;
+
+ CopyMem ((VOID *)&PrivFileData->FileIo, (VOID *)&gUdfFileIoOps,
+ sizeof (EFI_FILE_PROTOCOL));
+
+ *Root = &PrivFileData->FileIo;
+
+ PrivFsData->OpenFiles++;
+
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+
+Error_Alloc_Priv_File_Data:
+ CleanupFileInformation (&PrivFsData->Root);
+
+Error_Find_Root_Dir:
+
+Error_Read_Udf_Volume:
+Error_Invalid_Params:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+/**
+ Opens a new file relative to the source file's location.
+
+ @param This The protocol instance pointer.
+ @param NewHandle Returns File Handle for FileName.
+ @param FileName Null terminated string. "\", ".", and ".." are supported.
+ @param OpenMode Open mode for file.
+ @param Attributes Only used for EFI_FILE_MODE_CREATE.
+
+ @retval EFI_SUCCESS The device was opened.
+ @retval EFI_NOT_FOUND The specified file could not be found on the
+ device.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_MEDIA_CHANGED The media has changed.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_ACCESS_DENIED The service denied access to the file.
+ @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of
+ resources.
+ @retval EFI_VOLUME_FULL The volume is full.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfOpen (
+ IN EFI_FILE_PROTOCOL *This,
+ OUT EFI_FILE_PROTOCOL **NewHandle,
+ IN CHAR16 *FileName,
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes
+ )
+{
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ PRIVATE_UDF_FILE_DATA *PrivFileData;
+ PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;
+ CHAR16 FilePath[UDF_PATH_LENGTH];
+ UDF_FILE_INFO File;
+ PRIVATE_UDF_FILE_DATA *NewPrivFileData;
+ CHAR16 *TempFileName;
+
+ ZeroMem (FilePath, sizeof FilePath);
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ if (This == NULL || NewHandle == NULL || FileName == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Error_Invalid_Params;
+ }
+
+ if (OpenMode != EFI_FILE_MODE_READ) {
+ Status = EFI_WRITE_PROTECTED;
+ goto Error_Invalid_Params;
+ }
+
+ PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
+
+ PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs);
+
+ //
+ // Build full path
+ //
+ if (*FileName == L'\\') {
+ StrCpyS (FilePath, UDF_PATH_LENGTH, FileName);
+ } else {
+ StrCpyS (FilePath, UDF_PATH_LENGTH, PrivFileData->AbsoluteFileName);
+ StrCatS (FilePath, UDF_PATH_LENGTH, L"\\");
+ StrCatS (FilePath, UDF_PATH_LENGTH, FileName);
+ }
+
+ MangleFileName (FilePath);
+ if (FilePath[0] == L'\0') {
+ Status = EFI_NOT_FOUND;
+ goto Error_Bad_FileName;
+ }
+
+ Status = FindFile (
+ PrivFsData->BlockIo,
+ PrivFsData->DiskIo,
+ &PrivFsData->Volume,
+ FilePath,
+ _ROOT_FILE (PrivFileData),
+ _PARENT_FILE (PrivFileData),
+ &_PARENT_FILE(PrivFileData)->FileIdentifierDesc->Icb,
+ &File
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error_Find_File;
+ }
+
+ NewPrivFileData =
+ (PRIVATE_UDF_FILE_DATA *)AllocateZeroPool (sizeof (PRIVATE_UDF_FILE_DATA));
+ if (NewPrivFileData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error_Alloc_New_Priv_File_Data;
+ }
+
+ CopyMem ((VOID *)NewPrivFileData, (VOID *)PrivFileData,
+ sizeof (PRIVATE_UDF_FILE_DATA));
+ CopyMem ((VOID *)&NewPrivFileData->File, &File, sizeof (UDF_FILE_INFO));
+
+ NewPrivFileData->IsRootDirectory = FALSE;
+
+ StrCpyS (NewPrivFileData->AbsoluteFileName, UDF_PATH_LENGTH, FilePath);
+ FileName = NewPrivFileData->AbsoluteFileName;
+
+ while ((TempFileName = StrStr (FileName, L"\\")) != NULL) {
+ FileName = TempFileName + 1;
+ }
+
+ StrCpyS (NewPrivFileData->FileName, UDF_FILENAME_LENGTH, FileName);
+
+ Status = GetFileSize (
+ PrivFsData->BlockIo,
+ PrivFsData->DiskIo,
+ &PrivFsData->Volume,
+ &NewPrivFileData->File,
+ &NewPrivFileData->FileSize
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: GetFileSize() fails with status - %r.\n",
+ __FUNCTION__, Status
+ ));
+ goto Error_Get_File_Size;
+ }
+
+ NewPrivFileData->FilePosition = 0;
+ ZeroMem ((VOID *)&NewPrivFileData->ReadDirInfo,
+ sizeof (UDF_READ_DIRECTORY_INFO));
+
+ *NewHandle = &NewPrivFileData->FileIo;
+
+ PrivFsData->OpenFiles++;
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+
+Error_Get_File_Size:
+ FreePool ((VOID *)NewPrivFileData);
+
+Error_Alloc_New_Priv_File_Data:
+ CleanupFileInformation (&File);
+
+Error_Find_File:
+Error_Bad_FileName:
+Error_Invalid_Params:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+/**
+ Read data from the file.
+
+ @param This Protocol instance pointer.
+ @param BufferSize On input size of buffer, on output amount of data in
+ buffer.
+ @param Buffer The buffer in which data is read.
+
+ @retval EFI_SUCCESS Data was read.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains
+ required size.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfRead (
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ PRIVATE_UDF_FILE_DATA *PrivFileData;
+ PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;
+ UDF_VOLUME_INFO *Volume;
+ UDF_FILE_INFO *Parent;
+ UDF_READ_DIRECTORY_INFO *ReadDirInfo;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ UDF_FILE_INFO FoundFile;
+ UDF_FILE_IDENTIFIER_DESCRIPTOR *NewFileIdentifierDesc;
+ VOID *NewFileEntryData;
+ CHAR16 FileName[UDF_FILENAME_LENGTH];
+ UINT64 FileSize;
+ UINT64 BufferSizeUint64;
+
+ ZeroMem (FileName, sizeof FileName);
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ if (This == NULL || BufferSize == NULL || (*BufferSize != 0 &&
+ Buffer == NULL)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Error_Invalid_Params;
+ }
+
+ PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
+ PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs);
+
+ BlockIo = PrivFsData->BlockIo;
+ DiskIo = PrivFsData->DiskIo;
+ Volume = &PrivFsData->Volume;
+ ReadDirInfo = &PrivFileData->ReadDirInfo;
+ NewFileIdentifierDesc = NULL;
+ NewFileEntryData = NULL;
+
+ Parent = _PARENT_FILE (PrivFileData);
+
+ Status = EFI_VOLUME_CORRUPTED;
+
+ if (IS_FID_NORMAL_FILE (Parent->FileIdentifierDesc)) {
+ if (PrivFileData->FilePosition > PrivFileData->FileSize) {
+ //
+ // File's position is beyond the EOF
+ //
+ Status = EFI_DEVICE_ERROR;
+ goto Error_File_Beyond_The_Eof;
+ }
+
+ if (PrivFileData->FilePosition == PrivFileData->FileSize) {
+ *BufferSize = 0;
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ BufferSizeUint64 = *BufferSize;
+
+ Status = ReadFileData (
+ BlockIo,
+ DiskIo,
+ Volume,
+ Parent,
+ PrivFileData->FileSize,
+ &PrivFileData->FilePosition,
+ Buffer,
+ &BufferSizeUint64
+ );
+ ASSERT (BufferSizeUint64 <= MAX_UINTN);
+ *BufferSize = (UINTN)BufferSizeUint64;
+ } else if (IS_FID_DIRECTORY_FILE (Parent->FileIdentifierDesc)) {
+ if (ReadDirInfo->FidOffset == 0 && PrivFileData->FilePosition > 0) {
+ Status = EFI_DEVICE_ERROR;
+ *BufferSize = 0;
+ goto Done;
+ }
+
+ for (;;) {
+ Status = ReadDirectoryEntry (
+ BlockIo,
+ DiskIo,
+ Volume,
+ &Parent->FileIdentifierDesc->Icb,
+ Parent->FileEntry,
+ ReadDirInfo,
+ &NewFileIdentifierDesc
+ );
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_DEVICE_ERROR) {
+ FreePool (ReadDirInfo->DirectoryData);
+ ZeroMem ((VOID *)ReadDirInfo, sizeof (UDF_READ_DIRECTORY_INFO));
+
+ *BufferSize = 0;
+ Status = EFI_SUCCESS;
+ }
+
+ goto Done;
+ }
+ //
+ // After calling function ReadDirectoryEntry(), if 'NewFileIdentifierDesc'
+ // is NULL, then the 'Status' must be EFI_OUT_OF_RESOURCES. Hence, if the
+ // code reaches here, 'NewFileIdentifierDesc' must be not NULL.
+ //
+ // The ASSERT here is for addressing a false positive NULL pointer
+ // dereference issue raised from static analysis.
+ //
+ ASSERT (NewFileIdentifierDesc != NULL);
+
+ if (!IS_FID_PARENT_FILE (NewFileIdentifierDesc)) {
+ break;
+ }
+
+ FreePool ((VOID *)NewFileIdentifierDesc);
+ }
+
+ Status = FindFileEntry (
+ BlockIo,
+ DiskIo,
+ Volume,
+ &NewFileIdentifierDesc->Icb,
+ &NewFileEntryData
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error_Find_Fe;
+ }
+ ASSERT (NewFileEntryData != NULL);
+
+ if (FE_ICB_FILE_TYPE (NewFileEntryData) == UdfFileEntrySymlink) {
+ Status = ResolveSymlink (
+ BlockIo,
+ DiskIo,
+ Volume,
+ Parent,
+ NewFileEntryData,
+ &FoundFile
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error_Resolve_Symlink;
+ }
+
+ FreePool ((VOID *)NewFileEntryData);
+ NewFileEntryData = FoundFile.FileEntry;
+
+ Status = GetFileNameFromFid (NewFileIdentifierDesc, ARRAY_SIZE (FileName), FileName);
+ if (EFI_ERROR (Status)) {
+ FreePool ((VOID *)FoundFile.FileIdentifierDesc);
+ goto Error_Get_FileName;
+ }
+
+ FreePool ((VOID *)NewFileIdentifierDesc);
+ NewFileIdentifierDesc = FoundFile.FileIdentifierDesc;
+ } else {
+ FoundFile.FileIdentifierDesc = NewFileIdentifierDesc;
+ FoundFile.FileEntry = NewFileEntryData;
+
+ Status = GetFileNameFromFid (FoundFile.FileIdentifierDesc, ARRAY_SIZE (FileName), FileName);
+ if (EFI_ERROR (Status)) {
+ goto Error_Get_FileName;
+ }
+ }
+
+ Status = GetFileSize (
+ BlockIo,
+ DiskIo,
+ Volume,
+ &FoundFile,
+ &FileSize
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error_Get_File_Size;
+ }
+
+ Status = SetFileInfo (
+ &FoundFile,
+ FileSize,
+ FileName,
+ BufferSize,
+ Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error_Set_File_Info;
+ }
+
+ PrivFileData->FilePosition++;
+ Status = EFI_SUCCESS;
+ } else if (IS_FID_DELETED_FILE (Parent->FileIdentifierDesc)) {
+ //
+ // Code should never reach here.
+ //
+ ASSERT (FALSE);
+ Status = EFI_DEVICE_ERROR;
+ }
+
+Error_Set_File_Info:
+Error_Get_File_Size:
+Error_Get_FileName:
+Error_Resolve_Symlink:
+ if (NewFileEntryData != NULL) {
+ FreePool (NewFileEntryData);
+ }
+
+Error_Find_Fe:
+ if (NewFileIdentifierDesc != NULL) {
+ FreePool ((VOID *)NewFileIdentifierDesc);
+ }
+
+Done:
+Error_File_Beyond_The_Eof:
+Error_Invalid_Params:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+/**
+ Close the file handle.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The file was closed.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfClose (
+ IN EFI_FILE_PROTOCOL *This
+ )
+{
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ PRIVATE_UDF_FILE_DATA *PrivFileData;
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ Status = EFI_SUCCESS;
+
+ if (This == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
+
+ if (!PrivFileData->IsRootDirectory) {
+ CleanupFileInformation (&PrivFileData->File);
+
+ if (PrivFileData->ReadDirInfo.DirectoryData != NULL) {
+ FreePool (PrivFileData->ReadDirInfo.DirectoryData);
+ }
+ }
+
+ FreePool ((VOID *)PrivFileData);
+
+Exit:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+/**
+ Close and delete the file handle.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The file was closed and deleted.
+ @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not
+ deleted.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfDelete (
+ IN EFI_FILE_PROTOCOL *This
+ )
+{
+ PRIVATE_UDF_FILE_DATA *PrivFileData;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
+
+ (VOID)PrivFileData->FileIo.Close(This);
+
+ return EFI_WARN_DELETE_FAILURE;
+}
+
+/**
+ Write data to a file.
+
+ @param This Protocol instance pointer.
+ @param BufferSize On input size of buffer, on output amount of data in
+ buffer.
+ @param Buffer The buffer in which data to write.
+
+ @retval EFI_SUCCESS Data was written.
+ @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The device is write protected.
+ @retval EFI_ACCESS_DENIED The file was open for read only.
+ @retval EFI_VOLUME_FULL The volume is full.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfWrite (
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Get file's current position.
+
+ @param This Protocol instance pointer.
+ @param Position Byte position from the start of the file.
+
+ @retval EFI_SUCCESS Position was updated.
+ @retval EFI_UNSUPPORTED Seek request for directories is not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfGetPosition (
+ IN EFI_FILE_PROTOCOL *This,
+ OUT UINT64 *Position
+ )
+{
+ PRIVATE_UDF_FILE_DATA *PrivFileData;
+
+ if (This == NULL || Position == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
+
+ //
+ // As per UEFI spec, if the file handle is a directory, then the current file
+ // position has no meaning and the operation is not supported.
+ //
+ if (IS_FID_DIRECTORY_FILE (PrivFileData->File.FileIdentifierDesc)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // The file is not a directory. So, return its position.
+ //
+ *Position = PrivFileData->FilePosition;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set file's current position.
+
+ @param This Protocol instance pointer.
+ @param Position Byte position from the start of the file.
+
+ @retval EFI_SUCCESS Position was updated.
+ @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfSetPosition (
+ IN EFI_FILE_PROTOCOL *This,
+ IN UINT64 Position
+ )
+{
+ EFI_STATUS Status;
+ PRIVATE_UDF_FILE_DATA *PrivFileData;
+ UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_UNSUPPORTED;
+
+ PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
+
+ FileIdentifierDesc = _FILE (PrivFileData)->FileIdentifierDesc;
+ ASSERT (FileIdentifierDesc != NULL);
+ if (IS_FID_DIRECTORY_FILE (FileIdentifierDesc)) {
+ //
+ // If the file handle is a directory, the _only_ position that may be set is
+ // zero. This has no effect of starting the read proccess of the directory
+ // entries over.
+ //
+ if (Position == 0) {
+ PrivFileData->FilePosition = Position;
+ PrivFileData->ReadDirInfo.FidOffset = 0;
+ Status = EFI_SUCCESS;
+ }
+ } else if (IS_FID_NORMAL_FILE (FileIdentifierDesc)) {
+ //
+ // Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to be
+ // set to the EOF.
+ //
+ if (Position == 0xFFFFFFFFFFFFFFFF) {
+ PrivFileData->FilePosition = PrivFileData->FileSize;
+ } else {
+ PrivFileData->FilePosition = Position;
+ }
+
+ Status = EFI_SUCCESS;
+ }
+
+ return Status;
+}
+
+/**
+ Get information about a file.
+
+ @param This Protocol instance pointer.
+ @param InformationType Type of information to return in Buffer.
+ @param BufferSize On input size of buffer, on output amount of data in
+ buffer.
+ @param Buffer The buffer to return data.
+
+ @retval EFI_SUCCESS Data was returned.
+ @retval EFI_UNSUPPORTED InformationType is not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The device is write protected.
+ @retval EFI_ACCESS_DENIED The file was open for read only.
+ @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in
+ BufferSize.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfGetInfo (
+ IN EFI_FILE_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ PRIVATE_UDF_FILE_DATA *PrivFileData;
+ PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;
+ EFI_FILE_SYSTEM_INFO *FileSystemInfo;
+ UINTN FileSystemInfoLength;
+ UINT64 VolumeSize;
+ UINT64 FreeSpaceSize;
+ EFI_FILE_SYSTEM_VOLUME_LABEL *FileSystemVolumeLabel;
+ UINTN FileSystemVolumeLabelLength;
+ CHAR16 VolumeLabel[64];
+
+ if (This == NULL || InformationType == NULL || BufferSize == NULL ||
+ (*BufferSize != 0 && Buffer == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
+
+ PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs);
+
+ Status = EFI_UNSUPPORTED;
+
+ if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
+ Status = SetFileInfo (
+ _FILE (PrivFileData),
+ PrivFileData->FileSize,
+ PrivFileData->FileName,
+ BufferSize,
+ Buffer
+ );
+ } else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
+ Status = GetVolumeLabel (&PrivFsData->Volume, ARRAY_SIZE (VolumeLabel), VolumeLabel);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ FileSystemInfoLength = StrSize (VolumeLabel) +
+ sizeof (EFI_FILE_SYSTEM_INFO);
+ if (*BufferSize < FileSystemInfoLength) {
+ *BufferSize = FileSystemInfoLength;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ FileSystemInfo = (EFI_FILE_SYSTEM_INFO *)Buffer;
+ StrCpyS (
+ FileSystemInfo->VolumeLabel,
+ (*BufferSize - SIZE_OF_EFI_FILE_SYSTEM_INFO) / sizeof (CHAR16),
+ VolumeLabel
+ );
+ Status = GetVolumeSize (
+ PrivFsData->BlockIo,
+ PrivFsData->DiskIo,
+ &PrivFsData->Volume,
+ &VolumeSize,
+ &FreeSpaceSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ FileSystemInfo->Size = FileSystemInfoLength;
+ FileSystemInfo->ReadOnly = TRUE;
+ FileSystemInfo->BlockSize =
+ PrivFsData->Volume.LogicalVolDesc.LogicalBlockSize;
+ FileSystemInfo->VolumeSize = VolumeSize;
+ FileSystemInfo->FreeSpace = FreeSpaceSize;
+
+ *BufferSize = FileSystemInfoLength;
+ Status = EFI_SUCCESS;
+ } else if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
+ Status = GetVolumeLabel (&PrivFsData->Volume, ARRAY_SIZE (VolumeLabel), VolumeLabel);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ FileSystemVolumeLabelLength = StrSize (VolumeLabel) +
+ sizeof (EFI_FILE_SYSTEM_VOLUME_LABEL);
+ if (*BufferSize < FileSystemVolumeLabelLength) {
+ *BufferSize = FileSystemVolumeLabelLength;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ FileSystemVolumeLabel = (EFI_FILE_SYSTEM_VOLUME_LABEL *)Buffer;
+ StrCpyS (
+ FileSystemVolumeLabel->VolumeLabel,
+ (*BufferSize - SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL) / sizeof (CHAR16),
+ VolumeLabel
+ );
+ Status = EFI_SUCCESS;
+ }
+
+ return Status;
+}
+
+/**
+ Set information about a file.
+
+ @param This Protocol instance pointer.
+ @param InformationType Type of information in Buffer.
+ @param BufferSize Size of buffer.
+ @param Buffer The data to write.
+
+ @retval EFI_SUCCESS Data was set.
+ @retval EFI_UNSUPPORTED InformationType is not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The device is write protected.
+ @retval EFI_ACCESS_DENIED The file was open for read only.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfSetInfo (
+ IN EFI_FILE_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ return EFI_WRITE_PROTECTED;
+}
+
+/**
+ Flush data back for the file handle.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS Data was flushed.
+ @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The device is write protected.
+ @retval EFI_ACCESS_DENIED The file was open for read only.
+ @retval EFI_VOLUME_FULL The volume is full.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfFlush (
+ IN EFI_FILE_PROTOCOL *This
+ )
+{
+ return EFI_WRITE_PROTECTED;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UdfDxe/FileName.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UdfDxe/FileName.c
new file mode 100644
index 00000000..4be4dfec
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UdfDxe/FileName.c
@@ -0,0 +1,214 @@
+/** @file
+ Helper functions for mangling file names in UDF/ECMA-167 file systems.
+
+ Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "Udf.h"
+
+/**
+ Trim the leading and trailing spaces for a give Unicode string.
+
+ @param[in] String The Unicode string to trim.
+
+ @return A pointer to the trimmed string.
+
+**/
+CHAR16 *
+TrimString (
+ IN CHAR16 *String
+ )
+{
+ CHAR16 *TempString;
+
+ for ( ; *String != L'\0' && *String == L' '; String++) {
+ ;
+ }
+
+ TempString = String + StrLen (String) - 1;
+ while ((TempString >= String) && (*TempString == L' ')) {
+ TempString--;
+ }
+
+ *(TempString + 1) = L'\0';
+
+ return String;
+}
+
+/**
+ Replace the content of a Unicode string with the content of another Unicode
+ string.
+
+ @param[in] Destination A pointer to a Unicode string.
+ @param[in] Source A pointer to a Unicode string.
+
+**/
+VOID
+ReplaceLeft (
+ IN CHAR16 *Destination,
+ IN CONST CHAR16 *Source
+ )
+{
+ CONST CHAR16 *EndString;
+
+ EndString = Source + StrLen (Source);
+ while (Source <= EndString) {
+ *Destination++ = *Source++;
+ }
+}
+
+/**
+ Remove one or more consecutive backslashes starting from the second character
+ of a given Unicode string.
+
+ @param[in] String A pointer to a Unicode string.
+
+ @return A pointer to the modified string.
+
+**/
+CHAR16 *
+ExcludeTrailingBackslashes (
+ IN CHAR16 *String
+ )
+{
+ CHAR16 *TempString;
+
+ switch (*(String + 1)) {
+ case L'\\':
+ break;
+ case L'\0':
+ default:
+ String++;
+ goto Exit;
+ }
+
+ TempString = String;
+ while (*TempString != L'\0' && *TempString == L'\\') {
+ TempString++;
+ }
+
+ if (TempString - 1 > String) {
+ ReplaceLeft (String + 1, TempString);
+ }
+
+ String++;
+
+Exit:
+ return String;
+}
+
+/**
+ Mangle a filename by cutting off trailing whitespaces, "\\", "." and "..".
+
+ @param[in] FileName Filename.
+
+ @retval The mangled Filename.
+
+**/
+CHAR16 *
+MangleFileName (
+ IN CHAR16 *FileName
+ )
+{
+ CHAR16 *FileNameSavedPointer;
+ CHAR16 *TempFileName;
+ UINTN BackslashesNo;
+
+ if (FileName == NULL || *FileName == L'\0') {
+ FileName = NULL;
+ goto Exit;
+ }
+
+ FileName = TrimString (FileName);
+ if (*FileName == L'\0') {
+ goto Exit;
+ }
+
+ if ((StrLen (FileName) > 1) && (FileName[StrLen (FileName) - 1] == L'\\')) {
+ FileName[StrLen (FileName) - 1] = L'\0';
+ }
+
+ FileNameSavedPointer = FileName;
+
+ if (FileName[0] == L'.') {
+ if (FileName[1] == L'.') {
+ if (FileName[2] == L'\0') {
+ goto Exit;
+ } else {
+ FileName += 2;
+ }
+ } else if (FileName[1] == L'\0') {
+ goto Exit;
+ }
+ }
+
+ while (*FileName != L'\0') {
+ if (*FileName == L'\\') {
+ FileName = ExcludeTrailingBackslashes (FileName);
+ } else if (*FileName == L'.') {
+ switch (*(FileName + 1)) {
+ case L'\0':
+ *FileName = L'\0';
+ break;
+ case L'\\':
+ TempFileName = FileName + 1;
+ TempFileName = ExcludeTrailingBackslashes (TempFileName);
+ ReplaceLeft (FileName, TempFileName);
+ break;
+ case '.':
+ if ((*(FileName - 1) != L'\\') && ((*(FileName + 2) != L'\\') ||
+ (*(FileName + 2) != L'\0'))) {
+ FileName++;
+ continue;
+ }
+
+ BackslashesNo = 0;
+ TempFileName = FileName - 1;
+ while (TempFileName >= FileNameSavedPointer) {
+ if (*TempFileName == L'\\') {
+ if (++BackslashesNo == 2) {
+ break;
+ }
+ }
+
+ TempFileName--;
+ }
+
+ TempFileName++;
+
+ if ((*TempFileName == L'.') && (*(TempFileName + 1) == L'.')) {
+ FileName += 2;
+ } else {
+ if (*(FileName + 2) != L'\0') {
+ ReplaceLeft (TempFileName, FileName + 3);
+ if (*(TempFileName - 1) == L'\\') {
+ FileName = TempFileName;
+ ExcludeTrailingBackslashes (TempFileName - 1);
+ TempFileName = FileName;
+ }
+ } else {
+ *TempFileName = L'\0';
+ }
+
+ FileName = TempFileName;
+ }
+
+ break;
+ default:
+ FileName++;
+ }
+ } else {
+ FileName++;
+ }
+ }
+
+ FileName = FileNameSavedPointer;
+ if ((StrLen (FileName) > 1) && (FileName [StrLen (FileName) - 1] == L'\\')) {
+ FileName [StrLen (FileName) - 1] = L'\0';
+ }
+
+Exit:
+ return FileName;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c
new file mode 100644
index 00000000..182fb016
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c
@@ -0,0 +1,2924 @@
+/** @file
+ Handle on-disk format and volume structures in UDF/ECMA-167 file systems.
+
+ Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
+ Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "Udf.h"
+
+//
+// Vendor-Defined Device Path GUID for UDF file system
+//
+EFI_GUID gUdfDevPathGuid = EFI_UDF_DEVICE_PATH_GUID;
+
+/**
+ Find the anchor volume descriptor pointer.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[out] AnchorPoint Anchor volume descriptor pointer.
+
+ @retval EFI_SUCCESS Anchor volume descriptor pointer found.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval other Anchor volume descriptor pointer not found.
+
+**/
+EFI_STATUS
+FindAnchorVolumeDescriptorPointer (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ OUT UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoint
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ EFI_LBA EndLBA;
+ EFI_LBA DescriptorLBAs[4];
+ UINTN Index;
+ UDF_DESCRIPTOR_TAG *DescriptorTag;
+
+ BlockSize = BlockIo->Media->BlockSize;
+ EndLBA = BlockIo->Media->LastBlock;
+ DescriptorLBAs[0] = 256;
+ DescriptorLBAs[1] = EndLBA - 256;
+ DescriptorLBAs[2] = EndLBA;
+ DescriptorLBAs[3] = 512;
+
+ for (Index = 0; Index < ARRAY_SIZE (DescriptorLBAs); Index++) {
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 (DescriptorLBAs[Index], BlockSize),
+ sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER),
+ (VOID *)AnchorPoint
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DescriptorTag = &AnchorPoint->DescriptorTag;
+
+ //
+ // Check if read LBA has a valid AVDP descriptor.
+ //
+ if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {
+ return EFI_SUCCESS;
+ }
+ }
+ //
+ // No AVDP found.
+ //
+ return EFI_VOLUME_CORRUPTED;
+}
+
+/**
+ Save the content of Logical Volume Descriptors and Partitions Descriptors in
+ memory.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] AnchorPoint Anchor volume descriptor pointer.
+ @param[out] Volume UDF volume information structure.
+
+ @retval EFI_SUCCESS The descriptors were saved.
+ @retval EFI_OUT_OF_RESOURCES The descriptors were not saved due to lack of
+ resources.
+ @retval other The descriptors were not saved due to
+ ReadDisk error.
+
+**/
+EFI_STATUS
+StartMainVolumeDescriptorSequence (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoint,
+ OUT UDF_VOLUME_INFO *Volume
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ UDF_EXTENT_AD *ExtentAd;
+ EFI_LBA SeqStartBlock;
+ EFI_LBA SeqEndBlock;
+ BOOLEAN StopSequence;
+ VOID *Buffer;
+ UDF_DESCRIPTOR_TAG *DescriptorTag;
+ UINT32 LogicalBlockSize;
+
+ BlockSize = BlockIo->Media->BlockSize;
+ ExtentAd = &AnchorPoint->MainVolumeDescriptorSequenceExtent;
+
+ //
+ // Allocate buffer for reading disk blocks
+ //
+ Buffer = AllocateZeroPool ((UINTN)BlockSize);
+ if (Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // The logical partition created by Partition driver is relative to the main
+ // VDS extent location, so we start the Main Volume Descriptor Sequence at
+ // LBA 0.
+ //
+ // We don't need to check again if we have valid Volume Descriptors here since
+ // Partition driver already did.
+ //
+ SeqStartBlock = 0;
+ SeqEndBlock = SeqStartBlock + DivU64x32 ((UINT64)ExtentAd->ExtentLength,
+ BlockSize);
+ StopSequence = FALSE;
+ for (; SeqStartBlock < SeqEndBlock && !StopSequence; SeqStartBlock++) {
+ //
+ // Read disk block
+ //
+ Status = BlockIo->ReadBlocks (
+ BlockIo,
+ BlockIo->Media->MediaId,
+ SeqStartBlock,
+ BlockSize,
+ Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ goto Out_Free;
+ }
+
+ DescriptorTag = Buffer;
+
+ switch (DescriptorTag->TagIdentifier) {
+ case UdfPartitionDescriptor:
+ //
+ // Save Partition Descriptor
+ //
+ CopyMem (&Volume->PartitionDesc, Buffer, sizeof (Volume->PartitionDesc));
+ break;
+
+ case UdfLogicalVolumeDescriptor:
+ //
+ // Save Logical Volume Descriptor
+ //
+ CopyMem (&Volume->LogicalVolDesc, Buffer, sizeof (Volume->LogicalVolDesc));
+ break;
+
+ case UdfTerminatingDescriptor:
+ StopSequence = TRUE;
+ break;
+
+ default:
+ ;
+ }
+ }
+
+ //
+ // Determine FE (File Entry) size
+ //
+ LogicalBlockSize = Volume->LogicalVolDesc.LogicalBlockSize;
+ if (LogicalBlockSize >= UDF_LOGICAL_SECTOR_SIZE) {
+ Volume->FileEntrySize = (UINTN)LogicalBlockSize;
+ } else {
+ Volume->FileEntrySize = UDF_LOGICAL_SECTOR_SIZE;
+ }
+
+ Status = EFI_SUCCESS;
+
+Out_Free:
+ //
+ // Free block read buffer
+ //
+ FreePool (Buffer);
+
+ return Status;
+}
+
+/**
+ Return a Partition Descriptor given a Long Allocation Descriptor. This is
+ necessary to calculate the right extent (LongAd) offset which is added up
+ with partition's starting location.
+
+ @param[in] Volume Volume information pointer.
+ @param[in] LongAd Long Allocation Descriptor pointer.
+
+ @return A pointer to a Partition Descriptor.
+
+**/
+UDF_PARTITION_DESCRIPTOR *
+GetPdFromLongAd (
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_LONG_ALLOCATION_DESCRIPTOR *LongAd
+ )
+{
+ UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc;
+ UINT16 PartitionNum;
+
+ LogicalVolDesc = &Volume->LogicalVolDesc;
+
+ switch (LogicalVolDesc->DomainIdentifier.Suffix.Domain.UdfRevision) {
+ case 0x0102:
+ case 0x0150:
+ case 0x0200:
+ case 0x0201:
+ case 0x0250:
+ case 0x0260:
+ //
+ // UDF 1.02 specification:
+ //
+ // There shall be exactly one prevailing Logical Volume Descriptor recorded
+ // per Volume Set. The Partition Maps field shall contain only Type 1
+ // Partition Maps.
+ //
+ // UDF 1.50 through 2.60 specs say:
+ //
+ // For the purpose of interchange partition maps shall be limited to
+ // Partition Map type 1, except type 2 maps as described in the document.
+ //
+ // NOTE: Only one Type 1 (Physical) Partition is supported. It has been
+ // checked already in Partition driver for existence of a single Type 1
+ // Partition map. Hence, the 'PartitionReferenceNumber' field (the index
+ // used to access Partition Maps data within the Logical Volume Descriptor)
+ // in the Long Allocation Descriptor should be 0 to indicate there is only
+ // one partition.
+ //
+ if (LongAd->ExtentLocation.PartitionReferenceNumber != 0) {
+ return NULL;
+ }
+ //
+ // Since only one partition, get the first one directly.
+ //
+ PartitionNum = *(UINT16 *)((UINTN)&LogicalVolDesc->PartitionMaps[4]);
+ break;
+
+ default:
+ //
+ // Unsupported UDF revision
+ //
+ return NULL;
+ }
+
+ //
+ // Check if partition number matches Partition Descriptor found in Main Volume
+ // Descriptor Sequence.
+ //
+ if (Volume->PartitionDesc.PartitionNumber == PartitionNum) {
+ return &Volume->PartitionDesc;
+ }
+
+ return NULL;
+}
+
+/**
+ Return logical sector number of a given Long Allocation Descriptor.
+
+ @param[in] Volume Volume information pointer.
+ @param[in] LongAd Long Allocation Descriptor pointer.
+ @param[out] Lsn Logical sector number pointer.
+
+ @retval EFI_SUCCESS Logical sector number successfully returned.
+ @retval EFI_UNSUPPORTED Logical sector number is not returned due to
+ unrecognized format.
+
+**/
+EFI_STATUS
+GetLongAdLsn (
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_LONG_ALLOCATION_DESCRIPTOR *LongAd,
+ OUT UINT64 *Lsn
+ )
+{
+ UDF_PARTITION_DESCRIPTOR *PartitionDesc;
+
+ PartitionDesc = GetPdFromLongAd (Volume, LongAd);
+ if (PartitionDesc == NULL) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Fail to get the Partition Descriptor from the given Long Allocation Descriptor.\n",
+ __FUNCTION__
+ ));
+ return EFI_UNSUPPORTED;
+ }
+
+ *Lsn = (UINT64)PartitionDesc->PartitionStartingLocation -
+ Volume->MainVdsStartLocation +
+ LongAd->ExtentLocation.LogicalBlockNumber;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return logical sector number of a given Short Allocation Descriptor.
+
+ @param[in] Volume Volume pointer.
+ @param[in] PartitionDesc Partition Descriptor pointer.
+ @param[in] ShortAd Short Allocation Descriptor pointer.
+
+ @return The logical sector number of a given Short Allocation Descriptor.
+
+**/
+UINT64
+GetShortAdLsn (
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_PARTITION_DESCRIPTOR *PartitionDesc,
+ IN UDF_SHORT_ALLOCATION_DESCRIPTOR *ShortAd
+ )
+{
+ return (UINT64)PartitionDesc->PartitionStartingLocation -
+ Volume->MainVdsStartLocation + ShortAd->ExtentPosition;
+}
+
+/**
+ Find File Set Descriptor of a given Logical Volume Descriptor.
+
+ The found FSD will contain the extent (LogicalVolumeContentsUse) where our
+ root directory is.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume Volume information pointer.
+
+ @retval EFI_SUCCESS File Set Descriptor pointer found.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval other File Set Descriptor pointer not found.
+
+**/
+EFI_STATUS
+FindFileSetDescriptor (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Lsn;
+ UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc;
+ UDF_DESCRIPTOR_TAG *DescriptorTag;
+
+ LogicalVolDesc = &Volume->LogicalVolDesc;
+ Status = GetLongAdLsn (Volume, &LogicalVolDesc->LogicalVolumeContentsUse, &Lsn);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // As per UDF 2.60 specification:
+ //
+ // There shall be exactly one File Set Descriptor recorded per Logical
+ // Volume.
+ //
+ // Read disk block
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 (Lsn, LogicalVolDesc->LogicalBlockSize),
+ sizeof (Volume->FileSetDesc),
+ &Volume->FileSetDesc
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DescriptorTag = &Volume->FileSetDesc.DescriptorTag;
+
+ //
+ // Check if read block is a File Set Descriptor
+ //
+ if (DescriptorTag->TagIdentifier != UdfFileSetDescriptor) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read Volume and File Structure on an UDF file system.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[out] Volume Volume information pointer.
+
+ @retval EFI_SUCCESS Volume and File Structure were read.
+ @retval other Volume and File Structure were not read.
+
+**/
+EFI_STATUS
+ReadVolumeFileStructure (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ OUT UDF_VOLUME_INFO *Volume
+ )
+{
+ EFI_STATUS Status;
+ UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER AnchorPoint;
+ UDF_EXTENT_AD *ExtentAd;
+
+ //
+ // Find Anchor Volume Descriptor Pointer
+ //
+ Status = FindAnchorVolumeDescriptorPointer (
+ BlockIo,
+ DiskIo,
+ &AnchorPoint
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Save Main VDS start block number
+ //
+ ExtentAd = &AnchorPoint.MainVolumeDescriptorSequenceExtent;
+
+ Volume->MainVdsStartLocation = (UINT64)ExtentAd->ExtentLocation;
+
+ //
+ // Start Main Volume Descriptor Sequence.
+ //
+ Status = StartMainVolumeDescriptorSequence (
+ BlockIo,
+ DiskIo,
+ &AnchorPoint,
+ Volume
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return Status;
+}
+
+/**
+ Calculate length of a given File Identifier Descriptor.
+
+ @param[in] FileIdentifierDesc File Identifier Descriptor pointer.
+
+ @return The length of a given File Identifier Descriptor.
+
+**/
+UINT64
+GetFidDescriptorLength (
+ IN UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc
+ )
+{
+ return (UINT64)(
+ (INTN)((OFFSET_OF (UDF_FILE_IDENTIFIER_DESCRIPTOR, Data[0]) + 3 +
+ FileIdentifierDesc->LengthOfFileIdentifier +
+ FileIdentifierDesc->LengthOfImplementationUse) >> 2) << 2
+ );
+}
+
+/**
+ Duplicate a given File Identifier Descriptor.
+
+ @param[in] FileIdentifierDesc File Identifier Descriptor pointer.
+ @param[out] NewFileIdentifierDesc The duplicated File Identifier Descriptor.
+
+**/
+VOID
+DuplicateFid (
+ IN UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc,
+ OUT UDF_FILE_IDENTIFIER_DESCRIPTOR **NewFileIdentifierDesc
+ )
+{
+ *NewFileIdentifierDesc =
+ (UDF_FILE_IDENTIFIER_DESCRIPTOR *)AllocateCopyPool (
+ (UINTN) GetFidDescriptorLength (FileIdentifierDesc), FileIdentifierDesc);
+}
+
+/**
+ Duplicate either a given File Entry or a given Extended File Entry.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] Volume Volume information pointer.
+ @param[in] FileEntry (Extended) File Entry pointer.
+ @param[out] NewFileEntry The duplicated (Extended) File Entry.
+
+**/
+VOID
+DuplicateFe (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN VOID *FileEntry,
+ OUT VOID **NewFileEntry
+ )
+{
+ *NewFileEntry = AllocateCopyPool (Volume->FileEntrySize, FileEntry);
+}
+
+/**
+ Get raw data + length of a given File Entry or Extended File Entry.
+
+ The file's recorded data can contain either real file content (inline) or
+ a sequence of extents (or Allocation Descriptors) which tells where file's
+ content is stored in.
+
+ NOTE: The FE/EFE can be thought it was an inode.
+
+ @attention This is boundary function that may receive untrusted input.
+ @attention The input is from FileSystem.
+
+ The (Extended) File Entry is external input, so this routine will do basic
+ validation for (Extended) File Entry and report status.
+
+ @param[in] FileEntryData (Extended) File Entry pointer.
+ @param[in] FileEntrySize Size of the (Extended) File Entry specified
+ by FileEntryData.
+ @param[out] Data Buffer contains the raw data of a given
+ (Extended) File Entry.
+ @param[out] Length Length of the data in Buffer.
+
+ @retval EFI_SUCCESS Raw data and size of the FE/EFE was read.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+
+**/
+EFI_STATUS
+GetFileEntryData (
+ IN VOID *FileEntryData,
+ IN UINTN FileEntrySize,
+ OUT VOID **Data,
+ OUT UINT64 *Length
+ )
+{
+ UDF_DESCRIPTOR_TAG *DescriptorTag;
+ UDF_EXTENDED_FILE_ENTRY *ExtendedFileEntry;
+ UDF_FILE_ENTRY *FileEntry;
+
+ DescriptorTag = FileEntryData;
+
+ if (DescriptorTag->TagIdentifier == UdfExtendedFileEntry) {
+ ExtendedFileEntry = (UDF_EXTENDED_FILE_ENTRY *)FileEntryData;
+
+ *Length = ExtendedFileEntry->InformationLength;
+ *Data = (VOID *)((UINT8 *)ExtendedFileEntry->Data +
+ ExtendedFileEntry->LengthOfExtendedAttributes);
+ } else if (DescriptorTag->TagIdentifier == UdfFileEntry) {
+ FileEntry = (UDF_FILE_ENTRY *)FileEntryData;
+
+ *Length = FileEntry->InformationLength;
+ *Data = (VOID *)((UINT8 *)FileEntry->Data +
+ FileEntry->LengthOfExtendedAttributes);
+ }
+
+ if ((*Length > FileEntrySize) ||
+ ((UINTN)FileEntryData > (UINTN)(*Data)) ||
+ ((UINTN)(*Data) - (UINTN)FileEntryData > FileEntrySize - *Length)) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Get Allocation Descriptors' data information from a given FE/EFE.
+
+ @attention This is boundary function that may receive untrusted input.
+ @attention The input is from FileSystem.
+
+ The (Extended) File Entry is external input, so this routine will do basic
+ validation for (Extended) File Entry and report status.
+
+ @param[in] FileEntryData (Extended) File Entry pointer.
+ @param[in] FileEntrySize Size of the (Extended) File Entry specified
+ by FileEntryData.
+ @param[out] AdsData Buffer contains the Allocation Descriptors'
+ data from a given FE/EFE.
+ @param[out] Length Length of the data in AdsData.
+
+ @retval EFI_SUCCESS The data and size of Allocation Descriptors
+ were read from the FE/EFE.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+
+**/
+EFI_STATUS
+GetAdsInformation (
+ IN VOID *FileEntryData,
+ IN UINTN FileEntrySize,
+ OUT VOID **AdsData,
+ OUT UINT64 *Length
+ )
+{
+ UDF_DESCRIPTOR_TAG *DescriptorTag;
+ UDF_EXTENDED_FILE_ENTRY *ExtendedFileEntry;
+ UDF_FILE_ENTRY *FileEntry;
+
+ DescriptorTag = FileEntryData;
+
+ if (DescriptorTag->TagIdentifier == UdfExtendedFileEntry) {
+ ExtendedFileEntry = (UDF_EXTENDED_FILE_ENTRY *)FileEntryData;
+
+ *Length = ExtendedFileEntry->LengthOfAllocationDescriptors;
+ *AdsData = (VOID *)((UINT8 *)ExtendedFileEntry->Data +
+ ExtendedFileEntry->LengthOfExtendedAttributes);
+ } else if (DescriptorTag->TagIdentifier == UdfFileEntry) {
+ FileEntry = (UDF_FILE_ENTRY *)FileEntryData;
+
+ *Length = FileEntry->LengthOfAllocationDescriptors;
+ *AdsData = (VOID *)((UINT8 *)FileEntry->Data +
+ FileEntry->LengthOfExtendedAttributes);
+ }
+
+ if ((*Length > FileEntrySize) ||
+ ((UINTN)FileEntryData > (UINTN)(*AdsData)) ||
+ ((UINTN)(*AdsData) - (UINTN)FileEntryData > FileEntrySize - *Length)) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Read next Long Allocation Descriptor from a given file's data.
+
+ @param[in] Data File's data pointer.
+ @param[in,out] Offset Starting offset of the File's data to read.
+ @param[in] Length Length of the data to read.
+ @param[out] FoundLongAd Long Allocation Descriptor pointer.
+
+ @retval EFI_SUCCESS A Long Allocation Descriptor was found.
+ @retval EFI_DEVICE_ERROR No more Long Allocation Descriptors.
+
+**/
+EFI_STATUS
+GetLongAdFromAds (
+ IN VOID *Data,
+ IN OUT UINT64 *Offset,
+ IN UINT64 Length,
+ OUT UDF_LONG_ALLOCATION_DESCRIPTOR **FoundLongAd
+ )
+{
+ UDF_LONG_ALLOCATION_DESCRIPTOR *LongAd;
+ UDF_EXTENT_FLAGS ExtentFlags;
+
+ for (;;) {
+ if (*Offset >= Length) {
+ //
+ // No more Long Allocation Descriptors.
+ //
+ return EFI_DEVICE_ERROR;
+ }
+
+ LongAd =
+ (UDF_LONG_ALLOCATION_DESCRIPTOR *)((UINT8 *)Data + *Offset);
+
+ //
+ // If it's either an indirect AD (Extended Alllocation Descriptor) or an
+ // allocated AD, then return it.
+ //
+ ExtentFlags = GET_EXTENT_FLAGS (LongAdsSequence, LongAd);
+ if (ExtentFlags == ExtentIsNextExtent ||
+ ExtentFlags == ExtentRecordedAndAllocated) {
+ break;
+ }
+
+ //
+ // This AD is either not recorded but allocated, or not recorded and not
+ // allocated. Skip it.
+ //
+ *Offset += AD_LENGTH (LongAdsSequence);
+ }
+
+ *FoundLongAd = LongAd;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read next Short Allocation Descriptor from a given file's data.
+
+ @param[in] Data File's data pointer.
+ @param[in,out] Offset Starting offset of the File's data to read.
+ @param[in] Length Length of the data to read.
+ @param[out] FoundShortAd Short Allocation Descriptor pointer.
+
+ @retval EFI_SUCCESS A Short Allocation Descriptor was found.
+ @retval EFI_DEVICE_ERROR No more Short Allocation Descriptors.
+
+**/
+EFI_STATUS
+GetShortAdFromAds (
+ IN VOID *Data,
+ IN OUT UINT64 *Offset,
+ IN UINT64 Length,
+ OUT UDF_SHORT_ALLOCATION_DESCRIPTOR **FoundShortAd
+ )
+{
+ UDF_SHORT_ALLOCATION_DESCRIPTOR *ShortAd;
+ UDF_EXTENT_FLAGS ExtentFlags;
+
+ for (;;) {
+ if (*Offset >= Length) {
+ //
+ // No more Short Allocation Descriptors.
+ //
+ return EFI_DEVICE_ERROR;
+ }
+
+ ShortAd =
+ (UDF_SHORT_ALLOCATION_DESCRIPTOR *)((UINT8 *)Data + *Offset);
+
+ //
+ // If it's either an indirect AD (Extended Alllocation Descriptor) or an
+ // allocated AD, then return it.
+ //
+ ExtentFlags = GET_EXTENT_FLAGS (ShortAdsSequence, ShortAd);
+ if (ExtentFlags == ExtentIsNextExtent ||
+ ExtentFlags == ExtentRecordedAndAllocated) {
+ break;
+ }
+
+ //
+ // This AD is either not recorded but allocated, or not recorded and not
+ // allocated. Skip it.
+ //
+ *Offset += AD_LENGTH (ShortAdsSequence);
+ }
+
+ *FoundShortAd = ShortAd;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get either a Short Allocation Descriptor or a Long Allocation Descriptor from
+ file's data.
+
+ @param[in] RecordingFlags Flag to indicate the type of descriptor.
+ @param[in] Data File's data pointer.
+ @param[in,out] Offset Starting offset of the File's data to read.
+ @param[in] Length Length of the data to read.
+ @param[out] FoundAd Allocation Descriptor pointer.
+
+ @retval EFI_SUCCESS A Short Allocation Descriptor was found.
+ @retval EFI_DEVICE_ERROR No more Allocation Descriptors.
+ Invalid type of descriptor was given.
+
+**/
+EFI_STATUS
+GetAllocationDescriptor (
+ IN UDF_FE_RECORDING_FLAGS RecordingFlags,
+ IN VOID *Data,
+ IN OUT UINT64 *Offset,
+ IN UINT64 Length,
+ OUT VOID **FoundAd
+ )
+{
+ if (RecordingFlags == LongAdsSequence) {
+ return GetLongAdFromAds (
+ Data,
+ Offset,
+ Length,
+ (UDF_LONG_ALLOCATION_DESCRIPTOR **)FoundAd
+ );
+ } else if (RecordingFlags == ShortAdsSequence) {
+ return GetShortAdFromAds (
+ Data,
+ Offset,
+ Length,
+ (UDF_SHORT_ALLOCATION_DESCRIPTOR **)FoundAd
+ );
+ }
+
+ //
+ // Code should never reach here.
+ //
+ ASSERT (FALSE);
+ return EFI_DEVICE_ERROR;
+}
+
+/**
+ Return logical sector number of either Short or Long Allocation Descriptor.
+
+ @param[in] RecordingFlags Flag to indicate the type of descriptor.
+ @param[in] Volume Volume information pointer.
+ @param[in] ParentIcb Long Allocation Descriptor pointer.
+ @param[in] Ad Allocation Descriptor pointer.
+ @param[out] Lsn Logical sector number pointer.
+
+ @retval EFI_SUCCESS Logical sector number of the given Allocation
+ Descriptor successfully returned.
+ @retval EFI_UNSUPPORTED Logical sector number of the given Allocation
+ Descriptor is not returned due to unrecognized
+ format.
+
+**/
+EFI_STATUS
+GetAllocationDescriptorLsn (
+ IN UDF_FE_RECORDING_FLAGS RecordingFlags,
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,
+ IN VOID *Ad,
+ OUT UINT64 *Lsn
+ )
+{
+ UDF_PARTITION_DESCRIPTOR *PartitionDesc;
+
+ if (RecordingFlags == LongAdsSequence) {
+ return GetLongAdLsn (Volume, (UDF_LONG_ALLOCATION_DESCRIPTOR *)Ad, Lsn);
+ } else if (RecordingFlags == ShortAdsSequence) {
+ PartitionDesc = GetPdFromLongAd (Volume, ParentIcb);
+ if (PartitionDesc == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ *Lsn = GetShortAdLsn (
+ Volume,
+ PartitionDesc,
+ (UDF_SHORT_ALLOCATION_DESCRIPTOR *)Ad
+ );
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Code should never reach here.
+ //
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Return offset + length of a given indirect Allocation Descriptor (AED).
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume Volume information pointer.
+ @param[in] ParentIcb Long Allocation Descriptor pointer.
+ @param[in] RecordingFlags Flag to indicate the type of descriptor.
+ @param[in] Ad Allocation Descriptor pointer.
+ @param[out] Offset Offset of a given indirect Allocation
+ Descriptor.
+ @param[out] Length Length of a given indirect Allocation
+ Descriptor.
+
+ @retval EFI_SUCCESS The offset and length were returned.
+ @retval EFI_OUT_OF_RESOURCES The offset and length were not returned due
+ to lack of resources.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval other The offset and length were not returned.
+
+**/
+EFI_STATUS
+GetAedAdsOffset (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,
+ IN UDF_FE_RECORDING_FLAGS RecordingFlags,
+ IN VOID *Ad,
+ OUT UINT64 *Offset,
+ OUT UINT64 *Length
+ )
+{
+ EFI_STATUS Status;
+ UINT32 ExtentLength;
+ UINT64 Lsn;
+ VOID *Data;
+ UINT32 LogicalBlockSize;
+ UDF_ALLOCATION_EXTENT_DESCRIPTOR *AllocExtDesc;
+ UDF_DESCRIPTOR_TAG *DescriptorTag;
+
+ ExtentLength = GET_EXTENT_LENGTH (RecordingFlags, Ad);
+ Status = GetAllocationDescriptorLsn (RecordingFlags,
+ Volume,
+ ParentIcb,
+ Ad,
+ &Lsn);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Data = AllocatePool (ExtentLength);
+ if (Data == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ LogicalBlockSize = Volume->LogicalVolDesc.LogicalBlockSize;
+
+ //
+ // Read extent.
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 (Lsn, LogicalBlockSize),
+ ExtentLength,
+ Data
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ AllocExtDesc = (UDF_ALLOCATION_EXTENT_DESCRIPTOR *)Data;
+
+ DescriptorTag = &AllocExtDesc->DescriptorTag;
+
+ //
+ // Check if read extent contains a valid tag identifier for AED.
+ //
+ if (DescriptorTag->TagIdentifier != UdfAllocationExtentDescriptor) {
+ Status = EFI_VOLUME_CORRUPTED;
+ goto Exit;
+ }
+
+ //
+ // Get AED's block offset and its length.
+ //
+ *Offset = MultU64x32 (Lsn, LogicalBlockSize) +
+ sizeof (UDF_ALLOCATION_EXTENT_DESCRIPTOR);
+ *Length = AllocExtDesc->LengthOfAllocationDescriptors;
+
+Exit:
+ FreePool (Data);
+
+ return Status;
+}
+
+/**
+ Read Allocation Extent Descriptor into memory.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume Volume information pointer.
+ @param[in] ParentIcb Long Allocation Descriptor pointer.
+ @param[in] RecordingFlags Flag to indicate the type of descriptor.
+ @param[in] Ad Allocation Descriptor pointer.
+ @param[out] Data Buffer that contains the Allocation Extent
+ Descriptor.
+ @param[out] Length Length of Data.
+
+ @retval EFI_SUCCESS The Allocation Extent Descriptor was read.
+ @retval EFI_OUT_OF_RESOURCES The Allocation Extent Descriptor was not read
+ due to lack of resources.
+ @retval other Fail to read the disk.
+
+**/
+EFI_STATUS
+GetAedAdsData (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,
+ IN UDF_FE_RECORDING_FLAGS RecordingFlags,
+ IN VOID *Ad,
+ OUT VOID **Data,
+ OUT UINT64 *Length
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Offset;
+
+ //
+ // Get AED's offset + length.
+ //
+ Status = GetAedAdsOffset (
+ BlockIo,
+ DiskIo,
+ Volume,
+ ParentIcb,
+ RecordingFlags,
+ Ad,
+ &Offset,
+ Length
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Allocate buffer to read in AED's data.
+ //
+ *Data = AllocatePool ((UINTN) (*Length));
+ if (*Data == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ Offset,
+ (UINTN) (*Length),
+ *Data
+ );
+}
+
+/**
+ Function used to serialise reads of Allocation Descriptors.
+
+ @param[in] RecordingFlags Flag to indicate the type of descriptor.
+ @param[in] Ad Allocation Descriptor pointer.
+ @param[in, out] Buffer Buffer to hold the next Allocation Descriptor.
+ @param[in] Length Length of Buffer.
+
+ @retval EFI_SUCCESS Buffer was grown to hold the next Allocation
+ Descriptor.
+ @retval EFI_OUT_OF_RESOURCES Buffer was not grown due to lack of resources.
+
+**/
+EFI_STATUS
+GrowUpBufferToNextAd (
+ IN UDF_FE_RECORDING_FLAGS RecordingFlags,
+ IN VOID *Ad,
+ IN OUT VOID **Buffer,
+ IN UINT64 Length
+ )
+{
+ UINT32 ExtentLength;
+
+ ExtentLength = GET_EXTENT_LENGTH (RecordingFlags, Ad);
+
+ if (*Buffer == NULL) {
+ *Buffer = AllocatePool (ExtentLength);
+ if (*Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ *Buffer = ReallocatePool ((UINTN) Length, (UINTN) (Length + ExtentLength), *Buffer);
+ if (*Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read data or size of either a File Entry or an Extended File Entry.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume Volume information pointer.
+ @param[in] ParentIcb Long Allocation Descriptor pointer.
+ @param[in] FileEntryData FE/EFE structure pointer.
+ @param[in, out] ReadFileInfo Read file information pointer.
+
+ @retval EFI_SUCCESS Data or size of a FE/EFE was read.
+ @retval EFI_OUT_OF_RESOURCES Data or size of a FE/EFE was not read due to
+ lack of resources.
+ @retval EFI_INVALID_PARAMETER The read file flag given in ReadFileInfo is
+ invalid.
+ @retval EFI_UNSUPPORTED The FE recording flag given in FileEntryData
+ is not supported.
+ @retval other Data or size of a FE/EFE was not read.
+
+**/
+EFI_STATUS
+ReadFile (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,
+ IN VOID *FileEntryData,
+ IN OUT UDF_READ_FILE_INFO *ReadFileInfo
+ )
+{
+ EFI_STATUS Status;
+ UINT32 LogicalBlockSize;
+ VOID *Data;
+ VOID *DataBak;
+ UINT64 Length;
+ VOID *Ad;
+ UINT64 AdOffset;
+ UINT64 Lsn;
+ BOOLEAN DoFreeAed;
+ UINT64 FilePosition;
+ UINT64 Offset;
+ UINT64 DataOffset;
+ UINT64 BytesLeft;
+ UINT64 DataLength;
+ BOOLEAN FinishedSeeking;
+ UINT32 ExtentLength;
+ UDF_FE_RECORDING_FLAGS RecordingFlags;
+
+ LogicalBlockSize = Volume->LogicalVolDesc.LogicalBlockSize;
+ DoFreeAed = FALSE;
+
+ //
+ // set BytesLeft to suppress incorrect compiler/analyzer warnings
+ //
+ BytesLeft = 0;
+ DataOffset = 0;
+ FilePosition = 0;
+ FinishedSeeking = FALSE;
+ Data = NULL;
+
+ switch (ReadFileInfo->Flags) {
+ case ReadFileGetFileSize:
+ case ReadFileAllocateAndRead:
+ //
+ // Initialise ReadFileInfo structure for either getting file size, or
+ // reading file's recorded data.
+ //
+ ReadFileInfo->ReadLength = 0;
+ ReadFileInfo->FileData = NULL;
+ break;
+ case ReadFileSeekAndRead:
+ //
+ // About to seek a file and/or read its data.
+ //
+ Length = ReadFileInfo->FileSize - ReadFileInfo->FilePosition;
+ if (ReadFileInfo->FileDataSize > Length) {
+ //
+ // About to read beyond the EOF -- truncate it.
+ //
+ ReadFileInfo->FileDataSize = Length;
+ }
+
+ //
+ // Initialise data to start seeking and/or reading a file.
+ //
+ BytesLeft = ReadFileInfo->FileDataSize;
+ DataOffset = 0;
+ FilePosition = 0;
+ FinishedSeeking = FALSE;
+
+ break;
+ }
+
+ RecordingFlags = GET_FE_RECORDING_FLAGS (FileEntryData);
+ switch (RecordingFlags) {
+ case InlineData:
+ //
+ // There are no extents for this FE/EFE. All data is inline.
+ //
+ Status = GetFileEntryData (FileEntryData, Volume->FileEntrySize, &Data, &Length);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (ReadFileInfo->Flags == ReadFileGetFileSize) {
+ ReadFileInfo->ReadLength = Length;
+ } else if (ReadFileInfo->Flags == ReadFileAllocateAndRead) {
+ //
+ // Allocate buffer for starting read data.
+ //
+ ReadFileInfo->FileData = AllocatePool ((UINTN) Length);
+ if (ReadFileInfo->FileData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Read all inline data into ReadFileInfo->FileData
+ //
+ CopyMem (ReadFileInfo->FileData, Data, (UINTN) Length);
+ ReadFileInfo->ReadLength = Length;
+ } else if (ReadFileInfo->Flags == ReadFileSeekAndRead) {
+ //
+ // If FilePosition is non-zero, seek file to FilePosition, read
+ // FileDataSize bytes and then updates FilePosition.
+ //
+ CopyMem (
+ ReadFileInfo->FileData,
+ (VOID *)((UINT8 *)Data + ReadFileInfo->FilePosition),
+ (UINTN) ReadFileInfo->FileDataSize
+ );
+
+ ReadFileInfo->FilePosition += ReadFileInfo->FileDataSize;
+ } else {
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ break;
+
+ case LongAdsSequence:
+ case ShortAdsSequence:
+ //
+ // This FE/EFE contains a run of Allocation Descriptors. Get data + size
+ // for start reading them out.
+ //
+ Status = GetAdsInformation (FileEntryData, Volume->FileEntrySize, &Data, &Length);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ AdOffset = 0;
+
+ for (;;) {
+ //
+ // Read AD.
+ //
+ Status = GetAllocationDescriptor (
+ RecordingFlags,
+ Data,
+ &AdOffset,
+ Length,
+ &Ad
+ );
+ if (Status == EFI_DEVICE_ERROR) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ //
+ // Check if AD is an indirect AD. If so, read Allocation Extent
+ // Descriptor and its extents (ADs).
+ //
+ if (GET_EXTENT_FLAGS (RecordingFlags, Ad) == ExtentIsNextExtent) {
+ DataBak = Data;
+ Status = GetAedAdsData (
+ BlockIo,
+ DiskIo,
+ Volume,
+ ParentIcb,
+ RecordingFlags,
+ Ad,
+ &Data,
+ &Length
+ );
+
+ if (!DoFreeAed) {
+ DoFreeAed = TRUE;
+ } else {
+ FreePool (DataBak);
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto Error_Get_Aed;
+ }
+ ASSERT (Data != NULL);
+
+ AdOffset = 0;
+ continue;
+ }
+
+ ExtentLength = GET_EXTENT_LENGTH (RecordingFlags, Ad);
+
+ Status = GetAllocationDescriptorLsn (RecordingFlags,
+ Volume,
+ ParentIcb,
+ Ad,
+ &Lsn);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ switch (ReadFileInfo->Flags) {
+ case ReadFileGetFileSize:
+ ReadFileInfo->ReadLength += ExtentLength;
+ break;
+ case ReadFileAllocateAndRead:
+ //
+ // Increase FileData (if necessary) to read next extent.
+ //
+ Status = GrowUpBufferToNextAd (
+ RecordingFlags,
+ Ad,
+ &ReadFileInfo->FileData,
+ ReadFileInfo->ReadLength
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error_Alloc_Buffer_To_Next_Ad;
+ }
+
+ //
+ // Read extent's data into FileData.
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 (Lsn, LogicalBlockSize),
+ ExtentLength,
+ (VOID *)((UINT8 *)ReadFileInfo->FileData +
+ ReadFileInfo->ReadLength)
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error_Read_Disk_Blk;
+ }
+
+ ReadFileInfo->ReadLength += ExtentLength;
+ break;
+ case ReadFileSeekAndRead:
+ //
+ // Seek file first before reading in its data.
+ //
+ if (FinishedSeeking) {
+ Offset = 0;
+ goto Skip_File_Seek;
+ }
+
+ if (FilePosition + ExtentLength < ReadFileInfo->FilePosition) {
+ FilePosition += ExtentLength;
+ goto Skip_Ad;
+ }
+
+ if (FilePosition + ExtentLength > ReadFileInfo->FilePosition) {
+ Offset = ReadFileInfo->FilePosition - FilePosition;
+ } else {
+ Offset = 0;
+ }
+
+ //
+ // Done with seeking file. Start reading its data.
+ //
+ FinishedSeeking = TRUE;
+
+ Skip_File_Seek:
+ //
+ // Make sure we don't read more data than really wanted.
+ //
+ if (ExtentLength - Offset > BytesLeft) {
+ DataLength = BytesLeft;
+ } else {
+ DataLength = ExtentLength - Offset;
+ }
+
+ //
+ // Read extent's data into FileData.
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ Offset + MultU64x32 (Lsn, LogicalBlockSize),
+ (UINTN) DataLength,
+ (VOID *)((UINT8 *)ReadFileInfo->FileData +
+ DataOffset)
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error_Read_Disk_Blk;
+ }
+
+ //
+ // Update current file's position.
+ //
+ DataOffset += DataLength;
+ ReadFileInfo->FilePosition += DataLength;
+
+ BytesLeft -= DataLength;
+ if (BytesLeft == 0) {
+ //
+ // There is no more file data to read.
+ //
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ break;
+ }
+
+ Skip_Ad:
+ //
+ // Point to the next AD (extent).
+ //
+ AdOffset += AD_LENGTH (RecordingFlags);
+ }
+
+ break;
+ case ExtendedAdsSequence:
+ // FIXME: Not supported. Got no volume with it, yet.
+ ASSERT (FALSE);
+ Status = EFI_UNSUPPORTED;
+ break;
+
+ default:
+ //
+ // A flag value reserved by the ECMA-167 standard (3rd Edition - June
+ // 1997); 14.6 ICB Tag; 14.6.8 Flags (RBP 18); was found.
+ //
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+
+Done:
+ if (DoFreeAed) {
+ FreePool (Data);
+ }
+
+ return Status;
+
+Error_Read_Disk_Blk:
+Error_Alloc_Buffer_To_Next_Ad:
+ if (ReadFileInfo->Flags != ReadFileSeekAndRead) {
+ FreePool (ReadFileInfo->FileData);
+ }
+
+ if (DoFreeAed) {
+ FreePool (Data);
+ }
+
+Error_Get_Aed:
+ return Status;
+}
+
+/**
+ Find a file by its filename from a given Parent file.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume Volume information pointer.
+ @param[in] FileName File name string.
+ @param[in] Parent Parent directory file.
+ @param[in] Icb Long Allocation Descriptor pointer.
+ @param[out] File Found file.
+
+ @retval EFI_SUCCESS The file was found.
+ @retval EFI_INVALID_PARAMETER One or more input parameters are invalid.
+ @retval EFI_NOT_FOUND The file was not found.
+
+**/
+EFI_STATUS
+InternalFindFile (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN CHAR16 *FileName,
+ IN UDF_FILE_INFO *Parent,
+ IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb,
+ OUT UDF_FILE_INFO *File
+ )
+{
+ EFI_STATUS Status;
+ UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc;
+ UDF_READ_DIRECTORY_INFO ReadDirInfo;
+ BOOLEAN Found;
+ CHAR16 FoundFileName[UDF_FILENAME_LENGTH];
+ VOID *CompareFileEntry;
+
+ //
+ // Check if both Parent->FileIdentifierDesc and Icb are NULL.
+ //
+ if ((Parent->FileIdentifierDesc == NULL) && (Icb == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check if parent file is really directory.
+ //
+ if (FE_ICB_FILE_TYPE (Parent->FileEntry) != UdfFileEntryDirectory) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // If FileName is current file or working directory, just duplicate Parent's
+ // FE/EFE and FID descriptors.
+ //
+ if (StrCmp (FileName, L".") == 0) {
+ if (Parent->FileIdentifierDesc == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DuplicateFe (BlockIo, Volume, Parent->FileEntry, &File->FileEntry);
+ if (File->FileEntry == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DuplicateFid (Parent->FileIdentifierDesc, &File->FileIdentifierDesc);
+ if (File->FileIdentifierDesc == NULL) {
+ FreePool (File->FileEntry);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Start directory listing.
+ //
+ ZeroMem ((VOID *)&ReadDirInfo, sizeof (UDF_READ_DIRECTORY_INFO));
+ Found = FALSE;
+
+ for (;;) {
+ Status = ReadDirectoryEntry (
+ BlockIo,
+ DiskIo,
+ Volume,
+ (Parent->FileIdentifierDesc != NULL) ?
+ &Parent->FileIdentifierDesc->Icb :
+ Icb,
+ Parent->FileEntry,
+ &ReadDirInfo,
+ &FileIdentifierDesc
+ );
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_DEVICE_ERROR) {
+ Status = EFI_NOT_FOUND;
+ }
+
+ break;
+ }
+ //
+ // After calling function ReadDirectoryEntry(), if 'FileIdentifierDesc' is
+ // NULL, then the 'Status' must be EFI_OUT_OF_RESOURCES. Hence, if the code
+ // reaches here, 'FileIdentifierDesc' must be not NULL.
+ //
+ // The ASSERT here is for addressing a false positive NULL pointer
+ // dereference issue raised from static analysis.
+ //
+ ASSERT (FileIdentifierDesc != NULL);
+
+ if (FileIdentifierDesc->FileCharacteristics & PARENT_FILE) {
+ //
+ // This FID contains the location (FE/EFE) of the parent directory of this
+ // directory (Parent), and if FileName is either ".." or "\\", then it's
+ // the expected FID.
+ //
+ if (StrCmp (FileName, L"..") == 0 || StrCmp (FileName, L"\\") == 0) {
+ Found = TRUE;
+ break;
+ }
+ } else {
+ Status = GetFileNameFromFid (FileIdentifierDesc, ARRAY_SIZE (FoundFileName), FoundFileName);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (StrCmp (FileName, FoundFileName) == 0) {
+ //
+ // FID has been found. Prepare to find its respective FE/EFE.
+ //
+ Found = TRUE;
+ break;
+ }
+ }
+
+ FreePool ((VOID *)FileIdentifierDesc);
+ }
+
+ if (ReadDirInfo.DirectoryData != NULL) {
+ //
+ // Free all allocated resources for the directory listing.
+ //
+ FreePool (ReadDirInfo.DirectoryData);
+ }
+
+ if (Found) {
+ Status = EFI_SUCCESS;
+
+ File->FileIdentifierDesc = FileIdentifierDesc;
+
+ //
+ // If the requested file is root directory, then the FE/EFE was already
+ // retrieved in UdfOpenVolume() function, thus no need to find it again.
+ //
+ // Otherwise, find FE/EFE from the respective FID.
+ //
+ if (StrCmp (FileName, L"\\") != 0) {
+ Status = FindFileEntry (
+ BlockIo,
+ DiskIo,
+ Volume,
+ &FileIdentifierDesc->Icb,
+ &CompareFileEntry
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error_Find_Fe;
+ }
+
+ //
+ // Make sure that both Parent's FE/EFE and found FE/EFE are not equal.
+ //
+ if (CompareMem ((VOID *)Parent->FileEntry, (VOID *)CompareFileEntry,
+ Volume->FileEntrySize) != 0) {
+ File->FileEntry = CompareFileEntry;
+ } else {
+ FreePool ((VOID *)FileIdentifierDesc);
+ FreePool ((VOID *)CompareFileEntry);
+ Status = EFI_NOT_FOUND;
+ }
+ }
+ }
+
+ return Status;
+
+Error_Find_Fe:
+ FreePool ((VOID *)FileIdentifierDesc);
+
+ return Status;
+}
+
+/**
+ Read volume information on a medium which contains a valid UDF file system.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[out] Volume UDF volume information structure.
+
+ @retval EFI_SUCCESS Volume information read.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The volume was not read due to lack of resources.
+
+**/
+EFI_STATUS
+ReadUdfVolumeInformation (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ OUT UDF_VOLUME_INFO *Volume
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Read all necessary UDF volume information and keep it private to the driver
+ //
+ Status = ReadVolumeFileStructure (
+ BlockIo,
+ DiskIo,
+ Volume
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Find File Set Descriptor
+ //
+ Status = FindFileSetDescriptor (BlockIo, DiskIo, Volume);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return Status;
+}
+
+/**
+ Find the root directory on an UDF volume.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[out] File Root directory file.
+
+ @retval EFI_SUCCESS Root directory found.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The root directory was not found due to lack of
+ resources.
+
+**/
+EFI_STATUS
+FindRootDirectory (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ OUT UDF_FILE_INFO *File
+ )
+{
+ EFI_STATUS Status;
+ UDF_FILE_INFO Parent;
+
+ Status = FindFileEntry (
+ BlockIo,
+ DiskIo,
+ Volume,
+ &Volume->FileSetDesc.RootDirectoryIcb,
+ &File->FileEntry
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Parent.FileEntry = File->FileEntry;
+ Parent.FileIdentifierDesc = NULL;
+
+ Status = FindFile (
+ BlockIo,
+ DiskIo,
+ Volume,
+ L"\\",
+ NULL,
+ &Parent,
+ &Volume->FileSetDesc.RootDirectoryIcb,
+ File
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (File->FileEntry);
+ }
+
+ return Status;
+}
+
+/**
+ Find either a File Entry or a Extended File Entry from a given ICB.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[in] Icb ICB of the FID.
+ @param[out] FileEntry File Entry or Extended File Entry.
+
+ @retval EFI_SUCCESS File Entry or Extended File Entry found.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The FE/EFE entry was not found due to lack of
+ resources.
+
+**/
+EFI_STATUS
+FindFileEntry (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb,
+ OUT VOID **FileEntry
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Lsn;
+ UINT32 LogicalBlockSize;
+ UDF_DESCRIPTOR_TAG *DescriptorTag;
+ VOID *ReadBuffer;
+
+ Status = GetLongAdLsn (Volume, Icb, &Lsn);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ LogicalBlockSize = Volume->LogicalVolDesc.LogicalBlockSize;
+
+ ReadBuffer = AllocateZeroPool (Volume->FileEntrySize);
+ if (ReadBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Read extent.
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 (Lsn, LogicalBlockSize),
+ Volume->FileEntrySize,
+ ReadBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error_Read_Disk_Blk;
+ }
+
+ DescriptorTag = ReadBuffer;
+
+ //
+ // Check if the read extent contains a valid Tag Identifier for the expected
+ // FE/EFE.
+ //
+ if (DescriptorTag->TagIdentifier != UdfFileEntry &&
+ DescriptorTag->TagIdentifier != UdfExtendedFileEntry) {
+ Status = EFI_VOLUME_CORRUPTED;
+ goto Error_Invalid_Fe;
+ }
+
+ *FileEntry = ReadBuffer;
+ return EFI_SUCCESS;
+
+Error_Invalid_Fe:
+Error_Read_Disk_Blk:
+ FreePool (ReadBuffer);
+
+ return Status;
+}
+
+/**
+ Find a file given its absolute path on an UDF volume.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[in] FilePath File's absolute path.
+ @param[in] Root Root directory file.
+ @param[in] Parent Parent directory file.
+ @param[in] Icb ICB of Parent.
+ @param[out] File Found file.
+
+ @retval EFI_SUCCESS FilePath was found.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The FilePath file was not found due to lack of
+ resources.
+
+**/
+EFI_STATUS
+FindFile (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN CHAR16 *FilePath,
+ IN UDF_FILE_INFO *Root,
+ IN UDF_FILE_INFO *Parent,
+ IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb,
+ OUT UDF_FILE_INFO *File
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 FileName[UDF_FILENAME_LENGTH];
+ CHAR16 *FileNamePointer;
+ UDF_FILE_INFO PreviousFile;
+ VOID *FileEntry;
+
+ Status = EFI_NOT_FOUND;
+
+ CopyMem ((VOID *)&PreviousFile, (VOID *)Parent, sizeof (UDF_FILE_INFO));
+ while (*FilePath != L'\0') {
+ FileNamePointer = FileName;
+ while (*FilePath != L'\0' && *FilePath != L'\\') {
+ if ((((UINTN)FileNamePointer - (UINTN)FileName) / sizeof (CHAR16)) >=
+ (ARRAY_SIZE (FileName) - 1)) {
+ return EFI_NOT_FOUND;
+ }
+
+ *FileNamePointer++ = *FilePath++;
+ }
+
+ *FileNamePointer = L'\0';
+ if (FileName[0] == L'\0') {
+ //
+ // Open root directory.
+ //
+ if (Root == NULL) {
+ //
+ // There is no file found for the root directory yet. So, find only its
+ // FID by now.
+ //
+ // See UdfOpenVolume() function.
+ //
+ Status = InternalFindFile (BlockIo,
+ DiskIo,
+ Volume,
+ L"\\",
+ &PreviousFile,
+ Icb,
+ File);
+ } else {
+ //
+ // We've already a file pointer (Root) for the root directory. Duplicate
+ // its FE/EFE and FID descriptors.
+ //
+ Status = EFI_SUCCESS;
+ DuplicateFe (BlockIo, Volume, Root->FileEntry, &File->FileEntry);
+ if (File->FileEntry == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ } else {
+ //
+ // File->FileEntry is not NULL.
+ //
+ DuplicateFid (Root->FileIdentifierDesc, &File->FileIdentifierDesc);
+ if (File->FileIdentifierDesc == NULL) {
+ FreePool (File->FileEntry);
+ Status = EFI_OUT_OF_RESOURCES;
+ }
+ }
+ }
+ } else {
+ //
+ // No root directory. Find filename from the current directory.
+ //
+ Status = InternalFindFile (BlockIo,
+ DiskIo,
+ Volume,
+ FileName,
+ &PreviousFile,
+ Icb,
+ File);
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // If the found file is a symlink, then find its respective FE/EFE and
+ // FID descriptors.
+ //
+ if (FE_ICB_FILE_TYPE (File->FileEntry) == UdfFileEntrySymlink) {
+ FreePool ((VOID *)File->FileIdentifierDesc);
+
+ FileEntry = File->FileEntry;
+
+ Status = ResolveSymlink (BlockIo,
+ DiskIo,
+ Volume,
+ &PreviousFile,
+ FileEntry,
+ File);
+
+ FreePool (FileEntry);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ if (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent,
+ sizeof (UDF_FILE_INFO)) != 0) {
+ CleanupFileInformation (&PreviousFile);
+ }
+
+ CopyMem ((VOID *)&PreviousFile, (VOID *)File, sizeof (UDF_FILE_INFO));
+ if (*FilePath != L'\0' && *FilePath == L'\\') {
+ FilePath++;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Read a directory entry at a time on an UDF volume.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[in] ParentIcb ICB of the parent file.
+ @param[in] FileEntryData FE/EFE of the parent file.
+ @param[in, out] ReadDirInfo Next read directory listing structure
+ information.
+ @param[out] FoundFid File Identifier Descriptor pointer.
+
+ @retval EFI_SUCCESS Directory entry read.
+ @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The directory entry was not read due to lack of
+ resources.
+
+**/
+EFI_STATUS
+ReadDirectoryEntry (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,
+ IN VOID *FileEntryData,
+ IN OUT UDF_READ_DIRECTORY_INFO *ReadDirInfo,
+ OUT UDF_FILE_IDENTIFIER_DESCRIPTOR **FoundFid
+ )
+{
+ EFI_STATUS Status;
+ UDF_READ_FILE_INFO ReadFileInfo;
+ UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc;
+
+ if (ReadDirInfo->DirectoryData == NULL) {
+ //
+ // The directory's recorded data has not been read yet. So let's cache it
+ // into memory and the next calls won't need to read it again.
+ //
+ ReadFileInfo.Flags = ReadFileAllocateAndRead;
+
+ Status = ReadFile (
+ BlockIo,
+ DiskIo,
+ Volume,
+ ParentIcb,
+ FileEntryData,
+ &ReadFileInfo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Fill in ReadDirInfo structure with the read directory's data information.
+ //
+ ReadDirInfo->DirectoryData = ReadFileInfo.FileData;
+ ReadDirInfo->DirectoryLength = ReadFileInfo.ReadLength;
+ }
+
+ do {
+ if (ReadDirInfo->FidOffset >= ReadDirInfo->DirectoryLength) {
+ //
+ // There are no longer FIDs for this directory. By returning
+ // EFI_DEVICE_ERROR to the callee will indicate end of directory
+ // listening.
+ //
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Get FID for this entry.
+ //
+ FileIdentifierDesc = GET_FID_FROM_ADS (ReadDirInfo->DirectoryData,
+ ReadDirInfo->FidOffset);
+ //
+ // Update FidOffset to point to next FID.
+ //
+ ReadDirInfo->FidOffset += GetFidDescriptorLength (FileIdentifierDesc);
+ } while (FileIdentifierDesc->FileCharacteristics & DELETED_FILE);
+
+ DuplicateFid (FileIdentifierDesc, FoundFid);
+ if (*FoundFid == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get a filename (encoded in OSTA-compressed format) from a File Identifier
+ Descriptor on an UDF volume.
+
+ @attention This is boundary function that may receive untrusted input.
+ @attention The input is from FileSystem.
+
+ The File Identifier Descriptor is external input, so this routine will do
+ basic validation for File Identifier Descriptor and report status.
+
+ @param[in] FileIdentifierDesc File Identifier Descriptor pointer.
+ @param[in] CharMax The maximum number of FileName Unicode char,
+ including terminating null char.
+ @param[out] FileName Decoded filename.
+
+ @retval EFI_SUCCESS Filename decoded and read.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_BUFFER_TOO_SMALL The string buffer FileName cannot hold the
+ decoded filename.
+**/
+EFI_STATUS
+GetFileNameFromFid (
+ IN UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc,
+ IN UINTN CharMax,
+ OUT CHAR16 *FileName
+ )
+{
+ UINT8 *OstaCompressed;
+ UINT8 CompressionId;
+ UINT8 Length;
+ UINTN Index;
+ CHAR16 *FileNameBak;
+
+ if (CharMax == 0) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ OstaCompressed =
+ (UINT8 *)(
+ (UINT8 *)FileIdentifierDesc->Data +
+ FileIdentifierDesc->LengthOfImplementationUse
+ );
+
+ CompressionId = OstaCompressed[0];
+ if (!IS_VALID_COMPRESSION_ID (CompressionId)) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ FileNameBak = FileName;
+
+ //
+ // Decode filename.
+ //
+ Length = FileIdentifierDesc->LengthOfFileIdentifier;
+ if (CompressionId == 16) {
+ if (((UINTN)Length >> 1) > CharMax) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ } else {
+ if ((Length != 0) && ((UINTN)Length - 1 > CharMax)) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ }
+
+ for (Index = 1; Index < Length; Index++) {
+ if (CompressionId == 16) {
+ *FileName = OstaCompressed[Index++] << 8;
+ } else {
+ *FileName = 0;
+ }
+
+ if (Index < Length) {
+ *FileName |= (CHAR16)(OstaCompressed[Index]);
+ }
+
+ FileName++;
+ }
+
+ Index = ((UINTN)FileName - (UINTN)FileNameBak) / sizeof (CHAR16);
+ if (Index > CharMax - 1) {
+ Index = CharMax - 1;
+ }
+ FileNameBak[Index] = L'\0';
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Resolve a symlink file on an UDF volume.
+
+ @attention This is boundary function that may receive untrusted input.
+ @attention The input is from FileSystem.
+
+ The Path Component is external input, so this routine will do basic
+ validation for Path Component and report status.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[in] Parent Parent file.
+ @param[in] FileEntryData FE/EFE structure pointer.
+ @param[out] File Resolved file.
+
+ @retval EFI_SUCCESS Symlink file resolved.
+ @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The symlink file was not resolved due to lack of
+ resources.
+
+**/
+EFI_STATUS
+ResolveSymlink (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_FILE_INFO *Parent,
+ IN VOID *FileEntryData,
+ OUT UDF_FILE_INFO *File
+ )
+{
+ EFI_STATUS Status;
+ UDF_READ_FILE_INFO ReadFileInfo;
+ UINT8 *Data;
+ UINT64 Length;
+ UINT8 *EndData;
+ UDF_PATH_COMPONENT *PathComp;
+ UINT8 PathCompLength;
+ CHAR16 FileName[UDF_FILENAME_LENGTH];
+ CHAR16 *Char;
+ UINTN Index;
+ UINT8 CompressionId;
+ UDF_FILE_INFO PreviousFile;
+ BOOLEAN NotParent;
+ BOOLEAN NotFile;
+
+ ZeroMem ((VOID *)File, sizeof (UDF_FILE_INFO));
+
+ //
+ // Symlink files on UDF volumes do not contain so much data other than
+ // Path Components which resolves to real filenames, so it's OK to read in
+ // all its data here -- usually the data will be inline with the FE/EFE for
+ // lower filenames.
+ //
+ ReadFileInfo.Flags = ReadFileAllocateAndRead;
+
+ Status = ReadFile (
+ BlockIo,
+ DiskIo,
+ Volume,
+ &Parent->FileIdentifierDesc->Icb,
+ FileEntryData,
+ &ReadFileInfo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Length = ReadFileInfo.ReadLength;
+
+ Data = (UINT8 *)ReadFileInfo.FileData;
+ EndData = Data + Length;
+
+ CopyMem ((VOID *)&PreviousFile, (VOID *)Parent, sizeof (UDF_FILE_INFO));
+
+ for (;;) {
+ PathComp = (UDF_PATH_COMPONENT *)Data;
+
+ PathCompLength = PathComp->LengthOfComponentIdentifier;
+
+ switch (PathComp->ComponentType) {
+ case 1:
+ //
+ // This Path Component specifies the root directory hierarchy subject to
+ // agreement between the originator and recipient of the medium. Skip it.
+ //
+ // Fall through.
+ //
+ case 2:
+ //
+ // "\\." of the current directory. Read next Path Component.
+ //
+ goto Next_Path_Component;
+ case 3:
+ //
+ // ".." (parent directory). Go to it.
+ //
+ CopyMem ((VOID *)FileName, L"..", 6);
+ break;
+ case 4:
+ //
+ // "." (current file). Duplicate both FE/EFE and FID of this file.
+ //
+ DuplicateFe (BlockIo, Volume, PreviousFile.FileEntry, &File->FileEntry);
+ if (File->FileEntry == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error_Find_File;
+ }
+
+ DuplicateFid (PreviousFile.FileIdentifierDesc,
+ &File->FileIdentifierDesc);
+ if (File->FileIdentifierDesc == NULL) {
+ FreePool (File->FileEntry);
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error_Find_File;
+ }
+ goto Next_Path_Component;
+ case 5:
+ //
+ // This Path Component identifies an object, either a file or a
+ // directory or an alias.
+ //
+ // Decode it from the compressed data in ComponentIdentifier and find
+ // respective path.
+ //
+ CompressionId = PathComp->ComponentIdentifier[0];
+ if (!IS_VALID_COMPRESSION_ID (CompressionId)) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ if ((UINTN)PathComp->ComponentIdentifier + PathCompLength > (UINTN)EndData) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ Char = FileName;
+ for (Index = 1; Index < PathCompLength; Index++) {
+ if (CompressionId == 16) {
+ *Char = *(UINT8 *)((UINT8 *)PathComp->ComponentIdentifier +
+ Index) << 8;
+ Index++;
+ } else {
+ if (Index > ARRAY_SIZE (FileName)) {
+ return EFI_UNSUPPORTED;
+ }
+ *Char = 0;
+ }
+
+ if (Index < Length) {
+ *Char |= (CHAR16)(*(UINT8 *)((UINT8 *)PathComp->ComponentIdentifier + Index));
+ }
+
+ Char++;
+ }
+
+ Index = ((UINTN)Char - (UINTN)FileName) / sizeof (CHAR16);
+ if (Index > ARRAY_SIZE (FileName) - 1) {
+ Index = ARRAY_SIZE (FileName) - 1;
+ }
+ FileName[Index] = L'\0';
+ break;
+ default:
+ //
+ // According to the ECMA-167 standard (3rd Edition - June 1997), Section
+ // 14.16.1.1, all other values are reserved.
+ //
+ Status = EFI_VOLUME_CORRUPTED;
+ goto Error_Find_File;
+ }
+
+ //
+ // Find file from the read filename in symlink's file data.
+ //
+ Status = InternalFindFile (
+ BlockIo,
+ DiskIo,
+ Volume,
+ FileName,
+ &PreviousFile,
+ NULL,
+ File
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error_Find_File;
+ }
+
+ Next_Path_Component:
+ Data += sizeof (UDF_PATH_COMPONENT) + PathCompLength;
+ if (Data >= EndData) {
+ break;
+ }
+
+ //
+ // Check the content in the file info pointed by File.
+ //
+ if ((File->FileEntry == NULL) || (File->FileIdentifierDesc == NULL)) {
+ Status = EFI_VOLUME_CORRUPTED;
+ goto Error_Find_File;
+ }
+
+ NotParent = (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent,
+ sizeof (UDF_FILE_INFO)) != 0);
+ NotFile = (CompareMem ((VOID *)&PreviousFile, (VOID *)File,
+ sizeof (UDF_FILE_INFO)) != 0);
+
+ if (NotParent && NotFile) {
+ CleanupFileInformation (&PreviousFile);
+ }
+
+ if (NotFile) {
+ CopyMem ((VOID *)&PreviousFile, (VOID *)File, sizeof (UDF_FILE_INFO));
+ }
+ }
+
+ //
+ // Unmap the symlink file.
+ //
+ FreePool (ReadFileInfo.FileData);
+
+ //
+ // Check the content in the resolved file info.
+ //
+ if ((File->FileEntry == NULL) || (File->FileIdentifierDesc == NULL)) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ return EFI_SUCCESS;
+
+Error_Find_File:
+ if (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent,
+ sizeof (UDF_FILE_INFO)) != 0) {
+ CleanupFileInformation (&PreviousFile);
+ }
+
+ FreePool (ReadFileInfo.FileData);
+
+ return Status;
+}
+
+/**
+ Clean up in-memory UDF file information.
+
+ @param[in] File File information pointer.
+
+**/
+VOID
+CleanupFileInformation (
+ IN UDF_FILE_INFO *File
+ )
+{
+ if (File->FileEntry != NULL) {
+ FreePool (File->FileEntry);
+ }
+ if (File->FileIdentifierDesc != NULL) {
+ FreePool ((VOID *)File->FileIdentifierDesc);
+ }
+
+ ZeroMem ((VOID *)File, sizeof (UDF_FILE_INFO));
+}
+
+/**
+ Find a file from its absolute path on an UDF volume.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[in] File File information structure.
+ @param[out] Size Size of the file.
+
+ @retval EFI_SUCCESS File size calculated and set in Size.
+ @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The file size was not calculated due to lack of
+ resources.
+
+**/
+EFI_STATUS
+GetFileSize (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_FILE_INFO *File,
+ OUT UINT64 *Size
+ )
+{
+ EFI_STATUS Status;
+ UDF_READ_FILE_INFO ReadFileInfo;
+
+ ReadFileInfo.Flags = ReadFileGetFileSize;
+
+ Status = ReadFile (
+ BlockIo,
+ DiskIo,
+ Volume,
+ &File->FileIdentifierDesc->Icb,
+ File->FileEntry,
+ &ReadFileInfo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *Size = ReadFileInfo.ReadLength;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set information about a file on an UDF volume.
+
+ @param[in] File File pointer.
+ @param[in] FileSize Size of the file.
+ @param[in] FileName Filename of the file.
+ @param[in, out] BufferSize Size of the returned file infomation.
+ @param[out] Buffer Data of the returned file information.
+
+ @retval EFI_SUCCESS File information set.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The file information was not set due to lack of
+ resources.
+
+**/
+EFI_STATUS
+SetFileInfo (
+ IN UDF_FILE_INFO *File,
+ IN UINT64 FileSize,
+ IN CHAR16 *FileName,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ UINTN FileInfoLength;
+ EFI_FILE_INFO *FileInfo;
+ UDF_FILE_ENTRY *FileEntry;
+ UDF_EXTENDED_FILE_ENTRY *ExtendedFileEntry;
+ UDF_DESCRIPTOR_TAG *DescriptorTag;
+
+ //
+ // Calculate the needed size for the EFI_FILE_INFO structure.
+ //
+ FileInfoLength = sizeof (EFI_FILE_INFO) + ((FileName != NULL) ?
+ StrSize (FileName) :
+ sizeof (CHAR16));
+ if (*BufferSize < FileInfoLength) {
+ //
+ // The given Buffer has no size enough for EFI_FILE_INFO structure.
+ //
+ *BufferSize = FileInfoLength;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Buffer now contains room enough to store EFI_FILE_INFO structure.
+ // Now, fill it in with all necessary information about the file.
+ //
+ FileInfo = (EFI_FILE_INFO *)Buffer;
+ FileInfo->Size = FileInfoLength;
+ FileInfo->Attribute &= ~EFI_FILE_VALID_ATTR;
+ FileInfo->Attribute |= EFI_FILE_READ_ONLY;
+
+ if (IS_FID_DIRECTORY_FILE (File->FileIdentifierDesc)) {
+ FileInfo->Attribute |= EFI_FILE_DIRECTORY;
+ } else if (IS_FID_NORMAL_FILE (File->FileIdentifierDesc)) {
+ FileInfo->Attribute |= EFI_FILE_ARCHIVE;
+ }
+
+ if (IS_FID_HIDDEN_FILE (File->FileIdentifierDesc)) {
+ FileInfo->Attribute |= EFI_FILE_HIDDEN;
+ }
+
+ DescriptorTag = File->FileEntry;
+
+ if (DescriptorTag->TagIdentifier == UdfFileEntry) {
+ FileEntry = (UDF_FILE_ENTRY *)File->FileEntry;
+
+ //
+ // Check if FE has the system attribute set.
+ //
+ if (FileEntry->IcbTag.Flags & (1 << 10)) {
+ FileInfo->Attribute |= EFI_FILE_SYSTEM;
+ }
+
+ FileInfo->FileSize = FileSize;
+ FileInfo->PhysicalSize = FileSize;
+
+ FileInfo->CreateTime.Year = FileEntry->AccessTime.Year;
+ FileInfo->CreateTime.Month = FileEntry->AccessTime.Month;
+ FileInfo->CreateTime.Day = FileEntry->AccessTime.Day;
+ FileInfo->CreateTime.Hour = FileEntry->AccessTime.Hour;
+ FileInfo->CreateTime.Minute = FileEntry->AccessTime.Minute;
+ FileInfo->CreateTime.Second = FileEntry->AccessTime.Second;
+ FileInfo->CreateTime.Nanosecond =
+ FileEntry->AccessTime.HundredsOfMicroseconds;
+
+ FileInfo->LastAccessTime.Year =
+ FileEntry->AccessTime.Year;
+ FileInfo->LastAccessTime.Month =
+ FileEntry->AccessTime.Month;
+ FileInfo->LastAccessTime.Day =
+ FileEntry->AccessTime.Day;
+ FileInfo->LastAccessTime.Hour =
+ FileEntry->AccessTime.Hour;
+ FileInfo->LastAccessTime.Minute =
+ FileEntry->AccessTime.Minute;
+ FileInfo->LastAccessTime.Second =
+ FileEntry->AccessTime.Second;
+ FileInfo->LastAccessTime.Nanosecond =
+ FileEntry->AccessTime.HundredsOfMicroseconds;
+ } else if (DescriptorTag->TagIdentifier == UdfExtendedFileEntry) {
+ ExtendedFileEntry = (UDF_EXTENDED_FILE_ENTRY *)File->FileEntry;
+
+ //
+ // Check if EFE has the system attribute set.
+ //
+ if (ExtendedFileEntry->IcbTag.Flags & (1 << 10)) {
+ FileInfo->Attribute |= EFI_FILE_SYSTEM;
+ }
+
+ FileInfo->FileSize = FileSize;
+ FileInfo->PhysicalSize = FileSize;
+
+ FileInfo->CreateTime.Year = ExtendedFileEntry->CreationTime.Year;
+ FileInfo->CreateTime.Month = ExtendedFileEntry->CreationTime.Month;
+ FileInfo->CreateTime.Day = ExtendedFileEntry->CreationTime.Day;
+ FileInfo->CreateTime.Hour = ExtendedFileEntry->CreationTime.Hour;
+ FileInfo->CreateTime.Minute = ExtendedFileEntry->CreationTime.Second;
+ FileInfo->CreateTime.Second = ExtendedFileEntry->CreationTime.Second;
+ FileInfo->CreateTime.Nanosecond =
+ ExtendedFileEntry->AccessTime.HundredsOfMicroseconds;
+
+ FileInfo->LastAccessTime.Year =
+ ExtendedFileEntry->AccessTime.Year;
+ FileInfo->LastAccessTime.Month =
+ ExtendedFileEntry->AccessTime.Month;
+ FileInfo->LastAccessTime.Day =
+ ExtendedFileEntry->AccessTime.Day;
+ FileInfo->LastAccessTime.Hour =
+ ExtendedFileEntry->AccessTime.Hour;
+ FileInfo->LastAccessTime.Minute =
+ ExtendedFileEntry->AccessTime.Minute;
+ FileInfo->LastAccessTime.Second =
+ ExtendedFileEntry->AccessTime.Second;
+ FileInfo->LastAccessTime.Nanosecond =
+ ExtendedFileEntry->AccessTime.HundredsOfMicroseconds;
+ }
+
+ FileInfo->CreateTime.TimeZone = EFI_UNSPECIFIED_TIMEZONE;
+ FileInfo->CreateTime.Daylight = EFI_TIME_ADJUST_DAYLIGHT;
+ FileInfo->LastAccessTime.TimeZone = EFI_UNSPECIFIED_TIMEZONE;
+ FileInfo->LastAccessTime.Daylight = EFI_TIME_ADJUST_DAYLIGHT;
+
+ CopyMem ((VOID *)&FileInfo->ModificationTime,
+ (VOID *)&FileInfo->LastAccessTime,
+ sizeof (EFI_TIME));
+
+ if (FileName != NULL) {
+ StrCpyS (FileInfo->FileName, StrLen (FileName) + 1, FileName);
+ } else {
+ FileInfo->FileName[0] = '\0';
+ }
+
+ *BufferSize = FileInfoLength;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get volume label of an UDF volume.
+
+ @attention This is boundary function that may receive untrusted input.
+ @attention The input is from FileSystem.
+
+ The File Set Descriptor is external input, so this routine will do basic
+ validation for File Set Descriptor and report status.
+
+ @param[in] Volume Volume information pointer.
+ @param[in] CharMax The maximum number of Unicode char in String,
+ including terminating null char.
+ @param[out] String String buffer pointer to store the volume label.
+
+ @retval EFI_SUCCESS Volume label is returned.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_BUFFER_TOO_SMALL The string buffer String cannot hold the
+ volume label.
+
+**/
+EFI_STATUS
+GetVolumeLabel (
+ IN UDF_VOLUME_INFO *Volume,
+ IN UINTN CharMax,
+ OUT CHAR16 *String
+ )
+{
+ UDF_FILE_SET_DESCRIPTOR *FileSetDesc;
+ UINTN Index;
+ UINT8 *OstaCompressed;
+ UINT8 CompressionId;
+ CHAR16 *StringBak;
+
+ FileSetDesc = &Volume->FileSetDesc;
+
+ OstaCompressed = &FileSetDesc->LogicalVolumeIdentifier[0];
+
+ CompressionId = OstaCompressed[0];
+ if (!IS_VALID_COMPRESSION_ID (CompressionId)) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ StringBak = String;
+ for (Index = 1; Index < 128; Index++) {
+ if (CompressionId == 16) {
+ if ((Index >> 1) > CharMax) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *String = *(UINT8 *)(OstaCompressed + Index) << 8;
+ Index++;
+ } else {
+ if (Index > CharMax) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *String = 0;
+ }
+
+ if (Index < 128) {
+ *String |= (CHAR16)(*(UINT8 *)(OstaCompressed + Index));
+ }
+
+ //
+ // Unlike FID Identifiers, Logical Volume Identifier is stored in a
+ // NULL-terminated OSTA compressed format, so we must check for the NULL
+ // character.
+ //
+ if (*String == L'\0') {
+ break;
+ }
+
+ String++;
+ }
+
+ Index = ((UINTN)String - (UINTN)StringBak) / sizeof (CHAR16);
+ if (Index > CharMax - 1) {
+ Index = CharMax - 1;
+ }
+ StringBak[Index] = L'\0';
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get volume and free space size information of an UDF volume.
+
+ @attention This is boundary function that may receive untrusted input.
+ @attention The input is from FileSystem.
+
+ The Logical Volume Descriptor and the Logical Volume Integrity Descriptor are
+ external inputs, so this routine will do basic validation for both descriptors
+ and report status.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[out] VolumeSize Volume size.
+ @param[out] FreeSpaceSize Free space size.
+
+ @retval EFI_SUCCESS Volume and free space size calculated.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The volume and free space size were not
+ calculated due to lack of resources.
+
+**/
+EFI_STATUS
+GetVolumeSize (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ OUT UINT64 *VolumeSize,
+ OUT UINT64 *FreeSpaceSize
+ )
+{
+ EFI_STATUS Status;
+ UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc;
+ UDF_EXTENT_AD *ExtentAd;
+ UINT64 Lsn;
+ UINT32 LogicalBlockSize;
+ UDF_LOGICAL_VOLUME_INTEGRITY *LogicalVolInt;
+ UDF_DESCRIPTOR_TAG *DescriptorTag;
+ UINTN Index;
+ UINTN Length;
+ UINT32 LsnsNo;
+
+ LogicalVolDesc = &Volume->LogicalVolDesc;
+
+ ExtentAd = &LogicalVolDesc->IntegritySequenceExtent;
+
+ if ((ExtentAd->ExtentLength == 0) ||
+ (ExtentAd->ExtentLength < sizeof (UDF_LOGICAL_VOLUME_INTEGRITY))) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ LogicalVolInt = AllocatePool (ExtentAd->ExtentLength);
+ if (LogicalVolInt == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Get location of Logical Volume Integrity Descriptor
+ //
+ Lsn = (UINT64)ExtentAd->ExtentLocation - Volume->MainVdsStartLocation;
+
+ LogicalBlockSize = LogicalVolDesc->LogicalBlockSize;
+
+ //
+ // Read disk block
+ //
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32 (Lsn, LogicalBlockSize),
+ ExtentAd->ExtentLength,
+ LogicalVolInt
+ );
+ if (EFI_ERROR (Status)) {
+ goto Out_Free;
+ }
+
+ DescriptorTag = &LogicalVolInt->DescriptorTag;
+
+ //
+ // Check if read block is a Logical Volume Integrity Descriptor
+ //
+ if (DescriptorTag->TagIdentifier != UdfLogicalVolumeIntegrityDescriptor) {
+ Status = EFI_VOLUME_CORRUPTED;
+ goto Out_Free;
+ }
+
+ if ((LogicalVolInt->NumberOfPartitions > MAX_UINT32 / sizeof (UINT32) / 2) ||
+ (LogicalVolInt->NumberOfPartitions * sizeof (UINT32) * 2 >
+ ExtentAd->ExtentLength - sizeof (UDF_LOGICAL_VOLUME_INTEGRITY))) {
+ Status = EFI_VOLUME_CORRUPTED;
+ goto Out_Free;
+ }
+
+ *VolumeSize = 0;
+ *FreeSpaceSize = 0;
+
+ Length = LogicalVolInt->NumberOfPartitions;
+ for (Index = 0; Index < Length; Index += sizeof (UINT32)) {
+ LsnsNo = *(UINT32 *)((UINT8 *)LogicalVolInt->Data + Index);
+ //
+ // Check if size is not specified
+ //
+ if (LsnsNo == 0xFFFFFFFFUL) {
+ continue;
+ }
+ //
+ // Accumulate free space size
+ //
+ *FreeSpaceSize += MultU64x32 ((UINT64)LsnsNo, LogicalBlockSize);
+ }
+
+ Length = LogicalVolInt->NumberOfPartitions * sizeof (UINT32) * 2;
+ for (; Index < Length; Index += sizeof (UINT32)) {
+ LsnsNo = *(UINT32 *)((UINT8 *)LogicalVolInt->Data + Index);
+ //
+ // Check if size is not specified
+ //
+ if (LsnsNo == 0xFFFFFFFFUL) {
+ continue;
+ }
+ //
+ // Accumulate used volume space
+ //
+ *VolumeSize += MultU64x32 ((UINT64)LsnsNo, LogicalBlockSize);
+ }
+
+ Status = EFI_SUCCESS;
+
+Out_Free:
+ //
+ // Free Logical Volume Integrity Descriptor
+ //
+ FreePool (LogicalVolInt);
+
+ return Status;
+}
+
+/**
+ Seek a file and read its data into memory on an UDF volume.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[in] File File information structure.
+ @param[in] FileSize Size of the file.
+ @param[in, out] FilePosition File position.
+ @param[in, out] Buffer File data.
+ @param[in, out] BufferSize Read size.
+
+ @retval EFI_SUCCESS File seeked and read.
+ @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The file's recorded data was not read due to lack
+ of resources.
+
+**/
+EFI_STATUS
+ReadFileData (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_FILE_INFO *File,
+ IN UINT64 FileSize,
+ IN OUT UINT64 *FilePosition,
+ IN OUT VOID *Buffer,
+ IN OUT UINT64 *BufferSize
+ )
+{
+ EFI_STATUS Status;
+ UDF_READ_FILE_INFO ReadFileInfo;
+
+ ReadFileInfo.Flags = ReadFileSeekAndRead;
+ ReadFileInfo.FilePosition = *FilePosition;
+ ReadFileInfo.FileData = Buffer;
+ ReadFileInfo.FileDataSize = *BufferSize;
+ ReadFileInfo.FileSize = FileSize;
+
+ Status = ReadFile (
+ BlockIo,
+ DiskIo,
+ Volume,
+ &File->FileIdentifierDesc->Icb,
+ File->FileEntry,
+ &ReadFileInfo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *BufferSize = ReadFileInfo.FileDataSize;
+ *FilePosition = ReadFileInfo.FilePosition;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if ControllerHandle supports an UDF file system.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to test.
+
+ @retval EFI_SUCCESS UDF file system found.
+ @retval EFI_UNSUPPORTED UDF file system not found.
+
+**/
+EFI_STATUS
+SupportUdfFileSystem (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
+ EFI_DEVICE_PATH_PROTOCOL *LastDevicePathNode;
+ EFI_GUID *VendorDefinedGuid;
+
+ //
+ // Open Device Path protocol on ControllerHandle
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **)&DevicePath,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = EFI_UNSUPPORTED;
+
+ //
+ // Get last Device Path node
+ //
+ LastDevicePathNode = NULL;
+ DevicePathNode = DevicePath;
+ while (!IsDevicePathEnd (DevicePathNode)) {
+ LastDevicePathNode = DevicePathNode;
+ DevicePathNode = NextDevicePathNode (DevicePathNode);
+ }
+ //
+ // Check if last Device Path node contains a Vendor-Defined Media Device Path
+ // of an UDF file system.
+ //
+ if (LastDevicePathNode != NULL &&
+ DevicePathType (LastDevicePathNode) == MEDIA_DEVICE_PATH &&
+ DevicePathSubType (LastDevicePathNode) == MEDIA_VENDOR_DP) {
+ VendorDefinedGuid = (EFI_GUID *)((UINTN)LastDevicePathNode +
+ OFFSET_OF (VENDOR_DEVICE_PATH, Guid));
+ if (CompareGuid (VendorDefinedGuid, &gUdfDevPathGuid)) {
+ Status = EFI_SUCCESS;
+ }
+ }
+
+ //
+ // Close Device Path protocol on ControllerHandle
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UdfDxe/Udf.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UdfDxe/Udf.c
new file mode 100644
index 00000000..7b01e7a0
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UdfDxe/Udf.c
@@ -0,0 +1,331 @@
+/** @file
+ UDF/ECMA-167 file system driver.
+
+ Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "Udf.h"
+
+//
+// UDF filesystem driver's Global Variables.
+//
+EFI_DRIVER_BINDING_PROTOCOL gUdfDriverBinding = {
+ UdfDriverBindingSupported,
+ UdfDriverBindingStart,
+ UdfDriverBindingStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gUdfSimpleFsTemplate = {
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,
+ UdfOpenVolume
+};
+
+/**
+ Test to see if this driver supports ControllerHandle. Any ControllerHandle
+ than contains a BlockIo and DiskIo protocol or a BlockIo2 protocol can be
+ supported.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to test.
+ @param[in] RemainingDevicePath Optional parameter use to pick a specific
+ child device to start.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval EFI_ALREADY_STARTED This driver is already running on this device.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+
+ //
+ // Open DiskIo protocol on ControllerHandle
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ (VOID **)&DiskIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Close DiskIo protocol on ControllerHandle
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ //
+ // Test whether ControllerHandle supports BlockIo protocol
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+
+ return Status;
+}
+
+/**
+ Start this driver on ControllerHandle by opening a Block IO or a Block IO2
+ or both, and Disk IO protocol, reading Device Path, and creating a child
+ handle with a Disk IO and device path protocol.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to bind driver to
+ @param[in] RemainingDevicePath Optional parameter use to pick a specific
+ child device to start.
+
+ @retval EFI_SUCCESS This driver is added to ControllerHandle.
+ @retval EFI_ALREADY_STARTED This driver is already running on
+ ControllerHandle.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // Open BlockIo protocol on ControllerHandle
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **)&BlockIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Open DiskIo protocol on ControllerHandle
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ (VOID **)&DiskIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Check if ControllerHandle supports an UDF file system
+ //
+ Status = SupportUdfFileSystem (This, ControllerHandle);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ //
+ // Initialize private file system structure
+ //
+ PrivFsData =
+ (PRIVATE_UDF_SIMPLE_FS_DATA *)
+ AllocateZeroPool (sizeof (PRIVATE_UDF_SIMPLE_FS_DATA));
+ if (PrivFsData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ //
+ // Create new child handle
+ //
+ PrivFsData->Signature = PRIVATE_UDF_SIMPLE_FS_DATA_SIGNATURE;
+ PrivFsData->BlockIo = BlockIo;
+ PrivFsData->DiskIo = DiskIo;
+ PrivFsData->Handle = ControllerHandle;
+
+ //
+ // Set up SimpleFs protocol
+ //
+ CopyMem ((VOID *)&PrivFsData->SimpleFs, (VOID *)&gUdfSimpleFsTemplate,
+ sizeof (EFI_SIMPLE_FILE_SYSTEM_PROTOCOL));
+
+ //
+ // Install child handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &PrivFsData->Handle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ &PrivFsData->SimpleFs,
+ NULL
+ );
+
+Exit:
+ if (EFI_ERROR (Status)) {
+ //
+ // Close DiskIo protocol on ControllerHandle
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ //
+ // Close BlockIo protocol on ControllerHandle
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+/**
+ Stop this driver on ControllerHandle. Support stopping any child handles
+ created by this driver.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to stop driver on
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCESS This driver is removed ControllerHandle
+ @retval other This driver was not removed from this device
+
+**/
+EFI_STATUS
+EFIAPI
+UdfDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;
+ EFI_STATUS Status;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs;
+
+ //
+ // Open SimpleFs protocol on ControllerHandle
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ (VOID **)&SimpleFs,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (SimpleFs);
+
+ //
+ // Uninstall child handle
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ PrivFsData->Handle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ &PrivFsData->SimpleFs,
+ NULL
+ );
+
+ FreePool ((VOID *)PrivFsData);
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Close DiskIo protocol on ControllerHandle
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ //
+ // Close BlockIo protocol on ControllerHandle
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ }
+
+ return Status;
+}
+
+/**
+ The user Entry Point for UDF file system driver. The user code starts with
+ this function.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeUdf (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gUdfDriverBinding,
+ ImageHandle,
+ &gUdfComponentName,
+ &gUdfComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UdfDxe/Udf.h b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UdfDxe/Udf.h
new file mode 100644
index 00000000..55141302
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UdfDxe/Udf.h
@@ -0,0 +1,1215 @@
+/** @file
+ UDF/ECMA-167 file system driver.
+
+ Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
+ Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _UDF_H_
+#define _UDF_H_
+
+#include <Uefi.h>
+#include <Base.h>
+
+#include <Protocol/BlockIo.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/DiskIo.h>
+#include <Protocol/SimpleFileSystem.h>
+
+#include <Guid/FileInfo.h>
+#include <Guid/FileSystemInfo.h>
+#include <Guid/FileSystemVolumeLabelInfo.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+
+#include <IndustryStandard/ElTorito.h>
+#include <IndustryStandard/Udf.h>
+
+//
+// C5BD4D42-1A76-4996-8956-73CDA326CD0A
+//
+#define EFI_UDF_DEVICE_PATH_GUID \
+ { 0xC5BD4D42, 0x1A76, 0x4996, \
+ { 0x89, 0x56, 0x73, 0xCD, 0xA3, 0x26, 0xCD, 0x0A } \
+ }
+
+#define FE_ICB_FILE_TYPE(_Ptr) \
+ (UDF_FILE_ENTRY_TYPE)( \
+ ((UDF_DESCRIPTOR_TAG *)(_Ptr))->TagIdentifier == UdfFileEntry ? \
+ ((UDF_FILE_ENTRY *)(_Ptr))->IcbTag.FileType : \
+ ((UDF_EXTENDED_FILE_ENTRY *)(_Ptr))->IcbTag.FileType)
+
+typedef enum {
+ UdfFileEntryDirectory = 4,
+ UdfFileEntryStandardFile = 5,
+ UdfFileEntrySymlink = 12,
+} UDF_FILE_ENTRY_TYPE;
+
+#define HIDDEN_FILE (1 << 0)
+#define DIRECTORY_FILE (1 << 1)
+#define DELETED_FILE (1 << 2)
+#define PARENT_FILE (1 << 3)
+
+#define IS_FID_HIDDEN_FILE(_Fid) \
+ (BOOLEAN)((_Fid)->FileCharacteristics & HIDDEN_FILE)
+#define IS_FID_DIRECTORY_FILE(_Fid) \
+ (BOOLEAN)((_Fid)->FileCharacteristics & DIRECTORY_FILE)
+#define IS_FID_DELETED_FILE(_Fid) \
+ (BOOLEAN)((_Fid)->FileCharacteristics & DELETED_FILE)
+#define IS_FID_PARENT_FILE(_Fid) \
+ (BOOLEAN)((_Fid)->FileCharacteristics & PARENT_FILE)
+#define IS_FID_NORMAL_FILE(_Fid) \
+ (BOOLEAN)(!IS_FID_DIRECTORY_FILE (_Fid) && \
+ !IS_FID_PARENT_FILE (_Fid))
+
+typedef enum {
+ ShortAdsSequence,
+ LongAdsSequence,
+ ExtendedAdsSequence,
+ InlineData
+} UDF_FE_RECORDING_FLAGS;
+
+#define GET_FE_RECORDING_FLAGS(_Fe) \
+ ((UDF_FE_RECORDING_FLAGS)((UDF_ICB_TAG *)( \
+ (UINT8 *)(_Fe) + \
+ sizeof (UDF_DESCRIPTOR_TAG)))->Flags & 0x07)
+
+typedef enum {
+ ExtentRecordedAndAllocated,
+ ExtentNotRecordedButAllocated,
+ ExtentNotRecordedNotAllocated,
+ ExtentIsNextExtent,
+} UDF_EXTENT_FLAGS;
+
+#define AD_LENGTH(_RecFlags) \
+ ((_RecFlags) == ShortAdsSequence ? \
+ ((UINT64)(sizeof (UDF_SHORT_ALLOCATION_DESCRIPTOR))) : \
+ ((UINT64)(sizeof (UDF_LONG_ALLOCATION_DESCRIPTOR))))
+
+#define GET_EXTENT_FLAGS(_RecFlags, _Ad) \
+ ((_RecFlags) == ShortAdsSequence ? \
+ ((UDF_EXTENT_FLAGS)((((UDF_SHORT_ALLOCATION_DESCRIPTOR *)(_Ad))->ExtentLength >> \
+ 30) & 0x3)) : \
+ ((UDF_EXTENT_FLAGS)((((UDF_LONG_ALLOCATION_DESCRIPTOR *)(_Ad))->ExtentLength >> \
+ 30) & 0x3)))
+
+#define GET_EXTENT_LENGTH(_RecFlags, _Ad) \
+ ((_RecFlags) == ShortAdsSequence ? \
+ ((UINT32)((((UDF_SHORT_ALLOCATION_DESCRIPTOR *)(_Ad))->ExtentLength & \
+ ~0xC0000000UL))) : \
+ ((UINT32)((((UDF_LONG_ALLOCATION_DESCRIPTOR *)(_Ad))->ExtentLength & \
+ ~0xC0000000UL))))
+
+#define UDF_FILENAME_LENGTH 128
+#define UDF_PATH_LENGTH 512
+
+#define GET_FID_FROM_ADS(_Data, _Offs) \
+ ((UDF_FILE_IDENTIFIER_DESCRIPTOR *)((UINT8 *)(_Data) + (_Offs)))
+
+#define IS_VALID_COMPRESSION_ID(_CompId) \
+ ((BOOLEAN)((_CompId) == 8 || (_CompId) == 16))
+
+#define UDF_STANDARD_IDENTIFIER_LENGTH 5
+
+#pragma pack(1)
+
+typedef struct {
+ UINT8 StandardIdentifier[UDF_STANDARD_IDENTIFIER_LENGTH];
+} UDF_STANDARD_IDENTIFIER;
+
+#pragma pack()
+
+typedef enum {
+ ReadFileGetFileSize,
+ ReadFileAllocateAndRead,
+ ReadFileSeekAndRead,
+} UDF_READ_FILE_FLAGS;
+
+typedef struct {
+ VOID *FileData;
+ UDF_READ_FILE_FLAGS Flags;
+ UINT64 FileDataSize;
+ UINT64 FilePosition;
+ UINT64 FileSize;
+ UINT64 ReadLength;
+} UDF_READ_FILE_INFO;
+
+#pragma pack(1)
+
+typedef struct {
+ UINT16 TypeAndTimezone;
+ INT16 Year;
+ UINT8 Month;
+ UINT8 Day;
+ UINT8 Hour;
+ UINT8 Minute;
+ UINT8 Second;
+ UINT8 Centiseconds;
+ UINT8 HundredsOfMicroseconds;
+ UINT8 Microseconds;
+} UDF_TIMESTAMP;
+
+typedef struct {
+ UDF_DESCRIPTOR_TAG DescriptorTag;
+ UINT32 PrevAllocationExtentDescriptor;
+ UINT32 LengthOfAllocationDescriptors;
+} UDF_ALLOCATION_EXTENT_DESCRIPTOR;
+
+typedef struct {
+ UINT8 StructureType;
+ UINT8 StandardIdentifier[UDF_STANDARD_IDENTIFIER_LENGTH];
+ UINT8 StructureVersion;
+ UINT8 Reserved;
+ UINT8 StructureData[2040];
+} UDF_VOLUME_DESCRIPTOR;
+
+typedef struct {
+ UDF_DESCRIPTOR_TAG DescriptorTag;
+ UDF_TIMESTAMP RecordingDateTime;
+ UINT32 IntegrityType;
+ UDF_EXTENT_AD NextIntegrityExtent;
+ UINT8 LogicalVolumeContentsUse[32];
+ UINT32 NumberOfPartitions;
+ UINT32 LengthOfImplementationUse;
+ UINT8 Data[0];
+} UDF_LOGICAL_VOLUME_INTEGRITY;
+
+typedef struct {
+ UDF_DESCRIPTOR_TAG DescriptorTag;
+ UINT32 VolumeDescriptorSequenceNumber;
+ UINT16 PartitionFlags;
+ UINT16 PartitionNumber;
+ UDF_ENTITY_ID PartitionContents;
+ UINT8 PartitionContentsUse[128];
+ UINT32 AccessType;
+ UINT32 PartitionStartingLocation;
+ UINT32 PartitionLength;
+ UDF_ENTITY_ID ImplementationIdentifier;
+ UINT8 ImplementationUse[128];
+ UINT8 Reserved[156];
+} UDF_PARTITION_DESCRIPTOR;
+
+typedef struct {
+ UDF_DESCRIPTOR_TAG DescriptorTag;
+ UDF_TIMESTAMP RecordingDateAndTime;
+ UINT16 InterchangeLevel;
+ UINT16 MaximumInterchangeLevel;
+ UINT32 CharacterSetList;
+ UINT32 MaximumCharacterSetList;
+ UINT32 FileSetNumber;
+ UINT32 FileSetDescriptorNumber;
+ UDF_CHAR_SPEC LogicalVolumeIdentifierCharacterSet;
+ UINT8 LogicalVolumeIdentifier[128];
+ UDF_CHAR_SPEC FileSetCharacterSet;
+ UINT8 FileSetIdentifier[32];
+ UINT8 CopyrightFileIdentifier[32];
+ UINT8 AbstractFileIdentifier[32];
+ UDF_LONG_ALLOCATION_DESCRIPTOR RootDirectoryIcb;
+ UDF_ENTITY_ID DomainIdentifier;
+ UDF_LONG_ALLOCATION_DESCRIPTOR NextExtent;
+ UDF_LONG_ALLOCATION_DESCRIPTOR SystemStreamDirectoryIcb;
+ UINT8 Reserved[32];
+} UDF_FILE_SET_DESCRIPTOR;
+
+typedef struct {
+ UINT32 ExtentLength;
+ UINT32 ExtentPosition;
+} UDF_SHORT_ALLOCATION_DESCRIPTOR;
+
+typedef struct {
+ UDF_DESCRIPTOR_TAG DescriptorTag;
+ UINT16 FileVersionNumber;
+ UINT8 FileCharacteristics;
+ UINT8 LengthOfFileIdentifier;
+ UDF_LONG_ALLOCATION_DESCRIPTOR Icb;
+ UINT16 LengthOfImplementationUse;
+ UINT8 Data[0];
+} UDF_FILE_IDENTIFIER_DESCRIPTOR;
+
+typedef struct {
+ UINT32 PriorRecordNumberOfDirectEntries;
+ UINT16 StrategyType;
+ UINT16 StrategyParameter;
+ UINT16 MaximumNumberOfEntries;
+ UINT8 Reserved;
+ UINT8 FileType;
+ UDF_LB_ADDR ParentIcbLocation;
+ UINT16 Flags;
+} UDF_ICB_TAG;
+
+typedef struct {
+ UDF_DESCRIPTOR_TAG DescriptorTag;
+ UDF_ICB_TAG IcbTag;
+ UINT32 Uid;
+ UINT32 Gid;
+ UINT32 Permissions;
+ UINT16 FileLinkCount;
+ UINT8 RecordFormat;
+ UINT8 RecordDisplayAttributes;
+ UINT32 RecordLength;
+ UINT64 InformationLength;
+ UINT64 LogicalBlocksRecorded;
+ UDF_TIMESTAMP AccessTime;
+ UDF_TIMESTAMP ModificationTime;
+ UDF_TIMESTAMP AttributeTime;
+ UINT32 CheckPoint;
+ UDF_LONG_ALLOCATION_DESCRIPTOR ExtendedAttributeIcb;
+ UDF_ENTITY_ID ImplementationIdentifier;
+ UINT64 UniqueId;
+ UINT32 LengthOfExtendedAttributes;
+ UINT32 LengthOfAllocationDescriptors;
+ UINT8 Data[0]; // L_EA + L_AD
+} UDF_FILE_ENTRY;
+
+typedef struct {
+ UDF_DESCRIPTOR_TAG DescriptorTag;
+ UDF_ICB_TAG IcbTag;
+ UINT32 Uid;
+ UINT32 Gid;
+ UINT32 Permissions;
+ UINT16 FileLinkCount;
+ UINT8 RecordFormat;
+ UINT8 RecordDisplayAttributes;
+ UINT32 RecordLength;
+ UINT64 InformationLength;
+ UINT64 ObjectSize;
+ UINT64 LogicalBlocksRecorded;
+ UDF_TIMESTAMP AccessTime;
+ UDF_TIMESTAMP ModificationTime;
+ UDF_TIMESTAMP CreationTime;
+ UDF_TIMESTAMP AttributeTime;
+ UINT32 CheckPoint;
+ UINT32 Reserved;
+ UDF_LONG_ALLOCATION_DESCRIPTOR ExtendedAttributeIcb;
+ UDF_LONG_ALLOCATION_DESCRIPTOR StreamDirectoryIcb;
+ UDF_ENTITY_ID ImplementationIdentifier;
+ UINT64 UniqueId;
+ UINT32 LengthOfExtendedAttributes;
+ UINT32 LengthOfAllocationDescriptors;
+ UINT8 Data[0]; // L_EA + L_AD
+} UDF_EXTENDED_FILE_ENTRY;
+
+typedef struct {
+ UINT8 ComponentType;
+ UINT8 LengthOfComponentIdentifier;
+ UINT16 ComponentFileVersionNumber;
+ UINT8 ComponentIdentifier[0];
+} UDF_PATH_COMPONENT;
+
+#pragma pack()
+
+//
+// UDF filesystem driver's private data
+//
+typedef struct {
+ UINT64 MainVdsStartLocation;
+ UDF_LOGICAL_VOLUME_DESCRIPTOR LogicalVolDesc;
+ UDF_PARTITION_DESCRIPTOR PartitionDesc;
+ UDF_FILE_SET_DESCRIPTOR FileSetDesc;
+ UINTN FileEntrySize;
+} UDF_VOLUME_INFO;
+
+typedef struct {
+ VOID *FileEntry;
+ UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc;
+} UDF_FILE_INFO;
+
+typedef struct {
+ VOID *DirectoryData;
+ UINT64 DirectoryLength;
+ UINT64 FidOffset;
+} UDF_READ_DIRECTORY_INFO;
+
+#define PRIVATE_UDF_FILE_DATA_SIGNATURE SIGNATURE_32 ('U', 'd', 'f', 'f')
+
+#define PRIVATE_UDF_FILE_DATA_FROM_THIS(a) \
+ CR ( \
+ a, \
+ PRIVATE_UDF_FILE_DATA, \
+ FileIo, \
+ PRIVATE_UDF_FILE_DATA_SIGNATURE \
+ )
+
+typedef struct {
+ UINTN Signature;
+ BOOLEAN IsRootDirectory;
+ UDF_FILE_INFO *Root;
+ UDF_FILE_INFO File;
+ UDF_READ_DIRECTORY_INFO ReadDirInfo;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs;
+ EFI_FILE_PROTOCOL FileIo;
+ CHAR16 AbsoluteFileName[UDF_PATH_LENGTH];
+ CHAR16 FileName[UDF_FILENAME_LENGTH];
+ UINT64 FileSize;
+ UINT64 FilePosition;
+} PRIVATE_UDF_FILE_DATA;
+
+#define PRIVATE_UDF_SIMPLE_FS_DATA_SIGNATURE SIGNATURE_32 ('U', 'd', 'f', 's')
+
+#define PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS(a) \
+ CR ( \
+ a, \
+ PRIVATE_UDF_SIMPLE_FS_DATA, \
+ SimpleFs, \
+ PRIVATE_UDF_SIMPLE_FS_DATA_SIGNATURE \
+ )
+
+typedef struct {
+ UINTN Signature;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL SimpleFs;
+ UDF_VOLUME_INFO Volume;
+ UDF_FILE_INFO Root;
+ UINTN OpenFiles;
+ EFI_HANDLE Handle;
+} PRIVATE_UDF_SIMPLE_FS_DATA;
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gUdfDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gUdfComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gUdfComponentName2;
+
+//
+// Function Prototypes
+//
+
+/**
+ Open the root directory on a volume.
+
+ @param This Protocol instance pointer.
+ @param Root Returns an Open file handle for the root directory
+
+ @retval EFI_SUCCESS The device was opened.
+ @retval EFI_UNSUPPORTED This volume does not support the file system.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_ACCESS_DENIED The service denied access to the file.
+ @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfOpenVolume (
+ IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
+ OUT EFI_FILE_PROTOCOL **Root
+ );
+
+/**
+ Opens a new file relative to the source file's location.
+
+ @param This The protocol instance pointer.
+ @param NewHandle Returns File Handle for FileName.
+ @param FileName Null terminated string. "\", ".", and ".." are supported.
+ @param OpenMode Open mode for file.
+ @param Attributes Only used for EFI_FILE_MODE_CREATE.
+
+ @retval EFI_SUCCESS The device was opened.
+ @retval EFI_NOT_FOUND The specified file could not be found on the device.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_MEDIA_CHANGED The media has changed.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_ACCESS_DENIED The service denied access to the file.
+ @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
+ @retval EFI_VOLUME_FULL The volume is full.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfOpen (
+ IN EFI_FILE_PROTOCOL *This,
+ OUT EFI_FILE_PROTOCOL **NewHandle,
+ IN CHAR16 *FileName,
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes
+ );
+
+/**
+ Read data from the file.
+
+ @param This Protocol instance pointer.
+ @param BufferSize On input size of buffer, on output amount of data in buffer.
+ @param Buffer The buffer in which data is read.
+
+ @retval EFI_SUCCESS Data was read.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains required size.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfRead (
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Close the file handle.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The file was closed.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfClose (
+ IN EFI_FILE_PROTOCOL *This
+ );
+
+/**
+ Close and delete the file handle.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS The file was closed and deleted.
+ @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not
+ deleted.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfDelete (
+ IN EFI_FILE_PROTOCOL *This
+ );
+
+/**
+ Write data to a file.
+
+ @param This Protocol instance pointer.
+ @param BufferSize On input size of buffer, on output amount of data in buffer.
+ @param Buffer The buffer in which data to write.
+
+ @retval EFI_SUCCESS Data was written.
+ @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The device is write protected.
+ @retval EFI_ACCESS_DENIED The file was open for read only.
+ @retval EFI_VOLUME_FULL The volume is full.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfWrite (
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+ Get file's current position.
+
+ @param This Protocol instance pointer.
+ @param Position Byte position from the start of the file.
+
+ @retval EFI_SUCCESS Position was updated.
+ @retval EFI_UNSUPPORTED Seek request for directories is not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfGetPosition (
+ IN EFI_FILE_PROTOCOL *This,
+ OUT UINT64 *Position
+ );
+
+/**
+ Set file's current position.
+
+ @param This Protocol instance pointer.
+ @param Position Byte position from the start of the file.
+
+ @retval EFI_SUCCESS Position was updated.
+ @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfSetPosition (
+ IN EFI_FILE_PROTOCOL *This,
+ IN UINT64 Position
+ );
+
+/**
+ Get information about a file.
+
+ @attention This is boundary function that may receive untrusted input.
+ @attention The input is from FileSystem.
+
+ The File Set Descriptor is external input, so this routine will do basic
+ validation for File Set Descriptor and report status.
+
+ @param This Protocol instance pointer.
+ @param InformationType Type of information to return in Buffer.
+ @param BufferSize On input size of buffer, on output amount of data in
+ buffer.
+ @param Buffer The buffer to return data.
+
+ @retval EFI_SUCCESS Data was returned.
+ @retval EFI_UNSUPPORTED InformationType is not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The device is write protected.
+ @retval EFI_ACCESS_DENIED The file was open for read only.
+ @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in
+ BufferSize.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfGetInfo (
+ IN EFI_FILE_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Set information about a file.
+
+ @param This Protocol instance pointer.
+ @param InformationType Type of information in Buffer.
+ @param BufferSize Size of buffer.
+ @param Buffer The data to write.
+
+ @retval EFI_SUCCESS Data was set.
+ @retval EFI_UNSUPPORTED InformationType is not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The device is write protected.
+ @retval EFI_ACCESS_DENIED The file was open for read only.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfSetInfo (
+ IN EFI_FILE_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+ Flush data back for the file handle.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS Data was flushed.
+ @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The device is write protected.
+ @retval EFI_ACCESS_DENIED The file was open for read only.
+ @retval EFI_VOLUME_FULL The volume is full.
+
+**/
+EFI_STATUS
+EFIAPI
+UdfFlush (
+ IN EFI_FILE_PROTOCOL *This
+ );
+
+/**
+ Read volume information on a medium which contains a valid UDF file system.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[out] Volume UDF volume information structure.
+
+ @retval EFI_SUCCESS Volume information read.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The volume was not read due to lack of resources.
+
+**/
+EFI_STATUS
+ReadUdfVolumeInformation (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ OUT UDF_VOLUME_INFO *Volume
+ );
+
+/**
+ Find the root directory on an UDF volume.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[out] File Root directory file.
+
+ @retval EFI_SUCCESS Root directory found.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The root directory was not found due to lack of
+ resources.
+
+**/
+EFI_STATUS
+FindRootDirectory (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ OUT UDF_FILE_INFO *File
+ );
+
+/**
+ Find either a File Entry or a Extended File Entry from a given ICB.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[in] Icb ICB of the FID.
+ @param[out] FileEntry File Entry or Extended File Entry.
+
+ @retval EFI_SUCCESS File Entry or Extended File Entry found.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The FE/EFE entry was not found due to lack of
+ resources.
+
+**/
+EFI_STATUS
+FindFileEntry (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb,
+ OUT VOID **FileEntry
+ );
+
+/**
+ Find a file given its absolute path on an UDF volume.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[in] FilePath File's absolute path.
+ @param[in] Root Root directory file.
+ @param[in] Parent Parent directory file.
+ @param[in] Icb ICB of Parent.
+ @param[out] File Found file.
+
+ @retval EFI_SUCCESS FilePath was found.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The FilePath file was not found due to lack of
+ resources.
+
+**/
+EFI_STATUS
+FindFile (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN CHAR16 *FilePath,
+ IN UDF_FILE_INFO *Root,
+ IN UDF_FILE_INFO *Parent,
+ IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb,
+ OUT UDF_FILE_INFO *File
+ );
+
+/**
+ Read a directory entry at a time on an UDF volume.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[in] ParentIcb ICB of the parent file.
+ @param[in] FileEntryData FE/EFE of the parent file.
+ @param[in, out] ReadDirInfo Next read directory listing structure
+ information.
+ @param[out] FoundFid File Identifier Descriptor pointer.
+
+ @retval EFI_SUCCESS Directory entry read.
+ @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The directory entry was not read due to lack of
+ resources.
+
+**/
+EFI_STATUS
+ReadDirectoryEntry (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,
+ IN VOID *FileEntryData,
+ IN OUT UDF_READ_DIRECTORY_INFO *ReadDirInfo,
+ OUT UDF_FILE_IDENTIFIER_DESCRIPTOR **FoundFid
+ );
+
+/**
+ Get a filename (encoded in OSTA-compressed format) from a File Identifier
+ Descriptor on an UDF volume.
+
+ @attention This is boundary function that may receive untrusted input.
+ @attention The input is from FileSystem.
+
+ The File Identifier Descriptor is external input, so this routine will do
+ basic validation for File Identifier Descriptor and report status.
+
+ @param[in] FileIdentifierDesc File Identifier Descriptor pointer.
+ @param[in] CharMax The maximum number of FileName Unicode char,
+ including terminating null char.
+ @param[out] FileName Decoded filename.
+
+ @retval EFI_SUCCESS Filename decoded and read.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_BUFFER_TOO_SMALL The string buffer FileName cannot hold the
+ decoded filename.
+**/
+EFI_STATUS
+GetFileNameFromFid (
+ IN UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc,
+ IN UINTN CharMax,
+ OUT CHAR16 *FileName
+ );
+
+/**
+ Resolve a symlink file on an UDF volume.
+
+ @attention This is boundary function that may receive untrusted input.
+ @attention The input is from FileSystem.
+
+ The Path Component is external input, so this routine will do basic
+ validation for Path Component and report status.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[in] Parent Parent file.
+ @param[in] FileEntryData FE/EFE structure pointer.
+ @param[out] File Resolved file.
+
+ @retval EFI_SUCCESS Symlink file resolved.
+ @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The symlink file was not resolved due to lack of
+ resources.
+
+**/
+EFI_STATUS
+ResolveSymlink (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_FILE_INFO *Parent,
+ IN VOID *FileEntryData,
+ OUT UDF_FILE_INFO *File
+ );
+
+/**
+ Clean up in-memory UDF file information.
+
+ @param[in] File File information pointer.
+
+**/
+VOID
+CleanupFileInformation (
+ IN UDF_FILE_INFO *File
+ );
+
+/**
+ Find a file from its absolute path on an UDF volume.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[in] File File information structure.
+ @param[out] Size Size of the file.
+
+ @retval EFI_SUCCESS File size calculated and set in Size.
+ @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The file size was not calculated due to lack of
+ resources.
+
+**/
+EFI_STATUS
+GetFileSize (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_FILE_INFO *File,
+ OUT UINT64 *Size
+ );
+
+/**
+ Set information about a file on an UDF volume.
+
+ @param[in] File File pointer.
+ @param[in] FileSize Size of the file.
+ @param[in] FileName Filename of the file.
+ @param[in, out] BufferSize Size of the returned file infomation.
+ @param[out] Buffer Data of the returned file information.
+
+ @retval EFI_SUCCESS File information set.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The file information was not set due to lack of
+ resources.
+
+**/
+EFI_STATUS
+SetFileInfo (
+ IN UDF_FILE_INFO *File,
+ IN UINT64 FileSize,
+ IN CHAR16 *FileName,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Get volume label of an UDF volume.
+
+ @attention This is boundary function that may receive untrusted input.
+ @attention The input is from FileSystem.
+
+ The File Set Descriptor is external input, so this routine will do basic
+ validation for File Set Descriptor and report status.
+
+ @param[in] Volume Volume information pointer.
+ @param[in] CharMax The maximum number of Unicode char in String,
+ including terminating null char.
+ @param[out] String String buffer pointer to store the volume label.
+
+ @retval EFI_SUCCESS Volume label is returned.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_BUFFER_TOO_SMALL The string buffer String cannot hold the
+ volume label.
+
+**/
+EFI_STATUS
+GetVolumeLabel (
+ IN UDF_VOLUME_INFO *Volume,
+ IN UINTN CharMax,
+ OUT CHAR16 *String
+ );
+
+/**
+ Get volume and free space size information of an UDF volume.
+
+ @attention This is boundary function that may receive untrusted input.
+ @attention The input is from FileSystem.
+
+ The Logical Volume Descriptor and the Logical Volume Integrity Descriptor are
+ external inputs, so this routine will do basic validation for both descriptors
+ and report status.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[out] VolumeSize Volume size.
+ @param[out] FreeSpaceSize Free space size.
+
+ @retval EFI_SUCCESS Volume and free space size calculated.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The volume and free space size were not
+ calculated due to lack of resources.
+
+**/
+EFI_STATUS
+GetVolumeSize (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ OUT UINT64 *VolumeSize,
+ OUT UINT64 *FreeSpaceSize
+ );
+
+/**
+ Seek a file and read its data into memory on an UDF volume.
+
+ @param[in] BlockIo BlockIo interface.
+ @param[in] DiskIo DiskIo interface.
+ @param[in] Volume UDF volume information structure.
+ @param[in] File File information structure.
+ @param[in] FileSize Size of the file.
+ @param[in, out] FilePosition File position.
+ @param[in, out] Buffer File data.
+ @param[in, out] BufferSize Read size.
+
+ @retval EFI_SUCCESS File seeked and read.
+ @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_OUT_OF_RESOURCES The file's recorded data was not read due to lack
+ of resources.
+
+**/
+EFI_STATUS
+ReadFileData (
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN UDF_VOLUME_INFO *Volume,
+ IN UDF_FILE_INFO *File,
+ IN UINT64 FileSize,
+ IN OUT UINT64 *FilePosition,
+ IN OUT VOID *Buffer,
+ IN OUT UINT64 *BufferSize
+ );
+
+/**
+ Check if ControllerHandle supports an UDF file system.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to test.
+
+ @retval EFI_SUCCESS UDF file system found.
+ @retval EFI_UNSUPPORTED UDF file system not found.
+
+**/
+EFI_STATUS
+SupportUdfFileSystem (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle
+ );
+
+/**
+ Mangle a filename by cutting off trailing whitespaces, "\\", "." and "..".
+
+ @param[in] FileName Filename.
+
+ @retval The mangled Filename.
+
+**/
+CHAR16 *
+MangleFileName (
+ IN CHAR16 *FileName
+ );
+
+/**
+ Test to see if this driver supports ControllerHandle. Any ControllerHandle
+ than contains a BlockIo and DiskIo protocol can be supported.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to test
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver supports this device
+ @retval EFI_ALREADY_STARTED This driver is already running on this device
+ @retval other This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+UdfDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Start this driver on ControllerHandle by opening a Block IO and Disk IO
+ protocol, reading Device Path, and creating a child handle with a
+ Disk IO and device path protocol.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to bind driver to
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver is added to ControllerHandle
+ @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
+ @retval other This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+UdfDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop this driver on ControllerHandle. Support stopping any child handles
+ created by this driver.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to stop driver on
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCESS This driver is removed ControllerHandle
+ @retval other This driver was not removed from this device
+
+**/
+EFI_STATUS
+EFIAPI
+UdfDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ 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
+UdfComponentNameGetDriverName (
+ 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
+UdfComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+#endif // _UDF_H_
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UdfDxe/UdfDxe.inf b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UdfDxe/UdfDxe.inf
new file mode 100644
index 00000000..08f15b95
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UdfDxe/UdfDxe.inf
@@ -0,0 +1,62 @@
+## @file
+# UDF/ECMA-167 file system driver.
+#
+# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UdfDxe
+ FILE_GUID = 905f13b0-8f91-4b0a-bd76-e1e78f9422e4
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeUdf
+
+#
+# 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]
+ ComponentName.c
+ FileSystemOperations.c
+ FileName.c
+ File.c
+ Udf.c
+ Udf.h
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+
+[LibraryClasses]
+ DevicePathLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ UefiLib
+ BaseLib
+ UefiDriverEntryPoint
+ DebugLib
+
+
+[Guids]
+ gEfiFileInfoGuid ## SOMETIMES_CONSUMES ## Protocol
+ gEfiFileSystemInfoGuid ## SOMETIMES_CONSUMES ## Protocol
+ gEfiFileSystemVolumeLabelInfoIdGuid ## SOMETIMES_CONSUMES ## Protocol
+
+
+[Protocols]
+ gEfiSimpleFileSystemProtocolGuid ## BY_START
+ gEfiDevicePathProtocolGuid ## BY_START
+ gEfiBlockIoProtocolGuid ## TO_START
+ gEfiDiskIoProtocolGuid ## TO_START
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
new file mode 100644
index 00000000..98092215
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
@@ -0,0 +1,54 @@
+## @file
+# English module that provides Unicode Collation supports.
+#
+# This driver installs Unicode ISO 639-2 Collation and
+# RFC 4646 Unicode Collation 2 protocols based on feature flags
+# PcdUnicodeCollationSupport & PcdUnicodeCollation2Support respectively.
+# It allows code running in the boot services environment to perform lexical
+# comparison functions on Unicode strings for English languages.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = EnglishDxe
+ MODULE_UNI_FILE = EnglishDxe.uni
+ FILE_GUID = CD3BAFB6-50FB-4fe8-8E4E-AB74D2C1A600
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeUnicodeCollationEng
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ UnicodeCollationEng.c
+ UnicodeCollationEng.h
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ DebugLib
+ PcdLib
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdUnicodeCollationSupport ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdUnicodeCollation2Support ## CONSUMES
+
+[Protocols]
+ gEfiUnicodeCollationProtocolGuid | gEfiMdeModulePkgTokenSpaceGuid.PcdUnicodeCollationSupport ## SOMETIMES_PRODUCES
+ gEfiUnicodeCollation2ProtocolGuid | gEfiMdeModulePkgTokenSpaceGuid.PcdUnicodeCollation2Support ## PRODUCES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ EnglishDxeExtra.uni
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.uni
new file mode 100644
index 00000000..400d5185
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.uni
@@ -0,0 +1,20 @@
+// /** @file
+// English module that provides Unicode Collation supports.
+//
+// This driver installs Unicode ISO 639-2 Collation and
+// RFC 4646 Unicode Collation 2 protocols based on feature flags
+// PcdUnicodeCollationSupport & PcdUnicodeCollation2Support respectively.
+// It allows code running in the boot services environment to perform lexical
+// comparison functions on Unicode strings for English languages.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides Unicode Collation support"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver installs Unicode ISO 639-2 Collation and RFC 4646 Unicode Collation 2 protocols based on feature flags PcdUnicodeCollationSupport & PcdUnicodeCollation2Support respectively. It allows code running in the boot services environment to perform lexical comparison functions on Unicode strings for English languages."
+
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxeExtra.uni b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxeExtra.uni
new file mode 100644
index 00000000..ec4e8f58
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// EnglishDxe 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
+"English Language Support"
+
+
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/UnicodeCollationEng.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/UnicodeCollationEng.c
new file mode 100644
index 00000000..bcdb1b80
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/UnicodeCollationEng.c
@@ -0,0 +1,467 @@
+/** @file
+ Driver to implement English version of Unicode Collation Protocol.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "UnicodeCollationEng.h"
+
+CHAR8 mEngUpperMap[MAP_TABLE_SIZE];
+CHAR8 mEngLowerMap[MAP_TABLE_SIZE];
+CHAR8 mEngInfoMap[MAP_TABLE_SIZE];
+
+CHAR8 mOtherChars[] = {
+ '0',
+ '1',
+ '2',
+ '3',
+ '4',
+ '5',
+ '6',
+ '7',
+ '8',
+ '9',
+ '\\',
+ '.',
+ '_',
+ '^',
+ '$',
+ '~',
+ '!',
+ '#',
+ '%',
+ '&',
+ '-',
+ '{',
+ '}',
+ '(',
+ ')',
+ '@',
+ '`',
+ '\'',
+ '\0'
+};
+
+EFI_HANDLE mHandle = NULL;
+
+//
+// EFI Unicode Collation Protocol supporting ISO 639-2 language code
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_COLLATION_PROTOCOL UnicodeEng = {
+ EngStriColl,
+ EngMetaiMatch,
+ EngStrLwr,
+ EngStrUpr,
+ EngFatToStr,
+ EngStrToFat,
+ "eng"
+};
+
+//
+// EFI Unicode Collation2 Protocol supporting RFC 4646 language code
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_COLLATION_PROTOCOL Unicode2Eng = {
+ EngStriColl,
+ EngMetaiMatch,
+ EngStrLwr,
+ EngStrUpr,
+ EngFatToStr,
+ EngStrToFat,
+ "en"
+};
+
+/**
+ The user Entry Point for English module.
+
+ This function initializes unicode character mapping and then installs Unicode
+ Collation & Unicode Collation 2 Protocols based on the feature flags.
+
+ @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.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeUnicodeCollationEng (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN Index2;
+
+ //
+ // Initialize mapping tables for the supported languages
+ //
+ for (Index = 0; Index < MAP_TABLE_SIZE; Index++) {
+ mEngUpperMap[Index] = (CHAR8) Index;
+ mEngLowerMap[Index] = (CHAR8) Index;
+ mEngInfoMap[Index] = 0;
+
+ if ((Index >= 'a' && Index <= 'z') || (Index >= 0xe0 && Index <= 0xf6) || (Index >= 0xf8 && Index <= 0xfe)) {
+
+ Index2 = Index - 0x20;
+ mEngUpperMap[Index] = (CHAR8) Index2;
+ mEngLowerMap[Index2] = (CHAR8) Index;
+
+ mEngInfoMap[Index] |= CHAR_FAT_VALID;
+ mEngInfoMap[Index2] |= CHAR_FAT_VALID;
+ }
+ }
+
+ for (Index = 0; mOtherChars[Index] != 0; Index++) {
+ Index2 = mOtherChars[Index];
+ mEngInfoMap[Index2] |= CHAR_FAT_VALID;
+ }
+
+ if (FeaturePcdGet (PcdUnicodeCollation2Support)) {
+ if (FeaturePcdGet (PcdUnicodeCollationSupport)) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEfiUnicodeCollationProtocolGuid,
+ &UnicodeEng,
+ &gEfiUnicodeCollation2ProtocolGuid,
+ &Unicode2Eng,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEfiUnicodeCollation2ProtocolGuid,
+ &Unicode2Eng,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ } else {
+ if (FeaturePcdGet (PcdUnicodeCollationSupport)) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEfiUnicodeCollationProtocolGuid,
+ &UnicodeEng,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ //
+ // This module must support to produce at least one of Unicode Collation Protocol
+ // and Unicode Collation 2 Protocol.
+ //
+ ASSERT (FALSE);
+ Status = EFI_UNSUPPORTED;
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Performs a case-insensitive comparison of two Null-terminated strings.
+
+ @param This Protocol instance pointer.
+ @param Str1 A pointer to a Null-terminated string.
+ @param Str2 A pointer to a Null-terminated string.
+
+ @retval 0 Str1 is equivalent to Str2
+ @retval > 0 Str1 is lexically greater than Str2
+ @retval < 0 Str1 is lexically less than Str2
+
+**/
+INTN
+EFIAPI
+EngStriColl (
+ IN EFI_UNICODE_COLLATION_PROTOCOL *This,
+ IN CHAR16 *Str1,
+ IN CHAR16 *Str2
+ )
+{
+ while (*Str1 != 0) {
+ if (TO_UPPER (*Str1) != TO_UPPER (*Str2)) {
+ break;
+ }
+
+ Str1 += 1;
+ Str2 += 1;
+ }
+
+ return TO_UPPER (*Str1) - TO_UPPER (*Str2);
+}
+
+
+/**
+ Converts all the characters in a Null-terminated string to
+ lower case characters.
+
+ @param This Protocol instance pointer.
+ @param Str A pointer to a Null-terminated string.
+
+**/
+VOID
+EFIAPI
+EngStrLwr (
+ IN EFI_UNICODE_COLLATION_PROTOCOL *This,
+ IN OUT CHAR16 *Str
+ )
+{
+ while (*Str != 0) {
+ *Str = TO_LOWER (*Str);
+ Str += 1;
+ }
+}
+
+
+/**
+ Converts all the characters in a Null-terminated string to upper
+ case characters.
+
+ @param This Protocol instance pointer.
+ @param Str A pointer to a Null-terminated string.
+
+**/
+VOID
+EFIAPI
+EngStrUpr (
+ IN EFI_UNICODE_COLLATION_PROTOCOL *This,
+ IN OUT CHAR16 *Str
+ )
+{
+ while (*Str != 0) {
+ *Str = TO_UPPER (*Str);
+ Str += 1;
+ }
+}
+
+/**
+ Performs a case-insensitive comparison of a Null-terminated
+ pattern string and a Null-terminated string.
+
+ @param This Protocol instance pointer.
+ @param String A pointer to a Null-terminated string.
+ @param Pattern A pointer to a Null-terminated pattern string.
+
+ @retval TRUE Pattern was found in String.
+ @retval FALSE Pattern was not found in String.
+
+**/
+BOOLEAN
+EFIAPI
+EngMetaiMatch (
+ IN EFI_UNICODE_COLLATION_PROTOCOL *This,
+ IN CHAR16 *String,
+ IN CHAR16 *Pattern
+ )
+{
+ CHAR16 CharC;
+ CHAR16 CharP;
+ CHAR16 Index3;
+
+ for (;;) {
+ CharP = *Pattern;
+ Pattern += 1;
+
+ switch (CharP) {
+ case 0:
+ //
+ // End of pattern. If end of string, TRUE match
+ //
+ if (*String != 0) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+
+ case '*':
+ //
+ // Match zero or more chars
+ //
+ while (*String != 0) {
+ if (EngMetaiMatch (This, String, Pattern)) {
+ return TRUE;
+ }
+
+ String += 1;
+ }
+
+ return EngMetaiMatch (This, String, Pattern);
+
+ case '?':
+ //
+ // Match any one char
+ //
+ if (*String == 0) {
+ return FALSE;
+ }
+
+ String += 1;
+ break;
+
+ case '[':
+ //
+ // Match char set
+ //
+ CharC = *String;
+ if (CharC == 0) {
+ //
+ // syntax problem
+ //
+ return FALSE;
+ }
+
+ Index3 = 0;
+ CharP = *Pattern++;
+ while (CharP != 0) {
+ if (CharP == ']') {
+ return FALSE;
+ }
+
+ if (CharP == '-') {
+ //
+ // if range of chars, get high range
+ //
+ CharP = *Pattern;
+ if (CharP == 0 || CharP == ']') {
+ //
+ // syntax problem
+ //
+ return FALSE;
+ }
+
+ if (TO_UPPER (CharC) >= TO_UPPER (Index3) && TO_UPPER (CharC) <= TO_UPPER (CharP)) {
+ //
+ // if in range, it's a match
+ //
+ break;
+ }
+ }
+
+ Index3 = CharP;
+ if (TO_UPPER (CharC) == TO_UPPER (CharP)) {
+ //
+ // if char matches
+ //
+ break;
+ }
+
+ CharP = *Pattern++;
+ }
+ //
+ // skip to end of match char set
+ //
+ while ((CharP != 0) && (CharP != ']')) {
+ CharP = *Pattern;
+ Pattern += 1;
+ }
+
+ String += 1;
+ break;
+
+ default:
+ CharC = *String;
+ if (TO_UPPER (CharC) != TO_UPPER (CharP)) {
+ return FALSE;
+ }
+
+ String += 1;
+ break;
+ }
+ }
+}
+
+
+/**
+ Converts an 8.3 FAT file name in an OEM character set to a Null-terminated string.
+
+ @param This Protocol instance pointer.
+ @param FatSize The size of the string Fat in bytes.
+ @param Fat A pointer to a Null-terminated string that contains an 8.3 file
+ name using an 8-bit OEM character set.
+ @param String A pointer to a Null-terminated string. The string must
+ be preallocated to hold FatSize characters.
+
+**/
+VOID
+EFIAPI
+EngFatToStr (
+ IN EFI_UNICODE_COLLATION_PROTOCOL *This,
+ IN UINTN FatSize,
+ IN CHAR8 *Fat,
+ OUT CHAR16 *String
+ )
+{
+ //
+ // No DBCS issues, just expand and add null terminate to end of string
+ //
+ while ((*Fat != 0) && (FatSize != 0)) {
+ *String = *Fat;
+ String += 1;
+ Fat += 1;
+ FatSize -= 1;
+ }
+
+ *String = 0;
+}
+
+
+/**
+ Converts a Null-terminated string to legal characters in a FAT
+ filename using an OEM character set.
+
+ @param This Protocol instance pointer.
+ @param String A pointer to a Null-terminated string. The string must
+ be preallocated to hold FatSize characters.
+ @param FatSize The size of the string Fat in bytes.
+ @param Fat A pointer to a Null-terminated string that contains an 8.3 file
+ name using an OEM character set.
+
+ @retval TRUE Fat is a Long File Name
+ @retval FALSE Fat is an 8.3 file name
+
+**/
+BOOLEAN
+EFIAPI
+EngStrToFat (
+ IN EFI_UNICODE_COLLATION_PROTOCOL *This,
+ IN CHAR16 *String,
+ IN UINTN FatSize,
+ OUT CHAR8 *Fat
+ )
+{
+ BOOLEAN SpecialCharExist;
+
+ SpecialCharExist = FALSE;
+ while ((*String != 0) && (FatSize != 0)) {
+ //
+ // Skip '.' or ' ' when making a fat name
+ //
+ if (*String != '.' && *String != ' ') {
+ //
+ // If this is a valid fat char, move it.
+ // Otherwise, move a '_' and flag the fact that the name needs a long file name.
+ //
+ if (*String < MAP_TABLE_SIZE && ((mEngInfoMap[*String] & CHAR_FAT_VALID) != 0)) {
+ *Fat = mEngUpperMap[*String];
+ } else {
+ *Fat = '_';
+ SpecialCharExist = TRUE;
+ }
+
+ Fat += 1;
+ FatSize -= 1;
+ }
+
+ String += 1;
+ }
+ //
+ // Do not terminate that fat string
+ //
+ return SpecialCharExist;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/UnicodeCollationEng.h b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/UnicodeCollationEng.h
new file mode 100644
index 00000000..ee86784b
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/UnicodeCollationEng.h
@@ -0,0 +1,181 @@
+/** @file
+ Head file for Unicode Collation Protocol (English)
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _UNICODE_COLLATION_ENG_H_
+#define _UNICODE_COLLATION_ENG_H_
+
+
+
+#include <Uefi.h>
+
+#include <Protocol/UnicodeCollation.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/PcdLib.h>
+
+//
+// Bit mask to indicate the validity of character in FAT file name.
+//
+#define CHAR_FAT_VALID 0x01
+
+//
+// Maximum FAT table size.
+//
+#define MAP_TABLE_SIZE 0x100
+
+//
+// Macro to map character a to upper case.
+//
+#define TO_UPPER(a) (CHAR16) ((a) <= 0xFF ? mEngUpperMap[a] : (a))
+
+//
+// Macro to map character a to lower case.
+//
+#define TO_LOWER(a) (CHAR16) ((a) <= 0xFF ? mEngLowerMap[a] : (a))
+
+//
+// Prototypes
+//
+/**
+ Performs a case-insensitive comparison of two Null-terminated strings.
+
+ @param This Protocol instance pointer.
+ @param Str1 A pointer to a Null-terminated string.
+ @param Str2 A pointer to a Null-terminated string.
+
+ @retval 0 Str1 is equivalent to Str2
+ @retval > 0 Str1 is lexically greater than Str2
+ @retval < 0 Str1 is lexically less than Str2
+
+**/
+INTN
+EFIAPI
+EngStriColl (
+ IN EFI_UNICODE_COLLATION_PROTOCOL *This,
+ IN CHAR16 *Str1,
+ IN CHAR16 *Str2
+ );
+
+/**
+ Performs a case-insensitive comparison of a Null-terminated
+ pattern string and a Null-terminated string.
+
+ @param This Protocol instance pointer.
+ @param String A pointer to a Null-terminated string.
+ @param Pattern A pointer to a Null-terminated pattern string.
+
+ @retval TRUE Pattern was found in String.
+ @retval FALSE Pattern was not found in String.
+
+**/
+BOOLEAN
+EFIAPI
+EngMetaiMatch (
+ IN EFI_UNICODE_COLLATION_PROTOCOL *This,
+ IN CHAR16 *String,
+ IN CHAR16 *Pattern
+ );
+
+/**
+ Converts all the characters in a Null-terminated string to
+ lower case characters.
+
+ @param This Protocol instance pointer.
+ @param Str A pointer to a Null-terminated string.
+
+**/
+VOID
+EFIAPI
+EngStrLwr (
+ IN EFI_UNICODE_COLLATION_PROTOCOL *This,
+ IN OUT CHAR16 *Str
+ );
+
+/**
+ Converts all the characters in a Null-terminated string to upper
+ case characters.
+
+ @param This Protocol instance pointer.
+ @param Str A pointer to a Null-terminated string.
+
+**/
+VOID
+EFIAPI
+EngStrUpr (
+ IN EFI_UNICODE_COLLATION_PROTOCOL *This,
+ IN OUT CHAR16 *Str
+ );
+
+/**
+ Converts an 8.3 FAT file name in an OEM character set to a Null-terminated string.
+
+ @param This Protocol instance pointer.
+ @param FatSize The size of the string Fat in bytes.
+ @param Fat A pointer to a Null-terminated string that contains an 8.3 file
+ name using an 8-bit OEM character set.
+ @param String A pointer to a Null-terminated string. The string must
+ be preallocated to hold FatSize characters.
+
+**/
+VOID
+EFIAPI
+EngFatToStr (
+ IN EFI_UNICODE_COLLATION_PROTOCOL *This,
+ IN UINTN FatSize,
+ IN CHAR8 *Fat,
+ OUT CHAR16 *String
+ );
+
+/**
+ Converts a Null-terminated string to legal characters in a FAT
+ filename using an OEM character set.
+
+ @param This Protocol instance pointer.
+ @param String A pointer to a Null-terminated string. The string must
+ be preallocated to hold FatSize characters.
+ @param FatSize The size of the string Fat in bytes.
+ @param Fat A pointer to a Null-terminated string that contains an 8.3 file
+ name using an OEM character set.
+
+ @retval TRUE Fat is a Long File Name
+ @retval FALSE Fat is an 8.3 file name
+
+**/
+BOOLEAN
+EFIAPI
+EngStrToFat (
+ IN EFI_UNICODE_COLLATION_PROTOCOL *This,
+ IN CHAR16 *String,
+ IN UINTN FatSize,
+ OUT CHAR8 *Fat
+ );
+
+/**
+ The user Entry Point for English module.
+
+ This function initializes unicode character mapping and then installs Unicode
+ Collation & Unicode Collation 2 Protocols based on the feature flags.
+
+ @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.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeUnicodeCollationEng (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+#endif
+