x86: Move efi to platform
authorThomas Gleixner <tglx@linutronix.de>
Sat, 16 Oct 2010 08:19:54 +0000 (10:19 +0200)
committerThomas Gleixner <tglx@linutronix.de>
Wed, 27 Oct 2010 12:30:01 +0000 (14:30 +0200)
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Huang Ying <ying.huang@intel.com>
13 files changed:
arch/x86/kernel/Makefile
arch/x86/kernel/efi.c [deleted file]
arch/x86/kernel/efi_32.c [deleted file]
arch/x86/kernel/efi_64.c [deleted file]
arch/x86/kernel/efi_stub_32.S [deleted file]
arch/x86/kernel/efi_stub_64.S [deleted file]
arch/x86/platform/Makefile
arch/x86/platform/efi/Makefile [new file with mode: 0644]
arch/x86/platform/efi/efi.c [new file with mode: 0644]
arch/x86/platform/efi/efi_32.c [new file with mode: 0644]
arch/x86/platform/efi/efi_64.c [new file with mode: 0644]
arch/x86/platform/efi/efi_stub_32.S [new file with mode: 0644]
arch/x86/platform/efi/efi_stub_64.S [new file with mode: 0644]

index d9067d10c6af49531c3f66a3c4523be2b558b242..b01c7b1ac1bab0dfb4ed41775a9a51eea465a8d5 100644 (file)
@@ -81,7 +81,6 @@ obj-$(CONFIG_KEXEC)           += relocate_kernel_$(BITS).o crash.o
 obj-$(CONFIG_CRASH_DUMP)       += crash_dump_$(BITS).o
 obj-$(CONFIG_KPROBES)          += kprobes.o
 obj-$(CONFIG_MODULES)          += module.o
-obj-$(CONFIG_EFI)              += efi.o efi_$(BITS).o efi_stub_$(BITS).o
 obj-$(CONFIG_DOUBLEFAULT)      += doublefault_32.o
 obj-$(CONFIG_KGDB)             += kgdb.o
 obj-$(CONFIG_VM86)             += vm86_32.o
diff --git a/arch/x86/kernel/efi.c b/arch/x86/kernel/efi.c
deleted file mode 100644 (file)
index 0fe27d7..0000000
+++ /dev/null
@@ -1,613 +0,0 @@
-/*
- * Common EFI (Extensible Firmware Interface) support functions
- * Based on Extensible Firmware Interface Specification version 1.0
- *
- * Copyright (C) 1999 VA Linux Systems
- * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
- * Copyright (C) 1999-2002 Hewlett-Packard Co.
- *     David Mosberger-Tang <davidm@hpl.hp.com>
- *     Stephane Eranian <eranian@hpl.hp.com>
- * Copyright (C) 2005-2008 Intel Co.
- *     Fenghua Yu <fenghua.yu@intel.com>
- *     Bibo Mao <bibo.mao@intel.com>
- *     Chandramouli Narayanan <mouli@linux.intel.com>
- *     Huang Ying <ying.huang@intel.com>
- *
- * Copied from efi_32.c to eliminate the duplicated code between EFI
- * 32/64 support code. --ying 2007-10-26
- *
- * All EFI Runtime Services are not implemented yet as EFI only
- * supports physical mode addressing on SoftSDV. This is to be fixed
- * in a future version.  --drummond 1999-07-20
- *
- * Implemented EFI runtime services and virtual mode calls.  --davidm
- *
- * Goutham Rao: <goutham.rao@intel.com>
- *     Skip non-WB memory and ignore empty memory ranges.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/efi.h>
-#include <linux/bootmem.h>
-#include <linux/memblock.h>
-#include <linux/spinlock.h>
-#include <linux/uaccess.h>
-#include <linux/time.h>
-#include <linux/io.h>
-#include <linux/reboot.h>
-#include <linux/bcd.h>
-
-#include <asm/setup.h>
-#include <asm/efi.h>
-#include <asm/time.h>
-#include <asm/cacheflush.h>
-#include <asm/tlbflush.h>
-#include <asm/x86_init.h>
-
-#define EFI_DEBUG      1
-#define PFX            "EFI: "
-
-int efi_enabled;
-EXPORT_SYMBOL(efi_enabled);
-
-struct efi efi;
-EXPORT_SYMBOL(efi);
-
-struct efi_memory_map memmap;
-
-static struct efi efi_phys __initdata;
-static efi_system_table_t efi_systab __initdata;
-
-static int __init setup_noefi(char *arg)
-{
-       efi_enabled = 0;
-       return 0;
-}
-early_param("noefi", setup_noefi);
-
-int add_efi_memmap;
-EXPORT_SYMBOL(add_efi_memmap);
-
-static int __init setup_add_efi_memmap(char *arg)
-{
-       add_efi_memmap = 1;
-       return 0;
-}
-early_param("add_efi_memmap", setup_add_efi_memmap);
-
-
-static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
-{
-       return efi_call_virt2(get_time, tm, tc);
-}
-
-static efi_status_t virt_efi_set_time(efi_time_t *tm)
-{
-       return efi_call_virt1(set_time, tm);
-}
-
-static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled,
-                                            efi_bool_t *pending,
-                                            efi_time_t *tm)
-{
-       return efi_call_virt3(get_wakeup_time,
-                             enabled, pending, tm);
-}
-
-static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
-{
-       return efi_call_virt2(set_wakeup_time,
-                             enabled, tm);
-}
-
-static efi_status_t virt_efi_get_variable(efi_char16_t *name,
-                                         efi_guid_t *vendor,
-                                         u32 *attr,
-                                         unsigned long *data_size,
-                                         void *data)
-{
-       return efi_call_virt5(get_variable,
-                             name, vendor, attr,
-                             data_size, data);
-}
-
-static efi_status_t virt_efi_get_next_variable(unsigned long *name_size,
-                                              efi_char16_t *name,
-                                              efi_guid_t *vendor)
-{
-       return efi_call_virt3(get_next_variable,
-                             name_size, name, vendor);
-}
-
-static efi_status_t virt_efi_set_variable(efi_char16_t *name,
-                                         efi_guid_t *vendor,
-                                         unsigned long attr,
-                                         unsigned long data_size,
-                                         void *data)
-{
-       return efi_call_virt5(set_variable,
-                             name, vendor, attr,
-                             data_size, data);
-}
-
-static efi_status_t virt_efi_get_next_high_mono_count(u32 *count)
-{
-       return efi_call_virt1(get_next_high_mono_count, count);
-}
-
-static void virt_efi_reset_system(int reset_type,
-                                 efi_status_t status,
-                                 unsigned long data_size,
-                                 efi_char16_t *data)
-{
-       efi_call_virt4(reset_system, reset_type, status,
-                      data_size, data);
-}
-
-static efi_status_t virt_efi_set_virtual_address_map(
-       unsigned long memory_map_size,
-       unsigned long descriptor_size,
-       u32 descriptor_version,
-       efi_memory_desc_t *virtual_map)
-{
-       return efi_call_virt4(set_virtual_address_map,
-                             memory_map_size, descriptor_size,
-                             descriptor_version, virtual_map);
-}
-
-static efi_status_t __init phys_efi_set_virtual_address_map(
-       unsigned long memory_map_size,
-       unsigned long descriptor_size,
-       u32 descriptor_version,
-       efi_memory_desc_t *virtual_map)
-{
-       efi_status_t status;
-
-       efi_call_phys_prelog();
-       status = efi_call_phys4(efi_phys.set_virtual_address_map,
-                               memory_map_size, descriptor_size,
-                               descriptor_version, virtual_map);
-       efi_call_phys_epilog();
-       return status;
-}
-
-static efi_status_t __init phys_efi_get_time(efi_time_t *tm,
-                                            efi_time_cap_t *tc)
-{
-       efi_status_t status;
-
-       efi_call_phys_prelog();
-       status = efi_call_phys2(efi_phys.get_time, tm, tc);
-       efi_call_phys_epilog();
-       return status;
-}
-
-int efi_set_rtc_mmss(unsigned long nowtime)
-{
-       int real_seconds, real_minutes;
-       efi_status_t    status;
-       efi_time_t      eft;
-       efi_time_cap_t  cap;
-
-       status = efi.get_time(&eft, &cap);
-       if (status != EFI_SUCCESS) {
-               printk(KERN_ERR "Oops: efitime: can't read time!\n");
-               return -1;
-       }
-
-       real_seconds = nowtime % 60;
-       real_minutes = nowtime / 60;
-       if (((abs(real_minutes - eft.minute) + 15)/30) & 1)
-               real_minutes += 30;
-       real_minutes %= 60;
-       eft.minute = real_minutes;
-       eft.second = real_seconds;
-
-       status = efi.set_time(&eft);
-       if (status != EFI_SUCCESS) {
-               printk(KERN_ERR "Oops: efitime: can't write time!\n");
-               return -1;
-       }
-       return 0;
-}
-
-unsigned long efi_get_time(void)
-{
-       efi_status_t status;
-       efi_time_t eft;
-       efi_time_cap_t cap;
-
-       status = efi.get_time(&eft, &cap);
-       if (status != EFI_SUCCESS)
-               printk(KERN_ERR "Oops: efitime: can't read time!\n");
-
-       return mktime(eft.year, eft.month, eft.day, eft.hour,
-                     eft.minute, eft.second);
-}
-
-/*
- * Tell the kernel about the EFI memory map.  This might include
- * more than the max 128 entries that can fit in the e820 legacy
- * (zeropage) memory map.
- */
-
-static void __init do_add_efi_memmap(void)
-{
-       void *p;
-
-       for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
-               efi_memory_desc_t *md = p;
-               unsigned long long start = md->phys_addr;
-               unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
-               int e820_type;
-
-               switch (md->type) {
-               case EFI_LOADER_CODE:
-               case EFI_LOADER_DATA:
-               case EFI_BOOT_SERVICES_CODE:
-               case EFI_BOOT_SERVICES_DATA:
-               case EFI_CONVENTIONAL_MEMORY:
-                       if (md->attribute & EFI_MEMORY_WB)
-                               e820_type = E820_RAM;
-                       else
-                               e820_type = E820_RESERVED;
-                       break;
-               case EFI_ACPI_RECLAIM_MEMORY:
-                       e820_type = E820_ACPI;
-                       break;
-               case EFI_ACPI_MEMORY_NVS:
-                       e820_type = E820_NVS;
-                       break;
-               case EFI_UNUSABLE_MEMORY:
-                       e820_type = E820_UNUSABLE;
-                       break;
-               default:
-                       /*
-                        * EFI_RESERVED_TYPE EFI_RUNTIME_SERVICES_CODE
-                        * EFI_RUNTIME_SERVICES_DATA EFI_MEMORY_MAPPED_IO
-                        * EFI_MEMORY_MAPPED_IO_PORT_SPACE EFI_PAL_CODE
-                        */
-                       e820_type = E820_RESERVED;
-                       break;
-               }
-               e820_add_region(start, size, e820_type);
-       }
-       sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
-}
-
-void __init efi_memblock_x86_reserve_range(void)
-{
-       unsigned long pmap;
-
-#ifdef CONFIG_X86_32
-       pmap = boot_params.efi_info.efi_memmap;
-#else
-       pmap = (boot_params.efi_info.efi_memmap |
-               ((__u64)boot_params.efi_info.efi_memmap_hi<<32));
-#endif
-       memmap.phys_map = (void *)pmap;
-       memmap.nr_map = boot_params.efi_info.efi_memmap_size /
-               boot_params.efi_info.efi_memdesc_size;
-       memmap.desc_version = boot_params.efi_info.efi_memdesc_version;
-       memmap.desc_size = boot_params.efi_info.efi_memdesc_size;
-       memblock_x86_reserve_range(pmap, pmap + memmap.nr_map * memmap.desc_size,
-                     "EFI memmap");
-}
-
-#if EFI_DEBUG
-static void __init print_efi_memmap(void)
-{
-       efi_memory_desc_t *md;
-       void *p;
-       int i;
-
-       for (p = memmap.map, i = 0;
-            p < memmap.map_end;
-            p += memmap.desc_size, i++) {
-               md = p;
-               printk(KERN_INFO PFX "mem%02u: type=%u, attr=0x%llx, "
-                       "range=[0x%016llx-0x%016llx) (%lluMB)\n",
-                       i, md->type, md->attribute, md->phys_addr,
-                       md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT),
-                       (md->num_pages >> (20 - EFI_PAGE_SHIFT)));
-       }
-}
-#endif  /*  EFI_DEBUG  */
-
-void __init efi_init(void)
-{
-       efi_config_table_t *config_tables;
-       efi_runtime_services_t *runtime;
-       efi_char16_t *c16;
-       char vendor[100] = "unknown";
-       int i = 0;
-       void *tmp;
-
-#ifdef CONFIG_X86_32
-       efi_phys.systab = (efi_system_table_t *)boot_params.efi_info.efi_systab;
-#else
-       efi_phys.systab = (efi_system_table_t *)
-               (boot_params.efi_info.efi_systab |
-                ((__u64)boot_params.efi_info.efi_systab_hi<<32));
-#endif
-
-       efi.systab = early_ioremap((unsigned long)efi_phys.systab,
-                                  sizeof(efi_system_table_t));
-       if (efi.systab == NULL)
-               printk(KERN_ERR "Couldn't map the EFI system table!\n");
-       memcpy(&efi_systab, efi.systab, sizeof(efi_system_table_t));
-       early_iounmap(efi.systab, sizeof(efi_system_table_t));
-       efi.systab = &efi_systab;
-
-       /*
-        * Verify the EFI Table
-        */
-       if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
-               printk(KERN_ERR "EFI system table signature incorrect!\n");
-       if ((efi.systab->hdr.revision >> 16) == 0)
-               printk(KERN_ERR "Warning: EFI system table version "
-                      "%d.%02d, expected 1.00 or greater!\n",
-                      efi.systab->hdr.revision >> 16,
-                      efi.systab->hdr.revision & 0xffff);
-
-       /*
-        * Show what we know for posterity
-        */
-       c16 = tmp = early_ioremap(efi.systab->fw_vendor, 2);
-       if (c16) {
-               for (i = 0; i < sizeof(vendor) - 1 && *c16; ++i)
-                       vendor[i] = *c16++;
-               vendor[i] = '\0';
-       } else
-               printk(KERN_ERR PFX "Could not map the firmware vendor!\n");
-       early_iounmap(tmp, 2);
-
-       printk(KERN_INFO "EFI v%u.%.02u by %s\n",
-              efi.systab->hdr.revision >> 16,
-              efi.systab->hdr.revision & 0xffff, vendor);
-
-       /*
-        * Let's see what config tables the firmware passed to us.
-        */
-       config_tables = early_ioremap(
-               efi.systab->tables,
-               efi.systab->nr_tables * sizeof(efi_config_table_t));
-       if (config_tables == NULL)
-               printk(KERN_ERR "Could not map EFI Configuration Table!\n");
-
-       printk(KERN_INFO);
-       for (i = 0; i < efi.systab->nr_tables; i++) {
-               if (!efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID)) {
-                       efi.mps = config_tables[i].table;
-                       printk(" MPS=0x%lx ", config_tables[i].table);
-               } else if (!efi_guidcmp(config_tables[i].guid,
-                                       ACPI_20_TABLE_GUID)) {
-                       efi.acpi20 = config_tables[i].table;
-                       printk(" ACPI 2.0=0x%lx ", config_tables[i].table);
-               } else if (!efi_guidcmp(config_tables[i].guid,
-                                       ACPI_TABLE_GUID)) {
-                       efi.acpi = config_tables[i].table;
-                       printk(" ACPI=0x%lx ", config_tables[i].table);
-               } else if (!efi_guidcmp(config_tables[i].guid,
-                                       SMBIOS_TABLE_GUID)) {
-                       efi.smbios = config_tables[i].table;
-                       printk(" SMBIOS=0x%lx ", config_tables[i].table);
-#ifdef CONFIG_X86_UV
-               } else if (!efi_guidcmp(config_tables[i].guid,
-                                       UV_SYSTEM_TABLE_GUID)) {
-                       efi.uv_systab = config_tables[i].table;
-                       printk(" UVsystab=0x%lx ", config_tables[i].table);
-#endif
-               } else if (!efi_guidcmp(config_tables[i].guid,
-                                       HCDP_TABLE_GUID)) {
-                       efi.hcdp = config_tables[i].table;
-                       printk(" HCDP=0x%lx ", config_tables[i].table);
-               } else if (!efi_guidcmp(config_tables[i].guid,
-                                       UGA_IO_PROTOCOL_GUID)) {
-                       efi.uga = config_tables[i].table;
-                       printk(" UGA=0x%lx ", config_tables[i].table);
-               }
-       }
-       printk("\n");
-       early_iounmap(config_tables,
-                         efi.systab->nr_tables * sizeof(efi_config_table_t));
-
-       /*
-        * Check out the runtime services table. We need to map
-        * the runtime services table so that we can grab the physical
-        * address of several of the EFI runtime functions, needed to
-        * set the firmware into virtual mode.
-        */
-       runtime = early_ioremap((unsigned long)efi.systab->runtime,
-                               sizeof(efi_runtime_services_t));
-       if (runtime != NULL) {
-               /*
-                * We will only need *early* access to the following
-                * two EFI runtime services before set_virtual_address_map
-                * is invoked.
-                */
-               efi_phys.get_time = (efi_get_time_t *)runtime->get_time;
-               efi_phys.set_virtual_address_map =
-                       (efi_set_virtual_address_map_t *)
-                       runtime->set_virtual_address_map;
-               /*
-                * Make efi_get_time can be called before entering
-                * virtual mode.
-                */
-               efi.get_time = phys_efi_get_time;
-       } else
-               printk(KERN_ERR "Could not map the EFI runtime service "
-                      "table!\n");
-       early_iounmap(runtime, sizeof(efi_runtime_services_t));
-
-       /* Map the EFI memory map */
-       memmap.map = early_ioremap((unsigned long)memmap.phys_map,
-                                  memmap.nr_map * memmap.desc_size);
-       if (memmap.map == NULL)
-               printk(KERN_ERR "Could not map the EFI memory map!\n");
-       memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size);
-
-       if (memmap.desc_size != sizeof(efi_memory_desc_t))
-               printk(KERN_WARNING
-                 "Kernel-defined memdesc doesn't match the one from EFI!\n");
-
-       if (add_efi_memmap)
-               do_add_efi_memmap();
-
-#ifdef CONFIG_X86_32
-       x86_platform.get_wallclock = efi_get_time;
-       x86_platform.set_wallclock = efi_set_rtc_mmss;
-#endif
-
-       /* Setup for EFI runtime service */
-       reboot_type = BOOT_EFI;
-
-#if EFI_DEBUG
-       print_efi_memmap();
-#endif
-}
-
-static void __init runtime_code_page_mkexec(void)
-{
-       efi_memory_desc_t *md;
-       void *p;
-       u64 addr, npages;
-
-       /* Make EFI runtime service code area executable */
-       for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
-               md = p;
-
-               if (md->type != EFI_RUNTIME_SERVICES_CODE)
-                       continue;
-
-               addr = md->virt_addr;
-               npages = md->num_pages;
-               memrange_efi_to_native(&addr, &npages);
-               set_memory_x(addr, npages);
-       }
-}
-
-/*
- * This function will switch the EFI runtime services to virtual mode.
- * Essentially, look through the EFI memmap and map every region that
- * has the runtime attribute bit set in its memory descriptor and update
- * that memory descriptor with the virtual address obtained from ioremap().
- * This enables the runtime services to be called without having to
- * thunk back into physical mode for every invocation.
- */
-void __init efi_enter_virtual_mode(void)
-{
-       efi_memory_desc_t *md;
-       efi_status_t status;
-       unsigned long size;
-       u64 end, systab, addr, npages, end_pfn;
-       void *p, *va;
-
-       efi.systab = NULL;
-       for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
-               md = p;
-               if (!(md->attribute & EFI_MEMORY_RUNTIME))
-                       continue;
-
-               size = md->num_pages << EFI_PAGE_SHIFT;
-               end = md->phys_addr + size;
-
-               end_pfn = PFN_UP(end);
-               if (end_pfn <= max_low_pfn_mapped
-                   || (end_pfn > (1UL << (32 - PAGE_SHIFT))
-                       && end_pfn <= max_pfn_mapped))
-                       va = __va(md->phys_addr);
-               else
-                       va = efi_ioremap(md->phys_addr, size, md->type);
-
-               md->virt_addr = (u64) (unsigned long) va;
-
-               if (!va) {
-                       printk(KERN_ERR PFX "ioremap of 0x%llX failed!\n",
-                              (unsigned long long)md->phys_addr);
-                       continue;
-               }
-
-               if (!(md->attribute & EFI_MEMORY_WB)) {
-                       addr = md->virt_addr;
-                       npages = md->num_pages;
-                       memrange_efi_to_native(&addr, &npages);
-                       set_memory_uc(addr, npages);
-               }
-
-               systab = (u64) (unsigned long) efi_phys.systab;
-               if (md->phys_addr <= systab && systab < end) {
-                       systab += md->virt_addr - md->phys_addr;
-                       efi.systab = (efi_system_table_t *) (unsigned long) systab;
-               }
-       }
-
-       BUG_ON(!efi.systab);
-
-       status = phys_efi_set_virtual_address_map(
-               memmap.desc_size * memmap.nr_map,
-               memmap.desc_size,
-               memmap.desc_version,
-               memmap.phys_map);
-
-       if (status != EFI_SUCCESS) {
-               printk(KERN_ALERT "Unable to switch EFI into virtual mode "
-                      "(status=%lx)!\n", status);
-               panic("EFI call to SetVirtualAddressMap() failed!");
-       }
-
-       /*
-        * Now that EFI is in virtual mode, update the function
-        * pointers in the runtime service table to the new virtual addresses.
-        *
-        * Call EFI services through wrapper functions.
-        */
-       efi.get_time = virt_efi_get_time;
-       efi.set_time = virt_efi_set_time;
-       efi.get_wakeup_time = virt_efi_get_wakeup_time;
-       efi.set_wakeup_time = virt_efi_set_wakeup_time;
-       efi.get_variable = virt_efi_get_variable;
-       efi.get_next_variable = virt_efi_get_next_variable;
-       efi.set_variable = virt_efi_set_variable;
-       efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
-       efi.reset_system = virt_efi_reset_system;
-       efi.set_virtual_address_map = virt_efi_set_virtual_address_map;
-       if (__supported_pte_mask & _PAGE_NX)
-               runtime_code_page_mkexec();
-       early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size);
-       memmap.map = NULL;
-}
-
-/*
- * Convenience functions to obtain memory types and attributes
- */
-u32 efi_mem_type(unsigned long phys_addr)
-{
-       efi_memory_desc_t *md;
-       void *p;
-
-       for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
-               md = p;
-               if ((md->phys_addr <= phys_addr) &&
-                   (phys_addr < (md->phys_addr +
-                                 (md->num_pages << EFI_PAGE_SHIFT))))
-                       return md->type;
-       }
-       return 0;
-}
-
-u64 efi_mem_attributes(unsigned long phys_addr)
-{
-       efi_memory_desc_t *md;
-       void *p;
-
-       for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
-               md = p;
-               if ((md->phys_addr <= phys_addr) &&
-                   (phys_addr < (md->phys_addr +
-                                 (md->num_pages << EFI_PAGE_SHIFT))))
-                       return md->attribute;
-       }
-       return 0;
-}
diff --git a/arch/x86/kernel/efi_32.c b/arch/x86/kernel/efi_32.c
deleted file mode 100644 (file)
index 5cab48e..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Extensible Firmware Interface
- *
- * Based on Extensible Firmware Interface Specification version 1.0
- *
- * Copyright (C) 1999 VA Linux Systems
- * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
- * Copyright (C) 1999-2002 Hewlett-Packard Co.
- *     David Mosberger-Tang <davidm@hpl.hp.com>
- *     Stephane Eranian <eranian@hpl.hp.com>
- *
- * All EFI Runtime Services are not implemented yet as EFI only
- * supports physical mode addressing on SoftSDV. This is to be fixed
- * in a future version.  --drummond 1999-07-20
- *
- * Implemented EFI runtime services and virtual mode calls.  --davidm
- *
- * Goutham Rao: <goutham.rao@intel.com>
- *     Skip non-WB memory and ignore empty memory ranges.
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/ioport.h>
-#include <linux/efi.h>
-
-#include <asm/io.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/tlbflush.h>
-#include <asm/efi.h>
-
-/*
- * To make EFI call EFI runtime service in physical addressing mode we need
- * prelog/epilog before/after the invocation to disable interrupt, to
- * claim EFI runtime service handler exclusively and to duplicate a memory in
- * low memory space say 0 - 3G.
- */
-
-static unsigned long efi_rt_eflags;
-static pgd_t efi_bak_pg_dir_pointer[2];
-
-void efi_call_phys_prelog(void)
-{
-       unsigned long cr4;
-       unsigned long temp;
-       struct desc_ptr gdt_descr;
-
-       local_irq_save(efi_rt_eflags);
-
-       /*
-        * If I don't have PAE, I should just duplicate two entries in page
-        * directory. If I have PAE, I just need to duplicate one entry in
-        * page directory.
-        */
-       cr4 = read_cr4_safe();
-
-       if (cr4 & X86_CR4_PAE) {
-               efi_bak_pg_dir_pointer[0].pgd =
-                   swapper_pg_dir[pgd_index(0)].pgd;
-               swapper_pg_dir[0].pgd =
-                   swapper_pg_dir[pgd_index(PAGE_OFFSET)].pgd;
-       } else {
-               efi_bak_pg_dir_pointer[0].pgd =
-                   swapper_pg_dir[pgd_index(0)].pgd;
-               efi_bak_pg_dir_pointer[1].pgd =
-                   swapper_pg_dir[pgd_index(0x400000)].pgd;
-               swapper_pg_dir[pgd_index(0)].pgd =
-                   swapper_pg_dir[pgd_index(PAGE_OFFSET)].pgd;
-               temp = PAGE_OFFSET + 0x400000;
-               swapper_pg_dir[pgd_index(0x400000)].pgd =
-                   swapper_pg_dir[pgd_index(temp)].pgd;
-       }
-
-       /*
-        * After the lock is released, the original page table is restored.
-        */
-       __flush_tlb_all();
-
-       gdt_descr.address = __pa(get_cpu_gdt_table(0));
-       gdt_descr.size = GDT_SIZE - 1;
-       load_gdt(&gdt_descr);
-}
-
-void efi_call_phys_epilog(void)
-{
-       unsigned long cr4;
-       struct desc_ptr gdt_descr;
-
-       gdt_descr.address = (unsigned long)get_cpu_gdt_table(0);
-       gdt_descr.size = GDT_SIZE - 1;
-       load_gdt(&gdt_descr);
-
-       cr4 = read_cr4_safe();
-
-       if (cr4 & X86_CR4_PAE) {
-               swapper_pg_dir[pgd_index(0)].pgd =
-                   efi_bak_pg_dir_pointer[0].pgd;
-       } else {
-               swapper_pg_dir[pgd_index(0)].pgd =
-                   efi_bak_pg_dir_pointer[0].pgd;
-               swapper_pg_dir[pgd_index(0x400000)].pgd =
-                   efi_bak_pg_dir_pointer[1].pgd;
-       }
-
-       /*
-        * After the lock is released, the original page table is restored.
-        */
-       __flush_tlb_all();
-
-       local_irq_restore(efi_rt_eflags);
-}
diff --git a/arch/x86/kernel/efi_64.c b/arch/x86/kernel/efi_64.c
deleted file mode 100644 (file)
index ac0621a..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * x86_64 specific EFI support functions
- * Based on Extensible Firmware Interface Specification version 1.0
- *
- * Copyright (C) 2005-2008 Intel Co.
- *     Fenghua Yu <fenghua.yu@intel.com>
- *     Bibo Mao <bibo.mao@intel.com>
- *     Chandramouli Narayanan <mouli@linux.intel.com>
- *     Huang Ying <ying.huang@intel.com>
- *
- * Code to convert EFI to E820 map has been implemented in elilo bootloader
- * based on a EFI patch by Edgar Hucek. Based on the E820 map, the page table
- * is setup appropriately for EFI runtime code.
- * - mouli 06/14/2007.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/types.h>
-#include <linux/spinlock.h>
-#include <linux/bootmem.h>
-#include <linux/ioport.h>
-#include <linux/module.h>
-#include <linux/efi.h>
-#include <linux/uaccess.h>
-#include <linux/io.h>
-#include <linux/reboot.h>
-
-#include <asm/setup.h>
-#include <asm/page.h>
-#include <asm/e820.h>
-#include <asm/pgtable.h>
-#include <asm/tlbflush.h>
-#include <asm/proto.h>
-#include <asm/efi.h>
-#include <asm/cacheflush.h>
-#include <asm/fixmap.h>
-
-static pgd_t save_pgd __initdata;
-static unsigned long efi_flags __initdata;
-
-static void __init early_mapping_set_exec(unsigned long start,
-                                         unsigned long end,
-                                         int executable)
-{
-       unsigned long num_pages;
-
-       start &= PMD_MASK;
-       end = (end + PMD_SIZE - 1) & PMD_MASK;
-       num_pages = (end - start) >> PAGE_SHIFT;
-       if (executable)
-               set_memory_x((unsigned long)__va(start), num_pages);
-       else
-               set_memory_nx((unsigned long)__va(start), num_pages);
-}
-
-static void __init early_runtime_code_mapping_set_exec(int executable)
-{
-       efi_memory_desc_t *md;
-       void *p;
-
-       if (!(__supported_pte_mask & _PAGE_NX))
-               return;
-
-       /* Make EFI runtime service code area executable */
-       for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
-               md = p;
-               if (md->type == EFI_RUNTIME_SERVICES_CODE) {
-                       unsigned long end;
-                       end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
-                       early_mapping_set_exec(md->phys_addr, end, executable);
-               }
-       }
-}
-
-void __init efi_call_phys_prelog(void)
-{
-       unsigned long vaddress;
-
-       early_runtime_code_mapping_set_exec(1);
-       local_irq_save(efi_flags);
-       vaddress = (unsigned long)__va(0x0UL);
-       save_pgd = *pgd_offset_k(0x0UL);
-       set_pgd(pgd_offset_k(0x0UL), *pgd_offset_k(vaddress));
-       __flush_tlb_all();
-}
-
-void __init efi_call_phys_epilog(void)
-{
-       /*
-        * After the lock is released, the original page table is restored.
-        */
-       set_pgd(pgd_offset_k(0x0UL), save_pgd);
-       __flush_tlb_all();
-       local_irq_restore(efi_flags);
-       early_runtime_code_mapping_set_exec(0);
-}
-
-void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size,
-                                u32 type)
-{
-       unsigned long last_map_pfn;
-
-       if (type == EFI_MEMORY_MAPPED_IO)
-               return ioremap(phys_addr, size);
-
-       last_map_pfn = init_memory_mapping(phys_addr, phys_addr + size);
-       if ((last_map_pfn << PAGE_SHIFT) < phys_addr + size)
-               return NULL;
-
-       return (void __iomem *)__va(phys_addr);
-}
diff --git a/arch/x86/kernel/efi_stub_32.S b/arch/x86/kernel/efi_stub_32.S
deleted file mode 100644 (file)
index fbe66e6..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * EFI call stub for IA32.
- *
- * This stub allows us to make EFI calls in physical mode with interrupts
- * turned off.
- */
-
-#include <linux/linkage.h>
-#include <asm/page_types.h>
-
-/*
- * efi_call_phys(void *, ...) is a function with variable parameters.
- * All the callers of this function assure that all the parameters are 4-bytes.
- */
-
-/*
- * In gcc calling convention, EBX, ESP, EBP, ESI and EDI are all callee save.
- * So we'd better save all of them at the beginning of this function and restore
- * at the end no matter how many we use, because we can not assure EFI runtime
- * service functions will comply with gcc calling convention, too.
- */
-
-.text
-ENTRY(efi_call_phys)
-       /*
-        * 0. The function can only be called in Linux kernel. So CS has been
-        * set to 0x0010, DS and SS have been set to 0x0018. In EFI, I found
-        * the values of these registers are the same. And, the corresponding
-        * GDT entries are identical. So I will do nothing about segment reg
-        * and GDT, but change GDT base register in prelog and epilog.
-        */
-
-       /*
-        * 1. Now I am running with EIP = <physical address> + PAGE_OFFSET.
-        * But to make it smoothly switch from virtual mode to flat mode.
-        * The mapping of lower virtual memory has been created in prelog and
-        * epilog.
-        */
-       movl    $1f, %edx
-       subl    $__PAGE_OFFSET, %edx
-       jmp     *%edx
-1:
-
-       /*
-        * 2. Now on the top of stack is the return
-        * address in the caller of efi_call_phys(), then parameter 1,
-        * parameter 2, ..., param n. To make things easy, we save the return
-        * address of efi_call_phys in a global variable.
-        */
-       popl    %edx
-       movl    %edx, saved_return_addr
-       /* get the function pointer into ECX*/
-       popl    %ecx
-       movl    %ecx, efi_rt_function_ptr
-       movl    $2f, %edx
-       subl    $__PAGE_OFFSET, %edx
-       pushl   %edx
-
-       /*
-        * 3. Clear PG bit in %CR0.
-        */
-       movl    %cr0, %edx
-       andl    $0x7fffffff, %edx
-       movl    %edx, %cr0
-       jmp     1f
-1:
-
-       /*
-        * 4. Adjust stack pointer.
-        */
-       subl    $__PAGE_OFFSET, %esp
-
-       /*
-        * 5. Call the physical function.
-        */
-       jmp     *%ecx
-
-2:
-       /*
-        * 6. After EFI runtime service returns, control will return to
-        * following instruction. We'd better readjust stack pointer first.
-        */
-       addl    $__PAGE_OFFSET, %esp
-
-       /*
-        * 7. Restore PG bit
-        */
-       movl    %cr0, %edx
-       orl     $0x80000000, %edx
-       movl    %edx, %cr0
-       jmp     1f
-1:
-       /*
-        * 8. Now restore the virtual mode from flat mode by
-        * adding EIP with PAGE_OFFSET.
-        */
-       movl    $1f, %edx
-       jmp     *%edx
-1:
-
-       /*
-        * 9. Balance the stack. And because EAX contain the return value,
-        * we'd better not clobber it.
-        */
-       leal    efi_rt_function_ptr, %edx
-       movl    (%edx), %ecx
-       pushl   %ecx
-
-       /*
-        * 10. Push the saved return address onto the stack and return.
-        */
-       leal    saved_return_addr, %edx
-       movl    (%edx), %ecx
-       pushl   %ecx
-       ret
-ENDPROC(efi_call_phys)
-.previous
-
-.data
-saved_return_addr:
-       .long 0
-efi_rt_function_ptr:
-       .long 0
diff --git a/arch/x86/kernel/efi_stub_64.S b/arch/x86/kernel/efi_stub_64.S
deleted file mode 100644 (file)
index 4c07cca..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Function calling ABI conversion from Linux to EFI for x86_64
- *
- * Copyright (C) 2007 Intel Corp
- *     Bibo Mao <bibo.mao@intel.com>
- *     Huang Ying <ying.huang@intel.com>
- */
-
-#include <linux/linkage.h>
-
-#define SAVE_XMM                       \
-       mov %rsp, %rax;                 \
-       subq $0x70, %rsp;               \
-       and $~0xf, %rsp;                \
-       mov %rax, (%rsp);               \
-       mov %cr0, %rax;                 \
-       clts;                           \
-       mov %rax, 0x8(%rsp);            \
-       movaps %xmm0, 0x60(%rsp);       \
-       movaps %xmm1, 0x50(%rsp);       \
-       movaps %xmm2, 0x40(%rsp);       \
-       movaps %xmm3, 0x30(%rsp);       \
-       movaps %xmm4, 0x20(%rsp);       \
-       movaps %xmm5, 0x10(%rsp)
-
-#define RESTORE_XMM                    \
-       movaps 0x60(%rsp), %xmm0;       \
-       movaps 0x50(%rsp), %xmm1;       \
-       movaps 0x40(%rsp), %xmm2;       \
-       movaps 0x30(%rsp), %xmm3;       \
-       movaps 0x20(%rsp), %xmm4;       \
-       movaps 0x10(%rsp), %xmm5;       \
-       mov 0x8(%rsp), %rsi;            \
-       mov %rsi, %cr0;                 \
-       mov (%rsp), %rsp
-
-ENTRY(efi_call0)
-       SAVE_XMM
-       subq $32, %rsp
-       call *%rdi
-       addq $32, %rsp
-       RESTORE_XMM
-       ret
-ENDPROC(efi_call0)
-
-ENTRY(efi_call1)
-       SAVE_XMM
-       subq $32, %rsp
-       mov  %rsi, %rcx
-       call *%rdi
-       addq $32, %rsp
-       RESTORE_XMM
-       ret
-ENDPROC(efi_call1)
-
-ENTRY(efi_call2)
-       SAVE_XMM
-       subq $32, %rsp
-       mov  %rsi, %rcx
-       call *%rdi
-       addq $32, %rsp
-       RESTORE_XMM
-       ret
-ENDPROC(efi_call2)
-
-ENTRY(efi_call3)
-       SAVE_XMM
-       subq $32, %rsp
-       mov  %rcx, %r8
-       mov  %rsi, %rcx
-       call *%rdi
-       addq $32, %rsp
-       RESTORE_XMM
-       ret
-ENDPROC(efi_call3)
-
-ENTRY(efi_call4)
-       SAVE_XMM
-       subq $32, %rsp
-       mov %r8, %r9
-       mov %rcx, %r8
-       mov %rsi, %rcx
-       call *%rdi
-       addq $32, %rsp
-       RESTORE_XMM
-       ret
-ENDPROC(efi_call4)
-
-ENTRY(efi_call5)
-       SAVE_XMM
-       subq $48, %rsp
-       mov %r9, 32(%rsp)
-       mov %r8, %r9
-       mov %rcx, %r8
-       mov %rsi, %rcx
-       call *%rdi
-       addq $48, %rsp
-       RESTORE_XMM
-       ret
-ENDPROC(efi_call5)
-
-ENTRY(efi_call6)
-       SAVE_XMM
-       mov (%rsp), %rax
-       mov 8(%rax), %rax
-       subq $48, %rsp
-       mov %r9, 32(%rsp)
-       mov %rax, 40(%rsp)
-       mov %r8, %r9
-       mov %rcx, %r8
-       mov %rsi, %rcx
-       call *%rdi
-       addq $48, %rsp
-       RESTORE_XMM
-       ret
-ENDPROC(efi_call6)
index a964fa3c086858ee6a460073d89f40b5ab9651d3..99e95b32ae7dbba55bb8e4c441a5a7b26040fb3c 100644 (file)
@@ -1,2 +1,3 @@
 # Platform specific code goes here
+obj-y  += efi/
 obj-y  += sfi/
diff --git a/arch/x86/platform/efi/Makefile b/arch/x86/platform/efi/Makefile
new file mode 100644 (file)
index 0000000..73b8be0
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_EFI)              += efi.o efi_$(BITS).o efi_stub_$(BITS).o
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
new file mode 100644 (file)
index 0000000..0fe27d7
--- /dev/null
@@ -0,0 +1,613 @@
+/*
+ * Common EFI (Extensible Firmware Interface) support functions
+ * Based on Extensible Firmware Interface Specification version 1.0
+ *
+ * Copyright (C) 1999 VA Linux Systems
+ * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
+ * Copyright (C) 1999-2002 Hewlett-Packard Co.
+ *     David Mosberger-Tang <davidm@hpl.hp.com>
+ *     Stephane Eranian <eranian@hpl.hp.com>
+ * Copyright (C) 2005-2008 Intel Co.
+ *     Fenghua Yu <fenghua.yu@intel.com>
+ *     Bibo Mao <bibo.mao@intel.com>
+ *     Chandramouli Narayanan <mouli@linux.intel.com>
+ *     Huang Ying <ying.huang@intel.com>
+ *
+ * Copied from efi_32.c to eliminate the duplicated code between EFI
+ * 32/64 support code. --ying 2007-10-26
+ *
+ * All EFI Runtime Services are not implemented yet as EFI only
+ * supports physical mode addressing on SoftSDV. This is to be fixed
+ * in a future version.  --drummond 1999-07-20
+ *
+ * Implemented EFI runtime services and virtual mode calls.  --davidm
+ *
+ * Goutham Rao: <goutham.rao@intel.com>
+ *     Skip non-WB memory and ignore empty memory ranges.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/efi.h>
+#include <linux/bootmem.h>
+#include <linux/memblock.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/time.h>
+#include <linux/io.h>
+#include <linux/reboot.h>
+#include <linux/bcd.h>
+
+#include <asm/setup.h>
+#include <asm/efi.h>
+#include <asm/time.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+#include <asm/x86_init.h>
+
+#define EFI_DEBUG      1
+#define PFX            "EFI: "
+
+int efi_enabled;
+EXPORT_SYMBOL(efi_enabled);
+
+struct efi efi;
+EXPORT_SYMBOL(efi);
+
+struct efi_memory_map memmap;
+
+static struct efi efi_phys __initdata;
+static efi_system_table_t efi_systab __initdata;
+
+static int __init setup_noefi(char *arg)
+{
+       efi_enabled = 0;
+       return 0;
+}
+early_param("noefi", setup_noefi);
+
+int add_efi_memmap;
+EXPORT_SYMBOL(add_efi_memmap);
+
+static int __init setup_add_efi_memmap(char *arg)
+{
+       add_efi_memmap = 1;
+       return 0;
+}
+early_param("add_efi_memmap", setup_add_efi_memmap);
+
+
+static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
+{
+       return efi_call_virt2(get_time, tm, tc);
+}
+
+static efi_status_t virt_efi_set_time(efi_time_t *tm)
+{
+       return efi_call_virt1(set_time, tm);
+}
+
+static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled,
+                                            efi_bool_t *pending,
+                                            efi_time_t *tm)
+{
+       return efi_call_virt3(get_wakeup_time,
+                             enabled, pending, tm);
+}
+
+static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
+{
+       return efi_call_virt2(set_wakeup_time,
+                             enabled, tm);
+}
+
+static efi_status_t virt_efi_get_variable(efi_char16_t *name,
+                                         efi_guid_t *vendor,
+                                         u32 *attr,
+                                         unsigned long *data_size,
+                                         void *data)
+{
+       return efi_call_virt5(get_variable,
+                             name, vendor, attr,
+                             data_size, data);
+}
+
+static efi_status_t virt_efi_get_next_variable(unsigned long *name_size,
+                                              efi_char16_t *name,
+                                              efi_guid_t *vendor)
+{
+       return efi_call_virt3(get_next_variable,
+                             name_size, name, vendor);
+}
+
+static efi_status_t virt_efi_set_variable(efi_char16_t *name,
+                                         efi_guid_t *vendor,
+                                         unsigned long attr,
+                                         unsigned long data_size,
+                                         void *data)
+{
+       return efi_call_virt5(set_variable,
+                             name, vendor, attr,
+                             data_size, data);
+}
+
+static efi_status_t virt_efi_get_next_high_mono_count(u32 *count)
+{
+       return efi_call_virt1(get_next_high_mono_count, count);
+}
+
+static void virt_efi_reset_system(int reset_type,
+                                 efi_status_t status,
+                                 unsigned long data_size,
+                                 efi_char16_t *data)
+{
+       efi_call_virt4(reset_system, reset_type, status,
+                      data_size, data);
+}
+
+static efi_status_t virt_efi_set_virtual_address_map(
+       unsigned long memory_map_size,
+       unsigned long descriptor_size,
+       u32 descriptor_version,
+       efi_memory_desc_t *virtual_map)
+{
+       return efi_call_virt4(set_virtual_address_map,
+                             memory_map_size, descriptor_size,
+                             descriptor_version, virtual_map);
+}
+
+static efi_status_t __init phys_efi_set_virtual_address_map(
+       unsigned long memory_map_size,
+       unsigned long descriptor_size,
+       u32 descriptor_version,
+       efi_memory_desc_t *virtual_map)
+{
+       efi_status_t status;
+
+       efi_call_phys_prelog();
+       status = efi_call_phys4(efi_phys.set_virtual_address_map,
+                               memory_map_size, descriptor_size,
+                               descriptor_version, virtual_map);
+       efi_call_phys_epilog();
+       return status;
+}
+
+static efi_status_t __init phys_efi_get_time(efi_time_t *tm,
+                                            efi_time_cap_t *tc)
+{
+       efi_status_t status;
+
+       efi_call_phys_prelog();
+       status = efi_call_phys2(efi_phys.get_time, tm, tc);
+       efi_call_phys_epilog();
+       return status;
+}
+
+int efi_set_rtc_mmss(unsigned long nowtime)
+{
+       int real_seconds, real_minutes;
+       efi_status_t    status;
+       efi_time_t      eft;
+       efi_time_cap_t  cap;
+
+       status = efi.get_time(&eft, &cap);
+       if (status != EFI_SUCCESS) {
+               printk(KERN_ERR "Oops: efitime: can't read time!\n");
+               return -1;
+       }
+
+       real_seconds = nowtime % 60;
+       real_minutes = nowtime / 60;
+       if (((abs(real_minutes - eft.minute) + 15)/30) & 1)
+               real_minutes += 30;
+       real_minutes %= 60;
+       eft.minute = real_minutes;
+       eft.second = real_seconds;
+
+       status = efi.set_time(&eft);
+       if (status != EFI_SUCCESS) {
+               printk(KERN_ERR "Oops: efitime: can't write time!\n");
+               return -1;
+       }
+       return 0;
+}
+
+unsigned long efi_get_time(void)
+{
+       efi_status_t status;
+       efi_time_t eft;
+       efi_time_cap_t cap;
+
+       status = efi.get_time(&eft, &cap);
+       if (status != EFI_SUCCESS)
+               printk(KERN_ERR "Oops: efitime: can't read time!\n");
+
+       return mktime(eft.year, eft.month, eft.day, eft.hour,
+                     eft.minute, eft.second);
+}
+
+/*
+ * Tell the kernel about the EFI memory map.  This might include
+ * more than the max 128 entries that can fit in the e820 legacy
+ * (zeropage) memory map.
+ */
+
+static void __init do_add_efi_memmap(void)
+{
+       void *p;
+
+       for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+               efi_memory_desc_t *md = p;
+               unsigned long long start = md->phys_addr;
+               unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
+               int e820_type;
+
+               switch (md->type) {
+               case EFI_LOADER_CODE:
+               case EFI_LOADER_DATA:
+               case EFI_BOOT_SERVICES_CODE:
+               case EFI_BOOT_SERVICES_DATA:
+               case EFI_CONVENTIONAL_MEMORY:
+                       if (md->attribute & EFI_MEMORY_WB)
+                               e820_type = E820_RAM;
+                       else
+                               e820_type = E820_RESERVED;
+                       break;
+               case EFI_ACPI_RECLAIM_MEMORY:
+                       e820_type = E820_ACPI;
+                       break;
+               case EFI_ACPI_MEMORY_NVS:
+                       e820_type = E820_NVS;
+                       break;
+               case EFI_UNUSABLE_MEMORY:
+                       e820_type = E820_UNUSABLE;
+                       break;
+               default:
+                       /*
+                        * EFI_RESERVED_TYPE EFI_RUNTIME_SERVICES_CODE
+                        * EFI_RUNTIME_SERVICES_DATA EFI_MEMORY_MAPPED_IO
+                        * EFI_MEMORY_MAPPED_IO_PORT_SPACE EFI_PAL_CODE
+                        */
+                       e820_type = E820_RESERVED;
+                       break;
+               }
+               e820_add_region(start, size, e820_type);
+       }
+       sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
+}
+
+void __init efi_memblock_x86_reserve_range(void)
+{
+       unsigned long pmap;
+
+#ifdef CONFIG_X86_32
+       pmap = boot_params.efi_info.efi_memmap;
+#else
+       pmap = (boot_params.efi_info.efi_memmap |
+               ((__u64)boot_params.efi_info.efi_memmap_hi<<32));
+#endif
+       memmap.phys_map = (void *)pmap;
+       memmap.nr_map = boot_params.efi_info.efi_memmap_size /
+               boot_params.efi_info.efi_memdesc_size;
+       memmap.desc_version = boot_params.efi_info.efi_memdesc_version;
+       memmap.desc_size = boot_params.efi_info.efi_memdesc_size;
+       memblock_x86_reserve_range(pmap, pmap + memmap.nr_map * memmap.desc_size,
+                     "EFI memmap");
+}
+
+#if EFI_DEBUG
+static void __init print_efi_memmap(void)
+{
+       efi_memory_desc_t *md;
+       void *p;
+       int i;
+
+       for (p = memmap.map, i = 0;
+            p < memmap.map_end;
+            p += memmap.desc_size, i++) {
+               md = p;
+               printk(KERN_INFO PFX "mem%02u: type=%u, attr=0x%llx, "
+                       "range=[0x%016llx-0x%016llx) (%lluMB)\n",
+                       i, md->type, md->attribute, md->phys_addr,
+                       md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT),
+                       (md->num_pages >> (20 - EFI_PAGE_SHIFT)));
+       }
+}
+#endif  /*  EFI_DEBUG  */
+
+void __init efi_init(void)
+{
+       efi_config_table_t *config_tables;
+       efi_runtime_services_t *runtime;
+       efi_char16_t *c16;
+       char vendor[100] = "unknown";
+       int i = 0;
+       void *tmp;
+
+#ifdef CONFIG_X86_32
+       efi_phys.systab = (efi_system_table_t *)boot_params.efi_info.efi_systab;
+#else
+       efi_phys.systab = (efi_system_table_t *)
+               (boot_params.efi_info.efi_systab |
+                ((__u64)boot_params.efi_info.efi_systab_hi<<32));
+#endif
+
+       efi.systab = early_ioremap((unsigned long)efi_phys.systab,
+                                  sizeof(efi_system_table_t));
+       if (efi.systab == NULL)
+               printk(KERN_ERR "Couldn't map the EFI system table!\n");
+       memcpy(&efi_systab, efi.systab, sizeof(efi_system_table_t));
+       early_iounmap(efi.systab, sizeof(efi_system_table_t));
+       efi.systab = &efi_systab;
+
+       /*
+        * Verify the EFI Table
+        */
+       if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
+               printk(KERN_ERR "EFI system table signature incorrect!\n");
+       if ((efi.systab->hdr.revision >> 16) == 0)
+               printk(KERN_ERR "Warning: EFI system table version "
+                      "%d.%02d, expected 1.00 or greater!\n",
+                      efi.systab->hdr.revision >> 16,
+                      efi.systab->hdr.revision & 0xffff);
+
+       /*
+        * Show what we know for posterity
+        */
+       c16 = tmp = early_ioremap(efi.systab->fw_vendor, 2);
+       if (c16) {
+               for (i = 0; i < sizeof(vendor) - 1 && *c16; ++i)
+                       vendor[i] = *c16++;
+               vendor[i] = '\0';
+       } else
+               printk(KERN_ERR PFX "Could not map the firmware vendor!\n");
+       early_iounmap(tmp, 2);
+
+       printk(KERN_INFO "EFI v%u.%.02u by %s\n",
+              efi.systab->hdr.revision >> 16,
+              efi.systab->hdr.revision & 0xffff, vendor);
+
+       /*
+        * Let's see what config tables the firmware passed to us.
+        */
+       config_tables = early_ioremap(
+               efi.systab->tables,
+               efi.systab->nr_tables * sizeof(efi_config_table_t));
+       if (config_tables == NULL)
+               printk(KERN_ERR "Could not map EFI Configuration Table!\n");
+
+       printk(KERN_INFO);
+       for (i = 0; i < efi.systab->nr_tables; i++) {
+               if (!efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID)) {
+                       efi.mps = config_tables[i].table;
+                       printk(" MPS=0x%lx ", config_tables[i].table);
+               } else if (!efi_guidcmp(config_tables[i].guid,
+                                       ACPI_20_TABLE_GUID)) {
+                       efi.acpi20 = config_tables[i].table;
+                       printk(" ACPI 2.0=0x%lx ", config_tables[i].table);
+               } else if (!efi_guidcmp(config_tables[i].guid,
+                                       ACPI_TABLE_GUID)) {
+                       efi.acpi = config_tables[i].table;
+                       printk(" ACPI=0x%lx ", config_tables[i].table);
+               } else if (!efi_guidcmp(config_tables[i].guid,
+                                       SMBIOS_TABLE_GUID)) {
+                       efi.smbios = config_tables[i].table;
+                       printk(" SMBIOS=0x%lx ", config_tables[i].table);
+#ifdef CONFIG_X86_UV
+               } else if (!efi_guidcmp(config_tables[i].guid,
+                                       UV_SYSTEM_TABLE_GUID)) {
+                       efi.uv_systab = config_tables[i].table;
+                       printk(" UVsystab=0x%lx ", config_tables[i].table);
+#endif
+               } else if (!efi_guidcmp(config_tables[i].guid,
+                                       HCDP_TABLE_GUID)) {
+                       efi.hcdp = config_tables[i].table;
+                       printk(" HCDP=0x%lx ", config_tables[i].table);
+               } else if (!efi_guidcmp(config_tables[i].guid,
+                                       UGA_IO_PROTOCOL_GUID)) {
+                       efi.uga = config_tables[i].table;
+                       printk(" UGA=0x%lx ", config_tables[i].table);
+               }
+       }
+       printk("\n");
+       early_iounmap(config_tables,
+                         efi.systab->nr_tables * sizeof(efi_config_table_t));
+
+       /*
+        * Check out the runtime services table. We need to map
+        * the runtime services table so that we can grab the physical
+        * address of several of the EFI runtime functions, needed to
+        * set the firmware into virtual mode.
+        */
+       runtime = early_ioremap((unsigned long)efi.systab->runtime,
+                               sizeof(efi_runtime_services_t));
+       if (runtime != NULL) {
+               /*
+                * We will only need *early* access to the following
+                * two EFI runtime services before set_virtual_address_map
+                * is invoked.
+                */
+               efi_phys.get_time = (efi_get_time_t *)runtime->get_time;
+               efi_phys.set_virtual_address_map =
+                       (efi_set_virtual_address_map_t *)
+                       runtime->set_virtual_address_map;
+               /*
+                * Make efi_get_time can be called before entering
+                * virtual mode.
+                */
+               efi.get_time = phys_efi_get_time;
+       } else
+               printk(KERN_ERR "Could not map the EFI runtime service "
+                      "table!\n");
+       early_iounmap(runtime, sizeof(efi_runtime_services_t));
+
+       /* Map the EFI memory map */
+       memmap.map = early_ioremap((unsigned long)memmap.phys_map,
+                                  memmap.nr_map * memmap.desc_size);
+       if (memmap.map == NULL)
+               printk(KERN_ERR "Could not map the EFI memory map!\n");
+       memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size);
+
+       if (memmap.desc_size != sizeof(efi_memory_desc_t))
+               printk(KERN_WARNING
+                 "Kernel-defined memdesc doesn't match the one from EFI!\n");
+
+       if (add_efi_memmap)
+               do_add_efi_memmap();
+
+#ifdef CONFIG_X86_32
+       x86_platform.get_wallclock = efi_get_time;
+       x86_platform.set_wallclock = efi_set_rtc_mmss;
+#endif
+
+       /* Setup for EFI runtime service */
+       reboot_type = BOOT_EFI;
+
+#if EFI_DEBUG
+       print_efi_memmap();
+#endif
+}
+
+static void __init runtime_code_page_mkexec(void)
+{
+       efi_memory_desc_t *md;
+       void *p;
+       u64 addr, npages;
+
+       /* Make EFI runtime service code area executable */
+       for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+               md = p;
+
+               if (md->type != EFI_RUNTIME_SERVICES_CODE)
+                       continue;
+
+               addr = md->virt_addr;
+               npages = md->num_pages;
+               memrange_efi_to_native(&addr, &npages);
+               set_memory_x(addr, npages);
+       }
+}
+
+/*
+ * This function will switch the EFI runtime services to virtual mode.
+ * Essentially, look through the EFI memmap and map every region that
+ * has the runtime attribute bit set in its memory descriptor and update
+ * that memory descriptor with the virtual address obtained from ioremap().
+ * This enables the runtime services to be called without having to
+ * thunk back into physical mode for every invocation.
+ */
+void __init efi_enter_virtual_mode(void)
+{
+       efi_memory_desc_t *md;
+       efi_status_t status;
+       unsigned long size;
+       u64 end, systab, addr, npages, end_pfn;
+       void *p, *va;
+
+       efi.systab = NULL;
+       for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+               md = p;
+               if (!(md->attribute & EFI_MEMORY_RUNTIME))
+                       continue;
+
+               size = md->num_pages << EFI_PAGE_SHIFT;
+               end = md->phys_addr + size;
+
+               end_pfn = PFN_UP(end);
+               if (end_pfn <= max_low_pfn_mapped
+                   || (end_pfn > (1UL << (32 - PAGE_SHIFT))
+                       && end_pfn <= max_pfn_mapped))
+                       va = __va(md->phys_addr);
+               else
+                       va = efi_ioremap(md->phys_addr, size, md->type);
+
+               md->virt_addr = (u64) (unsigned long) va;
+
+               if (!va) {
+                       printk(KERN_ERR PFX "ioremap of 0x%llX failed!\n",
+                              (unsigned long long)md->phys_addr);
+                       continue;
+               }
+
+               if (!(md->attribute & EFI_MEMORY_WB)) {
+                       addr = md->virt_addr;
+                       npages = md->num_pages;
+                       memrange_efi_to_native(&addr, &npages);
+                       set_memory_uc(addr, npages);
+               }
+
+               systab = (u64) (unsigned long) efi_phys.systab;
+               if (md->phys_addr <= systab && systab < end) {
+                       systab += md->virt_addr - md->phys_addr;
+                       efi.systab = (efi_system_table_t *) (unsigned long) systab;
+               }
+       }
+
+       BUG_ON(!efi.systab);
+
+       status = phys_efi_set_virtual_address_map(
+               memmap.desc_size * memmap.nr_map,
+               memmap.desc_size,
+               memmap.desc_version,
+               memmap.phys_map);
+
+       if (status != EFI_SUCCESS) {
+               printk(KERN_ALERT "Unable to switch EFI into virtual mode "
+                      "(status=%lx)!\n", status);
+               panic("EFI call to SetVirtualAddressMap() failed!");
+       }
+
+       /*
+        * Now that EFI is in virtual mode, update the function
+        * pointers in the runtime service table to the new virtual addresses.
+        *
+        * Call EFI services through wrapper functions.
+        */
+       efi.get_time = virt_efi_get_time;
+       efi.set_time = virt_efi_set_time;
+       efi.get_wakeup_time = virt_efi_get_wakeup_time;
+       efi.set_wakeup_time = virt_efi_set_wakeup_time;
+       efi.get_variable = virt_efi_get_variable;
+       efi.get_next_variable = virt_efi_get_next_variable;
+       efi.set_variable = virt_efi_set_variable;
+       efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
+       efi.reset_system = virt_efi_reset_system;
+       efi.set_virtual_address_map = virt_efi_set_virtual_address_map;
+       if (__supported_pte_mask & _PAGE_NX)
+               runtime_code_page_mkexec();
+       early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size);
+       memmap.map = NULL;
+}
+
+/*
+ * Convenience functions to obtain memory types and attributes
+ */
+u32 efi_mem_type(unsigned long phys_addr)
+{
+       efi_memory_desc_t *md;
+       void *p;
+
+       for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+               md = p;
+               if ((md->phys_addr <= phys_addr) &&
+                   (phys_addr < (md->phys_addr +
+                                 (md->num_pages << EFI_PAGE_SHIFT))))
+                       return md->type;
+       }
+       return 0;
+}
+
+u64 efi_mem_attributes(unsigned long phys_addr)
+{
+       efi_memory_desc_t *md;
+       void *p;
+
+       for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+               md = p;
+               if ((md->phys_addr <= phys_addr) &&
+                   (phys_addr < (md->phys_addr +
+                                 (md->num_pages << EFI_PAGE_SHIFT))))
+                       return md->attribute;
+       }
+       return 0;
+}
diff --git a/arch/x86/platform/efi/efi_32.c b/arch/x86/platform/efi/efi_32.c
new file mode 100644 (file)
index 0000000..5cab48e
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Extensible Firmware Interface
+ *
+ * Based on Extensible Firmware Interface Specification version 1.0
+ *
+ * Copyright (C) 1999 VA Linux Systems
+ * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
+ * Copyright (C) 1999-2002 Hewlett-Packard Co.
+ *     David Mosberger-Tang <davidm@hpl.hp.com>
+ *     Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * All EFI Runtime Services are not implemented yet as EFI only
+ * supports physical mode addressing on SoftSDV. This is to be fixed
+ * in a future version.  --drummond 1999-07-20
+ *
+ * Implemented EFI runtime services and virtual mode calls.  --davidm
+ *
+ * Goutham Rao: <goutham.rao@intel.com>
+ *     Skip non-WB memory and ignore empty memory ranges.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/efi.h>
+
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+#include <asm/efi.h>
+
+/*
+ * To make EFI call EFI runtime service in physical addressing mode we need
+ * prelog/epilog before/after the invocation to disable interrupt, to
+ * claim EFI runtime service handler exclusively and to duplicate a memory in
+ * low memory space say 0 - 3G.
+ */
+
+static unsigned long efi_rt_eflags;
+static pgd_t efi_bak_pg_dir_pointer[2];
+
+void efi_call_phys_prelog(void)
+{
+       unsigned long cr4;
+       unsigned long temp;
+       struct desc_ptr gdt_descr;
+
+       local_irq_save(efi_rt_eflags);
+
+       /*
+        * If I don't have PAE, I should just duplicate two entries in page
+        * directory. If I have PAE, I just need to duplicate one entry in
+        * page directory.
+        */
+       cr4 = read_cr4_safe();
+
+       if (cr4 & X86_CR4_PAE) {
+               efi_bak_pg_dir_pointer[0].pgd =
+                   swapper_pg_dir[pgd_index(0)].pgd;
+               swapper_pg_dir[0].pgd =
+                   swapper_pg_dir[pgd_index(PAGE_OFFSET)].pgd;
+       } else {
+               efi_bak_pg_dir_pointer[0].pgd =
+                   swapper_pg_dir[pgd_index(0)].pgd;
+               efi_bak_pg_dir_pointer[1].pgd =
+                   swapper_pg_dir[pgd_index(0x400000)].pgd;
+               swapper_pg_dir[pgd_index(0)].pgd =
+                   swapper_pg_dir[pgd_index(PAGE_OFFSET)].pgd;
+               temp = PAGE_OFFSET + 0x400000;
+               swapper_pg_dir[pgd_index(0x400000)].pgd =
+                   swapper_pg_dir[pgd_index(temp)].pgd;
+       }
+
+       /*
+        * After the lock is released, the original page table is restored.
+        */
+       __flush_tlb_all();
+
+       gdt_descr.address = __pa(get_cpu_gdt_table(0));
+       gdt_descr.size = GDT_SIZE - 1;
+       load_gdt(&gdt_descr);
+}
+
+void efi_call_phys_epilog(void)
+{
+       unsigned long cr4;
+       struct desc_ptr gdt_descr;
+
+       gdt_descr.address = (unsigned long)get_cpu_gdt_table(0);
+       gdt_descr.size = GDT_SIZE - 1;
+       load_gdt(&gdt_descr);
+
+       cr4 = read_cr4_safe();
+
+       if (cr4 & X86_CR4_PAE) {
+               swapper_pg_dir[pgd_index(0)].pgd =
+                   efi_bak_pg_dir_pointer[0].pgd;
+       } else {
+               swapper_pg_dir[pgd_index(0)].pgd =
+                   efi_bak_pg_dir_pointer[0].pgd;
+               swapper_pg_dir[pgd_index(0x400000)].pgd =
+                   efi_bak_pg_dir_pointer[1].pgd;
+       }
+
+       /*
+        * After the lock is released, the original page table is restored.
+        */
+       __flush_tlb_all();
+
+       local_irq_restore(efi_rt_eflags);
+}
diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c
new file mode 100644 (file)
index 0000000..ac0621a
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * x86_64 specific EFI support functions
+ * Based on Extensible Firmware Interface Specification version 1.0
+ *
+ * Copyright (C) 2005-2008 Intel Co.
+ *     Fenghua Yu <fenghua.yu@intel.com>
+ *     Bibo Mao <bibo.mao@intel.com>
+ *     Chandramouli Narayanan <mouli@linux.intel.com>
+ *     Huang Ying <ying.huang@intel.com>
+ *
+ * Code to convert EFI to E820 map has been implemented in elilo bootloader
+ * based on a EFI patch by Edgar Hucek. Based on the E820 map, the page table
+ * is setup appropriately for EFI runtime code.
+ * - mouli 06/14/2007.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/bootmem.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/efi.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/reboot.h>
+
+#include <asm/setup.h>
+#include <asm/page.h>
+#include <asm/e820.h>
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+#include <asm/proto.h>
+#include <asm/efi.h>
+#include <asm/cacheflush.h>
+#include <asm/fixmap.h>
+
+static pgd_t save_pgd __initdata;
+static unsigned long efi_flags __initdata;
+
+static void __init early_mapping_set_exec(unsigned long start,
+                                         unsigned long end,
+                                         int executable)
+{
+       unsigned long num_pages;
+
+       start &= PMD_MASK;
+       end = (end + PMD_SIZE - 1) & PMD_MASK;
+       num_pages = (end - start) >> PAGE_SHIFT;
+       if (executable)
+               set_memory_x((unsigned long)__va(start), num_pages);
+       else
+               set_memory_nx((unsigned long)__va(start), num_pages);
+}
+
+static void __init early_runtime_code_mapping_set_exec(int executable)
+{
+       efi_memory_desc_t *md;
+       void *p;
+
+       if (!(__supported_pte_mask & _PAGE_NX))
+               return;
+
+       /* Make EFI runtime service code area executable */
+       for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+               md = p;
+               if (md->type == EFI_RUNTIME_SERVICES_CODE) {
+                       unsigned long end;
+                       end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
+                       early_mapping_set_exec(md->phys_addr, end, executable);
+               }
+       }
+}
+
+void __init efi_call_phys_prelog(void)
+{
+       unsigned long vaddress;
+
+       early_runtime_code_mapping_set_exec(1);
+       local_irq_save(efi_flags);
+       vaddress = (unsigned long)__va(0x0UL);
+       save_pgd = *pgd_offset_k(0x0UL);
+       set_pgd(pgd_offset_k(0x0UL), *pgd_offset_k(vaddress));
+       __flush_tlb_all();
+}
+
+void __init efi_call_phys_epilog(void)
+{
+       /*
+        * After the lock is released, the original page table is restored.
+        */
+       set_pgd(pgd_offset_k(0x0UL), save_pgd);
+       __flush_tlb_all();
+       local_irq_restore(efi_flags);
+       early_runtime_code_mapping_set_exec(0);
+}
+
+void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size,
+                                u32 type)
+{
+       unsigned long last_map_pfn;
+
+       if (type == EFI_MEMORY_MAPPED_IO)
+               return ioremap(phys_addr, size);
+
+       last_map_pfn = init_memory_mapping(phys_addr, phys_addr + size);
+       if ((last_map_pfn << PAGE_SHIFT) < phys_addr + size)
+               return NULL;
+
+       return (void __iomem *)__va(phys_addr);
+}
diff --git a/arch/x86/platform/efi/efi_stub_32.S b/arch/x86/platform/efi/efi_stub_32.S
new file mode 100644 (file)
index 0000000..fbe66e6
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * EFI call stub for IA32.
+ *
+ * This stub allows us to make EFI calls in physical mode with interrupts
+ * turned off.
+ */
+
+#include <linux/linkage.h>
+#include <asm/page_types.h>
+
+/*
+ * efi_call_phys(void *, ...) is a function with variable parameters.
+ * All the callers of this function assure that all the parameters are 4-bytes.
+ */
+
+/*
+ * In gcc calling convention, EBX, ESP, EBP, ESI and EDI are all callee save.
+ * So we'd better save all of them at the beginning of this function and restore
+ * at the end no matter how many we use, because we can not assure EFI runtime
+ * service functions will comply with gcc calling convention, too.
+ */
+
+.text
+ENTRY(efi_call_phys)
+       /*
+        * 0. The function can only be called in Linux kernel. So CS has been
+        * set to 0x0010, DS and SS have been set to 0x0018. In EFI, I found
+        * the values of these registers are the same. And, the corresponding
+        * GDT entries are identical. So I will do nothing about segment reg
+        * and GDT, but change GDT base register in prelog and epilog.
+        */
+
+       /*
+        * 1. Now I am running with EIP = <physical address> + PAGE_OFFSET.
+        * But to make it smoothly switch from virtual mode to flat mode.
+        * The mapping of lower virtual memory has been created in prelog and
+        * epilog.
+        */
+       movl    $1f, %edx
+       subl    $__PAGE_OFFSET, %edx
+       jmp     *%edx
+1:
+
+       /*
+        * 2. Now on the top of stack is the return
+        * address in the caller of efi_call_phys(), then parameter 1,
+        * parameter 2, ..., param n. To make things easy, we save the return
+        * address of efi_call_phys in a global variable.
+        */
+       popl    %edx
+       movl    %edx, saved_return_addr
+       /* get the function pointer into ECX*/
+       popl    %ecx
+       movl    %ecx, efi_rt_function_ptr
+       movl    $2f, %edx
+       subl    $__PAGE_OFFSET, %edx
+       pushl   %edx
+
+       /*
+        * 3. Clear PG bit in %CR0.
+        */
+       movl    %cr0, %edx
+       andl    $0x7fffffff, %edx
+       movl    %edx, %cr0
+       jmp     1f
+1:
+
+       /*
+        * 4. Adjust stack pointer.
+        */
+       subl    $__PAGE_OFFSET, %esp
+
+       /*
+        * 5. Call the physical function.
+        */
+       jmp     *%ecx
+
+2:
+       /*
+        * 6. After EFI runtime service returns, control will return to
+        * following instruction. We'd better readjust stack pointer first.
+        */
+       addl    $__PAGE_OFFSET, %esp
+
+       /*
+        * 7. Restore PG bit
+        */
+       movl    %cr0, %edx
+       orl     $0x80000000, %edx
+       movl    %edx, %cr0
+       jmp     1f
+1:
+       /*
+        * 8. Now restore the virtual mode from flat mode by
+        * adding EIP with PAGE_OFFSET.
+        */
+       movl    $1f, %edx
+       jmp     *%edx
+1:
+
+       /*
+        * 9. Balance the stack. And because EAX contain the return value,
+        * we'd better not clobber it.
+        */
+       leal    efi_rt_function_ptr, %edx
+       movl    (%edx), %ecx
+       pushl   %ecx
+
+       /*
+        * 10. Push the saved return address onto the stack and return.
+        */
+       leal    saved_return_addr, %edx
+       movl    (%edx), %ecx
+       pushl   %ecx
+       ret
+ENDPROC(efi_call_phys)
+.previous
+
+.data
+saved_return_addr:
+       .long 0
+efi_rt_function_ptr:
+       .long 0
diff --git a/arch/x86/platform/efi/efi_stub_64.S b/arch/x86/platform/efi/efi_stub_64.S
new file mode 100644 (file)
index 0000000..4c07cca
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Function calling ABI conversion from Linux to EFI for x86_64
+ *
+ * Copyright (C) 2007 Intel Corp
+ *     Bibo Mao <bibo.mao@intel.com>
+ *     Huang Ying <ying.huang@intel.com>
+ */
+
+#include <linux/linkage.h>
+
+#define SAVE_XMM                       \
+       mov %rsp, %rax;                 \
+       subq $0x70, %rsp;               \
+       and $~0xf, %rsp;                \
+       mov %rax, (%rsp);               \
+       mov %cr0, %rax;                 \
+       clts;                           \
+       mov %rax, 0x8(%rsp);            \
+       movaps %xmm0, 0x60(%rsp);       \
+       movaps %xmm1, 0x50(%rsp);       \
+       movaps %xmm2, 0x40(%rsp);       \
+       movaps %xmm3, 0x30(%rsp);       \
+       movaps %xmm4, 0x20(%rsp);       \
+       movaps %xmm5, 0x10(%rsp)
+
+#define RESTORE_XMM                    \
+       movaps 0x60(%rsp), %xmm0;       \
+       movaps 0x50(%rsp), %xmm1;       \
+       movaps 0x40(%rsp), %xmm2;       \
+       movaps 0x30(%rsp), %xmm3;       \
+       movaps 0x20(%rsp), %xmm4;       \
+       movaps 0x10(%rsp), %xmm5;       \
+       mov 0x8(%rsp), %rsi;            \
+       mov %rsi, %cr0;                 \
+       mov (%rsp), %rsp
+
+ENTRY(efi_call0)
+       SAVE_XMM
+       subq $32, %rsp
+       call *%rdi
+       addq $32, %rsp
+       RESTORE_XMM
+       ret
+ENDPROC(efi_call0)
+
+ENTRY(efi_call1)
+       SAVE_XMM
+       subq $32, %rsp
+       mov  %rsi, %rcx
+       call *%rdi
+       addq $32, %rsp
+       RESTORE_XMM
+       ret
+ENDPROC(efi_call1)
+
+ENTRY(efi_call2)
+       SAVE_XMM
+       subq $32, %rsp
+       mov  %rsi, %rcx
+       call *%rdi
+       addq $32, %rsp
+       RESTORE_XMM
+       ret
+ENDPROC(efi_call2)
+
+ENTRY(efi_call3)
+       SAVE_XMM
+       subq $32, %rsp
+       mov  %rcx, %r8
+       mov  %rsi, %rcx
+       call *%rdi
+       addq $32, %rsp
+       RESTORE_XMM
+       ret
+ENDPROC(efi_call3)
+
+ENTRY(efi_call4)
+       SAVE_XMM
+       subq $32, %rsp
+       mov %r8, %r9
+       mov %rcx, %r8
+       mov %rsi, %rcx
+       call *%rdi
+       addq $32, %rsp
+       RESTORE_XMM
+       ret
+ENDPROC(efi_call4)
+
+ENTRY(efi_call5)
+       SAVE_XMM
+       subq $48, %rsp
+       mov %r9, 32(%rsp)
+       mov %r8, %r9
+       mov %rcx, %r8
+       mov %rsi, %rcx
+       call *%rdi
+       addq $48, %rsp
+       RESTORE_XMM
+       ret
+ENDPROC(efi_call5)
+
+ENTRY(efi_call6)
+       SAVE_XMM
+       mov (%rsp), %rax
+       mov 8(%rax), %rax
+       subq $48, %rsp
+       mov %r9, 32(%rsp)
+       mov %rax, 40(%rsp)
+       mov %r8, %r9
+       mov %rcx, %r8
+       mov %rsi, %rcx
+       call *%rdi
+       addq $48, %rsp
+       RESTORE_XMM
+       ret
+ENDPROC(efi_call6)