aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/platform
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2012-02-12 16:24:29 -0500
committerH. Peter Anvin <hpa@zytor.com>2012-02-23 21:54:51 -0500
commit1adbfa3511ee1c1118e16a9a0246870f12fef4e6 (patch)
tree7bcdb0f37a98cdb7e97b996eda10a5aeca89c50f /arch/x86/platform
parent140bf275d3e89e9b36851d5cf498dbbbecdf7ca8 (diff)
x86, efi: Allow basic init with mixed 32/64-bit efi/kernel
Traditionally the kernel has refused to setup EFI at all if there's been a mismatch in 32/64-bit mode between EFI and the kernel. On some platforms that boot natively through EFI (Chrome OS being one), we still need to get at least some of the static data such as memory configuration out of EFI. Runtime services aren't as critical, and it's a significant amount of work to implement switching between the operating modes to call between kernel and firmware for thise cases. So I'm ignoring it for now. v5: * Fixed some printk strings based on feedback * Renamed 32/64-bit specific types to not have _ prefix * Fixed bug in printout of efi runtime disablement v4: * Some of the earlier cleanup was accidentally reverted by this patch, fixed. * Reworded some messages to not have to line wrap printk strings v3: * Reorganized to a series of patches to make it easier to review, and do some of the cleanups I had left out before. v2: * Added graceful error handling for 32-bit kernel that gets passed EFI data above 4GB. * Removed some warnings that were missed in first version. Signed-off-by: Olof Johansson <olof@lixom.net> Link: http://lkml.kernel.org/r/1329081869-20779-6-git-send-email-olof@lixom.net Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'arch/x86/platform')
-rw-r--r--arch/x86/platform/efi/efi.c164
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
69struct efi_memory_map memmap; 69struct efi_memory_map memmap;
70 70
71bool efi_64bit;
72static bool efi_native;
73
71static struct efi efi_phys __initdata; 74static struct efi efi_phys __initdata;
72static efi_system_table_t efi_systab __initdata; 75static 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
342void __init efi_memblock_x86_reserve_range(void) 345int __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
433static int __init efi_systab_init(void *phys) 443static 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
461static int __init efi_config_init(u64 tables, int nr_tables) 532static 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
909out:
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);