Commit 7ae65fd334232468a9d6b523a4fc141cd6ec5ea4
Committed by
Linus Torvalds
1 parent
4116c527ea
Exists in
master
and in
4 other branches
[PATCH] x86: fix EFI memory map parsing
The memory descriptors that comprise the EFI memory map are not fixed in stone such that the size could change in the future. This uses the memory descriptor size obtained from EFI to iterate over the memory map entries during boot. This enables the removal of an x86 specific pad (and ifdef) in the EFI header. I also couldn't stomach the broken up nature of the function to put EFI runtime calls into virtual mode any longer so I fixed that up a bit as well. For reference, this patch only impacts x86. Signed-off-by: Matt Tolentino <matthew.e.tolentino@intel.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 5 changed files with 67 additions and 69 deletions Side-by-side Diff
arch/i386/kernel/efi.c
| ... | ... | @@ -233,22 +233,23 @@ |
| 233 | 233 | { |
| 234 | 234 | memmap.map = NULL; |
| 235 | 235 | |
| 236 | - memmap.map = (efi_memory_desc_t *) | |
| 237 | - bt_ioremap((unsigned long) memmap.phys_map, | |
| 238 | - (memmap.nr_map * sizeof(efi_memory_desc_t))); | |
| 239 | - | |
| 236 | + memmap.map = bt_ioremap((unsigned long) memmap.phys_map, | |
| 237 | + (memmap.nr_map * memmap.desc_size)); | |
| 240 | 238 | if (memmap.map == NULL) |
| 241 | 239 | printk(KERN_ERR PFX "Could not remap the EFI memmap!\n"); |
| 240 | + | |
| 241 | + memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size); | |
| 242 | 242 | } |
| 243 | 243 | |
| 244 | 244 | #if EFI_DEBUG |
| 245 | 245 | static void __init print_efi_memmap(void) |
| 246 | 246 | { |
| 247 | 247 | efi_memory_desc_t *md; |
| 248 | + void *p; | |
| 248 | 249 | int i; |
| 249 | 250 | |
| 250 | - for (i = 0; i < memmap.nr_map; i++) { | |
| 251 | - md = &memmap.map[i]; | |
| 251 | + for (p = memmap.map, i = 0; p < memmap.map_end; p += memmap.desc_size, i++) { | |
| 252 | + md = p; | |
| 252 | 253 | printk(KERN_INFO "mem%02u: type=%u, attr=0x%llx, " |
| 253 | 254 | "range=[0x%016llx-0x%016llx) (%lluMB)\n", |
| 254 | 255 | i, md->type, md->attribute, md->phys_addr, |
| 255 | 256 | |
| ... | ... | @@ -271,10 +272,10 @@ |
| 271 | 272 | } prev, curr; |
| 272 | 273 | efi_memory_desc_t *md; |
| 273 | 274 | unsigned long start, end; |
| 274 | - int i; | |
| 275 | + void *p; | |
| 275 | 276 | |
| 276 | - for (i = 0; i < memmap.nr_map; i++) { | |
| 277 | - md = &memmap.map[i]; | |
| 277 | + for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { | |
| 278 | + md = p; | |
| 278 | 279 | |
| 279 | 280 | if ((md->num_pages == 0) || (!is_available_memory(md))) |
| 280 | 281 | continue; |
| ... | ... | @@ -325,6 +326,7 @@ |
| 325 | 326 | memmap.phys_map = EFI_MEMMAP; |
| 326 | 327 | memmap.nr_map = EFI_MEMMAP_SIZE/EFI_MEMDESC_SIZE; |
| 327 | 328 | memmap.desc_version = EFI_MEMDESC_VERSION; |
| 329 | + memmap.desc_size = EFI_MEMDESC_SIZE; | |
| 328 | 330 | |
| 329 | 331 | efi.systab = (efi_system_table_t *) |
| 330 | 332 | boot_ioremap((unsigned long) efi_phys.systab, |
| 331 | 333 | |
| 332 | 334 | |
| ... | ... | @@ -428,22 +430,30 @@ |
| 428 | 430 | printk(KERN_ERR PFX "Could not map the runtime service table!\n"); |
| 429 | 431 | |
| 430 | 432 | /* Map the EFI memory map for use until paging_init() */ |
| 431 | - | |
| 432 | - memmap.map = (efi_memory_desc_t *) | |
| 433 | - boot_ioremap((unsigned long) EFI_MEMMAP, EFI_MEMMAP_SIZE); | |
| 434 | - | |
| 433 | + memmap.map = boot_ioremap((unsigned long) EFI_MEMMAP, EFI_MEMMAP_SIZE); | |
| 435 | 434 | if (memmap.map == NULL) |
| 436 | 435 | printk(KERN_ERR PFX "Could not map the EFI memory map!\n"); |
| 437 | 436 | |
| 438 | - if (EFI_MEMDESC_SIZE != sizeof(efi_memory_desc_t)) { | |
| 439 | - printk(KERN_WARNING PFX "Warning! Kernel-defined memdesc doesn't " | |
| 440 | - "match the one from EFI!\n"); | |
| 441 | - } | |
| 437 | + memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size); | |
| 438 | + | |
| 442 | 439 | #if EFI_DEBUG |
| 443 | 440 | print_efi_memmap(); |
| 444 | 441 | #endif |
| 445 | 442 | } |
| 446 | 443 | |
| 444 | +static inline void __init check_range_for_systab(efi_memory_desc_t *md) | |
| 445 | +{ | |
| 446 | + if (((unsigned long)md->phys_addr <= (unsigned long)efi_phys.systab) && | |
| 447 | + ((unsigned long)efi_phys.systab < md->phys_addr + | |
| 448 | + ((unsigned long)md->num_pages << EFI_PAGE_SHIFT))) { | |
| 449 | + unsigned long addr; | |
| 450 | + | |
| 451 | + addr = md->virt_addr - md->phys_addr + | |
| 452 | + (unsigned long)efi_phys.systab; | |
| 453 | + efi.systab = (efi_system_table_t *)addr; | |
| 454 | + } | |
| 455 | +} | |
| 456 | + | |
| 447 | 457 | /* |
| 448 | 458 | * This function will switch the EFI runtime services to virtual mode. |
| 449 | 459 | * Essentially, look through the EFI memmap and map every region that |
| 450 | 460 | |
| 451 | 461 | |
| 452 | 462 | |
| 453 | 463 | |
| 454 | 464 | |
| ... | ... | @@ -457,43 +467,32 @@ |
| 457 | 467 | { |
| 458 | 468 | efi_memory_desc_t *md; |
| 459 | 469 | efi_status_t status; |
| 460 | - int i; | |
| 470 | + void *p; | |
| 461 | 471 | |
| 462 | 472 | efi.systab = NULL; |
| 463 | 473 | |
| 464 | - for (i = 0; i < memmap.nr_map; i++) { | |
| 465 | - md = &memmap.map[i]; | |
| 474 | + for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { | |
| 475 | + md = p; | |
| 466 | 476 | |
| 467 | - if (md->attribute & EFI_MEMORY_RUNTIME) { | |
| 468 | - md->virt_addr = | |
| 469 | - (unsigned long)ioremap(md->phys_addr, | |
| 470 | - md->num_pages << EFI_PAGE_SHIFT); | |
| 471 | - if (!(unsigned long)md->virt_addr) { | |
| 472 | - printk(KERN_ERR PFX "ioremap of 0x%lX failed\n", | |
| 473 | - (unsigned long)md->phys_addr); | |
| 474 | - } | |
| 477 | + if (!(md->attribute & EFI_MEMORY_RUNTIME)) | |
| 478 | + continue; | |
| 475 | 479 | |
| 476 | - if (((unsigned long)md->phys_addr <= | |
| 477 | - (unsigned long)efi_phys.systab) && | |
| 478 | - ((unsigned long)efi_phys.systab < | |
| 479 | - md->phys_addr + | |
| 480 | - ((unsigned long)md->num_pages << | |
| 481 | - EFI_PAGE_SHIFT))) { | |
| 482 | - unsigned long addr; | |
| 483 | - | |
| 484 | - addr = md->virt_addr - md->phys_addr + | |
| 485 | - (unsigned long)efi_phys.systab; | |
| 486 | - efi.systab = (efi_system_table_t *)addr; | |
| 487 | - } | |
| 480 | + md->virt_addr = (unsigned long)ioremap(md->phys_addr, | |
| 481 | + md->num_pages << EFI_PAGE_SHIFT); | |
| 482 | + if (!(unsigned long)md->virt_addr) { | |
| 483 | + printk(KERN_ERR PFX "ioremap of 0x%lX failed\n", | |
| 484 | + (unsigned long)md->phys_addr); | |
| 488 | 485 | } |
| 486 | + /* update the virtual address of the EFI system table */ | |
| 487 | + check_range_for_systab(md); | |
| 489 | 488 | } |
| 490 | 489 | |
| 491 | 490 | if (!efi.systab) |
| 492 | 491 | BUG(); |
| 493 | 492 | |
| 494 | 493 | status = phys_efi_set_virtual_address_map( |
| 495 | - sizeof(efi_memory_desc_t) * memmap.nr_map, | |
| 496 | - sizeof(efi_memory_desc_t), | |
| 494 | + memmap.desc_size * memmap.nr_map, | |
| 495 | + memmap.desc_size, | |
| 497 | 496 | memmap.desc_version, |
| 498 | 497 | memmap.phys_map); |
| 499 | 498 | |
| 500 | 499 | |
| ... | ... | @@ -533,10 +532,10 @@ |
| 533 | 532 | { |
| 534 | 533 | struct resource *res; |
| 535 | 534 | efi_memory_desc_t *md; |
| 536 | - int i; | |
| 535 | + void *p; | |
| 537 | 536 | |
| 538 | - for (i = 0; i < memmap.nr_map; i++) { | |
| 539 | - md = &memmap.map[i]; | |
| 537 | + for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { | |
| 538 | + md = p; | |
| 540 | 539 | |
| 541 | 540 | if ((md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT)) > |
| 542 | 541 | 0x100000000ULL) |
| 543 | 542 | |
| ... | ... | @@ -613,10 +612,10 @@ |
| 613 | 612 | u32 efi_mem_type(unsigned long phys_addr) |
| 614 | 613 | { |
| 615 | 614 | efi_memory_desc_t *md; |
| 616 | - int i; | |
| 615 | + void *p; | |
| 617 | 616 | |
| 618 | - for (i = 0; i < memmap.nr_map; i++) { | |
| 619 | - md = &memmap.map[i]; | |
| 617 | + for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { | |
| 618 | + md = p; | |
| 620 | 619 | if ((md->phys_addr <= phys_addr) && (phys_addr < |
| 621 | 620 | (md->phys_addr + (md-> num_pages << EFI_PAGE_SHIFT)) )) |
| 622 | 621 | return md->type; |
| 623 | 622 | |
| ... | ... | @@ -627,10 +626,10 @@ |
| 627 | 626 | u64 efi_mem_attributes(unsigned long phys_addr) |
| 628 | 627 | { |
| 629 | 628 | efi_memory_desc_t *md; |
| 630 | - int i; | |
| 629 | + void *p; | |
| 631 | 630 | |
| 632 | - for (i = 0; i < memmap.nr_map; i++) { | |
| 633 | - md = &memmap.map[i]; | |
| 631 | + for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { | |
| 632 | + md = p; | |
| 634 | 633 | if ((md->phys_addr <= phys_addr) && (phys_addr < |
| 635 | 634 | (md->phys_addr + (md-> num_pages << EFI_PAGE_SHIFT)) )) |
| 636 | 635 | return md->attribute; |
arch/i386/kernel/setup.c
| ... | ... | @@ -370,12 +370,16 @@ |
| 370 | 370 | int i; |
| 371 | 371 | |
| 372 | 372 | if (efi_enabled) { |
| 373 | - for (i = 0; i < memmap.nr_map; i++) { | |
| 374 | - current_addr = memmap.map[i].phys_addr + | |
| 375 | - (memmap.map[i].num_pages << 12); | |
| 376 | - if (memmap.map[i].type == EFI_CONVENTIONAL_MEMORY) { | |
| 373 | + efi_memory_desc_t *md; | |
| 374 | + void *p; | |
| 375 | + | |
| 376 | + for (p = memmap.map, i = 0; p < memmap.map_end; | |
| 377 | + p += memmap.desc_size, i++) { | |
| 378 | + md = p; | |
| 379 | + current_addr = md->phys_addr + (md->num_pages << 12); | |
| 380 | + if (md->type == EFI_CONVENTIONAL_MEMORY) { | |
| 377 | 381 | if (current_addr >= size) { |
| 378 | - memmap.map[i].num_pages -= | |
| 382 | + md->num_pages -= | |
| 379 | 383 | (((current_addr-size) + PAGE_SIZE-1) >> PAGE_SHIFT); |
| 380 | 384 | memmap.nr_map = i + 1; |
| 381 | 385 | return; |
arch/i386/mm/init.c
| ... | ... | @@ -198,9 +198,10 @@ |
| 198 | 198 | |
| 199 | 199 | if (efi_enabled) { |
| 200 | 200 | efi_memory_desc_t *md; |
| 201 | + void *p; | |
| 201 | 202 | |
| 202 | - for (i = 0; i < memmap.nr_map; i++) { | |
| 203 | - md = &memmap.map[i]; | |
| 203 | + for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { | |
| 204 | + md = p; | |
| 204 | 205 | if (!is_available_memory(md)) |
| 205 | 206 | continue; |
| 206 | 207 | addr = (md->phys_addr+PAGE_SIZE-1) >> PAGE_SHIFT; |
include/asm-i386/setup.h
| ... | ... | @@ -44,7 +44,7 @@ |
| 44 | 44 | #define EFI_SYSTAB ((efi_system_table_t *) *((unsigned long *)(PARAM+0x1c4))) |
| 45 | 45 | #define EFI_MEMDESC_SIZE (*((unsigned long *) (PARAM+0x1c8))) |
| 46 | 46 | #define EFI_MEMDESC_VERSION (*((unsigned long *) (PARAM+0x1cc))) |
| 47 | -#define EFI_MEMMAP ((efi_memory_desc_t *) *((unsigned long *)(PARAM+0x1d0))) | |
| 47 | +#define EFI_MEMMAP ((void *) *((unsigned long *)(PARAM+0x1d0))) | |
| 48 | 48 | #define EFI_MEMMAP_SIZE (*((unsigned long *) (PARAM+0x1d4))) |
| 49 | 49 | #define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2)) |
| 50 | 50 | #define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8)) |
include/linux/efi.h
| ... | ... | @@ -91,11 +91,6 @@ |
| 91 | 91 | |
| 92 | 92 | #define EFI_PAGE_SHIFT 12 |
| 93 | 93 | |
| 94 | -/* | |
| 95 | - * For current x86 implementations of EFI, there is | |
| 96 | - * additional padding in the mem descriptors. This is not | |
| 97 | - * the case in ia64. Need to have this fixed in the f/w. | |
| 98 | - */ | |
| 99 | 94 | typedef struct { |
| 100 | 95 | u32 type; |
| 101 | 96 | u32 pad; |
| ... | ... | @@ -103,9 +98,6 @@ |
| 103 | 98 | u64 virt_addr; |
| 104 | 99 | u64 num_pages; |
| 105 | 100 | u64 attribute; |
| 106 | -#if defined (__i386__) | |
| 107 | - u64 pad1; | |
| 108 | -#endif | |
| 109 | 101 | } efi_memory_desc_t; |
| 110 | 102 | |
| 111 | 103 | typedef int (*efi_freemem_callback_t) (unsigned long start, unsigned long end, void *arg); |
| 112 | 104 | |
| ... | ... | @@ -240,10 +232,12 @@ |
| 240 | 232 | } efi_system_table_t; |
| 241 | 233 | |
| 242 | 234 | struct efi_memory_map { |
| 243 | - efi_memory_desc_t *phys_map; | |
| 244 | - efi_memory_desc_t *map; | |
| 235 | + void *phys_map; | |
| 236 | + void *map; | |
| 237 | + void *map_end; | |
| 245 | 238 | int nr_map; |
| 246 | 239 | unsigned long desc_version; |
| 240 | + unsigned long desc_size; | |
| 247 | 241 | }; |
| 248 | 242 | |
| 249 | 243 | /* |