Support ELF32/64 format payloads regardless of operation mode

This allows to load and execute ELF32 or ELF64 format payloads
regardless of Ia32 or X64 SBL operation modes.

Signed-off-by: Aiden Park <aiden.park@intel.com>
This commit is contained in:
Aiden Park 2021-05-21 15:17:57 -07:00 committed by Maurice Ma
parent 3a02cd0f45
commit 236a800284
4 changed files with 145 additions and 29 deletions

View File

@ -10,6 +10,7 @@
#define __ELF_LIB_H__
#include <Uefi/UefiBaseType.h>
#include <IndustryStandard/PeImage.h>
/**
Check if the image is a bootable ELF image.
@ -40,9 +41,28 @@ IsElfImage (
@retval EFI_SUCCESS ELF binary is loaded successfully.
**/
EFI_STATUS
EFIAPI
LoadElfImage (
IN CONST VOID *ImageBase,
OUT VOID **EntryPoint
);
/**
Extract and return the machine type from ELF image.
@param[in] ImageBase Memory address of an image.
@param[out] MachinePtr The pointer to machine type to return.
@retval EFI_SUCCESS Machine was returned successfully.
@retval EFI_UNSUPPORTED Unsupported image format.
@retval EFI_INVALID_PARAMETER The ImageBase pointer is NULL.
**/
EFI_STATUS
EFIAPI
GetElfMachine (
IN VOID *ImageBase,
OUT UINT16 *MachinePtr OPTIONAL
);
#endif /* __ELF_LIB_H__ */

View File

@ -8,6 +8,10 @@
#include "ElfLibInternal.h"
#define ELF_CR(Record, TYPE, Field) (((TYPE *) Record)->Field)
#define ELF_CLASS_CR(Record, TYPE, Field, IsElf64) \
IsElf64 ? ELF_CR(Record,Elf64_##TYPE,Field) : ELF_CR(Record,Elf32_##TYPE,Field)
/**
Check if the image has ELF Header
@ -30,7 +34,31 @@ IsElfHeader (
}
/**
Check if the image is 32-bit ELF Format
Check if the image is 64-bit ELF Format
@param[in] ImageBase Memory address of an image.
@retval TRUE if ELF32, otherwise FALSE
**/
STATIC
BOOLEAN
IsElf64Format (
IN CONST UINT8 *ImageBase
)
{
Elf32_Ehdr *ElfHdr;
ElfHdr = (Elf32_Ehdr *)ImageBase;
if (ElfHdr->e_ident[EI_CLASS] == ELFCLASS64) {
return TRUE;
} else {
return FALSE;
}
}
/**
Check if the image is ELF Format
@param[in] ImageBase Memory address of an image.
@ -43,46 +71,54 @@ IsElfFormat (
IN CONST UINT8 *ImageBase
)
{
Elf_Ehdr *ElfHdr;
Elf32_Ehdr *ElfHdr;
UINT16 Data16;
UINT32 Data32;
BOOLEAN IsElf64;
if (ImageBase == NULL) {
return FALSE;
}
ElfHdr = (Elf_Ehdr *)ImageBase;
ElfHdr = (Elf32_Ehdr *)ImageBase;
//
// Check 32/64-bit architecture
//
if (ElfHdr->e_ident[EI_CLASS] != ELFCLASS) {
return FALSE;
}
IsElf64 = IsElf64Format (ImageBase);
//
// Support little-endian only
//
if (ElfHdr->e_ident[EI_DATA] != ELFDATA2LSB) {
DEBUG ((DEBUG_VERBOSE, "IsElfFormat: Not Little-Endian!\n"));
return FALSE;
}
//
// Support intel architecture only for now
//
if (ElfHdr->e_machine != ELF_EM) {
Data16 = (UINT16)ELF_CLASS_CR (ImageBase, Ehdr, e_machine, IsElf64);
if ((Data16 != EM_386) && (Data16 != EM_X86_64)) {
DEBUG ((DEBUG_VERBOSE, "IsElfFormat: Not Intel Architecture!\n"));
return FALSE;
}
//
// Support ELF types: EXEC (Executable file), DYN (Shared object file)
//
if ((ElfHdr->e_type != ET_EXEC) && (ElfHdr->e_type != ET_DYN)) {
Data16 = (UINT16)ELF_CLASS_CR (ImageBase, Ehdr, e_type, IsElf64);
if ((Data16 != ET_EXEC) && (Data16 != ET_DYN)) {
DEBUG ((DEBUG_VERBOSE, "IsElfFormat: Not Support ELF types(%d)!\n", Data16));
return FALSE;
}
//
// Support current ELF version only
//
if (ElfHdr->e_version != EV_CURRENT) {
Data32 = (UINT32)ELF_CLASS_CR (ImageBase, Ehdr, e_version, IsElf64);
if (Data32 != EV_CURRENT) {
DEBUG ((DEBUG_VERBOSE, "IsElfFormat: Not Support ELF version(0x%08X)!\n", Data32));
return FALSE;
}
@ -106,41 +142,59 @@ LoadElfSegments (
OUT VOID **EntryPoint
)
{
Elf_Ehdr *ElfHdr;
Elf_Phdr *ProgramHdr;
Elf_Phdr *ProgramHdrBase;
VOID *ProgramHdr;
UINT8 *ProgramHdrBase;
BOOLEAN IsElf64;
UINT16 Index;
UINT16 ProgramHdrNum;
UINT16 ProgramHdrEntSize;
UINT32 ProgramHdrType;
UINT64 ProgramHdrOffset;
UINT64 ProgramHdrFileOffset;
UINT64 ProgramHdrFileSize;
UINT64 ProgramHdrMemSize;
UINT64 ProgramHdrPaddr;
UINT64 ElfEntry;
if ((ImageBase == NULL) || (EntryPoint == NULL)) {
return EFI_INVALID_PARAMETER;
}
ElfHdr = (Elf_Ehdr *)ImageBase;
ProgramHdrBase = (Elf_Phdr *)(ImageBase + ElfHdr->e_phoff);
for (Index = 0; Index < ElfHdr->e_phnum; Index++) {
ProgramHdr = (Elf_Phdr *)((UINT8 *)ProgramHdrBase + Index * ElfHdr->e_phentsize);
IsElf64 = IsElf64Format (ImageBase);
ProgramHdrOffset = ELF_CLASS_CR (ImageBase, Ehdr, e_phoff, IsElf64);
ProgramHdrBase = (UINT8 *)ImageBase + ProgramHdrOffset;
ProgramHdrNum = ELF_CLASS_CR (ImageBase, Ehdr, e_phnum, IsElf64);
ProgramHdrEntSize = ELF_CLASS_CR (ImageBase, Ehdr, e_phentsize, IsElf64);
for (Index = 0; Index < ProgramHdrNum; Index++) {
ProgramHdr = (VOID *)(ProgramHdrBase + Index * ProgramHdrEntSize);
if ((ProgramHdr->p_type != PT_LOAD) ||
(ProgramHdr->p_memsz == 0) ||
(ProgramHdr->p_offset == 0)) {
ProgramHdrType = ELF_CLASS_CR (ProgramHdr, Phdr, p_type, IsElf64);
ProgramHdrFileOffset = ELF_CLASS_CR (ProgramHdr, Phdr, p_offset, IsElf64);
ProgramHdrMemSize = ELF_CLASS_CR (ProgramHdr, Phdr, p_memsz, IsElf64);
if ((ProgramHdrType != PT_LOAD) ||
(ProgramHdrMemSize == 0) ||
(ProgramHdrFileOffset == 0)) {
continue;
}
if (ProgramHdr->p_filesz > ProgramHdr->p_memsz) {
ProgramHdrFileSize = ELF_CLASS_CR (ProgramHdr, Phdr, p_filesz, IsElf64);
if (ProgramHdrFileSize > ProgramHdrMemSize) {
return EFI_LOAD_ERROR;
}
CopyMem ((VOID *)(UINTN)ProgramHdr->p_paddr,
ImageBase + ProgramHdr->p_offset,
(UINTN)ProgramHdr->p_filesz);
ProgramHdrPaddr = ELF_CLASS_CR (ProgramHdr, Phdr, p_paddr, IsElf64);
CopyMem ((VOID *)(UINTN)ProgramHdrPaddr,
(VOID *)(UINTN)(ImageBase + ProgramHdrFileOffset),
(UINTN)ProgramHdrFileSize);
if (ProgramHdr->p_memsz > ProgramHdr->p_filesz) {
ZeroMem ((VOID *)(UINTN)(ProgramHdr->p_paddr + ProgramHdr->p_filesz),
(UINTN)(ProgramHdr->p_memsz - ProgramHdr->p_filesz));
if (ProgramHdrMemSize > ProgramHdrFileSize) {
ZeroMem ((VOID *)(UINTN)(ProgramHdrPaddr + ProgramHdrFileSize),
(UINTN)(ProgramHdrMemSize - ProgramHdrFileSize));
}
}
*EntryPoint = (VOID *)(UINTN)ElfHdr->e_entry;
ElfEntry = ELF_CLASS_CR (ImageBase, Ehdr, e_entry, IsElf64);
*EntryPoint = (VOID *)(UINTN)ElfEntry;
return EFI_SUCCESS;
}
@ -170,7 +224,7 @@ IsElfImage (
This function loads ELF image segments into memory address specified
in ELF program header.
@param[in] ImageBase Memory address of an image.
@param[in] ElfBuffer Memory address of an image.
@param[out] EntryPoint The entry point of loaded ELF image.
@retval EFI_INVALID_PARAMETER Input parameters are not valid.
@ -179,6 +233,7 @@ IsElfImage (
@retval EFI_SUCCESS ELF binary is loaded successfully.
**/
EFI_STATUS
EFIAPI
LoadElfImage (
IN CONST VOID *ElfBuffer,
OUT VOID **EntryPoint
@ -202,3 +257,40 @@ LoadElfImage (
return Status;
}
/**
Extract and return the machine type from ELF image.
@param[in] ElfBuffer Memory address of an image.
@param[out] MachinePtr The pointer to machine type to return.
@retval EFI_SUCCESS Machine was returned successfully.
@retval EFI_UNSUPPORTED Unsupported image format.
@retval EFI_INVALID_PARAMETER The ElfBuffer pointer is NULL.
**/
EFI_STATUS
EFIAPI
GetElfMachine (
IN VOID *ElfBuffer,
OUT UINT16 *MachinePtr OPTIONAL
)
{
if (ElfBuffer == NULL) {
return EFI_INVALID_PARAMETER;
}
if (!IsElfImage (ElfBuffer)) {
return EFI_UNSUPPORTED;
}
if (MachinePtr != NULL) {
if (IsElf64Format (ElfBuffer)) {
*MachinePtr = IMAGE_FILE_MACHINE_X64;
} else {
*MachinePtr = IMAGE_FILE_MACHINE_I386;
}
}
return EFI_SUCCESS;
}

View File

@ -12,6 +12,7 @@
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/BaseMemoryLib.h>
#include <IndustryStandard/PeImage.h>
#include "ElfCommon.h"
#include "Elf32.h"
#include "Elf64.h"

View File

@ -183,7 +183,10 @@ NormalBootPath (
UefiSig = Dst[0];
Status = LoadFvImage (Dst, Stage2Param->PayloadActualLength, (VOID **)&PldEntry, &PldMachine);
} else if (IsElfImage (Dst)) {
Status = LoadElfImage (Dst, (VOID *)&PldEntry);
Status = GetElfMachine (Dst, &PldMachine);
if (!EFI_ERROR(Status)) {
Status = LoadElfImage (Dst, (VOID *)&PldEntry);
}
} else {
if (FeaturePcdGet (PcdLinuxPayloadEnabled)) {
if (IsBzImage (Dst)) {