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
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.
18 This implements a status code listener that logs status codes into the data
19 hub. This is only active during non-runtime DXE.
22 #include "BsDataHubStatusCode.h"
25 // Globals only work at BootService Time. NOT at Runtime!
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
;
34 STATUS_CODE_RECORD_LIST
*
42 Returned buffer of length BYTES_PER_RECORD
50 Entry in mRecordBuffer or NULL if non available
54 STATUS_CODE_RECORD_LIST
*Buffer
;
56 gBS
->AllocatePool (EfiBootServicesData
, sizeof (STATUS_CODE_RECORD_LIST
), (VOID
**) &Buffer
);
61 ZeroMem (Buffer
, sizeof (STATUS_CODE_RECORD_LIST
));
62 Buffer
->Signature
= BS_DATA_HUB_STATUS_CODE_SIGNATURE
;
67 DATA_HUB_STATUS_CODE_DATA_RECORD
*
68 AquireEmptyRecordBuffer (
75 Allocate a mRecordBuffer entry in the form of a pointer.
83 Pointer to new buffer. NULL if none exist.
87 STATUS_CODE_RECORD_LIST
*DataBuffer
;
89 if (mRecordNum
< MAX_RECORD_NUM
) {
90 DataBuffer
= GetRecordBuffer ();
91 if (DataBuffer
!= NULL
) {
92 EfiAcquireLock (&mStatusCodeReportLock
);
93 InsertTailList (&mRecordBuffer
, &DataBuffer
->Link
);
95 EfiReleaseLock (&mStatusCodeReportLock
);
96 return (DATA_HUB_STATUS_CODE_DATA_RECORD
*) DataBuffer
->RecordBuffer
;
104 ReleaseRecordBuffer (
105 IN STATUS_CODE_RECORD_LIST
*RecordBuffer
111 Release a mRecordBuffer entry allocated by AquireEmptyRecordBuffer ().
115 RecordBuffer - Data to free
119 EFI_SUCCESS - If DataRecord is valid
120 EFI_UNSUPPORTED - The record list has empty
124 ASSERT (RecordBuffer
!= NULL
);
125 if (mRecordNum
<= 0) {
126 return EFI_UNSUPPORTED
;
129 EfiAcquireLock (&mStatusCodeReportLock
);
130 RemoveEntryList (&RecordBuffer
->Link
);
132 EfiReleaseLock (&mStatusCodeReportLock
);
133 gBS
->FreePool (RecordBuffer
);
138 BsDataHubReportStatusCode (
139 IN EFI_STATUS_CODE_TYPE CodeType
,
140 IN EFI_STATUS_CODE_VALUE Value
,
142 IN EFI_GUID
* CallerId
,
143 IN EFI_STATUS_CODE_DATA
* Data OPTIONAL
149 Boot service report status code listener. This function logs the status code
154 Same as ReportStatusCode (See Tiano Runtime Specification)
162 DATA_HUB_STATUS_CODE_DATA_RECORD
*DataHub
;
167 CHAR16 FormatBuffer
[BYTES_PER_RECORD
];
169 if (EfiAtRuntime ()) {
171 // For now all we do is post code at runtime
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.
179 if (mEventHandlerActive
) {
183 DataHub
= (DATA_HUB_STATUS_CODE_DATA_RECORD
*) AquireEmptyRecordBuffer ();
184 if (DataHub
== NULL
) {
186 // There are no empty record buffer in private buffers
188 return EFI_OUT_OF_RESOURCES
;
191 // Construct Data Hub Extended Data
193 DataHub
->CodeType
= CodeType
;
194 DataHub
->Value
= Value
;
195 DataHub
->Instance
= Instance
;
197 if (CallerId
!= NULL
) {
198 CopyMem (&DataHub
->CallerId
, CallerId
, sizeof (EFI_GUID
));
200 ZeroMem (&DataHub
->CallerId
, sizeof (EFI_GUID
));
204 ZeroMem (&DataHub
->Data
, sizeof (EFI_STATUS_CODE_DATA
));
207 // Copy generic Header
209 CopyMem (&DataHub
->Data
, Data
, sizeof (EFI_STATUS_CODE_DATA
));
211 if (ReportStatusCodeExtractDebugInfo (Data
, &ErrorLevel
, &Marker
, &Format
)) {
213 // Convert Ascii Format string to Unicode.
215 for (Index
= 0; Format
[Index
] != '\0' && Index
< (BYTES_PER_RECORD
- 1); Index
+= 1) {
216 FormatBuffer
[Index
] = (CHAR16
) Format
[Index
];
219 FormatBuffer
[Index
] = L
'\0';
222 // Put processed string into the buffer
224 Index
= UnicodeVSPrint (
225 (CHAR16
*) (DataHub
+ 1),
226 BYTES_PER_RECORD
- (sizeof (DATA_HUB_STATUS_CODE_DATA_RECORD
)),
232 // DATA_HUB_STATUS_CODE_DATA_RECORD followed by VSPrint String Buffer
234 DataHub
->Data
.Size
= (UINT16
) (Index
* sizeof (CHAR16
));
238 // Default behavior is to copy optional data
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
));
244 CopyMem (DataHub
+ 1, Data
+ 1, DataHub
->Data
.Size
);
248 gBS
->SignalEvent (mLogDataHubEvent
);
255 LogDataHubEventHandler (
263 The Event handler which will be notified to log data in Data Hub.
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.
278 DATA_HUB_STATUS_CODE_DATA_RECORD
*DataRecord
;
280 UINT64 DataRecordClass
;
282 STATUS_CODE_RECORD_LIST
*BufferEntry
;
285 // Set our global flag so we don't recurse if we get an error here.
287 mEventHandlerActive
= TRUE
;
290 // Log DataRecord in Data Hub.
291 // If there are multiple DataRecords, Log all of them.
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
;
299 // Add in the size of the header we added.
301 Size
= sizeof (DATA_HUB_STATUS_CODE_DATA_RECORD
) + DataRecord
->Data
.Size
;
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
;
311 // Should never get here.
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
;
319 if (((DataRecord
->Instance
& EFI_D_ERROR
) != 0) &&
320 (((DataRecord
->Instance
& EFI_D_POOL
) != 0) || ((DataRecord
->Instance
& EFI_D_PAGE
) != 0))
323 // If memory error, do not call LogData ().
325 DebugPrint ((UINTN
)-1, "Memory Error\n");
326 Status
= EFI_OUT_OF_RESOURCES
;
329 // Log DataRecord in Data Hub
331 Status
= mDataHub
->LogData (
334 &gEfiStatusCodeRuntimeProtocolGuid
,
341 ReleaseRecordBuffer (BufferEntry
);
344 mEventHandlerActive
= FALSE
;
350 BsDataHubStatusCodeInitialize (
357 Install a data hub listener.
361 (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT)
365 EFI_SUCCESS - Logging Hub protocol installed
366 Other - No protocol installed, unload driver.
372 Status
= gBS
->LocateProtocol (&gEfiDataHubProtocolGuid
, NULL
, (VOID
**) &mDataHub
);
374 // Should never fail due to dependency grammer
376 ASSERT_EFI_ERROR (Status
);
381 InitializeListHead (&mRecordBuffer
);
384 EfiInitializeLock (&mStatusCodeReportLock
, EFI_TPL_HIGH_LEVEL
);
387 // Create a Notify Event to log data in Data Hub
389 Status
= gBS
->CreateEvent (
390 EFI_EVENT_NOTIFY_SIGNAL
,
392 LogDataHubEventHandler
,