diff options
author | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
---|---|---|
committer | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
commit | b7c51c9cf4864df6aabb99a1ae843becd577237c (patch) | |
tree | eebe9b0d0ca03062955223097e57da84dd618b9a /Core/CORE_DXE/DataHub.c | |
download | zprj-master.tar.xz |
Diffstat (limited to 'Core/CORE_DXE/DataHub.c')
-rw-r--r-- | Core/CORE_DXE/DataHub.c | 681 |
1 files changed, 681 insertions, 0 deletions
diff --git a/Core/CORE_DXE/DataHub.c b/Core/CORE_DXE/DataHub.c new file mode 100644 index 0000000..c2aa760 --- /dev/null +++ b/Core/CORE_DXE/DataHub.c @@ -0,0 +1,681 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2007, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 6145-F Northbelt Pkwy, Norcross, GA 30071 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** + +//********************************************************************** +// $Header: /Alaska/SOURCE/Core/CORE_DXE/DataHub.c 5 7/08/09 5:54p Vyacheslava $ +// +// $Revision: 5 $ +// +// $Date: 7/08/09 5:54p $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Core/CORE_DXE/DataHub.c $ +// +// 5 7/08/09 5:54p Vyacheslava +// Updated according to the coding standards. +// +// 4 12/16/08 1:32a Iminglin +// The function value of FindNextFiltermatch for compliance. +// +// 3 11/07/07 12:13p Felixp +// Bug fixes in record filtering logic. +// Old code was treating FilterClass parameter passed into +// RegisterFilterDriver routine as requested class value. +// However, data hub specification defines this parameter as a bit map of +// requested data classes. +// +// 2 9/05/07 5:51p Felixp +// 1. LogData routine is updated. +// Core that initializes RecordSize field of the data hub record +// header is updated to include header size (the header size was excluded +// in the previous Core verions).<br /> +// DataHub specification is vague regarding the RecordSize field. +// It says RecordSize is "Size of the data in the record in +// bytes". +// It's not clear if it should include or exclude the header size. +// In EDK DataHub implenetation RecordSize includes the header. +// Aptio implementation is updated to comply with EDK +// implementation. +// 2. When time is not available initialize time fields with default +// values +// +// 1 1/28/05 12:45p Felixp +// +// 2 1/18/05 3:22p Felixp +// PrintDebugMessage renamed to Trace +// +// 1 12/22/04 6:19p Admin +// +// 1 12/22/04 6:18p Admin +// +// 6 11/12/04 3:13p Markw +// Added signal event, to get previously logged data. +// +// 5 4/17/04 4:23p Felixp +// +// 4 3/24/04 10:17a Markw +// Using AmiDxeLib instead AmiLib. +// +// 3 3/23/04 5:45p Markw +// Added function and table headers (comments) to the file. +// +// 2 3/20/04 10:46a Felixp +// +// 1 3/16/04 2:38p Markw +// +// +//********************************************************************** +//<AMI_FHDR_START> +// +// Name: DataHub_c +// +// Description: Log data to be retrieved by functions or call events +// for data matching filter. +// +//<AMI_FHDR_END> +//********************************************************************** + +#include <AmiDxeLib.h> +#include <Protocol\DataHub.h> + +EFI_GUID gDataHubProtocolGuid = EFI_DATA_HUB_PROTOCOL_GUID; + +//********************************************************************** +//<AMI_THDR_START> +// +// Name: DATA_RECORD +// +// Description: This structure describes the Data Record header and data. +// +// Fields: +// Name Type Description +// ------------------------------------------------------------ +// Link DATA_RECORD* Next link +// RecordHeader EFI_DATA_RECORD_HEADER Log Record Header +/// +// Directly following Header (&RecordHeader + 1) is the data. +// +//<AMI_THDR_END> +//********************************************************************** + +typedef struct _DATA_RECORD DATA_RECORD; +struct _DATA_RECORD { + DATA_RECORD *Link; + EFI_DATA_RECORD_HEADER RecordHeader; +}; + +//********************************************************************** +//<AMI_THDR_START> +// +// Name: FILTER +// +// Description: This structure describes the filter link. +// +// Fields: +// Name Type Description +// ------------------------------------------------------------ +// Link FILTER* Next link +// Event EFI_EVENT Event +// Class UINT64 Class (0 if no class filtering) +// DataRecordGuid EFI_GUID Guid (undefined in no guid filtering) +// isGuid BOOLEAN TRUE if guid filtering. +// LastRead DATA_RECORD* Last read record for the filter. +// +//<AMI_THDR_END> +//********************************************************************** + +typedef struct _FILTER FILTER; +struct _FILTER { + FILTER *Link; + EFI_EVENT Event; + UINT64 Class; + EFI_GUID DataRecordGuid; + BOOLEAN isGuid; + DATA_RECORD *LastRead; +}; + + +FILTER *gFilHead = 0; //Filter Head +DATA_RECORD *gHead = 0; //Data Record Head +DATA_RECORD *gTail = 0; //Data Record Count +UINT64 gLogCount = 0; //Unique log count. +DATA_RECORD *gCache = 0; //Last reocrd cache. + + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: FindNextFilterMatch +// +// Description: Search log to find next record that matches filter. +// +// Input: +// DATA_RECORD *Record +// FILTER *Filter +// +// Output: DATA_RECORD* +// +// Referrals: guidcmp +// +// Notes: +// Here is the control flow of this function: +// 1. Starting at the current record for filter matching. +// 2. If Class and Class doesn't match continue at step 1 for next record. +// 3. If guid and DataRecordGuid doesn't match continue at step 1 for next record. +// 4. Match, return record. +// 5. If Steps 1-4, doesn't find any matching filter, return 0. +// +//<AMI_PHDR_END> +//********************************************************************** + +DATA_RECORD* FindNextFilterMatch( + DATA_RECORD *Record, + FILTER *Filter) +{ + for (; Record; Record=Record->Link) { + if ( Filter->Class && + !(Filter->Class & Record->RecordHeader.DataRecordClass) ) + continue; + + if ( Filter->isGuid && + guidcmp(&Filter->DataRecordGuid,&Record->RecordHeader.DataRecordGuid) != 0 ) + continue; + + return Record; + } + + return NULL; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: LogData +// +// Description: Log the record. If matching event, signal it. +// +// Input: +// IN EFI_DATA_HUB_PROTOCOL *This +// IN EFI_GUID *DataRecordGuid +// IN EFI_GUID *ProducerName +// IN UINT64 DataRecordClass +// IN VOID *RawData +// IN UINT32 RawDataSize +// +// Output: +// EFI_STATUS +// * EFI_SUCCESS - Event logged. +// * EFI_OUT_OF_RESOUCES - Not enough resources to log data. +// +// Modified: gHead gTail +// +// Referrals: AllocatePool +// +// Notes: +// Here is the control flow of this function: +// 1. Allocate memory enough for data record. If not enough memory, return EFI_OUT_OF_RESOURCES. +// 2. Fill data record header and increase log count. +// 3. Fill data to log. +// 4. Add record to log. +// 5. Check for a matching filter. +// 6. If matching filter, signal event. +// 7. Return EFI_SUCCESS. +// +//<AMI_PHDR_END> +//********************************************************************** + +EFI_STATUS LogData( + IN EFI_DATA_HUB_PROTOCOL *This, + IN EFI_GUID *DataRecordGuid, + IN EFI_GUID *ProducerName, + IN UINT64 DataRecordClass, + IN VOID *RawData, + IN UINT32 RawDataSize +) +{ + EFI_DATA_RECORD_HEADER *RcdHdr; + DATA_RECORD *Record; + FILTER *Filter; + UINT8 *Data; + EFI_STATUS Status; + + //16 dummy bytes to make sure struct alignment isn't an issue in platform. + if ( pBS->AllocatePool( + EfiBootServicesData, + sizeof(DATA_RECORD) + RawDataSize + 16, + &Record ) != EFI_SUCCESS ) + return EFI_OUT_OF_RESOURCES; + + RcdHdr = &Record->RecordHeader; + + Record->Link = 0; + RcdHdr->Version = EFI_DATA_RECORD_HEADER_VERSION; + RcdHdr->HeaderSize = sizeof(EFI_DATA_RECORD_HEADER); +//DataHub specification is vague regarding the RecordSize field. +//It says RecordSize is "Size of the data in the record in bytes". +//It's not clear if it should include or exclude the header size. +//It's sounds more like it should not, however, +//in EDK DataHub implenetation RecordSize includes the header. +//For the sake of compatibility let's do the same. + RcdHdr->RecordSize = RawDataSize+sizeof(EFI_DATA_RECORD_HEADER); + RcdHdr->DataRecordGuid = *DataRecordGuid; + RcdHdr->ProducerName = *ProducerName; + RcdHdr->DataRecordClass = DataRecordClass; + RcdHdr->LogMonotonicCount = ++gLogCount; //Each log count must be unique. + Status = pRS->GetTime(&(RcdHdr->LogTime),NULL); + + if (EFI_ERROR(Status)) { //time not available, set default values + RcdHdr->LogTime.Year = 0; + RcdHdr->LogTime.Month = 1; + RcdHdr->LogTime.Day = 1; + RcdHdr->LogTime.Hour = 0; + RcdHdr->LogTime.Minute = 0; + RcdHdr->LogTime.Second = 0; + } + + //Store data to be logged. + Data = (UINT8*)(RcdHdr + 1); + MemCpy( + Data, + RawData, + RawDataSize + ); + + //Add record to log. + if (!gHead) + gHead = Record; + else + gTail->Link = Record; + + gTail = Record; + + //Check for matching filter. + for (Filter = gFilHead; Filter; Filter = Filter->Link) { + if ( Filter->Class && + !(Filter->Class & DataRecordClass) ) + continue; + + if ( Filter->isGuid && + guidcmp(&Filter->DataRecordGuid, DataRecordGuid) != 0 ) + continue; + + pBS->SignalEvent(Filter->Event); + } + + return EFI_SUCCESS; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: GetNextDataRecord +// +// Description: Search log to find next record that matches Count or filter. +// Return next record or if Filter, next record matching filter. +// +// Input: +// IN EFI_DATA_HUB_PROTOCOL *This +// IN OUT UINT64 *MonotonicCount +// IN EFI_EVENT *FilterDriver OPTIONAL +// OUT EFI_DATA_RECORD_HEADER **Record +// +// Output: +// EFI_STATUS +// * EFI_SUCCESS - If Data Record returned. +// * EFI_NOT_FOUND - Data Record not found. +// * EFI_INVALID_PARAMETER - *FilterDriver doesn't match registered filters. +// +// Modified: gCache +// +// Referrals: FindNextFilterMatch +// +// Notes: +// Here is the control flow of this function: +// 1. If no logged records, return EFI_NOT_FOUND. +// 2. If using FilterDriver, find filter. If filter not found, return EFI_INVALID_PARAMETER; +// 3. If *MonotonicCount != 0, go to step 14. +// ---*MonotonicCount = 0--- +// 4. If no filter driver, set *MonotonicCount = 1, go to step 14. +// ---Filter Driver--- +// 5. If no last read, start at Head. +// 6. If last read, start at the next. If no next, return EFI_NOT_FOUND. +// 7. Find record matching filter. +// 8. If no match, set last read to tail, and return EFI_NOT_FOUND. +// 9. Set *Record to found record, and set LastRead to record. +// 10. Find next match, to get *MonotonicCount. +// 11. If not found, set *MonotonicCount = 0. +// 12. Set cache to link. +// 13. Return EFI_SUCCESS. +// ---MontonicCount exists--- +// 14. Get starting link. If after cache, use cache, otherwise use head. +// 15. Search until log count is found, regardless of filter. +// 16. If not found, return EFI_NOT_FOUND. +// 17. If filter set LastRead. +// 18. If last link, *MontonicCount = 0. Go to step 21. +// ---If not last link,--- +// 19. If FilterDriver, find next match for *MonotonicCounter. +// 20. If no next match, set *MonotonicCounter = 0. +// ------- +// 21. Set cache. Return EFI_SUCCESS. +// +//<AMI_PHDR_END> +//********************************************************************** + +EFI_STATUS GetNextDataRecord( + IN EFI_DATA_HUB_PROTOCOL *This, + IN OUT UINT64 *MonotonicCount, + IN EFI_EVENT *FilterDriver OPTIONAL, + OUT EFI_DATA_RECORD_HEADER **Record +) +{ + DATA_RECORD *Link; + FILTER *Filter; + + if (!gHead) + return EFI_NOT_FOUND; //Any records logged? + + //Find Matching filter + if (FilterDriver) { + //In future, binary search may be more efficient, or some caching. + for (Filter = gFilHead; Filter && Filter->Event != *FilterDriver; Filter = Filter->Link) + ; //Find matching Filter for Event. + + if (!Filter) + return EFI_INVALID_PARAMETER; + } + + //If monotonic count is zero? + if (!*MonotonicCount) { + //If filter driver, get first unread record matching filter. + if (!FilterDriver) { + *MonotonicCount = 1; //If not filter driver, get first record. + + } else { + //Get the record after the last read record. If not, get the first record. + if (Filter->LastRead) + Link = Filter->LastRead->Link; + else + Link = gHead; + + if (!Link) + return EFI_NOT_FOUND; //If record doesn't exist, return EFI_NOT_FOUND. + + if ( !(Link = FindNextFilterMatch(Link, Filter)) ) { //Get record matching filter, zero if no match. + //No matching record. Set LastRead to tail, and return EFI_NOT_FOUND. + Filter->LastRead = gTail; + return EFI_NOT_FOUND; + } + + //Save pointer to matching record, and last read record. + *Record = &Link->RecordHeader; + Filter->LastRead = Link; + + //Find the next matching record to return the next Monotonic Count. + if ( Link = FindNextFilterMatch(Link->Link, Filter) ) //zero if no match. + *MonotonicCount = Link->RecordHeader.LogMonotonicCount; + else + *MonotonicCount = 0; //If no matching record, set last read to end. + + gCache = Link; //Set cache to find the next record. + return EFI_SUCCESS; + } + } + + //Find a specific MonotonicCount. + //If Count is same or after cache, start with cache. Otherwise start at beginning. + if (gCache && gCache->RecordHeader.LogMonotonicCount <= *MonotonicCount) + Link = gCache; + else + Link = gHead; + + //Search for Log. + for (; Link; Link = Link->Link) { + if (Link->RecordHeader.LogMonotonicCount == *MonotonicCount) { + *Record = &Link->RecordHeader; //Save pointer to matching record. + + if (Link == gTail) { //If last log, Count = 0. + *MonotonicCount = 0; + + if (FilterDriver) + Filter->LastRead = Link; //If filter, store last read. + + } else { //If not last log. + if (FilterDriver) { + Filter->LastRead = Link; //Set last read. + + if ( Link = FindNextFilterMatch(Link->Link, Filter) ) + *MonotonicCount = Link->RecordHeader.LogMonotonicCount; //Get count of next matching record. + else + *MonotonicCount = 0; //If no more matching record, set count to 0. + + } else + ++*MonotonicCount; //If not filter driver, increase count. + } + + gCache = Link; //Set cache. + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; //Record does't exist. +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: RegisterFilterDriver +// +// Description: Register new filter driver. +// +// Input: +// IN EFI_DATA_HUB_PROTOCOL *This +// IN EFI_EVENT FilterEvent +// IN EFI_TPL FilterTpl +// IN UINT64 FilterClass +// IN EFI_GUID *FilterDataRecordGuid OPTIONAL +// +// Output: +// EFI_STATUS +// * EFI_SUCCESS - Filter driver registered. +// * EFI_ALREADY_STARTED - Filter driver was already registered. +// * EFI_OUT_OF_RESOURCES - Not enough resources to allocate Link. +// +// Modified: gFilHead +// +// Referrals: AllocatePool +// +// Notes: +// Here is the control flow of this function: +// 1. Search filters for matching Event. If Event return return EFI_ALREADY_STARTED. +// 2. Allocate Link for filter. If out of resources, return EFI_OUT_OF_RESOURCES. +// 3. Fill in filter data. +// 4. Add link to end. +// 5. Return EFI_SUCCESS. +// +//<AMI_PHDR_END> +//********************************************************************** + +EFI_STATUS RegisterFilterDriver( + IN EFI_DATA_HUB_PROTOCOL *This, + IN EFI_EVENT FilterEvent, + IN EFI_TPL FilterTpl, + IN UINT64 FilterClass, + IN EFI_GUID *FilterDataRecordGuid OPTIONAL +) +{ + FILTER *Filter; + FILTER *Link, *PLink; + FILTER **Ptr; + + if (gFilHead) { + for (Link = gFilHead; Link; Link = Link->Link) { + if (Link->Event == FilterEvent) + return EFI_ALREADY_STARTED; + + PLink = Link; + } + + Ptr = &PLink->Link; + + } else + Ptr = &gFilHead; + + if ( pBS->AllocatePool( + EfiBootServicesData, + sizeof(FILTER), + &Filter) != EFI_SUCCESS ) + return EFI_OUT_OF_RESOURCES; + + Filter->Link = 0; + Filter->Event = FilterEvent; + Filter->Class = FilterClass; + Filter->LastRead = NULL; + + if (FilterDataRecordGuid) { //Guid is optional. isGuid, determines if to test Guid. + Filter->DataRecordGuid = *FilterDataRecordGuid; + Filter->isGuid = TRUE; + + } else + Filter->isGuid = FALSE; + + *Ptr = Filter; + + // Signal the Filter driver to get all the previous logged data. Otherwise, + // One must wait until the next signal to get the previous logged data. + pBS->SignalEvent(FilterEvent); + + return EFI_SUCCESS; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: UnregisterFilterDriver +// +// Description: Unregister a filter driver. +// +// Input: +// IN EFI_DATA_HUB_PROTOCOL *This +// IN EFI_EVENT FilterEvent +// +// Output: +// EFI_STATUS +// * EFI_SUCCESS - Filter driver removed. +// * EFI_NOT_FOUND - Filter driver not found. +// +// Modified: gFilHead +// +// Referrals: FreePool +// +// Notes: +// Here is the control flow of this function: +// 1. If no filter drivers, return EFI_NOT_FOUND. +// 2. If filter stored in Filter Driver Head, free filter driver +// and set Head to next link. +// 3. Find filter driver. +// 4. If found, remove link, then free link. Return EFI_SUCCESS. +// 5. If not found, return EFI_NOT_FOUND. +// +//<AMI_PHDR_END> +//********************************************************************** + +EFI_STATUS UnregisterFilterDriver( + IN EFI_DATA_HUB_PROTOCOL *This, + IN EFI_EVENT FilterEvent +) +{ + FILTER *Link, *PLink; + + PLink = gFilHead; + + if (!gFilHead) + return EFI_NOT_FOUND; + + if (gFilHead->Event == FilterEvent) { + gFilHead = gFilHead->Link; + pBS->FreePool(PLink); + return EFI_SUCCESS; + } + + for (Link = gFilHead->Link; Link; Link = Link->Link) { + if (Link->Event == FilterEvent) { + PLink->Link = Link->Link; + pBS->FreePool(Link); + return EFI_SUCCESS; + } + + PLink = Link; + } + + return EFI_NOT_FOUND; +} + +EFI_DATA_HUB_PROTOCOL gDataHub = { + LogData, + GetNextDataRecord, + RegisterFilterDriver, + UnregisterFilterDriver +}; + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: InitDataHub +// +// Description: Install Data Hub Protocol. +// +// Input: +// IN EFI_HANDLE ImageHandle +// IN EFI_SYSTEM_TABLE *SystemTable +// +// Output: EFI_STATUS +// +// Referrals: InstallMultipleProtocolInterfaces +// +// Notes: +// Here is the control flow of this function: +// 1. Install Data Hub Protocol. +// +//<AMI_PHDR_END> +//********************************************************************** + +EFI_STATUS InitDataHub( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable +) +{ + InitAmiLib(ImageHandle, SystemTable); + + return pBS->InstallMultipleProtocolInterfaces( + &ImageHandle, + &gDataHubProtocolGuid, + &gDataHub, + NULL + ); +} + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2007, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 6145-F Northbelt Pkwy, Norcross, GA 30071 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** |