]> git.proxmox.com Git - mirror_edk2.git/commitdiff
OvmfPkg: Create a GHCB page for use during Sec phase
authorTom Lendacky <thomas.lendacky@amd.com>
Wed, 12 Aug 2020 20:21:40 +0000 (15:21 -0500)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Mon, 17 Aug 2020 02:46:39 +0000 (02:46 +0000)
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2198

A GHCB page is needed during the Sec phase, so this new page must be
created. Since the #VC exception handler routines assume that a per-CPU
variable area is immediately after the GHCB, this per-CPU variable area
must also be created. Since the GHCB must be marked as an un-encrypted,
or shared, page, an additional pagetable page is required to break down
the 2MB region where the GHCB page lives into 4K pagetable entries.

Create a new entry in the OVMF memory layout for the new page table
page and for the SEC GHCB and per-CPU variable pages. After breaking down
the 2MB page, update the GHCB page table entry to remove the encryption
mask.

The GHCB page will be used by the SEC #VC exception handler. The #VC
exception handler will fill in the necessary fields of the GHCB and exit
to the hypervisor using the VMGEXIT instruction. The hypervisor then
accesses the GHCB in order to perform the requested function.

Four new fixed PCDs are needed to support the SEC GHCB page:
  - PcdOvmfSecGhcbBase  UINT32 value that is the base address of the
                        GHCB used during the SEC phase.
  - PcdOvmfSecGhcbSize  UINT32 value that is the size, in bytes, of the
                        GHCB area used during the SEC phase.

  - PcdOvmfSecGhcbPageTableBase  UINT32 value that is address of a page
                        table page used to break down the 2MB page into
                        512 4K pages.
  - PcdOvmfSecGhcbPageTableSize  UINT32 value that is the size, in bytes,
                        of the page table page.

Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@arm.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Regression-tested-by: Laszlo Ersek <lersek@redhat.com>
OvmfPkg/OvmfPkg.dec
OvmfPkg/OvmfPkgX64.fdf
OvmfPkg/ResetVector/Ia32/PageTables64.asm
OvmfPkg/ResetVector/ResetVector.inf
OvmfPkg/ResetVector/ResetVector.nasmb

index 55bb8ea91a00aec90dee45496bb2b8c75bc055c4..6abde4fd9351d3de7ee7afbd176daa07d72f3227 100644 (file)
   ## Number of page frames to use for storing grant table entries.\r
   gUefiOvmfPkgTokenSpaceGuid.PcdXenGrantFrames|4|UINT32|0x33\r
 \r
+  ## Specify the extra page table needed to mark the GHCB as unencrypted.\r
+  #  The value should be a multiple of 4KB for each.\r
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase|0x0|UINT32|0x3e\r
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize|0x0|UINT32|0x3f\r
+\r
+  ## The base address of the SEC GHCB page used by SEV-ES.\r
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|0|UINT32|0x40\r
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize|0|UINT32|0x41\r
+\r
 [PcdsDynamic, PcdsDynamicEx]\r
   gUefiOvmfPkgTokenSpaceGuid.PcdEmuVariableEvent|0|UINT64|2\r
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashVariablesEnable|FALSE|BOOLEAN|0x10\r
index 83ff6aef2e8c8a5bd1bf28fd9b3575e896dd7783..edb03b5464d40dfb99c66c4772a72d294346f2c6 100644 (file)
@@ -76,6 +76,12 @@ gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase|gUefiOvmfPkgTokenSpaceGuid.
 0x007000|0x001000\r
 gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress|gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize\r
 \r
+0x008000|0x001000\r
+gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize\r
+\r
+0x009000|0x002000\r
+gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize\r
+\r
 0x010000|0x010000\r
 gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize\r
 \r
index abad009f20f59a56caec34085f28a15c10fc3e17..9f86ddf6f08fed955b3f0ab84049dac9c9867b05 100644 (file)
@@ -21,6 +21,11 @@ BITS    32
 %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_2M_PDE_ATTR (PAGE_2M_MBO + \\r
                           PAGE_ACCESSED + \\r
                           PAGE_DIRTY + \\r
@@ -75,6 +80,37 @@ NoSev:
 SevExit:\r
     OneTimeCallRet CheckSevFeature\r
 \r
+; Check if Secure Encrypted Virtualization - Encrypted State (SEV-ES) feature\r
+; is enabled.\r
+;\r
+; Modified:  EAX, EBX, ECX\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
+CheckSevEsFeature:\r
+    xor       eax, eax\r
+\r
+    ; SEV-ES can't be enabled if SEV isn't, so first check the encryption\r
+    ; mask.\r
+    test      edx, edx\r
+    jz        NoSevEs\r
+\r
+    ; Save current value of encryption mask\r
+    mov       ebx, edx\r
+\r
+    ; Check if SEV-ES is enabled\r
+    ;  MSR_0xC0010131 - Bit 1 (SEV-ES enabled)\r
+    mov       ecx, 0xc0010131\r
+    rdmsr\r
+    and       eax, 2\r
+\r
+    ; Restore encryption mask\r
+    mov       edx, ebx\r
+\r
+NoSevEs:\r
+    OneTimeCallRet CheckSevEsFeature\r
+\r
 ;\r
 ; Modified:  EAX, EBX, ECX, EDX\r
 ;\r
@@ -139,6 +175,46 @@ pageTableEntriesLoop:
     mov     [(ecx * 8 + PT_ADDR (0x2000 - 8)) + 4], edx\r
     loop    pageTableEntriesLoop\r
 \r
+    OneTimeCall   CheckSevEsFeature\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
+\r
+SetCr3:\r
     ;\r
     ; Set CR3 now that the paging structures are available\r
     ;\r
index b0ddfa5832a21f6bb863fbfc3638e938c3820fa3..483fd90fe78595bc34a86b0fc060584877fc054d 100644 (file)
@@ -26,6 +26,7 @@
 [Packages]\r
   OvmfPkg/OvmfPkg.dec\r
   MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
   UefiCpuPkg/UefiCpuPkg.dec\r
 \r
 [BuildOptions]\r
@@ -33,5 +34,9 @@
    *_*_X64_NASMB_FLAGS = -I$(WORKSPACE)/UefiCpuPkg/ResetVector/Vtf0/\r
 \r
 [Pcd]\r
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase\r
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbSize\r
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableBase\r
+  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbPageTableSize\r
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase\r
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize\r
index 75cfe16654b13a28189d4ae765edd6d90b98d889..bfb77e43910512364ef1f4cd6bca4c78d965ac26 100644 (file)
     %error "This implementation inherently depends on PcdOvmfSecPageTablesSize"\r
   %endif\r
 \r
+  %if (FixedPcdGet32 (PcdOvmfSecGhcbPageTableSize) != 0x1000)\r
+    %error "This implementation inherently depends on PcdOvmfSecGhcbPageTableSize"\r
+  %endif\r
+\r
+  %if (FixedPcdGet32 (PcdOvmfSecGhcbSize) != 0x2000)\r
+    %error "This implementation inherently depends on PcdOvmfSecGhcbSize"\r
+  %endif\r
+\r
+  %if ((FixedPcdGet32 (PcdOvmfSecGhcbBase) >> 21) != \\r
+       ((FixedPcdGet32 (PcdOvmfSecGhcbBase) + FixedPcdGet32 (PcdOvmfSecGhcbSize) - 1) >> 21))\r
+    %error "This implementation inherently depends on PcdOvmfSecGhcbBase not straddling a 2MB boundary"\r
+  %endif\r
+\r
   %define PT_ADDR(Offset) (FixedPcdGet32 (PcdOvmfSecPageTablesBase) + (Offset))\r
 %include "Ia32/Flat32ToFlat64.asm"\r
+\r
+  %define GHCB_PT_ADDR (FixedPcdGet32 (PcdOvmfSecGhcbPageTableBase))\r
+  %define GHCB_BASE (FixedPcdGet32 (PcdOvmfSecGhcbBase))\r
+  %define GHCB_SIZE (FixedPcdGet32 (PcdOvmfSecGhcbSize))\r
 %include "Ia32/PageTables64.asm"\r
 %endif\r
 \r