//********************************************************************** //********************************************************************** //** ** //** (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).
// 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 // // //********************************************************************** // // // Name: DataHub_c // // Description: Log data to be retrieved by functions or call events // for data matching filter. // // //********************************************************************** #include #include EFI_GUID gDataHubProtocolGuid = EFI_DATA_HUB_PROTOCOL_GUID; //********************************************************************** // // // 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. // // //********************************************************************** typedef struct _DATA_RECORD DATA_RECORD; struct _DATA_RECORD { DATA_RECORD *Link; EFI_DATA_RECORD_HEADER RecordHeader; }; //********************************************************************** // // // 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. // // //********************************************************************** 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. //********************************************************************** // // // 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. // // //********************************************************************** 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; } //********************************************************************** // // // 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. // // //********************************************************************** 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; } //********************************************************************** // // // 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. // // //********************************************************************** 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. } //********************************************************************** // // // 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. // // //********************************************************************** 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; } //********************************************************************** // // // 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. // // //********************************************************************** 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 }; //********************************************************************** // // // 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. // // //********************************************************************** 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 ** //** ** //********************************************************************** //**********************************************************************