RunAxf.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. /** @file
  2. *
  3. * Shell command for launching AXF files.
  4. *
  5. * Copyright (c) 2014 - 2020, ARM Limited. All rights reserved.
  6. *
  7. * SPDX-License-Identifier: BSD-2-Clause-Patent
  8. *
  9. **/
  10. #include <Guid/GlobalVariable.h>
  11. #include <Library/CacheMaintenanceLib.h>
  12. #include <Library/PrintLib.h>
  13. #include <Library/HandleParsingLib.h>
  14. #include <Library/DevicePathLib.h>
  15. #include <Library/BaseLib.h>
  16. #include <Library/BaseMemoryLib.h>
  17. #include <Library/MemoryAllocationLib.h>
  18. #include <Library/DebugLib.h>
  19. #include <Library/ArmLib.h>
  20. #include <Protocol/LoadedImage.h>
  21. #include "ArmShellCmdRunAxf.h"
  22. #include "ElfLoader.h"
  23. #include "BootMonFsLoader.h"
  24. // Provide arguments to AXF?
  25. typedef VOID (*ELF_ENTRYPOINT)(UINTN arg0, UINTN arg1,
  26. UINTN arg2, UINTN arg3);
  27. STATIC
  28. EFI_STATUS
  29. ShutdownUefiBootServices (
  30. VOID
  31. )
  32. {
  33. EFI_STATUS Status;
  34. UINTN MemoryMapSize;
  35. EFI_MEMORY_DESCRIPTOR *MemoryMap;
  36. UINTN MapKey;
  37. UINTN DescriptorSize;
  38. UINT32 DescriptorVersion;
  39. UINTN Pages;
  40. MemoryMap = NULL;
  41. MemoryMapSize = 0;
  42. Pages = 0;
  43. do {
  44. Status = gBS->GetMemoryMap (
  45. &MemoryMapSize,
  46. MemoryMap,
  47. &MapKey,
  48. &DescriptorSize,
  49. &DescriptorVersion
  50. );
  51. if (Status == EFI_BUFFER_TOO_SMALL) {
  52. Pages = EFI_SIZE_TO_PAGES (MemoryMapSize) + 1;
  53. MemoryMap = AllocatePages (Pages);
  54. //
  55. // Get System MemoryMap
  56. //
  57. Status = gBS->GetMemoryMap (
  58. &MemoryMapSize,
  59. MemoryMap,
  60. &MapKey,
  61. &DescriptorSize,
  62. &DescriptorVersion
  63. );
  64. }
  65. // Don't do anything between the GetMemoryMap() and ExitBootServices()
  66. if (!EFI_ERROR(Status)) {
  67. Status = gBS->ExitBootServices (gImageHandle, MapKey);
  68. if (EFI_ERROR(Status)) {
  69. FreePages (MemoryMap, Pages);
  70. MemoryMap = NULL;
  71. MemoryMapSize = 0;
  72. }
  73. }
  74. } while (EFI_ERROR(Status));
  75. return Status;
  76. }
  77. // Process arguments to pass to AXF?
  78. STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
  79. {NULL, TypeMax}
  80. };
  81. VOID
  82. RunAxfPivot (
  83. IN ELF_ENTRYPOINT ElfEntry,
  84. IN UINTN Arg0,
  85. IN UINTN Arg1,
  86. IN UINTN Arg2,
  87. IN UINTN Arg3
  88. );
  89. /**
  90. This is the shell command handler function pointer callback type. This
  91. function handles the command when it is invoked in the shell.
  92. @param[in] This The instance of the
  93. EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
  94. @param[in] SystemTable The pointer to the system table.
  95. @param[in] ShellParameters The parameters associated with the command.
  96. @param[in] Shell The instance of the shell protocol used in the
  97. context of processing this command.
  98. @return EFI_SUCCESS The operation was successful.
  99. @return other The operation failed.
  100. **/
  101. SHELL_STATUS
  102. EFIAPI
  103. ShellDynCmdRunAxfHandler (
  104. IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This,
  105. IN EFI_SYSTEM_TABLE *SystemTable,
  106. IN EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters,
  107. IN EFI_SHELL_PROTOCOL *Shell
  108. )
  109. {
  110. LIST_ENTRY *ParamPackage;
  111. EFI_STATUS Status;
  112. SHELL_STATUS ShellStatus;
  113. SHELL_FILE_HANDLE FileHandle;
  114. ELF_ENTRYPOINT StartElf;
  115. CONST CHAR16 *FileName;
  116. EFI_FILE_INFO *Info;
  117. UINTN FileSize;
  118. VOID *FileData;
  119. VOID *Entrypoint;
  120. LIST_ENTRY LoadList;
  121. LIST_ENTRY *Node;
  122. LIST_ENTRY *NextNode;
  123. RUNAXF_LOAD_LIST *LoadNode;
  124. CHAR16 *TmpFileName;
  125. CHAR16 *TmpChar16;
  126. EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
  127. ShellStatus = SHELL_SUCCESS;
  128. FileHandle = NULL;
  129. FileData = NULL;
  130. InitializeListHead (&LoadList);
  131. // Only install if they are not there yet? First time or every time?
  132. // These can change if the shell exits and start again.
  133. Status = gBS->InstallMultipleProtocolInterfaces (&gImageHandle,
  134. &gEfiShellProtocolGuid, Shell,
  135. &gEfiShellParametersProtocolGuid, ShellParameters,
  136. NULL);
  137. if (EFI_ERROR (Status)) {
  138. return SHELL_DEVICE_ERROR;
  139. }
  140. // Update the protocols for the application library
  141. Status = ShellInitialize ();
  142. ASSERT_EFI_ERROR (Status);
  143. // Add support to load AXF with optipnal args?
  144. //
  145. // Process Command Line arguments
  146. //
  147. Status = ShellCommandLineParse (ParamList, &ParamPackage, NULL, TRUE);
  148. if (EFI_ERROR (Status)) {
  149. ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_RUNAXF_INVALID_ARG), gRunAxfHiiHandle);
  150. ShellStatus = SHELL_INVALID_PARAMETER;
  151. } else {
  152. //
  153. // Check for "-?"
  154. //
  155. if ((ShellCommandLineGetFlag (ParamPackage, L"-?")) ||
  156. (ShellCommandLineGetRawValue (ParamPackage, 1) == NULL)) {
  157. //
  158. // We didn't get a file to load
  159. //
  160. ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_RUNAXF_INVALID_ARG), gRunAxfHiiHandle);
  161. ShellStatus = SHELL_INVALID_PARAMETER;
  162. } else {
  163. // For the moment we assume we only ever get one file to load with no arguments.
  164. FileName = ShellCommandLineGetRawValue (ParamPackage, 1);
  165. Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ, 0);
  166. if (EFI_ERROR (Status)) {
  167. // BootMonFS supports file extensions, but they are stripped by default
  168. // when the NOR is programmed.
  169. // Remove the file extension and try to open again.
  170. ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_RUNAXF_FILE_NOT_FOUND),
  171. gRunAxfHiiHandle, FileName);
  172. // Go through the filename and remove file extension. Preserve the
  173. // original name.
  174. TmpFileName = AllocateCopyPool (StrSize (FileName), (VOID *)FileName);
  175. if (TmpFileName != NULL) {
  176. TmpChar16 = StrStr (TmpFileName, L".");
  177. if (TmpChar16 != NULL) {
  178. *TmpChar16 = '\0';
  179. DEBUG((EFI_D_ERROR, "Trying to open file: %s\n", TmpFileName));
  180. Status = ShellOpenFileByName (TmpFileName, &FileHandle,
  181. EFI_FILE_MODE_READ, 0);
  182. }
  183. FreePool (TmpFileName);
  184. }
  185. // Do we now have an open file after trying again?
  186. if (EFI_ERROR (Status)) {
  187. ShellStatus = SHELL_INVALID_PARAMETER;
  188. FileHandle = NULL;
  189. }
  190. }
  191. if (FileHandle != NULL) {
  192. Info = ShellGetFileInfo (FileHandle);
  193. FileSize = (UINTN) Info->FileSize;
  194. FreePool (Info);
  195. //
  196. // Allocate buffer to read file. 'Runtime' so we can access it after
  197. // ExitBootServices().
  198. //
  199. FileData = AllocateRuntimeZeroPool (FileSize);
  200. if (FileData == NULL) {
  201. ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_RUNAXF_NO_MEM), gRunAxfHiiHandle);
  202. ShellStatus = SHELL_OUT_OF_RESOURCES;
  203. } else {
  204. //
  205. // Read file into Buffer
  206. //
  207. Status = ShellReadFile (FileHandle, &FileSize, FileData);
  208. if (EFI_ERROR (Status)) {
  209. ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_RUNAXF_READ_FAIL), gRunAxfHiiHandle);
  210. SHELL_FREE_NON_NULL (FileData);
  211. FileData = NULL;
  212. ShellStatus = SHELL_DEVICE_ERROR;
  213. }
  214. }
  215. }
  216. }
  217. //
  218. // Free the command line package
  219. //
  220. ShellCommandLineFreeVarList (ParamPackage);
  221. }
  222. // We have a file in memory. Try to work out if we can use it.
  223. // It can either be in ELF format or BootMonFS format.
  224. if (FileData != NULL) {
  225. // Do some validation on the file before we try to load it. The file can
  226. // either be an proper ELF file or one processed by the FlashLoader.
  227. // Since the data might need to go to various locations in memory we cannot
  228. // load the data directly while UEFI is running. We use the file loaders to
  229. // populate a linked list of data and load addresses. This is processed and
  230. // data copied to where it needs to go after calling ExitBootServices. At
  231. // that stage we've reached the point of no return, so overwriting UEFI code
  232. // does not make a difference.
  233. Status = ElfCheckFile (FileData);
  234. if (!EFI_ERROR (Status)) {
  235. // Load program into memory
  236. Status = ElfLoadFile ((VOID*)FileData, &Entrypoint, &LoadList);
  237. } else {
  238. // Try to see if it is a BootMonFs executable
  239. Status = BootMonFsCheckFile ((EFI_FILE_HANDLE)FileHandle);
  240. if (!EFI_ERROR (Status)) {
  241. // Load program into memory
  242. Status = BootMonFsLoadFile ((EFI_FILE_HANDLE)FileHandle,
  243. (VOID*)FileData, &Entrypoint, &LoadList);
  244. } else {
  245. ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_RUNAXF_BAD_FILE),
  246. gRunAxfHiiHandle);
  247. SHELL_FREE_NON_NULL (FileData);
  248. ShellStatus = SHELL_UNSUPPORTED;
  249. }
  250. }
  251. }
  252. WriteBackDataCacheRange (FileData, FileSize);
  253. InvalidateInstructionCacheRange (FileData, FileSize);
  254. // Program load list created.
  255. // Shutdown UEFI, copy and jump to code.
  256. if (!IsListEmpty (&LoadList) && !EFI_ERROR (Status)) {
  257. // Exit boot services here. This means we cannot return and cannot assume to
  258. // have access to UEFI functions.
  259. Status = ShutdownUefiBootServices ();
  260. if (EFI_ERROR (Status)) {
  261. DEBUG ((EFI_D_ERROR,"Can not shutdown UEFI boot services. Status=0x%X\n",
  262. Status));
  263. } else {
  264. // Process linked list. Copy data to Memory.
  265. Node = GetFirstNode (&LoadList);
  266. while (!IsNull (&LoadList, Node)) {
  267. LoadNode = (RUNAXF_LOAD_LIST *)Node;
  268. // Do we have data to copy or do we need to set Zeroes (.bss)?
  269. if (LoadNode->Zeroes) {
  270. ZeroMem ((VOID*)LoadNode->MemOffset, LoadNode->Length);
  271. } else {
  272. CopyMem ((VOID *)LoadNode->MemOffset, (VOID *)LoadNode->FileOffset,
  273. LoadNode->Length);
  274. }
  275. Node = GetNextNode (&LoadList, Node);
  276. }
  277. Status = gBS->HandleProtocol (gImageHandle, &gEfiLoadedImageProtocolGuid,
  278. (VOID **)&LoadedImage);
  279. ASSERT_EFI_ERROR (Status);
  280. //
  281. // Ensure that the currently running image is clean to the PoC so we can
  282. // safely keep executing it with the MMU and caches off
  283. //
  284. WriteBackDataCacheRange (LoadedImage->ImageBase, LoadedImage->ImageSize);
  285. StartElf = (ELF_ENTRYPOINT)Entrypoint;
  286. RunAxfPivot (StartElf, 0, 0, 0, 0);
  287. // We should never get here.. But if we do, spin..
  288. ASSERT (FALSE);
  289. while (1);
  290. }
  291. }
  292. // Free file related information as we are returning to UEFI.
  293. Node = GetFirstNode (&LoadList);
  294. while (!IsNull (&LoadList, Node)) {
  295. NextNode = RemoveEntryList (Node);
  296. FreePool (Node);
  297. Node = NextNode;
  298. }
  299. SHELL_FREE_NON_NULL (FileData);
  300. if (FileHandle != NULL) {
  301. ShellCloseFile (&FileHandle);
  302. }
  303. // Uninstall protocols as we don't know if they will change.
  304. // If the shell exits and come in again these mappings may be different
  305. // and cause a crash.
  306. Status = gBS->UninstallMultipleProtocolInterfaces (gImageHandle,
  307. &gEfiShellProtocolGuid, Shell,
  308. &gEfiShellParametersProtocolGuid, ShellParameters,
  309. NULL);
  310. if (EFI_ERROR (Status) && ShellStatus == SHELL_SUCCESS) {
  311. ShellStatus = SHELL_DEVICE_ERROR;
  312. }
  313. return ShellStatus;
  314. }
  315. /**
  316. This is the command help handler function pointer callback type. This
  317. function is responsible for displaying help information for the associated
  318. command.
  319. @param[in] This The instance of the
  320. EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
  321. @param[in] Language The pointer to the language string to use.
  322. @return string Pool allocated help string, must be freed by
  323. caller.
  324. **/
  325. CHAR16*
  326. EFIAPI
  327. ShellDynCmdRunAxfGetHelp (
  328. IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *This,
  329. IN CONST CHAR8 *Language
  330. )
  331. {
  332. CHAR16 *HelpText;
  333. ASSERT (gRunAxfHiiHandle != NULL);
  334. // This allocates memory. The caller is responsoible to free.
  335. HelpText = HiiGetString (gRunAxfHiiHandle, STRING_TOKEN (STR_GET_HELP_RUNAXF),
  336. Language);
  337. return HelpText;
  338. }