]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Library/EdkRuntimeStatusCodeLib/BsDataHubStatusCode/BsDataHubStatusCode.c
1. Updated function headers in all assembly files.
[mirror_edk2.git] / EdkModulePkg / Library / EdkRuntimeStatusCodeLib / BsDataHubStatusCode / BsDataHubStatusCode.c
CommitLineData
878ddf1f 1/*++\r
2\r
3Copyright (c) 2006, Intel Corporation \r
4All rights reserved. This program and the accompanying materials \r
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13\r
14 BsDataHubStatusCode.c\r
15\r
16Abstract:\r
17\r
18 This implements a status code listener that logs status codes into the data\r
19 hub. This is only active during non-runtime DXE.\r
20\r
21--*/\r
22#include "BsDataHubStatusCode.h"\r
23\r
24//\r
25// Globals only work at BootService Time. NOT at Runtime!\r
26//\r
27static EFI_DATA_HUB_PROTOCOL *mDataHub;\r
28static LIST_ENTRY mRecordBuffer;\r
29static INTN mRecordNum;\r
30static EFI_EVENT mLogDataHubEvent;\r
31static EFI_LOCK mStatusCodeReportLock;\r
32static BOOLEAN mEventHandlerActive = FALSE;\r
33\r
34STATUS_CODE_RECORD_LIST *\r
35GetRecordBuffer (\r
36 VOID\r
37 )\r
38/*++\r
39\r
40Routine Description:\r
41\r
42 Returned buffer of length BYTES_PER_RECORD\r
43\r
44Arguments:\r
45\r
46 None\r
47\r
48Returns:\r
49\r
50 Entry in mRecordBuffer or NULL if non available\r
51\r
52--*/\r
53{\r
54 STATUS_CODE_RECORD_LIST *Buffer;\r
55\r
56 gBS->AllocatePool (EfiBootServicesData, sizeof (STATUS_CODE_RECORD_LIST), (VOID **) &Buffer);\r
57 if (Buffer == NULL) {\r
58 return NULL;\r
59 }\r
60\r
61 ZeroMem (Buffer, sizeof (STATUS_CODE_RECORD_LIST));\r
62 Buffer->Signature = BS_DATA_HUB_STATUS_CODE_SIGNATURE;\r
63\r
64 return Buffer;\r
65}\r
66\r
67DATA_HUB_STATUS_CODE_DATA_RECORD *\r
68AquireEmptyRecordBuffer (\r
69 VOID\r
70 )\r
71/*++\r
72\r
73Routine Description:\r
74\r
75 Allocate a mRecordBuffer entry in the form of a pointer.\r
76\r
77Arguments:\r
78\r
79 None\r
80\r
81Returns:\r
82\r
83 Pointer to new buffer. NULL if none exist.\r
84\r
85--*/\r
86{\r
87 STATUS_CODE_RECORD_LIST *DataBuffer;\r
88\r
89 if (mRecordNum < MAX_RECORD_NUM) {\r
90 DataBuffer = GetRecordBuffer ();\r
91 if (DataBuffer != NULL) {\r
92 EfiAcquireLock (&mStatusCodeReportLock);\r
93 InsertTailList (&mRecordBuffer, &DataBuffer->Link);\r
94 mRecordNum++;\r
95 EfiReleaseLock (&mStatusCodeReportLock);\r
96 return (DATA_HUB_STATUS_CODE_DATA_RECORD *) DataBuffer->RecordBuffer;\r
97 }\r
98 }\r
99\r
100 return NULL;\r
101}\r
102\r
103EFI_STATUS\r
104ReleaseRecordBuffer (\r
105 IN STATUS_CODE_RECORD_LIST *RecordBuffer\r
106 )\r
107/*++\r
108\r
109Routine Description:\r
110\r
111 Release a mRecordBuffer entry allocated by AquireEmptyRecordBuffer ().\r
112\r
113Arguments:\r
114\r
115 RecordBuffer - Data to free\r
116\r
117Returns:\r
118\r
119 EFI_SUCCESS - If DataRecord is valid\r
120 EFI_UNSUPPORTED - The record list has empty\r
121\r
122--*/\r
123{\r
124 ASSERT (RecordBuffer != NULL);\r
125 if (mRecordNum <= 0) {\r
126 return EFI_UNSUPPORTED;\r
127 }\r
128\r
129 EfiAcquireLock (&mStatusCodeReportLock);\r
130 RemoveEntryList (&RecordBuffer->Link);\r
131 mRecordNum--;\r
132 EfiReleaseLock (&mStatusCodeReportLock);\r
133 gBS->FreePool (RecordBuffer);\r
134 return EFI_SUCCESS;\r
135}\r
136\r
137EFI_STATUS\r
138BsDataHubReportStatusCode (\r
139 IN EFI_STATUS_CODE_TYPE CodeType,\r
140 IN EFI_STATUS_CODE_VALUE Value,\r
141 IN UINT32 Instance,\r
142 IN EFI_GUID * CallerId,\r
143 IN EFI_STATUS_CODE_DATA * Data OPTIONAL\r
144 )\r
145/*++\r
146\r
147Routine Description:\r
148\r
149 Boot service report status code listener. This function logs the status code\r
150 into the data hub.\r
151\r
152Arguments:\r
153\r
154 Same as ReportStatusCode (See Tiano Runtime Specification)\r
155\r
156Returns:\r
157\r
158 None\r
159\r
160--*/\r
161{\r
162 DATA_HUB_STATUS_CODE_DATA_RECORD *DataHub;\r
163 UINT32 ErrorLevel;\r
164 VA_LIST Marker;\r
165 CHAR8 *Format;\r
166 UINTN Index;\r
167 CHAR16 FormatBuffer[BYTES_PER_RECORD];\r
168\r
169 if (EfiAtRuntime ()) {\r
170 //\r
171 // For now all we do is post code at runtime\r
172 //\r
173 return EFI_SUCCESS;\r
174 }\r
175 //\r
176 // If we had an error while in our event handler, then do nothing so\r
177 // that we don't get in an endless loop.\r
178 //\r
179 if (mEventHandlerActive) {\r
180 return EFI_SUCCESS;\r
181 }\r
182\r
183 DataHub = (DATA_HUB_STATUS_CODE_DATA_RECORD *) AquireEmptyRecordBuffer ();\r
184 if (DataHub == NULL) {\r
185 //\r
186 // There are no empty record buffer in private buffers\r
187 //\r
188 return EFI_OUT_OF_RESOURCES;\r
189 }\r
190 //\r
191 // Construct Data Hub Extended Data\r
192 //\r
193 DataHub->CodeType = CodeType;\r
194 DataHub->Value = Value;\r
195 DataHub->Instance = Instance;\r
196\r
197 if (CallerId != NULL) {\r
198 CopyMem (&DataHub->CallerId, CallerId, sizeof (EFI_GUID));\r
199 } else {\r
200 ZeroMem (&DataHub->CallerId, sizeof (EFI_GUID));\r
201 }\r
202\r
203 if (Data == NULL) {\r
204 ZeroMem (&DataHub->Data, sizeof (EFI_STATUS_CODE_DATA));\r
205 } else {\r
206 //\r
207 // Copy generic Header\r
208 //\r
209 CopyMem (&DataHub->Data, Data, sizeof (EFI_STATUS_CODE_DATA));\r
210\r
211 if (ReportStatusCodeExtractDebugInfo (Data, &ErrorLevel, &Marker, &Format)) {\r
212 //\r
213 // Convert Ascii Format string to Unicode.\r
214 //\r
215 for (Index = 0; Format[Index] != '\0' && Index < (BYTES_PER_RECORD - 1); Index += 1) {\r
216 FormatBuffer[Index] = (CHAR16) Format[Index];\r
217 }\r
218\r
219 FormatBuffer[Index] = L'\0';\r
220\r
221 //\r
222 // Put processed string into the buffer\r
223 //\r
224 Index = UnicodeVSPrint (\r
225 (CHAR16 *) (DataHub + 1),\r
226 BYTES_PER_RECORD - (sizeof (DATA_HUB_STATUS_CODE_DATA_RECORD)),\r
227 FormatBuffer,\r
228 Marker\r
229 );\r
230\r
231 //\r
232 // DATA_HUB_STATUS_CODE_DATA_RECORD followed by VSPrint String Buffer\r
233 //\r
234 DataHub->Data.Size = (UINT16) (Index * sizeof (CHAR16));\r
235\r
236 } else {\r
237 //\r
238 // Default behavior is to copy optional data\r
239 //\r
240 if (Data->Size > (BYTES_PER_RECORD - sizeof (DATA_HUB_STATUS_CODE_DATA_RECORD))) {\r
241 DataHub->Data.Size = (UINT16) (BYTES_PER_RECORD - sizeof (DATA_HUB_STATUS_CODE_DATA_RECORD));\r
242 }\r
243\r
244 CopyMem (DataHub + 1, Data + 1, DataHub->Data.Size);\r
245 }\r
246 }\r
247\r
248 gBS->SignalEvent (mLogDataHubEvent);\r
249\r
250 return EFI_SUCCESS;\r
251}\r
252\r
253VOID\r
254EFIAPI\r
255LogDataHubEventHandler (\r
256 IN EFI_EVENT Event,\r
257 IN VOID *Context\r
258 )\r
259/*++\r
260\r
261Routine Description:\r
262\r
263 The Event handler which will be notified to log data in Data Hub.\r
264\r
265Arguments:\r
266\r
267 Event - Instance of the EFI_EVENT to signal whenever data is\r
268 available to be logged in the system.\r
269 Context - Context of the event.\r
270\r
271Returns:\r
272\r
273 None.\r
274\r
275--*/\r
276{\r
277 EFI_STATUS Status;\r
278 DATA_HUB_STATUS_CODE_DATA_RECORD *DataRecord;\r
279 UINTN Size;\r
280 UINT64 DataRecordClass;\r
281 LIST_ENTRY *Link;\r
282 STATUS_CODE_RECORD_LIST *BufferEntry;\r
283\r
284 //\r
285 // Set our global flag so we don't recurse if we get an error here.\r
286 //\r
287 mEventHandlerActive = TRUE;\r
288\r
289 //\r
290 // Log DataRecord in Data Hub.\r
291 // If there are multiple DataRecords, Log all of them.\r
292 //\r
293 for (Link = mRecordBuffer.ForwardLink; Link != &mRecordBuffer;) {\r
294 BufferEntry = CR (Link, STATUS_CODE_RECORD_LIST, Link, BS_DATA_HUB_STATUS_CODE_SIGNATURE);\r
295 DataRecord = (DATA_HUB_STATUS_CODE_DATA_RECORD *) (BufferEntry->RecordBuffer);\r
296 Link = Link->ForwardLink;\r
297\r
298 //\r
299 // Add in the size of the header we added.\r
300 //\r
301 Size = sizeof (DATA_HUB_STATUS_CODE_DATA_RECORD) + DataRecord->Data.Size;\r
302\r
303 if ((DataRecord->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) {\r
304 DataRecordClass = EFI_DATA_RECORD_CLASS_PROGRESS_CODE;\r
305 } else if ((DataRecord->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) {\r
306 DataRecordClass = EFI_DATA_RECORD_CLASS_ERROR;\r
307 } else if ((DataRecord->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE) {\r
308 DataRecordClass = EFI_DATA_RECORD_CLASS_DEBUG;\r
309 } else {\r
310 //\r
311 // Should never get here.\r
312 //\r
313 DataRecordClass = EFI_DATA_RECORD_CLASS_DEBUG |\r
314 EFI_DATA_RECORD_CLASS_ERROR |\r
315 EFI_DATA_RECORD_CLASS_DATA |\r
316 EFI_DATA_RECORD_CLASS_PROGRESS_CODE;\r
317 }\r
318\r
319 if (((DataRecord->Instance & EFI_D_ERROR) != 0) &&\r
320 (((DataRecord->Instance & EFI_D_POOL) != 0) || ((DataRecord->Instance & EFI_D_PAGE) != 0))\r
321 ) {\r
322 //\r
323 // If memory error, do not call LogData ().\r
324 //\r
325 DebugPrint ((UINTN)-1, "Memory Error\n");\r
326 Status = EFI_OUT_OF_RESOURCES;\r
327 } else {\r
328 //\r
329 // Log DataRecord in Data Hub\r
330 //\r
331 Status = mDataHub->LogData (\r
332 mDataHub,\r
333 &gEfiStatusCodeGuid,\r
334 &gEfiStatusCodeRuntimeProtocolGuid,\r
335 DataRecordClass,\r
336 DataRecord,\r
337 (UINT32) Size\r
338 );\r
339 }\r
340\r
341 ReleaseRecordBuffer (BufferEntry);\r
342 }\r
343\r
344 mEventHandlerActive = FALSE;\r
345\r
346 return ;\r
347}\r
348\r
349VOID\r
350BsDataHubStatusCodeInitialize (\r
351 VOID\r
352 )\r
353/*++\r
354\r
355Routine Description:\r
356\r
357 Install a data hub listener.\r
358\r
359Arguments:\r
360\r
361 (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT)\r
362\r
363Returns:\r
364\r
365 EFI_SUCCESS - Logging Hub protocol installed\r
366 Other - No protocol installed, unload driver.\r
367\r
368--*/\r
369{\r
370 EFI_STATUS Status;\r
371\r
372 Status = gBS->LocateProtocol (&gEfiDataHubProtocolGuid, NULL, (VOID **) &mDataHub);\r
373 //\r
374 // Should never fail due to dependency grammer\r
375 //\r
376 ASSERT_EFI_ERROR (Status);\r
377\r
378 //\r
379 // Initialize FIFO\r
380 //\r
381 InitializeListHead (&mRecordBuffer);\r
382 mRecordNum = 0;\r
383\r
384 EfiInitializeLock (&mStatusCodeReportLock, EFI_TPL_HIGH_LEVEL);\r
385\r
386 //\r
387 // Create a Notify Event to log data in Data Hub\r
388 //\r
389 Status = gBS->CreateEvent (\r
390 EFI_EVENT_NOTIFY_SIGNAL,\r
391 EFI_TPL_CALLBACK,\r
392 LogDataHubEventHandler,\r
393 NULL,\r
394 &mLogDataHubEvent\r
395 );\r
396\r
397}\r