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   PEI_CPU_MP_DATA                      *PeiCpuMpData;
48   UINTN                                BistInformationSize;
49   UINTN                                CpuIndex;
50   EFI_SEC_PLATFORM_INFORMATION_CPU     *CpuInstance;
51 
52   PeiCpuMpData = GetMpHobData ();
53 
54   BistInformationSize = sizeof (EFI_SEC_PLATFORM_INFORMATION_RECORD2) +
55                         sizeof (EFI_SEC_PLATFORM_INFORMATION_CPU) * PeiCpuMpData->CpuCount;
56   //
57   // return the information size if input buffer size is too small
58   //
59   if ((*StructureSize) < (UINT64) BistInformationSize) {
60     *StructureSize = (UINT64) BistInformationSize;
61     return EFI_BUFFER_TOO_SMALL;
62   }
63 
64   PlatformInformationRecord2->NumberOfCpus = PeiCpuMpData->CpuCount;
65   CpuInstance = PlatformInformationRecord2->CpuInstance;
66   for (CpuIndex = 0; CpuIndex < PeiCpuMpData->CpuCount; CpuIndex ++) {
67     CpuInstance[CpuIndex].CpuLocation                = PeiCpuMpData->CpuData[CpuIndex].ApicId;
68     CpuInstance[CpuIndex].InfoRecord.IA32HealthFlags = PeiCpuMpData->CpuData[CpuIndex].Health;
69   }
70 
71   return EFI_SUCCESS;
72 }
73 
74 /**
75   Worker function to get CPUs' BIST by calling SecPlatformInformationPpi
76   or SecPlatformInformation2Ppi.
77 
78   @param  PeiServices         Pointer to PEI Services Table
79   @param  Guid                PPI Guid
80   @param  PpiDescriptor       Return a pointer to instance of the
81                               EFI_PEI_PPI_DESCRIPTOR
82   @param  BistInformationData Pointer to BIST information data
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)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   )
96 {
97   EFI_STATUS                            Status;
98   EFI_SEC_PLATFORM_INFORMATION2_PPI     *SecPlatformInformation2Ppi;
99   EFI_SEC_PLATFORM_INFORMATION_RECORD2  *SecPlatformInformation2;
100   UINT64                                InformationSize;
101 
102   Status = PeiServicesLocatePpi (
103              Guid,                                // GUID
104              0,                                   // INSTANCE
105              PpiDescriptor,                       // EFI_PEI_PPI_DESCRIPTOR
106              (VOID **)&SecPlatformInformation2Ppi // PPI
107              );
108   if (Status == EFI_NOT_FOUND) {
109     return EFI_NOT_FOUND;
110   }
111 
112   if (Status == EFI_SUCCESS) {
113     //
114     // Get the size of the sec platform information2(BSP/APs' BIST data)
115     //
116     InformationSize         = 0;
117     SecPlatformInformation2 = NULL;
118     Status = SecPlatformInformation2Ppi->PlatformInformation2 (
119                                            PeiServices,
120                                            &InformationSize,
121                                            SecPlatformInformation2
122                                            );
123     if (Status == EFI_BUFFER_TOO_SMALL) {
124       Status = PeiServicesAllocatePool (
125                  (UINTN) InformationSize,
126                  (VOID **) &SecPlatformInformation2
127                  );
128       if (Status == EFI_SUCCESS) {
129         //
130         // Retrieve BIST data
131         //
132         Status = SecPlatformInformation2Ppi->PlatformInformation2 (
133                                                PeiServices,
134                                                &InformationSize,
135                                                SecPlatformInformation2
136                                                );
137         if (Status == EFI_SUCCESS) {
138           *BistInformationData = SecPlatformInformation2;
139           return EFI_SUCCESS;
140         }
141       }
142     }
143   }
144 
145   return EFI_DEVICE_ERROR;
146 }
147 
148 /**
149   Collects BIST data from PPI.
150 
151   This function collects BIST data from Sec Platform Information2 PPI
152   or SEC Platform Information PPI.
153 
154   @param PeiServices         Pointer to PEI Services Table
155   @param PeiCpuMpData        Pointer to PEI CPU MP Data
156 
157 **/
158 VOID
CollectBistDataFromPpi(IN CONST EFI_PEI_SERVICES ** PeiServices,IN PEI_CPU_MP_DATA * PeiCpuMpData)159 CollectBistDataFromPpi (
160   IN CONST EFI_PEI_SERVICES             **PeiServices,
161   IN PEI_CPU_MP_DATA                    *PeiCpuMpData
162   )
163 {
164   EFI_STATUS                            Status;
165   EFI_PEI_PPI_DESCRIPTOR                *SecInformationDescriptor;
166   EFI_SEC_PLATFORM_INFORMATION_RECORD2  *SecPlatformInformation2;
167   EFI_SEC_PLATFORM_INFORMATION_RECORD   *SecPlatformInformation;
168   UINTN                                 NumberOfData;
169   EFI_SEC_PLATFORM_INFORMATION_CPU      *CpuInstance;
170   EFI_SEC_PLATFORM_INFORMATION_CPU      BspCpuInstance;
171   UINTN                                 ProcessorNumber;
172   UINTN                                 CpuIndex;
173   PEI_CPU_DATA                          *CpuData;
174 
175   SecPlatformInformation2 = NULL;
176   SecPlatformInformation  = NULL;
177   NumberOfData            = 0;
178   CpuInstance             = NULL;
179 
180   //
181   // Get BIST information from Sec Platform Information2 Ppi firstly
182   //
183   Status = GetBistInfoFromPpi (
184              PeiServices,
185              &gEfiSecPlatformInformation2PpiGuid,
186              &SecInformationDescriptor,
187              (VOID *) &SecPlatformInformation2
188              );
189   if (Status == EFI_SUCCESS) {
190     //
191     // Sec Platform Information2 PPI includes BSP/APs' BIST information
192     //
193     NumberOfData = SecPlatformInformation2->NumberOfCpus;
194     CpuInstance  = SecPlatformInformation2->CpuInstance;
195   } else {
196     //
197     // Otherwise, get BIST information from Sec Platform Information Ppi
198     //
199     Status = GetBistInfoFromPpi (
200                PeiServices,
201                &gEfiSecPlatformInformationPpiGuid,
202                &SecInformationDescriptor,
203                (VOID *) &SecPlatformInformation
204                );
205     if (Status == EFI_SUCCESS) {
206       NumberOfData = 1;
207       //
208       // SEC Platform Information only includes BSP's BIST information
209       // and does not have BSP's APIC ID
210       //
211       BspCpuInstance.CpuLocation = GetInitialApicId ();
212       BspCpuInstance.InfoRecord.IA32HealthFlags.Uint32  = SecPlatformInformation->IA32HealthFlags.Uint32;
213       CpuInstance = &BspCpuInstance;
214     } else {
215       DEBUG ((EFI_D_INFO, "Does not find any stored CPU BIST information from PPI!\n"));
216     }
217   }
218   for (ProcessorNumber = 0; ProcessorNumber < PeiCpuMpData->CpuCount; ProcessorNumber ++) {
219     CpuData = &PeiCpuMpData->CpuData[ProcessorNumber];
220     for (CpuIndex = 0; CpuIndex < NumberOfData; CpuIndex ++) {
221       ASSERT (CpuInstance != NULL);
222       if (CpuData->ApicId == CpuInstance[CpuIndex].CpuLocation) {
223         //
224         // Update processor's BIST data if it is already stored before
225         //
226         CpuData->Health = CpuInstance[CpuIndex].InfoRecord.IA32HealthFlags;
227       }
228     }
229     if (CpuData->Health.Uint32 == 0) {
230       CpuData->CpuHealthy = TRUE;
231     } else {
232       CpuData->CpuHealthy = FALSE;
233       //
234       // Report Status Code that self test is failed
235       //
236       REPORT_STATUS_CODE (
237         EFI_ERROR_CODE | EFI_ERROR_MAJOR,
238         (EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_EC_SELF_TEST)
239         );
240     }
241     DEBUG ((EFI_D_INFO, "  APICID - 0x%08x, BIST - 0x%08x\n",
242             PeiCpuMpData->CpuData[ProcessorNumber].ApicId,
243             PeiCpuMpData->CpuData[ProcessorNumber].Health.Uint32
244             ));
245   }
246 
247   if (SecPlatformInformation2 != NULL && NumberOfData < PeiCpuMpData->CpuCount) {
248     //
249     // Reinstall SecPlatformInformation2 PPI to include new BIST inforamtion
250     //
251     Status = PeiServicesReInstallPpi (
252                SecInformationDescriptor,
253                &mPeiSecPlatformInformation2Ppi
254                );
255     ASSERT_EFI_ERROR (Status);
256   } else {
257     //
258     // Install SecPlatformInformation2 PPI to include new BIST inforamtion
259     //
260     Status = PeiServicesInstallPpi (&mPeiSecPlatformInformation2Ppi);
261     ASSERT_EFI_ERROR(Status);
262   }
263 }
264