NTSTATUS BlpTimeMeasureTscFrequency ( VOID ) { ULONG Count; INT CpuInfo[4]; ULONGLONG TimeStamp1, TimeStamp2, Delta; /* Check if the ISVM bit it set, meaning we're in a hypervisor */ __cpuid(CpuInfo, 1); Count = CpuInfo[2] & 0x80000000 ? 10 : 1; /* Loop trying to get an accurate TSC */ do { /* Stall for 1us and get count 1 */ EfiStall(1); TimeStamp1 = __rdtsc(); /* Stall for 1000us and get count 2*/ EfiStall(1000); TimeStamp2 = __rdtsc(); /* Stall for 9000us and get the difference */ EfiStall(9000); Delta = __rdtsc() - TimeStamp2; /* Keep going as long as the TSC is fluctuating */ --Count; } while (((TimeStamp2 - TimeStamp1) > Delta) && (Count)); /* Set the frequency based on the two measurements we took */ BlpTimePerformanceFrequency = 125 * (Delta - (TimeStamp2 - TimeStamp1)) & 0x1FFFFFFFFFFFFFF; return STATUS_SUCCESS; }
NTSTATUS BiEnumerateElements ( _In_ HANDLE BcdHandle, _In_ HANDLE ObjectHandle, _In_ ULONG RootElementType, _In_ ULONG Flags, _Out_opt_ PBCD_PACKED_ELEMENT Elements, _Inout_ PULONG ElementSize, _Out_ PULONG ElementCount ) { HANDLE ElementsHandle, ElementHandle; ULONG TotalLength, RegistryElementDataLength, RemainingLength; NTSTATUS Status; ULONG i; PVOID ElementData, SubObjectList, RegistryElementData; BcdElementType ElementType; PBCD_PACKED_ELEMENT PreviousElement, ElementsStart; ULONG SubElementCount, SubKeyCount, SubObjectCount, ElementDataLength; PWCHAR ElementName; PWCHAR* SubKeys; /* Assume failure */ *ElementCount = 0; /* Initialize all locals that are checked at the end*/ SubKeys = NULL; ElementsHandle = NULL; ElementHandle = NULL; ElementData = NULL; RegistryElementData = NULL; PreviousElement = NULL; ElementName = NULL; SubObjectList = NULL; TotalLength = 0; ElementDataLength = 0; SubObjectCount = 0; RemainingLength = 0; ElementsStart = Elements; /* Open the root object key's elements */ Status = BiOpenKey(ObjectHandle, L"Elements", &ElementsHandle); if (!NT_SUCCESS(Status)) { goto Quickie; } /* Enumerate all elements */ Status = BiEnumerateSubKeys(ElementsHandle, &SubKeys, &SubKeyCount); if (!NT_SUCCESS(Status)) { goto Quickie; } /* Iterate over each one */ for (i = 0; i < SubKeyCount; i++) { /* Open the element */ ElementName = SubKeys[i]; Status = BiOpenKey(ElementsHandle, ElementName, &ElementHandle); if (!NT_SUCCESS(Status)) { EfiPrintf(L"ELEMENT ERROR: %lx\r\n", Status); EfiStall(100000); break; } /* The name of the element is its data type */ ElementType.PackedValue = wcstoul(SubKeys[i], NULL, 16); if (!(ElementType.PackedValue) || (ElementType.PackedValue == -1)) { EfiPrintf(L"Value invalid\r\n"); BiCloseKey(ElementHandle); ElementHandle = 0; continue; } /* Read the appropriate registry value type for this element */ Status = BiGetRegistryValue(ElementHandle, L"Element", BiConvertElementFormatToValueType( ElementType.Format), &RegistryElementData, &RegistryElementDataLength); if (!NT_SUCCESS(Status)) { EfiPrintf(L"Element invalid\r\n"); break; } /* Now figure out how much space the converted element will need */ ElementDataLength = 0; Status = BiConvertRegistryDataToElement(ObjectHandle, RegistryElementData, RegistryElementDataLength, ElementType, NULL, &ElementDataLength); if (Status != STATUS_BUFFER_TOO_SMALL) { break; } /* Allocate a buffer big enough for the converted element */ ElementData = BlMmAllocateHeap(ElementDataLength); if (!ElementData) { Status = STATUS_INSUFFICIENT_RESOURCES; break; } /* And actually convert it this time around */ Status = BiConvertRegistryDataToElement(ObjectHandle, RegistryElementData, RegistryElementDataLength, ElementType, ElementData, &ElementDataLength); if (!NT_SUCCESS(Status)) { break; } /* Safely add space for the packed element header */ Status = RtlULongAdd(TotalLength, FIELD_OFFSET(BCD_PACKED_ELEMENT, Data), &TotalLength); if (!NT_SUCCESS(Status)) { break; } /* Safely add space for the data of the element itself */ Status = RtlULongAdd(TotalLength, ElementDataLength, &TotalLength); if (!NT_SUCCESS(Status)) { break; } /* One more element */ ++*ElementCount; /* See how much space we were given */ RemainingLength = *ElementSize; if (RemainingLength >= TotalLength) { /* Set the next pointer */ Elements->NextEntry = (PBCD_PACKED_ELEMENT)((ULONG_PTR)ElementsStart + TotalLength); /* Fill this one out */ Elements->RootType.PackedValue = RootElementType; Elements->Version = 1; Elements->Type = ElementType.PackedValue; Elements->Size = ElementDataLength; /* Add the data */ RtlCopyMemory(Elements->Data, ElementData, ElementDataLength); RemainingLength -= TotalLength; /* Move to the next element on the next pass */ PreviousElement = Elements; Elements = Elements->NextEntry; } else { /* We're out of space */ RemainingLength = 0; } /* Are we enumerating devices, and is this a device? */ if ((Flags & BCD_ENUMERATE_FLAG_DEVICES) && (ElementType.Format == BCD_TYPE_DEVICE)) { /* Yep, so go inside to enumerate it */ Status = BiEnumerateSubElements(BcdHandle, ElementData, ElementType.PackedValue, Flags, &Elements, &ElementDataLength, &SubElementCount); if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_TOO_SMALL)) { /* Safely add the length of the sub elements */ Status = RtlULongAdd(TotalLength, ElementDataLength, &TotalLength); if (!NT_SUCCESS(Status)) { break; } /* Add the sub elements to the total */ *ElementCount += SubElementCount; /* See if we have enough space*/ if (*ElementSize >= TotalLength) { /* Were there any subelements? */ if (SubElementCount) { /* Update to keep track of these new subelements */ ElementDataLength = *ElementSize - TotalLength; /* Link the subelements into the chain */ PreviousElement = Elements; PreviousElement->NextEntry = (PBCD_PACKED_ELEMENT)((ULONG_PTR)ElementsStart + TotalLength); Elements = PreviousElement->NextEntry; } } else { /* We're out of space */ ElementDataLength = 0; } } else if ((Status != STATUS_NOT_FOUND) && (Status != STATUS_OBJECT_NAME_NOT_FOUND)) { /* Fatal error trying to read the data, so fail */ break; } } else if ((Flags & BCD_ENUMERATE_FLAG_DEEP) && (ElementType.PackedValue == BcdLibraryObjectList_InheritedObjects)) { /* Inherited objects are requsted, so allocate a buffer for them */ SubObjectList = BlMmAllocateHeap(ElementDataLength); if (!SubObjectList) { Status = STATUS_INSUFFICIENT_RESOURCES; break; } /* Copy the elements into the list. They are arrays of GUIDs */ RtlCopyMemory(SubObjectList, ElementData, ElementDataLength); SubObjectCount = ElementDataLength / sizeof(GUID); } /* Free our local buffers */ BlMmFreeHeap(ElementData); BlMmFreeHeap(RegistryElementData); ElementData = NULL; RegistryElementData = NULL; /* Close the key */ BiCloseKey(ElementHandle); ElementHandle = NULL; ElementName = NULL; } /* Did we end up here with a sub object list after successful loop parsing? */ if ((i != 0) && (i == SubKeyCount) && (SubObjectList)) { /* We will actually enumerate it now, at the end */ Status = BiEnumerateSubObjectElements(BcdHandle, SubObjectList, SubObjectCount, Flags, Elements, &RemainingLength, &SubElementCount); if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_TOO_SMALL)) { /* Safely add the length of the sub elements */ Status = RtlULongAdd(TotalLength, RemainingLength, &TotalLength); if ((NT_SUCCESS(Status)) && (SubElementCount)) { /* Add the sub elements to the total */ *ElementCount += SubElementCount; /* Don't touch PreviousElement anymore */ PreviousElement = NULL; } } } Quickie: /* Free the sub object list, if any */ if (SubObjectList) { BlMmFreeHeap(SubObjectList); } /* Free any local element data */ if (ElementData) { BlMmFreeHeap(ElementData); } /* Free any local registry data */ if (RegistryElementData) { BlMmFreeHeap(RegistryElementData); } /* Close the handle if still opened */ if (ElementHandle) { BiCloseKey(ElementHandle); } /* Terminate the last element, if any */ if (PreviousElement) { PreviousElement->NextEntry = NULL; } /* Close the root handle if still opened */ if (ElementsHandle) { BiCloseKey(ElementsHandle); } /* Set failure code if out of space */ if (*ElementSize < TotalLength) { Status = STATUS_BUFFER_TOO_SMALL; } /* Other errors will send a notification error */ if (!(NT_SUCCESS(Status)) && (Status != STATUS_BUFFER_TOO_SMALL)) { BiNotifyEnumerationError(ObjectHandle, ElementName, Status); } /* Finally free the subkeys array */ if (SubKeys) { BlMmFreeHeap(SubKeys); } /* And return the required, final length and status */ *ElementSize = TotalLength; return Status; }