diff options
| author | H. Peter Anvin <hpa@linux.intel.com> | 2014-08-11 16:58:54 -0400 |
|---|---|---|
| committer | H. Peter Anvin <hpa@linux.intel.com> | 2014-08-11 16:58:54 -0400 |
| commit | 9e13bcf7e0981f1db0c8c8255ac17d5f898903e9 (patch) | |
| tree | 2bb16d5bceab26b92ea68c2b895ce4a353d9338a | |
| parent | b16d8c231e4d03fefc7de1b8b62bad5659ee8070 (diff) | |
| parent | 7b2a583afb4ab894f78bc0f8bd136e96b6499a7e (diff) | |
Merge tag 'efi-urgent' into x86/efi
* Enforce CONFIG_RELOCATABLE for the x86 EFI boot stub, otherwise
it's possible to overwrite random pieces of unallocated memory during
kernel decompression, leading to machine resets.
Resolved Conflicts:
arch/x86/Kconfig
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
| -rw-r--r-- | arch/x86/Kconfig | 1 | ||||
| -rw-r--r-- | arch/x86/boot/header.S | 26 | ||||
| -rw-r--r-- | arch/x86/boot/tools/build.c | 38 | ||||
| -rw-r--r-- | drivers/firmware/efi/efi-pstore.c | 2 | ||||
| -rw-r--r-- | drivers/firmware/efi/efi.c | 28 | ||||
| -rw-r--r-- | drivers/firmware/efi/libstub/fdt.c | 2 |
6 files changed, 73 insertions, 24 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 7ea8aaaab7fc..842a5abf3aed 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
| @@ -1537,6 +1537,7 @@ config EFI | |||
| 1537 | config EFI_STUB | 1537 | config EFI_STUB |
| 1538 | bool "EFI stub support" | 1538 | bool "EFI stub support" |
| 1539 | depends on EFI && !X86_USE_3DNOW | 1539 | depends on EFI && !X86_USE_3DNOW |
| 1540 | select RELOCATABLE | ||
| 1540 | ---help--- | 1541 | ---help--- |
| 1541 | This kernel feature allows a bzImage to be loaded directly | 1542 | This kernel feature allows a bzImage to be loaded directly |
| 1542 | by EFI firmware without the use of a bootloader. | 1543 | by EFI firmware without the use of a bootloader. |
diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S index 1fdb350c4a58..16ef02596db2 100644 --- a/arch/x86/boot/header.S +++ b/arch/x86/boot/header.S | |||
| @@ -91,10 +91,9 @@ bs_die: | |||
| 91 | 91 | ||
| 92 | .section ".bsdata", "a" | 92 | .section ".bsdata", "a" |
| 93 | bugger_off_msg: | 93 | bugger_off_msg: |
| 94 | .ascii "Direct floppy boot is not supported. " | 94 | .ascii "Use a boot loader.\r\n" |
| 95 | .ascii "Use a boot loader program instead.\r\n" | ||
| 96 | .ascii "\n" | 95 | .ascii "\n" |
| 97 | .ascii "Remove disk and press any key to reboot ...\r\n" | 96 | .ascii "Remove disk and press any key to reboot...\r\n" |
| 98 | .byte 0 | 97 | .byte 0 |
| 99 | 98 | ||
| 100 | #ifdef CONFIG_EFI_STUB | 99 | #ifdef CONFIG_EFI_STUB |
| @@ -108,7 +107,7 @@ coff_header: | |||
| 108 | #else | 107 | #else |
| 109 | .word 0x8664 # x86-64 | 108 | .word 0x8664 # x86-64 |
| 110 | #endif | 109 | #endif |
| 111 | .word 3 # nr_sections | 110 | .word 4 # nr_sections |
| 112 | .long 0 # TimeDateStamp | 111 | .long 0 # TimeDateStamp |
| 113 | .long 0 # PointerToSymbolTable | 112 | .long 0 # PointerToSymbolTable |
| 114 | .long 1 # NumberOfSymbols | 113 | .long 1 # NumberOfSymbols |
| @@ -250,6 +249,25 @@ section_table: | |||
| 250 | .word 0 # NumberOfLineNumbers | 249 | .word 0 # NumberOfLineNumbers |
| 251 | .long 0x60500020 # Characteristics (section flags) | 250 | .long 0x60500020 # Characteristics (section flags) |
| 252 | 251 | ||
| 252 | # | ||
| 253 | # The offset & size fields are filled in by build.c. | ||
| 254 | # | ||
| 255 | .ascii ".bss" | ||
| 256 | .byte 0 | ||
| 257 | .byte 0 | ||
| 258 | .byte 0 | ||
| 259 | .byte 0 | ||
| 260 | .long 0 | ||
| 261 | .long 0x0 | ||
| 262 | .long 0 # Size of initialized data | ||
| 263 | # on disk | ||
| 264 | .long 0x0 | ||
| 265 | .long 0 # PointerToRelocations | ||
| 266 | .long 0 # PointerToLineNumbers | ||
| 267 | .word 0 # NumberOfRelocations | ||
| 268 | .word 0 # NumberOfLineNumbers | ||
| 269 | .long 0xc8000080 # Characteristics (section flags) | ||
| 270 | |||
| 253 | #endif /* CONFIG_EFI_STUB */ | 271 | #endif /* CONFIG_EFI_STUB */ |
| 254 | 272 | ||
| 255 | # Kernel attributes; used by setup. This is part 1 of the | 273 | # 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 1a2f2121cada..a7661c430cd9 100644 --- a/arch/x86/boot/tools/build.c +++ b/arch/x86/boot/tools/build.c | |||
| @@ -143,7 +143,7 @@ static void usage(void) | |||
| 143 | 143 | ||
| 144 | #ifdef CONFIG_EFI_STUB | 144 | #ifdef CONFIG_EFI_STUB |
| 145 | 145 | ||
| 146 | static void update_pecoff_section_header(char *section_name, u32 offset, u32 size) | 146 | static void update_pecoff_section_header_fields(char *section_name, u32 vma, u32 size, u32 datasz, u32 offset) |
| 147 | { | 147 | { |
| 148 | unsigned int pe_header; | 148 | unsigned int pe_header; |
| 149 | unsigned short num_sections; | 149 | unsigned short num_sections; |
| @@ -164,10 +164,10 @@ static void update_pecoff_section_header(char *section_name, u32 offset, u32 siz | |||
| 164 | put_unaligned_le32(size, section + 0x8); | 164 | put_unaligned_le32(size, section + 0x8); |
| 165 | 165 | ||
| 166 | /* section header vma field */ | 166 | /* section header vma field */ |
| 167 | put_unaligned_le32(offset, section + 0xc); | 167 | put_unaligned_le32(vma, section + 0xc); |
| 168 | 168 | ||
| 169 | /* section header 'size of initialised data' field */ | 169 | /* section header 'size of initialised data' field */ |
| 170 | put_unaligned_le32(size, section + 0x10); | 170 | put_unaligned_le32(datasz, section + 0x10); |
| 171 | 171 | ||
| 172 | /* section header 'file offset' field */ | 172 | /* section header 'file offset' field */ |
| 173 | put_unaligned_le32(offset, section + 0x14); | 173 | put_unaligned_le32(offset, section + 0x14); |
| @@ -179,6 +179,11 @@ static void update_pecoff_section_header(char *section_name, u32 offset, u32 siz | |||
| 179 | } | 179 | } |
| 180 | } | 180 | } |
| 181 | 181 | ||
| 182 | static void update_pecoff_section_header(char *section_name, u32 offset, u32 size) | ||
| 183 | { | ||
| 184 | update_pecoff_section_header_fields(section_name, offset, size, size, offset); | ||
| 185 | } | ||
| 186 | |||
| 182 | static void update_pecoff_setup_and_reloc(unsigned int size) | 187 | static void update_pecoff_setup_and_reloc(unsigned int size) |
| 183 | { | 188 | { |
| 184 | u32 setup_offset = 0x200; | 189 | u32 setup_offset = 0x200; |
| @@ -203,9 +208,6 @@ static void update_pecoff_text(unsigned int text_start, unsigned int file_sz) | |||
| 203 | 208 | ||
| 204 | pe_header = get_unaligned_le32(&buf[0x3c]); | 209 | pe_header = get_unaligned_le32(&buf[0x3c]); |
| 205 | 210 | ||
| 206 | /* Size of image */ | ||
| 207 | put_unaligned_le32(file_sz, &buf[pe_header + 0x50]); | ||
| 208 | |||
| 209 | /* | 211 | /* |
| 210 | * Size of code: Subtract the size of the first sector (512 bytes) | 212 | * Size of code: Subtract the size of the first sector (512 bytes) |
| 211 | * which includes the header. | 213 | * which includes the header. |
| @@ -220,6 +222,22 @@ static void update_pecoff_text(unsigned int text_start, unsigned int file_sz) | |||
| 220 | update_pecoff_section_header(".text", text_start, text_sz); | 222 | update_pecoff_section_header(".text", text_start, text_sz); |
| 221 | } | 223 | } |
| 222 | 224 | ||
| 225 | static void update_pecoff_bss(unsigned int file_sz, unsigned int init_sz) | ||
| 226 | { | ||
| 227 | unsigned int pe_header; | ||
| 228 | unsigned int bss_sz = init_sz - file_sz; | ||
| 229 | |||
| 230 | pe_header = get_unaligned_le32(&buf[0x3c]); | ||
| 231 | |||
| 232 | /* Size of uninitialized data */ | ||
| 233 | put_unaligned_le32(bss_sz, &buf[pe_header + 0x24]); | ||
| 234 | |||
| 235 | /* Size of image */ | ||
| 236 | put_unaligned_le32(init_sz, &buf[pe_header + 0x50]); | ||
| 237 | |||
| 238 | update_pecoff_section_header_fields(".bss", file_sz, bss_sz, 0, 0); | ||
| 239 | } | ||
| 240 | |||
| 223 | static int reserve_pecoff_reloc_section(int c) | 241 | static int reserve_pecoff_reloc_section(int c) |
| 224 | { | 242 | { |
| 225 | /* Reserve 0x20 bytes for .reloc section */ | 243 | /* Reserve 0x20 bytes for .reloc section */ |
| @@ -259,6 +277,8 @@ static void efi_stub_entry_update(void) | |||
| 259 | static inline void update_pecoff_setup_and_reloc(unsigned int size) {} | 277 | static inline void update_pecoff_setup_and_reloc(unsigned int size) {} |
| 260 | static inline void update_pecoff_text(unsigned int text_start, | 278 | static inline void update_pecoff_text(unsigned int text_start, |
| 261 | unsigned int file_sz) {} | 279 | unsigned int file_sz) {} |
| 280 | static inline void update_pecoff_bss(unsigned int file_sz, | ||
| 281 | unsigned int init_sz) {} | ||
| 262 | static inline void efi_stub_defaults(void) {} | 282 | static inline void efi_stub_defaults(void) {} |
| 263 | static inline void efi_stub_entry_update(void) {} | 283 | static inline void efi_stub_entry_update(void) {} |
| 264 | 284 | ||
| @@ -310,7 +330,7 @@ static void parse_zoffset(char *fname) | |||
| 310 | 330 | ||
| 311 | int main(int argc, char ** argv) | 331 | int main(int argc, char ** argv) |
| 312 | { | 332 | { |
| 313 | unsigned int i, sz, setup_sectors; | 333 | unsigned int i, sz, setup_sectors, init_sz; |
| 314 | int c; | 334 | int c; |
| 315 | u32 sys_size; | 335 | u32 sys_size; |
| 316 | struct stat sb; | 336 | struct stat sb; |
| @@ -376,7 +396,9 @@ int main(int argc, char ** argv) | |||
| 376 | buf[0x1f1] = setup_sectors-1; | 396 | buf[0x1f1] = setup_sectors-1; |
| 377 | put_unaligned_le32(sys_size, &buf[0x1f4]); | 397 | put_unaligned_le32(sys_size, &buf[0x1f4]); |
| 378 | 398 | ||
| 379 | update_pecoff_text(setup_sectors * 512, sz + i + ((sys_size * 16) - sz)); | 399 | update_pecoff_text(setup_sectors * 512, i + (sys_size * 16)); |
| 400 | init_sz = get_unaligned_le32(&buf[0x260]); | ||
| 401 | update_pecoff_bss(i + (sys_size * 16), init_sz); | ||
| 380 | 402 | ||
| 381 | efi_stub_entry_update(); | 403 | efi_stub_entry_update(); |
| 382 | 404 | ||
diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c index 4b9dc836dcf9..e992abc5ef26 100644 --- a/drivers/firmware/efi/efi-pstore.c +++ b/drivers/firmware/efi/efi-pstore.c | |||
| @@ -40,7 +40,7 @@ struct pstore_read_data { | |||
| 40 | static inline u64 generic_id(unsigned long timestamp, | 40 | static inline u64 generic_id(unsigned long timestamp, |
| 41 | unsigned int part, int count) | 41 | unsigned int part, int count) |
| 42 | { | 42 | { |
| 43 | return (timestamp * 100 + part) * 1000 + count; | 43 | return ((u64) timestamp * 100 + part) * 1000 + count; |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | static int efi_pstore_read_func(struct efivar_entry *entry, void *data) | 46 | static int efi_pstore_read_func(struct efivar_entry *entry, void *data) |
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 36ffa1747e84..64ecbb501c50 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c | |||
| @@ -364,6 +364,7 @@ static __initdata struct { | |||
| 364 | 364 | ||
| 365 | struct param_info { | 365 | struct param_info { |
| 366 | int verbose; | 366 | int verbose; |
| 367 | int found; | ||
| 367 | void *params; | 368 | void *params; |
| 368 | }; | 369 | }; |
| 369 | 370 | ||
| @@ -371,25 +372,21 @@ static int __init fdt_find_uefi_params(unsigned long node, const char *uname, | |||
| 371 | int depth, void *data) | 372 | int depth, void *data) |
| 372 | { | 373 | { |
| 373 | struct param_info *info = data; | 374 | struct param_info *info = data; |
| 374 | void *prop, *dest; | 375 | const void *prop; |
| 375 | unsigned long len; | 376 | void *dest; |
| 376 | u64 val; | 377 | u64 val; |
| 377 | int i; | 378 | int i, len; |
| 378 | 379 | ||
| 379 | if (depth != 1 || | 380 | if (depth != 1 || |
| 380 | (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0)) | 381 | (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0)) |
| 381 | return 0; | 382 | return 0; |
| 382 | 383 | ||
| 383 | pr_info("Getting parameters from FDT:\n"); | ||
| 384 | |||
| 385 | for (i = 0; i < ARRAY_SIZE(dt_params); i++) { | 384 | for (i = 0; i < ARRAY_SIZE(dt_params); i++) { |
| 386 | prop = of_get_flat_dt_prop(node, dt_params[i].propname, &len); | 385 | prop = of_get_flat_dt_prop(node, dt_params[i].propname, &len); |
| 387 | if (!prop) { | 386 | if (!prop) |
| 388 | pr_err("Can't find %s in device tree!\n", | ||
| 389 | dt_params[i].name); | ||
| 390 | return 0; | 387 | return 0; |
| 391 | } | ||
| 392 | dest = info->params + dt_params[i].offset; | 388 | dest = info->params + dt_params[i].offset; |
| 389 | info->found++; | ||
| 393 | 390 | ||
| 394 | val = of_read_number(prop, len / sizeof(u32)); | 391 | val = of_read_number(prop, len / sizeof(u32)); |
| 395 | 392 | ||
| @@ -408,10 +405,21 @@ static int __init fdt_find_uefi_params(unsigned long node, const char *uname, | |||
| 408 | int __init efi_get_fdt_params(struct efi_fdt_params *params, int verbose) | 405 | int __init efi_get_fdt_params(struct efi_fdt_params *params, int verbose) |
| 409 | { | 406 | { |
| 410 | struct param_info info; | 407 | struct param_info info; |
| 408 | int ret; | ||
| 409 | |||
| 410 | pr_info("Getting EFI parameters from FDT:\n"); | ||
| 411 | 411 | ||
| 412 | info.verbose = verbose; | 412 | info.verbose = verbose; |
| 413 | info.found = 0; | ||
| 413 | info.params = params; | 414 | info.params = params; |
| 414 | 415 | ||
| 415 | return of_scan_flat_dt(fdt_find_uefi_params, &info); | 416 | ret = of_scan_flat_dt(fdt_find_uefi_params, &info); |
| 417 | if (!info.found) | ||
| 418 | pr_info("UEFI not found.\n"); | ||
| 419 | else if (!ret) | ||
| 420 | pr_err("Can't find '%s' in device tree!\n", | ||
| 421 | dt_params[info.found].name); | ||
| 422 | |||
| 423 | return ret; | ||
| 416 | } | 424 | } |
| 417 | #endif /* CONFIG_EFI_PARAMS_FROM_FDT */ | 425 | #endif /* CONFIG_EFI_PARAMS_FROM_FDT */ |
diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c index 86d2934840e2..a56bb3528755 100644 --- a/drivers/firmware/efi/libstub/fdt.c +++ b/drivers/firmware/efi/libstub/fdt.c | |||
| @@ -57,7 +57,7 @@ efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, | |||
| 57 | */ | 57 | */ |
| 58 | prev = 0; | 58 | prev = 0; |
| 59 | for (;;) { | 59 | for (;;) { |
| 60 | const char *type, *name; | 60 | const char *type; |
| 61 | int len; | 61 | int len; |
| 62 | 62 | ||
| 63 | node = fdt_next_node(fdt, prev, NULL); | 63 | node = fdt_next_node(fdt, prev, NULL); |
