3 * Shell command for launching AXF files.
5 * Copyright (c) 2014, ARM Limited. All rights reserved.
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
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.
17 #include <Guid/GlobalVariable.h>
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/BdsLib.h>
25 #include <Library/MemoryAllocationLib.h>
26 #include <Library/DebugLib.h>
28 #include <Library/ArmLib.h>
30 #include "ArmShellCmdRunAxf.h"
31 #include "ElfLoader.h"
32 #include "BootMonFsLoader.h"
34 // Provide arguments to AXF?
35 typedef VOID (*ELF_ENTRYPOINT
)(UINTN arg0
, UINTN arg1
,
36 UINTN arg2
, UINTN arg3
);
41 PreparePlatformHardware (
45 //Note: Interrupts will be disabled by the GIC driver when ExitBootServices() will be called.
47 // Clean before Disable else the Stack gets corrupted with old data.
49 ArmDisableDataCache ();
50 // Invalidate all the entries that might have snuck in.
51 ArmInvalidateDataCache ();
53 // Disable and invalidate the instruction cache
54 ArmDisableInstructionCache ();
55 ArmInvalidateInstructionCache ();
63 // Process arguments to pass to AXF?
64 STATIC CONST SHELL_PARAM_ITEM ParamList
[] = {
70 This is the shell command handler function pointer callback type. This
71 function handles the command when it is invoked in the shell.
73 @param[in] This The instance of the
74 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
75 @param[in] SystemTable The pointer to the system table.
76 @param[in] ShellParameters The parameters associated with the command.
77 @param[in] Shell The instance of the shell protocol used in the
78 context of processing this command.
80 @return EFI_SUCCESS The operation was successful.
81 @return other The operation failed.
85 ShellDynCmdRunAxfHandler (
86 IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*This
,
87 IN EFI_SYSTEM_TABLE
*SystemTable
,
88 IN EFI_SHELL_PARAMETERS_PROTOCOL
*ShellParameters
,
89 IN EFI_SHELL_PROTOCOL
*Shell
92 LIST_ENTRY
*ParamPackage
;
94 SHELL_STATUS ShellStatus
;
95 SHELL_FILE_HANDLE FileHandle
;
96 ELF_ENTRYPOINT StartElf
;
97 CONST CHAR16
*FileName
;
104 LIST_ENTRY
*NextNode
;
105 RUNAXF_LOAD_LIST
*LoadNode
;
110 ShellStatus
= SHELL_SUCCESS
;
113 InitializeListHead (&LoadList
);
115 // Only install if they are not there yet? First time or every time?
116 // These can change if the shell exits and start again.
117 Status
= gBS
->InstallMultipleProtocolInterfaces (&gImageHandle
,
118 &gEfiShellProtocolGuid
, Shell
,
119 &gEfiShellParametersProtocolGuid
, ShellParameters
,
122 if (EFI_ERROR (Status
)) {
123 return SHELL_DEVICE_ERROR
;
126 // Update the protocols for the application library
127 Status
= ShellInitialize ();
128 ASSERT_EFI_ERROR (Status
);
129 // Add support to load AXF with optipnal args?
132 // Process Command Line arguments
134 Status
= ShellCommandLineParse (ParamList
, &ParamPackage
, NULL
, TRUE
);
135 if (EFI_ERROR (Status
)) {
136 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_RUNAXF_INVALID_ARG
), gRunAxfHiiHandle
);
137 ShellStatus
= SHELL_INVALID_PARAMETER
;
142 if ((ShellCommandLineGetFlag (ParamPackage
, L
"-?")) ||
143 (ShellCommandLineGetRawValue (ParamPackage
, 1) == NULL
)) {
145 // We didn't get a file to load
147 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_RUNAXF_INVALID_ARG
), gRunAxfHiiHandle
);
148 ShellStatus
= SHELL_INVALID_PARAMETER
;
150 // For the moment we assume we only ever get one file to load with no arguments.
151 FileName
= ShellCommandLineGetRawValue (ParamPackage
, 1);
152 Status
= ShellOpenFileByName (FileName
, &FileHandle
, EFI_FILE_MODE_READ
, 0);
153 if (EFI_ERROR (Status
)) {
154 // BootMonFS supports file extensions, but they are stripped by default
155 // when the NOR is programmed.
156 // Remove the file extension and try to open again.
157 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_RUNAXF_FILE_NOT_FOUND
),
158 gRunAxfHiiHandle
, FileName
);
159 // Go through the filename and remove file extension. Preserve the
161 TmpFileName
= AllocateCopyPool (StrSize (FileName
), (VOID
*)FileName
);
162 if (TmpFileName
!= NULL
) {
163 TmpChar16
= StrStr (TmpFileName
, L
".");
164 if (TmpChar16
!= NULL
) {
166 DEBUG((EFI_D_ERROR
, "Trying to open file: %s\n", TmpFileName
));
167 Status
= ShellOpenFileByName (TmpFileName
, &FileHandle
,
168 EFI_FILE_MODE_READ
, 0);
170 FreePool (TmpFileName
);
172 // Do we now have an open file after trying again?
173 if (EFI_ERROR (Status
)) {
174 ShellStatus
= SHELL_INVALID_PARAMETER
;
179 if (FileHandle
!= NULL
) {
180 Info
= ShellGetFileInfo (FileHandle
);
181 FileSize
= (UINTN
) Info
->FileSize
;
185 // Allocate buffer to read file. 'Runtime' so we can access it after
186 // ExitBootServices().
188 FileData
= AllocateRuntimeZeroPool (FileSize
);
189 if (FileData
== NULL
) {
190 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_RUNAXF_NO_MEM
), gRunAxfHiiHandle
);
191 ShellStatus
= SHELL_OUT_OF_RESOURCES
;
194 // Read file into Buffer
196 Status
= ShellReadFile (FileHandle
, &FileSize
, FileData
);
197 if (EFI_ERROR (Status
)) {
198 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_RUNAXF_READ_FAIL
), gRunAxfHiiHandle
);
199 SHELL_FREE_NON_NULL (FileData
);
201 ShellStatus
= SHELL_DEVICE_ERROR
;
208 // Free the command line package
210 ShellCommandLineFreeVarList (ParamPackage
);
213 // We have a file in memory. Try to work out if we can use it.
214 // It can either be in ELF format or BootMonFS format.
215 if (FileData
!= NULL
) {
216 // Do some validation on the file before we try to load it. The file can
217 // either be an proper ELF file or one processed by the FlashLoader.
218 // Since the data might need to go to various locations in memory we cannot
219 // load the data directly while UEFI is running. We use the file loaders to
220 // populate a linked list of data and load addresses. This is processed and
221 // data copied to where it needs to go after calling ExitBootServices. At
222 // that stage we've reached the point of no return, so overwriting UEFI code
223 // does not make a difference.
224 Status
= ElfCheckFile (FileData
);
225 if (!EFI_ERROR (Status
)) {
226 // Load program into memory
227 Status
= ElfLoadFile ((VOID
*)FileData
, &Entrypoint
, &LoadList
);
229 // Try to see if it is a BootMonFs executable
230 Status
= BootMonFsCheckFile ((EFI_FILE_HANDLE
)FileHandle
);
231 if (!EFI_ERROR (Status
)) {
232 // Load program into memory
233 Status
= BootMonFsLoadFile ((EFI_FILE_HANDLE
)FileHandle
,
234 (VOID
*)FileData
, &Entrypoint
, &LoadList
);
236 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_RUNAXF_BAD_FILE
),
238 SHELL_FREE_NON_NULL (FileData
);
239 ShellStatus
= SHELL_UNSUPPORTED
;
244 // Program load list created.
245 // Shutdown UEFI, copy and jump to code.
246 if (!IsListEmpty (&LoadList
) && !EFI_ERROR (Status
)) {
247 // Exit boot services here. This means we cannot return and cannot assume to
248 // have access to UEFI functions.
249 Status
= ShutdownUefiBootServices ();
250 if (EFI_ERROR (Status
)) {
251 DEBUG ((EFI_D_ERROR
,"Can not shutdown UEFI boot services. Status=0x%X\n",
254 // Process linked list. Copy data to Memory.
255 Node
= GetFirstNode (&LoadList
);
256 while (!IsNull (&LoadList
, Node
)) {
257 LoadNode
= (RUNAXF_LOAD_LIST
*)Node
;
258 // Do we have data to copy or do we need to set Zeroes (.bss)?
259 if (LoadNode
->Zeroes
) {
260 ZeroMem ((VOID
*)LoadNode
->MemOffset
, LoadNode
->Length
);
262 CopyMem ((VOID
*)LoadNode
->MemOffset
, (VOID
*)LoadNode
->FileOffset
,
265 Node
= GetNextNode (&LoadList
, Node
);
269 // Switch off interrupts, caches, mmu, etc
271 Status
= PreparePlatformHardware ();
272 ASSERT_EFI_ERROR (Status
);
274 StartElf
= (ELF_ENTRYPOINT
)Entrypoint
;
277 // We should never get here.. But if we do, spin..
283 // Free file related information as we are returning to UEFI.
284 Node
= GetFirstNode (&LoadList
);
285 while (!IsNull (&LoadList
, Node
)) {
286 NextNode
= RemoveEntryList (Node
);
290 SHELL_FREE_NON_NULL (FileData
);
291 if (FileHandle
!= NULL
) {
292 ShellCloseFile (&FileHandle
);
295 // Uninstall protocols as we don't know if they will change.
296 // If the shell exits and come in again these mappings may be different
297 // and cause a crash.
298 Status
= gBS
->UninstallMultipleProtocolInterfaces (gImageHandle
,
299 &gEfiShellProtocolGuid
, Shell
,
300 &gEfiShellParametersProtocolGuid
, ShellParameters
,
303 if (EFI_ERROR (Status
) && ShellStatus
== SHELL_SUCCESS
) {
304 ShellStatus
= SHELL_DEVICE_ERROR
;
312 This is the command help handler function pointer callback type. This
313 function is responsible for displaying help information for the associated
316 @param[in] This The instance of the
317 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL.
318 @param[in] Language The pointer to the language string to use.
320 @return string Pool allocated help string, must be freed by
325 ShellDynCmdRunAxfGetHelp (
326 IN EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*This
,
327 IN CONST CHAR8
*Language
332 ASSERT (gRunAxfHiiHandle
!= NULL
);
334 // This allocates memory. The caller is responsoible to free.
335 HelpText
= HiiGetString (gRunAxfHiiHandle
, STRING_TOKEN (STR_GET_HELP_RUNAXF
),