aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/e820_64.c
diff options
context:
space:
mode:
authorYinghai Lu <yhlu.kernel@gmail.com>2008-05-11 03:30:15 -0400
committerThomas Gleixner <tglx@linutronix.de>2008-05-25 04:55:10 -0400
commitb79cd8f1268bab57ff85b19d131f7f23deab2dee (patch)
tree9f7c90389329bf76ba5f0ced29a3dc4c6ec7680b /arch/x86/kernel/e820_64.c
parent833e78bfeeef628f0201349a0a05a54f48f07884 (diff)
x86: make e820.c to have common functions
remove the duplicated copy of these functions. Signed-off-by: Yinghai Lu <yhlu.kernel@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/e820_64.c')
-rw-r--r--arch/x86/kernel/e820_64.c444
1 files changed, 0 insertions, 444 deletions
diff --git a/arch/x86/kernel/e820_64.c b/arch/x86/kernel/e820_64.c
index c45b4dea4055..28a14eb65d3d 100644
--- a/arch/x86/kernel/e820_64.c
+++ b/arch/x86/kernel/e820_64.c
@@ -29,8 +29,6 @@
29#include <asm/kdebug.h> 29#include <asm/kdebug.h>
30#include <asm/trampoline.h> 30#include <asm/trampoline.h>
31 31
32struct e820map e820;
33
34/* 32/*
35 * PFN of last memory page. 33 * PFN of last memory page.
36 */ 34 */
@@ -176,62 +174,6 @@ again:
176 } 174 }
177 return changed; 175 return changed;
178} 176}
179/*
180 * This function checks if any part of the range <start,end> is mapped
181 * with type.
182 */
183int
184e820_any_mapped(unsigned long start, unsigned long end, unsigned type)
185{
186 int i;
187
188 for (i = 0; i < e820.nr_map; i++) {
189 struct e820entry *ei = &e820.map[i];
190
191 if (type && ei->type != type)
192 continue;
193 if (ei->addr >= end || ei->addr + ei->size <= start)
194 continue;
195 return 1;
196 }
197 return 0;
198}
199EXPORT_SYMBOL_GPL(e820_any_mapped);
200
201/*
202 * This function checks if the entire range <start,end> is mapped with type.
203 *
204 * Note: this function only works correct if the e820 table is sorted and
205 * not-overlapping, which is the case
206 */
207int __init e820_all_mapped(unsigned long start, unsigned long end,
208 unsigned type)
209{
210 int i;
211
212 for (i = 0; i < e820.nr_map; i++) {
213 struct e820entry *ei = &e820.map[i];
214
215 if (type && ei->type != type)
216 continue;
217 /* is the region (part) in overlap with the current region ?*/
218 if (ei->addr >= end || ei->addr + ei->size <= start)
219 continue;
220
221 /* if the region is at the beginning of <start,end> we move
222 * start to the end of the region since it's ok until there
223 */
224 if (ei->addr <= start)
225 start = ei->addr + ei->size;
226 /*
227 * if start is now at or beyond end, we're done, full
228 * coverage
229 */
230 if (start >= end)
231 return 1;
232 }
233 return 0;
234}
235 177
236/* 178/*
237 * Find a free area with specified alignment in a specific range. 179 * Find a free area with specified alignment in a specific range.
@@ -435,24 +377,6 @@ e820_register_active_regions(int nid, unsigned long start_pfn,
435} 377}
436 378
437/* 379/*
438 * Add a memory region to the kernel e820 map.
439 */
440void __init add_memory_region(unsigned long start, unsigned long size, int type)
441{
442 int x = e820.nr_map;
443
444 if (x == E820MAX) {
445 printk(KERN_ERR "Ooops! Too many entries in the memory map!\n");
446 return;
447 }
448
449 e820.map[x].addr = start;
450 e820.map[x].size = size;
451 e820.map[x].type = type;
452 e820.nr_map++;
453}
454
455/*
456 * Find the hole size (in bytes) in the memory range. 380 * Find the hole size (in bytes) in the memory range.
457 * @start: starting address of the memory range to scan 381 * @start: starting address of the memory range to scan
458 * @end: ending address of the memory range to scan 382 * @end: ending address of the memory range to scan
@@ -473,266 +397,6 @@ unsigned long __init e820_hole_size(unsigned long start, unsigned long end)
473 return end - start - (ram << PAGE_SHIFT); 397 return end - start - (ram << PAGE_SHIFT);
474} 398}
475 399
476static void __init e820_print_map(char *who)
477{
478 int i;
479
480 for (i = 0; i < e820.nr_map; i++) {
481 printk(KERN_INFO " %s: %016Lx - %016Lx ", who,
482 (unsigned long long) e820.map[i].addr,
483 (unsigned long long)
484 (e820.map[i].addr + e820.map[i].size));
485 switch (e820.map[i].type) {
486 case E820_RAM:
487 printk(KERN_CONT "(usable)\n");
488 break;
489 case E820_RESERVED:
490 printk(KERN_CONT "(reserved)\n");
491 break;
492 case E820_ACPI:
493 printk(KERN_CONT "(ACPI data)\n");
494 break;
495 case E820_NVS:
496 printk(KERN_CONT "(ACPI NVS)\n");
497 break;
498 default:
499 printk(KERN_CONT "type %u\n", e820.map[i].type);
500 break;
501 }
502 }
503}
504
505/*
506 * Sanitize the BIOS e820 map.
507 *
508 * Some e820 responses include overlapping entries. The following
509 * replaces the original e820 map with a new one, removing overlaps.
510 *
511 */
512static int __init sanitize_e820_map(struct e820entry *biosmap, char *pnr_map)
513{
514 struct change_member {
515 struct e820entry *pbios; /* pointer to original bios entry */
516 unsigned long long addr; /* address for this change point */
517 };
518 static struct change_member change_point_list[2*E820MAX] __initdata;
519 static struct change_member *change_point[2*E820MAX] __initdata;
520 static struct e820entry *overlap_list[E820MAX] __initdata;
521 static struct e820entry new_bios[E820MAX] __initdata;
522 struct change_member *change_tmp;
523 unsigned long current_type, last_type;
524 unsigned long long last_addr;
525 int chgidx, still_changing;
526 int overlap_entries;
527 int new_bios_entry;
528 int old_nr, new_nr, chg_nr;
529 int i;
530
531 /*
532 Visually we're performing the following
533 (1,2,3,4 = memory types)...
534
535 Sample memory map (w/overlaps):
536 ____22__________________
537 ______________________4_
538 ____1111________________
539 _44_____________________
540 11111111________________
541 ____________________33__
542 ___________44___________
543 __________33333_________
544 ______________22________
545 ___________________2222_
546 _________111111111______
547 _____________________11_
548 _________________4______
549
550 Sanitized equivalent (no overlap):
551 1_______________________
552 _44_____________________
553 ___1____________________
554 ____22__________________
555 ______11________________
556 _________1______________
557 __________3_____________
558 ___________44___________
559 _____________33_________
560 _______________2________
561 ________________1_______
562 _________________4______
563 ___________________2____
564 ____________________33__
565 ______________________4_
566 */
567
568 /* if there's only one memory region, don't bother */
569 if (*pnr_map < 2)
570 return -1;
571
572 old_nr = *pnr_map;
573
574 /* bail out if we find any unreasonable addresses in bios map */
575 for (i = 0; i < old_nr; i++)
576 if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr)
577 return -1;
578
579 /* create pointers for initial change-point information (for sorting) */
580 for (i = 0; i < 2 * old_nr; i++)
581 change_point[i] = &change_point_list[i];
582
583 /* record all known change-points (starting and ending addresses),
584 omitting those that are for empty memory regions */
585 chgidx = 0;
586 for (i = 0; i < old_nr; i++) {
587 if (biosmap[i].size != 0) {
588 change_point[chgidx]->addr = biosmap[i].addr;
589 change_point[chgidx++]->pbios = &biosmap[i];
590 change_point[chgidx]->addr = biosmap[i].addr +
591 biosmap[i].size;
592 change_point[chgidx++]->pbios = &biosmap[i];
593 }
594 }
595 chg_nr = chgidx;
596
597 /* sort change-point list by memory addresses (low -> high) */
598 still_changing = 1;
599 while (still_changing) {
600 still_changing = 0;
601 for (i = 1; i < chg_nr; i++) {
602 unsigned long long curaddr, lastaddr;
603 unsigned long long curpbaddr, lastpbaddr;
604
605 curaddr = change_point[i]->addr;
606 lastaddr = change_point[i - 1]->addr;
607 curpbaddr = change_point[i]->pbios->addr;
608 lastpbaddr = change_point[i - 1]->pbios->addr;
609
610 /*
611 * swap entries, when:
612 *
613 * curaddr > lastaddr or
614 * curaddr == lastaddr and curaddr == curpbaddr and
615 * lastaddr != lastpbaddr
616 */
617 if (curaddr < lastaddr ||
618 (curaddr == lastaddr && curaddr == curpbaddr &&
619 lastaddr != lastpbaddr)) {
620 change_tmp = change_point[i];
621 change_point[i] = change_point[i-1];
622 change_point[i-1] = change_tmp;
623 still_changing = 1;
624 }
625 }
626 }
627
628 /* create a new bios memory map, removing overlaps */
629 overlap_entries = 0; /* number of entries in the overlap table */
630 new_bios_entry = 0; /* index for creating new bios map entries */
631 last_type = 0; /* start with undefined memory type */
632 last_addr = 0; /* start with 0 as last starting address */
633
634 /* loop through change-points, determining affect on the new bios map */
635 for (chgidx = 0; chgidx < chg_nr; chgidx++) {
636 /* keep track of all overlapping bios entries */
637 if (change_point[chgidx]->addr ==
638 change_point[chgidx]->pbios->addr) {
639 /*
640 * add map entry to overlap list (> 1 entry
641 * implies an overlap)
642 */
643 overlap_list[overlap_entries++] =
644 change_point[chgidx]->pbios;
645 } else {
646 /*
647 * remove entry from list (order independent,
648 * so swap with last)
649 */
650 for (i = 0; i < overlap_entries; i++) {
651 if (overlap_list[i] ==
652 change_point[chgidx]->pbios)
653 overlap_list[i] =
654 overlap_list[overlap_entries-1];
655 }
656 overlap_entries--;
657 }
658 /*
659 * if there are overlapping entries, decide which
660 * "type" to use (larger value takes precedence --
661 * 1=usable, 2,3,4,4+=unusable)
662 */
663 current_type = 0;
664 for (i = 0; i < overlap_entries; i++)
665 if (overlap_list[i]->type > current_type)
666 current_type = overlap_list[i]->type;
667 /*
668 * continue building up new bios map based on this
669 * information
670 */
671 if (current_type != last_type) {
672 if (last_type != 0) {
673 new_bios[new_bios_entry].size =
674 change_point[chgidx]->addr - last_addr;
675 /*
676 * move forward only if the new size
677 * was non-zero
678 */
679 if (new_bios[new_bios_entry].size != 0)
680 /*
681 * no more space left for new
682 * bios entries ?
683 */
684 if (++new_bios_entry >= E820MAX)
685 break;
686 }
687 if (current_type != 0) {
688 new_bios[new_bios_entry].addr =
689 change_point[chgidx]->addr;
690 new_bios[new_bios_entry].type = current_type;
691 last_addr = change_point[chgidx]->addr;
692 }
693 last_type = current_type;
694 }
695 }
696 /* retain count for new bios entries */
697 new_nr = new_bios_entry;
698
699 /* copy new bios mapping into original location */
700 memcpy(biosmap, new_bios, new_nr * sizeof(struct e820entry));
701 *pnr_map = new_nr;
702
703 return 0;
704}
705
706/*
707 * Copy the BIOS e820 map into a safe place.
708 *
709 * Sanity-check it while we're at it..
710 *
711 * If we're lucky and live on a modern system, the setup code
712 * will have given us a memory map that we can use to properly
713 * set up memory. If we aren't, we'll fake a memory map.
714 */
715static int __init copy_e820_map(struct e820entry *biosmap, int nr_map)
716{
717 /* Only one memory region (or negative)? Ignore it */
718 if (nr_map < 2)
719 return -1;
720
721 do {
722 u64 start = biosmap->addr;
723 u64 size = biosmap->size;
724 u64 end = start + size;
725 u32 type = biosmap->type;
726
727 /* Overflow in 64 bits? Ignore the memory map. */
728 if (start > end)
729 return -1;
730
731 add_memory_region(start, size, type);
732 } while (biosmap++, --nr_map);
733 return 0;
734}
735
736static void early_panic(char *msg) 400static void early_panic(char *msg)
737{ 401{
738 early_printk(msg); 402 early_printk(msg);
@@ -829,114 +493,6 @@ void __init finish_e820_parsing(void)
829 } 493 }
830} 494}
831 495
832u64 __init update_memory_range(u64 start, u64 size, unsigned old_type,
833 unsigned new_type)
834{
835 int i;
836 u64 real_updated_size = 0;
837
838 BUG_ON(old_type == new_type);
839
840 for (i = 0; i < e820.nr_map; i++) {
841 struct e820entry *ei = &e820.map[i];
842 u64 final_start, final_end;
843 if (ei->type != old_type)
844 continue;
845 /* totally covered? */
846 if (ei->addr >= start &&
847 (ei->addr + ei->size) <= (start + size)) {
848 ei->type = new_type;
849 real_updated_size += ei->size;
850 continue;
851 }
852 /* partially covered */
853 final_start = max(start, ei->addr);
854 final_end = min(start + size, ei->addr + ei->size);
855 if (final_start >= final_end)
856 continue;
857 add_memory_region(final_start, final_end - final_start,
858 new_type);
859 real_updated_size += final_end - final_start;
860 }
861 return real_updated_size;
862}
863
864void __init update_e820(void)
865{
866 u8 nr_map;
867
868 nr_map = e820.nr_map;
869 if (sanitize_e820_map(e820.map, &nr_map))
870 return;
871 e820.nr_map = nr_map;
872 printk(KERN_INFO "modified physical RAM map:\n");
873 e820_print_map("modified");
874}
875
876unsigned long pci_mem_start = 0xaeedbabe;
877EXPORT_SYMBOL(pci_mem_start);
878
879/*
880 * Search for the biggest gap in the low 32 bits of the e820
881 * memory space. We pass this space to PCI to assign MMIO resources
882 * for hotplug or unconfigured devices in.
883 * Hopefully the BIOS let enough space left.
884 */
885__init void e820_setup_gap(void)
886{
887 unsigned long gapstart, gapsize, round;
888 unsigned long last;
889 int i;
890 int found = 0;
891
892 last = 0x100000000ull;
893 gapstart = 0x10000000;
894 gapsize = 0x400000;
895 i = e820.nr_map;
896 while (--i >= 0) {
897 unsigned long long start = e820.map[i].addr;
898 unsigned long long end = start + e820.map[i].size;
899
900 /*
901 * Since "last" is at most 4GB, we know we'll
902 * fit in 32 bits if this condition is true
903 */
904 if (last > end) {
905 unsigned long gap = last - end;
906
907 if (gap > gapsize) {
908 gapsize = gap;
909 gapstart = end;
910 found = 1;
911 }
912 }
913 if (start < last)
914 last = start;
915 }
916
917 if (!found) {
918 gapstart = (end_pfn << PAGE_SHIFT) + 1024*1024;
919 printk(KERN_ERR "PCI: Warning: Cannot find a gap in the 32bit "
920 "address range\n"
921 KERN_ERR "PCI: Unassigned devices with 32bit resource "
922 "registers may break!\n");
923 }
924
925 /*
926 * See how much we want to round up: start off with
927 * rounding to the next 1MB area.
928 */
929 round = 0x100000;
930 while ((gapsize >> 4) > round)
931 round += round;
932 /* Fun with two's complement */
933 pci_mem_start = (gapstart + round) & -round;
934
935 printk(KERN_INFO
936 "Allocating PCI resources starting at %lx (gap: %lx:%lx)\n",
937 pci_mem_start, gapstart, gapsize);
938}
939
940int __init arch_get_ram_range(int slot, u64 *addr, u64 *size) 496int __init arch_get_ram_range(int slot, u64 *addr, u64 *size)
941{ 497{
942 int i; 498 int i;