fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / i386 / kernel / efi.c
index c9cad7b..8f9c624 100644 (file)
@@ -19,7 +19,6 @@
  *     Skip non-WB memory and ignore empty memory ranges.
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/mm.h>
@@ -66,7 +65,7 @@ static unsigned long efi_rt_eflags;
 static DEFINE_SPINLOCK(efi_rt_lock);
 static pgd_t efi_bak_pg_dir_pointer[2];
 
-static void efi_call_phys_prelog(void)
+static void efi_call_phys_prelog(void) __acquires(efi_rt_lock)
 {
        unsigned long cr4;
        unsigned long temp;
@@ -110,12 +109,12 @@ static void efi_call_phys_prelog(void)
        load_gdt(cpu_gdt_descr);
 }
 
-static void efi_call_phys_epilog(void)
+static void efi_call_phys_epilog(void) __releases(efi_rt_lock)
 {
        unsigned long cr4;
        struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, 0);
 
-       cpu_gdt_descr->address = __va(cpu_gdt_descr->address);
+       cpu_gdt_descr->address = (unsigned long)__va(cpu_gdt_descr->address);
        load_gdt(cpu_gdt_descr);
 
        cr4 = read_cr4();
@@ -195,17 +194,24 @@ inline int efi_set_rtc_mmss(unsigned long nowtime)
        return 0;
 }
 /*
- * This should only be used during kernel init and before runtime
- * services have been remapped, therefore, we'll need to call in physical
- * mode.  Note, this call isn't used later, so mark it __init.
+ * This is used during kernel init before runtime
+ * services have been remapped and also during suspend, therefore,
+ * we'll need to call both in physical and virtual modes.
  */
-inline unsigned long __init efi_get_time(void)
+inline unsigned long efi_get_time(void)
 {
        efi_status_t status;
        efi_time_t eft;
        efi_time_cap_t cap;
 
-       status = phys_efi_get_time(&eft, &cap);
+       if (efi.get_time) {
+               /* if we are in virtual mode use remapped function */
+               status = efi.get_time(&eft, &cap);
+       } else {
+               /* we are in physical mode */
+               status = phys_efi_get_time(&eft, &cap);
+       }
+
        if (status != EFI_SUCCESS)
                printk("Oops: efitime: can't read time status: 0x%lx\n",status);
 
@@ -361,7 +367,7 @@ void __init efi_init(void)
         */
        c16 = (efi_char16_t *) boot_ioremap(efi.systab->fw_vendor, 2);
        if (c16) {
-               for (i = 0; i < sizeof(vendor) && *c16; ++i)
+               for (i = 0; i < (sizeof(vendor) - 1) && *c16; ++i)
                        vendor[i] = *c16++;
                vendor[i] = '\0';
        } else
@@ -381,29 +387,38 @@ void __init efi_init(void)
        if (config_tables == NULL)
                printk(KERN_ERR PFX "Could not map EFI Configuration Table!\n");
 
+       efi.mps        = EFI_INVALID_TABLE_ADDR;
+       efi.acpi       = EFI_INVALID_TABLE_ADDR;
+       efi.acpi20     = EFI_INVALID_TABLE_ADDR;
+       efi.smbios     = EFI_INVALID_TABLE_ADDR;
+       efi.sal_systab = EFI_INVALID_TABLE_ADDR;
+       efi.boot_info  = EFI_INVALID_TABLE_ADDR;
+       efi.hcdp       = EFI_INVALID_TABLE_ADDR;
+       efi.uga        = EFI_INVALID_TABLE_ADDR;
+
        for (i = 0; i < num_config_tables; i++) {
                if (efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID) == 0) {
-                       efi.mps = (void *)config_tables[i].table;
+                       efi.mps = config_tables[i].table;
                        printk(KERN_INFO " MPS=0x%lx ", config_tables[i].table);
                } else
                    if (efi_guidcmp(config_tables[i].guid, ACPI_20_TABLE_GUID) == 0) {
-                       efi.acpi20 = __va(config_tables[i].table);
+                       efi.acpi20 = config_tables[i].table;
                        printk(KERN_INFO " ACPI 2.0=0x%lx ", config_tables[i].table);
                } else
                    if (efi_guidcmp(config_tables[i].guid, ACPI_TABLE_GUID) == 0) {
-                       efi.acpi = __va(config_tables[i].table);
+                       efi.acpi = config_tables[i].table;
                        printk(KERN_INFO " ACPI=0x%lx ", config_tables[i].table);
                } else
                    if (efi_guidcmp(config_tables[i].guid, SMBIOS_TABLE_GUID) == 0) {
-                       efi.smbios = (void *) config_tables[i].table;
+                       efi.smbios = config_tables[i].table;
                        printk(KERN_INFO " SMBIOS=0x%lx ", config_tables[i].table);
                } else
                    if (efi_guidcmp(config_tables[i].guid, HCDP_TABLE_GUID) == 0) {
-                       efi.hcdp = (void *)config_tables[i].table;
+                       efi.hcdp = config_tables[i].table;
                        printk(KERN_INFO " HCDP=0x%lx ", config_tables[i].table);
                } else
                    if (efi_guidcmp(config_tables[i].guid, UGA_IO_PROTOCOL_GUID) == 0) {
-                       efi.uga = (void *)config_tables[i].table;
+                       efi.uga = config_tables[i].table;
                        printk(KERN_INFO " UGA=0x%lx ", config_tables[i].table);
                }
        }
@@ -457,6 +472,70 @@ static inline void __init check_range_for_systab(efi_memory_desc_t *md)
        }
 }
 
+/*
+ * Wrap all the virtual calls in a way that forces the parameters on the stack.
+ */
+
+#define efi_call_virt(f, args...) \
+     ((efi_##f##_t __attribute__((regparm(0)))*)efi.systab->runtime->f)(args)
+
+static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
+{
+       return efi_call_virt(get_time, tm, tc);
+}
+
+static efi_status_t virt_efi_set_time (efi_time_t *tm)
+{
+       return efi_call_virt(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_virt(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_virt(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_virt(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_virt(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_virt(set_variable, name, vendor, attr, data_size, data);
+}
+
+static efi_status_t virt_efi_get_next_high_mono_count (u32 *count)
+{
+       return efi_call_virt(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_virt(reset_system, reset_type, status, data_size, data);
+}
+
 /*
  * This function will switch the EFI runtime services to virtual mode.
  * Essentially, look through the EFI memmap and map every region that
@@ -490,8 +569,7 @@ void __init efi_enter_virtual_mode(void)
                check_range_for_systab(md);
        }
 
-       if (!efi.systab)
-               BUG();
+       BUG_ON(!efi.systab);
 
        status = phys_efi_set_virtual_address_map(
                        memmap.desc_size * memmap.nr_map,
@@ -511,22 +589,15 @@ void __init efi_enter_virtual_mode(void)
         * pointers in the runtime service table to the new virtual addresses.
         */
 
-       efi.get_time = (efi_get_time_t *) efi.systab->runtime->get_time;
-       efi.set_time = (efi_set_time_t *) efi.systab->runtime->set_time;
-       efi.get_wakeup_time = (efi_get_wakeup_time_t *)
-                                       efi.systab->runtime->get_wakeup_time;
-       efi.set_wakeup_time = (efi_set_wakeup_time_t *)
-                                       efi.systab->runtime->set_wakeup_time;
-       efi.get_variable = (efi_get_variable_t *)
-                                       efi.systab->runtime->get_variable;
-       efi.get_next_variable = (efi_get_next_variable_t *)
-                                       efi.systab->runtime->get_next_variable;
-       efi.set_variable = (efi_set_variable_t *)
-                                       efi.systab->runtime->set_variable;
-       efi.get_next_high_mono_count = (efi_get_next_high_mono_count_t *)
-                                       efi.systab->runtime->get_next_high_mono_count;
-       efi.reset_system = (efi_reset_system_t *)
-                                       efi.systab->runtime->reset_system;
+       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;
 }
 
 void __init
@@ -543,7 +614,7 @@ efi_initialize_iomem_resources(struct resource *code_resource,
                if ((md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT)) >
                    0x100000000ULL)
                        continue;
-               res = alloc_bootmem_low(sizeof(struct resource));
+               res = kzalloc(sizeof(struct resource), GFP_ATOMIC);
                switch (md->type) {
                case EFI_RESERVED_TYPE:
                        res->name = "Reserved Memory";
@@ -592,8 +663,10 @@ efi_initialize_iomem_resources(struct resource *code_resource,
                res->end = res->start + ((md->num_pages << EFI_PAGE_SHIFT) - 1);
                res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
                if (request_resource(&iomem_resource, res) < 0)
-                       printk(KERN_ERR PFX "Failed to allocate res %s : 0x%lx-0x%lx\n",
-                               res->name, res->start, res->end);
+                       printk(KERN_ERR PFX "Failed to allocate res %s : "
+                               "0x%llx-0x%llx\n", res->name,
+                               (unsigned long long)res->start,
+                               (unsigned long long)res->end);
                /*
                 * We don't know which region contains kernel data so we try
                 * it repeatedly and let the resource manager test it.