]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/SmmAccess/SmramInternal.c
OvmfPkg/PvScsiDxe: Reset adapter on init
[mirror_edk2.git] / OvmfPkg / SmmAccess / SmramInternal.c
1 /** @file
2
3 Functions and types shared by the SMM accessor PEI and DXE modules.
4
5 Copyright (C) 2015, Red Hat, Inc.
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
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>
16
17 #include "SmramInternal.h"
18
19 //
20 // The value of PcdQ35TsegMbytes is saved into this variable at module startup.
21 //
22 UINT16 mQ35TsegMbytes;
23
24 //
25 // The value of PcdQ35SmramAtDefaultSmbase is saved into this variable at
26 // module startup.
27 //
28 STATIC BOOLEAN mQ35SmramAtDefaultSmbase;
29
30 /**
31 Save PcdQ35TsegMbytes into mQ35TsegMbytes.
32 **/
33 VOID
34 InitQ35TsegMbytes (
35 VOID
36 )
37 {
38 mQ35TsegMbytes = PcdGet16 (PcdQ35TsegMbytes);
39 }
40
41 /**
42 Save PcdQ35SmramAtDefaultSmbase into mQ35SmramAtDefaultSmbase.
43 **/
44 VOID
45 InitQ35SmramAtDefaultSmbase (
46 VOID
47 )
48 {
49 mQ35SmramAtDefaultSmbase = PcdGetBool (PcdQ35SmramAtDefaultSmbase);
50 }
51
52 /**
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.
56
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.
60
61 @param[out] LockState Reflects the D_LCK bit on output; TRUE iff SMRAM is
62 locked.
63 @param[out] OpenState Reflects the inverse of the T_EN bit on output; TRUE
64 iff SMRAM is open.
65 **/
66 VOID
67 GetStates (
68 OUT BOOLEAN *LockState,
69 OUT BOOLEAN *OpenState
70 )
71 {
72 UINT8 SmramVal, EsmramcVal;
73
74 SmramVal = PciRead8 (DRAMC_REGISTER_Q35 (MCH_SMRAM));
75 EsmramcVal = PciRead8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC));
76
77 *LockState = !!(SmramVal & MCH_SMRAM_D_LCK);
78 *OpenState = !(EsmramcVal & MCH_ESMRAMC_T_EN);
79 }
80
81 //
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).
86 //
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.
90 //
91
92 EFI_STATUS
93 SmramAccessOpen (
94 OUT BOOLEAN *LockState,
95 OUT BOOLEAN *OpenState
96 )
97 {
98 //
99 // Open TSEG by clearing T_EN.
100 //
101 PciAnd8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC),
102 (UINT8)((~(UINT32)MCH_ESMRAMC_T_EN) & 0xff));
103
104 GetStates (LockState, OpenState);
105 if (!*OpenState) {
106 return EFI_DEVICE_ERROR;
107 }
108 return EFI_SUCCESS;
109 }
110
111 EFI_STATUS
112 SmramAccessClose (
113 OUT BOOLEAN *LockState,
114 OUT BOOLEAN *OpenState
115 )
116 {
117 //
118 // Close TSEG by setting T_EN.
119 //
120 PciOr8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC), MCH_ESMRAMC_T_EN);
121
122 GetStates (LockState, OpenState);
123 if (*OpenState) {
124 return EFI_DEVICE_ERROR;
125 }
126 return EFI_SUCCESS;
127 }
128
129 EFI_STATUS
130 SmramAccessLock (
131 OUT BOOLEAN *LockState,
132 IN OUT BOOLEAN *OpenState
133 )
134 {
135 if (*OpenState) {
136 return EFI_DEVICE_ERROR;
137 }
138
139 //
140 // Close & lock TSEG by setting T_EN and D_LCK.
141 //
142 PciOr8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC), MCH_ESMRAMC_T_EN);
143 PciOr8 (DRAMC_REGISTER_Q35 (MCH_SMRAM), MCH_SMRAM_D_LCK);
144
145 //
146 // Close & lock the SMRAM at the default SMBASE, if it exists.
147 //
148 if (mQ35SmramAtDefaultSmbase) {
149 PciWrite8 (DRAMC_REGISTER_Q35 (MCH_DEFAULT_SMBASE_CTL),
150 MCH_DEFAULT_SMBASE_LCK);
151 }
152
153 GetStates (LockState, OpenState);
154 if (*OpenState || !*LockState) {
155 return EFI_DEVICE_ERROR;
156 }
157 return EFI_SUCCESS;
158 }
159
160 EFI_STATUS
161 SmramAccessGetCapabilities (
162 IN BOOLEAN LockState,
163 IN BOOLEAN OpenState,
164 IN OUT UINTN *SmramMapSize,
165 IN OUT EFI_SMRAM_DESCRIPTOR *SmramMap
166 )
167 {
168 UINTN OriginalSize;
169 UINT32 TsegMemoryBaseMb, TsegMemoryBase;
170 UINT64 CommonRegionState;
171 UINT8 TsegSizeBits;
172
173 OriginalSize = *SmramMapSize;
174 *SmramMapSize = DescIdxCount * sizeof *SmramMap;
175 if (OriginalSize < *SmramMapSize) {
176 return EFI_BUFFER_TOO_SMALL;
177 }
178
179 //
180 // Read the TSEG Memory Base register.
181 //
182 TsegMemoryBaseMb = PciRead32 (DRAMC_REGISTER_Q35 (MCH_TSEGMB));
183 TsegMemoryBase = (TsegMemoryBaseMb >> MCH_TSEGMB_MB_SHIFT) << 20;
184
185 //
186 // Precompute the region state bits that will be set for all regions.
187 //
188 CommonRegionState = (OpenState ? EFI_SMRAM_OPEN : EFI_SMRAM_CLOSED) |
189 (LockState ? EFI_SMRAM_LOCKED : 0) |
190 EFI_CACHEABLE;
191
192 //
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.
196 //
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;
203
204 //
205 // Get the TSEG size bits from the ESMRAMC register.
206 //
207 TsegSizeBits = PciRead8 (DRAMC_REGISTER_Q35 (MCH_ESMRAMC)) &
208 MCH_ESMRAMC_TSEG_MASK;
209
210 //
211 // The second region is the main one, following the first.
212 //
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;
224
225 return EFI_SUCCESS;
226 }