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