diff options
Diffstat (limited to 'src/commonlib')
-rw-r--r-- | src/commonlib/fsp_relocate.c | 61 |
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; } |