3 * Copyright (c) 2014, ARM Limited. All rights reserved.
5 * This program and the accompanying materials
6 * are licensed and made available under the terms and conditions of the BSD License
7 * which accompanies this distribution. The full text of the license may be found at
8 * http://opensource.org/licenses/bsd-license.php
10 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include <Library/BaseLib.h>
16 #include <Library/BaseMemoryLib.h>
17 #include <Library/MemoryAllocationLib.h>
18 #include <Library/DebugLib.h>
19 #include <Library/UefiLib.h>
21 #include "ArmShellCmdRunAxf.h"
22 #include "ElfLoader.h"
23 #include "elf_common.h"
28 // Put the functions the #ifdef. We only use the appropriate one for the platform.
29 // This prevents 'defined but not used' compiler warning.
37 Elf32_Ehdr
*Hdr
= (Elf32_Ehdr
*)Buf
;
39 if (Hdr
->e_ident
[EI_CLASS
] != ELFCLASS32
) {
40 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_RUNAXF_ELFWRONGCLASS_32
), gRunAxfHiiHandle
);
44 if (Hdr
->e_machine
!= EM_ARM
) {
45 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_RUNAXF_ELFWRONGMACH_32
), gRunAxfHiiHandle
);
49 // We don't currently check endianness of ELF data (hdr->e_ident[EI_DATA])
53 #elif defined(MDE_CPU_AARCH64)
60 Elf64_Ehdr
*Hdr
= (Elf64_Ehdr
*)Buf
;
62 if (Hdr
->e_ident
[EI_CLASS
] != ELFCLASS64
) {
63 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_RUNAXF_ELFWRONGCLASS_64
), gRunAxfHiiHandle
);
67 if (Hdr
->e_machine
!= EM_AARCH64
) {
68 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_RUNAXF_ELFWRONGMACH_64
), gRunAxfHiiHandle
);
72 // We don't currently check endianness of ELF data (hdr->e_ident[EI_DATA])
76 #endif // MDE_CPU_ARM , MDE_CPU_AARCH64
80 Support checking 32 and 64bit as the header could be valid, we might just
81 not support loading it.
89 Elf32_Ehdr
*Hdr32
= (Elf32_Ehdr
*)Buf
;
91 if (!IS_ELF (*Hdr32
)) {
92 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_RUNAXF_ELFMAGIC
), gRunAxfHiiHandle
);
93 return EFI_INVALID_PARAMETER
;
96 if (Hdr32
->e_type
!= ET_EXEC
) {
97 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_RUNAXF_ELFNOTEXEC
), gRunAxfHiiHandle
);
98 return EFI_INVALID_PARAMETER
;
101 if (Hdr32
->e_ident
[EI_CLASS
] == ELFCLASS32
) {
102 if ((Hdr32
->e_phoff
== 0) || (Hdr32
->e_phentsize
== 0) || (Hdr32
->e_phnum
== 0)) {
103 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_RUNAXF_ELFNOPROG
), gRunAxfHiiHandle
);
104 return EFI_INVALID_PARAMETER
;
107 if (Hdr32
->e_flags
!= 0) {
108 DEBUG ((EFI_D_INFO
, "Warning: Wrong processor-specific flags, expected 0.\n"));
111 DEBUG ((EFI_D_INFO
, "Entry point addr: 0x%lx\n", Hdr32
->e_entry
));
112 DEBUG ((EFI_D_INFO
, "Start of program headers: 0x%lx\n", Hdr32
->e_phoff
));
113 DEBUG ((EFI_D_INFO
, "Size of 1 program header: %d\n", Hdr32
->e_phentsize
));
114 DEBUG ((EFI_D_INFO
, "Number of program headers: %d\n", Hdr32
->e_phnum
));
115 } else if (Hdr32
->e_ident
[EI_CLASS
] == ELFCLASS64
) {
116 Elf64_Ehdr
*Hdr64
= (Elf64_Ehdr
*)Buf
;
118 if ((Hdr64
->e_phoff
== 0) || (Hdr64
->e_phentsize
== 0) || (Hdr64
->e_phnum
== 0)) {
119 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_RUNAXF_ELFNOPROG
), gRunAxfHiiHandle
);
120 return EFI_INVALID_PARAMETER
;
123 if (Hdr64
->e_flags
!= 0) {
124 DEBUG ((EFI_D_INFO
, "Warning: Wrong processor-specific flags, expected 0.\n"));
127 DEBUG ((EFI_D_INFO
, "Entry point addr: 0x%lx\n", Hdr64
->e_entry
));
128 DEBUG ((EFI_D_INFO
, "Start of program headers: 0x%lx\n", Hdr64
->e_phoff
));
129 DEBUG ((EFI_D_INFO
, "Size of 1 program header: %d\n", Hdr64
->e_phentsize
));
130 DEBUG ((EFI_D_INFO
, "Number of program headers: %d\n", Hdr64
->e_phnum
));
132 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_RUNAXF_ELFWRONGCLASS
), gRunAxfHiiHandle
);
133 return EFI_INVALID_PARAMETER
;
141 Load an ELF segment into memory.
143 This function assumes the ELF file is valid.
144 This function is meant to be called for PT_LOAD type segments only.
149 IN CONST VOID
*ElfImage
,
151 IN LIST_ENTRY
*LoadList
157 UINTN ExtraZeroesCount
;
158 RUNAXF_LOAD_LIST
*LoadNode
;
161 Elf32_Phdr
*ProgramHdr
;
162 ProgramHdr
= (Elf32_Phdr
*)PHdr
;
163 #elif defined(MDE_CPU_AARCH64)
164 Elf64_Phdr
*ProgramHdr
;
165 ProgramHdr
= (Elf64_Phdr
*)PHdr
;
168 ASSERT (ElfImage
!= NULL
);
169 ASSERT (ProgramHdr
!= NULL
);
171 FileSegment
= (VOID
*)((UINTN
)ElfImage
+ ProgramHdr
->p_offset
);
172 MemSegment
= (VOID
*)ProgramHdr
->p_vaddr
;
174 // If the segment's memory size p_memsz is larger than the file size p_filesz,
175 // the "extra" bytes are defined to hold the value 0 and to follow the
176 // segment's initialised area.
177 // This is typically the case for the .bss segment.
178 // The file size may not be larger than the memory size.
179 if (ProgramHdr
->p_filesz
> ProgramHdr
->p_memsz
) {
180 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_RUNAXF_ELFBADFORMAT
), gRunAxfHiiHandle
);
181 return EFI_INVALID_PARAMETER
;
184 // Load the segment in memory.
185 if (ProgramHdr
->p_filesz
!= 0) {
186 DEBUG ((EFI_D_INFO
, "Loading segment from 0x%lx to 0x%lx (size = %ld)\n",
187 FileSegment
, MemSegment
, ProgramHdr
->p_filesz
));
189 LoadNode
= AllocateRuntimeZeroPool (sizeof (RUNAXF_LOAD_LIST
));
190 if (LoadNode
== NULL
) {
191 return EFI_OUT_OF_RESOURCES
;
193 LoadNode
->MemOffset
= (UINTN
)MemSegment
;
194 LoadNode
->FileOffset
= (UINTN
)FileSegment
;
195 LoadNode
->Length
= (UINTN
)ProgramHdr
->p_filesz
;
196 InsertTailList (LoadList
, &LoadNode
->Link
);
199 ExtraZeroes
= ((UINTN
)MemSegment
+ ProgramHdr
->p_filesz
);
200 ExtraZeroesCount
= ProgramHdr
->p_memsz
- ProgramHdr
->p_filesz
;
201 DEBUG ((EFI_D_INFO
, "Completing segment with %d zero bytes.\n", ExtraZeroesCount
));
202 if (ExtraZeroesCount
> 0) {
203 // Extra Node to add the Zeroes.
204 LoadNode
= AllocateRuntimeZeroPool (sizeof (RUNAXF_LOAD_LIST
));
205 if (LoadNode
== NULL
) {
206 return EFI_OUT_OF_RESOURCES
;
208 LoadNode
->MemOffset
= (UINTN
)ExtraZeroes
;
209 LoadNode
->Zeroes
= TRUE
;
210 LoadNode
->Length
= ExtraZeroesCount
;
211 InsertTailList (LoadList
, &LoadNode
->Link
);
219 Check that the ELF File Header is valid and Machine type supported.
221 Not all information is checked in the ELF header, only the stuff that
222 matters to us in our simplified ELF loader.
224 @param[in] ElfImage Address of the ELF file to check.
226 @retval EFI_SUCCESS on success.
227 @retval EFI_INVALID_PARAMETER if the header is invalid.
228 @retval EFI_UNSUPPORTED if the file type/platform is not supported.
232 IN CONST VOID
*ElfImage
237 ASSERT (ElfImage
!= NULL
);
239 // Check that the ELF header is valid.
240 Status
= ElfCheckHeader (ElfImage
);
241 if (EFI_ERROR(Status
)) {
242 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_RUNAXF_ELFBADHEADER
), gRunAxfHiiHandle
);
243 return EFI_INVALID_PARAMETER
;
247 if (IsArmElf (ElfImage
)) {
250 #elif defined(MDE_CPU_AARCH64)
251 if (IsAarch64Elf (ElfImage
)) {
256 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_RUNAXF_BAD_ARCH
), gRunAxfHiiHandle
);
257 return EFI_UNSUPPORTED
;
264 @param[in] ElfImage Address of the ELF file in memory.
266 @param[out] EntryPoint Will be filled with the ELF entry point address.
268 @param[out] ImageSize Will be filled with the ELF size in memory. This will
269 effectively be equal to the sum of the segments sizes.
271 This functon assumes the header is valid and supported as checked with
274 @retval EFI_SUCCESS on success.
275 @retval EFI_INVALID_PARAMETER if the ELF file is invalid.
279 IN CONST VOID
*ElfImage
,
280 OUT VOID
**EntryPoint
,
281 OUT LIST_ENTRY
*LoadList
291 Elf32_Phdr
*ProgramHdrPtr
;
293 ElfHdr
= (Elf32_Ehdr
*)ElfImage
;
294 #elif defined(MDE_CPU_AARCH64)
296 Elf64_Phdr
*ProgramHdrPtr
;
298 ElfHdr
= (Elf64_Ehdr
*)ElfImage
;
301 ASSERT (ElfImage
!= NULL
);
302 ASSERT (EntryPoint
!= NULL
);
303 ASSERT (LoadList
!= NULL
);
305 ProgramHdr
= (UINT8
*)ElfImage
+ ElfHdr
->e_phoff
;
306 DEBUG ((EFI_D_INFO
, "ELF program header entry : 0x%lx\n", ProgramHdr
));
310 // Load every loadable ELF segment into memory.
311 for (Index
= 0; Index
< ElfHdr
->e_phnum
; ++Index
) {
314 ProgramHdrPtr
= (Elf32_Phdr
*)ProgramHdr
;
315 #elif defined(MDE_CPU_AARCH64)
316 ProgramHdrPtr
= (Elf64_Phdr
*)ProgramHdr
;
319 // Only consider PT_LOAD type segments, ignore others.
320 if (ProgramHdrPtr
->p_type
== PT_LOAD
) {
321 Status
= ElfLoadSegment (ElfImage
, (VOID
*)ProgramHdrPtr
, LoadList
);
322 if (EFI_ERROR (Status
)) {
323 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_RUNAXF_ELFFAILSEG
), gRunAxfHiiHandle
);
324 return EFI_INVALID_PARAMETER
;
326 ImageSize
+= ProgramHdrPtr
->p_memsz
;
328 ProgramHdr
+= ElfHdr
->e_phentsize
;
331 if (ImageSize
== 0) {
332 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_RUNAXF_ELFNOSEG
), gRunAxfHiiHandle
);
333 return EFI_INVALID_PARAMETER
;
336 // Return the entry point specified in the ELF header.
337 *EntryPoint
= (void*)ElfHdr
->e_entry
;