new file mode 100644
@@ -0,0 +1,50 @@
+#
+# Copyright (c) 2014-2018, 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.PcdRdkSystemPartitionName|""|VOID*|0x02000003
+ gRdkTokenSpaceGuid.PcdRdkConfFileName|""|VOID*|0x02000004
+ gRdkTokenSpaceGuid.PcdRdkCmdLineArgs|""|VOID*|0x02000013
+ gRdkTokenSpaceGuid.PcdRdkConfFileDevicePath|L""|VOID*|0x02000014
+ gRdkTokenSpaceGuid.PcdDtbAvailable|FALSE|BOOLEAN|0x00300014
+
+ # 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
new file mode 100644
@@ -0,0 +1,76 @@
+#
+# Copyright (c) 2014-2018, 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 = 0x0001001A
+ 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
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ NetworkPkg/NetworkPkg.dec
+ Platform/Comcast/Library/RdkBootManagerLib/RdkBootManagerLib.dec
+ ShellPkg/ShellPkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[Guids]
+ gEfiCertX509Guid
+ gEfiCertPkcs7Guid
+ gEfiCustomModeEnableGuid
+ gEfiImageSecurityDatabaseGuid
+ gFdtTableGuid
+ gRdkGlobalVariableGuid
+
+[Protocols]
+ gEfiBlockIoProtocolGuid
+ gEfiDevicePathToTextProtocolGuid
+ gEfiDevicePathFromTextProtocolGuid
+ gEfiLoadedImageProtocolGuid
+ gEfiShellProtocolGuid
+ gEfiDiskIoProtocolGuid
+ gEfiLoadFileProtocolGuid
+
+[Pcd]
+ gRdkTokenSpaceGuid.PcdRdkCmdLineArgs
+ gRdkTokenSpaceGuid.PcdRdkSystemPartitionName
+ gRdkTokenSpaceGuid.PcdRdkConfFileName
+ gRdkTokenSpaceGuid.PcdRdkConfFileDevicePath
+ gRdkTokenSpaceGuid.PcdDtbAvailable
+
+[LibraryClasses]
+ ArmLib
+ BaseLib
+ DebugLib
+ DevicePathLib
+ FileHandleLib
+ NetLib
+ PcdLib
+
new file mode 100644
@@ -0,0 +1,99 @@
+/*
+# Copyright (c) 2014-2018, 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.
+#
+*/
+#ifndef __RDK_BOOT_MANAGER_LIB_H__
+#define __RDK_BOOT_MANAGER_LIB_H__
+
+#include <Library/BdsLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PrintLib.h>
+#include <Library/ShellLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/FileHandleLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Protocol/DiskIo.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/LoadFile.h>
+#include <Protocol/SimpleTextOut.h>
+#include <Protocol/DevicePathFromText.h>
+#include <Protocol/DevicePathToText.h>
+#include <Protocol/AndroidFastbootPlatform.h>
+#include <Guid/ImageAuthentication.h>
+#include <Guid/AuthenticatedVariableFormat.h>
+#include <HttpBootDxe/HttpBootDxe.h>
+#include <Include/Guid/AuthenticatedVariableFormat.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
+ );
+
+extern
+EFI_STATUS
+GetRdkVariable (
+ IN CONST CHAR16 *Name,
+ OUT CONST CHAR16 **Value
+ );
+
+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
+ );
+
+extern
+EFI_STATUS
+RdkHttpBoot (
+ VOID
+ );
+
+#endif /* __RDK_BOOT_MANAGER_LIB_H__ */
new file mode 100644
@@ -0,0 +1,376 @@
+/*
+# Copyright (c) 2014-2018, 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 <RdkBootManagerLib.h>
+
+/* 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;
+
+/*
+ * 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;
+ }
+}
+
+/*
+ * lists the available Block Io and adds handle of given dev path
+ */
+STATIC
+EFI_STATUS
+ListBlockIos (
+ IN CHAR16 *PartitionName
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *AllHandles;
+ EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINTN LoopIndex;
+ UINTN NumHandles;
+ UINT16 *DeviceFullPath;
+ DISKIO_PARTITION_LIST *Entry;
+
+ InitializeListHead (&mPartitionListHead);
+
+ Status = gBS->LocateProtocol (
+ &gEfiDevicePathToTextProtocolGuid,
+ NULL,
+ (VOID **) &DevPathToText
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ // Get every Block IO protocol instance installed in the system
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiBlockIoProtocolGuid,
+ NULL,
+ &NumHandles,
+ &AllHandles
+ );
+ ASSERT_EFI_ERROR (Status);
+ DEBUG ((DEBUG_INFO, "Block IO: %d handles \n", NumHandles));
+
+ // Get HTTP driver handle from AllHandles
+ 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
+ );
+
+ DeviceFullPath = DevPathToText->ConvertDevicePathToText (
+ DevicePath,
+ FALSE,
+ TRUE
+ );
+
+ DEBUG((DEBUG_INFO,"Handle[%d] is %p, fullpath %s\n", \
+ LoopIndex, AllHandles[LoopIndex], DeviceFullPath));
+
+ if (StrCmp (PartitionName, DeviceFullPath) == 0) {
+ DEBUG((DEBUG_INFO, "rootfs partition path matched\n"));
+ //
+ // Add the partition handle to the list
+ //
+ // Create entry
+ Entry = AllocatePool (sizeof (DISKIO_PARTITION_LIST));
+ if (Entry == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ // Copy handle and partition name
+ Entry->PartitionHandle = AllHandles[LoopIndex];
+ StrnCpy (
+ Entry->PartitionName,
+ PartitionName,
+ PARTITION_NAME_MAX_LENGTH
+ );
+ InsertTailList (&mPartitionListHead, &Entry->Link);
+ break;
+ }
+ }
+ FreePool (AllHandles);
+ ASSERT (LoopIndex < NumHandles);
+Exit:
+ 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;
+ SPARSE_HEADER *SparseHeader;
+ UINT16 UnicodePartitionName[100];
+
+ AsciiStrToUnicodeStr ( PartitionName, UnicodePartitionName);
+ DEBUG((DEBUG_INFO, "Unicode partition name %s\n", UnicodePartitionName));
+
+ Status = ListBlockIos (UnicodePartitionName);
+ ASSERT_EFI_ERROR (Status);
+
+ Entry = (DISKIO_PARTITION_LIST *)GetFirstNode (&(mPartitionListHead));
+ ASSERT (Entry != NULL);
+
+ 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:
+ FreePartitionList ();
+ 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;
+}
new file mode 100644
@@ -0,0 +1,350 @@
+/*
+# Copyright (c) 2014-2018, 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 <RdkBootManagerLib.h>
+
+#define FILE_HDR_SIZE 16
+
+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;
+
+ UINTN Offset = (UINTN)&Ip4Nic->LoadFile;
+
+ Ip4Nic = (VOID *)((CHAR8 *)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) {
+ DEBUG((DEBUG_INFO, "IPv4 protocol found\n"));
+ 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 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 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 Exit;
+ }
+
+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 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 Exit;
+ }
+
+ *FileBuffer = AllocatePool (*FileSize);
+ if (*FileBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ Status = LoadFile->LoadFile (LoadFile, NewDevicePath, \
+ TRUE, FileSize, *FileBuffer);
+ if (EFI_ERROR (Status)) {
+ FreePool (FileBuffer);
+ goto Exit;
+ }
+
+Exit:
+
+ if (NewDevicePath != NULL) {
+ FreePool (NewDevicePath);
+ }
+
+ return Status;
+}
+
+UINTN
+ParseHeader (
+ VOID * Str
+ )
+{
+ UINTN i, Size;
+ UINT8 *Ptr;
+
+ Ptr = Str;
+ for (i = 0, Size = 0; i < FILE_HDR_SIZE; i++) {
+ Size = (Ptr[i] - '0') + (Size * 10);
+ }
+
+ return Size;
+}
+
+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; LoopIndex < FileSize; LoopIndex++) {
+ Uri[LoopIndex] = FileBuffer[LoopIndex];
+ }
+
+ if(FileBuffer[FileSize-1] == '\n') {
+ Uri[FileSize-1] = '\0';
+ }
+
+ FreePool (FileBuffer);
+ FileBuffer=NULL;
+
+ // Disable watchdog
+ Status = gBS->SetWatchdogTimer (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 = ParseHeader (FilePtr);
+ FilePtr += FILE_HDR_SIZE;
+ Status = PartitionWrite ((CHAR8 *)FixedPcdGetPtr (\
+ PcdRdkSystemPartitionName), FilePtr, Size);
+ ASSERT_EFI_ERROR (Status);
+
+ FilePtr += Size;
+ Size = ParseHeader (FilePtr);
+ FilePtr += FILE_HDR_SIZE;
+ Status = GetRdkVariable (L"IMAGE", &ImagePath);
+ ASSERT_EFI_ERROR (Status);
+ Status = RdkWriteFile (ImagePath, &FilePtr, &Size);
+ ASSERT_EFI_ERROR (Status);
+
+ if ( FixedPcdGetBool (PcdDtbAvailable) ) {
+ FilePtr += Size;
+ Size = ParseHeader (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;
+}
new file mode 100644
@@ -0,0 +1,389 @@
+/*
+# Copyright (c) 2014-2018, 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 <RdkBootManagerLib.h>
+
+#define MAX_VAR 6
+
+#define ALLOCATE_STRING_MEM(X) AllocateZeroPool((X + 1) * sizeof(CHAR16))
+
+/**
+ * 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 = BASE_CR((Head)->ForwardLink, typeof(*Pos), Member); \
+ &Pos->Member != (Head); \
+ Pos = BASE_CR(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 = BASE_CR((Head)->ForwardLink, typeof(*Pos), Member), \
+ N = BASE_CR(Pos->Member.ForwardLink, typeof(*Pos), Member); \
+ &Pos->Member != (Head); \
+ Pos = N, N = BASE_CR(N->Member.ForwardLink, typeof(*N), Member))
+
+/* ************************** */
+
+typedef struct {
+ CHAR16 *Name;
+ LIST_ENTRY List;
+} DIR_NODE;
+/* ************************** */
+
+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));
+ ASSERT (Dest != NULL);
+ 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));
+ //append directory name to the path
+ SaveString (&Node->Name, TempPath, FileInfo->FileName);
+ InsertHeadList (Head, &Node->List);
+ } else if (StrCmp (FileInfo->FileName, TargetFile) == 0) {
+ //append file to the absolute path
+ SaveString (Result, TempPath, FileInfo->FileName);
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+ }
+
+ Status = EFI_NOT_FOUND;
+
+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 = Next = 0, Status = 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
+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;
+
+ //Initialize to NULL
+ for (OuterLoopIndex = 0; OuterLoopIndex < MAX_VAR; OuterLoopIndex++) {
+ VarResult[OuterLoopIndex][0] = VarResult[OuterLoopIndex][1] = NULL;
+ }
+
+ for (OuterLoopIndex = 0, Next=0;
+ OuterLoopIndex < MAX_VAR && Next < FileSize;
+ OuterLoopIndex++) {
+ for (InnerLoopIndex = 0; InnerLoopIndex < 2; InnerLoopIndex++) {
+ Current = Next;
+ Next += StrSpn (&FileData[Next], VarDelimiter[InnerLoopIndex]);
+ FileData[Next] = '\0';
+ if (VarResult[OuterLoopIndex][InnerLoopIndex]) {
+ FreePool (VarResult[OuterLoopIndex][InnerLoopIndex]);
+ }
+ VarResult[OuterLoopIndex][InnerLoopIndex] = \
+ ALLOCATE_STRING_MEM (AsciiStrLen (&FileData[Current]));
+ AsciiStrToUnicodeStr (&FileData[Current], \
+ VarResult[OuterLoopIndex][InnerLoopIndex]);
+ //skip new line
+ Next += 2;
+ }
+ }
+
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+InitRdkVariables (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN RdkSize;
+ UINT8 *RdkData;
+ CHAR16 *Result;
+ CONST CHAR16 *DevPath;
+ CONST CHAR16 *RdkFileName;
+
+ DevPath = (CONST CHAR16 *)FixedPcdGetPtr (PcdRdkConfFileDevicePath);
+ RdkFileName = (CONST CHAR16 *)FixedPcdGetPtr (PcdRdkConfFileName);
+
+ Status = FindFileInDir (DevPath, RdkFileName, &Result);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to find file %s in %s\n", \
+ RdkFileName, DevPath));
+ return Status;
+ }
+
+ Status = RdkReadFile ((CONST CHAR16 *)Result, \
+ (VOID**)&RdkData, &RdkSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to read file %s\n", RdkFileName));
+ return Status;
+ }
+
+ Status = InitVarList ((CHAR8 *)RdkData, RdkSize);
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+GetVarValue (
+ IN CONST CHAR16 *Name,
+ OUT CONST CHAR16 **Value
+ )
+{
+ UINTN Count;
+ EFI_STATUS Status;
+
+ if (!VarablesInitialzed) {
+ Status = InitRdkVariables ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ VarablesInitialzed = 1;
+ }
+
+ //Initialize to NULL
+ *Value = NULL;
+
+ for (Count = 0; Count < MAX_VAR; Count++) {
+ if (VarResult[Count][0] != NULL &&
+ StrCmp (Name, VarResult[Count][0]) == 0) {
+ *Value = VarResult[Count][1];
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+EFI_STATUS
+GetRdkVariable (
+ IN CONST CHAR16 *Name,
+ OUT CONST CHAR16 **Value
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GetVarValue (Name, Value);
+ return Status;
+}
+
+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);
+
+ Buffer = NULL;
+
+ // Get the file size
+ Status = FileHandle->SetPosition (FileHandle, (UINT64) -1);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ Status = FileHandle->GetPosition (FileHandle, &SourceFileSize);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ Status = FileHandle->SetPosition (FileHandle, 0);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ BufferSize = (UINTN)SourceFileSize;
+ Buffer = AllocateZeroPool (BufferSize);
+ if (Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (FileSize != NULL) *FileSize = BufferSize;
+
+ Status = FileHandle->Read (FileHandle, &BufferSize, Buffer);
+ if (EFI_ERROR (Status) || BufferSize != SourceFileSize) {
+ FreePool (Buffer);
+ Buffer = NULL;
+ Status = EFI_BAD_BUFFER_SIZE;
+ goto Exit;
+ }
+
+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;
+}
new file mode 100644
@@ -0,0 +1,523 @@
+/*
+# Copyright (c) 2014-2018, 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 <RdkBootManagerLib.h>
+
+typedef enum KEY
+{
+ PK_KEY=1,
+ KEK_KEY,
+ DB_KEY,
+ DBX_KEY
+} eKey;
+/* ************************** */
+
+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) {
+ 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 = DevicePathFromTextProtocol->ConvertTextToDevicePath (Path);
+ if (KeyFileDevicePath != NULL)
+ {
+ Status = OpenFileByDevicePath (&KeyFileDevicePath, FileHandle, OpenMode, 0);
+ if (Status != EFI_SUCCESS)
+ {
+ DEBUG ((DEBUG_ERROR, "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;
+
+ 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;
+
+ 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;
+}
+
+STATIC
+VOID
+RdkSetVariable (
+ VOID
+)
+{
+ CONST CHAR16 *KeyPath;
+ EFI_STATUS Status;
+ UINT8 *KekKey, *PkKey, *KekCrtData;
+ UINTN KekKeySize, PkKeySize, KekCrtSize;
+ INT8* SetupMode;
+ eKey KeyType;
+
+ KeyPath = NULL;
+ SetupMode = NULL;
+ KekKey = PkKey = KekCrtData = NULL;
+ KekKeySize = PkKeySize = KekCrtSize = 0;
+
+ Status = GetRdkVariable (L"ROOTCERT", &KeyPath);
+
+ //set only if the Kek Crt file mentioned in the configuration file
+ if (KeyPath != NULL) {
+ Status = RdkReadFile (
+ KeyPath,
+ (VOID **)&KekCrtData,
+ &KekCrtSize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gRT->SetVariable (
+ L"RdkRootCertificate",
+ &gRdkGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ KekCrtSize,
+ KekCrtData
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (KekCrtData) FreePool (KekCrtData);
+ }
+
+ Status = GetRdkVariable (L"KEKCERT", &KeyPath);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = RdkReadFile (
+ KeyPath,
+ (VOID **)&KekKey,
+ &KekKeySize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = GetRdkVariable (L"PKCERT", &KeyPath);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = RdkReadFile (
+ KeyPath,
+ (VOID **)&PkKey,
+ &PkKeySize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ 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);
+ }
+
+ if ( PkKey ) FreePool (PkKey);
+ if ( KekKey ) FreePool (KekKey);
+}
+
+EFI_STATUS
+RdkSecureBoot (
+ EFI_HANDLE ImageHandle,
+ EFI_BOOT_SERVICES *BootServices
+)
+{
+ UINTN ExitDataSize;
+ CHAR16 *ExitData;
+ CHAR16 LoadOption[128];
+ CONST CHAR8 *CmdLine;
+ CHAR16 *ImagePath;
+ UINT8 *FdtData;
+ 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;
+ CmdLine = (CONST CHAR8 *)FixedPcdGetPtr (PcdRdkCmdLineArgs);
+
+ if (FixedPcdGetBool (PcdDtbAvailable)) {
+ FdtData = NULL;
+ DtbPath = NULL;
+
+ Status = GetRdkVariable (L"DTB", &DtbPath);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = RdkReadFile (DtbPath, (VOID**) &FdtData, NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->InstallConfigurationTable (&gFdtTableGuid,(VOID*)FdtData);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ RdkSetVariable ();
+
+ Status = GetRdkVariable (L"IMAGE", (CONST CHAR16**)&ImagePath);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->LocateProtocol (
+ &gEfiDevicePathFromTextProtocolGuid,
+ NULL,
+ (VOID**)&DevicePathFromTextProtocol
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ FilePath = DevicePathFromTextProtocol->ConvertTextToDevicePath (ImagePath);
+ ASSERT(NULL != FilePath);
+
+ 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;
+}