]> git.proxmox.com Git - mirror_edk2.git/blob - EmbeddedPkg/Library/AndroidBootImgLib/AndroidBootImgLib.c
cc39fef4895c36583192bc46c64f9e137b5ced00
[mirror_edk2.git] / EmbeddedPkg / Library / AndroidBootImgLib / AndroidBootImgLib.c
1 /** @file
2
3 Copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>
4 Copyright (c) 2017, Linaro. All rights reserved.
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include <libfdt.h>
11 #include <Library/AndroidBootImgLib.h>
12 #include <Library/PrintLib.h>
13 #include <Library/DevicePathLib.h>
14 #include <Library/UefiBootServicesTableLib.h>
15 #include <Library/UefiLib.h>
16
17 #include <Protocol/AndroidBootImg.h>
18 #include <Protocol/LoadFile2.h>
19 #include <Protocol/LoadedImage.h>
20
21 #include <Guid/LinuxEfiInitrdMedia.h>
22
23 #define FDT_ADDITIONAL_ENTRIES_SIZE 0x400
24
25 typedef struct {
26 MEMMAP_DEVICE_PATH Node1;
27 EFI_DEVICE_PATH_PROTOCOL End;
28 } MEMORY_DEVICE_PATH;
29
30 typedef struct {
31 VENDOR_DEVICE_PATH VendorMediaNode;
32 EFI_DEVICE_PATH_PROTOCOL EndNode;
33 } RAMDISK_DEVICE_PATH;
34
35 STATIC ANDROID_BOOTIMG_PROTOCOL *mAndroidBootImg;
36 STATIC VOID *mRamdiskData = NULL;
37 STATIC UINTN mRamdiskSize = 0;
38 STATIC EFI_HANDLE mRamDiskLoadFileHandle = NULL;
39
40 STATIC CONST MEMORY_DEVICE_PATH mMemoryDevicePathTemplate =
41 {
42 {
43 {
44 HARDWARE_DEVICE_PATH,
45 HW_MEMMAP_DP,
46 {
47 (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
48 (UINT8)((sizeof (MEMMAP_DEVICE_PATH)) >> 8),
49 },
50 }, // Header
51 0, // StartingAddress (set at runtime)
52 0 // EndingAddress (set at runtime)
53 }, // Node1
54 {
55 END_DEVICE_PATH_TYPE,
56 END_ENTIRE_DEVICE_PATH_SUBTYPE,
57 { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
58 } // End
59 };
60
61 STATIC CONST RAMDISK_DEVICE_PATH mRamdiskDevicePath =
62 {
63 {
64 {
65 MEDIA_DEVICE_PATH,
66 MEDIA_VENDOR_DP,
67 { sizeof (VENDOR_DEVICE_PATH), 0 }
68 },
69 LINUX_EFI_INITRD_MEDIA_GUID
70 },
71 {
72 END_DEVICE_PATH_TYPE,
73 END_ENTIRE_DEVICE_PATH_SUBTYPE,
74 { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
75 }
76 };
77
78 /**
79 Causes the driver to load a specified file.
80
81 @param This Protocol instance pointer.
82 @param FilePath The device specific path of the file to load.
83 @param BootPolicy Should always be FALSE.
84 @param BufferSize On input the size of Buffer in bytes. On output with a return
85 code of EFI_SUCCESS, the amount of data transferred to
86 Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,
87 the size of Buffer required to retrieve the requested file.
88 @param Buffer The memory buffer to transfer the file to. IF Buffer is NULL,
89 then no the size of the requested file is returned in
90 BufferSize.
91
92 @retval EFI_SUCCESS The file was loaded.
93 @retval EFI_UNSUPPORTED BootPolicy is TRUE.
94 @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or
95 BufferSize is NULL.
96 @retval EFI_NO_MEDIA No medium was present to load the file.
97 @retval EFI_DEVICE_ERROR The file was not loaded due to a device error.
98 @retval EFI_NO_RESPONSE The remote system did not respond.
99 @retval EFI_NOT_FOUND The file was not found
100 @retval EFI_ABORTED The file load process was manually canceled.
101 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current
102 directory entry. BufferSize has been updated with
103 the size needed to complete the request.
104
105
106 **/
107 EFI_STATUS
108 EFIAPI
109 AndroidBootImgLoadFile2 (
110 IN EFI_LOAD_FILE2_PROTOCOL *This,
111 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
112 IN BOOLEAN BootPolicy,
113 IN OUT UINTN *BufferSize,
114 IN VOID *Buffer OPTIONAL
115 )
116
117 {
118 // Verify if the valid parameters
119 if (This == NULL ||
120 BufferSize == NULL ||
121 FilePath == NULL ||
122 !IsDevicePathValid (FilePath, 0)) {
123 return EFI_INVALID_PARAMETER;
124 }
125
126 if (BootPolicy) {
127 return EFI_UNSUPPORTED;
128 }
129
130 // Check if the given buffer size is big enough
131 // EFI_BUFFER_TOO_SMALL to allow caller to allocate a bigger buffer
132 if (mRamdiskSize == 0) {
133 return EFI_NOT_FOUND;
134 }
135 if (Buffer == NULL || *BufferSize < mRamdiskSize) {
136 *BufferSize = mRamdiskSize;
137 return EFI_BUFFER_TOO_SMALL;
138 }
139
140 // Copy InitRd
141 CopyMem (Buffer, mRamdiskData, mRamdiskSize);
142 *BufferSize = mRamdiskSize;
143
144 return EFI_SUCCESS;
145 }
146
147 ///
148 /// Load File Protocol instance
149 ///
150 STATIC EFI_LOAD_FILE2_PROTOCOL mAndroidBootImgLoadFile2 = {
151 AndroidBootImgLoadFile2
152 };
153
154 EFI_STATUS
155 AndroidBootImgGetImgSize (
156 IN VOID *BootImg,
157 OUT UINTN *ImgSize
158 )
159 {
160 ANDROID_BOOTIMG_HEADER *Header;
161
162 Header = (ANDROID_BOOTIMG_HEADER *) BootImg;
163
164 if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC,
165 ANDROID_BOOT_MAGIC_LENGTH) != 0) {
166 return EFI_INVALID_PARAMETER;
167 }
168
169 /* The page size is not specified, but it should be power of 2 at least */
170 ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize));
171
172 /* Get real size of abootimg */
173 *ImgSize = ALIGN_VALUE (Header->KernelSize, Header->PageSize) +
174 ALIGN_VALUE (Header->RamdiskSize, Header->PageSize) +
175 ALIGN_VALUE (Header->SecondStageBootloaderSize, Header->PageSize) +
176 Header->PageSize;
177 return EFI_SUCCESS;
178 }
179
180 EFI_STATUS
181 AndroidBootImgGetKernelInfo (
182 IN VOID *BootImg,
183 OUT VOID **Kernel,
184 OUT UINTN *KernelSize
185 )
186 {
187 ANDROID_BOOTIMG_HEADER *Header;
188
189 Header = (ANDROID_BOOTIMG_HEADER *) BootImg;
190
191 if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC,
192 ANDROID_BOOT_MAGIC_LENGTH) != 0) {
193 return EFI_INVALID_PARAMETER;
194 }
195
196 if (Header->KernelSize == 0) {
197 return EFI_NOT_FOUND;
198 }
199
200 ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize));
201
202 *KernelSize = Header->KernelSize;
203 *Kernel = (VOID *)((UINTN)BootImg + Header->PageSize);
204 return EFI_SUCCESS;
205 }
206
207 EFI_STATUS
208 AndroidBootImgGetRamdiskInfo (
209 IN VOID *BootImg,
210 OUT VOID **Ramdisk,
211 OUT UINTN *RamdiskSize
212 )
213 {
214 ANDROID_BOOTIMG_HEADER *Header;
215
216 Header = (ANDROID_BOOTIMG_HEADER *)BootImg;
217
218 if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC,
219 ANDROID_BOOT_MAGIC_LENGTH) != 0) {
220 return EFI_INVALID_PARAMETER;
221 }
222
223 ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize));
224
225 *RamdiskSize = Header->RamdiskSize;
226
227 if (Header->RamdiskSize != 0) {
228 *Ramdisk = (VOID *)((INTN)BootImg
229 + Header->PageSize
230 + ALIGN_VALUE (Header->KernelSize, Header->PageSize));
231 }
232 return EFI_SUCCESS;
233 }
234
235 EFI_STATUS
236 AndroidBootImgGetSecondBootLoaderInfo (
237 IN VOID *BootImg,
238 OUT VOID **Second,
239 OUT UINTN *SecondSize
240 )
241 {
242 ANDROID_BOOTIMG_HEADER *Header;
243
244 Header = (ANDROID_BOOTIMG_HEADER *)BootImg;
245
246 if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC,
247 ANDROID_BOOT_MAGIC_LENGTH) != 0) {
248 return EFI_INVALID_PARAMETER;
249 }
250
251 ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize));
252
253 *SecondSize = Header->SecondStageBootloaderSize;
254
255 if (Header->SecondStageBootloaderSize != 0) {
256 *Second = (VOID *)((UINTN)BootImg
257 + Header->PageSize
258 + ALIGN_VALUE (Header->KernelSize, Header->PageSize)
259 + ALIGN_VALUE (Header->RamdiskSize, Header->PageSize));
260 }
261 return EFI_SUCCESS;
262 }
263
264 EFI_STATUS
265 AndroidBootImgGetKernelArgs (
266 IN VOID *BootImg,
267 OUT CHAR8 *KernelArgs
268 )
269 {
270 ANDROID_BOOTIMG_HEADER *Header;
271
272 Header = (ANDROID_BOOTIMG_HEADER *) BootImg;
273 AsciiStrnCpyS (KernelArgs, ANDROID_BOOTIMG_KERNEL_ARGS_SIZE, Header->KernelArgs,
274 ANDROID_BOOTIMG_KERNEL_ARGS_SIZE);
275
276 return EFI_SUCCESS;
277 }
278
279 EFI_STATUS
280 AndroidBootImgGetFdt (
281 IN VOID *BootImg,
282 IN VOID **FdtBase
283 )
284 {
285 UINTN SecondLoaderSize;
286 EFI_STATUS Status;
287
288 /* Check whether FDT is located in second boot region as some vendor do so,
289 * because second loader is never used as far as I know. */
290 Status = AndroidBootImgGetSecondBootLoaderInfo (
291 BootImg,
292 FdtBase,
293 &SecondLoaderSize
294 );
295 return Status;
296 }
297
298 EFI_STATUS
299 AndroidBootImgUpdateArgs (
300 IN VOID *BootImg,
301 OUT VOID *KernelArgs
302 )
303 {
304 CHAR8 ImageKernelArgs[ANDROID_BOOTIMG_KERNEL_ARGS_SIZE];
305 EFI_STATUS Status;
306
307 // Get kernel arguments from Android boot image
308 Status = AndroidBootImgGetKernelArgs (BootImg, ImageKernelArgs);
309 if (EFI_ERROR (Status)) {
310 return Status;
311 }
312 AsciiStrToUnicodeStrS (ImageKernelArgs, KernelArgs,
313 ANDROID_BOOTIMG_KERNEL_ARGS_SIZE >> 1);
314 // Append platform kernel arguments
315 if(mAndroidBootImg->AppendArgs) {
316 Status = mAndroidBootImg->AppendArgs (KernelArgs,
317 ANDROID_BOOTIMG_KERNEL_ARGS_SIZE);
318 }
319 return Status;
320 }
321
322 EFI_STATUS
323 AndroidBootImgInstallLoadFile2 (
324 IN VOID *RamdiskData,
325 IN UINTN RamdiskSize
326 )
327 {
328 mRamDiskLoadFileHandle = NULL;
329 mRamdiskData = RamdiskData;
330 mRamdiskSize = RamdiskSize;
331 return gBS->InstallMultipleProtocolInterfaces (
332 &mRamDiskLoadFileHandle,
333 &gEfiLoadFile2ProtocolGuid,
334 &mAndroidBootImgLoadFile2,
335 &gEfiDevicePathProtocolGuid,
336 &mRamdiskDevicePath,
337 NULL
338 );
339 }
340
341 EFI_STATUS
342 AndroidBootImgUninstallLoadFile2 (
343 VOID
344 )
345 {
346 EFI_STATUS Status;
347
348 Status = EFI_SUCCESS;
349 mRamdiskData = NULL;
350 mRamdiskSize = 0;
351 if (mRamDiskLoadFileHandle != NULL) {
352 Status = gBS->UninstallMultipleProtocolInterfaces (
353 mRamDiskLoadFileHandle,
354 &gEfiLoadFile2ProtocolGuid,
355 &mAndroidBootImgLoadFile2,
356 &gEfiDevicePathProtocolGuid,
357 &mRamdiskDevicePath,
358 NULL
359 );
360 mRamDiskLoadFileHandle = NULL;
361 }
362 return Status;
363 }
364
365 BOOLEAN AndroidBootImgAcpiSupported (
366 VOID
367 )
368 {
369 EFI_STATUS Status;
370 VOID *AcpiTable;
371
372 Status = EfiGetSystemConfigurationTable (&gEfiAcpiTableGuid, &AcpiTable);
373 return !EFI_ERROR (Status);
374 }
375
376 EFI_STATUS
377 AndroidBootImgLocateFdt (
378 IN VOID *BootImg,
379 IN VOID **FdtBase
380 )
381 {
382 INTN Err;
383 EFI_STATUS Status;
384
385 Status = EfiGetSystemConfigurationTable (&gFdtTableGuid, FdtBase);
386 if (!EFI_ERROR (Status)) {
387 return EFI_SUCCESS;
388 }
389
390 Status = AndroidBootImgGetFdt (BootImg, FdtBase);
391 if (EFI_ERROR (Status)) {
392 return Status;
393 }
394 Err = fdt_check_header (*FdtBase);
395 if (Err != 0) {
396 DEBUG ((DEBUG_ERROR, "ERROR: Device Tree header not valid (Err:%d)\n",
397 Err));
398 return EFI_INVALID_PARAMETER;
399 }
400 return EFI_SUCCESS;
401 }
402
403 INTN
404 AndroidBootImgGetChosenNode (
405 IN INTN UpdatedFdtBase
406 )
407 {
408 INTN ChosenNode;
409
410 ChosenNode = fdt_subnode_offset ((CONST VOID *)UpdatedFdtBase, 0, "chosen");
411 if (ChosenNode < 0) {
412 ChosenNode = fdt_add_subnode((VOID *)UpdatedFdtBase, 0, "chosen");
413 if (ChosenNode < 0) {
414 DEBUG ((DEBUG_ERROR, "Fail to find fdt node chosen!\n"));
415 return 0;
416 }
417 }
418 return ChosenNode;
419 }
420
421 EFI_STATUS
422 AndroidBootImgSetProperty64 (
423 IN INTN UpdatedFdtBase,
424 IN INTN ChosenNode,
425 IN CHAR8 *PropertyName,
426 IN UINT64 Val
427 )
428 {
429 INTN Err;
430 struct fdt_property *Property;
431 int Len;
432
433 Property = fdt_get_property_w((VOID *)UpdatedFdtBase, ChosenNode,
434 PropertyName, &Len);
435 if (NULL == Property && Len == -FDT_ERR_NOTFOUND) {
436 Val = cpu_to_fdt64(Val);
437 Err = fdt_appendprop ((VOID *)UpdatedFdtBase, ChosenNode,
438 PropertyName, &Val, sizeof (UINT64));
439 if (Err) {
440 DEBUG ((DEBUG_ERROR, "fdt_appendprop() fail: %a\n", fdt_strerror (Err)));
441 return EFI_INVALID_PARAMETER;
442 }
443 } else if (Property != NULL) {
444 Err = fdt_setprop_u64((VOID *)UpdatedFdtBase, ChosenNode,
445 PropertyName, Val);
446 if (Err) {
447 DEBUG ((DEBUG_ERROR, "fdt_setprop_u64() fail: %a\n", fdt_strerror (Err)));
448 return EFI_INVALID_PARAMETER;
449 }
450 } else {
451 DEBUG ((DEBUG_ERROR, "Failed to set fdt Property %a\n", PropertyName));
452 return EFI_INVALID_PARAMETER;
453 }
454 return EFI_SUCCESS;
455 }
456
457 EFI_STATUS
458 AndroidBootImgUpdateFdt (
459 IN VOID *BootImg,
460 IN VOID *FdtBase,
461 IN VOID *RamdiskData,
462 IN UINTN RamdiskSize
463 )
464 {
465 INTN ChosenNode, Err, NewFdtSize;
466 EFI_STATUS Status;
467 EFI_PHYSICAL_ADDRESS UpdatedFdtBase, NewFdtBase;
468
469 NewFdtSize = (UINTN)fdt_totalsize (FdtBase)
470 + FDT_ADDITIONAL_ENTRIES_SIZE;
471 Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData,
472 EFI_SIZE_TO_PAGES (NewFdtSize), &UpdatedFdtBase);
473 if (EFI_ERROR (Status)) {
474 DEBUG ((DEBUG_WARN, "Warning: Failed to reallocate FDT, err %d.\n",
475 Status));
476 return Status;
477 }
478
479 // Load the Original FDT tree into the new region
480 Err = fdt_open_into(FdtBase, (VOID*)(INTN)UpdatedFdtBase, NewFdtSize);
481 if (Err) {
482 DEBUG ((DEBUG_ERROR, "fdt_open_into(): %a\n", fdt_strerror (Err)));
483 Status = EFI_INVALID_PARAMETER;
484 goto Fdt_Exit;
485 }
486
487 if (FeaturePcdGet (PcdAndroidBootLoadFile2)) {
488 Status = AndroidBootImgInstallLoadFile2 (RamdiskData, RamdiskSize);
489 if (EFI_ERROR (Status)) {
490 goto Fdt_Exit;
491 }
492 } else {
493 ChosenNode = AndroidBootImgGetChosenNode(UpdatedFdtBase);
494 if (!ChosenNode) {
495 goto Fdt_Exit;
496 }
497
498 Status = AndroidBootImgSetProperty64 (UpdatedFdtBase, ChosenNode,
499 "linux,initrd-start",
500 (UINTN)RamdiskData);
501 if (EFI_ERROR (Status)) {
502 goto Fdt_Exit;
503 }
504
505 Status = AndroidBootImgSetProperty64 (UpdatedFdtBase, ChosenNode,
506 "linux,initrd-end",
507 (UINTN)RamdiskData + RamdiskSize);
508 if (EFI_ERROR (Status)) {
509 goto Fdt_Exit;
510 }
511 }
512
513 if (mAndroidBootImg->UpdateDtb) {
514 Status = mAndroidBootImg->UpdateDtb (UpdatedFdtBase, &NewFdtBase);
515 if (EFI_ERROR (Status)) {
516 goto Fdt_Exit;
517 }
518 } else {
519 NewFdtBase = UpdatedFdtBase;
520 }
521 Status = gBS->InstallConfigurationTable (
522 &gFdtTableGuid,
523 (VOID *)(UINTN)NewFdtBase
524 );
525
526 if (!EFI_ERROR (Status)) {
527 return EFI_SUCCESS;
528 }
529
530 Fdt_Exit:
531 gBS->FreePages (UpdatedFdtBase, EFI_SIZE_TO_PAGES (NewFdtSize));
532 return Status;
533 }
534
535 EFI_STATUS
536 AndroidBootImgBoot (
537 IN VOID *Buffer,
538 IN UINTN BufferSize
539 )
540 {
541 EFI_STATUS Status;
542 VOID *Kernel;
543 UINTN KernelSize;
544 MEMORY_DEVICE_PATH KernelDevicePath;
545 EFI_HANDLE ImageHandle;
546 VOID *NewKernelArg;
547 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
548 VOID *RamdiskData;
549 UINTN RamdiskSize;
550 IN VOID *FdtBase;
551
552 NewKernelArg = NULL;
553 ImageHandle = NULL;
554
555 Status = gBS->LocateProtocol (&gAndroidBootImgProtocolGuid, NULL,
556 (VOID **) &mAndroidBootImg);
557 if (EFI_ERROR (Status)) {
558 goto Exit;
559 }
560
561 Status = AndroidBootImgGetKernelInfo (
562 Buffer,
563 &Kernel,
564 &KernelSize
565 );
566 if (EFI_ERROR (Status)) {
567 goto Exit;
568 }
569
570 NewKernelArg = AllocateZeroPool (ANDROID_BOOTIMG_KERNEL_ARGS_SIZE);
571 if (NewKernelArg == NULL) {
572 DEBUG ((DEBUG_ERROR, "Fail to allocate memory\n"));
573 Status = EFI_OUT_OF_RESOURCES;
574 goto Exit;
575 }
576
577 Status = AndroidBootImgUpdateArgs (Buffer, NewKernelArg);
578 if (EFI_ERROR (Status)) {
579 goto Exit;
580 }
581
582 Status = AndroidBootImgGetRamdiskInfo (
583 Buffer,
584 &RamdiskData,
585 &RamdiskSize
586 );
587 if (EFI_ERROR (Status)) {
588 goto Exit;
589 }
590
591 if (AndroidBootImgAcpiSupported ()) {
592 Status = AndroidBootImgInstallLoadFile2 (RamdiskData, RamdiskSize);
593 if (EFI_ERROR (Status)) {
594 goto Exit;
595 }
596 } else {
597 Status = AndroidBootImgLocateFdt (Buffer, &FdtBase);
598 if (EFI_ERROR (Status)) {
599 goto Exit;
600 }
601
602 Status = AndroidBootImgUpdateFdt (Buffer, FdtBase, RamdiskData, RamdiskSize);
603 if (EFI_ERROR (Status)) {
604 goto Exit;
605 }
606 }
607
608 KernelDevicePath = mMemoryDevicePathTemplate;
609
610 KernelDevicePath.Node1.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Kernel;
611 KernelDevicePath.Node1.EndingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Kernel
612 + KernelSize;
613
614 Status = gBS->LoadImage (TRUE, gImageHandle,
615 (EFI_DEVICE_PATH *)&KernelDevicePath,
616 (VOID*)(UINTN)Kernel, KernelSize, &ImageHandle);
617 if (EFI_ERROR (Status)) {
618 goto Exit;
619 }
620
621 // Set kernel arguments
622 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid,
623 (VOID **) &ImageInfo);
624 if (EFI_ERROR (Status)) {
625 goto Exit;
626 }
627 ImageInfo->LoadOptions = NewKernelArg;
628 ImageInfo->LoadOptionsSize = StrLen (NewKernelArg) * sizeof (CHAR16);
629
630 // Before calling the image, enable the Watchdog Timer for the 5 Minute period
631 gBS->SetWatchdogTimer (5 * 60, 0x10000, 0, NULL);
632 // Start the image
633 Status = gBS->StartImage (ImageHandle, NULL, NULL);
634 // Clear the Watchdog Timer if the image returns
635 gBS->SetWatchdogTimer (0, 0x10000, 0, NULL);
636
637 Exit:
638 //Unload image as it will not be used anymore
639 if (ImageHandle != NULL) {
640 gBS->UnloadImage (ImageHandle);
641 ImageHandle = NULL;
642 }
643 if (EFI_ERROR (Status)) {
644 if (NewKernelArg != NULL) {
645 FreePool (NewKernelArg);
646 NewKernelArg = NULL;
647 }
648 }
649 AndroidBootImgUninstallLoadFile2 ();
650 return Status;
651 }