From 22ac9670349e9db88e8138cd833fbbd120e9a6c2 Mon Sep 17 00:00:00 2001 From: Doug Goldstein Date: Thu, 26 Jan 2017 15:34:56 -0600 Subject: [PATCH 01/11] add support for EFI in prep_segment() NOTE: I need some feedback here on how to implement this within the style of iPXE. I've noticed that there's interfaces but those didn't seem to line up with moving prep_segment into there nor did any of the arch directories. The prep_segment function is called by the elf_load() function and its job is to ensure that the segment that is about to be loaded can be at the address it wants to be without trampling existing memory and then clears BSS. It uses the get_memmap() function which has been disabled on EFI so this provides an alternative that uses EFI's allocation functions to ensure that chunk of memory that the segment wants to be loaded at is available and clears BSS. Signed-off-by: Doug Goldstein --- src/image/segment.c | 49 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/image/segment.c b/src/image/segment.c index 2d0f2f0fc60..875379c1ebb 100644 --- a/src/image/segment.c +++ b/src/image/segment.c @@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * */ +#include #include #include #include @@ -49,6 +50,53 @@ struct errortab segment_errors[] __errortab = { __einfo_errortab ( EINFO_ERANGE_SEGMENT ), }; +#ifdef EFIAPI +/** + * Prepare segment for loading + * + * @v segment Segment start + * @v filesz Size of the "allocated bytes" portion of the segment + * @v memsz Size of the segment + * @ret rc Return status code + */ +int prep_segment ( userptr_t segment, size_t filesz, size_t memsz ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + unsigned int pages; + EFI_PHYSICAL_ADDRESS phys_addr; + physaddr_t start = user_to_phys ( segment, 0 ); + physaddr_t mid = user_to_phys ( segment, filesz ); + physaddr_t end = user_to_phys ( segment, memsz ); + + DBG ( "Preparing segment [%lx,%lx,%lx)\n", start, mid, end ); + + /* Sanity check */ + if ( filesz > memsz ) { + DBG ( "Insane segment [%lx,%lx,%lx)\n", start, mid, end ); + return -EINVAL; + } + + /* Start address of the segment so that we know where to allocate from */ + phys_addr = start; + /* Size of the segment in pages */ + pages = EFI_SIZE_TO_PAGES ( memsz ); + /* Allocate the memory via EFI to ensure its reserved */ + if ( bs->AllocatePages ( AllocateAddress, + EfiLoaderData, + pages, + &phys_addr ) != 0 ) { + /* No suitable memory region found */ + DBG ( "Segment [%lx,%lx,%lx) does not fit into available memory\n", + start, mid, end ); + return -ERANGE_SEGMENT; + } + + assert ( phys_to_user ( phys_addr ) == segment ); + + /* Found valid region: zero bss and return */ + memset_user ( segment, filesz, 0, ( memsz - filesz ) ); + return 0; +} +#else /** * Prepare segment for loading * @@ -93,3 +141,4 @@ int prep_segment ( userptr_t segment, size_t filesz, size_t memsz ) { start, mid, end ); return -ERANGE_SEGMENT; } +#endif /* EFIAPI */ From 36929d26d836f1aef83b593c2cb1ae37aed0e152 Mon Sep 17 00:00:00 2001 From: Doug Goldstein Date: Thu, 26 Jan 2017 15:34:57 -0600 Subject: [PATCH 02/11] let elf_load() provide load addr This allows elf_load() to return back the load address where this ELF is being loaded which is necessary for multiboot2 support. Signed-off-by: Doug Goldstein --- src/arch/x86/image/elfboot.c | 4 ++-- src/arch/x86/image/multiboot.c | 2 +- src/image/elf.c | 18 +++++++++++++----- src/include/ipxe/elf.h | 5 +++-- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/arch/x86/image/elfboot.c b/src/arch/x86/image/elfboot.c index dc35689293e..9a47e2cf2c5 100644 --- a/src/arch/x86/image/elfboot.c +++ b/src/arch/x86/image/elfboot.c @@ -51,7 +51,7 @@ static int elfboot_exec ( struct image *image ) { int rc; /* Load the image using core ELF support */ - if ( ( rc = elf_load ( image, &entry, &max ) ) != 0 ) { + if ( ( rc = elf_load ( image, NULL, &entry, &max ) ) != 0 ) { DBGC ( image, "ELF %p could not load: %s\n", image, strerror ( rc ) ); return rc; @@ -129,7 +129,7 @@ static int elfboot_probe ( struct image *image ) { /* Check that this image uses flat physical addressing */ if ( ( rc = elf_segments ( image, &ehdr, elfboot_check_segment, - &entry, &max ) ) != 0 ) { + NULL, &entry, &max ) ) != 0 ) { DBGC ( image, "Unloadable ELF image\n" ); return rc; } diff --git a/src/arch/x86/image/multiboot.c b/src/arch/x86/image/multiboot.c index 0c85df70864..c153bb7fd82 100644 --- a/src/arch/x86/image/multiboot.c +++ b/src/arch/x86/image/multiboot.c @@ -372,7 +372,7 @@ static int multiboot_load_elf ( struct image *image, physaddr_t *entry, int rc; /* Load ELF image*/ - if ( ( rc = elf_load ( image, entry, max ) ) != 0 ) { + if ( ( rc = elf_load ( image, NULL, entry, max ) ) != 0 ) { DBGC ( image, "MULTIBOOT %p ELF image failed to load: %s\n", image, strerror ( rc ) ); return rc; diff --git a/src/image/elf.c b/src/image/elf.c index 5c2f9db255d..f8e3b38e9c4 100644 --- a/src/image/elf.c +++ b/src/image/elf.c @@ -85,7 +85,7 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr, static int elf_segment ( struct image *image, Elf_Ehdr *ehdr, Elf_Phdr *phdr, int ( * process ) ( struct image *image, Elf_Phdr *phdr, physaddr_t dest ), - physaddr_t *entry, physaddr_t *max ) { + physaddr_t *load, physaddr_t *entry, physaddr_t *max ) { physaddr_t dest; physaddr_t end; unsigned long e_offset; @@ -123,6 +123,10 @@ static int elf_segment ( struct image *image, Elf_Ehdr *ehdr, Elf_Phdr *phdr, if ( ( rc = process ( image, phdr, dest ) ) != 0 ) return rc; + /* Set the load address if it hadn't been set yet */ + if ( load && *load == 0 ) + *load = dest; + /* Set execution address, if it lies within this segment */ if ( ( e_offset = ( ehdr->e_entry - dest ) ) < phdr->p_filesz ) { *entry = ehdr->e_entry; @@ -154,7 +158,7 @@ static int elf_segment ( struct image *image, Elf_Ehdr *ehdr, Elf_Phdr *phdr, int elf_segments ( struct image *image, Elf_Ehdr *ehdr, int ( * process ) ( struct image *image, Elf_Phdr *phdr, physaddr_t dest ), - physaddr_t *entry, physaddr_t *max ) { + physaddr_t *load, physaddr_t *entry, physaddr_t *max ) { Elf_Phdr phdr; Elf_Off phoff; unsigned int phnum; @@ -166,6 +170,10 @@ int elf_segments ( struct image *image, Elf_Ehdr *ehdr, /* Invalidate entry point */ *entry = 0; + /* Invalidate load address */ + if ( load ) + *load = 0; + /* Read and process ELF program headers */ for ( phoff = ehdr->e_phoff , phnum = ehdr->e_phnum ; phnum ; phoff += ehdr->e_phentsize, phnum-- ) { @@ -176,7 +184,7 @@ int elf_segments ( struct image *image, Elf_Ehdr *ehdr, } copy_from_user ( &phdr, image->data, phoff, sizeof ( phdr ) ); if ( ( rc = elf_segment ( image, ehdr, &phdr, process, - entry, max ) ) != 0 ) + load, entry, max ) ) != 0 ) return rc; } @@ -198,7 +206,7 @@ int elf_segments ( struct image *image, Elf_Ehdr *ehdr, * @ret max Maximum used address * @ret rc Return status code */ -int elf_load ( struct image *image, physaddr_t *entry, physaddr_t *max ) { +int elf_load ( struct image *image, physaddr_t *load, physaddr_t *entry, physaddr_t *max ) { static const uint8_t e_ident[] = { [EI_MAG0] = ELFMAG0, [EI_MAG1] = ELFMAG1, @@ -219,7 +227,7 @@ int elf_load ( struct image *image, physaddr_t *entry, physaddr_t *max ) { /* Load ELF segments into memory */ if ( ( rc = elf_segments ( image, &ehdr, elf_load_segment, - entry, max ) ) != 0 ) + load, entry, max ) ) != 0 ) return rc; return 0; diff --git a/src/include/ipxe/elf.h b/src/include/ipxe/elf.h index 033c3f7a80d..4d511de7cd8 100644 --- a/src/include/ipxe/elf.h +++ b/src/include/ipxe/elf.h @@ -22,7 +22,8 @@ typedef Elf32_Off Elf_Off; extern int elf_segments ( struct image *image, Elf_Ehdr *ehdr, int ( * process ) ( struct image *image, Elf_Phdr *phdr, physaddr_t dest ), - physaddr_t *entry, physaddr_t *max ); -extern int elf_load ( struct image *image, physaddr_t *entry, physaddr_t *max ); + physaddr_t *load, physaddr_t *entry, physaddr_t *max ); +extern int elf_load ( struct image *image, physaddr_t *load, + physaddr_t *entry, physaddr_t *max ); #endif /* _IPXE_ELF_H */ From e1bacfc0b750db0b1877bc8335478f9c06c0aae1 Mon Sep 17 00:00:00 2001 From: Jonathan Creekmore Date: Thu, 26 Jan 2017 15:34:58 -0600 Subject: [PATCH 03/11] add the GRUB multiboot2 header Import the multiboot2 header from GRUB where the official spec for multiboot2 lives. Signed-off-by: Jonathan Creekmore --- src/arch/x86/include/multiboot2.h | 417 ++++++++++++++++++++++++++++++ 1 file changed, 417 insertions(+) create mode 100644 src/arch/x86/include/multiboot2.h diff --git a/src/arch/x86/include/multiboot2.h b/src/arch/x86/include/multiboot2.h new file mode 100644 index 00000000000..2c93a2a6d01 --- /dev/null +++ b/src/arch/x86/include/multiboot2.h @@ -0,0 +1,417 @@ +/* multiboot2.h - Multiboot 2 header file. */ +/* Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY + * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef MULTIBOOT_HEADER +#define MULTIBOOT_HEADER 1 + +/* How many bytes from the start of the file we search for the header. */ +#define MULTIBOOT_SEARCH 32768 +#define MULTIBOOT_HEADER_ALIGN 8 + +/* The magic field should contain this. */ +#define MULTIBOOT2_HEADER_MAGIC 0xe85250d6 + +/* This should be in %eax. */ +#define MULTIBOOT2_BOOTLOADER_MAGIC 0x36d76289 + +/* Alignment of multiboot modules. */ +#define MULTIBOOT_MOD_ALIGN 0x00001000 + +/* Alignment of the multiboot info structure. */ +#define MULTIBOOT_INFO_ALIGN 0x00000008 + +/* Flags set in the 'flags' member of the multiboot header. */ + +#define MULTIBOOT_TAG_ALIGN 8 +#define MULTIBOOT_TAG_TYPE_END 0 +#define MULTIBOOT_TAG_TYPE_CMDLINE 1 +#define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME 2 +#define MULTIBOOT_TAG_TYPE_MODULE 3 +#define MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 4 +#define MULTIBOOT_TAG_TYPE_BOOTDEV 5 +#define MULTIBOOT_TAG_TYPE_MMAP 6 +#define MULTIBOOT_TAG_TYPE_VBE 7 +#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8 +#define MULTIBOOT_TAG_TYPE_ELF_SECTIONS 9 +#define MULTIBOOT_TAG_TYPE_APM 10 +#define MULTIBOOT_TAG_TYPE_EFI32 11 +#define MULTIBOOT_TAG_TYPE_EFI64 12 +#define MULTIBOOT_TAG_TYPE_SMBIOS 13 +#define MULTIBOOT_TAG_TYPE_ACPI_OLD 14 +#define MULTIBOOT_TAG_TYPE_ACPI_NEW 15 +#define MULTIBOOT_TAG_TYPE_NETWORK 16 +#define MULTIBOOT_TAG_TYPE_EFI_MMAP 17 +#define MULTIBOOT_TAG_TYPE_EFI_BS 18 +#define MULTIBOOT_TAG_TYPE_EFI32_IH 19 +#define MULTIBOOT_TAG_TYPE_EFI64_IH 20 +#define MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR 21 + +#define MULTIBOOT_HEADER_TAG_END 0 +#define MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 1 +#define MULTIBOOT_HEADER_TAG_ADDRESS 2 +#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS 3 +#define MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS 4 +#define MULTIBOOT_HEADER_TAG_FRAMEBUFFER 5 +#define MULTIBOOT_HEADER_TAG_MODULE_ALIGN 6 +#define MULTIBOOT_HEADER_TAG_EFI_BS 7 +#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI32 8 +#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64 9 +#define MULTIBOOT_HEADER_TAG_RELOCATABLE 10 + +#define MULTIBOOT_ARCHITECTURE_I386 0 +#define MULTIBOOT_ARCHITECTURE_MIPS32 4 +#define MULTIBOOT_HEADER_TAG_OPTIONAL 1 + +#define MULTIBOOT_LOAD_PREFERENCE_NONE 0 +#define MULTIBOOT_LOAD_PREFERENCE_LOW 1 +#define MULTIBOOT_LOAD_PREFERENCE_HIGH 2 + +#define MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED 1 +#define MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2 + +#ifndef ASM_FILE + +typedef unsigned char multiboot_uint8_t; +typedef unsigned short multiboot_uint16_t; +typedef unsigned int multiboot_uint32_t; +typedef unsigned long long multiboot_uint64_t; + +struct multiboot_header +{ + /* Must be MULTIBOOT_MAGIC - see above. */ + multiboot_uint32_t magic; + + /* ISA */ + multiboot_uint32_t architecture; + + /* Total header length. */ + multiboot_uint32_t header_length; + + /* The above fields plus this one must equal 0 mod 2^32. */ + multiboot_uint32_t checksum; +}; + +struct multiboot_header_tag +{ + multiboot_uint16_t type; + multiboot_uint16_t flags; + multiboot_uint32_t size; +}; + +struct multiboot_header_tag_information_request +{ + multiboot_uint16_t type; + multiboot_uint16_t flags; + multiboot_uint32_t size; + multiboot_uint32_t requests[0]; +}; + +struct multiboot_header_tag_address +{ + multiboot_uint16_t type; + multiboot_uint16_t flags; + multiboot_uint32_t size; + multiboot_uint32_t header_addr; + multiboot_uint32_t load_addr; + multiboot_uint32_t load_end_addr; + multiboot_uint32_t bss_end_addr; +}; + +struct multiboot_header_tag_entry_address +{ + multiboot_uint16_t type; + multiboot_uint16_t flags; + multiboot_uint32_t size; + multiboot_uint32_t entry_addr; +}; + +struct multiboot_header_tag_console_flags +{ + multiboot_uint16_t type; + multiboot_uint16_t flags; + multiboot_uint32_t size; + multiboot_uint32_t console_flags; +}; + +struct multiboot_header_tag_framebuffer +{ + multiboot_uint16_t type; + multiboot_uint16_t flags; + multiboot_uint32_t size; + multiboot_uint32_t width; + multiboot_uint32_t height; + multiboot_uint32_t depth; +}; + +struct multiboot_header_tag_module_align +{ + multiboot_uint16_t type; + multiboot_uint16_t flags; + multiboot_uint32_t size; +}; + +struct multiboot_header_tag_relocatable +{ + multiboot_uint16_t type; + multiboot_uint16_t flags; + multiboot_uint32_t size; + multiboot_uint32_t min_addr; + multiboot_uint32_t max_addr; + multiboot_uint32_t align; + multiboot_uint32_t preference; +}; + +struct multiboot_color +{ + multiboot_uint8_t red; + multiboot_uint8_t green; + multiboot_uint8_t blue; +}; + +struct multiboot_mmap_entry +{ + multiboot_uint64_t addr; + multiboot_uint64_t len; +#define MULTIBOOT_MEMORY_AVAILABLE 1 +#define MULTIBOOT_MEMORY_RESERVED 2 +#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3 +#define MULTIBOOT_MEMORY_NVS 4 +#define MULTIBOOT_MEMORY_BADRAM 5 + multiboot_uint32_t type; + multiboot_uint32_t zero; +}; +typedef struct multiboot_mmap_entry multiboot_memory_map_t; + +struct multiboot_tag +{ + multiboot_uint32_t type; + multiboot_uint32_t size; +}; + +struct multiboot_tag_string +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + char string[0]; +}; + +struct multiboot_tag_module +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t mod_start; + multiboot_uint32_t mod_end; + char cmdline[0]; +}; + +struct multiboot_tag_basic_meminfo +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t mem_lower; + multiboot_uint32_t mem_upper; +}; + +struct multiboot_tag_bootdev +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t biosdev; + multiboot_uint32_t slice; + multiboot_uint32_t part; +}; + +struct multiboot_tag_mmap +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t entry_size; + multiboot_uint32_t entry_version; + struct multiboot_mmap_entry entries[0]; +}; + +struct multiboot_vbe_info_block +{ + multiboot_uint8_t external_specification[512]; +}; + +struct multiboot_vbe_mode_info_block +{ + multiboot_uint8_t external_specification[256]; +}; + +struct multiboot_tag_vbe +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + + multiboot_uint16_t vbe_mode; + multiboot_uint16_t vbe_interface_seg; + multiboot_uint16_t vbe_interface_off; + multiboot_uint16_t vbe_interface_len; + + struct multiboot_vbe_info_block vbe_control_info; + struct multiboot_vbe_mode_info_block vbe_mode_info; +}; + +struct multiboot_tag_framebuffer_common +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + + multiboot_uint64_t framebuffer_addr; + multiboot_uint32_t framebuffer_pitch; + multiboot_uint32_t framebuffer_width; + multiboot_uint32_t framebuffer_height; + multiboot_uint8_t framebuffer_bpp; +#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0 +#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1 +#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2 + multiboot_uint8_t framebuffer_type; + multiboot_uint16_t reserved; +}; + +struct multiboot_tag_framebuffer +{ + struct multiboot_tag_framebuffer_common common; + + union + { + struct + { + multiboot_uint16_t framebuffer_palette_num_colors; + struct multiboot_color framebuffer_palette[0]; + }; + struct + { + multiboot_uint8_t framebuffer_red_field_position; + multiboot_uint8_t framebuffer_red_mask_size; + multiboot_uint8_t framebuffer_green_field_position; + multiboot_uint8_t framebuffer_green_mask_size; + multiboot_uint8_t framebuffer_blue_field_position; + multiboot_uint8_t framebuffer_blue_mask_size; + }; + }; +}; + +struct multiboot_tag_elf_sections +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t num; + multiboot_uint32_t entsize; + multiboot_uint32_t shndx; + char sections[0]; +}; + +struct multiboot_tag_apm +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint16_t version; + multiboot_uint16_t cseg; + multiboot_uint32_t offset; + multiboot_uint16_t cseg_16; + multiboot_uint16_t dseg; + multiboot_uint16_t flags; + multiboot_uint16_t cseg_len; + multiboot_uint16_t cseg_16_len; + multiboot_uint16_t dseg_len; +}; + +struct multiboot_tag_efi32 +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t pointer; +}; + +struct multiboot_tag_efi64 +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint64_t pointer; +}; + +struct multiboot_tag_smbios +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint8_t major; + multiboot_uint8_t minor; + multiboot_uint8_t reserved[6]; + multiboot_uint8_t tables[0]; +}; + +struct multiboot_tag_old_acpi +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint8_t rsdp[0]; +}; + +struct multiboot_tag_new_acpi +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint8_t rsdp[0]; +}; + +struct multiboot_tag_network +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint8_t dhcpack[0]; +}; + +struct multiboot_tag_efi_mmap +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t descr_size; + multiboot_uint32_t descr_vers; + multiboot_uint8_t efi_mmap[0]; +}; + +struct multiboot_tag_efi32_ih +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t pointer; +}; + +struct multiboot_tag_efi64_ih +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint64_t pointer; +}; + +struct multiboot_tag_load_base_addr +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t load_base_addr; +}; + +#endif /* ! ASM_FILE */ + +#endif /* ! MULTIBOOT_HEADER */ From 753deeef7153b44443135f11afa973ab95fb1700 Mon Sep 17 00:00:00 2001 From: Jonathan Creekmore Date: Thu, 26 Jan 2017 15:34:59 -0600 Subject: [PATCH 04/11] stub out multiboot2 support Signed-off-by: Jonathan Creekmore --- src/arch/x86/image/multiboot2.c | 76 +++++++++++++++++++++++++++++ src/arch/x86/include/bits/errfile.h | 1 + src/include/ipxe/features.h | 1 + 3 files changed, 78 insertions(+) create mode 100644 src/arch/x86/image/multiboot2.c diff --git a/src/arch/x86/image/multiboot2.c b/src/arch/x86/image/multiboot2.c new file mode 100644 index 00000000000..503a549b614 --- /dev/null +++ b/src/arch/x86/image/multiboot2.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2016 Star Lab Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** + * @file + * + * Multiboot2 image format + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +FEATURE ( FEATURE_IMAGE, "MBOOT2", DHCP_EB_FEATURE_MULTIBOOT2, 1 ); + +/** + * Execute multiboot2 image + * + * @v image Multiboot image + * @ret rc Return status code + */ +static int multiboot2_exec ( struct image *image ) { + (void)image; + return -ENOEXEC; +} + +/** + * Probe multiboot2 image + * + * @v image Multiboot file + * @ret rc Return status code + */ +static int multiboot2_probe ( struct image *image ) { + (void)image; + return -ENOEXEC; +} + +/** Multiboot image type */ +struct image_type multiboot2_image_type __image_type ( PROBE_MULTIBOOT2 ) = { + .name = "Multiboot 2", + .probe = multiboot2_probe, + .exec = multiboot2_exec, +}; diff --git a/src/arch/x86/include/bits/errfile.h b/src/arch/x86/include/bits/errfile.h index 8ae3e23e1c4..ef0ad95fd4d 100644 --- a/src/arch/x86/include/bits/errfile.h +++ b/src/arch/x86/include/bits/errfile.h @@ -43,6 +43,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_sdi ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000b0000 ) #define ERRFILE_initrd ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000c0000 ) #define ERRFILE_pxe_call ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000d0000 ) +#define ERRFILE_multiboot2 ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000e0000 ) #define ERRFILE_landing_zone ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000f0000 ) #define ERRFILE_undi ( ERRFILE_ARCH | ERRFILE_NET | 0x00000000 ) diff --git a/src/include/ipxe/features.h b/src/include/ipxe/features.h index e86a2d226cf..985c4146a7e 100644 --- a/src/include/ipxe/features.h +++ b/src/include/ipxe/features.h @@ -55,6 +55,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define DHCP_EB_FEATURE_MENU 0x27 /**< Menu support */ #define DHCP_EB_FEATURE_SDI 0x28 /**< SDI image support */ #define DHCP_EB_FEATURE_NFS 0x29 /**< NFS protocol */ +#define DHCP_EB_FEATURE_MULTIBOOT2 0x2a /**< Multiboot2 format */ /** @} */ From 46ddedfdfc960e14eaa632fdb5cfa098fc262f64 Mon Sep 17 00:00:00 2001 From: Jonathan Creekmore Date: Thu, 26 Jan 2017 15:35:00 -0600 Subject: [PATCH 05/11] implement the ability to load mb2 images Add the ability to load multiboot2 images on EFI only at this time. This has been tested with Xen 4.9 using their multiboot2 support. Signed-off-by: Jonathan Creekmore --- src/arch/x86/image/multiboot2.c | 558 +++++++++++++++++++++++++++++++- 1 file changed, 554 insertions(+), 4 deletions(-) diff --git a/src/arch/x86/image/multiboot2.c b/src/arch/x86/image/multiboot2.c index 503a549b614..851b178ca29 100644 --- a/src/arch/x86/image/multiboot2.c +++ b/src/arch/x86/image/multiboot2.c @@ -41,11 +41,436 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include +#ifdef EFIAPI +#include +#endif FEATURE ( FEATURE_IMAGE, "MBOOT2", DHCP_EB_FEATURE_MULTIBOOT2, 1 ); +/** + * Maximum multiboot2 boot information size + */ +#define MB_MAX_BOOTINFO_SIZE 4096 + +/** Multiboot2 boot information buffer */ +static union { + uint64_t align; + char bib[MB_MAX_BOOTINFO_SIZE]; +} mb2_bib; + +/** A multiboot2 header descriptor */ +struct multiboot2_header_info { + /** The actual multiboot2 header */ + struct multiboot_header mb; + /** Offset of header within the multiboot2 image */ + size_t offset; +}; + +/** + * Find multiboot2 header + * + * @v image Multiboot file + * @v hdr Multiboot header descriptor to fill in + * @ret rc Return status code + */ +static int multiboot2_find_header ( struct image *image, + struct multiboot2_header_info *hdr ) { + uint32_t buf[64]; + size_t offset; + unsigned int buf_idx; + uint32_t checksum; + + /* Scan through first MULTIBOOT_SEARCH of image file 256 bytes at a time. + * (Use the buffering to avoid the overhead of a + * copy_from_user() for every dword.) + */ + for ( offset = 0 ; offset < MULTIBOOT_SEARCH ; offset += sizeof ( buf[0] ) ) { + /* Check for end of image */ + if ( offset > image->len ) + break; + /* Refill buffer if applicable */ + buf_idx = ( ( offset % sizeof ( buf ) ) / sizeof ( buf[0] ) ); + if ( buf_idx == 0 ) { + copy_from_user ( buf, image->data, offset, + sizeof ( buf ) ); + } + /* Check signature */ + if ( buf[buf_idx] != MULTIBOOT2_HEADER_MAGIC ) + continue; + /* Copy header and verify checksum */ + copy_from_user ( &hdr->mb, image->data, offset, + sizeof ( hdr->mb ) ); + checksum = ( hdr->mb.magic + hdr->mb.architecture + hdr->mb.header_length + + hdr->mb.checksum ); + if ( checksum != 0 ) + continue; + + /* Make sure that the multiboot architecture is x86 */ + if (hdr->mb.architecture != MULTIBOOT_ARCHITECTURE_I386) { + return -ENOEXEC; + } + + /* Record offset of multiboot header and return */ + hdr->offset = offset; + return 0; + } + + /* No multiboot header found */ + return -ENOEXEC; +} + +struct multiboot2_tags { + int module_align; + int boot_services; + + int entry_addr_valid; + int entry_addr_efi32_valid; + int entry_addr_efi64_valid; + int relocatable_valid; + + uint32_t entry_addr; + uint32_t entry_addr_efi32; + uint32_t entry_addr_efi64; + uint32_t reloc_min_addr; + uint32_t reloc_max_addr; + uint32_t reloc_align; + uint32_t reloc_preference; +}; + +static int multiboot2_validate_inforeq ( struct image *image, size_t offset, size_t num_reqs ) { + uint32_t inforeq; + + while (num_reqs) { + copy_from_user ( &inforeq, image->data, offset, sizeof ( inforeq ) ); + offset += sizeof(inforeq); + num_reqs--; + + switch (inforeq) { + case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO: + case MULTIBOOT_TAG_TYPE_MMAP: + continue; + + default: + return -ENOTSUP; + } + } + + return 0; +} + +static int multiboot2_validate_tags ( struct image *image, struct multiboot2_header_info *hdr, + struct multiboot2_tags *tags ) { + size_t offset = hdr->offset + sizeof(struct multiboot_header); + size_t end_offset = offset + hdr->mb.header_length; + struct multiboot_header_tag tag; + + /* Clear out the multiboot2 tags structure */ + memset(tags, 0, sizeof(*tags)); + + while (offset < end_offset) { + copy_from_user ( &tag, image->data, offset, sizeof ( tag ) ); + + DBGC ( image, "MULTIBOOT2 %p (offset: %d) TAG type: %x flags: %x size: %d\n", image, + (int)(offset - hdr->offset), tag.type, tag.flags, tag.size ); + + if (tag.type == MULTIBOOT_HEADER_TAG_END) { + DBGC ( image, "MULTIBOOT2 %p tag end\n", image ); + return 0; + } + + switch (tag.type) { + case MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST: + { + size_t num_inforeqs; + + DBGC ( image, "MULTIBOOT2 %p has an information request tag\n", + image ); + + num_inforeqs = (tag.size - sizeof(tag)) / sizeof(uint32_t); + + if (multiboot2_validate_inforeq ( image, offset + sizeof(tag), num_inforeqs ) != 0) { + DBGC ( image, "MULTIBOOT2 %p cannot support all information request tags\n", + image ); + return -ENOTSUP; + } + + break; + } + case MULTIBOOT_HEADER_TAG_ADDRESS: + DBGC ( image, "MULTIBOOT2 %p has an address tag\n", + image ); + + if ((tag.flags & MULTIBOOT_HEADER_TAG_OPTIONAL) != MULTIBOOT_HEADER_TAG_OPTIONAL) + return -ENOTSUP; + + break; + + case MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS: + { + struct multiboot_header_tag_entry_address mb_tag = { 0 }; + copy_from_user ( &mb_tag, image->data, offset, tag.size ); + + DBGC ( image, "MULTIBOOT2 %p has an entry address tag\n", + image ); + + tags->entry_addr_valid = 1; + tags->entry_addr = mb_tag.entry_addr; + break; + } + case MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS: + DBGC ( image, "MULTIBOOT2 %p has a console flags tag\n", + image ); + + if ((tag.flags & MULTIBOOT_HEADER_TAG_OPTIONAL) != MULTIBOOT_HEADER_TAG_OPTIONAL) + return -ENOTSUP; + + break; + + case MULTIBOOT_HEADER_TAG_FRAMEBUFFER: + DBGC ( image, "MULTIBOOT2 %p has a framebuffer tag\n", + image ); + + if ((tag.flags & MULTIBOOT_HEADER_TAG_OPTIONAL) != MULTIBOOT_HEADER_TAG_OPTIONAL) + return -ENOTSUP; + + break; + + case MULTIBOOT_HEADER_TAG_MODULE_ALIGN: + DBGC ( image, "MULTIBOOT2 %p has a module align tag\n", + image ); + tags->module_align = 1; + break; + + case MULTIBOOT_HEADER_TAG_EFI_BS: + DBGC ( image, "MULTIBOOT2 %p has a boot services tag\n", + image ); + tags->boot_services = 1; + break; + + case MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI32: + { + struct multiboot_header_tag_entry_address mb_tag = { 0 }; + copy_from_user ( &mb_tag, image->data, offset, tag.size ); + + DBGC ( image, "MULTIBOOT2 %p has an entry address EFI32 tag\n", + image ); + + tags->entry_addr_efi32_valid = 1; + tags->entry_addr_efi32 = mb_tag.entry_addr; + break; + } + case MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64: + { + struct multiboot_header_tag_entry_address mb_tag = { 0 }; + copy_from_user ( &mb_tag, image->data, offset, tag.size ); + + DBGC ( image, "MULTIBOOT2 %p has an entry address EFI64 tag: %x\n", + image, mb_tag.entry_addr ); + + tags->entry_addr_efi64_valid = 1; + tags->entry_addr_efi64 = mb_tag.entry_addr; + break; + } + case MULTIBOOT_HEADER_TAG_RELOCATABLE: + { + struct multiboot_header_tag_relocatable mb_tag = { 0 }; + copy_from_user ( &mb_tag, image->data, offset, tag.size ); + + DBGC ( image, "MULTIBOOT2 %p has a relocatable tag\n", + image ); + + tags->relocatable_valid = 1; + tags->reloc_min_addr = mb_tag.min_addr; + tags->reloc_max_addr = mb_tag.max_addr; + tags->reloc_align = mb_tag.align; + tags->reloc_preference = mb_tag.preference; + break; + } + default: + DBGC ( image, "MULTIBOOT2 %p unknown tag %x\n", + image, tag.type ); + return -ENOTSUP; + } + + offset += tag.size + (MULTIBOOT_TAG_ALIGN - 1); + offset = offset & ~(MULTIBOOT_TAG_ALIGN - 1); + } + + /* If we did not get a MULTIBOOT_HEADER_TAG_END, fail out */ + DBGC ( image, "MULTIBOOT %p missing tag end\n", image ); + return -ENOTSUP; +} + +/** + * Add bootloader into bib + */ +static size_t multiboot2_add_bootloader ( struct image *image, size_t offset ) { + struct multiboot_tag_string *bootloader = (struct multiboot_tag_string *)&mb2_bib.bib[offset]; + size_t remaining = MB_MAX_BOOTINFO_SIZE - offset - sizeof(*bootloader); + size_t len; + char *buf = bootloader->string; + + len = ( snprintf ( buf, remaining, "iPXE %s", product_version ) + 1 /* NUL */ ); + if ( len > remaining ) + len = remaining; + + DBGC ( image, "MULTIBOOT2 %p bootloader: %s\n", image, bootloader->string ); + + bootloader->type = MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME; + bootloader->size = len + sizeof(*bootloader); + return bootloader->size; +} + +/** + * Add command line into bib + */ +static size_t multiboot2_add_cmdline ( struct image *image, size_t offset ) { + struct multiboot_tag_string *cmdline = (struct multiboot_tag_string *)&mb2_bib.bib[offset]; + size_t remaining = MB_MAX_BOOTINFO_SIZE - offset - sizeof(*cmdline); + size_t len; + char *buf = cmdline->string; + + cmdline->type = MULTIBOOT_TAG_TYPE_CMDLINE; + cmdline->size = sizeof(*cmdline); + + /* Copy image URI to base memory buffer as start of command line */ + len = ( format_uri ( image->uri, buf, remaining ) + 1 /* NUL */ ); + if ( len > remaining ) + len = remaining; + buf += len; + remaining -= len; + cmdline->size += len; + + /* Copy command line to base memory buffer, if present */ + if ( image->cmdline ) { + buf--; + cmdline->size--; + remaining++; + len = ( snprintf ( buf, remaining, " %s", image->cmdline ) + 1 /* NUL */ ); + if ( len > remaining ) + len = remaining; + } + + DBGC ( image, "MULTIBOOT2 %p cmdline: %s\n", image, cmdline->string ); + + cmdline->size += len; + return cmdline->size; +} + +/** + * Load multiboot2 image into memory + * + * @v image Multiboot file + * @v hdr Multiboot header descriptor + * @ret entry Entry point + * @ret max Maximum used address + * @ret rc Return status code + */ +static int multiboot2_load ( struct image *image, struct multiboot2_tags *tags, + physaddr_t *load, physaddr_t *entry, physaddr_t *max ) { + + int rc; + + if ( ( rc = elf_load ( image, load, entry, max ) ) < 0 ) { + DBGC ( image, "MULTIBOOT2 %p could not load elf image\n", image ); + return rc; + } + *entry = tags->entry_addr_efi64; + + return rc; +} + +static size_t adjust_tag_offset(size_t offset) { + if ((offset & 7) != 0) { + return ((offset + 8) & ~7); + } + return offset; +} + +/** + * Add multiboot modules + */ +static size_t multiboot2_add_modules ( struct image *image, size_t offset ) { + struct image *module_image; + struct multiboot_tag_module *module; + char *buf; + size_t remaining; + size_t len; + userptr_t memory; + + /* Add each image as a multiboot module */ + for_each_image ( module_image ) { + + /* Do not include kernel image itself as a module */ + if ( module_image == image ) + continue; + + memory = umalloc ( module_image->len ); + if ( memory == UNULL ) { + DBGC ( image, "MULTIBOOT2 %p could not allocate %zd bytes.\n", module_image, module_image->len ); + return 0; + } + + memcpy_user ( memory, 0, module_image->data, 0, module_image->len ); + + /* Add module to list */ + module = (struct multiboot_tag_module *)&mb2_bib.bib[offset]; + module->type = MULTIBOOT_TAG_TYPE_MODULE; + module->size = sizeof(*module); + module->mod_start = memory; + module->mod_end = ( memory + module_image->len ); + + buf = module->cmdline; + remaining = MB_MAX_BOOTINFO_SIZE - offset - sizeof(*module); + + /* Copy image URI to base memory buffer as start of command line */ + len = ( format_uri ( module_image->uri, buf, remaining ) + 1 /* NUL */ ); + if ( len > remaining ) + len = remaining; + buf += len; + remaining -= len; + module->size += len; + + /* Copy command line to base memory buffer, if present */ + if ( module_image->cmdline ) { + buf--; + module->size--; + remaining++; + len = ( snprintf ( buf, remaining, " %s", module_image->cmdline ) + 1 /* NUL */ ); + if ( len > remaining ) + len = remaining; + module->size += len; + } + + offset += module->size; + offset = adjust_tag_offset(offset); + + DBGC ( image, "MULTIBOOT2 %p module %s is [%x,%x): %s\n", + image, module_image->name, module->mod_start, + module->mod_end, module->cmdline ); + } + + return offset; +} + +void multiboot2_boot(uint32_t *bib, uint32_t entry) { +#ifdef EFIAPI + __asm__ __volatile__ ( "push %%rbp\n\t" + "call *%%rdi\n\t" + "pop %%rbp\n\t" + : : "a" ( MULTIBOOT2_BOOTLOADER_MAGIC ), + "b" ( bib ), + "D" ( entry ) + : "rcx", "rdx", "rsi", "memory" ); +#else + (void)bib; + (void)entry; +#endif +} + /** * Execute multiboot2 image * @@ -53,8 +478,123 @@ FEATURE ( FEATURE_IMAGE, "MBOOT2", DHCP_EB_FEATURE_MULTIBOOT2, 1 ); * @ret rc Return status code */ static int multiboot2_exec ( struct image *image ) { - (void)image; - return -ENOEXEC; + struct multiboot2_header_info hdr; + struct multiboot2_tags mb_tags; + struct multiboot_tag *tag; + struct multiboot_tag_load_base_addr *load_base_addr_tag; +#ifdef EFIAPI + struct multiboot_tag_efi64 *tag_efi64; +#endif + uint32_t *total_size; + uint32_t *reserved; + physaddr_t load; + physaddr_t entry; + physaddr_t max; + size_t offset; + int rc; + + /* Locate multiboot2 header, if present */ + if ( ( rc = multiboot2_find_header ( image, &hdr ) ) != 0 ) { + DBGC ( image, "MULTIBOOT2 %p has no multiboot header\n", + image ); + return rc; + } + + /* Abort if we detect tags that we cannot support */ + if ( ( rc = multiboot2_validate_tags ( image, &hdr, &mb_tags ) ) != 0 ) { + DBGC ( image, "MULTIBOOT2 %p contains unsupported tags\n", + image ); + return -ENOTSUP; + } + + /* Attempt to load the image into memory of our choosing */ + if ( ( rc = multiboot2_load ( image, &mb_tags, &load, &entry, &max ) ) != 0) { + DBGC ( image, "MULTIBOOT2 %p could not load\n", image ); + return rc; + } + + /* Populate multiboot information structure */ + offset = 0; + + total_size = (uint32_t *)&mb2_bib.bib[offset]; + offset += sizeof(*total_size); + + reserved = (uint32_t *)&mb2_bib.bib[offset]; + offset += sizeof(*reserved); + + /* Clear out the reserved word */ + *reserved = 0; + + /* Add the load base address tag */ + load_base_addr_tag = (struct multiboot_tag_load_base_addr *)&mb2_bib.bib[offset]; + load_base_addr_tag->type = MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR; + load_base_addr_tag->size = sizeof(*load_base_addr_tag); + load_base_addr_tag->load_base_addr = load; + offset += load_base_addr_tag->size; + offset = adjust_tag_offset(offset); + +#ifdef EFIAPI + /* Add the EFI boot services not terminated tag */ + tag = (struct multiboot_tag *)&mb2_bib.bib[offset]; + tag->type = MULTIBOOT_TAG_TYPE_EFI_BS; + tag->size = sizeof(*tag); + offset += tag->size; + offset = adjust_tag_offset(offset); + + /* Add the EFI 64-bit image handle pointer */ + tag_efi64 = (struct multiboot_tag_efi64 *)&mb2_bib.bib[offset]; + tag_efi64->type = MULTIBOOT_TAG_TYPE_EFI64_IH; + tag_efi64->size = sizeof(*tag_efi64); + tag_efi64->pointer = (multiboot_uint64_t)efi_image_handle; + offset += tag_efi64->size; + offset = adjust_tag_offset(offset); + + /* Add the EFI 64-bit system table handle pointer */ + tag_efi64 = (struct multiboot_tag_efi64 *)&mb2_bib.bib[offset]; + tag_efi64->type = MULTIBOOT_TAG_TYPE_EFI64; + tag_efi64->size = sizeof(*tag_efi64); + tag_efi64->pointer = (multiboot_uint64_t)efi_systab; + offset += tag_efi64->size; + offset = adjust_tag_offset(offset); +#endif + + /* add the boot command line */ + offset += multiboot2_add_cmdline ( image, offset ); + offset = adjust_tag_offset(offset); + + /* add the bootloader */ + offset += multiboot2_add_bootloader ( image, offset ); + offset = adjust_tag_offset(offset); + + /* Add the modules */ + offset = multiboot2_add_modules ( image, offset ); + offset = adjust_tag_offset(offset); + + /* Terminate the tags */ + tag = (struct multiboot_tag *)&mb2_bib.bib[offset]; + tag->type = 0; + tag->size = sizeof(*tag); + offset += tag->size; + + *total_size = offset; + + DBGC ( image, "MULTIBOOT2 %p BIB is %d bytes\n", image, *total_size ); + + /* Multiboot images may not return and have no callback + * interface, so shut everything down prior to booting the OS. + */ + shutdown_boot(); + + /* Jump to OS with flat physical addressing */ + DBGC ( image, "MULTIBOOT2 %p starting execution at %lx\n", image, entry ); + + multiboot2_boot ( total_size, entry ); + DBGC ( image, "MULTIBOOT2 %p returned\n", image ); + + /* It isn't safe to continue after calling shutdown() */ + while ( 1 ) {} + + return -ECANCELED; /* -EIMPOSSIBLE, anyone? */ } /** @@ -64,8 +604,18 @@ static int multiboot2_exec ( struct image *image ) { * @ret rc Return status code */ static int multiboot2_probe ( struct image *image ) { - (void)image; - return -ENOEXEC; + struct multiboot2_header_info hdr; + int rc; + + /* Locate multiboot2 header, if present */ + if ( ( rc = multiboot2_find_header ( image, &hdr ) ) != 0 ) { + DBGC ( image, "MULTIBOOT2 %p has no multiboot2 header\n", + image ); + return rc; + } + DBGC ( image, "MULTIBOOT2 %p found header with architecture %08x and header_length %d\n", + image, hdr.mb.architecture, hdr.mb.header_length ); + return 0; } /** Multiboot image type */ From fe0536912dd3426dc9bb464cea40c071e8629e3f Mon Sep 17 00:00:00 2001 From: Jonathan Creekmore Date: Thu, 26 Jan 2017 15:35:01 -0600 Subject: [PATCH 06/11] add support for probing mb2 images on EFI This adds support for probing for multiboot2 images when booting from EFI. Signed-off-by: Jonathan Creekmore --- src/config/config.c | 3 +++ src/config/defaults/efi.h | 1 + src/include/ipxe/image.h | 15 ++++++++++++--- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/config/config.c b/src/config/config.c index 2ca05dff7d7..3c80363fd3e 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -156,6 +156,9 @@ REQUIRE_OBJECT ( elfboot ); #ifdef IMAGE_MULTIBOOT REQUIRE_OBJECT ( multiboot ); #endif +#ifdef IMAGE_MULTIBOOT2 +REQUIRE_OBJECT ( multiboot2 ); +#endif #ifdef IMAGE_PXE REQUIRE_OBJECT ( pxe_image ); #endif diff --git a/src/config/defaults/efi.h b/src/config/defaults/efi.h index 53a7a7b4bd4..59ad7854004 100644 --- a/src/config/defaults/efi.h +++ b/src/config/defaults/efi.h @@ -28,6 +28,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define IMAGE_EFI /* EFI image support */ #define IMAGE_SCRIPT /* iPXE script image support */ +#define IMAGE_MULTIBOOT2 /* Multiboot2 image support */ #define SANBOOT_PROTO_ISCSI /* iSCSI protocol */ #define SANBOOT_PROTO_AOE /* AoE protocol */ diff --git a/src/include/ipxe/image.h b/src/include/ipxe/image.h index 2e7eb4cee39..f0bc8c50c06 100644 --- a/src/include/ipxe/image.h +++ b/src/include/ipxe/image.h @@ -115,18 +115,27 @@ struct image_type { struct asn1_cursor **cursor ); }; +/** + * Multiboot2 image probe priority + * + * Multiboot2 images are also valid executables in another format + * (e.g. ELF) AND might also have multiboot headers on them, so we + * must perform the multiboot2 probe first. + */ +#define PROBE_MULTIBOOT2 01 + /** * Multiboot image probe priority * * Multiboot images are also valid executables in another format * (e.g. ELF), so we must perform the multiboot probe first. */ -#define PROBE_MULTIBOOT 01 +#define PROBE_MULTIBOOT 02 /** * Normal image probe priority */ -#define PROBE_NORMAL 02 +#define PROBE_NORMAL 03 /** * PXE image probe priority @@ -134,7 +143,7 @@ struct image_type { * PXE images have no signature checks, so will claim all image files. * They must therefore be tried last in the probe order list. */ -#define PROBE_PXE 03 +#define PROBE_PXE 04 /** Executable image type table */ #define IMAGE_TYPES __table ( struct image_type, "image_types" ) From 1d09143f499c8309d65008de2438dce73a9a321d Mon Sep 17 00:00:00 2001 From: Krystian Hebel Date: Wed, 18 Mar 2020 22:17:24 +0100 Subject: [PATCH 07/11] [image] add LZ support for Multiboot2 kernels Memory information is missing. ELF format is assumed. Signed-off-by: Krystian Hebel --- src/arch/x86/image/bzimage.c | 3 ++- src/arch/x86/image/landing_zone.c | 9 ++++--- src/arch/x86/image/multiboot2.c | 41 ++++++++++++++++++++++------- src/arch/x86/include/landing_zone.h | 5 +++- src/config/defaults/pcbios.h | 1 + 5 files changed, 44 insertions(+), 15 deletions(-) diff --git a/src/arch/x86/image/bzimage.c b/src/arch/x86/image/bzimage.c index 6bfac770ebb..18d9bf05ec8 100644 --- a/src/arch/x86/image/bzimage.c +++ b/src/arch/x86/image/bzimage.c @@ -673,7 +673,8 @@ static int bzimage_exec ( struct image *image ) { */ bzimg.pm_sz = ( bzimg.pm_sz + LZ_ALIGN - 1 ) & ~( LZ_ALIGN - 1 ); - lz_set_bzimage ( lz, bzimg.rm_kernel, bzimg.pm_kernel + bzimg.pm_sz ); + lz_set ( lz, bzimg.rm_kernel, bzimg.pm_kernel + bzimg.pm_sz, + LZ_PROTO_LINUX_BOOT ); bzimg.pm_sz += SLB_SIZE; } diff --git a/src/arch/x86/image/landing_zone.c b/src/arch/x86/image/landing_zone.c index f5f8701e36a..65910c9a49e 100644 --- a/src/arch/x86/image/landing_zone.c +++ b/src/arch/x86/image/landing_zone.c @@ -18,8 +18,8 @@ struct sl_header { struct lz_header { u8 uuid[16]; - u32 slaunch_loader_size; - u32 zero_page_addr; + u32 boot_protocol; + u32 proto_struct; u32 event_log_addr; u32 event_log_size; u8 msb_key_hash[20]; @@ -52,7 +52,7 @@ static physaddr_t target; * @v image LZ file * @v zeropage Address of zero page */ -int lz_set_bzimage ( struct image *image, userptr_t zeropage, userptr_t tgt ) { +int lz_set ( struct image *image, userptr_t zeropage, userptr_t tgt, int proto ) { target = user_to_phys ( tgt, 0 ); int rc; @@ -73,7 +73,8 @@ int lz_set_bzimage ( struct image *image, userptr_t zeropage, userptr_t tgt ) { DBGC ( image, "LZ %p writing zeropage address: 0x%lx\n", image, user_to_phys ( zeropage, 0 ) ); - hdr->zero_page_addr = user_to_phys ( zeropage, 0 ); + hdr->boot_protocol = proto; + hdr->proto_struct = user_to_phys ( zeropage, 0 ); struct drtm_t *drtm = ( struct drtm_t *) acpi_find ( ACPI_SIGNATURE ('D', 'R', 'T', 'M'), 0 ); diff --git a/src/arch/x86/image/multiboot2.c b/src/arch/x86/image/multiboot2.c index 851b178ca29..2439196b43b 100644 --- a/src/arch/x86/image/multiboot2.c +++ b/src/arch/x86/image/multiboot2.c @@ -34,6 +34,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include #include @@ -378,7 +379,11 @@ static int multiboot2_load ( struct image *image, struct multiboot2_tags *tags, DBGC ( image, "MULTIBOOT2 %p could not load elf image\n", image ); return rc; } +#ifdef EFIAPI *entry = tags->entry_addr_efi64; +#else + (void)tags; +#endif return rc; } @@ -457,18 +462,13 @@ static size_t multiboot2_add_modules ( struct image *image, size_t offset ) { } void multiboot2_boot(uint32_t *bib, uint32_t entry) { -#ifdef EFIAPI - __asm__ __volatile__ ( "push %%rbp\n\t" - "call *%%rdi\n\t" - "pop %%rbp\n\t" + __asm__ __volatile__ ( "push %%ebp\n\t" + "call *%%edi\n\t" + "pop %%ebp\n\t" : : "a" ( MULTIBOOT2_BOOTLOADER_MAGIC ), "b" ( bib ), "D" ( entry ) - : "rcx", "rdx", "rsi", "memory" ); -#else - (void)bib; - (void)entry; -#endif + : "ecx", "edx", "esi", "memory" ); } /** @@ -485,6 +485,7 @@ static int multiboot2_exec ( struct image *image ) { #ifdef EFIAPI struct multiboot_tag_efi64 *tag_efi64; #endif + struct image *lz; uint32_t *total_size; uint32_t *reserved; physaddr_t load; @@ -513,6 +514,19 @@ static int multiboot2_exec ( struct image *image ) { return rc; } + if ( ( lz = find_image ( "landing_zone" ) ) != NULL ) { + unregister_image ( image_get ( lz ) ); + + max = ( max + LZ_ALIGN - 1 ) & ~( LZ_ALIGN - 1 ); + + lz_set ( lz, ( userptr_t ) mb2_bib.bib, phys_to_user ( max ), + LZ_PROTO_MULTIBOOT2 ); + /* Doesn't seem that max is used anywhere... Can LZ and kernel be + * overwritten by modules? + */ + max += SLB_SIZE; + } + /* Populate multiboot information structure */ offset = 0; @@ -570,6 +584,8 @@ static int multiboot2_exec ( struct image *image ) { offset = multiboot2_add_modules ( image, offset ); offset = adjust_tag_offset(offset); + /* TODO: provide memory information */ + /* Terminate the tags */ tag = (struct multiboot_tag *)&mb2_bib.bib[offset]; tag->type = 0; @@ -585,6 +601,13 @@ static int multiboot2_exec ( struct image *image ) { */ shutdown_boot(); + if ( lz != NULL ) { + register_image ( lz ); + image_put ( lz ); + + return image_replace ( lz ); + } + /* Jump to OS with flat physical addressing */ DBGC ( image, "MULTIBOOT2 %p starting execution at %lx\n", image, entry ); diff --git a/src/arch/x86/include/landing_zone.h b/src/arch/x86/include/landing_zone.h index f2e7763ea38..fdc19139e6c 100644 --- a/src/arch/x86/include/landing_zone.h +++ b/src/arch/x86/include/landing_zone.h @@ -16,7 +16,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define LZ_ALIGN ( 64 * 1024 ) #define SLB_SIZE ( 64 * 1024 ) -int lz_set_bzimage ( struct image *image, userptr_t zeropage, physaddr_t tgt ); +#define LZ_PROTO_LINUX_BOOT 0 +#define LZ_PROTO_MULTIBOOT2 2 + +int lz_set ( struct image *image, userptr_t zeropage, physaddr_t tgt, int proto ); #endif /* _LANDING_ZONE_H */ diff --git a/src/config/defaults/pcbios.h b/src/config/defaults/pcbios.h index 21821c95cb0..83d60bbb4d0 100644 --- a/src/config/defaults/pcbios.h +++ b/src/config/defaults/pcbios.h @@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define IMAGE_ELF /* ELF image support */ #define IMAGE_MULTIBOOT /* MultiBoot image support */ +#define IMAGE_MULTIBOOT2 /* MultiBoot image support */ #define IMAGE_PXE /* PXE image support */ #define IMAGE_SCRIPT /* iPXE script image support */ #define IMAGE_BZIMAGE /* Linux bzImage image support */ From 869ff31932fee5d65f9f3729d836599bc2d8314e Mon Sep 17 00:00:00 2001 From: Krystian Hebel Date: Wed, 18 Mar 2020 23:24:56 +0100 Subject: [PATCH 08/11] multiboot2: use physical addresses for modules Signed-off-by: Krystian Hebel --- src/arch/x86/image/multiboot2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/arch/x86/image/multiboot2.c b/src/arch/x86/image/multiboot2.c index 2439196b43b..25c3be00c77 100644 --- a/src/arch/x86/image/multiboot2.c +++ b/src/arch/x86/image/multiboot2.c @@ -425,8 +425,8 @@ static size_t multiboot2_add_modules ( struct image *image, size_t offset ) { module = (struct multiboot_tag_module *)&mb2_bib.bib[offset]; module->type = MULTIBOOT_TAG_TYPE_MODULE; module->size = sizeof(*module); - module->mod_start = memory; - module->mod_end = ( memory + module_image->len ); + module->mod_start = user_to_phys ( memory, 0 ); + module->mod_end = user_to_phys ( memory, module_image->len ); buf = module->cmdline; remaining = MB_MAX_BOOTINFO_SIZE - offset - sizeof(*module); From 2cdc7223caef128c492e8665f1c348339ddc32e7 Mon Sep 17 00:00:00 2001 From: Krystian Hebel Date: Thu, 19 Mar 2020 19:14:39 +0100 Subject: [PATCH 09/11] multiboot2: pass kernel size in the reserved field of MBI structure This assumes that only the first section of ELF file is to be measured. LZ should clear the reserved file after reading kernel size. Signed-off-by: Krystian Hebel --- src/arch/x86/image/multiboot2.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/arch/x86/image/multiboot2.c b/src/arch/x86/image/multiboot2.c index 25c3be00c77..23f5a094949 100644 --- a/src/arch/x86/image/multiboot2.c +++ b/src/arch/x86/image/multiboot2.c @@ -602,6 +602,9 @@ static int multiboot2_exec ( struct image *image ) { shutdown_boot(); if ( lz != NULL ) { + Elf_Ehdr *Ehdr = (Elf_Ehdr *) image->data; + Elf_Phdr *Phdr = (Elf_Phdr *) ( image->data + Ehdr->e_phoff ); + *reserved = Phdr->p_filesz; register_image ( lz ); image_put ( lz ); From c25cb6a1959899e5819c6ed53ece489afaa87639 Mon Sep 17 00:00:00 2001 From: Krystian Hebel Date: Thu, 27 Aug 2020 13:14:58 +0200 Subject: [PATCH 10/11] image/landing_zone: pass information to LZ using tags Signed-off-by: Krystian Hebel --- src/arch/x86/image/landing_zone.c | 153 ++++++++++++++++++++++++++---- 1 file changed, 136 insertions(+), 17 deletions(-) diff --git a/src/arch/x86/image/landing_zone.c b/src/arch/x86/image/landing_zone.c index 65910c9a49e..968674631bf 100644 --- a/src/arch/x86/image/landing_zone.c +++ b/src/arch/x86/image/landing_zone.c @@ -9,21 +9,22 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include +#include +#include #include struct sl_header { - u16 lz_offet; - u16 lz_length; + u16 lz_entry_point; + u16 bootloader_data_offset; + u16 lz_info_offset; } __attribute__ (( packed )); -struct lz_header { +struct lz_info { u8 uuid[16]; - u32 boot_protocol; - u32 proto_struct; - u32 event_log_addr; - u32 event_log_size; - u8 msb_key_hash[20]; - u8 lz_hashes[]; + u32 version; + u16 msb_key_algo; + u8 msb_key_hash[]; } __attribute__ (( packed )); const unsigned char @@ -44,6 +45,58 @@ struct drtm_t { u8 var_len_fields[]; } __attribute__ (( packed )); +#define LZ_TAG_CLASS_MASK 0xF0 + +/* Tags with no particular class */ +#define LZ_TAG_NO_CLASS 0x00 +#define LZ_TAG_END 0x00 +#define LZ_TAG_UNAWARE_OS 0x01 +#define LZ_TAG_TAGS_SIZE 0x0F /* Always first */ + +/* Tags specifying kernel type */ +#define LZ_TAG_BOOT_CLASS 0x10 +#define LZ_TAG_BOOT_LINUX 0x10 +#define LZ_TAG_BOOT_MB2 0x11 + +/* Tags specific to TPM event log */ +#define LZ_TAG_EVENT_LOG_CLASS 0x20 +#define LZ_TAG_EVENT_LOG 0x20 +#define LZ_TAG_HASH 0x21 + +struct lz_tag_hdr { + u8 type; + u8 len; +} __attribute__ (( packed )); + +struct lz_tag_tags_size { + struct lz_tag_hdr hdr; + u16 size; +} __attribute__ (( packed )); + +struct lz_tag_boot_linux { + struct lz_tag_hdr hdr; + u32 zero_page; +} __attribute__ (( packed )); + +struct lz_tag_boot_mb2 { + struct lz_tag_hdr hdr; + u32 mbi; + u32 kernel_size; +} __attribute__ (( packed )); + +struct lz_tag_evtlog { + struct lz_tag_hdr hdr; + u32 address; + u32 size; +} __attribute__ (( packed )); + +struct lz_tag_hash { + struct lz_tag_hdr hdr; + u16 algo_id; + u8 digest[]; +} __attribute__ (( packed )); + + static physaddr_t target; /** @@ -68,24 +121,89 @@ int lz_set ( struct image *image, userptr_t zeropage, userptr_t tgt, int proto ) memcpy_user ( tgt, 0, image->data, 0, image->len ); struct sl_header *sl_hdr = ( struct sl_header *) tgt; - struct lz_header *hdr = ( struct lz_header *) ( tgt + sl_hdr->lz_length ); + struct lz_tag_tags_size *tags = ( struct lz_tag_tags_size *) + ( tgt + sl_hdr->bootloader_data_offset ); + + /* Tags header */ + tags->hdr.type = LZ_TAG_TAGS_SIZE; + tags->hdr.len = sizeof(struct lz_tag_tags_size); + tags->size = sizeof(struct lz_tag_tags_size); + + /* Hashes of LZ */ + { + u8 buff[SHA256_CTX_SIZE]; /* SHA1_CTX_SIZE is smaller */ + struct lz_tag_hash *h = ((void *)tags) + tags->size; + h->hdr.type = LZ_TAG_HASH; + h->hdr.len = sizeof(struct lz_tag_hash) + SHA256_DIGEST_SIZE; + h->algo_id = 0x000B; + sha256_algorithm.init ( buff ); + sha256_algorithm.update ( buff, (void *) tgt, + sl_hdr->bootloader_data_offset ); + sha256_algorithm.final ( buff, h->digest ); + tags->size += h->hdr.len; + + h = ((void *)tags) + tags->size; + h->hdr.type = LZ_TAG_HASH; + h->hdr.len = sizeof(struct lz_tag_hash) + SHA1_DIGEST_SIZE; + h->algo_id = 0x0004; + sha1_algorithm.init ( buff ); + sha1_algorithm.update ( buff, (void *) tgt, + sl_hdr->bootloader_data_offset ); + sha1_algorithm.final ( buff, h->digest ); + tags->size += h->hdr.len; + } + /* Boot protocol data */ DBGC ( image, "LZ %p writing zeropage address: 0x%lx\n", image, user_to_phys ( zeropage, 0 ) ); - hdr->boot_protocol = proto; - hdr->proto_struct = user_to_phys ( zeropage, 0 ); + switch (proto) { + case LZ_PROTO_LINUX_BOOT: + { + struct lz_tag_boot_linux *b = ((void *)tags) + tags->size; + b->hdr.type = LZ_TAG_BOOT_LINUX; + b->hdr.len = sizeof(struct lz_tag_boot_linux); + b->zero_page = user_to_phys ( zeropage, 0 ); + tags->size += b->hdr.len; + break; + } + case LZ_PROTO_MULTIBOOT2: + { + struct lz_tag_boot_mb2 *b = ((void *)tags) + tags->size; + b->hdr.type = LZ_TAG_BOOT_MB2; + b->hdr.len = sizeof(struct lz_tag_boot_mb2); + b->mbi = user_to_phys ( zeropage, 0 ); + b->kernel_size = 0; + tags->size += b->hdr.len; + break; + + } + default: + return 1; + } + /* DRTM Event log address and size */ struct drtm_t *drtm = ( struct drtm_t *) acpi_find ( ACPI_SIGNATURE ('D', 'R', 'T', 'M'), 0 ); if ( drtm != UNULL ) { DBGC ( image, "ACPI DRTM table at %p (0x%lx physical)\n", drtm, user_to_phys ( ( userptr_t ) drtm, 0 ) ); - hdr->event_log_addr = drtm->Log_Area_Start; - hdr->event_log_size = drtm->Log_Area_Length; + + struct lz_tag_evtlog *e = ((void *)tags) + tags->size; + e->hdr.type = LZ_TAG_EVENT_LOG; + e->hdr.len = sizeof(struct lz_tag_evtlog); + e->address = drtm->Log_Area_Start; + e->size = drtm->Log_Area_Length; + tags->size += e->hdr.len; } + /* Mark end of tags */ + struct lz_tag_hdr *end = ((void *)tags) + tags->size; + end->type = LZ_TAG_END; + end->len = sizeof(struct lz_tag_hdr); + tags->size += end->len; + return 0; } @@ -151,6 +269,7 @@ static int lz_exec ( struct image *image ) { /* There is no way for the image to return, since we provide * no return address. */ + DBGC ( image, "LZ %p SKINIT returned\n", image ); assert ( 0 ); return -ECANCELED; /* -EIMPOSSIBLE */ @@ -165,7 +284,7 @@ static int lz_exec ( struct image *image ) { static int lz_probe ( struct image *image ) { int rc; struct sl_header sl_hdr; - struct lz_header hdr; + struct lz_info lzi; uint32_t eax, ebx, ecx, edx; cpuid ( CPUID_AMD_CHECK, 0, &eax, &ebx, &ecx, &edx ); @@ -187,9 +306,9 @@ static int lz_probe ( struct image *image ) { return -ENOEXEC; } copy_from_user ( &sl_hdr, image->data, 0, sizeof ( sl_hdr ) ); - copy_from_user ( &hdr, image->data, sl_hdr.lz_length, sizeof ( hdr ) ); + copy_from_user ( &lzi, image->data, sl_hdr.lz_info_offset, sizeof ( lzi ) ); - rc = memcmp ( hdr.uuid, lz_header_uuid, sizeof ( lz_header_uuid ) ); + rc = memcmp ( lzi.uuid, lz_header_uuid, sizeof ( lz_header_uuid ) ); if ( rc == 0 ) { image_set_name ( image, "landing_zone" ); From e1a6a92b4ad9ec5790eb4227619994fd756f5e8a Mon Sep 17 00:00:00 2001 From: Krystian Hebel Date: Wed, 2 Sep 2020 15:54:59 +0200 Subject: [PATCH 11/11] image/multiboot2: pass kernel size and entry point to LZ in lz_set() call mb2_bib structure is not yet filled, so it was used to pass that information Signed-off-by: Krystian Hebel --- src/arch/x86/image/landing_zone.c | 5 ++++- src/arch/x86/image/multiboot2.c | 10 ++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/arch/x86/image/landing_zone.c b/src/arch/x86/image/landing_zone.c index 968674631bf..929f449d264 100644 --- a/src/arch/x86/image/landing_zone.c +++ b/src/arch/x86/image/landing_zone.c @@ -81,6 +81,7 @@ struct lz_tag_boot_linux { struct lz_tag_boot_mb2 { struct lz_tag_hdr hdr; u32 mbi; + u32 kernel_entry; u32 kernel_size; } __attribute__ (( packed )); @@ -170,10 +171,12 @@ int lz_set ( struct image *image, userptr_t zeropage, userptr_t tgt, int proto ) case LZ_PROTO_MULTIBOOT2: { struct lz_tag_boot_mb2 *b = ((void *)tags) + tags->size; + physaddr_t *args = (physaddr_t *)zeropage; b->hdr.type = LZ_TAG_BOOT_MB2; b->hdr.len = sizeof(struct lz_tag_boot_mb2); b->mbi = user_to_phys ( zeropage, 0 ); - b->kernel_size = 0; + b->kernel_entry = args[0]; + b->kernel_size = args[1]; tags->size += b->hdr.len; break; diff --git a/src/arch/x86/image/multiboot2.c b/src/arch/x86/image/multiboot2.c index 23f5a094949..69cb2ebcf66 100644 --- a/src/arch/x86/image/multiboot2.c +++ b/src/arch/x86/image/multiboot2.c @@ -515,11 +515,16 @@ static int multiboot2_exec ( struct image *image ) { } if ( ( lz = find_image ( "landing_zone" ) ) != NULL ) { + physaddr_t *args = (physaddr_t *) &mb2_bib; unregister_image ( image_get ( lz ) ); max = ( max + LZ_ALIGN - 1 ) & ~( LZ_ALIGN - 1 ); - lz_set ( lz, ( userptr_t ) mb2_bib.bib, phys_to_user ( max ), + args[0] = entry; + Elf_Ehdr *Ehdr = (Elf_Ehdr *) image->data; + Elf_Phdr *Phdr = (Elf_Phdr *) ( image->data + Ehdr->e_phoff ); + args[1] = Phdr->p_filesz; + lz_set ( lz, ( userptr_t ) &mb2_bib, phys_to_user ( max ), LZ_PROTO_MULTIBOOT2 ); /* Doesn't seem that max is used anywhere... Can LZ and kernel be * overwritten by modules? @@ -602,9 +607,6 @@ static int multiboot2_exec ( struct image *image ) { shutdown_boot(); if ( lz != NULL ) { - Elf_Ehdr *Ehdr = (Elf_Ehdr *) image->data; - Elf_Phdr *Phdr = (Elf_Phdr *) ( image->data + Ehdr->e_phoff ); - *reserved = Phdr->p_filesz; register_image ( lz ); image_put ( lz );