diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
commit | f215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch) | |
tree | 6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library | |
parent | Initial commit. (diff) | |
download | virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip |
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library')
55 files changed, 9852 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/AcpiLib/AcpiLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/AcpiLib/AcpiLib.c new file mode 100644 index 00000000..e71bbad7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/AcpiLib/AcpiLib.c @@ -0,0 +1,172 @@ +/** @file +* +* Copyright (c) 2014-2015, ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#include <Uefi.h> + +#include <Library/AcpiLib.h> +#include <Library/DebugLib.h> +#include <Library/UefiBootServicesTableLib.h> + +#include <Protocol/AcpiTable.h> +#include <Protocol/FirmwareVolume2.h> + +#include <IndustryStandard/Acpi.h> + +/** + Locate and Install the ACPI tables from the Firmware Volume if it verifies + the function condition. + + @param AcpiFile Guid of the ACPI file into the Firmware Volume + @param CheckAcpiTableFunction Function that checks if the ACPI table should be installed + + @return EFI_SUCCESS The function completed successfully. + @return EFI_NOT_FOUND The protocol could not be located. + @return EFI_OUT_OF_RESOURCES There are not enough resources to find the protocol. + +**/ +EFI_STATUS +LocateAndInstallAcpiFromFvConditional ( + IN CONST EFI_GUID* AcpiFile, + IN EFI_LOCATE_ACPI_CHECK CheckAcpiTableFunction + ) +{ + EFI_STATUS Status; + EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol; + EFI_HANDLE *HandleBuffer; + UINTN NumberOfHandles; + UINT32 FvStatus; + UINTN Index; + EFI_FIRMWARE_VOLUME2_PROTOCOL *FvInstance; + INTN SectionInstance; + UINTN SectionSize; + EFI_ACPI_COMMON_HEADER *AcpiTable; + UINTN AcpiTableSize; + UINTN AcpiTableKey; + BOOLEAN Valid; + + // Ensure the ACPI Table is present + Status = gBS->LocateProtocol ( + &gEfiAcpiTableProtocolGuid, + NULL, + (VOID**)&AcpiProtocol + ); + if (EFI_ERROR (Status)) { + return Status; + } + + FvStatus = 0; + SectionInstance = 0; + + // Locate all the Firmware Volume protocols. + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareVolume2ProtocolGuid, + NULL, + &NumberOfHandles, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // Looking for FV with ACPI storage file + for (Index = 0; Index < NumberOfHandles; Index++) { + // + // Get the protocol on this handle + // This should not fail because of LocateHandleBuffer + // + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiFirmwareVolume2ProtocolGuid, + (VOID**) &FvInstance + ); + if (EFI_ERROR (Status)) { + goto FREE_HANDLE_BUFFER; + } + + while (Status == EFI_SUCCESS) { + // AcpiTable must be allocated by ReadSection (ie: AcpiTable == NULL) + AcpiTable = NULL; + + // See if it has the ACPI storage file + Status = FvInstance->ReadSection ( + FvInstance, + AcpiFile, + EFI_SECTION_RAW, + SectionInstance, + (VOID**) &AcpiTable, + &SectionSize, + &FvStatus + ); + if (!EFI_ERROR (Status)) { + AcpiTableKey = 0; + AcpiTableSize = ((EFI_ACPI_DESCRIPTION_HEADER *) AcpiTable)->Length; + ASSERT (SectionSize >= AcpiTableSize); + + DEBUG ((EFI_D_ERROR, "- Found '%c%c%c%c' ACPI Table\n", + (((EFI_ACPI_DESCRIPTION_HEADER *) AcpiTable)->Signature & 0xFF), + ((((EFI_ACPI_DESCRIPTION_HEADER *) AcpiTable)->Signature >> 8) & 0xFF), + ((((EFI_ACPI_DESCRIPTION_HEADER *) AcpiTable)->Signature >> 16) & 0xFF), + ((((EFI_ACPI_DESCRIPTION_HEADER *) AcpiTable)->Signature >> 24) & 0xFF))); + + // Is the ACPI table valid? + if (CheckAcpiTableFunction) { + Valid = CheckAcpiTableFunction ((EFI_ACPI_DESCRIPTION_HEADER *)AcpiTable); + } else { + Valid = TRUE; + } + + // Install the ACPI Table + if (Valid) { + Status = AcpiProtocol->InstallAcpiTable ( + AcpiProtocol, + AcpiTable, + AcpiTableSize, + &AcpiTableKey + ); + } + + // Free memory allocated by ReadSection + gBS->FreePool (AcpiTable); + + if (EFI_ERROR (Status)) { + break; + } + + // Increment the section instance + SectionInstance++; + } + } + } + +FREE_HANDLE_BUFFER: + // + // Free any allocated buffers + // + gBS->FreePool (HandleBuffer); + + return EFI_SUCCESS; +} + +/** + Locate and Install the ACPI tables from the Firmware Volume + + @param AcpiFile Guid of the ACPI file into the Firmware Volume + + @return EFI_SUCCESS The function completed successfully. + @return EFI_NOT_FOUND The protocol could not be located. + @return EFI_OUT_OF_RESOURCES There are not enough resources to find the protocol. + +**/ +EFI_STATUS +LocateAndInstallAcpiFromFv ( + IN CONST EFI_GUID* AcpiFile + ) +{ + return LocateAndInstallAcpiFromFvConditional (AcpiFile, NULL); +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/AcpiLib/AcpiLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/AcpiLib/AcpiLib.inf new file mode 100644 index 00000000..7f0fb091 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/AcpiLib/AcpiLib.inf @@ -0,0 +1,31 @@ +#/** @file +# +# Copyright (c) 2014, ARM Ltd. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = AcpiLib + FILE_GUID = 24b9d62c-5a36-417b-94b6-38dbaea90dcf + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = AcpiLib + +[Sources.common] + AcpiLib.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + DebugLib + UefiBootServicesTableLib + +[Protocols] + gEfiAcpiTableProtocolGuid + gEfiFirmwareVolume2ProtocolGuid diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.c new file mode 100644 index 00000000..444884c9 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.c @@ -0,0 +1,470 @@ +/** @file + + Copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR> + Copyright (c) 2017, Linaro. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <libfdt.h> +#include <Library/AndroidBootImgLib.h> +#include <Library/PrintLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> + +#include <Protocol/AndroidBootImg.h> +#include <Protocol/LoadedImage.h> + +#include <libfdt.h> + +#define FDT_ADDITIONAL_ENTRIES_SIZE 0x400 + +typedef struct { + MEMMAP_DEVICE_PATH Node1; + EFI_DEVICE_PATH_PROTOCOL End; +} MEMORY_DEVICE_PATH; + +STATIC ANDROID_BOOTIMG_PROTOCOL *mAndroidBootImg; + +STATIC CONST MEMORY_DEVICE_PATH mMemoryDevicePathTemplate = +{ + { + { + HARDWARE_DEVICE_PATH, + HW_MEMMAP_DP, + { + (UINT8)(sizeof (MEMMAP_DEVICE_PATH)), + (UINT8)((sizeof (MEMMAP_DEVICE_PATH)) >> 8), + }, + }, // Header + 0, // StartingAddress (set at runtime) + 0 // EndingAddress (set at runtime) + }, // Node1 + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } + } // End +}; + +EFI_STATUS +AndroidBootImgGetImgSize ( + IN VOID *BootImg, + OUT UINTN *ImgSize + ) +{ + ANDROID_BOOTIMG_HEADER *Header; + + Header = (ANDROID_BOOTIMG_HEADER *) BootImg; + + if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC, + ANDROID_BOOT_MAGIC_LENGTH) != 0) { + return EFI_INVALID_PARAMETER; + } + + /* The page size is not specified, but it should be power of 2 at least */ + ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize)); + + /* Get real size of abootimg */ + *ImgSize = ALIGN_VALUE (Header->KernelSize, Header->PageSize) + + ALIGN_VALUE (Header->RamdiskSize, Header->PageSize) + + ALIGN_VALUE (Header->SecondStageBootloaderSize, Header->PageSize) + + Header->PageSize; + return EFI_SUCCESS; +} + +EFI_STATUS +AndroidBootImgGetKernelInfo ( + IN VOID *BootImg, + OUT VOID **Kernel, + OUT UINTN *KernelSize + ) +{ + ANDROID_BOOTIMG_HEADER *Header; + + Header = (ANDROID_BOOTIMG_HEADER *) BootImg; + + if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC, + ANDROID_BOOT_MAGIC_LENGTH) != 0) { + return EFI_INVALID_PARAMETER; + } + + if (Header->KernelSize == 0) { + return EFI_NOT_FOUND; + } + + ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize)); + + *KernelSize = Header->KernelSize; + *Kernel = (VOID *)((UINTN)BootImg + Header->PageSize); + return EFI_SUCCESS; +} + +EFI_STATUS +AndroidBootImgGetRamdiskInfo ( + IN VOID *BootImg, + OUT VOID **Ramdisk, + OUT UINTN *RamdiskSize + ) +{ + ANDROID_BOOTIMG_HEADER *Header; + + Header = (ANDROID_BOOTIMG_HEADER *)BootImg; + + if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC, + ANDROID_BOOT_MAGIC_LENGTH) != 0) { + return EFI_INVALID_PARAMETER; + } + + ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize)); + + *RamdiskSize = Header->RamdiskSize; + + if (Header->RamdiskSize != 0) { + *Ramdisk = (VOID *)((INTN)BootImg + + Header->PageSize + + ALIGN_VALUE (Header->KernelSize, Header->PageSize)); + } + return EFI_SUCCESS; +} + +EFI_STATUS +AndroidBootImgGetSecondBootLoaderInfo ( + IN VOID *BootImg, + OUT VOID **Second, + OUT UINTN *SecondSize + ) +{ + ANDROID_BOOTIMG_HEADER *Header; + + Header = (ANDROID_BOOTIMG_HEADER *)BootImg; + + if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC, + ANDROID_BOOT_MAGIC_LENGTH) != 0) { + return EFI_INVALID_PARAMETER; + } + + ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize)); + + *SecondSize = Header->SecondStageBootloaderSize; + + if (Header->SecondStageBootloaderSize != 0) { + *Second = (VOID *)((UINTN)BootImg + + Header->PageSize + + ALIGN_VALUE (Header->KernelSize, Header->PageSize) + + ALIGN_VALUE (Header->RamdiskSize, Header->PageSize)); + } + return EFI_SUCCESS; +} + +EFI_STATUS +AndroidBootImgGetKernelArgs ( + IN VOID *BootImg, + OUT CHAR8 *KernelArgs + ) +{ + ANDROID_BOOTIMG_HEADER *Header; + + Header = (ANDROID_BOOTIMG_HEADER *) BootImg; + AsciiStrnCpyS (KernelArgs, ANDROID_BOOTIMG_KERNEL_ARGS_SIZE, Header->KernelArgs, + ANDROID_BOOTIMG_KERNEL_ARGS_SIZE); + + return EFI_SUCCESS; +} + +EFI_STATUS +AndroidBootImgGetFdt ( + IN VOID *BootImg, + IN VOID **FdtBase + ) +{ + UINTN SecondLoaderSize; + EFI_STATUS Status; + + /* Check whether FDT is located in second boot region as some vendor do so, + * because second loader is never used as far as I know. */ + Status = AndroidBootImgGetSecondBootLoaderInfo ( + BootImg, + FdtBase, + &SecondLoaderSize + ); + return Status; +} + +EFI_STATUS +AndroidBootImgUpdateArgs ( + IN VOID *BootImg, + OUT VOID *KernelArgs + ) +{ + CHAR8 ImageKernelArgs[ANDROID_BOOTIMG_KERNEL_ARGS_SIZE]; + EFI_STATUS Status; + + // Get kernel arguments from Android boot image + Status = AndroidBootImgGetKernelArgs (BootImg, ImageKernelArgs); + if (EFI_ERROR (Status)) { + return Status; + } + AsciiStrToUnicodeStrS (ImageKernelArgs, KernelArgs, + ANDROID_BOOTIMG_KERNEL_ARGS_SIZE >> 1); + // Append platform kernel arguments + if(mAndroidBootImg->AppendArgs) { + Status = mAndroidBootImg->AppendArgs (KernelArgs, + ANDROID_BOOTIMG_KERNEL_ARGS_SIZE); + } + return Status; +} + +EFI_STATUS +AndroidBootImgLocateFdt ( + IN VOID *BootImg, + IN VOID **FdtBase + ) +{ + INTN Err; + EFI_STATUS Status; + + Status = EfiGetSystemConfigurationTable (&gFdtTableGuid, FdtBase); + if (!EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + + Status = AndroidBootImgGetFdt (BootImg, FdtBase); + if (EFI_ERROR (Status)) { + return Status; + } + Err = fdt_check_header (*FdtBase); + if (Err != 0) { + DEBUG ((DEBUG_ERROR, "ERROR: Device Tree header not valid (Err:%d)\n", + Err)); + return EFI_INVALID_PARAMETER; + } + return EFI_SUCCESS; +} + +INTN +AndroidBootImgGetChosenNode ( + IN INTN UpdatedFdtBase + ) +{ + INTN ChosenNode; + + ChosenNode = fdt_subnode_offset ((CONST VOID *)UpdatedFdtBase, 0, "chosen"); + if (ChosenNode < 0) { + ChosenNode = fdt_add_subnode((VOID *)UpdatedFdtBase, 0, "chosen"); + if (ChosenNode < 0) { + DEBUG ((DEBUG_ERROR, "Fail to find fdt node chosen!\n")); + return 0; + } + } + return ChosenNode; +} + +EFI_STATUS +AndroidBootImgSetProperty64 ( + IN INTN UpdatedFdtBase, + IN INTN ChosenNode, + IN CHAR8 *PropertyName, + IN UINT64 Val + ) +{ + INTN Err; + struct fdt_property *Property; + int Len; + + Property = fdt_get_property_w((VOID *)UpdatedFdtBase, ChosenNode, + PropertyName, &Len); + if (NULL == Property && Len == -FDT_ERR_NOTFOUND) { + Val = cpu_to_fdt64(Val); + Err = fdt_appendprop ((VOID *)UpdatedFdtBase, ChosenNode, + PropertyName, &Val, sizeof (UINT64)); + if (Err) { + DEBUG ((DEBUG_ERROR, "fdt_appendprop() fail: %a\n", fdt_strerror (Err))); + return EFI_INVALID_PARAMETER; + } + } else if (Property != NULL) { + Err = fdt_setprop_u64((VOID *)UpdatedFdtBase, ChosenNode, + PropertyName, Val); + if (Err) { + DEBUG ((DEBUG_ERROR, "fdt_setprop_u64() fail: %a\n", fdt_strerror (Err))); + return EFI_INVALID_PARAMETER; + } + } else { + DEBUG ((DEBUG_ERROR, "Failed to set fdt Property %a\n", PropertyName)); + return EFI_INVALID_PARAMETER; + } + return EFI_SUCCESS; +} + +EFI_STATUS +AndroidBootImgUpdateFdt ( + IN VOID *BootImg, + IN VOID *FdtBase, + IN VOID *RamdiskData, + IN UINTN RamdiskSize + ) +{ + INTN ChosenNode, Err, NewFdtSize; + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS UpdatedFdtBase, NewFdtBase; + + NewFdtSize = (UINTN)fdt_totalsize (FdtBase) + + FDT_ADDITIONAL_ENTRIES_SIZE; + Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, + EFI_SIZE_TO_PAGES (NewFdtSize), &UpdatedFdtBase); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "Warning: Failed to reallocate FDT, err %d.\n", + Status)); + return Status; + } + + // Load the Original FDT tree into the new region + Err = fdt_open_into(FdtBase, (VOID*)(INTN)UpdatedFdtBase, NewFdtSize); + if (Err) { + DEBUG ((DEBUG_ERROR, "fdt_open_into(): %a\n", fdt_strerror (Err))); + Status = EFI_INVALID_PARAMETER; + goto Fdt_Exit; + } + + ChosenNode = AndroidBootImgGetChosenNode(UpdatedFdtBase); + if (!ChosenNode) { + goto Fdt_Exit; + } + + Status = AndroidBootImgSetProperty64 (UpdatedFdtBase, ChosenNode, + "linux,initrd-start", + (UINTN)RamdiskData); + if (EFI_ERROR (Status)) { + goto Fdt_Exit; + } + + Status = AndroidBootImgSetProperty64 (UpdatedFdtBase, ChosenNode, + "linux,initrd-end", + (UINTN)RamdiskData + RamdiskSize); + if (EFI_ERROR (Status)) { + goto Fdt_Exit; + } + + if (mAndroidBootImg->UpdateDtb) { + Status = mAndroidBootImg->UpdateDtb (UpdatedFdtBase, &NewFdtBase); + if (EFI_ERROR (Status)) { + goto Fdt_Exit; + } + + Status = gBS->InstallConfigurationTable ( + &gFdtTableGuid, + (VOID *)(UINTN)NewFdtBase + ); + } + + if (!EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + +Fdt_Exit: + gBS->FreePages (UpdatedFdtBase, EFI_SIZE_TO_PAGES (NewFdtSize)); + return Status; +} + +EFI_STATUS +AndroidBootImgBoot ( + IN VOID *Buffer, + IN UINTN BufferSize + ) +{ + EFI_STATUS Status; + VOID *Kernel; + UINTN KernelSize; + MEMORY_DEVICE_PATH KernelDevicePath; + EFI_HANDLE ImageHandle; + VOID *NewKernelArg; + EFI_LOADED_IMAGE_PROTOCOL *ImageInfo; + VOID *RamdiskData; + UINTN RamdiskSize; + IN VOID *FdtBase; + + Status = gBS->LocateProtocol (&gAndroidBootImgProtocolGuid, NULL, + (VOID **) &mAndroidBootImg); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = AndroidBootImgGetKernelInfo ( + Buffer, + &Kernel, + &KernelSize + ); + if (EFI_ERROR (Status)) { + return Status; + } + + NewKernelArg = AllocateZeroPool (ANDROID_BOOTIMG_KERNEL_ARGS_SIZE); + if (NewKernelArg == NULL) { + DEBUG ((DEBUG_ERROR, "Fail to allocate memory\n")); + return EFI_OUT_OF_RESOURCES; + } + + Status = AndroidBootImgUpdateArgs (Buffer, NewKernelArg); + if (EFI_ERROR (Status)) { + FreePool (NewKernelArg); + return Status; + } + + Status = AndroidBootImgGetRamdiskInfo ( + Buffer, + &RamdiskData, + &RamdiskSize + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = AndroidBootImgLocateFdt (Buffer, &FdtBase); + if (EFI_ERROR (Status)) { + FreePool (NewKernelArg); + return Status; + } + + Status = AndroidBootImgUpdateFdt (Buffer, FdtBase, RamdiskData, RamdiskSize); + if (EFI_ERROR (Status)) { + FreePool (NewKernelArg); + return Status; + } + + KernelDevicePath = mMemoryDevicePathTemplate; + + KernelDevicePath.Node1.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Kernel; + KernelDevicePath.Node1.EndingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Kernel + + KernelSize; + + Status = gBS->LoadImage (TRUE, gImageHandle, + (EFI_DEVICE_PATH *)&KernelDevicePath, + (VOID*)(UINTN)Kernel, KernelSize, &ImageHandle); + if (EFI_ERROR (Status)) { + // + // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created + // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now. + // If the caller doesn't have the option to defer the execution of an image, we should + // unload image for the EFI_SECURITY_VIOLATION to avoid resource leak. + // + if (Status == EFI_SECURITY_VIOLATION) { + gBS->UnloadImage (ImageHandle); + } + return Status; + } + + // Set kernel arguments + Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, + (VOID **) &ImageInfo); + ImageInfo->LoadOptions = NewKernelArg; + ImageInfo->LoadOptionsSize = StrLen (NewKernelArg) * sizeof (CHAR16); + + // Before calling the image, enable the Watchdog Timer for the 5 Minute period + gBS->SetWatchdogTimer (5 * 60, 0x10000, 0, NULL); + // Start the image + Status = gBS->StartImage (ImageHandle, NULL, NULL); + // Clear the Watchdog Timer if the image returns + gBS->SetWatchdogTimer (0, 0x10000, 0, NULL); + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.inf new file mode 100644 index 00000000..2e3b6f50 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.inf @@ -0,0 +1,44 @@ +#/** @file +# +# Copyright (c) 2013-2015, ARM Ltd. All rights reserved.<BR> +# Copyright (c) 2017, Linaro. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = AndroidBootImgLib + FILE_GUID = ed3b8739-6fa7-4cb1-8aeb-2496f8fcaefa + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = AndroidBootImgLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = ARM AARCH64 +# + +[Sources] + AndroidBootImgLib.c + +[LibraryClasses] + DebugLib + FdtLib + PrintLib + UefiBootServicesTableLib + UefiLib + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + +[Protocols] + gAndroidBootImgProtocolGuid + gEfiLoadedImageProtocolGuid + +[Guids] + gFdtTableGuid diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/CoherentDmaLib/CoherentDmaLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/CoherentDmaLib/CoherentDmaLib.c new file mode 100644 index 00000000..5d458213 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/CoherentDmaLib/CoherentDmaLib.c @@ -0,0 +1,195 @@ +/** @file + Generic ARM implementation of DmaLib.h + + Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Uefi.h> +#include <Library/DebugLib.h> +#include <Library/DmaLib.h> +#include <Library/MemoryAllocationLib.h> + + +STATIC +PHYSICAL_ADDRESS +HostToDeviceAddress ( + IN VOID *Address + ) +{ + return (PHYSICAL_ADDRESS)(UINTN)Address + PcdGet64 (PcdDmaDeviceOffset); +} + +/** + Provides the DMA controller-specific addresses needed to access system memory. + + Operation is relative to the DMA bus master. + + @param Operation Indicates if the bus master is going to read or write to system memory. + @param HostAddress The system memory address to map to the DMA controller. + @param NumberOfBytes On input the number of bytes to map. On output the number of bytes + that were mapped. + @param DeviceAddress The resulting map address for the bus master controller to use to + access the hosts HostAddress. + @param Mapping A resulting value to pass to Unmap(). + + @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes. + @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_DEVICE_ERROR The system hardware could not map the requested address. + +**/ +EFI_STATUS +EFIAPI +DmaMap ( + IN DMA_MAP_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) +{ + if (HostAddress == NULL || + NumberOfBytes == NULL || + DeviceAddress == NULL || + Mapping == NULL ) { + return EFI_INVALID_PARAMETER; + } + *DeviceAddress = HostToDeviceAddress (HostAddress); + *Mapping = NULL; + return EFI_SUCCESS; +} + + +/** + Completes the DmaMapBusMasterRead(), DmaMapBusMasterWrite(), or DmaMapBusMasterCommonBuffer() + operation and releases any corresponding resources. + + @param Mapping The mapping value returned from DmaMap*(). + + @retval EFI_SUCCESS The range was unmapped. + @retval EFI_DEVICE_ERROR The data was not committed to the target system memory. + +**/ +EFI_STATUS +EFIAPI +DmaUnmap ( + IN VOID *Mapping + ) +{ + return EFI_SUCCESS; +} + +/** + Allocates pages that are suitable for an DmaMap() of type MapOperationBusMasterCommonBuffer. + mapping. + + @param MemoryType The type of memory to allocate, EfiBootServicesData or + EfiRuntimeServicesData. + @param Pages The number of pages to allocate. + @param HostAddress A pointer to store the base system memory address of the + allocated range. + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are + MEMORY_WRITE_COMBINE and MEMORY_CACHED. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +EFI_STATUS +EFIAPI +DmaAllocateBuffer ( + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress + ) +{ + return DmaAllocateAlignedBuffer (MemoryType, Pages, 0, HostAddress); +} + + +/** + Allocates pages that are suitable for an DmaMap() of type + MapOperationBusMasterCommonBuffer mapping, at the requested alignment. + + @param MemoryType The type of memory to allocate, EfiBootServicesData or + EfiRuntimeServicesData. + @param Pages The number of pages to allocate. + @param Alignment Alignment in bytes of the base of the returned + buffer (must be a power of 2) + @param HostAddress A pointer to store the base system memory address of the + allocated range. + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are + MEMORY_WRITE_COMBINE and MEMORY_CACHED. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +EFI_STATUS +EFIAPI +DmaAllocateAlignedBuffer ( + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN UINTN Alignment, + OUT VOID **HostAddress + ) +{ + if (Alignment == 0) { + Alignment = EFI_PAGE_SIZE; + } + + if (HostAddress == NULL || + (Alignment & (Alignment - 1)) != 0) { + return EFI_INVALID_PARAMETER; + } + + // + // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData + // + if (MemoryType == EfiBootServicesData) { + *HostAddress = AllocateAlignedPages (Pages, Alignment); + } else if (MemoryType == EfiRuntimeServicesData) { + *HostAddress = AllocateAlignedRuntimePages (Pages, Alignment); + } else { + return EFI_INVALID_PARAMETER; + } + + if (*HostAddress == NULL) { + return EFI_OUT_OF_RESOURCES; + } + return EFI_SUCCESS; +} + + +/** + Frees memory that was allocated with DmaAllocateBuffer(). + + @param Pages The number of pages to free. + @param HostAddress The base system memory address of the allocated range. + + @retval EFI_SUCCESS The requested memory pages were freed. + @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages + was not allocated with DmaAllocateBuffer(). + +**/ +EFI_STATUS +EFIAPI +DmaFreeBuffer ( + IN UINTN Pages, + IN VOID *HostAddress + ) +{ + if (HostAddress == NULL) { + return EFI_INVALID_PARAMETER; + } + + FreePages (HostAddress, Pages); + return EFI_SUCCESS; +} + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/CoherentDmaLib/CoherentDmaLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/CoherentDmaLib/CoherentDmaLib.inf new file mode 100644 index 00000000..7e518d9f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/CoherentDmaLib/CoherentDmaLib.inf @@ -0,0 +1,30 @@ +#/** @file +# +# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR> +# Copyright (c) 2017, Linaro, Ltd. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = CoherentDmaLib + FILE_GUID = 0F2A0816-D319-4ee7-A6B8-D58524E4428F + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = DmaLib + +[Sources] + CoherentDmaLib.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + DebugLib + MemoryAllocationLib + +[Pcd] + gEmbeddedTokenSpaceGuid.PcdDmaDeviceOffset diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/DebugAgentTimerLibNull/DebugAgentTimerLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/DebugAgentTimerLibNull/DebugAgentTimerLib.c new file mode 100644 index 00000000..dac101e7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/DebugAgentTimerLibNull/DebugAgentTimerLib.c @@ -0,0 +1,57 @@ +/** @file + Null Debug Agent timer. + + The debug agent uses the timer so the debugger can break into running programs. + If you link against this library you will not be able to break into a running + program with the debugger. + + Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +/** + Setup all the hardware needed for the debug agents timer. + + This function is used to set up debug environment. It may enable interrupts. + +**/ +VOID +EFIAPI +DebugAgentTimerIntialize ( + VOID + ) +{ +} + + +/** + Set the period for the debug agent timer. Zero means disable the timer. + + @param[in] TimerPeriodMilliseconds Frequency of the debug agent timer. + +**/ +VOID +EFIAPI +DebugAgentTimerSetPeriod ( + IN UINT32 TimerPeriodMilliseconds + ) +{ +} + + +/** + Perform End Of Interrupt for the debug agent timer. This is called in the + interrupt handler after the interrupt has been processed. + +**/ +VOID +EFIAPI +DebugAgentTimerEndOfInterrupt ( + VOID + ) +{ +} + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/DebugAgentTimerLibNull/DebugAgentTimerLibNull.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/DebugAgentTimerLibNull/DebugAgentTimerLibNull.inf new file mode 100644 index 00000000..48e83cae --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/DebugAgentTimerLibNull/DebugAgentTimerLibNull.inf @@ -0,0 +1,32 @@ +#/** @file +# Component description file for Base PCI Cf8 Library. +# +# PCI CF8 Library that uses I/O ports 0xCF8 and 0xCFC to perform PCI Configuration cycles. +# Layers on top of an I/O Library instance. +# Copyright (c) 2007, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DebugAgentTimerLibNull + FILE_GUID = 02f04694-2c0a-4f1e-b0ce-64be25890b03 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = DebugAgentTimerLib|SEC BASE DXE_CORE + + +[Sources.common] + DebugAgentTimerLib.c + + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + IoLib + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/DxeDtPlatformDtbLoaderLibDefault/DxeDtPlatformDtbLoaderLibDefault.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/DxeDtPlatformDtbLoaderLibDefault/DxeDtPlatformDtbLoaderLibDefault.c new file mode 100644 index 00000000..53c2050a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/DxeDtPlatformDtbLoaderLibDefault/DxeDtPlatformDtbLoaderLibDefault.c @@ -0,0 +1,54 @@ +/** @file +* +* Copyright (c) 2017, Linaro, Ltd. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#include <PiDxe.h> + +#include <Library/BaseLib.h> +#include <Library/DxeServicesLib.h> +#include <Library/MemoryAllocationLib.h> + +/** + Return a pool allocated copy of the DTB image that is appropriate for + booting the current platform via DT. + + @param[out] Dtb Pointer to the DTB copy + @param[out] DtbSize Size of the DTB copy + + @retval EFI_SUCCESS Operation completed successfully + @retval EFI_NOT_FOUND No suitable DTB image could be located + @retval EFI_OUT_OF_RESOURCES No pool memory available + +**/ +EFI_STATUS +EFIAPI +DtPlatformLoadDtb ( + OUT VOID **Dtb, + OUT UINTN *DtbSize + ) +{ + EFI_STATUS Status; + VOID *OrigDtb; + VOID *CopyDtb; + UINTN OrigDtbSize; + + Status = GetSectionFromAnyFv (&gDtPlatformDefaultDtbFileGuid, + EFI_SECTION_RAW, 0, &OrigDtb, &OrigDtbSize); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + CopyDtb = AllocateCopyPool (OrigDtbSize, OrigDtb); + if (CopyDtb == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + *Dtb = CopyDtb; + *DtbSize = OrigDtbSize; + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/DxeDtPlatformDtbLoaderLibDefault/DxeDtPlatformDtbLoaderLibDefault.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/DxeDtPlatformDtbLoaderLibDefault/DxeDtPlatformDtbLoaderLibDefault.inf new file mode 100644 index 00000000..9e27c453 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/DxeDtPlatformDtbLoaderLibDefault/DxeDtPlatformDtbLoaderLibDefault.inf @@ -0,0 +1,30 @@ +/** @file +* +* Copyright (c) 2017, Linaro, Ltd. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = DxeDtPlatformDtbLoaderLibDefault + FILE_GUID = 419a1910-70da-4c99-8696-ba81a57be508 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = DtPlatformDtbLoaderLib|DXE_DRIVER + +[Sources] + DxeDtPlatformDtbLoaderLibDefault.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + BaseLib + DxeServicesLib + MemoryAllocationLib + +[Guids] + gDtPlatformDefaultDtbFileGuid diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/FdtLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/FdtLib.inf new file mode 100644 index 00000000..d4cb9a0e --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/FdtLib.inf @@ -0,0 +1,41 @@ +#/* @file +# Copyright (c) 2011-2014, ARM Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#*/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = FdtLib + FILE_GUID = 6b2478c0-be23-11e0-a28c-0002a5d5c51b + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = FdtLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = ARM AARCH64 +# + +[Sources] + libfdt_internal.h + fdt_empty_tree.c + fdt_overlay.c + fdt_ro.c + fdt_rw.c + fdt_strerror.c + fdt_strtoul.c + fdt_sw.c + fdt_wip.c + fdt.c + fdt_addresses.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + BaseLib + DebugLib diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/Makefile.libfdt b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/Makefile.libfdt new file mode 100644 index 00000000..09c322ed --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/Makefile.libfdt @@ -0,0 +1,11 @@ +# Makefile.libfdt +# +# This is not a complete Makefile of itself. Instead, it is designed to +# be easily embeddable into other systems of Makefiles. +# +LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1 +LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h +LIBFDT_VERSION = version.lds +LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c \ + fdt_addresses.c +LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o) diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/TODO b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/TODO new file mode 100644 index 00000000..288437e3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/TODO @@ -0,0 +1,3 @@ +- Tree traversal functions +- Graft function +- Complete libfdt.h documenting comments diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt.c new file mode 100644 index 00000000..22286a1a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt.c @@ -0,0 +1,251 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library 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; either version 2 of the + * License, or (at your option) any later version. + * + * This library 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 library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +int fdt_check_header(const void *fdt) +{ + if (fdt_magic(fdt) == FDT_MAGIC) { + /* Complete tree */ + if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) + return -FDT_ERR_BADVERSION; + if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) + return -FDT_ERR_BADVERSION; + } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { + /* Unfinished sequential-write blob */ + if (fdt_size_dt_struct(fdt) == 0) + return -FDT_ERR_BADSTATE; + } else { + return -FDT_ERR_BADMAGIC; + } + + return 0; +} + +const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) +{ + unsigned absoffset = offset + fdt_off_dt_struct(fdt); + + if ((absoffset < offset) + || ((absoffset + len) < absoffset) + || (absoffset + len) > fdt_totalsize(fdt)) + return NULL; + + if (fdt_version(fdt) >= 0x11) + if (((offset + len) < offset) + || ((offset + len) > fdt_size_dt_struct(fdt))) + return NULL; + + return _fdt_offset_ptr(fdt, offset); +} + +uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) +{ + const fdt32_t *tagp, *lenp; + uint32_t tag; + int offset = startoffset; + const char *p; + + *nextoffset = -FDT_ERR_TRUNCATED; + tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); + if (!tagp) + return FDT_END; /* premature end */ + tag = fdt32_to_cpu(*tagp); + offset += FDT_TAGSIZE; + + *nextoffset = -FDT_ERR_BADSTRUCTURE; + switch (tag) { + case FDT_BEGIN_NODE: + /* skip name */ + do { + p = fdt_offset_ptr(fdt, offset++, 1); + } while (p && (*p != '\0')); + if (!p) + return FDT_END; /* premature end */ + break; + + case FDT_PROP: + lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); + if (!lenp) + return FDT_END; /* premature end */ + /* skip-name offset, length and value */ + offset += sizeof(struct fdt_property) - FDT_TAGSIZE + + fdt32_to_cpu(*lenp); + break; + + case FDT_END: + case FDT_END_NODE: + case FDT_NOP: + break; + + default: + return FDT_END; + } + + if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset)) + return FDT_END; /* premature end */ + + *nextoffset = FDT_TAGALIGN(offset); + return tag; +} + +int _fdt_check_node_offset(const void *fdt, int offset) +{ + if ((offset < 0) || (offset % FDT_TAGSIZE) + || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE)) + return -FDT_ERR_BADOFFSET; + + return offset; +} + +int _fdt_check_prop_offset(const void *fdt, int offset) +{ + if ((offset < 0) || (offset % FDT_TAGSIZE) + || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP)) + return -FDT_ERR_BADOFFSET; + + return offset; +} + +int fdt_next_node(const void *fdt, int offset, int *depth) +{ + int nextoffset = 0; + uint32_t tag; + + if (offset >= 0) + if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0) + return nextoffset; + + do { + offset = nextoffset; + tag = fdt_next_tag(fdt, offset, &nextoffset); + + switch (tag) { + case FDT_PROP: + case FDT_NOP: + break; + + case FDT_BEGIN_NODE: + if (depth) + (*depth)++; + break; + + case FDT_END_NODE: + if (depth && ((--(*depth)) < 0)) + return nextoffset; + break; + + case FDT_END: + if ((nextoffset >= 0) + || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth)) + return -FDT_ERR_NOTFOUND; + else + return nextoffset; + } + } while (tag != FDT_BEGIN_NODE); + + return offset; +} + +int fdt_first_subnode(const void *fdt, int offset) +{ + int depth = 0; + + offset = fdt_next_node(fdt, offset, &depth); + if (offset < 0 || depth != 1) + return -FDT_ERR_NOTFOUND; + + return offset; +} + +int fdt_next_subnode(const void *fdt, int offset) +{ + int depth = 1; + + /* + * With respect to the parent, the depth of the next subnode will be + * the same as the last. + */ + do { + offset = fdt_next_node(fdt, offset, &depth); + if (offset < 0 || depth < 1) + return -FDT_ERR_NOTFOUND; + } while (depth > 1); + + return offset; +} + +const char *_fdt_find_string(const char *strtab, int tabsize, const char *s) +{ + int len = strlen(s) + 1; + const char *last = strtab + tabsize - len; + const char *p; + + for (p = strtab; p <= last; p++) + if (memcmp(p, s, len) == 0) + return p; + return NULL; +} + +int fdt_move(const void *fdt, void *buf, int bufsize) +{ + FDT_CHECK_HEADER(fdt); + + if (fdt_totalsize(fdt) > bufsize) + return -FDT_ERR_NOSPACE; + + memmove(buf, fdt, fdt_totalsize(fdt)); + return 0; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_addresses.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_addresses.c new file mode 100644 index 00000000..eff4dbcc --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_addresses.c @@ -0,0 +1,96 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au> + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library 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; either version 2 of the + * License, or (at your option) any later version. + * + * This library 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 library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +int fdt_address_cells(const void *fdt, int nodeoffset) +{ + const fdt32_t *ac; + int val; + int len; + + ac = fdt_getprop(fdt, nodeoffset, "#address-cells", &len); + if (!ac) + return 2; + + if (len != sizeof(*ac)) + return -FDT_ERR_BADNCELLS; + + val = fdt32_to_cpu(*ac); + if ((val <= 0) || (val > FDT_MAX_NCELLS)) + return -FDT_ERR_BADNCELLS; + + return val; +} + +int fdt_size_cells(const void *fdt, int nodeoffset) +{ + const fdt32_t *sc; + int val; + int len; + + sc = fdt_getprop(fdt, nodeoffset, "#size-cells", &len); + if (!sc) + return 2; + + if (len != sizeof(*sc)) + return -FDT_ERR_BADNCELLS; + + val = fdt32_to_cpu(*sc); + if ((val < 0) || (val > FDT_MAX_NCELLS)) + return -FDT_ERR_BADNCELLS; + + return val; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_empty_tree.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_empty_tree.c new file mode 100644 index 00000000..f2ae9b77 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_empty_tree.c @@ -0,0 +1,83 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2012 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library 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; either version 2 of the + * License, or (at your option) any later version. + * + * This library 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 library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +int fdt_create_empty_tree(void *buf, int bufsize) +{ + int err; + + err = fdt_create(buf, bufsize); + if (err) + return err; + + err = fdt_finish_reservemap(buf); + if (err) + return err; + + err = fdt_begin_node(buf, ""); + if (err) + return err; + + err = fdt_end_node(buf); + if (err) + return err; + + err = fdt_finish(buf); + if (err) + return err; + + return fdt_open_into(buf, buf, bufsize); +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_overlay.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_overlay.c new file mode 100644 index 00000000..804852c6 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_overlay.c @@ -0,0 +1,914 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2016 Free Electrons + * Copyright (C) 2016 NextThing Co. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library 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; either version 2 of the + * License, or (at your option) any later version. + * + * This library 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 library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +/** + * overlay_get_target_phandle - retrieves the target phandle of a fragment + * @fdto: pointer to the device tree overlay blob + * @fragment: node offset of the fragment in the overlay + * + * overlay_get_target_phandle() retrieves the target phandle of an + * overlay fragment when that fragment uses a phandle (target + * property) instead of a path (target-path property). + * + * returns: + * the phandle pointed by the target property + * 0, if the phandle was not found + * -1, if the phandle was malformed + */ +static uint32_t overlay_get_target_phandle(const void *fdto, int fragment) +{ + const fdt32_t *val; + int len; + + val = fdt_getprop(fdto, fragment, "target", &len); + if (!val) + return 0; + + if ((len != sizeof(*val)) || (fdt32_to_cpu(*val) == (uint32_t)-1)) + return (uint32_t)-1; + + return fdt32_to_cpu(*val); +} + +/** + * overlay_get_target - retrieves the offset of a fragment's target + * @fdt: Base device tree blob + * @fdto: Device tree overlay blob + * @fragment: node offset of the fragment in the overlay + * @pathp: pointer which receives the path of the target (or NULL) + * + * overlay_get_target() retrieves the target offset in the base + * device tree of a fragment, no matter how the actual targetting is + * done (through a phandle or a path) + * + * returns: + * the targetted node offset in the base device tree + * Negative error code on error + */ +static int overlay_get_target(const void *fdt, const void *fdto, + int fragment, char const **pathp) +{ + uint32_t phandle; + const char *path = NULL; + int path_len = 0, ret; + + /* Try first to do a phandle based lookup */ + phandle = overlay_get_target_phandle(fdto, fragment); + if (phandle == (uint32_t)-1) + return -FDT_ERR_BADPHANDLE; + + /* no phandle, try path */ + if (!phandle) { + /* And then a path based lookup */ + path = fdt_getprop(fdto, fragment, "target-path", &path_len); + if (path) + ret = fdt_path_offset(fdt, path); + else + ret = path_len; + } else + ret = fdt_node_offset_by_phandle(fdt, phandle); + + /* + * If we haven't found either a target or a + * target-path property in a node that contains a + * __overlay__ subnode (we wouldn't be called + * otherwise), consider it a improperly written + * overlay + */ + if (ret < 0 && path_len == -FDT_ERR_NOTFOUND) + ret = -FDT_ERR_BADOVERLAY; + + /* return on error */ + if (ret < 0) + return ret; + + /* return pointer to path (if available) */ + if (pathp) + *pathp = path ? path : NULL; + + return ret; +} + +/** + * overlay_phandle_add_offset - Increases a phandle by an offset + * @fdt: Base device tree blob + * @node: Device tree overlay blob + * @name: Name of the property to modify (phandle or linux,phandle) + * @delta: offset to apply + * + * overlay_phandle_add_offset() increments a node phandle by a given + * offset. + * + * returns: + * 0 on success. + * Negative error code on error + */ +static int overlay_phandle_add_offset(void *fdt, int node, + const char *name, uint32_t delta) +{ + const fdt32_t *val; + uint32_t adj_val; + int len; + + val = fdt_getprop(fdt, node, name, &len); + if (!val) + return len; + + if (len != sizeof(*val)) + return -FDT_ERR_BADPHANDLE; + + adj_val = fdt32_to_cpu(*val); + if ((adj_val + delta) < adj_val) + return -FDT_ERR_NOPHANDLES; + + adj_val += delta; + if (adj_val == (uint32_t)-1) + return -FDT_ERR_NOPHANDLES; + + return fdt_setprop_inplace_u32(fdt, node, name, adj_val); +} + +/** + * overlay_adjust_node_phandles - Offsets the phandles of a node + * @fdto: Device tree overlay blob + * @node: Offset of the node we want to adjust + * @delta: Offset to shift the phandles of + * + * overlay_adjust_node_phandles() adds a constant to all the phandles + * of a given node. This is mainly use as part of the overlay + * application process, when we want to update all the overlay + * phandles to not conflict with the overlays of the base device tree. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_adjust_node_phandles(void *fdto, int node, + uint32_t delta) +{ + int child; + int ret; + + ret = overlay_phandle_add_offset(fdto, node, "phandle", delta); + if (ret && ret != -FDT_ERR_NOTFOUND) + return ret; + + ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta); + if (ret && ret != -FDT_ERR_NOTFOUND) + return ret; + + fdt_for_each_subnode(child, fdto, node) { + ret = overlay_adjust_node_phandles(fdto, child, delta); + if (ret) + return ret; + } + + return 0; +} + +/** + * overlay_adjust_local_phandles - Adjust the phandles of a whole overlay + * @fdto: Device tree overlay blob + * @delta: Offset to shift the phandles of + * + * overlay_adjust_local_phandles() adds a constant to all the + * phandles of an overlay. This is mainly use as part of the overlay + * application process, when we want to update all the overlay + * phandles to not conflict with the overlays of the base device tree. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_adjust_local_phandles(void *fdto, uint32_t delta) +{ + /* + * Start adjusting the phandles from the overlay root + */ + return overlay_adjust_node_phandles(fdto, 0, delta); +} + +/** + * overlay_update_local_node_references - Adjust the overlay references + * @fdto: Device tree overlay blob + * @tree_node: Node offset of the node to operate on + * @fixup_node: Node offset of the matching local fixups node + * @delta: Offset to shift the phandles of + * + * overlay_update_local_nodes_references() update the phandles + * pointing to a node within the device tree overlay by adding a + * constant delta. + * + * This is mainly used as part of a device tree application process, + * where you want the device tree overlays phandles to not conflict + * with the ones from the base device tree before merging them. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_update_local_node_references(void *fdto, + int tree_node, + int fixup_node, + uint32_t delta) +{ + int fixup_prop; + int fixup_child; + int ret; + + fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) { + const fdt32_t *fixup_val; + const char *tree_val; + const char *name; + int fixup_len; + int tree_len; + int i; + + fixup_val = fdt_getprop_by_offset(fdto, fixup_prop, + &name, &fixup_len); + if (!fixup_val) + return fixup_len; + + if (fixup_len % sizeof(uint32_t)) + return -FDT_ERR_BADOVERLAY; + + tree_val = fdt_getprop(fdto, tree_node, name, &tree_len); + if (!tree_val) { + if (tree_len == -FDT_ERR_NOTFOUND) + return -FDT_ERR_BADOVERLAY; + + return tree_len; + } + + for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) { + fdt32_t adj_val; + uint32_t poffset; + + poffset = fdt32_to_cpu(fixup_val[i]); + + /* + * phandles to fixup can be unaligned. + * + * Use a memcpy for the architectures that do + * not support unaligned accesses. + */ + memcpy(&adj_val, tree_val + poffset, sizeof(adj_val)); + + adj_val = cpu_to_fdt32(fdt32_to_cpu(adj_val) + delta); + + ret = fdt_setprop_inplace_namelen_partial(fdto, + tree_node, + name, + strlen(name), + poffset, + &adj_val, + sizeof(adj_val)); + if (ret == -FDT_ERR_NOSPACE) + return -FDT_ERR_BADOVERLAY; + + if (ret) + return ret; + } + } + + fdt_for_each_subnode(fixup_child, fdto, fixup_node) { + const char *fixup_child_name = fdt_get_name(fdto, fixup_child, + NULL); + int tree_child; + + tree_child = fdt_subnode_offset(fdto, tree_node, + fixup_child_name); + if (tree_child == -FDT_ERR_NOTFOUND) + return -FDT_ERR_BADOVERLAY; + if (tree_child < 0) + return tree_child; + + ret = overlay_update_local_node_references(fdto, + tree_child, + fixup_child, + delta); + if (ret) + return ret; + } + + return 0; +} + +/** + * overlay_update_local_references - Adjust the overlay references + * @fdto: Device tree overlay blob + * @delta: Offset to shift the phandles of + * + * overlay_update_local_references() update all the phandles pointing + * to a node within the device tree overlay by adding a constant + * delta to not conflict with the base overlay. + * + * This is mainly used as part of a device tree application process, + * where you want the device tree overlays phandles to not conflict + * with the ones from the base device tree before merging them. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_update_local_references(void *fdto, uint32_t delta) +{ + int fixups; + + fixups = fdt_path_offset(fdto, "/__local_fixups__"); + if (fixups < 0) { + /* There's no local phandles to adjust, bail out */ + if (fixups == -FDT_ERR_NOTFOUND) + return 0; + + return fixups; + } + + /* + * Update our local references from the root of the tree + */ + return overlay_update_local_node_references(fdto, 0, fixups, + delta); +} + +/** + * overlay_fixup_one_phandle - Set an overlay phandle to the base one + * @fdt: Base Device Tree blob + * @fdto: Device tree overlay blob + * @symbols_off: Node offset of the symbols node in the base device tree + * @path: Path to a node holding a phandle in the overlay + * @path_len: number of path characters to consider + * @name: Name of the property holding the phandle reference in the overlay + * @name_len: number of name characters to consider + * @poffset: Offset within the overlay property where the phandle is stored + * @label: Label of the node referenced by the phandle + * + * overlay_fixup_one_phandle() resolves an overlay phandle pointing to + * a node in the base device tree. + * + * This is part of the device tree overlay application process, when + * you want all the phandles in the overlay to point to the actual + * base dt nodes. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_fixup_one_phandle(void *fdt, void *fdto, + int symbols_off, + const char *path, uint32_t path_len, + const char *name, uint32_t name_len, + int poffset, const char *label) +{ + const char *symbol_path; + uint32_t phandle; + fdt32_t phandle_prop; + int symbol_off, fixup_off; + int prop_len; + + if (symbols_off < 0) + return symbols_off; + + symbol_path = fdt_getprop(fdt, symbols_off, label, + &prop_len); + if (!symbol_path) + return prop_len; + + symbol_off = fdt_path_offset(fdt, symbol_path); + if (symbol_off < 0) + return symbol_off; + + phandle = fdt_get_phandle(fdt, symbol_off); + if (!phandle) + return -FDT_ERR_NOTFOUND; + + fixup_off = fdt_path_offset_namelen(fdto, path, path_len); + if (fixup_off == -FDT_ERR_NOTFOUND) + return -FDT_ERR_BADOVERLAY; + if (fixup_off < 0) + return fixup_off; + + phandle_prop = cpu_to_fdt32(phandle); + return fdt_setprop_inplace_namelen_partial(fdto, fixup_off, + name, name_len, poffset, + &phandle_prop, + sizeof(phandle_prop)); +}; + +unsigned long strtoul(const char *nptr, char **endptr, int base); + +/** + * overlay_fixup_phandle - Set an overlay phandle to the base one + * @fdt: Base Device Tree blob + * @fdto: Device tree overlay blob + * @symbols_off: Node offset of the symbols node in the base device tree + * @property: Property offset in the overlay holding the list of fixups + * + * overlay_fixup_phandle() resolves all the overlay phandles pointed + * to in a __fixups__ property, and updates them to match the phandles + * in use in the base device tree. + * + * This is part of the device tree overlay application process, when + * you want all the phandles in the overlay to point to the actual + * base dt nodes. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off, + int property) +{ + const char *value; + const char *label; + int len; + + value = fdt_getprop_by_offset(fdto, property, + &label, &len); + if (!value) { + if (len == -FDT_ERR_NOTFOUND) + return -FDT_ERR_INTERNAL; + + return len; + } + + do { + const char *path, *name, *fixup_end; + const char *fixup_str = value; + uint32_t path_len, name_len; + uint32_t fixup_len; + char *sep, *endptr; + int poffset, ret; + + fixup_end = memchr(value, '\0', len); + if (!fixup_end) + return -FDT_ERR_BADOVERLAY; + fixup_len = fixup_end - fixup_str; + + len -= fixup_len + 1; + value += fixup_len + 1; + + path = fixup_str; + sep = memchr(fixup_str, ':', fixup_len); + if (!sep || *sep != ':') + return -FDT_ERR_BADOVERLAY; + + path_len = sep - path; + if (path_len == (fixup_len - 1)) + return -FDT_ERR_BADOVERLAY; + + fixup_len -= path_len + 1; + name = sep + 1; + sep = memchr(name, ':', fixup_len); + if (!sep || *sep != ':') + return -FDT_ERR_BADOVERLAY; + + name_len = sep - name; + if (!name_len) + return -FDT_ERR_BADOVERLAY; + + poffset = strtoul(sep + 1, &endptr, 10); + if ((*endptr != '\0') || (endptr <= (sep + 1))) + return -FDT_ERR_BADOVERLAY; + + ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off, + path, path_len, name, name_len, + poffset, label); + if (ret) + return ret; + } while (len > 0); + + return 0; +} + +/** + * overlay_fixup_phandles - Resolve the overlay phandles to the base + * device tree + * @fdt: Base Device Tree blob + * @fdto: Device tree overlay blob + * + * overlay_fixup_phandles() resolves all the overlay phandles pointing + * to nodes in the base device tree. + * + * This is one of the steps of the device tree overlay application + * process, when you want all the phandles in the overlay to point to + * the actual base dt nodes. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_fixup_phandles(void *fdt, void *fdto) +{ + int fixups_off, symbols_off; + int property; + + /* We can have overlays without any fixups */ + fixups_off = fdt_path_offset(fdto, "/__fixups__"); + if (fixups_off == -FDT_ERR_NOTFOUND) + return 0; /* nothing to do */ + if (fixups_off < 0) + return fixups_off; + + /* And base DTs without symbols */ + symbols_off = fdt_path_offset(fdt, "/__symbols__"); + if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND))) + return symbols_off; + + fdt_for_each_property_offset(property, fdto, fixups_off) { + int ret; + + ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property); + if (ret) + return ret; + } + + return 0; +} + +/** + * overlay_apply_node - Merges a node into the base device tree + * @fdt: Base Device Tree blob + * @target: Node offset in the base device tree to apply the fragment to + * @fdto: Device tree overlay blob + * @node: Node offset in the overlay holding the changes to merge + * + * overlay_apply_node() merges a node into a target base device tree + * node pointed. + * + * This is part of the final step in the device tree overlay + * application process, when all the phandles have been adjusted and + * resolved and you just have to merge overlay into the base device + * tree. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_apply_node(void *fdt, int target, + void *fdto, int node) +{ + int property; + int subnode; + + fdt_for_each_property_offset(property, fdto, node) { + const char *name; + const void *prop; + int prop_len; + int ret; + + prop = fdt_getprop_by_offset(fdto, property, &name, + &prop_len); + if (prop_len == -FDT_ERR_NOTFOUND) + return -FDT_ERR_INTERNAL; + if (prop_len < 0) + return prop_len; + + ret = fdt_setprop(fdt, target, name, prop, prop_len); + if (ret) + return ret; + } + + fdt_for_each_subnode(subnode, fdto, node) { + const char *name = fdt_get_name(fdto, subnode, NULL); + int nnode; + int ret; + + nnode = fdt_add_subnode(fdt, target, name); + if (nnode == -FDT_ERR_EXISTS) { + nnode = fdt_subnode_offset(fdt, target, name); + if (nnode == -FDT_ERR_NOTFOUND) + return -FDT_ERR_INTERNAL; + } + + if (nnode < 0) + return nnode; + + ret = overlay_apply_node(fdt, nnode, fdto, subnode); + if (ret) + return ret; + } + + return 0; +} + +/** + * overlay_merge - Merge an overlay into its base device tree + * @fdt: Base Device Tree blob + * @fdto: Device tree overlay blob + * + * overlay_merge() merges an overlay into its base device tree. + * + * This is the next to last step in the device tree overlay application + * process, when all the phandles have been adjusted and resolved and + * you just have to merge overlay into the base device tree. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_merge(void *fdt, void *fdto) +{ + int fragment; + + fdt_for_each_subnode(fragment, fdto, 0) { + int overlay; + int target; + int ret; + + /* + * Each fragments will have an __overlay__ node. If + * they don't, it's not supposed to be merged + */ + overlay = fdt_subnode_offset(fdto, fragment, "__overlay__"); + if (overlay == -FDT_ERR_NOTFOUND) + continue; + + if (overlay < 0) + return overlay; + + target = overlay_get_target(fdt, fdto, fragment, NULL); + if (target < 0) + return target; + + ret = overlay_apply_node(fdt, target, fdto, overlay); + if (ret) + return ret; + } + + return 0; +} + +static int get_path_len(const void *fdt, int nodeoffset) +{ + int len = 0, namelen; + const char *name; + + FDT_CHECK_HEADER(fdt); + + for (;;) { + name = fdt_get_name(fdt, nodeoffset, &namelen); + if (!name) + return namelen; + + /* root? we're done */ + if (namelen == 0) + break; + + nodeoffset = fdt_parent_offset(fdt, nodeoffset); + if (nodeoffset < 0) + return nodeoffset; + len += namelen + 1; + } + + /* in case of root pretend it's "/" */ + if (len == 0) + len++; + return len; +} + +/** + * overlay_symbol_update - Update the symbols of base tree after a merge + * @fdt: Base Device Tree blob + * @fdto: Device tree overlay blob + * + * overlay_symbol_update() updates the symbols of the base tree with the + * symbols of the applied overlay + * + * This is the last step in the device tree overlay application + * process, allowing the reference of overlay symbols by subsequent + * overlay operations. + * + * returns: + * 0 on success + * Negative error code on failure + */ +static int overlay_symbol_update(void *fdt, void *fdto) +{ + int root_sym, ov_sym, prop, path_len, fragment, target; + int len, frag_name_len, ret, rel_path_len; + const char *s, *e; + const char *path; + const char *name; + const char *frag_name; + const char *rel_path; + const char *target_path; + char *buf; + void *p; + + ov_sym = fdt_subnode_offset(fdto, 0, "__symbols__"); + + /* if no overlay symbols exist no problem */ + if (ov_sym < 0) + return 0; + + root_sym = fdt_subnode_offset(fdt, 0, "__symbols__"); + + /* it no root symbols exist we should create them */ + if (root_sym == -FDT_ERR_NOTFOUND) + root_sym = fdt_add_subnode(fdt, 0, "__symbols__"); + + /* any error is fatal now */ + if (root_sym < 0) + return root_sym; + + /* iterate over each overlay symbol */ + fdt_for_each_property_offset(prop, fdto, ov_sym) { + path = fdt_getprop_by_offset(fdto, prop, &name, &path_len); + if (!path) + return path_len; + + /* verify it's a string property (terminated by a single \0) */ + if (path_len < 1 || memchr(path, '\0', path_len) != &path[path_len - 1]) + return -FDT_ERR_BADVALUE; + + /* keep end marker to avoid strlen() */ + e = path + path_len; + + /* format: /<fragment-name>/__overlay__/<relative-subnode-path> */ + + if (*path != '/') + return -FDT_ERR_BADVALUE; + + /* get fragment name first */ + s = strchr(path + 1, '/'); + if (!s) + return -FDT_ERR_BADOVERLAY; + + frag_name = path + 1; + frag_name_len = s - path - 1; + + /* verify format; safe since "s" lies in \0 terminated prop */ + len = sizeof("/__overlay__/") - 1; + if ((e - s) < len || memcmp(s, "/__overlay__/", len)) + return -FDT_ERR_BADOVERLAY; + + rel_path = s + len; + rel_path_len = e - rel_path; + + /* find the fragment index in which the symbol lies */ + ret = fdt_subnode_offset_namelen(fdto, 0, frag_name, + frag_name_len); + /* not found? */ + if (ret < 0) + return -FDT_ERR_BADOVERLAY; + fragment = ret; + + /* an __overlay__ subnode must exist */ + ret = fdt_subnode_offset(fdto, fragment, "__overlay__"); + if (ret < 0) + return -FDT_ERR_BADOVERLAY; + + /* get the target of the fragment */ + ret = overlay_get_target(fdt, fdto, fragment, &target_path); + if (ret < 0) + return ret; + target = ret; + + /* if we have a target path use */ + if (!target_path) { + ret = get_path_len(fdt, target); + if (ret < 0) + return ret; + len = ret; + } else { + len = strlen(target_path); + } + + ret = fdt_setprop_placeholder(fdt, root_sym, name, + len + (len > 1) + rel_path_len + 1, &p); + if (ret < 0) + return ret; + + if (!target_path) { + /* again in case setprop_placeholder changed it */ + ret = overlay_get_target(fdt, fdto, fragment, &target_path); + if (ret < 0) + return ret; + target = ret; + } + + buf = p; + if (len > 1) { /* target is not root */ + if (!target_path) { + ret = fdt_get_path(fdt, target, buf, len + 1); + if (ret < 0) + return ret; + } else + memcpy(buf, target_path, len + 1); + + } else + len--; + + buf[len] = '/'; + memcpy(buf + len + 1, rel_path, rel_path_len); + buf[len + 1 + rel_path_len] = '\0'; + } + + return 0; +} + +int fdt_overlay_apply(void *fdt, void *fdto) +{ + uint32_t delta = fdt_get_max_phandle(fdt); + int ret; + + FDT_CHECK_HEADER(fdt); + FDT_CHECK_HEADER(fdto); + + ret = overlay_adjust_local_phandles(fdto, delta); + if (ret) + goto err; + + ret = overlay_update_local_references(fdto, delta); + if (ret) + goto err; + + ret = overlay_fixup_phandles(fdt, fdto); + if (ret) + goto err; + + ret = overlay_merge(fdt, fdto); + if (ret) + goto err; + + ret = overlay_symbol_update(fdt, fdto); + if (ret) + goto err; + + /* + * The overlay has been damaged, erase its magic. + */ + fdt_set_magic(fdto, ~0); + + return 0; + +err: + /* + * The overlay might have been damaged, erase its magic. + */ + fdt_set_magic(fdto, ~0); + + /* + * The base device tree might have been damaged, erase its + * magic. + */ + fdt_set_magic(fdt, ~0); + + return ret; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_ro.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_ro.c new file mode 100644 index 00000000..08de2cce --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_ro.c @@ -0,0 +1,703 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library 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; either version 2 of the + * License, or (at your option) any later version. + * + * This library 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 library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +static int _fdt_nodename_eq(const void *fdt, int offset, + const char *s, int len) +{ + const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1); + + if (!p) + /* short match */ + return 0; + + if (memcmp(p, s, len) != 0) + return 0; + + if (p[len] == '\0') + return 1; + else if (!memchr(s, '@', len) && (p[len] == '@')) + return 1; + else + return 0; +} + +const char *fdt_string(const void *fdt, int stroffset) +{ + return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; +} + +static int _fdt_string_eq(const void *fdt, int stroffset, + const char *s, int len) +{ + const char *p = fdt_string(fdt, stroffset); + + return (strlen(p) == len) && (memcmp(p, s, len) == 0); +} + +uint32_t fdt_get_max_phandle(const void *fdt) +{ + uint32_t max_phandle = 0; + int offset; + + for (offset = fdt_next_node(fdt, -1, NULL);; + offset = fdt_next_node(fdt, offset, NULL)) { + uint32_t phandle; + + if (offset == -FDT_ERR_NOTFOUND) + return max_phandle; + + if (offset < 0) + return (uint32_t)-1; + + phandle = fdt_get_phandle(fdt, offset); + if (phandle == (uint32_t)-1) + continue; + + if (phandle > max_phandle) + max_phandle = phandle; + } + + return 0; +} + +int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) +{ + FDT_CHECK_HEADER(fdt); + *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address); + *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size); + return 0; +} + +int fdt_num_mem_rsv(const void *fdt) +{ + int i = 0; + + while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0) + i++; + return i; +} + +static int _nextprop(const void *fdt, int offset) +{ + uint32_t tag; + int nextoffset; + + do { + tag = fdt_next_tag(fdt, offset, &nextoffset); + + switch (tag) { + case FDT_END: + if (nextoffset >= 0) + return -FDT_ERR_BADSTRUCTURE; + else + return nextoffset; + + case FDT_PROP: + return offset; + } + offset = nextoffset; + } while (tag == FDT_NOP); + + return -FDT_ERR_NOTFOUND; +} + +int fdt_subnode_offset_namelen(const void *fdt, int offset, + const char *name, int namelen) +{ + int depth; + + FDT_CHECK_HEADER(fdt); + + for (depth = 0; + (offset >= 0) && (depth >= 0); + offset = fdt_next_node(fdt, offset, &depth)) + if ((depth == 1) + && _fdt_nodename_eq(fdt, offset, name, namelen)) + return offset; + + if (depth < 0) + return -FDT_ERR_NOTFOUND; + return offset; /* error */ +} + +int fdt_subnode_offset(const void *fdt, int parentoffset, + const char *name) +{ + return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name)); +} + +int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen) +{ + const char *end = path + namelen; + const char *p = path; + int offset = 0; + + FDT_CHECK_HEADER(fdt); + + /* see if we have an alias */ + if (*path != '/') { + const char *q = memchr(path, '/', end - p); + + if (!q) + q = end; + + p = fdt_get_alias_namelen(fdt, p, q - p); + if (!p) + return -FDT_ERR_BADPATH; + offset = fdt_path_offset(fdt, p); + + p = q; + } + + while (p < end) { + const char *q; + + while (*p == '/') { + p++; + if (p == end) + return offset; + } + q = memchr(p, '/', end - p); + if (! q) + q = end; + + offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p); + if (offset < 0) + return offset; + + p = q; + } + + return offset; +} + +int fdt_path_offset(const void *fdt, const char *path) +{ + return fdt_path_offset_namelen(fdt, path, strlen(path)); +} + +const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) +{ + const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset); + int err; + + if (((err = fdt_check_header(fdt)) != 0) + || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0)) + goto fail; + + if (len) + *len = strlen(nh->name); + + return nh->name; + + fail: + if (len) + *len = err; + return NULL; +} + +int fdt_first_property_offset(const void *fdt, int nodeoffset) +{ + int offset; + + if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0) + return offset; + + return _nextprop(fdt, offset); +} + +int fdt_next_property_offset(const void *fdt, int offset) +{ + if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0) + return offset; + + return _nextprop(fdt, offset); +} + +const struct fdt_property *fdt_get_property_by_offset(const void *fdt, + int offset, + int *lenp) +{ + int err; + const struct fdt_property *prop; + + if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) { + if (lenp) + *lenp = err; + return NULL; + } + + prop = _fdt_offset_ptr(fdt, offset); + + if (lenp) + *lenp = fdt32_to_cpu(prop->len); + + return prop; +} + +const struct fdt_property *fdt_get_property_namelen(const void *fdt, + int offset, + const char *name, + int namelen, int *lenp) +{ + for (offset = fdt_first_property_offset(fdt, offset); + (offset >= 0); + (offset = fdt_next_property_offset(fdt, offset))) { + const struct fdt_property *prop; + + if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) { + offset = -FDT_ERR_INTERNAL; + break; + } + if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff), + name, namelen)) + return prop; + } + + if (lenp) + *lenp = offset; + return NULL; +} + +const struct fdt_property *fdt_get_property(const void *fdt, + int nodeoffset, + const char *name, int *lenp) +{ + return fdt_get_property_namelen(fdt, nodeoffset, name, + strlen(name), lenp); +} + +const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, + const char *name, int namelen, int *lenp) +{ + const struct fdt_property *prop; + + prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp); + if (!prop) + return NULL; + + return prop->data; +} + +const void *fdt_getprop_by_offset(const void *fdt, int offset, + const char **namep, int *lenp) +{ + const struct fdt_property *prop; + + prop = fdt_get_property_by_offset(fdt, offset, lenp); + if (!prop) + return NULL; + if (namep) + *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); + return prop->data; +} + +const void *fdt_getprop(const void *fdt, int nodeoffset, + const char *name, int *lenp) +{ + return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp); +} + +uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) +{ + const fdt32_t *php; + int len; + + /* FIXME: This is a bit sub-optimal, since we potentially scan + * over all the properties twice. */ + php = fdt_getprop(fdt, nodeoffset, "phandle", &len); + if (!php || (len != sizeof(*php))) { + php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len); + if (!php || (len != sizeof(*php))) + return 0; + } + + return fdt32_to_cpu(*php); +} + +const char *fdt_get_alias_namelen(const void *fdt, + const char *name, int namelen) +{ + int aliasoffset; + + aliasoffset = fdt_path_offset(fdt, "/aliases"); + if (aliasoffset < 0) + return NULL; + + return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL); +} + +const char *fdt_get_alias(const void *fdt, const char *name) +{ + return fdt_get_alias_namelen(fdt, name, strlen(name)); +} + +int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) +{ + int pdepth = 0, p = 0; + int offset, depth, namelen; + const char *name; + + FDT_CHECK_HEADER(fdt); + + if (buflen < 2) + return -FDT_ERR_NOSPACE; + + for (offset = 0, depth = 0; + (offset >= 0) && (offset <= nodeoffset); + offset = fdt_next_node(fdt, offset, &depth)) { + while (pdepth > depth) { + do { + p--; + } while (buf[p-1] != '/'); + pdepth--; + } + + if (pdepth >= depth) { + name = fdt_get_name(fdt, offset, &namelen); + if (!name) + return namelen; + if ((p + namelen + 1) <= buflen) { + memcpy(buf + p, name, namelen); + p += namelen; + buf[p++] = '/'; + pdepth++; + } + } + + if (offset == nodeoffset) { + if (pdepth < (depth + 1)) + return -FDT_ERR_NOSPACE; + + if (p > 1) /* special case so that root path is "/", not "" */ + p--; + buf[p] = '\0'; + return 0; + } + } + + if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) + return -FDT_ERR_BADOFFSET; + else if (offset == -FDT_ERR_BADOFFSET) + return -FDT_ERR_BADSTRUCTURE; + + return offset; /* error from fdt_next_node() */ +} + +int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, + int supernodedepth, int *nodedepth) +{ + int offset, depth; + int supernodeoffset = -FDT_ERR_INTERNAL; + + FDT_CHECK_HEADER(fdt); + + if (supernodedepth < 0) + return -FDT_ERR_NOTFOUND; + + for (offset = 0, depth = 0; + (offset >= 0) && (offset <= nodeoffset); + offset = fdt_next_node(fdt, offset, &depth)) { + if (depth == supernodedepth) + supernodeoffset = offset; + + if (offset == nodeoffset) { + if (nodedepth) + *nodedepth = depth; + + if (supernodedepth > depth) + return -FDT_ERR_NOTFOUND; + else + return supernodeoffset; + } + } + + if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) + return -FDT_ERR_BADOFFSET; + else if (offset == -FDT_ERR_BADOFFSET) + return -FDT_ERR_BADSTRUCTURE; + + return offset; /* error from fdt_next_node() */ +} + +int fdt_node_depth(const void *fdt, int nodeoffset) +{ + int nodedepth; + int err; + + err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth); + if (err) + return (err < 0) ? err : -FDT_ERR_INTERNAL; + return nodedepth; +} + +int fdt_parent_offset(const void *fdt, int nodeoffset) +{ + int nodedepth = fdt_node_depth(fdt, nodeoffset); + + if (nodedepth < 0) + return nodedepth; + return fdt_supernode_atdepth_offset(fdt, nodeoffset, + nodedepth - 1, NULL); +} + +int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, + const char *propname, + const void *propval, int proplen) +{ + int offset; + const void *val; + int len; + + FDT_CHECK_HEADER(fdt); + + /* FIXME: The algorithm here is pretty horrible: we scan each + * property of a node in fdt_getprop(), then if that didn't + * find what we want, we scan over them again making our way + * to the next node. Still it's the easiest to implement + * approach; performance can come later. */ + for (offset = fdt_next_node(fdt, startoffset, NULL); + offset >= 0; + offset = fdt_next_node(fdt, offset, NULL)) { + val = fdt_getprop(fdt, offset, propname, &len); + if (val && (len == proplen) + && (memcmp(val, propval, len) == 0)) + return offset; + } + + return offset; /* error from fdt_next_node() */ +} + +int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) +{ + int offset; + + if ((phandle == 0) || (phandle == -1)) + return -FDT_ERR_BADPHANDLE; + + FDT_CHECK_HEADER(fdt); + + /* FIXME: The algorithm here is pretty horrible: we + * potentially scan each property of a node in + * fdt_get_phandle(), then if that didn't find what + * we want, we scan over them again making our way to the next + * node. Still it's the easiest to implement approach; + * performance can come later. */ + for (offset = fdt_next_node(fdt, -1, NULL); + offset >= 0; + offset = fdt_next_node(fdt, offset, NULL)) { + if (fdt_get_phandle(fdt, offset) == phandle) + return offset; + } + + return offset; /* error from fdt_next_node() */ +} + +int fdt_stringlist_contains(const char *strlist, int listlen, const char *str) +{ + int len = strlen(str); + const char *p; + + while (listlen >= len) { + if (memcmp(str, strlist, len+1) == 0) + return 1; + p = memchr(strlist, '\0', listlen); + if (!p) + return 0; /* malformed strlist.. */ + listlen -= (p-strlist) + 1; + strlist = p + 1; + } + return 0; +} + +int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property) +{ + const char *list, *end; + int length, count = 0; + + list = fdt_getprop(fdt, nodeoffset, property, &length); + if (!list) + return length; + + end = list + length; + + while (list < end) { + length = strnlen(list, end - list) + 1; + + /* Abort if the last string isn't properly NUL-terminated. */ + if (list + length > end) + return -FDT_ERR_BADVALUE; + + list += length; + count++; + } + + return count; +} + +int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, + const char *string) +{ + int length, len, idx = 0; + const char *list, *end; + + list = fdt_getprop(fdt, nodeoffset, property, &length); + if (!list) + return length; + + len = strlen(string) + 1; + end = list + length; + + while (list < end) { + length = strnlen(list, end - list) + 1; + + /* Abort if the last string isn't properly NUL-terminated. */ + if (list + length > end) + return -FDT_ERR_BADVALUE; + + if (length == len && memcmp(list, string, length) == 0) + return idx; + + list += length; + idx++; + } + + return -FDT_ERR_NOTFOUND; +} + +const char *fdt_stringlist_get(const void *fdt, int nodeoffset, + const char *property, int idx, + int *lenp) +{ + const char *list, *end; + int length; + + list = fdt_getprop(fdt, nodeoffset, property, &length); + if (!list) { + if (lenp) + *lenp = length; + + return NULL; + } + + end = list + length; + + while (list < end) { + length = strnlen(list, end - list) + 1; + + /* Abort if the last string isn't properly NUL-terminated. */ + if (list + length > end) { + if (lenp) + *lenp = -FDT_ERR_BADVALUE; + + return NULL; + } + + if (idx == 0) { + if (lenp) + *lenp = length - 1; + + return list; + } + + list += length; + idx--; + } + + if (lenp) + *lenp = -FDT_ERR_NOTFOUND; + + return NULL; +} + +int fdt_node_check_compatible(const void *fdt, int nodeoffset, + const char *compatible) +{ + const void *prop; + int len; + + prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); + if (!prop) + return len; + + return !fdt_stringlist_contains(prop, len, compatible); +} + +int fdt_node_offset_by_compatible(const void *fdt, int startoffset, + const char *compatible) +{ + int offset, err; + + FDT_CHECK_HEADER(fdt); + + /* FIXME: The algorithm here is pretty horrible: we scan each + * property of a node in fdt_node_check_compatible(), then if + * that didn't find what we want, we scan over them again + * making our way to the next node. Still it's the easiest to + * implement approach; performance can come later. */ + for (offset = fdt_next_node(fdt, startoffset, NULL); + offset >= 0; + offset = fdt_next_node(fdt, offset, NULL)) { + err = fdt_node_check_compatible(fdt, offset, compatible); + if ((err < 0) && (err != -FDT_ERR_NOTFOUND)) + return err; + else if (err == 0) + return offset; + } + + return offset; /* error from fdt_next_node() */ +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_rw.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_rw.c new file mode 100644 index 00000000..5c3a2bb0 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_rw.c @@ -0,0 +1,505 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library 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; either version 2 of the + * License, or (at your option) any later version. + * + * This library 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 library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +static int _fdt_blocks_misordered(const void *fdt, + int mem_rsv_size, int struct_size) +{ + return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8)) + || (fdt_off_dt_struct(fdt) < + (fdt_off_mem_rsvmap(fdt) + mem_rsv_size)) + || (fdt_off_dt_strings(fdt) < + (fdt_off_dt_struct(fdt) + struct_size)) + || (fdt_totalsize(fdt) < + (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))); +} + +static int _fdt_rw_check_header(void *fdt) +{ + FDT_CHECK_HEADER(fdt); + + if (fdt_version(fdt) < 17) + return -FDT_ERR_BADVERSION; + if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry), + fdt_size_dt_struct(fdt))) + return -FDT_ERR_BADLAYOUT; + if (fdt_version(fdt) > 17) + fdt_set_version(fdt, 17); + + return 0; +} + +#define FDT_RW_CHECK_HEADER(fdt) \ + { \ + int __err; \ + if ((__err = _fdt_rw_check_header(fdt)) != 0) \ + return __err; \ + } + +static inline int _fdt_data_size(void *fdt) +{ + return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); +} + +static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen) +{ + char *p = splicepoint; + char *end = (char *)fdt + _fdt_data_size(fdt); + + if (((p + oldlen) < p) || ((p + oldlen) > end)) + return -FDT_ERR_BADOFFSET; + if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt)) + return -FDT_ERR_BADOFFSET; + if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt))) + return -FDT_ERR_NOSPACE; + memmove(p + newlen, p + oldlen, end - p - oldlen); + return 0; +} + +static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p, + int oldn, int newn) +{ + int delta = (newn - oldn) * sizeof(*p); + int err; + err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p)); + if (err) + return err; + fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta); + fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); + return 0; +} + +static int _fdt_splice_struct(void *fdt, void *p, + int oldlen, int newlen) +{ + int delta = newlen - oldlen; + int err; + + if ((err = _fdt_splice(fdt, p, oldlen, newlen))) + return err; + + fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta); + fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); + return 0; +} + +static int _fdt_splice_string(void *fdt, int newlen) +{ + void *p = (char *)fdt + + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); + int err; + + if ((err = _fdt_splice(fdt, p, 0, newlen))) + return err; + + fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen); + return 0; +} + +static int _fdt_find_add_string(void *fdt, const char *s) +{ + char *strtab = (char *)fdt + fdt_off_dt_strings(fdt); + const char *p; + char *new; + int len = strlen(s) + 1; + int err; + + p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s); + if (p) + /* found it */ + return (p - strtab); + + new = strtab + fdt_size_dt_strings(fdt); + err = _fdt_splice_string(fdt, len); + if (err) + return err; + + memcpy(new, s, len); + return (new - strtab); +} + +int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) +{ + struct fdt_reserve_entry *re; + int err; + + FDT_RW_CHECK_HEADER(fdt); + + re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt)); + err = _fdt_splice_mem_rsv(fdt, re, 0, 1); + if (err) + return err; + + re->address = cpu_to_fdt64(address); + re->size = cpu_to_fdt64(size); + return 0; +} + +int fdt_del_mem_rsv(void *fdt, int n) +{ + struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n); + + FDT_RW_CHECK_HEADER(fdt); + + if (n >= fdt_num_mem_rsv(fdt)) + return -FDT_ERR_NOTFOUND; + + return _fdt_splice_mem_rsv(fdt, re, 1, 0); +} + +static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name, + int len, struct fdt_property **prop) +{ + int oldlen; + int err; + + *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); + if (!*prop) + return oldlen; + + if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen), + FDT_TAGALIGN(len)))) + return err; + + (*prop)->len = cpu_to_fdt32(len); + return 0; +} + +static int _fdt_add_property(void *fdt, int nodeoffset, const char *name, + int len, struct fdt_property **prop) +{ + int proplen; + int nextoffset; + int namestroff; + int err; + + if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0) + return nextoffset; + + namestroff = _fdt_find_add_string(fdt, name); + if (namestroff < 0) + return namestroff; + + *prop = _fdt_offset_ptr_w(fdt, nextoffset); + proplen = sizeof(**prop) + FDT_TAGALIGN(len); + + err = _fdt_splice_struct(fdt, *prop, 0, proplen); + if (err) + return err; + + (*prop)->tag = cpu_to_fdt32(FDT_PROP); + (*prop)->nameoff = cpu_to_fdt32(namestroff); + (*prop)->len = cpu_to_fdt32(len); + return 0; +} + +int fdt_set_name(void *fdt, int nodeoffset, const char *name) +{ + char *namep; + int oldlen, newlen; + int err; + + FDT_RW_CHECK_HEADER(fdt); + + namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen); + if (!namep) + return oldlen; + + newlen = strlen(name); + + err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1), + FDT_TAGALIGN(newlen+1)); + if (err) + return err; + + memcpy(namep, name, newlen+1); + return 0; +} + +int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name, + int len, void **prop_data) +{ + struct fdt_property *prop; + int err; + + FDT_RW_CHECK_HEADER(fdt); + + err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop); + if (err == -FDT_ERR_NOTFOUND) + err = _fdt_add_property(fdt, nodeoffset, name, len, &prop); + if (err) + return err; + + *prop_data = prop->data; + return 0; +} + +int fdt_setprop(void *fdt, int nodeoffset, const char *name, + const void *val, int len) +{ + void *prop_data; + int err; + + err = fdt_setprop_placeholder(fdt, nodeoffset, name, len, &prop_data); + if (err) + return err; + + if (len) + memcpy(prop_data, val, len); + return 0; +} + +int fdt_appendprop(void *fdt, int nodeoffset, const char *name, + const void *val, int len) +{ + struct fdt_property *prop; + int err, oldlen, newlen; + + FDT_RW_CHECK_HEADER(fdt); + + prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); + if (prop) { + newlen = len + oldlen; + err = _fdt_splice_struct(fdt, prop->data, + FDT_TAGALIGN(oldlen), + FDT_TAGALIGN(newlen)); + if (err) + return err; + prop->len = cpu_to_fdt32(newlen); + memcpy(prop->data + oldlen, val, len); + } else { + err = _fdt_add_property(fdt, nodeoffset, name, len, &prop); + if (err) + return err; + memcpy(prop->data, val, len); + } + return 0; +} + +int fdt_delprop(void *fdt, int nodeoffset, const char *name) +{ + struct fdt_property *prop; + int len, proplen; + + FDT_RW_CHECK_HEADER(fdt); + + prop = fdt_get_property_w(fdt, nodeoffset, name, &len); + if (!prop) + return len; + + proplen = sizeof(*prop) + FDT_TAGALIGN(len); + return _fdt_splice_struct(fdt, prop, proplen, 0); +} + +int fdt_add_subnode_namelen(void *fdt, int parentoffset, + const char *name, int namelen) +{ + struct fdt_node_header *nh; + int offset, nextoffset; + int nodelen; + int err; + uint32_t tag; + fdt32_t *endtag; + + FDT_RW_CHECK_HEADER(fdt); + + offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); + if (offset >= 0) + return -FDT_ERR_EXISTS; + else if (offset != -FDT_ERR_NOTFOUND) + return offset; + + /* Try to place the new node after the parent's properties */ + fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */ + do { + offset = nextoffset; + tag = fdt_next_tag(fdt, offset, &nextoffset); + } while ((tag == FDT_PROP) || (tag == FDT_NOP)); + + nh = _fdt_offset_ptr_w(fdt, offset); + nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE; + + err = _fdt_splice_struct(fdt, nh, 0, nodelen); + if (err) + return err; + + nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); + memset(nh->name, 0, FDT_TAGALIGN(namelen+1)); + memcpy(nh->name, name, namelen); + endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE); + *endtag = cpu_to_fdt32(FDT_END_NODE); + + return offset; +} + +int fdt_add_subnode(void *fdt, int parentoffset, const char *name) +{ + return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name)); +} + +int fdt_del_node(void *fdt, int nodeoffset) +{ + int endoffset; + + FDT_RW_CHECK_HEADER(fdt); + + endoffset = _fdt_node_end_offset(fdt, nodeoffset); + if (endoffset < 0) + return endoffset; + + return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset), + endoffset - nodeoffset, 0); +} + +static void _fdt_packblocks(const char *old, char *new, + int mem_rsv_size, int struct_size) +{ + int mem_rsv_off, struct_off, strings_off; + + mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8); + struct_off = mem_rsv_off + mem_rsv_size; + strings_off = struct_off + struct_size; + + memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size); + fdt_set_off_mem_rsvmap(new, mem_rsv_off); + + memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size); + fdt_set_off_dt_struct(new, struct_off); + fdt_set_size_dt_struct(new, struct_size); + + memmove(new + strings_off, old + fdt_off_dt_strings(old), + fdt_size_dt_strings(old)); + fdt_set_off_dt_strings(new, strings_off); + fdt_set_size_dt_strings(new, fdt_size_dt_strings(old)); +} + +int fdt_open_into(const void *fdt, void *buf, int bufsize) +{ + int err; + int mem_rsv_size, struct_size; + int newsize; + const char *fdtstart = fdt; + const char *fdtend = fdtstart + fdt_totalsize(fdt); + char *tmp; + + FDT_CHECK_HEADER(fdt); + + mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) + * sizeof(struct fdt_reserve_entry); + + if (fdt_version(fdt) >= 17) { + struct_size = fdt_size_dt_struct(fdt); + } else { + struct_size = 0; + while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END) + ; + if (struct_size < 0) + return struct_size; + } + + if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) { + /* no further work necessary */ + err = fdt_move(fdt, buf, bufsize); + if (err) + return err; + fdt_set_version(buf, 17); + fdt_set_size_dt_struct(buf, struct_size); + fdt_set_totalsize(buf, bufsize); + return 0; + } + + /* Need to reorder */ + newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size + + struct_size + fdt_size_dt_strings(fdt); + + if (bufsize < newsize) + return -FDT_ERR_NOSPACE; + + /* First attempt to build converted tree at beginning of buffer */ + tmp = buf; + /* But if that overlaps with the old tree... */ + if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) { + /* Try right after the old tree instead */ + tmp = (char *)(uintptr_t)fdtend; + if ((tmp + newsize) > ((char *)buf + bufsize)) + return -FDT_ERR_NOSPACE; + } + + _fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size); + memmove(buf, tmp, newsize); + + fdt_set_magic(buf, FDT_MAGIC); + fdt_set_totalsize(buf, bufsize); + fdt_set_version(buf, 17); + fdt_set_last_comp_version(buf, 16); + fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt)); + + return 0; +} + +int fdt_pack(void *fdt) +{ + int mem_rsv_size; + + FDT_RW_CHECK_HEADER(fdt); + + mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) + * sizeof(struct fdt_reserve_entry); + _fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt)); + fdt_set_totalsize(fdt, _fdt_data_size(fdt)); + + return 0; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_strerror.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_strerror.c new file mode 100644 index 00000000..9677a188 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_strerror.c @@ -0,0 +1,102 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library 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; either version 2 of the + * License, or (at your option) any later version. + * + * This library 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 library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +struct fdt_errtabent { + const char *str; +}; + +#define FDT_ERRTABENT(val) \ + [(val)] = { .str = #val, } + +static struct fdt_errtabent fdt_errtable[] = { + FDT_ERRTABENT(FDT_ERR_NOTFOUND), + FDT_ERRTABENT(FDT_ERR_EXISTS), + FDT_ERRTABENT(FDT_ERR_NOSPACE), + + FDT_ERRTABENT(FDT_ERR_BADOFFSET), + FDT_ERRTABENT(FDT_ERR_BADPATH), + FDT_ERRTABENT(FDT_ERR_BADPHANDLE), + FDT_ERRTABENT(FDT_ERR_BADSTATE), + + FDT_ERRTABENT(FDT_ERR_TRUNCATED), + FDT_ERRTABENT(FDT_ERR_BADMAGIC), + FDT_ERRTABENT(FDT_ERR_BADVERSION), + FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE), + FDT_ERRTABENT(FDT_ERR_BADLAYOUT), + FDT_ERRTABENT(FDT_ERR_INTERNAL), + FDT_ERRTABENT(FDT_ERR_BADNCELLS), + FDT_ERRTABENT(FDT_ERR_BADVALUE), + FDT_ERRTABENT(FDT_ERR_BADOVERLAY), + FDT_ERRTABENT(FDT_ERR_NOPHANDLES), +}; +#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0])) + +const char *fdt_strerror(int errval) +{ + if (errval > 0) + return "<valid offset/length>"; + else if (errval == 0) + return "<no error>"; + else if (errval > -FDT_ERRTABSIZE) { + const char *s = fdt_errtable[-errval].str; + + if (s) + return s; + } + + return "<unknown error>"; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_strtoul.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_strtoul.c new file mode 100644 index 00000000..013ea58a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_strtoul.c @@ -0,0 +1,32 @@ +#/* @file +# Copyright (c) 2018, Linaro Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#*/ + +#include <Base.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> + +unsigned long strtoul(const char *nptr, char **endptr, int base) +{ + RETURN_STATUS Status; + UINTN ReturnValue; + + ASSERT (base == 10 || base == 16); + + if (base == 10) { + Status = AsciiStrDecimalToUintnS (nptr, endptr, &ReturnValue); + } else if (base == 16) { + Status = AsciiStrHexToUintnS (nptr, endptr, &ReturnValue); + } else { + Status = RETURN_INVALID_PARAMETER; + } + + if (RETURN_ERROR (Status)) { + return MAX_UINTN; + } + + return ReturnValue; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_sw.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_sw.c new file mode 100644 index 00000000..2bd15e7a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_sw.c @@ -0,0 +1,300 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library 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; either version 2 of the + * License, or (at your option) any later version. + * + * This library 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 library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +static int _fdt_sw_check_header(void *fdt) +{ + if (fdt_magic(fdt) != FDT_SW_MAGIC) + return -FDT_ERR_BADMAGIC; + /* FIXME: should check more details about the header state */ + return 0; +} + +#define FDT_SW_CHECK_HEADER(fdt) \ + { \ + int err; \ + if ((err = _fdt_sw_check_header(fdt)) != 0) \ + return err; \ + } + +static void *_fdt_grab_space(void *fdt, size_t len) +{ + int offset = fdt_size_dt_struct(fdt); + int spaceleft; + + spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt) + - fdt_size_dt_strings(fdt); + + if ((offset + len < offset) || (offset + len > spaceleft)) + return NULL; + + fdt_set_size_dt_struct(fdt, offset + len); + return _fdt_offset_ptr_w(fdt, offset); +} + +int fdt_create(void *buf, int bufsize) +{ + void *fdt = buf; + + if (bufsize < sizeof(struct fdt_header)) + return -FDT_ERR_NOSPACE; + + memset(buf, 0, bufsize); + + fdt_set_magic(fdt, FDT_SW_MAGIC); + fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); + fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); + fdt_set_totalsize(fdt, bufsize); + + fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header), + sizeof(struct fdt_reserve_entry))); + fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); + fdt_set_off_dt_strings(fdt, bufsize); + + return 0; +} + +int fdt_resize(void *fdt, void *buf, int bufsize) +{ + size_t headsize, tailsize; + char *oldtail, *newtail; + + FDT_SW_CHECK_HEADER(fdt); + + headsize = fdt_off_dt_struct(fdt); + tailsize = fdt_size_dt_strings(fdt); + + if ((headsize + tailsize) > bufsize) + return -FDT_ERR_NOSPACE; + + oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize; + newtail = (char *)buf + bufsize - tailsize; + + /* Two cases to avoid clobbering data if the old and new + * buffers partially overlap */ + if (buf <= fdt) { + memmove(buf, fdt, headsize); + memmove(newtail, oldtail, tailsize); + } else { + memmove(newtail, oldtail, tailsize); + memmove(buf, fdt, headsize); + } + + fdt_set_off_dt_strings(buf, bufsize); + fdt_set_totalsize(buf, bufsize); + + return 0; +} + +int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) +{ + struct fdt_reserve_entry *re; + int offset; + + FDT_SW_CHECK_HEADER(fdt); + + if (fdt_size_dt_struct(fdt)) + return -FDT_ERR_BADSTATE; + + offset = fdt_off_dt_struct(fdt); + if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) + return -FDT_ERR_NOSPACE; + + re = (struct fdt_reserve_entry *)((char *)fdt + offset); + re->address = cpu_to_fdt64(addr); + re->size = cpu_to_fdt64(size); + + fdt_set_off_dt_struct(fdt, offset + sizeof(*re)); + + return 0; +} + +int fdt_finish_reservemap(void *fdt) +{ + return fdt_add_reservemap_entry(fdt, 0, 0); +} + +int fdt_begin_node(void *fdt, const char *name) +{ + struct fdt_node_header *nh; + int namelen = strlen(name) + 1; + + FDT_SW_CHECK_HEADER(fdt); + + nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); + if (! nh) + return -FDT_ERR_NOSPACE; + + nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); + memcpy(nh->name, name, namelen); + return 0; +} + +int fdt_end_node(void *fdt) +{ + fdt32_t *en; + + FDT_SW_CHECK_HEADER(fdt); + + en = _fdt_grab_space(fdt, FDT_TAGSIZE); + if (! en) + return -FDT_ERR_NOSPACE; + + *en = cpu_to_fdt32(FDT_END_NODE); + return 0; +} + +static int _fdt_find_add_string(void *fdt, const char *s) +{ + char *strtab = (char *)fdt + fdt_totalsize(fdt); + const char *p; + int strtabsize = fdt_size_dt_strings(fdt); + int len = strlen(s) + 1; + int struct_top, offset; + + p = _fdt_find_string(strtab - strtabsize, strtabsize, s); + if (p) + return p - strtab; + + /* Add it */ + offset = -strtabsize - len; + struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); + if (fdt_totalsize(fdt) + offset < struct_top) + return 0; /* no more room :( */ + + memcpy(strtab + offset, s, len); + fdt_set_size_dt_strings(fdt, strtabsize + len); + return offset; +} + +int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp) +{ + struct fdt_property *prop; + int nameoff; + + FDT_SW_CHECK_HEADER(fdt); + + nameoff = _fdt_find_add_string(fdt, name); + if (nameoff == 0) + return -FDT_ERR_NOSPACE; + + prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); + if (! prop) + return -FDT_ERR_NOSPACE; + + prop->tag = cpu_to_fdt32(FDT_PROP); + prop->nameoff = cpu_to_fdt32(nameoff); + prop->len = cpu_to_fdt32(len); + *valp = prop->data; + return 0; +} + +int fdt_property(void *fdt, const char *name, const void *val, int len) +{ + void *ptr; + int ret; + + ret = fdt_property_placeholder(fdt, name, len, &ptr); + if (ret) + return ret; + memcpy(ptr, val, len); + return 0; +} + +int fdt_finish(void *fdt) +{ + char *p = (char *)fdt; + fdt32_t *end; + int oldstroffset, newstroffset; + uint32_t tag; + int offset, nextoffset; + + FDT_SW_CHECK_HEADER(fdt); + + /* Add terminator */ + end = _fdt_grab_space(fdt, sizeof(*end)); + if (! end) + return -FDT_ERR_NOSPACE; + *end = cpu_to_fdt32(FDT_END); + + /* Relocate the string table */ + oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt); + newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); + memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt)); + fdt_set_off_dt_strings(fdt, newstroffset); + + /* Walk the structure, correcting string offsets */ + offset = 0; + while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { + if (tag == FDT_PROP) { + struct fdt_property *prop = + _fdt_offset_ptr_w(fdt, offset); + int nameoff; + + nameoff = fdt32_to_cpu(prop->nameoff); + nameoff += fdt_size_dt_strings(fdt); + prop->nameoff = cpu_to_fdt32(nameoff); + } + offset = nextoffset; + } + if (nextoffset < 0) + return nextoffset; + + /* Finally, adjust the header */ + fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); + fdt_set_magic(fdt, FDT_MAGIC); + return 0; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_wip.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_wip.c new file mode 100644 index 00000000..5e859198 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/fdt_wip.c @@ -0,0 +1,139 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library 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; either version 2 of the + * License, or (at your option) any later version. + * + * This library 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 library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, + const char *name, int namelen, + uint32_t idx, const void *val, + int len) +{ + void *propval; + int proplen; + + propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen, + &proplen); + if (!propval) + return proplen; + + if (proplen < (len + idx)) + return -FDT_ERR_NOSPACE; + + memcpy((char *)propval + idx, val, len); + return 0; +} + +int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, + const void *val, int len) +{ + const void *propval; + int proplen; + + propval = fdt_getprop(fdt, nodeoffset, name, &proplen); + if (!propval) + return proplen; + + if (proplen != len) + return -FDT_ERR_NOSPACE; + + return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name, + strlen(name), 0, + val, len); +} + +static void _fdt_nop_region(void *start, int len) +{ + fdt32_t *p; + + for (p = start; (char *)p < ((char *)start + len); p++) + *p = cpu_to_fdt32(FDT_NOP); +} + +int fdt_nop_property(void *fdt, int nodeoffset, const char *name) +{ + struct fdt_property *prop; + int len; + + prop = fdt_get_property_w(fdt, nodeoffset, name, &len); + if (!prop) + return len; + + _fdt_nop_region(prop, len + sizeof(*prop)); + + return 0; +} + +int _fdt_node_end_offset(void *fdt, int offset) +{ + int depth = 0; + + while ((offset >= 0) && (depth >= 0)) + offset = fdt_next_node(fdt, offset, &depth); + + return offset; +} + +int fdt_nop_node(void *fdt, int nodeoffset) +{ + int endoffset; + + endoffset = _fdt_node_end_offset(fdt, nodeoffset); + if (endoffset < 0) + return endoffset; + + _fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0), + endoffset - nodeoffset); + return 0; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/libfdt_internal.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/libfdt_internal.h new file mode 100644 index 00000000..02cfa6fb --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/libfdt_internal.h @@ -0,0 +1,95 @@ +#ifndef _LIBFDT_INTERNAL_H +#define _LIBFDT_INTERNAL_H +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * libfdt is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * + * a) This library 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; either version 2 of the + * License, or (at your option) any later version. + * + * This library 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 library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Alternatively, + * + * b) Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include <fdt.h> + +#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) +#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) + +#define FDT_CHECK_HEADER(fdt) \ + { \ + int __err; \ + if ((__err = fdt_check_header(fdt)) != 0) \ + return __err; \ + } + +int _fdt_check_node_offset(const void *fdt, int offset); +int _fdt_check_prop_offset(const void *fdt, int offset); +const char *_fdt_find_string(const char *strtab, int tabsize, const char *s); +int _fdt_node_end_offset(void *fdt, int nodeoffset); + +static inline const void *_fdt_offset_ptr(const void *fdt, int offset) +{ + return (const char *)fdt + fdt_off_dt_struct(fdt) + offset; +} + +static inline void *_fdt_offset_ptr_w(void *fdt, int offset) +{ + return (void *)(uintptr_t)_fdt_offset_ptr(fdt, offset); +} + +static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n) +{ + const struct fdt_reserve_entry *rsv_table = + (const struct fdt_reserve_entry *) + ((const char *)fdt + fdt_off_mem_rsvmap(fdt)); + + return rsv_table + n; +} +static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n) +{ + return (void *)(uintptr_t)_fdt_mem_rsv(fdt, n); +} + +#define FDT_SW_MAGIC (~FDT_MAGIC) + +#endif /* _LIBFDT_INTERNAL_H */ diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/version.lds b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/version.lds new file mode 100644 index 00000000..1f4e1eab --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/FdtLib/version.lds @@ -0,0 +1,67 @@ +LIBFDT_1.2 { + global: + fdt_next_node; + fdt_check_header; + fdt_move; + fdt_string; + fdt_num_mem_rsv; + fdt_get_mem_rsv; + fdt_subnode_offset_namelen; + fdt_subnode_offset; + fdt_path_offset_namelen; + fdt_path_offset; + fdt_get_name; + fdt_get_property_namelen; + fdt_get_property; + fdt_getprop_namelen; + fdt_getprop; + fdt_get_phandle; + fdt_get_alias_namelen; + fdt_get_alias; + fdt_get_path; + fdt_supernode_atdepth_offset; + fdt_node_depth; + fdt_parent_offset; + fdt_node_offset_by_prop_value; + fdt_node_offset_by_phandle; + fdt_node_check_compatible; + fdt_node_offset_by_compatible; + fdt_setprop_inplace; + fdt_nop_property; + fdt_nop_node; + fdt_create; + fdt_add_reservemap_entry; + fdt_finish_reservemap; + fdt_begin_node; + fdt_property; + fdt_end_node; + fdt_finish; + fdt_open_into; + fdt_pack; + fdt_add_mem_rsv; + fdt_del_mem_rsv; + fdt_set_name; + fdt_setprop; + fdt_delprop; + fdt_add_subnode_namelen; + fdt_add_subnode; + fdt_del_node; + fdt_strerror; + fdt_offset_ptr; + fdt_next_tag; + fdt_appendprop; + fdt_create_empty_tree; + fdt_first_property_offset; + fdt_get_property_by_offset; + fdt_getprop_by_offset; + fdt_next_property_offset; + fdt_first_subnode; + fdt_next_subnode; + fdt_address_cells; + fdt_size_cells; + fdt_stringlist_contains; + fdt_resize; + + local: + *; +}; diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.c new file mode 100644 index 00000000..552c8928 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.c @@ -0,0 +1,181 @@ +/** @file + Basic serial IO abstraction for GDB + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Uefi.h> +#include <Library/GdbSerialLib.h> +#include <Library/PcdLib.h> +#include <Library/IoLib.h> +#include <Library/DebugLib.h> +#include <Library/UefiBootServicesTableLib.h> + +#include <Protocol/DebugPort.h> + + +EFI_DEBUGPORT_PROTOCOL *gDebugPort = NULL; +UINTN gTimeOut = 0; + +/** + The constructor function initializes the UART. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS. + +**/ +RETURN_STATUS +EFIAPI +GdbSerialLibDebugPortConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = gBS->LocateProtocol (&gEfiDebugPortProtocolGuid, NULL, (VOID **)&gDebugPort); + if (!EFI_ERROR (Status)) { + gTimeOut = PcdGet32 (PcdGdbMaxPacketRetryCount); + gDebugPort->Reset (gDebugPort); + } + + return Status; +} + + + +/** + Sets the baud rate, receive FIFO depth, transmit/receive time out, parity, + data buts, and stop bits on a serial device. This call is optional as the serial + port will be set up with defaults base on PCD values. + + @param BaudRate The requested baud rate. A BaudRate value of 0 will use the the + device's default interface speed. + @param Parity The type of parity to use on this serial device. A Parity value of + DefaultParity will use the device's default parity value. + @param DataBits The number of data bits to use on the serial device. A DataBits + value of 0 will use the device's default data bit setting. + @param StopBits The number of stop bits to use on this serial device. A StopBits + value of DefaultStopBits will use the device's default number of + stop bits. + + @retval EFI_SUCCESS The device was configured. + @retval EFI_DEVICE_ERROR The serial device could not be configured. + +**/ +RETURN_STATUS +EFIAPI +GdbSerialInit ( + IN UINT64 BaudRate, + IN UINT8 Parity, + IN UINT8 DataBits, + IN UINT8 StopBits + ) +{ + EFI_STATUS Status; + + Status = gDebugPort->Reset (gDebugPort); + return Status; +} + + +/** + Check to see if a character is available from GDB. Do not read the character as that is + done via GdbGetChar(). + + @return TRUE - Character available + @return FALSE - Character not available + +**/ +BOOLEAN +EFIAPI +GdbIsCharAvailable ( + VOID + ) +{ + EFI_STATUS Status; + + Status = gDebugPort->Poll (gDebugPort); + + return (Status == EFI_SUCCESS ? TRUE : FALSE); +} + + +/** + Get a character from GDB. This function must be able to run in interrupt context. + + @return A character from GDB + +**/ +CHAR8 +EFIAPI +GdbGetChar ( + VOID + ) +{ + EFI_STATUS Status; + CHAR8 Char; + UINTN BufferSize; + + do { + BufferSize = sizeof (Char); + Status = gDebugPort->Read (gDebugPort, gTimeOut, &BufferSize, &Char); + } while (EFI_ERROR (Status) || BufferSize != sizeof (Char)); + + return Char; +} + + +/** + Send a character to GDB. This function must be able to run in interrupt context. + + + @param Char Send a character to GDB + +**/ + +VOID +EFIAPI +GdbPutChar ( + IN CHAR8 Char + ) +{ + EFI_STATUS Status; + UINTN BufferSize; + + do { + BufferSize = sizeof (Char); + Status = gDebugPort->Write (gDebugPort, gTimeOut, &BufferSize, &Char); + } while (EFI_ERROR (Status) || BufferSize != sizeof (Char)); + + return; +} + +/** + Send an ASCII string to GDB. This function must be able to run in interrupt context. + + + @param String Send a string to GDB + +**/ + +VOID +GdbPutString ( + IN CHAR8 *String + ) +{ + // We could performance enhance this function by calling gDebugPort->Write () + while (*String != '\0') { + GdbPutChar (*String); + String++; + } +} + + + + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.inf new file mode 100644 index 00000000..ab647e20 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/GdbSerialDebugPortLib/GdbSerialDebugPortLib.inf @@ -0,0 +1,44 @@ +#/** @file +# Component description file for Base PCI Cf8 Library. +# +# PCI CF8 Library that uses I/O ports 0xCF8 and 0xCFC to perform PCI Configuration cycles. +# Layers on top of an I/O Library instance. +# Copyright (c) 2007, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = GdbSerialDebugPortLib + FILE_GUID = 42ABB10A-660A-4BEC-AEFA-CC94AB4D993D + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = GdbSerialLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION UEFI_DRIVER + + CONSTRUCTOR = GdbSerialLibDebugPortConstructor + + +[Sources.common] + GdbSerialDebugPortLib.c + + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + DebugLib + IoLib + +[Protocols.common] + gEfiDebugPortProtocolGuid + +[FixedPcd.common] + gEmbeddedTokenSpaceGuid.PcdGdbBaudRate|115200 + gEmbeddedTokenSpaceGuid.PcdGdbDataBits|8 + gEmbeddedTokenSpaceGuid.PcdGdbParity|1 + gEmbeddedTokenSpaceGuid.PcdGdbStopBits|1 + gEmbeddedTokenSpaceGuid.PcdGdbMaxPacketRetryCount diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.c new file mode 100644 index 00000000..b788b769 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.c @@ -0,0 +1,256 @@ +/** @file + Basic serial IO abstraction for GDB + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Uefi.h> +#include <Library/GdbSerialLib.h> +#include <Library/PcdLib.h> +#include <Library/IoLib.h> +#include <Library/DebugLib.h> + + +//--------------------------------------------- +// UART Register Offsets +//--------------------------------------------- +#define BAUD_LOW_OFFSET 0x00 +#define BAUD_HIGH_OFFSET 0x01 +#define IER_OFFSET 0x01 +#define LCR_SHADOW_OFFSET 0x01 +#define FCR_SHADOW_OFFSET 0x02 +#define IR_CONTROL_OFFSET 0x02 +#define FCR_OFFSET 0x02 +#define EIR_OFFSET 0x02 +#define BSR_OFFSET 0x03 +#define LCR_OFFSET 0x03 +#define MCR_OFFSET 0x04 +#define LSR_OFFSET 0x05 +#define MSR_OFFSET 0x06 + +//--------------------------------------------- +// UART Register Bit Defines +//--------------------------------------------- +#define LSR_TXRDY 0x20U +#define LSR_RXDA 0x01U +#define DLAB 0x01U +#define ENABLE_FIFO 0x01U +#define CLEAR_FIFOS 0x06U + + + +// IO Port Base for the UART +UINTN gPort; + + +/** + The constructor function initializes the UART. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS. + +**/ +RETURN_STATUS +EFIAPI +GdbSerialLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + UINT64 BaudRate; + UINT8 DataBits; + UINT8 Parity; + UINT8 StopBits; + + gPort = (UINTN)PcdGet32 (PcdGdbUartPort); + + BaudRate = PcdGet64 (PcdGdbBaudRate); + Parity = PcdGet8 (PcdGdbParity); + DataBits = PcdGet8 (PcdGdbDataBits); + StopBits = PcdGet8 (PcdGdbStopBits); + + return GdbSerialInit (BaudRate, Parity, DataBits, StopBits); +} + + + +/** + Sets the baud rate, receive FIFO depth, transmit/receive time out, parity, + data buts, and stop bits on a serial device. This call is optional as the serial + port will be set up with defaults base on PCD values. + + @param BaudRate The requested baud rate. A BaudRate value of 0 will use the the + device's default interface speed. + @param Parity The type of parity to use on this serial device. A Parity value of + DefaultParity will use the device's default parity value. + @param DataBits The number of data bits to use on the serial device. A DataBits + value of 0 will use the device's default data bit setting. + @param StopBits The number of stop bits to use on this serial device. A StopBits + value of DefaultStopBits will use the device's default number of + stop bits. + + @retval EFI_SUCCESS The device was configured. + @retval EFI_DEVICE_ERROR The serial device could not be configured. + +**/ +RETURN_STATUS +EFIAPI +GdbSerialInit ( + IN UINT64 BaudRate, + IN UINT8 Parity, + IN UINT8 DataBits, + IN UINT8 StopBits + ) +{ + UINTN Divisor; + UINT8 OutputData; + UINT8 Data; + UINT8 BreakSet = 0; + + // + // We assume the UART has been turned on to decode gPort address range + // + + // + // Map 5..8 to 0..3 + // + Data = (UINT8) (DataBits - (UINT8)5); + + // + // Calculate divisor for baud generator + // + Divisor = 115200/(UINTN)BaudRate; + + // + // Set communications format + // + OutputData = (UINT8)((DLAB << 7) | ((BreakSet << 6) | ((Parity << 3) | ((StopBits << 2) | Data)))); + IoWrite8 (gPort + LCR_OFFSET, OutputData); + + // + // Configure baud rate + // + IoWrite8 (gPort + BAUD_HIGH_OFFSET, (UINT8)(Divisor >> 8)); + IoWrite8 (gPort + BAUD_LOW_OFFSET, (UINT8)(Divisor & 0xff)); + + + // + // Switch back to bank 0 + // + OutputData = (UINT8)((~DLAB<<7)|((BreakSet<<6)|((Parity<<3)|((StopBits<<2)| Data)))); + IoWrite8 (gPort + LCR_OFFSET, OutputData); + + // Not sure this is the right place to enable the FIFOs.... + // We probably need the FIFO enabled to not drop input + IoWrite8 (gPort + FCR_SHADOW_OFFSET, ENABLE_FIFO); + + + // Configure the UART hardware here + return RETURN_SUCCESS; +} + + +/** + Check to see if a character is available from GDB. Do not read the character as that is + done via GdbGetChar(). + + @return TRUE - Character available + @return FALSE - Character not available + +**/ +BOOLEAN +EFIAPI +GdbIsCharAvailable ( + VOID + ) +{ + UINT8 Data; + + Data = IoRead8 (gPort + LSR_OFFSET); + + return ((Data & LSR_RXDA) == LSR_RXDA); +} + + +/** + Get a character from GDB. This function must be able to run in interrupt context. + + @return A character from GDB + +**/ +CHAR8 +EFIAPI +GdbGetChar ( + VOID + ) +{ + UINT8 Data; + CHAR8 Char; + + // Wait for the serial port to be ready + do { + Data = IoRead8 (gPort + LSR_OFFSET); + } while ((Data & LSR_RXDA) == 0); + + Char = IoRead8 (gPort); + + // Make this an EFI_D_INFO after we get everything debugged. + DEBUG ((EFI_D_ERROR, "<%c<", Char)); + return Char; +} + + +/** + Send a character to GDB. This function must be able to run in interrupt context. + + + @param Char Send a character to GDB + +**/ + +VOID +EFIAPI +GdbPutChar ( + IN CHAR8 Char + ) +{ + UINT8 Data; + + // Make this an EFI_D_INFO after we get everything debugged. + DEBUG ((EFI_D_ERROR, ">%c>", Char)); + + // Wait for the serial port to be ready + do { + Data = IoRead8 (gPort + LSR_OFFSET); + } while ((Data & LSR_TXRDY) == 0); + + IoWrite8 (gPort, Char); +} + +/** + Send an ASCII string to GDB. This function must be able to run in interrupt context. + + + @param String Send a string to GDB + +**/ + +VOID +GdbPutString ( + IN CHAR8 *String + ) +{ + while (*String != '\0') { + GdbPutChar (*String); + String++; + } +} + + + + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.inf new file mode 100644 index 00000000..4ae9f4d5 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/GdbSerialLib/GdbSerialLib.inf @@ -0,0 +1,41 @@ +#/** @file +# Component description file for Base PCI Cf8 Library. +# +# PCI CF8 Library that uses I/O ports 0xCF8 and 0xCFC to perform PCI Configuration cycles. +# Layers on top of an I/O Library instance. +# Copyright (c) 2007, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = GdbSerialLib + FILE_GUID = 9999B4EE-081F-4501-AEDC-137A534BAF69 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = GdbSerialLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION UEFI_DRIVER + + CONSTRUCTOR = GdbSerialLibConstructor + + +[Sources.common] + GdbSerialLib.c + + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + DebugLib + IoLib + +[FixedPcd.common] + gEmbeddedTokenSpaceGuid.PcdGdbBaudRate|115200 + gEmbeddedTokenSpaceGuid.PcdGdbDataBits|8 + gEmbeddedTokenSpaceGuid.PcdGdbParity|1 + gEmbeddedTokenSpaceGuid.PcdGdbStopBits|1 + gEmbeddedTokenSpaceGuid.PcdGdbUartPort diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.c new file mode 100644 index 00000000..bd9cab9f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.c @@ -0,0 +1,624 @@ +/** @file + + Generic non-coherent implementation of DmaLib.h + + Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR> + Copyright (c) 2015 - 2017, Linaro, Ltd. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiDxe.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/DmaLib.h> +#include <Library/DxeServicesTableLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/IoLib.h> +#include <Library/BaseMemoryLib.h> + +#include <Protocol/Cpu.h> + +typedef struct { + EFI_PHYSICAL_ADDRESS HostAddress; + VOID *BufferAddress; + UINTN NumberOfBytes; + DMA_MAP_OPERATION Operation; + BOOLEAN DoubleBuffer; +} MAP_INFO_INSTANCE; + + +typedef struct { + LIST_ENTRY Link; + VOID *HostAddress; + UINTN NumPages; + UINT64 Attributes; +} UNCACHED_ALLOCATION; + +STATIC EFI_CPU_ARCH_PROTOCOL *mCpu; +STATIC LIST_ENTRY UncachedAllocationList; + +STATIC PHYSICAL_ADDRESS mDmaHostAddressLimit; + +STATIC +PHYSICAL_ADDRESS +HostToDeviceAddress ( + IN VOID *Address + ) +{ + return (PHYSICAL_ADDRESS)(UINTN)Address + PcdGet64 (PcdDmaDeviceOffset); +} + +/** + Allocates one or more 4KB pages of a certain memory type at a specified + alignment. + + Allocates the number of 4KB pages specified by Pages of a certain memory type + with an alignment specified by Alignment. The allocated buffer is returned. + If Pages is 0, then NULL is returned. If there is not enough memory at the + specified alignment remaining to satisfy the request, then NULL is returned. + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT(). + + @param MemoryType The type of memory to allocate. + @param Pages The number of 4 KB pages to allocate. + @param Alignment The requested alignment of the allocation. + Must be a power of two. + If Alignment is zero, then byte alignment is + used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +STATIC +VOID * +InternalAllocateAlignedPages ( + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN UINTN Alignment + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS Memory; + UINTN AlignedMemory; + UINTN AlignmentMask; + UINTN UnalignedPages; + UINTN RealPages; + + // + // Alignment must be a power of two or zero. + // + ASSERT ((Alignment & (Alignment - 1)) == 0); + + if (Pages == 0) { + return NULL; + } + if (Alignment > EFI_PAGE_SIZE) { + // + // Calculate the total number of pages since alignment is larger than page + // size. + // + AlignmentMask = Alignment - 1; + RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment); + // + // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not + // overflow. + // + ASSERT (RealPages > Pages); + + Memory = mDmaHostAddressLimit; + Status = gBS->AllocatePages (AllocateMaxAddress, MemoryType, RealPages, + &Memory); + if (EFI_ERROR (Status)) { + return NULL; + } + AlignedMemory = ((UINTN)Memory + AlignmentMask) & ~AlignmentMask; + UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN)Memory); + if (UnalignedPages > 0) { + // + // Free first unaligned page(s). + // + Status = gBS->FreePages (Memory, UnalignedPages); + ASSERT_EFI_ERROR (Status); + } + Memory = AlignedMemory + EFI_PAGES_TO_SIZE (Pages); + UnalignedPages = RealPages - Pages - UnalignedPages; + if (UnalignedPages > 0) { + // + // Free last unaligned page(s). + // + Status = gBS->FreePages (Memory, UnalignedPages); + ASSERT_EFI_ERROR (Status); + } + } else { + // + // Do not over-allocate pages in this case. + // + Memory = mDmaHostAddressLimit; + Status = gBS->AllocatePages (AllocateMaxAddress, MemoryType, Pages, + &Memory); + if (EFI_ERROR (Status)) { + return NULL; + } + AlignedMemory = (UINTN)Memory; + } + return (VOID *)AlignedMemory; +} + +/** + Provides the DMA controller-specific addresses needed to access system memory. + + Operation is relative to the DMA bus master. + + @param Operation Indicates if the bus master is going to read or + write to system memory. + @param HostAddress The system memory address to map to the DMA + controller. + @param NumberOfBytes On input the number of bytes to map. On output + the number of bytes that were mapped. + @param DeviceAddress The resulting map address for the bus master + controller to use to access the host's + HostAddress. + @param Mapping A resulting value to pass to Unmap(). + + @retval EFI_SUCCESS The range was mapped for the returned + NumberOfBytes. + @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common + buffer. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack + of resources. + @retval EFI_DEVICE_ERROR The system hardware could not map the requested + address. + +**/ +EFI_STATUS +EFIAPI +DmaMap ( + IN DMA_MAP_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) +{ + EFI_STATUS Status; + MAP_INFO_INSTANCE *Map; + VOID *Buffer; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor; + UINTN AllocSize; + + if (HostAddress == NULL || + NumberOfBytes == NULL || + DeviceAddress == NULL || + Mapping == NULL ) { + return EFI_INVALID_PARAMETER; + } + + if (Operation >= MapOperationMaximum) { + return EFI_INVALID_PARAMETER; + } + + *DeviceAddress = HostToDeviceAddress (HostAddress); + + // Remember range so we can flush on the other side + Map = AllocatePool (sizeof (MAP_INFO_INSTANCE)); + if (Map == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (((UINTN)HostAddress + *NumberOfBytes) > mDmaHostAddressLimit) { + + if (Operation == MapOperationBusMasterCommonBuffer) { + goto CommonBufferError; + } + + AllocSize = ALIGN_VALUE (*NumberOfBytes, mCpu->DmaBufferAlignment); + Map->BufferAddress = InternalAllocateAlignedPages (EfiBootServicesData, + EFI_SIZE_TO_PAGES (AllocSize), + mCpu->DmaBufferAlignment); + if (Map->BufferAddress == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto FreeMapInfo; + } + + if (Map->Operation == MapOperationBusMasterRead) { + CopyMem (Map->BufferAddress, (VOID *)(UINTN)HostAddress, *NumberOfBytes); + } + mCpu->FlushDataCache (mCpu, (UINTN)Map->BufferAddress, AllocSize, + EfiCpuFlushTypeWriteBack); + + *DeviceAddress = HostToDeviceAddress (Map->BufferAddress); + } else if (Operation != MapOperationBusMasterRead && + ((((UINTN)HostAddress & (mCpu->DmaBufferAlignment - 1)) != 0) || + ((*NumberOfBytes & (mCpu->DmaBufferAlignment - 1)) != 0))) { + + // Get the cacheability of the region + Status = gDS->GetMemorySpaceDescriptor ((UINTN)HostAddress, &GcdDescriptor); + if (EFI_ERROR(Status)) { + goto FreeMapInfo; + } + + // If the mapped buffer is not an uncached buffer + if ((GcdDescriptor.Attributes & (EFI_MEMORY_WB | EFI_MEMORY_WT)) != 0) { + // + // Operations of type MapOperationBusMasterCommonBuffer are only allowed + // on uncached buffers. + // + if (Operation == MapOperationBusMasterCommonBuffer) { + goto CommonBufferError; + } + + // + // If the buffer does not fill entire cache lines we must double buffer + // into a suitably aligned allocation that allows us to invalidate the + // cache without running the risk of corrupting adjacent unrelated data. + // Note that pool allocations are guaranteed to be 8 byte aligned, so + // we only have to add (alignment - 8) worth of padding. + // + Map->DoubleBuffer = TRUE; + AllocSize = ALIGN_VALUE (*NumberOfBytes, mCpu->DmaBufferAlignment) + + (mCpu->DmaBufferAlignment - 8); + Map->BufferAddress = AllocatePool (AllocSize); + if (Map->BufferAddress == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto FreeMapInfo; + } + + Buffer = ALIGN_POINTER (Map->BufferAddress, mCpu->DmaBufferAlignment); + *DeviceAddress = HostToDeviceAddress (Buffer); + + // + // Get rid of any dirty cachelines covering the double buffer. This + // prevents them from being written back unexpectedly, potentially + // overwriting the data we receive from the device. + // + mCpu->FlushDataCache (mCpu, (UINTN)Buffer, *NumberOfBytes, + EfiCpuFlushTypeWriteBack); + } else { + Map->DoubleBuffer = FALSE; + } + } else { + Map->DoubleBuffer = FALSE; + + DEBUG_CODE_BEGIN (); + + // + // The operation type check above only executes if the buffer happens to be + // misaligned with respect to CWG, but even if it is aligned, we should not + // allow arbitrary buffers to be used for creating consistent mappings. + // So duplicate the check here when running in DEBUG mode, just to assert + // that we are not trying to create a consistent mapping for cached memory. + // + Status = gDS->GetMemorySpaceDescriptor ((UINTN)HostAddress, &GcdDescriptor); + ASSERT_EFI_ERROR(Status); + + ASSERT (Operation != MapOperationBusMasterCommonBuffer || + (GcdDescriptor.Attributes & (EFI_MEMORY_WB | EFI_MEMORY_WT)) == 0); + + DEBUG_CODE_END (); + + // Flush the Data Cache (should not have any effect if the memory region is + // uncached) + mCpu->FlushDataCache (mCpu, (UINTN)HostAddress, *NumberOfBytes, + EfiCpuFlushTypeWriteBackInvalidate); + } + + Map->HostAddress = (UINTN)HostAddress; + Map->NumberOfBytes = *NumberOfBytes; + Map->Operation = Operation; + + *Mapping = Map; + + return EFI_SUCCESS; + +CommonBufferError: + DEBUG ((DEBUG_ERROR, + "%a: Operation type 'MapOperationBusMasterCommonBuffer' is only " + "supported\non memory regions that were allocated using " + "DmaAllocateBuffer ()\n", __FUNCTION__)); + Status = EFI_UNSUPPORTED; +FreeMapInfo: + FreePool (Map); + + return Status; +} + + +/** + Completes the DmaMapBusMasterRead(), DmaMapBusMasterWrite(), or + DmaMapBusMasterCommonBuffer() operation and releases any corresponding + resources. + + @param Mapping The mapping value returned from DmaMap*(). + + @retval EFI_SUCCESS The range was unmapped. + @retval EFI_DEVICE_ERROR The data was not committed to the target system + memory. + @retval EFI_INVALID_PARAMETER An inconsistency was detected between the + mapping type and the DoubleBuffer field + +**/ +EFI_STATUS +EFIAPI +DmaUnmap ( + IN VOID *Mapping + ) +{ + MAP_INFO_INSTANCE *Map; + EFI_STATUS Status; + VOID *Buffer; + UINTN AllocSize; + + if (Mapping == NULL) { + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + Map = (MAP_INFO_INSTANCE *)Mapping; + + Status = EFI_SUCCESS; + if (((UINTN)Map->HostAddress + Map->NumberOfBytes) > mDmaHostAddressLimit) { + AllocSize = ALIGN_VALUE (Map->NumberOfBytes, mCpu->DmaBufferAlignment); + if (Map->Operation == MapOperationBusMasterWrite) { + mCpu->FlushDataCache (mCpu, (UINTN)Map->BufferAddress, AllocSize, + EfiCpuFlushTypeInvalidate); + CopyMem ((VOID *)(UINTN)Map->HostAddress, Map->BufferAddress, + Map->NumberOfBytes); + } + FreePages (Map->BufferAddress, EFI_SIZE_TO_PAGES (AllocSize)); + } else if (Map->DoubleBuffer) { + + ASSERT (Map->Operation == MapOperationBusMasterWrite); + + if (Map->Operation != MapOperationBusMasterWrite) { + Status = EFI_INVALID_PARAMETER; + } else { + Buffer = ALIGN_POINTER (Map->BufferAddress, mCpu->DmaBufferAlignment); + + mCpu->FlushDataCache (mCpu, (UINTN)Buffer, Map->NumberOfBytes, + EfiCpuFlushTypeInvalidate); + + CopyMem ((VOID *)(UINTN)Map->HostAddress, Buffer, Map->NumberOfBytes); + + FreePool (Map->BufferAddress); + } + } else { + if (Map->Operation == MapOperationBusMasterWrite) { + // + // Make sure we read buffer from uncached memory and not the cache + // + mCpu->FlushDataCache (mCpu, Map->HostAddress, Map->NumberOfBytes, + EfiCpuFlushTypeInvalidate); + } + } + + FreePool (Map); + + return Status; +} + +/** + Allocates pages that are suitable for an DmaMap() of type + MapOperationBusMasterCommonBuffer mapping. + + @param MemoryType The type of memory to allocate, + EfiBootServicesData or EfiRuntimeServicesData. + @param Pages The number of pages to allocate. + @param HostAddress A pointer to store the base system memory + address of the allocated range. + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +EFI_STATUS +EFIAPI +DmaAllocateBuffer ( + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress + ) +{ + return DmaAllocateAlignedBuffer (MemoryType, Pages, 0, HostAddress); +} + +/** + Allocates pages that are suitable for an DmaMap() of type + MapOperationBusMasterCommonBuffer mapping, at the requested alignment. + + @param MemoryType The type of memory to allocate, + EfiBootServicesData or EfiRuntimeServicesData. + @param Pages The number of pages to allocate. + @param Alignment Alignment in bytes of the base of the returned + buffer (must be a power of 2) + @param HostAddress A pointer to store the base system memory + address of the allocated range. + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +EFI_STATUS +EFIAPI +DmaAllocateAlignedBuffer ( + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN UINTN Alignment, + OUT VOID **HostAddress + ) +{ + EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor; + VOID *Allocation; + UINT64 MemType; + UNCACHED_ALLOCATION *Alloc; + EFI_STATUS Status; + + if (Alignment == 0) { + Alignment = EFI_PAGE_SIZE; + } + + if (HostAddress == NULL || + (Alignment & (Alignment - 1)) != 0) { + return EFI_INVALID_PARAMETER; + } + + if (MemoryType == EfiBootServicesData || + MemoryType == EfiRuntimeServicesData) { + Allocation = InternalAllocateAlignedPages (MemoryType, Pages, Alignment); + } else { + return EFI_INVALID_PARAMETER; + } + + if (Allocation == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // Get the cacheability of the region + Status = gDS->GetMemorySpaceDescriptor ((UINTN)Allocation, &GcdDescriptor); + if (EFI_ERROR(Status)) { + goto FreeBuffer; + } + + // Choose a suitable uncached memory type that is supported by the region + if (GcdDescriptor.Capabilities & EFI_MEMORY_WC) { + MemType = EFI_MEMORY_WC; + } else if (GcdDescriptor.Capabilities & EFI_MEMORY_UC) { + MemType = EFI_MEMORY_UC; + } else { + Status = EFI_UNSUPPORTED; + goto FreeBuffer; + } + + Alloc = AllocatePool (sizeof *Alloc); + if (Alloc == NULL) { + goto FreeBuffer; + } + + Alloc->HostAddress = Allocation; + Alloc->NumPages = Pages; + Alloc->Attributes = GcdDescriptor.Attributes; + + InsertHeadList (&UncachedAllocationList, &Alloc->Link); + + // Remap the region with the new attributes + Status = gDS->SetMemorySpaceAttributes ((PHYSICAL_ADDRESS)(UINTN)Allocation, + EFI_PAGES_TO_SIZE (Pages), + MemType); + if (EFI_ERROR (Status)) { + goto FreeAlloc; + } + + Status = mCpu->FlushDataCache (mCpu, + (PHYSICAL_ADDRESS)(UINTN)Allocation, + EFI_PAGES_TO_SIZE (Pages), + EfiCpuFlushTypeInvalidate); + if (EFI_ERROR (Status)) { + goto FreeAlloc; + } + + *HostAddress = Allocation; + + return EFI_SUCCESS; + +FreeAlloc: + RemoveEntryList (&Alloc->Link); + FreePool (Alloc); + +FreeBuffer: + FreePages (Allocation, Pages); + return Status; +} + + +/** + Frees memory that was allocated with DmaAllocateBuffer(). + + @param Pages The number of pages to free. + @param HostAddress The base system memory address of the allocated + range. + + @retval EFI_SUCCESS The requested memory pages were freed. + @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and + Pages was not allocated with + DmaAllocateBuffer(). + +**/ +EFI_STATUS +EFIAPI +DmaFreeBuffer ( + IN UINTN Pages, + IN VOID *HostAddress + ) +{ + LIST_ENTRY *Link; + UNCACHED_ALLOCATION *Alloc; + BOOLEAN Found; + EFI_STATUS Status; + + if (HostAddress == NULL) { + return EFI_INVALID_PARAMETER; + } + + for (Link = GetFirstNode (&UncachedAllocationList), Found = FALSE; + !IsNull (&UncachedAllocationList, Link); + Link = GetNextNode (&UncachedAllocationList, Link)) { + + Alloc = BASE_CR (Link, UNCACHED_ALLOCATION, Link); + if (Alloc->HostAddress == HostAddress && Alloc->NumPages == Pages) { + Found = TRUE; + break; + } + } + + if (!Found) { + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + RemoveEntryList (&Alloc->Link); + + Status = gDS->SetMemorySpaceAttributes ((PHYSICAL_ADDRESS)(UINTN)HostAddress, + EFI_PAGES_TO_SIZE (Pages), + Alloc->Attributes); + if (EFI_ERROR (Status)) { + goto FreeAlloc; + } + + // + // If we fail to restore the original attributes, it is better to leak the + // memory than to return it to the heap + // + FreePages (HostAddress, Pages); + +FreeAlloc: + FreePool (Alloc); + return Status; +} + + +EFI_STATUS +EFIAPI +NonCoherentDmaLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + InitializeListHead (&UncachedAllocationList); + + // + // Ensure that the combination of DMA addressing offset and limit produces + // a sane value. + // + ASSERT (PcdGet64 (PcdDmaDeviceLimit) > PcdGet64 (PcdDmaDeviceOffset)); + + mDmaHostAddressLimit = PcdGet64 (PcdDmaDeviceLimit) - + PcdGet64 (PcdDmaDeviceOffset); + + // Get the Cpu protocol for later use + return gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&mCpu); +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.inf new file mode 100644 index 00000000..56491c3f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.inf @@ -0,0 +1,44 @@ +#/** @file +# +# Generic non-coherent implementation of DmaLib.h +# +# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR> +# Copyright (c) 2015 - 2017, Linaro, Ltd. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = NonCoherentDmaLib + FILE_GUID = 43ad4920-db15-4e24-9889-2db568431fbd + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = DmaLib + CONSTRUCTOR = NonCoherentDmaLibConstructor + +[Sources] + NonCoherentDmaLib.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseMemoryLib + DebugLib + DxeServicesTableLib + IoLib + MemoryAllocationLib + UefiBootServicesTableLib + +[Protocols] + gEfiCpuArchProtocolGuid + +[Pcd] + gEmbeddedTokenSpaceGuid.PcdDmaDeviceOffset + gEmbeddedTokenSpaceGuid.PcdDmaDeviceLimit + +[Depex] + gEfiCpuArchProtocolGuid diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NorFlashInfoLib/NorFlashInfoLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NorFlashInfoLib/NorFlashInfoLib.c new file mode 100644 index 00000000..9763323a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NorFlashInfoLib/NorFlashInfoLib.c @@ -0,0 +1,220 @@ +/** @file +* +* Copyright (c) 2017 Marvell International Ltd. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#include <PiDxe.h> + +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/DxeServicesLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/NorFlashInfoLib.h> + +STATIC CONST NOR_FLASH_INFO NorFlashIds[] = { + /* ATMEL */ + {L"at45db011d", {0x1f, 0x22, 0x00}, 3, 256, 64 * 1024, 4, NOR_FLASH_ERASE_4K}, + {L"at45db021d", {0x1f, 0x23, 0x00}, 3, 256, 64 * 1024, 8, NOR_FLASH_ERASE_4K}, + {L"at45db041d", {0x1f, 0x24, 0x00}, 3, 256, 64 * 1024, 8, NOR_FLASH_ERASE_4K}, + {L"at45db081d", {0x1f, 0x25, 0x00}, 3, 256, 64 * 1024, 16, NOR_FLASH_ERASE_4K}, + {L"at45db161d", {0x1f, 0x26, 0x00}, 3, 256, 64 * 1024, 32, NOR_FLASH_ERASE_4K}, + {L"at45db321d", {0x1f, 0x27, 0x00}, 3, 256, 64 * 1024, 64, NOR_FLASH_ERASE_4K}, + {L"at45db641d", {0x1f, 0x28, 0x00}, 3, 256, 64 * 1024, 128, NOR_FLASH_ERASE_4K}, + {L"at25df321a", {0x1f, 0x47, 0x01}, 3, 256, 64 * 1024, 64, NOR_FLASH_ERASE_4K}, + {L"at25df321", {0x1f, 0x47, 0x00}, 3, 256, 64 * 1024, 64, NOR_FLASH_ERASE_4K}, + {L"at26df081a", {0x1f, 0x45, 0x01}, 3, 256, 64 * 1024, 16, NOR_FLASH_ERASE_4K}, + /* EON */ + {L"en25q32b", {0x1c, 0x30, 0x16}, 3, 256, 64 * 1024, 64, 0}, + {L"en25q64", {0x1c, 0x30, 0x17}, 3, 256, 64 * 1024, 128, NOR_FLASH_ERASE_4K}, + {L"en25q128b", {0x1c, 0x30, 0x18}, 3, 256, 64 * 1024, 256, 0}, + {L"en25s64", {0x1c, 0x38, 0x17}, 3, 256, 64 * 1024, 128, 0}, + /* GIGADEVICE */ + {L"gd25q64b", {0xc8, 0x40, 0x17}, 3, 256, 64 * 1024, 128, NOR_FLASH_ERASE_4K}, + {L"gd25lq32", {0xc8, 0x60, 0x16}, 3, 256, 64 * 1024, 64, NOR_FLASH_ERASE_4K}, + /* ISSI */ + {L"is25lp032", {0x9d, 0x60, 0x16}, 3, 256, 64 * 1024, 64, 0}, + {L"is25lp064", {0x9d, 0x60, 0x17}, 3, 256, 64 * 1024, 128, 0}, + {L"is25lp128", {0x9d, 0x60, 0x18}, 3, 256, 64 * 1024, 256, 0}, + /* MACRONIX */ + {L"mx25l2006e", {0xc2, 0x20, 0x12}, 3, 256, 64 * 1024, 4, 0}, + {L"mx25l4005", {0xc2, 0x20, 0x13}, 3, 256, 64 * 1024, 8, 0}, + {L"mx25l8005", {0xc2, 0x20, 0x14}, 3, 256, 64 * 1024, 16, 0}, + {L"mx25l1605d", {0xc2, 0x20, 0x15}, 3, 256, 64 * 1024, 32, 0}, + {L"mx25l3205d", {0xc2, 0x20, 0x16}, 3, 256, 64 * 1024, 64, 0}, + {L"mx25l6405d", {0xc2, 0x20, 0x17}, 3, 256, 64 * 1024, 128, 0}, + {L"mx25l12805", {0xc2, 0x20, 0x18}, 3, 256, 64 * 1024, 256, 0}, + {L"mx25l25635f", {0xc2, 0x20, 0x19}, 3, 256, 64 * 1024, 512, 0}, + {L"mx25l51235f", {0xc2, 0x20, 0x1a}, 3, 256, 64 * 1024, 1024, 0}, + {L"mx25l12855e", {0xc2, 0x26, 0x18}, 3, 256, 64 * 1024, 256, 0}, + {L"mx66u51235f", {0xc2, 0x25, 0x3a}, 3, 256, 64 * 1024, 1024, 0}, + {L"mx66u1g45g", {0xc2, 0x25, 0x3b}, 3, 256, 64 * 1024, 2048, 0}, + {L"mx66l1g45g", {0xc2, 0x20, 0x1b}, 3, 256, 64 * 1024, 2048, 0}, + /* SPANSION */ + {L"s25fl008a", {0x01, 0x02, 0x13}, 3, 256, 64 * 1024, 16, 0}, + {L"s25fl016a", {0x01, 0x02, 0x14}, 3, 256, 64 * 1024, 32, 0}, + {L"s25fl032a", {0x01, 0x02, 0x15}, 3, 256, 64 * 1024, 64, 0}, + {L"s25fl064a", {0x01, 0x02, 0x16}, 3, 256, 64 * 1024, 128, 0}, + {L"s25fl116k", {0x01, 0x40, 0x15}, 3, 256, 64 * 1024, 128, 0}, + {L"s25fl164k", {0x01, 0x40, 0x17, 0x01, 0x40}, 5, 256, 64 * 1024, 128, 0}, + {L"s25fl128p_256k", {0x01, 0x20, 0x18, 0x03, 0x00}, 5, 256, 256 * 1024, 64, 0}, + {L"s25fl128p_64k", {0x01, 0x20, 0x18, 0x03, 0x01}, 5, 256, 64 * 1024, 256, 0}, + {L"s25fl032p", {0x01, 0x02, 0x15, 0x4d, 0x00}, 5, 256, 64 * 1024, 64, 0}, + {L"s25fl064p", {0x01, 0x02, 0x16, 0x4d, 0x00}, 5, 256, 64 * 1024, 128, 0}, + {L"s25fl128s_256k", {0x01, 0x20, 0x18, 0x4d, 0x00}, 5, 256, 256 * 1024, 64, 0}, + {L"s25fl128s_64k", {0x01, 0x20, 0x18, 0x4d, 0x01}, 5, 256, 64 * 1024, 256, 0}, + {L"s25fl256s_256k", {0x01, 0x02, 0x19, 0x4d, 0x00}, 5, 256, 256 * 1024, 128, 0}, + {L"s25fl256s_64k", {0x01, 0x02, 0x19, 0x4d, 0x01}, 5, 256, 64 * 1024, 512, 0}, + {L"s25fl512s_256k", {0x01, 0x02, 0x20, 0x4d, 0x00}, 5, 256, 256 * 1024, 256, 0}, + {L"s25fl512s_64k", {0x01, 0x02, 0x20, 0x4d, 0x01}, 5, 256, 64 * 1024, 1024, 0}, + {L"s25fl512s_512k", {0x01, 0x02, 0x20, 0x4f, 0x00}, 5, 256, 256 * 1024, 256, 0}, + /* STMICRO */ + {L"m25p10", {0x20, 0x20, 0x11}, 3, 256, 32 * 1024, 4, 0}, + {L"m25p20", {0x20, 0x20, 0x12}, 3, 256, 64 * 1024, 4, 0}, + {L"m25p40", {0x20, 0x20, 0x13}, 3, 256, 64 * 1024, 8, 0}, + {L"m25p80", {0x20, 0x20, 0x14}, 3, 256, 64 * 1024, 16, 0}, + {L"m25p16", {0x20, 0x20, 0x15}, 3, 256, 64 * 1024, 32, 0}, + {L"m25pE16", {0x20, 0x80, 0x15, 0x10, 0x00}, 5, 256, 64 * 1024, 32, 0}, + {L"m25pX16", {0x20, 0x71, 0x15, 0x10, 0x00}, 5, 256, 64 * 1024, 32, 0}, + {L"m25p32", {0x20, 0x20, 0x16}, 3, 256, 64 * 1024, 64, 0}, + {L"m25p64", {0x20, 0x20, 0x17}, 3, 256, 64 * 1024, 128, 0}, + {L"m25p128", {0x20, 0x20, 0x18}, 3, 256, 256 * 1024, 64, 0}, + {L"m25pX64", {0x20, 0x71, 0x17}, 3, 256, 64 * 1024, 128, NOR_FLASH_ERASE_4K}, + {L"n25q016a", {0x20, 0xbb, 0x15}, 3, 256, 64 * 1024, 32, NOR_FLASH_ERASE_4K}, + {L"n25q32", {0x20, 0xba, 0x16}, 3, 256, 64 * 1024, 64, NOR_FLASH_ERASE_4K}, + {L"n25q32a", {0x20, 0xbb, 0x16}, 3, 256, 64 * 1024, 64, NOR_FLASH_ERASE_4K}, + {L"n25q64", {0x20, 0xba, 0x17}, 3, 256, 64 * 1024, 128, NOR_FLASH_ERASE_4K}, + {L"n25q64a", {0x20, 0xbb, 0x17}, 3, 256, 64 * 1024, 128, NOR_FLASH_ERASE_4K}, + {L"n25q128", {0x20, 0xba, 0x18}, 3, 256, 64 * 1024, 256, 0}, + {L"n25q128a", {0x20, 0xbb, 0x18}, 3, 256, 64 * 1024, 256, 0}, + {L"n25q256", {0x20, 0xba, 0x19}, 3, 256, 64 * 1024, 512, NOR_FLASH_ERASE_4K}, + {L"n25q256a", {0x20, 0xbb, 0x19}, 3, 256, 64 * 1024, 512, NOR_FLASH_ERASE_4K}, + {L"n25q512", {0x20, 0xba, 0x20}, 3, 256, 64 * 1024, 1024, NOR_FLASH_WRITE_FSR | NOR_FLASH_ERASE_4K}, + {L"n25q512a", {0x20, 0xbb, 0x20}, 3, 256, 64 * 1024, 1024, NOR_FLASH_WRITE_FSR | NOR_FLASH_ERASE_4K}, + {L"n25q1024", {0x20, 0xba, 0x21}, 3, 256, 64 * 1024, 2048, NOR_FLASH_WRITE_FSR | NOR_FLASH_ERASE_4K}, + {L"n25q1024a", {0x20, 0xbb, 0x21}, 3, 256, 64 * 1024, 2048, NOR_FLASH_WRITE_FSR | NOR_FLASH_ERASE_4K}, + {L"mt25qu02g", {0x20, 0xbb, 0x22}, 3, 256, 64 * 1024, 4096, NOR_FLASH_WRITE_FSR | NOR_FLASH_ERASE_4K}, + {L"mt25ql02g", {0x20, 0xba, 0x22}, 3, 256, 64 * 1024, 4096, NOR_FLASH_WRITE_FSR | NOR_FLASH_ERASE_4K}, + /* SST */ + {L"sst25vf040b", {0xbf, 0x25, 0x8d}, 3, 256, 64 * 1024, 8, NOR_FLASH_ERASE_4K}, + {L"sst25vf080b", {0xbf, 0x25, 0x8e}, 3, 256, 64 * 1024, 16, NOR_FLASH_ERASE_4K}, + {L"sst25vf016b", {0xbf, 0x25, 0x41}, 3, 256, 64 * 1024, 32, NOR_FLASH_ERASE_4K}, + {L"sst25vf032b", {0xbf, 0x25, 0x4a}, 3, 256, 64 * 1024, 64, NOR_FLASH_ERASE_4K}, + {L"sst25vf064c", {0xbf, 0x25, 0x4b}, 3, 256, 64 * 1024, 128, NOR_FLASH_ERASE_4K}, + {L"sst25wf512", {0xbf, 0x25, 0x01}, 3, 256, 64 * 1024, 1, NOR_FLASH_ERASE_4K}, + {L"sst25wf010", {0xbf, 0x25, 0x02}, 3, 256, 64 * 1024, 2, NOR_FLASH_ERASE_4K}, + {L"sst25wf020", {0xbf, 0x25, 0x03}, 3, 256, 64 * 1024, 4, NOR_FLASH_ERASE_4K}, + {L"sst25wf040", {0xbf, 0x25, 0x04}, 3, 256, 64 * 1024, 8, NOR_FLASH_ERASE_4K}, + {L"sst25wf040b", {0x62, 0x16, 0x13}, 3, 256, 64 * 1024, 8, NOR_FLASH_ERASE_4K}, + {L"sst25wf080", {0xbf, 0x25, 0x05}, 3, 256, 64 * 1024, 16, NOR_FLASH_ERASE_4K}, + /* WINBOND */ + {L"w25p80", {0xef, 0x20, 0x14}, 3, 256, 64 * 1024, 16, 0}, + {L"w25p16", {0xef, 0x20, 0x15}, 3, 256, 64 * 1024, 32, 0}, + {L"w25p32", {0xef, 0x20, 0x16}, 3, 256, 64 * 1024, 64, 0}, + {L"w25x40", {0xef, 0x30, 0x13}, 3, 256, 64 * 1024, 8, NOR_FLASH_ERASE_4K}, + {L"w25x16", {0xef, 0x30, 0x15}, 3, 256, 64 * 1024, 32, NOR_FLASH_ERASE_4K}, + {L"w25x32", {0xef, 0x30, 0x16}, 3, 256, 64 * 1024, 64, NOR_FLASH_ERASE_4K}, + {L"w25x64", {0xef, 0x30, 0x17}, 3, 256, 64 * 1024, 128, NOR_FLASH_ERASE_4K}, + {L"w25q80bl", {0xef, 0x40, 0x14}, 3, 256, 64 * 1024, 16, NOR_FLASH_ERASE_4K}, + {L"w25q16cl", {0xef, 0x40, 0x15}, 3, 256, 64 * 1024, 32, NOR_FLASH_ERASE_4K}, + {L"w25q32bv", {0xef, 0x40, 0x16}, 3, 256, 64 * 1024, 64, NOR_FLASH_ERASE_4K}, + {L"w25q64cv", {0xef, 0x40, 0x17}, 3, 256, 64 * 1024, 128, NOR_FLASH_ERASE_4K}, + {L"w25q128bv", {0xef, 0x40, 0x18}, 3, 256, 64 * 1024, 256, NOR_FLASH_ERASE_4K}, + {L"w25q256", {0xef, 0x40, 0x19}, 3, 256, 64 * 1024, 512, NOR_FLASH_ERASE_4K}, + {L"w25q80bw", {0xef, 0x50, 0x14}, 3, 256, 64 * 1024, 16, NOR_FLASH_ERASE_4K}, + {L"w25q16dw", {0xef, 0x60, 0x15}, 3, 256, 64 * 1024, 32, NOR_FLASH_ERASE_4K}, + {L"w25q32dw", {0xef, 0x60, 0x16}, 3, 256, 64 * 1024, 64, NOR_FLASH_ERASE_4K}, + {L"w25q64dw", {0xef, 0x60, 0x17}, 3, 256, 64 * 1024, 128, NOR_FLASH_ERASE_4K}, + {L"w25q128fw", {0xef, 0x60, 0x18}, 3, 256, 64 * 1024, 256, NOR_FLASH_ERASE_4K}, + {}, /* Empty entry to terminate the list */ +}; + +/** + Return an allocated copy pool of the NOR flash information structure. + + @param[in] Id Pointer to an array with JEDEC ID obtained + from the NOR flash with READ_ID command + (0x9f) + @param[in out] FlashInfo Pointer to NOR flash information structure + @param[in] AllocateForRuntime A flag specifying a type of a copy pool + allocation (TRUE for runtime, FALSE for + normal) + + @retval EFI_SUCCESS Operation completed successfully + @retval EFI_NOT_FOUND No matching entry in NOR ID table found + @retval EFI_OUT_OF_RESOURCES No pool memory available + +**/ +EFI_STATUS +EFIAPI +NorFlashGetInfo ( + IN UINT8 *Id, + IN OUT NOR_FLASH_INFO **FlashInfo, + IN BOOLEAN AllocateForRuntime + ) +{ + CONST NOR_FLASH_INFO *TmpInfo; + + /* + * Iterate over NorFlashIds table, in order to find matching entry. + */ + TmpInfo = NorFlashIds; + for (; TmpInfo->Name != NULL; TmpInfo++) { + if (CompareMem (TmpInfo->Id, Id, TmpInfo->IdLen) == 0) { + break; + } + } + + /* + * Matching entry was not found. + */ + if (TmpInfo->Name == NULL) { + return EFI_NOT_FOUND; + } + + /* + * Allocate and copy NOR flash information structure. + */ + if (AllocateForRuntime) { + *FlashInfo = AllocateRuntimeCopyPool (sizeof (NOR_FLASH_INFO), TmpInfo); + } else { + *FlashInfo = AllocateCopyPool (sizeof (NOR_FLASH_INFO), TmpInfo); + } + if (FlashInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + +/** + Print NOR flash information basing on data stored in + the NOR_FLASH_INFO structure. + + @param[in] FlashInfo Pointer to NOR flash information structure + +**/ +VOID +EFIAPI +NorFlashPrintInfo ( + IN NOR_FLASH_INFO *Info + ) +{ + UINTN EraseSize; + + if (Info->Flags & NOR_FLASH_ERASE_4K) { + EraseSize = SIZE_4KB; + } else { + EraseSize = Info->SectorSize; + } + + DEBUG ((DEBUG_ERROR, + "Detected %s SPI NOR flash with page size %d B, erase size %d KB, total %d MB\n", + Info->Name, + Info->PageSize, + EraseSize / 1024, + (Info->SectorSize * Info->SectorCount) / 1024 / 1024)); +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NorFlashInfoLib/NorFlashInfoLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NorFlashInfoLib/NorFlashInfoLib.inf new file mode 100644 index 00000000..71e30a3a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NorFlashInfoLib/NorFlashInfoLib.inf @@ -0,0 +1,27 @@ +/** @file +* +* Copyright (c) 2017 Marvell International Ltd. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = NorFlashInfoLib + FILE_GUID = 6b639c7e-9b53-4e9f-89a3-2e711729709c + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = NorFlashInfoLib + +[Sources] + NorFlashInfoLib.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + DebugLib + MemoryAllocationLib diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NvVarStoreFormattedLib/NvVarStoreFormattedLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NvVarStoreFormattedLib/NvVarStoreFormattedLib.c new file mode 100644 index 00000000..9e4a4a49 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NvVarStoreFormattedLib/NvVarStoreFormattedLib.c @@ -0,0 +1,35 @@ +/** @file + A hook-in library for: + - MdeModulePkg/Universal/Variable/Pei/VariablePei.inf + - MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf + - MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf + + Plugging this library instance into one of the above modules makes that + variable service backend wait for another platform module to dynamically + initialize or verify EFI_FIRMWARE_VOLUME_HEADER and VARIABLE_STORE_HEADER in + the non-volatile variable store FVB device. The initialization / verification + is signaled by installing gEdkiiNvVarStoreFormattedGuid into the + phase-matching PPI or protocol database, with a NULL interface. (Note that + installing gEdkiiNvVarStoreFormattedGuid into either the DXE or the MM + protocol database will unblock VariableSmm -- refer to EFI_SECTION_MM_DEPEX + in the PI spec.) + + Copyright (C) 2018, Red Hat, Inc. + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include <Base.h> + +RETURN_STATUS +EFIAPI +NvVarStoreFormattedInitialize ( + VOID + ) +{ + // + // Do nothing, just imbue VariablePei / VariableRuntimeDxe / VariableSmm with + // a PPI or protocol dependency on EDKII_NV_VAR_STORE_FORMATTED_GUID. + // + return RETURN_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NvVarStoreFormattedLib/NvVarStoreFormattedLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NvVarStoreFormattedLib/NvVarStoreFormattedLib.inf new file mode 100644 index 00000000..4c91b6d8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/NvVarStoreFormattedLib/NvVarStoreFormattedLib.inf @@ -0,0 +1,46 @@ +## @file +# A hook-in library for: +# - MdeModulePkg/Universal/Variable/Pei/VariablePei.inf +# - MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf +# - MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf +# +# Plugging this library instance into one of the above modules makes that +# variable service backend wait for another platform module to dynamically +# initialize or verify EFI_FIRMWARE_VOLUME_HEADER and VARIABLE_STORE_HEADER in +# the non-volatile variable store FVB device. The initialization / verification +# is signaled by installing gEdkiiNvVarStoreFormattedGuid into the +# phase-matching PPI or protocol database, with a NULL interface. (Note that +# installing gEdkiiNvVarStoreFormattedGuid into either the DXE or the MM +# protocol database will unblock VariableSmm -- refer to EFI_SECTION_MM_DEPEX +# in the PI spec.) +# +# Copyright (C) 2018, Red Hat, Inc. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 1.27 + BASE_NAME = NvVarStoreFormattedLib + FILE_GUID = 78f76ae8-ae62-4455-8148-c3a7ebaaa3f3 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = NvVarStoreFormattedLib|PEIM DXE_RUNTIME_DRIVER DXE_DRIVER DXE_SMM_DRIVER + CONSTRUCTOR = NvVarStoreFormattedInitialize + +[Sources] + NvVarStoreFormattedLib.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +# +# The matching DEPEX section below will generate the EFI_SECTION_PEI_DEPEX, +# EFI_SECTION_DXE_DEPEX or EFI_SECTION_MM_DEPEX leaf section for the PEIM +# (EFI_FV_FILETYPE_PEIM), DXE_RUNTIME_DRIVER/DXE_DRIVER (EFI_FV_FILETYPE_DRIVER), or +# DXE_SMM_DRIVER (EFI_FV_FILETYPE_MM) module, respectively. +# +[Depex.common.PEIM, Depex.common.DXE_RUNTIME_DRIVER, Depex.common.DXE_DRIVER, Depex.common.DXE_SMM_DRIVER] + gEdkiiNvVarStoreFormattedGuid diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PlatformHasAcpiLib/PlatformHasAcpiLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PlatformHasAcpiLib/PlatformHasAcpiLib.c new file mode 100644 index 00000000..54603e90 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PlatformHasAcpiLib/PlatformHasAcpiLib.c @@ -0,0 +1,30 @@ +/** @file + A hook-in library for MdeModulePkg/Universal/Acpi/AcpiTableDxe. + + Plugging this library instance into AcpiTableDxe makes + EFI_ACPI_TABLE_PROTOCOL and (if enabled) EFI_ACPI_SDT_PROTOCOL depend on the + platform's dynamic decision whether to expose an ACPI-based hardware + description to the operating system. + + Universal and platform specific DXE drivers that produce ACPI tables depend + on EFI_ACPI_TABLE_PROTOCOL / EFI_ACPI_SDT_PROTOCOL in turn. + + Copyright (C) 2017, Red Hat, Inc. + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include <Base.h> + +RETURN_STATUS +EFIAPI +PlatformHasAcpiInitialize ( + VOID + ) +{ + // + // Do nothing, just imbue AcpiTableDxe with a protocol dependency on + // EDKII_PLATFORM_HAS_ACPI_GUID. + // + return RETURN_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PlatformHasAcpiLib/PlatformHasAcpiLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PlatformHasAcpiLib/PlatformHasAcpiLib.inf new file mode 100644 index 00000000..71d0dabb --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PlatformHasAcpiLib/PlatformHasAcpiLib.inf @@ -0,0 +1,34 @@ +## @file +# A hook-in library for MdeModulePkg/Universal/Acpi/AcpiTableDxe. +# +# Plugging this library instance into AcpiTableDxe makes +# EFI_ACPI_TABLE_PROTOCOL and (if enabled) EFI_ACPI_SDT_PROTOCOL depend on the +# platform's dynamic decision whether to expose an ACPI-based hardware +# description to the operating system. +# +# Universal and platform specific DXE drivers that produce ACPI tables depend +# on EFI_ACPI_TABLE_PROTOCOL / EFI_ACPI_SDT_PROTOCOL in turn. +# +# Copyright (C) 2017, Red Hat, Inc. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 1.25 + BASE_NAME = PlatformHasAcpiLib + FILE_GUID = 29beb028-0958-447b-be0a-12229235d77d + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = PlatformHasAcpiLib|DXE_DRIVER + CONSTRUCTOR = PlatformHasAcpiInitialize + +[Sources] + PlatformHasAcpiLib.c + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[Depex] + gEdkiiPlatformHasAcpiGuid diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.c new file mode 100644 index 00000000..f5beb66f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.c @@ -0,0 +1,255 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiPei.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/ExtractGuidedSectionLib.h> +#include <Library/PcdLib.h> +#include <Library/PrePiLib.h> + +#define PRE_PI_EXTRACT_GUIDED_SECTION_DATA_GUID { 0x385A982C, 0x2F49, 0x4043, { 0xA5, 0x1E, 0x49, 0x01, 0x02, 0x5C, 0x8B, 0x6B }} + +typedef struct { + UINT32 NumberOfExtractHandler; + GUID *ExtractHandlerGuidTable; + EXTRACT_GUIDED_SECTION_DECODE_HANDLER *ExtractDecodeHandlerTable; + EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER *ExtractGetInfoHandlerTable; +} PRE_PI_EXTRACT_GUIDED_SECTION_DATA; + +PRE_PI_EXTRACT_GUIDED_SECTION_DATA * +GetSavedData ( + VOID + ) +{ + EFI_HOB_GUID_TYPE *GuidHob; + GUID SavedDataGuid = PRE_PI_EXTRACT_GUIDED_SECTION_DATA_GUID; + + GuidHob = GetFirstGuidHob(&SavedDataGuid); + GuidHob++; + + return (PRE_PI_EXTRACT_GUIDED_SECTION_DATA *)GuidHob; +} + +RETURN_STATUS +EFIAPI +ExtractGuidedSectionRegisterHandlers ( + IN CONST GUID *SectionGuid, + IN EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER GetInfoHandler, + IN EXTRACT_GUIDED_SECTION_DECODE_HANDLER DecodeHandler + ) +{ + PRE_PI_EXTRACT_GUIDED_SECTION_DATA *SavedData; + UINT32 Index; + // + // Check input parameter. + // + if (SectionGuid == NULL) { + return RETURN_INVALID_PARAMETER; + } + + SavedData = GetSavedData(); + + // + // Search the match registered GetInfo handler for the input guided section. + // + for (Index = 0; Index < SavedData->NumberOfExtractHandler; Index ++) { + if (CompareGuid (&SavedData->ExtractHandlerGuidTable[Index], SectionGuid)) { + break; + } + } + + // + // If the guided handler has been registered before, only update its handler. + // + if (Index < SavedData->NumberOfExtractHandler) { + SavedData->ExtractDecodeHandlerTable [Index] = DecodeHandler; + SavedData->ExtractGetInfoHandlerTable [Index] = GetInfoHandler; + return RETURN_SUCCESS; + } + + // + // Check the global table is enough to contain new Handler. + // + if (SavedData->NumberOfExtractHandler >= PcdGet32 (PcdMaximumGuidedExtractHandler)) { + return RETURN_OUT_OF_RESOURCES; + } + + // + // Register new Handler and guid value. + // + CopyGuid (&SavedData->ExtractHandlerGuidTable [SavedData->NumberOfExtractHandler], SectionGuid); + SavedData->ExtractDecodeHandlerTable [SavedData->NumberOfExtractHandler] = DecodeHandler; + SavedData->ExtractGetInfoHandlerTable [SavedData->NumberOfExtractHandler++] = GetInfoHandler; + + return RETURN_SUCCESS; +} + +UINTN +EFIAPI +ExtractGuidedSectionGetGuidList ( + IN OUT GUID **ExtractHandlerGuidTable + ) +{ + PRE_PI_EXTRACT_GUIDED_SECTION_DATA *SavedData; + + ASSERT(ExtractHandlerGuidTable != NULL); + + SavedData = GetSavedData(); + + *ExtractHandlerGuidTable = SavedData->ExtractHandlerGuidTable; + return SavedData->NumberOfExtractHandler; +} + +RETURN_STATUS +EFIAPI +ExtractGuidedSectionGetInfo ( + IN CONST VOID *InputSection, + OUT UINT32 *OutputBufferSize, + OUT UINT32 *ScratchBufferSize, + OUT UINT16 *SectionAttribute + ) +{ + PRE_PI_EXTRACT_GUIDED_SECTION_DATA *SavedData; + UINT32 Index; + EFI_GUID *SectionDefinitionGuid; + + if (InputSection == NULL) { + return RETURN_INVALID_PARAMETER; + } + + ASSERT (OutputBufferSize != NULL); + ASSERT (ScratchBufferSize != NULL); + ASSERT (SectionAttribute != NULL); + + SavedData = GetSavedData(); + + if (IS_SECTION2 (InputSection)) { + SectionDefinitionGuid = &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid); + } else { + SectionDefinitionGuid = &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid); + } + + // + // Search the match registered GetInfo handler for the input guided section. + // + for (Index = 0; Index < SavedData->NumberOfExtractHandler; Index ++) { + if (CompareGuid (&SavedData->ExtractHandlerGuidTable[Index], SectionDefinitionGuid)) { + break; + } + } + + // + // Not found, the input guided section is not supported. + // + if (Index == SavedData->NumberOfExtractHandler) { + return RETURN_INVALID_PARAMETER; + } + + // + // Call the match handler to getinfo for the input section data. + // + return SavedData->ExtractGetInfoHandlerTable [Index] ( + InputSection, + OutputBufferSize, + ScratchBufferSize, + SectionAttribute + ); +} + +RETURN_STATUS +EFIAPI +ExtractGuidedSectionDecode ( + IN CONST VOID *InputSection, + OUT VOID **OutputBuffer, + OUT VOID *ScratchBuffer, OPTIONAL + OUT UINT32 *AuthenticationStatus + ) +{ + PRE_PI_EXTRACT_GUIDED_SECTION_DATA *SavedData; + UINT32 Index; + EFI_GUID *SectionDefinitionGuid; + + if (InputSection == NULL) { + return RETURN_INVALID_PARAMETER; + } + + ASSERT (OutputBuffer != NULL); + ASSERT (AuthenticationStatus != NULL); + + SavedData = GetSavedData(); + + if (IS_SECTION2 (InputSection)) { + SectionDefinitionGuid = &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid); + } else { + SectionDefinitionGuid = &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid); + } + + // + // Search the match registered GetInfo handler for the input guided section. + // + for (Index = 0; Index < SavedData->NumberOfExtractHandler; Index ++) { + if (CompareGuid (&SavedData->ExtractHandlerGuidTable[Index], SectionDefinitionGuid)) { + break; + } + } + + // + // Not found, the input guided section is not supported. + // + if (Index == SavedData->NumberOfExtractHandler) { + return RETURN_INVALID_PARAMETER; + } + + // + // Call the match handler to getinfo for the input section data. + // + return SavedData->ExtractDecodeHandlerTable [Index] ( + InputSection, + OutputBuffer, + ScratchBuffer, + AuthenticationStatus + ); +} + +RETURN_STATUS +EFIAPI +ExtractGuidedSectionLibConstructor ( + VOID + ) +{ + PRE_PI_EXTRACT_GUIDED_SECTION_DATA SavedData; + GUID HobGuid = PRE_PI_EXTRACT_GUIDED_SECTION_DATA_GUID; + + // + // Allocate global pool space to store the registered handler and its guid value. + // + SavedData.ExtractHandlerGuidTable = (GUID *)AllocatePool(PcdGet32(PcdMaximumGuidedExtractHandler) * sizeof(GUID)); + if (SavedData.ExtractHandlerGuidTable == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + + SavedData.ExtractDecodeHandlerTable = (EXTRACT_GUIDED_SECTION_DECODE_HANDLER *)AllocatePool(PcdGet32(PcdMaximumGuidedExtractHandler) * sizeof(EXTRACT_GUIDED_SECTION_DECODE_HANDLER)); + if (SavedData.ExtractDecodeHandlerTable == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + + SavedData.ExtractGetInfoHandlerTable = (EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER *)AllocatePool(PcdGet32(PcdMaximumGuidedExtractHandler) * sizeof(EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER)); + if (SavedData.ExtractGetInfoHandlerTable == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + + // + // the initialized number is Zero. + // + SavedData.NumberOfExtractHandler = 0; + + BuildGuidDataHob(&HobGuid, &SavedData, sizeof(SavedData)); + + return RETURN_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.inf new file mode 100644 index 00000000..52966c70 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.inf @@ -0,0 +1,30 @@ +#/** @file +# +# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PrePiExtractGuidedSectionLib + FILE_GUID = 36F6E94E-6E8E-488E-89A4-7AD911C5AFB1 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = ExtractGuidedSectionLib + + CONSTRUCTOR = ExtractGuidedSectionLibConstructor + +[Sources.common] + PrePiExtractGuidedSectionLib.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseMemoryLib + DebugLib + +[FixedPcd.common] + gEfiMdePkgTokenSpaceGuid.PcdMaximumGuidedExtractHandler diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiHobLib/Hob.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiHobLib/Hob.c new file mode 100644 index 00000000..ab9c3b8b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiHobLib/Hob.c @@ -0,0 +1,849 @@ +/** @file + + Copyright (c) 2010, Apple Inc. All rights reserved.<BR> + Copyright (c) 2017, Intel Corporation. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiPei.h> + +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/PeCoffLib.h> +#include <Library/HobLib.h> +#include <Library/PcdLib.h> +#include <Library/PrePiHobListPointerLib.h> + +#include <Protocol/PeCoffLoader.h> +#include <Guid/ExtractSection.h> +#include <Guid/MemoryTypeInformation.h> +#include <Guid/MemoryAllocationHob.h> + +VOID +BuildMemoryTypeInformationHob ( + VOID + ); + +/** + Returns the pointer to the HOB list. + + This function returns the pointer to first HOB in the list. + + @return The pointer to the HOB list. + +**/ +VOID * +EFIAPI +GetHobList ( + VOID + ) +{ + return PrePeiGetHobList (); +} + + + +/** + Updates the pointer to the HOB list. + + @param HobList Hob list pointer to store + +**/ +EFI_STATUS +EFIAPI +SetHobList ( + IN VOID *HobList + ) +{ + return PrePeiSetHobList (HobList); +} + +/** + + +**/ +EFI_HOB_HANDOFF_INFO_TABLE* +HobConstructor ( + IN VOID *EfiMemoryBegin, + IN UINTN EfiMemoryLength, + IN VOID *EfiFreeMemoryBottom, + IN VOID *EfiFreeMemoryTop + ) +{ + EFI_HOB_HANDOFF_INFO_TABLE *Hob; + EFI_HOB_GENERIC_HEADER *HobEnd; + + Hob = EfiFreeMemoryBottom; + HobEnd = (EFI_HOB_GENERIC_HEADER *)(Hob+1); + + Hob->Header.HobType = EFI_HOB_TYPE_HANDOFF; + Hob->Header.HobLength = sizeof(EFI_HOB_HANDOFF_INFO_TABLE); + Hob->Header.Reserved = 0; + + HobEnd->HobType = EFI_HOB_TYPE_END_OF_HOB_LIST; + HobEnd->HobLength = sizeof(EFI_HOB_GENERIC_HEADER); + HobEnd->Reserved = 0; + + Hob->Version = EFI_HOB_HANDOFF_TABLE_VERSION; + Hob->BootMode = BOOT_WITH_FULL_CONFIGURATION; + + Hob->EfiMemoryTop = (UINTN)EfiMemoryBegin + EfiMemoryLength; + Hob->EfiMemoryBottom = (UINTN)EfiMemoryBegin; + Hob->EfiFreeMemoryTop = (UINTN)EfiFreeMemoryTop; + Hob->EfiFreeMemoryBottom = (EFI_PHYSICAL_ADDRESS)(UINTN)(HobEnd+1); + Hob->EfiEndOfHobList = (EFI_PHYSICAL_ADDRESS)(UINTN)HobEnd; + + return Hob; +} + +VOID * +CreateHob ( + IN UINT16 HobType, + IN UINT16 HobLength + ) +{ + EFI_HOB_HANDOFF_INFO_TABLE *HandOffHob; + EFI_HOB_GENERIC_HEADER *HobEnd; + EFI_PHYSICAL_ADDRESS FreeMemory; + VOID *Hob; + + HandOffHob = GetHobList (); + + HobLength = (UINT16)((HobLength + 0x7) & (~0x7)); + + FreeMemory = HandOffHob->EfiFreeMemoryTop - HandOffHob->EfiFreeMemoryBottom; + + if (FreeMemory < HobLength) { + return NULL; + } + + Hob = (VOID*) (UINTN) HandOffHob->EfiEndOfHobList; + ((EFI_HOB_GENERIC_HEADER*) Hob)->HobType = HobType; + ((EFI_HOB_GENERIC_HEADER*) Hob)->HobLength = HobLength; + ((EFI_HOB_GENERIC_HEADER*) Hob)->Reserved = 0; + + HobEnd = (EFI_HOB_GENERIC_HEADER*) ((UINTN)Hob + HobLength); + HandOffHob->EfiEndOfHobList = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd; + + HobEnd->HobType = EFI_HOB_TYPE_END_OF_HOB_LIST; + HobEnd->HobLength = sizeof(EFI_HOB_GENERIC_HEADER); + HobEnd->Reserved = 0; + HobEnd++; + HandOffHob->EfiFreeMemoryBottom = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd; + + return Hob; +} + +/** + Builds a HOB that describes a chunk of system memory. + + This function builds a HOB that describes a chunk of system memory. + If there is no additional space for HOB creation, then ASSERT(). + + @param ResourceType The type of resource described by this HOB. + @param ResourceAttribute The resource attributes of the memory described by this HOB. + @param PhysicalStart The 64 bit physical address of memory described by this HOB. + @param NumberOfBytes The length of the memory described by this HOB in bytes. + +**/ +VOID +EFIAPI +BuildResourceDescriptorHob ( + IN EFI_RESOURCE_TYPE ResourceType, + IN EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute, + IN EFI_PHYSICAL_ADDRESS PhysicalStart, + IN UINT64 NumberOfBytes + ) +{ + EFI_HOB_RESOURCE_DESCRIPTOR *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, sizeof (EFI_HOB_RESOURCE_DESCRIPTOR)); + ASSERT(Hob != NULL); + + Hob->ResourceType = ResourceType; + Hob->ResourceAttribute = ResourceAttribute; + Hob->PhysicalStart = PhysicalStart; + Hob->ResourceLength = NumberOfBytes; +} + +VOID +EFIAPI +BuildFvHobs ( + IN EFI_PHYSICAL_ADDRESS PhysicalStart, + IN UINT64 NumberOfBytes, + IN EFI_RESOURCE_ATTRIBUTE_TYPE *ResourceAttribute + ) +{ + + EFI_RESOURCE_ATTRIBUTE_TYPE Resource; + + BuildFvHob (PhysicalStart, NumberOfBytes); + + if (ResourceAttribute == NULL) { + Resource = (EFI_RESOURCE_ATTRIBUTE_PRESENT | + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | + EFI_RESOURCE_ATTRIBUTE_TESTED | + EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE); + } else { + Resource = *ResourceAttribute; + } + + BuildResourceDescriptorHob (EFI_RESOURCE_FIRMWARE_DEVICE, Resource, PhysicalStart, NumberOfBytes); +} + +/** + Returns the next instance of a HOB type from the starting HOB. + + This function searches the first instance of a HOB type from the starting HOB pointer. + If there does not exist such HOB type from the starting HOB pointer, it will return NULL. + In contrast with macro GET_NEXT_HOB(), this function does not skip the starting HOB pointer + unconditionally: it returns HobStart back if HobStart itself meets the requirement; + caller is required to use GET_NEXT_HOB() if it wishes to skip current HobStart. + If HobStart is NULL, then ASSERT(). + + @param Type The HOB type to return. + @param HobStart The starting HOB pointer to search from. + + @return The next instance of a HOB type from the starting HOB. + +**/ +VOID * +EFIAPI +GetNextHob ( + IN UINT16 Type, + IN CONST VOID *HobStart + ) +{ + EFI_PEI_HOB_POINTERS Hob; + + ASSERT (HobStart != NULL); + + Hob.Raw = (UINT8 *) HobStart; + // + // Parse the HOB list until end of list or matching type is found. + // + while (!END_OF_HOB_LIST (Hob)) { + if (Hob.Header->HobType == Type) { + return Hob.Raw; + } + Hob.Raw = GET_NEXT_HOB (Hob); + } + return NULL; +} + + + +/** + Returns the first instance of a HOB type among the whole HOB list. + + This function searches the first instance of a HOB type among the whole HOB list. + If there does not exist such HOB type in the HOB list, it will return NULL. + + @param Type The HOB type to return. + + @return The next instance of a HOB type from the starting HOB. + +**/ +VOID * +EFIAPI +GetFirstHob ( + IN UINT16 Type + ) +{ + VOID *HobList; + + HobList = GetHobList (); + return GetNextHob (Type, HobList); +} + + +/** + This function searches the first instance of a HOB from the starting HOB pointer. + Such HOB should satisfy two conditions: + its HOB type is EFI_HOB_TYPE_GUID_EXTENSION and its GUID Name equals to the input Guid. + If there does not exist such HOB from the starting HOB pointer, it will return NULL. + Caller is required to apply GET_GUID_HOB_DATA () and GET_GUID_HOB_DATA_SIZE () + to extract the data section and its size info respectively. + In contrast with macro GET_NEXT_HOB(), this function does not skip the starting HOB pointer + unconditionally: it returns HobStart back if HobStart itself meets the requirement; + caller is required to use GET_NEXT_HOB() if it wishes to skip current HobStart. + If Guid is NULL, then ASSERT(). + If HobStart is NULL, then ASSERT(). + + @param Guid The GUID to match with in the HOB list. + @param HobStart A pointer to a Guid. + + @return The next instance of the matched GUID HOB from the starting HOB. + +**/ +VOID * +EFIAPI +GetNextGuidHob ( + IN CONST EFI_GUID *Guid, + IN CONST VOID *HobStart + ){ + EFI_PEI_HOB_POINTERS GuidHob; + + GuidHob.Raw = (UINT8 *) HobStart; + while ((GuidHob.Raw = GetNextHob (EFI_HOB_TYPE_GUID_EXTENSION, GuidHob.Raw)) != NULL) { + if (CompareGuid (Guid, &GuidHob.Guid->Name)) { + break; + } + GuidHob.Raw = GET_NEXT_HOB (GuidHob); + } + return GuidHob.Raw; +} + + +/** + This function searches the first instance of a HOB among the whole HOB list. + Such HOB should satisfy two conditions: + its HOB type is EFI_HOB_TYPE_GUID_EXTENSION and its GUID Name equals to the input Guid. + If there does not exist such HOB from the starting HOB pointer, it will return NULL. + Caller is required to apply GET_GUID_HOB_DATA () and GET_GUID_HOB_DATA_SIZE () + to extract the data section and its size info respectively. + If Guid is NULL, then ASSERT(). + + @param Guid The GUID to match with in the HOB list. + + @return The first instance of the matched GUID HOB among the whole HOB list. + +**/ +VOID * +EFIAPI +GetFirstGuidHob ( + IN CONST EFI_GUID *Guid + ) +{ + VOID *HobList; + + HobList = GetHobList (); + return GetNextGuidHob (Guid, HobList); +} + + +/** + Get the Boot Mode from the HOB list. + + This function returns the system boot mode information from the + PHIT HOB in HOB list. + + @param VOID + + @return The Boot Mode. + +**/ +EFI_BOOT_MODE +EFIAPI +GetBootMode ( + VOID + ) +{ + EFI_PEI_HOB_POINTERS Hob; + + Hob.Raw = GetHobList (); + return Hob.HandoffInformationTable->BootMode; +} + + +/** + Get the Boot Mode from the HOB list. + + This function returns the system boot mode information from the + PHIT HOB in HOB list. + + @param VOID + + @return The Boot Mode. + +**/ +EFI_STATUS +EFIAPI +SetBootMode ( + IN EFI_BOOT_MODE BootMode + ) +{ + EFI_PEI_HOB_POINTERS Hob; + + Hob.Raw = GetHobList (); + Hob.HandoffInformationTable->BootMode = BootMode; + return BootMode; +} + +/** + Builds a HOB for a loaded PE32 module. + + This function builds a HOB for a loaded PE32 module. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If ModuleName is NULL, then ASSERT(). + If there is no additional space for HOB creation, then ASSERT(). + + @param ModuleName The GUID File Name of the module. + @param MemoryAllocationModule The 64 bit physical address of the module. + @param ModuleLength The length of the module in bytes. + @param EntryPoint The 64 bit physical address of the module entry point. + +**/ +VOID +EFIAPI +BuildModuleHob ( + IN CONST EFI_GUID *ModuleName, + IN EFI_PHYSICAL_ADDRESS MemoryAllocationModule, + IN UINT64 ModuleLength, + IN EFI_PHYSICAL_ADDRESS EntryPoint + ) +{ + EFI_HOB_MEMORY_ALLOCATION_MODULE *Hob; + + ASSERT (((MemoryAllocationModule & (EFI_PAGE_SIZE - 1)) == 0) && + ((ModuleLength & (EFI_PAGE_SIZE - 1)) == 0)); + + Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof (EFI_HOB_MEMORY_ALLOCATION_MODULE)); + + CopyGuid (&(Hob->MemoryAllocationHeader.Name), &gEfiHobMemoryAllocModuleGuid); + Hob->MemoryAllocationHeader.MemoryBaseAddress = MemoryAllocationModule; + Hob->MemoryAllocationHeader.MemoryLength = ModuleLength; + Hob->MemoryAllocationHeader.MemoryType = EfiBootServicesCode; + + // + // Zero the reserved space to match HOB spec + // + ZeroMem (Hob->MemoryAllocationHeader.Reserved, sizeof (Hob->MemoryAllocationHeader.Reserved)); + + CopyGuid (&Hob->ModuleName, ModuleName); + Hob->EntryPoint = EntryPoint; +} + +/** + Builds a GUID HOB with a certain data length. + + This function builds a customized HOB tagged with a GUID for identification + and returns the start address of GUID HOB data so that caller can fill the customized data. + The HOB Header and Name field is already stripped. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If Guid is NULL, then ASSERT(). + If there is no additional space for HOB creation, then ASSERT(). + If DataLength >= (0x10000 - sizeof (EFI_HOB_GUID_TYPE)), then ASSERT(). + + @param Guid The GUID to tag the customized HOB. + @param DataLength The size of the data payload for the GUID HOB. + + @return The start address of GUID HOB data. + +**/ +VOID * +EFIAPI +BuildGuidHob ( + IN CONST EFI_GUID *Guid, + IN UINTN DataLength + ) +{ + EFI_HOB_GUID_TYPE *Hob; + + // + // Make sure that data length is not too long. + // + ASSERT (DataLength <= (0xffff - sizeof (EFI_HOB_GUID_TYPE))); + + Hob = CreateHob (EFI_HOB_TYPE_GUID_EXTENSION, (UINT16) (sizeof (EFI_HOB_GUID_TYPE) + DataLength)); + CopyGuid (&Hob->Name, Guid); + return Hob + 1; +} + + +/** + Copies a data buffer to a newly-built HOB. + + This function builds a customized HOB tagged with a GUID for identification, + copies the input data to the HOB data field and returns the start address of the GUID HOB data. + The HOB Header and Name field is already stripped. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If Guid is NULL, then ASSERT(). + If Data is NULL and DataLength > 0, then ASSERT(). + If there is no additional space for HOB creation, then ASSERT(). + If DataLength >= (0x10000 - sizeof (EFI_HOB_GUID_TYPE)), then ASSERT(). + + @param Guid The GUID to tag the customized HOB. + @param Data The data to be copied into the data field of the GUID HOB. + @param DataLength The size of the data payload for the GUID HOB. + + @return The start address of GUID HOB data. + +**/ +VOID * +EFIAPI +BuildGuidDataHob ( + IN CONST EFI_GUID *Guid, + IN VOID *Data, + IN UINTN DataLength + ) +{ + VOID *HobData; + + ASSERT (Data != NULL || DataLength == 0); + + HobData = BuildGuidHob (Guid, DataLength); + + return CopyMem (HobData, Data, DataLength); +} + + +/** + Builds a Firmware Volume HOB. + + This function builds a Firmware Volume HOB. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The base address of the Firmware Volume. + @param Length The size of the Firmware Volume in bytes. + +**/ +VOID +EFIAPI +BuildFvHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + EFI_HOB_FIRMWARE_VOLUME *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_FV, sizeof (EFI_HOB_FIRMWARE_VOLUME)); + + Hob->BaseAddress = BaseAddress; + Hob->Length = Length; +} + + +/** + Builds a EFI_HOB_TYPE_FV2 HOB. + + This function builds a EFI_HOB_TYPE_FV2 HOB. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The base address of the Firmware Volume. + @param Length The size of the Firmware Volume in bytes. + @param FvName The name of the Firmware Volume. + @param FileName The name of the file. + +**/ +VOID +EFIAPI +BuildFv2Hob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN CONST EFI_GUID *FvName, + IN CONST EFI_GUID *FileName + ) +{ + EFI_HOB_FIRMWARE_VOLUME2 *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_FV2, sizeof (EFI_HOB_FIRMWARE_VOLUME2)); + + Hob->BaseAddress = BaseAddress; + Hob->Length = Length; + CopyGuid (&Hob->FvName, FvName); + CopyGuid (&Hob->FileName, FileName); +} + +/** + Builds a EFI_HOB_TYPE_FV3 HOB. + + This function builds a EFI_HOB_TYPE_FV3 HOB. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The base address of the Firmware Volume. + @param Length The size of the Firmware Volume in bytes. + @param AuthenticationStatus The authentication status. + @param ExtractedFv TRUE if the FV was extracted as a file within + another firmware volume. FALSE otherwise. + @param FvName The name of the Firmware Volume. + Valid only if IsExtractedFv is TRUE. + @param FileName The name of the file. + Valid only if IsExtractedFv is TRUE. + +**/ +VOID +EFIAPI +BuildFv3Hob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT32 AuthenticationStatus, + IN BOOLEAN ExtractedFv, + IN CONST EFI_GUID *FvName, OPTIONAL + IN CONST EFI_GUID *FileName OPTIONAL + ) +{ + EFI_HOB_FIRMWARE_VOLUME3 *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_FV3, sizeof (EFI_HOB_FIRMWARE_VOLUME3)); + + Hob->BaseAddress = BaseAddress; + Hob->Length = Length; + Hob->AuthenticationStatus = AuthenticationStatus; + Hob->ExtractedFv = ExtractedFv; + if (ExtractedFv) { + CopyGuid (&Hob->FvName, FvName); + CopyGuid (&Hob->FileName, FileName); + } +} + +/** + Builds a Capsule Volume HOB. + + This function builds a Capsule Volume HOB. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The base address of the Capsule Volume. + @param Length The size of the Capsule Volume in bytes. + +**/ +VOID +EFIAPI +BuildCvHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + ASSERT (FALSE); +} + + +/** + Builds a HOB for the CPU. + + This function builds a HOB for the CPU. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If there is no additional space for HOB creation, then ASSERT(). + + @param SizeOfMemorySpace The maximum physical memory addressability of the processor. + @param SizeOfIoSpace The maximum physical I/O addressability of the processor. + +**/ +VOID +EFIAPI +BuildCpuHob ( + IN UINT8 SizeOfMemorySpace, + IN UINT8 SizeOfIoSpace + ) +{ + EFI_HOB_CPU *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_CPU, sizeof (EFI_HOB_CPU)); + + Hob->SizeOfMemorySpace = SizeOfMemorySpace; + Hob->SizeOfIoSpace = SizeOfIoSpace; + + // + // Zero the reserved space to match HOB spec + // + ZeroMem (Hob->Reserved, sizeof (Hob->Reserved)); +} + + +/** + Builds a HOB for the Stack. + + This function builds a HOB for the stack. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The 64 bit physical address of the Stack. + @param Length The length of the stack in bytes. + +**/ +VOID +EFIAPI +BuildStackHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + EFI_HOB_MEMORY_ALLOCATION_STACK *Hob; + + ASSERT (((BaseAddress & (EFI_PAGE_SIZE - 1)) == 0) && + ((Length & (EFI_PAGE_SIZE - 1)) == 0)); + + Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof (EFI_HOB_MEMORY_ALLOCATION_STACK)); + + CopyGuid (&(Hob->AllocDescriptor.Name), &gEfiHobMemoryAllocStackGuid); + Hob->AllocDescriptor.MemoryBaseAddress = BaseAddress; + Hob->AllocDescriptor.MemoryLength = Length; + Hob->AllocDescriptor.MemoryType = EfiBootServicesData; + + // + // Zero the reserved space to match HOB spec + // + ZeroMem (Hob->AllocDescriptor.Reserved, sizeof (Hob->AllocDescriptor.Reserved)); +} + + +/** + Update the Stack Hob if the stack has been moved + + @param BaseAddress The 64 bit physical address of the Stack. + @param Length The length of the stack in bytes. + +**/ +VOID +UpdateStackHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + EFI_PEI_HOB_POINTERS Hob; + + Hob.Raw = GetHobList (); + while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw)) != NULL) { + if (CompareGuid (&gEfiHobMemoryAllocStackGuid, &(Hob.MemoryAllocationStack->AllocDescriptor.Name))) { + // + // Build a new memory allocation HOB with old stack info with EfiConventionalMemory type + // to be reclaimed by DXE core. + // + BuildMemoryAllocationHob ( + Hob.MemoryAllocationStack->AllocDescriptor.MemoryBaseAddress, + Hob.MemoryAllocationStack->AllocDescriptor.MemoryLength, + EfiConventionalMemory + ); + // + // Update the BSP Stack Hob to reflect the new stack info. + // + Hob.MemoryAllocationStack->AllocDescriptor.MemoryBaseAddress = BaseAddress; + Hob.MemoryAllocationStack->AllocDescriptor.MemoryLength = Length; + break; + } + Hob.Raw = GET_NEXT_HOB (Hob); + } +} + + + +/** + Builds a HOB for the memory allocation. + + This function builds a HOB for the memory allocation. + It can only be invoked during PEI phase; + for DXE phase, it will ASSERT() since PEI HOB is read-only for DXE phase. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The 64 bit physical address of the memory. + @param Length The length of the memory allocation in bytes. + @param MemoryType Type of memory allocated by this HOB. + +**/ +VOID +EFIAPI +BuildMemoryAllocationHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN EFI_MEMORY_TYPE MemoryType + ) +{ + EFI_HOB_MEMORY_ALLOCATION *Hob; + + ASSERT (((BaseAddress & (EFI_PAGE_SIZE - 1)) == 0) && + ((Length & (EFI_PAGE_SIZE - 1)) == 0)); + + Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof (EFI_HOB_MEMORY_ALLOCATION)); + + ZeroMem (&(Hob->AllocDescriptor.Name), sizeof (EFI_GUID)); + Hob->AllocDescriptor.MemoryBaseAddress = BaseAddress; + Hob->AllocDescriptor.MemoryLength = Length; + Hob->AllocDescriptor.MemoryType = MemoryType; + // + // Zero the reserved space to match HOB spec + // + ZeroMem (Hob->AllocDescriptor.Reserved, sizeof (Hob->AllocDescriptor.Reserved)); +} + + + +VOID +EFIAPI +BuildExtractSectionHob ( + IN EFI_GUID *Guid, + IN EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER SectionGetInfo, + IN EXTRACT_GUIDED_SECTION_DECODE_HANDLER SectionExtraction + ) +{ + EXTRACT_SECTION_DATA Data; + + Data.SectionGetInfo = SectionGetInfo; + Data.SectionExtraction = SectionExtraction; + BuildGuidDataHob (Guid, &Data, sizeof (Data)); +} + +PE_COFF_LOADER_PROTOCOL gPeCoffProtocol = { + PeCoffLoaderGetImageInfo, + PeCoffLoaderLoadImage, + PeCoffLoaderRelocateImage, + PeCoffLoaderImageReadFromMemory, + PeCoffLoaderRelocateImageForRuntime, + PeCoffLoaderUnloadImage +}; + + + +VOID +EFIAPI +BuildPeCoffLoaderHob ( + VOID + ) +{ + VOID *Ptr; + + Ptr = &gPeCoffProtocol; + BuildGuidDataHob (&gPeCoffLoaderProtocolGuid, &Ptr, sizeof (VOID *)); +} + +// May want to put this into a library so you only need the PCD settings if you are using the feature? +VOID +BuildMemoryTypeInformationHob ( + VOID + ) +{ + EFI_MEMORY_TYPE_INFORMATION Info[10]; + + Info[0].Type = EfiACPIReclaimMemory; + Info[0].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiACPIReclaimMemory); + Info[1].Type = EfiACPIMemoryNVS; + Info[1].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiACPIMemoryNVS); + Info[2].Type = EfiReservedMemoryType; + Info[2].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiReservedMemoryType); + Info[3].Type = EfiRuntimeServicesData; + Info[3].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiRuntimeServicesData); + Info[4].Type = EfiRuntimeServicesCode; + Info[4].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiRuntimeServicesCode); + Info[5].Type = EfiBootServicesCode; + Info[5].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiBootServicesCode); + Info[6].Type = EfiBootServicesData; + Info[6].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiBootServicesData); + Info[7].Type = EfiLoaderCode; + Info[7].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiLoaderCode); + Info[8].Type = EfiLoaderData; + Info[8].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiLoaderData); + + // Terminator for the list + Info[9].Type = EfiMaxMemoryType; + Info[9].NumberOfPages = 0; + + + BuildGuidDataHob (&gEfiMemoryTypeInformationGuid, &Info, sizeof (Info)); +} + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiHobLib/PrePiHobLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiHobLib/PrePiHobLib.inf new file mode 100644 index 00000000..b9103a93 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiHobLib/PrePiHobLib.inf @@ -0,0 +1,57 @@ +#/** @file +# Hob lib that does not contain the APIs as they are already in the PrePiLib +# +# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> +# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PrePiHobLib + FILE_GUID = AEF7D85A-6A91-4ACD-9A28-193DEFB325FB + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = HobLib + + +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources.common] + Hob.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + PrePiHobListPointerLib + +[Guids] + gEfiHobMemoryAllocModuleGuid + gEfiHobMemoryAllocStackGuid + +[FixedPcd.common] + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIReclaimMemory + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIMemoryNVS + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiReservedMemoryType + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesData + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesCode + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesCode + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesData + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderCode + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderData + +[FeaturePcd] + gEmbeddedTokenSpaceGuid.PcdPrePiProduceMemoryTypeInformationHob + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiLib/FwVol.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiLib/FwVol.c new file mode 100644 index 00000000..0ecd211c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiLib/FwVol.c @@ -0,0 +1,878 @@ +/** @file + Implementation of the 6 PEI Ffs (FV) APIs in library form. + + This code only knows about a FV if it has a EFI_HOB_TYPE_FV entry in the HOB list + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PrePi.h> +#include <Library/ExtractGuidedSectionLib.h> + + +#define GET_OCCUPIED_SIZE(ActualSize, Alignment) \ + (ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1)) + + +/** + Returns the highest bit set of the State field + + @param ErasePolarity Erase Polarity as defined by EFI_FVB2_ERASE_POLARITY + in the Attributes field. + @param FfsHeader Pointer to FFS File Header + + + @retval the highest bit in the State field + +**/ +STATIC +EFI_FFS_FILE_STATE +GetFileState( + IN UINT8 ErasePolarity, + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +{ + EFI_FFS_FILE_STATE FileState; + EFI_FFS_FILE_STATE HighestBit; + + FileState = FfsHeader->State; + + if (ErasePolarity != 0) { + FileState = (EFI_FFS_FILE_STATE)~FileState; + } + + HighestBit = 0x80; + while (HighestBit != 0 && (HighestBit & FileState) == 0) { + HighestBit >>= 1; + } + + return HighestBit; +} + + +/** + Calculates the checksum of the header of a file. + The header is a zero byte checksum, so zero means header is good + + @param FfsHeader Pointer to FFS File Header + + @retval Checksum of the header + +**/ +STATIC +UINT8 +CalculateHeaderChecksum ( + IN EFI_FFS_FILE_HEADER *FileHeader + ) +{ + UINT8 *Ptr; + UINTN Index; + UINT8 Sum; + + Sum = 0; + Ptr = (UINT8 *)FileHeader; + + for (Index = 0; Index < sizeof(EFI_FFS_FILE_HEADER) - 3; Index += 4) { + Sum = (UINT8)(Sum + Ptr[Index]); + Sum = (UINT8)(Sum + Ptr[Index+1]); + Sum = (UINT8)(Sum + Ptr[Index+2]); + Sum = (UINT8)(Sum + Ptr[Index+3]); + } + + for (; Index < sizeof(EFI_FFS_FILE_HEADER); Index++) { + Sum = (UINT8)(Sum + Ptr[Index]); + } + + // + // State field (since this indicates the different state of file). + // + Sum = (UINT8)(Sum - FileHeader->State); + // + // Checksum field of the file is not part of the header checksum. + // + Sum = (UINT8)(Sum - FileHeader->IntegrityCheck.Checksum.File); + + return Sum; +} + + +/** + Given a FileHandle return the VolumeHandle + + @param FileHandle File handle to look up + @param VolumeHandle Match for FileHandle + + @retval TRUE VolumeHandle is valid + +**/ +STATIC +BOOLEAN +EFIAPI +FileHandleToVolume ( + IN EFI_PEI_FILE_HANDLE FileHandle, + OUT EFI_PEI_FV_HANDLE *VolumeHandle + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_PEI_HOB_POINTERS Hob; + + Hob.Raw = GetHobList (); + if (Hob.Raw == NULL) { + return FALSE; + } + + do { + Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw); + if (Hob.Raw != NULL) { + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(Hob.FirmwareVolume->BaseAddress); + if (((UINT64) (UINTN) FileHandle > (UINT64) (UINTN) FwVolHeader ) && \ + ((UINT64) (UINTN) FileHandle <= ((UINT64) (UINTN) FwVolHeader + FwVolHeader->FvLength - 1))) { + *VolumeHandle = (EFI_PEI_FV_HANDLE)FwVolHeader; + return TRUE; + } + + Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, GET_NEXT_HOB (Hob)); + } + } while (Hob.Raw != NULL); + + return FALSE; +} + + + +/** + Given the input file pointer, search for the next matching file in the + FFS volume as defined by SearchType. The search starts from FileHeader inside + the Firmware Volume defined by FwVolHeader. + + @param FileHandle File handle to look up + @param VolumeHandle Match for FileHandle + + +**/ +EFI_STATUS +FindFileEx ( + IN CONST EFI_PEI_FV_HANDLE FvHandle, + IN CONST EFI_GUID *FileName, OPTIONAL + IN EFI_FV_FILETYPE SearchType, + IN OUT EFI_PEI_FILE_HANDLE *FileHandle + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_FFS_FILE_HEADER **FileHeader; + EFI_FFS_FILE_HEADER *FfsFileHeader; + EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExHeaderInfo; + UINT32 FileLength; + UINT32 FileOccupiedSize; + UINT32 FileOffset; + UINT64 FvLength; + UINT8 ErasePolarity; + UINT8 FileState; + + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FvHandle; + FileHeader = (EFI_FFS_FILE_HEADER **)FileHandle; + + FvLength = FwVolHeader->FvLength; + if (FwVolHeader->Attributes & EFI_FVB2_ERASE_POLARITY) { + ErasePolarity = 1; + } else { + ErasePolarity = 0; + } + + // + // If FileHeader is not specified (NULL) or FileName is not NULL, + // start with the first file in the firmware volume. Otherwise, + // start from the FileHeader. + // + if ((*FileHeader == NULL) || (FileName != NULL)) { + FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FwVolHeader + FwVolHeader->HeaderLength); + if (FwVolHeader->ExtHeaderOffset != 0) { + FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)(((UINT8 *)FwVolHeader) + FwVolHeader->ExtHeaderOffset); + FfsFileHeader = (EFI_FFS_FILE_HEADER *)(((UINT8 *)FwVolExHeaderInfo) + FwVolExHeaderInfo->ExtHeaderSize); + } + } else { + // + // Length is 24 bits wide so mask upper 8 bits + // FileLength is adjusted to FileOccupiedSize as it is 8 byte aligned. + // + FileLength = *(UINT32 *)(*FileHeader)->Size & 0x00FFFFFF; + FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8); + FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)*FileHeader + FileOccupiedSize); + } + + // FFS files begin with a header that is aligned on an 8-byte boundary + FfsFileHeader = ALIGN_POINTER (FfsFileHeader, 8); + + FileOffset = (UINT32) ((UINT8 *)FfsFileHeader - (UINT8 *)FwVolHeader); + ASSERT (FileOffset <= 0xFFFFFFFF); + + while (FileOffset < (FvLength - sizeof (EFI_FFS_FILE_HEADER))) { + // + // Get FileState which is the highest bit of the State + // + FileState = GetFileState (ErasePolarity, FfsFileHeader); + + switch (FileState) { + + case EFI_FILE_HEADER_INVALID: + FileOffset += sizeof(EFI_FFS_FILE_HEADER); + FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + sizeof(EFI_FFS_FILE_HEADER)); + break; + + case EFI_FILE_DATA_VALID: + case EFI_FILE_MARKED_FOR_UPDATE: + if (CalculateHeaderChecksum (FfsFileHeader) != 0) { + ASSERT (FALSE); + *FileHeader = NULL; + return EFI_NOT_FOUND; + } + + FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF; + FileOccupiedSize = GET_OCCUPIED_SIZE(FileLength, 8); + + if (FileName != NULL) { + if (CompareGuid (&FfsFileHeader->Name, (EFI_GUID*)FileName)) { + *FileHeader = FfsFileHeader; + return EFI_SUCCESS; + } + } else if (((SearchType == FfsFileHeader->Type) || (SearchType == EFI_FV_FILETYPE_ALL)) && + (FfsFileHeader->Type != EFI_FV_FILETYPE_FFS_PAD)) { + *FileHeader = FfsFileHeader; + return EFI_SUCCESS; + } + + FileOffset += FileOccupiedSize; + FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize); + break; + + case EFI_FILE_DELETED: + FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF; + FileOccupiedSize = GET_OCCUPIED_SIZE(FileLength, 8); + FileOffset += FileOccupiedSize; + FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize); + break; + + default: + *FileHeader = NULL; + return EFI_NOT_FOUND; + } + } + + + *FileHeader = NULL; + return EFI_NOT_FOUND; +} + + +/** + Go through the file to search SectionType section, + when meeting an encapsuled section. + + @param SectionType - Filter to find only section of this type. + @param Section - From where to search. + @param SectionSize - The file size to search. + @param OutputBuffer - Pointer to the section to search. + + @retval EFI_SUCCESS +**/ +EFI_STATUS +FfsProcessSection ( + IN EFI_SECTION_TYPE SectionType, + IN EFI_COMMON_SECTION_HEADER *Section, + IN UINTN SectionSize, + OUT VOID **OutputBuffer + ) +{ + EFI_STATUS Status; + UINT32 SectionLength; + UINT32 ParsedLength; + EFI_COMPRESSION_SECTION *CompressionSection; + EFI_COMPRESSION_SECTION2 *CompressionSection2; + UINT32 DstBufferSize; + VOID *ScratchBuffer; + UINT32 ScratchBufferSize; + VOID *DstBuffer; + UINT16 SectionAttribute; + UINT32 AuthenticationStatus; + CHAR8 *CompressedData; + UINTN CompressedDataLength; + + + *OutputBuffer = NULL; + ParsedLength = 0; + Status = EFI_NOT_FOUND; + while (ParsedLength < SectionSize) { + if (IS_SECTION2 (Section)) { + ASSERT (SECTION2_SIZE (Section) > 0x00FFFFFF); + } + + if (Section->Type == SectionType) { + if (IS_SECTION2 (Section)) { + *OutputBuffer = (VOID *)((UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER2)); + } else { + *OutputBuffer = (VOID *)((UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER)); + } + + return EFI_SUCCESS; + } else if ((Section->Type == EFI_SECTION_COMPRESSION) || (Section->Type == EFI_SECTION_GUID_DEFINED)) { + + if (Section->Type == EFI_SECTION_COMPRESSION) { + if (IS_SECTION2 (Section)) { + CompressionSection2 = (EFI_COMPRESSION_SECTION2 *) Section; + SectionLength = SECTION2_SIZE (Section); + + if (CompressionSection2->CompressionType != EFI_STANDARD_COMPRESSION) { + return EFI_UNSUPPORTED; + } + + CompressedData = (CHAR8 *) ((EFI_COMPRESSION_SECTION2 *) Section + 1); + CompressedDataLength = (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION2); + } else { + CompressionSection = (EFI_COMPRESSION_SECTION *) Section; + SectionLength = SECTION_SIZE (Section); + + if (CompressionSection->CompressionType != EFI_STANDARD_COMPRESSION) { + return EFI_UNSUPPORTED; + } + + CompressedData = (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1); + CompressedDataLength = (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION); + } + + Status = UefiDecompressGetInfo ( + CompressedData, + CompressedDataLength, + &DstBufferSize, + &ScratchBufferSize + ); + } else if (Section->Type == EFI_SECTION_GUID_DEFINED) { + Status = ExtractGuidedSectionGetInfo ( + Section, + &DstBufferSize, + &ScratchBufferSize, + &SectionAttribute + ); + } + + if (EFI_ERROR (Status)) { + // + // GetInfo failed + // + DEBUG ((EFI_D_ERROR, "Decompress GetInfo Failed - %r\n", Status)); + return EFI_NOT_FOUND; + } + // + // Allocate scratch buffer + // + ScratchBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize)); + if (ScratchBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Allocate destination buffer, extra one page for adjustment + // + DstBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1); + if (DstBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // DstBuffer still is one section. Adjust DstBuffer offset, skip EFI section header + // to make section data at page alignment. + // + if (IS_SECTION2 (Section)) + DstBuffer = (UINT8 *)DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER2); + else + DstBuffer = (UINT8 *)DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER); + // + // Call decompress function + // + if (Section->Type == EFI_SECTION_COMPRESSION) { + if (IS_SECTION2 (Section)) { + CompressedData = (CHAR8 *) ((EFI_COMPRESSION_SECTION2 *) Section + 1); + } + else { + CompressedData = (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1); + } + + Status = UefiDecompress ( + CompressedData, + DstBuffer, + ScratchBuffer + ); + } else if (Section->Type == EFI_SECTION_GUID_DEFINED) { + Status = ExtractGuidedSectionDecode ( + Section, + &DstBuffer, + ScratchBuffer, + &AuthenticationStatus + ); + } + + if (EFI_ERROR (Status)) { + // + // Decompress failed + // + DEBUG ((EFI_D_ERROR, "Decompress Failed - %r\n", Status)); + return EFI_NOT_FOUND; + } else { + return FfsProcessSection ( + SectionType, + DstBuffer, + DstBufferSize, + OutputBuffer + ); + } + } + + if (IS_SECTION2 (Section)) { + SectionLength = SECTION2_SIZE (Section); + } else { + SectionLength = SECTION_SIZE (Section); + } + // + // SectionLength is adjusted it is 4 byte aligned. + // Go to the next section + // + SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4); + ASSERT (SectionLength != 0); + ParsedLength += SectionLength; + Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength); + } + + return EFI_NOT_FOUND; +} + + + +/** + This service enables discovery sections of a given type within a valid FFS file. + + @param SearchType The value of the section type to find. + @param FfsFileHeader A pointer to the file header that contains the set of sections to + be searched. + @param SectionData A pointer to the discovered section, if successful. + + @retval EFI_SUCCESS The section was found. + @retval EFI_NOT_FOUND The section was not found. + +**/ +EFI_STATUS +EFIAPI +FfsFindSectionData ( + IN EFI_SECTION_TYPE SectionType, + IN EFI_PEI_FILE_HANDLE FileHandle, + OUT VOID **SectionData + ) +{ + EFI_FFS_FILE_HEADER *FfsFileHeader; + UINT32 FileSize; + EFI_COMMON_SECTION_HEADER *Section; + + FfsFileHeader = (EFI_FFS_FILE_HEADER *)(FileHandle); + + // + // Size is 24 bits wide so mask upper 8 bits. + // Does not include FfsFileHeader header size + // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned. + // + Section = (EFI_COMMON_SECTION_HEADER *)(FfsFileHeader + 1); + FileSize = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF; + FileSize -= sizeof (EFI_FFS_FILE_HEADER); + + return FfsProcessSection ( + SectionType, + Section, + FileSize, + SectionData + ); +} + + + + + + +/** + This service enables discovery of additional firmware files. + + @param SearchType A filter to find files only of this type. + @param FwVolHeader Pointer to the firmware volume header of the volume to search. + This parameter must point to a valid FFS volume. + @param FileHeader Pointer to the current file from which to begin searching. + + @retval EFI_SUCCESS The file was found. + @retval EFI_NOT_FOUND The file was not found. + @retval EFI_NOT_FOUND The header checksum was not zero. + +**/ +EFI_STATUS +EFIAPI +FfsFindNextFile ( + IN UINT8 SearchType, + IN EFI_PEI_FV_HANDLE VolumeHandle, + IN OUT EFI_PEI_FILE_HANDLE *FileHandle + ) +{ + return FindFileEx (VolumeHandle, NULL, SearchType, FileHandle); +} + + +/** + This service enables discovery of additional firmware volumes. + + @param Instance This instance of the firmware volume to find. The value 0 is the + Boot Firmware Volume (BFV). + @param FwVolHeader Pointer to the firmware volume header of the volume to return. + + @retval EFI_SUCCESS The volume was found. + @retval EFI_NOT_FOUND The volume was not found. + +**/ +EFI_STATUS +EFIAPI +FfsFindNextVolume ( + IN UINTN Instance, + IN OUT EFI_PEI_FV_HANDLE *VolumeHandle + ) +{ + EFI_PEI_HOB_POINTERS Hob; + + + Hob.Raw = GetHobList (); + if (Hob.Raw == NULL) { + return EFI_NOT_FOUND; + } + + do { + Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw); + if (Hob.Raw != NULL) { + if (Instance-- == 0) { + *VolumeHandle = (EFI_PEI_FV_HANDLE)(UINTN)(Hob.FirmwareVolume->BaseAddress); + return EFI_SUCCESS; + } + + Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, GET_NEXT_HOB (Hob)); + } + } while (Hob.Raw != NULL); + + return EFI_NOT_FOUND; + +} + + +/** + Find a file in the volume by name + + @param FileName A pointer to the name of the file to + find within the firmware volume. + + @param VolumeHandle The firmware volume to search FileHandle + Upon exit, points to the found file's + handle or NULL if it could not be found. + + @retval EFI_SUCCESS File was found. + + @retval EFI_NOT_FOUND File was not found. + + @retval EFI_INVALID_PARAMETER VolumeHandle or FileHandle or + FileName was NULL. + +**/ +EFI_STATUS +EFIAPI +FfsFindFileByName ( + IN CONST EFI_GUID *FileName, + IN EFI_PEI_FV_HANDLE VolumeHandle, + OUT EFI_PEI_FILE_HANDLE *FileHandle + ) +{ + EFI_STATUS Status; + if ((VolumeHandle == NULL) || (FileName == NULL) || (FileHandle == NULL)) { + return EFI_INVALID_PARAMETER; + } + Status = FindFileEx (VolumeHandle, FileName, 0, FileHandle); + if (Status == EFI_NOT_FOUND) { + *FileHandle = NULL; + } + return Status; +} + + + + +/** + Get information about the file by name. + + @param FileHandle Handle of the file. + + @param FileInfo Upon exit, points to the file's + information. + + @retval EFI_SUCCESS File information returned. + + @retval EFI_INVALID_PARAMETER If FileHandle does not + represent a valid file. + + @retval EFI_INVALID_PARAMETER If FileInfo is NULL. + +**/ +EFI_STATUS +EFIAPI +FfsGetFileInfo ( + IN EFI_PEI_FILE_HANDLE FileHandle, + OUT EFI_FV_FILE_INFO *FileInfo + ) +{ + UINT8 FileState; + UINT8 ErasePolarity; + EFI_FFS_FILE_HEADER *FileHeader; + EFI_PEI_FV_HANDLE VolumeHandle; + + if ((FileHandle == NULL) || (FileInfo == NULL)) { + return EFI_INVALID_PARAMETER; + } + + VolumeHandle = 0; + // + // Retrieve the FirmwareVolume which the file resides in. + // + if (!FileHandleToVolume(FileHandle, &VolumeHandle)) { + return EFI_INVALID_PARAMETER; + } + + if (((EFI_FIRMWARE_VOLUME_HEADER*)VolumeHandle)->Attributes & EFI_FVB2_ERASE_POLARITY) { + ErasePolarity = 1; + } else { + ErasePolarity = 0; + } + + // + // Get FileState which is the highest bit of the State + // + FileState = GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER*)FileHandle); + + switch (FileState) { + case EFI_FILE_DATA_VALID: + case EFI_FILE_MARKED_FOR_UPDATE: + break; + default: + return EFI_INVALID_PARAMETER; + } + + FileHeader = (EFI_FFS_FILE_HEADER *)FileHandle; + CopyMem (&FileInfo->FileName, &FileHeader->Name, sizeof(EFI_GUID)); + FileInfo->FileType = FileHeader->Type; + FileInfo->FileAttributes = FileHeader->Attributes; + FileInfo->BufferSize = ((*(UINT32 *)FileHeader->Size) & 0x00FFFFFF) - sizeof (EFI_FFS_FILE_HEADER); + FileInfo->Buffer = (FileHeader + 1); + return EFI_SUCCESS; +} + + +/** + Get Information about the volume by name + + @param VolumeHandle Handle of the volume. + + @param VolumeInfo Upon exit, points to the volume's + information. + + @retval EFI_SUCCESS File information returned. + + @retval EFI_INVALID_PARAMETER If FileHandle does not + represent a valid file. + + @retval EFI_INVALID_PARAMETER If FileInfo is NULL. + +**/ +EFI_STATUS +EFIAPI +FfsGetVolumeInfo ( + IN EFI_PEI_FV_HANDLE VolumeHandle, + OUT EFI_FV_INFO *VolumeInfo + ) +{ + EFI_FIRMWARE_VOLUME_HEADER FwVolHeader; + EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExHeaderInfo; + + if (VolumeInfo == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // VolumeHandle may not align at 8 byte, + // but FvLength is UINT64 type, which requires FvHeader align at least 8 byte. + // So, Copy FvHeader into the local FvHeader structure. + // + CopyMem (&FwVolHeader, VolumeHandle, sizeof (EFI_FIRMWARE_VOLUME_HEADER)); + // + // Check Fv Image Signature + // + if (FwVolHeader.Signature != EFI_FVH_SIGNATURE) { + return EFI_INVALID_PARAMETER; + } + VolumeInfo->FvAttributes = FwVolHeader.Attributes; + VolumeInfo->FvStart = (VOID *) VolumeHandle; + VolumeInfo->FvSize = FwVolHeader.FvLength; + CopyMem (&VolumeInfo->FvFormat, &FwVolHeader.FileSystemGuid, sizeof(EFI_GUID)); + + if (FwVolHeader.ExtHeaderOffset != 0) { + FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER*)(((UINT8 *)VolumeHandle) + FwVolHeader.ExtHeaderOffset); + CopyMem (&VolumeInfo->FvName, &FwVolExHeaderInfo->FvName, sizeof(EFI_GUID)); + } + return EFI_SUCCESS; +} + + + +/** + Search through every FV until you find a file of type FileType + + @param FileType File handle of a Fv type file. + @param Volumehandle On success Volume Handle of the match + @param FileHandle On success File Handle of the match + + @retval EFI_NOT_FOUND FV image can't be found. + @retval EFI_SUCCESS Successfully found FileType + +**/ +EFI_STATUS +EFIAPI +FfsAnyFvFindFirstFile ( + IN EFI_FV_FILETYPE FileType, + OUT EFI_PEI_FV_HANDLE *VolumeHandle, + OUT EFI_PEI_FILE_HANDLE *FileHandle + ) +{ + EFI_STATUS Status; + UINTN Instance; + + // + // Search every FV for the DXE Core + // + Instance = 0; + *FileHandle = NULL; + + while (1) + { + Status = FfsFindNextVolume (Instance++, VolumeHandle); + if (EFI_ERROR (Status)) + { + break; + } + + Status = FfsFindNextFile (FileType, *VolumeHandle, FileHandle); + if (!EFI_ERROR (Status)) + { + break; + } + } + + return Status; +} + + + +/** + Get Fv image from the FV type file, then add FV & FV2 Hob. + + @param FileHandle File handle of a Fv type file. + + + @retval EFI_NOT_FOUND FV image can't be found. + @retval EFI_SUCCESS Successfully to process it. + +**/ +EFI_STATUS +EFIAPI +FfsProcessFvFile ( + IN EFI_PEI_FILE_HANDLE FvFileHandle + ) +{ + EFI_STATUS Status; + EFI_PEI_FV_HANDLE FvImageHandle; + EFI_FV_INFO FvImageInfo; + UINT32 FvAlignment; + VOID *FvBuffer; + EFI_PEI_HOB_POINTERS HobFv2; + + FvBuffer = NULL; + + + // + // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already + // been extracted. + // + HobFv2.Raw = GetHobList (); + while ((HobFv2.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobFv2.Raw)) != NULL) { + if (CompareGuid (&(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name), &HobFv2.FirmwareVolume2->FileName)) { + // + // this FILE has been dispatched, it will not be dispatched again. + // + return EFI_SUCCESS; + } + HobFv2.Raw = GET_NEXT_HOB (HobFv2); + } + + // + // Find FvImage in FvFile + // + Status = FfsFindSectionData (EFI_SECTION_FIRMWARE_VOLUME_IMAGE, FvFileHandle, (VOID **)&FvImageHandle); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Collect FvImage Info. + // + ZeroMem (&FvImageInfo, sizeof (FvImageInfo)); + Status = FfsGetVolumeInfo (FvImageHandle, &FvImageInfo); + ASSERT_EFI_ERROR (Status); + + // + // FvAlignment must be more than 8 bytes required by FvHeader structure. + // + FvAlignment = 1 << ((FvImageInfo.FvAttributes & EFI_FVB2_ALIGNMENT) >> 16); + if (FvAlignment < 8) { + FvAlignment = 8; + } + + // + // Check FvImage + // + if ((UINTN) FvImageInfo.FvStart % FvAlignment != 0) { + FvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINT32) FvImageInfo.FvSize), FvAlignment); + if (FvBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem (FvBuffer, FvImageInfo.FvStart, (UINTN) FvImageInfo.FvSize); + // + // Update FvImageInfo after reload FvImage to new aligned memory + // + FfsGetVolumeInfo ((EFI_PEI_FV_HANDLE) FvBuffer, &FvImageInfo); + } + + + // + // Inform HOB consumer phase, i.e. DXE core, the existence of this FV + // + BuildFvHob ((EFI_PHYSICAL_ADDRESS) (UINTN) FvImageInfo.FvStart, FvImageInfo.FvSize); + + // + // Makes the encapsulated volume show up in DXE phase to skip processing of + // encapsulated file again. + // + BuildFv2Hob ( + (EFI_PHYSICAL_ADDRESS) (UINTN) FvImageInfo.FvStart, + FvImageInfo.FvSize, + &FvImageInfo.FvName, + &(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name) + ); + + return EFI_SUCCESS; +} + + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiLib/PrePi.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiLib/PrePi.h new file mode 100644 index 00000000..7a92be53 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiLib/PrePi.h @@ -0,0 +1,41 @@ +/** @file + Library that helps implement monolithic PEI (i.e. PEI part of SEC) + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _PI_PEI_H_ +#define _PI_PEI_H_ + +#include <PiPei.h> + +#include <Library/BaseLib.h> +#include <Library/PrePiLib.h> +#include <Library/PcdLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/UefiDecompressLib.h> +#include <Library/PeCoffLib.h> +#include <Library/CacheMaintenanceLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/TimerLib.h> +#include <Library/PerformanceLib.h> + +#include <Guid/MemoryAllocationHob.h> + + +#define GET_HOB_TYPE(Hob) ((Hob).Header->HobType) +#define GET_HOB_LENGTH(Hob) ((Hob).Header->HobLength) +#define GET_NEXT_HOB(Hob) ((Hob).Raw + GET_HOB_LENGTH (Hob)) +#define END_OF_HOB_LIST(Hob) (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_END_OF_HOB_LIST) + +// +// Get the data and data size field of GUID +// +#define GET_GUID_HOB_DATA(GuidHob) ((VOID *) (((UINT8 *) &((GuidHob)->Name)) + sizeof (EFI_GUID))) +#define GET_GUID_HOB_DATA_SIZE(GuidHob) (((GuidHob)->Header).HobLength - sizeof (EFI_HOB_GUID_TYPE)) + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiLib/PrePiLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiLib/PrePiLib.c new file mode 100644 index 00000000..1ff83b28 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiLib/PrePiLib.c @@ -0,0 +1,251 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PrePi.h> + +// +// Hack to work in NT32 +// +EFI_STATUS + +EFIAPI + +SecWinNtPeiLoadFile ( + IN VOID *Pe32Data, + IN EFI_PHYSICAL_ADDRESS *ImageAddress, + IN UINT64 *ImageSize, + IN EFI_PHYSICAL_ADDRESS *EntryPoint + ); + +STATIC +VOID* +EFIAPI +AllocateCodePages ( + IN UINTN Pages + ) +{ + VOID *Alloc; + EFI_PEI_HOB_POINTERS Hob; + + Alloc = AllocatePages (Pages); + if (Alloc == NULL) { + return NULL; + } + + // find the HOB we just created, and change the type to EfiBootServicesCode + Hob.Raw = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION); + while (Hob.Raw != NULL) { + if (Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress == (UINTN)Alloc) { + Hob.MemoryAllocation->AllocDescriptor.MemoryType = EfiBootServicesCode; + return Alloc; + } + Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, GET_NEXT_HOB (Hob)); + } + + ASSERT (FALSE); + + FreePages (Alloc, Pages); + return NULL; +} + + +EFI_STATUS +EFIAPI +LoadPeCoffImage ( + IN VOID *PeCoffImage, + OUT EFI_PHYSICAL_ADDRESS *ImageAddress, + OUT UINT64 *ImageSize, + OUT EFI_PHYSICAL_ADDRESS *EntryPoint + ) +{ + RETURN_STATUS Status; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + VOID *Buffer; + + ZeroMem (&ImageContext, sizeof (ImageContext)); + + ImageContext.Handle = PeCoffImage; + ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; + + Status = PeCoffLoaderGetImageInfo (&ImageContext); + ASSERT_EFI_ERROR (Status); + + + // + // Allocate Memory for the image + // + Buffer = AllocateCodePages (EFI_SIZE_TO_PAGES((UINT32)ImageContext.ImageSize)); + ASSERT (Buffer != 0); + + + ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer; + + // + // Load the image to our new buffer + // + Status = PeCoffLoaderLoadImage (&ImageContext); + ASSERT_EFI_ERROR (Status); + + // + // Relocate the image in our new buffer + // + Status = PeCoffLoaderRelocateImage (&ImageContext); + ASSERT_EFI_ERROR (Status); + + + *ImageAddress = ImageContext.ImageAddress; + *ImageSize = ImageContext.ImageSize; + *EntryPoint = ImageContext.EntryPoint; + + // + // Flush not needed for all architectures. We could have a processor specific + // function in this library that does the no-op if needed. + // + InvalidateInstructionCacheRange ((VOID *)(UINTN)*ImageAddress, (UINTN)*ImageSize); + + return Status; +} + + + +typedef +VOID +(EFIAPI *DXE_CORE_ENTRY_POINT) ( + IN VOID *HobStart + ); + +EFI_STATUS +EFIAPI +LoadDxeCoreFromFfsFile ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN UINTN StackSize + ) +{ + EFI_STATUS Status; + VOID *PeCoffImage; + EFI_PHYSICAL_ADDRESS ImageAddress; + UINT64 ImageSize; + EFI_PHYSICAL_ADDRESS EntryPoint; + VOID *BaseOfStack; + VOID *TopOfStack; + VOID *Hob; + EFI_FV_FILE_INFO FvFileInfo; + + Status = FfsFindSectionData (EFI_SECTION_PE32, FileHandle, &PeCoffImage); + if (EFI_ERROR (Status)) { + return Status; + } + + + Status = LoadPeCoffImage (PeCoffImage, &ImageAddress, &ImageSize, &EntryPoint); +// For NT32 Debug Status = SecWinNtPeiLoadFile (PeCoffImage, &ImageAddress, &ImageSize, &EntryPoint); + ASSERT_EFI_ERROR (Status); + + // + // Extract the DxeCore GUID file name. + // + Status = FfsGetFileInfo (FileHandle, &FvFileInfo); + ASSERT_EFI_ERROR (Status); + + BuildModuleHob (&FvFileInfo.FileName, (EFI_PHYSICAL_ADDRESS)(UINTN)ImageAddress, EFI_SIZE_TO_PAGES ((UINT32) ImageSize) * EFI_PAGE_SIZE, EntryPoint); + + DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading DxeCore at 0x%10p EntryPoint=0x%10p\n", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)EntryPoint)); + + Hob = GetHobList (); + if (StackSize == 0) { + // User the current stack + + ((DXE_CORE_ENTRY_POINT)(UINTN)EntryPoint) (Hob); + } else { + + // + // Allocate 128KB for the Stack + // + BaseOfStack = AllocatePages (EFI_SIZE_TO_PAGES (StackSize)); + ASSERT (BaseOfStack != NULL); + + // + // Compute the top of the stack we were allocated. Pre-allocate a UINTN + // for safety. + // + TopOfStack = (VOID *) ((UINTN) BaseOfStack + EFI_SIZE_TO_PAGES (StackSize) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT); + TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT); + + // + // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore. + // + UpdateStackHob ((EFI_PHYSICAL_ADDRESS)(UINTN) BaseOfStack, StackSize); + + SwitchStack ( + (SWITCH_STACK_ENTRY_POINT)(UINTN)EntryPoint, + Hob, + NULL, + TopOfStack + ); + + } + + // Should never get here as DXE Core does not return + DEBUG ((EFI_D_ERROR, "DxeCore returned\n")); + ASSERT (FALSE); + + return EFI_DEVICE_ERROR; +} + + + +EFI_STATUS +EFIAPI +LoadDxeCoreFromFv ( + IN UINTN *FvInstance, OPTIONAL + IN UINTN StackSize + ) +{ + EFI_STATUS Status; + EFI_PEI_FV_HANDLE VolumeHandle; + EFI_PEI_FILE_HANDLE FileHandle = NULL; + + if (FvInstance != NULL) { + // + // Caller passed in a specific FV to try, so only try that one + // + Status = FfsFindNextVolume (*FvInstance, &VolumeHandle); + if (!EFI_ERROR (Status)) { + Status = FfsFindNextFile (EFI_FV_FILETYPE_DXE_CORE, VolumeHandle, &FileHandle); + } + } else { + Status = FfsAnyFvFindFirstFile (EFI_FV_FILETYPE_DXE_CORE, &VolumeHandle, &FileHandle); + } + + if (!EFI_ERROR (Status)) { + return LoadDxeCoreFromFfsFile (FileHandle, StackSize); + } + + return Status; +} + + +EFI_STATUS +EFIAPI +DecompressFirstFv ( + VOID + ) +{ + EFI_STATUS Status; + EFI_PEI_FV_HANDLE VolumeHandle; + EFI_PEI_FILE_HANDLE FileHandle; + + Status = FfsAnyFvFindFirstFile (EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, &VolumeHandle, &FileHandle); + if (!EFI_ERROR (Status)) { + Status = FfsProcessFvFile (FileHandle); + } + + return Status; +} + + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiLib/PrePiLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiLib/PrePiLib.inf new file mode 100644 index 00000000..5c56451e --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiLib/PrePiLib.inf @@ -0,0 +1,74 @@ +#/** @file +# Component description file for Apple Pre PI Library +# +# LIbrary helps you build a platform that skips PEI and loads DXE Core +# directly. Helps building HOBs, reading data from the FV, and doing +# decompression. +# +# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> +# Copyright (c) 2008, Apple Inc. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PrePiLib + FILE_GUID = 1F3A3278-82EB-4C0D-86F1-5BCDA5846CB2 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = PrePiLib + + +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources.common] + PrePi.h + FwVol.c + PrePiLib.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + BaseLib + DebugLib + BaseMemoryLib + UefiDecompressLib + PeCoffLib + CacheMaintenanceLib + PrintLib + SerialPortLib + ExtractGuidedSectionLib + TimerLib + PerformanceLib + HobLib + +[Guids] + gEfiMemoryTypeInformationGuid + +[Protocols] + gPeCoffLoaderProtocolGuid + + +[FixedPcd.common] + gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize + + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIReclaimMemory + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIMemoryNVS + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiReservedMemoryType + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesData + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesCode + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesCode + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesData + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderCode + gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderData + +[FeaturePcd] + gEmbeddedTokenSpaceGuid.PcdPrePiProduceMemoryTypeInformationHob diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiMemoryAllocationLib/MemoryAllocationLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiMemoryAllocationLib/MemoryAllocationLib.c new file mode 100644 index 00000000..939516d7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiMemoryAllocationLib/MemoryAllocationLib.c @@ -0,0 +1,246 @@ +/** @file + Implementation of the 6 PEI Ffs (FV) APIs in library form. + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiPei.h> + +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/PrePiLib.h> +#include <Library/DebugLib.h> + + + +/** + Allocates one or more 4KB pages of type EfiBootServicesData. + + Allocates the number of 4KB pages of MemoryType and returns a pointer to the + allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL + is returned. If there is not enough memory remaining to satisfy the request, then NULL is + returned. + + @param Pages The number of 4 KB pages to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocatePages ( + IN UINTN Pages + ) +{ + EFI_PEI_HOB_POINTERS Hob; + EFI_PHYSICAL_ADDRESS Offset; + + Hob.Raw = GetHobList (); + + // Check to see if on 4k boundary + Offset = Hob.HandoffInformationTable->EfiFreeMemoryTop & 0xFFF; + if (Offset != 0) { + // If not aligned, make the allocation aligned. + Hob.HandoffInformationTable->EfiFreeMemoryTop -= Offset; + } + + // + // Verify that there is sufficient memory to satisfy the allocation + // + if (Hob.HandoffInformationTable->EfiFreeMemoryTop - ((Pages * EFI_PAGE_SIZE) + sizeof (EFI_HOB_MEMORY_ALLOCATION)) < Hob.HandoffInformationTable->EfiFreeMemoryBottom) { + return 0; + } else { + // + // Update the PHIT to reflect the memory usage + // + Hob.HandoffInformationTable->EfiFreeMemoryTop -= Pages * EFI_PAGE_SIZE; + + // This routine used to create a memory allocation HOB a la PEI, but that's not + // necessary for us. + + // + // Create a memory allocation HOB. + // + BuildMemoryAllocationHob ( + Hob.HandoffInformationTable->EfiFreeMemoryTop, + Pages * EFI_PAGE_SIZE, + EfiBootServicesData + ); + return (VOID *)(UINTN)Hob.HandoffInformationTable->EfiFreeMemoryTop; + } +} + + +/** + Allocates one or more 4KB pages of type EfiBootServicesData at a specified alignment. + + Allocates the number of 4KB pages specified by Pages of type EfiBootServicesData with an + alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is + returned. If there is not enough memory at the specified alignment remaining to satisfy the + request, then NULL is returned. + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + + @param Pages The number of 4 KB pages to allocate. + @param Alignment The requested alignment of the allocation. Must be a power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateAlignedPages ( + IN UINTN Pages, + IN UINTN Alignment + ) +{ + VOID *Memory; + UINTN AlignmentMask; + + // + // Alignment must be a power of two or zero. + // + ASSERT ((Alignment & (Alignment - 1)) == 0); + + if (Pages == 0) { + return NULL; + } + // + // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow. + // + ASSERT (Pages <= (MAX_ADDRESS - EFI_SIZE_TO_PAGES (Alignment))); + // + // We would rather waste some memory to save PEI code size. + // + Memory = (VOID *)(UINTN)AllocatePages (Pages + EFI_SIZE_TO_PAGES (Alignment)); + if (Alignment == 0) { + AlignmentMask = Alignment; + } else { + AlignmentMask = Alignment - 1; + } + return (VOID *) (UINTN) (((UINTN) Memory + AlignmentMask) & ~AlignmentMask); +} + + +/** + Frees one or more 4KB pages that were previously allocated with one of the page allocation + functions in the Memory Allocation Library. + + Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer + must have been allocated on a previous call to the page allocation services of the Memory + Allocation Library. If it is not possible to free allocated pages, then this function will + perform no actions. + + If Buffer was not allocated with a page allocation function in the Memory Allocation Library, + then ASSERT(). + If Pages is zero, then ASSERT(). + + @param Buffer Pointer to the buffer of pages to free. + @param Pages The number of 4 KB pages to free. + +**/ +VOID +EFIAPI +FreePages ( + IN VOID *Buffer, + IN UINTN Pages + ) +{ + // For now, we do not support the ability to free pages in the PrePei Memory Allocator. + // The allocated memory is lost. +} + +/** + Allocates a buffer of type EfiBootServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiBootServicesData and returns a + pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is + returned. If there is not enough memory remaining to satisfy the request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocatePool ( + IN UINTN AllocationSize + ) +{ + EFI_HOB_MEMORY_POOL *Hob; + + Hob = GetHobList (); + + + // + // Verify that there is sufficient memory to satisfy the allocation + // + if (AllocationSize > 0x10000) { + // Please call AllocatePages for big allocations + return 0; + } else { + + Hob = (EFI_HOB_MEMORY_POOL *)CreateHob (EFI_HOB_TYPE_MEMORY_POOL, + (UINT16)(sizeof (EFI_HOB_MEMORY_POOL) + + AllocationSize)); + return (VOID *)(Hob + 1); + } +} + +/** + Allocates and zeros a buffer of type EfiBootServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, clears the + buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a + valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the + request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate and zero. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateZeroPool ( + IN UINTN AllocationSize + ) +{ + VOID *Buffer; + + Buffer = AllocatePool (AllocationSize); + if (Buffer == NULL) { + return NULL; + } + + ZeroMem (Buffer, AllocationSize); + + return Buffer; +} + +/** + Frees a buffer that was previously allocated with one of the pool allocation functions in the + Memory Allocation Library. + + Frees the buffer specified by Buffer. Buffer must have been allocated on a previous call to the + pool allocation services of the Memory Allocation Library. If it is not possible to free pool + resources, then this function will perform no actions. + + If Buffer was not allocated with a pool allocation function in the Memory Allocation Library, + then ASSERT(). + + @param Buffer Pointer to the buffer to free. + +**/ +VOID +EFIAPI +FreePool ( + IN VOID *Buffer + ) +{ + // Not implemented yet +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiMemoryAllocationLib/PrePiMemoryAllocationLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiMemoryAllocationLib/PrePiMemoryAllocationLib.inf new file mode 100644 index 00000000..034a9a46 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/PrePiMemoryAllocationLib/PrePiMemoryAllocationLib.inf @@ -0,0 +1,33 @@ +#/** @file +# +# Copyright (c) 2011, ARM Ltd. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PrePiMemoryAllocationLib + FILE_GUID = 4f14c900-51a9-11e0-afbf-0002a5d5c51b + MODULE_TYPE = SEC + VERSION_STRING = 1.0 + LIBRARY_CLASS = MemoryAllocationLib + + +# +# VALID_ARCHITECTURES = ARM +# + +[Sources] + MemoryAllocationLib.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + DebugLib + BaseMemoryLib + PrePiLib + #PeiServicesLib + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TemplateRealTimeClockLib/RealTimeClockLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TemplateRealTimeClockLib/RealTimeClockLib.c new file mode 100644 index 00000000..73c53411 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TemplateRealTimeClockLib/RealTimeClockLib.c @@ -0,0 +1,169 @@ +/** @file + Implement EFI RealTimeClock runtime services via RTC Lib. + + Currently this driver does not support runtime virtual calling. + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiDxe.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/IoLib.h> +#include <Library/RealTimeClockLib.h> + + +/** + Returns the current time and date information, and the time-keeping capabilities + of the hardware platform. + + @param Time A pointer to storage to receive a snapshot of the current time. + @param Capabilities An optional pointer to a buffer to receive the real time clock + device's capabilities. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER Time is NULL. + @retval EFI_DEVICE_ERROR The time could not be retrieved due to hardware error. + +**/ +EFI_STATUS +EFIAPI +LibGetTime ( + OUT EFI_TIME *Time, + OUT EFI_TIME_CAPABILITIES *Capabilities + ) +{ + // + // Fill in Time and Capabilities via data from you RTC + // + return EFI_DEVICE_ERROR; +} + + +/** + Sets the current local time and date information. + + @param Time A pointer to the current time. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER A time field is out of range. + @retval EFI_DEVICE_ERROR The time could not be set due due to hardware error. + +**/ +EFI_STATUS +EFIAPI +LibSetTime ( + IN EFI_TIME *Time + ) +{ + // + // Use Time, to set the time in your RTC hardware + // + return EFI_DEVICE_ERROR; +} + + +/** + Returns the current wakeup alarm clock setting. + + @param Enabled Indicates if the alarm is currently enabled or disabled. + @param Pending Indicates if the alarm signal is pending and requires acknowledgement. + @param Time The current alarm setting. + + @retval EFI_SUCCESS The alarm settings were returned. + @retval EFI_INVALID_PARAMETER Any parameter is NULL. + @retval EFI_DEVICE_ERROR The wakeup time could not be retrieved due to a hardware error. + +**/ +EFI_STATUS +EFIAPI +LibGetWakeupTime ( + OUT BOOLEAN *Enabled, + OUT BOOLEAN *Pending, + OUT EFI_TIME *Time + ) +{ + // Not a required feature + return EFI_UNSUPPORTED; +} + + +/** + Sets the system wakeup alarm clock time. + + @param Enabled Enable or disable the wakeup alarm. + @param Time If Enable is TRUE, the time to set the wakeup alarm for. + + @retval EFI_SUCCESS If Enable is TRUE, then the wakeup alarm was enabled. If + Enable is FALSE, then the wakeup alarm was disabled. + @retval EFI_INVALID_PARAMETER A time field is out of range. + @retval EFI_DEVICE_ERROR The wakeup time could not be set due to a hardware error. + @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform. + +**/ +EFI_STATUS +EFIAPI +LibSetWakeupTime ( + IN BOOLEAN Enabled, + OUT EFI_TIME *Time + ) +{ + // Not a required feature + return EFI_UNSUPPORTED; +} + + + +/** + This is the declaration of an EFI image entry point. This can be the entry point to an application + written to this specification, an EFI boot service driver, or an EFI runtime driver. + + @param ImageHandle Handle that identifies the loaded image. + @param SystemTable System Table for this image. + + @retval EFI_SUCCESS The operation completed successfully. + +**/ +EFI_STATUS +EFIAPI +LibRtcInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + // + // Do some initialization if required to turn on the RTC + // + return EFI_SUCCESS; +} + + +/** + Fixup internal data so that EFI can be call in virtual mode. + Call the passed in Child Notify event and convert any pointers in + lib to virtual mode. + + @param[in] Event The Event that is being processed + @param[in] Context Event Context +**/ +VOID +EFIAPI +LibRtcVirtualNotifyEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // + // Only needed if you are going to support the OS calling RTC functions in virtual mode. + // You will need to call EfiConvertPointer (). To convert any stored physical addresses + // to virtual address. After the OS transitions to calling in virtual mode, all future + // runtime calls will be made in virtual mode. + // + return; +} + + + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TemplateRealTimeClockLib/TemplateRealTimeClockLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TemplateRealTimeClockLib/TemplateRealTimeClockLib.inf new file mode 100644 index 00000000..6fa6cfb4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TemplateRealTimeClockLib/TemplateRealTimeClockLib.inf @@ -0,0 +1,31 @@ +#/** @file +# Memory Status Code Library for UEFI drivers +# +# Lib to provide memory journal status code reporting Routines +# Copyright (c) 2006, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TemplateRealTimeClockLib + FILE_GUID = B661E02D-A90B-42AB-A5F9-CF841AAA43D9 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RealTimeClockLib + + +[Sources.common] + RealTimeClockLib.c + + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + IoLib + DebugLib diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TemplateResetSystemLib/ResetSystemLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TemplateResetSystemLib/ResetSystemLib.c new file mode 100644 index 00000000..79d1732b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TemplateResetSystemLib/ResetSystemLib.c @@ -0,0 +1,97 @@ +/** @file + Template library implementation to support ResetSystem Runtime call. + + Fill in the templates with what ever makes you system reset. + + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include <PiDxe.h> + +#include <Library/BaseLib.h> +#include <Library/IoLib.h> +#include <Library/EfiResetSystemLib.h> + + +/** + Resets the entire platform. + + @param ResetType The type of reset to perform. + @param ResetStatus The status code for the reset. + @param DataSize The size, in bytes, of WatchdogData. + @param ResetData For a ResetType of EfiResetCold, EfiResetWarm, or + EfiResetShutdown the data buffer starts with a Null-terminated + Unicode string, optionally followed by additional binary data. + +**/ +EFI_STATUS +EFIAPI +LibResetSystem ( + IN EFI_RESET_TYPE ResetType, + IN EFI_STATUS ResetStatus, + IN UINTN DataSize, + IN CHAR16 *ResetData OPTIONAL + ) +{ + UINTN Address; + UINT8 Data; + + + switch (ResetType) { + case EfiResetCold: + // system power cycle + + // Example using IoLib functions to do IO. + Address = 0x12345678; + Data = MmioRead8 (Address); + MmioWrite8 (Address, Data | 0x01); + + // Note this is a bad example asa MmioOr8 (Address, 0x01) does the same thing + break; + + case EfiResetWarm: + // not a full power cycle, maybe memory stays around. + // if not support do the same thing as EfiResetCold. + break; + + case EfiResetShutdown: + // turn off the system. + // if not support do the same thing as EfiResetCold. + break; + + default: + return EFI_INVALID_PARAMETER; + } + + // + // If we reset, we would not have returned... + // + return EFI_DEVICE_ERROR; +} + + + +/** + Initialize any infrastructure required for LibResetSystem () to function. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS. + +**/ +EFI_STATUS +EFIAPI +LibInitializeResetSystem ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return EFI_SUCCESS; +} + diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TemplateResetSystemLib/TemplateResetSystemLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TemplateResetSystemLib/TemplateResetSystemLib.inf new file mode 100644 index 00000000..41e15641 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TemplateResetSystemLib/TemplateResetSystemLib.inf @@ -0,0 +1,30 @@ +#/** @file +# Memory Status Code Library for UEFI drivers +# +# Lib to provide memory journal status code reporting Routines +# Copyright (c) 2006, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TemplateResetSystemLib + FILE_GUID = 40BAFDE5-4CC8-4FBE-A8BA-071890076E50 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = EfiResetSystemLib + + +[Sources.common] + ResetSystemLib.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + IoLib + DebugLib diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.c new file mode 100644 index 00000000..2a3962c4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.c @@ -0,0 +1,289 @@ +/** @file +* +* Copyright (c) 2016, Hisilicon Limited. All rights reserved. +* Copyright (c) 2016-2019, Linaro Limited. All rights reserved. +* Copyright (c) 2021, Ampere Computing LLC. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#include <Uefi/UefiBaseType.h> +#include <Uefi/UefiSpec.h> +#include <Library/DebugLib.h> +#include <Library/TimeBaseLib.h> + +/** + Converts Epoch seconds (elapsed since 1970 JANUARY 01, 00:00:00 UTC) to EFI_TIME. + + @param EpochSeconds Epoch seconds. + @param Time The time converted to UEFI format. + +**/ +VOID +EFIAPI +EpochToEfiTime ( + IN UINTN EpochSeconds, + OUT EFI_TIME *Time + ) +{ + UINTN a; + UINTN b; + UINTN c; + UINTN d; + UINTN g; + UINTN j; + UINTN m; + UINTN y; + UINTN da; + UINTN db; + UINTN dc; + UINTN dg; + UINTN hh; + UINTN mm; + UINTN ss; + UINTN J; + + J = (EpochSeconds / 86400) + 2440588; + j = J + 32044; + g = j / 146097; + dg = j % 146097; + c = (((dg / 36524) + 1) * 3) / 4; + dc = dg - (c * 36524); + b = dc / 1461; + db = dc % 1461; + a = (((db / 365) + 1) * 3) / 4; + da = db - (a * 365); + y = (g * 400) + (c * 100) + (b * 4) + a; + m = (((da * 5) + 308) / 153) - 2; + d = da - (((m + 4) * 153) / 5) + 122; + + Time->Year = (UINT16)(y - 4800 + ((m + 2) / 12)); + Time->Month = ((m + 2) % 12) + 1; + Time->Day = (UINT8)(d + 1); + + ss = EpochSeconds % 60; + a = (EpochSeconds - ss) / 60; + mm = a % 60; + b = (a - mm) / 60; + hh = b % 24; + + Time->Hour = (UINT8)hh; + Time->Minute = (UINT8)mm; + Time->Second = (UINT8)ss; + Time->Nanosecond = 0; + +} + +/** + Calculate Epoch days. + + @param Time The UEFI time to be calculated. + + @return Number of days. + +**/ +UINTN +EFIAPI +EfiGetEpochDays ( + IN EFI_TIME *Time + ) +{ + UINTN a; + UINTN y; + UINTN m; + UINTN JulianDate; // Absolute Julian Date representation of the supplied Time + UINTN EpochDays; // Number of days elapsed since EPOCH_JULIAN_DAY + + a = (14 - Time->Month) / 12 ; + y = Time->Year + 4800 - a; + m = Time->Month + (12*a) - 3; + + JulianDate = Time->Day + ((153*m + 2)/5) + (365*y) + (y/4) - (y/100) + (y/400) - 32045; + + ASSERT (JulianDate >= EPOCH_JULIAN_DATE); + EpochDays = JulianDate - EPOCH_JULIAN_DATE; + + return EpochDays; +} + +/** + Converts EFI_TIME to Epoch seconds (elapsed since 1970 JANUARY 01, 00:00:00 UTC). + + @param Time The UEFI time to be converted. + + @return Number of seconds. + +**/ +UINTN +EFIAPI +EfiTimeToEpoch ( + IN EFI_TIME *Time + ) +{ + UINTN EpochDays; // Number of days elapsed since EPOCH_JULIAN_DAY + UINTN EpochSeconds; + + EpochDays = EfiGetEpochDays (Time); + + EpochSeconds = (EpochDays * SEC_PER_DAY) + ((UINTN)Time->Hour * SEC_PER_HOUR) + (Time->Minute * SEC_PER_MIN) + Time->Second; + + return EpochSeconds; +} + +/** + Get the day of the week from the UEFI time. + + @param Time The UEFI time to be calculated. + + @return The day of the week: Sunday=0, Monday=1, ... Saturday=6 + +**/ +UINTN +EfiTimeToWday ( + IN EFI_TIME *Time + ) +{ + UINTN EpochDays; // Number of days elapsed since EPOCH_JULIAN_DAY + + EpochDays = EfiGetEpochDays (Time); + + // 4=1/1/1970 was a Thursday + + return (EpochDays + 4) % 7; +} + +/** + Check if it is a leap year. + + @param Time The UEFI time to be checked. + + @retval TRUE It is a leap year. + @retval FALSE It is NOT a leap year. + +**/ +BOOLEAN +EFIAPI +IsLeapYear ( + IN EFI_TIME *Time + ) +{ + if (Time->Year % 4 == 0) { + if (Time->Year % 100 == 0) { + if (Time->Year % 400 == 0) { + return TRUE; + } else { + return FALSE; + } + } else { + return TRUE; + } + } else { + return FALSE; + } +} + +/** + Check if the day in the UEFI time is valid. + + @param Time The UEFI time to be checked. + + @retval TRUE Valid. + @retval FALSE Invalid. + +**/ +BOOLEAN +EFIAPI +IsDayValid ( + IN EFI_TIME *Time + ) +{ + STATIC CONST INTN DayOfMonth[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + + if (Time->Day < 1 || + Time->Day > DayOfMonth[Time->Month - 1] || + (Time->Month == 2 && (!IsLeapYear (Time) && Time->Day > 28)) + ) { + return FALSE; + } + + return TRUE; +} + +/** + Check if the time zone is valid. + Valid values are between -1440 and 1440 or 2047 (EFI_UNSPECIFIED_TIMEZONE). + + @param TimeZone The time zone to be checked. + + @retval TRUE Valid. + @retval FALSE Invalid. + +**/ +BOOLEAN +EFIAPI +IsValidTimeZone ( + IN INT16 TimeZone + ) +{ + return TimeZone == EFI_UNSPECIFIED_TIMEZONE || + (TimeZone >= -1440 && TimeZone <= 1440); +} + +/** + Check if the daylight is valid. + Valid values are: + 0 : Time is not affected. + 1 : Time is affected, and has not been adjusted for daylight savings. + 3 : Time is affected, and has been adjusted for daylight savings. + All other values are invalid. + + @param Daylight The daylight to be checked. + + @retval TRUE Valid. + @retval FALSE Invalid. + +**/ +BOOLEAN +EFIAPI +IsValidDaylight ( + IN INT8 Daylight + ) +{ + return Daylight == 0 || + Daylight == EFI_TIME_ADJUST_DAYLIGHT || + Daylight == (EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT); +} + +/** + Check if the UEFI time is valid. + + @param Time The UEFI time to be checked. + + @retval TRUE Valid. + @retval FALSE Invalid. + +**/ +BOOLEAN +EFIAPI +IsTimeValid ( + IN EFI_TIME *Time + ) +{ + // Check the input parameters are within the range specified by UEFI + if ((Time->Year < 2000) || + (Time->Year > 2099) || + (Time->Month < 1 ) || + (Time->Month > 12 ) || + (!IsDayValid (Time) ) || + (Time->Hour > 23 ) || + (Time->Minute > 59 ) || + (Time->Second > 59 ) || + (Time->Nanosecond > 999999999) || + (!IsValidTimeZone(Time->TimeZone)) || + (!IsValidDaylight(Time->Daylight))) { + return FALSE; + } + + return TRUE; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.inf new file mode 100644 index 00000000..249da54b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.inf @@ -0,0 +1,28 @@ +#/** @file +# +# Copyright (c) 2016, Hisilicon Limited. All rights reserved. +# Copyright (c) 2016, Linaro Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TimeBaseLib + FILE_GUID = B1B07E01-6896-448C-8E75-F0E119ABDF49 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = TimeBaseLib + +[Sources.common] + TimeBaseLib.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + DebugLib + +[Pcd] diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c new file mode 100644 index 00000000..c93bf408 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.c @@ -0,0 +1,418 @@ +/** @file + * + * Implement virtual EFI RealTimeClock runtime services. + * + * Coypright (c) 2019, Pete Batard <pete@akeo.ie> + * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com> + * Copyright (c) 2011-2014, ARM Ltd. All rights reserved. + * Copyright (c) 2008-2010, Apple Inc. All rights reserved. + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + * Based on ArmPlatformPkg/Library/PL031RealTimeClockLib/PL031RealTimeClockLib.inf + * + **/ + +#include <PiDxe.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/IoLib.h> +#include <Library/RealTimeClockLib.h> +#include <Library/TimerLib.h> +#include <Library/TimeBaseLib.h> +#include <Library/UefiRuntimeLib.h> + +STATIC CONST CHAR16 mEpochVariableName[] = L"RtcEpochSeconds"; +STATIC CONST CHAR16 mTimeZoneVariableName[] = L"RtcTimeZone"; +STATIC CONST CHAR16 mDaylightVariableName[] = L"RtcDaylight"; + +/** + Returns the current time and date information, and the time-keeping capabilities + of the virtual RTC. + + @param Time A pointer to storage to receive a snapshot of the current time. + @param Capabilities An optional pointer to a buffer to receive the real time clock + device's capabilities. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER Time is NULL. + @retval EFI_DEVICE_ERROR The time could not be retrieved due to hardware error. + +**/ +EFI_STATUS +EFIAPI +LibGetTime ( + OUT EFI_TIME *Time, + OUT EFI_TIME_CAPABILITIES *Capabilities + ) +{ + EFI_STATUS Status; + INT16 TimeZone; + UINT8 Daylight; + UINT64 Freq; + UINT64 Counter; + UINT64 Remainder; + UINTN EpochSeconds; + UINTN Size; + + if (Time == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Get the counter frequency + Freq = GetPerformanceCounterProperties (NULL, NULL); + if (Freq == 0) { + return EFI_DEVICE_ERROR; + } + + // Get the epoch time from non-volatile storage + Size = sizeof (UINTN); + EpochSeconds = 0; + Status = EfiGetVariable ( + (CHAR16 *)mEpochVariableName, + &gEfiCallerIdGuid, + NULL, + &Size, + (VOID *)&EpochSeconds + ); + // Fall back to compilation-time epoch if not set + if (EFI_ERROR (Status)) { + ASSERT(Status != EFI_INVALID_PARAMETER); + ASSERT(Status != EFI_BUFFER_TOO_SMALL); + // + // The following is intended to produce a compilation error on build + // environments where BUILD_EPOCH can not be set from inline shell. + // If you are attempting to use this library on such an environment, please + // contact the edk2 mailing list, so we can try to add support for it. + // + EpochSeconds = BUILD_EPOCH; + DEBUG (( + DEBUG_INFO, + "LibGetTime: %s non volatile variable was not found - Using compilation time epoch.\n", + mEpochVariableName + )); + + EfiSetVariable ( + (CHAR16 *)mEpochVariableName, + &gEfiCallerIdGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof (EpochSeconds), + &EpochSeconds + ); + } + Counter = GetPerformanceCounter (); + EpochSeconds += DivU64x64Remainder (Counter, Freq, &Remainder); + + // Get the current time zone information from non-volatile storage + Size = sizeof (TimeZone); + Status = EfiGetVariable ( + (CHAR16 *)mTimeZoneVariableName, + &gEfiCallerIdGuid, + NULL, + &Size, + (VOID *)&TimeZone + ); + + if (EFI_ERROR (Status)) { + ASSERT(Status != EFI_INVALID_PARAMETER); + ASSERT(Status != EFI_BUFFER_TOO_SMALL); + + if (Status != EFI_NOT_FOUND) { + return Status; + } + + // The time zone variable does not exist in non-volatile storage, so create it. + Time->TimeZone = EFI_UNSPECIFIED_TIMEZONE; + // Store it + Status = EfiSetVariable ( + (CHAR16 *)mTimeZoneVariableName, + &gEfiCallerIdGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + Size, + (VOID *)&(Time->TimeZone) + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "LibGetTime: Failed to save %s variable to non-volatile storage, Status = %r\n", + mTimeZoneVariableName, + Status + )); + return Status; + } + } else { + // Got the time zone + Time->TimeZone = TimeZone; + + // Check TimeZone bounds: -1440 to 1440 or 2047 + if (((Time->TimeZone < -1440) || (Time->TimeZone > 1440)) + && (Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE)) { + Time->TimeZone = EFI_UNSPECIFIED_TIMEZONE; + } + + // Adjust for the correct time zone + if (Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE) { + EpochSeconds += Time->TimeZone * SEC_PER_MIN; + } + } + + // Get the current daylight information from non-volatile storage + Size = sizeof (Daylight); + Status = EfiGetVariable ( + (CHAR16 *)mDaylightVariableName, + &gEfiCallerIdGuid, + NULL, + &Size, + (VOID *)&Daylight + ); + + if (EFI_ERROR (Status)) { + ASSERT(Status != EFI_INVALID_PARAMETER); + ASSERT(Status != EFI_BUFFER_TOO_SMALL); + + if (Status != EFI_NOT_FOUND) { + return Status; + } + + // The daylight variable does not exist in non-volatile storage, so create it. + Time->Daylight = 0; + // Store it + Status = EfiSetVariable ( + (CHAR16 *)mDaylightVariableName, + &gEfiCallerIdGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + Size, + (VOID *)&(Time->Daylight) + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "LibGetTime: Failed to save %s variable to non-volatile storage, Status = %r\n", + mDaylightVariableName, + Status + )); + return Status; + } + } else { + // Got the daylight information + Time->Daylight = Daylight; + + // Adjust for the correct period + if ((Time->Daylight & EFI_TIME_IN_DAYLIGHT) == EFI_TIME_IN_DAYLIGHT) { + // Convert to adjusted time, i.e. spring forwards one hour + EpochSeconds += SEC_PER_HOUR; + } + } + + EpochToEfiTime (EpochSeconds, Time); + + // Because we use the performance counter, we can fill the Nanosecond attribute + // provided that the remainder doesn't overflow 64-bit during multiplication. + if (Remainder <= 18446744073U) { + Time->Nanosecond = (UINT32)(MultU64x64 (Remainder, 1000000000U) / Freq); + } else { + DEBUG ((DEBUG_WARN, "LibGetTime: Nanosecond value not set (64-bit overflow).\n")); + } + + if (Capabilities) { + Capabilities->Accuracy = 0; + Capabilities->Resolution = 1; + Capabilities->SetsToZero = FALSE; + } + + return EFI_SUCCESS; +} + +/** + Sets the current local time and date information. + + @param Time A pointer to the current time. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER A time field is out of range. + @retval EFI_DEVICE_ERROR The time could not be set due due to hardware error. + +**/ +EFI_STATUS +EFIAPI +LibSetTime ( + IN EFI_TIME *Time + ) +{ + EFI_STATUS Status; + UINT64 Freq; + UINT64 Counter; + UINT64 Remainder; + UINTN EpochSeconds; + + if (!IsTimeValid (Time)) { + return EFI_INVALID_PARAMETER; + } + + EpochSeconds = EfiTimeToEpoch (Time); + + // Adjust for the correct time zone, i.e. convert to UTC time zone + if ((Time->TimeZone != EFI_UNSPECIFIED_TIMEZONE) + && (EpochSeconds > Time->TimeZone * SEC_PER_MIN)) { + EpochSeconds -= Time->TimeZone * SEC_PER_MIN; + } + + // Adjust for the correct period + if (((Time->Daylight & EFI_TIME_IN_DAYLIGHT) == EFI_TIME_IN_DAYLIGHT) + && (EpochSeconds > SEC_PER_HOUR)) { + // Convert to un-adjusted time, i.e. fall back one hour + EpochSeconds -= SEC_PER_HOUR; + } + + // Use the performance counter to subtract the number of seconds + // since platform reset. Without this, setting time from the shell + // and immediately reading it back would result in a forward time + // offset, of the duration during which the platform has been up. + Freq = GetPerformanceCounterProperties (NULL, NULL); + if (Freq != 0) { + Counter = GetPerformanceCounter (); + if (EpochSeconds > DivU64x64Remainder (Counter, Freq, &Remainder)) { + EpochSeconds -= DivU64x64Remainder (Counter, Freq, &Remainder); + } + } + + // Save the current time zone information into non-volatile storage + Status = EfiSetVariable ( + (CHAR16 *)mTimeZoneVariableName, + &gEfiCallerIdGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof (Time->TimeZone), + (VOID *)&(Time->TimeZone) + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "LibSetTime: Failed to save %s variable to non-volatile storage, Status = %r\n", + mTimeZoneVariableName, + Status + )); + return Status; + } + + // Save the current daylight information into non-volatile storage + Status = EfiSetVariable ( + (CHAR16 *)mDaylightVariableName, + &gEfiCallerIdGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof(Time->Daylight), + (VOID *)&(Time->Daylight) + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "LibSetTime: Failed to save %s variable to non-volatile storage, Status = %r\n", + mDaylightVariableName, + Status + )); + return Status; + } + + Status = EfiSetVariable ( + (CHAR16 *)mEpochVariableName, + &gEfiCallerIdGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof (EpochSeconds), + &EpochSeconds + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "LibSetTime: Failed to save %s variable to non-volatile storage, Status = %r\n", + mDaylightVariableName, + Status + )); + return Status; + } + + return EFI_SUCCESS; +} + +/** + Returns the current wakeup alarm clock setting. + + @param Enabled Indicates if the alarm is currently enabled or disabled. + @param Pending Indicates if the alarm signal is pending and requires acknowledgement. + @param Time The current alarm setting. + + @retval EFI_SUCCESS The alarm settings were returned. + @retval EFI_INVALID_PARAMETER Any parameter is NULL. + @retval EFI_DEVICE_ERROR The wakeup time could not be retrieved due to a hardware error. + +**/ +EFI_STATUS +EFIAPI +LibGetWakeupTime ( + OUT BOOLEAN *Enabled, + OUT BOOLEAN *Pending, + OUT EFI_TIME *Time + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Sets the system wakeup alarm clock time. + + @param Enabled Enable or disable the wakeup alarm. + @param Time If Enable is TRUE, the time to set the wakeup alarm for. + + @retval EFI_SUCCESS If Enable is TRUE, then the wakeup alarm was enabled. If + Enable is FALSE, then the wakeup alarm was disabled. + @retval EFI_INVALID_PARAMETER A time field is out of range. + @retval EFI_DEVICE_ERROR The wakeup time could not be set due to a hardware error. + @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform. + +**/ +EFI_STATUS +EFIAPI +LibSetWakeupTime ( + IN BOOLEAN Enabled, + OUT EFI_TIME *Time + ) +{ + return EFI_UNSUPPORTED; +} + +/** + This is the declaration of an EFI image entry point. This can be the entry point to an application + written to this specification, an EFI boot service driver, or an EFI runtime driver. + + @param ImageHandle Handle that identifies the loaded image. + @param SystemTable System Table for this image. + + @retval EFI_SUCCESS The operation completed successfully. + +**/ +EFI_STATUS +EFIAPI +LibRtcInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return EFI_SUCCESS; +} + +/** + Fixup internal data so that EFI can be call in virtual mode. + Call the passed in Child Notify event and convert any pointers in + lib to virtual mode. + + @param[in] Event The Event that is being processed + @param[in] Context Event Context +**/ +VOID +EFIAPI +LibRtcVirtualNotifyEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + return; +} diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.inf new file mode 100644 index 00000000..873b8de6 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.inf @@ -0,0 +1,37 @@ +#/** @file +# +# Implement virtual EFI RealTimeClock runtime services. +# +# Copyright (c) 2019, Pete Batard <pete@akeo.ie> +# Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com> +# Copyright (c) Microsoft Corporation. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = VirtualRealTimeClockLib + FILE_GUID = 1E27D461-78F3-4F7D-B1C2-F72384F13A6E + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RealTimeClockLib + +[Sources.common] + VirtualRealTimeClockLib.c + +[Packages] + MdePkg/MdePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + +[LibraryClasses] + IoLib + DebugLib + TimerLib + TimeBaseLib + UefiRuntimeLib + +# Current usage of this library expects GCC in a UNIX-like shell environment with the date command +[BuildOptions] + GCC:*_*_*_CC_FLAGS = -DBUILD_EPOCH=`date +%s` |