efi_stub_64.S 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  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. #include <linux/linkage.h>
  9. #include <asm/segment.h>
  10. #include <asm/msr.h>
  11. #include <asm/processor-flags.h>
  12. #include <asm/page_types.h>
  13. #define SAVE_XMM \
  14. mov %rsp, %rax; \
  15. subq $0x70, %rsp; \
  16. and $~0xf, %rsp; \
  17. mov %rax, (%rsp); \
  18. mov %cr0, %rax; \
  19. clts; \
  20. mov %rax, 0x8(%rsp); \
  21. movaps %xmm0, 0x60(%rsp); \
  22. movaps %xmm1, 0x50(%rsp); \
  23. movaps %xmm2, 0x40(%rsp); \
  24. movaps %xmm3, 0x30(%rsp); \
  25. movaps %xmm4, 0x20(%rsp); \
  26. movaps %xmm5, 0x10(%rsp)
  27. #define RESTORE_XMM \
  28. movaps 0x60(%rsp), %xmm0; \
  29. movaps 0x50(%rsp), %xmm1; \
  30. movaps 0x40(%rsp), %xmm2; \
  31. movaps 0x30(%rsp), %xmm3; \
  32. movaps 0x20(%rsp), %xmm4; \
  33. movaps 0x10(%rsp), %xmm5; \
  34. mov 0x8(%rsp), %rsi; \
  35. mov %rsi, %cr0; \
  36. mov (%rsp), %rsp
  37. /* stolen from gcc */
  38. .macro FLUSH_TLB_ALL
  39. movq %r15, efi_scratch(%rip)
  40. movq %r14, efi_scratch+8(%rip)
  41. movq %cr4, %r15
  42. movq %r15, %r14
  43. andb $0x7f, %r14b
  44. movq %r14, %cr4
  45. movq %r15, %cr4
  46. movq efi_scratch+8(%rip), %r14
  47. movq efi_scratch(%rip), %r15
  48. .endm
  49. .macro SWITCH_PGT
  50. cmpb $0, efi_scratch+24(%rip)
  51. je 1f
  52. movq %r15, efi_scratch(%rip) # r15
  53. # save previous CR3
  54. movq %cr3, %r15
  55. movq %r15, efi_scratch+8(%rip) # prev_cr3
  56. movq efi_scratch+16(%rip), %r15 # EFI pgt
  57. movq %r15, %cr3
  58. 1:
  59. .endm
  60. .macro RESTORE_PGT
  61. cmpb $0, efi_scratch+24(%rip)
  62. je 2f
  63. movq efi_scratch+8(%rip), %r15
  64. movq %r15, %cr3
  65. movq efi_scratch(%rip), %r15
  66. FLUSH_TLB_ALL
  67. 2:
  68. .endm
  69. ENTRY(efi_call)
  70. SAVE_XMM
  71. mov (%rsp), %rax
  72. mov 8(%rax), %rax
  73. subq $48, %rsp
  74. mov %r9, 32(%rsp)
  75. mov %rax, 40(%rsp)
  76. mov %r8, %r9
  77. mov %rcx, %r8
  78. mov %rsi, %rcx
  79. SWITCH_PGT
  80. call *%rdi
  81. RESTORE_PGT
  82. addq $48, %rsp
  83. RESTORE_XMM
  84. ret
  85. ENDPROC(efi_call)
  86. #ifdef CONFIG_EFI_MIXED
  87. /*
  88. * We run this function from the 1:1 mapping.
  89. *
  90. * This function must be invoked with a 1:1 mapped stack.
  91. */
  92. ENTRY(__efi64_thunk)
  93. movl %ds, %eax
  94. push %rax
  95. movl %es, %eax
  96. push %rax
  97. movl %ss, %eax
  98. push %rax
  99. subq $32, %rsp
  100. movl %esi, 0x0(%rsp)
  101. movl %edx, 0x4(%rsp)
  102. movl %ecx, 0x8(%rsp)
  103. movq %r8, %rsi
  104. movl %esi, 0xc(%rsp)
  105. movq %r9, %rsi
  106. movl %esi, 0x10(%rsp)
  107. sgdt save_gdt(%rip)
  108. leaq 1f(%rip), %rbx
  109. movq %rbx, func_rt_ptr(%rip)
  110. /* Switch to gdt with 32-bit segments */
  111. movl 64(%rsp), %eax
  112. lgdt (%rax)
  113. leaq efi_enter32(%rip), %rax
  114. pushq $__KERNEL_CS
  115. pushq %rax
  116. lretq
  117. 1: addq $32, %rsp
  118. lgdt save_gdt(%rip)
  119. pop %rbx
  120. movl %ebx, %ss
  121. pop %rbx
  122. movl %ebx, %es
  123. pop %rbx
  124. movl %ebx, %ds
  125. /*
  126. * Convert 32-bit status code into 64-bit.
  127. */
  128. test %rax, %rax
  129. jz 1f
  130. movl %eax, %ecx
  131. andl $0x0fffffff, %ecx
  132. andl $0xf0000000, %eax
  133. shl $32, %rax
  134. or %rcx, %rax
  135. 1:
  136. ret
  137. ENDPROC(__efi64_thunk)
  138. ENTRY(efi_exit32)
  139. movq func_rt_ptr(%rip), %rax
  140. push %rax
  141. mov %rdi, %rax
  142. ret
  143. ENDPROC(efi_exit32)
  144. .code32
  145. /*
  146. * EFI service pointer must be in %edi.
  147. *
  148. * The stack should represent the 32-bit calling convention.
  149. */
  150. ENTRY(efi_enter32)
  151. movl $__KERNEL_DS, %eax
  152. movl %eax, %ds
  153. movl %eax, %es
  154. movl %eax, %ss
  155. /* Reload pgtables */
  156. movl %cr3, %eax
  157. movl %eax, %cr3
  158. /* Disable paging */
  159. movl %cr0, %eax
  160. btrl $X86_CR0_PG_BIT, %eax
  161. movl %eax, %cr0
  162. /* Disable long mode via EFER */
  163. movl $MSR_EFER, %ecx
  164. rdmsr
  165. btrl $_EFER_LME, %eax
  166. wrmsr
  167. call *%edi
  168. /* We must preserve return value */
  169. movl %eax, %edi
  170. /*
  171. * Some firmware will return with interrupts enabled. Be sure to
  172. * disable them before we switch GDTs.
  173. */
  174. cli
  175. movl 68(%esp), %eax
  176. movl %eax, 2(%eax)
  177. lgdtl (%eax)
  178. movl %cr4, %eax
  179. btsl $(X86_CR4_PAE_BIT), %eax
  180. movl %eax, %cr4
  181. movl %cr3, %eax
  182. movl %eax, %cr3
  183. movl $MSR_EFER, %ecx
  184. rdmsr
  185. btsl $_EFER_LME, %eax
  186. wrmsr
  187. xorl %eax, %eax
  188. lldt %ax
  189. movl 72(%esp), %eax
  190. pushl $__KERNEL_CS
  191. pushl %eax
  192. /* Enable paging */
  193. movl %cr0, %eax
  194. btsl $X86_CR0_PG_BIT, %eax
  195. movl %eax, %cr0
  196. lret
  197. ENDPROC(efi_enter32)
  198. .data
  199. .balign 8
  200. .global efi32_boot_gdt
  201. efi32_boot_gdt: .word 0
  202. .quad 0
  203. save_gdt: .word 0
  204. .quad 0
  205. func_rt_ptr: .quad 0
  206. .global efi_gdt64
  207. efi_gdt64:
  208. .word efi_gdt64_end - efi_gdt64
  209. .long 0 /* Filled out by user */
  210. .word 0
  211. .quad 0x0000000000000000 /* NULL descriptor */
  212. .quad 0x00af9a000000ffff /* __KERNEL_CS */
  213. .quad 0x00cf92000000ffff /* __KERNEL_DS */
  214. .quad 0x0080890000000000 /* TS descriptor */
  215. .quad 0x0000000000000000 /* TS continued */
  216. efi_gdt64_end:
  217. #endif /* CONFIG_EFI_MIXED */
  218. .data
  219. ENTRY(efi_scratch)
  220. .fill 3,8,0
  221. .byte 0
  222. .quad 0