众所周知:UEFI中没有中断(UEFI唯一一个中断int 0,timer )【参考1】,如果想实现一个定时器的功能,必须使用 Event。
实现的思路是:
1. CreateEvent 创建 Timer Event
2. SetTimer 设定 Periodic 触发
3. SetTimer 关闭定时器
4. CloseEvent 销毁 Timer Event
首先研究 CreateEvent ,这个函数是Boot Service中提供的【参考3】
第一个参数给出创建的类型,我们要选择EVT_TIMER;第二个参数是优先级,对我们来说影响不大;第三个参数给出当Event发生时对应的处理函数;第四个参数我的理解是自定义的数据;第五个参数是创建出来的Event。
接下来再看看SetTimer函数,同样也是 Boot Service 中提供的服务
第一个参数是你创建的Event;然后是Timer的类型,比如:周期性触发;最后是设定Timer的时间,多久触发一次,单位是100ns。
CloseEvent就很简单了
程序还参考了 ShellPkg\Library\UefiShellNetwork1CommandsLib\Ping.c 的代码。
最终代码如下
#include <Uefi.h> #include <Library/UefiLib.h> #include <Library/ShellCEntryLib.h> #include <stdio.h> #include <stdlib.h> #include <wchar.h> #include <Protocol/EfiShell.h> #include <Library/ShellLib.h> #include <Protocol/SimpleFileSystem.h> #include <Protocol/BlockIo.h> #include <Library/DevicePathLib.h> #include <Library/HandleParsingLib.h> #include <Library/SortLib.h> #include <Library/MemoryAllocationLib.h> #include <Library/BaseMemoryLib.h> extern EFI_BOOT_SERVICES *gBS; extern EFI_SYSTEM_TABLE *gST; extern EFI_RUNTIME_SERVICES *gRT; extern EFI_SHELL_ENVIRONMENT2 *mEfiShellEnvironment2; extern EFI_HANDLE gImageHandle; STATIC CONST UINTN SecondsToNanoSeconds = 10000000; UINTN Counter = 0; /** The callback function for the timer event used to get map. @param[in] Event The event this function is registered to. @param[in] Context The context registered to the event. **/ VOID EFIAPI Timeout ( IN EFI_EVENT Event, IN VOID *Context ) { Print(L"www.lab-z.com [%d]\r\n",++ Counter); return ; } int EFIAPI main ( IN int Argc, IN char **Argv ) { EFI_STATUS Status; EFI_HANDLE TimerOne = NULL; BOOLEAN ExitMark=FALSE; Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL | EVT_TIMER, TPL_CALLBACK, Timeout, NULL, &TimerOne ); if (EFI_ERROR (Status)) { Print(L"Create Event Error! \r\n"); return ; } Status = gBS->SetTimer ( TimerOne, TimerPeriodic, MultU64x32 (SecondsToNanoSeconds, 1) ); if (EFI_ERROR (Status)) { Print(L"Set Timer Error! \r\n"); return ; } while (!ExitMark) { if (mEfiShellEnvironment2 -> GetExecutionBreak()) {ExitMark=TRUE;} } gBS->SetTimer (TimerOne, TimerCancel, 0); gBS->CloseEvent (TimerOne); return EFI_SUCCESS; }
完整代码下载
TimerTest
后记:这部分对我来说还是比较复杂,在描述上定义概念可能会有偏差,如果阅读中发现,欢迎通知我及时改正。
参考:
1. http://blog.csdn.net/celiaqianhj/article/details/7180783 UEFI Events
2. http://biosren.com/viewthread.php?tid=2095&highlight=%B6%A8%CA%B1 什么是EFI Events?
3. UEFI Spec 2.4 P118
你好,为什么我写了一个SetTimer的显示时间的Driver,然后在shell在去load它,它不能常驻在系统里呢,执行完一次,显示一次时间就结束了,我明明是让它一秒钟print一次,还有为什么我使用load去安装driver,但是使用unload去卸载driver,它就会说无效的参数,请问楼主有没有这方面的Sample code或者经验可以学习一下,感谢!
你可以看一下 Driver Writer’s Guide for UEFI 2.3.1,我简单查了一下,其中提到driver可以使用 SetTimer 。我就不知道你遇到的具体问题是什么了。
1.创建一个定时器去通知显示系统时间
2.检查定时器是否被加载,它不允许被加载两次
3.能够卸载这个定时器驱动
满足这三点要求
請問 "SetTimer" 是否可以實現 wake the system from S5 by RTC?
我估计够呛。你可以查一下代码看看具体实现。