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:
parent
f725c24c37
commit
f40f5b6dd5
@ -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)
|
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_DOS_HEADER *doshdr;
|
||||||
EFI_IMAGE_OPTIONAL_HEADER32 *ophdr;
|
EFI_IMAGE_OPTIONAL_HEADER32 *ophdr;
|
||||||
|
EFI_IMAGE_OPTIONAL_HEADER64 *ophdr64;
|
||||||
FSP_INFO_HEADER *fih;
|
FSP_INFO_HEADER *fih;
|
||||||
uint32_t roffset, rsize;
|
uint32_t roffset, rsize;
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
uint8_t *pe_base = pe;
|
uint8_t *pe_base = pe;
|
||||||
uint32_t image_base;
|
uint64_t image_base;
|
||||||
uint32_t img_base_off;
|
uint64_t img_base_off;
|
||||||
uint32_t delta;
|
uint64_t delta;
|
||||||
|
|
||||||
doshdr = pe;
|
doshdr = pe;
|
||||||
if (read_le16(&doshdr->e_magic) != EFI_IMAGE_DOS_SIGNATURE) {
|
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);
|
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");
|
printk(BIOS_ERR, "Invalid PE32 header\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ophdr = &peih->OptionalHeader;
|
ophdr = &peih->Pe32.OptionalHeader;
|
||||||
|
ophdr64 = &peih->Pe32Plus.OptionalHeader;
|
||||||
|
|
||||||
if (read_le16(&ophdr->Magic) != EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
|
if (read_le16(&ophdr->Magic) == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
|
||||||
printk(BIOS_ERR, "No support for non-PE32 images\n");
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,21 +203,26 @@ static int pe_relocate(uintptr_t new_addr, void *pe, void *fsp, size_t fih_off)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
image_base = read_le32(&fih->ImageBase);
|
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;
|
delta = new_addr - image_base;
|
||||||
|
|
||||||
img_base_off = read_le32(&ophdr->ImageBase);
|
img_base_off = ophdr ? read_le32(&ophdr->ImageBase) : read_le64(&ophdr64->ImageBase);
|
||||||
printk(FSP_DBG_LVL, "lfanew 0x%x, delta-0x%x, FSP Base 0x%x, NT32ImageBase 0x%x, offset 0x%x\n",
|
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),
|
read_le32(&doshdr->e_lfanew),
|
||||||
delta, image_base, img_base_off,
|
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);
|
printk(FSP_DBG_LVL, "relocation table at offset-%x,size=%x\n", roffset, rsize);
|
||||||
// TODO - add support for PE32+ also
|
|
||||||
|
|
||||||
offset = roffset;
|
offset = roffset;
|
||||||
while (offset < (roffset + rsize)) {
|
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 roff = reloc_offset(rdata[i]);
|
||||||
uint16_t rtype = reloc_type(rdata[i]);
|
uint16_t rtype = reloc_type(rdata[i]);
|
||||||
uint32_t aoff = vaddr + roff;
|
uint32_t aoff = vaddr + roff;
|
||||||
uint32_t val;
|
uint64_t val;
|
||||||
printk(FSP_DBG_LVL, "\t\treloc type %x offset %x aoff %x, base-0x%x\n",
|
printk(FSP_DBG_LVL, "\t\treloc type %x offset %x aoff %x, base-0x%" PRIX64 "\n",
|
||||||
rtype, roff, aoff, img_base_off);
|
rtype, roff, aoff, img_base_off);
|
||||||
switch (rtype) {
|
switch (rtype) {
|
||||||
case EFI_IMAGE_REL_BASED_ABSOLUTE:
|
case EFI_IMAGE_REL_BASED_ABSOLUTE:
|
||||||
continue;
|
continue;
|
||||||
case EFI_IMAGE_REL_BASED_HIGHLOW:
|
case EFI_IMAGE_REL_BASED_HIGHLOW:
|
||||||
val = read_le32(&pe_base[aoff]);
|
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);
|
&pe_base[aoff], val, val + delta);
|
||||||
write_le32(&pe_base[aoff], val + delta);
|
write_le32(&pe_base[aoff], val + delta);
|
||||||
break;
|
break;
|
||||||
case EFI_IMAGE_REL_BASED_DIR64:
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
printk(BIOS_ERR, "Unsupported relocation type %d\n",
|
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;
|
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, img_base_off + delta);
|
||||||
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user