1 /** @file
2   This is the driver that produce AcpiVariable hob and slit SmramReserve hob
3   for ECP platform.
4 
5 Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
6 
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions
9 of the BSD License which accompanies this distribution.  The
10 full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
12 
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 
16 **/
17 
18 #include <PiPei.h>
19 #include <Guid/SmramMemoryReserve.h>
20 #include <Guid/AcpiS3Context.h>
21 
22 #include <Library/MemoryAllocationLib.h>
23 #include <Library/DebugLib.h>
24 #include <Library/HobLib.h>
25 #include <Library/PeiServicesLib.h>
26 #include <Library/BaseMemoryLib.h>
27 
28 /**
29   Retrieves the data structure associated witht he GUIDed HOB of type gEfiSmmPeiSmramMemoryReserveGuid
30 
31   @retval NULL   A HOB of type gEfiSmmPeiSmramMemoryReserveGuid could not be found.
32   @retval !NULL  A pointer to the GUID data from a HIB of type gEfiSmmPeiSmramMemoryReserveGuid
33 
34 **/
35 EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *
GetSrmamHobData(VOID)36 GetSrmamHobData (
37   VOID
38   )
39 {
40   VOID  *GuidHob;
41 
42   //
43   // Search SmramMemoryReserve HOB that describes SMRAM region
44   //
45   GuidHob = GetFirstGuidHob (&gEfiSmmPeiSmramMemoryReserveGuid);
46   if (GuidHob == NULL) {
47     return NULL;
48   }
49   return (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *)GET_GUID_HOB_DATA (GuidHob);
50 }
51 
52 /**
53   This routine will split SmramReserve hob to reserve 1 page for SMRAM content in S3 phase
54   for PI SMM core.
55 
56   @retval EFI_SUCCESS           The gEfiSmmPeiSmramMemoryReserveGuid is splited successfully.
57   @retval EFI_NOT_FOUND         The gEfiSmmPeiSmramMemoryReserveGuid is not found.
58 
59 **/
60 EFI_STATUS
61 EFIAPI
SplitSmramReserveHob(VOID)62 SplitSmramReserveHob (
63   VOID
64   )
65 {
66   EFI_HOB_GUID_TYPE                *GuidHob;
67   EFI_PEI_HOB_POINTERS             Hob;
68   EFI_SMRAM_HOB_DESCRIPTOR_BLOCK   *DescriptorBlock;
69   EFI_SMRAM_HOB_DESCRIPTOR_BLOCK   *NewDescriptorBlock;
70   UINTN                            BufferSize;
71   UINTN                            SmramRanges;
72   UINTN                            Index;
73   UINTN                            SubIndex;
74 
75   //
76   // Retrieve the GUID HOB data that contains the set of SMRAM descriptyors
77   //
78   GuidHob = GetFirstGuidHob (&gEfiSmmPeiSmramMemoryReserveGuid);
79   if (GuidHob == NULL) {
80     return EFI_NOT_FOUND;
81   }
82 
83   DescriptorBlock = (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *)GET_GUID_HOB_DATA (GuidHob);
84 
85   //
86   // Allocate one extra EFI_SMRAM_DESCRIPTOR to describe a page of SMRAM memory that contains a pointer
87   // to the SMM Services Table that is required on the S3 resume path
88   //
89   SmramRanges = DescriptorBlock->NumberOfSmmReservedRegions;
90   BufferSize = sizeof (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK) + (SmramRanges * sizeof (EFI_SMRAM_DESCRIPTOR));
91 
92   Hob.Raw = BuildGuidHob (
93               &gEfiSmmPeiSmramMemoryReserveGuid,
94               BufferSize
95               );
96   ASSERT (Hob.Raw);
97   NewDescriptorBlock = (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *)Hob.Raw;
98 
99   //
100   // Copy old EFI_SMRAM_HOB_DESCRIPTOR_BLOCK to new allocated region
101   //
102   CopyMem ((VOID *)Hob.Raw, DescriptorBlock, BufferSize - sizeof(EFI_SMRAM_DESCRIPTOR));
103 
104   //
105   // Increase the number of SMRAM descriptors by 1 to make room for the ALLOCATED descriptor of size EFI_PAGE_SIZE
106   //
107   NewDescriptorBlock->NumberOfSmmReservedRegions = (UINT32)(SmramRanges + 1);
108 
109   ASSERT (SmramRanges >= 1);
110   //
111   // Copy last entry to the end - we assume TSEG is last entry, which is same assumption as Framework CPU/SMM driver
112   //
113   CopyMem (&NewDescriptorBlock->Descriptor[SmramRanges], &NewDescriptorBlock->Descriptor[SmramRanges - 1], sizeof(EFI_SMRAM_DESCRIPTOR));
114 
115   //
116   // Update the last but 1 entry in the array with a size of EFI_PAGE_SIZE and put into the ALLOCATED state
117   //
118   NewDescriptorBlock->Descriptor[SmramRanges - 1].PhysicalSize    = EFI_PAGE_SIZE;
119   NewDescriptorBlock->Descriptor[SmramRanges - 1].RegionState    |= EFI_ALLOCATED;
120 
121   //
122   // Reduce the size of the last SMRAM descriptor by EFI_PAGE_SIZE
123   //
124   NewDescriptorBlock->Descriptor[SmramRanges].PhysicalStart += EFI_PAGE_SIZE;
125   NewDescriptorBlock->Descriptor[SmramRanges].CpuStart      += EFI_PAGE_SIZE;
126   NewDescriptorBlock->Descriptor[SmramRanges].PhysicalSize  -= EFI_PAGE_SIZE;
127 
128   //
129   // Now, we have created SmramReserve Hob for SmmAccess drive. But the issue is that, Framework SmmAccess will assume there is 2 SmramReserve region only.
130   // Reporting 3 SmramReserve region will cause buffer overflow. Moreover, we would like to filter AB-SEG or H-SEG to avoid SMM cache-poisoning issue.
131   // So we uses scan SmmReserve Hob to remove AB-SEG or H-SEG.
132   //
133   for (Index = 0; Index <= SmramRanges; Index++) {
134     if (NewDescriptorBlock->Descriptor[Index].PhysicalSize == 0) {
135       //
136       // Skip zero entry
137       //
138       continue;
139     }
140     if (NewDescriptorBlock->Descriptor[Index].PhysicalStart < BASE_1MB) {
141       //
142       // Find AB-SEG or H-SEG
143       // remove this region
144       //
145       for (SubIndex = Index; SubIndex < NewDescriptorBlock->NumberOfSmmReservedRegions - 1; SubIndex++) {
146         CopyMem (&NewDescriptorBlock->Descriptor[SubIndex], &NewDescriptorBlock->Descriptor[SubIndex + 1], sizeof (EFI_SMRAM_DESCRIPTOR));
147       }
148       //
149       // Zero last one
150       //
151       ZeroMem (&NewDescriptorBlock->Descriptor[SubIndex], sizeof(EFI_SMRAM_DESCRIPTOR));
152       //
153       // Decrease Number
154       //
155       NewDescriptorBlock->NumberOfSmmReservedRegions --;
156       //
157       // Decrease Index to let it test mew entry
158       //
159       Index --;
160     }
161   }
162 
163   //
164   // Last step, we can scrub old one
165   //
166   ZeroMem (&GuidHob->Name, sizeof(GuidHob->Name));
167 
168   return EFI_SUCCESS;
169 }
170 
171 /**
172   This routine will create AcpiVariable hob to point the reserved smram in S3 phase
173   for PI SMM core.
174 
175   @retval EFI_SUCCESS           The gEfiAcpiVariableGuid is created successfully.
176   @retval EFI_NOT_FOUND         The gEfiSmmPeiSmramMemoryReserveGuid is not found.
177 
178 **/
179 EFI_STATUS
180 EFIAPI
CreateAcpiVariableHob(VOID)181 CreateAcpiVariableHob (
182   VOID
183   )
184 {
185   EFI_PEI_HOB_POINTERS             Hob;
186   EFI_SMRAM_HOB_DESCRIPTOR_BLOCK   *DescriptorBlock;
187   UINTN                            SmramRanges;
188 
189   //
190   // Retrieve the GUID HOB data that contains the set of SMRAM descriptyors
191   //
192   DescriptorBlock = GetSrmamHobData ();
193   if (DescriptorBlock == NULL) {
194     return EFI_NOT_FOUND;
195   }
196 
197   Hob.Raw = BuildGuidHob (
198               &gEfiAcpiVariableGuid,
199               sizeof (EFI_SMRAM_DESCRIPTOR)
200               );
201   ASSERT (Hob.Raw);
202 
203   //
204   // It should be already patch, so just copy last but 1 region directly.
205   //
206   SmramRanges = DescriptorBlock->NumberOfSmmReservedRegions;
207   ASSERT (SmramRanges >= 2);
208   if (SmramRanges >= 2) {
209     CopyMem ((VOID *)Hob.Raw, &DescriptorBlock->Descriptor[SmramRanges - 2], sizeof (EFI_SMRAM_DESCRIPTOR));
210   }
211 
212   return EFI_SUCCESS;
213 }
214 
215 /**
216   Driver Entry for AcpiVariableHobOnSmramReservHob PEIM
217 
218   @param   FileHandle       Handle of the file being invoked.
219   @param   PeiServices      Describes the list of possible PEI Services.
220 
221   @retval EFI_SUCCESS      Success create gEfiAcpiVariableGuid and
222                            split gEfiSmmPeiSmramMemoryReserveGuid.
223   @retval EFI_NOT_FOUND    Can not get gEfiSmmPeiSmramMemoryReserveGuid hob
224 
225 **/
226 EFI_STATUS
227 EFIAPI
AcpiVariableHobEntry(IN EFI_PEI_FILE_HANDLE FileHandle,IN CONST EFI_PEI_SERVICES ** PeiServices)228 AcpiVariableHobEntry (
229   IN       EFI_PEI_FILE_HANDLE  FileHandle,
230   IN CONST EFI_PEI_SERVICES     **PeiServices
231   )
232 {
233   EFI_STATUS              Status;
234 
235   //
236   // Split SmramReserve hob, which is required for PI SMM Core for S3.
237   //
238   Status = SplitSmramReserveHob ();
239   if (EFI_ERROR (Status)) {
240     return Status;
241   }
242 
243   //
244   // Create AcpiVariable hob, which is required for PI SMM Core for S3.
245   //
246   Status = CreateAcpiVariableHob ();
247 
248   return Status;
249 }
250