aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/e820.c
diff options
context:
space:
mode:
authorPaul Jackson <pj@sgi.com>2008-06-22 10:22:07 -0400
committerIngo Molnar <mingo@elte.hu>2008-07-08 06:51:26 -0400
commitc4ba1320b7075e9ce33ad0afaef43ba13260b4c2 (patch)
treed9c3aa07da17153d4ac8489daf10dbc48e2220b1 /arch/x86/kernel/e820.c
parent05486fa7e631a3be31a0bbc5a575a389a1609e94 (diff)
x86 boot: allow overlapping early reserve memory ranges
Add support for overlapping early memory reservations. In general, they still can't overlap, and will panic with "Overlapping early reservations" if they do overlap. But if a memory range is reserved with the new call: reserve_early_overlap_ok() rather than with the usual call: reserve_early() then subsequent early reservations are allowed to overlap. This new reserve_early_overlap_ok() call is only used in one place so far, which is the "BIOS reserved" reservation for the the EBDA region, which out of Paranoia reserves more than what the BIOS might have specified, and which thus might overlap with another legitimate early memory reservation (such as, perhaps, the EFI memmap.) Signed-off-by: Paul Jackson <pj@sgi.com> Cc: "Yinghai Lu" <yhlu.kernel@gmail.com> Cc: "Jack Steiner" <steiner@sgi.com> Cc: "Mike Travis" <travis@sgi.com> Cc: "Huang Cc: Ying" <ying.huang@intel.com> Cc: "Andi Kleen" <andi@firstfloor.org> Cc: "Andrew Morton" <akpm@linux-foundation.org> Cc: Paul Jackson <pj@sgi.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/e820.c')
-rw-r--r--arch/x86/kernel/e820.c140
1 files changed, 131 insertions, 9 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)