aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/platform
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2014-01-10 13:48:30 -0500
committerMatt Fleming <matt.fleming@intel.com>2014-03-04 16:43:14 -0500
commit4f9dbcfc40299ddaa780fe8c1cd74998c1be3af5 (patch)
treef6d2f85b23fae5ee8d9da79f30c47351aa890d5b /arch/x86/platform
parentb8ff87a6158886771677e6dc8139bac6e3cba717 (diff)
x86/efi: Add mixed runtime services support
Setup the runtime services based on whether we're booting in EFI native mode or not. For non-native mode we need to thunk from 64-bit into 32-bit mode before invoking the EFI runtime services. Using the runtime services after SetVirtualAddressMap() is slightly more complicated because we need to ensure that all the addresses we pass to the firmware are below the 4GB boundary so that they can be addressed with 32-bit pointers, see efi_setup_page_tables(). Signed-off-by: Matt Fleming <matt.fleming@intel.com>
Diffstat (limited to 'arch/x86/platform')
-rw-r--r--arch/x86/platform/efi/Makefile1
-rw-r--r--arch/x86/platform/efi/efi.c127
-rw-r--r--arch/x86/platform/efi/efi_64.c335
-rw-r--r--arch/x86/platform/efi/efi_stub_64.S1
-rw-r--r--arch/x86/platform/efi/efi_thunk_64.S65
5 files changed, 496 insertions, 33 deletions
diff --git a/arch/x86/platform/efi/Makefile b/arch/x86/platform/efi/Makefile
index b7b0b35c1981..d51045afcaaf 100644
--- a/arch/x86/platform/efi/Makefile
+++ b/arch/x86/platform/efi/Makefile
@@ -1,3 +1,4 @@
1obj-$(CONFIG_EFI) += efi.o efi_$(BITS).o efi_stub_$(BITS).o 1obj-$(CONFIG_EFI) += efi.o efi_$(BITS).o efi_stub_$(BITS).o
2obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o 2obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o
3obj-$(CONFIG_EARLY_PRINTK_EFI) += early_printk.o 3obj-$(CONFIG_EARLY_PRINTK_EFI) += early_printk.o
4obj-$(CONFIG_EFI_MIXED) += efi_thunk_$(BITS).o
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index b96ae7918a16..39f5b7bba695 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -588,37 +588,85 @@ static int __init efi_systab_init(void *phys)
588 return 0; 588 return 0;
589} 589}
590 590
591static int __init efi_runtime_init(void) 591static int __init efi_runtime_init32(void)
592{ 592{
593 efi_runtime_services_t *runtime; 593 efi_runtime_services_32_t *runtime;
594
595 runtime = early_ioremap((unsigned long)efi.systab->runtime,
596 sizeof(efi_runtime_services_32_t));
597 if (!runtime) {
598 pr_err("Could not map the runtime service table!\n");
599 return -ENOMEM;
600 }
594 601
595 /* 602 /*
596 * Check out the runtime services table. We need to map 603 * We will only need *early* access to the following two
597 * the runtime services table so that we can grab the physical 604 * EFI runtime services before set_virtual_address_map
598 * address of several of the EFI runtime functions, needed to 605 * is invoked.
599 * set the firmware into virtual mode.
600 */ 606 */
607 efi_phys.get_time = (efi_get_time_t *)
608 (unsigned long)runtime->get_time;
609 efi_phys.set_virtual_address_map =
610 (efi_set_virtual_address_map_t *)
611 (unsigned long)runtime->set_virtual_address_map;
612 /*
613 * Make efi_get_time can be called before entering
614 * virtual mode.
615 */
616 efi.get_time = phys_efi_get_time;
617 early_iounmap(runtime, sizeof(efi_runtime_services_32_t));
618
619 return 0;
620}
621
622static int __init efi_runtime_init64(void)
623{
624 efi_runtime_services_64_t *runtime;
625
601 runtime = early_ioremap((unsigned long)efi.systab->runtime, 626 runtime = early_ioremap((unsigned long)efi.systab->runtime,
602 sizeof(efi_runtime_services_t)); 627 sizeof(efi_runtime_services_64_t));
603 if (!runtime) { 628 if (!runtime) {
604 pr_err("Could not map the runtime service table!\n"); 629 pr_err("Could not map the runtime service table!\n");
605 return -ENOMEM; 630 return -ENOMEM;
606 } 631 }
632
607 /* 633 /*
608 * We will only need *early* access to the following 634 * We will only need *early* access to the following two
609 * two EFI runtime services before set_virtual_address_map 635 * EFI runtime services before set_virtual_address_map
610 * is invoked. 636 * is invoked.
611 */ 637 */
612 efi_phys.get_time = (efi_get_time_t *)runtime->get_time; 638 efi_phys.get_time = (efi_get_time_t *)
639 (unsigned long)runtime->get_time;
613 efi_phys.set_virtual_address_map = 640 efi_phys.set_virtual_address_map =
614 (efi_set_virtual_address_map_t *) 641 (efi_set_virtual_address_map_t *)
615 runtime->set_virtual_address_map; 642 (unsigned long)runtime->set_virtual_address_map;
616 /* 643 /*
617 * Make efi_get_time can be called before entering 644 * Make efi_get_time can be called before entering
618 * virtual mode. 645 * virtual mode.
619 */ 646 */
620 efi.get_time = phys_efi_get_time; 647 efi.get_time = phys_efi_get_time;
621 early_iounmap(runtime, sizeof(efi_runtime_services_t)); 648 early_iounmap(runtime, sizeof(efi_runtime_services_64_t));
649
650 return 0;
651}
652
653static int __init efi_runtime_init(void)
654{
655 int rv;
656
657 /*
658 * Check out the runtime services table. We need to map
659 * the runtime services table so that we can grab the physical
660 * address of several of the EFI runtime functions, needed to
661 * set the firmware into virtual mode.
662 */
663 if (efi_enabled(EFI_64BIT))
664 rv = efi_runtime_init64();
665 else
666 rv = efi_runtime_init32();
667
668 if (rv)
669 return rv;
622 670
623 return 0; 671 return 0;
624} 672}
@@ -841,6 +889,22 @@ void __init old_map_region(efi_memory_desc_t *md)
841 (unsigned long long)md->phys_addr); 889 (unsigned long long)md->phys_addr);
842} 890}
843 891
892static void native_runtime_setup(void)
893{
894 efi.get_time = virt_efi_get_time;
895 efi.set_time = virt_efi_set_time;
896 efi.get_wakeup_time = virt_efi_get_wakeup_time;
897 efi.set_wakeup_time = virt_efi_set_wakeup_time;
898 efi.get_variable = virt_efi_get_variable;
899 efi.get_next_variable = virt_efi_get_next_variable;
900 efi.set_variable = virt_efi_set_variable;
901 efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
902 efi.reset_system = virt_efi_reset_system;
903 efi.query_variable_info = virt_efi_query_variable_info;
904 efi.update_capsule = virt_efi_update_capsule;
905 efi.query_capsule_caps = virt_efi_query_capsule_caps;
906}
907
844/* Merge contiguous regions of the same type and attribute */ 908/* Merge contiguous regions of the same type and attribute */
845static void __init efi_merge_regions(void) 909static void __init efi_merge_regions(void)
846{ 910{
@@ -1023,11 +1087,20 @@ void __init efi_enter_virtual_mode(void)
1023 efi_sync_low_kernel_mappings(); 1087 efi_sync_low_kernel_mappings();
1024 1088
1025 if (!efi_setup) { 1089 if (!efi_setup) {
1026 status = phys_efi_set_virtual_address_map( 1090 if (efi_is_native()) {
1027 memmap.desc_size * count, 1091 status = phys_efi_set_virtual_address_map(
1028 memmap.desc_size, 1092 memmap.desc_size * count,
1029 memmap.desc_version, 1093 memmap.desc_size,
1030 (efi_memory_desc_t *)__pa(new_memmap)); 1094 memmap.desc_version,
1095 (efi_memory_desc_t *)__pa(new_memmap));
1096 } else {
1097 status = efi_thunk_set_virtual_address_map(
1098 efi_phys.set_virtual_address_map,
1099 memmap.desc_size * count,
1100 memmap.desc_size,
1101 memmap.desc_version,
1102 (efi_memory_desc_t *)__pa(new_memmap));
1103 }
1031 1104
1032 if (status != EFI_SUCCESS) { 1105 if (status != EFI_SUCCESS) {
1033 pr_alert("Unable to switch EFI into virtual mode (status=%lx)!\n", 1106 pr_alert("Unable to switch EFI into virtual mode (status=%lx)!\n",
@@ -1043,19 +1116,13 @@ void __init efi_enter_virtual_mode(void)
1043 * Call EFI services through wrapper functions. 1116 * Call EFI services through wrapper functions.
1044 */ 1117 */
1045 efi.runtime_version = efi_systab.hdr.revision; 1118 efi.runtime_version = efi_systab.hdr.revision;
1046 efi.get_time = virt_efi_get_time; 1119
1047 efi.set_time = virt_efi_set_time; 1120 if (efi_is_native())
1048 efi.get_wakeup_time = virt_efi_get_wakeup_time; 1121 native_runtime_setup();
1049 efi.set_wakeup_time = virt_efi_set_wakeup_time; 1122 else
1050 efi.get_variable = virt_efi_get_variable; 1123 efi_thunk_runtime_setup();
1051 efi.get_next_variable = virt_efi_get_next_variable; 1124
1052 efi.set_variable = virt_efi_set_variable;
1053 efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
1054 efi.reset_system = virt_efi_reset_system;
1055 efi.set_virtual_address_map = NULL; 1125 efi.set_virtual_address_map = NULL;
1056 efi.query_variable_info = virt_efi_query_variable_info;
1057 efi.update_capsule = virt_efi_update_capsule;
1058 efi.query_capsule_caps = virt_efi_query_capsule_caps;
1059 1126
1060 efi_runtime_mkexec(); 1127 efi_runtime_mkexec();
1061 1128
diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c
index 0c2a234fef1e..12112ab4fd40 100644
--- a/arch/x86/platform/efi/efi_64.c
+++ b/arch/x86/platform/efi/efi_64.c
@@ -39,6 +39,7 @@
39#include <asm/cacheflush.h> 39#include <asm/cacheflush.h>
40#include <asm/fixmap.h> 40#include <asm/fixmap.h>
41#include <asm/realmode.h> 41#include <asm/realmode.h>
42#include <asm/time.h>
42 43
43static pgd_t *save_pgd __initdata; 44static pgd_t *save_pgd __initdata;
44static unsigned long efi_flags __initdata; 45static unsigned long efi_flags __initdata;
@@ -58,7 +59,8 @@ struct efi_scratch {
58 u64 prev_cr3; 59 u64 prev_cr3;
59 pgd_t *efi_pgt; 60 pgd_t *efi_pgt;
60 bool use_pgd; 61 bool use_pgd;
61}; 62 u64 phys_stack;
63} __packed;
62 64
63static void __init early_code_mapping_set_exec(int executable) 65static void __init early_code_mapping_set_exec(int executable)
64{ 66{
@@ -139,10 +141,40 @@ void efi_sync_low_kernel_mappings(void)
139 141
140void efi_setup_page_tables(void) 142void efi_setup_page_tables(void)
141{ 143{
144 unsigned long text;
145 unsigned npages;
146 struct page *page;
147
142 efi_scratch.efi_pgt = (pgd_t *)(unsigned long)real_mode_header->trampoline_pgd; 148 efi_scratch.efi_pgt = (pgd_t *)(unsigned long)real_mode_header->trampoline_pgd;
143 149
144 if (!efi_enabled(EFI_OLD_MEMMAP)) 150 if (efi_enabled(EFI_OLD_MEMMAP))
145 efi_scratch.use_pgd = true; 151 return;
152
153 efi_scratch.use_pgd = true;
154
155 /*
156 * When making calls to the firmware everything needs to be 1:1
157 * mapped and addressable with 32-bit pointers. Map the kernel
158 * text and allocate a new stack because we can't rely on the
159 * stack pointer being < 4GB.
160 */
161 if (!IS_ENABLED(CONFIG_EFI_MIXED))
162 return;
163
164 page = alloc_page(GFP_KERNEL|__GFP_DMA32);
165 if (!page)
166 panic("Unable to allocate EFI runtime stack < 4GB\n");
167
168 efi_scratch.phys_stack = virt_to_phys(page_address(page));
169 efi_scratch.phys_stack += PAGE_SIZE; /* stack grows down */
170
171 npages = (_end - _text) >> PAGE_SHIFT;
172 text = __pa(_text);
173
174 if (kernel_map_pages_in_pgd(__va(efi_scratch.efi_pgt),
175 text >> PAGE_SHIFT, text, npages, 0)) {
176 pr_err("Failed to map kernel text 1:1\n");
177 }
146} 178}
147 179
148static void __init __map_region(efi_memory_desc_t *md, u64 va) 180static void __init __map_region(efi_memory_desc_t *md, u64 va)
@@ -173,6 +205,16 @@ void __init efi_map_region(efi_memory_desc_t *md)
173 */ 205 */
174 __map_region(md, md->phys_addr); 206 __map_region(md, md->phys_addr);
175 207
208 /*
209 * Enforce the 1:1 mapping as the default virtual address when
210 * booting in EFI mixed mode, because even though we may be
211 * running a 64-bit kernel, the firmware may only be 32-bit.
212 */
213 if (!efi_is_native () && IS_ENABLED(CONFIG_EFI_MIXED)) {
214 md->virt_addr = md->phys_addr;
215 return;
216 }
217
176 efi_va -= size; 218 efi_va -= size;
177 219
178 /* Is PA 2M-aligned? */ 220 /* Is PA 2M-aligned? */
@@ -242,3 +284,290 @@ void __init efi_runtime_mkexec(void)
242 if (__supported_pte_mask & _PAGE_NX) 284 if (__supported_pte_mask & _PAGE_NX)
243 runtime_code_page_mkexec(); 285 runtime_code_page_mkexec();
244} 286}
287
288#ifdef CONFIG_EFI_MIXED
289extern efi_status_t efi64_thunk(u32, ...);
290
291#define runtime_service32(func) \
292({ \
293 u32 table = (u32)(unsigned long)efi.systab; \
294 u32 *rt, *___f; \
295 \
296 rt = (u32 *)(table + offsetof(efi_system_table_32_t, runtime)); \
297 ___f = (u32 *)(*rt + offsetof(efi_runtime_services_32_t, func)); \
298 *___f; \
299})
300
301/*
302 * Switch to the EFI page tables early so that we can access the 1:1
303 * runtime services mappings which are not mapped in any other page
304 * tables. This function must be called before runtime_service32().
305 *
306 * Also, disable interrupts because the IDT points to 64-bit handlers,
307 * which aren't going to function correctly when we switch to 32-bit.
308 */
309#define efi_thunk(f, ...) \
310({ \
311 efi_status_t __s; \
312 unsigned long flags; \
313 u32 func; \
314 \
315 efi_sync_low_kernel_mappings(); \
316 local_irq_save(flags); \
317 \
318 efi_scratch.prev_cr3 = read_cr3(); \
319 write_cr3((unsigned long)efi_scratch.efi_pgt); \
320 __flush_tlb_all(); \
321 \
322 func = runtime_service32(f); \
323 __s = efi64_thunk(func, __VA_ARGS__); \
324 \
325 write_cr3(efi_scratch.prev_cr3); \
326 __flush_tlb_all(); \
327 local_irq_restore(flags); \
328 \
329 __s; \
330})
331
332efi_status_t efi_thunk_set_virtual_address_map(
333 void *phys_set_virtual_address_map,
334 unsigned long memory_map_size,
335 unsigned long descriptor_size,
336 u32 descriptor_version,
337 efi_memory_desc_t *virtual_map)
338{
339 efi_status_t status;
340 unsigned long flags;
341 u32 func;
342
343 efi_sync_low_kernel_mappings();
344 local_irq_save(flags);
345
346 efi_scratch.prev_cr3 = read_cr3();
347 write_cr3((unsigned long)efi_scratch.efi_pgt);
348 __flush_tlb_all();
349
350 func = (u32)(unsigned long)phys_set_virtual_address_map;
351 status = efi64_thunk(func, memory_map_size, descriptor_size,
352 descriptor_version, virtual_map);
353
354 write_cr3(efi_scratch.prev_cr3);
355 __flush_tlb_all();
356 local_irq_restore(flags);
357
358 return status;
359}
360
361static efi_status_t efi_thunk_get_time(efi_time_t *tm, efi_time_cap_t *tc)
362{
363 efi_status_t status;
364 u32 phys_tm, phys_tc;
365
366 spin_lock(&rtc_lock);
367
368 phys_tm = virt_to_phys(tm);
369 phys_tc = virt_to_phys(tc);
370
371 status = efi_thunk(get_time, phys_tm, phys_tc);
372
373 spin_unlock(&rtc_lock);
374
375 return status;
376}
377
378static efi_status_t efi_thunk_set_time(efi_time_t *tm)
379{
380 efi_status_t status;
381 u32 phys_tm;
382
383 spin_lock(&rtc_lock);
384
385 phys_tm = virt_to_phys(tm);
386
387 status = efi_thunk(set_time, phys_tm);
388
389 spin_unlock(&rtc_lock);
390
391 return status;
392}
393
394static efi_status_t
395efi_thunk_get_wakeup_time(efi_bool_t *enabled, efi_bool_t *pending,
396 efi_time_t *tm)
397{
398 efi_status_t status;
399 u32 phys_enabled, phys_pending, phys_tm;
400
401 spin_lock(&rtc_lock);
402
403 phys_enabled = virt_to_phys(enabled);
404 phys_pending = virt_to_phys(pending);
405 phys_tm = virt_to_phys(tm);
406
407 status = efi_thunk(get_wakeup_time, phys_enabled,
408 phys_pending, phys_tm);
409
410 spin_unlock(&rtc_lock);
411
412 return status;
413}
414
415static efi_status_t
416efi_thunk_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
417{
418 efi_status_t status;
419 u32 phys_tm;
420
421 spin_lock(&rtc_lock);
422
423 phys_tm = virt_to_phys(tm);
424
425 status = efi_thunk(set_wakeup_time, enabled, phys_tm);
426
427 spin_unlock(&rtc_lock);
428
429 return status;
430}
431
432
433static efi_status_t
434efi_thunk_get_variable(efi_char16_t *name, efi_guid_t *vendor,
435 u32 *attr, unsigned long *data_size, void *data)
436{
437 efi_status_t status;
438 u32 phys_name, phys_vendor, phys_attr;
439 u32 phys_data_size, phys_data;
440
441 phys_data_size = virt_to_phys(data_size);
442 phys_vendor = virt_to_phys(vendor);
443 phys_name = virt_to_phys(name);
444 phys_attr = virt_to_phys(attr);
445 phys_data = virt_to_phys(data);
446
447 status = efi_thunk(get_variable, phys_name, phys_vendor,
448 phys_attr, phys_data_size, phys_data);
449
450 return status;
451}
452
453static efi_status_t
454efi_thunk_set_variable(efi_char16_t *name, efi_guid_t *vendor,
455 u32 attr, unsigned long data_size, void *data)
456{
457 u32 phys_name, phys_vendor, phys_data;
458 efi_status_t status;
459
460 phys_name = virt_to_phys(name);
461 phys_vendor = virt_to_phys(vendor);
462 phys_data = virt_to_phys(data);
463
464 /* If data_size is > sizeof(u32) we've got problems */
465 status = efi_thunk(set_variable, phys_name, phys_vendor,
466 attr, data_size, phys_data);
467
468 return status;
469}
470
471static efi_status_t
472efi_thunk_get_next_variable(unsigned long *name_size,
473 efi_char16_t *name,
474 efi_guid_t *vendor)
475{
476 efi_status_t status;
477 u32 phys_name_size, phys_name, phys_vendor;
478
479 phys_name_size = virt_to_phys(name_size);
480 phys_vendor = virt_to_phys(vendor);
481 phys_name = virt_to_phys(name);
482
483 status = efi_thunk(get_next_variable, phys_name_size,
484 phys_name, phys_vendor);
485
486 return status;
487}
488
489static efi_status_t
490efi_thunk_get_next_high_mono_count(u32 *count)
491{
492 efi_status_t status;
493 u32 phys_count;
494
495 phys_count = virt_to_phys(count);
496 status = efi_thunk(get_next_high_mono_count, phys_count);
497
498 return status;
499}
500
501static void
502efi_thunk_reset_system(int reset_type, efi_status_t status,
503 unsigned long data_size, efi_char16_t *data)
504{
505 u32 phys_data;
506
507 phys_data = virt_to_phys(data);
508
509 efi_thunk(reset_system, reset_type, status, data_size, phys_data);
510}
511
512static efi_status_t
513efi_thunk_update_capsule(efi_capsule_header_t **capsules,
514 unsigned long count, unsigned long sg_list)
515{
516 /*
517 * To properly support this function we would need to repackage
518 * 'capsules' because the firmware doesn't understand 64-bit
519 * pointers.
520 */
521 return EFI_UNSUPPORTED;
522}
523
524static efi_status_t
525efi_thunk_query_variable_info(u32 attr, u64 *storage_space,
526 u64 *remaining_space,
527 u64 *max_variable_size)
528{
529 efi_status_t status;
530 u32 phys_storage, phys_remaining, phys_max;
531
532 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
533 return EFI_UNSUPPORTED;
534
535 phys_storage = virt_to_phys(storage_space);
536 phys_remaining = virt_to_phys(remaining_space);
537 phys_max = virt_to_phys(max_variable_size);
538
539 status = efi_thunk(query_variable_info, phys_storage,
540 phys_remaining, phys_max);
541
542 return status;
543}
544
545static efi_status_t
546efi_thunk_query_capsule_caps(efi_capsule_header_t **capsules,
547 unsigned long count, u64 *max_size,
548 int *reset_type)
549{
550 /*
551 * To properly support this function we would need to repackage
552 * 'capsules' because the firmware doesn't understand 64-bit
553 * pointers.
554 */
555 return EFI_UNSUPPORTED;
556}
557
558void efi_thunk_runtime_setup(void)
559{
560 efi.get_time = efi_thunk_get_time;
561 efi.set_time = efi_thunk_set_time;
562 efi.get_wakeup_time = efi_thunk_get_wakeup_time;
563 efi.set_wakeup_time = efi_thunk_set_wakeup_time;
564 efi.get_variable = efi_thunk_get_variable;
565 efi.get_next_variable = efi_thunk_get_next_variable;
566 efi.set_variable = efi_thunk_set_variable;
567 efi.get_next_high_mono_count = efi_thunk_get_next_high_mono_count;
568 efi.reset_system = efi_thunk_reset_system;
569 efi.query_variable_info = efi_thunk_query_variable_info;
570 efi.update_capsule = efi_thunk_update_capsule;
571 efi.query_capsule_caps = efi_thunk_query_capsule_caps;
572}
573#endif /* CONFIG_EFI_MIXED */
diff --git a/arch/x86/platform/efi/efi_stub_64.S b/arch/x86/platform/efi/efi_stub_64.S
index a790d69cc85e..e811514beeac 100644
--- a/arch/x86/platform/efi/efi_stub_64.S
+++ b/arch/x86/platform/efi/efi_stub_64.S
@@ -318,3 +318,4 @@ efi_gdt64_end:
318ENTRY(efi_scratch) 318ENTRY(efi_scratch)
319 .fill 3,8,0 319 .fill 3,8,0
320 .byte 0 320 .byte 0
321 .quad 0
diff --git a/arch/x86/platform/efi/efi_thunk_64.S b/arch/x86/platform/efi/efi_thunk_64.S
new file mode 100644
index 000000000000..8806fa73e6e6
--- /dev/null
+++ b/arch/x86/platform/efi/efi_thunk_64.S
@@ -0,0 +1,65 @@
1/*
2 * Copyright (C) 2014 Intel Corporation; author Matt Fleming
3 */
4
5#include <linux/linkage.h>
6#include <asm/page_types.h>
7
8 .text
9 .code64
10ENTRY(efi64_thunk)
11 push %rbp
12 push %rbx
13
14 /*
15 * Switch to 1:1 mapped 32-bit stack pointer.
16 */
17 movq %rsp, efi_saved_sp(%rip)
18 movq efi_scratch+25(%rip), %rsp
19
20 /*
21 * Calculate the physical address of the kernel text.
22 */
23 movq $__START_KERNEL_map, %rax
24 subq phys_base(%rip), %rax
25
26 /*
27 * Push some physical addresses onto the stack. This is easier
28 * to do now in a code64 section while the assembler can address
29 * 64-bit values. Note that all the addresses on the stack are
30 * 32-bit.
31 */
32 subq $16, %rsp
33 leaq efi_exit32(%rip), %rbx
34 subq %rax, %rbx
35 movl %ebx, 8(%rsp)
36 leaq efi_gdt64(%rip), %rbx
37 subq %rax, %rbx
38 movl %ebx, 2(%ebx)
39 movl %ebx, 4(%rsp)
40 leaq efi_gdt32(%rip), %rbx
41 subq %rax, %rbx
42 movl %ebx, 2(%ebx)
43 movl %ebx, (%rsp)
44
45 leaq __efi64_thunk(%rip), %rbx
46 subq %rax, %rbx
47 call *%rbx
48
49 movq efi_saved_sp(%rip), %rsp
50 pop %rbx
51 pop %rbp
52 retq
53ENDPROC(efi64_thunk)
54
55 .data
56efi_gdt32:
57 .word efi_gdt32_end - efi_gdt32
58 .long 0 /* Filled out above */
59 .word 0
60 .quad 0x0000000000000000 /* NULL descriptor */
61 .quad 0x00cf9a000000ffff /* __KERNEL_CS */
62 .quad 0x00cf93000000ffff /* __KERNEL_DS */
63efi_gdt32_end:
64
65efi_saved_sp: .quad 0