Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Matt Tolentino and committed by
Linus Torvalds
7ae65fd3 4116c527

+67 -69
+50 -51
arch/i386/kernel/efi.c
··· 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, ··· 272 271 } prev, curr; 273 272 efi_memory_desc_t *md; 274 273 unsigned long start, end; 275 - int i; 274 + void *p; 276 275 277 - for (i = 0; i < memmap.nr_map; i++) { 278 - md = &memmap.map[i]; 276 + for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { 277 + md = p; 279 278 280 279 if ((md->num_pages == 0) || (!is_available_memory(md))) 281 280 continue; ··· 326 325 memmap.phys_map = EFI_MEMMAP; 327 326 memmap.nr_map = EFI_MEMMAP_SIZE/EFI_MEMDESC_SIZE; 328 327 memmap.desc_version = EFI_MEMDESC_VERSION; 328 + memmap.desc_size = EFI_MEMDESC_SIZE; 329 329 330 330 efi.systab = (efi_system_table_t *) 331 331 boot_ioremap((unsigned long) efi_phys.systab, ··· 430 428 printk(KERN_ERR PFX "Could not map the runtime service table!\n"); 431 429 432 430 /* Map the EFI memory map for use until paging_init() */ 433 - 434 - memmap.map = (efi_memory_desc_t *) 435 - boot_ioremap((unsigned long) EFI_MEMMAP, EFI_MEMMAP_SIZE); 436 - 431 + memmap.map = boot_ioremap((unsigned long) EFI_MEMMAP, EFI_MEMMAP_SIZE); 437 432 if (memmap.map == NULL) 438 433 printk(KERN_ERR PFX "Could not map the EFI memory map!\n"); 439 434 440 - if (EFI_MEMDESC_SIZE != sizeof(efi_memory_desc_t)) { 441 - printk(KERN_WARNING PFX "Warning! Kernel-defined memdesc doesn't " 442 - "match the one from EFI!\n"); 443 - } 435 + memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size); 436 + 444 437 #if EFI_DEBUG 445 438 print_efi_memmap(); 446 439 #endif 440 + } 441 + 442 + static inline void __init check_range_for_systab(efi_memory_desc_t *md) 443 + { 444 + if (((unsigned long)md->phys_addr <= (unsigned long)efi_phys.systab) && 445 + ((unsigned long)efi_phys.systab < md->phys_addr + 446 + ((unsigned long)md->num_pages << EFI_PAGE_SHIFT))) { 447 + unsigned long addr; 448 + 449 + addr = md->virt_addr - md->phys_addr + 450 + (unsigned long)efi_phys.systab; 451 + efi.systab = (efi_system_table_t *)addr; 452 + } 447 453 } 448 454 449 455 /* ··· 467 457 { 468 458 efi_memory_desc_t *md; 469 459 efi_status_t status; 470 - int i; 460 + void *p; 471 461 472 462 efi.systab = NULL; 473 463 474 - for (i = 0; i < memmap.nr_map; i++) { 475 - md = &memmap.map[i]; 464 + for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { 465 + md = p; 476 466 477 - if (md->attribute & EFI_MEMORY_RUNTIME) { 478 - md->virt_addr = 479 - (unsigned long)ioremap(md->phys_addr, 480 - md->num_pages << EFI_PAGE_SHIFT); 481 - if (!(unsigned long)md->virt_addr) { 482 - printk(KERN_ERR PFX "ioremap of 0x%lX failed\n", 483 - (unsigned long)md->phys_addr); 484 - } 467 + if (!(md->attribute & EFI_MEMORY_RUNTIME)) 468 + continue; 485 469 486 - if (((unsigned long)md->phys_addr <= 487 - (unsigned long)efi_phys.systab) && 488 - ((unsigned long)efi_phys.systab < 489 - md->phys_addr + 490 - ((unsigned long)md->num_pages << 491 - EFI_PAGE_SHIFT))) { 492 - unsigned long addr; 493 - 494 - addr = md->virt_addr - md->phys_addr + 495 - (unsigned long)efi_phys.systab; 496 - efi.systab = (efi_system_table_t *)addr; 497 - } 470 + md->virt_addr = (unsigned long)ioremap(md->phys_addr, 471 + md->num_pages << EFI_PAGE_SHIFT); 472 + if (!(unsigned long)md->virt_addr) { 473 + printk(KERN_ERR PFX "ioremap of 0x%lX failed\n", 474 + (unsigned long)md->phys_addr); 498 475 } 476 + /* update the virtual address of the EFI system table */ 477 + check_range_for_systab(md); 499 478 } 500 479 501 480 if (!efi.systab) 502 481 BUG(); 503 482 504 483 status = phys_efi_set_virtual_address_map( 505 - sizeof(efi_memory_desc_t) * memmap.nr_map, 506 - sizeof(efi_memory_desc_t), 484 + memmap.desc_size * memmap.nr_map, 485 + memmap.desc_size, 507 486 memmap.desc_version, 508 487 memmap.phys_map); 509 488 ··· 532 533 { 533 534 struct resource *res; 534 535 efi_memory_desc_t *md; 535 - int i; 536 + void *p; 536 537 537 - for (i = 0; i < memmap.nr_map; i++) { 538 - md = &memmap.map[i]; 538 + for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { 539 + md = p; 539 540 540 541 if ((md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT)) > 541 542 0x100000000ULL) ··· 612 613 u32 efi_mem_type(unsigned long phys_addr) 613 614 { 614 615 efi_memory_desc_t *md; 615 - int i; 616 + void *p; 616 617 617 - for (i = 0; i < memmap.nr_map; i++) { 618 - md = &memmap.map[i]; 618 + for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { 619 + md = p; 619 620 if ((md->phys_addr <= phys_addr) && (phys_addr < 620 621 (md->phys_addr + (md-> num_pages << EFI_PAGE_SHIFT)) )) 621 622 return md->type; ··· 626 627 u64 efi_mem_attributes(unsigned long phys_addr) 627 628 { 628 629 efi_memory_desc_t *md; 629 - int i; 630 + void *p; 630 631 631 - for (i = 0; i < memmap.nr_map; i++) { 632 - md = &memmap.map[i]; 632 + for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { 633 + md = p; 633 634 if ((md->phys_addr <= phys_addr) && (phys_addr < 634 635 (md->phys_addr + (md-> num_pages << EFI_PAGE_SHIFT)) )) 635 636 return md->attribute;
+9 -5
arch/i386/kernel/setup.c
··· 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;
+3 -2
arch/i386/mm/init.c
··· 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;
+1 -1
include/asm-i386/setup.h
··· 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))
+4 -10
include/linux/efi.h
··· 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; ··· 98 103 u64 virt_addr; 99 104 u64 num_pages; 100 105 u64 attribute; 101 - #if defined (__i386__) 102 - u64 pad1; 103 - #endif 104 106 } efi_memory_desc_t; 105 107 106 108 typedef int (*efi_freemem_callback_t) (unsigned long start, unsigned long end, void *arg); ··· 232 240 } efi_system_table_t; 233 241 234 242 struct efi_memory_map { 235 - efi_memory_desc_t *phys_map; 236 - efi_memory_desc_t *map; 243 + void *phys_map; 244 + void *map; 245 + void *map_end; 237 246 int nr_map; 238 247 unsigned long desc_version; 248 + unsigned long desc_size; 239 249 }; 240 250 241 251 /*