[PATCH 1/4 -v5] x86_64 EFI runtime service support: EFI basic runtime service support

2007-10-29 Thread Huang, Ying
This patch adds basic runtime services support for EFI x86_64
system. The main file of the patch is the addition of efi_64.c for
x86_64. This file is modeled after the EFI IA32 avatar. EFI runtime
services initialization are implemented in efi_64.c. Some x86_64
specifics are worth noting here. On x86_64, parameters passed to EFI
firmware services need to follow the EFI calling convention. For this
purpose, a set of functions named efi_call ( is the number of
parameters) are implemented. EFI function calls are wrapped before
calling the firmware service. The duplicated code between efi_32.c and
efi_64.c is placed in efi.c to remove them from efi_32.c.

Signed-off-by: Chandramouli Narayanan <[EMAIL PROTECTED]>
Signed-off-by: Huang Ying <[EMAIL PROTECTED]>

---

 arch/x86/kernel/Makefile_64   |1 
 arch/x86/kernel/efi.c |  483 ++
 arch/x86/kernel/efi_64.c  |  181 +++
 arch/x86/kernel/efi_stub_64.S |   68 +
 arch/x86/kernel/setup_64.c|   17 +
 arch/x86_64/Kconfig   |   11 
 include/asm-x86/bootparam.h   |5 
 include/asm-x86/efi.h |   70 ++
 include/asm-x86/fixmap_64.h   |3 
 9 files changed, 836 insertions(+), 3 deletions(-)

Index: linux-2.6.24-rc1/arch/x86/kernel/efi_64.c
===
--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6.24-rc1/arch/x86/kernel/efi_64.c   2007-10-30 10:07:57.0 
+0800
@@ -0,0 +1,181 @@
+/*
+ * x86_64 specific EFI support functions
+ * Based on Extensible Firmware Interface Specification version 1.0
+ *
+ * Copyright (C) 2005-2008 Intel Co.
+ * Fenghua Yu <[EMAIL PROTECTED]>
+ * Bibo Mao <[EMAIL PROTECTED]>
+ * Chandramouli Narayanan <[EMAIL PROTECTED]>
+ * Huang Ying <[EMAIL PROTECTED]>
+ *
+ * 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 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+int efi_time __initdata;
+
+static pgd_t save_pgd __initdata;
+static unsigned long efi_flags __initdata;
+/* efi_lock protects efi physical mode call */
+static __initdata DEFINE_SPINLOCK(efi_lock);
+
+static int __init setup_noefi(char *arg)
+{
+   efi_enabled = 0;
+   return 0;
+}
+early_param("noefi", setup_noefi);
+
+static int __init setup_efi_time(char *arg)
+{
+   if (arg && !strcmp("on", arg))
+   efi_time = 1;
+   return 0;
+}
+early_param("efi_time", setup_efi_time);
+
+static void __init early_mapping_set_exec(unsigned long start,
+ unsigned long end,
+ int executable)
+{
+   pte_t *kpte;
+
+   while (start < end) {
+   kpte = lookup_address((unsigned long)__va(start));
+   BUG_ON(!kpte);
+   if (executable)
+   set_pte(kpte, pte_mkexec(*kpte));
+   else
+   set_pte(kpte, __pte((pte_val(*kpte) | _PAGE_NX) & \
+   __supported_pte_mask));
+   if (pte_huge(*kpte))
+   start = (start + PMD_SIZE) & PMD_MASK;
+   else
+   start = (start + PAGE_SIZE) & PAGE_MASK;
+   }
+}
+
+static void __init early_runtime_code_mapping_set_exec(int executable)
+{
+   efi_memory_desc_t *md;
+   void *p;
+
+   /* 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 << PAGE_SHIFT);
+   early_mapping_set_exec(md->phys_addr, end, executable);
+   }
+   }
+}
+
+void __init efi_call_phys_prelog(void) __acquires(efi_lock)
+{
+   unsigned long vaddress;
+
+   /*
+* Lock sequence is different from normal case because
+* efi_flags is global
+*/
+   spin_lock(_lock);
+   local_irq_save(efi_flags);
+   early_runtime_code_mapping_set_exec(1);
+   vaddress = (unsigned long)__va(0x0UL);
+   pgd_val(save_pgd) = pgd_val(*pgd_offset_k(0x0UL));
+   set_pgd(pgd_offset_k(0x0UL), *pgd_offset_k(vaddress));
+   global_flush_tlb();
+}
+
+void __init efi_call_phys_epilog(void) __releases(efi_lock)
+{
+   /*
+* After the lock is released, the original page table is restored.
+*/
+   set_pgd(pgd_offset_k(0x0UL), save_pgd);
+   early_runtime_code_mapping_set_exec(0);
+   

[PATCH 1/4 -v5] x86_64 EFI runtime service support: EFI basic runtime service support

2007-10-29 Thread Huang, Ying
This patch adds basic runtime services support for EFI x86_64
system. The main file of the patch is the addition of efi_64.c for
x86_64. This file is modeled after the EFI IA32 avatar. EFI runtime
services initialization are implemented in efi_64.c. Some x86_64
specifics are worth noting here. On x86_64, parameters passed to EFI
firmware services need to follow the EFI calling convention. For this
purpose, a set of functions named efi_callx (x is the number of
parameters) are implemented. EFI function calls are wrapped before
calling the firmware service. The duplicated code between efi_32.c and
efi_64.c is placed in efi.c to remove them from efi_32.c.

Signed-off-by: Chandramouli Narayanan [EMAIL PROTECTED]
Signed-off-by: Huang Ying [EMAIL PROTECTED]

---

 arch/x86/kernel/Makefile_64   |1 
 arch/x86/kernel/efi.c |  483 ++
 arch/x86/kernel/efi_64.c  |  181 +++
 arch/x86/kernel/efi_stub_64.S |   68 +
 arch/x86/kernel/setup_64.c|   17 +
 arch/x86_64/Kconfig   |   11 
 include/asm-x86/bootparam.h   |5 
 include/asm-x86/efi.h |   70 ++
 include/asm-x86/fixmap_64.h   |3 
 9 files changed, 836 insertions(+), 3 deletions(-)

Index: linux-2.6.24-rc1/arch/x86/kernel/efi_64.c
===
--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6.24-rc1/arch/x86/kernel/efi_64.c   2007-10-30 10:07:57.0 
+0800
@@ -0,0 +1,181 @@
+/*
+ * x86_64 specific EFI support functions
+ * Based on Extensible Firmware Interface Specification version 1.0
+ *
+ * Copyright (C) 2005-2008 Intel Co.
+ * Fenghua Yu [EMAIL PROTECTED]
+ * Bibo Mao [EMAIL PROTECTED]
+ * Chandramouli Narayanan [EMAIL PROTECTED]
+ * Huang Ying [EMAIL PROTECTED]
+ *
+ * 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/cacheflush.h
+#include asm/proto.h
+#include asm/efi.h
+
+int efi_time __initdata;
+
+static pgd_t save_pgd __initdata;
+static unsigned long efi_flags __initdata;
+/* efi_lock protects efi physical mode call */
+static __initdata DEFINE_SPINLOCK(efi_lock);
+
+static int __init setup_noefi(char *arg)
+{
+   efi_enabled = 0;
+   return 0;
+}
+early_param(noefi, setup_noefi);
+
+static int __init setup_efi_time(char *arg)
+{
+   if (arg  !strcmp(on, arg))
+   efi_time = 1;
+   return 0;
+}
+early_param(efi_time, setup_efi_time);
+
+static void __init early_mapping_set_exec(unsigned long start,
+ unsigned long end,
+ int executable)
+{
+   pte_t *kpte;
+
+   while (start  end) {
+   kpte = lookup_address((unsigned long)__va(start));
+   BUG_ON(!kpte);
+   if (executable)
+   set_pte(kpte, pte_mkexec(*kpte));
+   else
+   set_pte(kpte, __pte((pte_val(*kpte) | _PAGE_NX)  \
+   __supported_pte_mask));
+   if (pte_huge(*kpte))
+   start = (start + PMD_SIZE)  PMD_MASK;
+   else
+   start = (start + PAGE_SIZE)  PAGE_MASK;
+   }
+}
+
+static void __init early_runtime_code_mapping_set_exec(int executable)
+{
+   efi_memory_desc_t *md;
+   void *p;
+
+   /* 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  PAGE_SHIFT);
+   early_mapping_set_exec(md-phys_addr, end, executable);
+   }
+   }
+}
+
+void __init efi_call_phys_prelog(void) __acquires(efi_lock)
+{
+   unsigned long vaddress;
+
+   /*
+* Lock sequence is different from normal case because
+* efi_flags is global
+*/
+   spin_lock(efi_lock);
+   local_irq_save(efi_flags);
+   early_runtime_code_mapping_set_exec(1);
+   vaddress = (unsigned long)__va(0x0UL);
+   pgd_val(save_pgd) = pgd_val(*pgd_offset_k(0x0UL));
+   set_pgd(pgd_offset_k(0x0UL), *pgd_offset_k(vaddress));
+   global_flush_tlb();
+}
+
+void __init efi_call_phys_epilog(void)