1 /** @file
2   Sample to provide FSP wrapper hob process related function.
3 
4   Copyright (c) 2014 - 2019, Intel Corporation. All rights reserved.<BR>
5   SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include <PiPei.h>
10 
11 #include <Library/PeiServicesLib.h>
12 #include <Library/PeiServicesTablePointerLib.h>
13 #include <Library/BaseLib.h>
14 #include <Library/DebugLib.h>
15 #include <Library/BaseMemoryLib.h>
16 #include <Library/HobLib.h>
17 #include <Library/PcdLib.h>
18 #include <Library/FspWrapperPlatformLib.h>
19 
20 #include <Guid/GuidHobFspEas.h>
21 #include <Guid/MemoryTypeInformation.h>
22 #include <Guid/PcdDataBaseHobGuid.h>
23 #include <Ppi/Capsule.h>
24 
25 //
26 // Additional pages are used by DXE memory manager.
27 // It should be consistent between RetrieveRequiredMemorySize() and GetPeiMemSize()
28 //
29 #define PEI_ADDITIONAL_MEMORY_SIZE    (16 * EFI_PAGE_SIZE)
30 
31 /**
32   Get the mem size in memory type infromation table.
33 
34   @param[in] PeiServices  PEI Services table.
35 
36   @return the mem size in memory type infromation table.
37 **/
38 UINT64
GetMemorySizeInMemoryTypeInformation(IN EFI_PEI_SERVICES ** PeiServices)39 GetMemorySizeInMemoryTypeInformation (
40   IN EFI_PEI_SERVICES **PeiServices
41   )
42 {
43   EFI_STATUS                  Status;
44   EFI_PEI_HOB_POINTERS        Hob;
45   EFI_MEMORY_TYPE_INFORMATION *MemoryData;
46   UINT8                       Index;
47   UINTN                       TempPageNum;
48 
49   MemoryData = NULL;
50   Status     = (*PeiServices)->GetHobList ((CONST EFI_PEI_SERVICES**)PeiServices, (VOID **) &Hob.Raw);
51   ASSERT_EFI_ERROR (Status);
52   while (!END_OF_HOB_LIST (Hob)) {
53     if (Hob.Header->HobType == EFI_HOB_TYPE_GUID_EXTENSION &&
54       CompareGuid (&Hob.Guid->Name, &gEfiMemoryTypeInformationGuid)) {
55       MemoryData = (EFI_MEMORY_TYPE_INFORMATION *) (Hob.Raw + sizeof (EFI_HOB_GENERIC_HEADER) + sizeof (EFI_GUID));
56       break;
57     }
58 
59     Hob.Raw = GET_NEXT_HOB (Hob);
60   }
61 
62   if (MemoryData == NULL) {
63     return 0;
64   }
65 
66   TempPageNum = 0;
67   for (Index = 0; MemoryData[Index].Type != EfiMaxMemoryType; Index++) {
68     //
69     // Accumulate default memory size requirements
70     //
71     TempPageNum += MemoryData[Index].NumberOfPages;
72   }
73 
74   return TempPageNum * EFI_PAGE_SIZE;
75 }
76 
77 /**
78   Get the mem size need to be reserved in PEI phase.
79 
80   @param[in] PeiServices  PEI Services table.
81 
82   @return the mem size need to be reserved in PEI phase.
83 **/
84 UINT64
RetrieveRequiredMemorySize(IN EFI_PEI_SERVICES ** PeiServices)85 RetrieveRequiredMemorySize (
86   IN EFI_PEI_SERVICES **PeiServices
87   )
88 {
89   UINT64                      Size;
90 
91   Size = GetMemorySizeInMemoryTypeInformation (PeiServices);
92   return Size + PEI_ADDITIONAL_MEMORY_SIZE;
93 }
94 
95 /**
96   Get the mem size need to be consumed and reserved in PEI phase.
97 
98   @param[in] PeiServices  PEI Services table.
99   @param[in] BootMode     Current boot mode.
100 
101   @return the mem size need to be consumed and reserved in PEI phase.
102 **/
103 UINT64
GetPeiMemSize(IN EFI_PEI_SERVICES ** PeiServices,IN UINT32 BootMode)104 GetPeiMemSize (
105   IN EFI_PEI_SERVICES **PeiServices,
106   IN UINT32           BootMode
107   )
108 {
109   UINT64                      Size;
110   UINT64                      MinSize;
111 
112   if (BootMode == BOOT_IN_RECOVERY_MODE) {
113     return PcdGet32 (PcdPeiRecoveryMinMemSize);
114   }
115 
116   Size = GetMemorySizeInMemoryTypeInformation (PeiServices);
117 
118   if (BootMode == BOOT_ON_FLASH_UPDATE) {
119     //
120     // Maybe more size when in CapsuleUpdate phase ?
121     //
122     MinSize = PcdGet32 (PcdPeiMinMemSize);
123   } else {
124     MinSize = PcdGet32 (PcdPeiMinMemSize);
125   }
126 
127   return MinSize + Size + PEI_ADDITIONAL_MEMORY_SIZE;
128 }
129 
130 /**
131   Post FSP-M HOB process for Memory Resource Descriptor.
132 
133   @param[in] FspHobList  Pointer to the HOB data structure produced by FSP.
134 
135   @return If platform process the FSP hob list successfully.
136 **/
137 EFI_STATUS
138 EFIAPI
PostFspmHobProcess(IN VOID * FspHobList)139 PostFspmHobProcess (
140   IN VOID                 *FspHobList
141   )
142 {
143   EFI_PEI_HOB_POINTERS Hob;
144   UINT64               LowMemorySize;
145   UINT64               FspMemorySize;
146   EFI_PHYSICAL_ADDRESS FspMemoryBase;
147   UINT64               PeiMemSize;
148   EFI_PHYSICAL_ADDRESS PeiMemBase;
149   UINT64               S3PeiMemSize;
150   EFI_PHYSICAL_ADDRESS S3PeiMemBase;
151   BOOLEAN              FoundFspMemHob;
152   EFI_STATUS           Status;
153   EFI_BOOT_MODE        BootMode;
154   EFI_PEI_CAPSULE_PPI  *Capsule;
155   VOID                 *CapsuleBuffer;
156   UINTN                CapsuleBufferLength;
157   UINT64               RequiredMemSize;
158   EFI_PEI_SERVICES     **PeiServices;
159 
160   PeiServices = (EFI_PEI_SERVICES **)GetPeiServicesTablePointer ();
161 
162   PeiServicesGetBootMode (&BootMode);
163 
164   PeiMemBase = 0;
165   LowMemorySize = 0;
166   FspMemorySize = 0;
167   FspMemoryBase = 0;
168   FoundFspMemHob = FALSE;
169 
170   //
171   // Parse the hob list from fsp
172   // Report all the resource hob except the memory between 1M and 4G
173   //
174   Hob.Raw = (UINT8 *)(UINTN)FspHobList;
175   DEBUG((DEBUG_INFO, "FspHobList - 0x%x\n", FspHobList));
176 
177   while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw)) != NULL) {
178     DEBUG((DEBUG_INFO, "\nResourceType: 0x%x\n", Hob.ResourceDescriptor->ResourceType));
179     if ((Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) ||
180         (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_MEMORY_RESERVED)) {
181       DEBUG((DEBUG_INFO, "ResourceAttribute: 0x%x\n", Hob.ResourceDescriptor->ResourceAttribute));
182       DEBUG((DEBUG_INFO, "PhysicalStart: 0x%x\n", Hob.ResourceDescriptor->PhysicalStart));
183       DEBUG((DEBUG_INFO, "ResourceLength: 0x%x\n", Hob.ResourceDescriptor->ResourceLength));
184       DEBUG((DEBUG_INFO, "Owner: %g\n\n", &Hob.ResourceDescriptor->Owner));
185     }
186 
187     if ((Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY)  // Found the low memory length below 4G
188         && (Hob.ResourceDescriptor->PhysicalStart >= BASE_1MB)
189         && (Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength <= BASE_4GB)) {
190         LowMemorySize += Hob.ResourceDescriptor->ResourceLength;
191       Hob.Raw = GET_NEXT_HOB (Hob);
192       continue;
193     }
194 
195     if ((Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_MEMORY_RESERVED)  // Found the low memory length below 4G
196         && (Hob.ResourceDescriptor->PhysicalStart >= BASE_1MB)
197         && (Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength <= BASE_4GB)
198         && (CompareGuid (&Hob.ResourceDescriptor->Owner, &gFspReservedMemoryResourceHobGuid))) {
199       FoundFspMemHob = TRUE;
200       FspMemoryBase = Hob.ResourceDescriptor->PhysicalStart;
201       FspMemorySize = Hob.ResourceDescriptor->ResourceLength;
202       DEBUG((DEBUG_INFO, "Find fsp mem hob, base 0x%x, len 0x%x\n", FspMemoryBase, FspMemorySize));
203     }
204 
205     //
206     // Report the resource hob
207     //
208     BuildResourceDescriptorHob (
209       Hob.ResourceDescriptor->ResourceType,
210       Hob.ResourceDescriptor->ResourceAttribute,
211       Hob.ResourceDescriptor->PhysicalStart,
212       Hob.ResourceDescriptor->ResourceLength
213       );
214 
215     Hob.Raw = GET_NEXT_HOB (Hob);
216   }
217 
218   if (!FoundFspMemHob) {
219     DEBUG((DEBUG_INFO, "Didn't find the fsp used memory information.\n"));
220     //ASSERT(FALSE);
221   }
222 
223   DEBUG((DEBUG_INFO, "LowMemorySize: 0x%x.\n", LowMemorySize));
224   DEBUG((DEBUG_INFO, "FspMemoryBase: 0x%x.\n", FspMemoryBase));
225   DEBUG((DEBUG_INFO, "FspMemorySize: 0x%x.\n", FspMemorySize));
226 
227   if (BootMode == BOOT_ON_S3_RESUME) {
228     BuildResourceDescriptorHob (
229       EFI_RESOURCE_SYSTEM_MEMORY,
230       (
231          EFI_RESOURCE_ATTRIBUTE_PRESENT |
232          EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
233          // EFI_RESOURCE_ATTRIBUTE_TESTED |
234          EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
235          EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
236          EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
237          EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
238       ),
239       BASE_1MB,
240       LowMemorySize
241       );
242 
243     S3PeiMemBase = 0;
244     S3PeiMemSize = 0;
245     Status = GetS3MemoryInfo (&S3PeiMemSize, &S3PeiMemBase);
246     ASSERT_EFI_ERROR (Status);
247     DEBUG((DEBUG_INFO, "S3 memory %Xh - %Xh bytes\n", S3PeiMemBase, S3PeiMemSize));
248 
249     //
250     // Make sure Stack and PeiMemory are not overlap
251     //
252 
253     Status = PeiServicesInstallPeiMemory (
254                S3PeiMemBase,
255                S3PeiMemSize
256                );
257     ASSERT_EFI_ERROR (Status);
258   } else {
259     PeiMemSize = GetPeiMemSize (PeiServices, BootMode);
260     DEBUG((DEBUG_INFO, "PEI memory size = %Xh bytes\n", PeiMemSize));
261 
262     //
263     // Capsule mode
264     //
265     Capsule = NULL;
266     CapsuleBuffer = NULL;
267     CapsuleBufferLength = 0;
268     if (BootMode == BOOT_ON_FLASH_UPDATE) {
269       Status = PeiServicesLocatePpi (
270                  &gEfiPeiCapsulePpiGuid,
271                  0,
272                  NULL,
273                  (VOID **) &Capsule
274                  );
275       ASSERT_EFI_ERROR (Status);
276 
277       if (Status == EFI_SUCCESS) {
278         //
279         // Make sure Stack and CapsuleBuffer are not overlap
280         //
281         CapsuleBuffer = (VOID *)(UINTN)BASE_1MB;
282         CapsuleBufferLength = (UINTN)(LowMemorySize - PeiMemSize);
283         //
284         // Call the Capsule PPI Coalesce function to coalesce the capsule data.
285         //
286         Status = Capsule->Coalesce (PeiServices, &CapsuleBuffer, &CapsuleBufferLength);
287       }
288     }
289 
290     RequiredMemSize = RetrieveRequiredMemorySize (PeiServices);
291     DEBUG((DEBUG_INFO, "Required memory size = %Xh bytes\n", RequiredMemSize));
292 
293     //
294     // Report the main memory
295     //
296     BuildResourceDescriptorHob (
297       EFI_RESOURCE_SYSTEM_MEMORY,
298       (
299          EFI_RESOURCE_ATTRIBUTE_PRESENT |
300          EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
301          EFI_RESOURCE_ATTRIBUTE_TESTED |
302          EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
303          EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
304          EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
305          EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
306       ),
307       BASE_1MB,
308       LowMemorySize
309       );
310 
311     //
312     // Make sure Stack and CapsuleBuffer are not overlap
313     //
314 
315     //
316     // Install efi memory
317     //
318     PeiMemBase = BASE_1MB + LowMemorySize - PeiMemSize;
319     Status = PeiServicesInstallPeiMemory (
320                PeiMemBase,
321                PeiMemSize - RequiredMemSize
322                );
323     ASSERT_EFI_ERROR (Status);
324 
325     if (Capsule != NULL) {
326       Status = Capsule->CreateState (PeiServices, CapsuleBuffer, CapsuleBufferLength);
327     }
328   }
329 
330   return EFI_SUCCESS;
331 }
332 
333 /**
334   Process FSP HOB list
335 
336   @param[in] FspHobList  Pointer to the HOB data structure produced by FSP.
337 
338 **/
339 VOID
ProcessFspHobList(IN VOID * FspHobList)340 ProcessFspHobList (
341   IN VOID                 *FspHobList
342   )
343 {
344   EFI_PEI_HOB_POINTERS  FspHob;
345 
346   FspHob.Raw = FspHobList;
347 
348   //
349   // Add all the HOBs from FSP binary to FSP wrapper
350   //
351   while (!END_OF_HOB_LIST (FspHob)) {
352     if (FspHob.Header->HobType == EFI_HOB_TYPE_GUID_EXTENSION) {
353       //
354       // Skip FSP binary creates PcdDataBaseHobGuid
355       //
356       if (!CompareGuid(&FspHob.Guid->Name, &gPcdDataBaseHobGuid)) {
357         BuildGuidDataHob (
358           &FspHob.Guid->Name,
359           GET_GUID_HOB_DATA(FspHob),
360           GET_GUID_HOB_DATA_SIZE(FspHob)
361         );
362       }
363     }
364     FspHob.Raw = GET_NEXT_HOB (FspHob);
365   }
366 }
367 
368 /**
369   Post FSP-S HOB process (not Memory Resource Descriptor).
370 
371   @param[in] FspHobList  Pointer to the HOB data structure produced by FSP.
372 
373   @return If platform process the FSP hob list successfully.
374 **/
375 EFI_STATUS
376 EFIAPI
PostFspsHobProcess(IN VOID * FspHobList)377 PostFspsHobProcess (
378   IN VOID                 *FspHobList
379   )
380 {
381   //
382   // PostFspsHobProcess () will be called in both FSP API and Dispatch modes to
383   // align the same behavior and support a variety of boot loader implementations.
384   // Boot loader provided library function is recommended to support both API and
385   // Dispatch modes by checking PcdFspModeSelection.
386   //
387   if (PcdGet8 (PcdFspModeSelection) == 1) {
388     //
389     // Only in FSP API mode the wrapper has to build hobs basing on FSP output data.
390     // In this case FspHobList cannot be NULL.
391     //
392     ASSERT (FspHobList != NULL);
393     ProcessFspHobList (FspHobList);
394   }
395   return EFI_SUCCESS;
396 }
397