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