1 /** @file
2   Update and publish processors' BIST information.
3 
4   Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
5   This program and the accompanying materials
6   are licensed and made available under the terms and conditions of the BSD License
7   which accompanies this distribution.  The full text of the license may be found at
8   http://opensource.org/licenses/bsd-license.php
9 
10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include "CpuMpPei.h"
16 
17 EFI_SEC_PLATFORM_INFORMATION2_PPI mSecPlatformInformation2Ppi = {
18   SecPlatformInformation2
19 };
20 
21 EFI_PEI_PPI_DESCRIPTOR mPeiSecPlatformInformation2Ppi = {
22   (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
23   &gEfiSecPlatformInformation2PpiGuid,
24   &mSecPlatformInformation2Ppi
25 };
26 
27 /**
28   Implementation of the PlatformInformation2 service in EFI_SEC_PLATFORM_INFORMATION2_PPI.
29 
30   @param  PeiServices                The pointer to the PEI Services Table.
31   @param  StructureSize              The pointer to the variable describing size of the input buffer.
32   @param  PlatformInformationRecord2 The pointer to the EFI_SEC_PLATFORM_INFORMATION_RECORD2.
33 
34   @retval EFI_SUCCESS                The data was successfully returned.
35   @retval EFI_BUFFER_TOO_SMALL       The buffer was too small. The current buffer size needed to
36                                      hold the record is returned in StructureSize.
37 
38 **/
39 EFI_STATUS
40 EFIAPI
SecPlatformInformation2(IN CONST EFI_PEI_SERVICES ** PeiServices,IN OUT UINT64 * StructureSize,OUT EFI_SEC_PLATFORM_INFORMATION_RECORD2 * PlatformInformationRecord2)41 SecPlatformInformation2 (
42   IN CONST EFI_PEI_SERVICES                   **PeiServices,
43   IN OUT UINT64                               *StructureSize,
44      OUT EFI_SEC_PLATFORM_INFORMATION_RECORD2 *PlatformInformationRecord2
45   )
46 {
47   EFI_HOB_GUID_TYPE       *GuidHob;
48   VOID                    *DataInHob;
49   UINTN                   DataSize;
50 
51   GuidHob = GetFirstGuidHob (&gEfiSecPlatformInformation2PpiGuid);
52   if (GuidHob == NULL) {
53     *StructureSize = 0;
54     return EFI_SUCCESS;
55   }
56 
57   DataInHob = GET_GUID_HOB_DATA (GuidHob);
58   DataSize  = GET_GUID_HOB_DATA_SIZE (GuidHob);
59 
60   //
61   // return the information from BistHob
62   //
63   if ((*StructureSize) < (UINT64) DataSize) {
64     *StructureSize = (UINT64) DataSize;
65     return EFI_BUFFER_TOO_SMALL;
66   }
67 
68   *StructureSize = (UINT64) DataSize;
69   CopyMem (PlatformInformationRecord2, DataInHob, DataSize);
70   return EFI_SUCCESS;
71 }
72 
73 /**
74   Worker function to get CPUs' BIST by calling SecPlatformInformationPpi
75   or SecPlatformInformation2Ppi.
76 
77   @param  PeiServices         Pointer to PEI Services Table
78   @param  Guid                PPI Guid
79   @param  PpiDescriptor       Return a pointer to instance of the
80                               EFI_PEI_PPI_DESCRIPTOR
81   @param  BistInformationData Pointer to BIST information data
82   @param  BistInformationSize Return the size in bytes of BIST information
83 
84   @retval EFI_SUCCESS         Retrieve of the BIST data successfully
85   @retval EFI_NOT_FOUND       No sec platform information(2) ppi export
86   @retval EFI_DEVICE_ERROR    Failed to get CPU Information
87 
88 **/
89 EFI_STATUS
GetBistInfoFromPpi(IN CONST EFI_PEI_SERVICES ** PeiServices,IN CONST EFI_GUID * Guid,OUT EFI_PEI_PPI_DESCRIPTOR ** PpiDescriptor,OUT VOID ** BistInformationData,OUT UINT64 * BistInformationSize OPTIONAL)90 GetBistInfoFromPpi (
91   IN CONST EFI_PEI_SERVICES     **PeiServices,
92   IN CONST EFI_GUID             *Guid,
93      OUT EFI_PEI_PPI_DESCRIPTOR **PpiDescriptor,
94      OUT VOID                   **BistInformationData,
95      OUT UINT64                 *BistInformationSize OPTIONAL
96   )
97 {
98   EFI_STATUS                            Status;
99   EFI_SEC_PLATFORM_INFORMATION2_PPI     *SecPlatformInformation2Ppi;
100   EFI_SEC_PLATFORM_INFORMATION_RECORD2  *SecPlatformInformation2;
101   UINT64                                InformationSize;
102 
103   Status = PeiServicesLocatePpi (
104              Guid,                                // GUID
105              0,                                   // INSTANCE
106              PpiDescriptor,                       // EFI_PEI_PPI_DESCRIPTOR
107              (VOID **)&SecPlatformInformation2Ppi // PPI
108              );
109   if (Status == EFI_NOT_FOUND) {
110     return EFI_NOT_FOUND;
111   }
112 
113   if (Status == EFI_SUCCESS) {
114     //
115     // Get the size of the sec platform information2(BSP/APs' BIST data)
116     //
117     InformationSize         = 0;
118     SecPlatformInformation2 = NULL;
119     Status = SecPlatformInformation2Ppi->PlatformInformation2 (
120                                            PeiServices,
121                                            &InformationSize,
122                                            SecPlatformInformation2
123                                            );
124     if (Status == EFI_BUFFER_TOO_SMALL) {
125       Status = PeiServicesAllocatePool (
126                  (UINTN) InformationSize,
127                  (VOID **) &SecPlatformInformation2
128                  );
129       if (Status == EFI_SUCCESS) {
130         //
131         // Retrieve BIST data
132         //
133         Status = SecPlatformInformation2Ppi->PlatformInformation2 (
134                                                PeiServices,
135                                                &InformationSize,
136                                                SecPlatformInformation2
137                                                );
138         if (Status == EFI_SUCCESS) {
139           *BistInformationData = SecPlatformInformation2;
140           if (BistInformationSize != NULL) {
141             *BistInformationSize = InformationSize;
142           }
143           return EFI_SUCCESS;
144         }
145       }
146     }
147   }
148 
149   return EFI_DEVICE_ERROR;
150 }
151 
152 /**
153   Collects BIST data from PPI.
154 
155   This function collects BIST data from Sec Platform Information2 PPI
156   or SEC Platform Information PPI.
157 
158   @param PeiServices         Pointer to PEI Services Table
159 
160 **/
161 VOID
CollectBistDataFromPpi(IN CONST EFI_PEI_SERVICES ** PeiServices)162 CollectBistDataFromPpi (
163   IN CONST EFI_PEI_SERVICES             **PeiServices
164   )
165 {
166   EFI_STATUS                            Status;
167   EFI_PEI_PPI_DESCRIPTOR                *SecInformationDescriptor;
168   EFI_SEC_PLATFORM_INFORMATION_RECORD2  *SecPlatformInformation2;
169   EFI_SEC_PLATFORM_INFORMATION_RECORD   *SecPlatformInformation;
170   UINTN                                 NumberOfData;
171   EFI_SEC_PLATFORM_INFORMATION_CPU      *CpuInstance;
172   EFI_SEC_PLATFORM_INFORMATION_CPU      BspCpuInstance;
173   UINTN                                 ProcessorNumber;
174   UINTN                                 CpuIndex;
175   EFI_PROCESSOR_INFORMATION             ProcessorInfo;
176   EFI_HEALTH_FLAGS                      BistData;
177   UINTN                                 NumberOfProcessors;
178   UINTN                                 NumberOfEnabledProcessors;
179   UINTN                                 BistInformationSize;
180   EFI_SEC_PLATFORM_INFORMATION_RECORD2  *PlatformInformationRecord2;
181   EFI_SEC_PLATFORM_INFORMATION_CPU      *CpuInstanceInHob;
182 
183 
184   MpInitLibGetNumberOfProcessors(&NumberOfProcessors, &NumberOfEnabledProcessors);
185 
186   BistInformationSize = sizeof (EFI_SEC_PLATFORM_INFORMATION_RECORD2) +
187                         sizeof (EFI_SEC_PLATFORM_INFORMATION_CPU) * NumberOfProcessors;
188   Status = PeiServicesAllocatePool (
189              (UINTN) BistInformationSize,
190              (VOID **) &PlatformInformationRecord2
191              );
192   ASSERT_EFI_ERROR (Status);
193   PlatformInformationRecord2->NumberOfCpus = (UINT32)NumberOfProcessors;
194 
195   SecPlatformInformation2 = NULL;
196   SecPlatformInformation  = NULL;
197   NumberOfData            = 0;
198   CpuInstance             = NULL;
199   //
200   // Get BIST information from Sec Platform Information2 Ppi firstly
201   //
202   Status = GetBistInfoFromPpi (
203              PeiServices,
204              &gEfiSecPlatformInformation2PpiGuid,
205              &SecInformationDescriptor,
206              (VOID *) &SecPlatformInformation2,
207              NULL
208              );
209   if (Status == EFI_SUCCESS) {
210     //
211     // Sec Platform Information2 PPI includes BSP/APs' BIST information
212     //
213     NumberOfData = SecPlatformInformation2->NumberOfCpus;
214     CpuInstance  = SecPlatformInformation2->CpuInstance;
215   } else {
216     //
217     // Otherwise, get BIST information from Sec Platform Information Ppi
218     //
219     Status = GetBistInfoFromPpi (
220                PeiServices,
221                &gEfiSecPlatformInformationPpiGuid,
222                &SecInformationDescriptor,
223                (VOID *) &SecPlatformInformation,
224                NULL
225                );
226     if (Status == EFI_SUCCESS) {
227       NumberOfData = 1;
228       //
229       // SEC Platform Information only includes BSP's BIST information
230       // and does not have BSP's APIC ID
231       //
232       BspCpuInstance.CpuLocation = GetInitialApicId ();
233       BspCpuInstance.InfoRecord.IA32HealthFlags.Uint32  = SecPlatformInformation->IA32HealthFlags.Uint32;
234       CpuInstance = &BspCpuInstance;
235     } else {
236       DEBUG ((EFI_D_INFO, "Does not find any stored CPU BIST information from PPI!\n"));
237     }
238   }
239   for (ProcessorNumber = 0; ProcessorNumber < NumberOfProcessors; ProcessorNumber ++) {
240     MpInitLibGetProcessorInfo (ProcessorNumber, &ProcessorInfo, &BistData);
241     for (CpuIndex = 0; CpuIndex < NumberOfData; CpuIndex ++) {
242       ASSERT (CpuInstance != NULL);
243       if (ProcessorInfo.ProcessorId == CpuInstance[CpuIndex].CpuLocation) {
244         //
245         // Update processor's BIST data if it is already stored before
246         //
247         BistData = CpuInstance[CpuIndex].InfoRecord.IA32HealthFlags;
248       }
249     }
250     if (BistData.Uint32 != 0) {
251       //
252       // Report Status Code that self test is failed
253       //
254       REPORT_STATUS_CODE (
255         EFI_ERROR_CODE | EFI_ERROR_MAJOR,
256         (EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_EC_SELF_TEST)
257         );
258     }
259     DEBUG ((EFI_D_INFO, "  APICID - 0x%08x, BIST - 0x%08x\n",
260             (UINT32) ProcessorInfo.ProcessorId,
261             BistData
262             ));
263     CpuInstanceInHob = PlatformInformationRecord2->CpuInstance;
264     CpuInstanceInHob[ProcessorNumber].CpuLocation = (UINT32) ProcessorInfo.ProcessorId;
265     CpuInstanceInHob[ProcessorNumber].InfoRecord.IA32HealthFlags = BistData;
266   }
267 
268   //
269   // Build SecPlatformInformation2 PPI GUIDed HOB that also could be consumed
270   // by CPU MP driver to get CPU BIST data
271   //
272   BuildGuidDataHob (
273     &gEfiSecPlatformInformation2PpiGuid,
274     PlatformInformationRecord2,
275     (UINTN) BistInformationSize
276     );
277 
278   if (SecPlatformInformation2 != NULL && NumberOfData < NumberOfProcessors) {
279     //
280     // Reinstall SecPlatformInformation2 PPI to include new BIST information
281     //
282     Status = PeiServicesReInstallPpi (
283                SecInformationDescriptor,
284                &mPeiSecPlatformInformation2Ppi
285                );
286     ASSERT_EFI_ERROR (Status);
287   } else {
288     //
289     // Install SecPlatformInformation2 PPI to include new BIST information
290     //
291     Status = PeiServicesInstallPpi (&mPeiSecPlatformInformation2Ppi);
292     ASSERT_EFI_ERROR(Status);
293   }
294 }
295 
296