本文件纯属个人理解,如有错误,欢迎指出
1. Task Priority Level, 任务优先级
任务优先级, 数值越大,优先级越高。优先级高于当前任务优先级的任务可能抢占当前中断当前任务的执行。在UEFI标准中,只有4个优先级
表格 1 任务优先级
|
Task Priority Level |
Value |
中断 |
使用经典场景 |
|
TPL_APPLICATION |
4 |
启用 |
.efi文件运行时的默认优先级;调用WaitForEvent时必须处于TPL_APPLICATION优先级 |
|
TPL_CALLBACK |
8 |
启用 |
中间优先级 |
|
TPL_NOTIFY |
16 |
启用 |
中间优先级 |
|
TPL_HIGH_LEVEL |
31 |
禁用 |
最高优先级,处于此优先级时 |
可调用BootService的RiseTPL/RestoreTPL提升或降低任务优先级。在RestoreTPL时,会调用处于等调用事件处理函数队列中高于当前任务优先级的事件处理函数。
2. Event, 事件
用于同步事件,如,定时器到达指定点后,定时器中断程序会通过调用事件中指定的回调函数及参数完成指定定时任务。
事件共有如下几种类型
表格 2 Event类型
|
Type |
值 |
功能 |
|
EVT_TIMER |
0x80000000 |
定时器 |
|
EVT_RUNTIME |
0x40000000 |
运行时事件 |
|
EVT_NOTIFY_WAIT |
0x00000100 |
等待事件,checkEvent时会被移入Notify_Callback待调用队列,在RestoreTPL时调用notify_callback函数 |
|
EVT_NOTIFY_SIGNAL |
0x00000200 |
通知事件,创建时增加进signal队列,如果 |
|
EVT_SIGNAL_EXITBOOT_SERVICES |
0x00000201 |
退出BOOT_SERVICES时通知事件,只在进OS才发生 |
|
EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE |
0x60000202 |
UNKOWN |
表格 3 有效Event类型组合
|
Type组合 |
有效TPL |
Notify Function |
Notify Context |
略注 |
|
EVT_TIMER | EVT_NOTIFY_SIGNAL |
TPL_CALLBACK TPL_NOTIFY |
必须有 |
|
Timer到达后,会将此Event移入signaled事件队列,在RestoreTPL时如果当前TPL为CreateEvent时指定的TPL则调用通知函数 |
|
EVT_TIMER |
Ignore |
Ignore |
Ignore |
|
|
EVT_NOTIFY_WAIT |
TPL_CALLBACK TPL_NOTIFY |
必须有 |
|
CheckEvent会通过RestoreTPL调用notify_callback |
|
EVT_NOTIFY_SIGNAL |
TPL_CALLBACK TPL_NOTIFY |
必须有 |
|
当有程序调用SignalEvent时,Event会被移入signaled事件队列, 在RestoreTPL时如果当前TPL为CreateEvent时指定的TPL则调用通知函数 |
|
EVT_SIGNAL_EXIT_BOOT_SERVICES |
TPL_CALLBACK TPL_NOTIFY |
必须有 |
|
退出BOOT_SERVICES时通知事件,只在进OS才发生 |
|
EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE |
TPL_CALLBACK TPL_NOTIFY |
必须有 |
|
|
|
0x00000000 |
Ignore |
Ignore |
Ignore |
|
|
EVT_TIMER | EVT_NOTIFY_WAIT |
TPL_CALLBACK TPL_NOTIFY |
必须有 |
|
到时间自动转成Signaled状态,CoreSignalEvent ,但checkevent不会调用通知函数 |
3. Timer, 定时器
定时器在UEFI中有着关重要的地位:1. 任务时间片切换, 2.定时功能
UEFI通常来讲只会启用BSP一个CPU内核;UEFI不但没有实现多任务机制,中断也除了定时器外全部禁用(SMI在这不涉及,不多提)。当进入时间中断处理函数时,会将TPL提升至TPL_HIGH_LEVEL,此时中断被关闭,然后将定时器事件队列中的已经抵达时间点的事件状态转为signaled。然后调用RestoreTPL函数逐级调用所有已被signaled的事件处理函数;中断在处理TPL_HIGH_LEVEL之下的事件时被打开。如果有低等级事件耗时过长,时间中断有可能再次进入。
4. 情景分析
① DXE驱动程序启动,后台Timer1已超时,事件1,事件2已经转成signaled状态
② 定时器中断触发,驱动程序强行被暂停,中断程序将任务优先级直接提到TPL_HIGH_LEVEL,中断被关闭,然后检查定时器队列中所有Timer Event是否超时,如有超时,移到signaled事件队列,在本情景中,Timer1 Event被移到signaled队列
③ 定时器队列检查程序完成,RestoreTPL到TPL_APPLICATION:降至TPL_NOTIFY,然后开启中断;接着查看此任务优先级signaled队列,发现Timer1需要处理,将Timer1 Event从signaled队列断开,调用Timer1处理程序
④ 继续降至TPL_CALLBACK, 发现事件1需要处理,将事件1 Event从signaled队列断开, 调用其处理程序
⑤ 事件1处理完成后,发现事件2需要处理,将事件2 Event从signaled队列断开, 调用事件2处理程序
⑥ 事件2处理程序还未完成,但时间中断再次降临,事件2处理程序被中断,任务优先级再次被提到TPL_HIGH_LEVEL,中断关闭, 执行定时器队列检查程序,发现Timer2已经超时,将其移到signaled队列
⑦ 定时器队列检查完成,Restore TPL到TPL_CALLBACK(在跳回TPL_NOTIFY时开启中断),TPL_HIGH_LEVEL及TPL_NOTIFY上没有signaled状态的事件。中断返回,继续执行事件2处理程序
⑧ 执行完事件2处理程序后,发现Timer2的Event处于signaled状态,帮执行Timer2的处理程序
事件2处理程序完成。Restore TPL在signaled队列中未找到其它节点,返回,第一次中断返回,继续DXE驱动执行
5.SpinLock机制
SpinLock的数据结构体是EFI_LOCK,内含三个变量
- Tpl 锁的TPL等级;上锁时TPL被提升至此等级,释放时还原TPL等级
- OwnerTpl 记录上锁之前程序的等级
- EFI_LOCK_STATE 锁的状态 共三种状态(uninitialized, Released, Acquired)
SpinLock相关函数有三个:
- EfiAcquireLock 先将当前任务优先级提升到Tpl,然后状态转换成Acquired
- EfiAcquireLockOrFail 先检查锁的状态,如果为Acquired,则返回Fail, 然后执行EfiAcquireLock逻辑
- EfiReleaseLock 先将状态转换成Released,然后将当前任务优先级还原
其实函数EfiAcquireLockOrFail的作用只是防止高优先级的任务异步获取低等级的锁。
SpinLock工作的基础是只有高于当前优先级的任务才能抢占当前的任务。
本文详细介绍了UEFI的抢占机制,包括Task Priority Level、Event、Timer及其应用场景,并通过具体的情景分析展示了如何处理中断和事件调度。此外,还讨论了SpinLock的工作原理,确保任务执行的正确性和顺序。
2862

被折叠的 条评论
为什么被折叠?



