]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/SmmAccess/SmramInternal.c
OvmfPkg: SmmCpuFeaturesLib: customize state save map format
[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
20#include <Library/PciLib.h>\r
21\r
22#include "SmramInternal.h"\r
23\r
24/**\r
25 Read the MCH_SMRAM and ESMRAMC registers, and update the LockState and\r
26 OpenState fields in the PEI_SMM_ACCESS_PPI / EFI_SMM_ACCESS2_PROTOCOL object,\r
27 from the D_LCK and T_EN bits.\r
28\r
29 PEI_SMM_ACCESS_PPI and EFI_SMM_ACCESS2_PROTOCOL member functions can rely on\r
30 the LockState and OpenState fields being up-to-date on entry, and they need\r
31 to restore the same invariant on exit, if they touch the bits in question.\r
32\r
33 @param[out] LockState Reflects the D_LCK bit on output; TRUE iff SMRAM is\r
34 locked.\r
35 @param[out] OpenState Reflects the inverse of the T_EN bit on output; TRUE\r
36 iff SMRAM is open.\r
37**/\r
38VOID\r
39GetStates (\r
40 OUT BOOLEAN *LockState,\r
41 OUT BOOLEAN *OpenState\r
42)\r
43{\r
44 UINT8 SmramVal, EsmramcVal;\r
45\r
46 SmramVal = PciRead8 (DRAMC_REGISTER_Q35 (MCH_SMRAM));\r
47 EsmramcVal = PciRead8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC));\r
48\r
49 *LockState = !!(SmramVal & MCH_SMRAM_D_LCK);\r
50 *OpenState = !(EsmramcVal & MCH_ESMRAMC_T_EN);\r
51}\r
52\r
53//\r
54// The functions below follow the PEI_SMM_ACCESS_PPI and\r
55// EFI_SMM_ACCESS2_PROTOCOL member declarations. The PeiServices and This\r
56// pointers are removed (TSEG doesn't depend on them), and so is the\r
57// DescriptorIndex parameter (TSEG doesn't support range-wise locking).\r
58//\r
59// The LockState and OpenState members that are common to both\r
60// PEI_SMM_ACCESS_PPI and EFI_SMM_ACCESS2_PROTOCOL are taken and updated in\r
61// isolation from the rest of the (non-shared) members.\r
62//\r
63\r
64EFI_STATUS\r
65SmramAccessOpen (\r
66 OUT BOOLEAN *LockState,\r
67 OUT BOOLEAN *OpenState\r
68 )\r
69{\r
70 //\r
71 // Open TSEG by clearing T_EN.\r
72 //\r
73 PciAnd8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC),\r
74 (UINT8)((~(UINT32)MCH_ESMRAMC_T_EN) & 0xff));\r
75\r
76 GetStates (LockState, OpenState);\r
77 if (!*OpenState) {\r
78 return EFI_DEVICE_ERROR;\r
79 }\r
80 return EFI_SUCCESS;\r
81}\r
82\r
83EFI_STATUS\r
84SmramAccessClose (\r
85 OUT BOOLEAN *LockState,\r
86 OUT BOOLEAN *OpenState\r
87 )\r
88{\r
89 //\r
90 // Close TSEG by setting T_EN.\r
91 //\r
92 PciOr8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC), MCH_ESMRAMC_T_EN);\r
93\r
94 GetStates (LockState, OpenState);\r
95 if (*OpenState) {\r
96 return EFI_DEVICE_ERROR;\r
97 }\r
98 return EFI_SUCCESS;\r
99}\r
100\r
101EFI_STATUS\r
102SmramAccessLock (\r
103 OUT BOOLEAN *LockState,\r
104 IN OUT BOOLEAN *OpenState\r
105 )\r
106{\r
107 if (*OpenState) {\r
108 return EFI_DEVICE_ERROR;\r
109 }\r
110\r
111 //\r
112 // Close & lock TSEG by setting T_EN and D_LCK.\r
113 //\r
114 PciOr8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC), MCH_ESMRAMC_T_EN);\r
115 PciOr8 (DRAMC_REGISTER_Q35 (MCH_SMRAM), MCH_SMRAM_D_LCK);\r
116\r
117 GetStates (LockState, OpenState);\r
118 if (*OpenState || !*LockState) {\r
119 return EFI_DEVICE_ERROR;\r
120 }\r
121 return EFI_SUCCESS;\r
122}\r
123\r
124EFI_STATUS\r
125SmramAccessGetCapabilities (\r
126 IN BOOLEAN LockState,\r
127 IN BOOLEAN OpenState,\r
128 IN OUT UINTN *SmramMapSize,\r
129 IN OUT EFI_SMRAM_DESCRIPTOR *SmramMap\r
130 )\r
131{\r
132 UINTN OriginalSize;\r
133 UINT32 TsegMemoryBaseMb, TsegMemoryBase;\r
134 UINT64 CommonRegionState;\r
135 UINT8 TsegSizeBits;\r
136\r
137 OriginalSize = *SmramMapSize;\r
138 *SmramMapSize = DescIdxCount * sizeof *SmramMap;\r
139 if (OriginalSize < *SmramMapSize) {\r
140 return EFI_BUFFER_TOO_SMALL;\r
141 }\r
142\r
143 //\r
144 // Read the TSEG Memory Base register.\r
145 //\r
146 TsegMemoryBaseMb = PciRead32 (DRAMC_REGISTER_Q35 (MCH_TSEGMB));\r
147 TsegMemoryBase = (TsegMemoryBaseMb >> MCH_TSEGMB_MB_SHIFT) << 20;\r
148\r
149 //\r
150 // Precompute the region state bits that will be set for all regions.\r
151 //\r
152 CommonRegionState = (OpenState ? EFI_SMRAM_OPEN : EFI_SMRAM_CLOSED) |\r
153 (LockState ? EFI_SMRAM_LOCKED : 0) |\r
154 EFI_CACHEABLE;\r
155\r
156 //\r
157 // The first region hosts an SMM_S3_RESUME_STATE object. It is located at the\r
158 // start of TSEG. We round up the size to whole pages, and we report it as\r
159 // EFI_ALLOCATED, so that the SMM_CORE stays away from it.\r
160 //\r
161 SmramMap[DescIdxSmmS3ResumeState].PhysicalStart = TsegMemoryBase;\r
162 SmramMap[DescIdxSmmS3ResumeState].CpuStart = TsegMemoryBase;\r
163 SmramMap[DescIdxSmmS3ResumeState].PhysicalSize =\r
164 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (sizeof (SMM_S3_RESUME_STATE)));\r
165 SmramMap[DescIdxSmmS3ResumeState].RegionState =\r
166 CommonRegionState | EFI_ALLOCATED;\r
167\r
168 //\r
169 // Get the TSEG size bits from the ESMRAMC register.\r
170 //\r
171 TsegSizeBits = PciRead8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC)) &\r
172 MCH_ESMRAMC_TSEG_MASK;\r
173\r
174 //\r
175 // The second region is the main one, following the first.\r
176 //\r
177 SmramMap[DescIdxMain].PhysicalStart =\r
178 SmramMap[DescIdxSmmS3ResumeState].PhysicalStart +\r
179 SmramMap[DescIdxSmmS3ResumeState].PhysicalSize;\r
180 SmramMap[DescIdxMain].CpuStart = SmramMap[DescIdxMain].PhysicalStart;\r
181 SmramMap[DescIdxMain].PhysicalSize =\r
182 (TsegSizeBits == MCH_ESMRAMC_TSEG_8MB ? SIZE_8MB :\r
183 TsegSizeBits == MCH_ESMRAMC_TSEG_2MB ? SIZE_2MB :\r
184 SIZE_1MB) - SmramMap[DescIdxSmmS3ResumeState].PhysicalSize;\r
185 SmramMap[DescIdxMain].RegionState = CommonRegionState;\r
186\r
187 return EFI_SUCCESS;\r
188}\r