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