3 Functions and types shared by the SMM accessor PEI and DXE modules.
5 Copyright (C) 2015, Red Hat, Inc.
7 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include <Guid/AcpiS3Context.h>
12 #include <IndustryStandard/Q35MchIch9.h>
13 #include <Library/DebugLib.h>
14 #include <Library/PcdLib.h>
15 #include <Library/PciLib.h>
17 #include "SmramInternal.h"
20 // The value of PcdQ35TsegMbytes is saved into this variable at module startup.
22 UINT16 mQ35TsegMbytes
;
25 // The value of PcdQ35SmramAtDefaultSmbase is saved into this variable at
28 STATIC BOOLEAN mQ35SmramAtDefaultSmbase
;
31 Save PcdQ35TsegMbytes into mQ35TsegMbytes.
38 mQ35TsegMbytes
= PcdGet16 (PcdQ35TsegMbytes
);
42 Save PcdQ35SmramAtDefaultSmbase into mQ35SmramAtDefaultSmbase.
45 InitQ35SmramAtDefaultSmbase (
49 mQ35SmramAtDefaultSmbase
= PcdGetBool (PcdQ35SmramAtDefaultSmbase
);
53 Read the MCH_SMRAM and ESMRAMC registers, and update the LockState and
54 OpenState fields in the PEI_SMM_ACCESS_PPI / EFI_SMM_ACCESS2_PROTOCOL object,
55 from the D_LCK and T_EN bits.
57 PEI_SMM_ACCESS_PPI and EFI_SMM_ACCESS2_PROTOCOL member functions can rely on
58 the LockState and OpenState fields being up-to-date on entry, and they need
59 to restore the same invariant on exit, if they touch the bits in question.
61 @param[out] LockState Reflects the D_LCK bit on output; TRUE iff SMRAM is
63 @param[out] OpenState Reflects the inverse of the T_EN bit on output; TRUE
68 OUT BOOLEAN
*LockState
,
69 OUT BOOLEAN
*OpenState
72 UINT8 SmramVal
, EsmramcVal
;
74 SmramVal
= PciRead8 (DRAMC_REGISTER_Q35 (MCH_SMRAM
));
75 EsmramcVal
= PciRead8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC
));
77 *LockState
= !!(SmramVal
& MCH_SMRAM_D_LCK
);
78 *OpenState
= !(EsmramcVal
& MCH_ESMRAMC_T_EN
);
82 // The functions below follow the PEI_SMM_ACCESS_PPI and
83 // EFI_SMM_ACCESS2_PROTOCOL member declarations. The PeiServices and This
84 // pointers are removed (TSEG doesn't depend on them), and so is the
85 // DescriptorIndex parameter (TSEG doesn't support range-wise locking).
87 // The LockState and OpenState members that are common to both
88 // PEI_SMM_ACCESS_PPI and EFI_SMM_ACCESS2_PROTOCOL are taken and updated in
89 // isolation from the rest of the (non-shared) members.
94 OUT BOOLEAN
*LockState
,
95 OUT BOOLEAN
*OpenState
99 // Open TSEG by clearing T_EN.
101 PciAnd8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC
),
102 (UINT8
)((~(UINT32
)MCH_ESMRAMC_T_EN
) & 0xff));
104 GetStates (LockState
, OpenState
);
106 return EFI_DEVICE_ERROR
;
113 OUT BOOLEAN
*LockState
,
114 OUT BOOLEAN
*OpenState
118 // Close TSEG by setting T_EN.
120 PciOr8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC
), MCH_ESMRAMC_T_EN
);
122 GetStates (LockState
, OpenState
);
124 return EFI_DEVICE_ERROR
;
131 OUT BOOLEAN
*LockState
,
132 IN OUT BOOLEAN
*OpenState
136 return EFI_DEVICE_ERROR
;
140 // Close & lock TSEG by setting T_EN and D_LCK.
142 PciOr8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC
), MCH_ESMRAMC_T_EN
);
143 PciOr8 (DRAMC_REGISTER_Q35 (MCH_SMRAM
), MCH_SMRAM_D_LCK
);
146 // Close & lock the SMRAM at the default SMBASE, if it exists.
148 if (mQ35SmramAtDefaultSmbase
) {
149 PciWrite8 (DRAMC_REGISTER_Q35 (MCH_DEFAULT_SMBASE_CTL
),
150 MCH_DEFAULT_SMBASE_LCK
);
153 GetStates (LockState
, OpenState
);
154 if (*OpenState
|| !*LockState
) {
155 return EFI_DEVICE_ERROR
;
161 SmramAccessGetCapabilities (
162 IN BOOLEAN LockState
,
163 IN BOOLEAN OpenState
,
164 IN OUT UINTN
*SmramMapSize
,
165 IN OUT EFI_SMRAM_DESCRIPTOR
*SmramMap
169 UINT32 TsegMemoryBaseMb
, TsegMemoryBase
;
170 UINT64 CommonRegionState
;
173 OriginalSize
= *SmramMapSize
;
174 *SmramMapSize
= DescIdxCount
* sizeof *SmramMap
;
175 if (OriginalSize
< *SmramMapSize
) {
176 return EFI_BUFFER_TOO_SMALL
;
180 // Read the TSEG Memory Base register.
182 TsegMemoryBaseMb
= PciRead32 (DRAMC_REGISTER_Q35 (MCH_TSEGMB
));
183 TsegMemoryBase
= (TsegMemoryBaseMb
>> MCH_TSEGMB_MB_SHIFT
) << 20;
186 // Precompute the region state bits that will be set for all regions.
188 CommonRegionState
= (OpenState
? EFI_SMRAM_OPEN
: EFI_SMRAM_CLOSED
) |
189 (LockState
? EFI_SMRAM_LOCKED
: 0) |
193 // The first region hosts an SMM_S3_RESUME_STATE object. It is located at the
194 // start of TSEG. We round up the size to whole pages, and we report it as
195 // EFI_ALLOCATED, so that the SMM_CORE stays away from it.
197 SmramMap
[DescIdxSmmS3ResumeState
].PhysicalStart
= TsegMemoryBase
;
198 SmramMap
[DescIdxSmmS3ResumeState
].CpuStart
= TsegMemoryBase
;
199 SmramMap
[DescIdxSmmS3ResumeState
].PhysicalSize
=
200 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (sizeof (SMM_S3_RESUME_STATE
)));
201 SmramMap
[DescIdxSmmS3ResumeState
].RegionState
=
202 CommonRegionState
| EFI_ALLOCATED
;
205 // Get the TSEG size bits from the ESMRAMC register.
207 TsegSizeBits
= PciRead8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC
)) &
208 MCH_ESMRAMC_TSEG_MASK
;
211 // The second region is the main one, following the first.
213 SmramMap
[DescIdxMain
].PhysicalStart
=
214 SmramMap
[DescIdxSmmS3ResumeState
].PhysicalStart
+
215 SmramMap
[DescIdxSmmS3ResumeState
].PhysicalSize
;
216 SmramMap
[DescIdxMain
].CpuStart
= SmramMap
[DescIdxMain
].PhysicalStart
;
217 SmramMap
[DescIdxMain
].PhysicalSize
=
218 (TsegSizeBits
== MCH_ESMRAMC_TSEG_8MB
? SIZE_8MB
:
219 TsegSizeBits
== MCH_ESMRAMC_TSEG_2MB
? SIZE_2MB
:
220 TsegSizeBits
== MCH_ESMRAMC_TSEG_1MB
? SIZE_1MB
:
221 mQ35TsegMbytes
* SIZE_1MB
) -
222 SmramMap
[DescIdxSmmS3ResumeState
].PhysicalSize
;
223 SmramMap
[DescIdxMain
].RegionState
= CommonRegionState
;