BootAndroidBootImg.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /** @file
  2. Copyright (c) 2013-2015, ARM Ltd. All rights reserved.<BR>
  3. SPDX-License-Identifier: BSD-2-Clause-Patent
  4. **/
  5. #include "AndroidFastbootApp.h"
  6. #include <Protocol/DevicePath.h>
  7. #include <Protocol/LoadedImage.h>
  8. #include <Library/DevicePathLib.h>
  9. #include <Library/UefiBootServicesTableLib.h>
  10. #include <Library/UefiLib.h>
  11. // Device Path representing an image in memory
  12. #pragma pack(1)
  13. typedef struct {
  14. MEMMAP_DEVICE_PATH Node1;
  15. EFI_DEVICE_PATH_PROTOCOL End;
  16. } MEMORY_DEVICE_PATH;
  17. #pragma pack()
  18. STATIC CONST MEMORY_DEVICE_PATH MemoryDevicePathTemplate =
  19. {
  20. {
  21. {
  22. HARDWARE_DEVICE_PATH,
  23. HW_MEMMAP_DP,
  24. {
  25. (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
  26. (UINT8)((sizeof (MEMMAP_DEVICE_PATH)) >> 8),
  27. },
  28. }, // Header
  29. 0, // StartingAddress (set at runtime)
  30. 0 // EndingAddress (set at runtime)
  31. }, // Node1
  32. {
  33. END_DEVICE_PATH_TYPE,
  34. END_ENTIRE_DEVICE_PATH_SUBTYPE,
  35. { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
  36. } // End
  37. };
  38. /**
  39. Start an EFI Application from a Device Path
  40. @param ParentImageHandle Handle of the calling image
  41. @param DevicePath Location of the EFI Application
  42. @retval EFI_SUCCESS All drivers have been connected
  43. @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found
  44. @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results.
  45. **/
  46. STATIC
  47. EFI_STATUS
  48. StartEfiApplication (
  49. IN EFI_HANDLE ParentImageHandle,
  50. IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
  51. IN UINTN LoadOptionsSize,
  52. IN VOID* LoadOptions
  53. )
  54. {
  55. EFI_STATUS Status;
  56. EFI_HANDLE ImageHandle;
  57. EFI_LOADED_IMAGE_PROTOCOL* LoadedImage;
  58. // Load the image from the device path with Boot Services function
  59. Status = gBS->LoadImage (TRUE, ParentImageHandle, DevicePath, NULL, 0,
  60. &ImageHandle);
  61. if (EFI_ERROR (Status)) {
  62. return Status;
  63. }
  64. // Passed LoadOptions to the EFI Application
  65. if (LoadOptionsSize != 0) {
  66. Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid,
  67. (VOID **) &LoadedImage);
  68. if (EFI_ERROR (Status)) {
  69. return Status;
  70. }
  71. LoadedImage->LoadOptionsSize = LoadOptionsSize;
  72. LoadedImage->LoadOptions = LoadOptions;
  73. }
  74. // Before calling the image, enable the Watchdog Timer for the 5 Minute period
  75. gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
  76. // Start the image
  77. Status = gBS->StartImage (ImageHandle, NULL, NULL);
  78. // Clear the Watchdog Timer after the image returns
  79. gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
  80. return Status;
  81. }
  82. EFI_STATUS
  83. BootAndroidBootImg (
  84. IN UINTN BufferSize,
  85. IN VOID *Buffer
  86. )
  87. {
  88. EFI_STATUS Status;
  89. CHAR8 KernelArgs[ANDROID_BOOTIMG_KERNEL_ARGS_SIZE];
  90. VOID *Kernel;
  91. UINTN KernelSize;
  92. VOID *Ramdisk;
  93. UINTN RamdiskSize;
  94. MEMORY_DEVICE_PATH KernelDevicePath;
  95. CHAR16 *LoadOptions, *NewLoadOptions;
  96. Status = ParseAndroidBootImg (
  97. Buffer,
  98. &Kernel,
  99. &KernelSize,
  100. &Ramdisk,
  101. &RamdiskSize,
  102. KernelArgs
  103. );
  104. if (EFI_ERROR (Status)) {
  105. return Status;
  106. }
  107. KernelDevicePath = MemoryDevicePathTemplate;
  108. // Have to cast to UINTN before casting to EFI_PHYSICAL_ADDRESS in order to
  109. // appease GCC.
  110. KernelDevicePath.Node1.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Kernel;
  111. KernelDevicePath.Node1.EndingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Kernel + KernelSize;
  112. // Initialize Linux command line
  113. LoadOptions = CatSPrint (NULL, L"%a", KernelArgs);
  114. if (LoadOptions == NULL) {
  115. return EFI_OUT_OF_RESOURCES;
  116. }
  117. if (RamdiskSize != 0) {
  118. NewLoadOptions = CatSPrint (LoadOptions, L" initrd=0x%x,0x%x",
  119. (UINTN)Ramdisk, RamdiskSize);
  120. FreePool (LoadOptions);
  121. if (NewLoadOptions == NULL) {
  122. return EFI_OUT_OF_RESOURCES;
  123. }
  124. LoadOptions = NewLoadOptions;
  125. }
  126. Status = StartEfiApplication (gImageHandle,
  127. (EFI_DEVICE_PATH_PROTOCOL *) &KernelDevicePath,
  128. StrSize (LoadOptions),
  129. LoadOptions);
  130. if (EFI_ERROR (Status)) {
  131. DEBUG ((EFI_D_ERROR, "Couldn't Boot Linux: %d\n", Status));
  132. Status = EFI_DEVICE_ERROR;
  133. goto FreeLoadOptions;
  134. }
  135. // If we got here we do a confused face because BootLinuxFdt returned,
  136. // reporting success.
  137. DEBUG ((EFI_D_ERROR, "WARNING: BdsBootLinuxFdt returned EFI_SUCCESS.\n"));
  138. return EFI_SUCCESS;
  139. FreeLoadOptions:
  140. FreePool (LoadOptions);
  141. return Status;
  142. }