空间服务 网站被黑,万维网如何建设网站,电动门 东莞网站建设,专业网站建设商家UEFI 不再支持中断#xff08;准确地说#xff0c;UEFI 不再为开发者提供中断支持#xff0c;但在UEFI内部还是使用了时钟中断#xff09;#xff0c;所有的异步操作都要通过事件#xff08;Event#xff09;来完成。
启动服务为开发者提供了用于操作事件、定时器及TPL…UEFI 不再支持中断准确地说UEFI 不再为开发者提供中断支持但在UEFI内部还是使用了时钟中断所有的异步操作都要通过事件Event来完成。
启动服务为开发者提供了用于操作事件、定时器及TPL任务优先级的函数。这些函数可以分为三类事件相关函数、定时器相关函数及 TPL相关函数。 事件函数
启动服务中事件相关函数有 6 个函数名大部分以 Event 结尾。提供给事件生产者的函数有 CreateEvent/CreateEventEx、SignalEvent及CloseEvent。提供给事件使用者的有WaitForEvent和CheckEvent。
等待事件的服务 WaitForEvent
WaitForEvent 用于等待事件的发生类似于 Windows 提供的 WaitForMultipleObjects(...)。 WaitForEvent 是阻塞操作直到 Event 数组内任一事件被触发或任一事件导致错误出现WaitForEvent 才返回。WaitForEvent 从前到后依次检查 Event 数组内的事件发现有被触发的事件或遇到错误则返回如果所有事件都没有被触发则从头开始重新检查。
当检查到某个事件处于触发态时*Index赋值为该事件在Event数组中的下标返回前该事件将重置为非触发态。
当检查到某个事件是EVT_NOTIFY_SIGNAL类型时*Index赋值为该事件在Event数组中的下标并返回EFI_INVALID_PARAMETER。 WaitForEvent必须运行在 TPL_APPLICAION 级别否则将返回 EFI_UNSUPPORTED。
WaitForEvent 没有超时属性如果想让 WaitForEvent 只等待一定的时间则需要在事件等待数组加入定时器事件。
生成事件的服务 CreateEvent
CreateEvent 用于生成一个事件。
1.事件的类型 事件的类型可以是以下一种或几种基本类型的组合
EVT_TIMER定时器事件。普通Timer事件没有Notification函数。生成事件后需调用SetTimer服务设置时钟属性EVT_NOTIFY_WAIT普通事件。这个事件有一个Notification函数当这个事件通过CheckEvent()检查状态或通过 WaitForEvent()等待时这个 Notification 函数会被放到待执行队列gEventQueue[Event-NotifyTpl]中EVT_NOTIFY_SIGNAL普通事件。这个事件有一个Notification函数当这个事件通过SignalEvent()被触发时这个 Notifcation 函数会被放到待执行队列 gEventQueue[Event-NotifyTpl] 中等待执行0x00000000普通事件。此类事件没有Notification 函数。
还有两种特殊的事件它们用在操作系统系统加载器从启动期向运行时期转换的过程中
EVT_SIGNAL_EXIT_BOOT_SERVICES此类事件是一种特殊的 EVT_NOTIFY_SIGNAL实际上它是 EVT_NOTIFY_SIGNAL 和0x00000001的组合。当ExitBootServices()执行时事件被触发。EVT_SIGNAL_EXIT_BOOT_SERVICES不能和其他类型混合使用。它的 Notification 函数和子函数不能使用启动服务中的内存分配服务在 Notification 函数执行前所有的定时器服务都已失效因而在Notificaiton 函数中也不能使用定时器服务。EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE它是EVT_RUNTIME_CONTEXT、EVT_RUNTIME、EVT_NOTIFY_SIGNAL和0x00000002的组合。它不能和这 4 种类型之外的类型组合使用。当 SetVirtualAddressMap()被调用时触发此类事件。
2.优先级 CreateEvent 的第二个参数为NotifyTPL即任务优先级它可以是 0 ~ 31 的一个整数。 UEFI 预定义了以下 4 个优先级
TPL_APPLICATION预定义的 4 个级别中最低的一个优先级。应用程序运行包括 Boot Manager 和 OS Loader在这个级别。当程序运行在这个级别时任务队列中没有任何处于就绪状态的事件 Notification 函数TPL_CALLBACK比较耗时的操作通常在这个优先级执行如文件系统、磁盘操作等TPL_NOTIFY运行在这个级别的程序不允许阻塞必须尽快执行完毕并且返回。如果需要更多操作则需要使用Event由内核重新调度。通常底层的 IO 操作允许在这个级别。大部分Event的Notification函数允许在这个级别TPL_HIGH_LEVEL优先级最高级别。在此级别中断被禁止。UEFI 内核全局变量的修改需要允许在这个级别。
3.Notification 函数 NotifyFunction CreateEvent的第三个参数NotifyFunction是EFI_EVENT_NOTIFY类型的函数指针。 如果事件的类型是 EVT_NOTIFY_WAIT则 EFI_EVENT_NOTIFY 函数会在等待此事件的过程中调用如果事件的类型是EVT_NOTIFY_SIGNAL则 EFI_EVENT_NOTIFY 函数会在事件触发时调用。既没有 EVT_NOTIFY_WAIT 属性也没有EVT_NOTIFY_SIGNAL属性的事件Notification 参数将被忽略。
CreateEvent 的第4个参数是NotifyContext将在Notification 函数被调用时作为第 2 个参数传递给该函数用于指向这个Notification 函数的上下文。
CreateEventEx 服务
CreateEventEx 服务用于生成事件并将事件加入事件组。 由 CreateEventEx 生成的事件会加入到EventGroup中。当EventGroup中的任一事件被触发后组中的所有其他事件都会被触发进而同组内所有的Notification函数都将被加入到待执行队列。同组内 NotifyTpl(优先级)高的Notification函数会先被执行。
如果输入参数EventGroup为NULL则CreateEventEx退化为 CreateEvent。
Type 不能是 EVT_SIGNAL_EXIT_BOOT_SERVICES 或 EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE因为这两种类型有各自对应的Group。
UEFI 预定义的 4 个 Event 组
事件相关的其他函数
1.检查事件状态的服务CheckEvent() CheckEvent 用于检测事件的状态。与WaitForEvent不同的是CheckEvent调用后立刻返回。
2.触发事件的服务 SignalEvent SignalEvent 用于将事件的状态设置为触发态。如果事件类型为EVT_NOTIFY_SIGNAL则将其 Notification函数添加到就绪队列准备执行。如果该事件属于一个组则将该组内所有事件都设置为触发态并将组内所有EVT_NOTIFY_SIGNAL事件的Notification函数添加到就绪队列准备执行。
3.关闭事件的服务CloseEvent 事件使用完毕后必须调用CloseEvent关闭这个事件
通常的原则是由事件的所有者即调用CreateEvent产生该事件的调用者调用CloseEvent函数。调用该函数后指定的事件将从内核中删除。
定时器函数
定时器是一类特殊的事件生成定时器事件后可以通过SetTimer服务设置定时器属性。
SetTimer 服务的函数原型 Type 是定时器类别
任务优先级
UEFI标准虽然不支持多线程但是UEFI中有任务的概念一个程序是一个任务事件的Notification函数也是一个任务。UEFI没有给开发者提供中断接口但 UEFI 内核的运行需要时钟中断的支持时钟中断处理函数也是一个任务。 例如时钟中断任务的重要性要大于定时器的Notification函数而定时器的 Notification函数的重要性大于普通应用程序。UEFI为任务定义了任务级别以便有限的计算机资源可以相对合理地分配给众多的任务。
提升和恢复任务优先级
RaiseTPL(NewTpl)用于提升当前任务的任务优先级至NewTpl该函数的返回值为原来的任务优先级。RestoreTPL用于恢复通常是降低任务优先级至原来的优先级。 RaiseTPL 和 RestoreTPL 必须成对出现执行了RaiseTPL后必须尽快调用 RaiseTPL 将任务优先级恢复到原来的值。
当任务优先级提升至TPL_HIGH_LEVEL时将关闭中断。当任务优先级从TPL_HIGH_LEVEL恢复到原来的比TPL_HIGH_LEVEL低的值时中断被重新打开。
在任务优先级恢复到原优先级之前所有高于原优先级的触发态事件的Notification函数都要执行完毕。
UEFI是单CPU单线程系统产生数据竞争的唯一可能来自中断处理函数因而可以利用这一特性实现锁这正是 UEFI 锁的实现机制。
UEFI 中的时钟中断
UEFI 用事件机制取代了 BIOS 中的中断机制虽然 UEFI 不再提供中断接口但其实现却离不开中断尤其是时钟中断。时钟中断是事件机制的基础。
1.时钟处理函数 CoreTimerTick 在时钟中断中调用是时钟中断处理函数的主体。该函数执行期间必须关中断并且不能被其他任何任务干扰因而进入函数时需要加锁离开函数时需要解锁。它的主要功能是维持系统时间检查定时器事件列表中是否有到期的事件。
2.设置时钟处理函数及安装时钟中断
mArchProtocols 数组是 UEFI 系统 DXE 阶段的全局变量存放了体系结构相关的 Protocol系统初始化时会为 mArchProtocols 中的每个元素生成一个事件当这个元素对应的 Protocol 安装时该事件会触发在事件的回调函数中会对该Protocol做相应的初始化。
Protocol 在内核中的组织 所有的 Protocol均放在 mProtocolDatabase指向的PROTOCOL_ENTRY链表中。PROTOCOL_ENTRY 包含三个链表。 AllEntries 是PROTOCOL_ENTRY 链。 Protocols 指向此Protocol的所有实例。 Notify指向 PROTOCOL_NOTIFY链表当 PROTOCOL_ENTRY.ProtocolD 对应的 Protocol 安装时Notify 链表中所有Event都会触发。
例如mArchProtocols[3]为{gEfiTimerArchProtocolGuid, (VOID**)gTimer, NULL, NULL, FALSE},是EFI_TIMER_ARCH_PROTOCOL 对应的 EFI_CORE_PROTOCOL_NOTIFY_ENTRY 项 CoreNotifyOnProtocolInstallation 执行后mArchProtocols[3]为{gEfiTimerArchProtocolGuid, ( VOlD** )gTimer, timerEvent, Registration, FALSE} ,TimerEvent 的 Notification 函数被 CoreRegisterProtocolNotify 函数注册到系统。 CoreRegisterProtocolNotify(…)函数的主要功能是在 mProtocolDatabase 数据库中注册PROTOCOL_NOTIFY。当Protocol安装时会检查该Protocol对应的PROTOCOL_ENTRY.Notify。如果PROTOCOL_ENTRY.Notify存在则触发它指向的事件。
当 EFI_TIMER_ARCH_PROTOCOL安装时mArchProtocols[3].Event事件会触发然后这个事件的响应函数 GenericProtocolNotify会执行在 GenericProtocoINotify中通过 EFI_TIMER_ARCH_PROTOCOL的RegisterHandler 时钟中断处理函数。
向 gimer 注册 CoreTimerTick 函数 gTimer 是EFI_TIMER_ARCH_PROTOCOL*类型的全局变量。 gTimer-RegisterHandler 这个函数指针指向了函数 TimerDriverRegisterHandler。
mTimerNotifyFunction这个函数指针将在时钟中断处理函数TimerInterruptHandler中被调用。
向 CPU 注册中断处理函数 TimerInterruptHandler 在 TimerDriverlnitialize 中最终通过 EFI_CPU_ARCH_PROTOCOL 的 RegisterInterruptHandler注册了 TimerInterruptHandler。另外在中断处理函数中将会调用 TimerInterruptHandler而TimerlnterruptHandler 又会调用 mTimerNotifyFunction, 即 CoreTimerTick。 而 mCpu-RegisterInterruptHandler 将会调用CpuRegisterInterruptHandler 函数 此函数注册并启用由 InterruptHandler 为处理器中断或由InterruptType指定的异常类型指定的处理程序。如果InterruptHandler为NULL则取消安装由InterruptType指定的处理器中断或异常类型的处理程序。安装的处理程序对于每个处理器中断或异常调用一次。
在 CPU 时钟中断向量中调用时钟中断处理函数
默认的中断向量主要功能是调用CommonInterruptEntry。该函数主要完成以下任务 1保存寄存器 2调用ExternalVectorTable[InterruptType] 3恢复寄存器从中断处理返回。 在时钟中断向量中ExternalVectorTable[InterruptType]指向函数 TimerInterruptHandler。
时钟中断的执行过程 注册时钟中断函数和注册时钟处理函数的过程
UEFI 事件 Notification 函数的派发
Event的一个重要作用是实现异步操作事件 Notification函数的派发是在gBS-RestoreTpl服务中完成的。gBS-RestoreTpl实际指向CoreRestoreTpl函数
内容来源于 《UEFI 原理与编程》。。。