aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorHuang, Ying <ying.huang@intel.com>2008-01-30 07:31:19 -0500
committerIngo Molnar <mingo@elte.hu>2008-01-30 07:31:19 -0500
commit5b83683f32b113d07edfb67a33ce389fc624423d (patch)
tree03efde0750c9d7e477ab695aeee26173ffcc4abf /arch/x86
parent8c8b8859b64baf6d7c33900e8720c7bafe775b2c (diff)
x86: EFI runtime service support
This patch adds basic runtime services support for EFI x86_64 system. The main file of the patch is the addition of efi_64.c for x86_64. This file is modeled after the EFI IA32 avatar. EFI runtime services initialization are implemented in efi_64.c. Some x86_64 specifics are worth noting here. On x86_64, parameters passed to EFI firmware services need to follow the EFI calling convention. For this purpose, a set of functions named efi_call<x> (<x> is the number of parameters) are implemented. EFI function calls are wrapped before calling the firmware service. The duplicated code between efi_32.c and efi_64.c is placed in efi.c to remove them from efi_32.c. Signed-off-by: Chandramouli Narayanan <mouli@linux.intel.com> Signed-off-by: Huang Ying <ying.huang@intel.com> Cc: Andi Kleen <ak@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/Kconfig2
-rw-r--r--arch/x86/kernel/Makefile_641
-rw-r--r--arch/x86/kernel/efi.c480
-rw-r--r--arch/x86/kernel/efi_64.c164
-rw-r--r--arch/x86/kernel/efi_stub_64.S109
-rw-r--r--arch/x86/kernel/setup_64.c17
6 files changed, 771 insertions, 2 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index fef944bb920e..23936301db56 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -959,7 +959,7 @@ config MTRR
959config EFI 959config EFI
960 def_bool n 960 def_bool n
961 prompt "Boot from EFI support" 961 prompt "Boot from EFI support"
962 depends on X86_32 && ACPI 962 depends on ACPI
963 ---help--- 963 ---help---
964 This enables the kernel to boot on EFI platforms using 964 This enables the kernel to boot on EFI platforms using
965 system configuration information passed to it from the firmware. 965 system configuration information passed to it from the firmware.
diff --git a/arch/x86/kernel/Makefile_64 b/arch/x86/kernel/Makefile_64
index 2ec96acf6486..e5093dd8cf01 100644
--- a/arch/x86/kernel/Makefile_64
+++ b/arch/x86/kernel/Makefile_64
@@ -39,6 +39,7 @@ obj-$(CONFIG_X86_PM_TIMER) += pmtimer_64.o
39obj-$(CONFIG_X86_VSMP) += vsmp_64.o 39obj-$(CONFIG_X86_VSMP) += vsmp_64.o
40obj-$(CONFIG_K8_NB) += k8.o 40obj-$(CONFIG_K8_NB) += k8.o
41obj-$(CONFIG_AUDIT) += audit_64.o 41obj-$(CONFIG_AUDIT) += audit_64.o
42obj-$(CONFIG_EFI) += efi.o efi_64.o efi_stub_64.o
42 43
43obj-$(CONFIG_MODULES) += module_64.o 44obj-$(CONFIG_MODULES) += module_64.o
44obj-$(CONFIG_PCI) += early-quirks.o 45obj-$(CONFIG_PCI) += early-quirks.o
diff --git a/arch/x86/kernel/efi.c b/arch/x86/kernel/efi.c
new file mode 100644
index 000000000000..0a61522e85c7
--- /dev/null
+++ b/arch/x86/kernel/efi.c
@@ -0,0 +1,480 @@
1/*
2 * Common EFI (Extensible Firmware Interface) support functions
3 * Based on Extensible Firmware Interface Specification version 1.0
4 *
5 * Copyright (C) 1999 VA Linux Systems
6 * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
7 * Copyright (C) 1999-2002 Hewlett-Packard Co.
8 * David Mosberger-Tang <davidm@hpl.hp.com>
9 * Stephane Eranian <eranian@hpl.hp.com>
10 * Copyright (C) 2005-2008 Intel Co.
11 * Fenghua Yu <fenghua.yu@intel.com>
12 * Bibo Mao <bibo.mao@intel.com>
13 * Chandramouli Narayanan <mouli@linux.intel.com>
14 * Huang Ying <ying.huang@intel.com>
15 *
16 * Copied from efi_32.c to eliminate the duplicated code between EFI
17 * 32/64 support code. --ying 2007-10-26
18 *
19 * All EFI Runtime Services are not implemented yet as EFI only
20 * supports physical mode addressing on SoftSDV. This is to be fixed
21 * in a future version. --drummond 1999-07-20
22 *
23 * Implemented EFI runtime services and virtual mode calls. --davidm
24 *
25 * Goutham Rao: <goutham.rao@intel.com>
26 * Skip non-WB memory and ignore empty memory ranges.
27 */
28
29#include <linux/kernel.h>
30#include <linux/init.h>
31#include <linux/efi.h>
32#include <linux/bootmem.h>
33#include <linux/spinlock.h>
34#include <linux/uaccess.h>
35#include <linux/time.h>
36#include <linux/io.h>
37#include <linux/reboot.h>
38#include <linux/bcd.h>
39
40#include <asm/setup.h>
41#include <asm/efi.h>
42#include <asm/time.h>
43
44#define EFI_DEBUG 1
45#define PFX "EFI: "
46
47int efi_enabled;
48EXPORT_SYMBOL(efi_enabled);
49
50struct efi efi;
51EXPORT_SYMBOL(efi);
52
53struct efi_memory_map memmap;
54
55struct efi efi_phys __initdata;
56static efi_system_table_t efi_systab __initdata;
57
58static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
59{
60 return efi_call_virt2(get_time, tm, tc);
61}
62
63static efi_status_t virt_efi_set_time(efi_time_t *tm)
64{
65 return efi_call_virt1(set_time, tm);
66}
67
68static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled,
69 efi_bool_t *pending,
70 efi_time_t *tm)
71{
72 return efi_call_virt3(get_wakeup_time,
73 enabled, pending, tm);
74}
75
76static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
77{
78 return efi_call_virt2(set_wakeup_time,
79 enabled, tm);
80}
81
82static efi_status_t virt_efi_get_variable(efi_char16_t *name,
83 efi_guid_t *vendor,
84 u32 *attr,
85 unsigned long *data_size,
86 void *data)
87{
88 return efi_call_virt5(get_variable,
89 name, vendor, attr,
90 data_size, data);
91}
92
93static efi_status_t virt_efi_get_next_variable(unsigned long *name_size,
94 efi_char16_t *name,
95 efi_guid_t *vendor)
96{
97 return efi_call_virt3(get_next_variable,
98 name_size, name, vendor);
99}
100
101static efi_status_t virt_efi_set_variable(efi_char16_t *name,
102 efi_guid_t *vendor,
103 unsigned long attr,
104 unsigned long data_size,
105 void *data)
106{
107 return efi_call_virt5(set_variable,
108 name, vendor, attr,
109 data_size, data);
110}
111
112static efi_status_t virt_efi_get_next_high_mono_count(u32 *count)
113{
114 return efi_call_virt1(get_next_high_mono_count, count);
115}
116
117static void virt_efi_reset_system(int reset_type,
118 efi_status_t status,
119 unsigned long data_size,
120 efi_char16_t *data)
121{
122 efi_call_virt4(reset_system, reset_type, status,
123 data_size, data);
124}
125
126static efi_status_t virt_efi_set_virtual_address_map(
127 unsigned long memory_map_size,
128 unsigned long descriptor_size,
129 u32 descriptor_version,
130 efi_memory_desc_t *virtual_map)
131{
132 return efi_call_virt4(set_virtual_address_map,
133 memory_map_size, descriptor_size,
134 descriptor_version, virtual_map);
135}
136
137static efi_status_t __init phys_efi_set_virtual_address_map(
138 unsigned long memory_map_size,
139 unsigned long descriptor_size,
140 u32 descriptor_version,
141 efi_memory_desc_t *virtual_map)
142{
143 efi_status_t status;
144
145 efi_call_phys_prelog();
146 status = efi_call_phys4(efi_phys.set_virtual_address_map,
147 memory_map_size, descriptor_size,
148 descriptor_version, virtual_map);
149 efi_call_phys_epilog();
150 return status;
151}
152
153static efi_status_t __init phys_efi_get_time(efi_time_t *tm,
154 efi_time_cap_t *tc)
155{
156 efi_status_t status;
157
158 efi_call_phys_prelog();
159 status = efi_call_phys2(efi_phys.get_time, tm, tc);
160 efi_call_phys_epilog();
161 return status;
162}
163
164int efi_set_rtc_mmss(unsigned long nowtime)
165{
166 int real_seconds, real_minutes;
167 efi_status_t status;
168 efi_time_t eft;
169 efi_time_cap_t cap;
170
171 status = efi.get_time(&eft, &cap);
172 if (status != EFI_SUCCESS) {
173 printk(KERN_ERR "Oops: efitime: can't read time!\n");
174 return -1;
175 }
176
177 real_seconds = nowtime % 60;
178 real_minutes = nowtime / 60;
179 if (((abs(real_minutes - eft.minute) + 15)/30) & 1)
180 real_minutes += 30;
181 real_minutes %= 60;
182 eft.minute = real_minutes;
183 eft.second = real_seconds;
184
185 status = efi.set_time(&eft);
186 if (status != EFI_SUCCESS) {
187 printk(KERN_ERR "Oops: efitime: can't write time!\n");
188 return -1;
189 }
190 return 0;
191}
192
193unsigned long efi_get_time(void)
194{
195 efi_status_t status;
196 efi_time_t eft;
197 efi_time_cap_t cap;
198
199 status = efi.get_time(&eft, &cap);
200 if (status != EFI_SUCCESS)
201 printk(KERN_ERR "Oops: efitime: can't read time!\n");
202
203 return mktime(eft.year, eft.month, eft.day, eft.hour,
204 eft.minute, eft.second);
205}
206
207#if EFI_DEBUG
208static void __init print_efi_memmap(void)
209{
210 efi_memory_desc_t *md;
211 void *p;
212 int i;
213
214 for (p = memmap.map, i = 0;
215 p < memmap.map_end;
216 p += memmap.desc_size, i++) {
217 md = p;
218 printk(KERN_INFO PFX "mem%02u: type=%u, attr=0x%llx, "
219 "range=[0x%016llx-0x%016llx) (%lluMB)\n",
220 i, md->type, md->attribute, md->phys_addr,
221 md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT),
222 (md->num_pages >> (20 - EFI_PAGE_SHIFT)));
223 }
224}
225#endif /* EFI_DEBUG */
226
227void __init efi_init(void)
228{
229 efi_config_table_t *config_tables;
230 efi_runtime_services_t *runtime;
231 efi_char16_t *c16;
232 char vendor[100] = "unknown";
233 int i = 0;
234 void *tmp;
235
236#ifdef CONFIG_X86_32
237 efi_phys.systab = (efi_system_table_t *)boot_params.efi_info.efi_systab;
238 memmap.phys_map = (void *)boot_params.efi_info.efi_memmap;
239#else
240 efi_phys.systab = (efi_system_table_t *)
241 (boot_params.efi_info.efi_systab |
242 ((__u64)boot_params.efi_info.efi_systab_hi<<32));
243 memmap.phys_map = (void *)
244 (boot_params.efi_info.efi_memmap |
245 ((__u64)boot_params.efi_info.efi_memmap_hi<<32));
246#endif
247 memmap.nr_map = boot_params.efi_info.efi_memmap_size /
248 boot_params.efi_info.efi_memdesc_size;
249 memmap.desc_version = boot_params.efi_info.efi_memdesc_version;
250 memmap.desc_size = boot_params.efi_info.efi_memdesc_size;
251
252 efi.systab = efi_early_ioremap((unsigned long)efi_phys.systab,
253 sizeof(efi_system_table_t));
254 if (efi.systab == NULL)
255 printk(KERN_ERR "Couldn't map the EFI system table!\n");
256 memcpy(&efi_systab, efi.systab, sizeof(efi_system_table_t));
257 efi_early_iounmap(efi.systab, sizeof(efi_system_table_t));
258 efi.systab = &efi_systab;
259
260 /*
261 * Verify the EFI Table
262 */
263 if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
264 printk(KERN_ERR "EFI system table signature incorrect!\n");
265 if ((efi.systab->hdr.revision >> 16) == 0)
266 printk(KERN_ERR "Warning: EFI system table version "
267 "%d.%02d, expected 1.00 or greater!\n",
268 efi.systab->hdr.revision >> 16,
269 efi.systab->hdr.revision & 0xffff);
270
271 /*
272 * Show what we know for posterity
273 */
274 c16 = tmp = efi_early_ioremap(efi.systab->fw_vendor, 2);
275 if (c16) {
276 for (i = 0; i < sizeof(vendor) && *c16; ++i)
277 vendor[i] = *c16++;
278 vendor[i] = '\0';
279 } else
280 printk(KERN_ERR PFX "Could not map the firmware vendor!\n");
281 efi_early_iounmap(tmp, 2);
282
283 printk(KERN_INFO "EFI v%u.%.02u by %s \n",
284 efi.systab->hdr.revision >> 16,
285 efi.systab->hdr.revision & 0xffff, vendor);
286
287 /*
288 * Let's see what config tables the firmware passed to us.
289 */
290 config_tables = efi_early_ioremap(
291 efi.systab->tables,
292 efi.systab->nr_tables * sizeof(efi_config_table_t));
293 if (config_tables == NULL)
294 printk(KERN_ERR "Could not map EFI Configuration Table!\n");
295
296 printk(KERN_INFO);
297 for (i = 0; i < efi.systab->nr_tables; i++) {
298 if (!efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID)) {
299 efi.mps = config_tables[i].table;
300 printk(" MPS=0x%lx ", config_tables[i].table);
301 } else if (!efi_guidcmp(config_tables[i].guid,
302 ACPI_20_TABLE_GUID)) {
303 efi.acpi20 = config_tables[i].table;
304 printk(" ACPI 2.0=0x%lx ", config_tables[i].table);
305 } else if (!efi_guidcmp(config_tables[i].guid,
306 ACPI_TABLE_GUID)) {
307 efi.acpi = config_tables[i].table;
308 printk(" ACPI=0x%lx ", config_tables[i].table);
309 } else if (!efi_guidcmp(config_tables[i].guid,
310 SMBIOS_TABLE_GUID)) {
311 efi.smbios = config_tables[i].table;
312 printk(" SMBIOS=0x%lx ", config_tables[i].table);
313 } else if (!efi_guidcmp(config_tables[i].guid,
314 HCDP_TABLE_GUID)) {
315 efi.hcdp = config_tables[i].table;
316 printk(" HCDP=0x%lx ", config_tables[i].table);
317 } else if (!efi_guidcmp(config_tables[i].guid,
318 UGA_IO_PROTOCOL_GUID)) {
319 efi.uga = config_tables[i].table;
320 printk(" UGA=0x%lx ", config_tables[i].table);
321 }
322 }
323 printk("\n");
324 efi_early_iounmap(config_tables,
325 efi.systab->nr_tables * sizeof(efi_config_table_t));
326
327 /*
328 * Check out the runtime services table. We need to map
329 * the runtime services table so that we can grab the physical
330 * address of several of the EFI runtime functions, needed to
331 * set the firmware into virtual mode.
332 */
333 runtime = efi_early_ioremap((unsigned long)efi.systab->runtime,
334 sizeof(efi_runtime_services_t));
335 if (runtime != NULL) {
336 /*
337 * We will only need *early* access to the following
338 * two EFI runtime services before set_virtual_address_map
339 * is invoked.
340 */
341 efi_phys.get_time = (efi_get_time_t *)runtime->get_time;
342 efi_phys.set_virtual_address_map =
343 (efi_set_virtual_address_map_t *)
344 runtime->set_virtual_address_map;
345 /*
346 * Make efi_get_time can be called before entering
347 * virtual mode.
348 */
349 efi.get_time = phys_efi_get_time;
350 } else
351 printk(KERN_ERR "Could not map the EFI runtime service "
352 "table!\n");
353 efi_early_iounmap(runtime, sizeof(efi_runtime_services_t));
354
355 /* Map the EFI memory map */
356 memmap.map = efi_early_ioremap((unsigned long)memmap.phys_map,
357 memmap.nr_map * memmap.desc_size);
358 if (memmap.map == NULL)
359 printk(KERN_ERR "Could not map the EFI memory map!\n");
360 memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size);
361 if (memmap.desc_size != sizeof(efi_memory_desc_t))
362 printk(KERN_WARNING "Kernel-defined memdesc"
363 "doesn't match the one from EFI!\n");
364
365#ifdef CONFIG_X86_64
366 /* Setup for EFI runtime service */
367 reboot_type = BOOT_EFI;
368
369#endif
370#if EFI_DEBUG
371 print_efi_memmap();
372#endif
373}
374
375/*
376 * This function will switch the EFI runtime services to virtual mode.
377 * Essentially, look through the EFI memmap and map every region that
378 * has the runtime attribute bit set in its memory descriptor and update
379 * that memory descriptor with the virtual address obtained from ioremap().
380 * This enables the runtime services to be called without having to
381 * thunk back into physical mode for every invocation.
382 */
383void __init efi_enter_virtual_mode(void)
384{
385 efi_memory_desc_t *md;
386 efi_status_t status;
387 unsigned long end;
388 void *p;
389
390 efi.systab = NULL;
391 for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
392 md = p;
393 if (!(md->attribute & EFI_MEMORY_RUNTIME))
394 continue;
395 if ((md->attribute & EFI_MEMORY_WB) &&
396 (((md->phys_addr + (md->num_pages<<EFI_PAGE_SHIFT)) >>
397 PAGE_SHIFT) < end_pfn_map))
398 md->virt_addr = (unsigned long)__va(md->phys_addr);
399 else
400 md->virt_addr = (unsigned long)
401 efi_ioremap(md->phys_addr,
402 md->num_pages << EFI_PAGE_SHIFT);
403 if (!md->virt_addr)
404 printk(KERN_ERR PFX "ioremap of 0x%llX failed!\n",
405 (unsigned long long)md->phys_addr);
406 end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
407 if ((md->phys_addr <= (unsigned long)efi_phys.systab) &&
408 ((unsigned long)efi_phys.systab < end))
409 efi.systab = (efi_system_table_t *)(unsigned long)
410 (md->virt_addr - md->phys_addr +
411 (unsigned long)efi_phys.systab);
412 }
413
414 BUG_ON(!efi.systab);
415
416 status = phys_efi_set_virtual_address_map(
417 memmap.desc_size * memmap.nr_map,
418 memmap.desc_size,
419 memmap.desc_version,
420 memmap.phys_map);
421
422 if (status != EFI_SUCCESS) {
423 printk(KERN_ALERT "Unable to switch EFI into virtual mode "
424 "(status=%lx)!\n", status);
425 panic("EFI call to SetVirtualAddressMap() failed!");
426 }
427
428 /*
429 * Now that EFI is in virtual mode, update the function
430 * pointers in the runtime service table to the new virtual addresses.
431 *
432 * Call EFI services through wrapper functions.
433 */
434 efi.get_time = virt_efi_get_time;
435 efi.set_time = virt_efi_set_time;
436 efi.get_wakeup_time = virt_efi_get_wakeup_time;
437 efi.set_wakeup_time = virt_efi_set_wakeup_time;
438 efi.get_variable = virt_efi_get_variable;
439 efi.get_next_variable = virt_efi_get_next_variable;
440 efi.set_variable = virt_efi_set_variable;
441 efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
442 efi.reset_system = virt_efi_reset_system;
443 efi.set_virtual_address_map = virt_efi_set_virtual_address_map;
444#ifdef CONFIG_X86_64
445 runtime_code_page_mkexec();
446#endif
447}
448
449/*
450 * Convenience functions to obtain memory types and attributes
451 */
452u32 efi_mem_type(unsigned long phys_addr)
453{
454 efi_memory_desc_t *md;
455 void *p;
456
457 for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
458 md = p;
459 if ((md->phys_addr <= phys_addr) &&
460 (phys_addr < (md->phys_addr +
461 (md->num_pages << EFI_PAGE_SHIFT))))
462 return md->type;
463 }
464 return 0;
465}
466
467u64 efi_mem_attributes(unsigned long phys_addr)
468{
469 efi_memory_desc_t *md;
470 void *p;
471
472 for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
473 md = p;
474 if ((md->phys_addr <= phys_addr) &&
475 (phys_addr < (md->phys_addr +
476 (md->num_pages << EFI_PAGE_SHIFT))))
477 return md->attribute;
478 }
479 return 0;
480}
diff --git a/arch/x86/kernel/efi_64.c b/arch/x86/kernel/efi_64.c
new file mode 100644
index 000000000000..f2000dbc7195
--- /dev/null
+++ b/arch/x86/kernel/efi_64.c
@@ -0,0 +1,164 @@
1/*
2 * x86_64 specific EFI support functions
3 * Based on Extensible Firmware Interface Specification version 1.0
4 *
5 * Copyright (C) 2005-2008 Intel Co.
6 * Fenghua Yu <fenghua.yu@intel.com>
7 * Bibo Mao <bibo.mao@intel.com>
8 * Chandramouli Narayanan <mouli@linux.intel.com>
9 * Huang Ying <ying.huang@intel.com>
10 *
11 * Code to convert EFI to E820 map has been implemented in elilo bootloader
12 * based on a EFI patch by Edgar Hucek. Based on the E820 map, the page table
13 * is setup appropriately for EFI runtime code.
14 * - mouli 06/14/2007.
15 *
16 */
17
18#include <linux/kernel.h>
19#include <linux/init.h>
20#include <linux/mm.h>
21#include <linux/types.h>
22#include <linux/spinlock.h>
23#include <linux/bootmem.h>
24#include <linux/ioport.h>
25#include <linux/module.h>
26#include <linux/efi.h>
27#include <linux/uaccess.h>
28#include <linux/io.h>
29#include <linux/reboot.h>
30
31#include <asm/setup.h>
32#include <asm/page.h>
33#include <asm/e820.h>
34#include <asm/pgtable.h>
35#include <asm/tlbflush.h>
36#include <asm/cacheflush.h>
37#include <asm/proto.h>
38#include <asm/efi.h>
39
40static pgd_t save_pgd __initdata;
41static unsigned long efi_flags __initdata;
42
43static int __init setup_noefi(char *arg)
44{
45 efi_enabled = 0;
46 return 0;
47}
48early_param("noefi", setup_noefi);
49
50static void __init early_mapping_set_exec(unsigned long start,
51 unsigned long end,
52 int executable)
53{
54 pte_t *kpte;
55 int level;
56
57 while (start < end) {
58 kpte = lookup_address((unsigned long)__va(start), &level);
59 BUG_ON(!kpte);
60 if (executable)
61 set_pte(kpte, pte_mkexec(*kpte));
62 else
63 set_pte(kpte, __pte((pte_val(*kpte) | _PAGE_NX) & \
64 __supported_pte_mask));
65 if (pte_huge(*kpte))
66 start = (start + PMD_SIZE) & PMD_MASK;
67 else
68 start = (start + PAGE_SIZE) & PAGE_MASK;
69 }
70}
71
72static void __init early_runtime_code_mapping_set_exec(int executable)
73{
74 efi_memory_desc_t *md;
75 void *p;
76
77 /* Make EFI runtime service code area executable */
78 for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
79 md = p;
80 if (md->type == EFI_RUNTIME_SERVICES_CODE) {
81 unsigned long end;
82 end = md->phys_addr + (md->num_pages << PAGE_SHIFT);
83 early_mapping_set_exec(md->phys_addr, end, executable);
84 }
85 }
86}
87
88void __init efi_call_phys_prelog(void)
89{
90 unsigned long vaddress;
91
92 local_irq_save(efi_flags);
93 early_runtime_code_mapping_set_exec(1);
94 vaddress = (unsigned long)__va(0x0UL);
95 pgd_val(save_pgd) = pgd_val(*pgd_offset_k(0x0UL));
96 set_pgd(pgd_offset_k(0x0UL), *pgd_offset_k(vaddress));
97 __flush_tlb_all();
98}
99
100void __init efi_call_phys_epilog(void)
101{
102 /*
103 * After the lock is released, the original page table is restored.
104 */
105 set_pgd(pgd_offset_k(0x0UL), save_pgd);
106 early_runtime_code_mapping_set_exec(0);
107 __flush_tlb_all();
108 local_irq_restore(efi_flags);
109}
110
111/*
112 * We need to map the EFI memory map again after init_memory_mapping().
113 */
114void __init efi_map_memmap(void)
115{
116 memmap.map = __va(memmap.phys_map);
117 memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size);
118}
119
120void __init efi_reserve_bootmem(void)
121{
122 reserve_bootmem_generic((unsigned long)memmap.phys_map,
123 memmap.nr_map * memmap.desc_size);
124}
125
126void __init runtime_code_page_mkexec(void)
127{
128 efi_memory_desc_t *md;
129 void *p;
130
131 /* Make EFI runtime service code area executable */
132 for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
133 md = p;
134 if (md->type == EFI_RUNTIME_SERVICES_CODE)
135 change_page_attr_addr(md->virt_addr,
136 md->num_pages,
137 PAGE_KERNEL_EXEC);
138 }
139 __flush_tlb_all();
140}
141
142void __iomem * __init efi_ioremap(unsigned long offset,
143 unsigned long size)
144{
145 static unsigned pages_mapped;
146 unsigned long last_addr;
147 unsigned i, pages;
148
149 last_addr = offset + size - 1;
150 offset &= PAGE_MASK;
151 pages = (PAGE_ALIGN(last_addr) - offset) >> PAGE_SHIFT;
152 if (pages_mapped + pages > MAX_EFI_IO_PAGES)
153 return NULL;
154
155 for (i = 0; i < pages; i++) {
156 set_fixmap_nocache(FIX_EFI_IO_MAP_FIRST_PAGE - pages_mapped,
157 offset);
158 offset += PAGE_SIZE;
159 pages_mapped++;
160 }
161
162 return (void __iomem *)__fix_to_virt(FIX_EFI_IO_MAP_FIRST_PAGE - \
163 (pages_mapped - pages));
164}
diff --git a/arch/x86/kernel/efi_stub_64.S b/arch/x86/kernel/efi_stub_64.S
new file mode 100644
index 000000000000..99b47d48c9f4
--- /dev/null
+++ b/arch/x86/kernel/efi_stub_64.S
@@ -0,0 +1,109 @@
1/*
2 * Function calling ABI conversion from Linux to EFI for x86_64
3 *
4 * Copyright (C) 2007 Intel Corp
5 * Bibo Mao <bibo.mao@intel.com>
6 * Huang Ying <ying.huang@intel.com>
7 */
8
9#include <linux/linkage.h>
10
11#define SAVE_XMM \
12 mov %rsp, %rax; \
13 subq $0x70, %rsp; \
14 and $~0xf, %rsp; \
15 mov %rax, (%rsp); \
16 mov %cr0, %rax; \
17 clts; \
18 mov %rax, 0x8(%rsp); \
19 movaps %xmm0, 0x60(%rsp); \
20 movaps %xmm1, 0x50(%rsp); \
21 movaps %xmm2, 0x40(%rsp); \
22 movaps %xmm3, 0x30(%rsp); \
23 movaps %xmm4, 0x20(%rsp); \
24 movaps %xmm5, 0x10(%rsp)
25
26#define RESTORE_XMM \
27 movaps 0x60(%rsp), %xmm0; \
28 movaps 0x50(%rsp), %xmm1; \
29 movaps 0x40(%rsp), %xmm2; \
30 movaps 0x30(%rsp), %xmm3; \
31 movaps 0x20(%rsp), %xmm4; \
32 movaps 0x10(%rsp), %xmm5; \
33 mov 0x8(%rsp), %rsi; \
34 mov %rsi, %cr0; \
35 mov (%rsp), %rsp
36
37ENTRY(efi_call0)
38 SAVE_XMM
39 subq $32, %rsp
40 call *%rdi
41 addq $32, %rsp
42 RESTORE_XMM
43 ret
44
45ENTRY(efi_call1)
46 SAVE_XMM
47 subq $32, %rsp
48 mov %rsi, %rcx
49 call *%rdi
50 addq $32, %rsp
51 RESTORE_XMM
52 ret
53
54ENTRY(efi_call2)
55 SAVE_XMM
56 subq $32, %rsp
57 mov %rsi, %rcx
58 call *%rdi
59 addq $32, %rsp
60 RESTORE_XMM
61 ret
62
63ENTRY(efi_call3)
64 SAVE_XMM
65 subq $32, %rsp
66 mov %rcx, %r8
67 mov %rsi, %rcx
68 call *%rdi
69 addq $32, %rsp
70 RESTORE_XMM
71 ret
72
73ENTRY(efi_call4)
74 SAVE_XMM
75 subq $32, %rsp
76 mov %r8, %r9
77 mov %rcx, %r8
78 mov %rsi, %rcx
79 call *%rdi
80 addq $32, %rsp
81 RESTORE_XMM
82 ret
83
84ENTRY(efi_call5)
85 SAVE_XMM
86 subq $48, %rsp
87 mov %r9, 32(%rsp)
88 mov %r8, %r9
89 mov %rcx, %r8
90 mov %rsi, %rcx
91 call *%rdi
92 addq $48, %rsp
93 RESTORE_XMM
94 ret
95
96ENTRY(efi_call6)
97 SAVE_XMM
98 mov (%rsp), %rax
99 mov 8(%rax), %rax
100 subq $48, %rsp
101 mov %r9, 32(%rsp)
102 mov %rax, 40(%rsp)
103 mov %r8, %r9
104 mov %rcx, %r8
105 mov %rsi, %rcx
106 call *%rdi
107 addq $48, %rsp
108 RESTORE_XMM
109 ret
diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c
index 8dd110d93e73..90b8bb4748b9 100644
--- a/arch/x86/kernel/setup_64.c
+++ b/arch/x86/kernel/setup_64.c
@@ -30,6 +30,7 @@
30#include <linux/crash_dump.h> 30#include <linux/crash_dump.h>
31#include <linux/root_dev.h> 31#include <linux/root_dev.h>
32#include <linux/pci.h> 32#include <linux/pci.h>
33#include <linux/efi.h>
33#include <linux/acpi.h> 34#include <linux/acpi.h>
34#include <linux/kallsyms.h> 35#include <linux/kallsyms.h>
35#include <linux/edd.h> 36#include <linux/edd.h>
@@ -299,6 +300,11 @@ void __init setup_arch(char **cmdline_p)
299 rd_prompt = ((boot_params.hdr.ram_size & RAMDISK_PROMPT_FLAG) != 0); 300 rd_prompt = ((boot_params.hdr.ram_size & RAMDISK_PROMPT_FLAG) != 0);
300 rd_doload = ((boot_params.hdr.ram_size & RAMDISK_LOAD_FLAG) != 0); 301 rd_doload = ((boot_params.hdr.ram_size & RAMDISK_LOAD_FLAG) != 0);
301#endif 302#endif
303#ifdef CONFIG_EFI
304 if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
305 "EL64", 4))
306 efi_enabled = 1;
307#endif
302 308
303 ARCH_SETUP 309 ARCH_SETUP
304 310
@@ -341,6 +347,8 @@ void __init setup_arch(char **cmdline_p)
341 discover_ebda(); 347 discover_ebda();
342 348
343 init_memory_mapping(0, (end_pfn_map << PAGE_SHIFT)); 349 init_memory_mapping(0, (end_pfn_map << PAGE_SHIFT));
350 if (efi_enabled)
351 efi_init();
344 352
345 dmi_scan_machine(); 353 dmi_scan_machine();
346 354
@@ -414,6 +422,12 @@ void __init setup_arch(char **cmdline_p)
414 */ 422 */
415 acpi_reserve_bootmem(); 423 acpi_reserve_bootmem();
416#endif 424#endif
425
426 if (efi_enabled) {
427 efi_map_memmap();
428 efi_reserve_bootmem();
429 }
430
417 /* 431 /*
418 * Find and reserve possible boot-time SMP configuration: 432 * Find and reserve possible boot-time SMP configuration:
419 */ 433 */
@@ -479,7 +493,8 @@ void __init setup_arch(char **cmdline_p)
479 493
480#ifdef CONFIG_VT 494#ifdef CONFIG_VT
481#if defined(CONFIG_VGA_CONSOLE) 495#if defined(CONFIG_VGA_CONSOLE)
482 conswitchp = &vga_con; 496 if (!efi_enabled || (efi_mem_type(0xa0000) != EFI_CONVENTIONAL_MEMORY))
497 conswitchp = &vga_con;
483#elif defined(CONFIG_DUMMY_CONSOLE) 498#elif defined(CONFIG_DUMMY_CONSOLE)
484 conswitchp = &dummy_con; 499 conswitchp = &dummy_con;
485#endif 500#endif