]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/x86/kernel/e820_64.c
x86: make e820.c to have common functions
[linux-2.6-omap-h63xx.git] / arch / x86 / kernel / e820_64.c
1 /*
2  * Handle the memory map.
3  * The functions here do the job until bootmem takes over.
4  *
5  *  Getting sanitize_e820_map() in sync with i386 version by applying change:
6  *  -  Provisions for empty E820 memory regions (reported by certain BIOSes).
7  *     Alex Achenbach <xela@slit.de>, December 2002.
8  *  Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
9  *
10  */
11 #include <linux/kernel.h>
12 #include <linux/types.h>
13 #include <linux/init.h>
14 #include <linux/bootmem.h>
15 #include <linux/ioport.h>
16 #include <linux/string.h>
17 #include <linux/kexec.h>
18 #include <linux/module.h>
19 #include <linux/mm.h>
20 #include <linux/suspend.h>
21 #include <linux/pfn.h>
22
23 #include <asm/pgtable.h>
24 #include <asm/page.h>
25 #include <asm/e820.h>
26 #include <asm/proto.h>
27 #include <asm/setup.h>
28 #include <asm/sections.h>
29 #include <asm/kdebug.h>
30 #include <asm/trampoline.h>
31
32 /*
33  * PFN of last memory page.
34  */
35 unsigned long end_pfn;
36
37 /*
38  * end_pfn only includes RAM, while max_pfn_mapped includes all e820 entries.
39  * The direct mapping extends to max_pfn_mapped, so that we can directly access
40  * apertures, ACPI and other tables without having to play with fixmaps.
41  */
42 unsigned long max_pfn_mapped;
43
44 /*
45  * Last pfn which the user wants to use.
46  */
47 static unsigned long __initdata end_user_pfn = MAXMEM>>PAGE_SHIFT;
48
49 /*
50  * Early reserved memory areas.
51  */
52 #define MAX_EARLY_RES 20
53
54 struct early_res {
55         unsigned long start, end;
56         char name[16];
57 };
58 static struct early_res early_res[MAX_EARLY_RES] __initdata = {
59         { 0, PAGE_SIZE, "BIOS data page" },                     /* BIOS data page */
60 #ifdef CONFIG_X86_TRAMPOLINE
61         { TRAMPOLINE_BASE, TRAMPOLINE_BASE + 2 * PAGE_SIZE, "TRAMPOLINE" },
62 #endif
63         {}
64 };
65
66 void __init reserve_early(unsigned long start, unsigned long end, char *name)
67 {
68         int i;
69         struct early_res *r;
70         for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) {
71                 r = &early_res[i];
72                 if (end > r->start && start < r->end)
73                         panic("Overlapping early reservations %lx-%lx %s to %lx-%lx %s\n",
74                               start, end - 1, name?name:"", r->start, r->end - 1, r->name);
75         }
76         if (i >= MAX_EARLY_RES)
77                 panic("Too many early reservations");
78         r = &early_res[i];
79         r->start = start;
80         r->end = end;
81         if (name)
82                 strncpy(r->name, name, sizeof(r->name) - 1);
83 }
84
85 void __init free_early(unsigned long start, unsigned long end)
86 {
87         struct early_res *r;
88         int i, j;
89
90         for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) {
91                 r = &early_res[i];
92                 if (start == r->start && end == r->end)
93                         break;
94         }
95         if (i >= MAX_EARLY_RES || !early_res[i].end)
96                 panic("free_early on not reserved area: %lx-%lx!", start, end);
97
98         for (j = i + 1; j < MAX_EARLY_RES && early_res[j].end; j++)
99                 ;
100
101         memmove(&early_res[i], &early_res[i + 1],
102                (j - 1 - i) * sizeof(struct early_res));
103
104         early_res[j - 1].end = 0;
105 }
106
107 void __init early_res_to_bootmem(unsigned long start, unsigned long end)
108 {
109         int i;
110         unsigned long final_start, final_end;
111         for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) {
112                 struct early_res *r = &early_res[i];
113                 final_start = max(start, r->start);
114                 final_end = min(end, r->end);
115                 if (final_start >= final_end)
116                         continue;
117                 printk(KERN_INFO "  early res: %d [%lx-%lx] %s\n", i,
118                         final_start, final_end - 1, r->name);
119                 reserve_bootmem_generic(final_start, final_end - final_start);
120         }
121 }
122
123 /* Check for already reserved areas */
124 static inline int __init
125 bad_addr(unsigned long *addrp, unsigned long size, unsigned long align)
126 {
127         int i;
128         unsigned long addr = *addrp, last;
129         int changed = 0;
130 again:
131         last = addr + size;
132         for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) {
133                 struct early_res *r = &early_res[i];
134                 if (last >= r->start && addr < r->end) {
135                         *addrp = addr = round_up(r->end, align);
136                         changed = 1;
137                         goto again;
138                 }
139         }
140         return changed;
141 }
142
143 /* Check for already reserved areas */
144 static inline int __init
145 bad_addr_size(unsigned long *addrp, unsigned long *sizep, unsigned long align)
146 {
147         int i;
148         unsigned long addr = *addrp, last;
149         unsigned long size = *sizep;
150         int changed = 0;
151 again:
152         last = addr + size;
153         for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) {
154                 struct early_res *r = &early_res[i];
155                 if (last > r->start && addr < r->start) {
156                         size = r->start - addr;
157                         changed = 1;
158                         goto again;
159                 }
160                 if (last > r->end && addr < r->end) {
161                         addr = round_up(r->end, align);
162                         size = last - addr;
163                         changed = 1;
164                         goto again;
165                 }
166                 if (last <= r->end && addr >= r->start) {
167                         (*sizep)++;
168                         return 0;
169                 }
170         }
171         if (changed) {
172                 *addrp = addr;
173                 *sizep = size;
174         }
175         return changed;
176 }
177
178 /*
179  * Find a free area with specified alignment in a specific range.
180  */
181 unsigned long __init find_e820_area(unsigned long start, unsigned long end,
182                                     unsigned long size, unsigned long align)
183 {
184         int i;
185
186         for (i = 0; i < e820.nr_map; i++) {
187                 struct e820entry *ei = &e820.map[i];
188                 unsigned long addr, last;
189                 unsigned long ei_last;
190
191                 if (ei->type != E820_RAM)
192                         continue;
193                 addr = round_up(ei->addr, align);
194                 ei_last = ei->addr + ei->size;
195                 if (addr < start)
196                         addr = round_up(start, align);
197                 if (addr >= ei_last)
198                         continue;
199                 while (bad_addr(&addr, size, align) && addr+size <= ei_last)
200                         ;
201                 last = addr + size;
202                 if (last > ei_last)
203                         continue;
204                 if (last > end)
205                         continue;
206                 return addr;
207         }
208         return -1UL;
209 }
210
211 /*
212  * Find next free range after *start
213  */
214 unsigned long __init find_e820_area_size(unsigned long start,
215                                          unsigned long *sizep,
216                                          unsigned long align)
217 {
218         int i;
219
220         for (i = 0; i < e820.nr_map; i++) {
221                 struct e820entry *ei = &e820.map[i];
222                 unsigned long addr, last;
223                 unsigned long ei_last;
224
225                 if (ei->type != E820_RAM)
226                         continue;
227                 addr = round_up(ei->addr, align);
228                 ei_last = ei->addr + ei->size;
229                 if (addr < start)
230                         addr = round_up(start, align);
231                 if (addr >= ei_last)
232                         continue;
233                 *sizep = ei_last - addr;
234                 while (bad_addr_size(&addr, sizep, align) &&
235                         addr + *sizep <= ei_last)
236                         ;
237                 last = addr + *sizep;
238                 if (last > ei_last)
239                         continue;
240                 return addr;
241         }
242         return -1UL;
243
244 }
245 /*
246  * Find the highest page frame number we have available
247  */
248 unsigned long __init e820_end_of_ram(void)
249 {
250         unsigned long end_pfn;
251
252         end_pfn = find_max_pfn_with_active_regions();
253
254         if (end_pfn > max_pfn_mapped)
255                 max_pfn_mapped = end_pfn;
256         if (max_pfn_mapped > MAXMEM>>PAGE_SHIFT)
257                 max_pfn_mapped = MAXMEM>>PAGE_SHIFT;
258         if (end_pfn > end_user_pfn)
259                 end_pfn = end_user_pfn;
260         if (end_pfn > max_pfn_mapped)
261                 end_pfn = max_pfn_mapped;
262
263         printk(KERN_INFO "max_pfn_mapped = %lu\n", max_pfn_mapped);
264         return end_pfn;
265 }
266
267 /*
268  * Mark e820 reserved areas as busy for the resource manager.
269  */
270 void __init e820_reserve_resources(void)
271 {
272         int i;
273         struct resource *res;
274
275         res = alloc_bootmem_low(sizeof(struct resource) * e820.nr_map);
276         for (i = 0; i < e820.nr_map; i++) {
277                 switch (e820.map[i].type) {
278                 case E820_RAM:  res->name = "System RAM"; break;
279                 case E820_ACPI: res->name = "ACPI Tables"; break;
280                 case E820_NVS:  res->name = "ACPI Non-volatile Storage"; break;
281                 default:        res->name = "reserved";
282                 }
283                 res->start = e820.map[i].addr;
284                 res->end = res->start + e820.map[i].size - 1;
285                 res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
286                 insert_resource(&iomem_resource, res);
287                 res++;
288         }
289 }
290
291 /*
292  * Find the ranges of physical addresses that do not correspond to
293  * e820 RAM areas and mark the corresponding pages as nosave for software
294  * suspend and suspend to RAM.
295  *
296  * This function requires the e820 map to be sorted and without any
297  * overlapping entries and assumes the first e820 area to be RAM.
298  */
299 void __init e820_mark_nosave_regions(void)
300 {
301         int i;
302         unsigned long paddr;
303
304         paddr = round_down(e820.map[0].addr + e820.map[0].size, PAGE_SIZE);
305         for (i = 1; i < e820.nr_map; i++) {
306                 struct e820entry *ei = &e820.map[i];
307
308                 if (paddr < ei->addr)
309                         register_nosave_region(PFN_DOWN(paddr),
310                                                 PFN_UP(ei->addr));
311
312                 paddr = round_down(ei->addr + ei->size, PAGE_SIZE);
313                 if (ei->type != E820_RAM)
314                         register_nosave_region(PFN_UP(ei->addr),
315                                                 PFN_DOWN(paddr));
316
317                 if (paddr >= (end_pfn << PAGE_SHIFT))
318                         break;
319         }
320 }
321
322 /*
323  * Finds an active region in the address range from start_pfn to end_pfn and
324  * returns its range in ei_startpfn and ei_endpfn for the e820 entry.
325  */
326 static int __init e820_find_active_region(const struct e820entry *ei,
327                                           unsigned long start_pfn,
328                                           unsigned long end_pfn,
329                                           unsigned long *ei_startpfn,
330                                           unsigned long *ei_endpfn)
331 {
332         *ei_startpfn = round_up(ei->addr, PAGE_SIZE) >> PAGE_SHIFT;
333         *ei_endpfn = round_down(ei->addr + ei->size, PAGE_SIZE) >> PAGE_SHIFT;
334
335         /* Skip map entries smaller than a page */
336         if (*ei_startpfn >= *ei_endpfn)
337                 return 0;
338
339         /* Check if max_pfn_mapped should be updated */
340         if (ei->type != E820_RAM && *ei_endpfn > max_pfn_mapped)
341                 max_pfn_mapped = *ei_endpfn;
342
343         /* Skip if map is outside the node */
344         if (ei->type != E820_RAM || *ei_endpfn <= start_pfn ||
345                                     *ei_startpfn >= end_pfn)
346                 return 0;
347
348         /* Check for overlaps */
349         if (*ei_startpfn < start_pfn)
350                 *ei_startpfn = start_pfn;
351         if (*ei_endpfn > end_pfn)
352                 *ei_endpfn = end_pfn;
353
354         /* Obey end_user_pfn to save on memmap */
355         if (*ei_startpfn >= end_user_pfn)
356                 return 0;
357         if (*ei_endpfn > end_user_pfn)
358                 *ei_endpfn = end_user_pfn;
359
360         return 1;
361 }
362
363 /* Walk the e820 map and register active regions within a node */
364 void __init
365 e820_register_active_regions(int nid, unsigned long start_pfn,
366                                                         unsigned long end_pfn)
367 {
368         unsigned long ei_startpfn;
369         unsigned long ei_endpfn;
370         int i;
371
372         for (i = 0; i < e820.nr_map; i++)
373                 if (e820_find_active_region(&e820.map[i],
374                                             start_pfn, end_pfn,
375                                             &ei_startpfn, &ei_endpfn))
376                         add_active_range(nid, ei_startpfn, ei_endpfn);
377 }
378
379 /*
380  * Find the hole size (in bytes) in the memory range.
381  * @start: starting address of the memory range to scan
382  * @end: ending address of the memory range to scan
383  */
384 unsigned long __init e820_hole_size(unsigned long start, unsigned long end)
385 {
386         unsigned long start_pfn = start >> PAGE_SHIFT;
387         unsigned long end_pfn = end >> PAGE_SHIFT;
388         unsigned long ei_startpfn, ei_endpfn, ram = 0;
389         int i;
390
391         for (i = 0; i < e820.nr_map; i++) {
392                 if (e820_find_active_region(&e820.map[i],
393                                             start_pfn, end_pfn,
394                                             &ei_startpfn, &ei_endpfn))
395                         ram += ei_endpfn - ei_startpfn;
396         }
397         return end - start - (ram << PAGE_SHIFT);
398 }
399
400 static void early_panic(char *msg)
401 {
402         early_printk(msg);
403         panic(msg);
404 }
405
406 /* We're not void only for x86 32-bit compat */
407 char * __init machine_specific_memory_setup(void)
408 {
409         char *who = "BIOS-e820";
410         /*
411          * Try to copy the BIOS-supplied E820-map.
412          *
413          * Otherwise fake a memory map; one section from 0k->640k,
414          * the next section from 1mb->appropriate_mem_k
415          */
416         sanitize_e820_map(boot_params.e820_map, &boot_params.e820_entries);
417         if (copy_e820_map(boot_params.e820_map, boot_params.e820_entries) < 0)
418                 early_panic("Cannot find a valid memory map");
419         printk(KERN_INFO "BIOS-provided physical RAM map:\n");
420         e820_print_map(who);
421
422         /* In case someone cares... */
423         return who;
424 }
425
426 static int __init parse_memopt(char *p)
427 {
428         if (!p)
429                 return -EINVAL;
430         end_user_pfn = memparse(p, &p);
431         end_user_pfn >>= PAGE_SHIFT;
432         return 0;
433 }
434 early_param("mem", parse_memopt);
435
436 static int userdef __initdata;
437
438 static int __init parse_memmap_opt(char *p)
439 {
440         char *oldp;
441         unsigned long long start_at, mem_size;
442
443         if (!strcmp(p, "exactmap")) {
444 #ifdef CONFIG_CRASH_DUMP
445                 /*
446                  * If we are doing a crash dump, we still need to know
447                  * the real mem size before original memory map is
448                  * reset.
449                  */
450                 e820_register_active_regions(0, 0, -1UL);
451                 saved_max_pfn = e820_end_of_ram();
452                 remove_all_active_ranges();
453 #endif
454                 max_pfn_mapped = 0;
455                 e820.nr_map = 0;
456                 userdef = 1;
457                 return 0;
458         }
459
460         oldp = p;
461         mem_size = memparse(p, &p);
462         if (p == oldp)
463                 return -EINVAL;
464
465         userdef = 1;
466         if (*p == '@') {
467                 start_at = memparse(p+1, &p);
468                 add_memory_region(start_at, mem_size, E820_RAM);
469         } else if (*p == '#') {
470                 start_at = memparse(p+1, &p);
471                 add_memory_region(start_at, mem_size, E820_ACPI);
472         } else if (*p == '$') {
473                 start_at = memparse(p+1, &p);
474                 add_memory_region(start_at, mem_size, E820_RESERVED);
475         } else {
476                 end_user_pfn = (mem_size >> PAGE_SHIFT);
477         }
478         return *p == '\0' ? 0 : -EINVAL;
479 }
480 early_param("memmap", parse_memmap_opt);
481
482 void __init finish_e820_parsing(void)
483 {
484         if (userdef) {
485                 char nr = e820.nr_map;
486
487                 if (sanitize_e820_map(e820.map, &nr) < 0)
488                         early_panic("Invalid user supplied memory map");
489                 e820.nr_map = nr;
490
491                 printk(KERN_INFO "user-defined physical RAM map:\n");
492                 e820_print_map("user");
493         }
494 }
495
496 int __init arch_get_ram_range(int slot, u64 *addr, u64 *size)
497 {
498         int i;
499
500         if (slot < 0 || slot >= e820.nr_map)
501                 return -1;
502         for (i = slot; i < e820.nr_map; i++) {
503                 if (e820.map[i].type != E820_RAM)
504                         continue;
505                 break;
506         }
507         if (i == e820.nr_map || e820.map[i].addr > (max_pfn << PAGE_SHIFT))
508                 return -1;
509         *addr = e820.map[i].addr;
510         *size = min_t(u64, e820.map[i].size + e820.map[i].addr,
511                 max_pfn << PAGE_SHIFT) - *addr;
512         return i + 1;
513 }