diff options
| author | Ingo Molnar <mingo@kernel.org> | 2015-02-18 08:40:40 -0500 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2015-02-18 08:40:40 -0500 |
| commit | 829bf7af647e489caa494cebdb2e4d455ec4644a (patch) | |
| tree | f8980bea7e8e62130cd477dd2ab32b54353448ab | |
| parent | e07e0d4cb0c4bfe822ec8491cc06269096a38bea (diff) | |
| parent | 43a9f69692b232d1c64c913a27507eb14a1c47fd (diff) | |
Merge tag 'efi-urgent' of git://git.kernel.org/pub/scm/linux/kernel/git/mfleming/efi into x86/urgent
Pull EFI fixes from Matt Fleming:
" - Leave a valid 64-bit IDT installed during runtime EFI mixed mode
calls to avoid triple faults if an NMI/MCE is received.
- Revert Ard's change to the libstub get_memory_map() that went into
the v3.20 merge window because it causes boot regressions on Qemu and
Xen. "
Signed-off-by: Ingo Molnar <mingo@kernel.org>
| -rw-r--r-- | arch/x86/boot/compressed/Makefile | 1 | ||||
| -rw-r--r-- | arch/x86/boot/compressed/efi_stub_64.S | 25 | ||||
| -rw-r--r-- | arch/x86/boot/compressed/efi_thunk_64.S | 196 | ||||
| -rw-r--r-- | arch/x86/platform/efi/efi_stub_64.S | 161 | ||||
| -rw-r--r-- | arch/x86/platform/efi/efi_thunk_64.S | 121 | ||||
| -rw-r--r-- | drivers/firmware/efi/libstub/efi-stub-helper.c | 16 |
6 files changed, 307 insertions, 213 deletions
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index ad754b4411f7..8bd44e8ee6e2 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile | |||
| @@ -49,6 +49,7 @@ $(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone | |||
| 49 | 49 | ||
| 50 | vmlinux-objs-$(CONFIG_EFI_STUB) += $(obj)/eboot.o $(obj)/efi_stub_$(BITS).o \ | 50 | vmlinux-objs-$(CONFIG_EFI_STUB) += $(obj)/eboot.o $(obj)/efi_stub_$(BITS).o \ |
| 51 | $(objtree)/drivers/firmware/efi/libstub/lib.a | 51 | $(objtree)/drivers/firmware/efi/libstub/lib.a |
| 52 | vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_thunk_$(BITS).o | ||
| 52 | 53 | ||
| 53 | $(obj)/vmlinux: $(vmlinux-objs-y) FORCE | 54 | $(obj)/vmlinux: $(vmlinux-objs-y) FORCE |
| 54 | $(call if_changed,ld) | 55 | $(call if_changed,ld) |
diff --git a/arch/x86/boot/compressed/efi_stub_64.S b/arch/x86/boot/compressed/efi_stub_64.S index 7ff3632806b1..99494dff2113 100644 --- a/arch/x86/boot/compressed/efi_stub_64.S +++ b/arch/x86/boot/compressed/efi_stub_64.S | |||
| @@ -3,28 +3,3 @@ | |||
| 3 | #include <asm/processor-flags.h> | 3 | #include <asm/processor-flags.h> |
| 4 | 4 | ||
| 5 | #include "../../platform/efi/efi_stub_64.S" | 5 | #include "../../platform/efi/efi_stub_64.S" |
| 6 | |||
| 7 | #ifdef CONFIG_EFI_MIXED | ||
| 8 | .code64 | ||
| 9 | .text | ||
| 10 | ENTRY(efi64_thunk) | ||
| 11 | push %rbp | ||
| 12 | push %rbx | ||
| 13 | |||
| 14 | subq $16, %rsp | ||
| 15 | leaq efi_exit32(%rip), %rax | ||
| 16 | movl %eax, 8(%rsp) | ||
| 17 | leaq efi_gdt64(%rip), %rax | ||
| 18 | movl %eax, 4(%rsp) | ||
| 19 | movl %eax, 2(%rax) /* Fixup the gdt base address */ | ||
| 20 | leaq efi32_boot_gdt(%rip), %rax | ||
| 21 | movl %eax, (%rsp) | ||
| 22 | |||
| 23 | call __efi64_thunk | ||
| 24 | |||
| 25 | addq $16, %rsp | ||
| 26 | pop %rbx | ||
| 27 | pop %rbp | ||
| 28 | ret | ||
| 29 | ENDPROC(efi64_thunk) | ||
| 30 | #endif /* CONFIG_EFI_MIXED */ | ||
diff --git a/arch/x86/boot/compressed/efi_thunk_64.S b/arch/x86/boot/compressed/efi_thunk_64.S new file mode 100644 index 000000000000..630384a4c14a --- /dev/null +++ b/arch/x86/boot/compressed/efi_thunk_64.S | |||
| @@ -0,0 +1,196 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2014, 2015 Intel Corporation; author Matt Fleming | ||
| 3 | * | ||
| 4 | * Early support for invoking 32-bit EFI services from a 64-bit kernel. | ||
| 5 | * | ||
| 6 | * Because this thunking occurs before ExitBootServices() we have to | ||
| 7 | * restore the firmware's 32-bit GDT before we make EFI serivce calls, | ||
| 8 | * since the firmware's 32-bit IDT is still currently installed and it | ||
| 9 | * needs to be able to service interrupts. | ||
| 10 | * | ||
| 11 | * On the plus side, we don't have to worry about mangling 64-bit | ||
| 12 | * addresses into 32-bits because we're executing with an identify | ||
| 13 | * mapped pagetable and haven't transitioned to 64-bit virtual addresses | ||
| 14 | * yet. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/linkage.h> | ||
| 18 | #include <asm/msr.h> | ||
| 19 | #include <asm/page_types.h> | ||
| 20 | #include <asm/processor-flags.h> | ||
| 21 | #include <asm/segment.h> | ||
| 22 | |||
| 23 | .code64 | ||
| 24 | .text | ||
| 25 | ENTRY(efi64_thunk) | ||
| 26 | push %rbp | ||
| 27 | push %rbx | ||
| 28 | |||
| 29 | subq $8, %rsp | ||
| 30 | leaq efi_exit32(%rip), %rax | ||
| 31 | movl %eax, 4(%rsp) | ||
| 32 | leaq efi_gdt64(%rip), %rax | ||
| 33 | movl %eax, (%rsp) | ||
| 34 | movl %eax, 2(%rax) /* Fixup the gdt base address */ | ||
| 35 | |||
| 36 | movl %ds, %eax | ||
| 37 | push %rax | ||
| 38 | movl %es, %eax | ||
| 39 | push %rax | ||
| 40 | movl %ss, %eax | ||
| 41 | push %rax | ||
| 42 | |||
| 43 | /* | ||
| 44 | * Convert x86-64 ABI params to i386 ABI | ||
| 45 | */ | ||
| 46 | subq $32, %rsp | ||
| 47 | movl %esi, 0x0(%rsp) | ||
| 48 | movl %edx, 0x4(%rsp) | ||
| 49 | movl %ecx, 0x8(%rsp) | ||
| 50 | movq %r8, %rsi | ||
| 51 | movl %esi, 0xc(%rsp) | ||
| 52 | movq %r9, %rsi | ||
| 53 | movl %esi, 0x10(%rsp) | ||
| 54 | |||
| 55 | sgdt save_gdt(%rip) | ||
| 56 | |||
| 57 | leaq 1f(%rip), %rbx | ||
| 58 | movq %rbx, func_rt_ptr(%rip) | ||
| 59 | |||
| 60 | /* | ||
| 61 | * Switch to gdt with 32-bit segments. This is the firmware GDT | ||
| 62 | * that was installed when the kernel started executing. This | ||
| 63 | * pointer was saved at the EFI stub entry point in head_64.S. | ||
| 64 | */ | ||
| 65 | leaq efi32_boot_gdt(%rip), %rax | ||
| 66 | lgdt (%rax) | ||
| 67 | |||
| 68 | pushq $__KERNEL_CS | ||
| 69 | leaq efi_enter32(%rip), %rax | ||
| 70 | pushq %rax | ||
| 71 | lretq | ||
| 72 | |||
| 73 | 1: addq $32, %rsp | ||
| 74 | |||
| 75 | lgdt save_gdt(%rip) | ||
| 76 | |||
| 77 | pop %rbx | ||
| 78 | movl %ebx, %ss | ||
| 79 | pop %rbx | ||
| 80 | movl %ebx, %es | ||
| 81 | pop %rbx | ||
| 82 | movl %ebx, %ds | ||
| 83 | |||
| 84 | /* | ||
| 85 | * Convert 32-bit status code into 64-bit. | ||
| 86 | */ | ||
| 87 | test %rax, %rax | ||
| 88 | jz 1f | ||
| 89 | movl %eax, %ecx | ||
| 90 | andl $0x0fffffff, %ecx | ||
| 91 | andl $0xf0000000, %eax | ||
| 92 | shl $32, %rax | ||
| 93 | or %rcx, %rax | ||
| 94 | 1: | ||
| 95 | addq $8, %rsp | ||
| 96 | pop %rbx | ||
| 97 | pop %rbp | ||
| 98 | ret | ||
| 99 | ENDPROC(efi64_thunk) | ||
| 100 | |||
| 101 | ENTRY(efi_exit32) | ||
| 102 | movq func_rt_ptr(%rip), %rax | ||
| 103 | push %rax | ||
| 104 | mov %rdi, %rax | ||
| 105 | ret | ||
| 106 | ENDPROC(efi_exit32) | ||
| 107 | |||
| 108 | .code32 | ||
| 109 | /* | ||
| 110 | * EFI service pointer must be in %edi. | ||
| 111 | * | ||
| 112 | * The stack should represent the 32-bit calling convention. | ||
| 113 | */ | ||
| 114 | ENTRY(efi_enter32) | ||
| 115 | movl $__KERNEL_DS, %eax | ||
| 116 | movl %eax, %ds | ||
| 117 | movl %eax, %es | ||
| 118 | movl %eax, %ss | ||
| 119 | |||
| 120 | /* Reload pgtables */ | ||
| 121 | movl %cr3, %eax | ||
| 122 | movl %eax, %cr3 | ||
| 123 | |||
| 124 | /* Disable paging */ | ||
| 125 | movl %cr0, %eax | ||
| 126 | btrl $X86_CR0_PG_BIT, %eax | ||
| 127 | movl %eax, %cr0 | ||
| 128 | |||
| 129 | /* Disable long mode via EFER */ | ||
| 130 | movl $MSR_EFER, %ecx | ||
| 131 | rdmsr | ||
| 132 | btrl $_EFER_LME, %eax | ||
| 133 | wrmsr | ||
| 134 | |||
| 135 | call *%edi | ||
| 136 | |||
| 137 | /* We must preserve return value */ | ||
| 138 | movl %eax, %edi | ||
| 139 | |||
