Commit 7ae65fd334232468a9d6b523a4fc141cd6ec5ea4

Authored by Matt Tolentino
Committed by Linus Torvalds
1 parent 4116c527ea

[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;
... ... @@ -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))
... ... @@ -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 /*