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