UEFI.原始碼分析.DXE的非同步事件服務.第二部分.任務優先順序
阿新 • • 發佈:2019-02-01
任務優先順序簡述
典型的優先順序有四種
/** 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)
實際上也就關了中斷