Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 4179

kernel-2.6.18-194.11.1.el5.src.rpm

From: Brian Maly <bmaly@redhat.com>
Date: Thu, 20 Dec 2007 14:10:45 -0500
Subject: [x86_64] UEFI code support
Message-id: 476ABE35.8070406@redhat.com
O-Subject: Re: [RHEL5 patch] UEFI support for x86_64
Bugzilla: 253295
RH-Acked-by: Prarit Bhargava <prarit@redhat.com>
RH-Acked-by: Jeff Garzik <jgarzik@redhat.com>
RH-Acked-by: Jon Masters <jcm@redhat.com>

Brian Maly wrote:
> Don Zickus wrote:
>> On Wed, Dec 19, 2007 at 09:23:02AM -0500, Brian Maly wrote:
>>
>>> resolves BZ 253295
>>>
>>>
>>> This is a preliminary patch to add x86_64 UEFI support to the RHEL5
>>> kenel. It is preliminary state is because we dont yet have the hardware
>>> with UEFI enabled firmware which is needed for testing. There is some
>>> likelyhood that some additional bits of code may be required in addition
>>> to this patch being that this patch is a backport from a 2.6.21 patch.
>>> If this is the case I will followup with additional patches as required.
>>> Basic testing on non-UEFI hardware revealed no regressions.
>>> In the interim we will need to depend on vendor testing of UEFI until
>>> some enabled hardware arrives.
>>>
>>> There are some CONFIG options that are required:
>>> CONFIG_EFI=y
>>> CONFIG_FB_EFI=y
>>> CONFIG_EFI_VARS=y
>>> CONFIG_EFI_PARTITION=y
>>>
>>> Don, would you prefer a patch for the config files?
>>>
>>

diff --git a/Documentation/i386/zero-page.txt b/Documentation/i386/zero-page.txt
index c04a421..53d650e 100644
--- a/Documentation/i386/zero-page.txt
+++ b/Documentation/i386/zero-page.txt
@@ -31,11 +31,11 @@ Offset	Type		Description
  0xb0 - 0x13f		Free. Add more parameters here if you really need them.
  0x140- 0x1be		EDID_INFO Video mode setup
 
-0x1c4	unsigned long	EFI system table pointer
-0x1c8	unsigned long	EFI memory descriptor size
-0x1cc	unsigned long	EFI memory descriptor version
+0x1c4	unsigned long	EFI system table pointer*
+0x1c8	unsigned long	EFI memory descriptor size*
+0x1cc	unsigned long	EFI memory descriptor version*
 0x1d0	unsigned long	EFI memory descriptor map pointer
-0x1d4	unsigned long	EFI memory descriptor map size
+0x1d4	unsigned long	EFI memory descriptor map size*
 0x1e0	unsigned long	ALT_MEM_K, alternative mem check, in Kb
 0x1e8	char		number of entries in E820MAP (below)
 0x1e9	unsigned char	number of entries in EDDBUF (below)
@@ -86,3 +86,13 @@ Offset	Type		Description
 0x2d0 - 0xd00		E820MAP
 0xd00 - 0xeff		EDDBUF (edd.S) for disk signature read sector
 0xd00 - 0xeeb		EDDBUF (edd.S) for edd data
+
+Changes for x86_64 implementation:
+---------------------------------
+For alignment purposes, the following parameters are rearranged.
+
+0x1b8	unsigned long	EFI system table pointer
+0x1c0	unsigned long	EFI Loader signature
+0x1c4	unsigned long	EFI memory descriptor size
+0x1c8	unsigned long	EFI memory descriptor version
+0x1cc	unsigned long	EFI memory descriptor map size
diff --git a/Documentation/x86_64/uefi.txt b/Documentation/x86_64/uefi.txt
new file mode 100644
index 0000000..a4816af
--- /dev/null
+++ b/Documentation/x86_64/uefi.txt
@@ -0,0 +1,42 @@
+General note on [U]EFI x86_64 support
+-------------------------------------
+
+This provides documentation on [U]EFI support for x86_64 architecture.
+The nomenclature EFI and UEFI are used intechangeably in this document.
+
+Although the tools below are _not_ needed for building the kernel,
+the needed bootloader support and associated tools for x86_64 platforms
+with EFI firmware and specifications are listed below.
+
+1. UEFI specification:  http://www.uefi.org
+
+2. Booting EFI64 enabled kernel requires boot loader support.
+Patches to elilo and gnu-efi library with x86_64 support and documentation
+have been submitted to respective project maintainers.
+	elilo: http://sourceforge.net/projects/elilo
+	gnu-efi library: http://sourceforge.net/projects/gnu-efi/
+	gnu-efi-3.0d release now supports [U]EFI x86_64.
+
+3. The tool to convert ELF to PE-COFF image:
+	binutils-2.17.50.0.14 supports Intel64 EFI.
+	see http://www.kernel.org/pub/linux/devel/binutils/
+	[ elilo/gnu-efi with x86_64 support need this binutils support ]
+
+4. x86_64 platform with EFI/UEFI firmware.
+ 
+Mechanics:
+---------
+- Apply the EFI64 kernel patches and build with the following configuration.
+	CONFIG_EFI=y
+	EFI_FB=y
+	CONFIG_FRAMEBUFFER_CONSOLE=y
+	CONFIG_EFI_VARS=y
+  
+- Create a VFAT partition on the disk
+- Copy the following to the VFAT partition:
+	elilo bootloader with x86_64 support and elilo configuration file
+	efi64 kernel image and initrd. Instructions on building elilo
+	and its dependencies can be found in the elilo sourceforge project.
+- Boot to EFI shell and invoke elilo choosing efi64 kernel image
+- On UEFI2.0 firmware systems, pass vga=normal for boot messages to show up
+  console. You can pass along the 'resume' boot option to test suspend/resume.
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
index fe3be72..8aec979 100644
--- a/arch/x86_64/Kconfig
+++ b/arch/x86_64/Kconfig
@@ -218,6 +218,19 @@ config X86_HT
 	depends on SMP && !MK8 && !X86_64_XEN
 	default y
 
+config EFI
+	bool "Boot from EFI support (EXPERIMENTAL)"
+	---help---
+	  This enables the the kernel to boot on EFI platforms using
+	  system configuration information passed to it from the firmware.
+	  This also enables the kernel to use any EFI runtime services that are
+	  available (such as the EFI variable services).
+	  This option is only useful on systems that have EFI firmware
+	  and will result in a kernel image that is ~8k larger. However,
+	  even with this option, the resultant kernel should continue to
+	  boot on existing non-EFI platforms. For more information on
+	  how to set up [U]EFI64 system, see Documentation/x86_64/uefi.txt.
+
 config MATH_EMULATION
 	bool
 
diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile
index f6b0cf5..d5eeace 100644
--- a/arch/x86_64/kernel/Makefile
+++ b/arch/x86_64/kernel/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_X86_PM_TIMER)	+= pmtimer.o
 obj-$(CONFIG_X86_VSMP)		+= vsmp.o
 obj-$(CONFIG_K8_NB)		+= k8.o
 obj-$(CONFIG_AUDIT)		+= audit.o
+obj-$(CONFIG_EFI)              += efi.o efi_callwrap.o
 
 obj-$(CONFIG_MODULES)		+= module.o
 
diff --git a/arch/x86_64/kernel/aperture.c b/arch/x86_64/kernel/aperture.c
index d8a434c..d99c749 100644
--- a/arch/x86_64/kernel/aperture.c
+++ b/arch/x86_64/kernel/aperture.c
@@ -82,6 +82,10 @@ static int __init aperture_valid(u64 aper_base, u32 aper_size)
 		printk("Aperture pointing to e820 RAM. Ignoring.\n");
 		return 0; 
 	} 
+	if (e820_any_mapped(aper_base, aper_base + aper_size, E820_RUNTIME_CODE)) {
+		printk("Aperture pointing to runtime code. Ignoring.\n");
+		return 0; 
+	} 
 	return 1;
 } 
 
diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c
index 52b313c..54a777d 100644
--- a/arch/x86_64/kernel/e820.c
+++ b/arch/x86_64/kernel/e820.c
@@ -17,6 +17,7 @@
 #include <linux/kexec.h>
 #include <linux/module.h>
 #include <linux/mm.h>
+#include <linux/efi.h>
 
 #include <asm/pgtable.h>
 #include <asm/page.h>
@@ -278,6 +279,7 @@ void __init e820_reserve_resources(void)
 		case E820_RAM:	res->name = "System RAM"; break;
 		case E820_ACPI:	res->name = "ACPI Tables"; break;
 		case E820_NVS:	res->name = "ACPI Non-volatile Storage"; break;
+		case E820_RUNTIME_CODE:	res->name = "EFI runtime code"; break;
 		default:	res->name = "reserved";
 		}
 		res->start = e820.map[i].addr;
@@ -384,6 +386,9 @@ void __init e820_print_map(char *who)
 		case E820_NVS:
 				printk("(ACPI NVS)\n");
 				break;
+		case E820_RUNTIME_CODE:
+				printk("(runtime code)\n");
+				break;
 		default:	printk("type %u\n", e820.map[i].type);
 				break;
 		}
@@ -624,6 +629,8 @@ void __init setup_memory_region(void)
 	 * Otherwise fake a memory map; one section from 0k->640k,
 	 * the next section from 1mb->appropriate_mem_k
 	 */
+	if (efi_enabled)
+		efi_init();
 	sanitize_e820_map(E820_MAP, &E820_MAP_NR);
 	if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
 		unsigned long mem_size;
diff --git a/arch/x86_64/kernel/efi.c b/arch/x86_64/kernel/efi.c
new file mode 100644
index 0000000..6f9c4df
--- /dev/null
+++ b/arch/x86_64/kernel/efi.c
@@ -0,0 +1,531 @@
+/*
+ * 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>
+ * Copyright (C) 2005-2008 Intel Co.
+ *	Fenghua Yu <fenghua.yu@intel.com>
+ *	Bibo Mao <bibo.mao@intel.com>
+ *	Chandramouli Narayanan <mouli@linux.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. NDIS wrapper code from
+ * sourceforge project is adapted here for UEFI wrapper call.
+ * - mouli 06/14/2007.
+ * 
+ * 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/mm.h>
+#include <linux/types.h>
+#include <linux/time.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 <asm/setup.h>
+#include <asm/bootsetup.h>
+#include <asm/io.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-x86_64/eficallwrap.h>
+
+#define EFI_DEBUG	0
+#define PFX 		"EFI: "
+
+struct efi efi;
+EXPORT_SYMBOL(efi);
+
+extern void (*machine_emergency_restart_func)(void);
+
+struct efi efi_phys __initdata;
+struct efi_memory_map memmap;
+static efi_system_table_t efi_systab __initdata;
+
+static unsigned long efi_rt_eflags;
+/* efi_rt_lock protects efi physical mode call */
+static spinlock_t efi_rt_lock = SPIN_LOCK_UNLOCKED;
+static pgd_t save_pgd;
+
+static efi_status_t _efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
+{
+	return LIN2WIN2((void*)efi.systab->runtime->get_time,
+					(u64)tm,
+					(u64)tc); 
+}
+
+static efi_status_t _efi_set_time(efi_time_t *tm)
+{
+	return LIN2WIN1((void*)efi.systab->runtime->set_time,
+					(u64)tm); 
+}
+
+static efi_status_t _efi_get_wakeup_time(
+	efi_bool_t *enabled, efi_bool_t *pending, efi_time_t *tm)
+{
+	return LIN2WIN3((void*)efi.systab->runtime->get_wakeup_time,
+					(u64)enabled,
+					(u64)pending,
+					(u64)tm); 
+}
+
+static efi_status_t _efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
+{
+	return LIN2WIN2((void*)efi.systab->runtime->set_wakeup_time,
+					(u64)enabled,
+					(u64)tm); 
+}
+
+static efi_status_t _efi_get_variable(
+	efi_char16_t *name, efi_guid_t *vendor, u32 *attr,
+	unsigned long *data_size, void *data)
+{
+	return LIN2WIN5((void*)efi.systab->runtime->get_variable,
+					(u64)name,
+					(u64)vendor,
+					(u64)attr,
+					(u64)data_size,
+					(u64)data); 
+}
+
+static efi_status_t _efi_get_next_variable(
+	unsigned long *name_size, efi_char16_t *name, efi_guid_t *vendor)
+{
+	return LIN2WIN3((void*)efi.systab->runtime->get_next_variable,
+					(u64)name_size,
+					(u64)name,
+					(u64)vendor); 
+}
+
+static efi_status_t _efi_set_variable(
+			efi_char16_t *name, efi_guid_t *vendor,
+			u64 attr, u64 data_size, void *data)
+{
+	return LIN2WIN5((void*)efi.systab->runtime->set_variable,
+					(u64)name,
+					(u64)vendor,
+					(u64)attr,
+					(u64)data_size,
+					(u64)data); 
+}
+
+static efi_status_t _efi_get_next_high_mono_count(u32 *count)
+{
+	return LIN2WIN1((void*)efi.systab->runtime->get_next_high_mono_count,
+					(u64)count); 
+}
+
+static efi_status_t _efi_reset_system(
+			int reset_type, efi_status_t status,
+			unsigned long data_size, efi_char16_t *data)
+{
+	return LIN2WIN4((void*)efi.systab->runtime->reset_system,
+					(u64)reset_type,
+					(u64)status,
+					(u64)data_size,
+					(u64)data); 
+}
+
+static efi_status_t _efi_set_virtual_address_map(
+			unsigned long memory_map_size,
+			unsigned long descriptor_size,
+			u32 descriptor_version, efi_memory_desc_t *virtual_map)
+{
+	return LIN2WIN4((void*)efi.systab->runtime->set_virtual_address_map,
+					(u64)memory_map_size,
+					(u64)descriptor_size,
+					(u64)descriptor_version,
+					(u64)virtual_map); 
+}
+
+static void __init efi_call_phys_prelog(void) __acquires(efi_rt_lock)
+{
+	unsigned long vaddress;
+
+	spin_lock(&efi_rt_lock);
+	local_irq_save(efi_rt_eflags);
+
+	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();
+}
+
+static void __init efi_call_phys_epilog(void) __releases(efi_rt_lock)
+{
+	/*
+	 * After the lock is released, the original page table is restored.
+	 */
+	set_pgd(pgd_offset_k(0x0UL), save_pgd);
+	global_flush_tlb();
+	local_irq_restore(efi_rt_eflags);
+	spin_unlock(&efi_rt_lock);
+}
+
+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 = LIN2WIN4(efi_phys.set_virtual_address_map,
+					(u64)memory_map_size,
+					(u64)descriptor_size,
+					(u64)descriptor_version, 
+					(u64)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 = LIN2WIN2(efi_phys.get_time,
+					(u64)tm,
+					(u64)tc);
+	efi_call_phys_epilog();
+	return status;
+}
+
+inline 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;
+
+	spin_lock(&efi_rt_lock);
+	status = efi.get_time(&eft, &cap);
+	spin_unlock(&efi_rt_lock);
+	if (status != EFI_SUCCESS) {
+		printk(KERN_ERR PFX "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;
+
+	spin_lock(&efi_rt_lock);
+	status = efi.set_time(&eft);
+	spin_unlock(&efi_rt_lock);
+	if (status != EFI_SUCCESS) {
+		printk(KERN_ERR PFX "Oops: efitime: can't write time!\n");
+		return -1;
+	}
+	return 0;
+}
+/*
+ * 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 efi_get_time(void)
+{
+	efi_status_t status;
+	efi_time_t eft;
+	efi_time_cap_t 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(KERN_ERR PFX "Oops: efitime: can't read time status: 0x%lx\n",status);
+
+	return mktime(eft.year, eft.month, eft.day, eft.hour,
+			eft.minute, eft.second);
+}
+
+/*
+ * We need to map the EFI memory map again after paging_init().
+ */
+void __init efi_map_memmap(void)
+{
+	int i;
+
+	memmap.map = __va((unsigned long)memmap.phys_map);
+	memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size);
+
+	/* Make EFI runtime code area executable */
+	for (i = 0; i < e820.nr_map; i++) {
+		switch (e820.map[i].type) {
+		case E820_RUNTIME_CODE:
+			init_memory_mapping(
+				e820.map[i].addr,
+				e820.map[i].addr + e820.map[i].size);
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+/* Override function for emergency restart on EFI enabled systems */
+static void efi_emergency_restart(void)
+{
+	/* If EFI enabled, reset system through EFI protocol. */
+	efi.reset_system(EFI_RESET_WARM, EFI_SUCCESS, 0, NULL);
+	return;
+}
+
+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;
+
+	memset(&efi, 0, sizeof(efi) );
+	memset(&efi_phys, 0, sizeof(efi_phys));
+
+	efi_phys.systab = (efi_system_table_t *)EFI_SYSTAB;
+	memmap.phys_map = (void*)EFI_MEMMAP;
+	memmap.nr_map = EFI_MEMMAP_SIZE/EFI_MEMDESC_SIZE;
+	memmap.desc_version = EFI_MEMDESC_VERSION;
+	memmap.desc_size = EFI_MEMDESC_SIZE;
+
+	efi.systab = (efi_system_table_t *) early_ioremap(
+						(unsigned long)efi_phys.systab,
+						sizeof(efi_system_table_t));
+	memcpy(&efi_systab, 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 PFX "Woah! EFI system table signature incorrect\n");
+	if ((efi.systab->hdr.revision ^ EFI_SYSTEM_TABLE_REVISION) >> 16 != 0)
+		printk(KERN_ERR PFX
+		       "Warning: EFI system table major version mismatch: "
+		       "got %d.%02d, expected %d.%02d\n",
+		       efi.systab->hdr.revision >> 16,
+		       efi.systab->hdr.revision & 0xffff,
+		       EFI_SYSTEM_TABLE_REVISION >> 16,
+		       EFI_SYSTEM_TABLE_REVISION & 0xffff);
+	/*
+	 * Grab some details from the system table
+	 */
+	config_tables = (efi_config_table_t *)efi.systab->tables;
+	runtime = efi.systab->runtime;
+
+	/*
+	 * Show what we know for posterity
+	 */
+	c16 = (efi_char16_t *) early_ioremap(efi.systab->fw_vendor, 2);
+	if (!probe_kernel_address(c16, i)) {
+		for (i = 0; i < sizeof(vendor) && *c16; ++i) 
+			vendor[i] = *c16++;
+		vendor[i] = '\0';
+	}
+
+	printk(KERN_INFO PFX "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 = (efi_config_table_t *)early_ioremap( efi.systab->tables,
+			        efi.systab->nr_tables * sizeof(efi_config_table_t));
+	if (config_tables == NULL)
+		printk(KERN_ERR PFX "Could not map EFI Configuration Table!\n");
+
+	for (i = 0; i < efi.systab->nr_tables; i++) {
+		if (efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID) == 0) {
+			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 = 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 = 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 = 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 = 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 = config_tables[i].table;
+			printk(KERN_INFO " UGA=0x%lx ", config_tables[i].table);
+		}
+	}
+	printk(KERN_INFO "\n");
+
+	/*
+	 * 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 = (efi_runtime_services_t *) 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;
+	} else
+		printk(KERN_ERR PFX "Could not map the runtime service table!\n");
+	/* Map the EFI memory map for use until paging_init() */
+	memmap.map = (efi_memory_desc_t *) early_ioremap(
+					(unsigned long) EFI_MEMMAP,
+					 EFI_MEMMAP_SIZE);
+	if (memmap.map == NULL)
+		printk(KERN_ERR PFX "Could not map the EFI memory map!\n");
+        if (EFI_MEMDESC_SIZE != sizeof(efi_memory_desc_t)) {
+                printk(KERN_WARNING PFX "Kernel-defined memdesc" 
+			"doesn't match the one from EFI!\n");
+        }
+	memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size);
+	/* Override the emergency restart function */
+	machine_emergency_restart_func = efi_emergency_restart;
+}
+
+/*
+ * 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 end;
+	void *p;
+
+	efi.systab = NULL;
+	for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+		md = p;
+		if (!(md->attribute & EFI_MEMORY_RUNTIME))
+			continue;
+		if (md->attribute & EFI_MEMORY_WB)
+			md->virt_addr = (unsigned long)__va(md->phys_addr);
+		else if (md->attribute & (EFI_MEMORY_UC | EFI_MEMORY_WC))
+			md->virt_addr = (unsigned long)ioremap(md->phys_addr,
+					 md->num_pages << EFI_PAGE_SHIFT);
+		end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
+		if ((md->phys_addr <= (unsigned long)efi_phys.systab) &&
+				((unsigned long)efi_phys.systab < end))
+			efi.systab = (efi_system_table_t *) 
+					(md->virt_addr - md->phys_addr +
+					(unsigned long)efi_phys.systab);
+	}
+
+	if (!efi.systab)
+		BUG();
+
+	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 "You are screwed! "
+			"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 = (efi_get_time_t *)_efi_get_time;
+	efi.set_time = (efi_set_time_t *)_efi_set_time;
+	efi.get_wakeup_time = (efi_get_wakeup_time_t *)_efi_get_wakeup_time;
+	efi.set_wakeup_time = (efi_set_wakeup_time_t *)_efi_set_wakeup_time;
+	efi.get_variable = (efi_get_variable_t *)_efi_get_variable;
+	efi.get_next_variable = (efi_get_next_variable_t *)_efi_get_next_variable;
+	efi.set_variable = (efi_set_variable_t *)_efi_set_variable;
+	efi.get_next_high_mono_count = (efi_get_next_high_mono_count_t *)
+					_efi_get_next_high_mono_count;
+	efi.reset_system = (efi_reset_system_t *)_efi_reset_system;
+	efi.set_virtual_address_map = (efi_set_virtual_address_map_t *)
+					_efi_set_virtual_address_map;
+}
+
+/*
+ * 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_64/kernel/efi_callwrap.c b/arch/x86_64/kernel/efi_callwrap.c
new file mode 100644
index 0000000..b0635cd
--- /dev/null
+++ b/arch/x86_64/kernel/efi_callwrap.c
@@ -0,0 +1,202 @@
+/*
+ *  Copyright (C) 2006 Giridhar Pemmasani
+ *  Copyright (C) 2007-2010 Intel Corp
+ *  	Contributed by Chandramouli Narayanan<mouli@linux.intel.com>
+ *	Adapted NDIS wrapper macros from http://ndiswrapper.sourceforge.net
+ *	for EFI x86_64 linux support
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/types.h>
+#include <linux/time.h>
+#include <linux/spinlock.h>
+#include <linux/bootmem.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/efi.h>
+
+#define alloc_win_stack_frame(argc)		\
+	"subq $" #argc "*8, %%rsp\n\t"
+#define free_win_stack_frame(argc)		\
+	"addq $" #argc "*8, %%rsp\n\t"
+
+/* m is index of Windows arg required, n is total number of args to
+ * function Windows arg 1 should be at 0(%rsp), arg 2 at 8(%rsp) and
+ * so on, after stack frame is allocated, which starts at -n*8(%rsp)
+ * when stack frame is allocated. 4 > m >= n.
+*/
+
+#define lin2win_win_arg(m,n) "(" #m "-1-" #n ")*8(%%rsp)"
+
+/* volatile args for Windows function must be in clobber / output list */
+
+efi_status_t LIN2WIN0(void *func)
+{									
+	u64 ret, dummy;
+	register u64 r8 __asm__("r8");
+	register u64 r9 __asm__("r9");
+	register u64 r10 __asm__("r10");
+	register u64 r11 __asm__("r11");
+	__asm__ __volatile__(					
+		alloc_win_stack_frame(4)				
+		"call *%[fptr]\n\t"					
+		free_win_stack_frame(4)					
+		: "=a" (ret), "=c" (dummy), "=d" (dummy),		
+		  "=r" (r8), "=r" (r9), "=r" (r10), "=r" (r11)		
+		: [fptr] "r" (func));					
+	return ret;								
+}
+
+efi_status_t LIN2WIN1(void *func, u64 arg1)
+{
+	u64 ret, dummy;
+	register u64 r8 __asm__("r8");
+	register u64 r9 __asm__("r9");
+	register u64 r10 __asm__("r10");
+	register u64 r11 __asm__("r11");
+	__asm__ __volatile__(
+		alloc_win_stack_frame(4)
+		"call *%[fptr]\n\t"
+		free_win_stack_frame(4)	
+		: "=a" (ret), "=c" (dummy), "=d" (dummy),
+		  "=r" (r8), "=r" (r9), "=r" (r10), "=r" (r11)
+		: "c" (arg1),
+		  [fptr] "r" (func));
+	return ret;
+}
+
+efi_status_t LIN2WIN2(void *func, u64 arg1, u64 arg2)
+{
+	u64 ret, dummy;
+	register u64 r8 __asm__("r8");
+	register u64 r9 __asm__("r9");
+	register u64 r10 __asm__("r10");
+	register u64 r11 __asm__("r11");
+	__asm__ __volatile__(
+		alloc_win_stack_frame(4)
+		"call *%[fptr]\n\t"
+		free_win_stack_frame(4)
+		: "=a" (ret), "=c" (dummy), "=d" (dummy),
+		  "=r" (r8), "=r" (r9), "=r" (r10), "=r" (r11)
+		: "c" (arg1), "d" (arg2),
+		  [fptr] "r" (func));
+	return ret;
+}
+
+efi_status_t LIN2WIN3(
+	void *func,
+	u64 arg1,
+	u64 arg2,
+	u64 arg3)
+{
+	u64 ret, dummy;
+	register u64 r8 __asm__("r8") = (u64)arg3;
+	register u64 r9 __asm__("r9");
+	register u64 r10 __asm__("r10");
+	register u64 r11 __asm__("r11");
+	__asm__ __volatile__(
+		alloc_win_stack_frame(4)
+		"call *%[fptr]\n\t"
+		free_win_stack_frame(4)
+		: "=a" (ret), "=c" (dummy), "=d" (dummy),
+		  "=r" (r8), "=r" (r9), "=r" (r10), "=r" (r11)
+		: "c" (arg1), "d" (arg2), "r" (r8),
+		  [fptr] "r" (func));
+	return ret;
+}
+
+efi_status_t LIN2WIN4(
+	void *func,
+	u64 arg1,
+	u64 arg2,
+	u64 arg3,
+	u64 arg4)
+{
+	u64 ret, dummy;
+	register u64 r8 __asm__("r8") = (u64)arg3;
+	register u64 r9 __asm__("r9") = (u64)arg4;
+	register u64 r10 __asm__("r10");
+	register u64 r11 __asm__("r11");
+	__asm__ __volatile__(
+		alloc_win_stack_frame(4)
+		"call *%[fptr]\n\t"
+		free_win_stack_frame(4)
+		: "=a" (ret), "=c" (dummy), "=d" (dummy),
+		  "=r" (r8), "=r" (r9), "=r" (r10), "=r" (r11)
+		: "c" (arg1), "d" (arg2), "r" (r8), "r" (r9),
+		  [fptr] "r" (func));
+	return ret;
+}
+
+efi_status_t LIN2WIN5(
+	void *func,
+	u64 arg1,
+	u64 arg2,
+	u64 arg3,
+	u64 arg4,
+	u64 arg5)
+{
+	u64 ret, dummy;
+	register u64 r8 __asm__("r8") = (u64)arg3;
+	register u64 r9 __asm__("r9") = (u64)arg4;
+	register u64 r10 __asm__("r10");
+	register u64 r11 __asm__("r11");
+	__asm__ __volatile__(
+		"mov %[rarg5], " lin2win_win_arg(5,6) "\n\t"
+		alloc_win_stack_frame(6)
+		"call *%[fptr]\n\t"
+		free_win_stack_frame(6)
+		: "=a" (ret), "=c" (dummy), "=d" (dummy),
+		  "=r" (r8), "=r" (r9), "=r" (r10), "=r" (r11)
+		: "c" (arg1), "d" (arg2), "r" (r8), "r" (r9),
+		  [rarg5] "r" ((unsigned long long)arg5),
+		  [fptr] "r" (func));
+	return ret;
+}
+
+efi_status_t LIN2WIN6(
+	void *func,
+	u64 arg1,
+	u64 arg2,
+	u64 arg3,
+	u64 arg4,
+	u64 arg5,
+	u64 arg6)
+{
+	u64 ret, dummy;
+	register u64 r8 __asm__("r8") = (u64)arg3;
+	register u64 r9 __asm__("r9") = (u64)arg4;
+	register u64 r10 __asm__("r10");
+	register u64 r11 __asm__("r11");
+	__asm__ __volatile__(
+		"movq %[rarg5], " lin2win_win_arg(5,6) "\n\t"
+		"movq %[rarg6], " lin2win_win_arg(6,6) "\n\t"
+		alloc_win_stack_frame(6)
+		"call *%[fptr]\n\t"
+		free_win_stack_frame(6)
+		: "=a" (ret), "=c" (dummy), "=d" (dummy),
+		  "=r" (r8), "=r" (r9), "=r" (r10), "=r" (r11)
+		: "c" (arg1), "d" (arg2), "r" (r8), "r" (r9),
+		  [rarg5] "r" ((u64)arg5), [rarg6] "r" ((u64)arg6),
+		  [fptr] "r" (func));
+	return ret;
+}
+EXPORT_SYMBOL_GPL(LIN2WIN0);
+EXPORT_SYMBOL_GPL(LIN2WIN1);
+EXPORT_SYMBOL_GPL(LIN2WIN2);
+EXPORT_SYMBOL_GPL(LIN2WIN3);
+EXPORT_SYMBOL_GPL(LIN2WIN4);
+EXPORT_SYMBOL_GPL(LIN2WIN5);
+EXPORT_SYMBOL_GPL(LIN2WIN6);
diff --git a/arch/x86_64/kernel/reboot.c b/arch/x86_64/kernel/reboot.c
index 6f56f2f..3bdfe22 100644
--- a/arch/x86_64/kernel/reboot.c
+++ b/arch/x86_64/kernel/reboot.c
@@ -7,6 +7,7 @@
 #include <linux/ctype.h>
 #include <linux/string.h>
 #include <linux/pm.h>
+#include <linux/efi.h>
 #include <asm/io.h>
 #include <asm/kdebug.h>
 #include <asm/delay.h>
@@ -23,6 +24,14 @@
 void (*pm_power_off)(void);
 EXPORT_SYMBOL(pm_power_off);
 
+/* machine_emergency_restart_func is set to the restart implementation here.
+ * The variable provides a way for overriding the implementation.
+ * For example, EFI initialization could set up an emergency restart
+ * function hiding its implementation from here.
+ */
+void (*machine_emergency_restart_func)(void) = machine_emergency_restart;
+EXPORT_SYMBOL(machine_emergency_restart_func);
+
 static long no_idt[3];
 static enum { 
 	BOOT_TRIPLE = 't',
@@ -151,7 +160,7 @@ void machine_restart(char * __unused)
 	if (!reboot_force) {
 		machine_shutdown();
 	}
-	machine_emergency_restart();
+	machine_emergency_restart_func();
 }
 
 void machine_halt(void)
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
index e18e3af..4f11f98 100644
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -45,6 +45,7 @@
 #include <linux/dmi.h>
 #include <linux/dma-mapping.h>
 #include <linux/ctype.h>
+#include <linux/efi.h>
 
 #include <asm/mtrr.h>
 #include <asm/uaccess.h>
@@ -70,6 +71,10 @@
  * Machine setup..
  */
 
+#ifdef CONFIG_EFI
+int efi_enabled = 0;
+EXPORT_SYMBOL(efi_enabled);
+#endif
 struct cpuinfo_x86 boot_cpu_data __read_mostly;
 EXPORT_SYMBOL(boot_cpu_data);
 
@@ -519,6 +524,10 @@ void __init setup_arch(char **cmdline_p)
 	rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
 	rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
 #endif
+#ifdef CONFIG_EFI
+	if (!strncmp(EFI_LOADER_SIG, "EFIL", 4))
+		efi_enabled = 1;
+#endif
 	setup_memory_region();
 	copy_edd();
 
@@ -553,6 +562,8 @@ void __init setup_arch(char **cmdline_p)
 	discover_ebda();
 
 	init_memory_mapping(0, (end_pfn_map << PAGE_SHIFT));
+	if (efi_enabled)
+		efi_map_memmap();
 
 	dmi_scan_machine();
 
@@ -695,7 +706,8 @@ void __init setup_arch(char **cmdline_p)
 
 #ifdef CONFIG_VT
 #if defined(CONFIG_VGA_CONSOLE)
-	conswitchp = &vga_con;
+	if (!efi_enabled || (efi_mem_type(0xa0000) != EFI_CONVENTIONAL_MEMORY))
+		conswitchp = &vga_con;
 #elif defined(CONFIG_DUMMY_CONSOLE)
 	conswitchp = &dummy_con;
 #endif
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c
index e2c3a21..23af13e 100644
--- a/arch/x86_64/kernel/time.c
+++ b/arch/x86_64/kernel/time.c
@@ -33,6 +33,7 @@
 #include <linux/notifier.h>
 #include <linux/cpu.h>
 #include <linux/kallsyms.h>
+#include <linux/efi.h>
 #include <linux/acpi.h>
 #ifdef CONFIG_ACPI
 #include <acpi/achware.h>	/* for PM timer frequency */
@@ -233,6 +234,11 @@ static void set_rtc_mmss(unsigned long nowtime)
  */
 
 	spin_lock(&rtc_lock);
+	if (efi_enabled) {
+		efi_set_rtc_mmss(nowtime);
+		spin_unlock(&rtc_lock);
+		return;
+	}
 
 /*
  * Tell the clock it's being set and stop it.
@@ -532,10 +538,15 @@ unsigned long long sched_clock(void)
 static unsigned long get_cmos_time(void)
 {
 	unsigned int year, mon, day, hour, min, sec;
-	unsigned long flags;
+	unsigned long flags, retval;
 	unsigned extyear = 0;
 
 	spin_lock_irqsave(&rtc_lock, flags);
+ 	if (efi_enabled) {
+ 		retval = efi_get_time();
+ 		spin_unlock_irqrestore(&rtc_lock, flags);
+ 		return retval;
+ 	}
 
 	do {
 		sec = CMOS_READ(RTC_SECONDS);
diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c
index 92fdae9..16d58db 100644
--- a/arch/x86_64/mm/init.c
+++ b/arch/x86_64/mm/init.c
@@ -52,6 +52,8 @@ struct dma_mapping_ops* dma_ops;
 EXPORT_SYMBOL(dma_ops);
 
 static unsigned long dma_reserve __initdata;
+/* Flag indicating EFI runtime executable code area */
+static int efi_runtime_code_area = 0;
 
 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 
@@ -96,6 +98,7 @@ void show_mem(void)
 }
 
 int after_bootmem;
+EXPORT_SYMBOL(after_bootmem);
 
 static __init void *spp_getpage(void)
 { 
@@ -235,11 +238,16 @@ phys_pmd_init(pmd_t *pmd, unsigned long address, unsigned long end)
 		unsigned long entry;
 
 		if (address >= end) {
-			for (; i < PTRS_PER_PMD; i++, pmd++)
-				set_pmd(pmd, __pmd(0));
+			if (!after_bootmem && !efi_runtime_code_area)
+				for (; i < PTRS_PER_PMD; i++, pmd++)
+					set_pmd(pmd, __pmd(0));
 			break;
 		}
 		entry = _PAGE_NX|_PAGE_PSE|_KERNPG_TABLE|_PAGE_GLOBAL|address;
+ 		if (efi_runtime_code_area) {
+ 			entry = pmd_val(*pmd);
+ 			entry &= ~_PAGE_NX;
+ 		} else entry = _PAGE_NX|_PAGE_PSE|_KERNPG_TABLE|_PAGE_GLOBAL|address;
 		entry &= __supported_pte_mask;
 		set_pmd(pmd, __pmd(entry));
 	}
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index c46e372..720b317 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -552,6 +552,17 @@ config FB_VESA
 	  You will get a boot time penguin logo at no additional cost. Please
 	  read <file:Documentation/fb/vesafb.txt>. If unsure, say Y.
 
+config FB_EFI
+	bool "EFI-based Framebuffer Support"
+	depends on (FB = y) && X86 && EFI
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	help
+	  This is the EFI frame buffer device driver. If the firmware on
+	  your platform is UEFI2.0, select Y to add support for
+	  Graphics Output Protocol for early console messages to appear.
+
 config FB_IMAC
 	bool "Intel-based Macintosh Framebuffer Support"
 	depends on (FB = y) && X86 && EFI
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 481c6c9..c261bde 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -102,6 +102,7 @@ obj-$(CONFIG_FB_PNX4008_DUM_RGB)  += pnx4008/
 # Platform or fallback drivers go here
 obj-$(CONFIG_FB_VESA)             += vesafb.o
 obj-$(CONFIG_FB_IMAC)             += imacfb.o
+obj-$(CONFIG_FB_EFI)              += efifb.o
 obj-$(CONFIG_FB_VGA16)            += vga16fb.o vgastate.o
 obj-$(CONFIG_FB_OF)               += offb.o
 
diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c
new file mode 100644
index 0000000..f555546
--- /dev/null
+++ b/drivers/video/efifb.c
@@ -0,0 +1,249 @@
+/*
+ * framebuffer driver for Intel Based Mac's
+ *
+ * (c) 2006 Edgar Hucek <gimli@dark-green.com>
+ * Original efi driver written by Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/screen_info.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/dmi.h>
+#include <linux/efi.h>
+
+#include <asm/io.h>
+
+#include <video/vga.h>
+
+static struct fb_var_screeninfo efifb_defined __initdata = {
+	.activate		= FB_ACTIVATE_NOW,
+	.height			= -1,
+	.width			= -1,
+	.right_margin		= 32,
+	.upper_margin		= 16,
+	.lower_margin		= 4,
+	.vsync_len		= 4,
+	.vmode			= FB_VMODE_NONINTERLACED,
+};
+
+static struct fb_fix_screeninfo efifb_fix __initdata = {
+	.id			= "EFI VGA",
+	.type			= FB_TYPE_PACKED_PIXELS,
+	.accel			= FB_ACCEL_NONE,
+	.visual			= FB_VISUAL_TRUECOLOR,
+};
+
+static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			    unsigned blue, unsigned transp,
+			    struct fb_info *info)
+{
+	/*
+	 *  Set a single color register. The values supplied are
+	 *  already rounded down to the hardware's capabilities
+	 *  (according to the entries in the `var' structure). Return
+	 *  != 0 for invalid regno.
+	 */
+
+	if (regno >= info->cmap.len)
+		return 1;
+
+	if (regno < 16) {
+		red   >>= 8;
+		green >>= 8;
+		blue  >>= 8;
+		((u32 *)(info->pseudo_palette))[regno] =
+			(red   << info->var.red.offset)   |
+			(green << info->var.green.offset) |
+			(blue  << info->var.blue.offset);
+	}
+	return 0;
+}
+
+static struct fb_ops efifb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_setcolreg	= efifb_setcolreg,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+};
+
+static int __init efifb_probe(struct platform_device *dev)
+{
+	struct fb_info *info;
+	int err;
+	unsigned int size_vmode;
+	unsigned int size_remap;
+	unsigned int size_total;
+
+	efifb_fix.smem_start = screen_info.lfb_base;
+	efifb_defined.bits_per_pixel = screen_info.lfb_depth;
+	efifb_defined.xres = screen_info.lfb_width;
+	efifb_defined.yres = screen_info.lfb_height;
+	efifb_fix.line_length = screen_info.lfb_linelength;
+
+	/*   size_vmode -- that is the amount of memory needed for the
+	 *                 used video mode, i.e. the minimum amount of
+	 *                 memory we need. */
+	size_vmode = efifb_defined.yres * efifb_fix.line_length;
+
+	/*   size_total -- all video memory we have. Used for
+	 *                 entries, ressource allocation and bounds
+	 *                 checking. */
+	//size_total = screen_info.lfb_size * 65536;
+	size_total = screen_info.lfb_size;
+	if (size_total < size_vmode)
+		size_total = size_vmode;
+
+	/*   size_remap -- the amount of video memory we are going to
+	 *                 use for efifb.  With modern cards it is no
+	 *                 option to simply use size_total as that
+	 *                 wastes plenty of kernel address space. */
+	size_remap  = size_vmode * 2;
+	if (size_remap < size_vmode)
+		size_remap = size_vmode;
+	if (size_remap > size_total)
+		size_remap = size_total;
+	efifb_fix.smem_len = size_remap;
+
+#ifndef __i386__
+	//screen_info.imacpm_seg = 0;
+#endif
+
+	if (!request_mem_region(efifb_fix.smem_start, size_total, "efifb")) {
+		printk(KERN_WARNING
+		       "efifb: cannot reserve video memory at 0x%lx\n",
+			efifb_fix.smem_start);
+		/* We cannot make this fatal. Sometimes this comes from magic
+		   spaces our resource handlers simply don't know about */
+	}
+
+	info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
+	if (!info) {
+		err = -ENOMEM;
+		goto err_release_mem;
+	}
+	info->pseudo_palette = info->par;
+	info->par = NULL;
+
+	info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len);
+	if (!info->screen_base) {
+		printk(KERN_ERR "efifb: abort, cannot ioremap video memory "
+				"0x%x @ 0x%lx\n",
+			efifb_fix.smem_len, efifb_fix.smem_start);
+		err = -EIO;
+		goto err_unmap;
+	}
+
+	printk(KERN_INFO "efifb: framebuffer at 0x%lx, mapped to 0x%p, "
+	       "using %dk, total %dk\n",
+	       efifb_fix.smem_start, info->screen_base,
+	       size_remap/1024, size_total/1024);
+	printk(KERN_INFO "efifb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
+	       efifb_defined.xres, efifb_defined.yres,
+	       efifb_defined.bits_per_pixel, efifb_fix.line_length,
+	       screen_info.pages);
+
+	efifb_defined.xres_virtual = efifb_defined.xres;
+	efifb_defined.yres_virtual = efifb_fix.smem_len /
+					efifb_fix.line_length;
+	printk(KERN_INFO "efifb: scrolling: redraw\n");
+	efifb_defined.yres_virtual = efifb_defined.yres;
+
+	/* some dummy values for timing to make fbset happy */
+	efifb_defined.pixclock     = 10000000 / efifb_defined.xres *
+					1000 / efifb_defined.yres;
+	efifb_defined.left_margin  = (efifb_defined.xres / 8) & 0xf8;
+	efifb_defined.hsync_len    = (efifb_defined.xres / 8) & 0xf8;
+
+	efifb_defined.red.offset    = screen_info.red_pos;
+	efifb_defined.red.length    = screen_info.red_size;
+	efifb_defined.green.offset  = screen_info.green_pos;
+	efifb_defined.green.length  = screen_info.green_size;
+	efifb_defined.blue.offset   = screen_info.blue_pos;
+	efifb_defined.blue.length   = screen_info.blue_size;
+	efifb_defined.transp.offset = screen_info.rsvd_pos;
+	efifb_defined.transp.length = screen_info.rsvd_size;
+
+	printk(KERN_INFO "efifb: %s: "
+	       "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
+	       "Truecolor",
+	       screen_info.rsvd_size,
+	       screen_info.red_size,
+	       screen_info.green_size,
+	       screen_info.blue_size,
+	       screen_info.rsvd_pos,
+	       screen_info.red_pos,
+	       screen_info.green_pos,
+	       screen_info.blue_pos);
+
+	efifb_fix.ypanstep  = 0;
+	efifb_fix.ywrapstep = 0;
+
+	info->fbops = &efifb_ops;
+	info->var = efifb_defined;
+	info->fix = efifb_fix;
+	info->flags = FBINFO_FLAG_DEFAULT;
+
+	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
+		err = -ENOMEM;
+		goto err_unmap;
+	}
+	if (register_framebuffer(info)<0) {
+		err = -EINVAL;
+		goto err_fb_dealoc;
+	}
+	printk(KERN_INFO "fb%d: %s frame buffer device\n",
+	       info->node, info->fix.id);
+	return 0;
+
+err_fb_dealoc:
+	fb_dealloc_cmap(&info->cmap);
+err_unmap:
+	iounmap(info->screen_base);
+	framebuffer_release(info);
+err_release_mem:
+	release_mem_region(efifb_fix.smem_start, size_total);
+	return err;
+}
+
+static struct platform_driver efifb_driver = {
+	.probe	= efifb_probe,
+	.driver	= {
+		.name	= "efifb",
+	},
+};
+
+static struct platform_device efifb_device = {
+	.name	= "efifb",
+};
+
+static int __init efifb_init(void)
+{
+	int ret;
+
+	if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
+		return -ENODEV;
+
+
+	ret = platform_driver_register(&efifb_driver);
+
+	if (!ret) {
+		ret = platform_device_register(&efifb_device);
+		if (ret)
+			platform_driver_unregister(&efifb_driver);
+	}
+	return ret;
+}
+module_init(efifb_init);
+
+MODULE_LICENSE("GPL");
diff --git a/include/asm-x86_64/bootsetup.h b/include/asm-x86_64/bootsetup.h
index b829f7b..743c11d 100644
--- a/include/asm-x86_64/bootsetup.h
+++ b/include/asm-x86_64/bootsetup.h
@@ -17,6 +17,12 @@ extern char x86_boot_params[BOOT_PARAM_SIZE];
 #define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+0x40))
 #define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
 #define SYS_DESC_TABLE (*(struct sys_desc_table_struct*)(PARAM+0xa0))
+#define EFI_SYSTAB (*((unsigned long *)(PARAM+0x1b8)))
+#define EFI_LOADER_SIG ((unsigned char *)(PARAM+0x1c0))
+#define EFI_MEMDESC_SIZE (*((unsigned int *) (PARAM+0x1c4)))
+#define EFI_MEMDESC_VERSION (*((unsigned int *) (PARAM+0x1c8)))
+#define EFI_MEMMAP_SIZE (*((unsigned int *) (PARAM+0x1cc)))
+#define EFI_MEMMAP (*((unsigned long *)(PARAM+0x1d0)))
 #define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))
 #define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8))
 #define SAVED_VIDEO_MODE (*(unsigned short *) (PARAM+0x1FA))
diff --git a/include/asm-x86_64/e820.h b/include/asm-x86_64/e820.h
index eaf2103..25b8d2e 100644
--- a/include/asm-x86_64/e820.h
+++ b/include/asm-x86_64/e820.h
@@ -21,6 +21,7 @@
 #define E820_RESERVED	2
 #define E820_ACPI	3 /* usable as RAM once ACPI tables have been read */
 #define E820_NVS	4
+#define E820_RUNTIME_CODE	5	/* efi runtime code */
 
 #define HIGH_MEMORY	(1024*1024)
 
diff --git a/include/asm-x86_64/eficallwrap.h b/include/asm-x86_64/eficallwrap.h
new file mode 100644
index 0000000..7147d72
--- /dev/null
+++ b/include/asm-x86_64/eficallwrap.h
@@ -0,0 +1,27 @@
+/*
+ *  Copyright (C) 2006 Giridhar Pemmasani
+ *  Copyright (C) 2007-2010 Intel Corp
+ *  	Contributed by Chandramouli Narayanan<mouli@linux.intel.com>
+ *	Adapted NDIS wrapper macros from http://ndiswrapper.sourceforge.net
+ *	for EFI x86_64 linux support
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ */
+extern efi_status_t LIN2WIN0(void *fp);
+extern efi_status_t LIN2WIN1(void *fp, u64 arg1);
+extern efi_status_t LIN2WIN2(void *fp, u64 arg1, u64 arg2);
+extern efi_status_t LIN2WIN3(void *fp, u64 arg1, u64 arg2, u64 arg3);
+extern efi_status_t LIN2WIN4(void *fp, u64 arg1, u64 arg2, u64 arg3, u64 arg4);
+extern efi_status_t LIN2WIN5(
+	void *fp, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5);
+extern efi_status_t LIN2WIN6(
+	void *fp, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, u64 arg6);
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 59abb68..6977fa2 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -213,6 +213,7 @@ typedef struct {
 } efi_config_table_t;
 
 #define EFI_SYSTEM_TABLE_SIGNATURE ((u64)0x5453595320494249ULL)
+#define EFI_SYSTEM_TABLE_REVISION  ((1 << 16) | 00)
 
 typedef struct {
 	efi_table_hdr_t hdr;
diff --git a/include/linux/screen_info.h b/include/linux/screen_info.h
index b02308e..a72009f 100644
--- a/include/linux/screen_info.h
+++ b/include/linux/screen_info.h
@@ -63,6 +63,7 @@ extern struct screen_info screen_info;
 #define VIDEO_TYPE_EGAC		0x21	/* EGA in Color Mode		*/
 #define VIDEO_TYPE_VGAC		0x22	/* VGA+ in Color Mode		*/
 #define VIDEO_TYPE_VLFB		0x23	/* VESA VGA in graphic mode	*/
+#define VIDEO_TYPE_EFI		0x24	/* EFI graphic mode		*/
 
 #define VIDEO_TYPE_PICA_S3	0x30	/* ACER PICA-61 local S3 video	*/
 #define VIDEO_TYPE_MIPS_G364	0x31    /* MIPS Magnum 4000 G364 video  */
diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h
index 391e7ed..975c963 100644
--- a/include/linux/uaccess.h
+++ b/include/linux/uaccess.h
@@ -1,8 +1,43 @@
 #ifndef __LINUX_UACCESS_H__
 #define __LINUX_UACCESS_H__
 
+#include <linux/preempt.h>
 #include <asm/uaccess.h>
 
+/*
+ * These routines enable/disable the pagefault handler in that
+ * it will not take any locks and go straight to the fixup table.
+ *
+ * They have great resemblance to the preempt_disable/enable calls
+ * and in fact they are identical; this is because currently there is
+ * no other way to make the pagefault handlers do this. So we do
+ * disable preemption but we don't necessarily care about that.
+ */
+static inline void pagefault_disable(void)
+{
+	inc_preempt_count();
+	/*
+	 * make sure to have issued the store before a pagefault
+	 * can hit.
+	 */
+	barrier();
+}
+
+static inline void pagefault_enable(void)
+{
+	/*
+	 * make sure to issue those last loads/stores before enabling
+	 * the pagefault handler again.
+	 */
+	barrier();
+	dec_preempt_count();
+	/*
+	 * make sure we do..
+	 */
+	barrier();
+	preempt_check_resched();
+}
+
 #ifndef ARCH_HAS_NOCACHE_UACCESS
 
 static inline unsigned long __copy_from_user_inatomic_nocache(void *to,
@@ -19,4 +54,34 @@ static inline unsigned long __copy_from_user_nocache(void *to,
 
 #endif		/* ARCH_HAS_NOCACHE_UACCESS */
 
+/**
+ * probe_kernel_address(): safely attempt to read from a location
+ * @addr: address to read from - its type is type typeof(retval)*
+ * @retval: read into this variable
+ *
+ * Safely read from address @addr into variable @revtal.  If a kernel fault
+ * happens, handle that and return -EFAULT.
+ * We ensure that the __get_user() is executed in atomic context so that
+ * do_page_fault() doesn't attempt to take mmap_sem.  This makes
+ * probe_kernel_address() suitable for use within regions where the caller
+ * already holds mmap_sem, or other locks which nest inside mmap_sem.
+ * This must be a macro because __get_user() needs to know the types of the
+ * args.
+ *
+ * We don't include enough header files to be able to do the set_fs().  We
+ * require that the probe_kernel_address() caller will do that.
+ */
+#define probe_kernel_address(addr, retval)		\
+	({						\
+		long ret;				\
+		mm_segment_t old_fs = get_fs();		\
+							\
+		set_fs(KERNEL_DS);			\
+		pagefault_disable();			\
+		ret = __get_user(retval, (__force typeof(retval) __user *)(addr));		\
+		pagefault_enable();			\
+		set_fs(old_fs);				\
+		ret;					\
+	})
+
 #endif		/* __LINUX_UACCESS_H__ */