1. 程式人生 > >UEFI.原始碼分析.DXE的非同步事件服務.第二部分.任務優先順序

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)實際上也就關了中斷