aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386
diff options
context:
space:
mode:
authorbibo,mao <bibo.mao@intel.com>2006-12-06 20:14:06 -0500
committerAndi Kleen <andi@basil.nowhere.org>2006-12-06 20:14:06 -0500
commit8e3342f736dd1c19ce7c28625dedd7d8730fc7ad (patch)
treeaa20a02988e3b65977d52014ec147d600ee372c6 /arch/i386
parent269c2d81ed66af7c09a1619ffe165f03e7470a5b (diff)
[PATCH] i386: create e820.c for e820 map sanitize and copy function
This patch moves bios e820 map sanitize and copy function from setup.c to e820.c Signed-off-by: bibo,mao <bibo.mao@intel.com> Signed-off-by: Andi Kleen <ak@suse.de> arch/i386/kernel/e820.c | 252 +++++++++++++++++++++++++++++++++++++++++++++++ arch/i386/kernel/setup.c | 240 -------------------------------------------- 2 files changed, 252 insertions(+), 240 deletions(-)
Diffstat (limited to 'arch/i386')
-rw-r--r--arch/i386/kernel/e820.c252
-rw-r--r--arch/i386/kernel/setup.c240
2 files changed, 252 insertions, 240 deletions
diff --git a/arch/i386/kernel/e820.c b/arch/i386/kernel/e820.c
index cce706049488..0db95760b073 100644
--- a/arch/i386/kernel/e820.c
+++ b/arch/i386/kernel/e820.c
@@ -19,6 +19,14 @@ EXPORT_SYMBOL(efi_enabled);
19#endif 19#endif
20 20
21struct e820map e820; 21struct e820map e820;
22struct change_member {
23 struct e820entry *pbios; /* pointer to original bios entry */
24 unsigned long long addr; /* address for this change point */
25};
26static struct change_member change_point_list[2*E820MAX] __initdata;
27static struct change_member *change_point[2*E820MAX] __initdata;
28static struct e820entry *overlap_list[E820MAX] __initdata;
29static struct e820entry new_bios[E820MAX] __initdata;
22struct resource data_resource = { 30struct resource data_resource = {
23 .name = "Kernel data", 31 .name = "Kernel data",
24 .start = 0, 32 .start = 0,
@@ -287,3 +295,247 @@ static int __init request_standard_resources(void)
287} 295}
288 296
289subsys_initcall(request_standard_resources); 297subsys_initcall(request_standard_resources);
298
299void __init add_memory_region(unsigned long long start,
300 unsigned long long size, int type)
301{
302 int x;
303
304 if (!efi_enabled) {
305 x = e820.nr_map;
306
307 if (x == E820MAX) {
308 printk(KERN_ERR "Ooops! Too many entries in the memory map!\n");
309 return;
310 }
311
312 e820.map[x].addr = start;
313 e820.map[x].size = size;
314 e820.map[x].type = type;
315 e820.nr_map++;
316 }
317} /* add_memory_region */
318
319/*
320 * Sanitize the BIOS e820 map.
321 *
322 * Some e820 responses include overlapping entries. The following
323 * replaces the original e820 map with a new one, removing overlaps.
324 *
325 */
326int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
327{
328 struct change_member *change_tmp;
329 unsigned long current_type, last_type;
330 unsigned long long last_addr;
331 int chgidx, still_changing;
332 int overlap_entries;
333 int new_bios_entry;
334 int old_nr, new_nr, chg_nr;
335 int i;
336
337 /*
338 Visually we're performing the following (1,2,3,4 = memory types)...
339
340 Sample memory map (w/overlaps):
341 ____22__________________
342 ______________________4_
343 ____1111________________
344 _44_____________________
345 11111111________________
346 ____________________33__
347 ___________44___________
348 __________33333_________
349 ______________22________
350 ___________________2222_
351 _________111111111______
352 _____________________11_
353 _________________4______
354
355 Sanitized equivalent (no overlap):
356 1_______________________
357 _44_____________________
358 ___1____________________
359 ____22__________________
360 ______11________________
361 _________1______________
362 __________3_____________
363 ___________44___________
364 _____________33_________
365 _______________2________
366 ________________1_______
367 _________________4______
368 ___________________2____
369 ____________________33__
370 ______________________4_
371 */
372 printk("sanitize start\n");
373 /* if there's only one memory region, don't bother */
374 if (*pnr_map < 2) {
375 printk("sanitize bail 0\n");
376 return -1;
377 }
378
379 old_nr = *pnr_map;
380
381 /* bail out if we find any unreasonable addresses in bios map */
382 for (i=0; i<old_nr; i++)
383 if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr) {
384 printk("sanitize bail 1\n");
385 return -1;
386 }
387
388 /* create pointers for initial change-point information (for sorting) */
389 for (i=0; i < 2*old_nr; i++)
390 change_point[i] = &change_point_list[i];
391
392 /* record all known change-points (starting and ending addresses),
393 omitting those that are for empty memory regions */
394 chgidx = 0;
395 for (i=0; i < old_nr; i++) {
396 if (biosmap[i].size != 0) {
397 change_point[chgidx]->addr = biosmap[i].addr;
398 change_point[chgidx++]->pbios = &biosmap[i];
399 change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size;
400 change_point[chgidx++]->pbios = &biosmap[i];
401 }
402 }
403 chg_nr = chgidx; /* true number of change-points */
404
405 /* sort change-point list by memory addresses (low -> high) */
406 still_changing = 1;
407 while (still_changing) {
408 still_changing = 0;
409 for (i=1; i < chg_nr; i++) {
410 /* if <current_addr> > <last_addr>, swap */
411 /* or, if current=<start_addr> & last=<end_addr>, swap */
412 if ((change_point[i]->addr < change_point[i-1]->addr) ||
413 ((change_point[i]->addr == change_point[i-1]->addr) &&
414 (change_point[i]->addr == change_point[i]->pbios->addr) &&
415 (change_point[i-1]->addr != change_point[i-1]->pbios->addr))
416 )
417 {
418 change_tmp = change_point[i];
419 change_point[i] = change_point[i-1];
420 change_point[i-1] = change_tmp;
421 still_changing=1;
422 }
423 }
424 }
425
426 /* create a new bios memory map, removing overlaps */
427 overlap_entries=0; /* number of entries in the overlap table */
428 new_bios_entry=0; /* index for creating new bios map entries */
429 last_type = 0; /* start with undefined memory type */
430 last_addr = 0; /* start with 0 as last starting address */
431 /* loop through change-points, determining affect on the new bios map */
432 for (chgidx=0; chgidx < chg_nr; chgidx++)
433 {
434 /* keep track of all overlapping bios entries */
435 if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr)
436 {
437 /* add map entry to overlap list (> 1 entry implies an overlap) */
438 overlap_list[overlap_entries++]=change_point[chgidx]->pbios;
439 }
440 else
441 {
442 /* remove entry from list (order independent, so swap with last) */
443 for (i=0; i<overlap_entries; i++)
444 {
445 if (overlap_list[i] == change_point[chgidx]->pbios)
446 overlap_list[i] = overlap_list[overlap_entries-1];
447 }
448 overlap_entries--;
449 }
450 /* if there are overlapping entries, decide which "type" to use */
451 /* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */
452 current_type = 0;
453 for (i=0; i<overlap_entries; i++)
454 if (overlap_list[i]->type > current_type)
455 current_type = overlap_list[i]->type;
456 /* continue building up new bios map based on this information */
457 if (current_type != last_type) {
458 if (last_type != 0) {
459 new_bios[new_bios_entry].size =
460 change_point[chgidx]->addr - last_addr;
461 /* move forward only if the new size was non-zero */
462 if (new_bios[new_bios_entry].size != 0)
463 if (++new_bios_entry >= E820MAX)
464 break; /* no more space left for new bios entries */
465 }
466 if (current_type != 0) {
467 new_bios[new_bios_entry].addr = change_point[chgidx]->addr;
468 new_bios[new_bios_entry].type = current_type;
469 last_addr=change_point[chgidx]->addr;
470 }
471 last_type = current_type;
472 }
473 }
474 new_nr = new_bios_entry; /* retain count for new bios entries */
475
476 /* copy new bios mapping into original location */
477 memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry));
478 *pnr_map = new_nr;
479
480 printk("sanitize end\n");
481 return 0;
482}
483
484/*
485 * Copy the BIOS e820 map into a safe place.
486 *
487 * Sanity-check it while we're at it..
488 *
489 * If we're lucky and live on a modern system, the setup code
490 * will have given us a memory map that we can use to properly
491 * set up memory. If we aren't, we'll fake a memory map.
492 *
493 * We check to see that the memory map contains at least 2 elements
494 * before we'll use it, because the detection code in setup.S may
495 * not be perfect and most every PC known to man has two memory
496 * regions: one from 0 to 640k, and one from 1mb up. (The IBM
497 * thinkpad 560x, for example, does not cooperate with the memory
498 * detection code.)
499 */
500int __init copy_e820_map(struct e820entry * biosmap, int nr_map)
501{
502 /* Only one memory region (or negative)? Ignore it */
503 if (nr_map < 2)
504 return -1;
505
506 do {
507 unsigned long long start = biosmap->addr;
508 unsigned long long size = biosmap->size;
509 unsigned long long end = start + size;
510 unsigned long type = biosmap->type;
511 printk("copy_e820_map() start: %016Lx size: %016Lx end: %016Lx type: %ld\n", start, size, end, type);
512
513 /* Overflow in 64 bits? Ignore the memory map. */
514 if (start > end)
515 return -1;
516
517 /*
518 * Some BIOSes claim RAM in the 640k - 1M region.
519 * Not right. Fix it up.
520 */
521 if (type == E820_RAM) {
522 printk("copy_e820_map() type is E820_RAM\n");
523 if (start < 0x100000ULL && end > 0xA0000ULL) {
524 printk("copy_e820_map() lies in range...\n");
525 if (start < 0xA0000ULL) {
526 printk("copy_e820_map() start < 0xA0000ULL\n");
527 add_memory_region(start, 0xA0000ULL-start, type);
528 }
529 if (end <= 0x100000ULL) {
530 printk("copy_e820_map() end <= 0x100000ULL\n");
531 continue;
532 }
533 start = 0x100000ULL;
534 size = end - start;
535 }
536 }
537 add_memory_region(start, size, type);
538 } while (biosmap++,--nr_map);
539 return 0;
540}
541
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index acd2d9392abb..b7509aec0eb1 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -191,26 +191,6 @@ static void __init limit_regions(unsigned long long size)
191 } 191 }
192} 192}
193 193
194void __init add_memory_region(unsigned long long start,
195 unsigned long long size, int type)
196{
197 int x;
198
199 if (!efi_enabled) {
200 x = e820.nr_map;
201
202 if (x == E820MAX) {
203 printk(KERN_ERR "Ooops! Too many entries in the memory map!\n");
204 return;
205 }
206
207 e820.map[x].addr = start;
208 e820.map[x].size = size;
209 e820.map[x].type = type;
210 e820.nr_map++;
211 }
212} /* add_memory_region */
213
214#define E820_DEBUG 1 194#define E820_DEBUG 1
215 195
216static void __init print_memory_map(char *who) 196static void __init print_memory_map(char *who)
@@ -239,226 +219,6 @@ static void __init print_memory_map(char *who)
239 } 219 }
240} 220}
241 221
242/*
243 * Sanitize the BIOS e820 map.
244 *
245 * Some e820 responses include overlapping entries. The following
246 * replaces the original e820 map with a new one, removing overlaps.
247 *
248 */
249struct change_member {
250 struct e820entry *pbios; /* pointer to original bios entry */
251 unsigned long long addr; /* address for this change point */
252};
253static struct change_member change_point_list[2*E820MAX] __initdata;
254static struct change_member *change_point[2*E820MAX] __initdata;
255static struct e820entry *overlap_list[E820MAX] __initdata;
256static struct e820entry new_bios[E820MAX] __initdata;
257
258int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
259{
260 struct change_member *change_tmp;
261 unsigned long current_type, last_type;
262 unsigned long long last_addr;
263 int chgidx, still_changing;
264 int overlap_entries;
265 int new_bios_entry;
266 int old_nr, new_nr, chg_nr;
267 int i;
268
269 /*
270 Visually we're performing the following (1,2,3,4 = memory types)...
271
272 Sample memory map (w/overlaps):
273 ____22__________________
274 ______________________4_
275 ____1111________________
276 _44_____________________
277 11111111________________
278 ____________________33__
279 ___________44___________
280 __________33333_________
281 ______________22________
282 ___________________2222_
283 _________111111111______
284 _____________________11_
285 _________________4______
286
287 Sanitized equivalent (no overlap):
288 1_______________________
289 _44_____________________
290 ___1____________________
291 ____22__________________
292 ______11________________
293 _________1______________
294 __________3_____________
295 ___________44___________
296 _____________33_________
297 _______________2________
298 ________________1_______
299 _________________4______
300 ___________________2____
301 ____________________33__
302 ______________________4_
303 */
304
305 /* if there's only one memory region, don't bother */
306 if (*pnr_map < 2)
307 return -1;
308
309 old_nr = *pnr_map;
310
311 /* bail out if we find any unreasonable addresses in bios map */
312 for (i=0; i<old_nr; i++)
313 if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr)
314 return -1;
315
316 /* create pointers for initial change-point information (for sorting) */
317 for (i=0; i < 2*old_nr; i++)
318 change_point[i] = &change_point_list[i];
319
320 /* record all known change-points (starting and ending addresses),
321 omitting those that are for empty memory regions */
322 chgidx = 0;
323 for (i=0; i < old_nr; i++) {
324 if (biosmap[i].size != 0) {
325 change_point[chgidx]->addr = biosmap[i].addr;
326 change_point[chgidx++]->pbios = &biosmap[i];
327 change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size;
328 change_point[chgidx++]->pbios = &biosmap[i];
329 }
330 }
331 chg_nr = chgidx; /* true number of change-points */
332
333 /* sort change-point list by memory addresses (low -> high) */
334 still_changing = 1;
335 while (still_changing) {
336 still_changing = 0;
337 for (i=1; i < chg_nr; i++) {
338 /* if <current_addr> > <last_addr>, swap */
339 /* or, if current=<start_addr> & last=<end_addr>, swap */
340 if ((change_point[i]->addr < change_point[i-1]->addr) ||
341 ((change_point[i]->addr == change_point[i-1]->addr) &&
342 (change_point[i]->addr == change_point[i]->pbios->addr) &&
343 (change_point[i-1]->addr != change_point[i-1]->pbios->addr))
344 )
345 {
346 change_tmp = change_point[i];
347 change_point[i] = change_point[i-1];
348 change_point[i-1] = change_tmp;
349 still_changing=1;
350 }
351 }
352 }
353
354 /* create a new bios memory map, removing overlaps */
355 overlap_entries=0; /* number of entries in the overlap table */
356 new_bios_entry=0; /* index for creating new bios map entries */
357 last_type = 0; /* start with undefined memory type */
358 last_addr = 0; /* start with 0 as last starting address */
359 /* loop through change-points, determining affect on the new bios map */
360 for (chgidx=0; chgidx < chg_nr; chgidx++)
361 {
362 /* keep track of all overlapping bios entries */
363 if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr)
364 {
365 /* add map entry to overlap list (> 1 entry implies an overlap) */
366 overlap_list[overlap_entries++]=change_point[chgidx]->pbios;
367 }
368 else
369 {
370 /* remove entry from list (order independent, so swap with last) */
371 for (i=0; i<overlap_entries; i++)
372 {
373 if (overlap_list[i] == change_point[chgidx]->pbios)
374 overlap_list[i] = overlap_list[overlap_entries-1];
375 }
376 overlap_entries--;
377 }
378 /* if there are overlapping entries, decide which "type" to use */
379 /* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */
380 current_type = 0;
381 for (i=0; i<overlap_entries; i++)
382 if (overlap_list[i]->type > current_type)
383 current_type = overlap_list[i]->type;
384 /* continue building up new bios map based on this information */
385 if (current_type != last_type) {
386 if (last_type != 0) {
387 new_bios[new_bios_entry].size =
388 change_point[chgidx]->addr - last_addr;
389 /* move forward only if the new size was non-zero */
390 if (new_bios[new_bios_entry].size != 0)
391 if (++new_bios_entry >= E820MAX)
392 break; /* no more space left for new bios entries */
393 }
394 if (current_type != 0) {
395 new_bios[new_bios_entry].addr = change_point[chgidx]->addr;
396 new_bios[new_bios_entry].type = current_type;
397 last_addr=change_point[chgidx]->addr;
398 }
399 last_type = current_type;
400 }
401 }
402 new_nr = new_bios_entry; /* retain count for new bios entries */
403
404 /* copy new bios mapping into original location */
405 memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry));
406 *pnr_map = new_nr;
407
408 return 0;
409}
410
411/*
412 * Copy the BIOS e820 map into a safe place.
413 *
414 * Sanity-check it while we're at it..
415 *
416 * If we're lucky and live on a modern system, the setup code
417 * will have given us a memory map that we can use to properly
418 * set up memory. If we aren't, we'll fake a memory map.
419 *
420 * We check to see that the memory map contains at least 2 elements
421 * before we'll use it, because the detection code in setup.S may
422 * not be perfect and most every PC known to man has two memory
423 * regions: one from 0 to 640k, and one from 1mb up. (The IBM
424 * thinkpad 560x, for example, does not cooperate with the memory
425 * detection code.)
426 */
427int __init copy_e820_map(struct e820entry * biosmap, int nr_map)
428{
429 /* Only one memory region (or negative)? Ignore it */
430 if (nr_map < 2)
431 return -1;
432
433 do {
434 unsigned long long start = biosmap->addr;
435 unsigned long long size = biosmap->size;
436 unsigned long long end = start + size;
437 unsigned long type = biosmap->type;
438
439 /* Overflow in 64 bits? Ignore the memory map. */
440 if (start > end)
441 return -1;
442
443 /*
444 * Some BIOSes claim RAM in the 640k - 1M region.
445 * Not right. Fix it up.
446 */
447 if (type == E820_RAM) {
448 if (start < 0x100000ULL && end > 0xA0000ULL) {
449 if (start < 0xA0000ULL)
450 add_memory_region(start, 0xA0000ULL-start, type);
451 if (end <= 0x100000ULL)
452 continue;
453 start = 0x100000ULL;
454 size = end - start;
455 }
456 }
457 add_memory_region(start, size, type);
458 } while (biosmap++,--nr_map);
459 return 0;
460}
461
462#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) 222#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
463struct edd edd; 223struct edd edd;
464#ifdef CONFIG_EDD_MODULE 224#ifdef CONFIG_EDD_MODULE