Matthew Garrett 0988eed
Default to physical mode in EFI. Fixes boot problems on some machines,
Matthew Garrett 0988eed
upstream will probably head in this direction.
Matthew Garrett 0988eed
Matthew Garrett 0988eed
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
Matthew Garrett 0988eed
index 8e4a165..3c62f15 100644
Matthew Garrett 0988eed
--- a/arch/x86/include/asm/efi.h
Matthew Garrett 0988eed
+++ b/arch/x86/include/asm/efi.h
Matthew Garrett 0988eed
@@ -93,6 +93,9 @@ extern int add_efi_memmap;
Matthew Garrett 0988eed
 extern void efi_memblock_x86_reserve_range(void);
Matthew Garrett 0988eed
 extern void efi_call_phys_prelog(void);
Matthew Garrett 0988eed
 extern void efi_call_phys_epilog(void);
Matthew Garrett 0988eed
+extern void efi_call_phys_prelog_in_physmode(void);
Matthew Garrett 0988eed
+extern void efi_call_phys_epilog_in_physmode(void);
Matthew Garrett 0988eed
+extern void efi_pagetable_init(void);
Matthew Garrett 0988eed
 
Matthew Garrett 0988eed
 #ifndef CONFIG_EFI
Matthew Garrett 0988eed
 /*
Matthew Garrett 0988eed
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
Matthew Garrett 0988eed
index 0fe27d7..e1158b0 100644
Matthew Garrett 0988eed
--- a/arch/x86/platform/efi/efi.c
Matthew Garrett 0988eed
+++ b/arch/x86/platform/efi/efi.c
Matthew Garrett 0988eed
@@ -58,6 +58,7 @@ struct efi_memory_map memmap;
Matthew Garrett 0988eed
 
Matthew Garrett 0988eed
 static struct efi efi_phys __initdata;
Matthew Garrett 0988eed
 static efi_system_table_t efi_systab __initdata;
Matthew Garrett 0988eed
+static efi_runtime_services_t phys_runtime;
Matthew Garrett 0988eed
 
Matthew Garrett 0988eed
 static int __init setup_noefi(char *arg)
Matthew Garrett 0988eed
 {
Matthew Garrett 0988eed
@@ -172,7 +173,7 @@ static efi_status_t __init phys_efi_set_virtual_address_map(
Matthew Garrett 0988eed
 	return status;
Matthew Garrett 0988eed
 }
Matthew Garrett 0988eed
 
Matthew Garrett 0988eed
-static efi_status_t __init phys_efi_get_time(efi_time_t *tm,
Matthew Garrett 0988eed
+static efi_status_t __init phys_efi_get_time_early(efi_time_t *tm,
Matthew Garrett 0988eed
 					     efi_time_cap_t *tc)
Matthew Garrett 0988eed
 {
Matthew Garrett 0988eed
 	efi_status_t status;
Matthew Garrett 0988eed
@@ -183,6 +184,112 @@ static efi_status_t __init phys_efi_get_time(efi_time_t *tm,
Matthew Garrett 0988eed
 	return status;
Matthew Garrett 0988eed
 }
Matthew Garrett 0988eed
 
Matthew Garrett 0988eed
+static efi_status_t phys_efi_get_time(efi_time_t *tm,
Matthew Garrett 0988eed
+				      efi_time_cap_t *tc)
Matthew Garrett 0988eed
+{
Matthew Garrett 0988eed
+	efi_status_t status;
Matthew Garrett 0988eed
+
Matthew Garrett 0988eed
+	efi_call_phys_prelog_in_physmode();
Matthew Garrett 0988eed
+	status = efi_call_phys2((void*)phys_runtime.get_time, tm, tc);
Matthew Garrett 0988eed
+	efi_call_phys_epilog_in_physmode();
Matthew Garrett 0988eed
+	return status;
Matthew Garrett 0988eed
+}
Matthew Garrett 0988eed
+
Matthew Garrett 0988eed
+static efi_status_t __init phys_efi_set_time(efi_time_t *tm)
Matthew Garrett 0988eed
+{
Matthew Garrett 0988eed
+	efi_status_t status;
Matthew Garrett 0988eed
+
Matthew Garrett 0988eed
+	efi_call_phys_prelog_in_physmode();
Matthew Garrett 0988eed
+	status = efi_call_phys1((void*)phys_runtime.set_time, tm);
Matthew Garrett 0988eed
+	efi_call_phys_epilog_in_physmode();
Matthew Garrett 0988eed
+	return status;
Matthew Garrett 0988eed
+}
Matthew Garrett 0988eed
+
Matthew Garrett 0988eed
+static efi_status_t phys_efi_get_wakeup_time(efi_bool_t *enabled,
Matthew Garrett 0988eed
+                                             efi_bool_t *pending,
Matthew Garrett 0988eed
+                                             efi_time_t *tm)
Matthew Garrett 0988eed
+{
Matthew Garrett 0988eed
+	efi_status_t status;
Matthew Garrett 0988eed
+
Matthew Garrett 0988eed
+	efi_call_phys_prelog_in_physmode();
Matthew Garrett 0988eed
+	status = efi_call_phys3((void*)phys_runtime.get_wakeup_time, enabled,
Matthew Garrett 0988eed
+				pending, tm);
Matthew Garrett 0988eed
+	efi_call_phys_epilog_in_physmode();
Matthew Garrett 0988eed
+	return status;
Matthew Garrett 0988eed
+}
Matthew Garrett 0988eed
+
Matthew Garrett 0988eed
+static efi_status_t phys_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
Matthew Garrett 0988eed
+{
Matthew Garrett 0988eed
+	efi_status_t status;
Matthew Garrett 0988eed
+	efi_call_phys_prelog_in_physmode();
Matthew Garrett 0988eed
+	status = efi_call_phys2((void*)phys_runtime.set_wakeup_time, enabled,
Matthew Garrett 0988eed
+				tm);
Matthew Garrett 0988eed
+	efi_call_phys_epilog_in_physmode();
Matthew Garrett 0988eed
+	return status;
Matthew Garrett 0988eed
+}
Matthew Garrett 0988eed
+
Matthew Garrett 0988eed
+static efi_status_t phys_efi_get_variable(efi_char16_t *name,
Matthew Garrett 0988eed
+					  efi_guid_t *vendor,
Matthew Garrett 0988eed
+					  u32 *attr,
Matthew Garrett 0988eed
+					  unsigned long *data_size,
Matthew Garrett 0988eed
+					  void *data)
Matthew Garrett 0988eed
+{
Matthew Garrett 0988eed
+	efi_status_t status;
Matthew Garrett 0988eed
+	efi_call_phys_prelog_in_physmode();
Matthew Garrett 0988eed
+	status = efi_call_phys5((void*)phys_runtime.get_variable, name, vendor,
Matthew Garrett 0988eed
+				attr, data_size, data);
Matthew Garrett 0988eed
+	efi_call_phys_epilog_in_physmode();
Matthew Garrett 0988eed
+	return status;
Matthew Garrett 0988eed
+}
Matthew Garrett 0988eed
+
Matthew Garrett 0988eed
+static efi_status_t phys_efi_get_next_variable(unsigned long *name_size,
Matthew Garrett 0988eed
+					       efi_char16_t *name,
Matthew Garrett 0988eed
+					       efi_guid_t *vendor)
Matthew Garrett 0988eed
+{
Matthew Garrett 0988eed
+	efi_status_t status;
Matthew Garrett 0988eed
+
Matthew Garrett 0988eed
+	efi_call_phys_prelog_in_physmode();
Matthew Garrett 0988eed
+	status = efi_call_phys3((void*)phys_runtime.get_next_variable,
Matthew Garrett 0988eed
+				name_size, name, vendor);
Matthew Garrett 0988eed
+	efi_call_phys_epilog_in_physmode();
Matthew Garrett 0988eed
+	return status;
Matthew Garrett 0988eed
+}
Matthew Garrett 0988eed
+
Matthew Garrett 0988eed
+static efi_status_t phys_efi_set_variable(efi_char16_t *name,
Matthew Garrett 0988eed
+					  efi_guid_t *vendor,
Matthew Garrett 0988eed
+					  unsigned long attr,
Matthew Garrett 0988eed
+					  unsigned long data_size,
Matthew Garrett 0988eed
+					  void *data)
Matthew Garrett 0988eed
+{
Matthew Garrett 0988eed
+	efi_status_t status;
Matthew Garrett 0988eed
+	efi_call_phys_prelog_in_physmode();
Matthew Garrett 0988eed
+	status = efi_call_phys5((void*)phys_runtime.set_variable, name,
Matthew Garrett 0988eed
+				vendor, attr, data_size, data);
Matthew Garrett 0988eed
+	efi_call_phys_epilog_in_physmode();
Matthew Garrett 0988eed
+	return status;
Matthew Garrett 0988eed
+}
Matthew Garrett 0988eed
+
Matthew Garrett 0988eed
+static efi_status_t phys_efi_get_next_high_mono_count(u32 *count)
Matthew Garrett 0988eed
+{
Matthew Garrett 0988eed
+	efi_status_t status;
Matthew Garrett 0988eed
+	efi_call_phys_prelog_in_physmode();
Matthew Garrett 0988eed
+	status = efi_call_phys1((void*)phys_runtime.get_next_high_mono_count,
Matthew Garrett 0988eed
+				count);
Matthew Garrett 0988eed
+	efi_call_phys_epilog_in_physmode();
Matthew Garrett 0988eed
+	return status;
Matthew Garrett 0988eed
+}
Matthew Garrett 0988eed
+
Matthew Garrett 0988eed
+static void phys_efi_reset_system(int reset_type,
Matthew Garrett 0988eed
+                                  efi_status_t status,
Matthew Garrett 0988eed
+                                  unsigned long data_size,
Matthew Garrett 0988eed
+                                  efi_char16_t *data)
Matthew Garrett 0988eed
+{
Matthew Garrett 0988eed
+	efi_call_phys_prelog_in_physmode();
Matthew Garrett 0988eed
+	efi_call_phys4((void*)phys_runtime.reset_system, reset_type, status,
Matthew Garrett 0988eed
+				data_size, data);
Matthew Garrett 0988eed
+	efi_call_phys_epilog_in_physmode();
Matthew Garrett 0988eed
+}
Matthew Garrett 0988eed
+
Matthew Garrett 0988eed
 int efi_set_rtc_mmss(unsigned long nowtime)
Matthew Garrett 0988eed
 {
Matthew Garrett 0988eed
 	int real_seconds, real_minutes;
Matthew Garrett 0988eed
@@ -435,7 +542,9 @@ void __init efi_init(void)
Matthew Garrett 0988eed
 		 * Make efi_get_time can be called before entering
Matthew Garrett 0988eed
 		 * virtual mode.
Matthew Garrett 0988eed
 		 */
Matthew Garrett 0988eed
-		efi.get_time = phys_efi_get_time;
Matthew Garrett 0988eed
+		efi.get_time = phys_efi_get_time_early;
Matthew Garrett 0988eed
+
Matthew Garrett 0988eed
+		memcpy(&phys_runtime, runtime, sizeof(efi_runtime_services_t));
Matthew Garrett 0988eed
 	} else
Matthew Garrett 0988eed
 		printk(KERN_ERR "Could not map the EFI runtime service "
Matthew Garrett 0988eed
 		       "table!\n");
Matthew Garrett 0988eed
@@ -466,6 +575,14 @@ void __init efi_init(void)
Matthew Garrett 0988eed
 #if EFI_DEBUG
Matthew Garrett 0988eed
 	print_efi_memmap();
Matthew Garrett 0988eed
 #endif
Matthew Garrett 0988eed
+
Matthew Garrett 0988eed
+#ifndef CONFIG_X86_64
Matthew Garrett 0988eed
+	/*
Matthew Garrett 0988eed
+	 * Only x86_64 supports physical mode as of now. Use virtual mode
Matthew Garrett 0988eed
+	 * forcibly.
Matthew Garrett 0988eed
+	 */
Matthew Garrett 0988eed
+	usevirtefi = 1;
Matthew Garrett 0988eed
+#endif
Matthew Garrett 0988eed
 }
Matthew Garrett 0988eed
 
Matthew Garrett 0988eed
 static void __init runtime_code_page_mkexec(void)
Matthew Garrett 0988eed
@@ -579,6 +696,27 @@ void __init efi_enter_virtual_mode(void)
Matthew Garrett 0988eed
 	memmap.map = NULL;
Matthew Garrett 0988eed
 }
Matthew Garrett 0988eed
 
Matthew Garrett 0988eed
+void __init efi_setup_physical_mode(void)
Matthew Garrett 0988eed
+{
Matthew Garrett 0988eed
+#ifdef CONFIG_X86_64
Matthew Garrett 0988eed
+	efi_pagetable_init();
Matthew Garrett 0988eed
+#endif
Matthew Garrett 0988eed
+	efi.get_time = phys_efi_get_time;
Matthew Garrett 0988eed
+	efi.set_time = phys_efi_set_time;
Matthew Garrett 0988eed
+	efi.get_wakeup_time = phys_efi_get_wakeup_time;
Matthew Garrett 0988eed
+	efi.set_wakeup_time = phys_efi_set_wakeup_time;
Matthew Garrett 0988eed
+	efi.get_variable = phys_efi_get_variable;
Matthew Garrett 0988eed
+	efi.get_next_variable = phys_efi_get_next_variable;
Matthew Garrett 0988eed
+	efi.set_variable = phys_efi_set_variable;
Matthew Garrett 0988eed
+	efi.get_next_high_mono_count =
Matthew Garrett 0988eed
+		phys_efi_get_next_high_mono_count;
Matthew Garrett 0988eed
+	efi.reset_system = phys_efi_reset_system;
Matthew Garrett 0988eed
+	efi.set_virtual_address_map = NULL; /* Not needed */
Matthew Garrett 0988eed
+
Matthew Garrett 0988eed
+	early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size);
Matthew Garrett 0988eed
+	memmap.map = NULL;
Matthew Garrett 0988eed
+}
Matthew Garrett 0988eed
+
Matthew Garrett 0988eed
 /*
Matthew Garrett 0988eed
  * Convenience functions to obtain memory types and attributes
Matthew Garrett 0988eed
  */
Matthew Garrett 0988eed
diff --git a/arch/x86/platform/efi/efi_32.c b/arch/x86/platform/efi/efi_32.c
Matthew Garrett 0988eed
index 5cab48e..90767b1 100644
Matthew Garrett 0988eed
--- a/arch/x86/platform/efi/efi_32.c
Matthew Garrett 0988eed
+++ b/arch/x86/platform/efi/efi_32.c
Matthew Garrett 0988eed
@@ -110,3 +110,7 @@ void efi_call_phys_epilog(void)
Matthew Garrett 0988eed
 
Matthew Garrett 0988eed
 	local_irq_restore(efi_rt_eflags);
Matthew Garrett 0988eed
 }
Matthew Garrett 0988eed
+
Matthew Garrett 0988eed
+void efi_call_phys_prelog_in_physmode(void) { /* Not supported */ }
Matthew Garrett 0988eed
+void efi_call_phys_epilog_in_physmode(void) { /* Not supported */ }
Matthew Garrett 0988eed
+
Matthew Garrett 0988eed
diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c
Matthew Garrett 0988eed
index ac0621a..33a8192 100644
Matthew Garrett 0988eed
--- a/arch/x86/platform/efi/efi_64.c
Matthew Garrett 0988eed
+++ b/arch/x86/platform/efi/efi_64.c
Matthew Garrett 0988eed
@@ -39,7 +39,9 @@
Matthew Garrett 0988eed
 #include <asm/fixmap.h>
Matthew Garrett 0988eed
 
Matthew Garrett 0988eed
 static pgd_t save_pgd __initdata;
Matthew Garrett 0988eed
-static unsigned long efi_flags __initdata;
Matthew Garrett 0988eed
+static DEFINE_PER_CPU(unsigned long, efi_flags);
Matthew Garrett 0988eed
+static DEFINE_PER_CPU(unsigned long, save_cr3);
Matthew Garrett 0988eed
+static pgd_t efi_pgd[PTRS_PER_PGD] __page_aligned_bss;
Matthew Garrett 0988eed
 
Matthew Garrett 0988eed
 static void __init early_mapping_set_exec(unsigned long start,
Matthew Garrett 0988eed
 					  unsigned long end,
Matthew Garrett 0988eed
@@ -80,7 +82,7 @@ void __init efi_call_phys_prelog(void)
Matthew Garrett 0988eed
 	unsigned long vaddress;
Matthew Garrett 0988eed
 
Matthew Garrett 0988eed
 	early_runtime_code_mapping_set_exec(1);
Matthew Garrett 0988eed
-	local_irq_save(efi_flags);
Matthew Garrett 0988eed
+	local_irq_save(get_cpu_var(efi_flags));
Matthew Garrett 0988eed
 	vaddress = (unsigned long)__va(0x0UL);
Matthew Garrett 0988eed
 	save_pgd = *pgd_offset_k(0x0UL);
Matthew Garrett 0988eed
 	set_pgd(pgd_offset_k(0x0UL), *pgd_offset_k(vaddress));
Matthew Garrett 0988eed
@@ -94,10 +96,23 @@ void __init efi_call_phys_epilog(void)
Matthew Garrett 0988eed
 	 */
Matthew Garrett 0988eed
 	set_pgd(pgd_offset_k(0x0UL), save_pgd);
Matthew Garrett 0988eed
 	__flush_tlb_all();
Matthew Garrett 0988eed
-	local_irq_restore(efi_flags);
Matthew Garrett 0988eed
+	local_irq_restore(get_cpu_var(efi_flags));
Matthew Garrett 0988eed
 	early_runtime_code_mapping_set_exec(0);
Matthew Garrett 0988eed
 }
Matthew Garrett 0988eed
 
Matthew Garrett 0988eed
+void efi_call_phys_prelog_in_physmode(void)
Matthew Garrett 0988eed
+{
Matthew Garrett 0988eed
+	local_irq_save(get_cpu_var(efi_flags));
Matthew Garrett 0988eed
+	get_cpu_var(save_cr3)= read_cr3();
Matthew Garrett 0988eed
+	write_cr3(virt_to_phys(efi_pgd));
Matthew Garrett 0988eed
+}
Matthew Garrett 0988eed
+
Matthew Garrett 0988eed
+void efi_call_phys_epilog_in_physmode(void)
Matthew Garrett 0988eed
+{
Matthew Garrett 0988eed
+	write_cr3(get_cpu_var(save_cr3));
Matthew Garrett 0988eed
+	local_irq_restore(get_cpu_var(efi_flags));
Matthew Garrett 0988eed
+}
Matthew Garrett 0988eed
+
Matthew Garrett 0988eed
 void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size,
Matthew Garrett 0988eed
 				 u32 type)
Matthew Garrett 0988eed
 {
Matthew Garrett 0988eed
@@ -112,3 +127,78 @@ void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size,
Matthew Garrett 0988eed
 
Matthew Garrett 0988eed
 	return (void __iomem *)__va(phys_addr);
Matthew Garrett 0988eed
 }
Matthew Garrett 0988eed
+
Matthew Garrett 0988eed
+static pud_t *fill_pud(pgd_t *pgd, unsigned long vaddr)
Matthew Garrett 0988eed
+{
Matthew Garrett 0988eed
+	if (pgd_none(*pgd)) {
Matthew Garrett 0988eed
+		pud_t *pud = (pud_t *)get_zeroed_page(GFP_ATOMIC);
Matthew Garrett 0988eed
+		set_pgd(pgd, __pgd(_PAGE_TABLE | __pa(pud)));
Matthew Garrett 0988eed
+		if (pud != pud_offset(pgd, 0))
Matthew Garrett 0988eed
+			printk(KERN_ERR "EFI PAGETABLE BUG #00! %p <-> %p\n",
Matthew Garrett 0988eed
+			       pud, pud_offset(pgd, 0));
Matthew Garrett 0988eed
+	}
Matthew Garrett 0988eed
+	return pud_offset(pgd, vaddr);
Matthew Garrett 0988eed
+}
Matthew Garrett 0988eed
+
Matthew Garrett 0988eed
+static pmd_t *fill_pmd(pud_t *pud, unsigned long vaddr)
Matthew Garrett 0988eed
+{
Matthew Garrett 0988eed
+	if (pud_none(*pud)) {
Matthew Garrett 0988eed
+		pmd_t *pmd = (pmd_t *)get_zeroed_page(GFP_ATOMIC);
Matthew Garrett 0988eed
+		set_pud(pud, __pud(_PAGE_TABLE | __pa(pmd)));
Matthew Garrett 0988eed
+		if (pmd != pmd_offset(pud, 0))
Matthew Garrett 0988eed
+			printk(KERN_ERR "EFI PAGETABLE BUG #01! %p <-> %p\n",
Matthew Garrett 0988eed
+			       pmd, pmd_offset(pud, 0));
Matthew Garrett 0988eed
+	}
Matthew Garrett 0988eed
+	return pmd_offset(pud, vaddr);
Matthew Garrett 0988eed
+}
Matthew Garrett 0988eed
+
Matthew Garrett 0988eed
+static pte_t *fill_pte(pmd_t *pmd, unsigned long vaddr)
Matthew Garrett 0988eed
+{
Matthew Garrett 0988eed
+	if (pmd_none(*pmd)) {
Matthew Garrett 0988eed
+		pte_t *pte = (pte_t *)get_zeroed_page(GFP_ATOMIC);
Matthew Garrett 0988eed
+		set_pmd(pmd, __pmd(_PAGE_TABLE | __pa(pte)));
Matthew Garrett 0988eed
+		if (pte != pte_offset_kernel(pmd, 0))
Matthew Garrett 0988eed
+			printk(KERN_ERR "EFI PAGETABLE BUG #02!\n");
Matthew Garrett 0988eed
+	}
Matthew Garrett 0988eed
+	return pte_offset_kernel(pmd, vaddr);
Matthew Garrett 0988eed
+}
Matthew Garrett 0988eed
+
Matthew Garrett 0988eed
+void __init efi_pagetable_init(void)
Matthew Garrett 0988eed
+{
Matthew Garrett 0988eed
+	efi_memory_desc_t *md;
Matthew Garrett 0988eed
+	unsigned long size;
Matthew Garrett 0988eed
+	u64 start_pfn, end_pfn, pfn, vaddr;
Matthew Garrett 0988eed
+	void *p;
Matthew Garrett 0988eed
+	pgd_t *pgd;
Matthew Garrett 0988eed
+	pud_t *pud;
Matthew Garrett 0988eed
+	pmd_t *pmd;
Matthew Garrett 0988eed
+	pte_t *pte;
Matthew Garrett 0988eed
+
Matthew Garrett 0988eed
+	memset(efi_pgd, 0, sizeof(efi_pgd));
Matthew Garrett 0988eed
+	for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
Matthew Garrett 0988eed
+		md = p;
Matthew Garrett 0988eed
+		if ((md->type != EFI_RUNTIME_SERVICES_CODE) &&
Matthew Garrett 0988eed
+		    (md->type != EFI_RUNTIME_SERVICES_DATA))
Matthew Garrett 0988eed
+			continue;
Matthew Garrett 0988eed
+
Matthew Garrett 0988eed
+		start_pfn = md->phys_addr >> PAGE_SHIFT;
Matthew Garrett 0988eed
+		size = md->num_pages << EFI_PAGE_SHIFT;
Matthew Garrett 0988eed
+		end_pfn = PFN_UP(md->phys_addr + size);
Matthew Garrett 0988eed
+
Matthew Garrett 0988eed
+		for (pfn = start_pfn; pfn <= end_pfn; pfn++) {
Matthew Garrett 0988eed
+			vaddr = pfn << PAGE_SHIFT;
Matthew Garrett 0988eed
+			pgd = efi_pgd + pgd_index(vaddr);
Matthew Garrett 0988eed
+			pud = fill_pud(pgd, vaddr);
Matthew Garrett 0988eed
+			pmd = fill_pmd(pud, vaddr);
Matthew Garrett 0988eed
+			pte = fill_pte(pmd, vaddr);
Matthew Garrett 0988eed
+			if (md->type == EFI_RUNTIME_SERVICES_CODE)
Matthew Garrett 0988eed
+				set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC));
Matthew Garrett 0988eed
+			else
Matthew Garrett 0988eed
+				set_pte(pte, pfn_pte(pfn, PAGE_KERNEL));
Matthew Garrett 0988eed
+		}
Matthew Garrett 0988eed
+	}
Matthew Garrett 0988eed
+	pgd = efi_pgd + pgd_index(PAGE_OFFSET);
Matthew Garrett 0988eed
+	set_pgd(pgd, *pgd_offset_k(PAGE_OFFSET));
Matthew Garrett 0988eed
+	pgd = efi_pgd + pgd_index(__START_KERNEL_map);
Matthew Garrett 0988eed
+	set_pgd(pgd, *pgd_offset_k(__START_KERNEL_map));
Matthew Garrett 0988eed
+}
Matthew Garrett 0988eed
diff --git a/include/linux/efi.h b/include/linux/efi.h
Matthew Garrett 0988eed
index fb737bc..c4e310e 100644
Matthew Garrett 0988eed
--- a/include/linux/efi.h
Matthew Garrett 0988eed
+++ b/include/linux/efi.h
Matthew Garrett 0988eed
@@ -290,6 +290,7 @@ extern void efi_map_pal_code (void);
Matthew Garrett 0988eed
 extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg);
Matthew Garrett 0988eed
 extern void efi_gettimeofday (struct timespec *ts);
Matthew Garrett 0988eed
 extern void efi_enter_virtual_mode (void);	/* switch EFI to virtual mode, if possible */
Matthew Garrett 0988eed
+extern void efi_setup_physical_mode(void);
Matthew Garrett 0988eed
 extern u64 efi_get_iobase (void);
Matthew Garrett 0988eed
 extern u32 efi_mem_type (unsigned long phys_addr);
Matthew Garrett 0988eed
 extern u64 efi_mem_attributes (unsigned long phys_addr);
Matthew Garrett 0988eed
diff --git a/include/linux/init.h b/include/linux/init.h
Matthew Garrett 0988eed
index 577671c..2f1b28f 100644
Matthew Garrett 0988eed
--- a/include/linux/init.h
Matthew Garrett 0988eed
+++ b/include/linux/init.h
Matthew Garrett 0988eed
@@ -149,6 +149,7 @@ extern int do_one_initcall(initcall_t fn);
Matthew Garrett 0988eed
 extern char __initdata boot_command_line[];
Matthew Garrett 0988eed
 extern char *saved_command_line;
Matthew Garrett 0988eed
 extern unsigned int reset_devices;
Matthew Garrett 0988eed
+extern unsigned int usevirtefi;
Matthew Garrett 0988eed
 
Matthew Garrett 0988eed
 /* used by init/main.c */
Matthew Garrett 0988eed
 void setup_arch(char **);
Matthew Garrett 0988eed
diff --git a/init/main.c b/init/main.c
Matthew Garrett 0988eed
index 8646401..726025e 100644
Matthew Garrett 0988eed
--- a/init/main.c
Matthew Garrett 0988eed
+++ b/init/main.c
Matthew Garrett 0988eed
@@ -196,6 +196,14 @@ static int __init set_reset_devices(char *str)
Matthew Garrett 0988eed
 
Matthew Garrett 0988eed
 __setup("reset_devices", set_reset_devices);
Matthew Garrett 0988eed
 
Matthew Garrett 0988eed
+unsigned int usevirtefi;
Matthew Garrett 0988eed
+static int __init set_virt_efi(char *str)
Matthew Garrett 0988eed
+{
Matthew Garrett 0988eed
+	usevirtefi = 1;
Matthew Garrett 0988eed
+	return 1;
Matthew Garrett 0988eed
+}
Matthew Garrett 0988eed
+__setup("virtefi", set_virt_efi);
Matthew Garrett 0988eed
+
Matthew Garrett 0988eed
 static const char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };
Matthew Garrett 0988eed
 const char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };
Matthew Garrett 0988eed
 static const char *panic_later, *panic_param;
Matthew Garrett 0988eed
@@ -668,8 +676,12 @@ asmlinkage void __init start_kernel(void)
Matthew Garrett 0988eed
 	pidmap_init();
Matthew Garrett 0988eed
 	anon_vma_init();
Matthew Garrett 0988eed
 #ifdef CONFIG_X86
Matthew Garrett 0988eed
-	if (efi_enabled)
Matthew Garrett 0988eed
-		efi_enter_virtual_mode();
Matthew Garrett 0988eed
+	if (efi_enabled) {
Matthew Garrett 0988eed
+		if (usevirtefi)
Matthew Garrett 0988eed
+			efi_enter_virtual_mode();
Matthew Garrett 0988eed
+		else
Matthew Garrett 0988eed
+			efi_setup_physical_mode();
Matthew Garrett 0988eed
+	}
Matthew Garrett 0988eed
 #endif
Matthew Garrett 0988eed
 	thread_info_cache_init();
Matthew Garrett 0988eed
 	cred_init();