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