@@ -91,7 +91,7 @@ $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
SETUP_OBJS = $(addprefix $(obj)/,$(setup-y))
-sed-zoffset := -e 's/^\([0-9a-fA-F]*\) [a-zA-Z] \(startup_32\|startup_64\|efi32_stub_entry\|efi64_stub_entry\|efi_pe_entry\|efi32_pe_entry\|efi_boot_params\|input_data\|kernel_info\|_end\|_ehead\|_text\|z_.*\)$$/\#define ZO_\2 0x\1/p'
+sed-zoffset := -e 's/^\([0-9a-fA-F]*\) [a-zA-Z] \(startup_32\|startup_64\|efi32_stub_entry\|efi64_stub_entry\|efi_pe_entry\|efi32_pe_entry\|efi_boot_params\|input_data\|kernel_info\|_end\|_data\|z_.*\)$$/\#define ZO_\2 0x\1/p'
quiet_cmd_zoffset = ZOFFSET $@
cmd_zoffset = $(NM) $< | sed -n $(sed-zoffset) > $@
@@ -47,6 +47,8 @@ SYSSEG = 0x1000 /* historical load address >> 4 */
#
.long LINUX_PE_MAGIC
.long pe_header
+
+ .align 8
pe_header:
.long PE_MAGIC
@@ -75,16 +77,13 @@ optional_header:
.byte 0x02 # MajorLinkerVersion
.byte 0x14 # MinorLinkerVersion
- # Filled in by build.c
+ # All of these are filled in by build.c
.long 0 # SizeOfCode
-
.long 0 # SizeOfInitializedData
.long 0 # SizeOfUninitializedData
-
- # Filled in by build.c
.long 0x0000 # AddressOfEntryPoint
+ .long 0x0000 # BaseOfCode
- .long 0x0200 # BaseOfCode
#ifdef CONFIG_X86_32
.long 0 # data
#endif
@@ -97,8 +96,8 @@ extra_header_fields:
#else
.quad image_base # ImageBase
#endif
- .long 0x20 # SectionAlignment
- .long 0x20 # FileAlignment
+ .long 0x1000 # SectionAlignment
+ .long 0x200 # FileAlignment
.word 0 # MajorOperatingSystemVersion
.word 0 # MinorOperatingSystemVersion
.word LINUX_EFISTUB_MAJOR_VERSION # MajorImageVersion
@@ -143,26 +142,6 @@ extra_header_fields:
# Section table
section_table:
- #
- # The offset & size fields are filled in by build.c.
- #
- .ascii ".setup"
- .byte 0
- .byte 0
- .long 0
- .long 0x0 # startup_{32,64}
- .long 0 # Size of initialized data
- # on disk
- .long 0x0 # startup_{32,64}
- .long 0 # PointerToRelocations
- .long 0 # PointerToLineNumbers
- .word 0 # NumberOfRelocations
- .word 0 # NumberOfLineNumbers
- .long IMAGE_SCN_CNT_CODE | \
- IMAGE_SCN_MEM_READ | \
- IMAGE_SCN_MEM_EXECUTE | \
- IMAGE_SCN_ALIGN_16BYTES # Characteristics
-
#
# The EFI application loader requires a relocation section
# because EFI applications must be relocatable. The .reloc
@@ -181,8 +160,7 @@ section_table:
.word 0 # NumberOfLineNumbers
.long IMAGE_SCN_CNT_INITIALIZED_DATA | \
IMAGE_SCN_MEM_READ | \
- IMAGE_SCN_MEM_DISCARDABLE | \
- IMAGE_SCN_ALIGN_1BYTES # Characteristics
+ IMAGE_SCN_MEM_DISCARDABLE # Characteristics
#ifdef CONFIG_EFI_MIXED
#
@@ -200,8 +178,7 @@ section_table:
.word 0 # NumberOfLineNumbers
.long IMAGE_SCN_CNT_INITIALIZED_DATA | \
IMAGE_SCN_MEM_READ | \
- IMAGE_SCN_MEM_DISCARDABLE | \
- IMAGE_SCN_ALIGN_1BYTES # Characteristics
+ IMAGE_SCN_MEM_DISCARDABLE # Characteristics
#endif
#
@@ -222,8 +199,27 @@ section_table:
.word 0 # NumberOfLineNumbers
.long IMAGE_SCN_CNT_CODE | \
IMAGE_SCN_MEM_READ | \
- IMAGE_SCN_MEM_EXECUTE | \
- IMAGE_SCN_ALIGN_16BYTES # Characteristics
+ IMAGE_SCN_MEM_EXECUTE # Characteristics
+
+ #
+ # The offset & size fields are filled in by build.c.
+ #
+ .ascii ".data"
+ .byte 0
+ .byte 0
+ .byte 0
+ .long 0
+ .long 0x0 # startup_{32,64}
+ .long 0 # Size of initialized data
+ # on disk
+ .long 0x0 # startup_{32,64}
+ .long 0 # PointerToRelocations
+ .long 0 # PointerToLineNumbers
+ .word 0 # NumberOfRelocations
+ .word 0 # NumberOfLineNumbers
+ .long IMAGE_SCN_CNT_INITIALIZED_DATA | \
+ IMAGE_SCN_MEM_READ | \
+ IMAGE_SCN_MEM_WRITE # Characteristics
.set section_count, (. - section_table) / 40
#endif /* CONFIG_EFI_STUB */
@@ -57,19 +57,20 @@ typedef unsigned int u32;
#define SECTOR_SIZE 512
#define FILE_ALIGNMENT 512
#define SECTION_ALIGNMENT 4096
+#define BASE_RVA 0x1000
/* This must be large enough to hold the entire setup */
u8 buf[SETUP_SECT_MAX*SECTOR_SIZE];
-#define PECOFF_RELOC_RESERVE 0x20
+#define PECOFF_RELOC_RESERVE round_up(0x20, FILE_ALIGNMENT)
#ifdef CONFIG_EFI_MIXED
-#define PECOFF_COMPAT_RESERVE 0x20
+#define PECOFF_COMPAT_RESERVE round_up(0x20, FILE_ALIGNMENT)
#else
#define PECOFF_COMPAT_RESERVE 0x0
#endif
-#define RELOC_SECTION_SIZE 10
+#define RELOC_SECTION_SIZE 12
/* PE header has different format depending on the architecture */
#ifdef CONFIG_X86_64
@@ -110,7 +111,7 @@ static unsigned long efi32_pe_entry;
static unsigned long efi_boot_params;
static unsigned long kernel_info;
static unsigned long startup_64;
-static unsigned long _ehead;
+static unsigned long _data;
static unsigned long _end;
/*----------------------------------------------------------------------*/
@@ -251,7 +252,7 @@ static void *map_output_file(const char *path, size_t size)
#ifdef CONFIG_EFI_STUB
-static void update_pecoff_section_header_fields(char *section_name, u32 vma, u32 size, u32 datasz, u32 offset)
+static void update_pecoff_section_header(char *section_name, u32 vma, u32 size, u32 datasz, u32 offset)
{
unsigned short num_sections;
struct section_header *section;
@@ -281,32 +282,44 @@ static void update_pecoff_section_header_fields(char *section_name, u32 vma, u32
}
}
-static void update_pecoff_section_header(char *section_name, u32 offset, u32 size)
-{
- update_pecoff_section_header_fields(section_name, offset, size, size, offset);
-}
-static void update_pecoff_setup_and_reloc(unsigned int size)
+static unsigned int update_pecoff_reloc_and_compat(unsigned int setup_size)
{
- u32 setup_offset = SECTOR_SIZE;
- u32 reloc_offset = size - PECOFF_RELOC_RESERVE - PECOFF_COMPAT_RESERVE;
+ unsigned int current_rva = BASE_RVA;
+ struct data_directory *dir;
+ u32 reloc_offset = setup_size - PECOFF_RELOC_RESERVE - PECOFF_COMPAT_RESERVE;
+ u32 reloc_memsz = round_up(PECOFF_RELOC_RESERVE, SECTION_ALIGNMENT);
+
#ifdef CONFIG_EFI_MIXED
u32 compat_offset = reloc_offset + PECOFF_RELOC_RESERVE;
+ u32 compat_memsz = round_up(PECOFF_COMPAT_RESERVE, SECTION_ALIGNMENT);
#endif
- u32 setup_size = reloc_offset - setup_offset;
- update_pecoff_section_header(".setup", setup_offset, setup_size);
- update_pecoff_section_header(".reloc", reloc_offset, PECOFF_RELOC_RESERVE);
+ update_pecoff_section_header(".reloc", current_rva, reloc_memsz,
+ PECOFF_RELOC_RESERVE, reloc_offset);
+
+ /* Update PE data directory to point to '.reloc' section */
+ dir = (struct data_directory *)(get_pe_opt_header(buf) + 1);
+ put_unaligned_le32(current_rva, &dir->base_relocations.virtual_address);
+ put_unaligned_le32(RELOC_SECTION_SIZE, &dir->base_relocations.size);
/*
- * Modify .reloc section contents with a single entry. The
- * relocation is applied to offset 10 of the relocation section.
+ * Modify .reloc section contents with two no-op entries. The
+ * relocation is applied to offset 12 of the relocation section.
+ * There are two entries since, according to the PE documentation,
+ * every base relocation block should start on 32-bit boundary.
+ * There is only one block, but some loaders incorrectly check
+ * the size to always be 32-bit aligned even on the last block.
*/
- put_unaligned_le32(reloc_offset + RELOC_SECTION_SIZE, &buf[reloc_offset]);
+ put_unaligned_le32(current_rva + RELOC_SECTION_SIZE, &buf[reloc_offset]);
put_unaligned_le32(RELOC_SECTION_SIZE, &buf[reloc_offset + 4]);
+ current_rva += reloc_memsz;
+
#ifdef CONFIG_EFI_MIXED
- update_pecoff_section_header(".compat", compat_offset, PECOFF_COMPAT_RESERVE);
+ update_pecoff_section_header(".compat", current_rva, compat_memsz,
+ PECOFF_COMPAT_RESERVE, compat_offset);
+ current_rva += compat_memsz;
/*
* Put the IA-32 machine type (0x14c) and the associated entry point
@@ -316,47 +329,56 @@ static void update_pecoff_setup_and_reloc(unsigned int size)
buf[compat_offset] = 0x1;
buf[compat_offset + 1] = 0x8;
put_unaligned_le16(IMAGE_FILE_MACHINE_I386, &buf[compat_offset + 2]);
- put_unaligned_le32(efi32_pe_entry + size, &buf[compat_offset + 4]);
+ put_unaligned_le32(efi32_pe_entry + setup_size, &buf[compat_offset + 4]);
#endif
+ return current_rva;
}
-static unsigned int update_pecoff_sections(unsigned int text_start, unsigned int text_sz,
- unsigned int init_sz)
+static void update_pecoff_sections(unsigned int setup_sz,
+ unsigned int text_sz,
+ unsigned int file_sz,
+ unsigned int image_sz)
{
- unsigned int file_sz = text_start + text_sz;
- unsigned int bss_sz = init_sz - file_sz;
+ unsigned int current_rva;
pe_opt_hdr *hdr = get_pe_opt_header(buf);
- /*
- * The PE/COFF loader may load the image at an address which is
- * misaligned with respect to the kernel_alignment field in the setup
- * header.
- *
- * In order to avoid relocating the kernel to correct the misalignment,
- * add slack to allow the buffer to be aligned within the declared size
- * of the image.
- */
- bss_sz += CONFIG_PHYSICAL_ALIGN;
- init_sz += CONFIG_PHYSICAL_ALIGN;
+ current_rva = update_pecoff_reloc_and_compat(setup_sz);
- /*
- * Size of code: Subtract the size of the first sector (512 bytes)
- * which includes the header.
- */
- put_unaligned_le32(file_sz - SECTOR_SIZE + bss_sz, &hdr->text_size);
+ /* Update sizes inside PE header: */
- /* Size of image */
- put_unaligned_le32(init_sz, &hdr->image_size);
+ /* Text size*/
+ put_unaligned_le32(text_sz, &hdr->text_size);
/*
- * Address of entry point for PE/COFF executable
+ * Initialized data size.
+ * Consider .compat, .reloc and .data sections as data
*/
- put_unaligned_le32(text_start + efi_pe_entry, &hdr->entry_point);
+ put_unaligned_le32(current_rva - BASE_RVA + file_sz - text_sz,
+ &hdr->data_size);
+
+ /* Uninialized data size */
+ put_unaligned_le32(image_sz - file_sz, &hdr->bss_size);
+
+ /* Total image size. Consider all rections and headers. */
+ put_unaligned_le32(current_rva + image_sz, &hdr->image_size);
+
+ /* Address of entry point for PE/COFF executable */
+ put_unaligned_le32(current_rva + efi_pe_entry, &hdr->entry_point);
+
+ /* Base of the text section */
+ put_unaligned_le32(current_rva, &hdr->code_base);
- update_pecoff_section_header_fields(".text", text_start, text_sz + bss_sz,
- text_sz, text_start);
+ /* Update PE sections offsets: */
+
+ /* Text section */
+ update_pecoff_section_header(".text", current_rva, text_sz,
+ text_sz, setup_sz);
+ current_rva += text_sz;
+
+ /* Text section */
+ update_pecoff_section_header(".data", current_rva, image_sz - text_sz,
+ file_sz - text_sz, setup_sz + text_sz);
- return text_start + file_sz;
}
static int reserve_pecoff_reloc_section(int c)
@@ -397,10 +419,10 @@ static void efi_stub_entry_update(void)
#else
-static inline void update_pecoff_setup_and_reloc(unsigned int size) {}
-static inline void update_pecoff_text(unsigned int text_start,
- unsigned int file_sz,
- unsigned int init_sz) {}
+static unsigned int update_pecoff_sections(unsigned int setup_sz,
+ unsigned int text_sz,
+ unsigned int file_sz,
+ unsigned int image_sz) {}
static inline void efi_stub_update_defaults(void) {}
static inline void efi_stub_entry_update(void) {}
@@ -447,7 +469,7 @@ static void parse_zoffset(char *fname)
PARSE_ZOFS(p, efi_boot_params);
PARSE_ZOFS(p, kernel_info);
PARSE_ZOFS(p, startup_64);
- PARSE_ZOFS(p, _ehead);
+ PARSE_ZOFS(p, _data);
PARSE_ZOFS(p, _end);
p = strchr(p, '\n');
@@ -506,7 +528,6 @@ int main(int argc, char **argv)
size_t kern_file_size;
unsigned int setup_size;
unsigned int setup_sectors;
- unsigned int init_size;
unsigned int total_size;
unsigned int kern_size;
void *kernel;
@@ -534,7 +555,6 @@ int main(int argc, char **argv)
#ifdef CONFIG_EFI_STUB
/* PE specification require 512-byte minimum section file alignment */
kern_size = round_up(kern_file_size + 4, FILE_ALIGNMENT);
- update_pecoff_setup_and_reloc(setup_size);
#else
/* Number of 16-byte paragraphs, including space for a 4-byte CRC */
kern_size = round_up(kern_file_size + 4, PARAGRAPH_SIZE);
@@ -547,36 +567,12 @@ int main(int argc, char **argv)
/* Update kernel_info_offset. */
put_unaligned_le32(kernel_info, &setup_header[0x77]);
- init_size = get_unaligned_le32(&setup_header[0x6F]);
-
#ifdef CONFIG_EFI_STUB
- /*
- * The decompression buffer will start at ImageBase. When relocating
- * the compressed kernel to its end, we must ensure that the head
- * section does not get overwritten. The head section occupies
- * [i, i + _ehead), and the destination is [init_sz - _end, init_sz).
- *
- * At present these should never overlap, because 'i' is at most 32k
- * because of SETUP_SECT_MAX, '_ehead' is less than 1k, and the
- * calculation of INIT_SIZE in boot/header.S ensures that
- * 'init_sz - _end' is at least 64k.
- *
- * For future-proofing, increase init_sz if necessary.
- */
-
- if (init_size - _end < setup_size + _ehead) {
- init_size = round_up(setup_size + _ehead + _end, SECTION_ALIGNMENT);
- put_unaligned_le32(init_size, &setup_header[0x6F]);
- }
-
- total_size = update_pecoff_sections(setup_size, kern_size, init_size);
-
+ update_pecoff_sections(setup_size, _data, kern_size, _end);
efi_stub_entry_update();
-#else
- (void)init_size;
- total_size = setup_size + kern_size;
#endif
+ total_size = setup_size + kern_size;
output = map_output_file(argv[4], total_size);
memcpy(output, buf, setup_size);