You've already forked slimbootloader
mirror of
https://github.com/Dasharo/slimbootloader.git
synced 2026-03-06 15:26:20 -08:00
594 lines
18 KiB
C
594 lines
18 KiB
C
/** @file
|
|
This file Multiboot specification (implementation).
|
|
|
|
Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
|
|
This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php.
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
**/
|
|
|
|
#include <PiPei.h>
|
|
#include <Library/MultibootLib.h>
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/HobLib.h>
|
|
#include <Guid/MemoryMapInfoGuid.h>
|
|
|
|
#include "Elf32.h"
|
|
|
|
#define SUPPORTED_FEATURES (MULTIBOOT_HEADER_MODS_ALIGNED | MULTIBOOT_HEADER_WANT_MEMORY)
|
|
UINT8 mLoaderName[] = "Slim BootLoader\0";
|
|
|
|
|
|
/**
|
|
Get multiboot header address
|
|
|
|
Get multiboot header following Multboot spec 0.6.98.
|
|
|
|
@param[in] ImageAddr Memory address of an image
|
|
|
|
@retval MultibootHeader Pointer to Multiboot header if found.
|
|
@retval NULL No valid Multiboot header found or requesting
|
|
features not support.
|
|
**/
|
|
CONST MULTIBOOT_HEADER *
|
|
EFIAPI
|
|
GetMultibootHeader (
|
|
IN VOID *ImageAddr
|
|
)
|
|
{
|
|
UINT32 AlignedAddress;
|
|
MULTIBOOT_HEADER *MbHeader;
|
|
UINT32 Offset;
|
|
|
|
// Multiboot header must be 32-bit aligned.
|
|
AlignedAddress = ((UINT32)ImageAddr + 3) & ~0x3;
|
|
|
|
// Multiboot header must completely within the first 8192 bytes of the image.
|
|
for (Offset = 0; Offset < 8192 - sizeof (MULTIBOOT_HEADER); Offset += 4) {
|
|
MbHeader = (MULTIBOOT_HEADER *) (AlignedAddress + Offset);
|
|
if ((MbHeader->Magic == MULTIBOOT_HEADER_MAGIC) &&
|
|
(MbHeader->Magic + MbHeader->Flags + MbHeader->Checksum == 0)) {
|
|
if ((MbHeader->Flags & (~SUPPORTED_FEATURES & 0xffff)) != 0) {
|
|
// Some Multiboot features are not supported yet.
|
|
DEBUG ((DEBUG_INFO, "Not supported Multiboot, flags=0x%x\n", MbHeader->Flags));
|
|
return NULL;
|
|
}
|
|
|
|
return (CONST MULTIBOOT_HEADER *) MbHeader;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
Check if it is Multiboot image
|
|
|
|
@param[in] ImageAddr Memory address of an image
|
|
|
|
@retval TRUE Image is Multiboot 0.6.98 compliant image
|
|
@retval FALSE Not multiboot image
|
|
**/
|
|
BOOLEAN
|
|
EFIAPI
|
|
IsMultiboot (
|
|
IN VOID *ImageAddr
|
|
)
|
|
{
|
|
CONST MULTIBOOT_HEADER *MbHeader;
|
|
|
|
MbHeader = GetMultibootHeader (ImageAddr);
|
|
if (MbHeader != NULL) {
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/**
|
|
Get memory map information.
|
|
|
|
@retval Memory Map Info pointer
|
|
**/
|
|
STATIC
|
|
MEMORY_MAP_INFO *
|
|
EFIAPI
|
|
GetMemoryMapInfo (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_HOB_GUID_TYPE *GuidHob;
|
|
|
|
GuidHob = GetNextGuidHob (&gLoaderMemoryMapInfoGuid, GetHobList());
|
|
if (GuidHob == NULL) {
|
|
ASSERT (GuidHob);
|
|
return NULL;
|
|
}
|
|
|
|
return (MEMORY_MAP_INFO *)GET_GUID_HOB_DATA (GuidHob);
|
|
}
|
|
|
|
|
|
/**
|
|
Init Multiboot memory map.
|
|
|
|
@param[out] MbMmap Multiboot memmap buffer
|
|
@param[in] MemoryMapInfo Memmap buffer from boot loader
|
|
**/
|
|
VOID
|
|
InitMultibotMmap (
|
|
OUT MULTIBOOT_MMAP *MbMmap,
|
|
IN MEMORY_MAP_INFO *MemoryMapInfo
|
|
)
|
|
{
|
|
UINT32 Index;
|
|
MEMORY_MAP_ENTRY *MmapEntry;
|
|
|
|
MmapEntry = &MemoryMapInfo->Entry[0];
|
|
for (Index = 0; Index < MemoryMapInfo->Count; Index++) {
|
|
MbMmap[Index].Size = sizeof (MULTIBOOT_MMAP) - sizeof (MbMmap[Index].Size);
|
|
MbMmap[Index].BaseAddr = MmapEntry[Index].Base;
|
|
MbMmap[Index].Length = MmapEntry[Index].Size;
|
|
MbMmap[Index].Type = MmapEntry[Index].Type;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
Setup the Multiboot info for boot usage.
|
|
|
|
@param[in,out] MultiBoot Point to loaded Multiboot image structure
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
SetupMultibootInfo (
|
|
IN OUT MULTIBOOT_IMAGE *MultiBoot
|
|
)
|
|
{
|
|
UINT32 MmapCount;
|
|
MULTIBOOT_MMAP *MbMmap;
|
|
MEMORY_MAP_INFO *MemoryMapInfo;
|
|
MULTIBOOT_INFO *MbInfo;
|
|
|
|
MbInfo = &MultiBoot->MbInfo;
|
|
MemoryMapInfo = GetMemoryMapInfo();
|
|
MmapCount = MemoryMapInfo->Count;
|
|
if (MmapCount > 0) {
|
|
MbMmap = (MULTIBOOT_MMAP *) AllocatePool (sizeof (MULTIBOOT_MMAP) * MmapCount);
|
|
if (MbMmap == NULL) {
|
|
DEBUG ((DEBUG_INFO, "Multiboot MMap allocation Error\n"));
|
|
ASSERT (MbMmap);
|
|
}
|
|
InitMultibotMmap (MbMmap, MemoryMapInfo);
|
|
|
|
MbInfo->MmapAddr = (UINT32 *) MbMmap;
|
|
MbInfo->MmapLength = MmapCount * sizeof (MULTIBOOT_MMAP);
|
|
MbInfo->Flags |= MULTIBOOT_INFO_HAS_MMAP;
|
|
|
|
// The amount of lower and upper memory size (in KB) will be updated
|
|
// later since current memmap is not the final memmap.
|
|
}
|
|
|
|
// boot device [MULTIBOOT_INFO_HAS_BOOT_DEVICE]: not supported.
|
|
|
|
if (MultiBoot->CmdFile.Size != 0) {
|
|
MbInfo->Cmdline = MultiBoot->CmdFile.Addr;
|
|
MbInfo->Flags |= MULTIBOOT_INFO_HAS_CMDLINE;
|
|
}
|
|
|
|
// modules [MULTIBOOT_INFO_HAS_MODS]
|
|
if (MultiBoot->MbModuleNumber > 0) {
|
|
MbInfo->ModsAddr = (V_ADDR)&MultiBoot->MbModule;
|
|
MbInfo->ModsCount = MultiBoot->MbModuleNumber;
|
|
MbInfo->Flags |= MULTIBOOT_INFO_HAS_MODS;
|
|
}
|
|
|
|
// a.out symbol table [MULTIBOOT_INFO_HAS_AOUT_SYMS]: provided by a.out loader
|
|
// ELF symbol table [MULTIBOOT_INFO_HAS_ELF_SYMS]: provided by ELF loader
|
|
|
|
// BIOS drive info [MULTIBOOT_INFO_HAS_DRIVES]: not supported
|
|
// BIOS ROM configuration table [MULTIBOOT_INFO_HAS_CONFIG_TABLE]: not supported.
|
|
|
|
// boot loader name:
|
|
MbInfo->LoaderName = (UINT8 *) &mLoaderName;
|
|
MbInfo->Flags |= MULTIBOOT_INFO_HAS_LOADER_NAME;
|
|
|
|
// BIOS APM table [MULTIBOOT_INFO_HAS_APM_TABLE]: not supported
|
|
// BIOS VBE video mode information [MULTIBOOT_INFO_HAS_VBE]: not supported
|
|
|
|
// Arrange for passing this data to the image.
|
|
MultiBoot->BootState.Eax = MULTIBOOT_INFO_MAGIC;
|
|
MultiBoot->BootState.Ebx = (UINT32) (MbInfo);
|
|
}
|
|
|
|
|
|
/**
|
|
Align multiboot modules if required by spec.
|
|
|
|
@param[in,out] MultiBoot Point to loaded Multiboot image structure
|
|
|
|
@retval RETURN_SUCCESS Align modules successfully
|
|
@retval Others There is error when align image
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AlignMulitibootModules (
|
|
IN OUT MULTIBOOT_IMAGE *MultiBoot
|
|
)
|
|
{
|
|
MULTIBOOT_MODULE *MbModule;
|
|
VOID *AlignedAddr;
|
|
UINT32 ModuleSize;
|
|
UINT32 Index;
|
|
|
|
for (Index = 0; Index < MultiBoot->MbModuleNumber; Index++) {
|
|
MbModule = &MultiBoot->MbModule[Index];
|
|
ModuleSize = MbModule->End - MbModule->Start;
|
|
if ((MbModule->Start & EFI_PAGE_MASK) != 0) {
|
|
AlignedAddr = AllocatePages (EFI_SIZE_TO_PAGES (ModuleSize));
|
|
if (AlignedAddr == NULL) {
|
|
return RETURN_OUT_OF_RESOURCES;
|
|
}
|
|
DEBUG ((DEBUG_INFO, "Align Module[%d] from 0x%x to 0x%p\n",
|
|
Index, MbModule->Start, AlignedAddr));
|
|
CopyMem (AlignedAddr, (CONST VOID *)MbModule->Start, ModuleSize);
|
|
MbModule->Start = (UINT32) AlignedAddr;
|
|
}
|
|
}
|
|
|
|
return RETURN_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Setup Multiboot image and its boot info.
|
|
|
|
@param[in,out] MultiBoot Point to loaded Multiboot image structure
|
|
|
|
@retval RETURN_SUCCESS Setup Multiboot image successfully
|
|
@retval Others There is error when setup image
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SetupMultibootImage (
|
|
IN OUT MULTIBOOT_IMAGE *MultiBoot
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 *LoadAddr;
|
|
UINT32 *LoadEnd;
|
|
UINT32 *BssEnd;
|
|
CONST MULTIBOOT_HEADER *MbHeader;
|
|
|
|
if (MultiBoot == NULL) {
|
|
return RETURN_INVALID_PARAMETER;
|
|
}
|
|
|
|
MbHeader = GetMultibootHeader (MultiBoot->BootFile.Addr);
|
|
if (MbHeader == NULL) {
|
|
return RETURN_LOAD_ERROR;
|
|
}
|
|
|
|
if ((MbHeader->Flags & MULTIBOOT_HEADER_HAS_ADDR) == 0) {
|
|
return RETURN_UNSUPPORTED;
|
|
}
|
|
|
|
if ((MbHeader->Flags & MULTIBOOT_HEADER_MODS_ALIGNED) != 0) {
|
|
// Other modules should be page (4KB) aligned
|
|
Status = AlignMulitibootModules (MultiBoot);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
LoadAddr = MbHeader->LoadAddr;
|
|
LoadEnd = MbHeader->LoadEndAddr;
|
|
BssEnd = MbHeader->BssEndAddr;
|
|
DEBUG ((DEBUG_INFO, "Mb: LoadAddr=0x%p, LoadEnd=0x%p , BssEnd=0x%p\n", LoadAddr, LoadEnd, BssEnd));
|
|
if (LoadEnd == NULL) {
|
|
// zero means "load the entire file"
|
|
CopyMem (LoadAddr, (UINT8 * )MultiBoot->BootFile.Addr, MultiBoot->BootFile.Size);
|
|
DEBUG ((DEBUG_INFO, "Mb: copy image to 0x%p, Size=0x%x\n", LoadAddr, MultiBoot->BootFile.Size));
|
|
} else {
|
|
CopyMem (LoadAddr, MultiBoot->BootFile.Addr, sizeof (UINT32) * (LoadEnd - LoadAddr));
|
|
DEBUG ((DEBUG_INFO, "Mb: copy image to 0x%p, Size=0x%x\n", LoadAddr, sizeof (UINT32) * (LoadEnd - LoadAddr)));
|
|
if ((UINT32)BssEnd != 0) {
|
|
ZeroMem ((VOID *) LoadEnd, BssEnd - LoadEnd);
|
|
}
|
|
}
|
|
|
|
SetupMultibootInfo (MultiBoot);
|
|
MultiBoot->BootState.EntryPoint = (UINT32) MbHeader->EntryAddr;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Print out the Multiboot information block.
|
|
|
|
@param[in] Mi The Multiboot information block to be printed.
|
|
**/
|
|
VOID
|
|
DumpMbInfo (
|
|
IN CONST MULTIBOOT_INFO *Mi
|
|
)
|
|
{
|
|
UINT32 Index;
|
|
MULTIBOOT_MODULE *Mod;
|
|
CONST MULTIBOOT_MMAP *Map;
|
|
UINT32 Offs;
|
|
|
|
DEBUG ((DEBUG_INFO, "\nDump MB info @%p:\n", Mi));
|
|
if (Mi == NULL) {
|
|
return;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "- Flags: %8x\n", Mi->Flags));
|
|
|
|
// Valid if mi_flags sets MULTIBOOT_INFO_HAS_MEMORY.
|
|
DEBUG ((DEBUG_INFO, "- MemLower: %8x (%dK)\n", Mi->MemLower, Mi->MemLower));
|
|
DEBUG ((DEBUG_INFO, "- MemUpper: %8x (%dK)\n", Mi->MemUpper, Mi->MemUpper));
|
|
|
|
// Valid if mi_flags sets MULTIBOOT_INFO_HAS_BOOT_DEVICE.
|
|
DEBUG ((DEBUG_INFO, "- BootDevicePart3: %8x\n", Mi->BootDevicePart3));
|
|
DEBUG ((DEBUG_INFO, "- BootDevicePart2: %8x\n", Mi->BootDevicePart2));
|
|
DEBUG ((DEBUG_INFO, "- BootDevicePart1: %8x\n", Mi->BootDevicePart1));
|
|
DEBUG ((DEBUG_INFO, "- BootDeviceDrive: %8x\n", Mi->BootDeviceDrive));
|
|
|
|
// Valid if mi_flags sets MULTIBOOT_INFO_HAS_CMDLINE.
|
|
DEBUG ((DEBUG_INFO, "- Cmdline addr: %8p\n", Mi->Cmdline));
|
|
if ((Mi->Flags & MULTIBOOT_INFO_HAS_CMDLINE) && Mi->Cmdline) {
|
|
DEBUG ((DEBUG_INFO, "cmd = '%a'\n", Mi->Cmdline));
|
|
}
|
|
|
|
// Valid if mi_flags sets MULTIBOOT_INFO_HAS_MODS.
|
|
DEBUG ((DEBUG_INFO, "- ModsCount: %8x\n", Mi->ModsCount));
|
|
DEBUG ((DEBUG_INFO, "- ModsAddr: %8x\n", Mi->ModsAddr));
|
|
if ((Mi->Flags & MULTIBOOT_INFO_HAS_MODS) && Mi->ModsCount > 0) {
|
|
Mod = (MULTIBOOT_MODULE *)Mi->ModsAddr;
|
|
for (Index = 0; Index < Mi->ModsCount; Index++) {
|
|
DEBUG ((DEBUG_INFO, "- Mod[%d].Start: %08x\n", Index, Mod[Index].Start));
|
|
DEBUG ((DEBUG_INFO, "- Mod[%d].End: %08x\n", Index, Mod[Index].End));
|
|
DEBUG ((DEBUG_INFO, "- Mod[%d].String: %08x\n", Index, (UINT32)Mod[Index].String));
|
|
}
|
|
}
|
|
|
|
// Valid if mi_flags sets MULTIBOOT_INFO_HAS_{AOUT,ELF}_SYMS.
|
|
DEBUG ((DEBUG_INFO, "- ElfshdrNum: %8x\n", Mi->ElfshdrNum));
|
|
DEBUG ((DEBUG_INFO, "- ElfshdrSize: %8x\n", Mi->ElfshdrSize));
|
|
DEBUG ((DEBUG_INFO, "- ElfshdrAddr: %8x\n", Mi->ElfshdrAddr));
|
|
DEBUG ((DEBUG_INFO, "- ElfshdrShndx: %8x\n", Mi->ElfshdrShndx));
|
|
|
|
// Valid if mi_flags sets MULTIBOOT_INFO_HAS_MMAP.
|
|
DEBUG ((DEBUG_INFO, "- MmapLength: %8x\n", Mi->MmapLength));
|
|
DEBUG ((DEBUG_INFO, "- MmapAddr: %8x\n", Mi->MmapAddr));
|
|
|
|
if ((Mi->Flags & MULTIBOOT_INFO_HAS_MMAP)) {
|
|
for (Offs = 0; Offs < Mi->MmapLength; Offs += Map->Size + sizeof (Map->Size)) {
|
|
Map = (VOID *) (((UINT32) (Mi->MmapAddr)) + Offs);
|
|
DEBUG ((DEBUG_INFO, "%3x: ", Offs));
|
|
DEBUG ((DEBUG_INFO, "%016lX", Map->BaseAddr));
|
|
DEBUG ((DEBUG_INFO, "--%016lX", Map->Length));
|
|
DEBUG ((DEBUG_INFO, " %d\n", Map->Type));
|
|
}
|
|
}
|
|
|
|
// Valid if mi_flags sets MULTIBOOT_INFO_HAS_DRIVES.
|
|
DEBUG ((DEBUG_INFO, "- DrivesLength: %8x\n", Mi->DrivesLength));
|
|
DEBUG ((DEBUG_INFO, "- DrivesAddr: %8x\n", Mi->DrivesAddr));
|
|
|
|
// Valid if mi_flags sets MULTIBOOT_INFO_HAS_CONFIG_TABLE.
|
|
DEBUG ((DEBUG_INFO, "- ConfigTable: %8p\n", Mi->UnusedConfigTable));
|
|
|
|
// Valid if mi_flags sets MULTIBOOT_INFO_HAS_LOADER_NAME.
|
|
DEBUG ((DEBUG_INFO, "- LoaderName: %8p\n", Mi->LoaderName));
|
|
if ((Mi->Flags & MULTIBOOT_INFO_HAS_LOADER_NAME) && Mi->LoaderName) {
|
|
DEBUG ((DEBUG_INFO, " '%a'\n", Mi->LoaderName));
|
|
}
|
|
|
|
// Valid if mi_flags sets MULTIBOOT_INFO_HAS_APM.
|
|
DEBUG ((DEBUG_INFO, "- ApmTable: %8p\n", Mi->UnusedApmTable));
|
|
|
|
// Valid if mi_flags sets MULTIBOOT_INFO_HAS_VBE.
|
|
DEBUG ((DEBUG_INFO, "- VbeControlInfo: %8p\n", Mi->UnusedVbeControlInfo));
|
|
DEBUG ((DEBUG_INFO, "- VbeModeInfo: %8p\n", Mi->UnusedVbeModeInfo));
|
|
DEBUG ((DEBUG_INFO, "- VbeInterfaceSeg: %8x\n", Mi->UnusedVbeInterfaceSeg));
|
|
DEBUG ((DEBUG_INFO, "- VbeInterfaceOff: %8x\n", Mi->UnusedVbeInterfaceOff));
|
|
DEBUG ((DEBUG_INFO, "- VbeInterfaceLen: %8x\n\n", Mi->UnusedVbeInterfaceLen));
|
|
}
|
|
|
|
/**
|
|
Print out the Multiboot boot state.
|
|
|
|
@param[in] BootState The Multiboot boot state pointer.
|
|
**/
|
|
VOID
|
|
DumpMbBootState (
|
|
IN CONST IA32_BOOT_STATE *BootState
|
|
)
|
|
{
|
|
DEBUG ((DEBUG_INFO, "Dump multiboot boot state:\n"));
|
|
DEBUG ((DEBUG_INFO, "- EntryPoint: %4x\n", BootState->EntryPoint));
|
|
DEBUG ((DEBUG_INFO, "- Eax: %4x\n", BootState->Eax));
|
|
DEBUG ((DEBUG_INFO, "- Ebx: %4x\n", BootState->Ebx));
|
|
DEBUG ((DEBUG_INFO, "- Esi: %4x\n", BootState->Esi));
|
|
DEBUG ((DEBUG_INFO, "- Edi: %4x\n\n", BootState->Edi));
|
|
}
|
|
|
|
|
|
#define IS_BOOTABLE_I386_ELF(h) \
|
|
( IS_ELF (h) && \
|
|
(h->E_Ident[EI_CLASS] == ELFCLASS32) && \
|
|
(h->E_Ident[EI_DATA] == ELFDATA2LSB) && \
|
|
(h->E_Ident[EI_VERSION] == EV_CURRENT) && \
|
|
((h->E_Type == ET_EXEC) || (h->E_Type == ET_DYN)) && \
|
|
(h->E_Machine == EM_386) && \
|
|
(h->E_Version == EV_CURRENT))
|
|
|
|
/**
|
|
Check if the image is a bootable ELF image.
|
|
|
|
@param[in] ImgAddr Memory address of an image
|
|
|
|
@retval TRUE Image is a bootable ELF image
|
|
@retval FALSE Not a bootable ELF image
|
|
**/
|
|
BOOLEAN
|
|
EFIAPI
|
|
IsElfImage (
|
|
IN VOID *ImgAddr
|
|
)
|
|
{
|
|
ELF32_EHDR *Ehdr;
|
|
|
|
Ehdr = (ELF32_EHDR *) ImgAddr;
|
|
|
|
return (BOOLEAN) IS_BOOTABLE_I386_ELF (Ehdr);
|
|
}
|
|
|
|
|
|
/**
|
|
load ELF image symbol table
|
|
|
|
@param[in] Img Memory address of ELF image
|
|
@param[in] Ehdr ELF file header
|
|
@param[in,out] Eaddr Start address for ELF symbols
|
|
@param[out] Mbi Multiboot info
|
|
|
|
@retval End address of loaded sysbols table
|
|
**/
|
|
UINT32 *
|
|
LoadElfSymtab (
|
|
IN UINT32 *Img,
|
|
IN CONST ELF32_EHDR *Ehdr,
|
|
IN OUT UINT32 *Eaddr,
|
|
OUT MULTIBOOT_INFO *Mbi
|
|
)
|
|
{
|
|
UINT32 Addr;
|
|
UINT32 Size;
|
|
UINT32 Index;
|
|
ELF32_SHDR *Shdr;
|
|
|
|
// Clear multiboot symbol table flags.
|
|
Mbi->Flags &= ~ (MULTIBOOT_INFO_HAS_AOUT_SYMS | MULTIBOOT_INFO_HAS_ELF_SYMS);
|
|
|
|
// Copy ELF section headers.
|
|
Size = Ehdr->E_Shnum * Ehdr->E_Shentsize;
|
|
Shdr = (ELF32_SHDR *) Eaddr;
|
|
CopyMem (Shdr, (VOID *) ((UINT32)Img + Ehdr->E_Shoff), Size);
|
|
Eaddr += Size;
|
|
|
|
// Copy sections that are part of the symbol table.
|
|
for (Index = 0 ; Index < Ehdr->E_Shnum ; Index += 1) {
|
|
if (Shdr[Index].Sh_Type != SHT_SYMTAB) {
|
|
continue;
|
|
}
|
|
Addr = ROUNDED_UP ((UINT32)Eaddr, Shdr[Index].Sh_Addralign);
|
|
Size = ROUNDED_UP (Shdr[Index].Sh_Size, 4);
|
|
|
|
CopyMem ((VOID *)Addr, (VOID *) ((UINT32)Img + Shdr[Index].Sh_Offset), Size);
|
|
Shdr[Index].Sh_Addr = Addr;
|
|
Eaddr = (UINT32 *) (Addr + Size);
|
|
}
|
|
|
|
// Record symbol table in the multiboot info structure.
|
|
Mbi->Flags |= MULTIBOOT_INFO_HAS_ELF_SYMS;
|
|
Mbi->ElfshdrNum = Ehdr->E_Shnum;
|
|
Mbi->ElfshdrSize = Ehdr->E_Shentsize;
|
|
Mbi->ElfshdrAddr = (UINT32 *) Shdr;
|
|
Mbi->ElfshdrShndx = Ehdr->E_Shstrndx;
|
|
|
|
return Eaddr;
|
|
}
|
|
|
|
/**
|
|
Load the ELF image to specified address in ELF header.
|
|
|
|
This function load ELF image section by section into memory address specified
|
|
in ELF program header, and also load ELF symbols.
|
|
|
|
@param[in,out] MultiBoot Loaded multiboot image.
|
|
|
|
@retval Image entry point The entry point of ELF image if load image success
|
|
@retval NULL Error with loading ELF image
|
|
**/
|
|
UINT32 *
|
|
EFIAPI
|
|
LoadElfImage (
|
|
IN OUT MULTIBOOT_IMAGE *MultiBoot
|
|
)
|
|
{
|
|
ELF32_EHDR Ehdr;
|
|
ELF32_PHDR *Phdr;
|
|
UINT32 Size;
|
|
UINT32 Eaddr;
|
|
UINT32 Index;
|
|
UINT32 Msize;
|
|
UINT32 Fsize;
|
|
UINT32 Mpos;
|
|
UINT32 Ipos;
|
|
UINT32 *Img;
|
|
|
|
//
|
|
// TODO: Check if image, load region overlap; if yes, move image away.
|
|
//
|
|
|
|
//
|
|
// Copy ELF header, program headers.
|
|
//
|
|
Img = (UINT32 *)MultiBoot->BootFile.Addr;
|
|
CopyMem (&Ehdr, (VOID *)Img, sizeof (Ehdr));
|
|
|
|
Size = Ehdr.E_Phnum * Ehdr.E_Phentsize;
|
|
Phdr = (ELF32_PHDR *) AllocatePool (Size);
|
|
CopyMem (Phdr, (VOID *) ((UINT32)Img + Ehdr.E_Phoff), Size);
|
|
|
|
//
|
|
// Iterate over the program headers and load all necessary segments.
|
|
// Keep track of the highest load address used in <eaddr>
|
|
//
|
|
for (Index = 0, Eaddr = 0 ; Index < Ehdr.E_Phnum ; Index += 1) {
|
|
if (Phdr[Index].P_Type != PT_LOAD) {
|
|
continue;
|
|
}
|
|
|
|
Msize = Phdr[Index].P_Memsz; // target (in-memory) segment size
|
|
Fsize = Phdr[Index].P_Filesz; // source (image) segment size
|
|
Mpos = Phdr[Index].P_Paddr; // target segment address
|
|
Ipos = Phdr[Index].P_Offset; // location of segment in image
|
|
|
|
if ((Mpos <= ((UINT32) Img)) && (Mpos + Msize > ((UINT32) Img))) {
|
|
DEBUG ((DEBUG_INFO, "** IMAGE overwrite, out of range **\n"));
|
|
return NULL;
|
|
}
|
|
|
|
if (Fsize != 0) {
|
|
CopyMem ((VOID *) Mpos, (VOID *) ((UINT32)Img + Ipos), Fsize);
|
|
}
|
|
|
|
if (Msize > Fsize) {
|
|
ZeroMem ((VOID *) (Mpos + Fsize), Msize - Fsize);
|
|
}
|
|
|
|
Eaddr = MAX (Eaddr, Mpos + Msize);
|
|
}
|
|
|
|
FreePool ((VOID *)Phdr);
|
|
|
|
//
|
|
// The image is now bootable; try to load the symbol table as well.
|
|
//
|
|
LoadElfSymtab (Img, &Ehdr, (UINT32 *) ROUNDED_UP (Eaddr, KB_ (4)), &MultiBoot->MbInfo);
|
|
return (UINT32 *) Ehdr.E_Entry;
|
|
}
|
|
|