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