From: Edgar Hucek EFI is this other Intel brain-damage (the first one being ACPI). It's totally different from a normal BIOS, and was brought on by ia64, which never had a BIOS, of course. Sadly, Apple bought into the whole "BIOS bad, EFI good" hype, so we now have x86 machines with EFI as the native boot protocol. The original EFI code in the kernel basically duplicates all the BIOS interfaces (ie everything that looks at a memory map comes in two varieties: the normal and tested BIOS e820 variety, and the usually broken and hacked-up EFI memory map variety). Translating the EFI memory map to e820 is very much the sane thing to do, and should have been done by ia64 in the first place. Sadly, EFI people (a) think that their stinking mess is better than a BIOS and (b) are historically ia64-only, so they didn't do that, but went the "we'll just duplicate everything using our inferior EFI interfaces" way. [akpm@osdl.org: borrowed the changelog from Linus's comments] Signed-off-by: Edgar Hucek Signed-off-by: Andrew Morton --- arch/i386/kernel/setup.c | 79 ++++++++++++++++++++++++++++++------- 1 file changed, 66 insertions(+), 13 deletions(-) diff -puN arch/i386/kernel/setup.c~add-efi-e820-memory-mapping-on-x86 arch/i386/kernel/setup.c --- a/arch/i386/kernel/setup.c~add-efi-e820-memory-mapping-on-x86 +++ a/arch/i386/kernel/setup.c @@ -402,19 +402,17 @@ void __init add_memory_region(unsigned l { int x; - if (!efi_enabled) { - x = e820.nr_map; + x = e820.nr_map; - if (x == E820MAX) { - printk(KERN_ERR "Ooops! Too many entries in the memory map!\n"); - return; - } - - e820.map[x].addr = start; - e820.map[x].size = size; - e820.map[x].type = type; - e820.nr_map++; + if (x == E820MAX) { + printk(KERN_ERR "Ooops! Too many entries in the memory map!\n"); + return; } + + e820.map[x].addr = start; + e820.map[x].size = size; + e820.map[x].type = type; + e820.nr_map++; } /* add_memory_region */ #define E820_DEBUG 1 @@ -1321,6 +1319,59 @@ static void set_mca_bus(int x) { } #endif /* + * Make a e820 memory map + */ +void __init efi_init_e820_map(void) +{ + efi_memory_desc_t *md; + unsigned long long start = 0; + unsigned long long end = 0; + unsigned long long size = 0; + void *p; + + e820.nr_map = 0; + + for (p = memmap.map; p < memmap.map_end; + p += memmap.desc_size) { + md = p; + switch (md->type) { + case EFI_ACPI_RECLAIM_MEMORY: + add_memory_region(md->phys_addr, md->num_pages << EFI_PAGE_SHIFT, E820_ACPI); + break; + case EFI_RUNTIME_SERVICES_CODE: + case EFI_RUNTIME_SERVICES_DATA: + case EFI_RESERVED_TYPE: + case EFI_MEMORY_MAPPED_IO: + case EFI_MEMORY_MAPPED_IO_PORT_SPACE: + case EFI_UNUSABLE_MEMORY: + add_memory_region(md->phys_addr, md->num_pages << EFI_PAGE_SHIFT, E820_RESERVED); + break; + case EFI_LOADER_CODE: + case EFI_LOADER_DATA: + case EFI_BOOT_SERVICES_CODE: + case EFI_BOOT_SERVICES_DATA: + case EFI_CONVENTIONAL_MEMORY: + start = md->phys_addr; + size = md->num_pages << EFI_PAGE_SHIFT; + end = start + size; + if (start < 0x100000ULL && end > 0xA0000ULL) { + if (start < 0xA0000ULL) + add_memory_region(start, 0xA0000ULL-start, E820_RAM); + if (end <= 0x100000ULL) + continue; + start = 0x100000ULL; + size = end - start; + } + add_memory_region(start, size, E820_RAM); + break; + case EFI_ACPI_MEMORY_NVS: + add_memory_region(md->phys_addr, md->num_pages << EFI_PAGE_SHIFT, E820_NVS); + break; + } + } +} + +/* * Determine if we were loaded by an EFI loader. If so, then we have also been * passed the efi memmap, systab, etc., so we should use these data structures * for initialization. Note, the efi init code path is determined by the @@ -1368,9 +1419,11 @@ void __init setup_arch(char **cmdline_p) rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); #endif ARCH_SETUP - if (efi_enabled) + if (efi_enabled) { efi_init(); - else { + efi_init_e820_map(); + print_memory_map("BIOS-EFI"); + } else { printk(KERN_INFO "BIOS-provided physical RAM map:\n"); print_memory_map(machine_specific_memory_setup()); } _