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