| Start/ | End/ | |||
| True | False | - | Line | Source |
| 1 | /* | |||
| 2 | * Handle the memory map. | |||
| 3 | * The functions here do the job until bootmem takes over. | |||
| 4 | * $Id: e820.c,v 1.4 2002/09/19 19:25:32 ak Exp $ | |||
| 5 | * | |||
| 6 | * Getting sanitize_e820_map() in sync with i386 version by applying change: | |||
| 7 | * - Provisions for empty E820 memory regions (reported by certain BIOSes). | |||
| 8 | * Alex Achenbach <xela@slit.de>, December 2002. | |||
| 9 | * Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> | |||
| 10 | * | |||
| 11 | */ | |||
| 12 | #include <linux/config.h> | |||
| 13 | #include <linux/kernel.h> | |||
| 14 | #include <linux/types.h> | |||
| 15 | #include <linux/init.h> | |||
| 16 | #include <linux/bootmem.h> | |||
| 17 | #include <linux/ioport.h> | |||
| 18 | #include <linux/string.h> | |||
| 19 | #include <linux/kexec.h> | |||
| 20 | #include <linux/module.h> | |||
| 21 | ||||
| 22 | #include <asm/page.h> | |||
| 23 | #include <asm/e820.h> | |||
| 24 | #include <asm/proto.h> | |||
| 25 | #include <asm/bootsetup.h> | |||
| 26 | #include <asm/sections.h> | |||
| 27 | ||||
| 28 | /* | |||
| 29 | * PFN of last memory page. | |||
| 30 | */ | |||
| 31 | unsigned long end_pfn; | |||
| 32 | EXPORT_SYMBOL(end_pfn); | |||
| 33 | ||||
| 34 | /* | |||
| 35 | * end_pfn only includes RAM, while end_pfn_map includes all e820 entries. | |||
| 36 | * The direct mapping extends to end_pfn_map, so that we can directly access | |||
| 37 | * apertures, ACPI and other tables without having to play with fixmaps. | |||
| 38 | */ | |||
| 39 | unsigned long end_pfn_map; | |||
| 40 | ||||
| 41 | /* | |||
| 42 | * Last pfn which the user wants to use. | |||
| 43 | */ | |||
| 44 | unsigned long end_user_pfn = MAXMEM>>PAGE_SHIFT; | |||
| 45 | ||||
| 46 | extern struct resource code_resource, data_resource; | |||
| 47 | ||||
| 48 | /* Check for some hardcoded bad areas that early boot is not allowed to touch */ | |||
| 24 | 0 | 49 | static inline int bad_addr(unsigned long *addrp, unsigned long size) | |
| 50 | { | |||
| 51 | unsigned long addr = *addrp, last = addr + size; | |||
| 52 | ||||
| 53 | /* various gunk below that needed for SMP startup */ | |||
| 6 | 18 | 54 | if (addr < 0x8000) { | |
| 55 | *addrp = 0x8000; | |||
| 6 | 56 | return 1; | ||
| 57 | } | |||
| 58 | ||||
| 59 | /* direct mapping tables of the kernel */ | |||
| 6 | 12 | 60 | if (last >= table_start<<PAGE_SHIFT && addr < table_end<<PAGE_SHIFT) { | |
| 6 | 60 | T && T | ||
| 12 | 60 | T && F | ||
| 0 | - | 60 | F && _ | |
| 61 | *addrp = table_end << PAGE_SHIFT; | |||
| 6 | 62 | return 1; | ||
| 63 | } | |||
| 64 | ||||
| 65 | /* initrd */ | |||
| 66 | #ifdef CONFIG_BLK_DEV_INITRD | |||
| 67 | if (LOADER_TYPE && INITRD_START && last >= INITRD_START && | |||
| 68 | addr < INITRD_START+INITRD_SIZE) { | |||
| 69 | *addrp = INITRD_START + INITRD_SIZE; | |||
| 70 | return 1; | |||
| 71 | } | |||
| 72 | #endif | |||
| 73 | /* kernel code + 640k memory hole (later should not be needed, but | |||
| 74 | be paranoid for now) */ | |||
| 0 | 12 | - | 75 | if (last >= 640*1024 && addr < __pa_symbol(&_end)) { |
| 0 | - | 75 | T && T | |
| 0 | - | 75 | T && F | |
| 12 | 75 | F && _ | ||
| 76 | *addrp = __pa_symbol(&_end); | |||
| 0 | - | 77 | return 1; | |
| 78 | } | |||
| 79 | /* XXX ramdisk image here? */ | |||
| 12 | 80 | return 0; | ||
| 81 | } | |||
| 82 | ||||
| 30 | 0 | 83 | int __init e820_mapped(unsigned long start, unsigned long end, unsigned type) | |
| 84 | { | |||
| 85 | int i; | |||
| 198 | 18 | 86 | for (i = 0; i < e820.nr_map; i++) { | |
| 87 | struct e820entry *ei = &e820.map[i]; | |||
| 36 | 162 | 88 | if (type && ei->type != type) | |
| 36 | 88 | T && T | ||
| 12 | 88 | T && F | ||
| 150 | 88 | F && _ | ||
| 36 | 89 | continue; | ||
| 150 | 12 | 90 | if (ei->addr >= end || ei->addr + ei->size <= start) | |
| 12 | 90 | T || _ | ||
| 138 | 90 | F || T | ||
| 12 | 90 | F || F | ||
| 150 | 91 | continue; | ||
| 12 | 92 | return 1; | ||
| 93 | } | |||
| 18 | 94 | return 0; | ||
| 95 | } | |||
| 96 | ||||
| 97 | /* | |||
| 98 | * Find a free area in a specific range. | |||
| 99 | */ | |||
| 12 | 0 | 100 | unsigned long __init find_e820_area(unsigned long start, unsigned long end, unsigned size) | |
| 101 | { | |||
| 102 | int i; | |||
| 12 | 0 | - | 103 | for (i = 0; i < e820.nr_map; i++) { |
| 104 | struct e820entry *ei = &e820.map[i]; | |||
| 105 | unsigned long addr = ei->addr, last; | |||
| 0 | 12 | - | 106 | if (ei->type != E820_RAM) |
| 0 | - | 107 | continue; | |
| 6 | 6 | 108 | if (addr < start) | |
| 109 | addr = start; | |||
| 0 | 12 | - | 110 | if (addr > ei->addr + ei->size) |
| 0 | - | 111 | continue; | |
| 12 | 12 | 112 | while (bad_addr(&addr, size) && addr+size < ei->addr + ei->size) | |
| 12 | 112 | T && T | ||
| 0 | - | 112 | T && F | |
| 12 | 112 | F && _ | ||
| 113 | ; | |||
| 114 | last = addr + size; | |||
| 0 | 12 | - | 115 | if (last > ei->addr + ei->size) |
| 0 | - | 116 | continue; | |
| 0 | 12 | - | 117 | if (last > end) |
| 0 | - | 118 | continue; | |
| 12 | 119 | return addr; | ||
| 120 | } | |||
| 0 | - | 121 | return -1UL; | |
| 122 | } | |||
| 123 | ||||
| 124 | /* | |||
| 125 | * Free bootmem based on the e820 table for a node. | |||
| 126 | */ | |||
| 6 | 6 | 127 | void __init e820_bootmem_free(pg_data_t *pgdat, unsigned long start,unsigned long end) | |
| 128 | { | |||
| 129 | int i; | |||
| 48 | 6 | 130 | for (i = 0; i < e820.nr_map; i++) { | |
| 131 | struct e820entry *ei = &e820.map[i]; | |||
| 132 | unsigned long last, addr; | |||
| 133 | ||||
| 134 | if (ei->type != E820_RAM || | |||
| 135 | ei->addr+ei->size <= start || | |||
| 36 | 12 | 136 | ei->addr >= end) | |
| 36 | 136 | T || _ || _ | ||
| 0 | - | 136 | F || T || _ | |
| 0 | - | 136 | F || F || T | |
| 12 | 136 | F || F || F | ||
| 36 | 137 | continue; | ||
| 138 | ||||
| 139 | addr = round_up(ei->addr, PAGE_SIZE); | |||
| 0 | 12 | - | 140 | if (addr < start) |
| 141 | addr = start; | |||
| 142 | ||||
| 143 | last = round_down(ei->addr + ei->size, PAGE_SIZE); | |||
| 6 | 6 | 144 | if (last >= end) | |
| 145 | last = end; | |||
| 146 | ||||
| 12 | 0 | - | 147 | if (last > addr && last-addr >= PAGE_SIZE) |
| 12 | 147 | T && T | ||
| 0 | - | 147 | T && F | |
| 0 | - | 147 | F && _ | |
| 148 | free_bootmem_node(pgdat, addr, last-addr); | |||
| 149 | } | |||
| 150 | } | |||
| 151 | ||||
| 152 | /* | |||
| 153 | * Find the highest page frame number we have available | |||
| 154 | */ | |||
| 6 | 0 | 155 | unsigned long __init e820_end_of_ram(void) | |
| 156 | { | |||
| 157 | int i; | |||
| 158 | unsigned long end_pfn = 0; | |||
| 159 | ||||
| 48 | 6 | 160 | for (i = 0; i < e820.nr_map; i++) { | |
| 161 | struct e820entry *ei = &e820.map[i]; | |||
| 162 | unsigned long start, end; | |||
| 163 | ||||
| 164 | start = round_up(ei->addr, PAGE_SIZE); | |||
| 165 | end = round_down(ei->addr + ei->size, PAGE_SIZE); | |||
| 0 | 48 | - | 166 | if (start >= end) |
| 0 | - | 167 | continue; | |
| 12 | 36 | 168 | if (ei->type == E820_RAM) { | |
| 12 | 0 | - | 169 | if (end > end_pfn<<PAGE_SHIFT) |
| 170 | end_pfn = end>>PAGE_SHIFT; | |||
| 171 | } else { | |||
| 36 | 0 | - | 172 | if (end > end_pfn_map<<PAGE_SHIFT) |
| 173 | end_pfn_map = end>>PAGE_SHIFT; | |||
| 174 | } | |||
| 175 | } | |||
| 176 | ||||
| 0 | 6 | - | 177 | if (end_pfn > end_pfn_map) |
| 178 | end_pfn_map = end_pfn; | |||
| 0 | 6 | - | 179 | if (end_pfn_map > MAXMEM>>PAGE_SHIFT) |
| 180 | end_pfn_map = MAXMEM>>PAGE_SHIFT; | |||
| 0 | 6 | - | 181 | if (end_pfn > end_user_pfn) |
| 182 | end_pfn = end_user_pfn; | |||
| 0 | 6 | - | 183 | if (end_pfn > end_pfn_map) |
| 184 | end_pfn = end_pfn_map; | |||
| 185 | ||||
| 6 | 186 | return end_pfn; | ||
| 187 | } | |||
| 188 | ||||
| 189 | /* | |||
| 190 | * Compute how much memory is missing in a range. | |||
| 191 | * Unlike the other functions in this file the arguments are in page numbers. | |||
| 192 | */ | |||
| 193 | unsigned long __init | |||
| 30 | 0 | 194 | e820_hole_size(unsigned long start_pfn, unsigned long end_pfn) | |
| 195 | { | |||
| 196 | unsigned long ram = 0; | |||
| 197 | unsigned long start = start_pfn << PAGE_SHIFT; | |||
| 198 | unsigned long end = end_pfn << PAGE_SHIFT; | |||
| 199 | int i; | |||
| 240 | 30 | 200 | for (i = 0; i < e820.nr_map; i++) { | |
| 201 | struct e820entry *ei = &e820.map[i]; | |||
| 202 | unsigned long last, addr; | |||
| 203 | ||||
| 204 | if (ei->type != E820_RAM || | |||
| 205 | ei->addr+ei->size <= start || | |||
| 210 | 30 | 206 | ei->addr >= end) | |
| 180 | 206 | T || _ || _ | ||
| 30 | 206 | F || T || _ | ||
| 0 | - | 206 | F || F || T | |
| 30 | 206 | F || F || F | ||
| 210 | 207 | continue; | ||
| 208 | ||||
| 209 | addr = round_up(ei->addr, PAGE_SIZE); | |||
| 6 | 24 | 210 | if (addr < start) | |
| 211 | addr = start; | |||
| 212 | ||||
| 213 | last = round_down(ei->addr + ei->size, PAGE_SIZE); | |||
| 18 | 12 | 214 | if (last >= end) | |
| 215 | last = end; | |||
| 216 | ||||
| 30 | 0 | - | 217 | if (last > addr) |
| 218 | ram += last - addr; | |||
| 219 | } | |||
| 30 | 220 | return ((end - start) - ram) >> PAGE_SHIFT; | ||
| 221 | } | |||
| 222 | ||||
| 223 | /* | |||
| 224 | * Mark e820 reserved areas as busy for the resource manager. | |||
| 225 | */ | |||
| 6 | 6 | 226 | void __init e820_reserve_resources(void) | |
| 227 | { | |||
| 228 | int i; | |||
| 48 | 6 | 229 | for (i = 0; i < e820.nr_map; i++) { | |
| 230 | struct resource *res; | |||
| 231 | res = alloc_bootmem_low(sizeof(struct resource)); | |||
| 232 | switch (e820.map[i].type) { | |||
| 12 | 233 | case E820_RAM: res->name = "System RAM"; break; | ||
| 12 | 233 | break | ||
| 6 | 234 | case E820_ACPI: res->name = "ACPI Tables"; break; | ||
| 6 | 234 | break | ||
| 6 | 235 | case E820_NVS: res->name = "ACPI Non-volatile Storage"; break; | ||
| 6 | 235 | break | ||
| 24 | 236 | default: res->name = "reserved"; | ||
| 237 | } | |||
| 238 | res->start = e820.map[i].addr; | |||
| 239 | res->end = res->start + e820.map[i].size - 1; | |||
| 240 | res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; | |||
| 241 | request_resource(&iomem_resource, res); | |||
| 12 | 36 | 242 | if (e820.map[i].type == E820_RAM) { | |
| 243 | /* | |||
| 244 | * We don't know which RAM region contains kernel data, | |||
| 245 | * so we try it repeatedly and let the resource manager | |||
| 246 | * test it. | |||
| 247 | */ | |||
| 248 | request_resource(res, &code_resource); | |||
| 249 | request_resource(res, &data_resource); | |||
| 250 | #ifdef CONFIG_KEXEC | |||
| 251 | request_resource(res, &crashk_res); | |||
| 252 | #endif | |||
| 253 | } | |||
| 254 | } | |||
| 255 | } | |||
| 256 | ||||
| 257 | /* | |||
| 258 | * Add a memory region to the kernel e820 map. | |||
| 259 | */ | |||
| 48 | 48 | 260 | void __init add_memory_region(unsigned long start, unsigned long size, int type) | |
| 261 | { | |||
| 262 | int x = e820.nr_map; | |||
| 263 | ||||
| 0 | 48 | - | 264 | if (x == E820MAX) { |
| 265 | printk(KERN_ERR "Ooops! Too many entries in the memory map!\n"); | |||
| 0 | - | 266 | return; | |
| 267 | } | |||
| 268 | ||||
| 269 | e820.map[x].addr = start; | |||
| 270 | e820.map[x].size = size; | |||
| 271 | e820.map[x].type = type; | |||
| 272 | e820.nr_map++; | |||
| 273 | } | |||
| 274 | ||||
| 6 | 6 | 275 | void __init e820_print_map(char *who) | |
| 276 | { | |||
| 277 | int i; | |||
| 278 | ||||
| 48 | 6 | 279 | for (i = 0; i < e820.nr_map; i++) { | |
| 280 | printk(" %s: %016Lx - %016Lx ", who, | |||
| 281 | (unsigned long long) e820.map[i].addr, | |||
| 282 | (unsigned long long) (e820.map[i].addr + e820.map[i].size)); | |||
| 283 | switch (e820.map[i].type) { | |||
| 12 | 284 | case E820_RAM: printk("(usable)\n"); | ||
| 12 | 285 | break; | ||
| 24 | 286 | case E820_RESERVED: | ||
| 287 | printk("(reserved)\n"); | |||
| 24 | 288 | break; | ||
| 6 | 289 | case E820_ACPI: | ||
| 290 | printk("(ACPI data)\n"); | |||
| 6 | 291 | break; | ||
| 6 | 292 | case E820_NVS: | ||
| 293 | printk("(ACPI NVS)\n"); | |||
| 6 | 294 | break; | ||
| 0 | - | 295 | default: printk("type %u\n", e820.map[i].type); | |
| 0 | - | 296 | break; | |
| 297 | } | |||
| 298 | } | |||
| 299 | } | |||
| 300 | ||||
| 301 | /* | |||
| 302 | * Sanitize the BIOS e820 map. | |||
| 303 | * | |||
| 304 | * Some e820 responses include overlapping entries. The following | |||
| 305 | * replaces the original e820 map with a new one, removing overlaps. | |||
| 306 | * | |||
| 307 | */ | |||
| 6 | 0 | 308 | static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map) | |
| 309 | { | |||
| 310 | struct change_member { | |||
| 311 | struct e820entry *pbios; /* pointer to original bios entry */ | |||
| 312 | unsigned long long addr; /* address for this change point */ | |||
| 313 | }; | |||
| 314 | static struct change_member change_point_list[2*E820MAX] __initdata; | |||
| 315 | static struct change_member *change_point[2*E820MAX] __initdata; | |||
| 316 | static struct e820entry *overlap_list[E820MAX] __initdata; | |||
| 317 | static struct e820entry new_bios[E820MAX] __initdata; | |||
| 318 | struct change_member *change_tmp; | |||
| 319 | unsigned long current_type, last_type; | |||
| 320 | unsigned long long last_addr; | |||
| 321 | int chgidx, still_changing; | |||
| 322 | int overlap_entries; | |||
| 323 | int new_bios_entry; | |||
| 324 | int old_nr, new_nr, chg_nr; | |||
| 325 | int i; | |||
| 326 | ||||
| 327 | /* | |||
| 328 | Visually we're performing the following (1,2,3,4 = memory types)... | |||
| 329 | ||||
| 330 | Sample memory map (w/overlaps): | |||
| 331 | ____22__________________ | |||
| 332 | ______________________4_ | |||
| 333 | ____1111________________ | |||
| 334 | _44_____________________ | |||
| 335 | 11111111________________ | |||
| 336 | ____________________33__ | |||
| 337 | ___________44___________ | |||
| 338 | __________33333_________ | |||
| 339 | ______________22________ | |||
| 340 | ___________________2222_ | |||
| 341 | _________111111111______ | |||
| 342 | _____________________11_ | |||
| 343 | _________________4______ | |||
| 344 | ||||
| 345 | Sanitized equivalent (no overlap): | |||
| 346 | 1_______________________ | |||
| 347 | _44_____________________ | |||
| 348 | ___1____________________ | |||
| 349 | ____22__________________ | |||
| 350 | ______11________________ | |||
| 351 | _________1______________ | |||
| 352 | __________3_____________ | |||
| 353 | ___________44___________ | |||
| 354 | _____________33_________ | |||
| 355 | _______________2________ | |||
| 356 | ________________1_______ | |||
| 357 | _________________4______ | |||
| 358 | ___________________2____ | |||
| 359 | ____________________33__ | |||
| 360 | ______________________4_ | |||
| 361 | */ | |||
| 362 | ||||
| 363 | /* if there's only one memory region, don't bother */ | |||
| 0 | 6 | - | 364 | if (*pnr_map < 2) |
| 0 | - | 365 | return -1; | |
| 366 | ||||
| 367 | old_nr = *pnr_map; | |||
| 368 | ||||
| 369 | /* bail out if we find any unreasonable addresses in bios map */ | |||
| 48 | 6 | 370 | for (i=0; i<old_nr; i++) | |
| 0 | 48 | - | 371 | if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr) |
| 0 | - | 372 | return -1; | |
| 373 | ||||
| 374 | /* create pointers for initial change-point information (for sorting) */ | |||
| 96 | 6 | 375 | for (i=0; i < 2*old_nr; i++) | |
| 376 | change_point[i] = &change_point_list[i]; | |||
| 377 | ||||
| 378 | /* record all known change-points (starting and ending addresses), | |||
| 379 | omitting those that are for empty memory regions */ | |||
| 380 | chgidx = 0; | |||
| 48 | 6 | 381 | for (i=0; i < old_nr; i++) { | |
| 48 | 0 | - | 382 | if (biosmap[i].size != 0) { |
| 383 | change_point[chgidx]->addr = biosmap[i].addr; | |||
| 384 | change_point[chgidx++]->pbios = &biosmap[i]; | |||
| 385 | change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size; | |||
| 386 | change_point[chgidx++]->pbios = &biosmap[i]; | |||
| 387 | } | |||
| 388 | } | |||
| 389 | chg_nr = chgidx; | |||
| 390 | ||||
| 391 | /* sort change-point list by memory addresses (low -> high) */ | |||
| 392 | still_changing = 1; | |||
| 12 | 6 | 393 | while (still_changing) { | |
| 394 | still_changing = 0; | |||
| 180 | 12 | 395 | for (i=1; i < chg_nr; i++) { | |
| 396 | /* if <current_addr> > <last_addr>, swap */ | |||
| 397 | /* or, if current=<start_addr> & last=<end_addr>, swap */ | |||
| 398 | if ((change_point[i]->addr < change_point[i-1]->addr) || | |||
| 399 | ((change_point[i]->addr == change_point[i-1]->addr) && | |||
| 400 | (change_point[i]->addr == change_point[i]->pbios->addr) && | |||
| 30 | 150 | 401 | (change_point[i-1]->addr != change_point[i-1]->pbios->addr)) | |
| 0 | - | 401 | (T) || ((_) && (_) && (_)) | |
| 30 | 401 | (F) || ((T) && (T) && (T)) | ||
| 0 | - | 401 | (F) || ((T) && (T) && (F)) | |
| 30 | 401 | (F) || ((T) && (F) && (_)) | ||
| 120 | 401 | (F) || ((F) && (_) && (_)) | ||
| 402 | ) | |||
| 403 | { | |||
| 404 | change_tmp = change_point[i]; | |||
| 405 | change_point[i] = change_point[i-1]; | |||
| 406 | change_point[i-1] = change_tmp; | |||
| 407 | still_changing=1; | |||
| 408 | } | |||
| 409 | } | |||
| 410 | } | |||
| 411 | ||||
| 412 | /* create a new bios memory map, removing overlaps */ | |||
| 413 | overlap_entries=0; /* number of entries in the overlap table */ | |||
| 414 | new_bios_entry=0; /* index for creating new bios map entries */ | |||
| 415 | last_type = 0; /* start with undefined memory type */ | |||
| 416 | last_addr = 0; /* start with 0 as last starting address */ | |||
| 417 | /* loop through change-points, determining affect on the new bios map */ | |||
| 96 | 6 | 418 | for (chgidx=0; chgidx < chg_nr; chgidx++) | |
| 419 | { | |||
| 420 | /* keep track of all overlapping bios entries */ | |||
| 48 | 48 | 421 | if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr) | |
| 422 | { | |||
| 423 | /* add map entry to overlap list (> 1 entry implies an overlap) */ | |||
| 424 | overlap_list[overlap_entries++]=change_point[chgidx]->pbios; | |||
| 425 | } | |||
| 426 | else | |||
| 427 | { | |||
| 428 | /* remove entry from list (order independent, so swap with last) */ | |||
| 78 | 48 | 429 | for (i=0; i<overlap_entries; i++) | |
| 430 | { | |||
| 48 | 30 | 431 | if (overlap_list[i] == change_point[chgidx]->pbios) | |
| 432 | overlap_list[i] = overlap_list[overlap_entries-1]; | |||
| 433 | } | |||
| 434 | overlap_entries--; | |||
| 435 | } | |||
| 436 | /* if there are overlapping entries, decide which "type" to use */ | |||
| 437 | /* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */ | |||
| 438 | current_type = 0; | |||
| 108 | 96 | 439 | for (i=0; i<overlap_entries; i++) | |
| 96 | 12 | 440 | if (overlap_list[i]->type > current_type) | |
| 441 | current_type = overlap_list[i]->type; | |||
| 442 | /* continue building up new bios map based on this information */ | |||
| 66 | 30 | 443 | if (current_type != last_type) { | |
| 48 | 18 | 444 | if (last_type != 0) { | |
| 445 | new_bios[new_bios_entry].size = | |||
| 446 | change_point[chgidx]->addr - last_addr; | |||
| 447 | /* move forward only if the new size was non-zero */ | |||
| 48 | 0 | - | 448 | if (new_bios[new_bios_entry].size != 0) |
| 0 | 48 | - | 449 | if (++new_bios_entry >= E820MAX) |
| 0 | - | 450 | break; /* no more space left for new bios entries */ | |
| 451 | } | |||
| 48 | 18 | 452 | if (current_type != 0) { | |
| 453 | new_bios[new_bios_entry].addr = change_point[chgidx]->addr; | |||
| 454 | new_bios[new_bios_entry].type = current_type; | |||
| 455 | last_addr=change_point[chgidx]->addr; | |||
| 456 | } | |||
| 457 | last_type = current_type; | |||
| 458 | } | |||
| 459 | } | |||
| 460 | new_nr = new_bios_entry; /* retain count for new bios entries */ | |||
| 461 | ||||
| 462 | /* copy new bios mapping into original location */ | |||
| 463 | memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry)); | |||
| 464 | *pnr_map = new_nr; | |||
| 465 | ||||
| 6 | 466 | return 0; | ||
| 467 | } | |||
| 468 | ||||
| 469 | /* | |||
| 470 | * Copy the BIOS e820 map into a safe place. | |||
| 471 | * | |||
| 472 | * Sanity-check it while we're at it.. | |||
| 473 | * | |||
| 474 | * If we're lucky and live on a modern system, the setup code | |||
| 475 | * will have given us a memory map that we can use to properly | |||
| 476 | * set up memory. If we aren't, we'll fake a memory map. | |||
| 477 | * | |||
| 478 | * We check to see that the memory map contains at least 2 elements | |||
| 479 | * before we'll use it, because the detection code in setup.S may | |||
| 480 | * not be perfect and most every PC known to man has two memory | |||
| 481 | * regions: one from 0 to 640k, and one from 1mb up. (The IBM | |||
| 482 | * thinkpad 560x, for example, does not cooperate with the memo | |||