--- /dev/null
+/** @file\r
+\r
+ Copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>\r
+ Copyright (c) 2017, Linaro. All rights reserved.\r
+\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <Library/AndroidBootImgLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/BdsLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+\r
+#include <Protocol/BlockIo.h>\r
+#include <Protocol/DevicePathFromText.h>\r
+\r
+/* Validate the node is media hard drive type */\r
+EFI_STATUS\r
+ValidateAndroidMediaDevicePath (\r
+ IN EFI_DEVICE_PATH *DevicePath\r
+ )\r
+{\r
+ EFI_DEVICE_PATH_PROTOCOL *Node, *NextNode;\r
+\r
+ NextNode = DevicePath;\r
+ while (NextNode != NULL) {\r
+ Node = NextNode;\r
+ if (IS_DEVICE_PATH_NODE (Node, MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ NextNode = NextDevicePathNode (Node);\r
+ }\r
+ return EFI_INVALID_PARAMETER;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+AndroidBootAppEntryPoint (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ CHAR16 *BootPathStr;\r
+ EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol;\r
+ EFI_DEVICE_PATH *DevicePath;\r
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+ UINT32 MediaId, BlockSize;\r
+ VOID *Buffer;\r
+ EFI_HANDLE Handle;\r
+ UINTN BootImgSize;\r
+\r
+ BootPathStr = (CHAR16 *)PcdGetPtr (PcdAndroidBootDevicePath);\r
+ ASSERT (BootPathStr != NULL);\r
+ Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL,\r
+ (VOID **)&EfiDevicePathFromTextProtocol);\r
+ ASSERT_EFI_ERROR(Status);\r
+ DevicePath = (EFI_DEVICE_PATH *)EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (BootPathStr);\r
+ ASSERT (DevicePath != NULL);\r
+\r
+ Status = ValidateAndroidMediaDevicePath (DevicePath);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid,\r
+ &DevicePath, &Handle);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Handle,\r
+ &gEfiBlockIoProtocolGuid,\r
+ (VOID **) &BlockIo,\r
+ gImageHandle,\r
+ NULL,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "Failed to get BlockIo: %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ MediaId = BlockIo->Media->MediaId;\r
+ BlockSize = BlockIo->Media->BlockSize;\r
+ Buffer = AllocatePages (EFI_SIZE_TO_PAGES (sizeof(ANDROID_BOOTIMG_HEADER)));\r
+ if (Buffer == NULL) {\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+ /* Load header of boot.img */\r
+ Status = BlockIo->ReadBlocks (\r
+ BlockIo,\r
+ MediaId,\r
+ 0,\r
+ BlockSize,\r
+ Buffer\r
+ );\r
+ Status = AndroidBootImgGetImgSize (Buffer, &BootImgSize);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "Failed to get AndroidBootImg Size: %r\n", Status));\r
+ return Status;\r
+ }\r
+ BootImgSize = ALIGN_VALUE (BootImgSize, BlockSize);\r
+ FreePages (Buffer, EFI_SIZE_TO_PAGES (sizeof(ANDROID_BOOTIMG_HEADER)));\r
+\r
+ /* Both PartitionStart and PartitionSize are counted as block size. */\r
+ Buffer = AllocatePages (EFI_SIZE_TO_PAGES (BootImgSize));\r
+ if (Buffer == NULL) {\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ /* Load header of boot.img */\r
+ Status = BlockIo->ReadBlocks (\r
+ BlockIo,\r
+ MediaId,\r
+ 0,\r
+ BootImgSize,\r
+ Buffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "Failed to read blocks: %r\n", Status));\r
+ goto EXIT;\r
+ }\r
+\r
+ Status = AndroidBootImgBoot (Buffer, BootImgSize);\r
+\r
+EXIT:\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+\r
+ Copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>\r
+ Copyright (c) 2017, Linaro. All rights reserved.\r
+\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <libfdt.h>\r
+#include <Library/AndroidBootImgLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+\r
+#include <Protocol/AndroidBootImg.h>\r
+#include <Protocol/LoadedImage.h>\r
+\r
+#include <libfdt.h>\r
+\r
+#define FDT_ADDITIONAL_ENTRIES_SIZE 0x400\r
+\r
+typedef struct {\r
+ MEMMAP_DEVICE_PATH Node1;\r
+ EFI_DEVICE_PATH_PROTOCOL End;\r
+} MEMORY_DEVICE_PATH;\r
+\r
+STATIC ANDROID_BOOTIMG_PROTOCOL *mAndroidBootImg;\r
+\r
+STATIC CONST MEMORY_DEVICE_PATH mMemoryDevicePathTemplate =\r
+{\r
+ {\r
+ {\r
+ HARDWARE_DEVICE_PATH,\r
+ HW_MEMMAP_DP,\r
+ {\r
+ (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),\r
+ (UINT8)((sizeof (MEMMAP_DEVICE_PATH)) >> 8),\r
+ },\r
+ }, // Header\r
+ 0, // StartingAddress (set at runtime)\r
+ 0 // EndingAddress (set at runtime)\r
+ }, // Node1\r
+ {\r
+ END_DEVICE_PATH_TYPE,\r
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+ { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }\r
+ } // End\r
+};\r
+\r
+EFI_STATUS\r
+AndroidBootImgGetImgSize (\r
+ IN VOID *BootImg,\r
+ OUT UINTN *ImgSize\r
+ )\r
+{\r
+ ANDROID_BOOTIMG_HEADER *Header;\r
+\r
+ Header = (ANDROID_BOOTIMG_HEADER *) BootImg;\r
+\r
+ if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC,\r
+ ANDROID_BOOT_MAGIC_LENGTH) != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ /* The page size is not specified, but it should be power of 2 at least */\r
+ ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize));\r
+\r
+ /* Get real size of abootimg */\r
+ *ImgSize = ALIGN_VALUE (Header->KernelSize, Header->PageSize) +\r
+ ALIGN_VALUE (Header->RamdiskSize, Header->PageSize) +\r
+ ALIGN_VALUE (Header->SecondStageBootloaderSize, Header->PageSize) +\r
+ Header->PageSize;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+AndroidBootImgGetKernelInfo (\r
+ IN VOID *BootImg,\r
+ OUT VOID **Kernel,\r
+ OUT UINTN *KernelSize\r
+ )\r
+{\r
+ ANDROID_BOOTIMG_HEADER *Header;\r
+\r
+ Header = (ANDROID_BOOTIMG_HEADER *) BootImg;\r
+\r
+ if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC,\r
+ ANDROID_BOOT_MAGIC_LENGTH) != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Header->KernelSize == 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize));\r
+\r
+ *KernelSize = Header->KernelSize;\r
+ *Kernel = BootImg + Header->PageSize;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+AndroidBootImgGetRamdiskInfo (\r
+ IN VOID *BootImg,\r
+ OUT VOID **Ramdisk,\r
+ OUT UINTN *RamdiskSize\r
+ )\r
+{\r
+ ANDROID_BOOTIMG_HEADER *Header;\r
+\r
+ Header = (ANDROID_BOOTIMG_HEADER *)BootImg;\r
+\r
+ if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC,\r
+ ANDROID_BOOT_MAGIC_LENGTH) != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize));\r
+\r
+ *RamdiskSize = Header->RamdiskSize;\r
+\r
+ if (Header->RamdiskSize != 0) {\r
+ *Ramdisk = (VOID *)((INTN)BootImg\r
+ + Header->PageSize\r
+ + ALIGN_VALUE (Header->KernelSize, Header->PageSize));\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+AndroidBootImgGetSecondBootLoaderInfo (\r
+ IN VOID *BootImg,\r
+ OUT VOID **Second,\r
+ OUT UINTN *SecondSize\r
+ )\r
+{\r
+ ANDROID_BOOTIMG_HEADER *Header;\r
+\r
+ Header = (ANDROID_BOOTIMG_HEADER *)BootImg;\r
+\r
+ if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC,\r
+ ANDROID_BOOT_MAGIC_LENGTH) != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize));\r
+\r
+ *SecondSize = Header->SecondStageBootloaderSize;\r
+\r
+ if (Header->SecondStageBootloaderSize != 0) {\r
+ *Second = (VOID *)((UINTN)BootImg\r
+ + Header->PageSize\r
+ + ALIGN_VALUE (Header->KernelSize, Header->PageSize)\r
+ + ALIGN_VALUE (Header->RamdiskSize, Header->PageSize));\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+AndroidBootImgGetKernelArgs (\r
+ IN VOID *BootImg,\r
+ OUT CHAR8 *KernelArgs\r
+ )\r
+{\r
+ ANDROID_BOOTIMG_HEADER *Header;\r
+\r
+ Header = (ANDROID_BOOTIMG_HEADER *) BootImg;\r
+ AsciiStrnCpyS (KernelArgs, ANDROID_BOOTIMG_KERNEL_ARGS_SIZE, Header->KernelArgs,\r
+ ANDROID_BOOTIMG_KERNEL_ARGS_SIZE);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+AndroidBootImgGetFdt (\r
+ IN VOID *BootImg,\r
+ IN VOID **FdtBase\r
+ )\r
+{\r
+ UINTN SecondLoaderSize;\r
+ EFI_STATUS Status;\r
+\r
+ /* Check whether FDT is located in second boot region as some vendor do so,\r
+ * because second loader is never used as far as I know. */\r
+ Status = AndroidBootImgGetSecondBootLoaderInfo (\r
+ BootImg,\r
+ FdtBase,\r
+ &SecondLoaderSize\r
+ );\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+AndroidBootImgUpdateArgs (\r
+ IN VOID *BootImg,\r
+ OUT VOID *KernelArgs\r
+ )\r
+{\r
+ CHAR8 ImageKernelArgs[ANDROID_BOOTIMG_KERNEL_ARGS_SIZE];\r
+ EFI_STATUS Status;\r
+\r
+ // Get kernel arguments from Android boot image\r
+ Status = AndroidBootImgGetKernelArgs (BootImg, ImageKernelArgs);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ AsciiStrToUnicodeStrS (ImageKernelArgs, KernelArgs,\r
+ ANDROID_BOOTIMG_KERNEL_ARGS_SIZE >> 1);\r
+ // Append platform kernel arguments\r
+ if(mAndroidBootImg->AppendArgs) {\r
+ Status = mAndroidBootImg->AppendArgs (KernelArgs,\r
+ ANDROID_BOOTIMG_KERNEL_ARGS_SIZE);\r
+ }\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+AndroidBootImgLocateFdt (\r
+ IN VOID *BootImg,\r
+ IN VOID **FdtBase\r
+ )\r
+{\r
+ INTN Err;\r
+ EFI_STATUS Status;\r
+\r
+ Status = EfiGetSystemConfigurationTable (&gFdtTableGuid, FdtBase);\r
+ if (!EFI_ERROR (Status)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Status = AndroidBootImgGetFdt (BootImg, FdtBase);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ Err = fdt_check_header (*FdtBase);\r
+ if (Err != 0) {\r
+ DEBUG ((DEBUG_ERROR, "ERROR: Device Tree header not valid (Err:%d)\n",\r
+ Err));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+INTN\r
+AndroidBootImgGetChosenNode (\r
+ IN INTN UpdatedFdtBase\r
+ )\r
+{\r
+ INTN ChosenNode;\r
+\r
+ ChosenNode = fdt_subnode_offset ((CONST VOID *)UpdatedFdtBase, 0, "chosen");\r
+ if (ChosenNode < 0) {\r
+ ChosenNode = fdt_add_subnode((VOID *)UpdatedFdtBase, 0, "chosen");\r
+ if (ChosenNode < 0) {\r
+ DEBUG ((DEBUG_ERROR, "Fail to find fdt node chosen!\n"));\r
+ return 0;\r
+ }\r
+ }\r
+ return ChosenNode;\r
+}\r
+\r
+EFI_STATUS\r
+AndroidBootImgSetProperty64 (\r
+ IN INTN UpdatedFdtBase,\r
+ IN INTN ChosenNode,\r
+ IN CHAR8 *PropertyName,\r
+ IN UINT64 Val\r
+ )\r
+{\r
+ INTN Err;\r
+ struct fdt_property *Property;\r
+ int Len;\r
+\r
+ Property = fdt_get_property_w((VOID *)UpdatedFdtBase, ChosenNode,\r
+ PropertyName, &Len);\r
+ if (NULL == Property && Len == -FDT_ERR_NOTFOUND) {\r
+ Val = cpu_to_fdt64(Val);\r
+ Err = fdt_appendprop ((VOID *)UpdatedFdtBase, ChosenNode,\r
+ PropertyName, &Val, sizeof (UINT64));\r
+ if (Err) {\r
+ DEBUG ((DEBUG_ERROR, "fdt_appendprop() fail: %a\n", fdt_strerror (Err)));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ } else if (Property != NULL) {\r
+ Err = fdt_setprop_u64((VOID *)UpdatedFdtBase, ChosenNode,\r
+ PropertyName, Val);\r
+ if (Err) {\r
+ DEBUG ((DEBUG_ERROR, "fdt_setprop_u64() fail: %a\n", fdt_strerror (Err)));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ } else {\r
+ DEBUG ((DEBUG_ERROR, "Failed to set fdt Property %a\n", PropertyName));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+AndroidBootImgUpdateFdt (\r
+ IN VOID *BootImg,\r
+ IN VOID *FdtBase,\r
+ IN VOID *RamdiskData,\r
+ IN UINTN RamdiskSize\r
+ )\r
+{\r
+ INTN ChosenNode, Err, NewFdtSize;\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS UpdatedFdtBase, NewFdtBase;\r
+\r
+ NewFdtSize = (UINTN)fdt_totalsize (FdtBase)\r
+ + FDT_ADDITIONAL_ENTRIES_SIZE;\r
+ Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData,\r
+ EFI_SIZE_TO_PAGES (NewFdtSize), &UpdatedFdtBase);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_WARN, "Warning: Failed to reallocate FDT, err %d.\n",\r
+ Status));\r
+ return Status;\r
+ }\r
+\r
+ // Load the Original FDT tree into the new region\r
+ Err = fdt_open_into(FdtBase, (VOID*)(INTN)UpdatedFdtBase, NewFdtSize);\r
+ if (Err) {\r
+ DEBUG ((DEBUG_ERROR, "fdt_open_into(): %a\n", fdt_strerror (Err)));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Fdt_Exit;\r
+ }\r
+\r
+ ChosenNode = AndroidBootImgGetChosenNode(UpdatedFdtBase);\r
+ if (!ChosenNode) {\r
+ goto Fdt_Exit;\r
+ }\r
+\r
+ Status = AndroidBootImgSetProperty64 (UpdatedFdtBase, ChosenNode,\r
+ "linux,initrd-start",\r
+ (UINTN)RamdiskData);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Fdt_Exit;\r
+ }\r
+\r
+ Status = AndroidBootImgSetProperty64 (UpdatedFdtBase, ChosenNode,\r
+ "linux,initrd-end",\r
+ (UINTN)(RamdiskData + RamdiskSize));\r
+ if (EFI_ERROR (Status)) {\r
+ goto Fdt_Exit;\r
+ }\r
+\r
+ if (mAndroidBootImg->UpdateDtb) {\r
+ Status = mAndroidBootImg->UpdateDtb (UpdatedFdtBase, &NewFdtBase);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Fdt_Exit;\r
+ }\r
+ }\r
+\r
+ Status = gBS->InstallConfigurationTable (\r
+ &gFdtTableGuid,\r
+ (VOID *)(UINTN)NewFdtBase\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+Fdt_Exit:\r
+ gBS->FreePages (UpdatedFdtBase, EFI_SIZE_TO_PAGES (NewFdtSize));\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+AndroidBootImgBoot (\r
+ IN VOID *Buffer,\r
+ IN UINTN BufferSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ VOID *Kernel;\r
+ UINTN KernelSize;\r
+ MEMORY_DEVICE_PATH KernelDevicePath;\r
+ EFI_HANDLE ImageHandle;\r
+ VOID *NewKernelArg;\r
+ EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;\r
+ VOID *RamdiskData;\r
+ UINTN RamdiskSize;\r
+ IN VOID *FdtBase;\r
+\r
+ Status = gBS->LocateProtocol (&gAndroidBootImgProtocolGuid, NULL,\r
+ (VOID **) &mAndroidBootImg);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = AndroidBootImgGetKernelInfo (\r
+ Buffer,\r
+ &Kernel,\r
+ &KernelSize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ NewKernelArg = AllocateZeroPool (ANDROID_BOOTIMG_KERNEL_ARGS_SIZE);\r
+ if (NewKernelArg == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "Fail to allocate memory\n"));\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = AndroidBootImgUpdateArgs (Buffer, NewKernelArg);\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (NewKernelArg);\r
+ return Status;\r
+ }\r
+\r
+ Status = AndroidBootImgGetRamdiskInfo (\r
+ Buffer,\r
+ &RamdiskData,\r
+ &RamdiskSize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = AndroidBootImgLocateFdt (Buffer, &FdtBase);\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (NewKernelArg);\r
+ return Status;\r
+ }\r
+\r
+ Status = AndroidBootImgUpdateFdt (Buffer, FdtBase, RamdiskData, RamdiskSize);\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (NewKernelArg);\r
+ return Status;\r
+ }\r
+\r
+ KernelDevicePath = mMemoryDevicePathTemplate;\r
+\r
+ KernelDevicePath.Node1.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Kernel;\r
+ KernelDevicePath.Node1.EndingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Kernel\r
+ + KernelSize;\r
+\r
+ Status = gBS->LoadImage (TRUE, gImageHandle,\r
+ (EFI_DEVICE_PATH *)&KernelDevicePath,\r
+ (VOID*)(UINTN)Kernel, KernelSize, &ImageHandle);\r
+\r
+ // Set kernel arguments\r
+ Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid,\r
+ (VOID **) &ImageInfo);\r
+ ImageInfo->LoadOptions = NewKernelArg;\r
+ ImageInfo->LoadOptionsSize = StrLen (NewKernelArg) * sizeof (CHAR16);\r
+\r
+ // Before calling the image, enable the Watchdog Timer for the 5 Minute period\r
+ gBS->SetWatchdogTimer (5 * 60, 0x10000, 0, NULL);\r
+ // Start the image\r
+ Status = gBS->StartImage (ImageHandle, NULL, NULL);\r
+ // Clear the Watchdog Timer if the image returns\r
+ gBS->SetWatchdogTimer (0, 0x10000, 0, NULL);\r
+ return EFI_SUCCESS;\r
+}\r