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