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