28714365a67b11a36a997bc719378fdf5fd97c2c
[people/mcb30/edk2.git] / edk2 / EdkModulePkg / Universal / StatusCode / Dxe / DataHubStatusCodeWorker.c
1 /** @file\r
2   Data Hub status code worker in DXE.\r
3 \r
4   Copyright (c) 2006, Intel Corporation                                                         \r
5   All rights reserved. This program and the accompanying materials                          \r
6   are licensed and made available under the terms and conditions of the BSD License         \r
7   which accompanies this distribution.  The full text of the license may be found at        \r
8   http://opensource.org/licenses/bsd-license.php                                            \r
9                                                                                             \r
10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
12 \r
13   Module Name:  DataHubStatusCodeWorker.c\r
14 \r
15 **/\r
16 #include "DxeStatusCode.h"\r
17 \r
18 //\r
19 // Initialize FIFO to cache records.\r
20 //\r
21 STATIC\r
22 LIST_ENTRY                mRecordsFifo          = INITIALIZE_LIST_HEAD_VARIABLE (mRecordsFifo);\r
23 STATIC\r
24 LIST_ENTRY                mRecordsBuffer        = INITIALIZE_LIST_HEAD_VARIABLE (mRecordsBuffer);\r
25 STATIC\r
26 EFI_EVENT                 mLogDataHubEvent;\r
27 //\r
28 // Cache data hub protocol.\r
29 //\r
30 STATIC\r
31 EFI_DATA_HUB_PROTOCOL     *mDataHubProtocol;\r
32 \r
33 \r
34 /**\r
35   Return one DATAHUB_STATUSCODE_RECORD space.\r
36   The size of free record pool would be extend, if the pool is empty. \r
37 \r
38  \r
39   @retval  NULL   Can not allocate free memeory for record.\r
40   @retval  !NULL  Point to buffer of record.\r
41 \r
42 **/\r
43 DATAHUB_STATUSCODE_RECORD *\r
44 AcquireRecordBuffer (\r
45   VOID\r
46   )\r
47 {\r
48   DATAHUB_STATUSCODE_RECORD *Record;\r
49   EFI_TPL                   CurrentTpl;\r
50   LIST_ENTRY                *Node;\r
51   UINT32                    Index;\r
52 \r
53   CurrentTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL);\r
54 \r
55   if (!IsListEmpty (&mRecordsBuffer)) {\r
56     Node = GetFirstNode (&mRecordsBuffer);\r
57     RemoveEntryList (Node);\r
58 \r
59     Record = CR (Node, DATAHUB_STATUSCODE_RECORD, Node, DATAHUB_STATUS_CODE_SIGNATURE);\r
60   } else {\r
61     if (CurrentTpl > EFI_TPL_NOTIFY) {\r
62       gBS->RestoreTPL (CurrentTpl);\r
63       return NULL;\r
64     }\r
65 \r
66     gBS->RestoreTPL (CurrentTpl);\r
67     Record   = (DATAHUB_STATUSCODE_RECORD *) AllocateZeroPool (sizeof (DATAHUB_STATUSCODE_RECORD) * 16);\r
68     if (NULL == Record) {\r
69       return NULL;\r
70     }\r
71 \r
72     CurrentTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL);\r
73     for (Index = 1; Index < 16; Index++) {\r
74       InsertTailList (&mRecordsBuffer, &Record[Index].Node);\r
75     }\r
76   }\r
77 \r
78   Record->Signature = DATAHUB_STATUS_CODE_SIGNATURE;\r
79   InsertTailList (&mRecordsFifo, &Record->Node);\r
80 \r
81   gBS->RestoreTPL (CurrentTpl);\r
82 \r
83   return Record;\r
84 }\r
85 \r
86 \r
87 /**\r
88   Release a mRecordBuffer entry allocated by AcquirRecordBuffer ().\r
89 \r
90   @param   Record        Point to record buffer which is acquired by AcquirRecordBuffer()\r
91  \r
92 **/\r
93 VOID\r
94 FreeRecordBuffer (\r
95   IN  DATAHUB_STATUSCODE_RECORD  *Record\r
96   )\r
97 {\r
98   EFI_TPL  CurrentTpl;\r
99 \r
100   ASSERT (Record != NULL);\r
101 \r
102   CurrentTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL);\r
103 \r
104   RemoveEntryList (&Record->Node);\r
105   InsertTailList (&mRecordsBuffer, &Record->Node);\r
106 \r
107   gBS->RestoreTPL (CurrentTpl);\r
108 }\r
109 \r
110 \r
111 /**\r
112   Report status code into DataHub.\r
113  \r
114   @param  CodeType      Indicates the type of status code being reported.  Type EFI_STATUS_CODE_TYPE is defined in "Related Definitions" below.\r
115  \r
116   @param  Value         Describes the current status of a hardware or software entity.  \r
117                         This included information about the class and subclass that is used to classify the entity \r
118                         as well as an operation.  For progress codes, the operation is the current activity. \r
119                         For error codes, it is the exception.  For debug codes, it is not defined at this time. \r
120                         Type EFI_STATUS_CODE_VALUE is defined in "Related Definitions" below.  \r
121                         Specific values are discussed in the Intel? Platform Innovation Framework for EFI Status Code Specification.\r
122  \r
123   @param  Instance      The enumeration of a hardware or software entity within the system.  \r
124                         A system may contain multiple entities that match a class/subclass pairing. \r
125                         The instance differentiates between them.  An instance of 0 indicates that instance information is unavailable, \r
126                         not meaningful, or not relevant.  Valid instance numbers start with 1.\r
127 \r
128 \r
129   @param  CallerId      This optional parameter may be used to identify the caller. \r
130                         This parameter allows the status code driver to apply different rules to different callers. \r
131                         Type EFI_GUID is defined in InstallProtocolInterface() in the EFI 1.10 Specification.\r
132 \r
133 \r
134   @param  Data          This optional parameter may be used to pass additional data\r
135  \r
136   @retval EFI_OUT_OF_RESOURCES   Can not acquire record buffer.\r
137   @retval EFI_DEVICE_ERROR       EFI serial device can not work after ExitBootService() is called .\r
138   @retval EFI_SUCCESS            Success to cache status code and signal log data event.\r
139 \r
140 **/\r
141 EFI_STATUS\r
142 DataHubStatusCodeReportWorker (\r
143   IN EFI_STATUS_CODE_TYPE     CodeType,\r
144   IN EFI_STATUS_CODE_VALUE    Value,\r
145   IN UINT32                   Instance,\r
146   IN EFI_GUID                 *CallerId,\r
147   IN EFI_STATUS_CODE_DATA     *Data OPTIONAL\r
148   )\r
149 {\r
150   DATAHUB_STATUSCODE_RECORD  *Record;\r
151   UINT32                     ErrorLevel;\r
152   VA_LIST                    Marker;\r
153   CHAR8                      *Format;\r
154   UINTN                      CharCount;\r
155 \r
156   //\r
157   // See whether in runtime phase or not.\r
158   //\r
159   if (EfiAtRuntime ()) {\r
160     return EFI_DEVICE_ERROR;\r
161   }\r
162 \r
163   Record = AcquireRecordBuffer ();\r
164   if (Record == NULL) {\r
165     //\r
166     // There are no empty record buffer in private buffers\r
167     //\r
168     return EFI_OUT_OF_RESOURCES;\r
169   }\r
170   //\r
171   // Construct Data Hub Extended Data\r
172   //\r
173   Record->CodeType = CodeType;\r
174   Record->Value    = Value;\r
175   Record->Instance = Instance;\r
176 \r
177   if (CallerId != NULL) {\r
178     CopyMem (&Record->CallerId, CallerId, sizeof (EFI_GUID));\r
179   }\r
180 \r
181   if (Data != NULL) {\r
182     if (ReportStatusCodeExtractDebugInfo (Data, &ErrorLevel, &Marker, &Format)) {\r
183       CharCount = UnicodeVSPrintAsciiFormat (\r
184                     (CHAR16 *) Record->ExtendData,\r
185                     EFI_STATUS_CODE_DATA_MAX_SIZE,\r
186                     Format,\r
187                     Marker\r
188                     );\r
189       //\r
190       // Change record data type from DebugType to String Type.\r
191       //\r
192       CopyGuid (&Record->Data.Type, &gEfiStatusCodeDataTypeStringGuid);\r
193       Record->Data.HeaderSize = Data->HeaderSize;\r
194       Record->Data.Size = (UINT16) ((CharCount + 1) * sizeof (CHAR16));\r
195     } else {\r
196       //\r
197       // Copy status code data header\r
198       //\r
199       CopyMem (&Record->Data, Data, sizeof (EFI_STATUS_CODE_DATA));\r
200 \r
201       if (Data->Size > EFI_STATUS_CODE_DATA_MAX_SIZE) {\r
202         Record->Data.Size = EFI_STATUS_CODE_DATA_MAX_SIZE;\r
203       } \r
204       CopyMem (Record->ExtendData, Data + 1, Record->Data.Size);\r
205     }\r
206   }\r
207 \r
208   gBS->SignalEvent (mLogDataHubEvent);\r
209 \r
210   return EFI_SUCCESS;\r
211 }\r
212 \r
213 \r
214 /**\r
215   The Event handler which will be notified to log data in Data Hub.\r
216 \r
217   @param  Event       Instance of the EFI_EVENT to signal whenever data is\r
218                       available to be logged in the system.\r
219   @param  Context     Context of the event.\r
220 \r
221 **/\r
222 VOID\r
223 EFIAPI\r
224 LogDataHubEventCallBack (\r
225   IN  EFI_EVENT     Event,\r
226   IN  VOID          *Context\r
227   )\r
228 {\r
229   DATAHUB_STATUSCODE_RECORD         *Record;\r
230   UINT32                            Size;\r
231   UINT64                            DataRecordClass;\r
232   LIST_ENTRY                        *Node;\r
233   EFI_TPL                           CurrentTpl;\r
234 \r
235   //\r
236   // Log DataRecord in Data Hub.\r
237   // Journal records fifo to find all record entry.\r
238   //\r
239   //\r
240   CurrentTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL);\r
241 \r
242   for (Node = mRecordsFifo.ForwardLink; Node != &mRecordsFifo;) {\r
243     Record = CR (Node, DATAHUB_STATUSCODE_RECORD, Node, DATAHUB_STATUS_CODE_SIGNATURE);\r
244     Node   = Node->ForwardLink;\r
245 \r
246     //\r
247     // Add in the size of the header we added.\r
248     //\r
249     Size = sizeof (DATAHUB_STATUSCODE_RECORD) + (UINT32) Record->Data.Size;\r
250 \r
251     if ((Record->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) {\r
252       DataRecordClass = EFI_DATA_RECORD_CLASS_PROGRESS_CODE;\r
253     } else if ((Record->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) {\r
254       DataRecordClass = EFI_DATA_RECORD_CLASS_ERROR;\r
255     } else if ((Record->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE) {\r
256       DataRecordClass = EFI_DATA_RECORD_CLASS_DEBUG;\r
257     } else {\r
258       //\r
259       // Should never get here.\r
260       //\r
261       DataRecordClass = EFI_DATA_RECORD_CLASS_DEBUG |\r
262         EFI_DATA_RECORD_CLASS_ERROR |\r
263         EFI_DATA_RECORD_CLASS_DATA |\r
264         EFI_DATA_RECORD_CLASS_PROGRESS_CODE;\r
265     }\r
266 \r
267     //\r
268     // Log DataRecord in Data Hub\r
269     //\r
270     \r
271     mDataHubProtocol->LogData (\r
272                         mDataHubProtocol,\r
273                         &gEfiStatusCodeGuid,\r
274                         &gEfiStatusCodeRuntimeProtocolGuid,\r
275                         DataRecordClass,\r
276                         Record,\r
277                         Size\r
278                         );\r
279 \r
280 \r
281 \r
282     FreeRecordBuffer (Record);\r
283   }\r
284 \r
285   gBS->RestoreTPL (CurrentTpl);\r
286 }\r
287 \r
288 \r
289 /**\r
290   Initialize data hubstatus code.\r
291   Create a data hub listener.\r
292  \r
293   @return  The function always return EFI_SUCCESS\r
294 \r
295 **/\r
296 EFI_STATUS\r
297 DataHubStatusCodeInitializeWorker (\r
298   VOID\r
299   )\r
300 {\r
301   EFI_STATUS  Status;\r
302 \r
303   Status = gBS->LocateProtocol (\r
304                   &gEfiDataHubProtocolGuid, \r
305                   NULL, \r
306                   (VOID **) &mDataHubProtocol\r
307                   );\r
308   ASSERT_EFI_ERROR (Status);\r
309 \r
310   //\r
311   // Create a Notify Event to log data in Data Hub\r
312   //\r
313   Status = gBS->CreateEvent (\r
314                   EFI_EVENT_NOTIFY_SIGNAL,\r
315                   EFI_TPL_CALLBACK,\r
316                   LogDataHubEventCallBack,\r
317                   NULL,\r
318                   &mLogDataHubEvent\r
319                   );\r
320 \r
321   ASSERT_EFI_ERROR (Status);\r
322 \r
323   return EFI_SUCCESS;\r
324 }\r
325 \r
326 \r