From: Matt Tolentino <metolent@snoqualmie.dp.intel.com>

Attached is another patch that enables EFI boot-up support in ia32 kernels. 
This one has numerous changes based on the various comments and suggestions
made on the last one several weeks ago.  The patch is against
2.6.0-test6-mm2.

This patch departs from the last in that I am no longer adding separate boot
parameters at the end of the the empty_zero_page; rather, based on Eric's
suggestion, I've added EFI parameters via offset grouped with the rest of the
existing boot parameters.  This allows the reuse of several parameters which
were redundant (command-line, initrd, etc.).  This also simplifies some of
the code in setup_arch().

In order to continue to determine whether the kernel should initialize using
EFI tables, I've temporarily added a check on the LOADER_TYPE boot parameter.
 Although I haven't requested that elilo be assigned an id for this yet, I've
used this to determine whether the kernel should use the EFI initialization
path as well as a check to see if the EFI_SYSTAB boot parameter contains
anything.  If someone has a better suggestion for determining this, I'm
open...

This patch also uses the existing ioremapping functions to map the efi tables
into kernel virtual address space.  I've added an option such that I could
use Dave Hansen's boot_ioremap() before paging_init().  After paging_init, I
then remap the efi memmap using bt_ioremap for use later.  This has
eliminated the need for several functions...thanks for the suggestions and
thanks for your help Dave.  Still this could use a look-see.

Something else that I'd like to solicit suggestions on is how to deal with
CONFIG_ACPI_EFI.  One of the goals of this patch is to enable the kernel to
"just know" at boot time when to use EFI information to initialize.  That
way, the same kernel image would theoretically still boot on existing systems
with a different BIOS.  I think this patch accomplishes that goal to some
degree, but how best to deal with when/when not to look at the EFI config
table for the RSDP is still dealt with at compile time.  I'd like to
dynamically determine this as well, but am not sure of the best
way...suggestions?  Len?  Andrew?

Note, I'm still working on verifying this works properly on a system with
>4GB system memory, as well as with the 4G/4G split (hence the reason this is
against the -mm kernel)...hopefully, I'll be able to steal some time on one
of those monsters next week.

DESC
efi warning fix
EDESC

arch/i386/kernel/efi_stub.S: Assembler messages:
arch/i386/kernel/efi_stub.S:26: Warning: ignoring changed section attributes for .text

DESC
fix EFI for ppc64, ia64
EDESC

Make non-ia32 kernels link.  efi_enabled isnot defined there.

DESC
efi: warning fixes
EDESC
From: Bill Irwin

Eliminate some compile warnings
DESC
ia32 EFI: Add CONFIG_EFI
EDESC
From: Matt Tolentino <metolent@snoqualmie.dp.intel.com>

1. Adds CONFIG_EFI option to boot on EFI platforms, but also continue
   to boot on existing platforms depending on the boot parameters.  

2. Kernels w/o CONFIG_EFI are smaller (nearly 8k, although I can
   probably move some more stuff around for greater savings).  

This was accomplished through the following changes:

+ Removed CONFIG_ACPI_EFI.  I've substituted the efi_enabled flag which
  is set depending on CONFIG_EFI at build time, but also dynamically at
  runtime through inspection of the boot parameters.

  Note, I haven't run this change by Len or David for input from the ACPI
  or IA64 perspectives.  However, this does allow for the behavior we need
  on x86.  I need to do one more ia64 specific patch (something like add
  int efi_enabled = 1; and a CONFIG_EFI option to always be on in Kconfig)
  to ensure this doesn't break itanium builds, but I wanted to get your
  input first.  

+ reorganized some of the functions in time.c.  I removed the
  efi_get_time and efi_set_rtc_mmss and put them as inline into efi.c.  I
  think the manner in which these are called makes more sense now and
  ensures that they aren't even compiled without CONFIG_EFI.  

I was able to boot both kernels (EFI and non-EFI) on several machines with
regular BIOS.  The ACPI tables were detected correctly, interrupts looked
like they were routed correctly, etc., so give a try.  

DESC
efi: Update Kconfig help
EDESC
From: Matt Tolentino <metolent@snoqualmie.dp.intel.com>

 - The help for CONFIG_EFI talks about requiring ELILO.  On ia32?  Is
   that correct?  What's the scoop here?

Yes, on EFI systems the ELILO loader is required to obtain platform config
info (like the memory map, EFI config table, etc.) from the EFI interface
to pass to the kernel as well as actually copying the kernel into memory
and transferring control to it.  In fact, that's what I've been using on
the prototype machines I have.  Grub and Lilo aren't very useful in a
"pure" EFI environment, because they are not EFI applications and have no
way to access EFI functionality.  I'll attach a Kconfig help patch that
might make this clearer...


 - Why do you say "dynamically at runtime through inspection of the boot
   parameters"?  It seems to be using "LOADER_TYPE".  What is that?  Did
   you mean to allow efi to be disabled with a kernel boot parameter?  If
   so, I don't see any code in there which will do this.

Currently, the ELILO loader sets the boot parameter LOADER_TYPE to 0x50. 
This "id" isn't currently used (according to Documentation/i386/boot.txt)
and I've currently hijacked it for proof of concept.  I'll send mail to
officially request the ID number shortly and update the boot protocol
documentation to add EFI.  So, if one wanted to set this to boot without
EFI support, it could be done via the loader via a config option (as it
sets the LOADER_TYPE).  So, the decision as to whether or not to take the
efi code path is based on how the loader sets this parameter.  

DESC
efi update patch (ia64)
EDESC
From: Matt Tolentino <metolent@snoqualmie.dp.intel.com>

Here's a simple ia64 patch that should work with the change.  Essentially,
it just adds CONFIG_EFI to Kconfig (and defconfig) for ia64 and efi_enabled
in setup.c.  



 25-akpm/arch/i386/Kconfig            |   21 +
 25-akpm/arch/i386/kernel/Makefile    |    1 
 25-akpm/arch/i386/kernel/acpi/boot.c |    7 
 25-akpm/arch/i386/kernel/efi.c       |  645 +++++++++++++++++++++++++++++++++++
 25-akpm/arch/i386/kernel/efi_stub.S  |  124 ++++++
 25-akpm/arch/i386/kernel/reboot.c    |   12 
 25-akpm/arch/i386/kernel/setup.c     |  141 ++++++-
 25-akpm/arch/i386/kernel/time.c      |   21 -
 25-akpm/arch/i386/mm/init.c          |   21 +
 25-akpm/arch/ia64/Kconfig            |   10 
 25-akpm/arch/ia64/defconfig          |    2 
 25-akpm/arch/ia64/kernel/setup.c     |    4 
 25-akpm/drivers/acpi/Kconfig         |    6 
 25-akpm/drivers/acpi/osl.c           |  109 ++---
 25-akpm/include/asm-i386/setup.h     |    5 
 25-akpm/include/linux/efi.h          |   60 ++-
 25-akpm/init/main.c                  |    5 
 17 files changed, 1091 insertions(+), 103 deletions(-)

diff -puN arch/i386/Kconfig~ia32-efi-support arch/i386/Kconfig
--- 25/arch/i386/Kconfig~ia32-efi-support	Mon Nov 17 12:09:20 2003
+++ 25-akpm/arch/i386/Kconfig	Mon Nov 17 12:09:20 2003
@@ -784,6 +784,25 @@ config MTRR
 
 	  See <file:Documentation/mtrr.txt> for more information.
 
+config EFI
+	bool "Boot from EFI support (EXPERIMENTAL)"
+	depends on ACPI
+	default n
+	---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.  In addition,
+	you must use the latest ELILO loader available at
+	ftp.hpl.hp.com/pub/linux-ia64/ in order to take advantage of kernel
+	initialization using EFI information (neither GRUB nor LILO know
+	anything about EFI).  However, even with this option, the resultant
+	kernel should continue to boot on existing non-EFI platforms.
+
 config HAVE_DEC_LOCK
 	bool
 	depends on (SMP || PREEMPT) && X86_CMPXCHG
@@ -793,7 +812,7 @@ config HAVE_DEC_LOCK
 # Summit needs it only when NUMA is on
 config BOOT_IOREMAP
 	bool
-	depends on ((X86_SUMMIT || X86_GENERICARCH) && NUMA)
+	depends on (((X86_SUMMIT || X86_GENERICARCH) && NUMA) || (X86 && EFI))
 	default y
 
 endmenu
diff -puN arch/i386/kernel/acpi/boot.c~ia32-efi-support arch/i386/kernel/acpi/boot.c
--- 25/arch/i386/kernel/acpi/boot.c~ia32-efi-support	Mon Nov 17 12:09:20 2003
+++ 25-akpm/arch/i386/kernel/acpi/boot.c	Mon Nov 17 12:09:20 2003
@@ -26,6 +26,7 @@
 #include <linux/init.h>
 #include <linux/config.h>
 #include <linux/acpi.h>
+#include <linux/efi.h>
 #include <asm/pgalloc.h>
 #include <asm/io_apic.h>
 #include <asm/apic.h>
@@ -331,6 +332,12 @@ acpi_find_rsdp (void)
 {
 	unsigned long		rsdp_phys = 0;
 
+	if (efi_enabled) {
+		if (efi.acpi20)
+			return __pa(efi.acpi20);
+		else if (efi.acpi)
+			return __pa(efi.acpi);
+	}
 	/*
 	 * Scan memory looking for the RSDP signature. First search EBDA (low
 	 * memory) paragraphs and then search upper memory (E0000-FFFFF).
diff -puN /dev/null arch/i386/kernel/efi.c
--- /dev/null	Thu Apr 11 07:25:15 2002
+++ 25-akpm/arch/i386/kernel/efi.c	Mon Nov 17 12:09:20 2003
@@ -0,0 +1,645 @@
+/*
+ * 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/config.h>
+#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/proc_fs.h>
+#include <linux/efi.h>
+
+#include <asm/setup.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/desc.h>
+#include <asm/pgalloc.h>
+#include <asm/tlbflush.h>
+
+#define EFI_DEBUG	0
+#define PFX 		"EFI: "
+
+extern efi_status_t asmlinkage efi_call_phys(void *, ...);
+
+struct efi efi;
+struct efi efi_phys __initdata;
+struct efi_memory_map memmap __initdata;
+
+/*
+ * We require an early boot_ioremap mapping mechanism initially
+ */
+extern void * boot_ioremap(unsigned long, unsigned long);
+
+/*
+ * efi_dir is allocated here, but the directory isn't created
+ * here, as proc_mkdir() doesn't work this early in the bootup
+ * process.  Therefore, each module, like efivars, must test for
+ *    if (!efi_dir) efi_dir = proc_mkdir("efi", NULL);
+ * prior to creating their own entries under /proc/efi.
+ */
+#ifdef CONFIG_PROC_FS
+struct proc_dir_entry *efi_dir;
+#endif
+
+
+/*
+ * 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 spinlock_t efi_rt_lock = SPIN_LOCK_UNLOCKED;
+static pgd_t efi_bak_pg_dir_pointer[2];
+
+static void efi_call_phys_prelog(void)
+{
+	unsigned long cr4;
+	unsigned long temp;
+
+	spin_lock(&efi_rt_lock);
+	local_irq_save(efi_rt_eflags);
+
+	/*
+	 * If I don't have PSE, I should just duplicate two entries in page
+	 * directory. If I have PSE, I just need to duplicate one entry in
+	 * page directory.
+	 */
+	__asm__ __volatile__("movl %%cr4, %0":"=r"(cr4));
+
+	if (cr4 & X86_CR4_PSE) {
+		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.
+	 */
+	local_flush_tlb();
+
+	cpu_gdt_descr[0].address = __pa(cpu_gdt_descr[0].address);
+	__asm__ __volatile__("lgdt %0":"=m"
+			    (*(struct Xgt_desc_struct *) __pa(&cpu_gdt_descr[0])));
+}
+
+static void efi_call_phys_epilog(void)
+{
+	unsigned long cr4;
+
+	cpu_gdt_descr[0].address =
+		(unsigned long) __va(cpu_gdt_descr[0].address);
+	__asm__ __volatile__("lgdt %0":"=m"(cpu_gdt_descr));
+	__asm__ __volatile__("movl %%cr4, %0":"=r"(cr4));
+
+	if (cr4 & X86_CR4_PSE) {
+		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.
+	 */
+	local_flush_tlb();
+
+	local_irq_restore(efi_rt_eflags);
+	spin_unlock(&efi_rt_lock);
+}
+
+static efi_status_t
+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_phys(efi_phys.set_virtual_address_map,
+				     memory_map_size, descriptor_size,
+				     descriptor_version, virtual_map);
+	efi_call_phys_epilog();
+	return status;
+}
+
+efi_status_t
+phys_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
+{
+	efi_status_t status;
+
+	efi_call_phys_prelog();
+	status = efi_call_phys(efi_phys.get_time, tm, tc);
+	efi_call_phys_epilog();
+	return status;
+}
+
+int inline 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)
+		panic("Ooops, efitime: can't read time!\n");
+	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;
+
+	if (status != EFI_SUCCESS) {
+		printk("Ooops: efitime: can't read time!\n");
+		return -1;
+	}
+	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.
+ */
+unsigned long inline __init 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 (status != EFI_SUCCESS)
+		printk("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);
+}
+
+int is_available_memory(efi_memory_desc_t * md)
+{
+	if (!(md->attribute & EFI_MEMORY_WB))
+		return 0;
+
+	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:
+			return 1;
+	}
+	return 0;
+}
+
+/*
+ * We need to map the EFI memory map again after paging_init().
+ */
+void __init efi_map_memmap(void)
+{
+	memmap.map = NULL;
+
+	memmap.map = (efi_memory_desc_t *)
+		bt_ioremap((unsigned long) memmap.phys_map,
+			(memmap.nr_map * sizeof(efi_memory_desc_t)));
+
+	if (memmap.map == NULL)
+		printk(KERN_ERR PFX "Could not remap the EFI memmap!\n");
+}
+
+void __init print_efi_memmap(void)
+{
+	efi_memory_desc_t *md;
+	int i;
+
+	for (i = 0; i < memmap.nr_map; i++) {
+		md = &memmap.map[i];
+		printk(KERN_INFO "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)));
+	}
+}
+
+/*
+ * Walks the EFI memory map and calls CALLBACK once for each EFI
+ * memory descriptor that has memory that is available for kernel use.
+ */
+void efi_memmap_walk(efi_freemem_callback_t callback, void *arg)
+{
+	int prev_valid = 0;
+	struct range {
+		unsigned long start;
+		unsigned long end;
+	} prev, curr;
+	efi_memory_desc_t *md;
+	unsigned long start, end;
+	int i;
+
+	for (i = 0; i < memmap.nr_map; i++) {
+		md = &memmap.map[i];
+
+		if ((md->num_pages == 0) || (!is_available_memory(md)))
+			continue;
+
+		curr.start = md->phys_addr;
+		curr.end = curr.start + (md->num_pages << EFI_PAGE_SHIFT);
+
+		if (!prev_valid) {
+			prev = curr;
+			prev_valid = 1;
+		} else {
+			if (curr.start < prev.start)
+				printk(KERN_INFO PFX "Unordered memory map\n");
+			if (prev.end == curr.start)
+				prev.end = curr.end;
+			else {
+				start =
+				    (unsigned long) (PAGE_ALIGN(prev.start));
+				end = (unsigned long) (prev.end & PAGE_MASK);
+				if ((end > start)
+				    && (*callback) (start, end, arg) < 0)
+					return;
+				prev = curr;
+			}
+		}
+	}
+	if (prev_valid) {
+		start = (unsigned long) PAGE_ALIGN(prev.start);
+		end = (unsigned long) (prev.end & PAGE_MASK);
+		if (end > start)
+			(*callback) (start, end, arg);
+	}
+}
+
+void __init efi_init(void)
+{
+	efi_config_table_t *config_tables;
+	efi_runtime_services_t *runtime;
+	efi_char16_t *c16;
+	char vendor[100] = "unknown";
+	unsigned long num_config_tables;
+	int i = 0;
+
+	memset(&efi, 0, sizeof(efi) );
+	memset(&efi_phys, 0, sizeof(efi_phys));
+
+	efi_phys.systab = EFI_SYSTAB;
+	memmap.phys_map = EFI_MEMMAP;
+	memmap.nr_map = EFI_MEMMAP_SIZE/EFI_MEMDESC_SIZE;
+	memmap.desc_version = EFI_MEMDESC_VERSION;
+
+	efi.systab = (efi_system_table_t *)
+		boot_ioremap((unsigned long) efi_phys.systab,
+			sizeof(efi_system_table_t));
+	/*
+	 * Verify the EFI Table
+	 */
+	if (efi.systab == NULL)
+		printk(KERN_ERR PFX "Woah! Couldn't map the EFI system table.\n");
+	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
+	 */
+	num_config_tables = efi.systab->nr_tables;
+	config_tables = (efi_config_table_t *)efi.systab->tables;
+	runtime = efi.systab->runtime;
+
+	/*
+	 * Show what we know for posterity
+	 */
+	c16 = (efi_char16_t *) boot_ioremap(efi.systab->fw_vendor, 2);
+	if (c16) {
+		for (i = 0; i < sizeof(vendor) && *c16; ++i)
+			vendor[i] = *c16++;
+		vendor[i] = '\0';
+	} else
+		printk(KERN_ERR PFX "Could not map the firmware vendor!\n");
+
+	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 *)
+				boot_ioremap((unsigned long) config_tables,
+			        num_config_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 < num_config_tables; i++) {
+		if (efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID) == 0) {
+			efi.mps = (void *)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);
+			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);
+			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;
+			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;
+			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;
+			printk(KERN_INFO " UGA=0x%lx ", config_tables[i].table);
+		}
+	}
+	printk("\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 *) boot_ioremap((unsigned long)
+						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 *)
+		boot_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 "Warning! Kernel-defined memdesc doesn't "
+			   "match the one from EFI!\n");
+	}
+#if EFI_DEBUG
+	print_efi_memmap();
+#endif
+}
+
+/*
+ * 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;
+	int i;
+
+	efi.systab = NULL;
+
+	for (i = 0; i < memmap.nr_map; i++) {
+		md = &memmap.map[i];
+
+		if (md->attribute & EFI_MEMORY_RUNTIME) {
+			md->virt_addr =
+				(unsigned long)ioremap(md->phys_addr,
+					md->num_pages << EFI_PAGE_SHIFT);
+			if (!(unsigned long)md->virt_addr) {
+				printk(KERN_ERR PFX "ioremap of 0x%lX failed\n",
+					(unsigned long)md->phys_addr);
+			}
+
+			if (((unsigned long)md->phys_addr <=
+					(unsigned long)efi_phys.systab) &&
+				((unsigned long)efi_phys.systab <
+					md->phys_addr +
+					((unsigned long)md->num_pages <<
+						EFI_PAGE_SHIFT))) {
+				unsigned long addr;
+
+				addr = md->virt_addr - md->phys_addr +
+						(unsigned long)efi_phys.systab;
+				efi.systab = (efi_system_table_t *)addr;
+			}
+		}
+	}
+
+	if (!efi.systab)
+		BUG();
+
+	status = phys_efi_set_virtual_address_map(
+			sizeof(efi_memory_desc_t) * memmap.nr_map,
+			sizeof(efi_memory_desc_t),
+			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.
+	 */
+
+	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;
+}
+
+void __init
+efi_initialize_iomem_resources(struct resource *code_resource,
+			       struct resource *data_resource)
+{
+	struct resource *res;
+	efi_memory_desc_t *md;
+	int i;
+
+	for (i = 0; i < memmap.nr_map; i++) {
+		md = &memmap.map[i];
+
+		if ((md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT)) >
+		    0x100000000ULL)
+			continue;
+		res = alloc_bootmem_low(sizeof(struct resource));
+		switch (md->type) {
+		case EFI_RESERVED_TYPE:
+			res->name = "Reserved Memory";
+			break;
+		case EFI_LOADER_CODE:
+			res->name = "Loader Code";
+			break;
+		case EFI_LOADER_DATA:
+			res->name = "Loader Data";
+			break;
+		case EFI_BOOT_SERVICES_DATA:
+			res->name = "BootServices Data";
+			break;
+		case EFI_BOOT_SERVICES_CODE:
+			res->name = "BootServices Code";
+			break;
+		case EFI_RUNTIME_SERVICES_CODE:
+			res->name = "Runtime Service Code";
+			break;
+		case EFI_RUNTIME_SERVICES_DATA:
+			res->name = "Runtime Service Data";
+			break;
+		case EFI_CONVENTIONAL_MEMORY:
+			res->name = "Conventional Memory";
+			break;
+		case EFI_UNUSABLE_MEMORY:
+			res->name = "Unusable Memory";
+			break;
+		case EFI_ACPI_RECLAIM_MEMORY:
+			res->name = "ACPI Reclaim";
+			break;
+		case EFI_ACPI_MEMORY_NVS:
+			res->name = "ACPI NVS";
+			break;
+		case EFI_MEMORY_MAPPED_IO:
+			res->name = "Memory Mapped IO";
+			break;
+		case EFI_MEMORY_MAPPED_IO_PORT_SPACE:
+			res->name = "Memory Mapped IO Port Space";
+			break;
+		default:
+			res->name = "Reserved";
+			break;
+		}
+		res->start = md->phys_addr;
+		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);
+		/*
+		 * We don't know which region contains kernel data so we try
+		 * it repeatedly and let the resource manager test it.
+		 */
+		if (md->type == EFI_CONVENTIONAL_MEMORY) {
+			request_resource(res, code_resource);
+			request_resource(res, data_resource);
+		}
+	}
+}
+
+/*
+ * Convenience functions to obtain memory types and attributes
+ */
+
+u32 efi_mem_type(unsigned long phys_addr)
+{
+	efi_memory_desc_t *md;
+	int i;
+
+	for (i = 0; i < memmap.nr_map; i++) {
+		md = &memmap.map[i];
+		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;
+	int i;
+
+	for (i = 0; i < memmap.nr_map; i++) {
+		md = &memmap.map[i];
+		if ((md->phys_addr <= phys_addr) && (phys_addr <
+			(md->phys_addr + (md-> num_pages << EFI_PAGE_SHIFT)) ))
+			return md->attribute;
+	}
+	return 0;
+}
diff -puN /dev/null arch/i386/kernel/efi_stub.S
--- /dev/null	Thu Apr 11 07:25:15 2002
+++ 25-akpm/arch/i386/kernel/efi_stub.S	Mon Nov 17 12:09:20 2003
@@ -0,0 +1,124 @@
+/*
+ * EFI call stub for IA32.
+ *
+ * This stub allows us to make EFI calls in physical mode with interrupts
+ * turned off.
+ */
+
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <asm/page.h>
+#include <asm/pgtable.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
+.previous
+
+.data
+saved_return_addr:
+	.long 0
+efi_rt_function_ptr:
+	.long 0
diff -puN arch/i386/kernel/Makefile~ia32-efi-support arch/i386/kernel/Makefile
--- 25/arch/i386/kernel/Makefile~ia32-efi-support	Mon Nov 17 12:09:20 2003
+++ 25-akpm/arch/i386/kernel/Makefile	Mon Nov 17 12:09:20 2003
@@ -31,6 +31,7 @@ obj-$(CONFIG_MODULES)		+= module.o
 obj-y				+= sysenter.o vsyscall.o
 obj-$(CONFIG_ACPI_SRAT) 	+= srat.o
 obj-$(CONFIG_HPET_TIMER) 	+= time_hpet.o
+obj-$(CONFIG_EFI) 		+= efi.o efi_stub.o
 
 EXTRA_AFLAGS   := -traditional
 
diff -puN arch/i386/kernel/reboot.c~ia32-efi-support arch/i386/kernel/reboot.c
--- 25/arch/i386/kernel/reboot.c~ia32-efi-support	Mon Nov 17 12:09:20 2003
+++ 25-akpm/arch/i386/kernel/reboot.c	Mon Nov 17 12:09:20 2003
@@ -8,6 +8,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/mc146818rtc.h>
+#include <linux/efi.h>
 #include <asm/uaccess.h>
 #include <asm/apic.h>
 #include "mach_reboot.h"
@@ -263,7 +264,12 @@ void machine_restart(char * __unused)
 	disable_IO_APIC();
 #endif
 
-	if(!reboot_thru_bios) {
+	if (!reboot_thru_bios) {
+		if (efi_enabled) {
+			efi.reset_system(EFI_RESET_COLD, EFI_SUCCESS, 0, 0);
+			__asm__ __volatile__("lidt %0": :"m" (no_idt));
+			__asm__ __volatile__("int3");
+		}
 		/* rebooting needs to touch the page at absolute addr 0 */
 		*((unsigned short *)__va(0x472)) = reboot_mode;
 		for (;;) {
@@ -273,6 +279,8 @@ void machine_restart(char * __unused)
 			__asm__ __volatile__("int3");
 		}
 	}
+	if (efi_enabled)
+		efi.reset_system(EFI_RESET_WARM, EFI_SUCCESS, 0, 0);
 
 	machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
 }
@@ -287,6 +295,8 @@ EXPORT_SYMBOL(machine_halt);
 
 void machine_power_off(void)
 {
+	if (efi_enabled)
+		efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, 0);
 	if (pm_power_off)
 		pm_power_off();
 }
diff -puN arch/i386/kernel/setup.c~ia32-efi-support arch/i386/kernel/setup.c
--- 25/arch/i386/kernel/setup.c~ia32-efi-support	Mon Nov 17 12:09:20 2003
+++ 25-akpm/arch/i386/kernel/setup.c	Mon Nov 17 12:09:20 2003
@@ -36,6 +36,8 @@
 #include <linux/root_dev.h>
 #include <linux/highmem.h>
 #include <linux/module.h>
+#include <linux/efi.h>
+#include <linux/init.h>
 #include <video/edid.h>
 #include <asm/e820.h>
 #include <asm/mpspec.h>
@@ -56,6 +58,10 @@ static inline char * __init machine_spec
  * Machine setup..
  */
 
+#ifdef CONFIG_EFI
+int efi_enabled = 0;
+#endif
+
 /* cpu data as detected by the assembly code in head.S */
 struct cpuinfo_x86 new_cpu_data __initdata = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };
 /* common cpu data for all cpus */
@@ -144,6 +150,20 @@ static void __init limit_regions(unsigne
 	unsigned long long current_addr = 0;
 	int i;
 
+	if (efi_enabled) {
+		for (i = 0; i < memmap.nr_map; i++) {
+			current_addr = memmap.map[i].phys_addr +
+				       (memmap.map[i].num_pages << 12);
+			if (memmap.map[i].type == EFI_CONVENTIONAL_MEMORY) {
+				if (current_addr >= size) {
+					memmap.map[i].num_pages -=
+						(((current_addr-size) + PAGE_SIZE-1) >> PAGE_SHIFT);
+					memmap.nr_map = i + 1;
+					return;
+				}
+			}
+		}
+	}
 	for (i = 0; i < e820.nr_map; i++) {
 		if (e820.map[i].type == E820_RAM) {
 			current_addr = e820.map[i].addr + e820.map[i].size;
@@ -159,17 +179,21 @@ static void __init limit_regions(unsigne
 static void __init add_memory_region(unsigned long long start,
                                   unsigned long long size, int type)
 {
-	int x = e820.nr_map;
+	int x;
 
-	if (x == E820MAX) {
-	    printk(KERN_ERR "Ooops! Too many entries in the memory map!\n");
-	    return;
-	}
+	if (!efi_enabled) {
+       		x = e820.nr_map;
 
-	e820.map[x].addr = start;
-	e820.map[x].size = size;
-	e820.map[x].type = type;
-	e820.nr_map++;
+		if (x == E820MAX) {
+		    printk(KERN_ERR "Ooops! Too many entries in the memory map!\n");
+		    return;
+		}
+
+		e820.map[x].addr = start;
+		e820.map[x].size = size;
+		e820.map[x].type = type;
+		e820.nr_map++;
+	}
 } /* add_memory_region */
 
 #define E820_DEBUG	1
@@ -446,7 +470,6 @@ static inline void copy_edd(void)
 static void __init setup_memory_region(void)
 {
 	char *who = machine_specific_memory_setup();
-
 	printk(KERN_INFO "BIOS-provided physical RAM map:\n");
 	print_memory_map(who);
 } /* setup_memory_region */
@@ -584,6 +607,23 @@ static void __init parse_cmdline_early (
 }
 
 /*
+ * Callback for efi_memory_walk.
+ */
+static int __init
+efi_find_max_pfn(unsigned long start, unsigned long end, void *arg)
+{
+	unsigned long *max_pfn = arg, pfn;
+
+	if (start < end) {
+		pfn = PFN_UP(end -1);
+		if (pfn > *max_pfn)
+			*max_pfn = pfn;
+	}
+	return 0;
+}
+
+
+/*
  * Find the highest page frame number we have available
  */
 void __init find_max_pfn(void)
@@ -591,6 +631,11 @@ void __init find_max_pfn(void)
 	int i;
 
 	max_pfn = 0;
+	if (efi_enabled) {
+		efi_memmap_walk(efi_find_max_pfn, &max_pfn);
+		return;
+	}
+
 	for (i = 0; i < e820.nr_map; i++) {
 		unsigned long start, end;
 		/* RAM? */
@@ -665,6 +710,25 @@ unsigned long __init find_max_low_pfn(vo
 }
 
 #ifndef CONFIG_DISCONTIGMEM
+
+/*
+ * Free all available memory for boot time allocation.  Used
+ * as a callback function by efi_memory_walk()
+ */
+
+static int __init
+free_available_memory(unsigned long start, unsigned long end, void *arg)
+{
+	/* check max_low_pfn */
+	if (start >= ((max_low_pfn + 1) << PAGE_SHIFT))
+		return 0;
+	if (end >= ((max_low_pfn + 1) << PAGE_SHIFT))
+		end = (max_low_pfn + 1) << PAGE_SHIFT;
+	if (start < end)
+		free_bootmem(start, end - start);
+
+	return 0;
+}
 /*
  * Register fully available low RAM pages with the bootmem allocator.
  */
@@ -672,6 +736,10 @@ static void __init register_bootmem_low_
 {
 	int i;
 
+	if (efi_enabled) {
+		efi_memmap_walk(free_available_memory, NULL);
+		return;
+	}
 	for (i = 0; i < e820.nr_map; i++) {
 		unsigned long curr_pfn, last_pfn, size;
 		/*
@@ -799,9 +867,9 @@ extern unsigned long setup_memory(void);
  * Request address space for all standard RAM and ROM resources
  * and also for regions reported as reserved by the e820.
  */
-static void __init register_memory(unsigned long max_low_pfn)
+static void __init
+legacy_init_iomem_resources(struct resource *code_resource, struct resource *data_resource)
 {
-	unsigned long low_mem_size;
 	int i;
 
 	probe_roms();
@@ -826,11 +894,26 @@ static void __init register_memory(unsig
 			 *  so we try it repeatedly and let the resource manager
 			 *  test it.
 			 */
-			request_resource(res, &code_resource);
-			request_resource(res, &data_resource);
+			request_resource(res, code_resource);
+			request_resource(res, data_resource);
 		}
 	}
+}
 
+/*
+ * Request address space for all standard resources
+ */
+static void __init register_memory(unsigned long max_low_pfn)
+{
+	unsigned long low_mem_size;
+	int i;
+
+	if (efi_enabled)
+		efi_initialize_iomem_resources(&code_resource, &data_resource);
+	else
+		legacy_init_iomem_resources(&code_resource, &data_resource);
+
+ 	 /* EFI systems may still have VGA */
 	request_graphics_resource();
 
 	/* request I/O space for devices used on all i[345]86 PCs */
@@ -950,6 +1033,13 @@ static int __init noreplacement_setup(ch
 
 __setup("noreplacement", noreplacement_setup); 
 
+/*
+ * Determine if we were loaded by an EFI loader.  If so, then we have also been
+ * passed the efi memmap, systab, etc., so we should use these data structures
+ * for initialization.  Note, the efi init code path is determined by the
+ * global efi_enabled. This allows the same kernel image to be used on existing
+ * systems (with a traditional BIOS) as well as on EFI systems.
+ */
 void __init setup_arch(char **cmdline_p)
 {
 	unsigned long max_low_pfn;
@@ -958,6 +1048,18 @@ void __init setup_arch(char **cmdline_p)
 	pre_setup_arch_hook();
 	early_cpu_init();
 
+	/*
+	 * FIXME: This isn't an official loader_type right
+	 * now but does currently work with elilo.
+	 * If we were configured as an EFI kernel, check to make
+	 * sure that we were loaded correctly from elilo and that
+	 * the system table is valid.  If not, then initialize normally.
+	 */
+#ifdef CONFIG_EFI
+	if ((LOADER_TYPE == 0x50) && EFI_SYSTAB)
+		efi_enabled = 1;
+#endif
+
  	ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV);
  	drive_info = DRIVE_INFO;
  	screen_info = SCREEN_INFO;
@@ -979,7 +1081,11 @@ void __init setup_arch(char **cmdline_p)
 	rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
 #endif
 	ARCH_SETUP
-	setup_memory_region();
+	if (efi_enabled)
+		efi_init();
+	else
+		setup_memory_region();
+
 	copy_edd();
 
 	if (!MOUNT_ROOT_RDONLY)
@@ -1013,6 +1119,8 @@ void __init setup_arch(char **cmdline_p)
 #ifdef CONFIG_X86_GENERICARCH
 	generic_apic_probe(*cmdline_p);
 #endif	
+	if (efi_enabled)
+		efi_map_memmap();
 
 	/*
 	 * Parse the ACPI tables for possible boot-time SMP configuration.
@@ -1028,7 +1136,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 -puN arch/i386/kernel/time.c~ia32-efi-support arch/i386/kernel/time.c
--- 25/arch/i386/kernel/time.c~ia32-efi-support	Mon Nov 17 12:09:20 2003
+++ 25-akpm/arch/i386/kernel/time.c	Mon Nov 17 12:09:20 2003
@@ -44,6 +44,7 @@
 #include <linux/module.h>
 #include <linux/sysdev.h>
 #include <linux/bcd.h>
+#include <linux/efi.h>
 
 #include <asm/io.h>
 #include <asm/smp.h>
@@ -169,7 +170,10 @@ static int set_rtc_mmss(unsigned long no
 
 	/* gets recalled with irq locally disabled */
 	spin_lock(&rtc_lock);
-	retval = mach_set_rtc_mmss(nowtime);
+	if (efi_enabled)
+		retval = efi_set_rtc_mmss(nowtime);
+	else
+		retval = mach_set_rtc_mmss(nowtime);
 	spin_unlock(&rtc_lock);
 
 	return retval;
@@ -227,7 +231,13 @@ static inline void do_timer_interrupt(in
 			>= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 &&
 	    (xtime.tv_nsec / 1000)
 			<= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2) {
-		if (set_rtc_mmss(xtime.tv_sec) == 0)
+		/* horrible...FIXME */
+		if (efi_enabled) {
+	 		if (efi_set_rtc_mmss(xtime.tv_sec) == 0)
+				last_rtc_update = xtime.tv_sec;
+			else
+				last_rtc_update = xtime.tv_sec - 600;
+		} else if (set_rtc_mmss(xtime.tv_sec) == 0)
 			last_rtc_update = xtime.tv_sec;
 		else
 			last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
@@ -281,7 +291,10 @@ unsigned long get_cmos_time(void)
 
 	spin_lock(&rtc_lock);
 
-	retval = mach_get_cmos_time();
+	if (efi_enabled)
+		retval = efi_get_time();
+	else
+		retval = mach_get_cmos_time();
 
 	spin_unlock(&rtc_lock);
 
@@ -292,6 +305,7 @@ static struct sysdev_class pit_sysclass 
 	set_kset_name("pit"),
 };
 
+
 /* XXX this driverfs stuff should probably go elsewhere later -john */
 static struct sys_device device_i8253 = {
 	.id	= 0,
@@ -339,7 +353,6 @@ void __init time_init(void)
 		return;
 	}
 #endif
-
 	xtime.tv_sec = get_cmos_time();
 	wall_to_monotonic.tv_sec = -xtime.tv_sec;
 	xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
diff -puN arch/i386/mm/init.c~ia32-efi-support arch/i386/mm/init.c
--- 25/arch/i386/mm/init.c~ia32-efi-support	Mon Nov 17 12:09:20 2003
+++ 25-akpm/arch/i386/mm/init.c	Mon Nov 17 12:09:20 2003
@@ -26,6 +26,7 @@
 #include <linux/bootmem.h>
 #include <linux/slab.h>
 #include <linux/proc_fs.h>
+#include <linux/efi.h>
 
 #include <asm/processor.h>
 #include <asm/system.h>
@@ -165,12 +166,30 @@ static inline int page_kills_ppro(unsign
 	return 0;
 }
 
+extern int is_available_memory(efi_memory_desc_t *);
+
 static inline int page_is_ram(unsigned long pagenr)
 {
 	int i;
+	unsigned long addr, end;
+
+	if (efi_enabled) {
+		efi_memory_desc_t *md;
+
+		for (i = 0; i < memmap.nr_map; i++) {
+			md = &memmap.map[i];
+			if (!is_available_memory(md))
+				continue;
+			addr = (md->phys_addr+PAGE_SIZE-1) >> PAGE_SHIFT;
+			end = (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT)) >> PAGE_SHIFT;
+
+			if ((pagenr >= addr) && (pagenr < end))
+				return 1;
+		}
+		return 0;
+	}
 
 	for (i = 0; i < e820.nr_map; i++) {
-		unsigned long addr, end;
 
 		if (e820.map[i].type != E820_RAM)	/* not usable memory */
 			continue;
diff -puN drivers/acpi/Kconfig~ia32-efi-support drivers/acpi/Kconfig
--- 25/drivers/acpi/Kconfig~ia32-efi-support	Mon Nov 17 12:09:20 2003
+++ 25-akpm/drivers/acpi/Kconfig	Mon Nov 17 12:09:20 2003
@@ -251,12 +251,6 @@ config ACPI_SYSTEM
 	  This driver will enable your system to shut down using ACPI, and
 	  dump your ACPI DSDT table using /proc/acpi/dsdt.
 
-config ACPI_EFI
-	bool
-	depends on ACPI_INTERPRETER
-	depends on IA64
-	default y
-
 config ACPI_RELAXED_AML
 	bool "Relaxed AML"
 	depends on ACPI_INTERPRETER
diff -puN drivers/acpi/osl.c~ia32-efi-support drivers/acpi/osl.c
--- 25/drivers/acpi/osl.c~ia32-efi-support	Mon Nov 17 12:09:20 2003
+++ 25-akpm/drivers/acpi/osl.c	Mon Nov 17 12:09:20 2003
@@ -41,10 +41,7 @@
 #include <acpi/acpi_bus.h>
 #include <asm/uaccess.h>
 
-#ifdef CONFIG_ACPI_EFI
 #include <linux/efi.h>
-u64 efi_mem_attributes (u64 phys_addr);
-#endif
 
 
 #define _COMPONENT		ACPI_OS_SERVICES
@@ -140,22 +137,24 @@ acpi_os_free(void *ptr)
 acpi_status
 acpi_os_get_root_pointer(u32 flags, struct acpi_pointer *addr)
 {
-#ifdef CONFIG_ACPI_EFI
-	addr->pointer_type = ACPI_PHYSICAL_POINTER;
-	if (efi.acpi20)
-		addr->pointer.physical = (acpi_physical_address) virt_to_phys(efi.acpi20);
-	else if (efi.acpi)
-		addr->pointer.physical = (acpi_physical_address) virt_to_phys(efi.acpi);
-	else {
-		printk(KERN_ERR PREFIX "System description tables not found\n");
-		return AE_NOT_FOUND;
-	}
-#else
-	if (ACPI_FAILURE(acpi_find_root_pointer(flags, addr))) {
-		printk(KERN_ERR PREFIX "System description tables not found\n");
-		return AE_NOT_FOUND;
+	if (efi_enabled) {
+		addr->pointer_type = ACPI_PHYSICAL_POINTER;
+		if (efi.acpi20)
+			addr->pointer.physical =
+				(acpi_physical_address) virt_to_phys(efi.acpi20);
+		else if (efi.acpi)
+			addr->pointer.physical =
+				(acpi_physical_address) virt_to_phys(efi.acpi);
+		else {
+			printk(KERN_ERR PREFIX "System description tables not found\n");
+			return AE_NOT_FOUND;
+		}
+	} else {
+		if (ACPI_FAILURE(acpi_find_root_pointer(flags, addr))) {
+			printk(KERN_ERR PREFIX "System description tables not found\n");
+			return AE_NOT_FOUND;
+		}
 	}
-#endif /*CONFIG_ACPI_EFI*/
 
 	return AE_OK;
 }
@@ -163,22 +162,22 @@ acpi_os_get_root_pointer(u32 flags, stru
 acpi_status
 acpi_os_map_memory(acpi_physical_address phys, acpi_size size, void **virt)
 {
-#ifdef CONFIG_ACPI_EFI
-	if (EFI_MEMORY_WB & efi_mem_attributes(phys)) {
-		*virt = phys_to_virt(phys);
+	if (efi_enabled) {
+		if (EFI_MEMORY_WB & efi_mem_attributes(phys)) {
+			*virt = phys_to_virt(phys);
+		} else {
+			*virt = ioremap(phys, size);
+		}
 	} else {
-		*virt = ioremap(phys, size);
-	}
-#else
-	if (phys > ULONG_MAX) {
-		printk(KERN_ERR PREFIX "Cannot map memory that high\n");
-		return AE_BAD_PARAMETER;
+		if (phys > ULONG_MAX) {
+			printk(KERN_ERR PREFIX "Cannot map memory that high\n");
+			return AE_BAD_PARAMETER;
+		}
+		/*
+	 	 * ioremap checks to ensure this is in reserved space
+	 	 */
+		*virt = ioremap((unsigned long) phys, size);
 	}
-	/*
-	 * ioremap checks to ensure this is in reserved space
-	 */
-	*virt = ioremap((unsigned long) phys, size);
-#endif
 
 	if (!*virt)
 		return AE_NO_MEMORY;
@@ -369,19 +368,17 @@ acpi_os_read_memory(
 {
 	u32			dummy;
 	void			*virt_addr;
-
-#ifdef CONFIG_ACPI_EFI
 	int			iomem = 0;
 
-	if (EFI_MEMORY_WB & efi_mem_attributes(phys_addr)) {
+	if (efi_enabled) {
+		if (EFI_MEMORY_WB & efi_mem_attributes(phys_addr)) {
+			virt_addr = phys_to_virt(phys_addr);
+		} else {
+			iomem = 1;
+			virt_addr = ioremap(phys_addr, width);
+		}
+	} else
 		virt_addr = phys_to_virt(phys_addr);
-	} else {
-		iomem = 1;
-		virt_addr = ioremap(phys_addr, width);
-	}
-#else
-	virt_addr = phys_to_virt(phys_addr);
-#endif
 	if (!value)
 		value = &dummy;
 
@@ -399,10 +396,10 @@ acpi_os_read_memory(
 		BUG();
 	}
 
-#ifdef CONFIG_ACPI_EFI
-	if (iomem)
-		iounmap(virt_addr);
-#endif
+	if (efi_enabled) {
+		if (iomem)
+			iounmap(virt_addr);
+	}
 
 	return AE_OK;
 }
@@ -414,19 +411,17 @@ acpi_os_write_memory(
 	u32			width)
 {
 	void			*virt_addr;
-
-#ifdef CONFIG_ACPI_EFI
 	int			iomem = 0;
 
-	if (EFI_MEMORY_WB & efi_mem_attributes(phys_addr)) {
+	if (efi_enabled) {
+		if (EFI_MEMORY_WB & efi_mem_attributes(phys_addr)) {
+			virt_addr = phys_to_virt(phys_addr);
+		} else {
+			iomem = 1;
+			virt_addr = ioremap(phys_addr, width);
+		}
+	} else
 		virt_addr = phys_to_virt(phys_addr);
-	} else {
-		iomem = 1;
-		virt_addr = ioremap(phys_addr, width);
-	}
-#else
-	virt_addr = phys_to_virt(phys_addr);
-#endif
 
 	switch (width) {
 	case 8:
@@ -442,10 +437,8 @@ acpi_os_write_memory(
 		BUG();
 	}
 
-#ifdef CONFIG_ACPI_EFI
 	if (iomem)
 		iounmap(virt_addr);
-#endif
 
 	return AE_OK;
 }
diff -puN include/asm-i386/setup.h~ia32-efi-support include/asm-i386/setup.h
--- 25/include/asm-i386/setup.h~ia32-efi-support	Mon Nov 17 12:09:20 2003
+++ 25-akpm/include/asm-i386/setup.h	Mon Nov 17 12:09:20 2003
@@ -29,6 +29,11 @@
 #define IST_INFO   (*(struct ist_info *) (PARAM+0x60))
 #define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
 #define SYS_DESC_TABLE (*(struct sys_desc_table_struct*)(PARAM+0xa0))
+#define EFI_SYSTAB ((efi_system_table_t *) *((unsigned long *)(PARAM+0x1c4)))
+#define EFI_MEMDESC_SIZE (*((unsigned long *) (PARAM+0x1c8)))
+#define EFI_MEMDESC_VERSION (*((unsigned long *) (PARAM+0x1cc)))
+#define EFI_MEMMAP ((efi_memory_desc_t *) *((unsigned long *)(PARAM+0x1d0)))
+#define EFI_MEMMAP_SIZE (*((unsigned long *) (PARAM+0x1d4)))
 #define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))
 #define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8))
 #define VIDEO_MODE (*(unsigned short *) (PARAM+0x1FA))
diff -puN include/linux/efi.h~ia32-efi-support include/linux/efi.h
--- 25/include/linux/efi.h~ia32-efi-support	Mon Nov 17 12:09:20 2003
+++ 25-akpm/include/linux/efi.h	Mon Nov 17 12:09:20 2003
@@ -16,6 +16,8 @@
 #include <linux/time.h>
 #include <linux/types.h>
 #include <linux/proc_fs.h>
+#include <linux/rtc.h>
+#include <linux/ioport.h>
 
 #include <asm/page.h>
 #include <asm/system.h>
@@ -77,18 +79,23 @@ typedef	struct {
 #define EFI_MAX_MEMORY_TYPE		14
 
 /* Attribute values: */
-#define EFI_MEMORY_UC		0x0000000000000001	/* uncached */
-#define EFI_MEMORY_WC		0x0000000000000002	/* write-coalescing */
-#define EFI_MEMORY_WT		0x0000000000000004	/* write-through */
-#define EFI_MEMORY_WB		0x0000000000000008	/* write-back */
-#define EFI_MEMORY_WP		0x0000000000001000	/* write-protect */
-#define EFI_MEMORY_RP		0x0000000000002000	/* read-protect */
-#define EFI_MEMORY_XP		0x0000000000004000	/* execute-protect */
-#define EFI_MEMORY_RUNTIME	0x8000000000000000	/* range requires runtime mapping */
+#define EFI_MEMORY_UC		((u64)0x0000000000000001ULL)	/* uncached */
+#define EFI_MEMORY_WC		((u64)0x0000000000000002ULL)	/* write-coalescing */
+#define EFI_MEMORY_WT		((u64)0x0000000000000004ULL)	/* write-through */
+#define EFI_MEMORY_WB		((u64)0x0000000000000008ULL)	/* write-back */
+#define EFI_MEMORY_WP		((u64)0x0000000000001000ULL)	/* write-protect */
+#define EFI_MEMORY_RP		((u64)0x0000000000002000ULL)	/* read-protect */
+#define EFI_MEMORY_XP		((u64)0x0000000000004000ULL)	/* execute-protect */
+#define EFI_MEMORY_RUNTIME	((u64)0x8000000000000000ULL)	/* range requires runtime mapping */
 #define EFI_MEMORY_DESCRIPTOR_VERSION	1
 
 #define EFI_PAGE_SHIFT		12
 
+/*
+ * For current x86 implementations of EFI, there is
+ * additional padding in the mem descriptors.  This is not
+ * the case in ia64.  Need to have this fixed in the f/w.
+ */
 typedef struct {
 	u32 type;
 	u32 pad;
@@ -96,6 +103,9 @@ typedef struct {
 	u64 virt_addr;
 	u64 num_pages;
 	u64 attribute;
+#if defined (__i386__)
+	u64 pad1;
+#endif
 } efi_memory_desc_t;
 
 typedef int efi_freemem_callback_t (unsigned long start, unsigned long end, void *arg);
@@ -132,11 +142,12 @@ typedef struct {
  */
 #define EFI_RESET_COLD 0
 #define EFI_RESET_WARM 1
+#define EFI_RESET_SHUTDOWN 2
 
 /*
  * EFI Runtime Services table
  */
-#define EFI_RUNTIME_SERVICES_SIGNATURE 0x5652453544e5552
+#define EFI_RUNTIME_SERVICES_SIGNATURE ((u64)0x5652453544e5552ULL)
 #define EFI_RUNTIME_SERVICES_REVISION  0x00010000
 
 typedef struct {
@@ -169,6 +180,10 @@ typedef efi_status_t efi_set_variable_t 
 typedef efi_status_t efi_get_next_high_mono_count_t (u32 *count);
 typedef void efi_reset_system_t (int reset_type, efi_status_t status,
 				 unsigned long data_size, efi_char16_t *data);
+typedef efi_status_t efi_set_virtual_address_map_t (unsigned long memory_map_size,
+						unsigned long descriptor_size,
+						u32 descriptor_version,
+						efi_memory_desc_t *virtual_map);
 
 /*
  *  EFI Configuration Table and GUID definitions
@@ -194,12 +209,15 @@ typedef void efi_reset_system_t (int res
 #define HCDP_TABLE_GUID	\
     EFI_GUID(  0xf951938d, 0x620b, 0x42ef, 0x82, 0x79, 0xa8, 0x4b, 0x79, 0x61, 0x78, 0x98 )
 
+#define UGA_IO_PROTOCOL_GUID \
+    EFI_GUID(  0x61a4d49e, 0x6f68, 0x4f1b, 0xb9, 0x22, 0xa8, 0x6e, 0xed, 0xb, 0x7, 0xa2 )
+
 typedef struct {
 	efi_guid_t guid;
 	unsigned long table;
 } efi_config_table_t;
 
-#define EFI_SYSTEM_TABLE_SIGNATURE 0x5453595320494249
+#define EFI_SYSTEM_TABLE_SIGNATURE ((u64)0x5453595320494249ULL)
 #define EFI_SYSTEM_TABLE_REVISION  ((1 << 16) | 00)
 
 typedef struct {
@@ -218,6 +236,13 @@ typedef struct {
 	unsigned long tables;
 } efi_system_table_t;
 
+struct efi_memory_map {
+	efi_memory_desc_t *phys_map;
+	efi_memory_desc_t *map;
+	int nr_map;
+	unsigned long desc_version;
+};
+
 /*
  * All runtime access to EFI goes through this structure:
  */
@@ -230,6 +255,7 @@ extern struct efi {
 	void *sal_systab;		/* SAL system table */
 	void *boot_info;		/* boot info table */
 	void *hcdp;			/* HCDP table */
+	void *uga;			/* UGA table */
 	efi_get_time_t *get_time;
 	efi_set_time_t *set_time;
 	efi_get_wakeup_time_t *get_wakeup_time;
@@ -239,6 +265,7 @@ extern struct efi {
 	efi_set_variable_t *set_variable;
 	efi_get_next_high_mono_count_t *get_next_high_mono_count;
 	efi_reset_system_t *reset_system;
+	efi_set_virtual_address_map_t *set_virtual_address_map;
 } efi;
 
 static inline int
@@ -260,12 +287,25 @@ efi_guid_unparse(efi_guid_t *guid, char 
 
 extern void efi_init (void);
 extern void efi_map_pal_code (void);
+extern void efi_map_memmap(void);
 extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg);
 extern void efi_gettimeofday (struct timespec *ts);
 extern void efi_enter_virtual_mode (void);	/* switch EFI to virtual mode, if possible */
 extern u64 efi_get_iobase (void);
 extern u32 efi_mem_type (unsigned long phys_addr);
 extern u64 efi_mem_attributes (unsigned long phys_addr);
+extern void efi_initialize_iomem_resources(struct resource *code_resource,
+					struct resource *data_resource);
+extern efi_status_t phys_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc);
+extern unsigned long inline __init efi_get_time(void);
+extern int inline __init efi_set_rtc_mmss(unsigned long nowtime);
+extern struct efi_memory_map memmap;
+
+#ifdef CONFIG_EFI
+extern int efi_enabled;
+#else
+#define efi_enabled 0
+#endif
 
 /*
  * Variable Attributes
diff -puN init/main.c~ia32-efi-support init/main.c
--- 25/init/main.c~ia32-efi-support	Mon Nov 17 12:09:20 2003
+++ 25-akpm/init/main.c	Mon Nov 17 12:09:20 2003
@@ -38,6 +38,7 @@
 #include <linux/moduleparam.h>
 #include <linux/writeback.h>
 #include <linux/cpu.h>
+#include <linux/efi.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -443,6 +444,10 @@ asmlinkage void __init start_kernel(void
 	pidmap_init();
 	pgtable_cache_init();
 	pte_chain_init();
+#ifdef CONFIG_X86
+	if (efi_enabled)
+		efi_enter_virtual_mode();
+#endif
 	fork_init(num_physpages);
 	proc_caches_init();
 	buffer_init();
diff -puN arch/ia64/defconfig~ia32-efi-support arch/ia64/defconfig
--- 25/arch/ia64/defconfig~ia32-efi-support	Mon Nov 17 12:09:20 2003
+++ 25-akpm/arch/ia64/defconfig	Mon Nov 17 12:09:20 2003
@@ -48,7 +48,6 @@ CONFIG_IA64_HP_ZX1=y
 CONFIG_IA64_PAGE_SIZE_16KB=y
 # CONFIG_IA64_PAGE_SIZE_64KB is not set
 CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
 CONFIG_ACPI_INTERPRETER=y
 CONFIG_ACPI_KERNEL_CONFIG=y
 CONFIG_IA64_L1_CACHE_SHIFT=7
@@ -76,6 +75,7 @@ CONFIG_IA32_SUPPORT=y
 CONFIG_COMPAT=y
 CONFIG_PERFMON=y
 CONFIG_IA64_PALINFO=y
+CONFIG_EFI=y
 CONFIG_EFI_VARS=y
 CONFIG_NR_CPUS=16
 CONFIG_BINFMT_ELF=y
diff -puN arch/ia64/Kconfig~ia32-efi-support arch/ia64/Kconfig
--- 25/arch/ia64/Kconfig~ia32-efi-support	Mon Nov 17 12:09:20 2003
+++ 25-akpm/arch/ia64/Kconfig	Mon Nov 17 12:09:20 2003
@@ -164,11 +164,6 @@ config ACPI
 	  The ACPI Sourceforge project may also be of interest:
 	  <http://sf.net/projects/acpi/>
 
-config ACPI_EFI
-	bool
-	depends on !IA64_HP_SIM
-	default y
-
 config ACPI_INTERPRETER
 	bool
 	depends on !IA64_HP_SIM
@@ -404,6 +399,11 @@ config IA64_SALINFO
 	  To use this option, you have to ensure that the "/proc file system
 	  support" (CONFIG_PROC_FS) is enabled, too.
 
+config EFI
+	bool
+	depends on !IA64_HP_SIM
+	default y
+
 config EFI_VARS
 	tristate "/proc/efi/vars support"
 	help
diff -puN arch/ia64/kernel/setup.c~ia32-efi-support arch/ia64/kernel/setup.c
--- 25/arch/ia64/kernel/setup.c~ia32-efi-support	Mon Nov 17 12:09:20 2003
+++ 25-akpm/arch/ia64/kernel/setup.c	Mon Nov 17 12:09:20 2003
@@ -54,6 +54,10 @@
 # error "struct cpuinfo_ia64 too big!"
 #endif
 
+#ifdef CONFIG_EFI
+int efi_enabled = 1;
+#endif
+
 #ifdef CONFIG_SMP
 unsigned long __per_cpu_offset[NR_CPUS];
 #endif

_