diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-11-14 11:26:24 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-11-14 11:26:24 -0500 |
commit | 53381e2e34f741350bd00f592d2b6c3710ba5177 (patch) | |
tree | 338e5093e343aaea9da9018ce71a5814c799437d | |
parent | 28ddafa5905310889defc485dbefe0a484edb2b6 (diff) | |
parent | f6697df36bdf0bf7fce984605c2918d4a7b4269f (diff) |
Merge branch 'efi-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull EFI fixes from Ingo Molnar:
"A boot crash fix and a build warning fix"
* 'efi-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86/efi: Prevent mixed mode boot corruption with CONFIG_VMAP_STACK=y
x86/efi: Fix EFI memmap pointer size warning
-rw-r--r-- | arch/x86/platform/efi/efi.c | 2 | ||||
-rw-r--r-- | arch/x86/platform/efi/efi_64.c | 80 |
2 files changed, 58 insertions, 24 deletions
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index bf99aa7005eb..936a488d6cf6 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c | |||
@@ -861,7 +861,7 @@ static void __init __efi_enter_virtual_mode(void) | |||
861 | int count = 0, pg_shift = 0; | 861 | int count = 0, pg_shift = 0; |
862 | void *new_memmap = NULL; | 862 | void *new_memmap = NULL; |
863 | efi_status_t status; | 863 | efi_status_t status; |
864 | phys_addr_t pa; | 864 | unsigned long pa; |
865 | 865 | ||
866 | efi.systab = NULL; | 866 | efi.systab = NULL; |
867 | 867 | ||
diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c index 58b0f801f66f..319148bd4b05 100644 --- a/arch/x86/platform/efi/efi_64.c +++ b/arch/x86/platform/efi/efi_64.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/io.h> | 31 | #include <linux/io.h> |
32 | #include <linux/reboot.h> | 32 | #include <linux/reboot.h> |
33 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
34 | #include <linux/ucs2_string.h> | ||
34 | 35 | ||
35 | #include <asm/setup.h> | 36 | #include <asm/setup.h> |
36 | #include <asm/page.h> | 37 | #include <asm/page.h> |
@@ -211,6 +212,35 @@ void efi_sync_low_kernel_mappings(void) | |||
211 | memcpy(pud_efi, pud_k, sizeof(pud_t) * num_entries); | 212 | memcpy(pud_efi, pud_k, sizeof(pud_t) * num_entries); |
212 | } | 213 | } |
213 | 214 | ||
215 | /* | ||
216 | * Wrapper for slow_virt_to_phys() that handles NULL addresses. | ||
217 | */ | ||
218 | static inline phys_addr_t | ||
219 | virt_to_phys_or_null_size(void *va, unsigned long size) | ||
220 | { | ||
221 | bool bad_size; | ||
222 | |||
223 | if (!va) | ||
224 | return 0; | ||
225 | |||
226 | if (virt_addr_valid(va)) | ||
227 | return virt_to_phys(va); | ||
228 | |||
229 | /* | ||
230 | * A fully aligned variable on the stack is guaranteed not to | ||
231 | * cross a page bounary. Try to catch strings on the stack by | ||
232 | * checking that 'size' is a power of two. | ||
233 | */ | ||
234 | bad_size = size > PAGE_SIZE || !is_power_of_2(size); | ||
235 | |||
236 | WARN_ON(!IS_ALIGNED((unsigned long)va, size) || bad_size); | ||
237 | |||
238 | return slow_virt_to_phys(va); | ||
239 | } | ||
240 | |||
241 | #define virt_to_phys_or_null(addr) \ | ||
242 | virt_to_phys_or_null_size((addr), sizeof(*(addr))) | ||
243 | |||
214 | int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages) | 244 | int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages) |
215 | { | 245 | { |
216 | unsigned long pfn, text; | 246 | unsigned long pfn, text; |
@@ -494,8 +524,8 @@ static efi_status_t efi_thunk_get_time(efi_time_t *tm, efi_time_cap_t *tc) | |||
494 | 524 | ||
495 | spin_lock(&rtc_lock); | 525 | spin_lock(&rtc_lock); |
496 | 526 | ||
497 | phys_tm = virt_to_phys(tm); | 527 | phys_tm = virt_to_phys_or_null(tm); |
498 | phys_tc = virt_to_phys(tc); | 528 | phys_tc = virt_to_phys_or_null(tc); |
499 | 529 | ||
500 | status = efi_thunk(get_time, phys_tm, phys_tc); | 530 | status = efi_thunk(get_time, phys_tm, phys_tc); |
501 | 531 | ||
@@ -511,7 +541,7 @@ static efi_status_t efi_thunk_set_time(efi_time_t *tm) | |||
511 | 541 | ||
512 | spin_lock(&rtc_lock); | 542 | spin_lock(&rtc_lock); |
513 | 543 | ||
514 | phys_tm = virt_to_phys(tm); | 544 | phys_tm = virt_to_phys_or_null(tm); |
515 | 545 | ||
516 | status = efi_thunk(set_time, phys_tm); | 546 | status = efi_thunk(set_time, phys_tm); |
517 | 547 | ||
@@ -529,9 +559,9 @@ efi_thunk_get_wakeup_time(efi_bool_t *enabled, efi_bool_t *pending, | |||
529 | 559 | ||
530 | spin_lock(&rtc_lock); | 560 | spin_lock(&rtc_lock); |
531 | 561 | ||
532 | phys_enabled = virt_to_phys(enabled); | 562 | phys_enabled = virt_to_phys_or_null(enabled); |
533 | phys_pending = virt_to_phys(pending); | 563 | phys_pending = virt_to_phys_or_null(pending); |
534 | phys_tm = virt_to_phys(tm); | 564 | phys_tm = virt_to_phys_or_null(tm); |
535 | 565 | ||
536 | status = efi_thunk(get_wakeup_time, phys_enabled, | 566 | status = efi_thunk(get_wakeup_time, phys_enabled, |
537 | phys_pending, phys_tm); | 567 | phys_pending, phys_tm); |
@@ -549,7 +579,7 @@ efi_thunk_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) | |||
549 | 579 | ||
550 | spin_lock(&rtc_lock); | 580 | spin_lock(&rtc_lock); |
551 | 581 | ||
552 | phys_tm = virt_to_phys(tm); | 582 | phys_tm = virt_to_phys_or_null(tm); |
553 | 583 | ||
554 | status = efi_thunk(set_wakeup_time, enabled, phys_tm); | 584 | status = efi_thunk(set_wakeup_time, enabled, phys_tm); |
555 | 585 | ||
@@ -558,6 +588,10 @@ efi_thunk_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) | |||
558 | return status; | 588 | return status; |
559 | } | 589 | } |
560 | 590 | ||
591 | static unsigned long efi_name_size(efi_char16_t *name) | ||
592 | { | ||
593 | return ucs2_strsize(name, EFI_VAR_NAME_LEN) + 1; | ||
594 | } | ||
561 | 595 | ||
562 | static efi_status_t | 596 | static efi_status_t |
563 | efi_thunk_get_variable(efi_char16_t *name, efi_guid_t *vendor, | 597 | efi_thunk_get_variable(efi_char16_t *name, efi_guid_t *vendor, |
@@ -567,11 +601,11 @@ efi_thunk_get_variable(efi_char16_t *name, efi_guid_t *vendor, | |||
567 | u32 phys_name, phys_vendor, phys_attr; | 601 | u32 phys_name, phys_vendor, phys_attr; |
568 | u32 phys_data_size, phys_data; | 602 | u32 phys_data_size, phys_data; |
569 | 603 | ||
570 | phys_data_size = virt_to_phys(data_size); | 604 | phys_data_size = virt_to_phys_or_null(data_size); |
571 | phys_vendor = virt_to_phys(vendor); | 605 | phys_vendor = virt_to_phys_or_null(vendor); |
572 | phys_name = virt_to_phys(name); | 606 | phys_name = virt_to_phys_or_null_size(name, efi_name_size(name)); |
573 | phys_attr = virt_to_phys(attr); | 607 | phys_attr = virt_to_phys_or_null(attr); |
574 | phys_data = virt_to_phys(data); | 608 | phys_data = virt_to_phys_or_null_size(data, *data_size); |
575 | 609 | ||
576 | status = efi_thunk(get_variable, phys_name, phys_vendor, | 610 | status = efi_thunk(get_variable, phys_name, phys_vendor, |
577 | phys_attr, phys_data_size, phys_data); | 611 | phys_attr, phys_data_size, phys_data); |
@@ -586,9 +620,9 @@ efi_thunk_set_variable(efi_char16_t *name, efi_guid_t *vendor, | |||
586 | u32 phys_name, phys_vendor, phys_data; | 620 | u32 phys_name, phys_vendor, phys_data; |
587 | efi_status_t status; | 621 | efi_status_t status; |
588 | 622 | ||
589 | phys_name = virt_to_phys(name); | 623 | phys_name = virt_to_phys_or_null_size(name, efi_name_size(name)); |
590 | phys_vendor = virt_to_phys(vendor); | 624 | phys_vendor = virt_to_phys_or_null(vendor); |
591 | phys_data = virt_to_phys(data); | 625 | phys_data = virt_to_phys_or_null_size(data, data_size); |
592 | 626 | ||
593 | /* If data_size is > sizeof(u32) we've got problems */ | 627 | /* If data_size is > sizeof(u32) we've got problems */ |
594 | status = efi_thunk(set_variable, phys_name, phys_vendor, | 628 | status = efi_thunk(set_variable, phys_name, phys_vendor, |
@@ -605,9 +639,9 @@ efi_thunk_get_next_variable(unsigned long *name_size, | |||
605 | efi_status_t status; | 639 | efi_status_t status; |
606 | u32 phys_name_size, phys_name, phys_vendor; | 640 | u32 phys_name_size, phys_name, phys_vendor; |
607 | 641 | ||
608 | phys_name_size = virt_to_phys(name_size); | 642 | phys_name_size = virt_to_phys_or_null(name_size); |
609 | phys_vendor = virt_to_phys(vendor); | 643 | phys_vendor = virt_to_phys_or_null(vendor); |
610 | phys_name = virt_to_phys(name); | 644 | phys_name = virt_to_phys_or_null_size(name, *name_size); |
611 | 645 | ||
612 | status = efi_thunk(get_next_variable, phys_name_size, | 646 | status = efi_thunk(get_next_variable, phys_name_size, |
613 | phys_name, phys_vendor); | 647 | phys_name, phys_vendor); |
@@ -621,7 +655,7 @@ efi_thunk_get_next_high_mono_count(u32 *count) | |||
621 | efi_status_t status; | 655 | efi_status_t status; |
622 | u32 phys_count; | 656 | u32 phys_count; |
623 | 657 | ||
624 | phys_count = virt_to_phys(count); | 658 | phys_count = virt_to_phys_or_null(count); |
625 | status = efi_thunk(get_next_high_mono_count, phys_count); | 659 | status = efi_thunk(get_next_high_mono_count, phys_count); |
626 | 660 | ||
627 | return status; | 661 | return status; |
@@ -633,7 +667,7 @@ efi_thunk_reset_system(int reset_type, efi_status_t status, | |||
633 | { | 667 | { |
634 | u32 phys_data; | 668 | u32 phys_data; |
635 | 669 | ||
636 | phys_data = virt_to_phys(data); | 670 | phys_data = virt_to_phys_or_null_size(data, data_size); |
637 | 671 | ||
638 | efi_thunk(reset_system, reset_type, status, data_size, phys_data); | 672 | efi_thunk(reset_system, reset_type, status, data_size, phys_data); |
639 | } | 673 | } |
@@ -661,9 +695,9 @@ efi_thunk_query_variable_info(u32 attr, u64 *storage_space, | |||
661 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) | 695 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) |
662 | return EFI_UNSUPPORTED; | 696 | return EFI_UNSUPPORTED; |
663 | 697 | ||
664 | phys_storage = virt_to_phys(storage_space); | 698 | phys_storage = virt_to_phys_or_null(storage_space); |
665 | phys_remaining = virt_to_phys(remaining_space); | 699 | phys_remaining = virt_to_phys_or_null(remaining_space); |
666 | phys_max = virt_to_phys(max_variable_size); | 700 | phys_max = virt_to_phys_or_null(max_variable_size); |
667 | 701 | ||
668 | status = efi_thunk(query_variable_info, attr, phys_storage, | 702 | status = efi_thunk(query_variable_info, attr, phys_storage, |
669 | phys_remaining, phys_max); | 703 | phys_remaining, phys_max); |