diff options
author | Jeff Garzik <jeff@garzik.org> | 2006-09-27 18:16:47 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-09-27 18:16:47 -0400 |
commit | 3b9f6cb8a1ec791be79c6c7595fea922f12d1e64 (patch) | |
tree | 2393a448add846e6c2ed12f68106c3018b72c6a9 /arch/x86_64/kernel/e820.c | |
parent | c38778c3a9aeadcd1ee319cfc8ea5a9cbf8cdafa (diff) | |
parent | a77c64c1a641950626181b4857abb701d8f38ccc (diff) |
Merge branch 'master' into upstream
Diffstat (limited to 'arch/x86_64/kernel/e820.c')
-rw-r--r-- | arch/x86_64/kernel/e820.c | 243 |
1 files changed, 101 insertions, 142 deletions
diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c index 708a3cd9a27e..b3f0908668ec 100644 --- a/arch/x86_64/kernel/e820.c +++ b/arch/x86_64/kernel/e820.c | |||
@@ -25,6 +25,8 @@ | |||
25 | #include <asm/bootsetup.h> | 25 | #include <asm/bootsetup.h> |
26 | #include <asm/sections.h> | 26 | #include <asm/sections.h> |
27 | 27 | ||
28 | struct e820map e820 __initdata; | ||
29 | |||
28 | /* | 30 | /* |
29 | * PFN of last memory page. | 31 | * PFN of last memory page. |
30 | */ | 32 | */ |
@@ -41,7 +43,7 @@ unsigned long end_pfn_map; | |||
41 | /* | 43 | /* |
42 | * Last pfn which the user wants to use. | 44 | * Last pfn which the user wants to use. |
43 | */ | 45 | */ |
44 | unsigned long end_user_pfn = MAXMEM>>PAGE_SHIFT; | 46 | static unsigned long __initdata end_user_pfn = MAXMEM>>PAGE_SHIFT; |
45 | 47 | ||
46 | extern struct resource code_resource, data_resource; | 48 | extern struct resource code_resource, data_resource; |
47 | 49 | ||
@@ -70,12 +72,7 @@ static inline int bad_addr(unsigned long *addrp, unsigned long size) | |||
70 | return 1; | 72 | return 1; |
71 | } | 73 | } |
72 | #endif | 74 | #endif |
73 | /* kernel code + 640k memory hole (later should not be needed, but | 75 | /* kernel code */ |
74 | be paranoid for now) */ | ||
75 | if (last >= 640*1024 && addr < 1024*1024) { | ||
76 | *addrp = 1024*1024; | ||
77 | return 1; | ||
78 | } | ||
79 | if (last >= __pa_symbol(&_text) && last < __pa_symbol(&_end)) { | 76 | if (last >= __pa_symbol(&_text) && last < __pa_symbol(&_end)) { |
80 | *addrp = __pa_symbol(&_end); | 77 | *addrp = __pa_symbol(&_end); |
81 | return 1; | 78 | return 1; |
@@ -165,59 +162,14 @@ unsigned long __init find_e820_area(unsigned long start, unsigned long end, unsi | |||
165 | return -1UL; | 162 | return -1UL; |
166 | } | 163 | } |
167 | 164 | ||
168 | /* | ||
169 | * Free bootmem based on the e820 table for a node. | ||
170 | */ | ||
171 | void __init e820_bootmem_free(pg_data_t *pgdat, unsigned long start,unsigned long end) | ||
172 | { | ||
173 | int i; | ||
174 | for (i = 0; i < e820.nr_map; i++) { | ||
175 | struct e820entry *ei = &e820.map[i]; | ||
176 | unsigned long last, addr; | ||
177 | |||
178 | if (ei->type != E820_RAM || | ||
179 | ei->addr+ei->size <= start || | ||
180 | ei->addr >= end) | ||
181 | continue; | ||
182 | |||
183 | addr = round_up(ei->addr, PAGE_SIZE); | ||
184 | if (addr < start) | ||
185 | addr = start; | ||
186 | |||
187 | last = round_down(ei->addr + ei->size, PAGE_SIZE); | ||
188 | if (last >= end) | ||
189 | last = end; | ||
190 | |||
191 | if (last > addr && last-addr >= PAGE_SIZE) | ||
192 | free_bootmem_node(pgdat, addr, last-addr); | ||
193 | } | ||
194 | } | ||
195 | |||
196 | /* | 165 | /* |
197 | * Find the highest page frame number we have available | 166 | * Find the highest page frame number we have available |
198 | */ | 167 | */ |
199 | unsigned long __init e820_end_of_ram(void) | 168 | unsigned long __init e820_end_of_ram(void) |
200 | { | 169 | { |
201 | int i; | ||
202 | unsigned long end_pfn = 0; | 170 | unsigned long end_pfn = 0; |
171 | end_pfn = find_max_pfn_with_active_regions(); | ||
203 | 172 | ||
204 | for (i = 0; i < e820.nr_map; i++) { | ||
205 | struct e820entry *ei = &e820.map[i]; | ||
206 | unsigned long start, end; | ||
207 | |||
208 | start = round_up(ei->addr, PAGE_SIZE); | ||
209 | end = round_down(ei->addr + ei->size, PAGE_SIZE); | ||
210 | if (start >= end) | ||
211 | continue; | ||
212 | if (ei->type == E820_RAM) { | ||
213 | if (end > end_pfn<<PAGE_SHIFT) | ||
214 | end_pfn = end>>PAGE_SHIFT; | ||
215 | } else { | ||
216 | if (end > end_pfn_map<<PAGE_SHIFT) | ||
217 | end_pfn_map = end>>PAGE_SHIFT; | ||
218 | } | ||
219 | } | ||
220 | |||
221 | if (end_pfn > end_pfn_map) | 173 | if (end_pfn > end_pfn_map) |
222 | end_pfn_map = end_pfn; | 174 | end_pfn_map = end_pfn; |
223 | if (end_pfn_map > MAXMEM>>PAGE_SHIFT) | 175 | if (end_pfn_map > MAXMEM>>PAGE_SHIFT) |
@@ -227,43 +179,10 @@ unsigned long __init e820_end_of_ram(void) | |||
227 | if (end_pfn > end_pfn_map) | 179 | if (end_pfn > end_pfn_map) |
228 | end_pfn = end_pfn_map; | 180 | end_pfn = end_pfn_map; |
229 | 181 | ||
182 | printk("end_pfn_map = %lu\n", end_pfn_map); | ||
230 | return end_pfn; | 183 | return end_pfn; |
231 | } | 184 | } |
232 | 185 | ||
233 | /* | ||
234 | * Compute how much memory is missing in a range. | ||
235 | * Unlike the other functions in this file the arguments are in page numbers. | ||
236 | */ | ||
237 | unsigned long __init | ||
238 | e820_hole_size(unsigned long start_pfn, unsigned long end_pfn) | ||
239 | { | ||
240 | unsigned long ram = 0; | ||
241 | unsigned long start = start_pfn << PAGE_SHIFT; | ||
242 | unsigned long end = end_pfn << PAGE_SHIFT; | ||
243 | int i; | ||
244 | for (i = 0; i < e820.nr_map; i++) { | ||
245 | struct e820entry *ei = &e820.map[i]; | ||
246 | unsigned long last, addr; | ||
247 | |||
248 | if (ei->type != E820_RAM || | ||
249 | ei->addr+ei->size <= start || | ||
250 | ei->addr >= end) | ||
251 | continue; | ||
252 | |||
253 | addr = round_up(ei->addr, PAGE_SIZE); | ||
254 | if (addr < start) | ||
255 | addr = start; | ||
256 | |||
257 | last = round_down(ei->addr + ei->size, PAGE_SIZE); | ||
258 | if (last >= end) | ||
259 | last = end; | ||
260 | |||
261 | if (last > addr) | ||
262 | ram += last - addr; | ||
263 | } | ||
264 | return ((end - start) - ram) >> PAGE_SHIFT; | ||
265 | } | ||
266 | |||
267 | /* | 186 | /* |
268 | * Mark e820 reserved areas as busy for the resource manager. | 187 | * Mark e820 reserved areas as busy for the resource manager. |
269 | */ | 188 | */ |
@@ -345,6 +264,49 @@ void __init e820_mark_nosave_regions(void) | |||
345 | } | 264 | } |
346 | } | 265 | } |
347 | 266 | ||
267 | /* Walk the e820 map and register active regions within a node */ | ||
268 | void __init | ||
269 | e820_register_active_regions(int nid, unsigned long start_pfn, | ||
270 | unsigned long end_pfn) | ||
271 | { | ||
272 | int i; | ||
273 | unsigned long ei_startpfn, ei_endpfn; | ||
274 | for (i = 0; i < e820.nr_map; i++) { | ||
275 | struct e820entry *ei = &e820.map[i]; | ||
276 | ei_startpfn = round_up(ei->addr, PAGE_SIZE) >> PAGE_SHIFT; | ||
277 | ei_endpfn = round_down(ei->addr + ei->size, PAGE_SIZE) | ||
278 | >> PAGE_SHIFT; | ||
279 | |||
280 | /* Skip map entries smaller than a page */ | ||
281 | if (ei_startpfn > ei_endpfn) | ||
282 | continue; | ||
283 | |||
284 | /* Check if end_pfn_map should be updated */ | ||
285 | if (ei->type != E820_RAM && ei_endpfn > end_pfn_map) | ||
286 | end_pfn_map = ei_endpfn; | ||
287 | |||
288 | /* Skip if map is outside the node */ | ||
289 | if (ei->type != E820_RAM || | ||
290 | ei_endpfn <= start_pfn || | ||
291 | ei_startpfn >= end_pfn) | ||
292 | continue; | ||
293 | |||
294 | /* Check for overlaps */ | ||
295 | if (ei_startpfn < start_pfn) | ||
296 | ei_startpfn = start_pfn; | ||
297 | if (ei_endpfn > end_pfn) | ||
298 | ei_endpfn = end_pfn; | ||
299 | |||
300 | /* Obey end_user_pfn to save on memmap */ | ||
301 | if (ei_startpfn >= end_user_pfn) | ||
302 | continue; | ||
303 | if (ei_endpfn > end_user_pfn) | ||
304 | ei_endpfn = end_user_pfn; | ||
305 | |||
306 | add_active_range(nid, ei_startpfn, ei_endpfn); | ||
307 | } | ||
308 | } | ||
309 | |||
348 | /* | 310 | /* |
349 | * Add a memory region to the kernel e820 map. | 311 | * Add a memory region to the kernel e820 map. |
350 | */ | 312 | */ |
@@ -565,13 +527,6 @@ static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map) | |||
565 | * If we're lucky and live on a modern system, the setup code | 527 | * If we're lucky and live on a modern system, the setup code |
566 | * will have given us a memory map that we can use to properly | 528 | * will have given us a memory map that we can use to properly |
567 | * set up memory. If we aren't, we'll fake a memory map. | 529 | * set up memory. If we aren't, we'll fake a memory map. |
568 | * | ||
569 | * We check to see that the memory map contains at least 2 elements | ||
570 | * before we'll use it, because the detection code in setup.S may | ||
571 | * not be perfect and most every PC known to man has two memory | ||
572 | * regions: one from 0 to 640k, and one from 1mb up. (The IBM | ||
573 | * thinkpad 560x, for example, does not cooperate with the memory | ||
574 | * detection code.) | ||
575 | */ | 530 | */ |
576 | static int __init copy_e820_map(struct e820entry * biosmap, int nr_map) | 531 | static int __init copy_e820_map(struct e820entry * biosmap, int nr_map) |
577 | { | 532 | { |
@@ -589,34 +544,19 @@ static int __init copy_e820_map(struct e820entry * biosmap, int nr_map) | |||
589 | if (start > end) | 544 | if (start > end) |
590 | return -1; | 545 | return -1; |
591 | 546 | ||
592 | /* | ||
593 | * Some BIOSes claim RAM in the 640k - 1M region. | ||
594 | * Not right. Fix it up. | ||
595 | * | ||
596 | * This should be removed on Hammer which is supposed to not | ||
597 | * have non e820 covered ISA mappings there, but I had some strange | ||
598 | * problems so it stays for now. -AK | ||
599 | */ | ||
600 | if (type == E820_RAM) { | ||
601 | if (start < 0x100000ULL && end > 0xA0000ULL) { | ||
602 | if (start < 0xA0000ULL) | ||
603 | add_memory_region(start, 0xA0000ULL-start, type); | ||
604 | if (end <= 0x100000ULL) | ||
605 | continue; | ||
606 | start = 0x100000ULL; | ||
607 | size = end - start; | ||
608 | } | ||
609 | } | ||
610 | |||
611 | add_memory_region(start, size, type); | 547 | add_memory_region(start, size, type); |
612 | } while (biosmap++,--nr_map); | 548 | } while (biosmap++,--nr_map); |
613 | return 0; | 549 | return 0; |
614 | } | 550 | } |
615 | 551 | ||
616 | void __init setup_memory_region(void) | 552 | void early_panic(char *msg) |
617 | { | 553 | { |
618 | char *who = "BIOS-e820"; | 554 | early_printk(msg); |
555 | panic(msg); | ||
556 | } | ||
619 | 557 | ||
558 | void __init setup_memory_region(void) | ||
559 | { | ||
620 | /* | 560 | /* |
621 | * Try to copy the BIOS-supplied E820-map. | 561 | * Try to copy the BIOS-supplied E820-map. |
622 | * | 562 | * |
@@ -624,51 +564,70 @@ void __init setup_memory_region(void) | |||
624 | * the next section from 1mb->appropriate_mem_k | 564 | * the next section from 1mb->appropriate_mem_k |
625 | */ | 565 | */ |
626 | sanitize_e820_map(E820_MAP, &E820_MAP_NR); | 566 | sanitize_e820_map(E820_MAP, &E820_MAP_NR); |
627 | if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) { | 567 | if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) |
628 | unsigned long mem_size; | 568 | early_panic("Cannot find a valid memory map"); |
629 | |||
630 | /* compare results from other methods and take the greater */ | ||
631 | if (ALT_MEM_K < EXT_MEM_K) { | ||
632 | mem_size = EXT_MEM_K; | ||
633 | who = "BIOS-88"; | ||
634 | } else { | ||
635 | mem_size = ALT_MEM_K; | ||
636 | who = "BIOS-e801"; | ||
637 | } | ||
638 | |||
639 | e820.nr_map = 0; | ||
640 | add_memory_region(0, LOWMEMSIZE(), E820_RAM); | ||
641 | add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM); | ||
642 | } | ||
643 | printk(KERN_INFO "BIOS-provided physical RAM map:\n"); | 569 | printk(KERN_INFO "BIOS-provided physical RAM map:\n"); |
644 | e820_print_map(who); | 570 | e820_print_map("BIOS-e820"); |
645 | } | 571 | } |
646 | 572 | ||
647 | void __init parse_memopt(char *p, char **from) | 573 | static int __init parse_memopt(char *p) |
648 | { | 574 | { |
649 | end_user_pfn = memparse(p, from); | 575 | if (!p) |
576 | return -EINVAL; | ||
577 | end_user_pfn = memparse(p, &p); | ||
650 | end_user_pfn >>= PAGE_SHIFT; | 578 | end_user_pfn >>= PAGE_SHIFT; |
579 | return 0; | ||
651 | } | 580 | } |
581 | early_param("mem", parse_memopt); | ||
652 | 582 | ||
653 | void __init parse_memmapopt(char *p, char **from) | 583 | static int userdef __initdata; |
584 | |||
585 | static int __init parse_memmap_opt(char *p) | ||
654 | { | 586 | { |
587 | char *oldp; | ||
655 | unsigned long long start_at, mem_size; | 588 | unsigned long long start_at, mem_size; |
656 | 589 | ||
657 | mem_size = memparse(p, from); | 590 | if (!strcmp(p, "exactmap")) { |
658 | p = *from; | 591 | #ifdef CONFIG_CRASH_DUMP |
592 | /* If we are doing a crash dump, we | ||
593 | * still need to know the real mem | ||
594 | * size before original memory map is | ||
595 | * reset. | ||
596 | */ | ||
597 | saved_max_pfn = e820_end_of_ram(); | ||
598 | #endif | ||
599 | end_pfn_map = 0; | ||
600 | e820.nr_map = 0; | ||
601 | userdef = 1; | ||
602 | return 0; | ||
603 | } | ||
604 | |||
605 | oldp = p; | ||
606 | mem_size = memparse(p, &p); | ||
607 | if (p == oldp) | ||
608 | return -EINVAL; | ||
659 | if (*p == '@') { | 609 | if (*p == '@') { |
660 | start_at = memparse(p+1, from); | 610 | start_at = memparse(p+1, &p); |
661 | add_memory_region(start_at, mem_size, E820_RAM); | 611 | add_memory_region(start_at, mem_size, E820_RAM); |
662 | } else if (*p == '#') { | 612 | } else if (*p == '#') { |
663 | start_at = memparse(p+1, from); | 613 | start_at = memparse(p+1, &p); |
664 | add_memory_region(start_at, mem_size, E820_ACPI); | 614 | add_memory_region(start_at, mem_size, E820_ACPI); |
665 | } else if (*p == '$') { | 615 | } else if (*p == '$') { |
666 | start_at = memparse(p+1, from); | 616 | start_at = memparse(p+1, &p); |
667 | add_memory_region(start_at, mem_size, E820_RESERVED); | 617 | add_memory_region(start_at, mem_size, E820_RESERVED); |
668 | } else { | 618 | } else { |
669 | end_user_pfn = (mem_size >> PAGE_SHIFT); | 619 | end_user_pfn = (mem_size >> PAGE_SHIFT); |
670 | } | 620 | } |
671 | p = *from; | 621 | return *p == '\0' ? 0 : -EINVAL; |
622 | } | ||
623 | early_param("memmap", parse_memmap_opt); | ||
624 | |||
625 | void finish_e820_parsing(void) | ||
626 | { | ||
627 | if (userdef) { | ||
628 | printk(KERN_INFO "user-defined physical RAM map:\n"); | ||
629 | e820_print_map("user"); | ||
630 | } | ||
672 | } | 631 | } |
673 | 632 | ||
674 | unsigned long pci_mem_start = 0xaeedbabe; | 633 | unsigned long pci_mem_start = 0xaeedbabe; |