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