aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/e820.c
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@novell.com>2009-03-12 09:07:23 -0400
committerIngo Molnar <mingo@elte.hu>2009-03-12 21:37:19 -0400
commit5c0e6f035df983210e4d22213aed624ced502d3d (patch)
tree6986ed92d5f62f421d3b3be776132994c8c05d6b /arch/x86/kernel/e820.c
parent82034d6f59b4772f4233bbb61c670290803a9960 (diff)
x86: fix code paths used by update_mptable
Impact: fix crashes under Xen due to unrobust e820 code find_e820_area_size() must return a properly distinguishable and out-of-bounds value when it fails, and -1UL does not meet that criteria on i386/PAE. Additionally, callers of the function must check against that value. early_reserve_e820() should be prepared for the region found to be outside of the addressable range on 32-bits. e820_update_range_map() should not blindly update e820, but should do all it work on the map it got a pointer passed for (which in 50% of the cases is &e820_saved). It must also not call e820_add_region(), as that again acts on e820 unconditionally. The issues were found when trying to make this option work in our Xen kernel (i.e. where some of the silent assumptions made in the code would not hold). Signed-off-by: Jan Beulich <jbeulich@novell.com> LKML-Reference: <49B9171B.76E4.0078.0@novell.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/e820.c')
-rw-r--r--arch/x86/kernel/e820.c32
1 files changed, 25 insertions, 7 deletions
diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c
index 508bec1cee2..3cf6681ac80 100644
--- a/arch/x86/kernel/e820.c
+++ b/arch/x86/kernel/e820.c
@@ -421,7 +421,7 @@ static u64 __init e820_update_range_map(struct e820map *e820x, u64 start,
421 u64 size, unsigned old_type, 421 u64 size, unsigned old_type,
422 unsigned new_type) 422 unsigned new_type)
423{ 423{
424 int i; 424 unsigned int i, x;
425 u64 real_updated_size = 0; 425 u64 real_updated_size = 0;
426 426
427 BUG_ON(old_type == new_type); 427 BUG_ON(old_type == new_type);
@@ -429,7 +429,7 @@ static u64 __init e820_update_range_map(struct e820map *e820x, u64 start,
429 if (size > (ULLONG_MAX - start)) 429 if (size > (ULLONG_MAX - start))
430 size = ULLONG_MAX - start; 430 size = ULLONG_MAX - start;
431 431
432 for (i = 0; i < e820.nr_map; i++) { 432 for (i = 0; i < e820x->nr_map; i++) {
433 struct e820entry *ei = &e820x->map[i]; 433 struct e820entry *ei = &e820x->map[i];
434 u64 final_start, final_end; 434 u64 final_start, final_end;
435 if (ei->type != old_type) 435 if (ei->type != old_type)
@@ -446,14 +446,23 @@ static u64 __init e820_update_range_map(struct e820map *e820x, u64 start,
446 final_end = min(start + size, ei->addr + ei->size); 446 final_end = min(start + size, ei->addr + ei->size);
447 if (final_start >= final_end) 447 if (final_start >= final_end)
448 continue; 448 continue;
449 e820_add_region(final_start, final_end - final_start, 449
450 new_type); 450 x = e820x->nr_map;
451 if (x == ARRAY_SIZE(e820x->map)) {
452 printk(KERN_ERR "Too many memory map entries!\n");
453 break;
454 }
455 e820x->map[x].addr = final_start;
456 e820x->map[x].size = final_end - final_start;
457 e820x->map[x].type = new_type;
458 e820x->nr_map++;
459
451 real_updated_size += final_end - final_start; 460 real_updated_size += final_end - final_start;
452 461
453 ei->size -= final_end - final_start;
454 if (ei->addr < final_start) 462 if (ei->addr < final_start)
455 continue; 463 continue;
456 ei->addr = final_end; 464 ei->addr = final_end;
465 ei->size -= final_end - final_start;
457 } 466 }
458 return real_updated_size; 467 return real_updated_size;
459} 468}
@@ -1020,8 +1029,8 @@ u64 __init find_e820_area_size(u64 start, u64 *sizep, u64 align)
1020 continue; 1029 continue;
1021 return addr; 1030 return addr;
1022 } 1031 }
1023 return -1UL;
1024 1032
1033 return -1ULL;
1025} 1034}
1026 1035
1027/* 1036/*
@@ -1034,13 +1043,22 @@ u64 __init early_reserve_e820(u64 startt, u64 sizet, u64 align)
1034 u64 start; 1043 u64 start;
1035 1044
1036 start = startt; 1045 start = startt;
1037 while (size < sizet) 1046 while (size < sizet && (start + 1))
1038 start = find_e820_area_size(start, &size, align); 1047 start = find_e820_area_size(start, &size, align);
1039 1048
1040 if (size < sizet) 1049 if (size < sizet)
1041 return 0; 1050 return 0;
1042 1051
1052#ifdef CONFIG_X86_32
1053 if (start >= MAXMEM)
1054 return 0;
1055 if (start + size > MAXMEM)
1056 size = MAXMEM - start;
1057#endif
1058
1043 addr = round_down(start + size - sizet, align); 1059 addr = round_down(start + size - sizet, align);
1060 if (addr < start)
1061 return 0;
1044 e820_update_range(addr, sizet, E820_RAM, E820_RESERVED); 1062 e820_update_range(addr, sizet, E820_RAM, E820_RESERVED);
1045 e820_update_range_saved(addr, sizet, E820_RAM, E820_RESERVED); 1063 e820_update_range_saved(addr, sizet, E820_RAM, E820_RESERVED);
1046 printk(KERN_INFO "update e820 for early_reserve_e820\n"); 1064 printk(KERN_INFO "update e820 for early_reserve_e820\n");