AmdSev.nasm 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. ;------------------------------------------------------------------------------ ;
  2. ; Copyright (c) 2021, AMD Inc. All rights reserved.<BR>
  3. ; SPDX-License-Identifier: BSD-2-Clause-Patent
  4. ;
  5. ; Module Name:
  6. ;
  7. ; AmdSev.nasm
  8. ;
  9. ; Abstract:
  10. ;
  11. ; This provides helper used by the MpFunc.nasm. If AMD SEV-ES is active
  12. ; then helpers perform the additional setups (such as GHCB).
  13. ;
  14. ;-------------------------------------------------------------------------------
  15. %define SIZE_4KB 0x1000
  16. RegisterGhcbGpa:
  17. ;
  18. ; Register GHCB GPA when SEV-SNP is enabled
  19. ;
  20. lea edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevSnpIsEnabled)]
  21. cmp byte [edi], 1 ; SevSnpIsEnabled
  22. jne RegisterGhcbGpaDone
  23. ; Save the rdi and rsi to used for later comparison
  24. push rdi
  25. push rsi
  26. mov edi, eax
  27. mov esi, edx
  28. or eax, 18 ; Ghcb registration request
  29. wrmsr
  30. rep vmmcall
  31. rdmsr
  32. mov r12, rax
  33. and r12, 0fffh
  34. cmp r12, 19 ; Ghcb registration response
  35. jne GhcbGpaRegisterFailure
  36. ; Verify that GPA is not changed
  37. and eax, 0fffff000h
  38. cmp edi, eax
  39. jne GhcbGpaRegisterFailure
  40. cmp esi, edx
  41. jne GhcbGpaRegisterFailure
  42. pop rsi
  43. pop rdi
  44. jmp RegisterGhcbGpaDone
  45. ;
  46. ; Request the guest termination
  47. ;
  48. GhcbGpaRegisterFailure:
  49. xor edx, edx
  50. mov eax, 256 ; GHCB terminate
  51. wrmsr
  52. rep vmmcall
  53. ; We should not return from the above terminate request, but if we do
  54. ; then enter into the hlt loop.
  55. DoHltLoop:
  56. cli
  57. hlt
  58. jmp DoHltLoop
  59. RegisterGhcbGpaDone:
  60. OneTimeCallRet RegisterGhcbGpa
  61. ;
  62. ; The function checks whether SEV-ES is enabled, if enabled
  63. ; then setup the GHCB page.
  64. ;
  65. SevEsSetupGhcb:
  66. lea edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevEsIsEnabled)]
  67. cmp byte [edi], 1 ; SevEsIsEnabled
  68. jne SevEsSetupGhcbExit
  69. ;
  70. ; program GHCB
  71. ; Each page after the GHCB is a per-CPU page, so the calculation programs
  72. ; a GHCB to be every 8KB.
  73. ;
  74. mov eax, SIZE_4KB
  75. shl eax, 1 ; EAX = SIZE_4K * 2
  76. mov ecx, ebx
  77. mul ecx ; EAX = SIZE_4K * 2 * CpuNumber
  78. mov edi, esi
  79. add edi, MP_CPU_EXCHANGE_INFO_FIELD (GhcbBase)
  80. add rax, qword [edi]
  81. mov rdx, rax
  82. shr rdx, 32
  83. mov rcx, 0xc0010130
  84. OneTimeCall RegisterGhcbGpa
  85. wrmsr
  86. SevEsSetupGhcbExit:
  87. OneTimeCallRet SevEsSetupGhcb
  88. ;
  89. ; The function checks whether SEV-ES is enabled, if enabled, use
  90. ; the GHCB
  91. ;
  92. SevEsGetApicId:
  93. lea edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevEsIsEnabled)]
  94. cmp byte [edi], 1 ; SevEsIsEnabled
  95. jne SevEsGetApicIdExit
  96. ;
  97. ; Since we don't have a stack yet, we can't take a #VC
  98. ; exception. Use the GHCB protocol to perform the CPUID
  99. ; calls.
  100. ;
  101. mov rcx, 0xc0010130
  102. rdmsr
  103. shl rdx, 32
  104. or rax, rdx
  105. mov rdi, rax ; RDI now holds the original GHCB GPA
  106. ;
  107. ; For SEV-SNP, the recommended handling for getting the x2APIC ID
  108. ; would be to use the SNP CPUID table to fetch CPUID.00H:EAX and
  109. ; CPUID:0BH:EBX[15:0] instead of the GHCB MSR protocol vmgexits
  110. ; below.
  111. ;
  112. ; To avoid the unecessary ugliness to accomplish that here, the BSP
  113. ; has performed these checks in advance (where #VC handler handles
  114. ; the CPUID table lookups automatically) and cached them in a flag
  115. ; so those checks can be skipped here.
  116. ;
  117. mov eax, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevSnpIsEnabled)]
  118. cmp al, 1
  119. jne CheckExtTopoAvail
  120. ;
  121. ; Even with SEV-SNP, the actual x2APIC ID in CPUID.0BH:EDX
  122. ; fetched from the hypervisor the same way SEV-ES does it.
  123. ;
  124. mov eax, [esi + MP_CPU_EXCHANGE_INFO_FIELD (ExtTopoAvail)]
  125. cmp al, 1
  126. je GetApicIdSevEs
  127. ; The 8-bit APIC ID fallback is also the same as with SEV-ES
  128. jmp NoX2ApicSevEs
  129. CheckExtTopoAvail:
  130. mov rdx, 0 ; CPUID function 0
  131. mov rax, 0 ; RAX register requested
  132. or rax, 4
  133. wrmsr
  134. rep vmmcall
  135. rdmsr
  136. cmp edx, 0bh
  137. jb NoX2ApicSevEs ; CPUID level below CPUID_EXTENDED_TOPOLOGY
  138. mov rdx, 0bh ; CPUID function 0x0b
  139. mov rax, 040000000h ; RBX register requested
  140. or rax, 4
  141. wrmsr
  142. rep vmmcall
  143. rdmsr
  144. test edx, 0ffffh
  145. jz NoX2ApicSevEs ; CPUID.0BH:EBX[15:0] is zero
  146. GetApicIdSevEs:
  147. mov rdx, 0bh ; CPUID function 0x0b
  148. mov rax, 0c0000000h ; RDX register requested
  149. or rax, 4
  150. wrmsr
  151. rep vmmcall
  152. rdmsr
  153. ; Processor is x2APIC capable; 32-bit x2APIC ID is now in EDX
  154. jmp RestoreGhcb
  155. NoX2ApicSevEs:
  156. ; Processor is not x2APIC capable, so get 8-bit APIC ID
  157. mov rdx, 1 ; CPUID function 1
  158. mov rax, 040000000h ; RBX register requested
  159. or rax, 4
  160. wrmsr
  161. rep vmmcall
  162. rdmsr
  163. shr edx, 24
  164. RestoreGhcb:
  165. mov rbx, rdx ; Save x2APIC/APIC ID
  166. mov rdx, rdi ; RDI holds the saved GHCB GPA
  167. shr rdx, 32
  168. mov eax, edi
  169. wrmsr
  170. mov rdx, rbx
  171. ; x2APIC ID or APIC ID is in EDX
  172. jmp GetProcessorNumber
  173. SevEsGetApicIdExit:
  174. OneTimeCallRet SevEsGetApicId
  175. ;-------------------------------------------------------------------------------------
  176. ;SwitchToRealProc procedure follows.
  177. ;ALSO THIS PROCEDURE IS EXECUTED BY APs TRANSITIONING TO 16 BIT MODE. HENCE THIS PROC
  178. ;IS IN MACHINE CODE.
  179. ; SwitchToRealProc (UINTN BufferStart, UINT16 Code16, UINT16 Code32, UINTN StackStart)
  180. ; rcx - Buffer Start
  181. ; rdx - Code16 Selector Offset
  182. ; r8 - Code32 Selector Offset
  183. ; r9 - Stack Start
  184. ;-------------------------------------------------------------------------------------
  185. SwitchToRealProcStart:
  186. BITS 64
  187. cli
  188. ;
  189. ; Get RDX reset value before changing stacks since the
  190. ; new stack won't be able to accomodate a #VC exception.
  191. ;
  192. push rax
  193. push rbx
  194. push rcx
  195. push rdx
  196. mov rax, 1
  197. cpuid
  198. mov rsi, rax ; Save off the reset value for RDX
  199. pop rdx
  200. pop rcx
  201. pop rbx
  202. pop rax
  203. ;
  204. ; Establish stack below 1MB
  205. ;
  206. mov rsp, r9
  207. ;
  208. ; Push ultimate Reset Vector onto the stack
  209. ;
  210. mov rax, rcx
  211. shr rax, 4
  212. push word 0x0002 ; RFLAGS
  213. push ax ; CS
  214. push word 0x0000 ; RIP
  215. push word 0x0000 ; For alignment, will be discarded
  216. ;
  217. ; Get address of "16-bit operand size" label
  218. ;
  219. lea rbx, [PM16Mode]
  220. ;
  221. ; Push addresses used to change to compatibility mode
  222. ;
  223. lea rax, [CompatMode]
  224. push r8
  225. push rax
  226. ;
  227. ; Clear R8 - R15, for reset, before going into 32-bit mode
  228. ;
  229. xor r8, r8
  230. xor r9, r9
  231. xor r10, r10
  232. xor r11, r11
  233. xor r12, r12
  234. xor r13, r13
  235. xor r14, r14
  236. xor r15, r15
  237. ;
  238. ; Far return into 32-bit mode
  239. ;
  240. retfq
  241. BITS 32
  242. CompatMode:
  243. ;
  244. ; Set up stack to prepare for exiting protected mode
  245. ;
  246. push edx ; Code16 CS
  247. push ebx ; PM16Mode label address
  248. ;
  249. ; Disable paging
  250. ;
  251. mov eax, cr0 ; Read CR0
  252. btr eax, 31 ; Set PG=0
  253. mov cr0, eax ; Write CR0
  254. ;
  255. ; Disable long mode
  256. ;
  257. mov ecx, 0c0000080h ; EFER MSR number
  258. rdmsr ; Read EFER
  259. btr eax, 8 ; Set LME=0
  260. wrmsr ; Write EFER
  261. ;
  262. ; Disable PAE
  263. ;
  264. mov eax, cr4 ; Read CR4
  265. btr eax, 5 ; Set PAE=0
  266. mov cr4, eax ; Write CR4
  267. mov edx, esi ; Restore RDX reset value
  268. ;
  269. ; Switch to 16-bit operand size
  270. ;
  271. retf
  272. BITS 16
  273. ;
  274. ; At entry to this label
  275. ; - RDX will have its reset value
  276. ; - On the top of the stack
  277. ; - Alignment data (two bytes) to be discarded
  278. ; - IP for Real Mode (two bytes)
  279. ; - CS for Real Mode (two bytes)
  280. ;
  281. ; This label is also used with AsmRelocateApLoop. During MP finalization,
  282. ; the code from PM16Mode to SwitchToRealProcEnd is copied to the start of
  283. ; the WakeupBuffer, allowing a parked AP to be booted by an OS.
  284. ;
  285. PM16Mode:
  286. mov eax, cr0 ; Read CR0
  287. btr eax, 0 ; Set PE=0
  288. mov cr0, eax ; Write CR0
  289. pop ax ; Discard alignment data
  290. ;
  291. ; Clear registers (except RDX and RSP) before going into 16-bit mode
  292. ;
  293. xor eax, eax
  294. xor ebx, ebx
  295. xor ecx, ecx
  296. xor esi, esi
  297. xor edi, edi
  298. xor ebp, ebp
  299. iret
  300. SwitchToRealProcEnd: