| /** @file | |
| Copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR> | |
| Copyright (c) 2017, Linaro. All rights reserved. | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include <Library/AndroidBootImgLib.h> | |
| #include <Library/BaseMemoryLib.h> | |
| #include <Library/FdtLib.h> | |
| #include <Library/PrintLib.h> | |
| #include <Library/DevicePathLib.h> | |
| #include <Library/UefiBootServicesTableLib.h> | |
| #include <Library/UefiLib.h> | |
| #include <Protocol/AndroidBootImg.h> | |
| #include <Protocol/LoadFile2.h> | |
| #include <Protocol/LoadedImage.h> | |
| #include <Guid/LinuxEfiInitrdMedia.h> | |
| #define FDT_ADDITIONAL_ENTRIES_SIZE 0x400 | |
| typedef struct { | |
| MEMMAP_DEVICE_PATH Node1; | |
| EFI_DEVICE_PATH_PROTOCOL End; | |
| } MEMORY_DEVICE_PATH; | |
| typedef struct { | |
| VENDOR_DEVICE_PATH VendorMediaNode; | |
| EFI_DEVICE_PATH_PROTOCOL EndNode; | |
| } RAMDISK_DEVICE_PATH; | |
| STATIC ANDROID_BOOTIMG_PROTOCOL *mAndroidBootImg; | |
| STATIC VOID *mRamdiskData = NULL; | |
| STATIC UINTN mRamdiskSize = 0; | |
| STATIC EFI_HANDLE mRamDiskLoadFileHandle = NULL; | |
| STATIC CONST MEMORY_DEVICE_PATH mMemoryDevicePathTemplate = | |
| { | |
| { | |
| { | |
| HARDWARE_DEVICE_PATH, | |
| HW_MEMMAP_DP, | |
| { | |
| (UINT8)(sizeof (MEMMAP_DEVICE_PATH)), | |
| (UINT8)((sizeof (MEMMAP_DEVICE_PATH)) >> 8), | |
| }, | |
| }, // Header | |
| 0, // StartingAddress (set at runtime) | |
| 0 // EndingAddress (set at runtime) | |
| }, // Node1 | |
| { | |
| END_DEVICE_PATH_TYPE, | |
| END_ENTIRE_DEVICE_PATH_SUBTYPE, | |
| { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } | |
| } // End | |
| }; | |
| STATIC CONST RAMDISK_DEVICE_PATH mRamdiskDevicePath = | |
| { | |
| { | |
| { | |
| MEDIA_DEVICE_PATH, | |
| MEDIA_VENDOR_DP, | |
| { sizeof (VENDOR_DEVICE_PATH), 0 } | |
| }, | |
| LINUX_EFI_INITRD_MEDIA_GUID | |
| }, | |
| { | |
| END_DEVICE_PATH_TYPE, | |
| END_ENTIRE_DEVICE_PATH_SUBTYPE, | |
| { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } | |
| } | |
| }; | |
| /** | |
| Causes the driver to load a specified file. | |
| @param This Protocol instance pointer. | |
| @param FilePath The device specific path of the file to load. | |
| @param BootPolicy Should always be FALSE. | |
| @param BufferSize On input the size of Buffer in bytes. On output with a return | |
| code of EFI_SUCCESS, the amount of data transferred to | |
| Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL, | |
| the size of Buffer required to retrieve the requested file. | |
| @param Buffer The memory buffer to transfer the file to. IF Buffer is NULL, | |
| then no the size of the requested file is returned in | |
| BufferSize. | |
| @retval EFI_SUCCESS The file was loaded. | |
| @retval EFI_UNSUPPORTED BootPolicy is TRUE. | |
| @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or | |
| BufferSize is NULL. | |
| @retval EFI_NO_MEDIA No medium was present to load the file. | |
| @retval EFI_DEVICE_ERROR The file was not loaded due to a device error. | |
| @retval EFI_NO_RESPONSE The remote system did not respond. | |
| @retval EFI_NOT_FOUND The file was not found | |
| @retval EFI_ABORTED The file load process was manually canceled. | |
| @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current | |
| directory entry. BufferSize has been updated with | |
| the size needed to complete the request. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| AndroidBootImgLoadFile2 ( | |
| IN EFI_LOAD_FILE2_PROTOCOL *This, | |
| IN EFI_DEVICE_PATH_PROTOCOL *FilePath, | |
| IN BOOLEAN BootPolicy, | |
| IN OUT UINTN *BufferSize, | |
| IN VOID *Buffer OPTIONAL | |
| ) | |
| { | |
| // Verify if the valid parameters | |
| if ((This == NULL) || | |
| (BufferSize == NULL) || | |
| (FilePath == NULL) || | |
| !IsDevicePathValid (FilePath, 0)) | |
| { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (BootPolicy) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| // Check if the given buffer size is big enough | |
| // EFI_BUFFER_TOO_SMALL to allow caller to allocate a bigger buffer | |
| if (mRamdiskSize == 0) { | |
| return EFI_NOT_FOUND; | |
| } | |
| if ((Buffer == NULL) || (*BufferSize < mRamdiskSize)) { | |
| *BufferSize = mRamdiskSize; | |
| return EFI_BUFFER_TOO_SMALL; | |
| } | |
| // Copy InitRd | |
| CopyMem (Buffer, mRamdiskData, mRamdiskSize); | |
| *BufferSize = mRamdiskSize; | |
| return EFI_SUCCESS; | |
| } | |
| /// | |
| /// Load File Protocol instance | |
| /// | |
| STATIC EFI_LOAD_FILE2_PROTOCOL mAndroidBootImgLoadFile2 = { | |
| AndroidBootImgLoadFile2 | |
| }; | |
| EFI_STATUS | |
| AndroidBootImgGetImgSize ( | |
| IN VOID *BootImg, | |
| OUT UINTN *ImgSize | |
| ) | |
| { | |
| ANDROID_BOOTIMG_HEADER *Header; | |
| Header = (ANDROID_BOOTIMG_HEADER *)BootImg; | |
| if (AsciiStrnCmp ( | |
| (CONST CHAR8 *)Header->BootMagic, | |
| ANDROID_BOOT_MAGIC, | |
| ANDROID_BOOT_MAGIC_LENGTH | |
| ) != 0) | |
| { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| /* The page size is not specified, but it should be power of 2 at least */ | |
| ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize)); | |
| /* Get real size of abootimg */ | |
| *ImgSize = ALIGN_VALUE (Header->KernelSize, Header->PageSize) + | |
| ALIGN_VALUE (Header->RamdiskSize, Header->PageSize) + | |
| ALIGN_VALUE (Header->SecondStageBootloaderSize, Header->PageSize) + | |
| Header->PageSize; | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| AndroidBootImgGetKernelInfo ( | |
| IN VOID *BootImg, | |
| OUT VOID **Kernel, | |
| OUT UINTN *KernelSize | |
| ) | |
| { | |
| ANDROID_BOOTIMG_HEADER *Header; | |
| Header = (ANDROID_BOOTIMG_HEADER *)BootImg; | |
| if (AsciiStrnCmp ( | |
| (CONST CHAR8 *)Header->BootMagic, | |
| ANDROID_BOOT_MAGIC, | |
| ANDROID_BOOT_MAGIC_LENGTH | |
| ) != 0) | |
| { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (Header->KernelSize == 0) { | |
| return EFI_NOT_FOUND; | |
| } | |
| ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize)); | |
| *KernelSize = Header->KernelSize; | |
| *Kernel = (VOID *)((UINTN)BootImg + Header->PageSize); | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| AndroidBootImgGetRamdiskInfo ( | |
| IN VOID *BootImg, | |
| OUT VOID **Ramdisk, | |
| OUT UINTN *RamdiskSize | |
| ) | |
| { | |
| ANDROID_BOOTIMG_HEADER *Header; | |
| Header = (ANDROID_BOOTIMG_HEADER *)BootImg; | |
| if (AsciiStrnCmp ( | |
| (CONST CHAR8 *)Header->BootMagic, | |
| ANDROID_BOOT_MAGIC, | |
| ANDROID_BOOT_MAGIC_LENGTH | |
| ) != 0) | |
| { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize)); | |
| *RamdiskSize = Header->RamdiskSize; | |
| if (Header->RamdiskSize != 0) { | |
| *Ramdisk = (VOID *)((INTN)BootImg | |
| + Header->PageSize | |
| + ALIGN_VALUE (Header->KernelSize, Header->PageSize)); | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| AndroidBootImgGetSecondBootLoaderInfo ( | |
| IN VOID *BootImg, | |
| OUT VOID **Second, | |
| OUT UINTN *SecondSize | |
| ) | |
| { | |
| ANDROID_BOOTIMG_HEADER *Header; | |
| Header = (ANDROID_BOOTIMG_HEADER *)BootImg; | |
| if (AsciiStrnCmp ( | |
| (CONST CHAR8 *)Header->BootMagic, | |
| ANDROID_BOOT_MAGIC, | |
| ANDROID_BOOT_MAGIC_LENGTH | |
| ) != 0) | |
| { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize)); | |
| *SecondSize = Header->SecondStageBootloaderSize; | |
| if (Header->SecondStageBootloaderSize != 0) { | |
| *Second = (VOID *)((UINTN)BootImg | |
| + Header->PageSize | |
| + ALIGN_VALUE (Header->KernelSize, Header->PageSize) | |
| + ALIGN_VALUE (Header->RamdiskSize, Header->PageSize)); | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| AndroidBootImgGetKernelArgs ( | |
| IN VOID *BootImg, | |
| OUT CHAR8 *KernelArgs | |
| ) | |
| { | |
| ANDROID_BOOTIMG_HEADER *Header; | |
| Header = (ANDROID_BOOTIMG_HEADER *)BootImg; | |
| AsciiStrnCpyS ( | |
| KernelArgs, | |
| ANDROID_BOOTIMG_KERNEL_ARGS_SIZE, | |
| Header->KernelArgs, | |
| ANDROID_BOOTIMG_KERNEL_ARGS_SIZE | |
| ); | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| AndroidBootImgGetFdt ( | |
| IN VOID *BootImg, | |
| IN VOID **FdtBase | |
| ) | |
| { | |
| UINTN SecondLoaderSize; | |
| EFI_STATUS Status; | |
| /* Check whether FDT is located in second boot region as some vendor do so, | |
| * because second loader is never used as far as I know. */ | |
| Status = AndroidBootImgGetSecondBootLoaderInfo ( | |
| BootImg, | |
| FdtBase, | |
| &SecondLoaderSize | |
| ); | |
| return Status; | |
| } | |
| EFI_STATUS | |
| AndroidBootImgUpdateArgs ( | |
| IN VOID *BootImg, | |
| OUT VOID **KernelArgs | |
| ) | |
| { | |
| CHAR8 ImageKernelArgs[ANDROID_BOOTIMG_KERNEL_ARGS_SIZE]; | |
| EFI_STATUS Status; | |
| UINT32 NewKernelArgSize; | |
| // Get kernel arguments from Android boot image | |
| Status = AndroidBootImgGetKernelArgs (BootImg, ImageKernelArgs); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| NewKernelArgSize = ANDROID_BOOTIMG_KERNEL_ARGS_SIZE + PcdGet32 (PcdAndroidKernelCommandLineOverflow); | |
| *KernelArgs = AllocateZeroPool (sizeof (CHAR16) * NewKernelArgSize); | |
| if (*KernelArgs == NULL) { | |
| DEBUG ((DEBUG_ERROR, "Fail to allocate memory\n")); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| AsciiStrToUnicodeStrS ( | |
| ImageKernelArgs, | |
| *KernelArgs, | |
| NewKernelArgSize | |
| ); | |
| // Append platform kernel arguments | |
| if (mAndroidBootImg->AppendArgs) { | |
| Status = mAndroidBootImg->AppendArgs ( | |
| *KernelArgs, | |
| NewKernelArgSize | |
| ); | |
| } | |
| return Status; | |
| } | |
| EFI_STATUS | |
| AndroidBootImgInstallLoadFile2 ( | |
| IN VOID *RamdiskData, | |
| IN UINTN RamdiskSize | |
| ) | |
| { | |
| mRamDiskLoadFileHandle = NULL; | |
| mRamdiskData = RamdiskData; | |
| mRamdiskSize = RamdiskSize; | |
| return gBS->InstallMultipleProtocolInterfaces ( | |
| &mRamDiskLoadFileHandle, | |
| &gEfiLoadFile2ProtocolGuid, | |
| &mAndroidBootImgLoadFile2, | |
| &gEfiDevicePathProtocolGuid, | |
| &mRamdiskDevicePath, | |
| NULL | |
| ); | |
| } | |
| EFI_STATUS | |
| AndroidBootImgUninstallLoadFile2 ( | |
| VOID | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| Status = EFI_SUCCESS; | |
| mRamdiskData = NULL; | |
| mRamdiskSize = 0; | |
| if (mRamDiskLoadFileHandle != NULL) { | |
| Status = gBS->UninstallMultipleProtocolInterfaces ( | |
| mRamDiskLoadFileHandle, | |
| &gEfiLoadFile2ProtocolGuid, | |
| &mAndroidBootImgLoadFile2, | |
| &gEfiDevicePathProtocolGuid, | |
| &mRamdiskDevicePath, | |
| NULL | |
| ); | |
| mRamDiskLoadFileHandle = NULL; | |
| } | |
| return Status; | |
| } | |
| BOOLEAN | |
| AndroidBootImgAcpiSupported ( | |
| VOID | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| VOID *AcpiTable; | |
| Status = EfiGetSystemConfigurationTable (&gEfiAcpiTableGuid, &AcpiTable); | |
| return !EFI_ERROR (Status); | |
| } | |
| EFI_STATUS | |
| AndroidBootImgLocateFdt ( | |
| IN VOID *BootImg, | |
| IN VOID **FdtBase | |
| ) | |
| { | |
| INTN Err; | |
| EFI_STATUS Status; | |
| Status = EfiGetSystemConfigurationTable (&gFdtTableGuid, FdtBase); | |
| if (!EFI_ERROR (Status)) { | |
| return EFI_SUCCESS; | |
| } | |
| Status = AndroidBootImgGetFdt (BootImg, FdtBase); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| Err = FdtCheckHeader (*FdtBase); | |
| if (Err != 0) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: Device Tree header not valid (Err:%d)\n", | |
| Err | |
| )); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| INTN | |
| AndroidBootImgGetChosenNode ( | |
| IN INTN UpdatedFdtBase | |
| ) | |
| { | |
| INTN ChosenNode; | |
| ChosenNode = FdtSubnodeOffset ((CONST VOID *)UpdatedFdtBase, 0, "chosen"); | |
| if (ChosenNode < 0) { | |
| ChosenNode = FdtAddSubnode ((VOID *)UpdatedFdtBase, 0, "chosen"); | |
| if (ChosenNode < 0) { | |
| DEBUG ((DEBUG_ERROR, "Fail to find fdt node chosen!\n")); | |
| return 0; | |
| } | |
| } | |
| return ChosenNode; | |
| } | |
| EFI_STATUS | |
| AndroidBootImgSetProperty64 ( | |
| IN INTN UpdatedFdtBase, | |
| IN INTN ChosenNode, | |
| IN CHAR8 *PropertyName, | |
| IN UINT64 Val | |
| ) | |
| { | |
| INTN Err; | |
| CONST FDT_PROPERTY *Property; | |
| int Len; | |
| Property = FdtGetPropertyW ( | |
| (VOID *)UpdatedFdtBase, | |
| ChosenNode, | |
| PropertyName, | |
| &Len | |
| ); | |
| if ((NULL == Property) && (Len == -FDT_ERR_NOTFOUND)) { | |
| Val = CpuToFdt64 (Val); | |
| Err = FdtAppendProp ( | |
| (VOID *)UpdatedFdtBase, | |
| ChosenNode, | |
| PropertyName, | |
| &Val, | |
| sizeof (UINT64) | |
| ); | |
| if (Err) { | |
| DEBUG ((DEBUG_ERROR, "FdtAppendProp() fail: %a\n", FdtStrerror (Err))); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| } else if (Property != NULL) { | |
| Err = FdtSetPropU64 ( | |
| (VOID *)UpdatedFdtBase, | |
| ChosenNode, | |
| PropertyName, | |
| Val | |
| ); | |
| if (Err) { | |
| DEBUG ((DEBUG_ERROR, "FdtSetpropU64() fail: %a\n", FdtStrerror (Err))); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| } else { | |
| DEBUG ((DEBUG_ERROR, "Failed to set fdt Property %a\n", PropertyName)); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| AndroidBootImgUpdateFdt ( | |
| IN VOID *BootImg, | |
| IN VOID *FdtBase, | |
| IN VOID *RamdiskData, | |
| IN UINTN RamdiskSize | |
| ) | |
| { | |
| INTN ChosenNode, Err, NewFdtSize; | |
| EFI_STATUS Status; | |
| EFI_PHYSICAL_ADDRESS UpdatedFdtBase, NewFdtBase; | |
| NewFdtSize = (UINTN)FdtTotalSize (FdtBase) | |
| + FDT_ADDITIONAL_ENTRIES_SIZE; | |
| Status = gBS->AllocatePages ( | |
| AllocateAnyPages, | |
| EfiBootServicesData, | |
| EFI_SIZE_TO_PAGES (NewFdtSize), | |
| &UpdatedFdtBase | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG (( | |
| DEBUG_WARN, | |
| "Warning: Failed to reallocate FDT, err %d.\n", | |
| Status | |
| )); | |
| return Status; | |
| } | |
| // Load the Original FDT tree into the new region | |
| Err = FdtOpenInto (FdtBase, (VOID *)(INTN)UpdatedFdtBase, NewFdtSize); | |
| if (Err) { | |
| DEBUG ((DEBUG_ERROR, "FdtOpenInto(): %a\n", FdtStrerror (Err))); | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Fdt_Exit; | |
| } | |
| if (FeaturePcdGet (PcdAndroidBootLoadFile2)) { | |
| Status = AndroidBootImgInstallLoadFile2 (RamdiskData, RamdiskSize); | |
| if (EFI_ERROR (Status)) { | |
| goto Fdt_Exit; | |
| } | |
| } else { | |
| ChosenNode = AndroidBootImgGetChosenNode (UpdatedFdtBase); | |
| if (!ChosenNode) { | |
| goto Fdt_Exit; | |
| } | |
| Status = AndroidBootImgSetProperty64 ( | |
| UpdatedFdtBase, | |
| ChosenNode, | |
| "linux,initrd-start", | |
| (UINTN)RamdiskData | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Fdt_Exit; | |
| } | |
| Status = AndroidBootImgSetProperty64 ( | |
| UpdatedFdtBase, | |
| ChosenNode, | |
| "linux,initrd-end", | |
| (UINTN)RamdiskData + RamdiskSize | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Fdt_Exit; | |
| } | |
| } | |
| if (mAndroidBootImg->UpdateDtb) { | |
| Status = mAndroidBootImg->UpdateDtb (UpdatedFdtBase, &NewFdtBase); | |
| if (EFI_ERROR (Status)) { | |
| goto Fdt_Exit; | |
| } | |
| } else { | |
| NewFdtBase = UpdatedFdtBase; | |
| } | |
| Status = gBS->InstallConfigurationTable ( | |
| &gFdtTableGuid, | |
| (VOID *)(UINTN)NewFdtBase | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| return EFI_SUCCESS; | |
| } | |
| Fdt_Exit: | |
| gBS->FreePages (UpdatedFdtBase, EFI_SIZE_TO_PAGES (NewFdtSize)); | |
| return Status; | |
| } | |
| EFI_STATUS | |
| AndroidBootImgBoot ( | |
| IN VOID *Buffer, | |
| IN UINTN BufferSize | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| VOID *Kernel; | |
| UINTN KernelSize; | |
| MEMORY_DEVICE_PATH KernelDevicePath; | |
| EFI_HANDLE ImageHandle; | |
| VOID *NewKernelArg; | |
| EFI_LOADED_IMAGE_PROTOCOL *ImageInfo; | |
| VOID *RamdiskData; | |
| UINTN RamdiskSize; | |
| IN VOID *FdtBase; | |
| if ((Buffer == NULL) || (BufferSize == 0)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| NewKernelArg = NULL; | |
| ImageHandle = NULL; | |
| Status = gBS->LocateProtocol ( | |
| &gAndroidBootImgProtocolGuid, | |
| NULL, | |
| (VOID **)&mAndroidBootImg | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Exit; | |
| } | |
| Status = AndroidBootImgGetKernelInfo ( | |
| Buffer, | |
| &Kernel, | |
| &KernelSize | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Exit; | |
| } | |
| Status = AndroidBootImgUpdateArgs (Buffer, &NewKernelArg); | |
| if (EFI_ERROR (Status)) { | |
| goto Exit; | |
| } | |
| Status = AndroidBootImgGetRamdiskInfo ( | |
| Buffer, | |
| &RamdiskData, | |
| &RamdiskSize | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Exit; | |
| } | |
| if (AndroidBootImgAcpiSupported ()) { | |
| Status = AndroidBootImgInstallLoadFile2 (RamdiskData, RamdiskSize); | |
| if (EFI_ERROR (Status)) { | |
| goto Exit; | |
| } | |
| } else { | |
| Status = AndroidBootImgLocateFdt (Buffer, &FdtBase); | |
| if (EFI_ERROR (Status)) { | |
| goto Exit; | |
| } | |
| Status = AndroidBootImgUpdateFdt (Buffer, FdtBase, RamdiskData, RamdiskSize); | |
| if (EFI_ERROR (Status)) { | |
| goto Exit; | |
| } | |
| } | |
| KernelDevicePath = mMemoryDevicePathTemplate; | |
| KernelDevicePath.Node1.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Kernel; | |
| KernelDevicePath.Node1.EndingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Kernel | |
| + KernelSize; | |
| Status = gBS->LoadImage ( | |
| TRUE, | |
| gImageHandle, | |
| (EFI_DEVICE_PATH *)&KernelDevicePath, | |
| (VOID *)(UINTN)Kernel, | |
| KernelSize, | |
| &ImageHandle | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Exit; | |
| } | |
| // Set kernel arguments | |
| Status = gBS->HandleProtocol ( | |
| ImageHandle, | |
| &gEfiLoadedImageProtocolGuid, | |
| (VOID **)&ImageInfo | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Exit; | |
| } | |
| ImageInfo->LoadOptions = NewKernelArg; | |
| ImageInfo->LoadOptionsSize = StrLen (NewKernelArg) * sizeof (CHAR16); | |
| // Before calling the image, enable the Watchdog Timer for the 5 Minute period | |
| gBS->SetWatchdogTimer (5 * 60, 0x10000, 0, NULL); | |
| // Start the image | |
| Status = gBS->StartImage (ImageHandle, NULL, NULL); | |
| // Clear the Watchdog Timer if the image returns | |
| gBS->SetWatchdogTimer (0, 0x10000, 0, NULL); | |
| Exit: | |
| // Unload image as it will not be used anymore | |
| if (ImageHandle != NULL) { | |
| gBS->UnloadImage (ImageHandle); | |
| ImageHandle = NULL; | |
| } | |
| if (EFI_ERROR (Status)) { | |
| if (NewKernelArg != NULL) { | |
| FreePool (NewKernelArg); | |
| NewKernelArg = NULL; | |
| } | |
| } | |
| AndroidBootImgUninstallLoadFile2 (); | |
| return Status; | |
| } |