summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Rudolph <patrick.rudolph@9elements.com>2024-05-27 16:09:59 +0200
committerFelix Held <felix-coreboot@felixheld.de>2024-06-21 15:49:38 +0000
commitf40f5b6dd5274f02bb0c84d05ed1cf112e1187e6 (patch)
treed186f0a22cbafe67c223ccdd95e4896a25acc1ec
parentf725c24c37b8ab6a0020fb7a0848fd715c9a7fc9 (diff)
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>
-rw-r--r--src/commonlib/fsp_relocate.c61
1 files changed, 39 insertions, 22 deletions
diff --git a/src/commonlib/fsp_relocate.c b/src/commonlib/fsp_relocate.c
index f57e278cf0..0bf50b497e 100644
--- a/src/commonlib/fsp_relocate.c
+++ b/src/commonlib/fsp_relocate.c
@@ -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;
}