UEFI.源码分析.DXE的异步事件服务.第三部分.定时器与时钟中断

Posted 木艮氵

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UEFI.源码分析.DXE的异步事件服务.第三部分.定时器与时钟中断相关的知识,希望对你有一定的参考价值。

  • 源代码:EDK2
  • 版本:UDK2017
  • UEFI源码分析第二篇,异步事件服务
  • 第三部分,定时器
  • 第一部分,事件驱动
  • 第二部分,任务优先级

设置定时器EVT_TIMER

244 EFI_STATUS                            
245 EFIAPI                                
246 CoreSetTimer (                        
247   IN EFI_EVENT            UserEvent,  
248   IN EFI_TIMER_DELAY      Type,       
249   IN UINT64               TriggerTime 
250   )                                   

函数CoreSetTimer将定时器类型的事件设置好超时时间,也就是更新Event->Timer

273   if (Event->Timer.Link.ForwardLink != NULL) 
274     RemoveEntryList (&Event->Timer.Link);     
275     Event->Timer.Link.ForwardLink = NULL;     
276                                              

进一步调用CoreInsertEventTimer将定时器设置好。

281   if (Type != TimerCancel)                                           
282                                                                       
283     if (Type == TimerPeriodic)                                       
284       if (TriggerTime == 0)                                          
285         gTimer->GetTimerPeriod (gTimer, &TriggerTime);                
286                                                                      
287       Event->Timer.Period = TriggerTime;                              
288                                                                      
289                                                                       
290     Event->Timer.TriggerTime = CoreCurrentSystemTime () + TriggerTime;
291     CoreInsertEventTimer (Event);                                     
292                                                                       
293     if (TriggerTime == 0)                                            
294       CoreSignalEvent (mEfiCheckTimerEvent);                          
295                                                                      
296                                                                      

函数CoreInsertEventTimer如下

 40 VOID                   
 41 CoreInsertEventTimer ( 
 42   IN IEVENT   *Event   
 43   )                    
 44                       
 54   TriggerTime = Event->Timer.TriggerTime; 
 59   for (Link = mEfiTimerList.ForwardLink; Link != &mEfiTimerList; Link = Link->ForwardLink) 
 60     Event2 = CR (Link, IEVENT, Timer.Link, EVENT_SIGNATURE);                                
 61                                                                                             
 62     if (Event2->Timer.TriggerTime > TriggerTime)                                           
 63       break;                                                                                
 64                                                                                            
 65                                                                                            
 66                                                                                             
 67   InsertTailList (Link, &Event->Timer.Link);                                                
 68 

将定时器按序插入到全局变量mEfiTimerList中。


时钟中断

在DXE阶段初始化事件服务时,会调用CoreInitializeEventServices

/** /Dxe/Event/Event.c **/
130 EFI_STATUS                                          
131 CoreInitializeEventServices (                       
132   VOID                                              
133   )                                                 
134                                                    
135   UINTN        Index;                               
136                                                     
137   for (Index=0; Index <= TPL_HIGH_LEVEL; Index++)  
138     InitializeListHead (&gEventQueue[Index]);       
139                                                    
140                                                     
141   CoreInitializeTimer ();                           
142                                                     
143   CoreCreateEventEx (                               
144     EVT_NOTIFY_SIGNAL,                              
145     TPL_NOTIFY,                                     
146     EfiEventEmptyFunction,                          
147     NULL,                                           
148     &gIdleLoopEventGuid,                            
149     &gIdleLoopEvent                                 
150     );                                              
151                                                     
152   return EFI_SUCCESS;                               
153                                                    

函数CoreInitializeTimer会初始化一个EVT_NORIFY_SIGNAL类型的事件,其回调函数为CoreCheckTimers

/** /Dxe/Event/Timer.c **/
168 VOID                                 
169 CoreInitializeTimer (                
170   VOID                               
171   )                                  
172                                     
173   EFI_STATUS  Status;                
174                                      
175   Status = CoreCreateEventInternal ( 
176              EVT_NOTIFY_SIGNAL,      
177              TPL_HIGH_LEVEL - 1,     
178              CoreCheckTimers,        
179              NULL,                   
180              NULL,                   
181              &mEfiCheckTimerEvent    
182              );                      
183   ASSERT_EFI_ERROR (Status);         
184                                     

该回调函数CoreCheckTimers就是检查所有的定时器,即mEfiTimerList,若到期则执行其回调函数。若是永久定时器,则增加一段时间后,再次将该定时器唤醒。

 98 VOID                                                                            
 99 EFIAPI                                                                          
100 CoreCheckTimers (                                                               
101   IN EFI_EVENT            CheckEvent,                                           
102   IN VOID                 *Context                                              
103   )                                                                             
104                                                                                
111   CoreAcquireLock (&mEfiTimerLock);                                             
112   SystemTime = CoreCurrentSystemTime ();                                        
113                                                                                 
114   while (!IsListEmpty (&mEfiTimerList))                                        
115     Event = CR (mEfiTimerList.ForwardLink, IEVENT, Timer.Link, EVENT_SIGNATURE);
116                                                                                 
120     if (Event->Timer.TriggerTime > SystemTime)                                 
121       break;                                                                    
122                                                                                
127                                                                                 
128     RemoveEntryList (&Event->Timer.Link);                                       
129     Event->Timer.Link.ForwardLink = NULL;                                       
130                                                                                 
134     CoreSignalEvent (Event);                                                    
135                                                                                  
139     if (Event->Timer.Period != 0)                                               
143       Event->Timer.TriggerTime = Event->Timer.TriggerTime + Event->Timer.Period; 
144                                                                                  
148       if (Event->Timer.TriggerTime <= SystemTime)                               
149         Event->Timer.TriggerTime = SystemTime;                                   
150         CoreSignalEvent (mEfiCheckTimerEvent);                                   
151                                                                                 
152                                                                                  
156       CoreInsertEventTimer (Event);                                              
157                                                                                 
158                                                                                 
159                                                                                  
160   CoreReleaseLock (&mEfiTimerLock);                                              
161                                                                                 

真正的时钟中断函数CoreTimerTick正是利用了事件mEfiCheckTimerEvent来执行定时器

  1. 更新全局时间mEfiSystemTime
  2. mEfiTimerList非空,且最近的定时器已过期,则SignalEvent事件mEfiCheckTimerEvent,也就是执行其回调函数CoreCheckTimers来处理定时器。
194 VOID                                                                            
195 EFIAPI                                                                          
196 CoreTimerTick (                                                                 
197   IN UINT64   Duration                                                          
198   )                                                                             
199                                                                                
205   CoreAcquireLock (&mEfiSystemTimeLock);                                        
206                                                                                 
210   mEfiSystemTime += Duration;                                                   
211                                                                                 
216   if (!IsListEmpty (&mEfiTimerList))                                           
217     Event = CR (mEfiTimerList.ForwardLink, IEVENT, Timer.Link, EVENT_SIGNATURE);
218                                                                                 
219     if (Event->Timer.TriggerTime <= mEfiSystemTime)                            
220       CoreSignalEvent (mEfiCheckTimerEvent);                                    
221                                                                                
222                                                                                
223                                                                                 
224   CoreReleaseLock (&mEfiSystemTimeLock);                                        
225                                                                                

时钟中断的初始化

1、 在DXE入口中调用函数CoreNotifyOnProtocolInstallation

/** /Dxe/DxeMain/DxeProtocolNotify.c **/
252 VOID                                                  
253 CoreNotifyOnProtocolInstallation (                    
254   VOID                                                
255   )                                                   
256                                                      
257   CoreNotifyOnProtocolEntryTable (mArchProtocols);    
258   CoreNotifyOnProtocolEntryTable (mOptionalProtocols);
259                                                      

2、函数CoreNotifyOnProtocolEntryTable为某些特定的协议设置对应的回调函数,当该协议的实例被安装时,回调函数就会被调用

215 VOID                                                   
216 CoreNotifyOnProtocolEntryTable (                       
217   EFI_CORE_PROTOCOL_NOTIFY_ENTRY  *Entry               
218   )                                                    
219                                                       
220   EFI_STATUS  Status;                                  
221                                                        
222   for (; Entry->ProtocolGuid != NULL; Entry++)        
226     Status = CoreCreateEvent (                         
227               EVT_NOTIFY_SIGNAL,                       
228               TPL_CALLBACK,                            
229               GenericProtocolNotify,                   
230               Entry,                                   
231               &Entry->Event                            
232               );                                       
233     ASSERT_EFI_ERROR(Status);                          
234                                                        
238     Status = CoreRegisterProtocolNotify (              
239               Entry->ProtocolGuid,                     
240               Entry->Event,                            
241               &Entry->Registration                     
242               );                                       
243     ASSERT_EFI_ERROR(Status);                          
244                                                       
245                                                       

指定的协议,如mArchProocol包括如下协议

 27 EFI_CORE_PROTOCOL_NOTIFY_ENTRY  mArchProtocols[] =                                       
 28    &gEfiSecurityArchProtocolGuid,         (VOID **)&gSecurity,      NULL, NULL, FALSE , 
 29    &gEfiCpuArchProtocolGuid,              (VOID **)&gCpu,           NULL, NULL, FALSE , 
 30    &gEfiMetronomeArchProtocolGuid,        (VOID **)&gMetronome,     NULL, NULL, FALSE , 
 31    &gEfiTimerArchProtocolGuid,            (VOID **)&gTimer,         NULL, NULL, FALSE , 
 32    &gEfiBdsArchProtocolGuid,              (VOID **)&gBds,           NULL, NULL, FALSE , 
 33    &gEfiWatchdogTimerArchProtocolGuid,    (VOID **)&gWatchdogTimer, NULL, NULL, FALSE , 
 34    &gEfiRuntimeArchProtocolGuid,          (VOID **)&gRuntime,       NULL, NULL, FALSE , 
 35    &gEfiVariableArchProtocolGuid,         (VOID **)NULL,            NULL, NULL, FALSE , 
 36    &gEfiVariableWriteArchProtocolGuid,    (VOID **)NULL,            NULL, NULL, FALSE , 
 37    &gEfiCapsuleArchProtocolGuid,          (VOID **)NULL,            NULL, NULL, FALSE , 
 38    &gEfiMonotonicCounterArchProtocolGuid, (VOID **)NULL,            NULL, NULL, FALSE , 
 39    &gEfiResetArchProtocolGuid,            (VOID **)NULL,            NULL, NULL, FALSE , 
 40    &gEfiRealTimeClockArchProtocolGuid,    (VOID **)NULL,            NULL, NULL, FALSE , 
 41    NULL,                                  (VOID **)NULL,            NULL, NULL, FALSE   
 42 ;                                                                                        

回调函数GenericProtocolNotify的工作注释解释的很清楚

这个回调函数被注册到每个ArchProcotol上,这个函数会使用协议实例来更新mArchProtocol

101 /**                                                                                
102   Notification event handler registered by CoreNotifyOnArchProtocolInstallation ().
103   This notify function is registered for every architectural protocol. This handler
104   updates mArchProtocol[] array entry with protocol instance data and sets it's    
105   present flag to TRUE. If any constructor is required it is executed. The EFI     
106   System Table headers are updated.                                                
107                                                                                    
108   @param  Event          The Event that is being processed, not used.              
109   @param  Context        Event Context, not used.                                  
110                                                                                    
111 **/                                                                                
112 VOID                                                                               
113 EFIAPI                                                                             
114 GenericProtocolNotify (                                                            
115   IN  EFI_EVENT  Event,                                                            
116   IN  VOID       *Context                                                          
117   )                                                                                
118                                                                                   

这里只注意这一段处理,和定时器相关的

157   if (CompareGuid (Entry->ProtocolGuid, &gEfiTimerArchProtocolGuid)) 
158     //                                                                
159     // Register the Core timer tick handler with the Timer AP         
160     //                                                                
161     gTimer->RegisterHandler (gTimer, CoreTimerTick);                  
162                                                                      

即当EFI_TIMER_ARCH_PROTOCOL的协议实例被注册的时候,则调用该协议的RegisterHandler接口,注册时钟中断处理程序,即CoreTimerTick

全局变量gTimer定义于DxeMain.c

29 EFI_TIMER_ARCH_PROTOCOL           *gTimer         = NULL;

注意到在全局变量mArchProtocols中有gTimer的地址,故回调函数GenericProtocolNotify会将协议的实例写入gTimer

以上是关于UEFI.源码分析.DXE的异步事件服务.第三部分.定时器与时钟中断的主要内容,如果未能解决你的问题,请参考以下文章

UEFI.源码分析.DXE的异步事件服务.第一部分.事件驱动

UEFI.源码分析.DXE的异步事件服务.第一部分.事件驱动

UEFI.源码分析.DXE的异步事件服务.第二部分.任务优先级

UEFI.源码分析.DXE的异步事件服务.第二部分.任务优先级

UEFI.源码分析.DXE的内存服务.第三部分.HeapGuard

UEFI.源码分析.DXE阶段的执行