]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/AmdSevDxe/AmdSevDxe.c
OvmfPkg/AmdSev: expose the SNP reserved pages through configuration table
[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
24 STATIC CONFIDENTIAL_COMPUTING_SNP_BLOB_LOCATION mSnpBootDxeTable = {
25 SIGNATURE_32 ('A', 'M', 'D', 'E'),
26 1,
27 0,
28 (UINT64)(UINTN)FixedPcdGet32 (PcdOvmfSnpSecretsBase),
29 FixedPcdGet32 (PcdOvmfSnpSecretsSize),
30 (UINT64)(UINTN)FixedPcdGet32 (PcdOvmfCpuidBase),
31 FixedPcdGet32 (PcdOvmfCpuidSize),
32 };
33
34 EFI_STATUS
35 EFIAPI
36 AmdSevDxeEntryPoint (
37 IN EFI_HANDLE ImageHandle,
38 IN EFI_SYSTEM_TABLE *SystemTable
39 )
40 {
41 EFI_STATUS Status;
42 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *AllDescMap;
43 UINTN NumEntries;
44 UINTN Index;
45
46 //
47 // Do nothing when SEV is not enabled
48 //
49 if (!MemEncryptSevIsEnabled ()) {
50 return EFI_UNSUPPORTED;
51 }
52
53 //
54 // Iterate through the GCD map and clear the C-bit from MMIO and NonExistent
55 // memory space. The NonExistent memory space will be used for mapping the
56 // MMIO space added later (eg PciRootBridge). By clearing both known MMIO and
57 // NonExistent memory space can gurantee that current and furture MMIO adds
58 // will have C-bit cleared.
59 //
60 Status = gDS->GetMemorySpaceMap (&NumEntries, &AllDescMap);
61 if (!EFI_ERROR (Status)) {
62 for (Index = 0; Index < NumEntries; Index++) {
63 CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Desc;
64
65 Desc = &AllDescMap[Index];
66 if ((Desc->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) ||
67 (Desc->GcdMemoryType == EfiGcdMemoryTypeNonExistent))
68 {
69 Status = MemEncryptSevClearMmioPageEncMask (
70 0,
71 Desc->BaseAddress,
72 EFI_SIZE_TO_PAGES (Desc->Length)
73 );
74 ASSERT_EFI_ERROR (Status);
75 }
76 }
77
78 FreePool (AllDescMap);
79 }
80
81 //
82 // If PCI Express is enabled, the MMCONFIG area has been reserved, rather
83 // than marked as MMIO, and so the C-bit won't be cleared by the above walk
84 // through the GCD map. Check for the MMCONFIG area and clear the C-bit for
85 // the range.
86 //
87 if (PcdGet16 (PcdOvmfHostBridgePciDevId) == INTEL_Q35_MCH_DEVICE_ID) {
88 Status = MemEncryptSevClearMmioPageEncMask (
89 0,
90 FixedPcdGet64 (PcdPciExpressBaseAddress),
91 EFI_SIZE_TO_PAGES (SIZE_256MB)
92 );
93
94 ASSERT_EFI_ERROR (Status);
95 }
96
97 //
98 // When SMM is enabled, clear the C-bit from SMM Saved State Area
99 //
100 // NOTES: The SavedStateArea address cleared here is before SMBASE
101 // relocation. Currently, we do not clear the SavedStateArea address after
102 // SMBASE is relocated due to the following reasons:
103 //
104 // 1) Guest BIOS never access the relocated SavedStateArea.
105 //
106 // 2) The C-bit works on page-aligned address, but the SavedStateArea
107 // address is not a page-aligned. Theoretically, we could roundup the address
108 // and clear the C-bit of aligned address but looking carefully we found
109 // that some portion of the page contains code -- which will causes a bigger
110 // issues for SEV guest. When SEV is enabled, all the code must be encrypted
111 // otherwise hardware will cause trap.
112 //
113 // We restore the C-bit for this SMM Saved State Area after SMBASE relocation
114 // is completed (See OvmfPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c).
115 //
116 if (FeaturePcdGet (PcdSmmSmramRequire)) {
117 UINTN MapPagesBase;
118 UINTN MapPagesCount;
119
120 Status = MemEncryptSevLocateInitialSmramSaveStateMapPages (
121 &MapPagesBase,
122 &MapPagesCount
123 );
124 ASSERT_EFI_ERROR (Status);
125
126 //
127 // Although these pages were set aside (i.e., allocated) by PlatformPei, we
128 // could be after a warm reboot from the OS. Don't leak any stale OS data
129 // to the hypervisor.
130 //
131 ZeroMem ((VOID *)MapPagesBase, EFI_PAGES_TO_SIZE (MapPagesCount));
132
133 Status = MemEncryptSevClearPageEncMask (
134 0, // Cr3BaseAddress -- use current CR3
135 MapPagesBase, // BaseAddress
136 MapPagesCount // NumPages
137 );
138 if (EFI_ERROR (Status)) {
139 DEBUG ((
140 DEBUG_ERROR,
141 "%a: MemEncryptSevClearPageEncMask(): %r\n",
142 __FUNCTION__,
143 Status
144 ));
145 ASSERT (FALSE);
146 CpuDeadLoop ();
147 }
148 }
149
150 //
151 // If its SEV-SNP active guest then install the CONFIDENTIAL_COMPUTING_SEV_SNP_BLOB.
152 // It contains the location for both the Secrets and CPUID page.
153 //
154 if (MemEncryptSevSnpIsEnabled ()) {
155 return gBS->InstallConfigurationTable (
156 &gConfidentialComputingSevSnpBlobGuid,
157 &mSnpBootDxeTable
158 );
159 }
160
161 return EFI_SUCCESS;
162 }