From nobody Wed Dec 25 01:19:08 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) smtp.mailfrom=edk2-devel-bounces@lists.01.org Return-Path: Received: from ml01.01.org (ml01.01.org [198.145.21.10]) by mx.zohomail.com with SMTPS id 1511177848063201.4428502479957; Mon, 20 Nov 2017 03:37:28 -0800 (PST) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id DE40220347139; Mon, 20 Nov 2017 03:33:12 -0800 (PST) Received: from mail-wm0-x22a.google.com (mail-wm0-x22a.google.com [IPv6:2a00:1450:400c:c09::22a]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id C773E21959707 for ; Mon, 20 Nov 2017 03:33:10 -0800 (PST) Received: by mail-wm0-x22a.google.com with SMTP id y80so17985228wmd.0 for ; Mon, 20 Nov 2017 03:37:24 -0800 (PST) Received: from localhost.localdomain ([154.145.25.106]) by smtp.gmail.com with ESMTPSA id d4sm14760181wmh.35.2017.11.20.03.37.20 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 20 Nov 2017 03:37:21 -0800 (PST) X-Original-To: edk2-devel@lists.01.org Received-SPF: none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) client-ip=198.145.21.10; envelope-from=edk2-devel-bounces@lists.01.org; helo=ml01.01.org; Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=2a00:1450:400c:c09::22a; helo=mail-wm0-x22a.google.com; envelope-from=ard.biesheuvel@linaro.org; receiver=edk2-devel@lists.01.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=wfsGkexouKYY46p3nvq/+6DLvAyrLEqlxCbbPpDN0rI=; b=WpxMMc/3UDdHUeoV3LVrTZ7tx5isYyHdrK5rAxDEgHnTGVaE+a1FNmEwjuP6NZJWMZ gIkpD+CBsHXyBMwKOZeH98TO/j1NCBK4Br/s5T4MeRoTaSNkgcPbFfe41CZSjYWBLc8C iHCCzCaQ5TFJvusaoDXR9bJOvC6LPyuiebhkQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=wfsGkexouKYY46p3nvq/+6DLvAyrLEqlxCbbPpDN0rI=; b=UDmzCIVBthYF7zXsV7NYN3K1eFoJLm83lQ91aKqkDwH3MVkPVVVdc0104ILoXms5+n w4L3f5vFL4BpVOUHfm8Bkp1p/PE2WzEBdFBYvzRzfk91nIWvD0vnq8Vmuu0SaMfYv3UN MwaDYrdBTlGM4kLjWERH7ec4bgQvknZQ5ALVWe5GG6tW1BBOaROkc8UxfJOiGppLxWsN 9giVxrSAl2rq+xjdSHeb1YXXiT+iSu2w10+sWhIl5FNIhhXFPVUn33bL1az4DHQzoeCp +z7XxmAwuyzAER2Nvk3KyOF1j+1ghP3p8ujqOGV8ajawLjezfI9m1aSeUvFvhVraDKTZ sOCA== X-Gm-Message-State: AJaThX7laeb/epfYu3vib+TOWil8H5ERpwWoyyFerp6ixYfgWFA+vJTQ xYuAfTk7vLuLMlpgU7kdGZmCPAkz0GA= X-Google-Smtp-Source: AGs4zMZxXbpnggjinywmk8ii6RUH+T7lpL88/HlrY4hyGrfblIxvSJXY1cfax9fYtGgC7Eo3EppjWQ== X-Received: by 10.28.194.139 with SMTP id s133mr9216282wmf.14.1511177842096; Mon, 20 Nov 2017 03:37:22 -0800 (PST) From: Ard Biesheuvel To: edk2-devel@lists.01.org Date: Mon, 20 Nov 2017 11:37:11 +0000 Message-Id: <20171120113714.21856-2-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20171120113714.21856-1-ard.biesheuvel@linaro.org> References: <20171120113714.21856-1-ard.biesheuvel@linaro.org> Subject: [edk2] [PATCH edk2-platforms 1/4] Platform/ARM: import BdsLib from ArmPkg X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: leif.lindholm@linaro.org, Ard Biesheuvel MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_4 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" 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 --- 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/Libr= ary/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 B= SD 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 IM= PLIED. +* +**/ + +#include "BdsInternal.h" + +/** + Locate an EFI application in a the Firmware Volumes by its Name + + @param EfiAppGuid Guid of the EFI Application into the Firmw= are 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 !=3D NULL); + + // Length of FilePath + UiStringLen =3D StrLen (EfiAppName); + + // Locate all the Firmware Volume protocols. + Status =3D gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareVolume2ProtocolGuid, + NULL, + &NumberOfHandles, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + *DevicePath =3D NULL; + + // Looking for FV with ACPI storage file + for (Index =3D 0; Index < NumberOfHandles; Index++) { + // + // Get the protocol on this handle + // This should not fail because of LocateHandleBuffer + // + Status =3D gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiFirmwareVolume2ProtocolGuid, + (VOID**) &FvInstance + ); + if (EFI_ERROR (Status)) { + goto FREE_HANDLE_BUFFER; + } + + // Allocate Key + Key =3D AllocatePool (FvInstance->KeySize); + ASSERT (Key !=3D NULL); + ZeroMem (Key, FvInstance->KeySize); + + do { + // Search in all files + FileType =3D EFI_FV_FILETYPE_ALL; + + Status =3D FvInstance->GetNextFile (FvInstance, Key, &FileType, &Nam= eGuid, &Attributes, &Size); + if (!EFI_ERROR (Status)) { + UiSection =3D NULL; + FileStatus =3D FvInstance->ReadSection ( + FvInstance, + &NameGuid, + EFI_SECTION_USER_INTERFACE, + 0, + (VOID **)&UiSection, + &Size, + &Authentication + ); + if (!EFI_ERROR (FileStatus)) { + if (StrnCmp (EfiAppName, UiSection, UiStringLen) =3D=3D 0) { + // + // We found a UiString match. + // + Status =3D gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevi= cePathProtocolGuid, (VOID **)&FvDevicePath); + + // Generate the Device Path for the file + EfiInitializeFwVolDevicepathNode (&FileDevicePath, &NameGuid); + *DevicePath =3D AppendDevicePathNode (FvDevicePath, (EFI_DEVIC= E_PATH_PROTOCOL *)&FileDevicePath); + ASSERT (*DevicePath !=3D 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 Firmw= are 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 !=3D NULL); + + // Locate all the Firmware Volume protocols. + Status =3D gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareVolume2ProtocolGuid, + NULL, + &NumberOfHandles, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + *DevicePath =3D NULL; + + // Looking for FV with ACPI storage file + for (Index =3D 0; Index < NumberOfHandles; Index++) { + // + // Get the protocol on this handle + // This should not fail because of LocateHandleBuffer + // + Status =3D gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiFirmwareVolume2ProtocolGuid, + (VOID**) &FvInstance + ); + if (EFI_ERROR (Status)) { + goto FREE_HANDLE_BUFFER; + } + + Status =3D 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 =3D NULL; + Status =3D 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 Filena= me of the application + // + *DevicePath =3D FileDevicePath (HandleBuffer[Index], UiSection); + } else { + Status =3D gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePa= thProtocolGuid, (VOID**)&FvDevicePath); + ASSERT_EFI_ERROR (Status); + + // + // Create the EFI Device Path for the application using the EFI GU= ID of the application + // + EfiInitializeFwVolDevicepathNode (&FvFileDevicePath, EfiAppGuid); + + *DevicePath =3D AppendDevicePathNode (FvDevicePath, (EFI_DEVICE_PA= TH_PROTOCOL *)&FvFileDevicePath); + ASSERT (*DevicePath !=3D NULL); + } + break; + } + } + +FREE_HANDLE_BUFFER: + // + // Free any allocated buffers + // + FreePool (HandleBuffer); + + if (*DevicePath =3D=3D NULL) { + return EFI_NOT_FOUND; + } else { + return EFI_SUCCESS; + } +} diff --git a/Platform/ARM/Library/BdsLib/BdsFilePath.c b/Platform/ARM/Libra= ry/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 B= SD 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 IM= PLIED. +* +**/ + +#include "BdsInternal.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#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 amoun= t of + progress in the dowloading of a TFTP file. +*/ + +// Frame for the progression slider +STATIC CONST CHAR16 mTftpProgressFrame[] =3D 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 sli= der: +// 40 characters)] (nb of KBytes downloaded so far: 7 characters) Kb". The= re +// are thus the number of characters in mTftpProgressFrame[] plus 11 chara= cters +// (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[] =3D 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 =3D (CHAR16*)StrDevicePath; + Node =3D 0; + while ((Str !=3D NULL) && (*Str !=3D L'\0') && (Node < NumberDevicePathN= ode)) { + if ((*Str =3D=3D L'/') || (*Str =3D=3D L'\\')) { + Node++; + } + Str++; + } + + if (*Str =3D=3D L'\0') { + return NULL; + } else { + return Str; + } +} + +BOOLEAN +BdsIsRemovableUsb ( + IN EFI_DEVICE_PATH* DevicePath + ) +{ + return ((DevicePathType (DevicePath) =3D=3D MESSAGING_DEVICE_PATH) && + ((DevicePathSubType (DevicePath) =3D=3D MSG_USB_CLASS_DP) || + (DevicePathSubType (DevicePath) =3D=3D 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 =3D 0; + Status =3D gBS->LocateHandleBuffer (ByProtocol, &gEfiUsbIoProtocolGuid, = NULL, &UsbIoHandleCount, &UsbIoBuffer); + if (EFI_ERROR (Status) || (UsbIoHandleCount =3D=3D 0)) { + return Status; + } + + // Check if one of the handles matches the USB description + for (Index =3D 0; Index < UsbIoHandleCount; Index++) { + Status =3D gBS->HandleProtocol (UsbIoBuffer[Index], &gEfiDevicePathPro= tocolGuid, (VOID **) &UsbIoDevicePath); + if (!EFI_ERROR (Status)) { + TmpDevicePath =3D UsbIoDevicePath; + while (!IsDevicePathEnd (TmpDevicePath)) { + // Check if the Device Path node is a USB Removable device Path no= de + if (BdsIsRemovableUsb (TmpDevicePath)) { + if (TmpDevicePath->SubType =3D=3D MSG_USB_WWID_DP) { + WwidDevicePath1 =3D (USB_WWID_DEVICE_PATH*)RemovableDevicePath; + WwidDevicePath2 =3D (USB_WWID_DEVICE_PATH*)TmpDevicePath; + if ((WwidDevicePath1->VendorId =3D=3D WwidDevicePath2->VendorI= d) && + (WwidDevicePath1->ProductId =3D=3D WwidDevicePath2->Produc= tId) && + (CompareMem (WwidDevicePath1+1, WwidDevicePath2+1, DeviceP= athNodeLength(WwidDevicePath1)-sizeof (USB_WWID_DEVICE_PATH)) =3D=3D 0)) + { + *DeviceHandle =3D UsbIoBuffer[Index]; + // Add the additional original Device Path Nodes (eg: FilePa= th Device Path Node) to the new Device Path + *NewDevicePath =3D AppendDevicePath (UsbIoDevicePath, NextDe= vicePathNode (RemovableDevicePath)); + return EFI_SUCCESS; + } + } else { + UsbClassDevicePath1 =3D (USB_CLASS_DEVICE_PATH*)RemovableDevic= ePath; + UsbClassDevicePath2 =3D (USB_CLASS_DEVICE_PATH*)TmpDevicePath; + if ((UsbClassDevicePath1->VendorId !=3D 0xFFFF) && (UsbClassDe= vicePath1->VendorId =3D=3D UsbClassDevicePath2->VendorId) && + (UsbClassDevicePath1->ProductId !=3D 0xFFFF) && (UsbClassD= evicePath1->ProductId =3D=3D UsbClassDevicePath2->ProductId) && + (UsbClassDevicePath1->DeviceClass !=3D 0xFF) && (UsbClassD= evicePath1->DeviceClass =3D=3D UsbClassDevicePath2->DeviceClass) && + (UsbClassDevicePath1->DeviceSubClass !=3D 0xFF) && (UsbCla= ssDevicePath1->DeviceSubClass =3D=3D UsbClassDevicePath2->DeviceSubClass) && + (UsbClassDevicePath1->DeviceProtocol !=3D 0xFF) && (UsbCla= ssDevicePath1->DeviceProtocol =3D=3D UsbClassDevicePath2->DeviceProtocol)) + { + *DeviceHandle =3D UsbIoBuffer[Index]; + // Add the additional original Device Path Nodes (eg: FilePa= th Device Path Node) to the new Device Path + *NewDevicePath =3D AppendDevicePath (UsbIoDevicePath, NextDe= vicePathNode (RemovableDevicePath)); + return EFI_SUCCESS; + } + } + } + TmpDevicePath =3D NextDevicePathNode (TmpDevicePath); + } + + } + } + + return EFI_NOT_FOUND; +} + +BOOLEAN +BdsIsRemovableHd ( + IN EFI_DEVICE_PATH* DevicePath + ) +{ + return IS_DEVICE_PATH_NODE (DevicePath, MEDIA_DEVICE_PATH, MEDIA_HARDDRI= VE_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 =3D 0; + Status =3D gBS->LocateHandleBuffer (ByProtocol, &gEfiDiskIoProtocolGuid,= NULL, &PartitionHandleCount, &PartitionBuffer); + if (EFI_ERROR (Status) || (PartitionHandleCount =3D=3D 0)) { + return Status; + } + + // Check if one of the handles matches the Hard Disk Description + for (Index =3D 0; Index < PartitionHandleCount; Index++) { + Status =3D gBS->HandleProtocol (PartitionBuffer[Index], &gEfiDevicePat= hProtocolGuid, (VOID **) &PartitionDevicePath); + if (!EFI_ERROR (Status)) { + TmpDevicePath =3D PartitionDevicePath; + while (!IsDevicePathEnd (TmpDevicePath)) { + // Check if the Device Path node is a HD Removable device Path node + if (BdsIsRemovableHd (TmpDevicePath)) { + HardDriveDevicePath1 =3D (HARDDRIVE_DEVICE_PATH*)RemovableDevice= Path; + HardDriveDevicePath2 =3D (HARDDRIVE_DEVICE_PATH*)TmpDevicePath; + if ((HardDriveDevicePath1->SignatureType =3D=3D HardDriveDeviceP= ath2->SignatureType) && + (CompareGuid ((EFI_GUID *)HardDriveDevicePath1->Signature, (= EFI_GUID *)HardDriveDevicePath2->Signature) =3D=3D TRUE) && + (HardDriveDevicePath1->PartitionNumber =3D=3D HardDriveDevic= ePath2->PartitionNumber)) + { + *DeviceHandle =3D PartitionBuffer[Index]; + // Add the additional original Device Path Nodes (eg: FilePath= Device Path Node) to the new Device Path + *NewDevicePath =3D AppendDevicePath (PartitionDevicePath, Next= DevicePathNode (RemovableDevicePath)); + return EFI_SUCCESS; + } + } + TmpDevicePath =3D NextDevicePathNode (TmpDevicePath); + } + + } + } + + return EFI_NOT_FOUND; +} + +/*BOOLEAN +BdsIsRemovableCdrom ( + IN EFI_DEVICE_PATH* DevicePath + ) +{ + return IS_DEVICE_PATH_NODE (DevicePath, MEDIA_DEVICE_PATH, MEDIA_CDROM_D= P); +} + +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[] =3D { + { BdsIsRemovableUsb, BdsGetDeviceUsb }, + { BdsIsRemovableHd, BdsGetDeviceHd }, + //{ BdsIsRemovableCdrom, BdsGetDeviceCdrom } +}; + +STATIC +BOOLEAN +IsRemovableDevice ( + IN EFI_DEVICE_PATH* DevicePath + ) +{ + UINTN Index; + EFI_DEVICE_PATH* TmpDevicePath; + + TmpDevicePath =3D DevicePath; + while (!IsDevicePathEnd (TmpDevicePath)) { + for (Index =3D 0; Index < sizeof (RemovableDeviceSupport) / sizeof (BD= S_REMOVABLE_DEVICE_SUPPORT); Index++) { + if (RemovableDeviceSupport[Index].IsRemovable (TmpDevicePath)) { + return TRUE; + } + } + TmpDevicePath =3D 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 =3D NULL; + RemovableDevicePath =3D NULL; + RemovableFound =3D FALSE; + TmpDevicePath =3D DevicePath; + + while (!IsDevicePathEnd (TmpDevicePath) && !RemovableFound) { + for (Index =3D 0; Index < sizeof (RemovableDeviceSupport) / sizeof (BD= S_REMOVABLE_DEVICE_SUPPORT); Index++) { + RemovableDevice =3D &RemovableDeviceSupport[Index]; + if (RemovableDevice->IsRemovable (TmpDevicePath)) { + RemovableDevicePath =3D TmpDevicePath; + RemovableFound =3D TRUE; + break; + } + } + TmpDevicePath =3D NextDevicePathNode (TmpDevicePath); + } + + if (!RemovableFound) { + return EFI_NOT_FOUND; + } + + // Search into the current started drivers + Status =3D RemovableDevice->GetDevice (RemovableDevicePath, DeviceHandle= , NewDevicePath); + if (Status =3D=3D EFI_NOT_FOUND) { + // Connect all the drivers + BdsConnectAllDrivers (); + + // Search again into all the drivers + Status =3D RemovableDevice->GetDevice (RemovableDevicePath, DeviceHand= le, 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 =3D=3D NULL) || (*DevicePath =3D=3D NULL) || (Handle =3D= =3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + PreviousHandle =3D NULL; + do { + Remaining =3D *DevicePath; + + // The LocateDevicePath() function locates all devices on DevicePath t= hat 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 =3D gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remain= ing, Handle); + + if (!EFI_ERROR (Status)) { + if (*Handle =3D=3D 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 =3D=3D EFI_SUCCESS means a driver was dispatched + // Status =3D=3D EFI_NOT_FOUND means no new drivers were dispatched + // + Status =3D gDS->Dispatch (); + } + + if (!EFI_ERROR (Status)) { + PreviousHandle =3D *Handle; + + // Recursive =3D FALSE: We do not want to start the whole device t= ree + Status =3D 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 Connec= tController to ensure all the supported Driver + // Binding Protocol are connected (such as DiskIo and SimpleFileSystem) + Remaining =3D *DevicePath; + Status =3D gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remain= ing, Handle); + if (!EFI_ERROR (Status)) { + Status =3D gBS->ConnectController (*Handle, NULL, Remaining, FALSE); + if (EFI_ERROR (Status)) { + // If the last node is a Memory Map Device Path just return EFI_SU= CCESS. + if ((Remaining->Type =3D=3D HARDWARE_DEVICE_PATH) && (Remaining->S= ubType =3D=3D HW_MEMMAP_DP)) { + Status =3D EFI_SUCCESS; + } + } + } + } else if (!IsDevicePathEnd (Remaining) && !IsRemovableDevice (Remaining= )) { + + /*// If the remaining Device Path is a FilePath or MemoryMap then we c= onsider the Device Path has been loaded correctly + if ((Remaining->Type =3D=3D MEDIA_DEVICE_PATH) && (Remaining->SubType = =3D=3D MEDIA_FILEPATH_DP)) { + Status =3D EFI_SUCCESS; + } else if ((Remaining->Type =3D=3D HARDWARE_DEVICE_PATH) && (Remaining= ->SubType =3D=3D HW_MEMMAP_DP)) { + Status =3D EFI_SUCCESS; + }*/ + + //TODO: Should we just return success and leave the caller decide if i= t is the expected RemainingPath + Status =3D EFI_SUCCESS; + } else { + Status =3D TryRemovableDevice (*DevicePath, Handle, &NewDevicePath); + if (!EFI_ERROR (Status)) { + Status =3D BdsConnectAndUpdateDevicePath (&NewDevicePath, Handle, Re= mainingDevicePath); + *DevicePath =3D NewDevicePath; + return Status; + } + } + + if (RemainingDevicePath) { + *RemainingDevicePath =3D Remaining; + } + + return Status; +} + +/** + Connect a Device Path and return the handle of the driver that support t= his DevicePath + + @param DevicePath Device Path of the File to connect + @param Handle Handle of the driver that support this Dev= icePath + @param RemainingDevicePath Remaining DevicePath nodes that do not mat= ch 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, RemainingDevi= cePath); +} + +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 =3D gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGui= d, (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, MED= IA_FILEPATH_DP)); + + FilePathDevicePath =3D (FILEPATH_DEVICE_PATH*)RemainingDevicePath; + + Status =3D 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 =3D FsProtocol->OpenVolume (FsProtocol, &Fs); + if (EFI_ERROR (Status)) { + goto CLOSE_PROTOCOL; + } + + Status =3D Fs->Open (Fs, &File, FilePathDevicePath->PathName, EFI_FILE_M= ODE_READ, 0); + if (EFI_ERROR (Status)) { + goto CLOSE_PROTOCOL; + } + + Size =3D 0; + File->GetInfo (File, &gEfiFileInfoGuid, &Size, NULL); + FileInfo =3D AllocatePool (Size); + Status =3D File->GetInfo (File, &gEfiFileInfoGuid, &Size, FileInfo); + if (EFI_ERROR (Status)) { + goto CLOSE_FILE; + } + + // Get the file size + Size =3D FileInfo->FileSize; + if (ImageSize) { + *ImageSize =3D Size; + } + FreePool (FileInfo); + + Status =3D gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PA= GES(Size), Image); + // Try to allocate in any pages if failed to allocate memory at the defi= ned location + if ((Status =3D=3D EFI_OUT_OF_RESOURCES) && (Type !=3D AllocateAnyPages)= ) { + Status =3D gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, = EFI_SIZE_TO_PAGES(Size), Image); + } + if (!EFI_ERROR (Status)) { + Status =3D 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, H= W_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_M= EMMAP_DP)) { + MemMapPathDevicePath =3D (MEMMAP_DEVICE_PATH*)RemainingDevicePath; + } else { + ASSERT (IS_DEVICE_PATH_NODE (*DevicePath, HARDWARE_DEVICE_PATH, HW_MEM= MAP_DP)); + MemMapPathDevicePath =3D (MEMMAP_DEVICE_PATH*)*DevicePath; + } + + Size =3D MemMapPathDevicePath->EndingAddress - MemMapPathDevicePath->Sta= rtingAddress; + if (Size =3D=3D 0) { + return EFI_INVALID_PARAMETER; + } + + Status =3D gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PA= GES(Size), Image); + // Try to allocate in any pages if failed to allocate memory at the defi= ned location + if ((Status =3D=3D EFI_OUT_OF_RESOURCES) && (Type !=3D AllocateAnyPages)= ) { + Status =3D gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, = EFI_SIZE_TO_PAGES(Size), Image); + } + if (!EFI_ERROR (Status)) { + CopyMem ((VOID*)(UINTN)(*Image), (CONST VOID*)(UINTN)MemMapPathDeviceP= ath->StartingAddress, Size); + + if (ImageSize !=3D NULL) { + *ImageSize =3D 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, MEDI= A_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, MED= IA_PIWG_FW_FILE_DP)); + + Status =3D gBS->HandleProtocol (Handle, &gEfiFirmwareVolume2ProtocolGuid= , (VOID **)&FwVol); + if (EFI_ERROR (Status)) { + return Status; + } + + FvNameGuid =3D EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VO= L_FILEPATH_DEVICE_PATH *)RemainingDevicePath); + if (FvNameGuid =3D=3D NULL) { + Status =3D EFI_INVALID_PARAMETER; + } + + SectionType =3D EFI_SECTION_PE32; + AuthenticationStatus =3D 0; + //Note: ReadSection at the opposite of ReadFile does not allow to pass I= mageBuffer =3D=3D NULL to get the size of the file. + ImageBuffer =3D NULL; + Status =3D 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 !=3D AllocateAnyPages) { + Status =3D gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_T= O_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 cal= ler could call gBS->FreePages() on the pool allocation + Status =3D gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_= PAGES(*ImageSize), Image); + // Try to allocate in any pages if failed to allocate memory at the de= fined location + if ((Status =3D=3D EFI_OUT_OF_RESOURCES) && (Type !=3D AllocateAnyPage= s)) { + Status =3D 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 =3D FwVol->ReadFile ( + FwVol, + FvNameGuid, + NULL, + ImageSize, + &FvType, + &Attrib, + &AuthenticationStatus + ); + if (!EFI_ERROR (Status)) { + Status =3D gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_T= O_PAGES(*ImageSize), Image); + // Try to allocate in any pages if failed to allocate memory at the = defined location + if ((Status =3D=3D EFI_OUT_OF_RESOURCES) && (Type !=3D AllocateAnyPa= ges)) { + Status =3D gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCo= de, EFI_SIZE_TO_PAGES(*ImageSize), Image); + } + if (!EFI_ERROR (Status)) { + Status =3D 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 =3D gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (V= OID **)&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 =3D gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID= **)&LoadFileProtocol); + if (EFI_ERROR (Status)) { + return Status; + } + + Status =3D LoadFileProtocol->LoadFile (LoadFileProtocol, RemainingDevice= Path, TRUE, &BufferSize, NULL); + if (Status =3D=3D EFI_BUFFER_TOO_SMALL) { + Status =3D gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_= PAGES(BufferSize), Image); + if (EFI_ERROR (Status)) { + return Status; + } + + Status =3D LoadFileProtocol->LoadFile (LoadFileProtocol, RemainingDevi= cePath, TRUE, &BufferSize, (VOID*)(UINTN)(*Image)); + if (!EFI_ERROR (Status) && (ImageSize !=3D NULL)) { + *ImageSize =3D BufferSize; + } + } + + if (Status =3D=3D EFI_ALREADY_STARTED) { + Status =3D gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (V= OID **)&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, Typ= e, 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, MS= G_IPv4_DP) && + !IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MS= G_IPv6_DP)) { + return FALSE; + } + NextDevicePath =3D NextDevicePathNode (RemainingDevicePath); + if (IsDevicePathEnd (NextDevicePath)) { + return FALSE; + } + if (!IS_DEVICE_PATH_NODE (NextDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEP= ATH_DP)) { + return FALSE; + } + + Status =3D gBS->HandleProtocol ( + Handle, &gEfiDevicePathProtocolGuid, + &Interface + ); + if (EFI_ERROR (Status)) { + return FALSE; + } + + // + // Check that the controller (identified by its handle "Handle") support= s the + // MTFTPv4 Service Binding Protocol. If it does, it means that it suppor= ts the + // EFI MTFTPv4 Protocol needed to download the image through TFTP. + // + Status =3D 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 T= FTP + 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 =3D (UINT8*)"tsize"; + OptBuf[0] =3D '0'; + OptBuf[1] =3D 0; + ReqOpt[0].ValueStr =3D OptBuf; + + Status =3D Mtftp4->GetInfo ( + Mtftp4, + NULL, + (UINT8*)FilePath, + NULL, + 1, + ReqOpt, + &PktLen, + &Packet + ); + + if (EFI_ERROR (Status)) { + goto Error; + } + + Status =3D Mtftp4->ParseOptions ( + Mtftp4, + PktLen, + Packet, + (UINT32 *) &OptCnt, + &TableOfOptions + ); + if (EFI_ERROR (Status)) { + goto Error; + } + + Option =3D TableOfOptions; + while (OptCnt !=3D 0) { + if (AsciiStrnCmp ((CHAR8 *)Option->OptionStr, "tsize", 5) =3D=3D 0) { + *FileSize =3D AsciiStrDecimalToUint64 ((CHAR8 *)Option->ValueStr); + break; + } + OptCnt--; + Option++; + } + FreePool (TableOfOptions); + + if (OptCnt =3D=3D 0) { + Status =3D 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)) =3D=3D EFI_MTFTP4_OPCODE_DATA) { + Context =3D (BDS_TFTP_CONTEXT*)Token->Context; + + if (Context->DownloadedNbOfBytes =3D=3D 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 =3D EFI_MTFTP4_OPCODE_DATA + // . Block =3D the number of this block of data + // + Context->DownloadedNbOfBytes +=3D PacketLen - sizeof (Packet->OpCode) = - sizeof (Packet->Data.Block); + NbOfKb =3D Context->DownloadedNbOfBytes / 1024; + + Progress[0] =3D L'\0'; + if (Context->FileSize > 0) { + LastStep =3D (Context->LastReportedNbOfBytes * TFTP_PROGRESS_SLIDER= _STEPS) / Context->FileSize; + Step =3D (Context->DownloadedNbOfBytes * TFTP_PROGRESS_SLIDER= _STEPS) / Context->FileSize; + if (Step > LastStep) { + Print (mTftpProgressDelete); + CopyMem (Progress, mTftpProgressFrame, sizeof mTftpProgressFrame); + for (Index =3D 1; Index < Step; Index++) { + Progress[Index] =3D L'=3D'; + } + Progress[Step] =3D L'>'; + + UnicodeSPrint ( + Progress + (sizeof (mTftpProgressFrame) / sizeof (CHAR16)) - 1, + sizeof (Progress) - sizeof (mTftpProgressFrame), + L" %7d Kb", + NbOfKb + ); + Context->LastReportedNbOfBytes =3D 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 =3D Context->LastReportedNbOfBytes / (50*1024); + NbOf50Kb =3D 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 =3D Context->DownloadedNbOfBytes; + } + } + if (Progress[0] !=3D 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 net= work controller + @param[in] Type Type to allocate memory pages + @param[out] Image Address of the bufer where the image i= s stored in + case of success + @param[out] ImageSize Size in number of bytes of the i;age i= n 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 =3D (IPv4_DEVICE_PATH*)RemainingDevicePath; + + Dhcp4ChildHandle =3D NULL; + Dhcp4 =3D NULL; + Dhcp4ToStop =3D FALSE; + Mtftp4ChildHandle =3D NULL; + Mtftp4 =3D NULL; + AsciiFilePath =3D NULL; + TftpContext =3D 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 =3D NetLibCreateServiceChild ( + ControllerHandle, + gImageHandle, + &gEfiDhcp4ServiceBindingProtocolGuid, + &Dhcp4ChildHandle + ); + if (!EFI_ERROR (Status)) { + Status =3D 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 t= he MTFTP4 service and + // install the MTFTP4 protocol on it. Then, open the MTFTP4 protocol. + // + Status =3D NetLibCreateServiceChild ( + ControllerHandle, + gImageHandle, + &gEfiMtftp4ServiceBindingProtocolGuid, + &Mtftp4ChildHandle + ); + if (!EFI_ERROR (Status)) { + Status =3D 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 t= hat 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 =3D DHCP_TAG_PARA_LIST; + ParaList.Head.Length =3D 2; + ParaList.Head.Data[0] =3D DHCP_TAG_NETMASK; + ParaList.Route =3D DHCP_TAG_ROUTER; + OptionList[0] =3D &ParaList.Head; + Dhcp4CfgData.OptionCount =3D 1; + Dhcp4CfgData.OptionList =3D OptionList; + + Status =3D Dhcp4->Configure (Dhcp4, &Dhcp4CfgData); + if (EFI_ERROR (Status)) { + if (Status !=3D 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 =3D Dhcp4->Start (Dhcp4, NULL); + if (EFI_ERROR (Status)) { + if (Status !=3D EFI_ALREADY_STARTED) { + Print (L"DHCP configuration failed\n"); + goto Error; + } + } else { + Dhcp4ToStop =3D TRUE; + } + + Status =3D Dhcp4->GetModeData (Dhcp4, &Dhcp4Mode); + if (EFI_ERROR (Status)) { + goto Error; + } + + if (Dhcp4Mode.State !=3D Dhcp4Bound) { + Status =3D EFI_TIMEOUT; + Print (L"DHCP configuration failed\n"); + goto Error; + } + } + + // + // Configure the TFTP4 protocol + // + + ZeroMem (&Mtftp4CfgData, sizeof (EFI_MTFTP4_CONFIG_DATA)); + Mtftp4CfgData.UseDefaultSetting =3D FALSE; + Mtftp4CfgData.TimeoutValue =3D 4; + Mtftp4CfgData.TryCount =3D 6; + + if (IPv4DevicePathNode->StaticIpAddress) { + CopyMem (&Mtftp4CfgData.StationIp , &IPv4DevicePathNode->LocalIpAddres= s, sizeof (EFI_IPv4_ADDRESS)); + CopyMem (&Mtftp4CfgData.SubnetMask, &IPv4DevicePathNode->SubnetMask, s= izeof (EFI_IPv4_ADDRESS)); + CopyMem (&Mtftp4CfgData.GatewayIp , &IPv4DevicePathNode->GatewayIpAddr= ess, 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 =3D 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 =3D ConvertDevicePathToText ((EFI_DEVICE_PATH_PROTOCOL*)(I= Pv4DevicePathNode + 1), FALSE, FALSE); + PathNameLen =3D StrLen (PathName) + 1; + AsciiFilePath =3D 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 =3D 0; + if (Mtftp4GetFileSize (Mtftp4, AsciiFilePath, &FileSize) =3D=3D EFI_SUCC= ESS) { + TftpBufferSize =3D FileSize; + } else { + TftpBufferSize =3D SIZE_16MB; + } + + TftpContext =3D AllocatePool (sizeof (BDS_TFTP_CONTEXT)); + if (TftpContext =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto Error; + } + TftpContext->FileSize =3D FileSize; + + for (; TftpBufferSize <=3D MAX_TFTP_FILE_SIZE; + TftpBufferSize =3D (TftpBufferSize + SIZE_16MB) & (~(SIZE_16MB-1)= )) { + // + // Allocate a buffer to hold the whole file. + // + Status =3D 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 =3D 0; + TftpContext->LastReportedNbOfBytes =3D 0; + + ZeroMem (&Mtftp4Token, sizeof (EFI_MTFTP4_TOKEN)); + Mtftp4Token.Filename =3D (UINT8*)AsciiFilePath; + Mtftp4Token.BufferSize =3D TftpBufferSize; + Mtftp4Token.Buffer =3D (VOID *)(UINTN)*Image; + Mtftp4Token.CheckPacket =3D Mtftp4CheckPacket; + Mtftp4Token.Context =3D (VOID*)TftpContext; + + Print (L"Downloading the file <%a> from the TFTP server\n", AsciiFileP= ath); + Status =3D Mtftp4->ReadFile (Mtftp4, &Mtftp4Token); + Print (L"\n"); + if (EFI_ERROR (Status)) { + gBS->FreePages (*Image, EFI_SIZE_TO_PAGES (TftpBufferSize)); + if (Status =3D=3D EFI_BUFFER_TOO_SMALL) { + Print (L"Downloading failed, file larger than expected.\n"); + continue; + } else { + goto Error; + } + } + + *ImageSize =3D Mtftp4Token.BufferSize; + break; + } + +Error: + if (Dhcp4ChildHandle !=3D NULL) { + if (Dhcp4 !=3D NULL) { + if (Dhcp4ToStop) { + Dhcp4->Stop (Dhcp4); + } + gBS->CloseProtocol ( + Dhcp4ChildHandle, + &gEfiDhcp4ProtocolGuid, + gImageHandle, + ControllerHandle + ); + } + NetLibDestroyServiceChild ( + ControllerHandle, + gImageHandle, + &gEfiDhcp4ServiceBindingProtocolGuid, + Dhcp4ChildHandle + ); + } + + if (Mtftp4ChildHandle !=3D NULL) { + if (Mtftp4 !=3D NULL) { + if (AsciiFilePath !=3D NULL) { + FreePool (AsciiFilePath); + } + if (TftpContext !=3D NULL) { + FreePool (TftpContext); + } + gBS->CloseProtocol ( + Mtftp4ChildHandle, + &gEfiMtftp4ProtocolGuid, + gImageHandle, + ControllerHandle + ); + } + NetLibDestroyServiceChild ( + ControllerHandle, + gImageHandle, + &gEfiMtftp4ServiceBindingProtocolGuid, + Mtftp4ChildHandle + ); + } + + if (EFI_ERROR (Status)) { + *Image =3D 0; + Print (L"Failed to download the file - Error=3D%r\n", Status); + } + + return Status; +} + +BDS_FILE_LOADER FileLoaders[] =3D { + { 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 =3D BdsConnectAndUpdateDevicePath (DevicePath, &Handle, &Remainin= gDevicePath); + if (EFI_ERROR (Status)) { + return Status; + } + + FileLoader =3D FileLoaders; + while (FileLoader->Support !=3D NULL) { + if (FileLoader->Support (*DevicePath, Handle, RemainingDevicePath)) { + return FileLoader->LoadImage (DevicePath, Handle, RemainingDevicePat= h, 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, FileSi= ze); +} + +/** + 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 sto= re 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 =3D BdsLoadImageAndUpdateDevicePath (&DevicePath, AllocateAnyPage= s, &BinaryBuffer, &BinarySize); + if (EFI_ERROR (Status)) { + return Status; + } + + // Load the image from the Buffer with Boot Services function + Status =3D gBS->LoadImage (TRUE, ParentImageHandle, DevicePath, (VOID*)(= UINTN)BinaryBuffer, BinarySize, &ImageHandle); + if (EFI_ERROR (Status)) { + return Status; + } + + // Passed LoadOptions to the EFI Application + if (LoadOptionsSize !=3D 0) { + Status =3D gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolG= uid, (VOID **) &LoadedImage); + if (EFI_ERROR (Status)) { + return Status; + } + + LoadedImage->LoadOptionsSize =3D LoadOptionsSize; + LoadedImage->LoadOptions =3D 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 =3D 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 B= SD 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 IM= PLIED. +* +**/ + +#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 =3D NULL; + MemoryMapSize =3D 0; + Pages =3D 0; + + do { + Status =3D gBS->GetMemoryMap ( + &MemoryMapSize, + MemoryMap, + &MapKey, + &DescriptorSize, + &DescriptorVersion + ); + if (Status =3D=3D EFI_BUFFER_TOO_SMALL) { + + Pages =3D EFI_SIZE_TO_PAGES (MemoryMapSize) + 1; + MemoryMap =3D AllocatePages (Pages); + + // + // Get System MemoryMap + // + Status =3D gBS->GetMemoryMap ( + &MemoryMapSize, + MemoryMap, + &MapKey, + &DescriptorSize, + &DescriptorVersion + ); + } + + // Don't do anything between the GetMemoryMap() and ExitBootServices() + if (!EFI_ERROR(Status)) { + Status =3D gBS->ExitBootServices (gImageHandle, MapKey); + if (EFI_ERROR(Status)) { + FreePages (MemoryMap, Pages); + MemoryMap =3D NULL; + MemoryMapSize =3D 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 =3D gBS->LocateHandleBuffer ( + AllHandles, + NULL, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + break; + } + + // Connect every handles + for (Index =3D 0; Index < HandleCount; Index++) { + gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE); + } + + if (HandleBuffer !=3D NULL) { + FreePool (HandleBuffer); + } + + // Check if new handles have been created after the start of the previ= ous handles + Status =3D 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 =3D NULL; + VariableSize =3D 0; + Status =3D gRT->GetVariable ((CHAR16 *) VariableName, VendorGuid, NULL, = &VariableSize, *Value); + if (Status =3D=3D EFI_NOT_FOUND) { + if ((DefaultValue !=3D NULL) && (Size !=3D NULL) && (*Size !=3D 0)) { + // If the environment variable does not exist yet then set it with t= he default value + Status =3D gRT->SetVariable ( + (CHAR16*)VariableName, + VendorGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_A= CCESS | EFI_VARIABLE_RUNTIME_ACCESS, + *Size, + DefaultValue + ); + *Value =3D AllocateCopyPool (*Size, DefaultValue); + } else { + return EFI_NOT_FOUND; + } + } else if (Status =3D=3D EFI_BUFFER_TOO_SMALL) { + // Get the environment variable value + *Value =3D AllocatePool (VariableSize); + if (*Value =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status =3D gRT->GetVariable ((CHAR16 *)VariableName, VendorGuid, NULL,= &VariableSize, *Value); + if (EFI_ERROR (Status)) { + FreePool(*Value); + return EFI_INVALID_PARAMETER; + } + + if (Size) { + *Size =3D VariableSize; + } + } else { + *Value =3D AllocateCopyPool (*Size, DefaultValue); + return Status; + } + + return EFI_SUCCESS; +} diff --git a/Platform/ARM/Library/BdsLib/BdsInternal.h b/Platform/ARM/Libra= ry/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 B= SD 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 IM= PLIED. +* +**/ + +#ifndef __BDS_INTERNAL_H__ +#define __BDS_INTERNAL_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +/** + * 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 ent= ry (ie: Boot####). + * @param Handle Handle of the driver supporting the device path + * @param RemainingDevicePath Part of the EFI Device Path that has not b= een 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 ent= ry (ie: Boot####). + * This path is also defined as 'OUT' as there are so= me device paths that + * might not be completed such as EFI path for remova= ble 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 b= een resolved during + * the Device Path discovery + * @param Type Define where the image should be loaded (see EFI_A= LLOCATE_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 en= try 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 B= SD 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 IM= PLIED. +# +#*/ + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D BdsLib + FILE_GUID =3D ddbf73a0-bb25-11df-8e4e-0002a5d5c51b + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 1.0 + LIBRARY_CLASS =3D 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/Lib= rary/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 B= SD 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 IM= PLIED. +* +**/ + +#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 =3D=3D 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 =3D=3D NULL) { + LoadOption =3D (BDS_LOAD_OPTION*)AllocateZeroPool (sizeof(BDS_LOAD_OPT= ION)); + if (LoadOption =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + } else { + LoadOption =3D *BdsLoadOption; + } + + EfiLoadOptionPtr =3D (UINTN)EfiLoadOption; + LoadOption->LoadOption =3D EfiLoadOption; + LoadOption->LoadOptionSize =3D EfiLoadOptionSize; + + LoadOption->Attributes =3D *(UINT32*)EfiLoadOptionPtr; + LoadOption->FilePathListLength =3D *(UINT16*)(EfiLoadOptionPtr + sizeof(= UINT32)); + LoadOption->Description =3D (CHAR16*)(EfiLoadOptionPtr + sizeof(U= INT32) + sizeof(UINT16)); + DescriptionLength =3D StrSize (LoadOption->Description); + LoadOption->FilePathList =3D (EFI_DEVICE_PATH_PROTOCOL*)(EfiLoadOp= tionPtr + sizeof(UINT32) + sizeof(UINT16) + DescriptionLength); + + // If ((End of EfiLoadOptiony - Start of EfiLoadOption) =3D=3D EfiLoadOp= tionSize) then No Optional Data + if ((UINTN)((UINTN)LoadOption->FilePathList + LoadOption->FilePathListLe= ngth - EfiLoadOptionPtr) =3D=3D EfiLoadOptionSize) { + LoadOption->OptionalData =3D NULL; + LoadOption->OptionalDataSize =3D 0; + } else { + LoadOption->OptionalData =3D (VOID*)((UINTN)(LoadOption->FilePathL= ist) + LoadOption->FilePathListLength); + LoadOption->OptionalDataSize =3D EfiLoadOptionSize - ((UINTN)LoadOptio= n->OptionalData - EfiLoadOptionPtr); + } + + if (*BdsLoadOption =3D=3D NULL) { + *BdsLoadOption =3D 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 =3D GetGlobalEnvironmentVariable (BootVariableName, NULL, &EfiLoa= dOptionSize, (VOID**)&EfiLoadOption); + if (!EFI_ERROR(Status)) { + *BdsLoadOption =3D NULL; + Status =3D 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", LoadOp= tionIndex); + + Status =3D BootOptionFromLoadOptionVariable (BootVariableName, BdsLoadOp= tion); + if (!EFI_ERROR(Status)) { + (*BdsLoadOption)->LoadOptionIndex =3D 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 pr= eviously allocated memory + if (BdsLoadOption->LoadOptionSize > 0) { + OldLoadOption =3D BdsLoadOption->LoadOption; + } else { + OldLoadOption =3D 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 =3D BootOptionAllocateBootIndex (); + + //TODO: Add to the the Boot Entry List + } + + DescriptionSize =3D StrSize(BdsLoadOption->Description); + + // Ensure the FilePathListLength information is correct + ASSERT (GetDevicePathSize (BdsLoadOption->FilePathList) =3D=3D BdsLoadOp= tion->FilePathListLength); + + // Allocate the memory for the EFI Load Option + BdsLoadOption->LoadOptionSize =3D sizeof(UINT32) + sizeof(UINT16) + Desc= riptionSize + BdsLoadOption->FilePathListLength + BdsLoadOption->OptionalDa= taSize; + + BdsLoadOption->LoadOption =3D (EFI_LOAD_OPTION *)AllocateZeroPool (BdsLo= adOption->LoadOptionSize); + if (BdsLoadOption->LoadOption =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + EfiLoadOptionPtr =3D (UINT8 *) BdsLoadOption->LoadOption; + + // + // Populate the EFI Load Option and BDS Boot Option structures + // + + // Attributes fields + *(UINT32*)EfiLoadOptionPtr =3D BdsLoadOption->Attributes; + EfiLoadOptionPtr +=3D sizeof(UINT32); + + // FilePath List fields + *(UINT16*)EfiLoadOptionPtr =3D BdsLoadOption->FilePathListLength; + EfiLoadOptionPtr +=3D sizeof(UINT16); + + // Boot description fields + CopyMem (EfiLoadOptionPtr, BdsLoadOption->Description, DescriptionSize); + EfiLoadOptionPtr +=3D DescriptionSize; + + // File path fields + DevicePathNode =3D BdsLoadOption->FilePathList; + while (!IsDevicePathEndType (DevicePathNode)) { + NodeLength =3D DevicePathNodeLength(DevicePathNode); + CopyMem (EfiLoadOptionPtr, DevicePathNode, NodeLength); + EfiLoadOptionPtr +=3D NodeLength; + DevicePathNode =3D NextDevicePathNode (DevicePathNode); + } + + // Set the End Device Path Type + SetDevicePathEndNode (EfiLoadOptionPtr); + EfiLoadOptionPtr +=3D 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 struc= ture, we need to update the pointers of BdsLoadOption + BootOptionParseLoadOption (BdsLoadOption->LoadOption, BdsLoadOption->L= oadOptionSize, &BdsLoadOption); + // Free the old packed structure + FreePool (OldLoadOption); + } + + // Create/Update Boot#### environment variable + UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BdsLoa= dOption->LoadOptionIndex); + Status =3D gRT->SetVariable ( + BootVariableName, + &gEfiGlobalVariableGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VA= RIABLE_RUNTIME_ACCESS, + BdsLoadOption->LoadOptionSize, + BdsLoadOption->LoadOption + ); + + // When it is a new entry we must add the entry to the BootOrder + if (OldLoadOption =3D=3D NULL) { + // Add the new Boot Index to the list + Status =3D GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrde= rSize, (VOID**)&BootOrder); + if (!EFI_ERROR(Status)) { + BootOrder =3D ReallocatePool (BootOrderSize, BootOrderSize + sizeof(= UINT16), BootOrder); + // Add the new index at the end + BootOrder[BootOrderSize / sizeof(UINT16)] =3D BdsLoadOption->LoadOpt= ionIndex; + BootOrderSize +=3D sizeof(UINT16); + } else { + // BootOrder does not exist. Create it + BootOrderSize =3D sizeof(UINT16); + BootOrder =3D &(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 =3D GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderS= ize, (VOID**)&BootOrder); + if (!EFI_ERROR(Status)) { + for (BootIndex =3D 0; BootIndex <=3D 0xFFFF; BootIndex++) { + Found =3D FALSE; + for (Index =3D 0; Index < BootOrderSize / sizeof (UINT16); Index++) { + if (BootOrder[Index] =3D=3D BootIndex) { + Found =3D TRUE; + break; + } + } + if (!Found) { + return BootIndex; + } + } + FreePool (BootOrder); + } + // Return the first index + return 0; +} --=20 2.11.0 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel