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