1 /** @file
2   Status code driver for IA32/X64/EBC architecture.
3 
4   Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5   SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "StatusCodeRuntimeDxe.h"
10 
11 EFI_EVENT    mVirtualAddressChangeEvent = NULL;
12 EFI_HANDLE   mHandle = NULL;
13 
14 //
15 // Declaration of status code protocol.
16 //
17 EFI_STATUS_CODE_PROTOCOL  mEfiStatusCodeProtocol  = {
18   ReportDispatcher
19 };
20 
21 //
22 // Report operation nest status.
23 // If it is set, then the report operation has nested.
24 //
25 UINT32  mStatusCodeNestStatus = 0;
26 
27 /**
28   Entry point of DXE Status Code Driver.
29 
30   This function is the entry point of this DXE Status Code Driver.
31   It installs Status Code Runtime Protocol, and registers event for EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
32 
33   @param  ImageHandle       The firmware allocated handle for the EFI image.
34   @param  SystemTable       A pointer to the EFI System Table.
35 
36   @retval EFI_SUCCESS       The entry point is executed successfully.
37 
38 **/
39 EFI_STATUS
40 EFIAPI
StatusCodeRuntimeDxeEntry(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)41 StatusCodeRuntimeDxeEntry (
42   IN EFI_HANDLE         ImageHandle,
43   IN EFI_SYSTEM_TABLE   *SystemTable
44   )
45 {
46   EFI_STATUS  Status;
47 
48   //
49   // Dispatch initialization request to supported devices
50   //
51   InitializationDispatcherWorker ();
52 
53   //
54   // Install Status Code Runtime Protocol implementation as defined in PI Specification.
55   //
56   Status = gBS->InstallMultipleProtocolInterfaces (
57                   &mHandle,
58                   &gEfiStatusCodeRuntimeProtocolGuid,
59                   &mEfiStatusCodeProtocol,
60                   NULL
61                   );
62   ASSERT_EFI_ERROR (Status);
63 
64   Status = gBS->CreateEventEx (
65                   EVT_NOTIFY_SIGNAL,
66                   TPL_NOTIFY,
67                   VirtualAddressChangeCallBack,
68                   NULL,
69                   &gEfiEventVirtualAddressChangeGuid,
70                   &mVirtualAddressChangeEvent
71                   );
72   ASSERT_EFI_ERROR (Status);
73 
74   return EFI_SUCCESS;
75 }
76 
77 /**
78   Report status code to all supported device.
79 
80   This function implements EFI_STATUS_CODE_PROTOCOL.ReportStatusCode().
81   It calls into the workers which dispatches the platform specific listeners.
82 
83   @param  CodeType         Indicates the type of status code being reported.
84   @param  Value            Describes the current status of a hardware or software entity.
85                            This included information about the class and subclass that is used to
86                            classify the entity as well as an operation.
87   @param  Instance         The enumeration of a hardware or software entity within
88                            the system. Valid instance numbers start with 1.
89   @param  CallerId         This optional parameter may be used to identify the caller.
90                            This parameter allows the status code driver to apply different rules to
91                            different callers.
92   @param  Data             This optional parameter may be used to pass additional data.
93 
94   @retval EFI_SUCCESS      The function completed successfully
95   @retval EFI_DEVICE_ERROR The function should not be completed due to a device error.
96 
97 **/
98 EFI_STATUS
99 EFIAPI
ReportDispatcher(IN EFI_STATUS_CODE_TYPE CodeType,IN EFI_STATUS_CODE_VALUE Value,IN UINT32 Instance,IN EFI_GUID * CallerId OPTIONAL,IN EFI_STATUS_CODE_DATA * Data OPTIONAL)100 ReportDispatcher (
101   IN EFI_STATUS_CODE_TYPE     CodeType,
102   IN EFI_STATUS_CODE_VALUE    Value,
103   IN UINT32                   Instance,
104   IN EFI_GUID                 *CallerId  OPTIONAL,
105   IN EFI_STATUS_CODE_DATA     *Data      OPTIONAL
106   )
107 {
108   //
109   // Use atom operation to avoid the reentant of report.
110   // If current status is not zero, then the function is reentrancy.
111   //
112   if (InterlockedCompareExchange32 (&mStatusCodeNestStatus, 0, 1) == 1) {
113     return EFI_DEVICE_ERROR;
114   }
115 
116   if (FeaturePcdGet (PcdStatusCodeUseSerial)) {
117     SerialStatusCodeReportWorker (
118       CodeType,
119       Value,
120       Instance,
121       CallerId,
122       Data
123       );
124   }
125   if (FeaturePcdGet (PcdStatusCodeUseMemory)) {
126     RtMemoryStatusCodeReportWorker (
127       CodeType,
128       Value,
129       Instance
130       );
131   }
132   if (FeaturePcdGet (PcdStatusCodeUseDataHub)) {
133     DataHubStatusCodeReportWorker (
134       CodeType,
135       Value,
136       Instance,
137       CallerId,
138       Data
139       );
140   }
141   if (FeaturePcdGet (PcdStatusCodeUseOEM)) {
142     //
143     // Call OEM hook status code library API to report status code to OEM device
144     //
145     OemHookStatusCodeReport (
146       CodeType,
147       Value,
148       Instance,
149       CallerId,
150       Data
151       );
152   }
153 
154   //
155   // Restore the nest status of report
156   //
157   InterlockedCompareExchange32 (&mStatusCodeNestStatus, 1, 0);
158 
159   return EFI_SUCCESS;
160 }
161 
162 
163 /**
164   Virtual address change notification call back. It converts global pointer
165   to virtual address.
166 
167   @param  Event         Event whose notification function is being invoked.
168   @param  Context       Pointer to the notification function's context, which is
169                         always zero in current implementation.
170 
171 **/
172 VOID
173 EFIAPI
VirtualAddressChangeCallBack(IN EFI_EVENT Event,IN VOID * Context)174 VirtualAddressChangeCallBack (
175   IN EFI_EVENT        Event,
176   IN VOID             *Context
177   )
178 {
179   //
180   // Convert memory status code table to virtual address;
181   //
182   EfiConvertPointer (
183     0,
184     (VOID **) &mRtMemoryStatusCodeTable
185     );
186 }
187 
188 /**
189   Dispatch initialization request to sub status code devices based on
190   customized feature flags.
191 
192 **/
193 VOID
InitializationDispatcherWorker(VOID)194 InitializationDispatcherWorker (
195   VOID
196   )
197 {
198   EFI_PEI_HOB_POINTERS              Hob;
199   EFI_STATUS                        Status;
200   MEMORY_STATUSCODE_PACKET_HEADER   *PacketHeader;
201   MEMORY_STATUSCODE_RECORD          *Record;
202   UINTN                             Index;
203   UINTN                             MaxRecordNumber;
204 
205   //
206   // If enable UseSerial, then initialize serial port.
207   // if enable UseRuntimeMemory, then initialize runtime memory status code worker.
208   // if enable UseDataHub, then initialize data hub status code worker.
209   //
210   if (FeaturePcdGet (PcdStatusCodeUseSerial)) {
211     //
212     // Call Serial Port Lib API to initialize serial port.
213     //
214     Status = SerialPortInitialize ();
215     ASSERT_EFI_ERROR (Status);
216   }
217   if (FeaturePcdGet (PcdStatusCodeUseMemory)) {
218     Status = RtMemoryStatusCodeInitializeWorker ();
219     ASSERT_EFI_ERROR (Status);
220   }
221   if (FeaturePcdGet (PcdStatusCodeUseDataHub)) {
222     DataHubStatusCodeInitializeWorker ();
223   }
224   if (FeaturePcdGet (PcdStatusCodeUseOEM)) {
225     //
226     // Call OEM hook status code library API to initialize OEM device for status code.
227     //
228     Status = OemHookStatusCodeInitialize ();
229     ASSERT_EFI_ERROR (Status);
230   }
231 
232   //
233   // Replay Status code which saved in GUID'ed HOB to all supported devices.
234   //
235   if (FeaturePcdGet (PcdStatusCodeReplayIn)) {
236     //
237     // Journal GUID'ed HOBs to find all record entry, if found,
238     // then output record to support replay device.
239     //
240     Hob.Raw   = GetFirstGuidHob (&gMemoryStatusCodeRecordGuid);
241     if (Hob.Raw != NULL) {
242       PacketHeader = (MEMORY_STATUSCODE_PACKET_HEADER *) GET_GUID_HOB_DATA (Hob.Guid);
243       Record = (MEMORY_STATUSCODE_RECORD *) (PacketHeader + 1);
244       MaxRecordNumber = (UINTN) PacketHeader->RecordIndex;
245       if (PacketHeader->PacketIndex > 0) {
246         //
247         // Record has been wrapped around. So, record number has arrived at max number.
248         //
249         MaxRecordNumber = (UINTN) PacketHeader->MaxRecordsNumber;
250       }
251       for (Index = 0; Index < MaxRecordNumber; Index++) {
252         //
253         // Dispatch records to devices based on feature flag.
254         //
255         if (FeaturePcdGet (PcdStatusCodeUseSerial)) {
256           SerialStatusCodeReportWorker (
257             Record[Index].CodeType,
258             Record[Index].Value,
259             Record[Index].Instance,
260             NULL,
261             NULL
262             );
263         }
264         if (FeaturePcdGet (PcdStatusCodeUseMemory)) {
265           RtMemoryStatusCodeReportWorker (
266             Record[Index].CodeType,
267             Record[Index].Value,
268             Record[Index].Instance
269             );
270         }
271         if (FeaturePcdGet (PcdStatusCodeUseDataHub)) {
272           DataHubStatusCodeReportWorker (
273             Record[Index].CodeType,
274             Record[Index].Value,
275             Record[Index].Instance,
276             NULL,
277             NULL
278             );
279         }
280         if (FeaturePcdGet (PcdStatusCodeUseOEM)) {
281           //
282           // Call OEM hook status code library API to report status code to OEM device
283           //
284           OemHookStatusCodeReport (
285             Record[Index].CodeType,
286             Record[Index].Value,
287             Record[Index].Instance,
288             NULL,
289             NULL
290             );
291         }
292       }
293     }
294   }
295 }
296