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