efi_thunk_64.S 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  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. #include <linux/linkage.h>
  22. #include <asm/page_types.h>
  23. #include <asm/segment.h>
  24. .text
  25. .code64
  26. ENTRY(efi64_thunk)
  27. push %rbp
  28. push %rbx
  29. /*
  30. * Switch to 1:1 mapped 32-bit stack pointer.
  31. */
  32. movq %rsp, efi_saved_sp(%rip)
  33. movq efi_scratch(%rip), %rsp
  34. /*
  35. * Calculate the physical address of the kernel text.
  36. */
  37. movq $__START_KERNEL_map, %rax
  38. subq phys_base(%rip), %rax
  39. /*
  40. * Push some physical addresses onto the stack. This is easier
  41. * to do now in a code64 section while the assembler can address
  42. * 64-bit values. Note that all the addresses on the stack are
  43. * 32-bit.
  44. */
  45. subq $16, %rsp
  46. leaq efi_exit32(%rip), %rbx
  47. subq %rax, %rbx
  48. movl %ebx, 8(%rsp)
  49. leaq __efi64_thunk(%rip), %rbx
  50. subq %rax, %rbx
  51. call *%rbx
  52. movq efi_saved_sp(%rip), %rsp
  53. pop %rbx
  54. pop %rbp
  55. retq
  56. ENDPROC(efi64_thunk)
  57. /*
  58. * We run this function from the 1:1 mapping.
  59. *
  60. * This function must be invoked with a 1:1 mapped stack.
  61. */
  62. ENTRY(__efi64_thunk)
  63. movl %ds, %eax
  64. push %rax
  65. movl %es, %eax
  66. push %rax
  67. movl %ss, %eax
  68. push %rax
  69. subq $32, %rsp
  70. movl %esi, 0x0(%rsp)
  71. movl %edx, 0x4(%rsp)
  72. movl %ecx, 0x8(%rsp)
  73. movq %r8, %rsi
  74. movl %esi, 0xc(%rsp)
  75. movq %r9, %rsi
  76. movl %esi, 0x10(%rsp)
  77. leaq 1f(%rip), %rbx
  78. movq %rbx, func_rt_ptr(%rip)
  79. /* Switch to 32-bit descriptor */
  80. pushq $__KERNEL32_CS
  81. leaq efi_enter32(%rip), %rax
  82. pushq %rax
  83. lretq
  84. 1: addq $32, %rsp
  85. pop %rbx
  86. movl %ebx, %ss
  87. pop %rbx
  88. movl %ebx, %es
  89. pop %rbx
  90. movl %ebx, %ds
  91. /*
  92. * Convert 32-bit status code into 64-bit.
  93. */
  94. test %rax, %rax
  95. jz 1f
  96. movl %eax, %ecx
  97. andl $0x0fffffff, %ecx
  98. andl $0xf0000000, %eax
  99. shl $32, %rax
  100. or %rcx, %rax
  101. 1:
  102. ret
  103. ENDPROC(__efi64_thunk)
  104. ENTRY(efi_exit32)
  105. movq func_rt_ptr(%rip), %rax
  106. push %rax
  107. mov %rdi, %rax
  108. ret
  109. ENDPROC(efi_exit32)
  110. .code32
  111. /*
  112. * EFI service pointer must be in %edi.
  113. *
  114. * The stack should represent the 32-bit calling convention.
  115. */
  116. ENTRY(efi_enter32)
  117. movl $__KERNEL_DS, %eax
  118. movl %eax, %ds
  119. movl %eax, %es
  120. movl %eax, %ss
  121. call *%edi
  122. /* We must preserve return value */
  123. movl %eax, %edi
  124. movl 72(%esp), %eax
  125. pushl $__KERNEL_CS
  126. pushl %eax
  127. lret
  128. ENDPROC(efi_enter32)
  129. .data
  130. .balign 8
  131. func_rt_ptr: .quad 0
  132. efi_saved_sp: .quad 0