]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/AmdSevDxe/AmdSevDxe.c
OvmfPkg: Realize EfiMemoryAcceptProtocol in AmdSevDxe
[mirror_edk2.git] / OvmfPkg / AmdSevDxe / AmdSevDxe.c
1 /** @file
2
3 AMD Sev Dxe driver. This driver is dispatched early in DXE, due to being list
4 in APRIORI. It clears C-bit from MMIO and NonExistent Memory space when SEV
5 is enabled.
6
7 Copyright (c) 2017 - 2020, AMD Inc. All rights reserved.<BR>
8
9 SPDX-License-Identifier: BSD-2-Clause-Patent
10
11 **/
12
13 #include <IndustryStandard/Q35MchIch9.h>
14 #include <Library/BaseLib.h>
15 #include <Library/BaseMemoryLib.h>
16 #include <Library/DebugLib.h>
17 #include <Library/DxeServicesTableLib.h>
18 #include <Library/MemEncryptSevLib.h>
19 #include <Library/MemoryAllocationLib.h>
20 #include <Library/UefiBootServicesTableLib.h>
21 #include <Guid/ConfidentialComputingSevSnpBlob.h>
22 #include <Library/PcdLib.h>
23 #include <Protocol/MemoryAccept.h>
24
25 STATIC CONFIDENTIAL_COMPUTING_SNP_BLOB_LOCATION mSnpBootDxeTable = {
26 SIGNATURE_32 ('A', 'M', 'D', 'E'),
27 1,
28 0,
29 (UINT64)(UINTN)FixedPcdGet32 (PcdOvmfSnpSecretsBase),
30 FixedPcdGet32 (PcdOvmfSnpSecretsSize),
31 (UINT64)(UINTN)FixedPcdGet32 (PcdOvmfCpuidBase),
32 FixedPcdGet32 (PcdOvmfCpuidSize),
33 };
34
35 STATIC EFI_HANDLE mAmdSevDxeHandle = NULL;
36
37 #define IS_ALIGNED(x, y) ((((x) & ((y) - 1)) == 0))
38
39 STATIC
40 EFI_STATUS
41 EFIAPI
42 AmdSevMemoryAccept (
43 IN EDKII_MEMORY_ACCEPT_PROTOCOL *This,
44 IN EFI_PHYSICAL_ADDRESS StartAddress,
45 IN UINTN Size
46 )
47 {
48 //
49 // The StartAddress must be page-aligned, and the Size must be a positive
50 // multiple of SIZE_4KB. Use an assert instead of returning an erros since
51 // this is an EDK2-internal protocol.
52 //
53 ASSERT (IS_ALIGNED (StartAddress, SIZE_4KB));
54 ASSERT (IS_ALIGNED (Size, SIZE_4KB));
55 ASSERT (Size != 0);
56
57 MemEncryptSevSnpPreValidateSystemRam (
58 StartAddress,
59 EFI_SIZE_TO_PAGES (Size)
60 );
61
62 return EFI_SUCCESS;
63 }
64
65 STATIC EDKII_MEMORY_ACCEPT_PROTOCOL mMemoryAcceptProtocol = {
66 AmdSevMemoryAccept
67 };
68
69 EFI_STATUS
70 EFIAPI
71 AmdSevDxeEntryPoint (
72 IN EFI_HANDLE ImageHandle,
73 IN EFI_SYSTEM_TABLE *SystemTable
74 )
75 {
76 EFI_STATUS Status;
77 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *AllDescMap;
78 UINTN NumEntries;
79 UINTN Index;
80
81 //
82 // Do nothing when SEV is not enabled
83 //
84 if (!MemEncryptSevIsEnabled ()) {
85 return EFI_UNSUPPORTED;
86 }
87
88 //
89 // Iterate through the GCD map and clear the C-bit from MMIO and NonExistent
90 // memory space. The NonExistent memory space will be used for mapping the
91 // MMIO space added later (eg PciRootBridge). By clearing both known MMIO and
92 // NonExistent memory space can gurantee that current and furture MMIO adds
93 // will have C-bit cleared.
94 //
95 Status = gDS->GetMemorySpaceMap (&NumEntries, &AllDescMap);
96 if (!EFI_ERROR (Status)) {
97 for (Index = 0; Index < NumEntries; Index++) {
98 CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Desc;
99
100 Desc = &AllDescMap[Index];
101 if ((Desc->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) ||
102 (Desc->GcdMemoryType == EfiGcdMemoryTypeNonExistent))
103 {
104 Status = MemEncryptSevClearMmioPageEncMask (
105 0,
106 Desc->BaseAddress,
107 EFI_SIZE_TO_PAGES (Desc->Length)
108 );
109 ASSERT_EFI_ERROR (Status);
110 }
111 }
112
113 FreePool (AllDescMap);
114 }
115
116 //
117 // If PCI Express is enabled, the MMCONFIG area has been reserved, rather
118 // than marked as MMIO, and so the C-bit won't be cleared by the above walk
119 // through the GCD map. Check for the MMCONFIG area and clear the C-bit for
120 // the range.
121 //
122 if (PcdGet16 (PcdOvmfHostBridgePciDevId) == INTEL_Q35_MCH_DEVICE_ID) {
123 Status = MemEncryptSevClearMmioPageEncMask (
124 0,
125 FixedPcdGet64 (PcdPciExpressBaseAddress),
126 EFI_SIZE_TO_PAGES (SIZE_256MB)
127 );
128
129 ASSERT_EFI_ERROR (Status);
130 }
131
132 //
133 // When SMM is enabled, clear the C-bit from SMM Saved State Area
134 //
135 // NOTES: The SavedStateArea address cleared here is before SMBASE
136 // relocation. Currently, we do not clear the SavedStateArea address after
137 // SMBASE is relocated due to the following reasons:
138 //
139 // 1) Guest BIOS never access the relocated SavedStateArea.
140 //
141 // 2) The C-bit works on page-aligned address, but the SavedStateArea
142 // address is not a page-aligned. Theoretically, we could roundup the address
143 // and clear the C-bit of aligned address but looking carefully we found
144 // that some portion of the page contains code -- which will causes a bigger
145 // issues for SEV guest. When SEV is enabled, all the code must be encrypted
146 // otherwise hardware will cause trap.
147 //
148 // We restore the C-bit for this SMM Saved State Area after SMBASE relocation
149 // is completed (See OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c).
150 //
151 if (FeaturePcdGet (PcdSmmSmramRequire)) {
152 UINTN MapPagesBase;
153 UINTN MapPagesCount;
154
155 Status = MemEncryptSevLocateInitialSmramSaveStateMapPages (
156 &MapPagesBase,
157 &MapPagesCount
158 );
159 ASSERT_EFI_ERROR (Status);
160
161 //
162 // Although these pages were set aside (i.e., allocated) by PlatformPei, we
163 // could be after a warm reboot from the OS. Don't leak any stale OS data
164 // to the hypervisor.
165 //
166 ZeroMem ((VOID *)MapPagesBase, EFI_PAGES_TO_SIZE (MapPagesCount));
167
168 Status = MemEncryptSevClearPageEncMask (
169 0, // Cr3BaseAddress -- use current CR3
170 MapPagesBase, // BaseAddress
171 MapPagesCount // NumPages
172 );
173 if (EFI_ERROR (Status)) {
174 DEBUG ((
175 DEBUG_ERROR,
176 "%a: MemEncryptSevClearPageEncMask(): %r\n",
177 __FUNCTION__,
178 Status
179 ));
180 ASSERT (FALSE);
181 CpuDeadLoop ();
182 }
183 }
184
185 if (MemEncryptSevSnpIsEnabled ()) {
186 //
187 // Memory acceptance began being required in SEV-SNP, so install the
188 // memory accept protocol implementation for a SEV-SNP active guest.
189 //
190 Status = gBS->InstallProtocolInterface (
191 &mAmdSevDxeHandle,
192 &gEdkiiMemoryAcceptProtocolGuid,
193 EFI_NATIVE_INTERFACE,
194 &mMemoryAcceptProtocol
195 );
196 ASSERT_EFI_ERROR (Status);
197
198 //
199 // If its SEV-SNP active guest then install the CONFIDENTIAL_COMPUTING_SEV_SNP_BLOB.
200 // It contains the location for both the Secrets and CPUID page.
201 //
202 return gBS->InstallConfigurationTable (
203 &gConfidentialComputingSevSnpBlobGuid,
204 &mSnpBootDxeTable
205 );
206 }
207
208 return EFI_SUCCESS;
209 }