ia64/xen-unstable

view xen/arch/x86/e820.c @ 18806:ed8524f4a044

x86: Re-initialise HPET on resume from S3

Signed-off-by: Guanqun Lu <guanqun.lu@intel.com>
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Nov 18 15:55:14 2008 +0000 (2008-11-18)
parents 9ab9dadf4876
children 202afa5384c4
line source
1 #include <xen/config.h>
2 #include <xen/init.h>
3 #include <xen/lib.h>
4 #include <xen/compat.h>
5 #include <xen/dmi.h>
6 #include <asm/e820.h>
7 #include <asm/mm.h>
8 #include <asm/page.h>
10 /* opt_mem: Limit of physical RAM. Any RAM beyond this point is ignored. */
11 unsigned long long opt_mem;
12 static void parse_mem(char *s) { opt_mem = parse_size_and_unit(s, NULL); }
13 custom_param("mem", parse_mem);
15 struct e820map e820;
17 static void __init add_memory_region(unsigned long long start,
18 unsigned long long size, int type)
19 {
20 int x;
22 /*if (!efi_enabled)*/ {
23 x = e820.nr_map;
25 if (x == E820MAX) {
26 printk(KERN_ERR "Ooops! Too many entries in the memory map!\n");
27 return;
28 }
30 e820.map[x].addr = start;
31 e820.map[x].size = size;
32 e820.map[x].type = type;
33 e820.nr_map++;
34 }
35 } /* add_memory_region */
37 static void __init print_e820_memory_map(struct e820entry *map, int entries)
38 {
39 int i;
41 for (i = 0; i < entries; i++) {
42 printk(" %016Lx - %016Lx ",
43 (unsigned long long)(map[i].addr),
44 (unsigned long long)(map[i].addr + map[i].size));
45 switch (map[i].type) {
46 case E820_RAM:
47 printk("(usable)\n");
48 break;
49 case E820_RESERVED:
50 printk("(reserved)\n");
51 break;
52 case E820_ACPI:
53 printk("(ACPI data)\n");
54 break;
55 case E820_NVS:
56 printk("(ACPI NVS)\n");
57 break;
58 case E820_UNUSABLE:
59 printk("(unusable)\n");
60 break;
61 default:
62 printk("type %u\n", map[i].type);
63 break;
64 }
65 }
66 }
68 /*
69 * Sanitize the BIOS e820 map.
70 *
71 * Some e820 responses include overlapping entries. The following
72 * replaces the original e820 map with a new one, removing overlaps.
73 *
74 */
75 struct change_member {
76 struct e820entry *pbios; /* pointer to original bios entry */
77 unsigned long long addr; /* address for this change point */
78 };
79 static struct change_member change_point_list[2*E820MAX] __initdata;
80 static struct change_member *change_point[2*E820MAX] __initdata;
81 static struct e820entry *overlap_list[E820MAX] __initdata;
82 static struct e820entry new_bios[E820MAX] __initdata;
84 static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
85 {
86 struct change_member *change_tmp;
87 unsigned long current_type, last_type;
88 unsigned long long last_addr;
89 int chgidx, still_changing;
90 int overlap_entries;
91 int new_bios_entry;
92 int old_nr, new_nr, chg_nr;
93 int i;
95 /*
96 Visually we're performing the following (1,2,3,4 = memory types)...
98 Sample memory map (w/overlaps):
99 ____22__________________
100 ______________________4_
101 ____1111________________
102 _44_____________________
103 11111111________________
104 ____________________33__
105 ___________44___________
106 __________33333_________
107 ______________22________
108 ___________________2222_
109 _________111111111______
110 _____________________11_
111 _________________4______
113 Sanitized equivalent (no overlap):
114 1_______________________
115 _44_____________________
116 ___1____________________
117 ____22__________________
118 ______11________________
119 _________1______________
120 __________3_____________
121 ___________44___________
122 _____________33_________
123 _______________2________
124 ________________1_______
125 _________________4______
126 ___________________2____
127 ____________________33__
128 ______________________4_
129 */
131 /* if there's only one memory region, don't bother */
132 if (*pnr_map < 2)
133 return -1;
135 old_nr = *pnr_map;
137 /* bail out if we find any unreasonable addresses in bios map */
138 for (i=0; i<old_nr; i++)
139 if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr)
140 return -1;
142 /* create pointers for initial change-point information (for sorting) */
143 for (i=0; i < 2*old_nr; i++)
144 change_point[i] = &change_point_list[i];
146 /* record all known change-points (starting and ending addresses),
147 omitting those that are for empty memory regions */
148 chgidx = 0;
149 for (i=0; i < old_nr; i++) {
150 if (biosmap[i].size != 0) {
151 change_point[chgidx]->addr = biosmap[i].addr;
152 change_point[chgidx++]->pbios = &biosmap[i];
153 change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size;
154 change_point[chgidx++]->pbios = &biosmap[i];
155 }
156 }
157 chg_nr = chgidx; /* true number of change-points */
159 /* sort change-point list by memory addresses (low -> high) */
160 still_changing = 1;
161 while (still_changing) {
162 still_changing = 0;
163 for (i=1; i < chg_nr; i++) {
164 /* if <current_addr> > <last_addr>, swap */
165 /* or, if current=<start_addr> & last=<end_addr>, swap */
166 if ((change_point[i]->addr < change_point[i-1]->addr) ||
167 ((change_point[i]->addr == change_point[i-1]->addr) &&
168 (change_point[i]->addr == change_point[i]->pbios->addr) &&
169 (change_point[i-1]->addr != change_point[i-1]->pbios->addr))
170 )
171 {
172 change_tmp = change_point[i];
173 change_point[i] = change_point[i-1];
174 change_point[i-1] = change_tmp;
175 still_changing=1;
176 }
177 }
178 }
180 /* create a new bios memory map, removing overlaps */
181 overlap_entries=0; /* number of entries in the overlap table */
182 new_bios_entry=0; /* index for creating new bios map entries */
183 last_type = 0; /* start with undefined memory type */
184 last_addr = 0; /* start with 0 as last starting address */
185 /* loop through change-points, determining affect on the new bios map */
186 for (chgidx=0; chgidx < chg_nr; chgidx++)
187 {
188 /* keep track of all overlapping bios entries */
189 if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr)
190 {
191 /* add map entry to overlap list (> 1 entry implies an overlap) */
192 overlap_list[overlap_entries++]=change_point[chgidx]->pbios;
193 }
194 else
195 {
196 /* remove entry from list (order independent, so swap with last) */
197 for (i=0; i<overlap_entries; i++)
198 {
199 if (overlap_list[i] == change_point[chgidx]->pbios)
200 overlap_list[i] = overlap_list[overlap_entries-1];
201 }
202 overlap_entries--;
203 }
204 /* if there are overlapping entries, decide which "type" to use */
205 /* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */
206 current_type = 0;
207 for (i=0; i<overlap_entries; i++)
208 if (overlap_list[i]->type > current_type)
209 current_type = overlap_list[i]->type;
210 /* continue building up new bios map based on this information */
211 if (current_type != last_type) {
212 if (last_type != 0) {
213 new_bios[new_bios_entry].size =
214 change_point[chgidx]->addr - last_addr;
215 /* move forward only if the new size was non-zero */
216 if (new_bios[new_bios_entry].size != 0)
217 if (++new_bios_entry >= E820MAX)
218 break; /* no more space left for new bios entries */
219 }
220 if (current_type != 0) {
221 new_bios[new_bios_entry].addr = change_point[chgidx]->addr;
222 new_bios[new_bios_entry].type = current_type;
223 last_addr=change_point[chgidx]->addr;
224 }
225 last_type = current_type;
226 }
227 }
228 new_nr = new_bios_entry; /* retain count for new bios entries */
230 /* copy new bios mapping into original location */
231 memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry));
232 *pnr_map = new_nr;
234 return 0;
235 }
237 /*
238 * Copy the BIOS e820 map into a safe place.
239 *
240 * Sanity-check it while we're at it..
241 *
242 * If we're lucky and live on a modern system, the setup code
243 * will have given us a memory map that we can use to properly
244 * set up memory. If we aren't, we'll fake a memory map.
245 *
246 * We check to see that the memory map contains at least 2 elements
247 * before we'll use it, because the detection code in setup.S may
248 * not be perfect and most every PC known to man has two memory
249 * regions: one from 0 to 640k, and one from 1mb up. (The IBM
250 * thinkpad 560x, for example, does not cooperate with the memory
251 * detection code.)
252 */
253 static int __init copy_e820_map(struct e820entry * biosmap, int nr_map)
254 {
255 /* Only one memory region (or negative)? Ignore it */
256 if (nr_map < 2)
257 return -1;
259 do {
260 unsigned long long start = biosmap->addr;
261 unsigned long long size = biosmap->size;
262 unsigned long long end = start + size;
263 unsigned long type = biosmap->type;
265 /* Overflow in 64 bits? Ignore the memory map. */
266 if (start > end)
267 return -1;
269 /*
270 * Some BIOSes claim RAM in the 640k - 1M region.
271 * Not right. Fix it up.
272 */
273 if (type == E820_RAM) {
274 if (start < 0x100000ULL && end > 0xA0000ULL) {
275 if (start < 0xA0000ULL)
276 add_memory_region(start, 0xA0000ULL-start, type);
277 if (end <= 0x100000ULL)
278 continue;
279 start = 0x100000ULL;
280 size = end - start;
281 }
282 }
283 add_memory_region(start, size, type);
284 } while (biosmap++,--nr_map);
285 return 0;
286 }
289 /*
290 * Find the highest page frame number we have available
291 */
292 static unsigned long __init find_max_pfn(void)
293 {
294 int i;
295 unsigned long max_pfn = 0;
297 #if 0
298 if (efi_enabled) {
299 efi_memmap_walk(efi_find_max_pfn, &max_pfn);
300 return;
301 }
302 #endif
304 for (i = 0; i < e820.nr_map; i++) {
305 unsigned long start, end;
306 /* RAM? */
307 if (e820.map[i].type != E820_RAM)
308 continue;
309 start = PFN_UP(e820.map[i].addr);
310 end = PFN_DOWN(e820.map[i].addr + e820.map[i].size);
311 if (start >= end)
312 continue;
313 if (end > max_pfn)
314 max_pfn = end;
315 }
317 return max_pfn;
318 }
320 static void __init clip_to_limit(uint64_t limit, char *warnmsg)
321 {
322 int i;
323 char _warnmsg[160];
325 for ( i = 0; i < e820.nr_map; i++ )
326 {
327 if ( (e820.map[i].addr + e820.map[i].size) <= limit )
328 continue;
329 if ( warnmsg )
330 {
331 snprintf(_warnmsg, sizeof(_warnmsg), warnmsg, (long)(limit>>30));
332 printk("WARNING: %s\n", _warnmsg);
333 }
334 printk("Truncating memory map to %lukB\n",
335 (unsigned long)(limit >> 10));
336 if ( e820.map[i].addr >= limit )
337 {
338 e820.nr_map = i;
339 }
340 else
341 {
342 e820.map[i].size = limit - e820.map[i].addr;
343 e820.nr_map = i + 1;
344 }
345 }
346 }
348 static void __init reserve_dmi_region(void)
349 {
350 u32 base, len;
351 if ( (dmi_get_table(&base, &len) == 0) && ((base + len) > base) &&
352 reserve_e820_ram(&e820, base, base + len) )
353 printk("WARNING: DMI table located in E820 RAM %08x-%08x. Fixed.\n",
354 base, base+len);
355 }
357 static void __init machine_specific_memory_setup(
358 struct e820entry *raw, int *raw_nr)
359 {
360 char nr = (char)*raw_nr;
361 sanitize_e820_map(raw, &nr);
362 *raw_nr = nr;
363 (void)copy_e820_map(raw, nr);
365 if ( opt_mem )
366 clip_to_limit(opt_mem, NULL);
368 #ifdef __i386__
369 clip_to_limit((1ULL << 30) * MACHPHYS_MBYTES,
370 "Only the first %lu GB of the physical memory map "
371 "can be accessed by Xen in 32-bit mode.");
372 #else
373 {
374 unsigned long limit, mpt_limit, pft_limit;
376 limit = DIRECTMAP_VIRT_END - DIRECTMAP_VIRT_START;
377 mpt_limit = ((RDWR_MPT_VIRT_END - RDWR_MPT_VIRT_START)
378 / sizeof(unsigned long)) << PAGE_SHIFT;
379 pft_limit = ((FRAMETABLE_VIRT_END - FRAMETABLE_VIRT_START)
380 / sizeof(struct page_info)) << PAGE_SHIFT;
381 if ( limit > mpt_limit )
382 limit = mpt_limit;
383 if ( limit > pft_limit )
384 limit = pft_limit;
385 clip_to_limit(limit,
386 "Only the first %lu GB of the physical "
387 "memory map can be accessed by Xen.");
388 }
389 #endif
391 reserve_dmi_region();
392 }
394 /* Reserve RAM area (@s,@e) in the specified e820 map. */
395 int __init reserve_e820_ram(struct e820map *e820, uint64_t s, uint64_t e)
396 {
397 uint64_t rs = 0, re = 0;
398 int i;
400 for ( i = 0; i < e820->nr_map; i++ )
401 {
402 /* Have we found the e820 region that includes the specified range? */
403 rs = e820->map[i].addr;
404 re = rs + e820->map[i].size;
405 if ( (s >= rs) && (e <= re) )
406 break;
407 }
409 if ( (i == e820->nr_map) || (e820->map[i].type != E820_RAM) )
410 return 0;
412 if ( (s == rs) && (e == re) )
413 {
414 /* Complete excision. */
415 memmove(&e820->map[i], &e820->map[i+1],
416 (e820->nr_map-i-1) * sizeof(e820->map[0]));
417 e820->nr_map--;
418 }
419 else if ( s == rs )
420 {
421 /* Truncate start. */
422 e820->map[i].addr += e - s;
423 e820->map[i].size -= e - s;
424 }
425 else if ( e == re )
426 {
427 /* Truncate end. */
428 e820->map[i].size -= e - s;
429 }
430 else if ( e820->nr_map < ARRAY_SIZE(e820->map) )
431 {
432 /* Split in two. */
433 memmove(&e820->map[i+1], &e820->map[i],
434 (e820->nr_map-i) * sizeof(e820->map[0]));
435 e820->nr_map++;
436 e820->map[i].size = s - rs;
437 i++;
438 e820->map[i].addr = e;
439 e820->map[i].size = re - e;
440 }
441 else
442 {
443 /* e820map is at maximum size. We have to leak some space. */
444 if ( (s - rs) > (re - e) )
445 {
446 printk("e820 overflow: leaking RAM %"PRIx64"-%"PRIx64"\n", e, re);
447 e820->map[i].size = s - rs;
448 }
449 else
450 {
451 printk("e820 overflow: leaking RAM %"PRIx64"-%"PRIx64"\n", rs, s);
452 e820->map[i].addr = e;
453 e820->map[i].size = re - e;
454 }
455 }
457 return 1;
458 }
460 unsigned long __init init_e820(
461 const char *str, struct e820entry *raw, int *raw_nr)
462 {
463 machine_specific_memory_setup(raw, raw_nr);
464 printk("%s RAM map:\n", str);
465 print_e820_memory_map(e820.map, e820.nr_map);
466 return find_max_pfn();
467 }