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

Posted 木艮氵

tags:

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

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

任务优先级简述

典型的优先级有四种

/** MdePkg/Include/Uefi/UefiSpec.h **/
585 //                               
586 // Task priority level           
587 //                               
588 #define TPL_APPLICATION       4  
589 #define TPL_CALLBACK          8  
590 #define TPL_NOTIFY            16 
591 #define TPL_HIGH_LEVEL        31 

Event.h中还提供了一个宏来判断合法

 20 #define VALID_TPL(a)            ((a) <= TPL_HIGH_LEVEL)  

第一部分中的gEventPending则是一个UINTN类型的变量

21 extern  UINTN                   gEventPending;

对于UINTN的定义,依赖于体系结构

MdePkg/Include/X64/ProcessorBind.h:237:typedef UINT64  UINTN;
MdePkg/Include/Ia32/ProcessorBind.h:224:typedef UINT32  UINTN;

Event.c中则使用全局变量保存了当前优先级

23 EFI_TPL  gEfiCurrentTpl = TPL_APPLICATION;

接口

提高优先级RaiseTpl

/** /Dxe/Event/Tpl.c **/
 59 EFI_TPL                  
 60 EFIAPI                   
 61 CoreRaiseTpl (           
 62   IN EFI_TPL      NewTpl 
 63   )                      
 64                         

保证优先级是不降低的,并检查合法性

 67   OldTpl = gEfiCurrentTpl;            
 68   if (OldTpl > NewTpl)               
 69     DEBUG ((EFI_D_ERROR, "FATAL ERROR 
 70     ASSERT (FALSE);                   
 71                                      
 72   ASSERT (VALID_TPL (NewTpl));        

若新优先级超过或等于TPL_HIGH_LEVEL,且原优先级低于TPL_HIGH_LEVEL,则关闭中断

 77   if (NewTpl >= TPL_HIGH_LEVEL  &&  OldTpl < TPL_HIGH_LEVEL) 
 78     CoreSetInterruptState (FALSE);                            
 79                                                              

更新全局变量gEfiCurrentTpl

 84   gEfiCurrentTpl = NewTpl; 
 85                            
 86   return OldTpl;           
 87                           

恢复优先级RestoreTpl

/** /Dxe/Event/Tpl.c **/
 99 VOID                
100 EFIAPI              
101 CoreRestoreTpl (    
102   IN EFI_TPL NewTpl 
103   )                 
104                    

保证是不提升的,并检查合法性

107   OldTpl = gEfiCurrentTpl;     
108   if (NewTpl > OldTpl)        
109     DEBUG ((EFI_D_ERROR, "FATAL
110     ASSERT (FALSE);            
111                               
112   ASSERT (VALID_TPL (NewTpl)); 

根据gEventPending来执行回调函数

126   while (((-2 << NewTpl) & gEventPending) != 0)          
127     gEfiCurrentTpl = (UINTN) HighBitSet64 (gEventPending);
128     if (gEfiCurrentTpl < TPL_HIGH_LEVEL)                 
129       CoreSetInterruptState (TRUE);                       
130                                                          
131     CoreDispatchEventNotifies (gEfiCurrentTpl);           
132                                                          

注意到gEventPending在置为1的时候是这样的

gEventPending |= (UINTN)(1 << Event->NotifyTpl); 

函数HighBitSet64是通过调用HighBitSet32来实现的,即返回最高位为1的索引

 34 INTN                                                                  
 35 EFIAPI                                                                
 36 HighBitSet32 (                                                        
 37   IN      UINT32                    Operand                           
 38   )                                                                   
 39                                                                      
 40   INTN                              BitIndex;                         
 41                                                                       
 42   if (Operand == 0)                                                  
 43     return - 1;                                                       
 44                                                                      
 45   for (BitIndex = 31; (INT32)Operand > 0; BitIndex--, Operand <<= 1); 
 46   return BitIndex;                                                    
 47                                                                      

操作(-2 << NewTpl) & gEventPending会将低于NewTpl的位屏蔽。

故实际上只会调度执行低于NewTpl的事件的回调函数。

最后恢复gEfiCurrentTpl并恢复中断状态

138   gEfiCurrentTpl = NewTpl;                 
139                                            
140   //                                       
141   // If lowering below HIGH_LEVEL, make sur
142   // interrupts are enabled                
143   //                                       
144   if (gEfiCurrentTpl < TPL_HIGH_LEVEL)    
145     CoreSetInterruptState (TRUE);          
146                                           

总结

  • RaiseTpl在提升到TPL_HIGH_LEVEL以上时会关中断
  • RestoreTpl在降低时会调度执行事件的回调函数,且只会调度执行高于或等于原优先级的事件的回调函数
  • 默认的优先级是TPL_APPLICATION即最低优先级,所以此时的RestoreTpl实际上会调度执行所有的回调函数
  • 在时钟中断的开始会RaiseTpl(TPL_HIGH_LEVEL)实际上也就关了中断

以上是关于UEFI.源码分析.DXE的异步事件服务.第二部分.任务优先级的主要内容,如果未能解决你的问题,请参考以下文章

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

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

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

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

UEFI.源码分析.DXE的内存服务.第二部分.函数接口

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