Felix Held has submitted this change. ( https://review.coreboot.org/c/coreboot/+/82680?usp=email )
Change subject: commonlib/fsp_relocate: Add PE32+ support ......................................................................
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 --- M src/commonlib/fsp_relocate.c 1 file changed, 39 insertions(+), 22 deletions(-)
Approvals: Subrata Banik: Looks good to me, approved build bot (Jenkins): Verified
diff --git a/src/commonlib/fsp_relocate.c b/src/commonlib/fsp_relocate.c index f57e278..0bf50b4 100644 --- a/src/commonlib/fsp_relocate.c +++ b/src/commonlib/fsp_relocate.c @@ -160,16 +160,17 @@
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 @@
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 @@ 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 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, "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, "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 @@ 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 @@ } 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; }