diff options
Diffstat (limited to 'arch/x86/kernel/e820.c')
-rw-r--r-- | arch/x86/kernel/e820.c | 142 |
1 files changed, 96 insertions, 46 deletions
diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c index 508bec1cee27..ef2c3563357d 100644 --- a/arch/x86/kernel/e820.c +++ b/arch/x86/kernel/e820.c | |||
@@ -110,19 +110,50 @@ int __init e820_all_mapped(u64 start, u64 end, unsigned type) | |||
110 | /* | 110 | /* |
111 | * Add a memory region to the kernel e820 map. | 111 | * Add a memory region to the kernel e820 map. |
112 | */ | 112 | */ |
113 | void __init e820_add_region(u64 start, u64 size, int type) | 113 | static void __init __e820_add_region(struct e820map *e820x, u64 start, u64 size, |
114 | int type) | ||
114 | { | 115 | { |
115 | int x = e820.nr_map; | 116 | int x = e820x->nr_map; |
116 | 117 | ||
117 | if (x == ARRAY_SIZE(e820.map)) { | 118 | if (x == ARRAY_SIZE(e820x->map)) { |
118 | printk(KERN_ERR "Ooops! Too many entries in the memory map!\n"); | 119 | printk(KERN_ERR "Ooops! Too many entries in the memory map!\n"); |
119 | return; | 120 | return; |
120 | } | 121 | } |
121 | 122 | ||
122 | e820.map[x].addr = start; | 123 | e820x->map[x].addr = start; |
123 | e820.map[x].size = size; | 124 | e820x->map[x].size = size; |
124 | e820.map[x].type = type; | 125 | e820x->map[x].type = type; |
125 | e820.nr_map++; | 126 | e820x->nr_map++; |
127 | } | ||
128 | |||
129 | void __init e820_add_region(u64 start, u64 size, int type) | ||
130 | { | ||
131 | __e820_add_region(&e820, start, size, type); | ||
132 | } | ||
133 | |||
134 | static void __init e820_print_type(u32 type) | ||
135 | { | ||
136 | switch (type) { | ||
137 | case E820_RAM: | ||
138 | case E820_RESERVED_KERN: | ||
139 | printk(KERN_CONT "(usable)"); | ||
140 | break; | ||
141 | case E820_RESERVED: | ||
142 | printk(KERN_CONT "(reserved)"); | ||
143 | break; | ||
144 | case E820_ACPI: | ||
145 | printk(KERN_CONT "(ACPI data)"); | ||
146 | break; | ||
147 | case E820_NVS: | ||
148 | printk(KERN_CONT "(ACPI NVS)"); | ||
149 | break; | ||
150 | case E820_UNUSABLE: | ||
151 | printk(KERN_CONT "(unusable)"); | ||
152 | break; | ||
153 | default: | ||
154 | printk(KERN_CONT "type %u", type); | ||
155 | break; | ||
156 | } | ||
126 | } | 157 | } |
127 | 158 | ||
128 | void __init e820_print_map(char *who) | 159 | void __init e820_print_map(char *who) |
@@ -134,27 +165,8 @@ void __init e820_print_map(char *who) | |||
134 | (unsigned long long) e820.map[i].addr, | 165 | (unsigned long long) e820.map[i].addr, |
135 | (unsigned long long) | 166 | (unsigned long long) |
136 | (e820.map[i].addr + e820.map[i].size)); | 167 | (e820.map[i].addr + e820.map[i].size)); |
137 | switch (e820.map[i].type) { | 168 | e820_print_type(e820.map[i].type); |
138 | case E820_RAM: | 169 | printk(KERN_CONT "\n"); |
139 | case E820_RESERVED_KERN: | ||
140 | printk(KERN_CONT "(usable)\n"); | ||
141 | break; | ||
142 | case E820_RESERVED: | ||
143 | printk(KERN_CONT "(reserved)\n"); | ||
144 | break; | ||
145 | case E820_ACPI: | ||
146 | printk(KERN_CONT "(ACPI data)\n"); | ||
147 | break; | ||
148 | case E820_NVS: | ||
149 | printk(KERN_CONT "(ACPI NVS)\n"); | ||
150 | break; | ||
151 | case E820_UNUSABLE: | ||
152 | printk("(unusable)\n"); | ||
153 | break; | ||
154 | default: | ||
155 | printk(KERN_CONT "type %u\n", e820.map[i].type); | ||
156 | break; | ||
157 | } | ||
158 | } | 170 | } |
159 | } | 171 | } |
160 | 172 | ||
@@ -221,7 +233,7 @@ void __init e820_print_map(char *who) | |||
221 | */ | 233 | */ |
222 | 234 | ||
223 | int __init sanitize_e820_map(struct e820entry *biosmap, int max_nr_map, | 235 | int __init sanitize_e820_map(struct e820entry *biosmap, int max_nr_map, |
224 | int *pnr_map) | 236 | u32 *pnr_map) |
225 | { | 237 | { |
226 | struct change_member { | 238 | struct change_member { |
227 | struct e820entry *pbios; /* pointer to original bios entry */ | 239 | struct e820entry *pbios; /* pointer to original bios entry */ |
@@ -417,11 +429,12 @@ static int __init append_e820_map(struct e820entry *biosmap, int nr_map) | |||
417 | return __append_e820_map(biosmap, nr_map); | 429 | return __append_e820_map(biosmap, nr_map); |
418 | } | 430 | } |
419 | 431 | ||
420 | static u64 __init e820_update_range_map(struct e820map *e820x, u64 start, | 432 | static u64 __init __e820_update_range(struct e820map *e820x, u64 start, |
421 | u64 size, unsigned old_type, | 433 | u64 size, unsigned old_type, |
422 | unsigned new_type) | 434 | unsigned new_type) |
423 | { | 435 | { |
424 | int i; | 436 | u64 end; |
437 | unsigned int i; | ||
425 | u64 real_updated_size = 0; | 438 | u64 real_updated_size = 0; |
426 | 439 | ||
427 | BUG_ON(old_type == new_type); | 440 | BUG_ON(old_type == new_type); |
@@ -429,27 +442,55 @@ static u64 __init e820_update_range_map(struct e820map *e820x, u64 start, | |||
429 | if (size > (ULLONG_MAX - start)) | 442 | if (size > (ULLONG_MAX - start)) |
430 | size = ULLONG_MAX - start; | 443 | size = ULLONG_MAX - start; |
431 | 444 | ||
432 | for (i = 0; i < e820.nr_map; i++) { | 445 | end = start + size; |
446 | printk(KERN_DEBUG "e820 update range: %016Lx - %016Lx ", | ||
447 | (unsigned long long) start, | ||
448 | (unsigned long long) end); | ||
449 | e820_print_type(old_type); | ||
450 | printk(KERN_CONT " ==> "); | ||
451 | e820_print_type(new_type); | ||
452 | printk(KERN_CONT "\n"); | ||
453 | |||
454 | for (i = 0; i < e820x->nr_map; i++) { | ||
433 | struct e820entry *ei = &e820x->map[i]; | 455 | struct e820entry *ei = &e820x->map[i]; |
434 | u64 final_start, final_end; | 456 | u64 final_start, final_end; |
457 | u64 ei_end; | ||
458 | |||
435 | if (ei->type != old_type) | 459 | if (ei->type != old_type) |
436 | continue; | 460 | continue; |
437 | /* totally covered? */ | 461 | |
438 | if (ei->addr >= start && | 462 | ei_end = ei->addr + ei->size; |
439 | (ei->addr + ei->size) <= (start + size)) { | 463 | /* totally covered by new range? */ |
464 | if (ei->addr >= start && ei_end <= end) { | ||
440 | ei->type = new_type; | 465 | ei->type = new_type; |
441 | real_updated_size += ei->size; | 466 | real_updated_size += ei->size; |
442 | continue; | 467 | continue; |
443 | } | 468 | } |
469 | |||
470 | /* new range is totally covered? */ | ||
471 | if (ei->addr < start && ei_end > end) { | ||
472 | __e820_add_region(e820x, start, size, new_type); | ||
473 | __e820_add_region(e820x, end, ei_end - end, ei->type); | ||
474 | ei->size = start - ei->addr; | ||
475 | real_updated_size += size; | ||
476 | continue; | ||
477 | } | ||
478 | |||
444 | /* partially covered */ | 479 | /* partially covered */ |
445 | final_start = max(start, ei->addr); | 480 | final_start = max(start, ei->addr); |
446 | final_end = min(start + size, ei->addr + ei->size); | 481 | final_end = min(end, ei_end); |
447 | if (final_start >= final_end) | 482 | if (final_start >= final_end) |
448 | continue; | 483 | continue; |
449 | e820_add_region(final_start, final_end - final_start, | 484 | |
450 | new_type); | 485 | __e820_add_region(e820x, final_start, final_end - final_start, |
486 | new_type); | ||
487 | |||
451 | real_updated_size += final_end - final_start; | 488 | real_updated_size += final_end - final_start; |
452 | 489 | ||
490 | /* | ||
491 | * left range could be head or tail, so need to update | ||
492 | * size at first. | ||
493 | */ | ||
453 | ei->size -= final_end - final_start; | 494 | ei->size -= final_end - final_start; |
454 | if (ei->addr < final_start) | 495 | if (ei->addr < final_start) |
455 | continue; | 496 | continue; |
@@ -461,13 +502,13 @@ static u64 __init e820_update_range_map(struct e820map *e820x, u64 start, | |||
461 | u64 __init e820_update_range(u64 start, u64 size, unsigned old_type, | 502 | u64 __init e820_update_range(u64 start, u64 size, unsigned old_type, |
462 | unsigned new_type) | 503 | unsigned new_type) |
463 | { | 504 | { |
464 | return e820_update_range_map(&e820, start, size, old_type, new_type); | 505 | return __e820_update_range(&e820, start, size, old_type, new_type); |
465 | } | 506 | } |
466 | 507 | ||
467 | static u64 __init e820_update_range_saved(u64 start, u64 size, | 508 | static u64 __init e820_update_range_saved(u64 start, u64 size, |
468 | unsigned old_type, unsigned new_type) | 509 | unsigned old_type, unsigned new_type) |
469 | { | 510 | { |
470 | return e820_update_range_map(&e820_saved, start, size, old_type, | 511 | return __e820_update_range(&e820_saved, start, size, old_type, |
471 | new_type); | 512 | new_type); |
472 | } | 513 | } |
473 | 514 | ||
@@ -511,7 +552,7 @@ u64 __init e820_remove_range(u64 start, u64 size, unsigned old_type, | |||
511 | 552 | ||
512 | void __init update_e820(void) | 553 | void __init update_e820(void) |
513 | { | 554 | { |
514 | int nr_map; | 555 | u32 nr_map; |
515 | 556 | ||
516 | nr_map = e820.nr_map; | 557 | nr_map = e820.nr_map; |
517 | if (sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &nr_map)) | 558 | if (sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &nr_map)) |
@@ -522,7 +563,7 @@ void __init update_e820(void) | |||
522 | } | 563 | } |
523 | static void __init update_e820_saved(void) | 564 | static void __init update_e820_saved(void) |
524 | { | 565 | { |
525 | int nr_map; | 566 | u32 nr_map; |
526 | 567 | ||
527 | nr_map = e820_saved.nr_map; | 568 | nr_map = e820_saved.nr_map; |
528 | if (sanitize_e820_map(e820_saved.map, ARRAY_SIZE(e820_saved.map), &nr_map)) | 569 | if (sanitize_e820_map(e820_saved.map, ARRAY_SIZE(e820_saved.map), &nr_map)) |
@@ -1020,8 +1061,8 @@ u64 __init find_e820_area_size(u64 start, u64 *sizep, u64 align) | |||
1020 | continue; | 1061 | continue; |
1021 | return addr; | 1062 | return addr; |
1022 | } | 1063 | } |
1023 | return -1UL; | ||
1024 | 1064 | ||
1065 | return -1ULL; | ||
1025 | } | 1066 | } |
1026 | 1067 | ||
1027 | /* | 1068 | /* |
@@ -1034,13 +1075,22 @@ u64 __init early_reserve_e820(u64 startt, u64 sizet, u64 align) | |||
1034 | u64 start; | 1075 | u64 start; |
1035 | 1076 | ||
1036 | start = startt; | 1077 | start = startt; |
1037 | while (size < sizet) | 1078 | while (size < sizet && (start + 1)) |
1038 | start = find_e820_area_size(start, &size, align); | 1079 | start = find_e820_area_size(start, &size, align); |
1039 | 1080 | ||
1040 | if (size < sizet) | 1081 | if (size < sizet) |
1041 | return 0; | 1082 | return 0; |
1042 | 1083 | ||
1084 | #ifdef CONFIG_X86_32 | ||
1085 | if (start >= MAXMEM) | ||
1086 | return 0; | ||
1087 | if (start + size > MAXMEM) | ||
1088 | size = MAXMEM - start; | ||
1089 | #endif | ||
1090 | |||
1043 | addr = round_down(start + size - sizet, align); | 1091 | addr = round_down(start + size - sizet, align); |
1092 | if (addr < start) | ||
1093 | return 0; | ||
1044 | e820_update_range(addr, sizet, E820_RAM, E820_RESERVED); | 1094 | e820_update_range(addr, sizet, E820_RAM, E820_RESERVED); |
1045 | e820_update_range_saved(addr, sizet, E820_RAM, E820_RESERVED); | 1095 | e820_update_range_saved(addr, sizet, E820_RAM, E820_RESERVED); |
1046 | printk(KERN_INFO "update e820 for early_reserve_e820\n"); | 1096 | printk(KERN_INFO "update e820 for early_reserve_e820\n"); |
@@ -1253,7 +1303,7 @@ early_param("memmap", parse_memmap_opt); | |||
1253 | void __init finish_e820_parsing(void) | 1303 | void __init finish_e820_parsing(void) |
1254 | { | 1304 | { |
1255 | if (userdef) { | 1305 | if (userdef) { |
1256 | int nr = e820.nr_map; | 1306 | u32 nr = e820.nr_map; |
1257 | 1307 | ||
1258 | if (sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &nr) < 0) | 1308 | if (sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &nr) < 0) |
1259 | early_panic("Invalid user supplied memory map"); | 1309 | early_panic("Invalid user supplied memory map"); |
@@ -1336,7 +1386,7 @@ void __init e820_reserve_resources_late(void) | |||
1336 | char *__init default_machine_specific_memory_setup(void) | 1386 | char *__init default_machine_specific_memory_setup(void) |
1337 | { | 1387 | { |
1338 | char *who = "BIOS-e820"; | 1388 | char *who = "BIOS-e820"; |
1339 | int new_nr; | 1389 | u32 new_nr; |
1340 | /* | 1390 | /* |
1341 | * Try to copy the BIOS-supplied E820-map. | 1391 | * Try to copy the BIOS-supplied E820-map. |
1342 | * | 1392 | * |