AndroidBootImgLib.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. /** @file
  2. Copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>
  3. Copyright (c) 2017, Linaro. All rights reserved.
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include <libfdt.h>
  7. #include <Library/AndroidBootImgLib.h>
  8. #include <Library/PrintLib.h>
  9. #include <Library/UefiBootServicesTableLib.h>
  10. #include <Library/UefiLib.h>
  11. #include <Protocol/AndroidBootImg.h>
  12. #include <Protocol/LoadedImage.h>
  13. #include <libfdt.h>
  14. #define FDT_ADDITIONAL_ENTRIES_SIZE 0x400
  15. typedef struct {
  16. MEMMAP_DEVICE_PATH Node1;
  17. EFI_DEVICE_PATH_PROTOCOL End;
  18. } MEMORY_DEVICE_PATH;
  19. STATIC ANDROID_BOOTIMG_PROTOCOL *mAndroidBootImg;
  20. STATIC CONST MEMORY_DEVICE_PATH mMemoryDevicePathTemplate =
  21. {
  22. {
  23. {
  24. HARDWARE_DEVICE_PATH,
  25. HW_MEMMAP_DP,
  26. {
  27. (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
  28. (UINT8)((sizeof (MEMMAP_DEVICE_PATH)) >> 8),
  29. },
  30. }, // Header
  31. 0, // StartingAddress (set at runtime)
  32. 0 // EndingAddress (set at runtime)
  33. }, // Node1
  34. {
  35. END_DEVICE_PATH_TYPE,
  36. END_ENTIRE_DEVICE_PATH_SUBTYPE,
  37. { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
  38. } // End
  39. };
  40. EFI_STATUS
  41. AndroidBootImgGetImgSize (
  42. IN VOID *BootImg,
  43. OUT UINTN *ImgSize
  44. )
  45. {
  46. ANDROID_BOOTIMG_HEADER *Header;
  47. Header = (ANDROID_BOOTIMG_HEADER *) BootImg;
  48. if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC,
  49. ANDROID_BOOT_MAGIC_LENGTH) != 0) {
  50. return EFI_INVALID_PARAMETER;
  51. }
  52. /* The page size is not specified, but it should be power of 2 at least */
  53. ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize));
  54. /* Get real size of abootimg */
  55. *ImgSize = ALIGN_VALUE (Header->KernelSize, Header->PageSize) +
  56. ALIGN_VALUE (Header->RamdiskSize, Header->PageSize) +
  57. ALIGN_VALUE (Header->SecondStageBootloaderSize, Header->PageSize) +
  58. Header->PageSize;
  59. return EFI_SUCCESS;
  60. }
  61. EFI_STATUS
  62. AndroidBootImgGetKernelInfo (
  63. IN VOID *BootImg,
  64. OUT VOID **Kernel,
  65. OUT UINTN *KernelSize
  66. )
  67. {
  68. ANDROID_BOOTIMG_HEADER *Header;
  69. Header = (ANDROID_BOOTIMG_HEADER *) BootImg;
  70. if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC,
  71. ANDROID_BOOT_MAGIC_LENGTH) != 0) {
  72. return EFI_INVALID_PARAMETER;
  73. }
  74. if (Header->KernelSize == 0) {
  75. return EFI_NOT_FOUND;
  76. }
  77. ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize));
  78. *KernelSize = Header->KernelSize;
  79. *Kernel = BootImg + Header->PageSize;
  80. return EFI_SUCCESS;
  81. }
  82. EFI_STATUS
  83. AndroidBootImgGetRamdiskInfo (
  84. IN VOID *BootImg,
  85. OUT VOID **Ramdisk,
  86. OUT UINTN *RamdiskSize
  87. )
  88. {
  89. ANDROID_BOOTIMG_HEADER *Header;
  90. Header = (ANDROID_BOOTIMG_HEADER *)BootImg;
  91. if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC,
  92. ANDROID_BOOT_MAGIC_LENGTH) != 0) {
  93. return EFI_INVALID_PARAMETER;
  94. }
  95. ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize));
  96. *RamdiskSize = Header->RamdiskSize;
  97. if (Header->RamdiskSize != 0) {
  98. *Ramdisk = (VOID *)((INTN)BootImg
  99. + Header->PageSize
  100. + ALIGN_VALUE (Header->KernelSize, Header->PageSize));
  101. }
  102. return EFI_SUCCESS;
  103. }
  104. EFI_STATUS
  105. AndroidBootImgGetSecondBootLoaderInfo (
  106. IN VOID *BootImg,
  107. OUT VOID **Second,
  108. OUT UINTN *SecondSize
  109. )
  110. {
  111. ANDROID_BOOTIMG_HEADER *Header;
  112. Header = (ANDROID_BOOTIMG_HEADER *)BootImg;
  113. if (AsciiStrnCmp ((CONST CHAR8 *)Header->BootMagic, ANDROID_BOOT_MAGIC,
  114. ANDROID_BOOT_MAGIC_LENGTH) != 0) {
  115. return EFI_INVALID_PARAMETER;
  116. }
  117. ASSERT (IS_VALID_ANDROID_PAGE_SIZE (Header->PageSize));
  118. *SecondSize = Header->SecondStageBootloaderSize;
  119. if (Header->SecondStageBootloaderSize != 0) {
  120. *Second = (VOID *)((UINTN)BootImg
  121. + Header->PageSize
  122. + ALIGN_VALUE (Header->KernelSize, Header->PageSize)
  123. + ALIGN_VALUE (Header->RamdiskSize, Header->PageSize));
  124. }
  125. return EFI_SUCCESS;
  126. }
  127. EFI_STATUS
  128. AndroidBootImgGetKernelArgs (
  129. IN VOID *BootImg,
  130. OUT CHAR8 *KernelArgs
  131. )
  132. {
  133. ANDROID_BOOTIMG_HEADER *Header;
  134. Header = (ANDROID_BOOTIMG_HEADER *) BootImg;
  135. AsciiStrnCpyS (KernelArgs, ANDROID_BOOTIMG_KERNEL_ARGS_SIZE, Header->KernelArgs,
  136. ANDROID_BOOTIMG_KERNEL_ARGS_SIZE);
  137. return EFI_SUCCESS;
  138. }
  139. EFI_STATUS
  140. AndroidBootImgGetFdt (
  141. IN VOID *BootImg,
  142. IN VOID **FdtBase
  143. )
  144. {
  145. UINTN SecondLoaderSize;
  146. EFI_STATUS Status;
  147. /* Check whether FDT is located in second boot region as some vendor do so,
  148. * because second loader is never used as far as I know. */
  149. Status = AndroidBootImgGetSecondBootLoaderInfo (
  150. BootImg,
  151. FdtBase,
  152. &SecondLoaderSize
  153. );
  154. return Status;
  155. }
  156. EFI_STATUS
  157. AndroidBootImgUpdateArgs (
  158. IN VOID *BootImg,
  159. OUT VOID *KernelArgs
  160. )
  161. {
  162. CHAR8 ImageKernelArgs[ANDROID_BOOTIMG_KERNEL_ARGS_SIZE];
  163. EFI_STATUS Status;
  164. // Get kernel arguments from Android boot image
  165. Status = AndroidBootImgGetKernelArgs (BootImg, ImageKernelArgs);
  166. if (EFI_ERROR (Status)) {
  167. return Status;
  168. }
  169. AsciiStrToUnicodeStrS (ImageKernelArgs, KernelArgs,
  170. ANDROID_BOOTIMG_KERNEL_ARGS_SIZE >> 1);
  171. // Append platform kernel arguments
  172. if(mAndroidBootImg->AppendArgs) {
  173. Status = mAndroidBootImg->AppendArgs (KernelArgs,
  174. ANDROID_BOOTIMG_KERNEL_ARGS_SIZE);
  175. }
  176. return Status;
  177. }
  178. EFI_STATUS
  179. AndroidBootImgLocateFdt (
  180. IN VOID *BootImg,
  181. IN VOID **FdtBase
  182. )
  183. {
  184. INTN Err;
  185. EFI_STATUS Status;
  186. Status = EfiGetSystemConfigurationTable (&gFdtTableGuid, FdtBase);
  187. if (!EFI_ERROR (Status)) {
  188. return EFI_SUCCESS;
  189. }
  190. Status = AndroidBootImgGetFdt (BootImg, FdtBase);
  191. if (EFI_ERROR (Status)) {
  192. return Status;
  193. }
  194. Err = fdt_check_header (*FdtBase);
  195. if (Err != 0) {
  196. DEBUG ((DEBUG_ERROR, "ERROR: Device Tree header not valid (Err:%d)\n",
  197. Err));
  198. return EFI_INVALID_PARAMETER;
  199. }
  200. return EFI_SUCCESS;
  201. }
  202. INTN
  203. AndroidBootImgGetChosenNode (
  204. IN INTN UpdatedFdtBase
  205. )
  206. {
  207. INTN ChosenNode;
  208. ChosenNode = fdt_subnode_offset ((CONST VOID *)UpdatedFdtBase, 0, "chosen");
  209. if (ChosenNode < 0) {
  210. ChosenNode = fdt_add_subnode((VOID *)UpdatedFdtBase, 0, "chosen");
  211. if (ChosenNode < 0) {
  212. DEBUG ((DEBUG_ERROR, "Fail to find fdt node chosen!\n"));
  213. return 0;
  214. }
  215. }
  216. return ChosenNode;
  217. }
  218. EFI_STATUS
  219. AndroidBootImgSetProperty64 (
  220. IN INTN UpdatedFdtBase,
  221. IN INTN ChosenNode,
  222. IN CHAR8 *PropertyName,
  223. IN UINT64 Val
  224. )
  225. {
  226. INTN Err;
  227. struct fdt_property *Property;
  228. int Len;
  229. Property = fdt_get_property_w((VOID *)UpdatedFdtBase, ChosenNode,
  230. PropertyName, &Len);
  231. if (NULL == Property && Len == -FDT_ERR_NOTFOUND) {
  232. Val = cpu_to_fdt64(Val);
  233. Err = fdt_appendprop ((VOID *)UpdatedFdtBase, ChosenNode,
  234. PropertyName, &Val, sizeof (UINT64));
  235. if (Err) {
  236. DEBUG ((DEBUG_ERROR, "fdt_appendprop() fail: %a\n", fdt_strerror (Err)));
  237. return EFI_INVALID_PARAMETER;
  238. }
  239. } else if (Property != NULL) {
  240. Err = fdt_setprop_u64((VOID *)UpdatedFdtBase, ChosenNode,
  241. PropertyName, Val);
  242. if (Err) {
  243. DEBUG ((DEBUG_ERROR, "fdt_setprop_u64() fail: %a\n", fdt_strerror (Err)));
  244. return EFI_INVALID_PARAMETER;
  245. }
  246. } else {
  247. DEBUG ((DEBUG_ERROR, "Failed to set fdt Property %a\n", PropertyName));
  248. return EFI_INVALID_PARAMETER;
  249. }
  250. return EFI_SUCCESS;
  251. }
  252. EFI_STATUS
  253. AndroidBootImgUpdateFdt (
  254. IN VOID *BootImg,
  255. IN VOID *FdtBase,
  256. IN VOID *RamdiskData,
  257. IN UINTN RamdiskSize
  258. )
  259. {
  260. INTN ChosenNode, Err, NewFdtSize;
  261. EFI_STATUS Status;
  262. EFI_PHYSICAL_ADDRESS UpdatedFdtBase, NewFdtBase;
  263. NewFdtSize = (UINTN)fdt_totalsize (FdtBase)
  264. + FDT_ADDITIONAL_ENTRIES_SIZE;
  265. Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData,
  266. EFI_SIZE_TO_PAGES (NewFdtSize), &UpdatedFdtBase);
  267. if (EFI_ERROR (Status)) {
  268. DEBUG ((DEBUG_WARN, "Warning: Failed to reallocate FDT, err %d.\n",
  269. Status));
  270. return Status;
  271. }
  272. // Load the Original FDT tree into the new region
  273. Err = fdt_open_into(FdtBase, (VOID*)(INTN)UpdatedFdtBase, NewFdtSize);
  274. if (Err) {
  275. DEBUG ((DEBUG_ERROR, "fdt_open_into(): %a\n", fdt_strerror (Err)));
  276. Status = EFI_INVALID_PARAMETER;
  277. goto Fdt_Exit;
  278. }
  279. ChosenNode = AndroidBootImgGetChosenNode(UpdatedFdtBase);
  280. if (!ChosenNode) {
  281. goto Fdt_Exit;
  282. }
  283. Status = AndroidBootImgSetProperty64 (UpdatedFdtBase, ChosenNode,
  284. "linux,initrd-start",
  285. (UINTN)RamdiskData);
  286. if (EFI_ERROR (Status)) {
  287. goto Fdt_Exit;
  288. }
  289. Status = AndroidBootImgSetProperty64 (UpdatedFdtBase, ChosenNode,
  290. "linux,initrd-end",
  291. (UINTN)(RamdiskData + RamdiskSize));
  292. if (EFI_ERROR (Status)) {
  293. goto Fdt_Exit;
  294. }
  295. if (mAndroidBootImg->UpdateDtb) {
  296. Status = mAndroidBootImg->UpdateDtb (UpdatedFdtBase, &NewFdtBase);
  297. if (EFI_ERROR (Status)) {
  298. goto Fdt_Exit;
  299. }
  300. Status = gBS->InstallConfigurationTable (
  301. &gFdtTableGuid,
  302. (VOID *)(UINTN)NewFdtBase
  303. );
  304. }
  305. if (!EFI_ERROR (Status)) {
  306. return EFI_SUCCESS;
  307. }
  308. Fdt_Exit:
  309. gBS->FreePages (UpdatedFdtBase, EFI_SIZE_TO_PAGES (NewFdtSize));
  310. return Status;
  311. }
  312. EFI_STATUS
  313. AndroidBootImgBoot (
  314. IN VOID *Buffer,
  315. IN UINTN BufferSize
  316. )
  317. {
  318. EFI_STATUS Status;
  319. VOID *Kernel;
  320. UINTN KernelSize;
  321. MEMORY_DEVICE_PATH KernelDevicePath;
  322. EFI_HANDLE ImageHandle;
  323. VOID *NewKernelArg;
  324. EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
  325. VOID *RamdiskData;
  326. UINTN RamdiskSize;
  327. IN VOID *FdtBase;
  328. Status = gBS->LocateProtocol (&gAndroidBootImgProtocolGuid, NULL,
  329. (VOID **) &mAndroidBootImg);
  330. if (EFI_ERROR (Status)) {
  331. return Status;
  332. }
  333. Status = AndroidBootImgGetKernelInfo (
  334. Buffer,
  335. &Kernel,
  336. &KernelSize
  337. );
  338. if (EFI_ERROR (Status)) {
  339. return Status;
  340. }
  341. NewKernelArg = AllocateZeroPool (ANDROID_BOOTIMG_KERNEL_ARGS_SIZE);
  342. if (NewKernelArg == NULL) {
  343. DEBUG ((DEBUG_ERROR, "Fail to allocate memory\n"));
  344. return EFI_OUT_OF_RESOURCES;
  345. }
  346. Status = AndroidBootImgUpdateArgs (Buffer, NewKernelArg);
  347. if (EFI_ERROR (Status)) {
  348. FreePool (NewKernelArg);
  349. return Status;
  350. }
  351. Status = AndroidBootImgGetRamdiskInfo (
  352. Buffer,
  353. &RamdiskData,
  354. &RamdiskSize
  355. );
  356. if (EFI_ERROR (Status)) {
  357. return Status;
  358. }
  359. Status = AndroidBootImgLocateFdt (Buffer, &FdtBase);
  360. if (EFI_ERROR (Status)) {
  361. FreePool (NewKernelArg);
  362. return Status;
  363. }
  364. Status = AndroidBootImgUpdateFdt (Buffer, FdtBase, RamdiskData, RamdiskSize);
  365. if (EFI_ERROR (Status)) {
  366. FreePool (NewKernelArg);
  367. return Status;
  368. }
  369. KernelDevicePath = mMemoryDevicePathTemplate;
  370. KernelDevicePath.Node1.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Kernel;
  371. KernelDevicePath.Node1.EndingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Kernel
  372. + KernelSize;
  373. Status = gBS->LoadImage (TRUE, gImageHandle,
  374. (EFI_DEVICE_PATH *)&KernelDevicePath,
  375. (VOID*)(UINTN)Kernel, KernelSize, &ImageHandle);
  376. // Set kernel arguments
  377. Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid,
  378. (VOID **) &ImageInfo);
  379. ImageInfo->LoadOptions = NewKernelArg;
  380. ImageInfo->LoadOptionsSize = StrLen (NewKernelArg) * sizeof (CHAR16);
  381. // Before calling the image, enable the Watchdog Timer for the 5 Minute period
  382. gBS->SetWatchdogTimer (5 * 60, 0x10000, 0, NULL);
  383. // Start the image
  384. Status = gBS->StartImage (ImageHandle, NULL, NULL);
  385. // Clear the Watchdog Timer if the image returns
  386. gBS->SetWatchdogTimer (0, 0x10000, 0, NULL);
  387. return EFI_SUCCESS;
  388. }