summaryrefslogtreecommitdiff
path: root/Platform/Comcast/Library/RdkBootManagerLib/HttpBoot.c
diff options
context:
space:
mode:
Diffstat (limited to 'Platform/Comcast/Library/RdkBootManagerLib/HttpBoot.c')
-rw-r--r--Platform/Comcast/Library/RdkBootManagerLib/HttpBoot.c350
1 files changed, 350 insertions, 0 deletions
diff --git a/Platform/Comcast/Library/RdkBootManagerLib/HttpBoot.c b/Platform/Comcast/Library/RdkBootManagerLib/HttpBoot.c
new file mode 100644
index 00000000..85f71040
--- /dev/null
+++ b/Platform/Comcast/Library/RdkBootManagerLib/HttpBoot.c
@@ -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;
+}