]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - OvmfPkg/SmmAccess/SmramInternal.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / OvmfPkg / SmmAccess / SmramInternal.c
... / ...
CommitLineData
1/** @file\r
2\r
3 Functions and types shared by the SMM accessor PEI and DXE modules.\r
4\r
5 Copyright (C) 2015, Red Hat, Inc.\r
6\r
7 SPDX-License-Identifier: BSD-2-Clause-Patent\r
8\r
9**/\r
10\r
11#include <Guid/AcpiS3Context.h>\r
12#include <IndustryStandard/Q35MchIch9.h>\r
13#include <Library/DebugLib.h>\r
14#include <Library/PcdLib.h>\r
15#include <Library/PciLib.h>\r
16\r
17#include "SmramInternal.h"\r
18\r
19//\r
20// The value of PcdQ35TsegMbytes is saved into this variable at module startup.\r
21//\r
22UINT16 mQ35TsegMbytes;\r
23\r
24//\r
25// The value of PcdQ35SmramAtDefaultSmbase is saved into this variable at\r
26// module startup.\r
27//\r
28STATIC BOOLEAN mQ35SmramAtDefaultSmbase;\r
29\r
30/**\r
31 Save PcdQ35TsegMbytes into mQ35TsegMbytes.\r
32**/\r
33VOID\r
34InitQ35TsegMbytes (\r
35 VOID\r
36 )\r
37{\r
38 mQ35TsegMbytes = PcdGet16 (PcdQ35TsegMbytes);\r
39}\r
40\r
41/**\r
42 Save PcdQ35SmramAtDefaultSmbase into mQ35SmramAtDefaultSmbase.\r
43**/\r
44VOID\r
45InitQ35SmramAtDefaultSmbase (\r
46 VOID\r
47 )\r
48{\r
49 mQ35SmramAtDefaultSmbase = PcdGetBool (PcdQ35SmramAtDefaultSmbase);\r
50}\r
51\r
52/**\r
53 Read the MCH_SMRAM and ESMRAMC registers, and update the LockState and\r
54 OpenState fields in the PEI_SMM_ACCESS_PPI / EFI_SMM_ACCESS2_PROTOCOL object,\r
55 from the D_LCK and T_EN bits.\r
56\r
57 PEI_SMM_ACCESS_PPI and EFI_SMM_ACCESS2_PROTOCOL member functions can rely on\r
58 the LockState and OpenState fields being up-to-date on entry, and they need\r
59 to restore the same invariant on exit, if they touch the bits in question.\r
60\r
61 @param[out] LockState Reflects the D_LCK bit on output; TRUE iff SMRAM is\r
62 locked.\r
63 @param[out] OpenState Reflects the inverse of the T_EN bit on output; TRUE\r
64 iff SMRAM is open.\r
65**/\r
66VOID\r
67GetStates (\r
68 OUT BOOLEAN *LockState,\r
69 OUT BOOLEAN *OpenState\r
70 )\r
71{\r
72 UINT8 SmramVal, EsmramcVal;\r
73\r
74 SmramVal = PciRead8 (DRAMC_REGISTER_Q35 (MCH_SMRAM));\r
75 EsmramcVal = PciRead8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC));\r
76\r
77 *LockState = !!(SmramVal & MCH_SMRAM_D_LCK);\r
78 *OpenState = !(EsmramcVal & MCH_ESMRAMC_T_EN);\r
79}\r
80\r
81//\r
82// The functions below follow the PEI_SMM_ACCESS_PPI and\r
83// EFI_SMM_ACCESS2_PROTOCOL member declarations. The PeiServices and This\r
84// pointers are removed (TSEG doesn't depend on them), and so is the\r
85// DescriptorIndex parameter (TSEG doesn't support range-wise locking).\r
86//\r
87// The LockState and OpenState members that are common to both\r
88// PEI_SMM_ACCESS_PPI and EFI_SMM_ACCESS2_PROTOCOL are taken and updated in\r
89// isolation from the rest of the (non-shared) members.\r
90//\r
91\r
92EFI_STATUS\r
93SmramAccessOpen (\r
94 OUT BOOLEAN *LockState,\r
95 OUT BOOLEAN *OpenState\r
96 )\r
97{\r
98 //\r
99 // Open TSEG by clearing T_EN.\r
100 //\r
101 PciAnd8 (\r
102 DRAMC_REGISTER_Q35 (MCH_ESMRAMC),\r
103 (UINT8)((~(UINT32)MCH_ESMRAMC_T_EN) & 0xff)\r
104 );\r
105\r
106 GetStates (LockState, OpenState);\r
107 if (!*OpenState) {\r
108 return EFI_DEVICE_ERROR;\r
109 }\r
110\r
111 return EFI_SUCCESS;\r
112}\r
113\r
114EFI_STATUS\r
115SmramAccessClose (\r
116 OUT BOOLEAN *LockState,\r
117 OUT BOOLEAN *OpenState\r
118 )\r
119{\r
120 //\r
121 // Close TSEG by setting T_EN.\r
122 //\r
123 PciOr8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC), MCH_ESMRAMC_T_EN);\r
124\r
125 GetStates (LockState, OpenState);\r
126 if (*OpenState) {\r
127 return EFI_DEVICE_ERROR;\r
128 }\r
129\r
130 return EFI_SUCCESS;\r
131}\r
132\r
133EFI_STATUS\r
134SmramAccessLock (\r
135 OUT BOOLEAN *LockState,\r
136 IN OUT BOOLEAN *OpenState\r
137 )\r
138{\r
139 if (*OpenState) {\r
140 return EFI_DEVICE_ERROR;\r
141 }\r
142\r
143 //\r
144 // Close & lock TSEG by setting T_EN and D_LCK.\r
145 //\r
146 PciOr8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC), MCH_ESMRAMC_T_EN);\r
147 PciOr8 (DRAMC_REGISTER_Q35 (MCH_SMRAM), MCH_SMRAM_D_LCK);\r
148\r
149 //\r
150 // Close & lock the SMRAM at the default SMBASE, if it exists.\r
151 //\r
152 if (mQ35SmramAtDefaultSmbase) {\r
153 PciWrite8 (\r
154 DRAMC_REGISTER_Q35 (MCH_DEFAULT_SMBASE_CTL),\r
155 MCH_DEFAULT_SMBASE_LCK\r
156 );\r
157 }\r
158\r
159 GetStates (LockState, OpenState);\r
160 if (*OpenState || !*LockState) {\r
161 return EFI_DEVICE_ERROR;\r
162 }\r
163\r
164 return EFI_SUCCESS;\r
165}\r
166\r
167EFI_STATUS\r
168SmramAccessGetCapabilities (\r
169 IN BOOLEAN LockState,\r
170 IN BOOLEAN OpenState,\r
171 IN OUT UINTN *SmramMapSize,\r
172 IN OUT EFI_SMRAM_DESCRIPTOR *SmramMap\r
173 )\r
174{\r
175 UINTN OriginalSize;\r
176 UINT32 TsegMemoryBaseMb, TsegMemoryBase;\r
177 UINT64 CommonRegionState;\r
178 UINT8 TsegSizeBits;\r
179\r
180 OriginalSize = *SmramMapSize;\r
181 *SmramMapSize = DescIdxCount * sizeof *SmramMap;\r
182 if (OriginalSize < *SmramMapSize) {\r
183 return EFI_BUFFER_TOO_SMALL;\r
184 }\r
185\r
186 //\r
187 // Read the TSEG Memory Base register.\r
188 //\r
189 TsegMemoryBaseMb = PciRead32 (DRAMC_REGISTER_Q35 (MCH_TSEGMB));\r
190 TsegMemoryBase = (TsegMemoryBaseMb >> MCH_TSEGMB_MB_SHIFT) << 20;\r
191\r
192 //\r
193 // Precompute the region state bits that will be set for all regions.\r
194 //\r
195 CommonRegionState = (OpenState ? EFI_SMRAM_OPEN : EFI_SMRAM_CLOSED) |\r
196 (LockState ? EFI_SMRAM_LOCKED : 0) |\r
197 EFI_CACHEABLE;\r
198\r
199 //\r
200 // The first region hosts an SMM_S3_RESUME_STATE object. It is located at the\r
201 // start of TSEG. We round up the size to whole pages, and we report it as\r
202 // EFI_ALLOCATED, so that the SMM_CORE stays away from it.\r
203 //\r
204 SmramMap[DescIdxSmmS3ResumeState].PhysicalStart = TsegMemoryBase;\r
205 SmramMap[DescIdxSmmS3ResumeState].CpuStart = TsegMemoryBase;\r
206 SmramMap[DescIdxSmmS3ResumeState].PhysicalSize =\r
207 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (sizeof (SMM_S3_RESUME_STATE)));\r
208 SmramMap[DescIdxSmmS3ResumeState].RegionState =\r
209 CommonRegionState | EFI_ALLOCATED;\r
210\r
211 //\r
212 // Get the TSEG size bits from the ESMRAMC register.\r
213 //\r
214 TsegSizeBits = PciRead8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC)) &\r
215 MCH_ESMRAMC_TSEG_MASK;\r
216\r
217 //\r
218 // The second region is the main one, following the first.\r
219 //\r
220 SmramMap[DescIdxMain].PhysicalStart =\r
221 SmramMap[DescIdxSmmS3ResumeState].PhysicalStart +\r
222 SmramMap[DescIdxSmmS3ResumeState].PhysicalSize;\r
223 SmramMap[DescIdxMain].CpuStart = SmramMap[DescIdxMain].PhysicalStart;\r
224 SmramMap[DescIdxMain].PhysicalSize =\r
225 (TsegSizeBits == MCH_ESMRAMC_TSEG_8MB ? SIZE_8MB :\r
226 TsegSizeBits == MCH_ESMRAMC_TSEG_2MB ? SIZE_2MB :\r
227 TsegSizeBits == MCH_ESMRAMC_TSEG_1MB ? SIZE_1MB :\r
228 mQ35TsegMbytes * SIZE_1MB) -\r
229 SmramMap[DescIdxSmmS3ResumeState].PhysicalSize;\r
230 SmramMap[DescIdxMain].RegionState = CommonRegionState;\r
231\r
232 return EFI_SUCCESS;\r
233}\r