VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/UefiPayloadPkg/PayloadLoaderPeim/ElfLib/ElfLib.c@ 101297

Last change on this file since 101297 was 99404, checked in by vboxsync, 2 years ago

Devices/EFI/FirmwareNew: Update to edk2-stable202302 and make it build, bugref:4643

  • Property svn:eol-style set to native
File size: 12.6 KB
Line 
1/** @file
2 ELF library
3
4 Copyright (c) 2019 - 2021, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7**/
8
9#include "ElfLibInternal.h"
10
11/**
12 Check if the ELF image is valid.
13
14 @param[in] ImageBase Memory address of an image.
15
16 @retval TRUE if valid.
17
18**/
19BOOLEAN
20IsElfFormat (
21 IN CONST UINT8 *ImageBase
22 )
23{
24 Elf32_Ehdr *Elf32Hdr;
25 Elf64_Ehdr *Elf64Hdr;
26
27 ASSERT (ImageBase != NULL);
28
29 Elf32Hdr = (Elf32_Ehdr *)ImageBase;
30
31 //
32 // Start with correct signature "\7fELF"
33 //
34 if ((Elf32Hdr->e_ident[EI_MAG0] != ELFMAG0) ||
35 (Elf32Hdr->e_ident[EI_MAG1] != ELFMAG1) ||
36 (Elf32Hdr->e_ident[EI_MAG1] != ELFMAG1) ||
37 (Elf32Hdr->e_ident[EI_MAG2] != ELFMAG2)
38 )
39 {
40 return FALSE;
41 }
42
43 //
44 // Support little-endian only
45 //
46 if (Elf32Hdr->e_ident[EI_DATA] != ELFDATA2LSB) {
47 return FALSE;
48 }
49
50 //
51 // Check 32/64-bit architecture
52 //
53 if (Elf32Hdr->e_ident[EI_CLASS] == ELFCLASS64) {
54 Elf64Hdr = (Elf64_Ehdr *)Elf32Hdr;
55 Elf32Hdr = NULL;
56 } else if (Elf32Hdr->e_ident[EI_CLASS] == ELFCLASS32) {
57 Elf64Hdr = NULL;
58 } else {
59 return FALSE;
60 }
61
62 if (Elf64Hdr != NULL) {
63 //
64 // Support intel architecture only for now
65 //
66 if (Elf64Hdr->e_machine != EM_X86_64) {
67 return FALSE;
68 }
69
70 //
71 // Support ELF types: EXEC (Executable file), DYN (Shared object file)
72 //
73 if ((Elf64Hdr->e_type != ET_EXEC) && (Elf64Hdr->e_type != ET_DYN)) {
74 return FALSE;
75 }
76
77 //
78 // Support current ELF version only
79 //
80 if (Elf64Hdr->e_version != EV_CURRENT) {
81 return FALSE;
82 }
83 } else {
84 //
85 // Support intel architecture only for now
86 //
87 if (Elf32Hdr->e_machine != EM_386) {
88 return FALSE;
89 }
90
91 //
92 // Support ELF types: EXEC (Executable file), DYN (Shared object file)
93 //
94 if ((Elf32Hdr->e_type != ET_EXEC) && (Elf32Hdr->e_type != ET_DYN)) {
95 return FALSE;
96 }
97
98 //
99 // Support current ELF version only
100 //
101 if (Elf32Hdr->e_version != EV_CURRENT) {
102 return FALSE;
103 }
104 }
105
106 return TRUE;
107}
108
109/**
110 Calculate a ELF file size.
111
112 @param[in] ElfCt ELF image context pointer.
113 @param[out] FileSize Return the file size.
114
115 @retval EFI_INVALID_PARAMETER ElfCt or SecPos is NULL.
116 @retval EFI_NOT_FOUND Could not find the section.
117 @retval EFI_SUCCESS Section posistion was filled successfully.
118**/
119EFI_STATUS
120CalculateElfFileSize (
121 IN ELF_IMAGE_CONTEXT *ElfCt,
122 OUT UINTN *FileSize
123 )
124{
125 EFI_STATUS Status;
126 UINTN FileSize1;
127 UINTN FileSize2;
128 Elf32_Ehdr *Elf32Hdr;
129 Elf64_Ehdr *Elf64Hdr;
130 UINTN Offset;
131 UINTN Size;
132
133 if ((ElfCt == NULL) || (FileSize == NULL)) {
134 return EFI_INVALID_PARAMETER;
135 }
136
137 // Use last section as end of file
138 Status = GetElfSectionPos (ElfCt, ElfCt->ShNum - 1, &Offset, &Size);
139 if (EFI_ERROR (Status)) {
140 return EFI_UNSUPPORTED;
141 }
142
143 FileSize1 = Offset + Size;
144
145 // Use end of section header as end of file
146 FileSize2 = 0;
147 if (ElfCt->EiClass == ELFCLASS32) {
148 Elf32Hdr = (Elf32_Ehdr *)ElfCt->FileBase;
149 FileSize2 = Elf32Hdr->e_shoff + Elf32Hdr->e_shentsize * Elf32Hdr->e_shnum;
150 } else if (ElfCt->EiClass == ELFCLASS64) {
151 Elf64Hdr = (Elf64_Ehdr *)ElfCt->FileBase;
152 FileSize2 = ((UINTN)Elf64Hdr->e_shoff + (UINTN)(Elf64Hdr->e_shentsize * Elf64Hdr->e_shnum));
153 }
154
155 *FileSize = MAX (FileSize1, FileSize2);
156
157 return EFI_SUCCESS;
158}
159
160/**
161 Get a ELF program segment loading info.
162
163 @param[in] ImageBase Image base.
164 @param[in] EiClass ELF class.
165 @param[in] Index ELF segment index.
166 @param[out] SegInfo The pointer to the segment info.
167
168 @retval EFI_INVALID_PARAMETER ElfCt or SecPos is NULL.
169 @retval EFI_NOT_FOUND Could not find the section.
170 @retval EFI_SUCCESS Section posistion was filled successfully.
171**/
172EFI_STATUS
173GetElfSegmentInfo (
174 IN UINT8 *ImageBase,
175 IN UINT32 EiClass,
176 IN UINT32 Index,
177 OUT SEGMENT_INFO *SegInfo
178 )
179{
180 Elf32_Phdr *Elf32Phdr;
181 Elf64_Phdr *Elf64Phdr;
182
183 if ((ImageBase == NULL) || (SegInfo == NULL)) {
184 return EFI_INVALID_PARAMETER;
185 }
186
187 if (EiClass == ELFCLASS32) {
188 Elf32Phdr = GetElf32SegmentByIndex (ImageBase, Index);
189 if (Elf32Phdr != NULL) {
190 SegInfo->PtType = Elf32Phdr->p_type;
191 SegInfo->Offset = Elf32Phdr->p_offset;
192 SegInfo->Length = Elf32Phdr->p_filesz;
193 SegInfo->MemLen = Elf32Phdr->p_memsz;
194 SegInfo->MemAddr = Elf32Phdr->p_paddr;
195 SegInfo->Alignment = Elf32Phdr->p_align;
196 return EFI_SUCCESS;
197 }
198 } else if (EiClass == ELFCLASS64) {
199 Elf64Phdr = GetElf64SegmentByIndex (ImageBase, Index);
200 if (Elf64Phdr != NULL) {
201 SegInfo->PtType = Elf64Phdr->p_type;
202 SegInfo->Offset = (UINTN)Elf64Phdr->p_offset;
203 SegInfo->Length = (UINTN)Elf64Phdr->p_filesz;
204 SegInfo->MemLen = (UINTN)Elf64Phdr->p_memsz;
205 SegInfo->MemAddr = (UINTN)Elf64Phdr->p_paddr;
206 SegInfo->Alignment = (UINTN)Elf64Phdr->p_align;
207 return EFI_SUCCESS;
208 }
209 }
210
211 return EFI_NOT_FOUND;
212}
213
214/**
215 Parse the ELF image info.
216
217 On return, all fields in ElfCt are updated except ImageAddress.
218
219 @param[in] ImageBase Memory address of an image.
220 @param[out] ElfCt The EFL image context pointer.
221
222 @retval EFI_INVALID_PARAMETER Input parameters are not valid.
223 @retval EFI_UNSUPPORTED Unsupported binary type.
224 @retval EFI_LOAD_ERROR ELF binary loading error.
225 @retval EFI_SUCCESS ELF binary is loaded successfully.
226**/
227EFI_STATUS
228EFIAPI
229ParseElfImage (
230 IN VOID *ImageBase,
231 OUT ELF_IMAGE_CONTEXT *ElfCt
232 )
233{
234 Elf32_Ehdr *Elf32Hdr;
235 Elf64_Ehdr *Elf64Hdr;
236 Elf32_Shdr *Elf32Shdr;
237 Elf64_Shdr *Elf64Shdr;
238 EFI_STATUS Status;
239 UINT32 Index;
240 SEGMENT_INFO SegInfo;
241 UINTN End;
242 UINTN Base;
243
244 if (ElfCt == NULL) {
245 return EFI_INVALID_PARAMETER;
246 }
247
248 ZeroMem (ElfCt, sizeof (ELF_IMAGE_CONTEXT));
249
250 if (ImageBase == NULL) {
251 return (ElfCt->ParseStatus = EFI_INVALID_PARAMETER);
252 }
253
254 ElfCt->FileBase = (UINT8 *)ImageBase;
255 if (!IsElfFormat (ElfCt->FileBase)) {
256 return (ElfCt->ParseStatus = EFI_UNSUPPORTED);
257 }
258
259 Elf32Hdr = (Elf32_Ehdr *)ElfCt->FileBase;
260 ElfCt->EiClass = Elf32Hdr->e_ident[EI_CLASS];
261 if (ElfCt->EiClass == ELFCLASS32) {
262 if ((Elf32Hdr->e_type != ET_EXEC) && (Elf32Hdr->e_type != ET_DYN)) {
263 return (ElfCt->ParseStatus = EFI_UNSUPPORTED);
264 }
265
266 Elf32Shdr = (Elf32_Shdr *)GetElf32SectionByIndex (ElfCt->FileBase, Elf32Hdr->e_shstrndx);
267 if (Elf32Shdr == NULL) {
268 return (ElfCt->ParseStatus = EFI_UNSUPPORTED);
269 }
270
271 ElfCt->EntryPoint = (UINTN)Elf32Hdr->e_entry;
272 ElfCt->ShNum = Elf32Hdr->e_shnum;
273 ElfCt->PhNum = Elf32Hdr->e_phnum;
274 ElfCt->ShStrLen = Elf32Shdr->sh_size;
275 ElfCt->ShStrOff = Elf32Shdr->sh_offset;
276 } else {
277 Elf64Hdr = (Elf64_Ehdr *)Elf32Hdr;
278 if ((Elf64Hdr->e_type != ET_EXEC) && (Elf64Hdr->e_type != ET_DYN)) {
279 return (ElfCt->ParseStatus = EFI_UNSUPPORTED);
280 }
281
282 Elf64Shdr = (Elf64_Shdr *)GetElf64SectionByIndex (ElfCt->FileBase, Elf64Hdr->e_shstrndx);
283 if (Elf64Shdr == NULL) {
284 return (ElfCt->ParseStatus = EFI_UNSUPPORTED);
285 }
286
287 ElfCt->EntryPoint = (UINTN)Elf64Hdr->e_entry;
288 ElfCt->ShNum = Elf64Hdr->e_shnum;
289 ElfCt->PhNum = Elf64Hdr->e_phnum;
290 ElfCt->ShStrLen = (UINT32)Elf64Shdr->sh_size;
291 ElfCt->ShStrOff = (UINT32)Elf64Shdr->sh_offset;
292 }
293
294 //
295 // Get the preferred image base and required memory size when loaded to new location.
296 //
297 End = 0;
298 Base = MAX_UINT32;
299 ElfCt->ReloadRequired = FALSE;
300 for (Index = 0; Index < ElfCt->PhNum; Index++) {
301 Status = GetElfSegmentInfo (ElfCt->FileBase, ElfCt->EiClass, Index, &SegInfo);
302 ASSERT_EFI_ERROR (Status);
303
304 if (SegInfo.PtType != PT_LOAD) {
305 continue;
306 }
307
308 if (SegInfo.MemLen != SegInfo.Length) {
309 //
310 // Not enough space to execute at current location.
311 //
312 ElfCt->ReloadRequired = TRUE;
313 }
314
315 if (Base > (SegInfo.MemAddr & ~(EFI_PAGE_SIZE - 1))) {
316 Base = SegInfo.MemAddr & ~(EFI_PAGE_SIZE - 1);
317 }
318
319 if (End < ALIGN_VALUE (SegInfo.MemAddr + SegInfo.MemLen, EFI_PAGE_SIZE) - 1) {
320 End = ALIGN_VALUE (SegInfo.MemAddr + SegInfo.MemLen, EFI_PAGE_SIZE) - 1;
321 }
322 }
323
324 //
325 // 0 - MAX_UINT32 + 1 equals to 0.
326 //
327 ElfCt->ImageSize = End - Base + 1;
328 ElfCt->PreferredImageAddress = (VOID *)Base;
329
330 CalculateElfFileSize (ElfCt, &ElfCt->FileSize);
331 return (ElfCt->ParseStatus = EFI_SUCCESS);
332}
333
334/**
335 Load the ELF image to Context.ImageAddress.
336
337 Context should be initialized by ParseElfImage().
338 Caller should set Context.ImageAddress to a proper value, either pointing to
339 a new allocated memory whose size equal to Context.ImageSize, or pointing
340 to Context.PreferredImageAddress.
341
342 @param[in] ElfCt ELF image context pointer.
343
344 @retval EFI_INVALID_PARAMETER Input parameters are not valid.
345 @retval EFI_UNSUPPORTED Unsupported binary type.
346 @retval EFI_LOAD_ERROR ELF binary loading error.
347 @retval EFI_SUCCESS ELF binary is loaded successfully.
348**/
349EFI_STATUS
350EFIAPI
351LoadElfImage (
352 IN ELF_IMAGE_CONTEXT *ElfCt
353 )
354{
355 EFI_STATUS Status;
356
357 if (ElfCt == NULL) {
358 return EFI_INVALID_PARAMETER;
359 }
360
361 if (EFI_ERROR (ElfCt->ParseStatus)) {
362 return ElfCt->ParseStatus;
363 }
364
365 if (ElfCt->ImageAddress == NULL) {
366 return EFI_INVALID_PARAMETER;
367 }
368
369 Status = EFI_UNSUPPORTED;
370 if (ElfCt->EiClass == ELFCLASS32) {
371 Status = LoadElf32Image (ElfCt);
372 } else if (ElfCt->EiClass == ELFCLASS64) {
373 Status = LoadElf64Image (ElfCt);
374 }
375
376 return Status;
377}
378
379/**
380 Get a ELF section name from its index.
381
382 @param[in] ElfCt ELF image context pointer.
383 @param[in] SectionIndex ELF section index.
384 @param[out] SectionName The pointer to the section name.
385
386 @retval EFI_INVALID_PARAMETER ElfCt or SecName is NULL.
387 @retval EFI_NOT_FOUND Could not find the section.
388 @retval EFI_SUCCESS Section name was filled successfully.
389**/
390EFI_STATUS
391EFIAPI
392GetElfSectionName (
393 IN ELF_IMAGE_CONTEXT *ElfCt,
394 IN UINT32 SectionIndex,
395 OUT CHAR8 **SectionName
396 )
397{
398 Elf32_Shdr *Elf32Shdr;
399 Elf64_Shdr *Elf64Shdr;
400 CHAR8 *Name;
401
402 if ((ElfCt == NULL) || (SectionName == NULL)) {
403 return EFI_INVALID_PARAMETER;
404 }
405
406 if (EFI_ERROR (ElfCt->ParseStatus)) {
407 return ElfCt->ParseStatus;
408 }
409
410 Name = NULL;
411 if (ElfCt->EiClass == ELFCLASS32) {
412 Elf32Shdr = GetElf32SectionByIndex (ElfCt->FileBase, SectionIndex);
413 if ((Elf32Shdr != NULL) && (Elf32Shdr->sh_name < ElfCt->ShStrLen)) {
414 Name = (CHAR8 *)(ElfCt->FileBase + ElfCt->ShStrOff + Elf32Shdr->sh_name);
415 }
416 } else if (ElfCt->EiClass == ELFCLASS64) {
417 Elf64Shdr = GetElf64SectionByIndex (ElfCt->FileBase, SectionIndex);
418 if ((Elf64Shdr != NULL) && (Elf64Shdr->sh_name < ElfCt->ShStrLen)) {
419 Name = (CHAR8 *)(ElfCt->FileBase + ElfCt->ShStrOff + Elf64Shdr->sh_name);
420 }
421 }
422
423 if (Name == NULL) {
424 return EFI_NOT_FOUND;
425 }
426
427 *SectionName = Name;
428 return EFI_SUCCESS;
429}
430
431/**
432 Get the offset and size of x-th ELF section.
433
434 @param[in] ElfCt ELF image context pointer.
435 @param[in] Index ELF section index.
436 @param[out] Offset Return the offset of the specific section.
437 @param[out] Size Return the size of the specific section.
438
439 @retval EFI_INVALID_PARAMETER ImageBase, Offset or Size is NULL.
440 @retval EFI_INVALID_PARAMETER EiClass doesn't equal to ELFCLASS32 or ELFCLASS64.
441 @retval EFI_NOT_FOUND Could not find the section.
442 @retval EFI_SUCCESS Offset and Size are returned.
443**/
444EFI_STATUS
445EFIAPI
446GetElfSectionPos (
447 IN ELF_IMAGE_CONTEXT *ElfCt,
448 IN UINT32 Index,
449 OUT UINTN *Offset,
450 OUT UINTN *Size
451 )
452{
453 Elf32_Shdr *Elf32Shdr;
454 Elf64_Shdr *Elf64Shdr;
455
456 if ((ElfCt == NULL) || (Offset == NULL) || (Size == NULL)) {
457 return EFI_INVALID_PARAMETER;
458 }
459
460 if (EFI_ERROR (ElfCt->ParseStatus)) {
461 return ElfCt->ParseStatus;
462 }
463
464 if (ElfCt->EiClass == ELFCLASS32) {
465 Elf32Shdr = GetElf32SectionByIndex (ElfCt->FileBase, Index);
466 if (Elf32Shdr != NULL) {
467 *Offset = (UINTN)Elf32Shdr->sh_offset;
468 *Size = (UINTN)Elf32Shdr->sh_size;
469 return EFI_SUCCESS;
470 }
471 } else if (ElfCt->EiClass == ELFCLASS64) {
472 Elf64Shdr = GetElf64SectionByIndex (ElfCt->FileBase, Index);
473 if (Elf64Shdr != NULL) {
474 *Offset = (UINTN)Elf64Shdr->sh_offset;
475 *Size = (UINTN)Elf64Shdr->sh_size;
476 return EFI_SUCCESS;
477 }
478 }
479
480 return EFI_NOT_FOUND;
481}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette