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