* [PATCH edk2-platforms 1/4] Platform/ARM: import BdsLib from ArmPkg
2017-11-20 11:37 [PATCH edk2-platforms 0/4] Platform/ARM: import BdsLib and FdtPlatformDxe Ard Biesheuvel
@ 2017-11-20 11:37 ` Ard Biesheuvel
2017-11-20 11:37 ` [PATCH edk2-platforms 2/4] Platform/ARM: import FdtPlatformDxe driver from EDK2 Ard Biesheuvel
` (3 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Ard Biesheuvel @ 2017-11-20 11:37 UTC (permalink / raw)
To: edk2-devel; +Cc: leif.lindholm, Ard Biesheuvel
We are about to migrate the only remaining user of the deprecated ARM
BdsLib, i.e., FdtPlatformDxe, into Platform/ARM. So create our own
copy of BdsLib, allowing us to finally remove it from upstream EDK2.
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
Platform/ARM/Library/BdsLib/BdsAppLoader.c | 253 ++++
Platform/ARM/Library/BdsLib/BdsFilePath.c | 1413 ++++++++++++++++++++
Platform/ARM/Library/BdsLib/BdsHelper.c | 183 +++
Platform/ARM/Library/BdsLib/BdsInternal.h | 111 ++
Platform/ARM/Library/BdsLib/BdsLib.inf | 62 +
Platform/ARM/Library/BdsLib/BdsLoadOption.c | 272 ++++
6 files changed, 2294 insertions(+)
diff --git a/Platform/ARM/Library/BdsLib/BdsAppLoader.c b/Platform/ARM/Library/BdsLib/BdsAppLoader.c
new file mode 100644
index 000000000000..1f208f8dd796
--- /dev/null
+++ b/Platform/ARM/Library/BdsLib/BdsAppLoader.c
@@ -0,0 +1,253 @@
+/** @file
+*
+* Copyright (c) 2011-2015, ARM Limited. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include "BdsInternal.h"
+
+/**
+ Locate an EFI application in a the Firmware Volumes by its Name
+
+ @param EfiAppGuid Guid of the EFI Application into the Firmware Volume
+ @param DevicePath EFI Device Path of the EFI application
+
+ @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
+LocateEfiApplicationInFvByName (
+ IN CONST CHAR16* EfiAppName,
+ OUT EFI_DEVICE_PATH **DevicePath
+ )
+{
+ VOID *Key;
+ EFI_STATUS Status, FileStatus;
+ EFI_GUID NameGuid;
+ EFI_FV_FILETYPE FileType;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ UINTN Size;
+ UINTN UiStringLen;
+ CHAR16 *UiSection;
+ UINT32 Authentication;
+ EFI_DEVICE_PATH *FvDevicePath;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileDevicePath;
+ EFI_HANDLE *HandleBuffer;
+ UINTN NumberOfHandles;
+ UINTN Index;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *FvInstance;
+
+ ASSERT (DevicePath != NULL);
+
+ // Length of FilePath
+ UiStringLen = StrLen (EfiAppName);
+
+ // Locate all the Firmware Volume protocols.
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ &NumberOfHandles,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *DevicePath = NULL;
+
+ // 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;
+ }
+
+ // Allocate Key
+ Key = AllocatePool (FvInstance->KeySize);
+ ASSERT (Key != NULL);
+ ZeroMem (Key, FvInstance->KeySize);
+
+ do {
+ // Search in all files
+ FileType = EFI_FV_FILETYPE_ALL;
+
+ Status = FvInstance->GetNextFile (FvInstance, Key, &FileType, &NameGuid, &Attributes, &Size);
+ if (!EFI_ERROR (Status)) {
+ UiSection = NULL;
+ FileStatus = FvInstance->ReadSection (
+ FvInstance,
+ &NameGuid,
+ EFI_SECTION_USER_INTERFACE,
+ 0,
+ (VOID **)&UiSection,
+ &Size,
+ &Authentication
+ );
+ if (!EFI_ERROR (FileStatus)) {
+ if (StrnCmp (EfiAppName, UiSection, UiStringLen) == 0) {
+ //
+ // We found a UiString match.
+ //
+ Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);
+
+ // Generate the Device Path for the file
+ EfiInitializeFwVolDevicepathNode (&FileDevicePath, &NameGuid);
+ *DevicePath = AppendDevicePathNode (FvDevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&FileDevicePath);
+ ASSERT (*DevicePath != NULL);
+
+ FreePool (Key);
+ FreePool (UiSection);
+ FreePool (HandleBuffer);
+ return FileStatus;
+ }
+ FreePool (UiSection);
+ }
+ }
+ } while (!EFI_ERROR (Status));
+
+ FreePool (Key);
+ }
+
+FREE_HANDLE_BUFFER:
+ FreePool (HandleBuffer);
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Locate an EFI application in a the Firmware Volumes by its GUID
+
+ @param EfiAppGuid Guid of the EFI Application into the Firmware Volume
+ @param DevicePath EFI Device Path of the EFI application
+
+ @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
+LocateEfiApplicationInFvByGuid (
+ IN CONST EFI_GUID *EfiAppGuid,
+ OUT EFI_DEVICE_PATH **DevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH *FvDevicePath;
+ EFI_HANDLE *HandleBuffer;
+ UINTN NumberOfHandles;
+ UINTN Index;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *FvInstance;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ UINT32 AuthenticationStatus;
+ EFI_FV_FILETYPE Type;
+ UINTN Size;
+ CHAR16 *UiSection;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FvFileDevicePath;
+
+ ASSERT (DevicePath != NULL);
+
+ // Locate all the Firmware Volume protocols.
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ &NumberOfHandles,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *DevicePath = NULL;
+
+ // 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;
+ }
+
+ Status = FvInstance->ReadFile (
+ FvInstance,
+ EfiAppGuid,
+ NULL,
+ &Size,
+ &Type,
+ &Attributes,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Skip if no EFI application file in the FV
+ //
+ continue;
+ } else {
+ UiSection = NULL;
+ Status = FvInstance->ReadSection (
+ FvInstance,
+ EfiAppGuid,
+ EFI_SECTION_USER_INTERFACE,
+ 0,
+ (VOID **)&UiSection,
+ &Size,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Create the EFI Device Path for the application using the Filename of the application
+ //
+ *DevicePath = FileDevicePath (HandleBuffer[Index], UiSection);
+ } else {
+ Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID**)&FvDevicePath);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Create the EFI Device Path for the application using the EFI GUID of the application
+ //
+ EfiInitializeFwVolDevicepathNode (&FvFileDevicePath, EfiAppGuid);
+
+ *DevicePath = AppendDevicePathNode (FvDevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&FvFileDevicePath);
+ ASSERT (*DevicePath != NULL);
+ }
+ break;
+ }
+ }
+
+FREE_HANDLE_BUFFER:
+ //
+ // Free any allocated buffers
+ //
+ FreePool (HandleBuffer);
+
+ if (*DevicePath == NULL) {
+ return EFI_NOT_FOUND;
+ } else {
+ return EFI_SUCCESS;
+ }
+}
diff --git a/Platform/ARM/Library/BdsLib/BdsFilePath.c b/Platform/ARM/Library/BdsLib/BdsFilePath.c
new file mode 100644
index 000000000000..7a4a5052a786
--- /dev/null
+++ b/Platform/ARM/Library/BdsLib/BdsFilePath.c
@@ -0,0 +1,1413 @@
+/** @file
+*
+* Copyright (c) 2011-2014, ARM Limited. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include "BdsInternal.h"
+
+#include <Library/NetLib.h>
+
+#include <Protocol/Bds.h>
+#include <Protocol/UsbIo.h>
+#include <Protocol/DiskIo.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/SimpleNetwork.h>
+#include <Protocol/Dhcp4.h>
+#include <Protocol/Mtftp4.h>
+
+#define MAX_TFTP_FILE_SIZE 0x01000000
+
+/* Type and defines to set up the DHCP4 options */
+
+typedef struct {
+ EFI_DHCP4_PACKET_OPTION Head;
+ UINT8 Route;
+} DHCP4_OPTION;
+
+#define DHCP_TAG_PARA_LIST 55
+#define DHCP_TAG_NETMASK 1
+#define DHCP_TAG_ROUTER 3
+
+/*
+ Constant strings and define related to the message indicating the amount of
+ progress in the dowloading of a TFTP file.
+*/
+
+// Frame for the progression slider
+STATIC CONST CHAR16 mTftpProgressFrame[] = L"[ ]";
+
+// Number of steps in the progression slider
+#define TFTP_PROGRESS_SLIDER_STEPS ((sizeof (mTftpProgressFrame) / sizeof (CHAR16)) - 3)
+
+// Size in number of characters plus one (final zero) of the message to
+// indicate the progress of a tftp download. The format is "[(progress slider:
+// 40 characters)] (nb of KBytes downloaded so far: 7 characters) Kb". There
+// are thus the number of characters in mTftpProgressFrame[] plus 11 characters
+// (2 // spaces, "Kb" and seven characters for the number of KBytes).
+#define TFTP_PROGRESS_MESSAGE_SIZE ((sizeof (mTftpProgressFrame) / sizeof (CHAR16)) + 12)
+
+// String to delete the tftp progress message to be able to update it :
+// (TFTP_PROGRESS_MESSAGE_SIZE-1) '\b'
+STATIC CONST CHAR16 mTftpProgressDelete[] = L"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";
+
+
+// Extract the FilePath from the Device Path
+CHAR16*
+BdsExtractFilePathFromDevicePath (
+ IN CONST CHAR16 *StrDevicePath,
+ IN UINTN NumberDevicePathNode
+ )
+{
+ UINTN Node;
+ CHAR16 *Str;
+
+ Str = (CHAR16*)StrDevicePath;
+ Node = 0;
+ while ((Str != NULL) && (*Str != L'\0') && (Node < NumberDevicePathNode)) {
+ if ((*Str == L'/') || (*Str == L'\\')) {
+ Node++;
+ }
+ Str++;
+ }
+
+ if (*Str == L'\0') {
+ return NULL;
+ } else {
+ return Str;
+ }
+}
+
+BOOLEAN
+BdsIsRemovableUsb (
+ IN EFI_DEVICE_PATH* DevicePath
+ )
+{
+ return ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
+ ((DevicePathSubType (DevicePath) == MSG_USB_CLASS_DP) ||
+ (DevicePathSubType (DevicePath) == MSG_USB_WWID_DP)));
+}
+
+EFI_STATUS
+BdsGetDeviceUsb (
+ IN EFI_DEVICE_PATH* RemovableDevicePath,
+ OUT EFI_HANDLE* DeviceHandle,
+ OUT EFI_DEVICE_PATH** NewDevicePath
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN UsbIoHandleCount;
+ EFI_HANDLE *UsbIoBuffer;
+ EFI_DEVICE_PATH* UsbIoDevicePath;
+ EFI_DEVICE_PATH* TmpDevicePath;
+ USB_WWID_DEVICE_PATH* WwidDevicePath1;
+ USB_WWID_DEVICE_PATH* WwidDevicePath2;
+ USB_CLASS_DEVICE_PATH* UsbClassDevicePath1;
+ USB_CLASS_DEVICE_PATH* UsbClassDevicePath2;
+
+ // Get all the UsbIo handles
+ UsbIoHandleCount = 0;
+ Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiUsbIoProtocolGuid, NULL, &UsbIoHandleCount, &UsbIoBuffer);
+ if (EFI_ERROR (Status) || (UsbIoHandleCount == 0)) {
+ return Status;
+ }
+
+ // Check if one of the handles matches the USB description
+ for (Index = 0; Index < UsbIoHandleCount; Index++) {
+ Status = gBS->HandleProtocol (UsbIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **) &UsbIoDevicePath);
+ if (!EFI_ERROR (Status)) {
+ TmpDevicePath = UsbIoDevicePath;
+ while (!IsDevicePathEnd (TmpDevicePath)) {
+ // Check if the Device Path node is a USB Removable device Path node
+ if (BdsIsRemovableUsb (TmpDevicePath)) {
+ if (TmpDevicePath->SubType == MSG_USB_WWID_DP) {
+ WwidDevicePath1 = (USB_WWID_DEVICE_PATH*)RemovableDevicePath;
+ WwidDevicePath2 = (USB_WWID_DEVICE_PATH*)TmpDevicePath;
+ if ((WwidDevicePath1->VendorId == WwidDevicePath2->VendorId) &&
+ (WwidDevicePath1->ProductId == WwidDevicePath2->ProductId) &&
+ (CompareMem (WwidDevicePath1+1, WwidDevicePath2+1, DevicePathNodeLength(WwidDevicePath1)-sizeof (USB_WWID_DEVICE_PATH)) == 0))
+ {
+ *DeviceHandle = UsbIoBuffer[Index];
+ // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
+ *NewDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePathNode (RemovableDevicePath));
+ return EFI_SUCCESS;
+ }
+ } else {
+ UsbClassDevicePath1 = (USB_CLASS_DEVICE_PATH*)RemovableDevicePath;
+ UsbClassDevicePath2 = (USB_CLASS_DEVICE_PATH*)TmpDevicePath;
+ if ((UsbClassDevicePath1->VendorId != 0xFFFF) && (UsbClassDevicePath1->VendorId == UsbClassDevicePath2->VendorId) &&
+ (UsbClassDevicePath1->ProductId != 0xFFFF) && (UsbClassDevicePath1->ProductId == UsbClassDevicePath2->ProductId) &&
+ (UsbClassDevicePath1->DeviceClass != 0xFF) && (UsbClassDevicePath1->DeviceClass == UsbClassDevicePath2->DeviceClass) &&
+ (UsbClassDevicePath1->DeviceSubClass != 0xFF) && (UsbClassDevicePath1->DeviceSubClass == UsbClassDevicePath2->DeviceSubClass) &&
+ (UsbClassDevicePath1->DeviceProtocol != 0xFF) && (UsbClassDevicePath1->DeviceProtocol == UsbClassDevicePath2->DeviceProtocol))
+ {
+ *DeviceHandle = UsbIoBuffer[Index];
+ // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
+ *NewDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePathNode (RemovableDevicePath));
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ TmpDevicePath = NextDevicePathNode (TmpDevicePath);
+ }
+
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+BOOLEAN
+BdsIsRemovableHd (
+ IN EFI_DEVICE_PATH* DevicePath
+ )
+{
+ return IS_DEVICE_PATH_NODE (DevicePath, MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP);
+}
+
+EFI_STATUS
+BdsGetDeviceHd (
+ IN EFI_DEVICE_PATH* RemovableDevicePath,
+ OUT EFI_HANDLE* DeviceHandle,
+ OUT EFI_DEVICE_PATH** NewDevicePath
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN PartitionHandleCount;
+ EFI_HANDLE *PartitionBuffer;
+ EFI_DEVICE_PATH* PartitionDevicePath;
+ EFI_DEVICE_PATH* TmpDevicePath;
+ HARDDRIVE_DEVICE_PATH* HardDriveDevicePath1;
+ HARDDRIVE_DEVICE_PATH* HardDriveDevicePath2;
+
+ // Get all the DiskIo handles
+ PartitionHandleCount = 0;
+ Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiDiskIoProtocolGuid, NULL, &PartitionHandleCount, &PartitionBuffer);
+ if (EFI_ERROR (Status) || (PartitionHandleCount == 0)) {
+ return Status;
+ }
+
+ // Check if one of the handles matches the Hard Disk Description
+ for (Index = 0; Index < PartitionHandleCount; Index++) {
+ Status = gBS->HandleProtocol (PartitionBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **) &PartitionDevicePath);
+ if (!EFI_ERROR (Status)) {
+ TmpDevicePath = PartitionDevicePath;
+ while (!IsDevicePathEnd (TmpDevicePath)) {
+ // Check if the Device Path node is a HD Removable device Path node
+ if (BdsIsRemovableHd (TmpDevicePath)) {
+ HardDriveDevicePath1 = (HARDDRIVE_DEVICE_PATH*)RemovableDevicePath;
+ HardDriveDevicePath2 = (HARDDRIVE_DEVICE_PATH*)TmpDevicePath;
+ if ((HardDriveDevicePath1->SignatureType == HardDriveDevicePath2->SignatureType) &&
+ (CompareGuid ((EFI_GUID *)HardDriveDevicePath1->Signature, (EFI_GUID *)HardDriveDevicePath2->Signature) == TRUE) &&
+ (HardDriveDevicePath1->PartitionNumber == HardDriveDevicePath2->PartitionNumber))
+ {
+ *DeviceHandle = PartitionBuffer[Index];
+ // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path
+ *NewDevicePath = AppendDevicePath (PartitionDevicePath, NextDevicePathNode (RemovableDevicePath));
+ return EFI_SUCCESS;
+ }
+ }
+ TmpDevicePath = NextDevicePathNode (TmpDevicePath);
+ }
+
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/*BOOLEAN
+BdsIsRemovableCdrom (
+ IN EFI_DEVICE_PATH* DevicePath
+ )
+{
+ return IS_DEVICE_PATH_NODE (DevicePath, MEDIA_DEVICE_PATH, MEDIA_CDROM_DP);
+}
+
+EFI_STATUS
+BdsGetDeviceCdrom (
+ IN EFI_DEVICE_PATH* RemovableDevicePath,
+ OUT EFI_HANDLE* DeviceHandle,
+ OUT EFI_DEVICE_PATH** DevicePath
+ )
+{
+ ASSERT(0);
+ return EFI_UNSUPPORTED;
+}*/
+
+typedef BOOLEAN
+(*BDS_IS_REMOVABLE) (
+ IN EFI_DEVICE_PATH* DevicePath
+ );
+
+typedef EFI_STATUS
+(*BDS_GET_DEVICE) (
+ IN EFI_DEVICE_PATH* RemovableDevicePath,
+ OUT EFI_HANDLE* DeviceHandle,
+ OUT EFI_DEVICE_PATH** DevicePath
+ );
+
+typedef struct {
+ BDS_IS_REMOVABLE IsRemovable;
+ BDS_GET_DEVICE GetDevice;
+} BDS_REMOVABLE_DEVICE_SUPPORT;
+
+BDS_REMOVABLE_DEVICE_SUPPORT RemovableDeviceSupport[] = {
+ { BdsIsRemovableUsb, BdsGetDeviceUsb },
+ { BdsIsRemovableHd, BdsGetDeviceHd },
+ //{ BdsIsRemovableCdrom, BdsGetDeviceCdrom }
+};
+
+STATIC
+BOOLEAN
+IsRemovableDevice (
+ IN EFI_DEVICE_PATH* DevicePath
+ )
+{
+ UINTN Index;
+ EFI_DEVICE_PATH* TmpDevicePath;
+
+ TmpDevicePath = DevicePath;
+ while (!IsDevicePathEnd (TmpDevicePath)) {
+ for (Index = 0; Index < sizeof (RemovableDeviceSupport) / sizeof (BDS_REMOVABLE_DEVICE_SUPPORT); Index++) {
+ if (RemovableDeviceSupport[Index].IsRemovable (TmpDevicePath)) {
+ return TRUE;
+ }
+ }
+ TmpDevicePath = NextDevicePathNode (TmpDevicePath);
+ }
+
+ return FALSE;
+}
+
+STATIC
+EFI_STATUS
+TryRemovableDevice (
+ IN EFI_DEVICE_PATH* DevicePath,
+ OUT EFI_HANDLE* DeviceHandle,
+ OUT EFI_DEVICE_PATH** NewDevicePath
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_DEVICE_PATH* TmpDevicePath;
+ BDS_REMOVABLE_DEVICE_SUPPORT* RemovableDevice;
+ EFI_DEVICE_PATH* RemovableDevicePath;
+ BOOLEAN RemovableFound;
+
+ RemovableDevice = NULL;
+ RemovableDevicePath = NULL;
+ RemovableFound = FALSE;
+ TmpDevicePath = DevicePath;
+
+ while (!IsDevicePathEnd (TmpDevicePath) && !RemovableFound) {
+ for (Index = 0; Index < sizeof (RemovableDeviceSupport) / sizeof (BDS_REMOVABLE_DEVICE_SUPPORT); Index++) {
+ RemovableDevice = &RemovableDeviceSupport[Index];
+ if (RemovableDevice->IsRemovable (TmpDevicePath)) {
+ RemovableDevicePath = TmpDevicePath;
+ RemovableFound = TRUE;
+ break;
+ }
+ }
+ TmpDevicePath = NextDevicePathNode (TmpDevicePath);
+ }
+
+ if (!RemovableFound) {
+ return EFI_NOT_FOUND;
+ }
+
+ // Search into the current started drivers
+ Status = RemovableDevice->GetDevice (RemovableDevicePath, DeviceHandle, NewDevicePath);
+ if (Status == EFI_NOT_FOUND) {
+ // Connect all the drivers
+ BdsConnectAllDrivers ();
+
+ // Search again into all the drivers
+ Status = RemovableDevice->GetDevice (RemovableDevicePath, DeviceHandle, NewDevicePath);
+ }
+
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+BdsConnectAndUpdateDevicePath (
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
+ OUT EFI_HANDLE *Handle,
+ OUT EFI_DEVICE_PATH_PROTOCOL **RemainingDevicePath
+ )
+{
+ EFI_DEVICE_PATH* Remaining;
+ EFI_DEVICE_PATH* NewDevicePath;
+ EFI_STATUS Status;
+ EFI_HANDLE PreviousHandle;
+
+ if ((DevicePath == NULL) || (*DevicePath == NULL) || (Handle == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PreviousHandle = NULL;
+ do {
+ Remaining = *DevicePath;
+
+ // The LocateDevicePath() function locates all devices on DevicePath that support Protocol and returns
+ // the handle to the device that is closest to DevicePath. On output, the device path pointer is modified
+ // to point to the remaining part of the device path
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remaining, Handle);
+
+ if (!EFI_ERROR (Status)) {
+ if (*Handle == PreviousHandle) {
+ //
+ // If no forward progress is made try invoking the Dispatcher.
+ // A new FV may have been added to the system and new drivers
+ // may now be found.
+ // Status == EFI_SUCCESS means a driver was dispatched
+ // Status == EFI_NOT_FOUND means no new drivers were dispatched
+ //
+ Status = gDS->Dispatch ();
+ }
+
+ if (!EFI_ERROR (Status)) {
+ PreviousHandle = *Handle;
+
+ // Recursive = FALSE: We do not want to start the whole device tree
+ Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE);
+ }
+ }
+ } while (!EFI_ERROR (Status) && !IsDevicePathEnd (Remaining));
+
+ if (!EFI_ERROR (Status)) {
+ // Now, we have got the whole Device Path connected, call again ConnectController to ensure all the supported Driver
+ // Binding Protocol are connected (such as DiskIo and SimpleFileSystem)
+ Remaining = *DevicePath;
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remaining, Handle);
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE);
+ if (EFI_ERROR (Status)) {
+ // If the last node is a Memory Map Device Path just return EFI_SUCCESS.
+ if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) {
+ Status = EFI_SUCCESS;
+ }
+ }
+ }
+ } else if (!IsDevicePathEnd (Remaining) && !IsRemovableDevice (Remaining)) {
+
+ /*// If the remaining Device Path is a FilePath or MemoryMap then we consider the Device Path has been loaded correctly
+ if ((Remaining->Type == MEDIA_DEVICE_PATH) && (Remaining->SubType == MEDIA_FILEPATH_DP)) {
+ Status = EFI_SUCCESS;
+ } else if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) {
+ Status = EFI_SUCCESS;
+ }*/
+
+ //TODO: Should we just return success and leave the caller decide if it is the expected RemainingPath
+ Status = EFI_SUCCESS;
+ } else {
+ Status = TryRemovableDevice (*DevicePath, Handle, &NewDevicePath);
+ if (!EFI_ERROR (Status)) {
+ Status = BdsConnectAndUpdateDevicePath (&NewDevicePath, Handle, RemainingDevicePath);
+ *DevicePath = NewDevicePath;
+ return Status;
+ }
+ }
+
+ if (RemainingDevicePath) {
+ *RemainingDevicePath = Remaining;
+ }
+
+ return Status;
+}
+
+/**
+ Connect a Device Path and return the handle of the driver that support this DevicePath
+
+ @param DevicePath Device Path of the File to connect
+ @param Handle Handle of the driver that support this DevicePath
+ @param RemainingDevicePath Remaining DevicePath nodes that do not match the driver DevicePath
+
+ @retval EFI_SUCCESS A driver that matches the Device Path has been found
+ @retval EFI_NOT_FOUND No handles match the search.
+ @retval EFI_INVALID_PARAMETER DevicePath or Handle is NULL
+
+**/
+EFI_STATUS
+BdsConnectDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
+ OUT EFI_HANDLE *Handle,
+ OUT EFI_DEVICE_PATH_PROTOCOL **RemainingDevicePath
+ )
+{
+ return BdsConnectAndUpdateDevicePath (&DevicePath, Handle, RemainingDevicePath);
+}
+
+BOOLEAN
+BdsFileSystemSupport (
+ IN EFI_DEVICE_PATH *DevicePath,
+ IN EFI_HANDLE Handle,
+ IN EFI_DEVICE_PATH *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol;
+
+ Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol);
+
+ return (!EFI_ERROR (Status) && IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP));
+}
+
+EFI_STATUS
+BdsFileSystemLoadImage (
+ IN OUT EFI_DEVICE_PATH **DevicePath,
+ IN EFI_HANDLE Handle,
+ IN EFI_DEVICE_PATH *RemainingDevicePath,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN OUT EFI_PHYSICAL_ADDRESS *Image,
+ OUT UINTN *ImageSize
+ )
+{
+ EFI_STATUS Status;
+ FILEPATH_DEVICE_PATH *FilePathDevicePath;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol;
+ EFI_FILE_PROTOCOL *Fs;
+ EFI_FILE_INFO *FileInfo;
+ EFI_FILE_PROTOCOL *File;
+ UINTN Size;
+
+ ASSERT (IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP));
+
+ FilePathDevicePath = (FILEPATH_DEVICE_PATH*)RemainingDevicePath;
+
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ (VOID**)&FsProtocol,
+ gImageHandle,
+ Handle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Try to Open the volume and get root directory
+ Status = FsProtocol->OpenVolume (FsProtocol, &Fs);
+ if (EFI_ERROR (Status)) {
+ goto CLOSE_PROTOCOL;
+ }
+
+ Status = Fs->Open (Fs, &File, FilePathDevicePath->PathName, EFI_FILE_MODE_READ, 0);
+ if (EFI_ERROR (Status)) {
+ goto CLOSE_PROTOCOL;
+ }
+
+ Size = 0;
+ File->GetInfo (File, &gEfiFileInfoGuid, &Size, NULL);
+ FileInfo = AllocatePool (Size);
+ Status = File->GetInfo (File, &gEfiFileInfoGuid, &Size, FileInfo);
+ if (EFI_ERROR (Status)) {
+ goto CLOSE_FILE;
+ }
+
+ // Get the file size
+ Size = FileInfo->FileSize;
+ if (ImageSize) {
+ *ImageSize = Size;
+ }
+ FreePool (FileInfo);
+
+ Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);
+ // Try to allocate in any pages if failed to allocate memory at the defined location
+ if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {
+ Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);
+ }
+ if (!EFI_ERROR (Status)) {
+ Status = File->Read (File, &Size, (VOID*)(UINTN)(*Image));
+ }
+
+CLOSE_FILE:
+ File->Close (File);
+
+CLOSE_PROTOCOL:
+ gBS->CloseProtocol (
+ Handle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ gImageHandle,
+ Handle);
+
+ return Status;
+}
+
+BOOLEAN
+BdsMemoryMapSupport (
+ IN EFI_DEVICE_PATH *DevicePath,
+ IN EFI_HANDLE Handle,
+ IN EFI_DEVICE_PATH *RemainingDevicePath
+ )
+{
+ return IS_DEVICE_PATH_NODE (DevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP) ||
+ IS_DEVICE_PATH_NODE (RemainingDevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP);
+}
+
+EFI_STATUS
+BdsMemoryMapLoadImage (
+ IN OUT EFI_DEVICE_PATH **DevicePath,
+ IN EFI_HANDLE Handle,
+ IN EFI_DEVICE_PATH *RemainingDevicePath,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN OUT EFI_PHYSICAL_ADDRESS* Image,
+ OUT UINTN *ImageSize
+ )
+{
+ EFI_STATUS Status;
+ MEMMAP_DEVICE_PATH* MemMapPathDevicePath;
+ UINTN Size;
+
+ if (IS_DEVICE_PATH_NODE (RemainingDevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP)) {
+ MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)RemainingDevicePath;
+ } else {
+ ASSERT (IS_DEVICE_PATH_NODE (*DevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP));
+ MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)*DevicePath;
+ }
+
+ Size = MemMapPathDevicePath->EndingAddress - MemMapPathDevicePath->StartingAddress;
+ if (Size == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);
+ // Try to allocate in any pages if failed to allocate memory at the defined location
+ if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {
+ Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image);
+ }
+ if (!EFI_ERROR (Status)) {
+ CopyMem ((VOID*)(UINTN)(*Image), (CONST VOID*)(UINTN)MemMapPathDevicePath->StartingAddress, Size);
+
+ if (ImageSize != NULL) {
+ *ImageSize = Size;
+ }
+ }
+
+ return Status;
+}
+
+BOOLEAN
+BdsFirmwareVolumeSupport (
+ IN EFI_DEVICE_PATH *DevicePath,
+ IN EFI_HANDLE Handle,
+ IN EFI_DEVICE_PATH *RemainingDevicePath
+ )
+{
+ return IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP);
+}
+
+EFI_STATUS
+BdsFirmwareVolumeLoadImage (
+ IN OUT EFI_DEVICE_PATH **DevicePath,
+ IN EFI_HANDLE Handle,
+ IN EFI_DEVICE_PATH *RemainingDevicePath,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN OUT EFI_PHYSICAL_ADDRESS* Image,
+ OUT UINTN *ImageSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol;
+ EFI_GUID *FvNameGuid;
+ EFI_SECTION_TYPE SectionType;
+ EFI_FV_FILETYPE FvType;
+ EFI_FV_FILE_ATTRIBUTES Attrib;
+ UINT32 AuthenticationStatus;
+ VOID* ImageBuffer;
+
+ ASSERT (IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP));
+
+ Status = gBS->HandleProtocol (Handle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&FwVol);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ FvNameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)RemainingDevicePath);
+ if (FvNameGuid == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ SectionType = EFI_SECTION_PE32;
+ AuthenticationStatus = 0;
+ //Note: ReadSection at the opposite of ReadFile does not allow to pass ImageBuffer == NULL to get the size of the file.
+ ImageBuffer = NULL;
+ Status = FwVol->ReadSection (
+ FwVol,
+ FvNameGuid,
+ SectionType,
+ 0,
+ &ImageBuffer,
+ ImageSize,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+#if 0
+ // In case the buffer has some address requirements, we must copy the buffer to a buffer following the requirements
+ if (Type != AllocateAnyPages) {
+ Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize),Image);
+ if (!EFI_ERROR (Status)) {
+ CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize);
+ FreePool (ImageBuffer);
+ }
+ }
+#else
+ // We must copy the buffer into a page allocations. Otherwise, the caller could call gBS->FreePages() on the pool allocation
+ Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);
+ // Try to allocate in any pages if failed to allocate memory at the defined location
+ if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {
+ Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);
+ }
+ if (!EFI_ERROR (Status)) {
+ CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize);
+ FreePool (ImageBuffer);
+ }
+#endif
+ } else {
+ // Try a raw file, since a PE32 SECTION does not exist
+ Status = FwVol->ReadFile (
+ FwVol,
+ FvNameGuid,
+ NULL,
+ ImageSize,
+ &FvType,
+ &Attrib,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);
+ // Try to allocate in any pages if failed to allocate memory at the defined location
+ if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) {
+ Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image);
+ }
+ if (!EFI_ERROR (Status)) {
+ Status = FwVol->ReadFile (
+ FwVol,
+ FvNameGuid,
+ (VOID**)Image,
+ ImageSize,
+ &FvType,
+ &Attrib,
+ &AuthenticationStatus
+ );
+ }
+ }
+ }
+ return Status;
+}
+
+BOOLEAN
+BdsPxeSupport (
+ IN EFI_DEVICE_PATH* DevicePath,
+ IN EFI_HANDLE Handle,
+ IN EFI_DEVICE_PATH* RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_PXE_BASE_CODE_PROTOCOL* PxeBcProtocol;
+
+ if (!IsDevicePathEnd (RemainingDevicePath)) {
+ return FALSE;
+ }
+
+ Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+EFI_STATUS
+BdsPxeLoadImage (
+ IN OUT EFI_DEVICE_PATH **DevicePath,
+ IN EFI_HANDLE Handle,
+ IN EFI_DEVICE_PATH *RemainingDevicePath,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN OUT EFI_PHYSICAL_ADDRESS* Image,
+ OUT UINTN *ImageSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_LOAD_FILE_PROTOCOL *LoadFileProtocol;
+ UINTN BufferSize;
+ EFI_PXE_BASE_CODE_PROTOCOL *Pxe;
+
+ // Get Load File Protocol attached to the PXE protocol
+ Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID **)&LoadFileProtocol);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = LoadFileProtocol->LoadFile (LoadFileProtocol, RemainingDevicePath, TRUE, &BufferSize, NULL);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(BufferSize), Image);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = LoadFileProtocol->LoadFile (LoadFileProtocol, RemainingDevicePath, TRUE, &BufferSize, (VOID*)(UINTN)(*Image));
+ if (!EFI_ERROR (Status) && (ImageSize != NULL)) {
+ *ImageSize = BufferSize;
+ }
+ }
+
+ if (Status == EFI_ALREADY_STARTED) {
+ Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe);
+ if (!EFI_ERROR(Status)) {
+ // If PXE is already started, we stop it
+ Pxe->Stop (Pxe);
+ // And we try again
+ return BdsPxeLoadImage (DevicePath, Handle, RemainingDevicePath, Type, Image, ImageSize);
+ }
+ }
+ return Status;
+}
+
+BOOLEAN
+BdsTftpSupport (
+ IN EFI_DEVICE_PATH *DevicePath,
+ IN EFI_HANDLE Handle,
+ IN EFI_DEVICE_PATH *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH *NextDevicePath;
+ VOID *Interface;
+
+ // Validate the Remaining Device Path
+ if (IsDevicePathEnd (RemainingDevicePath)) {
+ return FALSE;
+ }
+ if (!IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MSG_IPv4_DP) &&
+ !IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MSG_IPv6_DP)) {
+ return FALSE;
+ }
+ NextDevicePath = NextDevicePathNode (RemainingDevicePath);
+ if (IsDevicePathEnd (NextDevicePath)) {
+ return FALSE;
+ }
+ if (!IS_DEVICE_PATH_NODE (NextDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP)) {
+ return FALSE;
+ }
+
+ Status = gBS->HandleProtocol (
+ Handle, &gEfiDevicePathProtocolGuid,
+ &Interface
+ );
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ //
+ // Check that the controller (identified by its handle "Handle") supports the
+ // MTFTPv4 Service Binding Protocol. If it does, it means that it supports the
+ // EFI MTFTPv4 Protocol needed to download the image through TFTP.
+ //
+ Status = gBS->HandleProtocol (
+ Handle, &gEfiMtftp4ServiceBindingProtocolGuid,
+ &Interface
+ );
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Worker function that get the size in numbers of bytes of a file from a TFTP
+ server before to download the file.
+
+ @param[in] Mtftp4 MTFTP4 protocol interface
+ @param[in] FilePath Path of the file, Ascii encoded
+ @param[out] FileSize Address where to store the file size in number of
+ bytes.
+
+ @retval EFI_SUCCESS The size of the file was returned.
+ @retval !EFI_SUCCESS The size of the file was not returned.
+
+**/
+STATIC
+EFI_STATUS
+Mtftp4GetFileSize (
+ IN EFI_MTFTP4_PROTOCOL *Mtftp4,
+ IN CHAR8 *FilePath,
+ OUT UINT64 *FileSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_MTFTP4_OPTION ReqOpt[1];
+ EFI_MTFTP4_PACKET *Packet;
+ UINT32 PktLen;
+ EFI_MTFTP4_OPTION *TableOfOptions;
+ EFI_MTFTP4_OPTION *Option;
+ UINT32 OptCnt;
+ UINT8 OptBuf[128];
+
+ ReqOpt[0].OptionStr = (UINT8*)"tsize";
+ OptBuf[0] = '0';
+ OptBuf[1] = 0;
+ ReqOpt[0].ValueStr = OptBuf;
+
+ Status = Mtftp4->GetInfo (
+ Mtftp4,
+ NULL,
+ (UINT8*)FilePath,
+ NULL,
+ 1,
+ ReqOpt,
+ &PktLen,
+ &Packet
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ Status = Mtftp4->ParseOptions (
+ Mtftp4,
+ PktLen,
+ Packet,
+ (UINT32 *) &OptCnt,
+ &TableOfOptions
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ Option = TableOfOptions;
+ while (OptCnt != 0) {
+ if (AsciiStrnCmp ((CHAR8 *)Option->OptionStr, "tsize", 5) == 0) {
+ *FileSize = AsciiStrDecimalToUint64 ((CHAR8 *)Option->ValueStr);
+ break;
+ }
+ OptCnt--;
+ Option++;
+ }
+ FreePool (TableOfOptions);
+
+ if (OptCnt == 0) {
+ Status = EFI_UNSUPPORTED;
+ }
+
+Error :
+
+ return Status;
+}
+
+/**
+ Update the progress of a file download
+ This procedure is called each time a new TFTP packet is received.
+
+ @param[in] This MTFTP4 protocol interface
+ @param[in] Token Parameters for the download of the file
+ @param[in] PacketLen Length of the packet
+ @param[in] Packet Address of the packet
+
+ @retval EFI_SUCCESS All packets are accepted.
+
+**/
+STATIC
+EFI_STATUS
+Mtftp4CheckPacket (
+ IN EFI_MTFTP4_PROTOCOL *This,
+ IN EFI_MTFTP4_TOKEN *Token,
+ IN UINT16 PacketLen,
+ IN EFI_MTFTP4_PACKET *Packet
+ )
+{
+ BDS_TFTP_CONTEXT *Context;
+ CHAR16 Progress[TFTP_PROGRESS_MESSAGE_SIZE];
+ UINT64 NbOfKb;
+ UINTN Index;
+ UINTN LastStep;
+ UINTN Step;
+ UINT64 LastNbOf50Kb;
+ UINT64 NbOf50Kb;
+
+ if ((NTOHS (Packet->OpCode)) == EFI_MTFTP4_OPCODE_DATA) {
+ Context = (BDS_TFTP_CONTEXT*)Token->Context;
+
+ if (Context->DownloadedNbOfBytes == 0) {
+ if (Context->FileSize > 0) {
+ Print (L"%s 0 Kb", mTftpProgressFrame);
+ } else {
+ Print (L" 0 Kb");
+ }
+ }
+
+ //
+ // The data is the packet are prepended with two UINT16 :
+ // . OpCode = EFI_MTFTP4_OPCODE_DATA
+ // . Block = the number of this block of data
+ //
+ Context->DownloadedNbOfBytes += PacketLen - sizeof (Packet->OpCode) - sizeof (Packet->Data.Block);
+ NbOfKb = Context->DownloadedNbOfBytes / 1024;
+
+ Progress[0] = L'\0';
+ if (Context->FileSize > 0) {
+ LastStep = (Context->LastReportedNbOfBytes * TFTP_PROGRESS_SLIDER_STEPS) / Context->FileSize;
+ Step = (Context->DownloadedNbOfBytes * TFTP_PROGRESS_SLIDER_STEPS) / Context->FileSize;
+ if (Step > LastStep) {
+ Print (mTftpProgressDelete);
+ CopyMem (Progress, mTftpProgressFrame, sizeof mTftpProgressFrame);
+ for (Index = 1; Index < Step; Index++) {
+ Progress[Index] = L'=';
+ }
+ Progress[Step] = L'>';
+
+ UnicodeSPrint (
+ Progress + (sizeof (mTftpProgressFrame) / sizeof (CHAR16)) - 1,
+ sizeof (Progress) - sizeof (mTftpProgressFrame),
+ L" %7d Kb",
+ NbOfKb
+ );
+ Context->LastReportedNbOfBytes = Context->DownloadedNbOfBytes;
+ }
+ } else {
+ //
+ // Case when we do not know the size of the final file.
+ // We print the updated size every 50KB of downloaded data
+ //
+ LastNbOf50Kb = Context->LastReportedNbOfBytes / (50*1024);
+ NbOf50Kb = Context->DownloadedNbOfBytes / (50*1024);
+ if (NbOf50Kb > LastNbOf50Kb) {
+ Print (L"\b\b\b\b\b\b\b\b\b\b");
+ UnicodeSPrint (Progress, sizeof (Progress), L"%7d Kb", NbOfKb);
+ Context->LastReportedNbOfBytes = Context->DownloadedNbOfBytes;
+ }
+ }
+ if (Progress[0] != L'\0') {
+ Print (L"%s", Progress);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Download an image from a TFTP server
+
+ @param[in] DevicePath Device path of the TFTP boot option
+ @param[in] ControllerHandle Handle of the network controller
+ @param[in] RemainingDevicePath Device path of the TFTP boot option but
+ the first node that identifies the network controller
+ @param[in] Type Type to allocate memory pages
+ @param[out] Image Address of the bufer where the image is stored in
+ case of success
+ @param[out] ImageSize Size in number of bytes of the i;age in case of
+ success
+
+ @retval EFI_SUCCESS The image was returned.
+ @retval !EFI_SUCCESS Something went wrong.
+
+**/
+EFI_STATUS
+BdsTftpLoadImage (
+ IN OUT EFI_DEVICE_PATH **DevicePath,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH *RemainingDevicePath,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN OUT EFI_PHYSICAL_ADDRESS *Image,
+ OUT UINTN *ImageSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Dhcp4ChildHandle;
+ EFI_DHCP4_PROTOCOL *Dhcp4;
+ BOOLEAN Dhcp4ToStop;
+ EFI_HANDLE Mtftp4ChildHandle;
+ EFI_MTFTP4_PROTOCOL *Mtftp4;
+ DHCP4_OPTION ParaList;
+ EFI_DHCP4_PACKET_OPTION *OptionList[2];
+ EFI_DHCP4_CONFIG_DATA Dhcp4CfgData;
+ EFI_DHCP4_MODE_DATA Dhcp4Mode;
+ EFI_MTFTP4_CONFIG_DATA Mtftp4CfgData;
+ IPv4_DEVICE_PATH *IPv4DevicePathNode;
+ CHAR16 *PathName;
+ CHAR8 *AsciiFilePath;
+ EFI_MTFTP4_TOKEN Mtftp4Token;
+ UINT64 FileSize;
+ UINT64 TftpBufferSize;
+ BDS_TFTP_CONTEXT *TftpContext;
+ UINTN PathNameLen;
+
+ ASSERT(IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MSG_IPv4_DP));
+ IPv4DevicePathNode = (IPv4_DEVICE_PATH*)RemainingDevicePath;
+
+ Dhcp4ChildHandle = NULL;
+ Dhcp4 = NULL;
+ Dhcp4ToStop = FALSE;
+ Mtftp4ChildHandle = NULL;
+ Mtftp4 = NULL;
+ AsciiFilePath = NULL;
+ TftpContext = NULL;
+
+ if (!IPv4DevicePathNode->StaticIpAddress) {
+ //
+ // Using the DHCP4 Service Binding Protocol, create a child handle of the DHCP4 service and
+ // install the DHCP4 protocol on it. Then, open the DHCP protocol.
+ //
+ Status = NetLibCreateServiceChild (
+ ControllerHandle,
+ gImageHandle,
+ &gEfiDhcp4ServiceBindingProtocolGuid,
+ &Dhcp4ChildHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->OpenProtocol (
+ Dhcp4ChildHandle,
+ &gEfiDhcp4ProtocolGuid,
+ (VOID **) &Dhcp4,
+ gImageHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ Print (L"Unable to open DHCP4 protocol\n");
+ goto Error;
+ }
+ }
+
+ //
+ // Using the MTFTP4 Service Binding Protocol, create a child handle of the MTFTP4 service and
+ // install the MTFTP4 protocol on it. Then, open the MTFTP4 protocol.
+ //
+ Status = NetLibCreateServiceChild (
+ ControllerHandle,
+ gImageHandle,
+ &gEfiMtftp4ServiceBindingProtocolGuid,
+ &Mtftp4ChildHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->OpenProtocol (
+ Mtftp4ChildHandle,
+ &gEfiMtftp4ProtocolGuid,
+ (VOID **) &Mtftp4,
+ gImageHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ Print (L"Unable to open MTFTP4 protocol\n");
+ goto Error;
+ }
+
+ if (!IPv4DevicePathNode->StaticIpAddress) {
+ //
+ // Configure the DHCP4, all default settings. It is acceptable for the configuration to
+ // fail if the return code is equal to EFI_ACCESS_DENIED which means that the configuration
+ // has been done by another instance of the DHCP4 protocol or that the DHCP configuration
+ // process has been started but is not completed yet.
+ //
+ ZeroMem (&Dhcp4CfgData, sizeof (EFI_DHCP4_CONFIG_DATA));
+ ParaList.Head.OpCode = DHCP_TAG_PARA_LIST;
+ ParaList.Head.Length = 2;
+ ParaList.Head.Data[0] = DHCP_TAG_NETMASK;
+ ParaList.Route = DHCP_TAG_ROUTER;
+ OptionList[0] = &ParaList.Head;
+ Dhcp4CfgData.OptionCount = 1;
+ Dhcp4CfgData.OptionList = OptionList;
+
+ Status = Dhcp4->Configure (Dhcp4, &Dhcp4CfgData);
+ if (EFI_ERROR (Status)) {
+ if (Status != EFI_ACCESS_DENIED) {
+ Print (L"Error while configuring the DHCP4 protocol\n");
+ goto Error;
+ }
+ }
+
+ //
+ // Start the DHCP configuration. This may have already been done thus do not leave in error
+ // if the return code is EFI_ALREADY_STARTED.
+ //
+ Status = Dhcp4->Start (Dhcp4, NULL);
+ if (EFI_ERROR (Status)) {
+ if (Status != EFI_ALREADY_STARTED) {
+ Print (L"DHCP configuration failed\n");
+ goto Error;
+ }
+ } else {
+ Dhcp4ToStop = TRUE;
+ }
+
+ Status = Dhcp4->GetModeData (Dhcp4, &Dhcp4Mode);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ if (Dhcp4Mode.State != Dhcp4Bound) {
+ Status = EFI_TIMEOUT;
+ Print (L"DHCP configuration failed\n");
+ goto Error;
+ }
+ }
+
+ //
+ // Configure the TFTP4 protocol
+ //
+
+ ZeroMem (&Mtftp4CfgData, sizeof (EFI_MTFTP4_CONFIG_DATA));
+ Mtftp4CfgData.UseDefaultSetting = FALSE;
+ Mtftp4CfgData.TimeoutValue = 4;
+ Mtftp4CfgData.TryCount = 6;
+
+ if (IPv4DevicePathNode->StaticIpAddress) {
+ CopyMem (&Mtftp4CfgData.StationIp , &IPv4DevicePathNode->LocalIpAddress, sizeof (EFI_IPv4_ADDRESS));
+ CopyMem (&Mtftp4CfgData.SubnetMask, &IPv4DevicePathNode->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
+ CopyMem (&Mtftp4CfgData.GatewayIp , &IPv4DevicePathNode->GatewayIpAddress, sizeof (EFI_IPv4_ADDRESS));
+ } else {
+ CopyMem (&Mtftp4CfgData.StationIp , &Dhcp4Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS));
+ CopyMem (&Mtftp4CfgData.SubnetMask, &Dhcp4Mode.SubnetMask , sizeof (EFI_IPv4_ADDRESS));
+ CopyMem (&Mtftp4CfgData.GatewayIp , &Dhcp4Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));
+ }
+
+ CopyMem (&Mtftp4CfgData.ServerIp , &IPv4DevicePathNode->RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS));
+
+ Status = Mtftp4->Configure (Mtftp4, &Mtftp4CfgData);
+ if (EFI_ERROR (Status)) {
+ Print (L"Error while configuring the MTFTP4 protocol\n");
+ goto Error;
+ }
+
+ // The Device Path might contain multiple FilePath nodes
+ PathName = ConvertDevicePathToText ((EFI_DEVICE_PATH_PROTOCOL*)(IPv4DevicePathNode + 1), FALSE, FALSE);
+ PathNameLen = StrLen (PathName) + 1;
+ AsciiFilePath = AllocatePool (PathNameLen);
+ UnicodeStrToAsciiStrS (PathName, AsciiFilePath, PathNameLen);
+
+ //
+ // Try to get the size of the file in bytes from the server. If it fails,
+ // start with a 8MB buffer to download the file.
+ //
+ FileSize = 0;
+ if (Mtftp4GetFileSize (Mtftp4, AsciiFilePath, &FileSize) == EFI_SUCCESS) {
+ TftpBufferSize = FileSize;
+ } else {
+ TftpBufferSize = SIZE_16MB;
+ }
+
+ TftpContext = AllocatePool (sizeof (BDS_TFTP_CONTEXT));
+ if (TftpContext == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+ TftpContext->FileSize = FileSize;
+
+ for (; TftpBufferSize <= MAX_TFTP_FILE_SIZE;
+ TftpBufferSize = (TftpBufferSize + SIZE_16MB) & (~(SIZE_16MB-1))) {
+ //
+ // Allocate a buffer to hold the whole file.
+ //
+ Status = gBS->AllocatePages (
+ Type,
+ EfiBootServicesCode,
+ EFI_SIZE_TO_PAGES (TftpBufferSize),
+ Image
+ );
+ if (EFI_ERROR (Status)) {
+ Print (L"Failed to allocate space for image\n");
+ goto Error;
+ }
+
+ TftpContext->DownloadedNbOfBytes = 0;
+ TftpContext->LastReportedNbOfBytes = 0;
+
+ ZeroMem (&Mtftp4Token, sizeof (EFI_MTFTP4_TOKEN));
+ Mtftp4Token.Filename = (UINT8*)AsciiFilePath;
+ Mtftp4Token.BufferSize = TftpBufferSize;
+ Mtftp4Token.Buffer = (VOID *)(UINTN)*Image;
+ Mtftp4Token.CheckPacket = Mtftp4CheckPacket;
+ Mtftp4Token.Context = (VOID*)TftpContext;
+
+ Print (L"Downloading the file <%a> from the TFTP server\n", AsciiFilePath);
+ Status = Mtftp4->ReadFile (Mtftp4, &Mtftp4Token);
+ Print (L"\n");
+ if (EFI_ERROR (Status)) {
+ gBS->FreePages (*Image, EFI_SIZE_TO_PAGES (TftpBufferSize));
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Print (L"Downloading failed, file larger than expected.\n");
+ continue;
+ } else {
+ goto Error;
+ }
+ }
+
+ *ImageSize = Mtftp4Token.BufferSize;
+ break;
+ }
+
+Error:
+ if (Dhcp4ChildHandle != NULL) {
+ if (Dhcp4 != NULL) {
+ if (Dhcp4ToStop) {
+ Dhcp4->Stop (Dhcp4);
+ }
+ gBS->CloseProtocol (
+ Dhcp4ChildHandle,
+ &gEfiDhcp4ProtocolGuid,
+ gImageHandle,
+ ControllerHandle
+ );
+ }
+ NetLibDestroyServiceChild (
+ ControllerHandle,
+ gImageHandle,
+ &gEfiDhcp4ServiceBindingProtocolGuid,
+ Dhcp4ChildHandle
+ );
+ }
+
+ if (Mtftp4ChildHandle != NULL) {
+ if (Mtftp4 != NULL) {
+ if (AsciiFilePath != NULL) {
+ FreePool (AsciiFilePath);
+ }
+ if (TftpContext != NULL) {
+ FreePool (TftpContext);
+ }
+ gBS->CloseProtocol (
+ Mtftp4ChildHandle,
+ &gEfiMtftp4ProtocolGuid,
+ gImageHandle,
+ ControllerHandle
+ );
+ }
+ NetLibDestroyServiceChild (
+ ControllerHandle,
+ gImageHandle,
+ &gEfiMtftp4ServiceBindingProtocolGuid,
+ Mtftp4ChildHandle
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ *Image = 0;
+ Print (L"Failed to download the file - Error=%r\n", Status);
+ }
+
+ return Status;
+}
+
+BDS_FILE_LOADER FileLoaders[] = {
+ { BdsFileSystemSupport, BdsFileSystemLoadImage },
+ { BdsFirmwareVolumeSupport, BdsFirmwareVolumeLoadImage },
+ //{ BdsLoadFileSupport, BdsLoadFileLoadImage },
+ { BdsMemoryMapSupport, BdsMemoryMapLoadImage },
+ { BdsPxeSupport, BdsPxeLoadImage },
+ { BdsTftpSupport, BdsTftpLoadImage },
+ { NULL, NULL }
+};
+
+EFI_STATUS
+BdsLoadImageAndUpdateDevicePath (
+ IN OUT EFI_DEVICE_PATH **DevicePath,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN OUT EFI_PHYSICAL_ADDRESS* Image,
+ OUT UINTN *FileSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH *RemainingDevicePath;
+ BDS_FILE_LOADER* FileLoader;
+
+ Status = BdsConnectAndUpdateDevicePath (DevicePath, &Handle, &RemainingDevicePath);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ FileLoader = FileLoaders;
+ while (FileLoader->Support != NULL) {
+ if (FileLoader->Support (*DevicePath, Handle, RemainingDevicePath)) {
+ return FileLoader->LoadImage (DevicePath, Handle, RemainingDevicePath, Type, Image, FileSize);
+ }
+ FileLoader++;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+BdsLoadImage (
+ IN EFI_DEVICE_PATH *DevicePath,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN OUT EFI_PHYSICAL_ADDRESS* Image,
+ OUT UINTN *FileSize
+ )
+{
+ return BdsLoadImageAndUpdateDevicePath (&DevicePath, Type, Image, FileSize);
+}
+
+/**
+ Start an EFI Application from a Device Path
+
+ @param ParentImageHandle Handle of the calling image
+ @param DevicePath Location of the EFI Application
+
+ @retval EFI_SUCCESS All drivers have been connected
+ @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results.
+
+**/
+EFI_STATUS
+BdsStartEfiApplication (
+ IN EFI_HANDLE ParentImageHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN UINTN LoadOptionsSize,
+ IN VOID* LoadOptions
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE ImageHandle;
+ EFI_PHYSICAL_ADDRESS BinaryBuffer;
+ UINTN BinarySize;
+ EFI_LOADED_IMAGE_PROTOCOL* LoadedImage;
+
+ // Find the nearest supported file loader
+ Status = BdsLoadImageAndUpdateDevicePath (&DevicePath, AllocateAnyPages, &BinaryBuffer, &BinarySize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Load the image from the Buffer with Boot Services function
+ Status = gBS->LoadImage (TRUE, ParentImageHandle, DevicePath, (VOID*)(UINTN)BinaryBuffer, BinarySize, &ImageHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Passed LoadOptions to the EFI Application
+ if (LoadOptionsSize != 0) {
+ Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &LoadedImage);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ LoadedImage->LoadOptionsSize = LoadOptionsSize;
+ LoadedImage->LoadOptions = LoadOptions;
+ }
+
+ // Before calling the image, enable the Watchdog Timer for the 5 Minute period
+ gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
+ // Start the image
+ Status = gBS->StartImage (ImageHandle, NULL, NULL);
+ // Clear the Watchdog Timer after the image returns
+ gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
+
+ return Status;
+}
diff --git a/Platform/ARM/Library/BdsLib/BdsHelper.c b/Platform/ARM/Library/BdsLib/BdsHelper.c
new file mode 100644
index 000000000000..b10fe2074d53
--- /dev/null
+++ b/Platform/ARM/Library/BdsLib/BdsHelper.c
@@ -0,0 +1,183 @@
+/** @file
+*
+* Copyright (c) 2011-2015, ARM Limited. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include "BdsInternal.h"
+
+EFI_STATUS
+ShutdownUefiBootServices (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN MemoryMapSize;
+ EFI_MEMORY_DESCRIPTOR *MemoryMap;
+ UINTN MapKey;
+ UINTN DescriptorSize;
+ UINT32 DescriptorVersion;
+ UINTN Pages;
+
+ MemoryMap = NULL;
+ MemoryMapSize = 0;
+ Pages = 0;
+
+ do {
+ Status = gBS->GetMemoryMap (
+ &MemoryMapSize,
+ MemoryMap,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+
+ Pages = EFI_SIZE_TO_PAGES (MemoryMapSize) + 1;
+ MemoryMap = AllocatePages (Pages);
+
+ //
+ // Get System MemoryMap
+ //
+ Status = gBS->GetMemoryMap (
+ &MemoryMapSize,
+ MemoryMap,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion
+ );
+ }
+
+ // Don't do anything between the GetMemoryMap() and ExitBootServices()
+ if (!EFI_ERROR(Status)) {
+ Status = gBS->ExitBootServices (gImageHandle, MapKey);
+ if (EFI_ERROR(Status)) {
+ FreePages (MemoryMap, Pages);
+ MemoryMap = NULL;
+ MemoryMapSize = 0;
+ }
+ }
+ } while (EFI_ERROR(Status));
+
+ return Status;
+}
+
+/**
+ Connect all DXE drivers
+
+ @retval EFI_SUCCESS All drivers have been connected
+ @retval EFI_NOT_FOUND No handles match the search.
+ @retval EFI_OUT_OF_RESOURCES There is not resource pool memory to store the matching results.
+
+**/
+EFI_STATUS
+BdsConnectAllDrivers (
+ VOID
+ )
+{
+ UINTN HandleCount, Index;
+ EFI_HANDLE *HandleBuffer;
+ EFI_STATUS Status;
+
+ do {
+ // Locate all the driver handles
+ Status = gBS->LocateHandleBuffer (
+ AllHandles,
+ NULL,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ // Connect every handles
+ for (Index = 0; Index < HandleCount; Index++) {
+ gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+
+ // Check if new handles have been created after the start of the previous handles
+ Status = gDS->Dispatch ();
+ } while (!EFI_ERROR(Status));
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+GetGlobalEnvironmentVariable (
+ IN CONST CHAR16* VariableName,
+ IN VOID* DefaultValue,
+ IN OUT UINTN* Size,
+ OUT VOID** Value
+ )
+{
+ return GetEnvironmentVariable (VariableName, &gEfiGlobalVariableGuid,
+ DefaultValue, Size, Value);
+}
+
+EFI_STATUS
+GetEnvironmentVariable (
+ IN CONST CHAR16* VariableName,
+ IN EFI_GUID* VendorGuid,
+ IN VOID* DefaultValue,
+ IN OUT UINTN* Size,
+ OUT VOID** Value
+ )
+{
+ EFI_STATUS Status;
+ UINTN VariableSize;
+
+ // Try to get the variable size.
+ *Value = NULL;
+ VariableSize = 0;
+ Status = gRT->GetVariable ((CHAR16 *) VariableName, VendorGuid, NULL, &VariableSize, *Value);
+ if (Status == EFI_NOT_FOUND) {
+ if ((DefaultValue != NULL) && (Size != NULL) && (*Size != 0)) {
+ // If the environment variable does not exist yet then set it with the default value
+ Status = gRT->SetVariable (
+ (CHAR16*)VariableName,
+ VendorGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ *Size,
+ DefaultValue
+ );
+ *Value = AllocateCopyPool (*Size, DefaultValue);
+ } else {
+ return EFI_NOT_FOUND;
+ }
+ } else if (Status == EFI_BUFFER_TOO_SMALL) {
+ // Get the environment variable value
+ *Value = AllocatePool (VariableSize);
+ if (*Value == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gRT->GetVariable ((CHAR16 *)VariableName, VendorGuid, NULL, &VariableSize, *Value);
+ if (EFI_ERROR (Status)) {
+ FreePool(*Value);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Size) {
+ *Size = VariableSize;
+ }
+ } else {
+ *Value = AllocateCopyPool (*Size, DefaultValue);
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/ARM/Library/BdsLib/BdsInternal.h b/Platform/ARM/Library/BdsLib/BdsInternal.h
new file mode 100644
index 000000000000..f70aae603d69
--- /dev/null
+++ b/Platform/ARM/Library/BdsLib/BdsInternal.h
@@ -0,0 +1,111 @@
+/** @file
+*
+* Copyright (c) 2011-2015, ARM Limited. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef __BDS_INTERNAL_H__
+#define __BDS_INTERNAL_H__
+
+#include <PiDxe.h>
+#include <Library/ArmLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/HobLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BdsLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#include <Guid/GlobalVariable.h>
+#include <Guid/FileInfo.h>
+
+#include <Protocol/DevicePath.h>
+#include <Protocol/DevicePathFromText.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/LoadFile.h>
+#include <Protocol/PxeBaseCode.h>
+
+#include <Uefi.h>
+
+/**
+ * Check if the file loader can support this device path.
+ *
+ * @param DevicePath EFI Device Path of the image to load.
+ * This device path generally comes from the boot entry (ie: Boot####).
+ * @param Handle Handle of the driver supporting the device path
+ * @param RemainingDevicePath Part of the EFI Device Path that has not been resolved during
+ * the Device Path discovery
+ */
+typedef BOOLEAN (*BDS_FILE_LOADER_SUPPORT) (
+ IN EFI_DEVICE_PATH *DevicePath,
+ IN EFI_HANDLE Handle,
+ IN EFI_DEVICE_PATH *RemainingDevicePath
+ );
+
+/**
+ * Function to load an image from a given Device Path for a
+ * specific support (FileSystem, TFTP, PXE, ...)
+ *
+ * @param DevicePath EFI Device Path of the image to load.
+ * This device path generally comes from the boot entry (ie: Boot####).
+ * This path is also defined as 'OUT' as there are some device paths that
+ * might not be completed such as EFI path for removable device. In these
+ * cases, it is expected the loader to add \EFI\BOOT\BOOT(ARM|AA64).EFI
+ * @param Handle Handle of the driver supporting the device path
+ * @param RemainingDevicePath Part of the EFI Device Path that has not been resolved during
+ * the Device Path discovery
+ * @param Type Define where the image should be loaded (see EFI_ALLOCATE_TYPE definition)
+ * @param Image Base Address of the image has been loaded
+ * @param ImageSize Size of the image that has been loaded
+ */
+typedef EFI_STATUS (*BDS_FILE_LOADER_LOAD_IMAGE) (
+ IN OUT EFI_DEVICE_PATH **DevicePath,
+ IN EFI_HANDLE Handle,
+ IN EFI_DEVICE_PATH *RemainingDevicePath,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN OUT EFI_PHYSICAL_ADDRESS* Image,
+ OUT UINTN *ImageSize
+ );
+
+typedef struct {
+ BDS_FILE_LOADER_SUPPORT Support;
+ BDS_FILE_LOADER_LOAD_IMAGE LoadImage;
+} BDS_FILE_LOADER;
+
+typedef struct _BDS_SYSTEM_MEMORY_RESOURCE {
+ LIST_ENTRY Link; // This attribute must be the first entry of this structure (to avoid pointer computation)
+ EFI_PHYSICAL_ADDRESS PhysicalStart;
+ UINT64 ResourceLength;
+} BDS_SYSTEM_MEMORY_RESOURCE;
+
+typedef struct {
+ UINT64 FileSize;
+ UINT64 DownloadedNbOfBytes;
+ UINT64 LastReportedNbOfBytes;
+} BDS_TFTP_CONTEXT;
+
+EFI_STATUS
+BdsLoadImage (
+ IN EFI_DEVICE_PATH *DevicePath,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN OUT EFI_PHYSICAL_ADDRESS* Image,
+ OUT UINTN *FileSize
+ );
+
+#endif
diff --git a/Platform/ARM/Library/BdsLib/BdsLib.inf b/Platform/ARM/Library/BdsLib/BdsLib.inf
new file mode 100644
index 000000000000..96c1d6e7e200
--- /dev/null
+++ b/Platform/ARM/Library/BdsLib/BdsLib.inf
@@ -0,0 +1,62 @@
+#/* @file
+#
+# Copyright (c) 2011-2014, ARM Limited. All rights reserved.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#*/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BdsLib
+ FILE_GUID = ddbf73a0-bb25-11df-8e4e-0002a5d5c51b
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = BdsLib
+
+[Sources.common]
+ BdsFilePath.c
+ BdsAppLoader.c
+ BdsHelper.c
+ BdsLoadOption.c
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ ArmLib
+ BaseLib
+ DebugLib
+ DevicePathLib
+ HobLib
+ PcdLib
+ NetLib
+
+[Guids]
+ gEfiFileInfoGuid
+
+[Protocols]
+ gEfiBdsArchProtocolGuid
+ gEfiDevicePathProtocolGuid
+ gEfiDevicePathFromTextProtocolGuid
+ gEfiSimpleFileSystemProtocolGuid
+ gEfiFirmwareVolume2ProtocolGuid
+ gEfiLoadFileProtocolGuid
+ gEfiPxeBaseCodeProtocolGuid
+ gEfiDiskIoProtocolGuid
+ gEfiUsbIoProtocolGuid
+ gEfiLoadedImageProtocolGuid
+ gEfiSimpleNetworkProtocolGuid
+ gEfiDhcp4ServiceBindingProtocolGuid
+ gEfiDhcp4ProtocolGuid
+ gEfiMtftp4ServiceBindingProtocolGuid
+ gEfiMtftp4ProtocolGuid
diff --git a/Platform/ARM/Library/BdsLib/BdsLoadOption.c b/Platform/ARM/Library/BdsLib/BdsLoadOption.c
new file mode 100644
index 000000000000..766a9890fc09
--- /dev/null
+++ b/Platform/ARM/Library/BdsLib/BdsLoadOption.c
@@ -0,0 +1,272 @@
+/** @file
+*
+* Copyright (c) 2011-2013, ARM Limited. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include "BdsInternal.h"
+
+EFI_STATUS
+BootOptionParseLoadOption (
+ IN EFI_LOAD_OPTION *EfiLoadOption,
+ IN UINTN EfiLoadOptionSize,
+ IN OUT BDS_LOAD_OPTION **BdsLoadOption
+ )
+{
+ BDS_LOAD_OPTION *LoadOption;
+ UINTN DescriptionLength;
+ UINTN EfiLoadOptionPtr;
+
+ if (EfiLoadOption == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (EfiLoadOptionSize < sizeof(UINT32) + sizeof(UINT16) + sizeof(CHAR16) + sizeof(EFI_DEVICE_PATH_PROTOCOL)) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (*BdsLoadOption == NULL) {
+ LoadOption = (BDS_LOAD_OPTION*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION));
+ if (LoadOption == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ LoadOption = *BdsLoadOption;
+ }
+
+ EfiLoadOptionPtr = (UINTN)EfiLoadOption;
+ LoadOption->LoadOption = EfiLoadOption;
+ LoadOption->LoadOptionSize = EfiLoadOptionSize;
+
+ LoadOption->Attributes = *(UINT32*)EfiLoadOptionPtr;
+ LoadOption->FilePathListLength = *(UINT16*)(EfiLoadOptionPtr + sizeof(UINT32));
+ LoadOption->Description = (CHAR16*)(EfiLoadOptionPtr + sizeof(UINT32) + sizeof(UINT16));
+ DescriptionLength = StrSize (LoadOption->Description);
+ LoadOption->FilePathList = (EFI_DEVICE_PATH_PROTOCOL*)(EfiLoadOptionPtr + sizeof(UINT32) + sizeof(UINT16) + DescriptionLength);
+
+ // If ((End of EfiLoadOptiony - Start of EfiLoadOption) == EfiLoadOptionSize) then No Optional Data
+ if ((UINTN)((UINTN)LoadOption->FilePathList + LoadOption->FilePathListLength - EfiLoadOptionPtr) == EfiLoadOptionSize) {
+ LoadOption->OptionalData = NULL;
+ LoadOption->OptionalDataSize = 0;
+ } else {
+ LoadOption->OptionalData = (VOID*)((UINTN)(LoadOption->FilePathList) + LoadOption->FilePathListLength);
+ LoadOption->OptionalDataSize = EfiLoadOptionSize - ((UINTN)LoadOption->OptionalData - EfiLoadOptionPtr);
+ }
+
+ if (*BdsLoadOption == NULL) {
+ *BdsLoadOption = LoadOption;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+BootOptionFromLoadOptionVariable (
+ IN CHAR16* BootVariableName,
+ OUT BDS_LOAD_OPTION** BdsLoadOption
+ )
+{
+ EFI_STATUS Status;
+ EFI_LOAD_OPTION *EfiLoadOption;
+ UINTN EfiLoadOptionSize;
+
+ Status = GetGlobalEnvironmentVariable (BootVariableName, NULL, &EfiLoadOptionSize, (VOID**)&EfiLoadOption);
+ if (!EFI_ERROR(Status)) {
+ *BdsLoadOption = NULL;
+ Status = BootOptionParseLoadOption (EfiLoadOption, EfiLoadOptionSize, BdsLoadOption);
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+BootOptionFromLoadOptionIndex (
+ IN UINT16 LoadOptionIndex,
+ OUT BDS_LOAD_OPTION **BdsLoadOption
+ )
+{
+ CHAR16 BootVariableName[9];
+ EFI_STATUS Status;
+
+ UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", LoadOptionIndex);
+
+ Status = BootOptionFromLoadOptionVariable (BootVariableName, BdsLoadOption);
+ if (!EFI_ERROR(Status)) {
+ (*BdsLoadOption)->LoadOptionIndex = LoadOptionIndex;
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+BootOptionToLoadOptionVariable (
+ IN BDS_LOAD_OPTION* BdsLoadOption
+ )
+{
+ EFI_STATUS Status;
+ UINTN DescriptionSize;
+ //UINT16 FilePathListLength;
+ EFI_DEVICE_PATH_PROTOCOL* DevicePathNode;
+ UINTN NodeLength;
+ UINT8* EfiLoadOptionPtr;
+ VOID* OldLoadOption;
+ CHAR16 BootVariableName[9];
+ UINTN BootOrderSize;
+ UINT16* BootOrder;
+
+ // If we are overwriting an existent Boot Option then we have to free previously allocated memory
+ if (BdsLoadOption->LoadOptionSize > 0) {
+ OldLoadOption = BdsLoadOption->LoadOption;
+ } else {
+ OldLoadOption = NULL;
+
+ // If this function is called at the creation of the Boot Device entry (not at the update) the
+ // BootOption->LoadOptionSize must be zero then we get a new BootIndex for this entry
+ BdsLoadOption->LoadOptionIndex = BootOptionAllocateBootIndex ();
+
+ //TODO: Add to the the Boot Entry List
+ }
+
+ DescriptionSize = StrSize(BdsLoadOption->Description);
+
+ // Ensure the FilePathListLength information is correct
+ ASSERT (GetDevicePathSize (BdsLoadOption->FilePathList) == BdsLoadOption->FilePathListLength);
+
+ // Allocate the memory for the EFI Load Option
+ BdsLoadOption->LoadOptionSize = sizeof(UINT32) + sizeof(UINT16) + DescriptionSize + BdsLoadOption->FilePathListLength + BdsLoadOption->OptionalDataSize;
+
+ BdsLoadOption->LoadOption = (EFI_LOAD_OPTION *)AllocateZeroPool (BdsLoadOption->LoadOptionSize);
+ if (BdsLoadOption->LoadOption == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ EfiLoadOptionPtr = (UINT8 *) BdsLoadOption->LoadOption;
+
+ //
+ // Populate the EFI Load Option and BDS Boot Option structures
+ //
+
+ // Attributes fields
+ *(UINT32*)EfiLoadOptionPtr = BdsLoadOption->Attributes;
+ EfiLoadOptionPtr += sizeof(UINT32);
+
+ // FilePath List fields
+ *(UINT16*)EfiLoadOptionPtr = BdsLoadOption->FilePathListLength;
+ EfiLoadOptionPtr += sizeof(UINT16);
+
+ // Boot description fields
+ CopyMem (EfiLoadOptionPtr, BdsLoadOption->Description, DescriptionSize);
+ EfiLoadOptionPtr += DescriptionSize;
+
+ // File path fields
+ DevicePathNode = BdsLoadOption->FilePathList;
+ while (!IsDevicePathEndType (DevicePathNode)) {
+ NodeLength = DevicePathNodeLength(DevicePathNode);
+ CopyMem (EfiLoadOptionPtr, DevicePathNode, NodeLength);
+ EfiLoadOptionPtr += NodeLength;
+ DevicePathNode = NextDevicePathNode (DevicePathNode);
+ }
+
+ // Set the End Device Path Type
+ SetDevicePathEndNode (EfiLoadOptionPtr);
+ EfiLoadOptionPtr += sizeof(EFI_DEVICE_PATH);
+
+ // Fill the Optional Data
+ if (BdsLoadOption->OptionalDataSize > 0) {
+ CopyMem (EfiLoadOptionPtr, BdsLoadOption->OptionalData, BdsLoadOption->OptionalDataSize);
+ }
+
+ // Case where the fields have been updated
+ if (OldLoadOption) {
+ // Now, the old data has been copied to the new allocated packed structure, we need to update the pointers of BdsLoadOption
+ BootOptionParseLoadOption (BdsLoadOption->LoadOption, BdsLoadOption->LoadOptionSize, &BdsLoadOption);
+ // Free the old packed structure
+ FreePool (OldLoadOption);
+ }
+
+ // Create/Update Boot#### environment variable
+ UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BdsLoadOption->LoadOptionIndex);
+ Status = gRT->SetVariable (
+ BootVariableName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ BdsLoadOption->LoadOptionSize,
+ BdsLoadOption->LoadOption
+ );
+
+ // When it is a new entry we must add the entry to the BootOrder
+ if (OldLoadOption == NULL) {
+ // Add the new Boot Index to the list
+ Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
+ if (!EFI_ERROR(Status)) {
+ BootOrder = ReallocatePool (BootOrderSize, BootOrderSize + sizeof(UINT16), BootOrder);
+ // Add the new index at the end
+ BootOrder[BootOrderSize / sizeof(UINT16)] = BdsLoadOption->LoadOptionIndex;
+ BootOrderSize += sizeof(UINT16);
+ } else {
+ // BootOrder does not exist. Create it
+ BootOrderSize = sizeof(UINT16);
+ BootOrder = &(BdsLoadOption->LoadOptionIndex);
+ }
+
+ // Update (or Create) the BootOrder environment variable
+ gRT->SetVariable (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ BootOrderSize,
+ BootOrder
+ );
+ DEBUG((EFI_D_ERROR,"Create %s\n",BootVariableName));
+
+ // Free memory allocated by GetGlobalEnvironmentVariable
+ if (!EFI_ERROR(Status)) {
+ FreePool (BootOrder);
+ }
+ } else {
+ DEBUG((EFI_D_ERROR,"Update %s\n",BootVariableName));
+ }
+
+ return EFI_SUCCESS;
+}
+
+UINT16
+BootOptionAllocateBootIndex (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINT32 BootIndex;
+ UINT16 *BootOrder;
+ UINTN BootOrderSize;
+ BOOLEAN Found;
+
+ // Get the Boot Option Order from the environment variable
+ Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
+ if (!EFI_ERROR(Status)) {
+ for (BootIndex = 0; BootIndex <= 0xFFFF; BootIndex++) {
+ Found = FALSE;
+ for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
+ if (BootOrder[Index] == BootIndex) {
+ Found = TRUE;
+ break;
+ }
+ }
+ if (!Found) {
+ return BootIndex;
+ }
+ }
+ FreePool (BootOrder);
+ }
+ // Return the first index
+ return 0;
+}
--
2.11.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH edk2-platforms 2/4] Platform/ARM: import FdtPlatformDxe driver from EDK2
2017-11-20 11:37 [PATCH edk2-platforms 0/4] Platform/ARM: import BdsLib and FdtPlatformDxe Ard Biesheuvel
2017-11-20 11:37 ` [PATCH edk2-platforms 1/4] Platform/ARM: import BdsLib from ArmPkg Ard Biesheuvel
@ 2017-11-20 11:37 ` Ard Biesheuvel
2017-11-20 11:37 ` [PATCH edk2-platforms 3/4] Platform/ARM/Juno: move to migrated FdtPlatformDxe Ard Biesheuvel
` (2 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Ard Biesheuvel @ 2017-11-20 11:37 UTC (permalink / raw)
To: edk2-devel; +Cc: leif.lindholm, Ard Biesheuvel
Import FdtPlatformDxe from EmbeddedPkg into Platform/ARM, given that it
is not used anywhere else, nor should it be.
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.c | 461 +++++++++++++++++++
Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.h | 174 ++++++++
Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.dec | 31 ++
Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf | 65 +++
Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.uni | 109 +++++
Platform/ARM/Drivers/FdtPlatformDxe/README.txt | 72 +++
Platform/ARM/Drivers/FdtPlatformDxe/ShellDumpFdt.c | 279 ++++++++++++
Platform/ARM/Drivers/FdtPlatformDxe/ShellSetFdt.c | 468 ++++++++++++++++++++
8 files changed, 1659 insertions(+)
diff --git a/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.c b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.c
new file mode 100644
index 000000000000..b4be2a078991
--- /dev/null
+++ b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.c
@@ -0,0 +1,461 @@
+/** @file
+
+ Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "FdtPlatform.h"
+
+#include <Library/PcdLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/BdsLib.h>
+
+#include <Protocol/DevicePath.h>
+
+//
+// Internal variables
+//
+
+STATIC CONST EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL mShellDynCmdProtocolSetFdt = {
+ L"setfdt", // Name of the command
+ ShellDynCmdSetFdtHandler, // Handler
+ ShellDynCmdSetFdtGetHelp // GetHelp
+};
+
+STATIC CONST EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL mShellDynCmdProtocolDumpFdt = {
+ L"dumpfdt", // Name of the command
+ ShellDynCmdDumpFdtHandler, // Handler
+ ShellDynCmdDumpFdtGetHelp // GetHelp
+};
+
+STATIC CONST EFI_GUID mFdtPlatformDxeHiiGuid = {
+ 0x8afa7610, 0x62b1, 0x46aa,
+ {0xb5, 0x34, 0xc3, 0xde, 0xff, 0x39, 0x77, 0x8c}
+ };
+
+EFI_HANDLE mFdtPlatformDxeHiiHandle;
+
+/**
+ Install the FDT specified by its device path in text form.
+
+ @param[in] TextDevicePath Device path of the FDT to install in text form
+
+ @retval EFI_SUCCESS The FDT was installed.
+ @retval EFI_NOT_FOUND Failed to locate a protocol or a file.
+ @retval EFI_INVALID_PARAMETER Invalid device path.
+ @retval EFI_UNSUPPORTED Device path not supported.
+ @retval EFI_OUT_OF_RESOURCES An allocation failed.
+**/
+STATIC
+EFI_STATUS
+InstallFdt (
+ IN CONST CHAR16* TextDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol;
+ EFI_DEVICE_PATH *DevicePath;
+ EFI_PHYSICAL_ADDRESS FdtBlobBase;
+ UINTN FdtBlobSize;
+ UINTN NumPages;
+ EFI_PHYSICAL_ADDRESS FdtConfigurationTableBase;
+
+ Status = gBS->LocateProtocol (
+ &gEfiDevicePathFromTextProtocolGuid,
+ NULL,
+ (VOID **)&EfiDevicePathFromTextProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "InstallFdt() - Failed to locate EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL protocol\n"));
+ return Status;
+ }
+
+ DevicePath = (EFI_DEVICE_PATH*)EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (TextDevicePath);
+ if (DevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Load the FDT given its device path.
+ // This operation may fail if the device path is not supported.
+ //
+ FdtBlobBase = 0;
+ NumPages = 0;
+ Status = BdsLoadImage (DevicePath, AllocateAnyPages, &FdtBlobBase, &FdtBlobSize);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ //
+ // Ensure that the FDT header is valid and that the Size of the Device Tree
+ // is smaller than the size of the read file
+ //
+ if (fdt_check_header ((VOID*)(UINTN)FdtBlobBase) != 0 ||
+ (UINTN)fdt_totalsize ((VOID*)(UINTN)FdtBlobBase) > FdtBlobSize) {
+ DEBUG ((EFI_D_ERROR, "InstallFdt() - loaded FDT binary image seems corrupt\n"));
+ Status = EFI_LOAD_ERROR;
+ goto Error;
+ }
+
+ //
+ // Store the FDT as Runtime Service Data to prevent the Kernel from
+ // overwritting its data.
+ //
+ NumPages = EFI_SIZE_TO_PAGES (FdtBlobSize);
+ Status = gBS->AllocatePages (
+ AllocateAnyPages, EfiRuntimeServicesData,
+ NumPages, &FdtConfigurationTableBase
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ CopyMem (
+ (VOID*)(UINTN)FdtConfigurationTableBase,
+ (VOID*)(UINTN)FdtBlobBase,
+ FdtBlobSize
+ );
+
+ //
+ // Install the FDT into the Configuration Table
+ //
+ Status = gBS->InstallConfigurationTable (
+ &gFdtTableGuid,
+ (VOID*)(UINTN)FdtConfigurationTableBase
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->FreePages (FdtConfigurationTableBase, NumPages);
+ }
+
+Error:
+ if (FdtBlobBase != 0) {
+ gBS->FreePages (FdtBlobBase, NumPages);
+ }
+ FreePool (DevicePath);
+
+ return Status;
+}
+
+/**
+ Main entry point of the FDT platform driver.
+
+ @param[in] ImageHandle The firmware allocated handle for the present driver
+ UEFI image.
+ @param[in] *SystemTable A pointer to the EFI System table.
+
+ @retval EFI_SUCCESS The driver was initialized.
+ @retval EFI_OUT_OF_RESOURCES The "End of DXE" event could not be allocated or
+ there was not enough memory in pool to install
+ the Shell Dynamic Command protocol.
+ @retval EFI_LOAD_ERROR Unable to add the HII package.
+
+**/
+EFI_STATUS
+FdtPlatformEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+
+ //
+ // Install the Device Tree from its expected location
+ //
+ Status = RunFdtInstallation (NULL);
+
+ if (FeaturePcdGet (PcdOverridePlatformFdt) || FeaturePcdGet (PcdDumpFdtShellCommand)) {
+ //
+ // Register the strings for the user interface in the HII Database.
+ // This shows the way to the multi-language support, even if
+ // only the English language is actually supported. The strings to register
+ // are stored in the "ShellSetFdtStrings[]" array. This array is
+ // built by the building process from the "*.uni" file associated to
+ // the present driver (cf. FdtPlatfromDxe.inf). Examine your Build
+ // folder under your package's DEBUG folder and you will find the array
+ // defined in a xxxStrDefs.h file.
+ //
+ mFdtPlatformDxeHiiHandle = HiiAddPackages (
+ &mFdtPlatformDxeHiiGuid,
+ ImageHandle,
+ FdtPlatformDxeStrings,
+ NULL
+ );
+ }
+
+ //
+ // If the development features are enabled, install the dynamic shell
+ // command "setfdt" to be able to define a device path for the FDT
+ // that has precedence over the device paths defined by
+ // "PcdFdtDevicePaths".
+ //
+
+ if (FeaturePcdGet (PcdOverridePlatformFdt)) {
+ if (mFdtPlatformDxeHiiHandle != NULL) {
+ // We install dynamic EFI command on separate handles as we cannot register
+ // more than one protocol of the same protocol interface on the same handle.
+ Handle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEfiShellDynamicCommandProtocolGuid,
+ &mShellDynCmdProtocolSetFdt,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ HiiRemovePackages (mFdtPlatformDxeHiiHandle);
+ }
+ } else {
+ Status = EFI_LOAD_ERROR;
+ }
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ EFI_D_WARN,
+ "Unable to install \"setfdt\" EFI Shell command - %r \n",
+ Status
+ ));
+ }
+ }
+
+ if (FeaturePcdGet (PcdDumpFdtShellCommand)) {
+ if (mFdtPlatformDxeHiiHandle != NULL) {
+ // We install dynamic EFI command on separate handles as we cannot register
+ // more than one protocol of the same protocol interface on the same handle.
+ Handle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEfiShellDynamicCommandProtocolGuid,
+ &mShellDynCmdProtocolDumpFdt,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ HiiRemovePackages (mFdtPlatformDxeHiiHandle);
+ }
+ } else {
+ Status = EFI_LOAD_ERROR;
+ }
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ EFI_D_WARN,
+ "Unable to install \"dumpfdt\" EFI Shell command - %r \n",
+ Status
+ ));
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Run the FDT installation process.
+
+ Loop in priority order over the device paths from which the FDT has
+ been asked to be retrieved for. For each device path, try to install
+ the FDT. Stop as soon as an installation succeeds.
+
+ @param[in] SuccessfullDevicePath If not NULL, address where to store the
+ pointer to the text device path from
+ which the FDT was successfully retrieved.
+ Not used if the FDT installation failed.
+ The returned address is the address of
+ an allocated buffer that has to be
+ freed by the caller.
+
+ @retval EFI_SUCCESS The FDT was installed.
+ @retval EFI_NOT_FOUND Failed to locate a protocol or a file.
+ @retval EFI_INVALID_PARAMETER Invalid device path.
+ @retval EFI_UNSUPPORTED Device path not supported.
+ @retval EFI_OUT_OF_RESOURCES An allocation failed.
+
+**/
+EFI_STATUS
+RunFdtInstallation (
+ OUT CHAR16 **SuccessfullDevicePath
+ )
+{
+ EFI_STATUS Status;
+ UINTN DataSize;
+ CHAR16 *TextDevicePath;
+ CHAR16 *TextDevicePathStart;
+ CHAR16 *TextDevicePathSeparator;
+ UINTN TextDevicePathLen;
+
+ TextDevicePath = NULL;
+ //
+ // For development purpose, if enabled through the "PcdOverridePlatformFdt"
+ // feature PCD, try first to install the FDT specified by the device path in
+ // text form stored in the "Fdt" UEFI variable.
+ //
+ if (FeaturePcdGet (PcdOverridePlatformFdt)) {
+ DataSize = 0;
+ Status = gRT->GetVariable (
+ L"Fdt",
+ &gFdtVariableGuid,
+ NULL,
+ &DataSize,
+ NULL
+ );
+
+ //
+ // Keep going only if the "Fdt" variable is defined.
+ //
+
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ TextDevicePath = AllocatePool (DataSize);
+ if (TextDevicePath == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ Status = gRT->GetVariable (
+ L"Fdt",
+ &gFdtVariableGuid,
+ NULL,
+ &DataSize,
+ TextDevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (TextDevicePath);
+ goto Error;
+ }
+
+ Status = InstallFdt (TextDevicePath);
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((
+ EFI_D_WARN,
+ "Installation of the FDT using the device path <%s> completed.\n",
+ TextDevicePath
+ ));
+ goto Done;
+ }
+ DEBUG ((
+ EFI_D_ERROR,
+ "Installation of the FDT specified by the \"Fdt\" UEFI variable failed - %r\n",
+ Status
+ ));
+ FreePool (TextDevicePath);
+ }
+ }
+
+ //
+ // Loop over the device path list provided by "PcdFdtDevicePaths". The device
+ // paths are in text form and separated by a semi-colon.
+ //
+
+ Status = EFI_NOT_FOUND;
+ for (TextDevicePathStart = (CHAR16*)PcdGetPtr (PcdFdtDevicePaths);
+ *TextDevicePathStart != L'\0' ; ) {
+ TextDevicePathSeparator = StrStr (TextDevicePathStart, L";");
+
+ //
+ // Last device path of the list
+ //
+ if (TextDevicePathSeparator == NULL) {
+ TextDevicePathLen = StrLen (TextDevicePathStart);
+ } else {
+ TextDevicePathLen = (UINTN)(TextDevicePathSeparator - TextDevicePathStart);
+ }
+
+ TextDevicePath = AllocateCopyPool (
+ (TextDevicePathLen + 1) * sizeof (CHAR16),
+ TextDevicePathStart
+ );
+ if (TextDevicePath == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+ TextDevicePath[TextDevicePathLen] = L'\0';
+
+ Status = InstallFdt (TextDevicePath);
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_WARN, "Installation of the FDT using the device path <%s> completed.\n",
+ TextDevicePath
+ ));
+ goto Done;
+ }
+
+ DEBUG ((EFI_D_WARN, "Installation of the FDT using the device path <%s> failed - %r.\n",
+ TextDevicePath, Status
+ ));
+ FreePool (TextDevicePath);
+
+ if (TextDevicePathSeparator == NULL) {
+ goto Error;
+ }
+ TextDevicePathStart = TextDevicePathSeparator + 1;
+ }
+
+Error:
+Done:
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Failed to install the FDT - %r.\n", Status));
+ return Status;
+ }
+
+ if (SuccessfullDevicePath != NULL) {
+ *SuccessfullDevicePath = TextDevicePath;
+ } else {
+ FreePool (TextDevicePath);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Transcode one of the EFI return code used by the model into an EFI Shell return code.
+
+ @param[in] Status EFI return code.
+
+ @return Transcoded EFI Shell return code.
+
+**/
+SHELL_STATUS
+EfiCodeToShellCode (
+ IN EFI_STATUS Status
+ )
+{
+ SHELL_STATUS ShellStatus;
+
+ switch (Status) {
+ case EFI_SUCCESS :
+ ShellStatus = SHELL_SUCCESS;
+ break;
+
+ case EFI_INVALID_PARAMETER :
+ ShellStatus = SHELL_INVALID_PARAMETER;
+ break;
+
+ case EFI_UNSUPPORTED :
+ ShellStatus = SHELL_UNSUPPORTED;
+ break;
+
+ case EFI_DEVICE_ERROR :
+ ShellStatus = SHELL_DEVICE_ERROR;
+ break;
+
+ case EFI_WRITE_PROTECTED :
+ case EFI_SECURITY_VIOLATION :
+ ShellStatus = SHELL_ACCESS_DENIED;
+ break;
+
+ case EFI_OUT_OF_RESOURCES :
+ ShellStatus = SHELL_OUT_OF_RESOURCES;
+ break;
+
+ case EFI_NOT_FOUND :
+ ShellStatus = SHELL_NOT_FOUND;
+ break;
+
+ default :
+ ShellStatus = SHELL_ABORTED;
+ }
+
+ return ShellStatus;
+}
diff --git a/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.h b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.h
new file mode 100644
index 000000000000..a631f2847bf5
--- /dev/null
+++ b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatform.h
@@ -0,0 +1,174 @@
+/** @file
+
+ Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __FDT_PLATFORM_DXE_H__
+#define __FDT_PLATFORM_DXE_H__
+
+#include <Uefi.h>
+
+#include <Protocol/DevicePathToText.h>
+#include <Protocol/DevicePathFromText.h>
+#include <Protocol/Shell.h>
+#include <Protocol/ShellDynamicCommand.h>
+
+#include <Library/DebugLib.h>
+#include <Library/HiiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/ShellLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#include <Guid/Fdt.h>
+
+#include <libfdt.h>
+
+extern EFI_HANDLE mFdtPlatformDxeHiiHandle;
+
+/**
+ Transcode one of the EFI return code used by the model into an EFI Shell return code.
+
+ @param[in] Status EFI return code.
+
+ @return Transcoded EFI Shell return code.
+
+**/
+SHELL_STATUS
+EfiCodeToShellCode (
+ IN EFI_STATUS Status
+ );
+
+/**
+ Run the FDT installation process.
+
+ Loop in priority order over the device paths from which the FDT has
+ been asked to be retrieved for. For each device path, try to install
+ the FDT. Stop as soon as an installation succeeds.
+
+ @param[in] SuccessfullDevicePath If not NULL, address where to store the
+ pointer to the text device path from
+ which the FDT was successfully retrieved.
+ Not used if the FDT installation failed.
+ The returned address is the address of
+ an allocated buffer that has to be
+ freed by the caller.
+
+ @retval EFI_SUCCESS The FDT was installed.
+ @retval EFI_NOT_FOUND Failed to locate a protocol or a file.
+ @retval EFI_INVALID_PARAMETER Invalid device path.
+ @retval EFI_UNSUPPORTED Device path not supported.
+ @retval EFI_OUT_OF_RESOURCES An allocation failed.
+
+**/
+EFI_STATUS
+RunFdtInstallation (
+ OUT CHAR16 **SuccessfullDevicePath
+ );
+
+/**
+ This is the shell command "setfdt" handler function. This function handles
+ the command when it is invoked in the shell.
+
+ @param[in] This The instance of the
+ EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
+ @param[in] SystemTable The pointer to the UEFI system table.
+ @param[in] ShellParameters The parameters associated with the command.
+ @param[in] Shell The instance of the shell protocol used in the
+ context of processing this command.
+
+ @return SHELL_SUCCESS The operation was successful.
+ @return SHELL_ABORTED Operation aborted due to internal error.
+ @return SHELL_INVALID_PARAMETER The parameters of the command are not valid.
+ @return SHELL_INVALID_PARAMETER The EFI Shell file path is not valid.
+ @return SHELL_NOT_FOUND Failed to locate a protocol or a file.
+ @return SHELL_UNSUPPORTED Device path not supported.
+ @return SHELL_OUT_OF_RESOURCES A memory allocation failed.
+ @return SHELL_DEVICE_ERROR The "Fdt" variable could not be saved due to a hardware failure.
+ @return SHELL_ACCESS_DENIED The "Fdt" variable is read-only.
+ @return SHELL_ACCESS_DENIED The "Fdt" variable cannot be deleted.
+ @return SHELL_ACCESS_DENIED The "Fdt" variable could not be written due to security violation.
+
+**/
+SHELL_STATUS
+EFIAPI
+ShellDynCmdSetFdtHandler (
+ IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This,
+ IN EFI_SYSTEM_TABLE *SystemTable,
+ IN EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters,
+ IN EFI_SHELL_PROTOCOL *Shell
+ );
+
+/**
+ This is the shell command "setfdt" help handler function. This
+ function returns the formatted help for the "setfdt" command.
+ The format matchs that in Appendix B of the revision 2.1 of the
+ UEFI Shell Specification.
+
+ @param[in] This The instance of the EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
+ @param[in] Language The pointer to the language string to use.
+
+ @return CHAR16* Pool allocated help string, must be freed by caller.
+**/
+CHAR16*
+EFIAPI
+ShellDynCmdSetFdtGetHelp (
+ IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This,
+ IN CONST CHAR8 *Language
+ );
+
+/**
+ This is the shell command "dumpfdt" handler function. This function handles
+ the command when it is invoked in the shell.
+
+ @param[in] This The instance of the
+ EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
+ @param[in] SystemTable The pointer to the UEFI system table.
+ @param[in] ShellParameters The parameters associated with the command.
+ @param[in] Shell The instance of the shell protocol used in the
+ context of processing this command.
+
+ @return SHELL_SUCCESS The operation was successful.
+ @return SHELL_ABORTED Operation aborted due to internal error.
+ @return SHELL_NOT_FOUND Failed to locate the Device Tree into the EFI Configuration Table
+ @return SHELL_OUT_OF_RESOURCES A memory allocation failed.
+
+**/
+SHELL_STATUS
+EFIAPI
+ShellDynCmdDumpFdtHandler (
+ IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This,
+ IN EFI_SYSTEM_TABLE *SystemTable,
+ IN EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters,
+ IN EFI_SHELL_PROTOCOL *Shell
+ );
+
+/**
+ This is the shell command "dumpfdt" help handler function. This
+ function returns the formatted help for the "dumpfdt" command.
+ The format matchs that in Appendix B of the revision 2.1 of the
+ UEFI Shell Specification.
+
+ @param[in] This The instance of the EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
+ @param[in] Language The pointer to the language string to use.
+
+ @return CHAR16* Pool allocated help string, must be freed by caller.
+**/
+CHAR16*
+EFIAPI
+ShellDynCmdDumpFdtGetHelp (
+ IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This,
+ IN CONST CHAR8 *Language
+ );
+
+#endif /* __FDT_PLATFORM_DXE_H__ */
diff --git a/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.dec b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.dec
new file mode 100644
index 000000000000..3faced589504
--- /dev/null
+++ b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.dec
@@ -0,0 +1,31 @@
+#/** @file
+#
+# Copyright (c) 2011-2017, ARM Limited. All rights reserved.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#**/
+
+[Defines]
+ DEC_SPECIFICATION = 0x0001001A
+ PACKAGE_NAME = FdtPlatformDxe
+ PACKAGE_GUID = ed22c1e5-71cb-48d6-a9d8-c20f8d6b909f
+ PACKAGE_VERSION = 0.1
+
+[Guids]
+ gFdtPlatformDxeTokenSpaceGuid = { 0xbfcaa0af, 0xedd4, 0x4ce7, { 0xbd, 0xb3, 0x39, 0x15, 0x07, 0x28, 0x65, 0x77 } }
+
+[PcdsFeatureFlag.common]
+ # Enable the development specific features
+ gFdtPlatformDxeTokenSpaceGuid.PcdOverridePlatformFdt|TRUE|BOOLEAN|0x00000001
+ # Add 'dumpfdt' EFI Shell command
+ gFdtPlatformDxeTokenSpaceGuid.PcdDumpFdtShellCommand|TRUE|BOOLEAN|0x00000002
+
+[PcdsFixedAtBuild.common, PcdsDynamic.common]
+ gFdtPlatformDxeTokenSpaceGuid.PcdFdtDevicePaths|L""|VOID*|0x00000055
diff --git a/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf
new file mode 100644
index 000000000000..f9a5aee3596e
--- /dev/null
+++ b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.inf
@@ -0,0 +1,65 @@
+#/** @file
+#
+# Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010006
+ BASE_NAME = FdtPlatformDxe
+ MODULE_UNI_FILE = FdtPlatformDxe.uni
+ FILE_GUID = 4bd726b2-d1c8-4e98-ba08-2bc2ab251daf
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 0.1
+ ENTRY_POINT = FdtPlatformEntryPoint
+
+[Sources.common]
+ FdtPlatform.c
+ FdtPlatformDxe.uni
+ ShellDumpFdt.c
+ ShellSetFdt.c
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.dec
+ ShellPkg/ShellPkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ BdsLib
+ DebugLib
+ DxeServicesTableLib
+ FdtLib
+ HiiLib
+ ShellLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiRuntimeServicesTableLib
+
+[Protocols]
+ gEfiDevicePathFromTextProtocolGuid
+ gEfiDevicePathToTextProtocolGuid
+ gEfiShellDynamicCommandProtocolGuid
+
+[Guids]
+ gEfiEndOfDxeEventGroupGuid
+ gFdtTableGuid
+ gFdtVariableGuid
+
+[FeaturePcd]
+ gFdtPlatformDxeTokenSpaceGuid.PcdDumpFdtShellCommand
+ gFdtPlatformDxeTokenSpaceGuid.PcdOverridePlatformFdt
+
+[Pcd]
+ gFdtPlatformDxeTokenSpaceGuid.PcdFdtDevicePaths
diff --git a/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.uni b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.uni
new file mode 100644
index 000000000000..f8bde834841d
--- /dev/null
+++ b/Platform/ARM/Drivers/FdtPlatformDxe/FdtPlatformDxe.uni
@@ -0,0 +1,109 @@
+// *++
+//
+// Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
+//
+// This program and the accompanying materials are licensed and made available
+// under the terms and conditions of the BSD License which accompanies this
+// distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+//
+// Module Name:
+//
+// FdtPlatformDxe
+//
+// Abstract:
+//
+// String definitions for the EFI Shell 'setfdt' command
+//
+// Revision History:
+//
+// --*/
+
+/=#
+
+#langdef en-US "English"
+
+#string STR_SETFDT_INSTALLING #language en-US "Installing the FDT ...\r\n"
+#string STR_SETFDT_INSTALL_SUCCEEDED #language en-US "Installation of\r\n'%s'\r\ncompleted.\r\n"
+
+#string STR_SETFDT_UPDATING #language en-US "Updating the FDT device path ...\r\n"
+#string STR_SETFDT_UPDATE_SUCCEEDED #language en-US "Update of the FDT device path '%s' completed.\r\n"
+#string STR_SETFDT_UPDATE_DELETED #language en-US "The UEFI variable "Fdt" was deleted.\r\n"
+
+#string STR_SETFDT_INVALID_DEVICE_PATH #language en-US "Invalid device path.\r\n"
+#string STR_SETFDT_INVALID_PATH #language en-US "The EFI Shell or device file path '%s' is invalid.\r\n"
+#string STR_SETFDT_ERROR #language en-US "Error - %r.\r\n"
+#string STR_SETFDT_DEVICE_PATH_LIST #language en-US "FDT device paths :\r\n"
+#string STR_SETFDT_DEVICE_PATH #language en-US "'%s'\r\n"
+
+#string STR_GET_HELP_SETFDT #language en-US ""
+".TH setfdt 0 "Define and/or install a new Flat Device Tree (FDT) for the platform."\r\n"
+".SH NAME\r\n"
+"Define and/or re-install a Flat Device Tree (FDT)\r\n"
+".SH SYNOPSIS\r\n"
+"setfdt [-i] [fdt_path]\r\n"
+".SH OPTIONS\r\n"
+"-i run the FDT installation process\r\n"
+"file_path EFI Shell file path or device path to a FDT\r\n"
+"\r\n"
+".SH DESCRIPTION\r\n"
+"NOTES:\r\n"
+"1. If a valid EFI Shell file path is passed to the command, then the\r\n"
+" command translates the EFI Shell file path into a device path in the\r\n"
+" text form and saves it in the non volatile UEFI variable "Fdt". If\r\n"
+" the path to the FDT is a device path in the text form, it is saved as\r\n"
+" it is in the non volatile UEFI variable "Fdt". The next time the FDT\r\n"
+" installation process is run, it will first try to install the FDT from\r\n"
+" the device path specified by the UEFI variable "Fdt".\r\n"
+" \r\n
+"2. If the option -i is passed to the command, then the FDT installation\r\n"
+" process is run. If a path to the FDT is passed to the command as well,\r\n"
+" the update of the "Fdt" UEFI variable is done first before to launch\r\n"
+" the FDT installation process.\r\n"
+" \r\n
+".SH RETURNVALUES\r\n"
+"SHELL_SUCCESS Operation(s) completed.\r\n"
+"SHELL_ABORTED Operation aborted.\r\n"
+"SHELL_INVALID_PARAMETER Invalid argument(s).\r\n"
+"SHELL_NOT_FOUND Failed to locate a protocol or a file.\r\n"
+"SHELL_UNSUPPORTED Device path not supported.\r\n"
+"SHELL_OUT_OF_RESOURCES A memory allocation failed.\r\n"
+"SHELL_DEVICE ERROR Hardware failure.\r\n"
+"SHELL_ACCESS_DENIED Access to the Fdt UEFI variable for modification denied.\r\n"
+".SH EXAMPLES\r\n"
+"EXAMPLES:\r\n"
+"1. Relaunch the FDT installation process :\r\n"
+" Shell> setfdt -i\r\n"
+" \r\n"
+"2. Set the EFI Shell file path 'fs0:\>fdt.dtb' to be the default path\r\n"
+" to the FDT :\r\n"
+" Shell> setfdt fs0:fdt.dtb\r\n"
+" \r\n"
+"3. Set a TFTP device path to be the default path to the FDT :\r\n"
+" Shell> setfdt MAC(0002f700570b,0x1)/IPv4(192.168.1.1)/fdt.dtb\r\n"
+" where . 00:02:f7:00:57:0b is the MAC address of the network\r\n"
+" interface card to be used. The 'ifconfig -l' EFI Shell\r\n"
+" command allows to get the MAC address of the network\r\n"
+" interface cards.\r\n"
+" . 192.168.1.1 is the address of the TFTP server.\r\n"
+" . fdt.dtb is the file path to the FDT file on the server.\r\n"
+"4. Display the FDT device paths from the highest to the lowest\r\n"
+" priority :\r\n"
+" Shell> setfdt\r\n"
+"5. Delete the "Fdt" UEFI variable :\r\n"
+" Shell> setfdt ""\r\n"
+"\r\n"
+
+#string STR_GET_HELP_DUMPFDT #language en-US ""
+".TH dumpfdt 0 "Dump installed Flat Device Tree (FDT) of the platform."\r\n"
+".SH NAME\r\n"
+"Dump current Flat Device Tree (FDT)\r\n"
+".SH SYNOPSIS\r\n"
+"dumpfdt\r\n"
+"\r\n"
+".SH DESCRIPTION\r\n"
+"\r\n"
diff --git a/Platform/ARM/Drivers/FdtPlatformDxe/README.txt b/Platform/ARM/Drivers/FdtPlatformDxe/README.txt
new file mode 100644
index 000000000000..5f052d9a63aa
--- /dev/null
+++ b/Platform/ARM/Drivers/FdtPlatformDxe/README.txt
@@ -0,0 +1,72 @@
+/** @file
+
+ Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+The purpose of the FdtPlatformDxe UEFI driver is to install the Flat Device
+Tree (FDT) of the platform the UEFI frimware is running on into the UEFI
+Configuration Table. The FDT is identified within the UEFI Configuration
+Table by the "gFdtTableGuid" GUID defined in "EmbeddedPkg.dec".
+
+Once installed, an UEFI application or OS boot loader can get from the UEFI
+Configuration Table the FDT of the platform from the "gFdtTableGuid" GUID.
+
+The installation is done after each boot at the end of the DXE phase,
+just before the BDS phase. It is done at the end of the DXE phase to be sure
+that all drivers have been dispatched. That way, all UEFI protocols that may
+be needed to retrieve the FDT can be made available. It is done before the BDS
+phase to be able to provide the FDT during that phase.
+
+The present driver tries to retrieve the FDT from the device paths defined in the
+"gFdtPlatformDxeTokenSpaceGuid.PcdFdtDevicePaths" PCD. The "PcdFdtDevicePaths"
+PCD contains a list a device paths. The device paths are in the text form and
+separated by semi-colons. The present driver tries the device paths in the order
+it finds them in the "PcdFdtDevicePaths" PCD as long as he did not install
+succesfully a FDT.
+
+The "PcdFdtDevicePaths" PCD is a dynamic PCD that can be modified during the
+DXE phase. This allows for exemple to select the right FDT when a binary is
+intended to run on several platforms and/or variants of a platform.
+
+If the driver manages to download a FDT from one of the device paths mentioned
+above then it installs it in the UEFI Configuration table and the run over the
+device paths is stopped.
+
+For development purposes only, if the feature PCD "gFdtPlatformDxeTokenSpaceGuid.
+PcdOverridePlatformFdt" is equal to TRUE, then before to try to install the
+FDT from the device paths listed in the "PcdFdtDevicePaths" PCD, the present
+driver tries to install it using the device path defined by the UEFI variable
+"Fdt". If the variable does not exist or the installation using the device path
+defined by the UEFI variable fails then the installation proceeds as described
+above.
+
+Furthermore and again for development purposes only, if the feature PCD
+"PcdOverridePlatformFdt" is equal to TRUE, the current driver provides the EFI
+Shell command "setfdt" to define the location of the FDT by the mean of an EFI
+Shell file path (like "fs2:\boot\fdt.dtb") or a device path.
+
+If the path passed in to the command is a valid EFI Shell file path, the
+command translates it into the corresponding device path and stores that
+device path in the "Fdt" UEFI variable asking for the variable to be non
+volatile.
+
+If the path passed in to the command is not recognised as a valid EFI
+Shell device path, the command handles it as device path and stored
+in the "Fdt" UEFI variable as it is.
+
+Finally, the "-i" option of the "setfdt" command allows to trigger the FDT
+installation process. The installation process is completed when the command
+returns. The command can be invoked with the "-i" option only and in that
+case the "Fdt" UEFI variable is not updated and the command just runs the
+FDT installation process. If the command is invoked with the "-i" option and
+an EFI Shell file path then first the "Fdt" UEFI variable is updated accordingly
+and then the FDT installation process is run.
diff --git a/Platform/ARM/Drivers/FdtPlatformDxe/ShellDumpFdt.c b/Platform/ARM/Drivers/FdtPlatformDxe/ShellDumpFdt.c
new file mode 100644
index 000000000000..c7dc8985685b
--- /dev/null
+++ b/Platform/ARM/Drivers/FdtPlatformDxe/ShellDumpFdt.c
@@ -0,0 +1,279 @@
+/** @file
+
+ Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "FdtPlatform.h"
+
+#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
+#define PALIGN(p, a) ((void *)(ALIGN ((unsigned long)(p), (a))))
+#define GET_CELL(p) (p += 4, *((const uint32_t *)(p-4)))
+
+STATIC
+UINTN
+IsPrintableString (
+ IN CONST VOID* data,
+ IN UINTN len
+ )
+{
+ CONST CHAR8 *s = data;
+ CONST CHAR8 *ss;
+
+ // Zero length is not
+ if (len == 0) {
+ return 0;
+ }
+
+ // Must terminate with zero
+ if (s[len - 1] != '\0') {
+ return 0;
+ }
+
+ ss = s;
+ while (*s/* && isprint (*s)*/) {
+ s++;
+ }
+
+ // Not zero, or not done yet
+ if (*s != '\0' || (s + 1 - ss) < len) {
+ return 0;
+ }
+
+ return 1;
+}
+
+STATIC
+VOID
+PrintData (
+ IN CONST CHAR8* data,
+ IN UINTN len
+ )
+{
+ UINTN i;
+ CONST CHAR8 *p = data;
+
+ // No data, don't print
+ if (len == 0)
+ return;
+
+ if (IsPrintableString (data, len)) {
+ Print (L" = \"%a\"", (const char *)data);
+ } else if ((len % 4) == 0) {
+ Print (L" = <");
+ for (i = 0; i < len; i += 4) {
+ Print (L"0x%08x%a", fdt32_to_cpu (GET_CELL (p)), i < (len - 4) ? " " : "");
+ }
+ Print (L">");
+ } else {
+ Print (L" = [");
+ for (i = 0; i < len; i++)
+ Print (L"%02x%a", *p++, i < len - 1 ? " " : "");
+ Print (L"]");
+ }
+}
+
+STATIC
+VOID
+DumpFdt (
+ IN VOID* FdtBlob
+ )
+{
+ struct fdt_header *bph;
+ UINT32 off_dt;
+ UINT32 off_str;
+ CONST CHAR8* p_struct;
+ CONST CHAR8* p_strings;
+ CONST CHAR8* p;
+ CONST CHAR8* s;
+ CONST CHAR8* t;
+ UINT32 tag;
+ UINTN sz;
+ UINTN depth;
+ UINTN shift;
+ UINT32 version;
+
+ {
+ // Can 'memreserve' be printed by below code?
+ INTN num = fdt_num_mem_rsv (FdtBlob);
+ INTN i, err;
+ UINT64 addr = 0, size = 0;
+
+ for (i = 0; i < num; i++) {
+ err = fdt_get_mem_rsv (FdtBlob, i, &addr, &size);
+ if (err) {
+ DEBUG ((EFI_D_ERROR, "Error (%d) : Cannot get memreserve section (%d)\n", err, i));
+ }
+ else {
+ Print (L"/memreserve/ \t0x%lx \t0x%lx;\n", addr, size);
+ }
+ }
+ }
+
+ depth = 0;
+ shift = 4;
+
+ bph = FdtBlob;
+ off_dt = fdt32_to_cpu (bph->off_dt_struct);
+ off_str = fdt32_to_cpu (bph->off_dt_strings);
+ p_struct = (CONST CHAR8*)FdtBlob + off_dt;
+ p_strings = (CONST CHAR8*)FdtBlob + off_str;
+ version = fdt32_to_cpu (bph->version);
+
+ p = p_struct;
+ while ((tag = fdt32_to_cpu (GET_CELL (p))) != FDT_END) {
+ if (tag == FDT_BEGIN_NODE) {
+ s = p;
+ p = PALIGN (p + AsciiStrLen (s) + 1, 4);
+
+ if (*s == '\0')
+ s = "/";
+
+ Print (L"%*s%a {\n", depth * shift, L" ", s);
+
+ depth++;
+ continue;
+ }
+
+ if (tag == FDT_END_NODE) {
+ depth--;
+
+ Print (L"%*s};\n", depth * shift, L" ");
+ continue;
+ }
+
+ if (tag == FDT_NOP) {
+ Print (L"%*s// [NOP]\n", depth * shift, L" ");
+ continue;
+ }
+
+ if (tag != FDT_PROP) {
+ Print (L"%*s ** Unknown tag 0x%08x\n", depth * shift, L" ", tag);
+ break;
+ }
+ sz = fdt32_to_cpu (GET_CELL (p));
+ s = p_strings + fdt32_to_cpu (GET_CELL (p));
+ if (version < 16 && sz >= 8)
+ p = PALIGN (p, 8);
+ t = p;
+
+ p = PALIGN (p + sz, 4);
+
+ Print (L"%*s%a", depth * shift, L" ", s);
+ PrintData (t, sz);
+ Print (L";\n");
+ }
+}
+
+/**
+ This is the shell command "dumpfdt" handler function. This function handles
+ the command when it is invoked in the shell.
+
+ @param[in] This The instance of the
+ EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
+ @param[in] SystemTable The pointer to the UEFI system table.
+ @param[in] ShellParameters The parameters associated with the command.
+ @param[in] Shell The instance of the shell protocol used in the
+ context of processing this command.
+
+ @return SHELL_SUCCESS The operation was successful.
+ @return SHELL_ABORTED Operation aborted due to internal error.
+ @return SHELL_NOT_FOUND Failed to locate the Device Tree into the EFI Configuration Table
+ @return SHELL_OUT_OF_RESOURCES A memory allocation failed.
+
+**/
+SHELL_STATUS
+EFIAPI
+ShellDynCmdDumpFdtHandler (
+ IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This,
+ IN EFI_SYSTEM_TABLE *SystemTable,
+ IN EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters,
+ IN EFI_SHELL_PROTOCOL *Shell
+ )
+{
+ SHELL_STATUS ShellStatus;
+ EFI_STATUS Status;
+ VOID *FdtBlob;
+
+ ShellStatus = SHELL_SUCCESS;
+
+ //
+ // Install the Shell and Shell Parameters Protocols on the driver
+ // image. This is necessary for the initialisation of the Shell
+ // Library to succeed in the next step.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &gImageHandle,
+ &gEfiShellProtocolGuid, Shell,
+ &gEfiShellParametersProtocolGuid, ShellParameters,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return SHELL_ABORTED;
+ }
+
+ //
+ // Initialise the Shell Library as we are going to use it.
+ // Assert that the return code is EFI_SUCCESS as it should.
+ // To anticipate any change is the codes returned by
+ // ShellInitialize(), leave in case of error.
+ //
+ Status = ShellInitialize ();
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return SHELL_ABORTED;
+ }
+
+ Status = EfiGetSystemConfigurationTable (&gFdtTableGuid, &FdtBlob);
+ if (EFI_ERROR (Status)) {
+ Print (L"ERROR: Did not find the Fdt Blob.\n");
+ return EfiCodeToShellCode (Status);
+ }
+
+ DumpFdt (FdtBlob);
+
+ gBS->UninstallMultipleProtocolInterfaces (
+ gImageHandle,
+ &gEfiShellProtocolGuid, Shell,
+ &gEfiShellParametersProtocolGuid, ShellParameters,
+ NULL
+ );
+
+ return ShellStatus;
+}
+
+/**
+ This is the shell command "dumpfdt" help handler function. This
+ function returns the formatted help for the "dumpfdt" command.
+ The format matchs that in Appendix B of the revision 2.1 of the
+ UEFI Shell Specification.
+
+ @param[in] This The instance of the EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
+ @param[in] Language The pointer to the language string to use.
+
+ @return CHAR16* Pool allocated help string, must be freed by caller.
+**/
+CHAR16*
+EFIAPI
+ShellDynCmdDumpFdtGetHelp (
+ IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This,
+ IN CONST CHAR8 *Language
+ )
+{
+ //
+ // This allocates memory. The caller has to free the allocated memory.
+ //
+ return HiiGetString (
+ mFdtPlatformDxeHiiHandle,
+ STRING_TOKEN (STR_GET_HELP_DUMPFDT),
+ Language
+ );
+}
diff --git a/Platform/ARM/Drivers/FdtPlatformDxe/ShellSetFdt.c b/Platform/ARM/Drivers/FdtPlatformDxe/ShellSetFdt.c
new file mode 100644
index 000000000000..9be23c845593
--- /dev/null
+++ b/Platform/ARM/Drivers/FdtPlatformDxe/ShellSetFdt.c
@@ -0,0 +1,468 @@
+/** @file
+
+ Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "FdtPlatform.h"
+
+STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
+ {L"-i", TypeFlag },
+ {NULL , TypeMax }
+};
+
+/**
+ Display FDT device paths.
+
+ Display in text form the device paths used to install the FDT from the
+ highest to the lowest priority.
+
+**/
+STATIC
+VOID
+DisplayFdtDevicePaths (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN DataSize;
+ CHAR16 *TextDevicePath;
+ CHAR16 *TextDevicePaths;
+ CHAR16 *TextDevicePathSeparator;
+
+ ShellPrintHiiEx (
+ -1, -1, NULL,
+ STRING_TOKEN (STR_SETFDT_DEVICE_PATH_LIST),
+ mFdtPlatformDxeHiiHandle
+ );
+
+ if (FeaturePcdGet (PcdOverridePlatformFdt)) {
+ DataSize = 0;
+ Status = gRT->GetVariable (
+ L"Fdt",
+ &gFdtVariableGuid,
+ NULL,
+ &DataSize,
+ NULL
+ );
+
+ //
+ // Keep going only if the "Fdt" variable is defined.
+ //
+
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ TextDevicePath = AllocatePool (DataSize);
+ if (TextDevicePath == NULL) {
+ return;
+ }
+
+ Status = gRT->GetVariable (
+ L"Fdt",
+ &gFdtVariableGuid,
+ NULL,
+ &DataSize,
+ TextDevicePath
+ );
+ if (!EFI_ERROR (Status)) {
+ ShellPrintHiiEx (
+ -1, -1, NULL,
+ STRING_TOKEN (STR_SETFDT_DEVICE_PATH),
+ mFdtPlatformDxeHiiHandle,
+ TextDevicePath
+ );
+ }
+
+ FreePool (TextDevicePath);
+ }
+ }
+
+ //
+ // Loop over the device path list provided by "PcdFdtDevicePaths". The device
+ // paths are in text form and separated by a semi-colon.
+ //
+
+ TextDevicePaths = AllocateCopyPool (
+ StrSize ((CHAR16*)PcdGetPtr (PcdFdtDevicePaths)),
+ (CHAR16*)PcdGetPtr (PcdFdtDevicePaths)
+ );
+ if (TextDevicePaths == NULL) {
+ return;
+ }
+
+ for (TextDevicePath = TextDevicePaths;
+ *TextDevicePath != L'\0' ; ) {
+ TextDevicePathSeparator = StrStr (TextDevicePath, L";");
+
+ if (TextDevicePathSeparator != NULL) {
+ *TextDevicePathSeparator = L'\0';
+ }
+
+ ShellPrintHiiEx (
+ -1, -1, NULL,
+ STRING_TOKEN (STR_SETFDT_DEVICE_PATH),
+ mFdtPlatformDxeHiiHandle,
+ TextDevicePath
+ );
+
+ if (TextDevicePathSeparator == NULL) {
+ break;
+ }
+ TextDevicePath = TextDevicePathSeparator + 1;
+ }
+
+ FreePool (TextDevicePaths);
+}
+
+/**
+ Update the text device path stored in the "Fdt" UEFI variable given
+ an EFI Shell file path or a text device path.
+
+ This function is a subroutine of the ShellDynCmdSetFdtHandler() function
+ to make its code easier to read.
+
+ @param[in] Shell The instance of the shell protocol used in the
+ context of processing the "setfdt" command.
+ @param[in] FilePath EFI Shell path or the device path to the FDT file.
+
+ @return SHELL_SUCCESS The text device path was succesfully updated.
+ @return SHELL_INVALID_PARAMETER The Shell file path is not valid.
+ @return SHELL_OUT_OF_RESOURCES A memory allocation failed.
+ @return SHELL_DEVICE_ERROR The "Fdt" variable could not be saved due to a hardware failure.
+ @return SHELL_ACCESS_DENIED The "Fdt" variable is read-only.
+ @return SHELL_ACCESS_DENIED The "Fdt" variable cannot be deleted.
+ @return SHELL_ACCESS_DENIED The "Fdt" variable could not be written due to security violation.
+ @return SHELL_NOT_FOUND Device path to text protocol not found.
+ @return SHELL_ABORTED Operation aborted.
+
+**/
+STATIC
+SHELL_STATUS
+UpdateFdtTextDevicePath (
+ IN EFI_SHELL_PROTOCOL *Shell,
+ IN CONST CHAR16 *FilePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH *DevicePath;
+ EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *EfiDevicePathToTextProtocol;
+ CHAR16 *TextDevicePath;
+ CHAR16 *FdtVariableValue;
+ EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol;
+ SHELL_STATUS ShellStatus;
+
+ ASSERT (FilePath != NULL);
+ DevicePath = NULL;
+ TextDevicePath = NULL;
+ FdtVariableValue = NULL;
+
+ if (*FilePath != L'\0') {
+ DevicePath = Shell->GetDevicePathFromFilePath (FilePath);
+ if (DevicePath != NULL) {
+ Status = gBS->LocateProtocol (
+ &gEfiDevicePathToTextProtocolGuid,
+ NULL,
+ (VOID **)&EfiDevicePathToTextProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ TextDevicePath = EfiDevicePathToTextProtocol->ConvertDevicePathToText (
+ DevicePath,
+ FALSE,
+ FALSE
+ );
+ if (TextDevicePath == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+ FdtVariableValue = TextDevicePath;
+ } else {
+ //
+ // Try to convert back the EFI Device Path String into a EFI device Path
+ // to ensure the format is valid
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiDevicePathFromTextProtocolGuid,
+ NULL,
+ (VOID **)&EfiDevicePathFromTextProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ DevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (
+ FilePath
+ );
+ if (DevicePath == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Error;
+ }
+ FdtVariableValue = (CHAR16*)FilePath;
+ }
+ }
+
+ Status = gRT->SetVariable (
+ (CHAR16*)L"Fdt",
+ &gFdtVariableGuid,
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS ,
+ (FdtVariableValue != NULL) ?
+ StrSize (FdtVariableValue) : 0,
+ FdtVariableValue
+ );
+
+Error:
+ ShellStatus = EfiCodeToShellCode (Status);
+ if (!EFI_ERROR (Status)) {
+ if (FdtVariableValue != NULL) {
+ ShellPrintHiiEx (
+ -1, -1, NULL,
+ STRING_TOKEN (STR_SETFDT_UPDATE_SUCCEEDED),
+ mFdtPlatformDxeHiiHandle,
+ FdtVariableValue
+ );
+ } else {
+ ShellPrintHiiEx (
+ -1, -1, NULL,
+ STRING_TOKEN (STR_SETFDT_UPDATE_DELETED),
+ mFdtPlatformDxeHiiHandle
+ );
+ }
+ } else {
+ if (Status == EFI_INVALID_PARAMETER) {
+ ShellPrintHiiEx (
+ -1, -1, NULL,
+ STRING_TOKEN (STR_SETFDT_INVALID_PATH),
+ mFdtPlatformDxeHiiHandle,
+ FilePath
+ );
+ } else {
+ ShellPrintHiiEx (
+ -1, -1, NULL,
+ STRING_TOKEN (STR_SETFDT_ERROR),
+ mFdtPlatformDxeHiiHandle,
+ Status
+ );
+ }
+ }
+
+ if (DevicePath != NULL) {
+ FreePool (DevicePath);
+ }
+ if (TextDevicePath != NULL) {
+ FreePool (TextDevicePath);
+ }
+
+ return ShellStatus;
+}
+
+/**
+ This is the shell command "setfdt" handler function. This function handles
+ the command when it is invoked in the shell.
+
+ @param[in] This The instance of the
+ EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
+ @param[in] SystemTable The pointer to the UEFI system table.
+ @param[in] ShellParameters The parameters associated with the command.
+ @param[in] Shell The instance of the shell protocol used in the
+ context of processing this command.
+
+ @return SHELL_SUCCESS The operation was successful.
+ @return SHELL_ABORTED Operation aborted due to internal error.
+ @return SHELL_INVALID_PARAMETER The parameters of the command are not valid.
+ @return SHELL_INVALID_PARAMETER The EFI Shell file path is not valid.
+ @return SHELL_NOT_FOUND Failed to locate a protocol or a file.
+ @return SHELL_UNSUPPORTED Device path not supported.
+ @return SHELL_OUT_OF_RESOURCES A memory allocation failed.
+ @return SHELL_DEVICE_ERROR The "Fdt" variable could not be saved due to a hardware failure.
+ @return SHELL_ACCESS_DENIED The "Fdt" variable is read-only.
+ @return SHELL_ACCESS_DENIED The "Fdt" variable cannot be deleted.
+ @return SHELL_ACCESS_DENIED The "Fdt" variable could not be written due to security violation.
+
+**/
+SHELL_STATUS
+EFIAPI
+ShellDynCmdSetFdtHandler (
+ IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This,
+ IN EFI_SYSTEM_TABLE *SystemTable,
+ IN EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters,
+ IN EFI_SHELL_PROTOCOL *Shell
+ )
+{
+ SHELL_STATUS ShellStatus;
+ EFI_STATUS Status;
+ LIST_ENTRY *ParamPackage;
+ BOOLEAN FilePath;
+ CONST CHAR16 *ValueStr;
+ CHAR16 *TextDevicePath;
+
+ ShellStatus = SHELL_SUCCESS;
+ ParamPackage = NULL;
+ FilePath = FALSE;
+
+ //
+ // Install the Shell and Shell Parameters Protocols on the driver
+ // image. This is necessary for the initialisation of the Shell
+ // Library to succeed in the next step.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &gImageHandle,
+ &gEfiShellProtocolGuid, Shell,
+ &gEfiShellParametersProtocolGuid, ShellParameters,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return SHELL_ABORTED;
+ }
+
+ //
+ // Initialise the Shell Library as we are going to use it.
+ // Assert that the return code is EFI_SUCCESS as it should.
+ // To anticipate any change is the codes returned by
+ // ShellInitialize(), leave in case of error.
+ //
+ Status = ShellInitialize ();
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return SHELL_ABORTED;
+ }
+
+ Status = ShellCommandLineParse (ParamList, &ParamPackage, NULL, TRUE);
+ if (!EFI_ERROR (Status)) {
+ switch (ShellCommandLineGetCount (ParamPackage)) {
+ case 1:
+ //
+ // Case "setfdt" or "setfdt -i"
+ //
+ if (!ShellCommandLineGetFlag (ParamPackage, L"-i")) {
+ DisplayFdtDevicePaths ();
+ }
+ break;
+
+ case 2:
+ //
+ // Case "setfdt file_path" or
+ // "setfdt -i file_path" or
+ // "setfdt file_path -i"
+ //
+ FilePath = TRUE;
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ }
+ }
+ if (EFI_ERROR (Status)) {
+ ShellStatus = EfiCodeToShellCode (Status);
+ ShellPrintHiiEx (
+ -1, -1, NULL,
+ STRING_TOKEN (STR_SETFDT_ERROR),
+ mFdtPlatformDxeHiiHandle,
+ Status
+ );
+ goto Error;
+ }
+
+ //
+ // Update the preferred device path for the FDT if asked for.
+ //
+ if (FilePath) {
+ ValueStr = ShellCommandLineGetRawValue (ParamPackage, 1);
+ ShellPrintHiiEx (
+ -1, -1, NULL,
+ STRING_TOKEN (STR_SETFDT_UPDATING),
+ mFdtPlatformDxeHiiHandle
+ );
+ ShellStatus = UpdateFdtTextDevicePath (Shell, ValueStr);
+ if (ShellStatus != SHELL_SUCCESS) {
+ goto Error;
+ }
+ }
+
+ //
+ // Run the FDT installation process if asked for.
+ //
+ if (ShellCommandLineGetFlag (ParamPackage, L"-i")) {
+ ShellPrintHiiEx (
+ -1, -1, NULL,
+ STRING_TOKEN (STR_SETFDT_INSTALLING),
+ mFdtPlatformDxeHiiHandle
+ );
+ Status = RunFdtInstallation (&TextDevicePath);
+ ShellStatus = EfiCodeToShellCode (Status);
+ if (!EFI_ERROR (Status)) {
+ ShellPrintHiiEx (
+ -1, -1, NULL,
+ STRING_TOKEN (STR_SETFDT_INSTALL_SUCCEEDED),
+ mFdtPlatformDxeHiiHandle,
+ TextDevicePath
+ );
+ FreePool (TextDevicePath);
+ } else {
+ if (Status == EFI_INVALID_PARAMETER) {
+ ShellPrintHiiEx (
+ -1, -1, NULL,
+ STRING_TOKEN (STR_SETFDT_INVALID_DEVICE_PATH),
+ mFdtPlatformDxeHiiHandle
+ );
+ } else {
+ ShellPrintHiiEx (
+ -1, -1, NULL,
+ STRING_TOKEN (STR_SETFDT_ERROR),
+ mFdtPlatformDxeHiiHandle,
+ Status
+ );
+ }
+ DisplayFdtDevicePaths ();
+ }
+ }
+
+Error:
+ gBS->UninstallMultipleProtocolInterfaces (
+ gImageHandle,
+ &gEfiShellProtocolGuid, Shell,
+ &gEfiShellParametersProtocolGuid, ShellParameters,
+ NULL
+ );
+ ShellCommandLineFreeVarList (ParamPackage);
+
+ return ShellStatus;
+}
+
+/**
+ This is the shell command "setfdt" help handler function. This
+ function returns the formatted help for the "setfdt" command.
+ The format matchs that in Appendix B of the revision 2.1 of the
+ UEFI Shell Specification.
+
+ @param[in] This The instance of the EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
+ @param[in] Language The pointer to the language string to use.
+
+ @return CHAR16* Pool allocated help string, must be freed by caller.
+**/
+CHAR16*
+EFIAPI
+ShellDynCmdSetFdtGetHelp (
+ IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This,
+ IN CONST CHAR8 *Language
+ )
+{
+ //
+ // This allocates memory. The caller has to free the allocated memory.
+ //
+ return HiiGetString (
+ mFdtPlatformDxeHiiHandle,
+ STRING_TOKEN (STR_GET_HELP_SETFDT),
+ Language
+ );
+}
--
2.11.0
^ permalink raw reply related [flat|nested] 7+ messages in thread