From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=2607:f8b0:400e:c00::22c; helo=mail-pf0-x22c.google.com; envelope-from=kalyankumar.nagabhirava@linaro.org; receiver=edk2-devel@lists.01.org Received: from mail-pf0-x22c.google.com (mail-pf0-x22c.google.com [IPv6:2607:f8b0:400e:c00::22c]) (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 49B0B21B02855 for ; Thu, 7 Dec 2017 05:31:55 -0800 (PST) Received: by mail-pf0-x22c.google.com with SMTP id p84so4706262pfd.3 for ; Thu, 07 Dec 2017 05:36:28 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:subject:date:message-id:in-reply-to:references; bh=oUcOvtrkEfii3vDuyF6GoR7OkAZQRk0K6zPzmVQvPK0=; b=LXk/s+hL7R54f0935WLndVHWIKL7yKsiWL52cGti+ZFXSbZiCiXruHc4sDAukK1mlY Jaen3z2/sVGejunx5Q3e7SfVmPDfdtPvspLZi0VLWGh6SDbRervWT/u36uSBLoU+lE8o hH5aDdGyHDGlK7Db4xcOugRa8n73DaH79M7jY= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=oUcOvtrkEfii3vDuyF6GoR7OkAZQRk0K6zPzmVQvPK0=; b=q3lcNWit/6qrR7FfOV8nUZAK/7hbFzOFNs1eE4sNPKxc90OSgXX0cj0OEJV/Tbqo+s 7Cvuw/OBeCVcGG7i62BsHWa1B/aWmAMoGM4y4kTJmZIRNQdb91ZPx3y8+GaHT738/3pm h+5YAWEeH5d43IpV4cu7ma6DSZTbDfIP9FL32LsfN5FOGYXi30I2oRvdc00R7jgVXnAP IJU5XiLuN68vBTxVHTy7yqjYKMlo/c8pqu0ic5t4jDiyKAXmErglAC3eDywPUffh7BvN g2ac2XSRrB7LpJkSuxha5DNR25Bdp+LTzeKqnqu/Z8De5llRDw0PSfnowoXm5JGbIbbe H1Nw== X-Gm-Message-State: AJaThX4FhwWny2qex2gjGRhsqanyqcpvCzOvqwSe6x33YJXCUt0VVcS9 SAp/HbFYXEACPh/nyO05FYhPM9KdekA= X-Google-Smtp-Source: AGs4zMbGVE4JbWVI94g4LZJtmWnP40pMJHTxGBZ6ZByYMCE5ONYeXqugkwkANERK3IcoryrsDXKHVw== X-Received: by 10.99.126.93 with SMTP id o29mr25452071pgn.304.1512653786930; Thu, 07 Dec 2017 05:36:26 -0800 (PST) Received: from localhost.localdomain ([220.225.120.129]) by smtp.gmail.com with ESMTPSA id o70sm10477059pfk.79.2017.12.07.05.36.24 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 07 Dec 2017 05:36:26 -0800 (PST) From: kalyan-nagabhirava To: edk2-devel@lists.01.org Date: Thu, 7 Dec 2017 19:04:22 +0530 Message-Id: <20171207133424.24674-2-kalyankumar.nagabhirava@linaro.org> X-Mailer: git-send-email 2.15.0 In-Reply-To: <20171207133424.24674-1-kalyankumar.nagabhirava@linaro.org> References: <20171207133424.24674-1-kalyankumar.nagabhirava@linaro.org> Subject: [PATCH v2 1/3] [edk2 EmbeddedPkg]:Implementation of secure boot and HTTP Image download 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: , X-List-Received-Date: Thu, 07 Dec 2017 13:31:55 -0000 Linaro and RDK are working on standardizing the boot process for RDK STB boxes using Uefi, as part of that implemented secure boot and HTTP image download functionality. Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: kalyan-nagabhirava --- EmbeddedPkg/Library/RdkBootManagerLib/RdkBootManagerLib.dec | 52 ++ EmbeddedPkg/Library/RdkBootManagerLib/RdkBootManagerLib.inf | 81 +++ EmbeddedPkg/Library/RdkBootManagerLib/Include/DiskIo.h | 20 + EmbeddedPkg/Library/RdkBootManagerLib/Include/HttpBoot.h | 7 + EmbeddedPkg/Library/RdkBootManagerLib/Include/List.h | 52 ++ EmbeddedPkg/Library/RdkBootManagerLib/Include/RdkBootManagerLib.h | 31 ++ EmbeddedPkg/Library/RdkBootManagerLib/Include/RdkFile.h | 20 + EmbeddedPkg/Library/RdkBootManagerLib/Include/SecureBoot.h | 40 ++ EmbeddedPkg/Library/RdkBootManagerLib/DiskIo.c | 536 ++++++++++++++++++ EmbeddedPkg/Library/RdkBootManagerLib/HttpBoot.c | 315 +++++++++++ EmbeddedPkg/Library/RdkBootManagerLib/RdkFile.c | 259 +++++++++ EmbeddedPkg/Library/RdkBootManagerLib/SecureBoot.c | 577 ++++++++++++++++++++ 12 files changed, 1990 insertions(+) diff --git a/EmbeddedPkg/Library/RdkBootManagerLib/RdkBootManagerLib.dec b/EmbeddedPkg/Library/RdkBootManagerLib/RdkBootManagerLib.dec new file mode 100644 index 000000000000..2f84d1c56db3 --- /dev/null +++ b/EmbeddedPkg/Library/RdkBootManagerLib/RdkBootManagerLib.dec @@ -0,0 +1,52 @@ +# +# Copyright (c) 2014-2017, Linaro 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 = 0x00010019 + PACKAGE_NAME = RdkPkg + PACKAGE_GUID = 2f1f2d5e-d9e1-4aa1-8eb9-fed94682e140 + PACKAGE_VERSION = 0.1 + +################################################################################ +# +# Include Section - list of Include Paths that are provided by this package. +# Comments are used for Keywords and Module Types. +# +# Supported Module Types: +# BASE SEC PEI_CORE PEIM DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_SAL_DRIVER UEFI_DRIVER UEFI_APPLICATION +# +################################################################################ +[Includes.common] + Include # Root include for the package + +[Guids.common] + gRdkTokenSpaceGuid = { 0x408c1892, 0xf11a, 0x40c7, { 0xaa, 0x5f, 0x0d, 0x16, 0xc8, 0xb2, 0x52, 0x59 } } + gRdkGlobalVariableGuid = { 0xc3253c90, 0xa24f, 0x4599, { 0xa6, 0x64, 0x1f, 0x88, 0x13, 0x77, 0x8f, 0xc9 } } + +[PcdsFixedAtBuild.common] + # Rdk Library + gRdkTokenSpaceGuid.PcdRdkRsvdReadSize|0x2000|UINT32|0x02000001 + gRdkTokenSpaceGuid.PcdRdkRsvdPartitionName|""|VOID*|0x02000002 + gRdkTokenSpaceGuid.PcdRdkSystemPartitionName|""|VOID*|0x02000003 + gRdkTokenSpaceGuid.PcdRdkConfFileName|""|VOID*|0x02000004 + gRdkTokenSpaceGuid.PcdRdkCmdLineArgs|""|VOID*|0x02000013 + gRdkTokenSpaceGuid.PcdRdkConfFileDevicePath|L""|VOID*|0x02000014 + gRdkTokenSpaceGuid.PcdAndroidFastbootNvmDevicePath|L""|VOID*|0x00300013 + + # GUID of RdkSecureBootLoader + gRdkTokenSpaceGuid.PcdRdkSecureBootFile|{ 0x0f, 0x93, 0xc7, 0xb2, 0xef, 0x07, 0x05, 0x43, 0xac, 0x4e, 0x1c, 0xe2, 0x08, 0x5a, 0x70, 0x31 }|VOID*|0x00000100 + + # GUID of RdkDri + gRdkTokenSpaceGuid.PcdRdkDriFile|{ 0x8a, 0xa1, 0x1b, 0x08, 0x1e, 0xd7, 0xa7, 0x40, 0x99, 0xa9, 0xcd, 0xb8, 0x64, 0x63, 0x96, 0x6d }|VOID*|0x00001000 + + # GUID of RdkDriSecureBootLoader + gRdkTokenSpaceGuid.PcdRdkDriSecureBootFile|{ 0xd7, 0xd1, 0x52, 0xdd, 0xe2, 0x0d, 0x52, 0x45, 0x98, 0xe0, 0x8d, 0xbe, 0xe4, 0x58, 0xa5, 0x02 }|VOID*|0x00100000 diff --git a/EmbeddedPkg/Library/RdkBootManagerLib/RdkBootManagerLib.inf b/EmbeddedPkg/Library/RdkBootManagerLib/RdkBootManagerLib.inf new file mode 100644 index 000000000000..aee849db2333 --- /dev/null +++ b/EmbeddedPkg/Library/RdkBootManagerLib/RdkBootManagerLib.inf @@ -0,0 +1,81 @@ +# +# Copyright (c) 2016-2017, Linaro Limited. All rights reserved. +# Copyright (c) 2016-2017, comcast . 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 Section - statements that will be processed to create a Makefile. +# +################################################################################ + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = RdkBootManagerLib + FILE_GUID = 901f54f2-9d70-9b89-9c0a-d9ca25379059 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = RdkBootManagerLib|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION UEFI_DRIVER + +[Sources] + DiskIo.c + SecureBoot.c + HttpBoot.c + RdkFile.c + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + ShellPkg/ShellPkg.dec + SecurityPkg/SecurityPkg.dec + CryptoPkg/CryptoPkg.dec + NetworkPkg/NetworkPkg.dec + EmbeddedPkg/Library/RdkBootManagerLib/RdkBootManagerLib.dec + +[Guids] + gEfiCertX509Guid + gEfiCertPkcs7Guid + gEfiCustomModeEnableGuid + gEfiImageSecurityDatabaseGuid + gFdtTableGuid + gRdkGlobalVariableGuid + +[Protocols] + gEfiBlockIoProtocolGuid + gEfiDevicePathToTextProtocolGuid + gEfiDevicePathFromTextProtocolGuid + gEfiLoadedImageProtocolGuid + gEfiShellProtocolGuid + gEfiDiskIoProtocolGuid + gEfiLoadFileProtocolGuid + +[Pcd] + gRdkTokenSpaceGuid.PcdRdkCmdLineArgs + gRdkTokenSpaceGuid.PcdRdkRsvdReadSize + gRdkTokenSpaceGuid.PcdRdkRsvdPartitionName + gRdkTokenSpaceGuid.PcdRdkSystemPartitionName + gRdkTokenSpaceGuid.PcdRdkConfFileName + gRdkTokenSpaceGuid.PcdRdkConfFileDevicePath + gRdkTokenSpaceGuid.PcdAndroidFastbootNvmDevicePath + +[LibraryClasses] + FileHandleLib + ArmLib + BaseLib + DebugLib + DevicePathLib + HobLib + PcdLib + NetLib + diff --git a/EmbeddedPkg/Library/RdkBootManagerLib/Include/DiskIo.h b/EmbeddedPkg/Library/RdkBootManagerLib/Include/DiskIo.h new file mode 100644 index 000000000000..003df0c0715c --- /dev/null +++ b/EmbeddedPkg/Library/RdkBootManagerLib/Include/DiskIo.h @@ -0,0 +1,20 @@ +#ifndef _RDK_DISK_IO_H_ +#define _RDK_DISK_IO_H_ + +extern +EFI_STATUS +PartitionRead ( + IN CHAR8 *PartitionName, + IN VOID *Image, + IN UINTN Size + ); + +extern +EFI_STATUS +PartitionWrite ( + IN CHAR8 *PartitionName, + IN VOID *Image, + IN UINTN Size + ); + +#endif /* _RDK_DISK_IO_H_ */ diff --git a/EmbeddedPkg/Library/RdkBootManagerLib/Include/HttpBoot.h b/EmbeddedPkg/Library/RdkBootManagerLib/Include/HttpBoot.h new file mode 100644 index 000000000000..80f448ee4140 --- /dev/null +++ b/EmbeddedPkg/Library/RdkBootManagerLib/Include/HttpBoot.h @@ -0,0 +1,7 @@ +#ifndef _RDK_HTTP_BOOT_H_ +#define _RDK_HTTP_BOOT_H_ + +extern EFI_STATUS +RdkHttpBoot ( VOID ); + +#endif /* _RDK_HTTP_BOOT_H_ */ diff --git a/EmbeddedPkg/Library/RdkBootManagerLib/Include/List.h b/EmbeddedPkg/Library/RdkBootManagerLib/Include/List.h new file mode 100644 index 000000000000..02a44f6699ac --- /dev/null +++ b/EmbeddedPkg/Library/RdkBootManagerLib/Include/List.h @@ -0,0 +1,52 @@ +#ifndef __LIST_H__ +#define __LIST_H__ + +#define OFFSETOF(TYPE, MEMBER) ((long unsigned int) &((TYPE *)0)->MEMBER) + +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define CONTAINER_OF(Ptr, Type, Member) ({ \ + const typeof( ((Type *)0)->Member ) *__Mptr = (Ptr); \ + (Type *)( (char *)__Mptr - OFFSETOF(Type,Member) );}) + + + +/** + * list_entry - get the struct for this entry + * @ptr: the &LIST_HEAD pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define LIST_ENTRY(Ptr, Type, Member) \ + CONTAINER_OF(Ptr, Type, Member) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define LIST_FOR_EACH_ENTRY(Pos, Head, Member) \ + for (Pos = LIST_ENTRY((Head)->ForwardLink, typeof(*Pos), Member); \ + &Pos->Member != (Head); \ + Pos = LIST_ENTRY(Pos->Member.ForwardLink, typeof(*Pos), Member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define LIST_FOR_EACH_ENTRY_SAFE(Pos, N, Head, Member) \ + for (Pos = LIST_ENTRY((Head)->ForwardLink, typeof(*Pos), Member), \ + N = LIST_ENTRY(Pos->Member.ForwardLink, typeof(*Pos), Member); \ + &Pos->Member != (Head); \ + Pos = N, N = LIST_ENTRY(N->Member.ForwardLink, typeof(*N), Member)) + +#endif /* __LIST_H__ */ diff --git a/EmbeddedPkg/Library/RdkBootManagerLib/Include/RdkBootManagerLib.h b/EmbeddedPkg/Library/RdkBootManagerLib/Include/RdkBootManagerLib.h new file mode 100644 index 000000000000..5b0b2b1afb79 --- /dev/null +++ b/EmbeddedPkg/Library/RdkBootManagerLib/Include/RdkBootManagerLib.h @@ -0,0 +1,31 @@ +#ifndef __RDK_BOOT_MANAGER_LIB_H__ +#define __RDK_BOOT_MANAGER_LIB_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "SecureBoot.h" +#include "HttpBoot.h" +#include "RdkFile.h" +#include "DiskIo.h" + +#endif /* __RDK_BOOT_MANAGER_LIB_H__ */ diff --git a/EmbeddedPkg/Library/RdkBootManagerLib/Include/RdkFile.h b/EmbeddedPkg/Library/RdkBootManagerLib/Include/RdkFile.h new file mode 100644 index 000000000000..e3dd09ab332c --- /dev/null +++ b/EmbeddedPkg/Library/RdkBootManagerLib/Include/RdkFile.h @@ -0,0 +1,20 @@ +#ifndef __RDK_FILE_H__ +#define __RDK_FILE_H__ + +#include "List.h" + +#define ALLOCATE_STRING_MEM(X) AllocateZeroPool((X + 1) * sizeof(CHAR16)) +#define MAX_VAR 4 + +typedef struct { + CHAR16 *Name; + LIST_ENTRY List; +} DIR_NODE; + +extern EFI_STATUS +GetRdkVariable ( + IN CONST CHAR16 *Name, + OUT CONST CHAR16 **Value + ); + +#endif /* __RDK_FILE_H__ */ diff --git a/EmbeddedPkg/Library/RdkBootManagerLib/Include/SecureBoot.h b/EmbeddedPkg/Library/RdkBootManagerLib/Include/SecureBoot.h new file mode 100644 index 000000000000..3cfd687670b5 --- /dev/null +++ b/EmbeddedPkg/Library/RdkBootManagerLib/Include/SecureBoot.h @@ -0,0 +1,40 @@ +#ifndef _RDK_SECURE_BOOT_H_ +#define _RDK_SECURE_BOOT_H_ + +#define FILE_HDR_SIZE 16 + +extern UINTN Str2Int ( + VOID * Str +); + +extern EFI_STATUS RdkSecureBoot ( + EFI_HANDLE ImageHandle, + EFI_BOOT_SERVICES *BootServices); + +extern EFI_STATUS RdkReadFile ( + IN CONST CHAR16 *Path, + IN OUT VOID **BufferPtr, + OUT UINTN *FileSize + ); + +extern EFI_STATUS RdkWriteFile ( + IN CONST CHAR16 *Path, + IN OUT VOID **BufferPtr, + OUT UINTN *FileSize + ); + +extern EFI_STATUS GetFileHandler ( + OUT EFI_FILE_HANDLE *FileHandle, + IN CONST CHAR16 *Path, + IN UINT64 OpenMode +); + +typedef enum KEY +{ + PK_KEY=1, + KEK_KEY, + DB_KEY, + DBX_KEY +} eKey; + +#endif /* _RDK_SECURE_BOOT_H_ */ diff --git a/EmbeddedPkg/Library/RdkBootManagerLib/DiskIo.c b/EmbeddedPkg/Library/RdkBootManagerLib/DiskIo.c new file mode 100644 index 000000000000..204a139d9fcb --- /dev/null +++ b/EmbeddedPkg/Library/RdkBootManagerLib/DiskIo.c @@ -0,0 +1,536 @@ +#include + +/* See sparse_format.h in AOSP */ +#define SPARSE_HEADER_MAGIC 0xed26ff3a +#define CHUNK_TYPE_RAW 0xCAC1 +#define CHUNK_TYPE_FILL 0xCAC2 +#define CHUNK_TYPE_DONT_CARE 0xCAC3 +#define CHUNK_TYPE_CRC32 0xCAC4 + +#define PARTITION_NAME_MAX_LENGTH 72/2 + +#define FLASH_DEVICE_PATH_SIZE(DevPath) ( GetDevicePathSize (DevPath) - \ + sizeof (EFI_DEVICE_PATH_PROTOCOL)) + +#define IS_ALPHA(Char) (((Char) <= L'z' && (Char) >= L'a') || \ + ((Char) <= L'Z' && (Char) >= L'Z')) + +typedef struct _DISKIO_PARTITION_LIST { + LIST_ENTRY Link; + CHAR16 PartitionName[PARTITION_NAME_MAX_LENGTH]; + EFI_HANDLE PartitionHandle; +} DISKIO_PARTITION_LIST; + +typedef struct _SPARSE_HEADER { + UINT32 Magic; + UINT16 MajorVersion; + UINT16 MinorVersion; + UINT16 FileHeaderSize; + UINT16 ChunkHeaderSize; + UINT32 BlockSize; + UINT32 TotalBlocks; + UINT32 TotalChunks; + UINT32 ImageChecksum; +} SPARSE_HEADER; + +typedef struct _CHUNK_HEADER { + UINT16 ChunkType; + UINT16 Reserved1; + UINT32 ChunkSize; + UINT32 TotalSize; +} CHUNK_HEADER; + +STATIC LIST_ENTRY mPartitionListHead; +STATIC EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *mTextOut; +STATIC UINT8 PartitionInited = 0; + +/* + * Helper to free the partition list + */ +STATIC +VOID +FreePartitionList ( + VOID +) +{ + DISKIO_PARTITION_LIST *Entry; + DISKIO_PARTITION_LIST *NextEntry; + + Entry = (DISKIO_PARTITION_LIST *) GetFirstNode (&mPartitionListHead); + while (!IsNull (&mPartitionListHead, &Entry->Link)) { + NextEntry = (DISKIO_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &Entry->Link); + + RemoveEntryList (&Entry->Link); + FreePool (Entry); + + Entry = NextEntry; + } +} + +/* + * Read the PartitionName fields from the GPT partition entries, putting them + * into an allocated array that should later be freed. + */ +STATIC +EFI_STATUS +ReadPartitionEntries ( + IN EFI_BLOCK_IO_PROTOCOL *BlockIo, + OUT EFI_PARTITION_ENTRY **PartitionEntries + ) +{ + UINTN EntrySize; + UINTN NumEntries; + UINTN BufferSize; + UINT32 MediaId; + EFI_PARTITION_TABLE_HEADER *GptHeader; + EFI_STATUS Status; + + MediaId = BlockIo->Media->MediaId; + + // + // Read size of Partition entry and number of entries from GPT header + // + GptHeader = AllocatePool (BlockIo->Media->BlockSize); + if (GptHeader == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = BlockIo->ReadBlocks (BlockIo, MediaId, 1, BlockIo->Media->BlockSize, (VOID *) GptHeader); + if (EFI_ERROR (Status)) { + return Status; + } + + // Check there is a GPT on the media + if (GptHeader->Header.Signature != EFI_PTAB_HEADER_ID || + GptHeader->MyLBA != 1) { + DEBUG ((DEBUG_ERROR, + "Fastboot platform: No GPT on flash. " + "Fastboot on Versatile Express does not support MBR.\n" + )); + return EFI_DEVICE_ERROR; + } + + EntrySize = GptHeader->SizeOfPartitionEntry; + NumEntries = GptHeader->NumberOfPartitionEntries; + + FreePool (GptHeader); + + ASSERT (EntrySize != 0); + ASSERT (NumEntries != 0); + + BufferSize = ALIGN_VALUE (EntrySize * NumEntries, BlockIo->Media->BlockSize); + *PartitionEntries = AllocatePool (BufferSize); + if (PartitionEntries == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = BlockIo->ReadBlocks (BlockIo, MediaId, 2, BufferSize, (VOID *) *PartitionEntries); + if (EFI_ERROR (Status)) { + FreePool (PartitionEntries); + return Status; + } + + return Status; +} + +/* + * Initialise: Open the Android NVM device and find the partitions on it. Save them in + * a list along with the "PartitionName" fields for their GPT entries. + * We will use these partition names as the key in + * FastbootPlatformFlashPartition. + */ +EFI_STATUS +InitDiskIo ( + VOID + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *FlashDevicePath; + EFI_DEVICE_PATH_PROTOCOL *FlashDevicePathDup; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *NextNode; + HARDDRIVE_DEVICE_PATH *PartitionNode; + UINTN NumHandles; + EFI_HANDLE *AllHandles; + UINTN LoopIndex; + EFI_HANDLE FlashHandle; + EFI_BLOCK_IO_PROTOCOL *FlashBlockIo; + EFI_PARTITION_ENTRY *PartitionEntries; + DISKIO_PARTITION_LIST *Entry; + + InitializeListHead (&mPartitionListHead); + + Status = gBS->LocateProtocol (&gEfiSimpleTextOutProtocolGuid, NULL, (VOID **) &mTextOut); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "Fastboot platform: Couldn't open Text Output Protocol: %r\n", Status + )); + return Status; + } + + // + // Get EFI_HANDLES for all the partitions on the block devices pointed to by + // PcdFastbootFlashDevicePath, also saving their GPT partition labels. + // There's no way to find all of a device's children, so we get every handle + // in the system supporting EFI_BLOCK_IO_PROTOCOL and then filter out ones + // that don't represent partitions on the flash device. + // + + FlashDevicePath = ConvertTextToDevicePath ((CHAR16*)PcdGetPtr (PcdAndroidFastbootNvmDevicePath)); + + // + // Open the Disk IO protocol on the flash device - this will be used to read + // partition names out of the GPT entries + // + // Create another device path pointer because LocateDevicePath will modify it. + FlashDevicePathDup = FlashDevicePath; + Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &FlashDevicePathDup, &FlashHandle); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "Warning: Couldn't locate Android NVM device (status: %r)\n", Status)); + // Failing to locate partitions should not prevent to do other Android FastBoot actions + return EFI_SUCCESS; + } + + Status = gBS->OpenProtocol ( + FlashHandle, + &gEfiBlockIoProtocolGuid, + (VOID **) &FlashBlockIo, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "Fastboot platform: Couldn't open Android NVM device (status: %r)\n", Status)); + return EFI_DEVICE_ERROR; + } + + // Read the GPT partition entry array into memory so we can get the partition names + Status = ReadPartitionEntries (FlashBlockIo, &PartitionEntries); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "Warning: Failed to read partitions from Android NVM device (status: %r)\n", Status)); + // Failing to locate partitions should not prevent to do other Android FastBoot actions + return EFI_SUCCESS; + } + + // Get every Block IO protocol instance installed in the system + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiBlockIoProtocolGuid, + NULL, + &NumHandles, + &AllHandles + ); + ASSERT_EFI_ERROR (Status); + + // Filter out handles that aren't children of the flash device + for (LoopIndex = 0; LoopIndex < NumHandles; LoopIndex++) { + // Get the device path for the handle + Status = gBS->OpenProtocol ( + AllHandles[LoopIndex], + &gEfiDevicePathProtocolGuid, + (VOID **) &DevicePath, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + ASSERT_EFI_ERROR (Status); + + // Check if it is a sub-device of the flash device + if (!CompareMem (DevicePath, FlashDevicePath, FLASH_DEVICE_PATH_SIZE (FlashDevicePath))) { + // Device path starts with path of flash device. Check it isn't the flash + // device itself. + NextNode = NextDevicePathNode (DevicePath); + if (IsDevicePathEndType (NextNode)) { + // Create entry + Entry = AllocatePool (sizeof (DISKIO_PARTITION_LIST)); + if (Entry == NULL) { + Status = EFI_OUT_OF_RESOURCES; + FreePartitionList (); + goto Exit; + } + + // Copy handle and partition name + Entry->PartitionHandle = AllHandles[LoopIndex]; + StrCpy (Entry->PartitionName, L"ptable"); + InsertTailList (&mPartitionListHead, &Entry->Link); + continue; + } + + // Assert that this device path node represents a partition. + ASSERT (NextNode->Type == MEDIA_DEVICE_PATH && + NextNode->SubType == MEDIA_HARDDRIVE_DP); + + PartitionNode = (HARDDRIVE_DEVICE_PATH *) NextNode; + + // Assert that the partition type is GPT. ReadPartitionEntries checks for + // presence of a GPT, so we should never find MBR partitions. + // ("MBRType" is a misnomer - this field is actually called "Partition + // Format") + ASSERT (PartitionNode->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER); + + // The firmware may install a handle for "partition 0", representing the + // whole device. Ignore it. + if (PartitionNode->PartitionNumber == 0) { + continue; + } + + // + // Add the partition handle to the list + // + + // Create entry + Entry = AllocatePool (sizeof (DISKIO_PARTITION_LIST)); + if (Entry == NULL) { + Status = EFI_OUT_OF_RESOURCES; + FreePartitionList (); + goto Exit; + } + + // Copy handle and partition name + Entry->PartitionHandle = AllHandles[LoopIndex]; + StrnCpy ( + Entry->PartitionName, + PartitionEntries[PartitionNode->PartitionNumber - 1].PartitionName, // Partition numbers start from 1. + PARTITION_NAME_MAX_LENGTH + ); + InsertTailList (&mPartitionListHead, &Entry->Link); + + // Print a debug message if the partition label is empty or looks like + // garbage. + if (!IS_ALPHA (Entry->PartitionName[0])) { + DEBUG ((DEBUG_WARN, + "Warning: Partition %d doesn't seem to have a GPT partition label. " + "You won't be able to flash it with Fastboot.\n", + PartitionNode->PartitionNumber + )); + } + } + } + + Exit: + FreePool (PartitionEntries); + FreePool (FlashDevicePath); + FreePool (AllHandles); + return Status; + +} + +STATIC +EFI_STATUS +OpenPartition ( + IN CHAR8 *PartitionName, + IN VOID *Image, + IN UINTN Size, + OUT EFI_BLOCK_IO_PROTOCOL **BlockIo, + OUT EFI_DISK_IO_PROTOCOL **DiskIo + ) +{ + EFI_STATUS Status; + UINTN PartitionSize; + DISKIO_PARTITION_LIST *Entry; + CHAR16 PartitionNameUnicode[60]; + BOOLEAN PartitionFound; + SPARSE_HEADER *SparseHeader; + + if(!PartitionInited) + { + InitDiskIo(); + PartitionInited = 1; + } + + AsciiStrToUnicodeStr (PartitionName, PartitionNameUnicode); + + PartitionFound = FALSE; + Entry = (DISKIO_PARTITION_LIST *) GetFirstNode (&(mPartitionListHead)); + while (!IsNull (&mPartitionListHead, &Entry->Link)) { + // Search the partition list for the partition named by PartitionName + if (StrCmp (Entry->PartitionName, PartitionNameUnicode) == 0) { + PartitionFound = TRUE; + break; + } + + Entry = (DISKIO_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &(Entry)->Link); + } + if (!PartitionFound) { + Status = EFI_NOT_FOUND; + goto exit; + } + + Status = gBS->OpenProtocol ( + Entry->PartitionHandle, + &gEfiBlockIoProtocolGuid, + (VOID **) BlockIo, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Unable to open Block IO protocol: %r\n", Status)); + Status = EFI_NOT_FOUND; + goto exit; + } + + SparseHeader=(SPARSE_HEADER *)Image; + + if (SparseHeader->Magic == SPARSE_HEADER_MAGIC) { + DEBUG ((DEBUG_INFO, "Sparse Magic: 0x%x Major: %d Minor: %d fhs: %d chs: %d bs: %d tbs: %d tcs: %d checksum: %d \n", + SparseHeader->Magic, SparseHeader->MajorVersion, SparseHeader->MinorVersion, SparseHeader->FileHeaderSize, + SparseHeader->ChunkHeaderSize, SparseHeader->BlockSize, SparseHeader->TotalBlocks, + SparseHeader->TotalChunks, SparseHeader->ImageChecksum)); + + if (SparseHeader->MajorVersion != 1) { + DEBUG ((DEBUG_ERROR, "Sparse image version %d.%d not supported.\n", + SparseHeader->MajorVersion, SparseHeader->MinorVersion)); + Status = EFI_INVALID_PARAMETER; + goto exit; + } + + Size = SparseHeader->BlockSize * SparseHeader->TotalBlocks; + } + + // Check image will fit on device + PartitionSize = (BlockIo[0]->Media->LastBlock + 1) * BlockIo[0]->Media->BlockSize; + if (PartitionSize < Size) { + DEBUG ((DEBUG_ERROR, "Partition not big enough.\n")); + DEBUG ((DEBUG_ERROR, "Partition Size:\t%ld\nImage Size:\t%ld\n", PartitionSize, Size)); + + Status = EFI_VOLUME_FULL; + goto exit; + } + + Status = gBS->OpenProtocol ( + Entry->PartitionHandle, + &gEfiDiskIoProtocolGuid, + (VOID **) DiskIo, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + +exit: + return Status; +} + +EFI_STATUS +PartitionRead ( + IN CHAR8 *PartitionName, + IN VOID *Image, + IN UINTN Size + ) +{ + EFI_STATUS Status; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + EFI_DISK_IO_PROTOCOL *DiskIo; + UINT32 MediaId; + + Status = OpenPartition (PartitionName, Image, Size, &BlockIo, &DiskIo); + if (EFI_ERROR (Status)) { + goto exit; + } + + MediaId = BlockIo->Media->MediaId; + + Status = DiskIo->ReadDisk (DiskIo, MediaId, 0, Size, Image); + if (EFI_ERROR (Status)) { + goto exit; + } + + BlockIo->FlushBlocks(BlockIo); + +exit: + return Status; +} + + +EFI_STATUS +PartitionWrite ( + IN CHAR8 *PartitionName, + IN VOID *Image, + IN UINTN Size + ) +{ + EFI_STATUS Status; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + EFI_DISK_IO_PROTOCOL *DiskIo; + UINT32 MediaId; + SPARSE_HEADER *SparseHeader; + CHUNK_HEADER *ChunkHeader; + UINT32 Chunk; + UINTN Offset; + + Status = OpenPartition (PartitionName, Image, Size, &BlockIo, &DiskIo); + if (EFI_ERROR (Status)) { + goto exit; + } + + Offset = 0; + MediaId = BlockIo->Media->MediaId; + SparseHeader = (SPARSE_HEADER *)Image; + + if (SparseHeader->Magic == SPARSE_HEADER_MAGIC) { + CHAR16 OutputString[64]; + UINTN ChunkPrintDensity = + SparseHeader->TotalChunks > 1600 ? SparseHeader->TotalChunks / 200 : 32; + + Image += SparseHeader->FileHeaderSize; + for (Chunk = 0; Chunk < SparseHeader->TotalChunks; Chunk++) { + UINTN WriteSize; + ChunkHeader = (CHUNK_HEADER *)Image; + + // Show progress. Don't do it for every packet as outputting text + // might be time consuming. ChunkPrintDensity is calculated to + // provide an update every half percent change for large + // downloads. + if (Chunk % ChunkPrintDensity == 0) { + UnicodeSPrint(OutputString, sizeof(OutputString), + L"\r%5d / %5d chunks written (%d%%)", Chunk, + SparseHeader->TotalChunks, + (Chunk * 100) / SparseHeader->TotalChunks); + mTextOut->OutputString(mTextOut, OutputString); + } + + DEBUG ((DEBUG_INFO, "Chunk #%d - Type: 0x%x Size: %d TotalSize: %d Offset %d\n", + (Chunk+1), ChunkHeader->ChunkType, ChunkHeader->ChunkSize, + ChunkHeader->TotalSize, Offset)); + Image += sizeof(CHUNK_HEADER); + WriteSize=(SparseHeader->BlockSize) * ChunkHeader->ChunkSize; + switch (ChunkHeader->ChunkType) { + case CHUNK_TYPE_RAW: + DEBUG ((DEBUG_INFO, "Writing %d at Offset %d\n", WriteSize, Offset)); + Status = DiskIo->WriteDisk (DiskIo, MediaId, Offset, WriteSize, Image); + if (EFI_ERROR (Status)) { + goto exit; + } + Image+=WriteSize; + break; + case CHUNK_TYPE_DONT_CARE: + break; + case CHUNK_TYPE_CRC32: + break; + default: + DEBUG ((DEBUG_ERROR, "Unknown Chunk Type: 0x%x", ChunkHeader->ChunkType)); + Status = EFI_PROTOCOL_ERROR; + goto exit; + } + Offset += WriteSize; + } + + UnicodeSPrint(OutputString, sizeof(OutputString), + L"\r%5d / %5d chunks written (100%%)\r\n", + SparseHeader->TotalChunks, SparseHeader->TotalChunks); + mTextOut->OutputString(mTextOut, OutputString); + + } else { + + Status = DiskIo->WriteDisk (DiskIo, MediaId, 0, Size, Image); + if (EFI_ERROR (Status)) { + goto exit; + } + } + + BlockIo->FlushBlocks(BlockIo); + +exit: + return Status; +} diff --git a/EmbeddedPkg/Library/RdkBootManagerLib/HttpBoot.c b/EmbeddedPkg/Library/RdkBootManagerLib/HttpBoot.c new file mode 100644 index 000000000000..e89241c51b99 --- /dev/null +++ b/EmbeddedPkg/Library/RdkBootManagerLib/HttpBoot.c @@ -0,0 +1,315 @@ +/* +# Copyright (c) 2016-2017, Linaro 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 + +STATIC EFI_LOAD_FILE_PROTOCOL *LoadFile = NULL; +STATIC HTTP_BOOT_PRIVATE_DATA *Private = NULL; + +STATIC +VOID +HttpPrivateFromLoadFile ( + IN EFI_LOAD_FILE_PROTOCOL *LoadFile, + OUT HTTP_BOOT_PRIVATE_DATA **Private + ) +{ + HTTP_BOOT_VIRTUAL_NIC *Ip4Nic = NULL; + + INT64 Offset = (INT64)&Ip4Nic->LoadFile; + Ip4Nic = (VOID *)((char *)LoadFile - Offset); + ASSERT (Ip4Nic->Signature == HTTP_BOOT_VIRTUAL_NIC_SIGNATURE); + *Private = Ip4Nic->Private; +} + +STATIC +VOID +HttpGetLoadFileHandle ( + OUT EFI_LOAD_FILE_PROTOCOL **LoadFile + ) +{ + EFI_STATUS Status; + UINTN LoopIndex; + UINTN NumHandles; + EFI_HANDLE *AllHandles; + EFI_HANDLE Handle; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText; + UINT16 *DeviceFullPath; + + Status = gBS->LocateProtocol ( + &gEfiDevicePathToTextProtocolGuid, + NULL, + (VOID **) &DevPathToText + ); + ASSERT_EFI_ERROR (Status); + + // Get every LoadFile protocol instance installed in the system + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiLoadFileProtocolGuid, + NULL, + &NumHandles, + &AllHandles + ); + ASSERT_EFI_ERROR (Status); + + // Get HTTP driver handle from AllHandles + for (LoopIndex = 0; LoopIndex < NumHandles; LoopIndex++) { + + Handle = AllHandles[LoopIndex]; + + // Get the device path for the handle + Status = gBS->OpenProtocol ( + Handle, + &gEfiDevicePathProtocolGuid, + (VOID **) &DevicePath, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + ASSERT_EFI_ERROR (Status); + + DeviceFullPath = DevPathToText->ConvertDevicePathToText ( + DevicePath, + FALSE, + TRUE + ); + + ASSERT(DeviceFullPath != NULL); + + if(StrStr(DeviceFullPath, L"IPv4") != NULL) { + + Status = gBS->OpenProtocol ( + Handle, + &gEfiLoadFileProtocolGuid, + (VOID **) LoadFile, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + ASSERT_EFI_ERROR (Status); + + FreePool (AllHandles); + break; + } + } + + ASSERT ( LoopIndex < NumHandles ); +} + +STATIC +EFI_STATUS +HttpUpdatePath ( + IN CHAR16 *Uri, + OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath + ) +{ + EFI_DEV_PATH *Node; + EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath; + EFI_STATUS Status; + UINTN Index; + UINTN Length; + CHAR8 AsciiUri[URI_STR_MAX_SIZE]; + + Node = NULL; + TmpDevicePath = NULL; + Status = EFI_SUCCESS; + + // Convert the scheme to all lower case. + for (Index = 0; Index < StrLen (Uri); Index++) { + if (Uri[Index] == L':') { + break; + } + if (Uri[Index] >= L'A' && Uri[Index] <= L'Z') { + Uri[Index] -= (CHAR16)(L'A' - L'a'); + } + } + + // Only accept empty URI, or http and https URI. + if ((StrLen (Uri) != 0) && (StrnCmp (Uri, L"http://", 7) != 0) && (StrnCmp (Uri, L"https://", 8) != 0)) { + return EFI_INVALID_PARAMETER; + } + + // Create a new device path by appending the IP node and URI node to + // the driver's parent device path + Node = AllocateZeroPool (sizeof (IPv4_DEVICE_PATH)); + if (Node == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + Node->Ipv4.Header.Type = MESSAGING_DEVICE_PATH; + Node->Ipv4.Header.SubType = MSG_IPv4_DP; + SetDevicePathNodeLength (Node, sizeof (IPv4_DEVICE_PATH)); + TmpDevicePath = AppendDevicePathNode (Private->ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node); + FreePool (Node); + if (TmpDevicePath == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // Update the URI node with the input boot file URI. + UnicodeStrToAsciiStrS (Uri, AsciiUri, sizeof (AsciiUri)); + Length = sizeof (EFI_DEVICE_PATH_PROTOCOL) + AsciiStrSize (AsciiUri); + Node = AllocatePool (Length); + if (Node == NULL) { + Status = EFI_OUT_OF_RESOURCES; + FreePool (TmpDevicePath); + goto ON_EXIT; + } + Node->DevPath.Type = MESSAGING_DEVICE_PATH; + Node->DevPath.SubType = MSG_URI_DP; + SetDevicePathNodeLength (Node, Length); + CopyMem ((UINT8*) Node + sizeof (EFI_DEVICE_PATH_PROTOCOL), AsciiUri, AsciiStrSize (AsciiUri)); + *NewDevicePath = AppendDevicePathNode (TmpDevicePath, (EFI_DEVICE_PATH_PROTOCOL*) Node); + FreePool (Node); + FreePool (TmpDevicePath); + if (*NewDevicePath == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + +ON_EXIT: + + return Status; +} + +STATIC +EFI_STATUS +HttpGetImage ( + IN CHAR16 *Uri, + OUT UINT8 **FileBuffer, + OUT UINTN *FileSize + ) +{ + EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; + EFI_STATUS Status; + + *FileBuffer = NULL; + NewDevicePath = NULL; + *FileSize = 0; + + // Get the LoadFile Handle and + // Private structure of HTTP driver + if (LoadFile == NULL) { + HttpGetLoadFileHandle (&LoadFile); + HttpPrivateFromLoadFile (LoadFile, &Private); + } + + // Update URI path + Status = HttpUpdatePath (Uri, &NewDevicePath); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + // Get the HTTP image from server + Status = LoadFile->LoadFile (LoadFile, NewDevicePath, TRUE, FileSize, *FileBuffer); + if((Status != EFI_WARN_FILE_SYSTEM) && (Status != EFI_BUFFER_TOO_SMALL)) { + goto ON_EXIT; + } + + *FileBuffer = AllocatePool (*FileSize); + if (*FileBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + Status = LoadFile->LoadFile (LoadFile, NewDevicePath, TRUE, FileSize, *FileBuffer); + if (EFI_ERROR (Status)) { + FreePool (FileBuffer); + goto ON_EXIT; + } + +ON_EXIT: + + if (NewDevicePath != NULL) { + FreePool (NewDevicePath); + } + + return Status; +} + +EFI_STATUS +RdkHttpBoot ( + VOID + ) +{ + EFI_STATUS Status; + VOID *FilePtr; + UINT8 *FileBuffer; + UINT16 *Uri; + UINTN FileSize; + UINTN LoopIndex; + UINTN Size; + CONST CHAR16 *DtbPath; + CONST CHAR16 *ImagePath; + CONST CHAR16 *ServerUrlPath; + + Status = GetRdkVariable(L"URL", &ServerUrlPath); + ASSERT_EFI_ERROR (Status); + + // Get the Server name stored in file Server.url + Status = RdkReadFile(ServerUrlPath, (VOID **)&FileBuffer, &FileSize); + ASSERT_EFI_ERROR (Status); + + Uri = AllocateZeroPool (sizeof(*Uri) * (FileSize+1)); + if (Uri == NULL) { + Status = EFI_OUT_OF_RESOURCES; + ASSERT_EFI_ERROR (Status); + } + + for(LoopIndex=0; LoopIndexSetWatchdogTimer (0, 0x10000, 0, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "HttpBoot: Couldn't disable watchdog timer: %r\n", Status)); + } + + // Get the File from server using it's URI + Status = HttpGetImage (Uri, &FileBuffer, &FileSize); + ASSERT_EFI_ERROR (Status); + + // Write the received image to flash + FilePtr = FileBuffer; + Size = Str2Int(FilePtr); + FilePtr += FILE_HDR_SIZE; + Status = PartitionWrite((CHAR8 *) FixedPcdGetPtr (PcdRdkSystemPartitionName), FilePtr, Size); + ASSERT_EFI_ERROR (Status); + + FilePtr += Size; + Size = Str2Int(FilePtr); + FilePtr += FILE_HDR_SIZE; + Status = GetRdkVariable(L"IMAGE", &ImagePath); + ASSERT_EFI_ERROR (Status); + Status = RdkWriteFile(ImagePath, &FilePtr, &Size); + ASSERT_EFI_ERROR (Status); + + FilePtr += Size; + Size = Str2Int(FilePtr); + FilePtr += FILE_HDR_SIZE; + Status = GetRdkVariable(L"DTB", &DtbPath); + ASSERT_EFI_ERROR (Status); + Status = RdkWriteFile(DtbPath, &FilePtr, &Size); + ASSERT_EFI_ERROR (Status); + + FreePool (FileBuffer); + FreePool (Uri); + + return Status; +} diff --git a/EmbeddedPkg/Library/RdkBootManagerLib/RdkFile.c b/EmbeddedPkg/Library/RdkBootManagerLib/RdkFile.c new file mode 100644 index 000000000000..3f454e6605b9 --- /dev/null +++ b/EmbeddedPkg/Library/RdkBootManagerLib/RdkFile.c @@ -0,0 +1,259 @@ +#include + +STATIC UINT8 VarablesInitialzed = 0; +STATIC CHAR16 *VarResult[MAX_VAR][2]; + +STATIC +VOID +SaveString ( + OUT CHAR16 **Dest, + IN CHAR16 *String1, + IN CHAR16 *String2 + ) +{ + *Dest = ALLOCATE_STRING_MEM(StrLen(String1) + StrLen(String2)); + StrCat(*Dest, String1); + StrCat(*Dest, String2); +} + +STATIC +EFI_STATUS +LsFiles ( + IN CONST CHAR16 *DirPath, + IN CONST CHAR16 *TargetFile, + OUT CHAR16 **Result, + IN LIST_ENTRY *Head + ) +{ + EFI_STATUS Status; + EFI_FILE_INFO *FileInfo; + EFI_FILE_PROTOCOL *FileHandle; + BOOLEAN NoFile; + CHAR16 *TempPath; + DIR_NODE *Node; + + NoFile = FALSE; + TempPath = ALLOCATE_STRING_MEM(StrLen(DirPath) + 1); + StrCat(TempPath, DirPath); + StrCat(TempPath, L"/"); + + Status = GetFileHandler(&FileHandle, DirPath, EFI_FILE_MODE_READ); + ASSERT_EFI_ERROR(Status); + + for ( Status = FileHandleFindFirstFile(FileHandle, &FileInfo) + ; !EFI_ERROR(Status) && !NoFile + ; Status = FileHandleFindNextFile(FileHandle, FileInfo, &NoFile) + ) { + if((FileInfo->Attribute & EFI_FILE_DIRECTORY) && + (StrCmp(FileInfo->FileName, L".") != 0) && + (StrCmp(FileInfo->FileName, L"..") != 0)) { + Node = AllocateZeroPool(sizeof (DIR_NODE)); + SaveString(&Node->Name, TempPath, FileInfo->FileName); + InsertHeadList(Head,&Node->List); + } + else if(StrCmp(FileInfo->FileName, TargetFile) == 0) { + SaveString(Result, TempPath, FileInfo->FileName); + Status = EFI_SUCCESS; + goto ON_EXIT; + } + } + + Status = EFI_NOT_FOUND; + +ON_EXIT: + FreePool(TempPath); + return Status; +} + +STATIC +VOID +DelDirList ( + IN LIST_ENTRY *Head + ) +{ + DIR_NODE *Node; + DIR_NODE *Temp; + + LIST_FOR_EACH_ENTRY_SAFE (Node, Temp, Head, List) { + RemoveEntryList(&Node->List); + FreePool(Node->Name); + FreePool(Node); + } +} + +STATIC +EFI_STATUS +FindFileInDir ( + IN CONST CHAR16 *DevPath, + IN CONST CHAR16 *TargetFile, + OUT CHAR16 **Result + ) +{ + UINT8 Current; + UINT8 Next; + DIR_NODE *Temp; + LIST_ENTRY DirList[2]; + + *Result = NULL; + EFI_STATUS Status = EFI_NOT_FOUND; + + InitializeListHead(&DirList[0]); + InitializeListHead(&DirList[1]); + + for (Current = 0, LsFiles(DevPath, TargetFile, Result, &DirList[Current]); + !IsListEmpty(&DirList[Current]); + Current = Next) { + Next = Current ^ 1; + DelDirList(&DirList[Next]); + + LIST_FOR_EACH_ENTRY(Temp, &DirList[Current], List) { + Status = LsFiles(Temp->Name, TargetFile, Result, &DirList[Next]); + if(!EFI_ERROR(Status)) { + DelDirList(&DirList[Current]); + break; + } + } + } + + DelDirList(&DirList[Next]); + return Status; +} + +STATIC +UINTN +StrSpn ( + IN CHAR8 *String, + IN CHAR8 *CharSet + ) +{ + UINTN Count; + + for(Count=0; String[Count] && !(String[Count] == CharSet[0]); Count++); + return Count; +} + +STATIC +CHAR16 * +Ascii2Uefi ( + IN CHAR8 *String + ) +{ + CHAR16 *Result; + UINTN Size; + + Size = AsciiStrLen(String); + Result = ALLOCATE_STRING_MEM(Size); + + while(Size--) { + Result[Size] = String[Size]; + } + + return Result; +} + +STATIC +EFI_STATUS +InitVarList ( + IN CHAR8 *FileData, + IN UINTN FileSize + ) +{ + UINTN InnerLoopIndex; + UINTN OuterLoopIndex; + UINTN Current; + UINTN Next; + CHAR8 *VarDelimiter[2]; + EFI_STATUS Status; + + VarDelimiter[0] = "="; + VarDelimiter[1] = "\""; + Status = EFI_SUCCESS; + + for(OuterLoopIndex=0, Next=0; OuterLoopIndex + +STATIC +EFI_STATUS +OpenFileByDevicePath( + IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath, + OUT EFI_FILE_HANDLE *FileHandle, + IN UINT64 OpenMode, + IN UINT64 Attributes +) +{ + EFI_STATUS Status; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *EfiSimpleFileSystemProtocol; + EFI_FILE_PROTOCOL *Handle1; + EFI_FILE_PROTOCOL *Handle2; + EFI_HANDLE DeviceHandle; + + //if ((FilePath == NULL || FileHandle == NULL)) { + if ((FilePath == NULL )) { + return EFI_INVALID_PARAMETER; + } + + Status = gBS->LocateDevicePath ( + &gEfiSimpleFileSystemProtocolGuid, + FilePath, + &DeviceHandle + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->OpenProtocol( + DeviceHandle, + &gEfiSimpleFileSystemProtocolGuid, + (VOID**)&EfiSimpleFileSystemProtocol, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = EfiSimpleFileSystemProtocol->OpenVolume(EfiSimpleFileSystemProtocol, &Handle1); + if (EFI_ERROR (Status)) { + FileHandle = NULL; + return Status; + } + + // + // go down directories one node at a time. + // + while (!IsDevicePathEnd (*FilePath)) { + // + // For file system access each node should be a file path component + // + if (DevicePathType (*FilePath) != MEDIA_DEVICE_PATH || + DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP + ) { + FileHandle = NULL; + return (EFI_INVALID_PARAMETER); + } + // + // Open this file path node + // + Handle2 = Handle1; + Handle1 = NULL; + + // + // Try to test opening an existing file + // + Status = Handle2->Open ( + Handle2, + &Handle1, + ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName, + OpenMode &~EFI_FILE_MODE_CREATE, + 0 + ); + + // + // see if the error was that it needs to be created + // + if ((EFI_ERROR (Status)) && (OpenMode != (OpenMode &~EFI_FILE_MODE_CREATE))) { + Status = Handle2->Open ( + Handle2, + &Handle1, + ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName, + OpenMode, + Attributes + ); + } + // + // Close the last node + // + Handle2->Close (Handle2); + + if (EFI_ERROR(Status)) { + return (Status); + } + + // + // Get the next node + // + *FilePath = NextDevicePathNode (*FilePath); + } + + // + // This is a weak spot since if the undefined SHELL_FILE_HANDLE format changes this must change also! + // + *FileHandle = (VOID*)Handle1; + + return EFI_SUCCESS; +} + +EFI_STATUS +GetFileHandler ( + OUT EFI_FILE_HANDLE *FileHandle, + IN CONST CHAR16 *Path, + IN UINT64 OpenMode +) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *KeyFileDevicePath; + EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *DevicePathFromTextProtocol; + + Status = EFI_SUCCESS; + KeyFileDevicePath = NULL; + + Status = gBS->LocateProtocol ( + &gEfiDevicePathFromTextProtocolGuid, + NULL, + (VOID**)&DevicePathFromTextProtocol + ); + ASSERT_EFI_ERROR(Status); + + // KeyFileDevicePath = gEfiShellProtocol->GetDevicePathFromFilePath(Path); + KeyFileDevicePath = DevicePathFromTextProtocol->ConvertTextToDevicePath(Path); + if(KeyFileDevicePath != NULL) + { + Status = OpenFileByDevicePath(&KeyFileDevicePath,FileHandle,OpenMode,0); + if(Status != EFI_SUCCESS) + { + DEBUG ((DEBUG_INFO, "Getting FileHandle of %s Failed\n",Path)); + } + } + return Status; +} + +STATIC +EFI_STATUS +CreateTimeBasedPayload ( + IN OUT UINTN *DataSize, + IN OUT UINT8 **Data +) +{ + EFI_STATUS Status; + UINT8 *NewData; + UINT8 *Payload; + UINTN PayloadSize; + EFI_VARIABLE_AUTHENTICATION_2 *DescriptorData; + UINTN DescriptorSize; + EFI_TIME Time; + + if (Data == NULL || DataSize == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // In Setup mode or Custom mode, the variable does not need to be signed but the + // parameters to the SetVariable() call still need to be prepared as authenticated + // variable. So we create EFI_VARIABLE_AUTHENTICATED_2 descriptor without certificate + // data in it. + // + + Payload = *Data; + PayloadSize = *DataSize; + + DescriptorSize = OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData); + NewData = (UINT8*) AllocateZeroPool (DescriptorSize + PayloadSize); + if (NewData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if ((Payload != NULL) && (PayloadSize != 0)) { + CopyMem (NewData + DescriptorSize, Payload, PayloadSize); + } + + DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *) (NewData); + + ZeroMem (&Time, sizeof (EFI_TIME)); + Status = gRT->GetTime (&Time, NULL); + if (EFI_ERROR (Status)) { + FreePool(NewData); + return Status; + } + Time.Pad1 = 0; + Time.Nanosecond = 0; + Time.TimeZone = 0; + Time.Daylight = 0; + Time.Pad2 = 0; + CopyMem (&DescriptorData->TimeStamp, &Time, sizeof (EFI_TIME)); + + DescriptorData->AuthInfo.Hdr.dwLength = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData); + DescriptorData->AuthInfo.Hdr.wRevision = 0x0200; + DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID; + CopyGuid (&DescriptorData->AuthInfo.CertType, &gEfiCertPkcs7Guid); + + if (Payload != NULL) { + FreePool(Payload); + } + + *DataSize = DescriptorSize + PayloadSize; + *Data = NewData; + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +SetBootMode ( + IN UINT8 SecureBootMode +) +{ + return gRT->SetVariable ( + EFI_CUSTOM_MODE_NAME, + &gEfiCustomModeEnableGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof (UINT8), + &SecureBootMode + ); +} + +STATIC +EFI_STATUS +SetVariable ( + IN EFI_SIGNATURE_LIST *PkCert, + IN UINTN DataSize, + IN eKey KeyType +) +{ + UINT32 Attr; + EFI_STATUS Status=EFI_SUCCESS ; + Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS + | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; + if(KeyType == PK_KEY) + { + DEBUG ((DEBUG_INFO, "Setting PK Key\n")); + Status = gRT->SetVariable ( + EFI_PLATFORM_KEY_NAME, + &gEfiGlobalVariableGuid, + Attr, + DataSize, + PkCert + ); + } + else if( KeyType == KEK_KEY) + { + DEBUG ((DEBUG_INFO, "Setting KEK Key\n")); + Status = gRT->SetVariable ( + EFI_KEY_EXCHANGE_KEY_NAME, + &gEfiGlobalVariableGuid, + Attr, + DataSize, + PkCert + ); + + Status = gRT->SetVariable ( + EFI_IMAGE_SECURITY_DATABASE, + &gEfiImageSecurityDatabaseGuid, + Attr, + DataSize, + PkCert + ); + } + else + { + ASSERT(FALSE); + } + return Status; + +} + +STATIC +VOID +PopulateCert ( + OUT EFI_SIGNATURE_LIST **Cert, + IN UINTN DataSize, + IN UINT8 *Data +) +{ + EFI_SIGNATURE_DATA *CertData = NULL; + + if( (*Cert) == NULL) + { + (*Cert) = (EFI_SIGNATURE_LIST*) AllocateZeroPool ( sizeof(EFI_SIGNATURE_LIST) + + sizeof(EFI_SIGNATURE_DATA) - 1 + + DataSize ); + + ASSERT ((*Cert) != NULL); + } + (*Cert)->SignatureListSize = (UINT32) (sizeof(EFI_SIGNATURE_LIST) + + sizeof(EFI_SIGNATURE_DATA) - 1 + + DataSize); + (*Cert)->SignatureSize = (UINT32) (sizeof(EFI_SIGNATURE_DATA) - 1 + DataSize); + (*Cert)->SignatureHeaderSize = 0; + CopyGuid (&(*Cert)->SignatureType, &gEfiCertX509Guid); + + + CertData = (EFI_SIGNATURE_DATA*) ((UINTN)(*Cert) + sizeof(EFI_SIGNATURE_LIST) + (*Cert)->SignatureHeaderSize); + ASSERT (CertData != NULL); + + CopyGuid (&CertData->SignatureOwner, &gEfiGlobalVariableGuid); + CopyMem (&CertData->SignatureData, Data, DataSize); +} + +STATIC +EFI_STATUS +RegisterCert ( + IN UINT8 *KeyData, + IN UINTN KeySize, + IN eKey KeyType +) +{ + EFI_STATUS Status; + EFI_SIGNATURE_LIST *Cert = NULL; + + Status = SetBootMode(CUSTOM_SECURE_BOOT_MODE); + ASSERT_EFI_ERROR (Status); + + PopulateCert(&Cert, KeySize, KeyData); + + KeySize = Cert->SignatureListSize; + + Status = CreateTimeBasedPayload (&KeySize, (UINT8**) &Cert); + ASSERT_EFI_ERROR (Status); + + Status = SetVariable(Cert,KeySize,KeyType); + return Status; +} + +UINTN +Str2Int ( + VOID * Str +) +{ + UINTN i, Size; + UINT8 *Ptr = Str; + + for(i=0, Size=0; iSetVariable ( + L"RdkRootCertificate", + &gRdkGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + KekCrtSize, + KekCrtData + ); + ASSERT_EFI_ERROR(Status); + + /* Read PK and KEK keys from reserved partition */ + STATIC UINT8 *Buffer = NULL; + UINT32 RsvdReadSize = PcdGet32 (PcdRdkRsvdReadSize); + Buffer = AllocateZeroPool(RsvdReadSize); + PartitionRead((CHAR8 *)FixedPcdGetPtr (PcdRdkRsvdPartitionName), Buffer, RsvdReadSize); + + INT32 PkKeySize, KekKeySize; + + UINT8 * PkKey = Buffer; + PkKeySize = Str2Int (PkKey); + PkKey += FILE_HDR_SIZE; + + UINT8 * KekKey = PkKey + PkKeySize; + KekKeySize = Str2Int (KekKey); + KekKey += FILE_HDR_SIZE; + + INT8* SetupMode = NULL; + eKey KeyType; + + KeyType = PK_KEY; + Status = RegisterCert(PkKey,PkKeySize,KeyType); + GetEfiGlobalVariable2 (L"SetupMode", (VOID**)&SetupMode, NULL); + + if (*SetupMode == 0) + { + DEBUG ((DEBUG_INFO, "PK Key Got Registered. Now System in User Mode\n")); + KeyType = KEK_KEY; + Status = RegisterCert(KekKey,KekKeySize,KeyType); + } + else if(*SetupMode == 1) + { + DEBUG ((DEBUG_INFO, "System in Standard System Mode ::: Secure Boot Not enabled\n")); + ASSERT_EFI_ERROR(Status); + } + + FreePool(Buffer); +} + +EFI_STATUS +RdkReadFile ( + IN CONST CHAR16 *Path, + IN OUT VOID **BufferPtr, + OUT UINTN *FileSize +) +{ + UINTN BufferSize; + UINT64 SourceFileSize; + VOID *Buffer; + EFI_STATUS Status; + EFI_FILE_HANDLE FileHandle; + + Status = GetFileHandler(&FileHandle, Path, EFI_FILE_MODE_READ); + ASSERT_EFI_ERROR(Status); + + if (FileSize == NULL) { + return EFI_INVALID_PARAMETER; + } + + Buffer = NULL; + + // Get the file size + Status = FileHandle->SetPosition (FileHandle, (UINT64) -1); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + Status = FileHandle->GetPosition (FileHandle, &SourceFileSize); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + Status = FileHandle->SetPosition (FileHandle, 0); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + BufferSize = (UINTN) SourceFileSize; + Buffer = AllocateZeroPool(BufferSize); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + BufferSize = (UINTN) SourceFileSize; + *FileSize = BufferSize; + + Status = FileHandle->Read (FileHandle, &BufferSize, Buffer); + if (EFI_ERROR (Status) || BufferSize != *FileSize) { + FreePool (Buffer); + Buffer = NULL; + Status = EFI_BAD_BUFFER_SIZE; + goto ON_EXIT; + } + +ON_EXIT: + + *BufferPtr = Buffer; + return Status; +} + +EFI_STATUS +RdkWriteFile ( + IN CONST CHAR16 *Path, + IN OUT VOID **BufferPtr, + OUT UINTN *FileSize +) +{ + EFI_STATUS Status; + EFI_FILE_HANDLE FileHandle; + + if (FileSize == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = GetFileHandler(&FileHandle, Path, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE); + ASSERT_EFI_ERROR(Status); + + Status = FileHandle->Write (FileHandle, FileSize, *BufferPtr); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +EFI_STATUS +RdkSecureBoot ( + EFI_HANDLE ImageHandle, + EFI_BOOT_SERVICES *BootServices +) +{ + UINT8 *FdtData; + UINTN FdtDataSize; + UINTN *ExitDataSize; + CHAR16 **ExitData; + CHAR16 LoadOption[128]; + CONST CHAR8 *CmdLine; + CONST CHAR16 *ImagePath; + CONST CHAR16 *DtbPath; + EFI_STATUS Status; + EFI_HANDLE Handle; + EFI_DEVICE_PATH_PROTOCOL *FilePath; + EFI_LOADED_IMAGE_PROTOCOL *ImageInfo; + EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *DevicePathFromTextProtocol; + + FilePath = NULL; + ExitData = NULL; + ExitDataSize = NULL; + CmdLine = (CONST CHAR8 *)FixedPcdGetPtr (PcdRdkCmdLineArgs); + + Status = GetRdkVariable(L"DTB", &DtbPath); + ASSERT_EFI_ERROR (Status); + + Status = RdkReadFile (DtbPath, (VOID**) &FdtData, &FdtDataSize); + ASSERT_EFI_ERROR (Status); + + Status = gBS->InstallConfigurationTable (&gFdtTableGuid,(VOID*)FdtData); + ASSERT_EFI_ERROR (Status); + + RdkSetVariable(); + + Status = GetRdkVariable(L"IMAGE", &ImagePath); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol ( + &gEfiDevicePathFromTextProtocolGuid, + NULL, + (VOID**)&DevicePathFromTextProtocol + ); + ASSERT_EFI_ERROR(Status); + + FilePath = DevicePathFromTextProtocol->ConvertTextToDevicePath(ImagePath); + + Status = BootServices->LoadImage ( + TRUE, + ImageHandle, + FilePath, + NULL, + 0, + &Handle + ); + ASSERT_EFI_ERROR (Status); + + UnicodeSPrintAsciiFormat (LoadOption, sizeof(LoadOption), CmdLine); + + Status = BootServices->HandleProtocol (Handle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo); + ASSERT_EFI_ERROR (Status); + ImageInfo->LoadOptionsSize = sizeof(LoadOption); + ImageInfo->LoadOptions = LoadOption; + + Status = BootServices->StartImage (Handle, ExitDataSize, ExitData); + ASSERT_EFI_ERROR (Status); + + return Status; +} -- 2.15.0