]> git.proxmox.com Git - mirror_edk2.git/blob - EdkCompatibilityPkg/Sample/Platform/Generic/RuntimeDxe/StatusCode/Lib/BsDataHubStatusCode/BsDataHubStatusCode.c
980635dc7f01b55cd3b235e8ebf1e0769b6b652c
[mirror_edk2.git] / EdkCompatibilityPkg / Sample / Platform / Generic / RuntimeDxe / StatusCode / Lib / BsDataHubStatusCode / BsDataHubStatusCode.c
1 /*++
2
3 Copyright (c) 2004 - 2007, 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 The status codes are recorded in a extensiable buffer, and a event is signalled
21 to log them to the data hub. The recorder is the producer of the status code in
22 buffer and the event notify function the consummer.
23
24 --*/
25
26 #include "BsDataHubStatusCode.h"
27
28 //
29 // Initialize FIFO to cache records.
30 //
31 STATIC EFI_LIST_ENTRY mRecordsFifo = INITIALIZE_LIST_HEAD_VARIABLE (mRecordsFifo);
32 STATIC EFI_LIST_ENTRY mRecordsBuffer = INITIALIZE_LIST_HEAD_VARIABLE (mRecordsBuffer);
33 STATIC EFI_EVENT mLogDataHubEvent;
34 STATIC BOOLEAN mEventHandlerActive = FALSE;
35
36 //
37 // Cache data hub protocol.
38 //
39 STATIC EFI_DATA_HUB_PROTOCOL *mDataHubProtocol;
40
41 STATIC
42 DATA_HUB_STATUS_CODE_DATA_RECORD *
43 AcquireRecordBuffer (
44 VOID
45 )
46 /*++
47
48 Routine Description:
49
50 Return one DATAHUB_STATUSCODE_RECORD space.
51 The size of free record pool would be extend, if the pool is empty.
52
53 Arguments:
54
55 None
56
57 Returns:
58
59 A pointer to the new allocated node or NULL if non available
60
61 --*/
62 {
63 DATAHUB_STATUSCODE_RECORD *Record;
64 EFI_TPL CurrentTpl;
65 EFI_LIST_ENTRY *Node;
66 UINT32 Index;
67
68 Record = NULL;
69 CurrentTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL);
70
71 if (!IsListEmpty (&mRecordsBuffer)) {
72 Node = GetFirstNode (&mRecordsBuffer);
73 RemoveEntryList (Node);
74
75 Record = _CR (Node, DATAHUB_STATUSCODE_RECORD, Node);
76 } else {
77 if (CurrentTpl > EFI_TPL_NOTIFY) {
78 gBS->RestoreTPL (CurrentTpl);
79 return NULL;
80 }
81
82 gBS->RestoreTPL (CurrentTpl);
83
84 gBS->AllocatePool (EfiBootServicesData, sizeof (DATAHUB_STATUSCODE_RECORD) * 16, &Record);
85 if (Record == NULL) {
86 return NULL;
87 }
88 EfiCommonLibZeroMem (Record, sizeof (DATAHUB_STATUSCODE_RECORD) * 16);
89
90
91 CurrentTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL);
92 for (Index = 1; Index < 16; Index++) {
93 InsertTailList (&mRecordsBuffer, &Record[Index].Node);
94 }
95 }
96
97 Record->Signature = BS_DATA_HUB_STATUS_CODE_SIGNATURE;
98 InsertTailList (&mRecordsFifo, &Record->Node);
99
100 gBS->RestoreTPL (CurrentTpl);
101
102 return (DATA_HUB_STATUS_CODE_DATA_RECORD *) (Record->Data);
103 }
104
105 STATIC
106 DATA_HUB_STATUS_CODE_DATA_RECORD *
107 RetrieveRecord (
108 VOID
109 )
110 /*++
111
112 Routine Description:
113
114 Retrieve one record from Records FIFO. The record would be removed from FIFO and
115 release to free record buffer.
116
117 Arguments:
118
119 None
120
121 Returns:
122
123 Point to record which is ready to be logged, or NULL if the FIFO of record is empty.
124
125 --*/
126 {
127 DATA_HUB_STATUS_CODE_DATA_RECORD *RecordData;
128 DATAHUB_STATUSCODE_RECORD *Record;
129 EFI_LIST_ENTRY *Node;
130 EFI_TPL CurrentTpl;
131
132 RecordData = NULL;
133
134 CurrentTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL);
135
136 if (!IsListEmpty (&mRecordsFifo)) {
137 Node = GetFirstNode (&mRecordsFifo);
138 Record = CR (Node, DATAHUB_STATUSCODE_RECORD, Node, BS_DATA_HUB_STATUS_CODE_SIGNATURE);
139
140 RemoveEntryList (&Record->Node);
141 InsertTailList (&mRecordsBuffer, &Record->Node);
142 Record->Signature = 0;
143 RecordData = (DATA_HUB_STATUS_CODE_DATA_RECORD *) Record->Data;
144 }
145
146 gBS->RestoreTPL (CurrentTpl);
147
148 return RecordData;
149 }
150
151 EFI_STATUS
152 EFIAPI
153 BsDataHubReportStatusCode (
154 IN EFI_STATUS_CODE_TYPE CodeType,
155 IN EFI_STATUS_CODE_VALUE Value,
156 IN UINT32 Instance,
157 IN EFI_GUID * CallerId,
158 IN EFI_STATUS_CODE_DATA * Data OPTIONAL
159 )
160 /*++
161
162 Routine Description:
163
164 Boot service report status code listener. This function logs the status code
165 into the data hub.
166
167 Arguments:
168
169 Same as gRT->ReportStatusCode (See Tiano Runtime Specification)
170
171 Returns:
172
173 None
174
175 --*/
176 {
177 DATA_HUB_STATUS_CODE_DATA_RECORD *Record;
178 UINT32 ErrorLevel;
179 VA_LIST Marker;
180 CHAR8 *Format;
181 CHAR16 FormatBuffer[BYTES_PER_RECORD];
182 UINTN Index;
183
184 //
185 // See whether in runtime phase or not.
186 //
187 if (EfiAtRuntime ()) {
188 //
189 // For now all we do is post code at runtime
190 //
191 return EFI_SUCCESS;
192 }
193
194 //
195 // Discard new DataHubRecord caused by DataHub->LogData()
196 //
197 if (mEventHandlerActive) {
198 return EFI_SUCCESS;
199 }
200
201 Record = AcquireRecordBuffer ();
202 if (Record == NULL) {
203 //
204 // There are no empty record buffer in private buffers
205 //
206 return EFI_OUT_OF_RESOURCES;
207 }
208 //
209 // Construct Data Hub Extended Data
210 //
211 Record->CodeType = CodeType;
212 Record->Value = Value;
213 Record->Instance = Instance;
214
215 if (CallerId != NULL) {
216 EfiCopyMem (&Record->CallerId, CallerId, sizeof (EFI_GUID));
217 }
218
219 if (Data != NULL) {
220 if (ReportStatusCodeExtractDebugInfo (Data, &ErrorLevel, &Marker, &Format)) {
221 //
222 // Convert Ascii Format string to Unicode.
223 //
224 for (Index = 0; Format[Index] != '\0' && Index < (BYTES_PER_RECORD - 1); Index += 1) {
225 FormatBuffer[Index] = (CHAR16) Format[Index];
226 }
227
228 FormatBuffer[Index] = L'\0';
229
230 //
231 // Put processed string into the buffer
232 //
233 Index = VSPrint (
234 (CHAR16 *) (Record + 1),
235 BYTES_PER_RECORD - (sizeof (DATA_HUB_STATUS_CODE_DATA_RECORD)),
236 FormatBuffer,
237 Marker
238 );
239
240 EfiCopyMem (&Record->Data.Type, &gEfiStatusCodeDataTypeDebugGuid, sizeof (EFI_GUID));
241 Record->Data.HeaderSize = Data->HeaderSize;
242 Record->Data.Size = (UINT16) (Index * sizeof (CHAR16));
243 } else {
244 //
245 // Copy status code data header
246 //
247 EfiCopyMem (&Record->Data, Data, sizeof (EFI_STATUS_CODE_DATA));
248
249 if (Data->Size > BYTES_PER_RECORD - sizeof (DATA_HUB_STATUS_CODE_DATA_RECORD)) {
250 Record->Data.Size = (UINT16) (BYTES_PER_RECORD - sizeof (DATA_HUB_STATUS_CODE_DATA_RECORD));
251 }
252 EfiCopyMem ((VOID *) (Record + 1), Data + 1, Record->Data.Size);
253 }
254 }
255
256 gBS->SignalEvent (mLogDataHubEvent);
257
258 return EFI_SUCCESS;
259 }
260
261 VOID
262 EFIAPI
263 LogDataHubEventHandler (
264 IN EFI_EVENT Event,
265 IN VOID *Context
266 )
267 /*++
268
269 Routine Description:
270
271 The Event handler which will be notified to log data in Data Hub.
272
273 Arguments:
274
275 Event - Instance of the EFI_EVENT to signal whenever data is
276 available to be logged in the system.
277 Context - Context of the event.
278
279 Returns:
280
281 None.
282
283 --*/
284 {
285 DATA_HUB_STATUS_CODE_DATA_RECORD *Record;
286 UINT32 Size;
287 UINT64 DataRecordClass;
288
289 //
290 // Set global flag so we don't recurse if DataHub->LogData eventually causes new DataHubRecord
291 //
292 mEventHandlerActive = TRUE;
293
294 //
295 // Log DataRecord in Data Hub.
296 // Journal records fifo to find all record entry.
297 //
298 while (1) {
299 Record = RetrieveRecord ();
300 if (Record == NULL) {
301 break;
302 }
303 //
304 // Add in the size of the header we added.
305 //
306 Size = sizeof (DATA_HUB_STATUS_CODE_DATA_RECORD) + (UINT32) Record->Data.Size;
307
308 if ((Record->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) {
309 DataRecordClass = EFI_DATA_RECORD_CLASS_PROGRESS_CODE;
310 } else if ((Record->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) {
311 DataRecordClass = EFI_DATA_RECORD_CLASS_ERROR;
312 } else if ((Record->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE) {
313 DataRecordClass = EFI_DATA_RECORD_CLASS_DEBUG;
314 } else {
315 //
316 // Should never get here.
317 //
318 DataRecordClass = EFI_DATA_RECORD_CLASS_DEBUG |
319 EFI_DATA_RECORD_CLASS_ERROR |
320 EFI_DATA_RECORD_CLASS_DATA |
321 EFI_DATA_RECORD_CLASS_PROGRESS_CODE;
322 }
323
324 //
325 // Log DataRecord in Data Hub
326 //
327
328 mDataHubProtocol->LogData (
329 mDataHubProtocol,
330 &gEfiStatusCodeGuid,
331 &gEfiStatusCodeRuntimeProtocolGuid,
332 DataRecordClass,
333 Record,
334 Size
335 );
336
337 }
338
339 mEventHandlerActive = FALSE;
340
341 }
342
343 EFI_STATUS
344 EFIAPI
345 BsDataHubInitializeStatusCode (
346 IN EFI_HANDLE ImageHandle,
347 IN EFI_SYSTEM_TABLE *SystemTable
348 )
349 /*++
350
351 Routine Description:
352
353 Install a data hub listener.
354
355 Arguments:
356
357 (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT)
358
359 Returns:
360
361 EFI_SUCCESS - Logging Hub protocol installed
362 Other - No protocol installed, unload driver.
363
364 --*/
365 {
366 EFI_STATUS Status;
367
368 Status = gBS->LocateProtocol (
369 &gEfiDataHubProtocolGuid,
370 NULL,
371 (VOID **) &mDataHubProtocol
372 );
373 ASSERT_EFI_ERROR (Status);
374
375 //
376 // Create a Notify Event to log data in Data Hub
377 //
378 Status = gBS->CreateEvent (
379 EFI_EVENT_NOTIFY_SIGNAL,
380 EFI_TPL_CALLBACK,
381 LogDataHubEventHandler,
382 NULL,
383 &mLogDataHubEvent
384 );
385
386 ASSERT_EFI_ERROR (Status);
387
388 return EFI_SUCCESS;
389 }
390
391