]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/SmmAccess/SmramInternal.c
OvmfPkg/SmmAccess: support extended TSEG size
[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
7 This program and the accompanying materials are licensed and made available\r
8 under the terms and conditions of the BSD License which accompanies this\r
9 distribution. The full text of the license may be found at\r
10 http://opensource.org/licenses/bsd-license.php\r
11\r
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
13 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/\r
16\r
17#include <Guid/AcpiS3Context.h>\r
18#include <IndustryStandard/Q35MchIch9.h>\r
19#include <Library/DebugLib.h>\r
1372f8d3 20#include <Library/PcdLib.h>\r
9d560947
LE
21#include <Library/PciLib.h>\r
22\r
23#include "SmramInternal.h"\r
24\r
1372f8d3
LE
25//\r
26// The value of PcdQ35TsegMbytes is saved into this variable at module startup.\r
27//\r
28UINT16 mQ35TsegMbytes;\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
9d560947
LE
41/**\r
42 Read the MCH_SMRAM and ESMRAMC registers, and update the LockState and\r
43 OpenState fields in the PEI_SMM_ACCESS_PPI / EFI_SMM_ACCESS2_PROTOCOL object,\r
44 from the D_LCK and T_EN bits.\r
45\r
46 PEI_SMM_ACCESS_PPI and EFI_SMM_ACCESS2_PROTOCOL member functions can rely on\r
47 the LockState and OpenState fields being up-to-date on entry, and they need\r
48 to restore the same invariant on exit, if they touch the bits in question.\r
49\r
50 @param[out] LockState Reflects the D_LCK bit on output; TRUE iff SMRAM is\r
51 locked.\r
52 @param[out] OpenState Reflects the inverse of the T_EN bit on output; TRUE\r
53 iff SMRAM is open.\r
54**/\r
55VOID\r
56GetStates (\r
57 OUT BOOLEAN *LockState,\r
58 OUT BOOLEAN *OpenState\r
59)\r
60{\r
61 UINT8 SmramVal, EsmramcVal;\r
62\r
63 SmramVal = PciRead8 (DRAMC_REGISTER_Q35 (MCH_SMRAM));\r
64 EsmramcVal = PciRead8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC));\r
65\r
66 *LockState = !!(SmramVal & MCH_SMRAM_D_LCK);\r
67 *OpenState = !(EsmramcVal & MCH_ESMRAMC_T_EN);\r
68}\r
69\r
70//\r
71// The functions below follow the PEI_SMM_ACCESS_PPI and\r
72// EFI_SMM_ACCESS2_PROTOCOL member declarations. The PeiServices and This\r
73// pointers are removed (TSEG doesn't depend on them), and so is the\r
74// DescriptorIndex parameter (TSEG doesn't support range-wise locking).\r
75//\r
76// The LockState and OpenState members that are common to both\r
77// PEI_SMM_ACCESS_PPI and EFI_SMM_ACCESS2_PROTOCOL are taken and updated in\r
78// isolation from the rest of the (non-shared) members.\r
79//\r
80\r
81EFI_STATUS\r
82SmramAccessOpen (\r
83 OUT BOOLEAN *LockState,\r
84 OUT BOOLEAN *OpenState\r
85 )\r
86{\r
87 //\r
88 // Open TSEG by clearing T_EN.\r
89 //\r
90 PciAnd8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC),\r
91 (UINT8)((~(UINT32)MCH_ESMRAMC_T_EN) & 0xff));\r
92\r
93 GetStates (LockState, OpenState);\r
94 if (!*OpenState) {\r
95 return EFI_DEVICE_ERROR;\r
96 }\r
97 return EFI_SUCCESS;\r
98}\r
99\r
100EFI_STATUS\r
101SmramAccessClose (\r
102 OUT BOOLEAN *LockState,\r
103 OUT BOOLEAN *OpenState\r
104 )\r
105{\r
106 //\r
107 // Close TSEG by setting T_EN.\r
108 //\r
109 PciOr8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC), MCH_ESMRAMC_T_EN);\r
110\r
111 GetStates (LockState, OpenState);\r
112 if (*OpenState) {\r
113 return EFI_DEVICE_ERROR;\r
114 }\r
115 return EFI_SUCCESS;\r
116}\r
117\r
118EFI_STATUS\r
119SmramAccessLock (\r
120 OUT BOOLEAN *LockState,\r
121 IN OUT BOOLEAN *OpenState\r
122 )\r
123{\r
124 if (*OpenState) {\r
125 return EFI_DEVICE_ERROR;\r
126 }\r
127\r
128 //\r
129 // Close & lock TSEG by setting T_EN and D_LCK.\r
130 //\r
131 PciOr8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC), MCH_ESMRAMC_T_EN);\r
132 PciOr8 (DRAMC_REGISTER_Q35 (MCH_SMRAM), MCH_SMRAM_D_LCK);\r
133\r
134 GetStates (LockState, OpenState);\r
135 if (*OpenState || !*LockState) {\r
136 return EFI_DEVICE_ERROR;\r
137 }\r
138 return EFI_SUCCESS;\r
139}\r
140\r
141EFI_STATUS\r
142SmramAccessGetCapabilities (\r
143 IN BOOLEAN LockState,\r
144 IN BOOLEAN OpenState,\r
145 IN OUT UINTN *SmramMapSize,\r
146 IN OUT EFI_SMRAM_DESCRIPTOR *SmramMap\r
147 )\r
148{\r
149 UINTN OriginalSize;\r
150 UINT32 TsegMemoryBaseMb, TsegMemoryBase;\r
151 UINT64 CommonRegionState;\r
152 UINT8 TsegSizeBits;\r
153\r
154 OriginalSize = *SmramMapSize;\r
155 *SmramMapSize = DescIdxCount * sizeof *SmramMap;\r
156 if (OriginalSize < *SmramMapSize) {\r
157 return EFI_BUFFER_TOO_SMALL;\r
158 }\r
159\r
160 //\r
161 // Read the TSEG Memory Base register.\r
162 //\r
163 TsegMemoryBaseMb = PciRead32 (DRAMC_REGISTER_Q35 (MCH_TSEGMB));\r
164 TsegMemoryBase = (TsegMemoryBaseMb >> MCH_TSEGMB_MB_SHIFT) << 20;\r
165\r
166 //\r
167 // Precompute the region state bits that will be set for all regions.\r
168 //\r
169 CommonRegionState = (OpenState ? EFI_SMRAM_OPEN : EFI_SMRAM_CLOSED) |\r
170 (LockState ? EFI_SMRAM_LOCKED : 0) |\r
171 EFI_CACHEABLE;\r
172\r
173 //\r
174 // The first region hosts an SMM_S3_RESUME_STATE object. It is located at the\r
175 // start of TSEG. We round up the size to whole pages, and we report it as\r
176 // EFI_ALLOCATED, so that the SMM_CORE stays away from it.\r
177 //\r
178 SmramMap[DescIdxSmmS3ResumeState].PhysicalStart = TsegMemoryBase;\r
179 SmramMap[DescIdxSmmS3ResumeState].CpuStart = TsegMemoryBase;\r
180 SmramMap[DescIdxSmmS3ResumeState].PhysicalSize =\r
181 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (sizeof (SMM_S3_RESUME_STATE)));\r
182 SmramMap[DescIdxSmmS3ResumeState].RegionState =\r
183 CommonRegionState | EFI_ALLOCATED;\r
184\r
185 //\r
186 // Get the TSEG size bits from the ESMRAMC register.\r
187 //\r
188 TsegSizeBits = PciRead8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC)) &\r
189 MCH_ESMRAMC_TSEG_MASK;\r
190\r
191 //\r
192 // The second region is the main one, following the first.\r
193 //\r
194 SmramMap[DescIdxMain].PhysicalStart =\r
195 SmramMap[DescIdxSmmS3ResumeState].PhysicalStart +\r
196 SmramMap[DescIdxSmmS3ResumeState].PhysicalSize;\r
197 SmramMap[DescIdxMain].CpuStart = SmramMap[DescIdxMain].PhysicalStart;\r
198 SmramMap[DescIdxMain].PhysicalSize =\r
199 (TsegSizeBits == MCH_ESMRAMC_TSEG_8MB ? SIZE_8MB :\r
200 TsegSizeBits == MCH_ESMRAMC_TSEG_2MB ? SIZE_2MB :\r
6812bb7b
LE
201 TsegSizeBits == MCH_ESMRAMC_TSEG_1MB ? SIZE_1MB :\r
202 mQ35TsegMbytes * SIZE_1MB) -\r
203 SmramMap[DescIdxSmmS3ResumeState].PhysicalSize;\r
9d560947
LE
204 SmramMap[DescIdxMain].RegionState = CommonRegionState;\r
205\r
206 return EFI_SUCCESS;\r
207}\r