3 Copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>
4 Copyright (c) 2017, Linaro. All rights reserved.
6 SPDX-License-Identifier: BSD-2-Clause-Patent
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>
17 #include <Protocol/AndroidBootImg.h>
18 #include <Protocol/LoadFile2.h>
19 #include <Protocol/LoadedImage.h>
21 #include <Guid/LinuxEfiInitrdMedia.h>
23 #define FDT_ADDITIONAL_ENTRIES_SIZE 0x400
26 MEMMAP_DEVICE_PATH Node1
;
27 EFI_DEVICE_PATH_PROTOCOL End
;
31 VENDOR_DEVICE_PATH VendorMediaNode
;
32 EFI_DEVICE_PATH_PROTOCOL EndNode
;
33 } RAMDISK_DEVICE_PATH
;
35 STATIC ANDROID_BOOTIMG_PROTOCOL
*mAndroidBootImg
;
36 STATIC VOID
*mRamdiskData
= NULL
;
37 STATIC UINTN mRamdiskSize
= 0;
38 STATIC EFI_HANDLE mRamDiskLoadFileHandle
= NULL
;
40 STATIC CONST MEMORY_DEVICE_PATH mMemoryDevicePathTemplate
=
47 (UINT8
)(sizeof (MEMMAP_DEVICE_PATH
)),
48 (UINT8
)((sizeof (MEMMAP_DEVICE_PATH
)) >> 8),
51 0, // StartingAddress (set at runtime)
52 0 // EndingAddress (set at runtime)
56 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
57 { sizeof (EFI_DEVICE_PATH_PROTOCOL
), 0 }
61 STATIC CONST RAMDISK_DEVICE_PATH mRamdiskDevicePath
=
67 { sizeof (VENDOR_DEVICE_PATH
), 0 }
69 LINUX_EFI_INITRD_MEDIA_GUID
73 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
74 { sizeof (EFI_DEVICE_PATH_PROTOCOL
), 0 }
79 Causes the driver to load a specified file.
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
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
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.
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
118 // Verify if the valid parameters
120 BufferSize
== NULL
||
122 !IsDevicePathValid (FilePath
, 0)) {
123 return EFI_INVALID_PARAMETER
;
127 return EFI_UNSUPPORTED
;
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
;
135 if (Buffer
== NULL
|| *BufferSize
< mRamdiskSize
) {
136 *BufferSize
= mRamdiskSize
;
137 return EFI_BUFFER_TOO_SMALL
;
141 CopyMem (Buffer
, mRamdiskData
, mRamdiskSize
);
142 *BufferSize
= mRamdiskSize
;
148 /// Load File Protocol instance
150 STATIC EFI_LOAD_FILE2_PROTOCOL mAndroidBootImgLoadFile2
= {
151 AndroidBootImgLoadFile2
155 AndroidBootImgGetImgSize (
160 ANDROID_BOOTIMG_HEADER
*Header
;
162 Header
= (ANDROID_BOOTIMG_HEADER
*) BootImg
;
164 if (AsciiStrnCmp ((CONST CHAR8
*)Header
->BootMagic
, ANDROID_BOOT_MAGIC
,
165 ANDROID_BOOT_MAGIC_LENGTH
) != 0) {
166 return EFI_INVALID_PARAMETER
;
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
));
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
) +
181 AndroidBootImgGetKernelInfo (
184 OUT UINTN
*KernelSize
187 ANDROID_BOOTIMG_HEADER
*Header
;
189 Header
= (ANDROID_BOOTIMG_HEADER
*) BootImg
;
191 if (AsciiStrnCmp ((CONST CHAR8
*)Header
->BootMagic
, ANDROID_BOOT_MAGIC
,
192 ANDROID_BOOT_MAGIC_LENGTH
) != 0) {
193 return EFI_INVALID_PARAMETER
;
196 if (Header
->KernelSize
== 0) {
197 return EFI_NOT_FOUND
;
200 ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header
->PageSize
));
202 *KernelSize
= Header
->KernelSize
;
203 *Kernel
= (VOID
*)((UINTN
)BootImg
+ Header
->PageSize
);
208 AndroidBootImgGetRamdiskInfo (
211 OUT UINTN
*RamdiskSize
214 ANDROID_BOOTIMG_HEADER
*Header
;
216 Header
= (ANDROID_BOOTIMG_HEADER
*)BootImg
;
218 if (AsciiStrnCmp ((CONST CHAR8
*)Header
->BootMagic
, ANDROID_BOOT_MAGIC
,
219 ANDROID_BOOT_MAGIC_LENGTH
) != 0) {
220 return EFI_INVALID_PARAMETER
;
223 ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header
->PageSize
));
225 *RamdiskSize
= Header
->RamdiskSize
;
227 if (Header
->RamdiskSize
!= 0) {
228 *Ramdisk
= (VOID
*)((INTN
)BootImg
230 + ALIGN_VALUE (Header
->KernelSize
, Header
->PageSize
));
236 AndroidBootImgGetSecondBootLoaderInfo (
239 OUT UINTN
*SecondSize
242 ANDROID_BOOTIMG_HEADER
*Header
;
244 Header
= (ANDROID_BOOTIMG_HEADER
*)BootImg
;
246 if (AsciiStrnCmp ((CONST CHAR8
*)Header
->BootMagic
, ANDROID_BOOT_MAGIC
,
247 ANDROID_BOOT_MAGIC_LENGTH
) != 0) {
248 return EFI_INVALID_PARAMETER
;
251 ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header
->PageSize
));
253 *SecondSize
= Header
->SecondStageBootloaderSize
;
255 if (Header
->SecondStageBootloaderSize
!= 0) {
256 *Second
= (VOID
*)((UINTN
)BootImg
258 + ALIGN_VALUE (Header
->KernelSize
, Header
->PageSize
)
259 + ALIGN_VALUE (Header
->RamdiskSize
, Header
->PageSize
));
265 AndroidBootImgGetKernelArgs (
267 OUT CHAR8
*KernelArgs
270 ANDROID_BOOTIMG_HEADER
*Header
;
272 Header
= (ANDROID_BOOTIMG_HEADER
*) BootImg
;
273 AsciiStrnCpyS (KernelArgs
, ANDROID_BOOTIMG_KERNEL_ARGS_SIZE
, Header
->KernelArgs
,
274 ANDROID_BOOTIMG_KERNEL_ARGS_SIZE
);
280 AndroidBootImgGetFdt (
285 UINTN SecondLoaderSize
;
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 (
299 AndroidBootImgUpdateArgs (
304 CHAR8 ImageKernelArgs
[ANDROID_BOOTIMG_KERNEL_ARGS_SIZE
];
307 // Get kernel arguments from Android boot image
308 Status
= AndroidBootImgGetKernelArgs (BootImg
, ImageKernelArgs
);
309 if (EFI_ERROR (Status
)) {
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
);
323 AndroidBootImgInstallLoadFile2 (
324 IN VOID
*RamdiskData
,
328 mRamDiskLoadFileHandle
= NULL
;
329 mRamdiskData
= RamdiskData
;
330 mRamdiskSize
= RamdiskSize
;
331 return gBS
->InstallMultipleProtocolInterfaces (
332 &mRamDiskLoadFileHandle
,
333 &gEfiLoadFile2ProtocolGuid
,
334 &mAndroidBootImgLoadFile2
,
335 &gEfiDevicePathProtocolGuid
,
342 AndroidBootImgUninstallLoadFile2 (
348 Status
= EFI_SUCCESS
;
351 if (mRamDiskLoadFileHandle
!= NULL
) {
352 Status
= gBS
->UninstallMultipleProtocolInterfaces (
353 mRamDiskLoadFileHandle
,
354 &gEfiLoadFile2ProtocolGuid
,
355 &mAndroidBootImgLoadFile2
,
356 &gEfiDevicePathProtocolGuid
,
360 mRamDiskLoadFileHandle
= NULL
;
365 BOOLEAN
AndroidBootImgAcpiSupported (
372 Status
= EfiGetSystemConfigurationTable (&gEfiAcpiTableGuid
, &AcpiTable
);
373 return !EFI_ERROR (Status
);
377 AndroidBootImgLocateFdt (
385 Status
= EfiGetSystemConfigurationTable (&gFdtTableGuid
, FdtBase
);
386 if (!EFI_ERROR (Status
)) {
390 Status
= AndroidBootImgGetFdt (BootImg
, FdtBase
);
391 if (EFI_ERROR (Status
)) {
394 Err
= fdt_check_header (*FdtBase
);
396 DEBUG ((DEBUG_ERROR
, "ERROR: Device Tree header not valid (Err:%d)\n",
398 return EFI_INVALID_PARAMETER
;
404 AndroidBootImgGetChosenNode (
405 IN INTN UpdatedFdtBase
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"));
422 AndroidBootImgSetProperty64 (
423 IN INTN UpdatedFdtBase
,
425 IN CHAR8
*PropertyName
,
430 struct fdt_property
*Property
;
433 Property
= fdt_get_property_w((VOID
*)UpdatedFdtBase
, ChosenNode
,
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
));
440 DEBUG ((DEBUG_ERROR
, "fdt_appendprop() fail: %a\n", fdt_strerror (Err
)));
441 return EFI_INVALID_PARAMETER
;
443 } else if (Property
!= NULL
) {
444 Err
= fdt_setprop_u64((VOID
*)UpdatedFdtBase
, ChosenNode
,
447 DEBUG ((DEBUG_ERROR
, "fdt_setprop_u64() fail: %a\n", fdt_strerror (Err
)));
448 return EFI_INVALID_PARAMETER
;
451 DEBUG ((DEBUG_ERROR
, "Failed to set fdt Property %a\n", PropertyName
));
452 return EFI_INVALID_PARAMETER
;
458 AndroidBootImgUpdateFdt (
461 IN VOID
*RamdiskData
,
465 INTN ChosenNode
, Err
, NewFdtSize
;
467 EFI_PHYSICAL_ADDRESS UpdatedFdtBase
, NewFdtBase
;
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",
479 // Load the Original FDT tree into the new region
480 Err
= fdt_open_into(FdtBase
, (VOID
*)(INTN
)UpdatedFdtBase
, NewFdtSize
);
482 DEBUG ((DEBUG_ERROR
, "fdt_open_into(): %a\n", fdt_strerror (Err
)));
483 Status
= EFI_INVALID_PARAMETER
;
487 if (FeaturePcdGet (PcdAndroidBootLoadFile2
)) {
488 Status
= AndroidBootImgInstallLoadFile2 (RamdiskData
, RamdiskSize
);
489 if (EFI_ERROR (Status
)) {
493 ChosenNode
= AndroidBootImgGetChosenNode(UpdatedFdtBase
);
498 Status
= AndroidBootImgSetProperty64 (UpdatedFdtBase
, ChosenNode
,
499 "linux,initrd-start",
501 if (EFI_ERROR (Status
)) {
505 Status
= AndroidBootImgSetProperty64 (UpdatedFdtBase
, ChosenNode
,
507 (UINTN
)RamdiskData
+ RamdiskSize
);
508 if (EFI_ERROR (Status
)) {
513 if (mAndroidBootImg
->UpdateDtb
) {
514 Status
= mAndroidBootImg
->UpdateDtb (UpdatedFdtBase
, &NewFdtBase
);
515 if (EFI_ERROR (Status
)) {
519 NewFdtBase
= UpdatedFdtBase
;
521 Status
= gBS
->InstallConfigurationTable (
523 (VOID
*)(UINTN
)NewFdtBase
526 if (!EFI_ERROR (Status
)) {
531 gBS
->FreePages (UpdatedFdtBase
, EFI_SIZE_TO_PAGES (NewFdtSize
));
544 MEMORY_DEVICE_PATH KernelDevicePath
;
545 EFI_HANDLE ImageHandle
;
547 EFI_LOADED_IMAGE_PROTOCOL
*ImageInfo
;
555 Status
= gBS
->LocateProtocol (&gAndroidBootImgProtocolGuid
, NULL
,
556 (VOID
**) &mAndroidBootImg
);
557 if (EFI_ERROR (Status
)) {
561 Status
= AndroidBootImgGetKernelInfo (
566 if (EFI_ERROR (Status
)) {
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
;
577 Status
= AndroidBootImgUpdateArgs (Buffer
, NewKernelArg
);
578 if (EFI_ERROR (Status
)) {
582 Status
= AndroidBootImgGetRamdiskInfo (
587 if (EFI_ERROR (Status
)) {
591 if (AndroidBootImgAcpiSupported ()) {
592 Status
= AndroidBootImgInstallLoadFile2 (RamdiskData
, RamdiskSize
);
593 if (EFI_ERROR (Status
)) {
597 Status
= AndroidBootImgLocateFdt (Buffer
, &FdtBase
);
598 if (EFI_ERROR (Status
)) {
602 Status
= AndroidBootImgUpdateFdt (Buffer
, FdtBase
, RamdiskData
, RamdiskSize
);
603 if (EFI_ERROR (Status
)) {
608 KernelDevicePath
= mMemoryDevicePathTemplate
;
610 KernelDevicePath
.Node1
.StartingAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
) Kernel
;
611 KernelDevicePath
.Node1
.EndingAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
) Kernel
614 Status
= gBS
->LoadImage (TRUE
, gImageHandle
,
615 (EFI_DEVICE_PATH
*)&KernelDevicePath
,
616 (VOID
*)(UINTN
)Kernel
, KernelSize
, &ImageHandle
);
617 if (EFI_ERROR (Status
)) {
621 // Set kernel arguments
622 Status
= gBS
->HandleProtocol (ImageHandle
, &gEfiLoadedImageProtocolGuid
,
623 (VOID
**) &ImageInfo
);
624 if (EFI_ERROR (Status
)) {
627 ImageInfo
->LoadOptions
= NewKernelArg
;
628 ImageInfo
->LoadOptionsSize
= StrLen (NewKernelArg
) * sizeof (CHAR16
);
630 // Before calling the image, enable the Watchdog Timer for the 5 Minute period
631 gBS
->SetWatchdogTimer (5 * 60, 0x10000, 0, NULL
);
633 Status
= gBS
->StartImage (ImageHandle
, NULL
, NULL
);
634 // Clear the Watchdog Timer if the image returns
635 gBS
->SetWatchdogTimer (0, 0x10000, 0, NULL
);
638 //Unload image as it will not be used anymore
639 if (ImageHandle
!= NULL
) {
640 gBS
->UnloadImage (ImageHandle
);
643 if (EFI_ERROR (Status
)) {
644 if (NewKernelArg
!= NULL
) {
645 FreePool (NewKernelArg
);
649 AndroidBootImgUninstallLoadFile2 ();