1 /**@file
2   Initialize Secure Encrypted Virtualization (SEV) support
3 
4   Copyright (c) 2017, Advanced Micro Devices. All rights reserved.<BR>
5 
6   SPDX-License-Identifier: BSD-2-Clause-Patent
7 
8 **/
9 //
10 // The package level header files this module uses
11 //
12 #include <IndustryStandard/Q35MchIch9.h>
13 #include <Library/BaseMemoryLib.h>
14 #include <Library/DebugLib.h>
15 #include <Library/HobLib.h>
16 #include <Library/MemEncryptSevLib.h>
17 #include <Library/MemoryAllocationLib.h>
18 #include <Library/PcdLib.h>
19 #include <PiPei.h>
20 #include <Register/Amd/Cpuid.h>
21 #include <Register/Amd/Msr.h>
22 #include <Register/Cpuid.h>
23 #include <Register/Intel/SmramSaveStateMap.h>
24 
25 #include "Platform.h"
26 
27 /**
28 
29   Initialize SEV-ES support if running as an SEV-ES guest.
30 
31   **/
32 STATIC
33 VOID
AmdSevEsInitialize(VOID)34 AmdSevEsInitialize (
35   VOID
36   )
37 {
38   VOID              *GhcbBase;
39   PHYSICAL_ADDRESS  GhcbBasePa;
40   UINTN             GhcbPageCount, PageCount;
41   RETURN_STATUS     PcdStatus, DecryptStatus;
42   IA32_DESCRIPTOR   Gdtr;
43   VOID              *Gdt;
44 
45   if (!MemEncryptSevEsIsEnabled ()) {
46     return;
47   }
48 
49   PcdStatus = PcdSetBoolS (PcdSevEsIsEnabled, TRUE);
50   ASSERT_RETURN_ERROR (PcdStatus);
51 
52   //
53   // Allocate GHCB and per-CPU variable pages.
54   //   Since the pages must survive across the UEFI to OS transition
55   //   make them reserved.
56   //
57   GhcbPageCount = mMaxCpuCount * 2;
58   GhcbBase = AllocateReservedPages (GhcbPageCount);
59   ASSERT (GhcbBase != NULL);
60 
61   GhcbBasePa = (PHYSICAL_ADDRESS)(UINTN) GhcbBase;
62 
63   //
64   // Each vCPU gets two consecutive pages, the first is the GHCB and the
65   // second is the per-CPU variable page. Loop through the allocation and
66   // only clear the encryption mask for the GHCB pages.
67   //
68   for (PageCount = 0; PageCount < GhcbPageCount; PageCount += 2) {
69     DecryptStatus = MemEncryptSevClearPageEncMask (
70       0,
71       GhcbBasePa + EFI_PAGES_TO_SIZE (PageCount),
72       1,
73       TRUE
74       );
75     ASSERT_RETURN_ERROR (DecryptStatus);
76   }
77 
78   ZeroMem (GhcbBase, EFI_PAGES_TO_SIZE (GhcbPageCount));
79 
80   PcdStatus = PcdSet64S (PcdGhcbBase, GhcbBasePa);
81   ASSERT_RETURN_ERROR (PcdStatus);
82   PcdStatus = PcdSet64S (PcdGhcbSize, EFI_PAGES_TO_SIZE (GhcbPageCount));
83   ASSERT_RETURN_ERROR (PcdStatus);
84 
85   DEBUG ((DEBUG_INFO,
86     "SEV-ES is enabled, %lu GHCB pages allocated starting at 0x%p\n",
87     (UINT64)GhcbPageCount, GhcbBase));
88 
89   AsmWriteMsr64 (MSR_SEV_ES_GHCB, GhcbBasePa);
90 
91   //
92   // The SEV support will clear the C-bit from non-RAM areas.  The early GDT
93   // lives in a non-RAM area, so when an exception occurs (like a #VC) the GDT
94   // will be read as un-encrypted even though it was created before the C-bit
95   // was cleared (encrypted). This will result in a failure to be able to
96   // handle the exception.
97   //
98   AsmReadGdtr (&Gdtr);
99 
100   Gdt = AllocatePages (EFI_SIZE_TO_PAGES ((UINTN) Gdtr.Limit + 1));
101   ASSERT (Gdt != NULL);
102 
103   CopyMem (Gdt, (VOID *) Gdtr.Base, Gdtr.Limit + 1);
104   Gdtr.Base = (UINTN) Gdt;
105   AsmWriteGdtr (&Gdtr);
106 }
107 
108 /**
109 
110   Function checks if SEV support is available, if present then it sets
111   the dynamic PcdPteMemoryEncryptionAddressOrMask with memory encryption mask.
112 
113   **/
114 VOID
AmdSevInitialize(VOID)115 AmdSevInitialize (
116   VOID
117   )
118 {
119   CPUID_MEMORY_ENCRYPTION_INFO_EBX  Ebx;
120   UINT64                            EncryptionMask;
121   RETURN_STATUS                     PcdStatus;
122 
123   //
124   // Check if SEV is enabled
125   //
126   if (!MemEncryptSevIsEnabled ()) {
127     return;
128   }
129 
130   //
131   // CPUID Fn8000_001F[EBX] Bit 0:5 (memory encryption bit position)
132   //
133   AsmCpuid (CPUID_MEMORY_ENCRYPTION_INFO, NULL, &Ebx.Uint32, NULL, NULL);
134   EncryptionMask = LShiftU64 (1, Ebx.Bits.PtePosBits);
135 
136   //
137   // Set Memory Encryption Mask PCD
138   //
139   PcdStatus = PcdSet64S (PcdPteMemoryEncryptionAddressOrMask, EncryptionMask);
140   ASSERT_RETURN_ERROR (PcdStatus);
141 
142   DEBUG ((DEBUG_INFO, "SEV is enabled (mask 0x%lx)\n", EncryptionMask));
143 
144   //
145   // Set Pcd to Deny the execution of option ROM when security
146   // violation.
147   //
148   PcdStatus = PcdSet32S (PcdOptionRomImageVerificationPolicy, 0x4);
149   ASSERT_RETURN_ERROR (PcdStatus);
150 
151   //
152   // When SMM is required, cover the pages containing the initial SMRAM Save
153   // State Map with a memory allocation HOB:
154   //
155   // There's going to be a time interval between our decrypting those pages for
156   // SMBASE relocation and re-encrypting the same pages after SMBASE
157   // relocation. We shall ensure that the DXE phase stay away from those pages
158   // until after re-encryption, in order to prevent an information leak to the
159   // hypervisor.
160   //
161   if (FeaturePcdGet (PcdSmmSmramRequire) && (mBootMode != BOOT_ON_S3_RESUME)) {
162     RETURN_STATUS LocateMapStatus;
163     UINTN         MapPagesBase;
164     UINTN         MapPagesCount;
165 
166     LocateMapStatus = MemEncryptSevLocateInitialSmramSaveStateMapPages (
167                         &MapPagesBase,
168                         &MapPagesCount
169                         );
170     ASSERT_RETURN_ERROR (LocateMapStatus);
171 
172     if (mQ35SmramAtDefaultSmbase) {
173       //
174       // The initial SMRAM Save State Map has been covered as part of a larger
175       // reserved memory allocation in InitializeRamRegions().
176       //
177       ASSERT (SMM_DEFAULT_SMBASE <= MapPagesBase);
178       ASSERT (
179         (MapPagesBase + EFI_PAGES_TO_SIZE (MapPagesCount) <=
180          SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE)
181         );
182     } else {
183       BuildMemoryAllocationHob (
184         MapPagesBase,                      // BaseAddress
185         EFI_PAGES_TO_SIZE (MapPagesCount), // Length
186         EfiBootServicesData                // MemoryType
187         );
188     }
189   }
190 
191   //
192   // Check and perform SEV-ES initialization if required.
193   //
194   AmdSevEsInitialize ();
195 }
196