]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Universal/DataHub/DataHub/Dxe/DataHub.c
Add DataHub & DataHubStdErr modules
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / DataHub / DataHub / Dxe / DataHub.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 DataHub.c
15
16 Abstract:
17
18 This code produces the Data Hub protocol. It preloads the data hub
19 with status information copied in from PEI HOBs.
20
21 Only code that implements the Data Hub protocol should go in this file!
22
23 The Term MTC stands for MonoTonicCounter.
24
25 For more information please look at DataHub.doc
26
27 NOTE: For extra security of the log GetNextDataRecord () could return a copy
28 of the data record.
29 --*/
30
31 #include "DataHub.h"
32
33 CONST EFI_GUID gZeroGuid = { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } };
34
35 //
36 // Worker functions private to this file
37 //
38 STATIC
39 DATA_HUB_FILTER_DRIVER *
40 FindFilterDriverByEvent (
41 IN LIST_ENTRY *Head,
42 IN EFI_EVENT Event
43 );
44
45 STATIC
46 EFI_DATA_RECORD_HEADER *
47 GetNextDataRecord (
48 IN LIST_ENTRY *Head,
49 IN UINT64 ClassFilter,
50 IN OUT UINT64 *PtrCurrentMTC
51 );
52
53 STATIC
54 EFI_STATUS
55 EFIAPI
56 DataHubLogData (
57 IN EFI_DATA_HUB_PROTOCOL *This,
58 IN EFI_GUID *DataRecordGuid,
59 IN EFI_GUID *ProducerName,
60 IN UINT64 DataRecordClass,
61 IN VOID *RawData,
62 IN UINT32 RawDataSize
63 )
64 /*++
65
66 Routine Description:
67
68 Log data record into the data logging hub
69
70 Arguments:
71
72 This - Protocol instance structure
73
74 DataRecordGuid - GUID that defines record contents
75
76 ProducerName - GUID that defines the name of the producer of the data
77
78 DataRecordClass - Class that defines generic record type
79
80 RawData - Data Log record as defined by DataRecordGuid
81
82 RawDataSize - Size of Data Log data in bytes
83
84 Returns:
85
86 EFI_SUCCESS - If data was logged
87
88 EFI_OUT_OF_RESOURCES - If data was not logged due to lack of system
89 resources.
90 --*/
91 {
92 EFI_STATUS Status;
93 DATA_HUB_INSTANCE *Private;
94 EFI_DATA_ENTRY *LogEntry;
95 UINT32 TotalSize;
96 UINT32 RecordSize;
97 EFI_DATA_RECORD_HEADER *Record;
98 VOID *Raw;
99 DATA_HUB_FILTER_DRIVER *FilterEntry;
100 LIST_ENTRY *Link;
101 LIST_ENTRY *Head;
102
103 Private = DATA_HUB_INSTANCE_FROM_THIS (This);
104
105 //
106 // Combine the storage for the internal structs and a copy of the log record.
107 // Record follows PrivateLogEntry. The consumer will be returned a pointer
108 // to Record so we don't what it to be the thing that was allocated from
109 // pool, so the consumer can't free an data record by mistake.
110 //
111 RecordSize = sizeof (EFI_DATA_RECORD_HEADER) + RawDataSize;
112 TotalSize = sizeof (EFI_DATA_ENTRY) + RecordSize;
113
114 //
115 // The Logging action is the critical section, so it is locked.
116 // The MTC asignment & update, time, and logging must be an
117 // atomic operation, so use the lock.
118 //
119 Status = EfiAcquireLockOrFail (&Private->DataLock);
120 if (EFI_ERROR (Status)) {
121 //
122 // Reentrancy detected so exit!
123 //
124 return Status;
125 }
126
127 LogEntry = AllocatePool (TotalSize);
128
129 if (LogEntry == NULL) {
130 EfiReleaseLock (&Private->DataLock);
131 return EFI_OUT_OF_RESOURCES;
132 }
133
134 ZeroMem (LogEntry, TotalSize);
135
136 Record = (EFI_DATA_RECORD_HEADER *) (LogEntry + 1);
137 Raw = (VOID *) (Record + 1);
138
139 //
140 // Build Standard Log Header
141 //
142 Record->Version = EFI_DATA_RECORD_HEADER_VERSION;
143 Record->HeaderSize = sizeof (EFI_DATA_RECORD_HEADER);
144 Record->RecordSize = RecordSize;
145 CopyMem (&Record->DataRecordGuid, DataRecordGuid, sizeof (EFI_GUID));
146 CopyMem (&Record->ProducerName, ProducerName, sizeof (EFI_GUID));
147 Record->DataRecordClass = DataRecordClass;
148
149 Record->LogMonotonicCount = Private->GlobalMonotonicCount++;
150
151 gRT->GetTime (&Record->LogTime, NULL);
152
153 //
154 // Insert log into the internal linked list.
155 //
156 LogEntry->Signature = EFI_DATA_ENTRY_SIGNATURE;
157 LogEntry->Record = Record;
158 LogEntry->RecordSize = sizeof (EFI_DATA_ENTRY) + RawDataSize;
159 InsertTailList (&Private->DataListHead, &LogEntry->Link);
160
161 CopyMem (Raw, RawData, RawDataSize);
162
163 EfiReleaseLock (&Private->DataLock);
164
165 //
166 // Send Signal to all the filter drivers which are interested
167 // in the record's class and guid.
168 //
169 Head = &Private->FilterDriverListHead;
170 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
171 FilterEntry = FILTER_ENTRY_FROM_LINK (Link);
172 if (((FilterEntry->ClassFilter & DataRecordClass) != 0) &&
173 (CompareGuid (&FilterEntry->FilterDataRecordGuid, &gZeroGuid) ||
174 CompareGuid (&FilterEntry->FilterDataRecordGuid, DataRecordGuid))) {
175 gBS->SignalEvent (FilterEntry->Event);
176 }
177 }
178
179 return EFI_SUCCESS;
180 }
181
182 STATIC
183 EFI_STATUS
184 EFIAPI
185 DataHubGetNextRecord (
186 IN EFI_DATA_HUB_PROTOCOL *This,
187 IN OUT UINT64 *MonotonicCount,
188 IN EFI_EVENT *FilterDriverEvent, OPTIONAL
189 OUT EFI_DATA_RECORD_HEADER **Record
190 )
191 /*++
192
193 Routine Description:
194
195 Get a previously logged data record and the MonotonicCount for the next
196 availible Record. This allows all records or all records later
197 than a give MonotonicCount to be returned. If an optional FilterDriverEvent
198 is passed in with a MonotonicCout of zero return the first record
199 not yet read by the filter driver. If FilterDriverEvent is NULL and
200 MonotonicCount is zero return the first data record.
201
202 Arguments:
203
204 This - The EFI_DATA_HUB_PROTOCOL instance.
205 MonotonicCount - Specifies the Record to return. On input, zero means
206 return the first record. On output, contains the next
207 record to availible. Zero indicates no more records.
208 FilterDriverEvent - If FilterDriverEvent is not passed in a MonotonicCount
209 of zero, it means to return the first data record.
210 If FilterDriverEvent is passed in, then a MonotonicCount
211 of zero means to return the first data not yet read by
212 FilterDriverEvent.
213 Record - Returns a dynamically allocated memory buffer with a data
214 record that matches MonotonicCount.
215
216 Returns:
217
218 EFI_SUCCESS - Data was returned in Record.
219 EFI_INVALID_PARAMETER - FilterDriverEvent was passed in but does not exist.
220 EFI_NOT_FOUND - MonotonicCount does not match any data record in the
221 system. If a MonotonicCount of zero was passed in, then
222 no data records exist in the system.
223 EFI_OUT_OF_RESOURCES - Record was not returned due to lack of system resources.
224
225 --*/
226 {
227 DATA_HUB_INSTANCE *Private;
228 DATA_HUB_FILTER_DRIVER *FilterDriver;
229 UINT64 ClassFilter;
230 UINT64 FilterMonotonicCount;
231
232 Private = DATA_HUB_INSTANCE_FROM_THIS (This);
233
234 FilterDriver = NULL;
235 FilterMonotonicCount = 0;
236 ClassFilter = EFI_DATA_RECORD_CLASS_DEBUG |
237 EFI_DATA_RECORD_CLASS_ERROR |
238 EFI_DATA_RECORD_CLASS_DATA |
239 EFI_DATA_RECORD_CLASS_PROGRESS_CODE;
240
241 if (FilterDriverEvent != NULL) {
242 //
243 // For events the beginning is the last unread record. This info is
244 // stored in the instance structure, so we must look up the event
245 // to get the data.
246 //
247 FilterDriver = FindFilterDriverByEvent (
248 &Private->FilterDriverListHead,
249 *FilterDriverEvent
250 );
251 if (FilterDriver == NULL) {
252 return EFI_INVALID_PARAMETER;
253 }
254 //
255 // Use the Class filter the event was created with.
256 //
257 ClassFilter = FilterDriver->ClassFilter;
258
259 if (*MonotonicCount == 0) {
260 //
261 // Use the MTC from the Filter Driver.
262 //
263 FilterMonotonicCount = FilterDriver->GetNextMonotonicCount;
264 if (FilterMonotonicCount != 0) {
265 //
266 // The GetNextMonotonicCount field remembers the last value from the previous time.
267 // But we already processed this vaule, so we need to find the next one. So if
268 // It is not the first time get the new record entry.
269 //
270 *Record = GetNextDataRecord (&Private->DataListHead, ClassFilter, &FilterMonotonicCount);
271 *MonotonicCount = FilterMonotonicCount;
272 if (FilterMonotonicCount == 0) {
273 //
274 // If there is no new record to get exit now.
275 //
276 return EFI_NOT_FOUND;
277 }
278 }
279 }
280 }
281 //
282 // Return the record
283 //
284 *Record = GetNextDataRecord (&Private->DataListHead, ClassFilter, MonotonicCount);
285 if (*Record == NULL) {
286 return EFI_NOT_FOUND;
287 }
288
289 if (FilterDriver != NULL) {
290 //
291 // If we have a filter driver update the records that have been read.
292 // If MonotonicCount is zero No more reacords left.
293 //
294 if (*MonotonicCount == 0) {
295 if (FilterMonotonicCount != 0) {
296 //
297 // Return the result of our extra GetNextDataRecord.
298 //
299 FilterDriver->GetNextMonotonicCount = FilterMonotonicCount;
300 }
301 } else {
302 //
303 // Point to next undread record
304 //
305 FilterDriver->GetNextMonotonicCount = *MonotonicCount;
306 }
307 }
308
309 return EFI_SUCCESS;
310 }
311
312 STATIC
313 EFI_STATUS
314 EFIAPI
315 DataHubRegisterFilterDriver (
316 IN EFI_DATA_HUB_PROTOCOL * This,
317 IN EFI_EVENT FilterEvent,
318 IN EFI_TPL FilterTpl,
319 IN UINT64 FilterClass,
320 IN EFI_GUID * FilterDataRecordGuid OPTIONAL
321 )
322 /*++
323
324 Routine Description:
325
326 This function registers the data hub filter driver that is represented
327 by FilterEvent. Only one instance of each FilterEvent can be registered.
328 After the FilterEvent is registered, it will be signaled so it can sync
329 with data records that have been recorded prior to the FilterEvent being
330 registered.
331
332 Arguments:
333
334 This - The EFI_DATA_HUB_PROTOCOL instance.
335 FilterEvent - The EFI_EVENT to signal whenever data that matches
336 FilterClass is logged in the system.
337 FilterTpl - The maximum EFI_TPL at which FilterEvent can be
338 signaled. It is strongly recommended that you use the
339 lowest EFI_TPL possible.
340 FilterClass - FilterEvent will be signaled whenever a bit in
341 EFI_DATA_RECORD_HEADER.DataRecordClass is also set in
342 FilterClass. If FilterClass is zero, no class-based
343 filtering will be performed.
344 FilterDataRecordGuid - FilterEvent will be signaled whenever FilterDataRecordGuid
345 matches EFI_DATA_RECORD_HEADER.DataRecordGuid. If
346 FilterDataRecordGuid is NULL, then no GUID-based filtering
347 will be performed.
348 Returns:
349
350 EFI_SUCCESS - The filter driver event was registered.
351 EFI_ALREADY_STARTED - FilterEvent was previously registered and cannot be
352 registered again.
353 EFI_OUT_OF_RESOURCES - The filter driver event was not registered due to lack of
354 system resources.
355
356 --*/
357 {
358 DATA_HUB_INSTANCE *Private;
359 DATA_HUB_FILTER_DRIVER *FilterDriver;
360
361 Private = DATA_HUB_INSTANCE_FROM_THIS (This);
362
363 FilterDriver = (DATA_HUB_FILTER_DRIVER *) AllocateZeroPool (sizeof (DATA_HUB_FILTER_DRIVER));
364 if (FilterDriver == NULL) {
365 return EFI_OUT_OF_RESOURCES;
366 }
367 //
368 // Initialize filter driver info
369 //
370 FilterDriver->Signature = EFI_DATA_HUB_FILTER_DRIVER_SIGNATURE;
371 FilterDriver->Event = FilterEvent;
372 FilterDriver->Tpl = FilterTpl;
373 FilterDriver->GetNextMonotonicCount = 0;
374 if (FilterClass == 0) {
375 FilterDriver->ClassFilter = EFI_DATA_RECORD_CLASS_DEBUG |
376 EFI_DATA_RECORD_CLASS_ERROR |
377 EFI_DATA_RECORD_CLASS_DATA |
378 EFI_DATA_RECORD_CLASS_PROGRESS_CODE;
379 } else {
380 FilterDriver->ClassFilter = FilterClass;
381 }
382
383 if (FilterDataRecordGuid != NULL) {
384 CopyMem (&FilterDriver->FilterDataRecordGuid, FilterDataRecordGuid, sizeof (EFI_GUID));
385 }
386 //
387 // Search for duplicate entries
388 //
389 if (FindFilterDriverByEvent (&Private->FilterDriverListHead, FilterEvent) != NULL) {
390 FreePool (FilterDriver);
391 return EFI_ALREADY_STARTED;
392 }
393 //
394 // Make insertion an atomic operation with the lock.
395 //
396 EfiAcquireLock (&Private->DataLock);
397 InsertTailList (&Private->FilterDriverListHead, &FilterDriver->Link);
398 EfiReleaseLock (&Private->DataLock);
399
400 //
401 // Signal the Filter driver we just loaded so they will recieve all the
402 // previous history. If we did not signal here we would have to wait until
403 // the next data was logged to get the history. In a case where no next
404 // data was logged we would never get synced up.
405 //
406 gBS->SignalEvent (FilterEvent);
407
408 return EFI_SUCCESS;
409 }
410
411 STATIC
412 EFI_STATUS
413 EFIAPI
414 DataHubUnregisterFilterDriver (
415 IN EFI_DATA_HUB_PROTOCOL *This,
416 IN EFI_EVENT FilterEvent
417 )
418 /*++
419
420 Routine Description:
421
422 Remove a Filter Driver, so it no longer gets called when data
423 information is logged.
424
425 Arguments:
426
427 This - Protocol instance structure
428
429 FilterEvent - Event that represents a filter driver that is to be
430 Unregistered.
431
432 Returns:
433
434 EFI_SUCCESS - If FilterEvent was unregistered
435
436 EFI_NOT_FOUND - If FilterEvent does not exist
437
438 --*/
439 {
440 DATA_HUB_INSTANCE *Private;
441 DATA_HUB_FILTER_DRIVER *FilterDriver;
442
443 Private = DATA_HUB_INSTANCE_FROM_THIS (This);
444
445 //
446 // Search for duplicate entries
447 //
448 FilterDriver = FindFilterDriverByEvent (
449 &Private->FilterDriverListHead,
450 FilterEvent
451 );
452 if (FilterDriver == NULL) {
453 return EFI_NOT_FOUND;
454 }
455 //
456 // Make removal an atomic operation with the lock
457 //
458 EfiAcquireLock (&Private->DataLock);
459 RemoveEntryList (&FilterDriver->Link);
460 EfiReleaseLock (&Private->DataLock);
461
462 return EFI_SUCCESS;
463 }
464 //
465 // STATIC Worker fucntions follow
466 //
467 STATIC
468 DATA_HUB_FILTER_DRIVER *
469 FindFilterDriverByEvent (
470 IN LIST_ENTRY *Head,
471 IN EFI_EVENT Event
472 )
473 /*++
474
475 Routine Description:
476 Search the Head list for a EFI_DATA_HUB_FILTER_DRIVER member that
477 represents Event and return it.
478
479 Arguments:
480
481 Head - Head of dual linked list of EFI_DATA_HUB_FILTER_DRIVER
482 structures.
483
484 Event - Event to be search for in the Head list.
485
486 Returns:
487
488 EFI_DATA_HUB_FILTER_DRIVER - Returned if Event stored in the
489 Head doubly linked list.
490
491 NULL - If Event is not in the list
492
493 --*/
494 {
495 DATA_HUB_FILTER_DRIVER *FilterEntry;
496 LIST_ENTRY *Link;
497
498 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
499 FilterEntry = FILTER_ENTRY_FROM_LINK (Link);
500 if (FilterEntry->Event == Event) {
501 return FilterEntry;
502 }
503 }
504
505 return NULL;
506 }
507
508 STATIC
509 EFI_DATA_RECORD_HEADER *
510 GetNextDataRecord (
511 IN LIST_ENTRY *Head,
512 IN UINT64 ClassFilter,
513 IN OUT UINT64 *PtrCurrentMTC
514 )
515 /*++
516
517 Routine Description:
518 Search the Head doubly linked list for the passed in MTC. Return the
519 matching element in Head and the MTC on the next entry.
520
521 Arguments:
522
523 Head - Head of Data Log linked list.
524
525 ClassFilter - Only match the MTC if it is in the same Class as the
526 ClassFilter.
527
528 PtrCurrentMTC - On IN contians MTC to search for. On OUT contians next
529 MTC in the data log list or zero if at end of the list.
530
531 Returns:
532
533 EFI_DATA_LOG_ENTRY - Return pointer to data log data from Head list.
534
535 NULL - If no data record exists.
536
537 --*/
538 {
539 EFI_DATA_ENTRY *LogEntry;
540 LIST_ENTRY *Link;
541 BOOLEAN ReturnFirstEntry;
542 EFI_DATA_RECORD_HEADER *Record;
543 EFI_DATA_ENTRY *NextLogEntry;
544
545 //
546 // If MonotonicCount == 0 just return the first one
547 //
548 ReturnFirstEntry = (BOOLEAN) (*PtrCurrentMTC == 0);
549
550 Record = NULL;
551 for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
552 LogEntry = DATA_ENTRY_FROM_LINK (Link);
553 if ((LogEntry->Record->DataRecordClass & ClassFilter) == 0) {
554 //
555 // Skip any entry that does not have the correct ClassFilter
556 //
557 continue;
558 }
559
560 if ((LogEntry->Record->LogMonotonicCount == *PtrCurrentMTC) || ReturnFirstEntry) {
561 //
562 // Return record to the user
563 //
564 Record = LogEntry->Record;
565
566 //
567 // Calculate the next MTC value. If there is no next entry set
568 // MTC to zero.
569 //
570 *PtrCurrentMTC = 0;
571 for (Link = Link->ForwardLink; Link != Head; Link = Link->ForwardLink) {
572 NextLogEntry = DATA_ENTRY_FROM_LINK (Link);
573 if ((NextLogEntry->Record->DataRecordClass & ClassFilter) != 0) {
574 //
575 // Return the MTC of the next thing to search for if found
576 //
577 *PtrCurrentMTC = NextLogEntry->Record->LogMonotonicCount;
578 break;
579 }
580 }
581 //
582 // Record found exit loop and return
583 //
584 break;
585 }
586 }
587
588 return Record;
589 }
590 //
591 // Module Global:
592 // Since this driver will only ever produce one instance of the Logging Hub
593 // protocol you are not required to dynamically allocate the PrivateData.
594 //
595 DATA_HUB_INSTANCE mPrivateData;
596
597 EFI_STATUS
598 EFIAPI
599 DataHubInstall (
600 IN EFI_HANDLE ImageHandle,
601 IN EFI_SYSTEM_TABLE *SystemTable
602 )
603 /*++
604
605 Routine Description:
606 Install Driver to produce Data Hub protocol.
607
608 Arguments:
609 (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT)
610
611 Returns:
612
613 EFI_SUCCESS - Logging Hub protocol installed
614
615 Other - No protocol installed, unload driver.
616
617 --*/
618 {
619 EFI_STATUS Status;
620 UINT32 HighMontonicCount;
621
622 mPrivateData.Signature = DATA_HUB_INSTANCE_SIGNATURE;
623 mPrivateData.DataHub.LogData = DataHubLogData;
624 mPrivateData.DataHub.GetNextRecord = DataHubGetNextRecord;
625 mPrivateData.DataHub.RegisterFilterDriver = DataHubRegisterFilterDriver;
626 mPrivateData.DataHub.UnregisterFilterDriver = DataHubUnregisterFilterDriver;
627
628 //
629 // Initialize Private Data in CORE_LOGGING_HUB_INSTANCE that is
630 // required by this protocol
631 //
632 InitializeListHead (&mPrivateData.DataListHead);
633 InitializeListHead (&mPrivateData.FilterDriverListHead);
634
635 EfiInitializeLock (&mPrivateData.DataLock, TPL_NOTIFY);
636
637 //
638 // Make sure we get a bigger MTC number on every boot!
639 //
640 Status = gRT->GetNextHighMonotonicCount (&HighMontonicCount);
641 if (EFI_ERROR (Status)) {
642 //
643 // if system service fails pick a sane value.
644 //
645 mPrivateData.GlobalMonotonicCount = 0;
646 } else {
647 mPrivateData.GlobalMonotonicCount = LShiftU64 ((UINT64) HighMontonicCount, 32);
648 }
649 //
650 // Make a new handle and install the protocol
651 //
652 mPrivateData.Handle = NULL;
653 Status = gBS->InstallProtocolInterface (
654 &mPrivateData.Handle,
655 &gEfiDataHubProtocolGuid,
656 EFI_NATIVE_INTERFACE,
657 &mPrivateData.DataHub
658 );
659 return Status;
660 }