]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/SmmAccess/SmramInternal.c
OvmfPkg/PvScsiDxe: Enable device 64-bit DMA addresses
[mirror_edk2.git] / OvmfPkg / SmmAccess / SmramInternal.c
CommitLineData
9d560947
LE
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
b26f0cf9 7 SPDX-License-Identifier: BSD-2-Clause-Patent\r
9d560947
LE
8\r
9**/\r
10\r
11#include <Guid/AcpiS3Context.h>\r
12#include <IndustryStandard/Q35MchIch9.h>\r
13#include <Library/DebugLib.h>\r
1372f8d3 14#include <Library/PcdLib.h>\r
9d560947
LE
15#include <Library/PciLib.h>\r
16\r
17#include "SmramInternal.h"\r
18\r
1372f8d3
LE
19//\r
20// The value of PcdQ35TsegMbytes is saved into this variable at module startup.\r
21//\r
22UINT16 mQ35TsegMbytes;\r
23\r
9108fc17
LE
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
1372f8d3
LE
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
9108fc17
LE
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
9d560947
LE
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 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC),\r
102 (UINT8)((~(UINT32)MCH_ESMRAMC_T_EN) & 0xff));\r
103\r
104 GetStates (LockState, OpenState);\r
105 if (!*OpenState) {\r
106 return EFI_DEVICE_ERROR;\r
107 }\r
108 return EFI_SUCCESS;\r
109}\r
110\r
111EFI_STATUS\r
112SmramAccessClose (\r
113 OUT BOOLEAN *LockState,\r
114 OUT BOOLEAN *OpenState\r
115 )\r
116{\r
117 //\r
118 // Close TSEG by setting T_EN.\r
119 //\r
120 PciOr8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC), MCH_ESMRAMC_T_EN);\r
121\r
122 GetStates (LockState, OpenState);\r
123 if (*OpenState) {\r
124 return EFI_DEVICE_ERROR;\r
125 }\r
126 return EFI_SUCCESS;\r
127}\r
128\r
129EFI_STATUS\r
130SmramAccessLock (\r
131 OUT BOOLEAN *LockState,\r
132 IN OUT BOOLEAN *OpenState\r
133 )\r
134{\r
135 if (*OpenState) {\r
136 return EFI_DEVICE_ERROR;\r
137 }\r
138\r
139 //\r
140 // Close & lock TSEG by setting T_EN and D_LCK.\r
141 //\r
142 PciOr8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC), MCH_ESMRAMC_T_EN);\r
143 PciOr8 (DRAMC_REGISTER_Q35 (MCH_SMRAM), MCH_SMRAM_D_LCK);\r
144\r
9108fc17
LE
145 //\r
146 // Close & lock the SMRAM at the default SMBASE, if it exists.\r
147 //\r
148 if (mQ35SmramAtDefaultSmbase) {\r
149 PciWrite8 (DRAMC_REGISTER_Q35 (MCH_DEFAULT_SMBASE_CTL),\r
150 MCH_DEFAULT_SMBASE_LCK);\r
151 }\r
152\r
9d560947
LE
153 GetStates (LockState, OpenState);\r
154 if (*OpenState || !*LockState) {\r
155 return EFI_DEVICE_ERROR;\r
156 }\r
157 return EFI_SUCCESS;\r
158}\r
159\r
160EFI_STATUS\r
161SmramAccessGetCapabilities (\r
162 IN BOOLEAN LockState,\r
163 IN BOOLEAN OpenState,\r
164 IN OUT UINTN *SmramMapSize,\r
165 IN OUT EFI_SMRAM_DESCRIPTOR *SmramMap\r
166 )\r
167{\r
168 UINTN OriginalSize;\r
169 UINT32 TsegMemoryBaseMb, TsegMemoryBase;\r
170 UINT64 CommonRegionState;\r
171 UINT8 TsegSizeBits;\r
172\r
173 OriginalSize = *SmramMapSize;\r
174 *SmramMapSize = DescIdxCount * sizeof *SmramMap;\r
175 if (OriginalSize < *SmramMapSize) {\r
176 return EFI_BUFFER_TOO_SMALL;\r
177 }\r
178\r
179 //\r
180 // Read the TSEG Memory Base register.\r
181 //\r
182 TsegMemoryBaseMb = PciRead32 (DRAMC_REGISTER_Q35 (MCH_TSEGMB));\r
183 TsegMemoryBase = (TsegMemoryBaseMb >> MCH_TSEGMB_MB_SHIFT) << 20;\r
184\r
185 //\r
186 // Precompute the region state bits that will be set for all regions.\r
187 //\r
188 CommonRegionState = (OpenState ? EFI_SMRAM_OPEN : EFI_SMRAM_CLOSED) |\r
189 (LockState ? EFI_SMRAM_LOCKED : 0) |\r
190 EFI_CACHEABLE;\r
191\r
192 //\r
193 // The first region hosts an SMM_S3_RESUME_STATE object. It is located at the\r
194 // start of TSEG. We round up the size to whole pages, and we report it as\r
195 // EFI_ALLOCATED, so that the SMM_CORE stays away from it.\r
196 //\r
197 SmramMap[DescIdxSmmS3ResumeState].PhysicalStart = TsegMemoryBase;\r
198 SmramMap[DescIdxSmmS3ResumeState].CpuStart = TsegMemoryBase;\r
199 SmramMap[DescIdxSmmS3ResumeState].PhysicalSize =\r
200 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (sizeof (SMM_S3_RESUME_STATE)));\r
201 SmramMap[DescIdxSmmS3ResumeState].RegionState =\r
202 CommonRegionState | EFI_ALLOCATED;\r
203\r
204 //\r
205 // Get the TSEG size bits from the ESMRAMC register.\r
206 //\r
207 TsegSizeBits = PciRead8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC)) &\r
208 MCH_ESMRAMC_TSEG_MASK;\r
209\r
210 //\r
211 // The second region is the main one, following the first.\r
212 //\r
213 SmramMap[DescIdxMain].PhysicalStart =\r
214 SmramMap[DescIdxSmmS3ResumeState].PhysicalStart +\r
215 SmramMap[DescIdxSmmS3ResumeState].PhysicalSize;\r
216 SmramMap[DescIdxMain].CpuStart = SmramMap[DescIdxMain].PhysicalStart;\r
217 SmramMap[DescIdxMain].PhysicalSize =\r
218 (TsegSizeBits == MCH_ESMRAMC_TSEG_8MB ? SIZE_8MB :\r
219 TsegSizeBits == MCH_ESMRAMC_TSEG_2MB ? SIZE_2MB :\r
6812bb7b
LE
220 TsegSizeBits == MCH_ESMRAMC_TSEG_1MB ? SIZE_1MB :\r
221 mQ35TsegMbytes * SIZE_1MB) -\r
222 SmramMap[DescIdxSmmS3ResumeState].PhysicalSize;\r
9d560947
LE
223 SmramMap[DescIdxMain].RegionState = CommonRegionState;\r
224\r
225 return EFI_SUCCESS;\r
226}\r