]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Universal/StatusCode/Dxe/DataHubStatusCodeWorker.c
Change _CR() to BASE_CR() to follow naming convention
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / StatusCode / Dxe / DataHubStatusCodeWorker.c
1 /** @file
2 Data Hub status code worker in DXE.
3
4 Copyright (c) 2006, Intel Corporation
5 All rights reserved. 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 "DxeStatusCode.h"
16
17 //
18 // Initialize FIFO to cache records.
19 //
20 LIST_ENTRY mRecordsFifo = INITIALIZE_LIST_HEAD_VARIABLE (mRecordsFifo);
21 LIST_ENTRY mRecordsBuffer = INITIALIZE_LIST_HEAD_VARIABLE (mRecordsBuffer);
22 UINT32 mLogDataHubStatus = 0;
23 EFI_EVENT mLogDataHubEvent;
24 //
25 // Cache data hub protocol.
26 //
27 EFI_DATA_HUB_PROTOCOL *mDataHubProtocol;
28
29
30 /**
31 Return one DATAHUB_STATUSCODE_RECORD space.
32 The size of free record pool would be extend, if the pool is empty.
33
34
35 @retval NULL Can not allocate free memeory for record.
36 @retval !NULL Point to buffer of record.
37
38 **/
39 DATA_HUB_STATUS_CODE_DATA_RECORD *
40 AcquireRecordBuffer (
41 VOID
42 )
43 {
44 DATAHUB_STATUSCODE_RECORD *Record;
45 EFI_TPL CurrentTpl;
46 LIST_ENTRY *Node;
47 UINT32 Index;
48
49 CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
50
51 if (!IsListEmpty (&mRecordsBuffer)) {
52 Node = GetFirstNode (&mRecordsBuffer);
53 RemoveEntryList (Node);
54
55 Record = BASE_CR (Node, DATAHUB_STATUSCODE_RECORD, Node);
56 } else {
57 if (CurrentTpl > TPL_NOTIFY) {
58 //
59 // Memory management should work at <=TPL_NOTIFY
60 //
61 gBS->RestoreTPL (CurrentTpl);
62 return NULL;
63 }
64
65 gBS->RestoreTPL (CurrentTpl);
66 Record = (DATAHUB_STATUSCODE_RECORD *) AllocateZeroPool (sizeof (DATAHUB_STATUSCODE_RECORD) * 16);
67 if (NULL == Record) {
68 return NULL;
69 }
70
71 CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
72 for (Index = 1; Index < 16; Index++) {
73 InsertTailList (&mRecordsBuffer, &Record[Index].Node);
74 }
75 }
76
77 Record->Signature = DATAHUB_STATUS_CODE_SIGNATURE;
78 InsertTailList (&mRecordsFifo, &Record->Node);
79
80 gBS->RestoreTPL (CurrentTpl);
81
82 return (DATA_HUB_STATUS_CODE_DATA_RECORD *) (Record->Data);
83 }
84
85
86 /**
87 Retrieve one record from Records FIFO. The record would be removed from FIFO and
88 release to free record buffer.
89
90 @return !NULL Point to record, which is ready to be logged.
91 @return NULL the FIFO of record is empty.
92
93 **/
94 DATA_HUB_STATUS_CODE_DATA_RECORD *
95 RetrieveRecord (
96 VOID
97 )
98 {
99 DATA_HUB_STATUS_CODE_DATA_RECORD *RecordData = NULL;
100 DATAHUB_STATUSCODE_RECORD *Record;
101 LIST_ENTRY *Node;
102 EFI_TPL CurrentTpl;
103
104 CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
105
106 if (!IsListEmpty (&mRecordsFifo)) {
107 Node = GetFirstNode (&mRecordsFifo);
108 Record = CR (Node, DATAHUB_STATUSCODE_RECORD, Node, DATAHUB_STATUS_CODE_SIGNATURE);
109 ASSERT (NULL != Record);
110
111 RemoveEntryList (&Record->Node);
112 RecordData = (DATA_HUB_STATUS_CODE_DATA_RECORD *) Record->Data;
113 }
114
115 gBS->RestoreTPL (CurrentTpl);
116
117 return RecordData;
118 }
119
120 /**
121 Release Records to FIFO.
122
123 @param RecordData Point to the record buffer allocated
124 from AcquireRecordBuffer.
125
126 **/
127 VOID
128 ReleaseRecord (
129 DATA_HUB_STATUS_CODE_DATA_RECORD *RecordData
130 )
131 {
132 DATAHUB_STATUSCODE_RECORD *Record;
133 EFI_TPL CurrentTpl;
134
135 Record = CR (RecordData, DATAHUB_STATUSCODE_RECORD, Data[0], DATAHUB_STATUS_CODE_SIGNATURE);
136 ASSERT (NULL != Record);
137
138 CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
139
140 InsertTailList (&mRecordsBuffer, &Record->Node);
141 Record->Signature = 0;
142
143 gBS->RestoreTPL (CurrentTpl);
144 }
145
146
147
148 /**
149 Report status code into DataHub.
150
151 @param CodeType Indicates the type of status code being reported. Type EFI_STATUS_CODE_TYPE is defined in "Related Definitions" below.
152
153 @param Value Describes the current status of a hardware or software entity.
154 This included information about the class and subclass that is used to classify the entity
155 as well as an operation. For progress codes, the operation is the current activity.
156 For error codes, it is the exception. For debug codes, it is not defined at this time.
157 Type EFI_STATUS_CODE_VALUE is defined in "Related Definitions" below.
158 Specific values are discussed in the Intel? Platform Innovation Framework for EFI Status Code Specification.
159
160 @param Instance The enumeration of a hardware or software entity within the system.
161 A system may contain multiple entities that match a class/subclass pairing.
162 The instance differentiates between them. An instance of 0 indicates that instance information is unavailable,
163 not meaningful, or not relevant. Valid instance numbers start with 1.
164
165
166 @param CallerId This optional parameter may be used to identify the caller.
167 This parameter allows the status code driver to apply different rules to different callers.
168 Type EFI_GUID is defined in InstallProtocolInterface() in the UEFI 2.0 Specification.
169
170
171 @param Data This optional parameter may be used to pass additional data
172
173 @retval EFI_OUT_OF_RESOURCES Can not acquire record buffer.
174 @retval EFI_DEVICE_ERROR EFI serial device can not work after ExitBootService() is called .
175 @retval EFI_SUCCESS Success to cache status code and signal log data event.
176
177 **/
178 EFI_STATUS
179 DataHubStatusCodeReportWorker (
180 IN EFI_STATUS_CODE_TYPE CodeType,
181 IN EFI_STATUS_CODE_VALUE Value,
182 IN UINT32 Instance,
183 IN EFI_GUID *CallerId,
184 IN EFI_STATUS_CODE_DATA *Data OPTIONAL
185 )
186 {
187 DATA_HUB_STATUS_CODE_DATA_RECORD *Record;
188 UINT32 ErrorLevel;
189 VA_LIST Marker;
190 CHAR8 *Format;
191 UINTN CharCount;
192
193
194 //
195 // Use atom operation to avoid the reentant of report.
196 // If current status is not zero, then the function is reentrancy.
197 //
198 if (1 == InterlockedCompareExchange32 (&mLogDataHubStatus, 0, 0)) {
199 return EFI_DEVICE_ERROR;
200 }
201
202 //
203 // See whether in runtime phase or not.
204 //
205 if (EfiAtRuntime ()) {
206 return EFI_DEVICE_ERROR;
207 }
208
209 Record = AcquireRecordBuffer ();
210 if (Record == NULL) {
211 //
212 // There are no empty record buffer in private buffers
213 //
214 return EFI_OUT_OF_RESOURCES;
215 }
216
217 //
218 // Construct Data Hub Extended Data
219 //
220 Record->CodeType = CodeType;
221 Record->Value = Value;
222 Record->Instance = Instance;
223
224 if (CallerId != NULL) {
225 CopyMem (&Record->CallerId, CallerId, sizeof (EFI_GUID));
226 }
227
228 if (Data != NULL) {
229 if (ReportStatusCodeExtractDebugInfo (Data, &ErrorLevel, &Marker, &Format)) {
230 CharCount = UnicodeVSPrintAsciiFormat (
231 (CHAR16 *) (Record + 1),
232 EFI_STATUS_CODE_DATA_MAX_SIZE,
233 Format,
234 Marker
235 );
236 //
237 // Change record data type from DebugType to String Type.
238 //
239 CopyGuid (&Record->Data.Type, &gEfiStatusCodeDataTypeDebugGuid);
240 Record->Data.HeaderSize = Data->HeaderSize;
241 Record->Data.Size = (UINT16) ((CharCount + 1) * sizeof (CHAR16));
242 } else {
243 //
244 // Copy status code data header
245 //
246 CopyMem (&Record->Data, Data, sizeof (EFI_STATUS_CODE_DATA));
247
248 if (Data->Size > EFI_STATUS_CODE_DATA_MAX_SIZE) {
249 Record->Data.Size = EFI_STATUS_CODE_DATA_MAX_SIZE;
250 }
251 CopyMem ((VOID *) (Record + 1), Data + 1, Record->Data.Size);
252 }
253 }
254
255 gBS->SignalEvent (mLogDataHubEvent);
256
257 return EFI_SUCCESS;
258 }
259
260
261 /**
262 The Event handler which will be notified to log data in Data Hub.
263
264 @param Event Instance of the EFI_EVENT to signal whenever data is
265 available to be logged in the system.
266 @param Context Context of the event.
267
268 **/
269 VOID
270 EFIAPI
271 LogDataHubEventCallBack (
272 IN EFI_EVENT Event,
273 IN VOID *Context
274 )
275 {
276 DATA_HUB_STATUS_CODE_DATA_RECORD *Record;
277 UINT32 Size;
278 UINT64 DataRecordClass;
279
280 //
281 // Use atom operation to avoid the reentant of report.
282 // If current status is not zero, then the function is reentrancy.
283 //
284 if (1 == InterlockedCompareExchange32 (&mLogDataHubStatus, 0, 1)) {
285 return;
286 }
287
288 //
289 // Log DataRecord in Data Hub.
290 // Journal records fifo to find all record entry.
291 //
292 while (1) {
293 Record = RetrieveRecord ();
294 if (Record == NULL) {
295 break;
296 }
297 //
298 // Add in the size of the header we added.
299 //
300 Size = sizeof (DATA_HUB_STATUS_CODE_DATA_RECORD) + (UINT32) Record->Data.Size;
301
302 if ((Record->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) {
303 DataRecordClass = EFI_DATA_RECORD_CLASS_PROGRESS_CODE;
304 } else if ((Record->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) {
305 DataRecordClass = EFI_DATA_RECORD_CLASS_ERROR;
306 } else if ((Record->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE) {
307 DataRecordClass = EFI_DATA_RECORD_CLASS_DEBUG;
308 } else {
309 //
310 // Should never get here.
311 //
312 DataRecordClass = EFI_DATA_RECORD_CLASS_DEBUG |
313 EFI_DATA_RECORD_CLASS_ERROR |
314 EFI_DATA_RECORD_CLASS_DATA |
315 EFI_DATA_RECORD_CLASS_PROGRESS_CODE;
316 }
317
318 //
319 // Log DataRecord in Data Hub
320 //
321
322 mDataHubProtocol->LogData (
323 mDataHubProtocol,
324 &gEfiDataHubStatusCodeRecordGuid,
325 &gEfiStatusCodeRuntimeProtocolGuid,
326 DataRecordClass,
327 Record,
328 Size
329 );
330
331 ReleaseRecord (Record);
332 }
333
334 //
335 // Restore the nest status of report
336 //
337 InterlockedCompareExchange32 (&mLogDataHubStatus, 1, 0);
338 }
339
340
341 /**
342 Initialize data hubstatus code.
343 Create a data hub listener.
344
345 @return The function always return EFI_SUCCESS
346
347 **/
348 EFI_STATUS
349 DataHubStatusCodeInitializeWorker (
350 VOID
351 )
352 {
353 EFI_STATUS Status;
354
355 Status = gBS->LocateProtocol (
356 &gEfiDataHubProtocolGuid,
357 NULL,
358 (VOID **) &mDataHubProtocol
359 );
360 ASSERT_EFI_ERROR (Status);
361
362 //
363 // Create a Notify Event to log data in Data Hub
364 //
365 Status = gBS->CreateEvent (
366 EVT_NOTIFY_SIGNAL,
367 TPL_CALLBACK,
368 LogDataHubEventCallBack,
369 NULL,
370 &mLogDataHubEvent
371 );
372
373 ASSERT_EFI_ERROR (Status);
374
375 return EFI_SUCCESS;
376 }
377
378