diff options
| author | Jordan Justen <jordan.l.justen@intel.com> | 2012-06-07 12:05:21 -0400 |
|---|---|---|
| committer | H. Peter Anvin <hpa@zytor.com> | 2012-06-07 12:52:33 -0400 |
| commit | 743628e868c5992354fc80b4d1e9a6143da1c0e6 (patch) | |
| tree | 1089643db1f1b80100ca7a9ebc29fc3d60acfa55 | |
| parent | f6175f5bfb4c9f2ed32758c95f765b529b1a7f15 (diff) | |
x86, efi stub: Add .reloc section back into image
Some UEFI firmware will not load a .efi with a .reloc section
with a size of 0.
Therefore, we create a .efi image with 4 main areas and 3 sections.
1. PE/COFF file header
2. .setup section (covers all setup code following the first sector)
3. .reloc section (contains 1 dummy reloc entry, created in build.c)
4. .text section (covers the remaining kernel image)
To make room for the new .setup section data, the header
bugger_off_msg had to be shortened.
Reported-by: Henrik Rydberg <rydberg@euromail.se>
Signed-off-by: Jordan Justen <jordan.l.justen@intel.com>
Link: http://lkml.kernel.org/r/1339085121-12760-1-git-send-email-jordan.l.justen@intel.com
Tested-by: Lee G Rosenbaum <lee.g.rosenbaum@intel.com>
Tested-by: Henrik Rydberg <rydberg@euromail.se>
Cc: Matt Fleming <matt.fleming@intel.com>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
| -rw-r--r-- | arch/x86/boot/header.S | 42 | ||||
| -rw-r--r-- | arch/x86/boot/tools/build.c | 172 |
2 files changed, 140 insertions, 74 deletions
diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S index 8bbea6aa40d9..efe5acfc79c3 100644 --- a/arch/x86/boot/header.S +++ b/arch/x86/boot/header.S | |||
| @@ -94,10 +94,10 @@ bs_die: | |||
| 94 | 94 | ||
| 95 | .section ".bsdata", "a" | 95 | .section ".bsdata", "a" |
| 96 | bugger_off_msg: | 96 | bugger_off_msg: |
| 97 | .ascii "Direct booting from floppy is no longer supported.\r\n" | 97 | .ascii "Direct floppy boot is not supported. " |
| 98 | .ascii "Please use a boot loader program instead.\r\n" | 98 | .ascii "Use a boot loader program instead.\r\n" |
| 99 | .ascii "\n" | 99 | .ascii "\n" |
| 100 | .ascii "Remove disk and press any key to reboot . . .\r\n" | 100 | .ascii "Remove disk and press any key to reboot ...\r\n" |
| 101 | .byte 0 | 101 | .byte 0 |
| 102 | 102 | ||
| 103 | #ifdef CONFIG_EFI_STUB | 103 | #ifdef CONFIG_EFI_STUB |
| @@ -111,7 +111,7 @@ coff_header: | |||
| 111 | #else | 111 | #else |
| 112 | .word 0x8664 # x86-64 | 112 | .word 0x8664 # x86-64 |
| 113 | #endif | 113 | #endif |
| 114 | .word 2 # nr_sections | 114 | .word 3 # nr_sections |
| 115 | .long 0 # TimeDateStamp | 115 | .long 0 # TimeDateStamp |
| 116 | .long 0 # PointerToSymbolTable | 116 | .long 0 # PointerToSymbolTable |
| 117 | .long 1 # NumberOfSymbols | 117 | .long 1 # NumberOfSymbols |
| @@ -158,8 +158,8 @@ extra_header_fields: | |||
| 158 | #else | 158 | #else |
| 159 | .quad 0 # ImageBase | 159 | .quad 0 # ImageBase |
| 160 | #endif | 160 | #endif |
| 161 | .long 0x1000 # SectionAlignment | 161 | .long 0x20 # SectionAlignment |
| 162 | .long 0x200 # FileAlignment | 162 | .long 0x20 # FileAlignment |
| 163 | .word 0 # MajorOperatingSystemVersion | 163 | .word 0 # MajorOperatingSystemVersion |
| 164 | .word 0 # MinorOperatingSystemVersion | 164 | .word 0 # MinorOperatingSystemVersion |
| 165 | .word 0 # MajorImageVersion | 165 | .word 0 # MajorImageVersion |
| @@ -200,8 +200,10 @@ extra_header_fields: | |||
| 200 | 200 | ||
| 201 | # Section table | 201 | # Section table |
| 202 | section_table: | 202 | section_table: |
| 203 | .ascii ".text" | 203 | # |
| 204 | .byte 0 | 204 | # The offset & size fields are filled in by build.c. |
| 205 | # | ||
| 206 | .ascii ".setup" | ||
| 205 | .byte 0 | 207 | .byte 0 |
| 206 | .byte 0 | 208 | .byte 0 |
| 207 | .long 0 | 209 | .long 0 |
| @@ -217,9 +219,8 @@ section_table: | |||
| 217 | 219 | ||
| 218 | # | 220 | # |
| 219 | # The EFI application loader requires a relocation section | 221 | # The EFI application loader requires a relocation section |
| 220 | # because EFI applications must be relocatable. But since | 222 | # because EFI applications must be relocatable. The .reloc |
| 221 | # we don't need the loader to fixup any relocs for us, we | 223 | # offset & size fields are filled in by build.c. |
| 222 | # just create an empty (zero-length) .reloc section header. | ||
| 223 | # | 224 | # |
| 224 | .ascii ".reloc" | 225 | .ascii ".reloc" |
| 225 | .byte 0 | 226 | .byte 0 |
| @@ -233,6 +234,25 @@ section_table: | |||
| 233 | .word 0 # NumberOfRelocations | 234 | .word 0 # NumberOfRelocations |
| 234 | .word 0 # NumberOfLineNumbers | 235 | .word 0 # NumberOfLineNumbers |
| 235 | .long 0x42100040 # Characteristics (section flags) | 236 | .long 0x42100040 # Characteristics (section flags) |
| 237 | |||
| 238 | # | ||
| 239 | # The offset & size fields are filled in by build.c. | ||
| 240 | # | ||
| 241 | .ascii ".text" | ||
| 242 | .byte 0 | ||
| 243 | .byte 0 | ||
| 244 | .byte 0 | ||
| 245 | .long 0 | ||
| 246 | .long 0x0 # startup_{32,64} | ||
| 247 | .long 0 # Size of initialized data | ||
| 248 | # on disk | ||
| 249 | .long 0x0 # startup_{32,64} | ||
| 250 | .long 0 # PointerToRelocations | ||
| 251 | .long 0 # PointerToLineNumbers | ||
| 252 | .word 0 # NumberOfRelocations | ||
| 253 | .word 0 # NumberOfLineNumbers | ||
| 254 | .long 0x60500020 # Characteristics (section flags) | ||
| 255 | |||
| 236 | #endif /* CONFIG_EFI_STUB */ | 256 | #endif /* CONFIG_EFI_STUB */ |
| 237 | 257 | ||
| 238 | # Kernel attributes; used by setup. This is part 1 of the | 258 | # Kernel attributes; used by setup. This is part 1 of the |
diff --git a/arch/x86/boot/tools/build.c b/arch/x86/boot/tools/build.c index 3f61f6e2b46f..4b8e165ee572 100644 --- a/arch/x86/boot/tools/build.c +++ b/arch/x86/boot/tools/build.c | |||
| @@ -50,6 +50,8 @@ typedef unsigned int u32; | |||
| 50 | u8 buf[SETUP_SECT_MAX*512]; | 50 | u8 buf[SETUP_SECT_MAX*512]; |
| 51 | int is_big_kernel; | 51 | int is_big_kernel; |
| 52 | 52 | ||
| 53 | #define PECOFF_RELOC_RESERVE 0x20 | ||
| 54 | |||
| 53 | /*----------------------------------------------------------------------*/ | 55 | /*----------------------------------------------------------------------*/ |
| 54 | 56 | ||
| 55 | static const u32 crctab32[] = { | 57 | static const u32 crctab32[] = { |
| @@ -133,11 +135,103 @@ static void usage(void) | |||
| 133 | die("Usage: build setup system [> image]"); | 135 | die("Usage: build setup system [> image]"); |
| 134 | } | 136 | } |
| 135 | 137 | ||
| 136 | int main(int argc, char ** argv) | ||
| 137 | { | ||
| 138 | #ifdef CONFIG_EFI_STUB | 138 | #ifdef CONFIG_EFI_STUB |
| 139 | unsigned int file_sz, pe_header; | 139 | |
| 140 | static void update_pecoff_section_header(char *section_name, u32 offset, u32 size) | ||
| 141 | { | ||
| 142 | unsigned int pe_header; | ||
| 143 | unsigned short num_sections; | ||
| 144 | u8 *section; | ||
| 145 | |||
| 146 | pe_header = get_unaligned_le32(&buf[0x3c]); | ||
| 147 | num_sections = get_unaligned_le16(&buf[pe_header + 6]); | ||
| 148 | |||
| 149 | #ifdef CONFIG_X86_32 | ||
| 150 | section = &buf[pe_header + 0xa8]; | ||
| 151 | #else | ||
| 152 | section = &buf[pe_header + 0xb8]; | ||
| 140 | #endif | 153 | #endif |
| 154 | |||
| 155 | while (num_sections > 0) { | ||
| 156 | if (strncmp((char*)section, section_name, 8) == 0) { | ||
| 157 | /* section header size field */ | ||
| 158 | put_unaligned_le32(size, section + 0x8); | ||
| 159 | |||
| 160 | /* section header vma field */ | ||
| 161 | put_unaligned_le32(offset, section + 0xc); | ||
| 162 | |||
| 163 | /* section header 'size of initialised data' field */ | ||
| 164 | put_unaligned_le32(size, section + 0x10); | ||
| 165 | |||
| 166 | /* section header 'file offset' field */ | ||
| 167 | put_unaligned_le32(offset, section + 0x14); | ||
| 168 | |||
| 169 | break; | ||
| 170 | } | ||
| 171 | section += 0x28; | ||
| 172 | num_sections--; | ||
| 173 | } | ||
| 174 | } | ||
| 175 | |||
| 176 | static void update_pecoff_setup_and_reloc(unsigned int size) | ||
| 177 | { | ||
| 178 | u32 setup_offset = 0x200; | ||
| 179 | u32 reloc_offset = size - PECOFF_RELOC_RESERVE; | ||
| 180 | u32 setup_size = reloc_offset - setup_offset; | ||
| 181 | |||
| 182 | update_pecoff_section_header(".setup", setup_offset, setup_size); | ||
| 183 | update_pecoff_section_header(".reloc", reloc_offset, PECOFF_RELOC_RESERVE); | ||
| 184 | |||
| 185 | /* | ||
| 186 | * Modify .reloc section contents with a single entry. The | ||
| 187 | * relocation is applied to offset 10 of the relocation section. | ||
| 188 | */ | ||
| 189 | put_unaligned_le32(reloc_offset + 10, &buf[reloc_offset]); | ||
| 190 | put_unaligned_le32(10, &buf[reloc_offset + 4]); | ||
| 191 | } | ||
| 192 | |||
| 193 | static void update_pecoff_text(unsigned int text_start, unsigned int file_sz) | ||
| 194 | { | ||
| 195 | unsigned int pe_header; | ||
| 196 | unsigned int text_sz = file_sz - text_start; | ||
| 197 | |||
| 198 | pe_header = get_unaligned_le32(&buf[0x3c]); | ||
| 199 | |||
| 200 | /* Size of image */ | ||
| 201 | put_unaligned_le32(file_sz, &buf[pe_header + 0x50]); | ||
| 202 | |||
| 203 | /* | ||
| 204 | * Size of code: Subtract the size of the first sector (512 bytes) | ||
| 205 | * which includes the header. | ||
| 206 | */ | ||
| 207 | put_unaligned_le32(file_sz - 512, &buf[pe_header + 0x1c]); | ||
| 208 | |||
| 209 | #ifdef CONFIG_X86_32 | ||
| 210 | /* | ||
| 211 | * Address of entry point. | ||
| 212 | * | ||
| 213 | * The EFI stub entry point is +16 bytes from the start of | ||
| 214 | * the .text section. | ||
| 215 | */ | ||
| 216 | put_unaligned_le32(text_start + 16, &buf[pe_header + 0x28]); | ||
| 217 | #else | ||
| 218 | /* | ||
| 219 | * Address of entry point. startup_32 is at the beginning and | ||
| 220 | * the 64-bit entry point (startup_64) is always 512 bytes | ||
| 221 | * after. The EFI stub entry point is 16 bytes after that, as | ||
| 222 | * the first instruction allows legacy loaders to jump over | ||
| 223 | * the EFI stub initialisation | ||
| 224 | */ | ||
| 225 | put_unaligned_le32(text_start + 528, &buf[pe_header + 0x28]); | ||
| 226 | #endif /* CONFIG_X86_32 */ | ||
| 227 | |||
| 228 | update_pecoff_section_header(".text", text_start, text_sz); | ||
| 229 | } | ||
| 230 | |||
| 231 | #endif /* CONFIG_EFI_STUB */ | ||
| 232 | |||
| 233 | int main(int argc, char ** argv) | ||
| 234 | { | ||
| 141 | unsigned int i, sz, setup_sectors; | 235 | unsigned int i, sz, setup_sectors; |
| 142 | int c; | 236 | int c; |
| 143 | u32 sys_size; | 237 | u32 sys_size; |
| @@ -163,6 +257,12 @@ int main(int argc, char ** argv) | |||
| 163 | die("Boot block hasn't got boot flag (0xAA55)"); | 257 | die("Boot block hasn't got boot flag (0xAA55)"); |
| 164 | fclose(file); | 258 | fclose(file); |
| 165 | 259 | ||
| 260 | #ifdef CONFIG_EFI_STUB | ||
| 261 | /* Reserve 0x20 bytes for .reloc section */ | ||
| 262 | memset(buf+c, 0, PECOFF_RELOC_RESERVE); | ||
| 263 | c += PECOFF_RELOC_RESERVE; | ||
| 264 | #endif | ||
| 265 | |||
| 166 | /* Pad unused space with zeros */ | 266 | /* Pad unused space with zeros */ |
| 167 | setup_sectors = (c + 511) / 512; | 267 | setup_sectors = (c + 511) / 512; |
| 168 | if (setup_sectors < SETUP_SECT_MIN) | 268 | if (setup_sectors < SETUP_SECT_MIN) |
| @@ -170,6 +270,10 @@ int main(int argc, char ** argv) | |||
| 170 | i = setup_sectors*512; | 270 | i = setup_sectors*512; |
| 171 | memset(buf+c, 0, i-c); | 271 | memset(buf+c, 0, i-c); |
| 172 | 272 | ||
| 273 | #ifdef CONFIG_EFI_STUB | ||
| 274 | update_pecoff_setup_and_reloc(i); | ||
| 275 | #endif | ||
| 276 | |||
| 173 | /* Set the default root device */ | 277 | /* Set the default root device */ |
| 174 | put_unaligned_le16(DEFAULT_ROOT_DEV, &buf[508]); | 278 | put_unaligned_le16(DEFAULT_ROOT_DEV, &buf[508]); |
| 175 | 279 | ||
| @@ -194,66 +298,8 @@ int main(int argc, char ** argv) | |||
| 194 | put_unaligned_le32(sys_size, &buf[0x1f4]); | 298 | put_unaligned_le32(sys_size, &buf[0x1f4]); |
| 195 | 299 | ||
| 196 | #ifdef CONFIG_EFI_STUB | 300 | #ifdef CONFIG_EFI_STUB |
| 197 | file_sz = sz + i + ((sys_size * 16) - sz); | 301 | update_pecoff_text(setup_sectors * 512, sz + i + ((sys_size * 16) - sz)); |
| 198 | 302 | #endif | |
| 199 | pe_header = get_unaligned_le32(&buf[0x3c]); | ||
| 200 | |||
| 201 | /* Size of image */ | ||
| 202 | put_unaligned_le32(file_sz, &buf[pe_header + 0x50]); | ||
| 203 | |||
| 204 | /* | ||
| 205 | * Subtract the size of the first section (512 bytes) which | ||
| 206 | * includes the header and .reloc section. The remaining size | ||
| 207 | * is that of the .text section. | ||
| 208 | */ | ||
| 209 | file_sz -= 512; | ||
| 210 | |||
| 211 | /* Size of code */ | ||
| 212 | put_unaligned_le32(file_sz, &buf[pe_header + 0x1c]); | ||
| 213 | |||
| 214 | #ifdef CONFIG_X86_32 | ||
| 215 | /* | ||
| 216 | * Address of entry point. | ||
| 217 | * | ||
| 218 | * The EFI stub entry point is +16 bytes from the start of | ||
| 219 | * the .text section. | ||
| 220 | */ | ||
| 221 | put_unaligned_le32(i + 16, &buf[pe_header + 0x28]); | ||
| 222 | |||
| 223 | /* .text size */ | ||
| 224 | put_unaligned_le32(file_sz, &buf[pe_header + 0xb0]); | ||
| 225 | |||
| 226 | /* .text vma */ | ||
| 227 | put_unaligned_le32(0x200, &buf[pe_header + 0xb4]); | ||
| 228 | |||
| 229 | /* .text size of initialised data */ | ||
| 230 | put_unaligned_le32(file_sz, &buf[pe_header + 0xb8]); | ||
| 231 | |||
| 232 | /* .text file offset */ | ||
| 233 | put_unaligned_le32(0x200, &buf[pe_header + 0xbc]); | ||
| 234 | #else | ||
| 235 | /* | ||
| 236 | * Address of entry point. startup_32 is at the beginning and | ||
| 237 | * the 64-bit entry point (startup_64) is always 512 bytes | ||
| 238 | * after. The EFI stub entry point is 16 bytes after that, as | ||
| 239 | * the first instruction allows legacy loaders to jump over | ||
| 240 | * the EFI stub initialisation | ||
| 241 | */ | ||
| 242 | put_unaligned_le32(i + 528, &buf[pe_header + 0x28]); | ||
| 243 | |||
| 244 | /* .text size */ | ||
| 245 | put_unaligned_le32(file_sz, &buf[pe_header + 0xc0]); | ||
| 246 | |||
| 247 | /* .text vma */ | ||
| 248 | put_unaligned_le32(0x200, &buf[pe_header + 0xc4]); | ||
| 249 | |||
| 250 | /* .text size of initialised data */ | ||
| 251 | put_unaligned_le32(file_sz, &buf[pe_header + 0xc8]); | ||
| 252 | |||
| 253 | /* .text file offset */ | ||
| 254 | put_unaligned_le32(0x200, &buf[pe_header + 0xcc]); | ||
| 255 | #endif /* CONFIG_X86_32 */ | ||
| 256 | #endif /* CONFIG_EFI_STUB */ | ||
| 257 | 303 | ||
| 258 | crc = partial_crc32(buf, i, crc); | 304 | crc = partial_crc32(buf, i, crc); |
| 259 | if (fwrite(buf, 1, i, stdout) != i) | 305 | if (fwrite(buf, 1, i, stdout) != i) |
