aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinn Crosetto <linn@hp.com>2013-09-22 21:59:08 -0400
committerMatt Fleming <matt.fleming@intel.com>2013-09-30 05:23:10 -0400
commitd2078d5adbe227d64d7963d93f13479c890a9a16 (patch)
tree2f9e6e2abc7f3d9aa69fd0587c3ae407f4e19b18
parent3203209d61440e02429fc52f192797adf5d8c053 (diff)
x86: EFI stub support for large memory maps
This patch fixes a problem with EFI memory maps larger than 128 entries when booting using the EFI stub, which results in overflowing e820_map in boot_params and an eventual halt when checking the map size in sanitize_e820_map(). If the number of map entries is greater than what can fit in e820_map, add the extra entries to the setup_data list using type SETUP_E820_EXT. These extra entries are then picked up when the setup_data list is parsed in parse_e820_ext(). Signed-off-by: Linn Crosetto <linn@hp.com> Signed-off-by: Matt Fleming <matt.fleming@intel.com>
-rw-r--r--arch/x86/boot/compressed/eboot.c222
1 files changed, 161 insertions, 61 deletions
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index beb07a4529ac..5c0dc55f2387 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -519,71 +519,47 @@ fail:
519 return NULL; 519 return NULL;
520} 520}
521 521
522static efi_status_t exit_boot(struct boot_params *boot_params, 522static void add_e820ext(struct boot_params *params,
523 void *handle) 523 struct setup_data *e820ext, u32 nr_entries)
524{ 524{
525 struct efi_info *efi = &boot_params->efi_info; 525 struct setup_data *data;
526 struct e820entry *e820_map = &boot_params->e820_map[0];
527 struct e820entry *prev = NULL;
528 unsigned long size, key, desc_size, _size;
529 efi_memory_desc_t *mem_map;
530 efi_status_t status; 526 efi_status_t status;
531 __u32 desc_version; 527 unsigned long size;
532 bool called_exit = false;
533 u8 nr_entries;
534 int i;
535
536get_map:
537 status = efi_get_memory_map(sys_table, &mem_map, &size, &desc_size,
538 &desc_version, &key);
539
540 if (status != EFI_SUCCESS)
541 return status;
542 528
543 memcpy(&efi->efi_loader_signature, EFI_LOADER_SIGNATURE, sizeof(__u32)); 529 e820ext->type = SETUP_E820_EXT;
544 efi->efi_systab = (unsigned long)sys_table; 530 e820ext->len = nr_entries * sizeof(struct e820entry);
545 efi->efi_memdesc_size = desc_size; 531 e820ext->next = 0;
546 efi->efi_memdesc_version = desc_version;
547 efi->efi_memmap = (unsigned long)mem_map;
548 efi->efi_memmap_size = size;
549 532
550#ifdef CONFIG_X86_64 533 data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
551 efi->efi_systab_hi = (unsigned long)sys_table >> 32;
552 efi->efi_memmap_hi = (unsigned long)mem_map >> 32;
553#endif
554 534
555 /* Might as well exit boot services now */ 535 while (data && data->next)
556 status = efi_call_phys2(sys_table->boottime->exit_boot_services, 536 data = (struct setup_data *)(unsigned long)data->next;
557 handle, key);
558 if (status != EFI_SUCCESS) {
559 /*
560 * ExitBootServices() will fail if any of the event
561 * handlers change the memory map. In which case, we
562 * must be prepared to retry, but only once so that
563 * we're guaranteed to exit on repeated failures instead
564 * of spinning forever.
565 */
566 if (called_exit)
567 goto free_mem_map;
568 537
569 called_exit = true; 538 if (data)
570 efi_call_phys1(sys_table->boottime->free_pool, mem_map); 539 data->next = (unsigned long)e820ext;
571 goto get_map; 540 else
572 } 541 params->hdr.setup_data = (unsigned long)e820ext;
542}
573 543
574 /* Historic? */ 544static efi_status_t setup_e820(struct boot_params *params,
575 boot_params->alt_mem_k = 32 * 1024; 545 struct setup_data *e820ext, u32 e820ext_size)
546{
547 struct e820entry *e820_map = &params->e820_map[0];
548 struct efi_info *efi = &params->efi_info;
549 struct e820entry *prev = NULL;
550 u32 nr_entries;
551 u32 nr_desc;
552 int i;
576 553
577 /*
578 * Convert the EFI memory map to E820.
579 */
580 nr_entries = 0; 554 nr_entries = 0;
581 for (i = 0; i < size / desc_size; i++) { 555 nr_desc = efi->efi_memmap_size / efi->efi_memdesc_size;
556
557 for (i = 0; i < nr_desc; i++) {
582 efi_memory_desc_t *d; 558 efi_memory_desc_t *d;
583 unsigned int e820_type = 0; 559 unsigned int e820_type = 0;
584 unsigned long m = (unsigned long)mem_map; 560 unsigned long m = efi->efi_memmap;
585 561
586 d = (efi_memory_desc_t *)(m + (i * desc_size)); 562 d = (efi_memory_desc_t *)(m + (i * efi->efi_memdesc_size));
587 switch (d->type) { 563 switch (d->type) {
588 case EFI_RESERVED_TYPE: 564 case EFI_RESERVED_TYPE:
589 case EFI_RUNTIME_SERVICES_CODE: 565 case EFI_RUNTIME_SERVICES_CODE:
@@ -620,18 +596,142 @@ get_map:
620 596
621 /* Merge adjacent mappings */ 597 /* Merge adjacent mappings */
622 if (prev && prev->type == e820_type && 598 if (prev && prev->type == e820_type &&
623 (prev->addr + prev->size) == d->phys_addr) 599 (prev->addr + prev->size) == d->phys_addr) {
624 prev->size += d->num_pages << 12; 600 prev->size += d->num_pages << 12;
625 else { 601 continue;
626 e820_map->addr = d->phys_addr;
627 e820_map->size = d->num_pages << 12;
628 e820_map->type = e820_type;
629 prev = e820_map++;
630 nr_entries++;
631 } 602 }
603
604 if (nr_entries == ARRAY_SIZE(params->e820_map)) {
605 u32 need = (nr_desc - i) * sizeof(struct e820entry) +
606 sizeof(struct setup_data);
607
608 if (!e820ext || e820ext_size < need)
609 return EFI_BUFFER_TOO_SMALL;
610
611 /* boot_params map full, switch to e820 extended */
612 e820_map = (struct e820entry *)e820ext->data;
613 }
614
615 e820_map->addr = d->phys_addr;
616 e820_map->size = d->num_pages << PAGE_SHIFT;
617 e820_map->type = e820_type;
618 prev = e820_map++;
619 nr_entries++;
632 } 620 }
633 621
634 boot_params->e820_entries = nr_entries; 622 if (nr_entries > ARRAY_SIZE(params->e820_map)) {
623 u32 nr_e820ext = nr_entries - ARRAY_SIZE(params->e820_map);
624
625 add_e820ext(params, e820ext, nr_e820ext);
626 nr_entries -= nr_e820ext;
627 }
628
629 params->e820_entries = (u8)nr_entries;
630
631 return EFI_SUCCESS;
632}
633
634static efi_status_t alloc_e820ext(u32 nr_desc, struct setup_data **e820ext,
635 u32 *e820ext_size)
636{
637 efi_status_t status;
638 unsigned long size;
639
640 size = sizeof(struct setup_data) +
641 sizeof(struct e820entry) * nr_desc;
642
643 if (*e820ext) {
644 efi_call_phys1(sys_table->boottime->free_pool, *e820ext);
645 *e820ext = NULL;
646 *e820ext_size = 0;
647 }
648
649 status = efi_call_phys3(sys_table->boottime->allocate_pool,
650 EFI_LOADER_DATA, size, e820ext);
651
652 if (status == EFI_SUCCESS)
653 *e820ext_size = size;
654
655 return status;
656}
657
658static efi_status_t exit_boot(struct boot_params *boot_params,
659 void *handle)
660{
661 struct efi_info *efi = &boot_params->efi_info;
662 unsigned long map_sz, key, desc_size;
663 efi_memory_desc_t *mem_map;
664 struct setup_data *e820ext;
665 __u32 e820ext_size;
666 __u32 nr_desc, prev_nr_desc;
667 efi_status_t status;
668 __u32 desc_version;
669 bool called_exit = false;
670 u8 nr_entries;
671 int i;
672
673 nr_desc = 0;
674 e820ext = NULL;
675 e820ext_size = 0;
676
677get_map:
678 status = efi_get_memory_map(sys_table, &mem_map, &map_sz, &desc_size,
679 &desc_version, &key);
680
681 if (status != EFI_SUCCESS)
682 return status;
683
684 prev_nr_desc = nr_desc;
685 nr_desc = map_sz / desc_size;
686 if (nr_desc > prev_nr_desc &&
687 nr_desc > ARRAY_SIZE(boot_params->e820_map)) {
688 u32 nr_e820ext = nr_desc - ARRAY_SIZE(boot_params->e820_map);
689
690 status = alloc_e820ext(nr_e820ext, &e820ext, &e820ext_size);
691 if (status != EFI_SUCCESS)
692 goto free_mem_map;
693
694 efi_call_phys1(sys_table->boottime->free_pool, mem_map);
695 goto get_map; /* Allocated memory, get map again */
696 }
697
698 memcpy(&efi->efi_loader_signature, EFI_LOADER_SIGNATURE, sizeof(__u32));
699 efi->efi_systab = (unsigned long)sys_table;
700 efi->efi_memdesc_size = desc_size;
701 efi->efi_memdesc_version = desc_version;
702 efi->efi_memmap = (unsigned long)mem_map;
703 efi->efi_memmap_size = map_sz;
704
705#ifdef CONFIG_X86_64
706 efi->efi_systab_hi = (unsigned long)sys_table >> 32;
707 efi->efi_memmap_hi = (unsigned long)mem_map >> 32;
708#endif
709
710 /* Might as well exit boot services now */
711 status = efi_call_phys2(sys_table->boottime->exit_boot_services,
712 handle, key);
713 if (status != EFI_SUCCESS) {
714 /*
715 * ExitBootServices() will fail if any of the event
716 * handlers change the memory map. In which case, we
717 * must be prepared to retry, but only once so that
718 * we're guaranteed to exit on repeated failures instead
719 * of spinning forever.
720 */
721 if (called_exit)
722 goto free_mem_map;
723
724 called_exit = true;
725 efi_call_phys1(sys_table->boottime->free_pool, mem_map);
726 goto get_map;
727 }
728
729 /* Historic? */
730 boot_params->alt_mem_k = 32 * 1024;
731
732 status = setup_e820(boot_params, e820ext, e820ext_size);
733 if (status != EFI_SUCCESS)
734 return status;
635 735
636 return EFI_SUCCESS; 736 return EFI_SUCCESS;
637 737