]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/PlatformPei/AmdSev.c
a2b38c5912363bff6eb6fc05023b7045fd9bb929
[mirror_edk2.git] / OvmfPkg / PlatformPei / AmdSev.c
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
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 //
55 GhcbPageCount = mMaxCpuCount * 2;
56 GhcbBase = AllocatePages (GhcbPageCount);
57 ASSERT (GhcbBase != NULL);
58
59 GhcbBasePa = (PHYSICAL_ADDRESS)(UINTN) GhcbBase;
60
61 //
62 // Each vCPU gets two consecutive pages, the first is the GHCB and the
63 // second is the per-CPU variable page. Loop through the allocation and
64 // only clear the encryption mask for the GHCB pages.
65 //
66 for (PageCount = 0; PageCount < GhcbPageCount; PageCount += 2) {
67 DecryptStatus = MemEncryptSevClearPageEncMask (
68 0,
69 GhcbBasePa + EFI_PAGES_TO_SIZE (PageCount),
70 1,
71 TRUE
72 );
73 ASSERT_RETURN_ERROR (DecryptStatus);
74 }
75
76 ZeroMem (GhcbBase, EFI_PAGES_TO_SIZE (GhcbPageCount));
77
78 PcdStatus = PcdSet64S (PcdGhcbBase, GhcbBasePa);
79 ASSERT_RETURN_ERROR (PcdStatus);
80 PcdStatus = PcdSet64S (PcdGhcbSize, EFI_PAGES_TO_SIZE (GhcbPageCount));
81 ASSERT_RETURN_ERROR (PcdStatus);
82
83 DEBUG ((DEBUG_INFO,
84 "SEV-ES is enabled, %lu GHCB pages allocated starting at 0x%p\n",
85 (UINT64)GhcbPageCount, GhcbBase));
86
87 AsmWriteMsr64 (MSR_SEV_ES_GHCB, GhcbBasePa);
88
89 //
90 // The SEV support will clear the C-bit from non-RAM areas. The early GDT
91 // lives in a non-RAM area, so when an exception occurs (like a #VC) the GDT
92 // will be read as un-encrypted even though it was created before the C-bit
93 // was cleared (encrypted). This will result in a failure to be able to
94 // handle the exception.
95 //
96 AsmReadGdtr (&Gdtr);
97
98 Gdt = AllocatePages (EFI_SIZE_TO_PAGES ((UINTN) Gdtr.Limit + 1));
99 ASSERT (Gdt != NULL);
100
101 CopyMem (Gdt, (VOID *) Gdtr.Base, Gdtr.Limit + 1);
102 Gdtr.Base = (UINTN) Gdt;
103 AsmWriteGdtr (&Gdtr);
104 }
105
106 /**
107
108 Function checks if SEV support is available, if present then it sets
109 the dynamic PcdPteMemoryEncryptionAddressOrMask with memory encryption mask.
110
111 **/
112 VOID
113 AmdSevInitialize (
114 VOID
115 )
116 {
117 CPUID_MEMORY_ENCRYPTION_INFO_EBX Ebx;
118 UINT64 EncryptionMask;
119 RETURN_STATUS PcdStatus;
120
121 //
122 // Check if SEV is enabled
123 //
124 if (!MemEncryptSevIsEnabled ()) {
125 return;
126 }
127
128 //
129 // CPUID Fn8000_001F[EBX] Bit 0:5 (memory encryption bit position)
130 //
131 AsmCpuid (CPUID_MEMORY_ENCRYPTION_INFO, NULL, &Ebx.Uint32, NULL, NULL);
132 EncryptionMask = LShiftU64 (1, Ebx.Bits.PtePosBits);
133
134 //
135 // Set Memory Encryption Mask PCD
136 //
137 PcdStatus = PcdSet64S (PcdPteMemoryEncryptionAddressOrMask, EncryptionMask);
138 ASSERT_RETURN_ERROR (PcdStatus);
139
140 DEBUG ((DEBUG_INFO, "SEV is enabled (mask 0x%lx)\n", EncryptionMask));
141
142 //
143 // Set Pcd to Deny the execution of option ROM when security
144 // violation.
145 //
146 PcdStatus = PcdSet32S (PcdOptionRomImageVerificationPolicy, 0x4);
147 ASSERT_RETURN_ERROR (PcdStatus);
148
149 //
150 // When SMM is required, cover the pages containing the initial SMRAM Save
151 // State Map with a memory allocation HOB:
152 //
153 // There's going to be a time interval between our decrypting those pages for
154 // SMBASE relocation and re-encrypting the same pages after SMBASE
155 // relocation. We shall ensure that the DXE phase stay away from those pages
156 // until after re-encryption, in order to prevent an information leak to the
157 // hypervisor.
158 //
159 if (FeaturePcdGet (PcdSmmSmramRequire) && (mBootMode != BOOT_ON_S3_RESUME)) {
160 RETURN_STATUS LocateMapStatus;
161 UINTN MapPagesBase;
162 UINTN MapPagesCount;
163
164 LocateMapStatus = MemEncryptSevLocateInitialSmramSaveStateMapPages (
165 &MapPagesBase,
166 &MapPagesCount
167 );
168 ASSERT_RETURN_ERROR (LocateMapStatus);
169
170 if (mQ35SmramAtDefaultSmbase) {
171 //
172 // The initial SMRAM Save State Map has been covered as part of a larger
173 // reserved memory allocation in InitializeRamRegions().
174 //
175 ASSERT (SMM_DEFAULT_SMBASE <= MapPagesBase);
176 ASSERT (
177 (MapPagesBase + EFI_PAGES_TO_SIZE (MapPagesCount) <=
178 SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE)
179 );
180 } else {
181 BuildMemoryAllocationHob (
182 MapPagesBase, // BaseAddress
183 EFI_PAGES_TO_SIZE (MapPagesCount), // Length
184 EfiBootServicesData // MemoryType
185 );
186 }
187 }
188
189 //
190 // Check and perform SEV-ES initialization if required.
191 //
192 AmdSevEsInitialize ();
193 }