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