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#include <asm/segment.h> 11#include <asm/msr.h> 12#include <asm/processor-flags.h> 13#include <asm/page_types.h> 14 15#define SAVE_XMM \ 16 mov %rsp, %rax; \ 17 subq $0x70, %rsp; \ 18 and $~0xf, %rsp; \ 19 mov %rax, (%rsp); \ 20 mov %cr0, %rax; \ 21 clts; \ 22 mov %rax, 0x8(%rsp); \ 23 movaps %xmm0, 0x60(%rsp); \ 24 movaps %xmm1, 0x50(%rsp); \ 25 movaps %xmm2, 0x40(%rsp); \ 26 movaps %xmm3, 0x30(%rsp); \ 27 movaps %xmm4, 0x20(%rsp); \ 28 movaps %xmm5, 0x10(%rsp) 29 30#define RESTORE_XMM \ 31 movaps 0x60(%rsp), %xmm0; \ 32 movaps 0x50(%rsp), %xmm1; \ 33 movaps 0x40(%rsp), %xmm2; \ 34 movaps 0x30(%rsp), %xmm3; \ 35 movaps 0x20(%rsp), %xmm4; \ 36 movaps 0x10(%rsp), %xmm5; \ 37 mov 0x8(%rsp), %rsi; \ 38 mov %rsi, %cr0; \ 39 mov (%rsp), %rsp 40 41 /* stolen from gcc */ 42 .macro FLUSH_TLB_ALL 43 movq %r15, efi_scratch(%rip) 44 movq %r14, efi_scratch+8(%rip) 45 movq %cr4, %r15 46 movq %r15, %r14 47 andb $0x7f, %r14b 48 movq %r14, %cr4 49 movq %r15, %cr4 50 movq efi_scratch+8(%rip), %r14 51 movq efi_scratch(%rip), %r15 52 .endm 53 54 .macro SWITCH_PGT 55 cmpb $0, efi_scratch+24(%rip) 56 je 1f 57 movq %r15, efi_scratch(%rip) # r15 58 # save previous CR3 59 movq %cr3, %r15 60 movq %r15, efi_scratch+8(%rip) # prev_cr3 61 movq efi_scratch+16(%rip), %r15 # EFI pgt 62 movq %r15, %cr3 63 1: 64 .endm 65 66 .macro RESTORE_PGT 67 cmpb $0, efi_scratch+24(%rip) 68 je 2f 69 movq efi_scratch+8(%rip), %r15 70 movq %r15, %cr3 71 movq efi_scratch(%rip), %r15 72 FLUSH_TLB_ALL 73 2: 74 .endm 75 76ENTRY(efi_call0) 77 SAVE_XMM 78 subq $32, %rsp 79 SWITCH_PGT 80 call *%rdi 81 RESTORE_PGT 82 addq $32, %rsp 83 RESTORE_XMM 84 ret 85ENDPROC(efi_call0) 86 87ENTRY(efi_call1) 88 SAVE_XMM 89 subq $32, %rsp 90 mov %rsi, %rcx 91 SWITCH_PGT 92 call *%rdi 93 RESTORE_PGT 94 addq $32, %rsp 95 RESTORE_XMM 96 ret 97ENDPROC(efi_call1) 98 99ENTRY(efi_call2) 100 SAVE_XMM 101 subq $32, %rsp 102 mov %rsi, %rcx 103 SWITCH_PGT 104 call *%rdi 105 RESTORE_PGT 106 addq $32, %rsp 107 RESTORE_XMM 108 ret 109ENDPROC(efi_call2) 110 111ENTRY(efi_call3) 112 SAVE_XMM 113 subq $32, %rsp 114 mov %rcx, %r8 115 mov %rsi, %rcx 116 SWITCH_PGT 117 call *%rdi 118 RESTORE_PGT 119 addq $32, %rsp 120 RESTORE_XMM 121 ret 122ENDPROC(efi_call3) 123 124ENTRY(efi_call4) 125 SAVE_XMM 126 subq $32, %rsp 127 mov %r8, %r9 128 mov %rcx, %r8 129 mov %rsi, %rcx 130 SWITCH_PGT 131 call *%rdi 132 RESTORE_PGT 133 addq $32, %rsp 134 RESTORE_XMM 135 ret 136ENDPROC(efi_call4) 137 138ENTRY(efi_call5) 139 SAVE_XMM 140 subq $48, %rsp 141 mov %r9, 32(%rsp) 142 mov %r8, %r9 143 mov %rcx, %r8 144 mov %rsi, %rcx 145 SWITCH_PGT 146 call *%rdi 147 RESTORE_PGT 148 addq $48, %rsp 149 RESTORE_XMM 150 ret 151ENDPROC(efi_call5) 152 153ENTRY(efi_call6) 154 SAVE_XMM 155 mov (%rsp), %rax 156 mov 8(%rax), %rax 157 subq $48, %rsp 158 mov %r9, 32(%rsp) 159 mov %rax, 40(%rsp) 160 mov %r8, %r9 161 mov %rcx, %r8 162 mov %rsi, %rcx 163 SWITCH_PGT 164 call *%rdi 165 RESTORE_PGT 166 addq $48, %rsp 167 RESTORE_XMM 168 ret 169ENDPROC(efi_call6) 170 171#ifdef CONFIG_EFI_MIXED 172 173/* 174 * We run this function from the 1:1 mapping. 175 * 176 * This function must be invoked with a 1:1 mapped stack. 177 */ 178ENTRY(__efi64_thunk) 179 movl %ds, %eax 180 push %rax 181 movl %es, %eax 182 push %rax 183 movl %ss, %eax 184 push %rax 185 186 subq $32, %rsp 187 movl %esi, 0x0(%rsp) 188 movl %edx, 0x4(%rsp) 189 movl %ecx, 0x8(%rsp) 190 movq %r8, %rsi 191 movl %esi, 0xc(%rsp) 192 movq %r9, %rsi 193 movl %esi, 0x10(%rsp) 194 195 sgdt save_gdt(%rip) 196 197 leaq 1f(%rip), %rbx 198 movq %rbx, func_rt_ptr(%rip) 199 200 /* Switch to gdt with 32-bit segments */ 201 movl 64(%rsp), %eax 202 lgdt (%rax) 203 204 leaq efi_enter32(%rip), %rax 205 pushq $__KERNEL_CS 206 pushq %rax 207 lretq 208 2091: addq $32, %rsp 210 211 lgdt save_gdt(%rip) 212 213 pop %rbx 214 movl %ebx, %ss 215 pop %rbx 216 movl %ebx, %es 217 pop %rbx 218 movl %ebx, %ds 219 220 /* 221 * Convert 32-bit status code into 64-bit. 222 */ 223 test %rax, %rax 224 jz 1f 225 movl %eax, %ecx 226 andl $0x0fffffff, %ecx 227 andl $0xf0000000, %eax 228 shl $32, %rax 229 or %rcx, %rax 2301: 231 ret 232ENDPROC(__efi64_thunk) 233 234ENTRY(efi_exit32) 235 movq func_rt_ptr(%rip), %rax 236 push %rax 237 mov %rdi, %rax 238 ret 239ENDPROC(efi_exit32) 240 241 .code32 242/* 243 * EFI service pointer must be in %edi. 244 * 245 * The stack should represent the 32-bit calling convention. 246 */ 247ENTRY(efi_enter32) 248 movl $__KERNEL_DS, %eax 249 movl %eax, %ds 250 movl %eax, %es 251 movl %eax, %ss 252 253 /* Reload pgtables */ 254 movl %cr3, %eax 255 movl %eax, %cr3 256 257 /* Disable paging */ 258 movl %cr0, %eax 259 btrl $X86_CR0_PG_BIT, %eax 260 movl %eax, %cr0 261 262 /* Disable long mode via EFER */ 263 movl $MSR_EFER, %ecx 264 rdmsr 265 btrl $_EFER_LME, %eax 266 wrmsr 267 268 call *%edi 269 270 /* We must preserve return value */ 271 movl %eax, %edi 272 273 /* 274 * Some firmware will return with interrupts enabled. Be sure to 275 * disable them before we switch GDTs. 276 */ 277 cli 278 279 movl 68(%esp), %eax 280 movl %eax, 2(%eax) 281 lgdtl (%eax) 282 283 movl %cr4, %eax 284 btsl $(X86_CR4_PAE_BIT), %eax 285 movl %eax, %cr4 286 287 movl %cr3, %eax 288 movl %eax, %cr3 289 290 movl $MSR_EFER, %ecx 291 rdmsr 292 btsl $_EFER_LME, %eax 293 wrmsr 294 295 xorl %eax, %eax 296 lldt %ax 297 298 movl 72(%esp), %eax 299 pushl $__KERNEL_CS 300 pushl %eax 301 302 /* Enable paging */ 303 movl %cr0, %eax 304 btsl $X86_CR0_PG_BIT, %eax 305 movl %eax, %cr0 306 lret 307ENDPROC(efi_enter32) 308 309 .data 310 .balign 8 311 .global efi32_boot_gdt 312efi32_boot_gdt: .word 0 313 .quad 0 314 315save_gdt: .word 0 316 .quad 0 317func_rt_ptr: .quad 0 318 319 .global efi_gdt64 320efi_gdt64: 321 .word efi_gdt64_end - efi_gdt64 322 .long 0 /* Filled out by user */ 323 .word 0 324 .quad 0x0000000000000000 /* NULL descriptor */ 325 .quad 0x00af9a000000ffff /* __KERNEL_CS */ 326 .quad 0x00cf92000000ffff /* __KERNEL_DS */ 327 .quad 0x0080890000000000 /* TS descriptor */ 328 .quad 0x0000000000000000 /* TS continued */ 329efi_gdt64_end: 330#endif /* CONFIG_EFI_MIXED */ 331 332 .data 333ENTRY(efi_scratch) 334 .fill 3,8,0 335 .byte 0 336 .quad 0 337