如何理解UEFI的事件机制(三)——时钟中断
一,时钟中断概述
UEFI 中的EVENT是使用时钟中断来驱动的。
在时钟中断处理函数中,它会检查系统中的定时器事件并处理到期的定时器事件,并在合适的时机调度事件的Notify函数,是事件的实现基础。时钟中断在DXE的主函数DxeMain中初始化(准确的说是在初始化事件时)并开始使用,具体的流程请看下图——当时作为UEFI小白的我画了一天!其实后来看,有一些是架构协议与触发函数注册的内容,待会浅提一下。
二,时钟中断执行流程
执行时钟中断的单元函数是CoreTimerTick,我剧透一下,因为它被注册为mTimerNotifyFunction,所以在其他架构下看到的mTimerNotifyFunction函数其实就对应CoreTimerTick。
当然你也可以叛逆期到了自己写一个……
CoreTimerTick (IN UINT64 Duration)
{IEVENT *Event;CoreAcquireLock (&mEfiSystemTimeLock);mEfiSystemTime += Duration;if (!IsListEmpty (&mEfiTimerList)) {Event = CR (mEfiTimerList.ForwardLink, IEVENT, Timer.Link, EVENT_SIGNATURE);if (Event->Timer.TriggerTime <= mEfiSystemTime) {CoreSignalEvent (mEfiCheckTimerEvent);}}CoreReleaseLock (&mEfiSystemTimeLock);
}
其实源代码里注释写的很清楚了
首先升高优先级,更新系统时间,这里的优先级是31——UEFI中定义的最高优先级,不会被抢断
mEfiTimerList是所有定时事件,按触发时间从近到远排列,如果第一个没有被触发,说明没有定时器事件到期,反之,开始触发定时器事件。
不过需要注意一点,我之前写过事件在升高降低优先级时进行调度,这里也进行了这一行为,但实际上,在进这个函数时优先级已经很高了,所以调度并不是在这里,而是在另一个函数里,这就涉及到时钟中断的注册流程。
三,时钟中断的注册流程
时钟中断的注册分为好几部分,我们先来看最简单的部分好了
句柄注册与触发函数
(好大的图片!)
这段就是我之前说的,不应该放在这里的部分,稍微提一提就好了。
我们都知道BDS阶段的入口是BdsEntry函数,然而它是怎么跳过去的呢?这就涉及架构协议注册与触发函数机制(我起的名)
在DXE中,定义了以下协议为架构协议,这些协议大多承担了比较重要的架构功能
EFI_CORE_PROTOCOL_NOTIFY_ENTRY mArchProtocols[] = {{ &gEfiSecurityArchProtocolGuid, (VOID **)&gSecurity, NULL, NULL, FALSE },{ &gEfiCpuArchProtocolGuid, (VOID **)&gCpu, NULL, NULL, FALSE },{ &gEfiMetronomeArchProtocolGuid, (VOID **)&gMetronome, NULL, NULL, FALSE },{ &gEfiTimerArchProtocolGuid, (VOID **)&gTimer, NULL, NULL, FALSE },{ &gEfiBdsArchProtocolGuid, (VOID **)&gBds, NULL, NULL, FALSE },{ &gEfiWatchdogTimerArchProtocolGuid, (VOID **)&gWatchdogTimer, NULL, NULL, FALSE },{ &gEfiRuntimeArchProtocolGuid, (VOID **)&gRuntime, NULL, NULL, FALSE },{ &gEfiVariableArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },{ &gEfiVariableWriteArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },{ &gEfiCapsuleArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },{ &gEfiMonotonicCounterArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },{ &gEfiResetArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },{ &gEfiRealTimeClockArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },{ NULL, (VOID **)NULL, NULL, NULL, FALSE }
};
对于这些架构协议,DXE设计了一套机制,在主函数DxeMain中调用CoreNotifyOnProtocolInstallation给这些函数都注册了一个事件,当上述协议被模块Install时,事件会触发回调函数GenericProtocolNotify
在回调函数中,UEFI注册了传入的协议对应的Entry函数(比如对于Bds,这个函数就是BdsEntry),并且,当判断到传入的协议是gTimer时,会做如下处理
if (CompareGuid (Entry->ProtocolGuid, &gEfiTimerArchProtocolGuid)) {//// Register the Core timer tick handler with the Timer AP//gTimer->RegisterHandler (gTimer, CoreTimerTick);}
相当于,在gTimer被注册后,会调用gTimer->RegisterHandler (gTimer, CoreTimerTick);这个函数
这个函数其实就一行有用的
mTimerNotifyFunction = NotifyFunction;
其实就是把CoreTimerTick注册为时钟中断的原子函数
CPU视角下的时钟中断
在内核中,唯一不变的只有CPU一次次的打点,就像我灰暗的人生,唯一不变的只有、永远一秒一秒流逝的时间。
时钟中断的计时依赖于CPU,那么在CPU视角下,是如何注册时钟中断的呢?
这部分不同架构实现的也不太一样,而且涉及到汇编,有些复杂,这里的例子用的源码的OVM架构的,因为其他架构的我没看懂
在Ovm架构下,Timer模块初始化时运行了如下内容
Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&mCpu);
Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **)&mLegacy8259);
TimerVector = 0;
Status = mLegacy8259->GetVector (mLegacy8259, Efi8259Irq0, (UINT8 *)&TimerVector);
Status = mCpu->RegisterInterruptHandler (mCpu, TimerVector, TimerInterruptHandler);
前两行,分别找到打开的CPU架构和8259协议,8259是芯片,它的IRQ0记录了时钟中断的中断号,在第四行被提取了出来
然后调用RegisterInterruptHandler将传入的中断号为默认中断(TimerVector),并且保存了函数指针到ExternalVectorTable[InterruptType]
在CPU驱动中,调用CommonInterruptEntry进入中断,这个函数只干三件事,保存寄存器、调用ExternalVectorTable[InterruptType]、恢复寄存器。
这部分戴正华老师的书里描述的很详细,我就不写了。
如何理解UEFI的事件机制(三)——时钟中断相关推荐
- Flex事件机制(三)
上一篇主要以代码的方式说明了如何使用自定义事件在父子组件之间传递数据,那么在开发中,我们可能会遇到另一种情况,就是想在任意一个地方监听到任意一个组件中被触发的事件,这样事件处理更灵活,并不局限于父子组 ...
- Android 触摸事件机制(三) View中触摸事件详解
本文将对View中触摸事件相关的内容进行介绍.重点介绍的是dispatchTouchEvent(), onTouchEvent()这两个API以及OnTouchListener接口. 注意:本文是基于 ...
- Web Control 开发系列(三) 解析IPostBackEventHandler和WebForm的事件机制
WebForm最大的魅力大概就是它自己的一套事件处理机制了,要做一个好的Control,必须深入理解这套机制,只有这样才可以让我们的Control有一整套Professional的Event,而IPo ...
- 深入理解DOM事件机制
前言 本文主要介绍: DOM事件级别 DOM事件流 DOM事件模型 事件代理 Event对象常见的方法和属性 一.DOM事件级别 针对不同级别的DOM,我们的DOM事件处理方式也是不一样的. DOM级 ...
- 完全理解Android TouchEvent事件分发机制(一)
本文能给你带来和解决一些你模糊的Touch事件概念及用法 1.掌握View及ViewGroup的TouchEvent事件分发机制 2.为解决View滑动冲突及点击事件消费提供支持 3.为你解决面试中的 ...
- 【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 三 )
Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...
- gtest之断言宏的使用以及三种事件机制
前面简单的介绍了一下gtest以及在Windows下如何安装gtest,今天再介绍一下在Linux下该如何安装. 本文重点: 在Linux下如何安装gtest: gtest下断言宏的介绍: gtest ...
- 「前端面试题系列7」Javascript 中的事件机制(从原生到框架)
前言 这是前端面试题系列的第 7 篇,你可能错过了前面的篇章,可以在这里找到: 理解函数的柯里化 ES6 中箭头函数的用法 this 的原理以及用法 伪类与伪元素的区别及实战 如何实现一个圣杯布局? ...
- 【探讨】javascript事件机制底层实现原理
前言 又到了扯淡时间了,我最近在思考javascript事件机制底层的实现,但是暂时没有勇气去看chrome源码,所以今天我来猜测一把 我们今天来猜一猜,探讨探讨,javascript底层事件机制是如 ...
- 我也来说说js的事件机制
原文链接:http://www.w3cfuns.com/notes/17398/8062de2558ef495ce6cb7679f940ae5c.html 学js,不懂事件机制,基本可以说学了js,就 ...
最新文章
- Ubuntu 安装软件方法
- 以前写的一点东西,放上来吧。否则就扔掉了
- MFC框架程序----实现十
- 再谈对比学习:更好的对比样本选择,更好的对比效果
- 逆水寒服务器更新响应超时,逆水寒patcher.zip文件更新失败怎么办 更新文件异常问题解决方法...
- MySQL社区介绍_mysql社区服务器
- 有道智能学习灯 初体验
- JAVA中通过时间格式来生成唯一的文件名
- 基于 EntityFramework 生成 Repository 模式代码
- php访问服务器文件路径,PHP与服务器文件系统的简单交互
- react实现全选和反选_全选的实现
- springboot的yaml属性配置文件注入
- 机器学习 -- 用户画像
- layuiadmin上手好难_孩子学什么乐器好?十种最受欢迎乐器的优劣势分析
- ylbtech_dbs_article_五大主流数据库模型
- 【C++笔记】封装的意义,结构体和类的区别
- tongweb php,TongWeb服务器部署
- Linux环境进程间通信(一)管道和FIFO
- graphpad prism图标设置_科研绘图软件-Graphpad prism使用教程(六)
- catalina.log localhost.log localhost_access_log.txt manager.log tomcat-stdout.log 文件占用过大,处理方式