最近在看 EFI_CPU_ARCH_PROTOCOL 相关内容,相关定义只在 PI Specification的DXE_CIS 章节,和 UEFI Specification 无关。具体如下:
这次先试试其中的NumberOfTimers 和GetTimerValue 。NumberOfTimers 返回的是当前系统中的Timer数量,从我的几个机器的实验看,目前都是 1。GetTimerValue定义如下:
其中的 TimerValue 给出当前系统Timer的值;TimerPeriod给出当前系统Timer值的单位,这个单位是飞秒(10^-15)。比如,TimerPeriod=10^6 (1ns),TimerValue=10^3,那么 Timer 经过的事件是两者相乘的 10^9, 1 微秒(1 microsecond)。
我们编写一个代码来进行实验,测试一个 gBS->stall 1秒,经过的时间。代码如下 :
/** @file A simple, basic, application showing how the Hello application could be built using the "Standard C Libraries" from StdLib. Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license. THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #include <Library/BaseLib.h> #include <Uefi.h> #include <Library/UefiLib.h> #include <Library/PrintLib.h> #include <Library/ShellCEntryLib.h> #include <Protocol/Cpu.h> EFI_GUID gEfiCpuArchProtocolGuid = { 0x26BACCB1, 0x6F42, 0x11D4, { 0xBC, 0xE7, 0x00, 0x80, 0xC7, 0x3C, 0x88, 0x81 }}; extern EFI_BOOT_SERVICES *gBS; /*** Demonstrates basic workings of the main() function by displaying a welcoming message. Note that the UEFI command line is composed of 16-bit UCS2 wide characters. The easiest way to access the command line parameters is to cast Argv as: wchar_t **wArgv = (wchar_t **)Argv; @param[in] Argc Number of argument tokens pointed to by Argv. @param[in] Argv Array of Argc pointers to command line tokens. @retval 0 The application exited normally. @retval Other An error occurred. ***/ int main ( IN int Argc, IN char **Argv ) { EFI_CPU_ARCH_PROTOCOL *Cpu; UINT64 TimerValue; UINT64 StartTimerValue; UINT64 EndTimerValue; UINT64 TimerPerioid; EFI_STATUS Status; UINT64 tmp; // // Locate the Cpu Arch Protocol. // Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, &Cpu); if (EFI_ERROR (Status)) { Print(L"Can't find EFI_CPU_ARCH_PROTOCOL\n"); return Status; } //Get some base information Cpu->GetTimerValue( Cpu, 0, //There is only one timer in system &TimerValue, &TimerPerioid ); //Usually there is only one timer in this protocol Print(L"NumberOfTimers: %d\n",Cpu->NumberOfTimers); //The unite of one timer ,femtoseconds 10^(-15)s Print(L"Timer period : %ld\n",TimerPerioid); //Make a simple test here, delay 1 second //And check how long it is in the timer Print(L"Timer Test Start delay 1s\n"); Cpu->GetTimerValue( Cpu, 0, //There is only one timer in system &StartTimerValue, &TimerPerioid ); Print(L" Start at: %ld\n",StartTimerValue); gBS->Stall(1000000UL); Cpu->GetTimerValue( Cpu, 0, //There is only one timer in system &EndTimerValue, &TimerPerioid ); Print(L" End at: %ld\n",EndTimerValue); tmp = MultU64x64(EndTimerValue-StartTimerValue,TimerPerioid); tmp = DivU64x32 (tmp,1000000000UL); Print(L" Elapsed: %ld us\n",tmp); return 0; }
NT32 的虚拟机实验结果如下:
实体机上实验结果如下(看起来实体机上偏差更大?):
X64 EFI Application下载:
完整代码下载:
时间单位的简单介绍【参考1】:
second millisecond microsecond nanosecond picosecond femtosecond
1ms (毫秒) 1毫秒=0.001秒=10-3秒
1μs (微秒) 1微秒=0.000001=10-6秒
1ns (纳秒) 1纳秒=0.0000000001秒=10-9秒
1ps (皮秒) 1皮秒=0.0000000000001秒=10-12秒
1fs (飞秒) 1飞秒=0.000000000000001秒=10-15秒
参考:
- http://blog.163.com/digoal@126/blog/static/163877040201062810748700/
Print(L” Start at: %ld\n”,StartTimerValue);
這行也會花些許時間,如果移到最後,誤差又變小一些。