+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation \r
+All rights reserved. This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution. The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php \r
+ \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+Module Name:\r
+\r
+ DataHub.c\r
+\r
+Abstract:\r
+\r
+ This code produces the Data Hub protocol. It preloads the data hub\r
+ with status information copied in from PEI HOBs.\r
+ \r
+ Only code that implements the Data Hub protocol should go in this file!\r
+\r
+ The Term MTC stands for MonoTonicCounter. \r
+\r
+ For more information please look at DataHub.doc\r
+\r
+ NOTE: For extra security of the log GetNextDataRecord () could return a copy\r
+ of the data record.\r
+--*/\r
+\r
+#include "DataHub.h"\r
+\r
+CONST EFI_GUID gZeroGuid = { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } };\r
+\r
+//\r
+// Worker functions private to this file\r
+//\r
+STATIC\r
+DATA_HUB_FILTER_DRIVER *\r
+FindFilterDriverByEvent (\r
+ IN LIST_ENTRY *Head,\r
+ IN EFI_EVENT Event\r
+ );\r
+\r
+STATIC\r
+EFI_DATA_RECORD_HEADER *\r
+GetNextDataRecord (\r
+ IN LIST_ENTRY *Head,\r
+ IN UINT64 ClassFilter,\r
+ IN OUT UINT64 *PtrCurrentMTC\r
+ );\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+DataHubLogData (\r
+ IN EFI_DATA_HUB_PROTOCOL *This,\r
+ IN EFI_GUID *DataRecordGuid,\r
+ IN EFI_GUID *ProducerName,\r
+ IN UINT64 DataRecordClass,\r
+ IN VOID *RawData,\r
+ IN UINT32 RawDataSize\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Log data record into the data logging hub\r
+\r
+Arguments:\r
+\r
+ This - Protocol instance structure\r
+\r
+ DataRecordGuid - GUID that defines record contents\r
+\r
+ ProducerName - GUID that defines the name of the producer of the data\r
+\r
+ DataRecordClass - Class that defines generic record type\r
+\r
+ RawData - Data Log record as defined by DataRecordGuid\r
+ \r
+ RawDataSize - Size of Data Log data in bytes\r
+\r
+Returns: \r
+\r
+ EFI_SUCCESS - If data was logged\r
+\r
+ EFI_OUT_OF_RESOURCES - If data was not logged due to lack of system \r
+ resources.\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ DATA_HUB_INSTANCE *Private;\r
+ EFI_DATA_ENTRY *LogEntry;\r
+ UINT32 TotalSize;\r
+ UINT32 RecordSize;\r
+ EFI_DATA_RECORD_HEADER *Record;\r
+ VOID *Raw;\r
+ DATA_HUB_FILTER_DRIVER *FilterEntry;\r
+ LIST_ENTRY *Link;\r
+ LIST_ENTRY *Head;\r
+\r
+ Private = DATA_HUB_INSTANCE_FROM_THIS (This);\r
+\r
+ //\r
+ // Combine the storage for the internal structs and a copy of the log record.\r
+ // Record follows PrivateLogEntry. The consumer will be returned a pointer\r
+ // to Record so we don't what it to be the thing that was allocated from\r
+ // pool, so the consumer can't free an data record by mistake.\r
+ //\r
+ RecordSize = sizeof (EFI_DATA_RECORD_HEADER) + RawDataSize;\r
+ TotalSize = sizeof (EFI_DATA_ENTRY) + RecordSize;\r
+\r
+ //\r
+ // The Logging action is the critical section, so it is locked.\r
+ // The MTC asignment & update, time, and logging must be an\r
+ // atomic operation, so use the lock.\r
+ //\r
+ Status = EfiAcquireLockOrFail (&Private->DataLock);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Reentrancy detected so exit!\r
+ //\r
+ return Status;\r
+ }\r
+\r
+ LogEntry = AllocatePool (TotalSize);\r
+\r
+ if (LogEntry == NULL) {\r
+ EfiReleaseLock (&Private->DataLock);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ ZeroMem (LogEntry, TotalSize);\r
+\r
+ Record = (EFI_DATA_RECORD_HEADER *) (LogEntry + 1);\r
+ Raw = (VOID *) (Record + 1);\r
+\r
+ //\r
+ // Build Standard Log Header\r
+ //\r
+ Record->Version = EFI_DATA_RECORD_HEADER_VERSION;\r
+ Record->HeaderSize = sizeof (EFI_DATA_RECORD_HEADER);\r
+ Record->RecordSize = RecordSize;\r
+ CopyMem (&Record->DataRecordGuid, DataRecordGuid, sizeof (EFI_GUID));\r
+ CopyMem (&Record->ProducerName, ProducerName, sizeof (EFI_GUID));\r
+ Record->DataRecordClass = DataRecordClass;\r
+\r
+ Record->LogMonotonicCount = Private->GlobalMonotonicCount++;\r
+\r
+ gRT->GetTime (&Record->LogTime, NULL);\r
+\r
+ //\r
+ // Insert log into the internal linked list.\r
+ //\r
+ LogEntry->Signature = EFI_DATA_ENTRY_SIGNATURE;\r
+ LogEntry->Record = Record;\r
+ LogEntry->RecordSize = sizeof (EFI_DATA_ENTRY) + RawDataSize;\r
+ InsertTailList (&Private->DataListHead, &LogEntry->Link);\r
+\r
+ CopyMem (Raw, RawData, RawDataSize);\r
+\r
+ EfiReleaseLock (&Private->DataLock);\r
+\r
+ //\r
+ // Send Signal to all the filter drivers which are interested\r
+ // in the record's class and guid.\r
+ //\r
+ Head = &Private->FilterDriverListHead;\r
+ for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
+ FilterEntry = FILTER_ENTRY_FROM_LINK (Link);\r
+ if (((FilterEntry->ClassFilter & DataRecordClass) != 0) &&\r
+ (CompareGuid (&FilterEntry->FilterDataRecordGuid, &gZeroGuid) || \r
+ CompareGuid (&FilterEntry->FilterDataRecordGuid, DataRecordGuid))) {\r
+ gBS->SignalEvent (FilterEntry->Event);\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+DataHubGetNextRecord (\r
+ IN EFI_DATA_HUB_PROTOCOL *This,\r
+ IN OUT UINT64 *MonotonicCount,\r
+ IN EFI_EVENT *FilterDriverEvent, OPTIONAL\r
+ OUT EFI_DATA_RECORD_HEADER **Record\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get a previously logged data record and the MonotonicCount for the next\r
+ availible Record. This allows all records or all records later \r
+ than a give MonotonicCount to be returned. If an optional FilterDriverEvent\r
+ is passed in with a MonotonicCout of zero return the first record \r
+ not yet read by the filter driver. If FilterDriverEvent is NULL and \r
+ MonotonicCount is zero return the first data record.\r
+\r
+Arguments:\r
+\r
+ This - The EFI_DATA_HUB_PROTOCOL instance.\r
+ MonotonicCount - Specifies the Record to return. On input, zero means\r
+ return the first record. On output, contains the next\r
+ record to availible. Zero indicates no more records.\r
+ FilterDriverEvent - If FilterDriverEvent is not passed in a MonotonicCount \r
+ of zero, it means to return the first data record. \r
+ If FilterDriverEvent is passed in, then a MonotonicCount \r
+ of zero means to return the first data not yet read by \r
+ FilterDriverEvent.\r
+ Record - Returns a dynamically allocated memory buffer with a data \r
+ record that matches MonotonicCount.\r
+\r
+Returns: \r
+\r
+ EFI_SUCCESS - Data was returned in Record.\r
+ EFI_INVALID_PARAMETER - FilterDriverEvent was passed in but does not exist.\r
+ EFI_NOT_FOUND - MonotonicCount does not match any data record in the\r
+ system. If a MonotonicCount of zero was passed in, then\r
+ no data records exist in the system.\r
+ EFI_OUT_OF_RESOURCES - Record was not returned due to lack of system resources.\r
+\r
+--*/\r
+{\r
+ DATA_HUB_INSTANCE *Private;\r
+ DATA_HUB_FILTER_DRIVER *FilterDriver;\r
+ UINT64 ClassFilter;\r
+ UINT64 FilterMonotonicCount;\r
+\r
+ Private = DATA_HUB_INSTANCE_FROM_THIS (This);\r
+\r
+ FilterDriver = NULL;\r
+ FilterMonotonicCount = 0;\r
+ ClassFilter = EFI_DATA_RECORD_CLASS_DEBUG |\r
+ EFI_DATA_RECORD_CLASS_ERROR |\r
+ EFI_DATA_RECORD_CLASS_DATA |\r
+ EFI_DATA_RECORD_CLASS_PROGRESS_CODE;\r
+\r
+ if (FilterDriverEvent != NULL) {\r
+ //\r
+ // For events the beginning is the last unread record. This info is\r
+ // stored in the instance structure, so we must look up the event\r
+ // to get the data.\r
+ //\r
+ FilterDriver = FindFilterDriverByEvent (\r
+ &Private->FilterDriverListHead,\r
+ *FilterDriverEvent\r
+ );\r
+ if (FilterDriver == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Use the Class filter the event was created with.\r
+ //\r
+ ClassFilter = FilterDriver->ClassFilter;\r
+\r
+ if (*MonotonicCount == 0) {\r
+ //\r
+ // Use the MTC from the Filter Driver.\r
+ //\r
+ FilterMonotonicCount = FilterDriver->GetNextMonotonicCount;\r
+ if (FilterMonotonicCount != 0) {\r
+ //\r
+ // The GetNextMonotonicCount field remembers the last value from the previous time.\r
+ // But we already processed this vaule, so we need to find the next one. So if\r
+ // It is not the first time get the new record entry.\r
+ //\r
+ *Record = GetNextDataRecord (&Private->DataListHead, ClassFilter, &FilterMonotonicCount);\r
+ *MonotonicCount = FilterMonotonicCount;\r
+ if (FilterMonotonicCount == 0) {\r
+ //\r
+ // If there is no new record to get exit now.\r
+ //\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // Return the record\r
+ //\r
+ *Record = GetNextDataRecord (&Private->DataListHead, ClassFilter, MonotonicCount);\r
+ if (*Record == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ if (FilterDriver != NULL) {\r
+ //\r
+ // If we have a filter driver update the records that have been read.\r
+ // If MonotonicCount is zero No more reacords left.\r
+ //\r
+ if (*MonotonicCount == 0) {\r
+ if (FilterMonotonicCount != 0) {\r
+ //\r
+ // Return the result of our extra GetNextDataRecord.\r
+ //\r
+ FilterDriver->GetNextMonotonicCount = FilterMonotonicCount;\r
+ }\r
+ } else {\r
+ //\r
+ // Point to next undread record\r
+ //\r
+ FilterDriver->GetNextMonotonicCount = *MonotonicCount;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+DataHubRegisterFilterDriver (\r
+ IN EFI_DATA_HUB_PROTOCOL * This,\r
+ IN EFI_EVENT FilterEvent,\r
+ IN EFI_TPL FilterTpl,\r
+ IN UINT64 FilterClass,\r
+ IN EFI_GUID * FilterDataRecordGuid OPTIONAL\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This function registers the data hub filter driver that is represented \r
+ by FilterEvent. Only one instance of each FilterEvent can be registered.\r
+ After the FilterEvent is registered, it will be signaled so it can sync \r
+ with data records that have been recorded prior to the FilterEvent being \r
+ registered.\r
+ \r
+Arguments:\r
+\r
+ This - The EFI_DATA_HUB_PROTOCOL instance.\r
+ FilterEvent - The EFI_EVENT to signal whenever data that matches \r
+ FilterClass is logged in the system.\r
+ FilterTpl - The maximum EFI_TPL at which FilterEvent can be \r
+ signaled. It is strongly recommended that you use the \r
+ lowest EFI_TPL possible.\r
+ FilterClass - FilterEvent will be signaled whenever a bit in \r
+ EFI_DATA_RECORD_HEADER.DataRecordClass is also set in \r
+ FilterClass. If FilterClass is zero, no class-based \r
+ filtering will be performed.\r
+ FilterDataRecordGuid - FilterEvent will be signaled whenever FilterDataRecordGuid \r
+ matches EFI_DATA_RECORD_HEADER.DataRecordGuid. If \r
+ FilterDataRecordGuid is NULL, then no GUID-based filtering \r
+ will be performed. \r
+Returns: \r
+\r
+ EFI_SUCCESS - The filter driver event was registered.\r
+ EFI_ALREADY_STARTED - FilterEvent was previously registered and cannot be \r
+ registered again.\r
+ EFI_OUT_OF_RESOURCES - The filter driver event was not registered due to lack of \r
+ system resources.\r
+\r
+--*/\r
+{\r
+ DATA_HUB_INSTANCE *Private;\r
+ DATA_HUB_FILTER_DRIVER *FilterDriver;\r
+\r
+ Private = DATA_HUB_INSTANCE_FROM_THIS (This);\r
+\r
+ FilterDriver = (DATA_HUB_FILTER_DRIVER *) AllocateZeroPool (sizeof (DATA_HUB_FILTER_DRIVER));\r
+ if (FilterDriver == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // Initialize filter driver info\r
+ //\r
+ FilterDriver->Signature = EFI_DATA_HUB_FILTER_DRIVER_SIGNATURE;\r
+ FilterDriver->Event = FilterEvent;\r
+ FilterDriver->Tpl = FilterTpl;\r
+ FilterDriver->GetNextMonotonicCount = 0;\r
+ if (FilterClass == 0) {\r
+ FilterDriver->ClassFilter = EFI_DATA_RECORD_CLASS_DEBUG |\r
+ EFI_DATA_RECORD_CLASS_ERROR |\r
+ EFI_DATA_RECORD_CLASS_DATA |\r
+ EFI_DATA_RECORD_CLASS_PROGRESS_CODE;\r
+ } else {\r
+ FilterDriver->ClassFilter = FilterClass;\r
+ }\r
+\r
+ if (FilterDataRecordGuid != NULL) {\r
+ CopyMem (&FilterDriver->FilterDataRecordGuid, FilterDataRecordGuid, sizeof (EFI_GUID));\r
+ }\r
+ //\r
+ // Search for duplicate entries\r
+ //\r
+ if (FindFilterDriverByEvent (&Private->FilterDriverListHead, FilterEvent) != NULL) {\r
+ FreePool (FilterDriver);\r
+ return EFI_ALREADY_STARTED;\r
+ }\r
+ //\r
+ // Make insertion an atomic operation with the lock.\r
+ //\r
+ EfiAcquireLock (&Private->DataLock);\r
+ InsertTailList (&Private->FilterDriverListHead, &FilterDriver->Link);\r
+ EfiReleaseLock (&Private->DataLock);\r
+\r
+ //\r
+ // Signal the Filter driver we just loaded so they will recieve all the\r
+ // previous history. If we did not signal here we would have to wait until\r
+ // the next data was logged to get the history. In a case where no next\r
+ // data was logged we would never get synced up.\r
+ //\r
+ gBS->SignalEvent (FilterEvent);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+DataHubUnregisterFilterDriver (\r
+ IN EFI_DATA_HUB_PROTOCOL *This,\r
+ IN EFI_EVENT FilterEvent\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Remove a Filter Driver, so it no longer gets called when data \r
+ information is logged.\r
+\r
+Arguments:\r
+\r
+ This - Protocol instance structure\r
+\r
+ FilterEvent - Event that represents a filter driver that is to be \r
+ Unregistered.\r
+\r
+Returns: \r
+\r
+ EFI_SUCCESS - If FilterEvent was unregistered\r
+\r
+ EFI_NOT_FOUND - If FilterEvent does not exist\r
+\r
+--*/\r
+{\r
+ DATA_HUB_INSTANCE *Private;\r
+ DATA_HUB_FILTER_DRIVER *FilterDriver;\r
+\r
+ Private = DATA_HUB_INSTANCE_FROM_THIS (This);\r
+\r
+ //\r
+ // Search for duplicate entries\r
+ //\r
+ FilterDriver = FindFilterDriverByEvent (\r
+ &Private->FilterDriverListHead,\r
+ FilterEvent\r
+ );\r
+ if (FilterDriver == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ //\r
+ // Make removal an atomic operation with the lock\r
+ //\r
+ EfiAcquireLock (&Private->DataLock);\r
+ RemoveEntryList (&FilterDriver->Link);\r
+ EfiReleaseLock (&Private->DataLock);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+//\r
+// STATIC Worker fucntions follow\r
+//\r
+STATIC\r
+DATA_HUB_FILTER_DRIVER *\r
+FindFilterDriverByEvent (\r
+ IN LIST_ENTRY *Head,\r
+ IN EFI_EVENT Event\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Search the Head list for a EFI_DATA_HUB_FILTER_DRIVER member that\r
+ represents Event and return it.\r
+\r
+Arguments:\r
+\r
+ Head - Head of dual linked list of EFI_DATA_HUB_FILTER_DRIVER\r
+ structures.\r
+\r
+ Event - Event to be search for in the Head list.\r
+\r
+Returns: \r
+\r
+ EFI_DATA_HUB_FILTER_DRIVER - Returned if Event stored in the\r
+ Head doubly linked list.\r
+\r
+ NULL - If Event is not in the list\r
+\r
+--*/\r
+{\r
+ DATA_HUB_FILTER_DRIVER *FilterEntry;\r
+ LIST_ENTRY *Link;\r
+\r
+ for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
+ FilterEntry = FILTER_ENTRY_FROM_LINK (Link);\r
+ if (FilterEntry->Event == Event) {\r
+ return FilterEntry;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+STATIC\r
+EFI_DATA_RECORD_HEADER *\r
+GetNextDataRecord (\r
+ IN LIST_ENTRY *Head,\r
+ IN UINT64 ClassFilter,\r
+ IN OUT UINT64 *PtrCurrentMTC\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Search the Head doubly linked list for the passed in MTC. Return the \r
+ matching element in Head and the MTC on the next entry.\r
+\r
+Arguments:\r
+\r
+ Head - Head of Data Log linked list.\r
+\r
+ ClassFilter - Only match the MTC if it is in the same Class as the\r
+ ClassFilter.\r
+\r
+ PtrCurrentMTC - On IN contians MTC to search for. On OUT contians next\r
+ MTC in the data log list or zero if at end of the list.\r
+ \r
+Returns:\r
+\r
+ EFI_DATA_LOG_ENTRY - Return pointer to data log data from Head list.\r
+\r
+ NULL - If no data record exists.\r
+\r
+--*/\r
+{\r
+ EFI_DATA_ENTRY *LogEntry;\r
+ LIST_ENTRY *Link;\r
+ BOOLEAN ReturnFirstEntry;\r
+ EFI_DATA_RECORD_HEADER *Record;\r
+ EFI_DATA_ENTRY *NextLogEntry;\r
+\r
+ //\r
+ // If MonotonicCount == 0 just return the first one\r
+ //\r
+ ReturnFirstEntry = (BOOLEAN) (*PtrCurrentMTC == 0);\r
+\r
+ Record = NULL;\r
+ for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
+ LogEntry = DATA_ENTRY_FROM_LINK (Link);\r
+ if ((LogEntry->Record->DataRecordClass & ClassFilter) == 0) {\r
+ //\r
+ // Skip any entry that does not have the correct ClassFilter\r
+ //\r
+ continue;\r
+ }\r
+\r
+ if ((LogEntry->Record->LogMonotonicCount == *PtrCurrentMTC) || ReturnFirstEntry) {\r
+ //\r
+ // Return record to the user\r
+ //\r
+ Record = LogEntry->Record;\r
+\r
+ //\r
+ // Calculate the next MTC value. If there is no next entry set\r
+ // MTC to zero.\r
+ //\r
+ *PtrCurrentMTC = 0;\r
+ for (Link = Link->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
+ NextLogEntry = DATA_ENTRY_FROM_LINK (Link);\r
+ if ((NextLogEntry->Record->DataRecordClass & ClassFilter) != 0) {\r
+ //\r
+ // Return the MTC of the next thing to search for if found\r
+ //\r
+ *PtrCurrentMTC = NextLogEntry->Record->LogMonotonicCount;\r
+ break;\r
+ }\r
+ }\r
+ //\r
+ // Record found exit loop and return\r
+ //\r
+ break;\r
+ }\r
+ }\r
+\r
+ return Record;\r
+}\r
+//\r
+// Module Global:\r
+// Since this driver will only ever produce one instance of the Logging Hub\r
+// protocol you are not required to dynamically allocate the PrivateData.\r
+//\r
+DATA_HUB_INSTANCE mPrivateData;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+DataHubInstall (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Install Driver to produce Data Hub protocol. \r
+\r
+Arguments:\r
+ (Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT)\r
+\r
+Returns: \r
+\r
+ EFI_SUCCESS - Logging Hub protocol installed\r
+\r
+ Other - No protocol installed, unload driver.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 HighMontonicCount;\r
+\r
+ mPrivateData.Signature = DATA_HUB_INSTANCE_SIGNATURE;\r
+ mPrivateData.DataHub.LogData = DataHubLogData;\r
+ mPrivateData.DataHub.GetNextRecord = DataHubGetNextRecord;\r
+ mPrivateData.DataHub.RegisterFilterDriver = DataHubRegisterFilterDriver;\r
+ mPrivateData.DataHub.UnregisterFilterDriver = DataHubUnregisterFilterDriver;\r
+\r
+ //\r
+ // Initialize Private Data in CORE_LOGGING_HUB_INSTANCE that is\r
+ // required by this protocol\r
+ //\r
+ InitializeListHead (&mPrivateData.DataListHead);\r
+ InitializeListHead (&mPrivateData.FilterDriverListHead);\r
+\r
+ EfiInitializeLock (&mPrivateData.DataLock, TPL_NOTIFY);\r
+\r
+ //\r
+ // Make sure we get a bigger MTC number on every boot!\r
+ //\r
+ Status = gRT->GetNextHighMonotonicCount (&HighMontonicCount);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // if system service fails pick a sane value.\r
+ //\r
+ mPrivateData.GlobalMonotonicCount = 0;\r
+ } else {\r
+ mPrivateData.GlobalMonotonicCount = LShiftU64 ((UINT64) HighMontonicCount, 32);\r
+ }\r
+ //\r
+ // Make a new handle and install the protocol\r
+ //\r
+ mPrivateData.Handle = NULL;\r
+ Status = gBS->InstallProtocolInterface (\r
+ &mPrivateData.Handle,\r
+ &gEfiDataHubProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ &mPrivateData.DataHub\r
+ );\r
+ return Status;\r
+}\r