Используйте таймер HPET с платформой EDK2.
В настоящее время я разрабатываю программу UEFI с использованием платформы EDK2 и хотел бы получить время HPET или использовать прерывание HPET в качестве таймера обратного отсчета. Я попытался использовать HpetTimerDxe из PcAtChipsetPkg, но понятия не имею, как это реализовать.
В Интернете имеется ограниченное количество информации и статей по этой теме, но я все же надеюсь использовать ее для решения проблем, связанных со временем.
- Целевая архитектура: x86_64.
- Версия edk2: edk2-stable202105
EFI_STATUS
FindHpetTable(
EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_HEADER **HpetTable)
{
EFI_STATUS Status;
EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;
EFI_ACPI_DESCRIPTION_HEADER *Xsdt;
UINTN EntryCount;
UINTN Index;
Status = EfiGetSystemConfigurationTable(
&gEfiAcpi20TableGuid,
(VOID **)&Rsdp);
if (EFI_ERROR(Status))
{
return Status;
}
Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)Rsdp->XsdtAddress;
EntryCount = (Xsdt->Length - sizeof(EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT64);
for (Index = 0; Index < EntryCount; Index++)
{
EFI_ACPI_DESCRIPTION_HEADER *CurrentTable;
CurrentTable = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)(((UINT64 *)(Xsdt + 1))[Index]);
if (CurrentTable->Signature == EFI_ACPI_3_0_HIGH_PRECISION_EVENT_TIMER_TABLE_SIGNATURE)
{
*HpetTable = (EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_HEADER *)CurrentTable;
return EFI_SUCCESS;
}
}
return EFI_NOT_FOUND;
}
VOID AccessHpetRegisters(
EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_HEADER *HpetTable)
{
if (HpetTable == NULL)
{
return;
}
UINT64 HpetBaseAddress = HpetTable->BaseAddressLower32Bit.Address;
// Access HPET registers using HpetBaseAddress
// Read the General Capabilities and ID Register
UINT64 CapabilitiesAndId = *(volatile UINT64 *)HpetBaseAddress;
Print(L"HPET General Capabilities and ID Register: 0x%lX\n", CapabilitiesAndId);
// Read the Main Counter Value register
UINT64 MainCounterValue = *(volatile UINT64 *)(HpetBaseAddress + HPET_MAIN_COUNTER_OFFSET);
Print(L"HPET Main Counter Value: 0x%lX\n", MainCounterValue);
UINT64 HpetPeriod = MmioRead32(HpetBaseAddress + 0x4);
// 1 femtosecond = 1e-15 seconds
UINT64 timeValue = DivU64x64Remainder(MultU64x64(MainCounterValue, HpetPeriod), 1000000000000ULL, NULL);
Print(L"time in microsecond: %llu\n", timeValue);
}
// in UefiMain
EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_HEADER *HpetTable;
Status = FindHpetTable(&HpetTable);
if (EFI_ERROR(Status))
{
Print(L"HPET table not found.\n");
return Status;
}
AccessHpetRegisters(HpetTable);