diff options
Diffstat (limited to 'arch/x86/platform')
-rw-r--r-- | arch/x86/platform/efi/efi.c | 164 |
1 files changed, 142 insertions, 22 deletions
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 5a053e7737b7..92660edaa1e7 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c | |||
@@ -68,6 +68,9 @@ EXPORT_SYMBOL(efi); | |||
68 | 68 | ||
69 | struct efi_memory_map memmap; | 69 | struct efi_memory_map memmap; |
70 | 70 | ||
71 | bool efi_64bit; | ||
72 | static bool efi_native; | ||
73 | |||
71 | static struct efi efi_phys __initdata; | 74 | static struct efi efi_phys __initdata; |
72 | static efi_system_table_t efi_systab __initdata; | 75 | static efi_system_table_t efi_systab __initdata; |
73 | 76 | ||
@@ -339,11 +342,16 @@ static void __init do_add_efi_memmap(void) | |||
339 | sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map); | 342 | sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map); |
340 | } | 343 | } |
341 | 344 | ||
342 | void __init efi_memblock_x86_reserve_range(void) | 345 | int __init efi_memblock_x86_reserve_range(void) |
343 | { | 346 | { |
344 | unsigned long pmap; | 347 | unsigned long pmap; |
345 | 348 | ||
346 | #ifdef CONFIG_X86_32 | 349 | #ifdef CONFIG_X86_32 |
350 | /* Can't handle data above 4GB at this time */ | ||
351 | if (boot_params.efi_info.efi_memmap_hi) { | ||
352 | pr_err("Memory map is above 4GB, disabling EFI.\n"); | ||
353 | return -EINVAL; | ||
354 | } | ||
347 | pmap = boot_params.efi_info.efi_memmap; | 355 | pmap = boot_params.efi_info.efi_memmap; |
348 | #else | 356 | #else |
349 | pmap = (boot_params.efi_info.efi_memmap | | 357 | pmap = (boot_params.efi_info.efi_memmap | |
@@ -355,6 +363,8 @@ void __init efi_memblock_x86_reserve_range(void) | |||
355 | memmap.desc_version = boot_params.efi_info.efi_memdesc_version; | 363 | memmap.desc_version = boot_params.efi_info.efi_memdesc_version; |
356 | memmap.desc_size = boot_params.efi_info.efi_memdesc_size; | 364 | memmap.desc_size = boot_params.efi_info.efi_memdesc_size; |
357 | memblock_reserve(pmap, memmap.nr_map * memmap.desc_size); | 365 | memblock_reserve(pmap, memmap.nr_map * memmap.desc_size); |
366 | |||
367 | return 0; | ||
358 | } | 368 | } |
359 | 369 | ||
360 | #if EFI_DEBUG | 370 | #if EFI_DEBUG |
@@ -432,14 +442,75 @@ static void __init efi_free_boot_services(void) | |||
432 | 442 | ||
433 | static int __init efi_systab_init(void *phys) | 443 | static int __init efi_systab_init(void *phys) |
434 | { | 444 | { |
435 | efi.systab = early_ioremap((unsigned long)efi_phys.systab, | 445 | if (efi_64bit) { |
436 | sizeof(efi_system_table_t)); | 446 | efi_system_table_64_t *systab64; |
437 | if (efi.systab == NULL) { | 447 | u64 tmp = 0; |
438 | pr_err("Couldn't map the system table!\n"); | 448 | |
439 | return -ENOMEM; | 449 | systab64 = early_ioremap((unsigned long)phys, |
450 | sizeof(*systab64)); | ||
451 | if (systab64 == NULL) { | ||
452 | pr_err("Couldn't map the system table!\n"); | ||
453 | return -ENOMEM; | ||
454 | } | ||
455 | |||
456 | efi_systab.hdr = systab64->hdr; | ||
457 | efi_systab.fw_vendor = systab64->fw_vendor; | ||
458 | tmp |= systab64->fw_vendor; | ||
459 | efi_systab.fw_revision = systab64->fw_revision; | ||
460 | efi_systab.con_in_handle = systab64->con_in_handle; | ||
461 | tmp |= systab64->con_in_handle; | ||
462 | efi_systab.con_in = systab64->con_in; | ||
463 | tmp |= systab64->con_in; | ||
464 | efi_systab.con_out_handle = systab64->con_out_handle; | ||
465 | tmp |= systab64->con_out_handle; | ||
466 | efi_systab.con_out = systab64->con_out; | ||
467 | tmp |= systab64->con_out; | ||
468 | efi_systab.stderr_handle = systab64->stderr_handle; | ||
469 | tmp |= systab64->stderr_handle; | ||
470 | efi_systab.stderr = systab64->stderr; | ||
471 | tmp |= systab64->stderr; | ||
472 | efi_systab.runtime = (void *)(unsigned long)systab64->runtime; | ||
473 | tmp |= systab64->runtime; | ||
474 | efi_systab.boottime = (void *)(unsigned long)systab64->boottime; | ||
475 | tmp |= systab64->boottime; | ||
476 | efi_systab.nr_tables = systab64->nr_tables; | ||
477 | efi_systab.tables = systab64->tables; | ||
478 | tmp |= systab64->tables; | ||
479 | |||
480 | early_iounmap(systab64, sizeof(*systab64)); | ||
481 | #ifdef CONFIG_X86_32 | ||
482 | if (tmp >> 32) { | ||
483 | pr_err("EFI data located above 4GB, disabling EFI.\n"); | ||
484 | return -EINVAL; | ||
485 | } | ||
486 | #endif | ||
487 | } else { | ||
488 | efi_system_table_32_t *systab32; | ||
489 | |||
490 | systab32 = early_ioremap((unsigned long)phys, | ||
491 | sizeof(*systab32)); | ||
492 | if (systab32 == NULL) { | ||
493 | pr_err("Couldn't map the system table!\n"); | ||
494 | return -ENOMEM; | ||
495 | } | ||
496 | |||
497 | efi_systab.hdr = systab32->hdr; | ||
498 | efi_systab.fw_vendor = systab32->fw_vendor; | ||
499 | efi_systab.fw_revision = systab32->fw_revision; | ||
500 | efi_systab.con_in_handle = systab32->con_in_handle; | ||
501 | efi_systab.con_in = systab32->con_in; | ||
502 | efi_systab.con_out_handle = systab32->con_out_handle; | ||
503 | efi_systab.con_out = systab32->con_out; | ||
504 | efi_systab.stderr_handle = systab32->stderr_handle; | ||
505 | efi_systab.stderr = systab32->stderr; | ||
506 | efi_systab.runtime = (void *)(unsigned long)systab32->runtime; | ||
507 | efi_systab.boottime = (void *)(unsigned long)systab32->boottime; | ||
508 | efi_systab.nr_tables = systab32->nr_tables; | ||
509 | efi_systab.tables = systab32->tables; | ||
510 | |||
511 | early_iounmap(systab32, sizeof(*systab32)); | ||
440 | } | 512 | } |
441 | memcpy(&efi_systab, efi.systab, sizeof(efi_system_table_t)); | 513 | |
442 | early_iounmap(efi.systab, sizeof(efi_system_table_t)); | ||
443 | efi.systab = &efi_systab; | 514 | efi.systab = &efi_systab; |
444 | 515 | ||
445 | /* | 516 | /* |
@@ -460,24 +531,47 @@ static int __init efi_systab_init(void *phys) | |||
460 | 531 | ||
461 | static int __init efi_config_init(u64 tables, int nr_tables) | 532 | static int __init efi_config_init(u64 tables, int nr_tables) |
462 | { | 533 | { |
463 | efi_config_table_t *config_tables; | 534 | void *config_tables, *tablep; |
464 | int i, sz = sizeof(efi_config_table_t); | 535 | int i, sz; |
536 | |||
537 | if (efi_64bit) | ||
538 | sz = sizeof(efi_config_table_64_t); | ||
539 | else | ||
540 | sz = sizeof(efi_config_table_32_t); | ||
465 | 541 | ||
466 | /* | 542 | /* |
467 | * Let's see what config tables the firmware passed to us. | 543 | * Let's see what config tables the firmware passed to us. |
468 | */ | 544 | */ |
469 | config_tables = early_ioremap(efi.systab->tables, | 545 | config_tables = early_ioremap(tables, nr_tables * sz); |
470 | efi.systab->nr_tables * sz); | ||
471 | if (config_tables == NULL) { | 546 | if (config_tables == NULL) { |
472 | pr_err("Could not map Configuration table!\n"); | 547 | pr_err("Could not map Configuration table!\n"); |
473 | return -ENOMEM; | 548 | return -ENOMEM; |
474 | } | 549 | } |
475 | 550 | ||
551 | tablep = config_tables; | ||
476 | pr_info(""); | 552 | pr_info(""); |
477 | for (i = 0; i < efi.systab->nr_tables; i++) { | 553 | for (i = 0; i < efi.systab->nr_tables; i++) { |
478 | efi_guid_t guid = config_tables[i].guid; | 554 | efi_guid_t guid; |
479 | unsigned long table = config_tables[i].table; | 555 | unsigned long table; |
480 | 556 | ||
557 | if (efi_64bit) { | ||
558 | u64 table64; | ||
559 | guid = ((efi_config_table_64_t *)tablep)->guid; | ||
560 | table64 = ((efi_config_table_64_t *)tablep)->table; | ||
561 | table = table64; | ||
562 | #ifdef CONFIG_X86_32 | ||
563 | if (table64 >> 32) { | ||
564 | pr_cont("\n"); | ||
565 | pr_err("Table located above 4GB, disabling EFI.\n"); | ||
566 | early_iounmap(config_tables, | ||
567 | efi.systab->nr_tables * sz); | ||
568 | return -EINVAL; | ||
569 | } | ||
570 | #endif | ||
571 | } else { | ||
572 | guid = ((efi_config_table_32_t *)tablep)->guid; | ||
573 | table = ((efi_config_table_32_t *)tablep)->table; | ||
574 | } | ||
481 | if (!efi_guidcmp(guid, MPS_TABLE_GUID)) { | 575 | if (!efi_guidcmp(guid, MPS_TABLE_GUID)) { |
482 | efi.mps = table; | 576 | efi.mps = table; |
483 | pr_cont(" MPS=0x%lx ", table); | 577 | pr_cont(" MPS=0x%lx ", table); |
@@ -502,10 +596,10 @@ static int __init efi_config_init(u64 tables, int nr_tables) | |||
502 | efi.uga = table; | 596 | efi.uga = table; |
503 | pr_cont(" UGA=0x%lx ", table); | 597 | pr_cont(" UGA=0x%lx ", table); |
504 | } | 598 | } |
599 | tablep += sz; | ||
505 | } | 600 | } |
506 | pr_cont("\n"); | 601 | pr_cont("\n"); |
507 | early_iounmap(config_tables, efi.systab->nr_tables * sz); | 602 | early_iounmap(config_tables, efi.systab->nr_tables * sz); |
508 | |||
509 | return 0; | 603 | return 0; |
510 | } | 604 | } |
511 | 605 | ||
@@ -569,11 +663,19 @@ void __init efi_init(void) | |||
569 | void *tmp; | 663 | void *tmp; |
570 | 664 | ||
571 | #ifdef CONFIG_X86_32 | 665 | #ifdef CONFIG_X86_32 |
666 | if (boot_params.efi_info.efi_systab_hi || | ||
667 | boot_params.efi_info.efi_memmap_hi) { | ||
668 | pr_info("Table located above 4GB, disabling EFI.\n"); | ||
669 | efi_enabled = 0; | ||
670 | return; | ||
671 | } | ||
572 | efi_phys.systab = (efi_system_table_t *)boot_params.efi_info.efi_systab; | 672 | efi_phys.systab = (efi_system_table_t *)boot_params.efi_info.efi_systab; |
673 | efi_native = !efi_64bit; | ||
573 | #else | 674 | #else |
574 | efi_phys.systab = (efi_system_table_t *) | 675 | efi_phys.systab = (efi_system_table_t *) |
575 | (boot_params.efi_info.efi_systab | | 676 | (boot_params.efi_info.efi_systab | |
576 | ((__u64)boot_params.efi_info.efi_systab_hi<<32)); | 677 | ((__u64)boot_params.efi_info.efi_systab_hi<<32)); |
678 | efi_native = efi_64bit; | ||
577 | #endif | 679 | #endif |
578 | 680 | ||
579 | if (efi_systab_init(efi_phys.systab)) { | 681 | if (efi_systab_init(efi_phys.systab)) { |
@@ -602,7 +704,14 @@ void __init efi_init(void) | |||
602 | return; | 704 | return; |
603 | } | 705 | } |
604 | 706 | ||
605 | if (efi_runtime_init()) { | 707 | /* |
708 | * Note: We currently don't support runtime services on an EFI | ||
709 | * that doesn't match the kernel 32/64-bit mode. | ||
710 | */ | ||
711 | |||
712 | if (!efi_native) | ||
713 | pr_info("No EFI runtime due to 32/64-bit mismatch with kernel\n"); | ||
714 | else if (efi_runtime_init()) { | ||
606 | efi_enabled = 0; | 715 | efi_enabled = 0; |
607 | return; | 716 | return; |
608 | } | 717 | } |
@@ -611,10 +720,11 @@ void __init efi_init(void) | |||
611 | efi_enabled = 0; | 720 | efi_enabled = 0; |
612 | return; | 721 | return; |
613 | } | 722 | } |
614 | |||
615 | #ifdef CONFIG_X86_32 | 723 | #ifdef CONFIG_X86_32 |
616 | x86_platform.get_wallclock = efi_get_time; | 724 | if (efi_native) { |
617 | x86_platform.set_wallclock = efi_set_rtc_mmss; | 725 | x86_platform.get_wallclock = efi_get_time; |
726 | x86_platform.set_wallclock = efi_set_rtc_mmss; | ||
727 | } | ||
618 | #endif | 728 | #endif |
619 | 729 | ||
620 | #if EFI_DEBUG | 730 | #if EFI_DEBUG |
@@ -672,6 +782,14 @@ void __init efi_enter_virtual_mode(void) | |||
672 | 782 | ||
673 | efi.systab = NULL; | 783 | efi.systab = NULL; |
674 | 784 | ||
785 | /* | ||
786 | * We don't do virtual mode, since we don't do runtime services, on | ||
787 | * non-native EFI | ||
788 | */ | ||
789 | |||
790 | if (!efi_native) | ||
791 | goto out; | ||
792 | |||
675 | /* Merge contiguous regions of the same type and attribute */ | 793 | /* Merge contiguous regions of the same type and attribute */ |
676 | for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { | 794 | for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { |
677 | u64 prev_size; | 795 | u64 prev_size; |
@@ -787,6 +905,8 @@ void __init efi_enter_virtual_mode(void) | |||
787 | efi.query_capsule_caps = virt_efi_query_capsule_caps; | 905 | efi.query_capsule_caps = virt_efi_query_capsule_caps; |
788 | if (__supported_pte_mask & _PAGE_NX) | 906 | if (__supported_pte_mask & _PAGE_NX) |
789 | runtime_code_page_mkexec(); | 907 | runtime_code_page_mkexec(); |
908 | |||
909 | out: | ||
790 | early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size); | 910 | early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size); |
791 | memmap.map = NULL; | 911 | memmap.map = NULL; |
792 | kfree(new_memmap); | 912 | kfree(new_memmap); |