123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732 |
- /** @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 <libfdt.h>
- #include <Library/AndroidBootImgLib.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;
- // Get kernel arguments from Android boot image
- Status = AndroidBootImgGetKernelArgs (BootImg, ImageKernelArgs);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- AsciiStrToUnicodeStrS (
- ImageKernelArgs,
- KernelArgs,
- ANDROID_BOOTIMG_KERNEL_ARGS_SIZE >> 1
- );
- // Append platform kernel arguments
- if (mAndroidBootImg->AppendArgs) {
- Status = mAndroidBootImg->AppendArgs (
- KernelArgs,
- ANDROID_BOOTIMG_KERNEL_ARGS_SIZE
- );
- }
- 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 = fdt_check_header (*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 = fdt_subnode_offset ((CONST VOID *)UpdatedFdtBase, 0, "chosen");
- if (ChosenNode < 0) {
- ChosenNode = fdt_add_subnode ((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;
- struct fdt_property *Property;
- int Len;
- Property = fdt_get_property_w (
- (VOID *)UpdatedFdtBase,
- ChosenNode,
- PropertyName,
- &Len
- );
- if ((NULL == Property) && (Len == -FDT_ERR_NOTFOUND)) {
- Val = cpu_to_fdt64 (Val);
- Err = fdt_appendprop (
- (VOID *)UpdatedFdtBase,
- ChosenNode,
- PropertyName,
- &Val,
- sizeof (UINT64)
- );
- if (Err) {
- DEBUG ((DEBUG_ERROR, "fdt_appendprop() fail: %a\n", fdt_strerror (Err)));
- return EFI_INVALID_PARAMETER;
- }
- } else if (Property != NULL) {
- Err = fdt_setprop_u64 (
- (VOID *)UpdatedFdtBase,
- ChosenNode,
- PropertyName,
- Val
- );
- if (Err) {
- DEBUG ((DEBUG_ERROR, "fdt_setprop_u64() fail: %a\n", fdt_strerror (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)fdt_totalsize (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 = fdt_open_into (FdtBase, (VOID *)(INTN)UpdatedFdtBase, NewFdtSize);
- if (Err) {
- DEBUG ((DEBUG_ERROR, "fdt_open_into(): %a\n", fdt_strerror (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;
- 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;
- }
- NewKernelArg = AllocateZeroPool (ANDROID_BOOTIMG_KERNEL_ARGS_SIZE);
- if (NewKernelArg == NULL) {
- DEBUG ((DEBUG_ERROR, "Fail to allocate memory\n"));
- Status = EFI_OUT_OF_RESOURCES;
- 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;
- }
|