; The unexpected response code\r
%define TERM_UNEXPECTED_RESP_CODE 2\r
\r
+%define PAGE_PRESENT 0x01\r
+%define PAGE_READ_WRITE 0x02\r
+%define PAGE_USER_SUPERVISOR 0x04\r
+%define PAGE_WRITE_THROUGH 0x08\r
+%define PAGE_CACHE_DISABLE 0x010\r
+%define PAGE_ACCESSED 0x020\r
+%define PAGE_DIRTY 0x040\r
+%define PAGE_PAT 0x080\r
+%define PAGE_GLOBAL 0x0100\r
+%define PAGE_2M_MBO 0x080\r
+%define PAGE_2M_PAT 0x01000\r
+\r
+%define PAGE_4K_PDE_ATTR (PAGE_ACCESSED + \\r
+ PAGE_DIRTY + \\r
+ PAGE_READ_WRITE + \\r
+ PAGE_PRESENT)\r
+\r
+%define PAGE_PDP_ATTR (PAGE_ACCESSED + \\r
+ PAGE_READ_WRITE + \\r
+ PAGE_PRESENT)\r
+\r
\r
; Macro is used to issue the MSR protocol based VMGEXIT. The caller is\r
; responsible to populate values in the EDX:EAX registers. After the vmmcall\r
SevEsUnexpectedRespTerminate:\r
TerminateVmgExit TERM_UNEXPECTED_RESP_CODE\r
\r
+; If SEV-ES is enabled then initialize and make the GHCB page shared\r
+SevClearPageEncMaskForGhcbPage:\r
+ ; Check if SEV is enabled\r
+ cmp byte[WORK_AREA_GUEST_TYPE], 1\r
+ jnz SevClearPageEncMaskForGhcbPageExit\r
+\r
+ ; Check if SEV-ES is enabled\r
+ cmp byte[SEV_ES_WORK_AREA], 1\r
+ jnz SevClearPageEncMaskForGhcbPageExit\r
+\r
+ ;\r
+ ; The initial GHCB will live at GHCB_BASE and needs to be un-encrypted.\r
+ ; This requires the 2MB page for this range be broken down into 512 4KB\r
+ ; pages. All will be marked encrypted, except for the GHCB.\r
+ ;\r
+ mov ecx, (GHCB_BASE >> 21)\r
+ mov eax, GHCB_PT_ADDR + PAGE_PDP_ATTR\r
+ mov [ecx * 8 + PT_ADDR (0x2000)], eax\r
+\r
+ ;\r
+ ; Page Table Entries (512 * 4KB entries => 2MB)\r
+ ;\r
+ mov ecx, 512\r
+pageTableEntries4kLoop:\r
+ mov eax, ecx\r
+ dec eax\r
+ shl eax, 12\r
+ add eax, GHCB_BASE & 0xFFE0_0000\r
+ add eax, PAGE_4K_PDE_ATTR\r
+ mov [ecx * 8 + GHCB_PT_ADDR - 8], eax\r
+ mov [(ecx * 8 + GHCB_PT_ADDR - 8) + 4], edx\r
+ loop pageTableEntries4kLoop\r
+\r
+ ;\r
+ ; Clear the encryption bit from the GHCB entry\r
+ ;\r
+ mov ecx, (GHCB_BASE & 0x1F_FFFF) >> 12\r
+ mov [ecx * 8 + GHCB_PT_ADDR + 4], strict dword 0\r
+\r
+ mov ecx, GHCB_SIZE / 4\r
+ xor eax, eax\r
+clearGhcbMemoryLoop:\r
+ mov dword[ecx * 4 + GHCB_BASE - 4], eax\r
+ loop clearGhcbMemoryLoop\r
+\r
+SevClearPageEncMaskForGhcbPageExit:\r
+ OneTimeCallRet SevClearPageEncMaskForGhcbPage\r
+\r
+; Check if SEV is enabled, and get the C-bit mask above 31.\r
+; Modified: EDX\r
+;\r
+; The value is returned in the EDX\r
+GetSevCBitMaskAbove31:\r
+ xor edx, edx\r
+\r
+ ; Check if SEV is enabled\r
+ cmp byte[WORK_AREA_GUEST_TYPE], 1\r
+ jnz GetSevCBitMaskAbove31Exit\r
+\r
+ mov edx, dword[SEV_ES_WORK_AREA_ENC_MASK + 4]\r
+\r
+GetSevCBitMaskAbove31Exit:\r
+ OneTimeCallRet GetSevCBitMaskAbove31\r
+\r
; Check if Secure Encrypted Virtualization (SEV) features are enabled.\r
;\r
; Register usage is tight in this routine, so multiple calls for the\r
\r
OneTimeCallRet CheckSevFeatures\r
\r
-; Check if Secure Encrypted Virtualization - Encrypted State (SEV-ES) feature\r
-; is enabled.\r
-;\r
-; Modified: EAX\r
-;\r
-; If SEV-ES is enabled then EAX will be non-zero.\r
-; If SEV-ES is disabled then EAX will be zero.\r
-;\r
-IsSevEsEnabled:\r
- xor eax, eax\r
-\r
- ; During CheckSevFeatures, the WORK_AREA_GUEST_TYPE is set\r
- ; to 1 if SEV is enabled.\r
- cmp byte[WORK_AREA_GUEST_TYPE], 1\r
- jne SevEsDisabled\r
-\r
- ; During CheckSevFeatures, the SEV_ES_WORK_AREA was set to 1 if\r
- ; SEV-ES is enabled.\r
- cmp byte[SEV_ES_WORK_AREA], 1\r
- jne SevEsDisabled\r
-\r
- mov eax, 1\r
-\r
-SevEsDisabled:\r
- OneTimeCallRet IsSevEsEnabled\r
-\r
; Start of #VC exception handling routines\r
;\r
\r
; work area when detected.\r
mov byte[WORK_AREA_GUEST_TYPE], 0\r
\r
+ ; Check whether the SEV is active and populate the SevEsWorkArea\r
OneTimeCall CheckSevFeatures\r
- xor edx, edx\r
- test eax, eax\r
- jz SevNotActive\r
\r
- ; If SEV is enabled, C-bit is always above 31\r
- sub eax, 32\r
- bts edx, eax\r
-\r
-SevNotActive:\r
+ ; If SEV is enabled, the C-bit position is always above 31.\r
+ ; The mask will be saved in the EDX and applied during the\r
+ ; the page table build below.\r
+ OneTimeCall GetSevCBitMaskAbove31\r
\r
;\r
; For OVMF, build some initial page tables at\r
mov [(ecx * 8 + PT_ADDR (0x2000 - 8)) + 4], edx\r
loop pageTableEntriesLoop\r
\r
- OneTimeCall IsSevEsEnabled\r
- test eax, eax\r
- jz SetCr3\r
-\r
- ;\r
- ; The initial GHCB will live at GHCB_BASE and needs to be un-encrypted.\r
- ; This requires the 2MB page for this range be broken down into 512 4KB\r
- ; pages. All will be marked encrypted, except for the GHCB.\r
- ;\r
- mov ecx, (GHCB_BASE >> 21)\r
- mov eax, GHCB_PT_ADDR + PAGE_PDP_ATTR\r
- mov [ecx * 8 + PT_ADDR (0x2000)], eax\r
-\r
- ;\r
- ; Page Table Entries (512 * 4KB entries => 2MB)\r
- ;\r
- mov ecx, 512\r
-pageTableEntries4kLoop:\r
- mov eax, ecx\r
- dec eax\r
- shl eax, 12\r
- add eax, GHCB_BASE & 0xFFE0_0000\r
- add eax, PAGE_4K_PDE_ATTR\r
- mov [ecx * 8 + GHCB_PT_ADDR - 8], eax\r
- mov [(ecx * 8 + GHCB_PT_ADDR - 8) + 4], edx\r
- loop pageTableEntries4kLoop\r
-\r
- ;\r
- ; Clear the encryption bit from the GHCB entry\r
- ;\r
- mov ecx, (GHCB_BASE & 0x1F_FFFF) >> 12\r
- mov [ecx * 8 + GHCB_PT_ADDR + 4], strict dword 0\r
-\r
- mov ecx, GHCB_SIZE / 4\r
- xor eax, eax\r
-clearGhcbMemoryLoop:\r
- mov dword[ecx * 4 + GHCB_BASE - 4], eax\r
- loop clearGhcbMemoryLoop\r
+ ; Clear the C-bit from the GHCB page if the SEV-ES is enabled.\r
+ OneTimeCall SevClearPageEncMaskForGhcbPage\r
\r
SetCr3:\r
;\r