commonlib/fsp_relocate: Add PE32+ support

Add support for PE32+ binaries which can be found on X64 UEFI
builds.

TEST: Able to relocate and boot a X64 FSP.

Change-Id: I22586834d7c9f3ab3a5e31bba957584587ec14e0
Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/82680
Reviewed-by: Subrata Banik <subratabanik@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Patrick Rudolph 2024-05-27 16:09:59 +02:00 committed by Felix Held
parent f725c24c37
commit f40f5b6dd5

View File

@ -160,16 +160,17 @@ static FSP_INFO_HEADER *fsp_get_info_hdr(void *fsp, size_t fih_offset)
static int pe_relocate(uintptr_t new_addr, void *pe, void *fsp, size_t fih_off)
{
EFI_IMAGE_NT_HEADERS32 *peih;
EFI_IMAGE_OPTIONAL_HEADER_UNION *peih;
EFI_IMAGE_DOS_HEADER *doshdr;
EFI_IMAGE_OPTIONAL_HEADER32 *ophdr;
EFI_IMAGE_OPTIONAL_HEADER64 *ophdr64;
FSP_INFO_HEADER *fih;
uint32_t roffset, rsize;
uint32_t offset;
uint8_t *pe_base = pe;
uint32_t image_base;
uint32_t img_base_off;
uint32_t delta;
uint64_t image_base;
uint64_t img_base_off;
uint64_t delta;
doshdr = pe;
if (read_le16(&doshdr->e_magic) != EFI_IMAGE_DOS_SIGNATURE) {
@ -179,15 +180,20 @@ static int pe_relocate(uintptr_t new_addr, void *pe, void *fsp, size_t fih_off)
peih = relative_offset(pe, doshdr->e_lfanew);
if (read_le32(&peih->Signature) != EFI_IMAGE_NT_SIGNATURE) {
if (read_le32(&peih->Pe32.Signature) != EFI_IMAGE_NT_SIGNATURE) {
printk(BIOS_ERR, "Invalid PE32 header\n");
return -1;
}
ophdr = &peih->OptionalHeader;
ophdr = &peih->Pe32.OptionalHeader;
ophdr64 = &peih->Pe32Plus.OptionalHeader;
if (read_le16(&ophdr->Magic) != EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
printk(BIOS_ERR, "No support for non-PE32 images\n");
if (read_le16(&ophdr->Magic) == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
ophdr64 = NULL;
} else if (read_le16(&ophdr64->Magic) == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
ophdr = NULL;
} else {
printk(BIOS_ERR, "No support for non-PE32/PE32+ images\n");
return -1;
}
@ -197,21 +203,26 @@ static int pe_relocate(uintptr_t new_addr, void *pe, void *fsp, size_t fih_off)
return -1;
}
image_base = read_le32(&fih->ImageBase);
printk(FSP_DBG_LVL, "FSP InfoHdr Image Base is %x\n", image_base);
printk(FSP_DBG_LVL, "FSP InfoHdr Image Base is %" PRIX64"\n", image_base);
delta = new_addr - image_base;
img_base_off = read_le32(&ophdr->ImageBase);
printk(FSP_DBG_LVL, "lfanew 0x%x, delta-0x%x, FSP Base 0x%x, NT32ImageBase 0x%x, offset 0x%x\n",
img_base_off = ophdr ? read_le32(&ophdr->ImageBase) : read_le64(&ophdr64->ImageBase);
printk(FSP_DBG_LVL, "lfanew 0x%x, delta-0x%" PRIX64 ", FSP Base 0x%" PRIX64 ", NT32ImageBase 0x%" PRIX64 ", offset 0x%" PRIX64 "\n",
read_le32(&doshdr->e_lfanew),
delta, image_base, img_base_off,
(uint32_t)((uint8_t *)&ophdr->ImageBase - pe_base));
(uint64_t)((uint8_t *)(uintptr_t)img_base_off - pe_base));
printk(FSP_DBG_LVL, "relocating PE32%s image at addr - 0x%" PRIxPTR "\n", ophdr ? "" : "+", new_addr);
if (ophdr) {
rsize = read_le32(&ophdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size);
roffset = read_le32(&ophdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
} else {
rsize = read_le32(&ophdr64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size);
roffset = read_le32(&ophdr64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
}
printk(FSP_DBG_LVL, "relocating PE32 image at addr - 0x%" PRIxPTR "\n", new_addr);
rsize = read_le32(&ophdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size);
roffset = read_le32(&ophdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
printk(FSP_DBG_LVL, "relocation table at offset-%x,size=%x\n", roffset, rsize);
// TODO - add support for PE32+ also
offset = roffset;
while (offset < (roffset + rsize)) {
@ -234,20 +245,23 @@ static int pe_relocate(uintptr_t new_addr, void *pe, void *fsp, size_t fih_off)
uint16_t roff = reloc_offset(rdata[i]);
uint16_t rtype = reloc_type(rdata[i]);
uint32_t aoff = vaddr + roff;
uint32_t val;
printk(FSP_DBG_LVL, "\t\treloc type %x offset %x aoff %x, base-0x%x\n",
uint64_t val;
printk(FSP_DBG_LVL, "\t\treloc type %x offset %x aoff %x, base-0x%" PRIX64 "\n",
rtype, roff, aoff, img_base_off);
switch (rtype) {
case EFI_IMAGE_REL_BASED_ABSOLUTE:
continue;
case EFI_IMAGE_REL_BASED_HIGHLOW:
val = read_le32(&pe_base[aoff]);
printk(FSP_DBG_LVL, "Adjusting %p %x -> %x\n",
printk(FSP_DBG_LVL, "Adjusting %p %" PRIX64 " -> %" PRIX64 "\n",
&pe_base[aoff], val, val + delta);
write_le32(&pe_base[aoff], val + delta);
break;
case EFI_IMAGE_REL_BASED_DIR64:
printk(BIOS_ERR, "Unsupported DIR64\n");
val = read_le64(&pe_base[aoff]);
printk(FSP_DBG_LVL, "Adjusting %p %" PRIX64 " -> %" PRIX64 "\n",
&pe_base[aoff], val, val + delta);
write_le64(&pe_base[aoff], val + delta);
break;
default:
printk(BIOS_ERR, "Unsupported relocation type %d\n",
@ -257,10 +271,13 @@ static int pe_relocate(uintptr_t new_addr, void *pe, void *fsp, size_t fih_off)
}
offset += sizeof(*rdata) * rnum;
}
printk(FSP_DBG_LVL, "Adjust Image Base %x->%x\n",
printk(FSP_DBG_LVL, "Adjust Image Base %" PRIX64 "->%" PRIX64 "\n",
img_base_off, img_base_off + delta);
img_base_off += delta;
write_le32(&ophdr->ImageBase, img_base_off);
if (ophdr)
write_le32(&ophdr->ImageBase, img_base_off);
else
write_le64(&ophdr64->ImageBase, img_base_off);
return 0;
}