aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/e820.c140
-rw-r--r--arch/x86/kernel/head.c2
-rw-r--r--include/asm-x86/e820.h1
3 files changed, 133 insertions, 10 deletions
diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c
index 8a8afbdeb34e..600c9de237a0 100644
--- a/arch/x86/kernel/e820.c
+++ b/arch/x86/kernel/e820.c
@@ -604,6 +604,7 @@ void __init e820_mark_nosave_regions(unsigned long limit_pfn)
604struct early_res { 604struct early_res {
605 u64 start, end; 605 u64 start, end;
606 char name[16]; 606 char name[16];
607 char overlap_ok;
607}; 608};
608static struct early_res early_res[MAX_EARLY_RES] __initdata = { 609static struct early_res early_res[MAX_EARLY_RES] __initdata = {
609 { 0, PAGE_SIZE, "BIOS data page" }, /* BIOS data page */ 610 { 0, PAGE_SIZE, "BIOS data page" }, /* BIOS data page */
@@ -640,7 +641,93 @@ static int __init find_overlapped_early(u64 start, u64 end)
640 return i; 641 return i;
641} 642}
642 643
643void __init reserve_early(u64 start, u64 end, char *name) 644/*
645 * Drop the i-th range from the early reservation map,
646 * by copying any higher ranges down one over it, and
647 * clearing what had been the last slot.
648 */
649static void __init drop_range(int i)
650{
651 int j;
652
653 for (j = i + 1; j < MAX_EARLY_RES && early_res[j].end; j++)
654 ;
655
656 memmove(&early_res[i], &early_res[i + 1],
657 (j - 1 - i) * sizeof(struct early_res));
658
659 early_res[j - 1].end = 0;
660}
661
662/*
663 * Split any existing ranges that:
664 * 1) are marked 'overlap_ok', and
665 * 2) overlap with the stated range [start, end)
666 * into whatever portion (if any) of the existing range is entirely
667 * below or entirely above the stated range. Drop the portion
668 * of the existing range that overlaps with the stated range,
669 * which will allow the caller of this routine to then add that
670 * stated range without conflicting with any existing range.
671 */
672static void __init drop_overlaps_that_are_ok(u64 start, u64 end)
673{
674 int i;
675 struct early_res *r;
676 u64 lower_start, lower_end;
677 u64 upper_start, upper_end;
678 char name[16];
679
680 for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) {
681 r = &early_res[i];
682
683 /* Continue past non-overlapping ranges */
684 if (end <= r->start || start >= r->end)
685 continue;
686
687 /*
688 * Leave non-ok overlaps as is; let caller
689 * panic "Overlapping early reservations"
690 * when it hits this overlap.
691 */
692 if (!r->overlap_ok)
693 return;
694
695 /*
696 * We have an ok overlap. We will drop it from the early
697 * reservation map, and add back in any non-overlapping
698 * portions (lower or upper) as separate, overlap_ok,
699 * non-overlapping ranges.
700 */
701
702 /* 1. Note any non-overlapping (lower or upper) ranges. */
703 strncpy(name, r->name, sizeof(name) - 1);
704
705 lower_start = lower_end = 0;
706 upper_start = upper_end = 0;
707 if (r->start < start) {
708 lower_start = r->start;
709 lower_end = start;
710 }
711 if (r->end > end) {
712 upper_start = end;
713 upper_end = r->end;
714 }
715
716 /* 2. Drop the original ok overlapping range */
717 drop_range(i);
718
719 i--; /* resume for-loop on copied down entry */
720
721 /* 3. Add back in any non-overlapping ranges. */
722 if (lower_end)
723 reserve_early_overlap_ok(lower_start, lower_end, name);
724 if (upper_end)
725 reserve_early_overlap_ok(upper_start, upper_end, name);
726 }
727}
728
729static void __init __reserve_early(u64 start, u64 end, char *name,
730 int overlap_ok)
644{ 731{
645 int i; 732 int i;
646 struct early_res *r; 733 struct early_res *r;
@@ -656,14 +743,55 @@ void __init reserve_early(u64 start, u64 end, char *name)
656 r->end - 1, r->name); 743 r->end - 1, r->name);
657 r->start = start; 744 r->start = start;
658 r->end = end; 745 r->end = end;
746 r->overlap_ok = overlap_ok;
659 if (name) 747 if (name)
660 strncpy(r->name, name, sizeof(r->name) - 1); 748 strncpy(r->name, name, sizeof(r->name) - 1);
661} 749}
662 750
751/*
752 * A few early reservtations come here.
753 *
754 * The 'overlap_ok' in the name of this routine does -not- mean it
755 * is ok for these reservations to overlap an earlier reservation.
756 * Rather it means that it is ok for subsequent reservations to
757 * overlap this one.
758 *
759 * Use this entry point to reserve early ranges when you are doing
760 * so out of "Paranoia", reserving perhaps more memory than you need,
761 * just in case, and don't mind a subsequent overlapping reservation
762 * that is known to be needed.
763 *
764 * The drop_overlaps_that_are_ok() call here isn't really needed.
765 * It would be needed if we had two colliding 'overlap_ok'
766 * reservations, so that the second such would not panic on the
767 * overlap with the first. We don't have any such as of this
768 * writing, but might as well tolerate such if it happens in
769 * the future.
770 */
771void __init reserve_early_overlap_ok(u64 start, u64 end, char *name)
772{
773 drop_overlaps_that_are_ok(start, end);
774 __reserve_early(start, end, name, 1);
775}
776
777/*
778 * Most early reservations come here.
779 *
780 * We first have drop_overlaps_that_are_ok() drop any pre-existing
781 * 'overlap_ok' ranges, so that we can then reserve this memory
782 * range without risk of panic'ing on an overlapping overlap_ok
783 * early reservation.
784 */
785void __init reserve_early(u64 start, u64 end, char *name)
786{
787 drop_overlaps_that_are_ok(start, end);
788 __reserve_early(start, end, name, 0);
789}
790
663void __init free_early(u64 start, u64 end) 791void __init free_early(u64 start, u64 end)
664{ 792{
665 struct early_res *r; 793 struct early_res *r;
666 int i, j; 794 int i;
667 795
668 i = find_overlapped_early(start, end); 796 i = find_overlapped_early(start, end);
669 r = &early_res[i]; 797 r = &early_res[i];
@@ -671,13 +799,7 @@ void __init free_early(u64 start, u64 end)
671 panic("free_early on not reserved area: %llx-%llx!", 799 panic("free_early on not reserved area: %llx-%llx!",
672 start, end - 1); 800 start, end - 1);
673 801
674 for (j = i + 1; j < MAX_EARLY_RES && early_res[j].end; j++) 802 drop_range(i);
675 ;
676
677 memmove(&early_res[i], &early_res[i + 1],
678 (j - 1 - i) * sizeof(struct early_res));
679
680 early_res[j - 1].end = 0;
681} 803}
682 804
683void __init early_res_to_bootmem(u64 start, u64 end) 805void __init early_res_to_bootmem(u64 start, u64 end)
diff --git a/arch/x86/kernel/head.c b/arch/x86/kernel/head.c
index a727c0b9819c..a6816be01cd6 100644
--- a/arch/x86/kernel/head.c
+++ b/arch/x86/kernel/head.c
@@ -51,7 +51,7 @@ void __init reserve_ebda_region(void)
51 lowmem = 0x9f000; 51 lowmem = 0x9f000;
52 52
53 /* reserve all memory between lowmem and the 1MB mark */ 53 /* reserve all memory between lowmem and the 1MB mark */
54 reserve_early(lowmem, 0x100000, "BIOS reserved"); 54 reserve_early_overlap_ok(lowmem, 0x100000, "BIOS reserved");
55} 55}
56 56
57void __init reserve_setup_data(void) 57void __init reserve_setup_data(void)
diff --git a/include/asm-x86/e820.h b/include/asm-x86/e820.h
index 7c32df07bae4..13fa5a076aa2 100644
--- a/include/asm-x86/e820.h
+++ b/include/asm-x86/e820.h
@@ -88,6 +88,7 @@ extern unsigned long end_user_pfn;
88extern u64 find_e820_area(u64 start, u64 end, u64 size, u64 align); 88extern u64 find_e820_area(u64 start, u64 end, u64 size, u64 align);
89extern u64 find_e820_area_size(u64 start, u64 *sizep, u64 align); 89extern u64 find_e820_area_size(u64 start, u64 *sizep, u64 align);
90extern void reserve_early(u64 start, u64 end, char *name); 90extern void reserve_early(u64 start, u64 end, char *name);
91extern void reserve_early_overlap_ok(u64 start, u64 end, char *name);
91extern void free_early(u64 start, u64 end); 92extern void free_early(u64 start, u64 end);
92extern void early_res_to_bootmem(u64 start, u64 end); 93extern void early_res_to_bootmem(u64 start, u64 end);
93extern u64 early_reserve_e820(u64 startt, u64 sizet, u64 align); 94extern u64 early_reserve_e820(u64 startt, u64 sizet, u64 align);