1/* SPDX-License-Identifier: GPL-2.0 */ 2/* 3 * Copyright (C) 2014 Intel Corporation; author Matt Fleming 4 * 5 * Support for invoking 32-bit EFI runtime services from a 64-bit 6 * kernel. 7 * 8 * The below thunking functions are only used after ExitBootServices() 9 * has been called. This simplifies things considerably as compared with 10 * the early EFI thunking because we can leave all the kernel state 11 * intact (GDT, IDT, etc) and simply invoke the the 32-bit EFI runtime 12 * services from __KERNEL32_CS. This means we can continue to service 13 * interrupts across an EFI mixed mode call. 14 * 15 * We do however, need to handle the fact that we're running in a full 16 * 64-bit virtual address space. Things like the stack and instruction 17 * addresses need to be accessible by the 32-bit firmware, so we rely on 18 * using the identity mappings in the EFI page table to access the stack 19 * and kernel text (see efi_setup_page_tables()). 20 */ 21 22#include <linux/linkage.h> 23#include <asm/page_types.h> 24#include <asm/segment.h> 25 26 .text 27 .code64 28ENTRY(efi64_thunk) 29 push %rbp 30 push %rbx 31 32 /* 33 * Switch to 1:1 mapped 32-bit stack pointer. 34 */ 35 movq %rsp, efi_saved_sp(%rip) 36 movq efi_scratch(%rip), %rsp 37 38 /* 39 * Calculate the physical address of the kernel text. 40 */ 41 movq $__START_KERNEL_map, %rax 42 subq phys_base(%rip), %rax 43 44 /* 45 * Push some physical addresses onto the stack. This is easier 46 * to do now in a code64 section while the assembler can address 47 * 64-bit values. Note that all the addresses on the stack are 48 * 32-bit. 49 */ 50 subq $16, %rsp 51 leaq efi_exit32(%rip), %rbx 52 subq %rax, %rbx 53 movl %ebx, 8(%rsp) 54 55 leaq __efi64_thunk(%rip), %rbx 56 subq %rax, %rbx 57 call *%rbx 58 59 movq efi_saved_sp(%rip), %rsp 60 pop %rbx 61 pop %rbp 62 retq 63ENDPROC(efi64_thunk) 64 65/* 66 * We run this function from the 1:1 mapping. 67 * 68 * This function must be invoked with a 1:1 mapped stack. 69 */ 70ENTRY(__efi64_thunk) 71 movl %ds, %eax 72 push %rax 73 movl %es, %eax 74 push %rax 75 movl %ss, %eax 76 push %rax 77 78 subq $32, %rsp 79 movl %esi, 0x0(%rsp) 80 movl %edx, 0x4(%rsp) 81 movl %ecx, 0x8(%rsp) 82 movq %r8, %rsi 83 movl %esi, 0xc(%rsp) 84 movq %r9, %rsi 85 movl %esi, 0x10(%rsp) 86 87 leaq 1f(%rip), %rbx 88 movq %rbx, func_rt_ptr(%rip) 89 90 /* Switch to 32-bit descriptor */ 91 pushq $__KERNEL32_CS 92 leaq efi_enter32(%rip), %rax 93 pushq %rax 94 lretq 95 961: addq $32, %rsp 97 98 pop %rbx 99 movl %ebx, %ss 100 pop %rbx 101 movl %ebx, %es 102 pop %rbx 103 movl %ebx, %ds 104 105 /* 106 * Convert 32-bit status code into 64-bit. 107 */ 108 test %rax, %rax 109 jz 1f 110 movl %eax, %ecx 111 andl $0x0fffffff, %ecx 112 andl $0xf0000000, %eax 113 shl $32, %rax 114 or %rcx, %rax 1151: 116 ret 117ENDPROC(__efi64_thunk) 118 119ENTRY(efi_exit32) 120 movq func_rt_ptr(%rip), %rax 121 push %rax 122 mov %rdi, %rax 123 ret 124ENDPROC(efi_exit32) 125 126 .code32 127/* 128 * EFI service pointer must be in %edi. 129 * 130 * The stack should represent the 32-bit calling convention. 131 */ 132ENTRY(efi_enter32) 133 movl $__KERNEL_DS, %eax 134 movl %eax, %ds 135 movl %eax, %es 136 movl %eax, %ss 137 138 call *%edi 139 140 /* We must preserve return value */ 141 movl %eax, %edi 142 143 movl 72(%esp), %eax 144 pushl $__KERNEL_CS 145 pushl %eax 146 147 lret 148ENDPROC(efi_enter32) 149 150 .data 151 .balign 8 152func_rt_ptr: .quad 0 153efi_saved_sp: .quad 0 154