UEFI中的中断处理流程

1
中断向量表
你有没有好奇过,0内存地址开始放了些什么东西呢?毕竟是最开始就要用的东西,一定非常重要!没错,那里就是中断向量表的家。在8086开始,中断向量表就占据这里,甚至在我们最新时髦的酷睿x代,它们还在这里。想不想看看这个顽固的家伙的样子?写个简单的 程序:
long *p = (long *) 0;
printf(“%x”, *p);
运行下看看。不出所料你的程序将产生一个异常,导致被强制关闭。还记得我们前面讲过地址转换,这个0地址是虚拟地址而不是物理地址,在保护模式下0的虚拟地址访问会产生一个异常,你是访问不到物理0地址的。我们在内核模式使用一些技巧或者我们进入实模式,我们才能看到它们。每个中断向量(vector)占据4个字节,intel定义了256个向量,共用去1kb的内存空间。每个向量朴实无华,就是一个地址,指向该中断(int)处理函数的入口,这也是它起名vector的原因。整个中断向量表就是一个大函数指针表,一个中断发生,cpu硬件就来这里查表,跳到相应地址就行了,好方便!实际情况稍微复杂点,cpu还要保护现场,将当前环境保存起来(一些寄存器和返回地址等压栈),以便处理完后返回现场继续执行。不过相对于我们接下来的保护模式的中断处理简单很多。没错,这个史前遗迹只在实模式发挥作用,我们只草草看看它的样子就行了:
这里主要是异常处理
硬件中断向量一区。和我们上文的8259连接两相对照一下:
没错,这里就是主8259的irq的中断向量区。接下来就是bios保留区,作为介绍bios的专区,这里必须看一下:
pc传统legacy bios的服务例程都在这里。看到它们不胜唏嘘,曾经int 10h打字和int 13h读写磁盘的美(yuan)好(shi)日子又浮现在眼前。。。不好,这是个暴露年龄的话题,后面我们就不讲了,下课。
开个玩笑,不过中断向量表今天也只在uefi bios为了兼容传统os启动的csm模块中起作用,我们大致了解一下其中的原理即可。
2
中断描述符
在pc进入保护模式,一个复杂但有很多妙处的机制代替了中断向量表,它就是中断描述符表(idt,interrupt descriptor table)。idt将每个中断或者异常与它的服务例程连接起来。idt不再固定放在某个位置,而是可以放在idtr寄存器指向的任意内存(说是任意,也不能太随性,有些小要求,如8字节对齐等),idt的表项也从4个字节扩展到8个字节,大小也可以不满256,idtr也指出了它的最大限制。如图:
idt除了和中断向量一样指向一个例程地址之外,还包括其他一些信息:
其中的dpl(描述符特权级)与cs寄存器的cpl完成特权级的检查,可以避免低特权级的代码通过软件中断形式提权。它的运作形式和中断向量表类似,更多的是安全检查和可能的执行环境切换(例如ring 3 -> ring 0)。
3
中断和异常
arm体系中断和异常是单独处理的,irq中断只是异常列表里的一项而已。x86中断和异常处理却混杂在一起,使用同一套机制,看似比较混乱。其实异常往往是处理器内部发生的,是同步的;而中断却是外部事件,是异步的。而它们的分布也是不同的,0到31号向量保留给异常,而更高的则往往是硬件中断和软件中断。异常分为三种:错误,陷阱和中止。这三种类型cpu对它们有不同的处理原则:错误往往是可以恢复的,错误修正后再执行刚才的错误就不会出问题了,改了就是好同志嘛!例如常用于内存管理的缺页异常,os常常把内存换出到硬盘,它会在页表上动些手脚,cpu再次访问这块内存会发生异常,os页面错误异常例程捕获到后赶紧把内存换回来,然后返回原处执行,就像没事发生一样。陷阱是留给软件挖坑的,cpu希望软件自己挖的坑自己能填上,它可以装作没看见,从下条继续。典型的例子是int 3,我们的几乎所有调试工具(vs,windbg,甚至uefi的source level debugger)都用它添加软件断点。中止就严重了,意味着发生硬件错误了,它往往能造成windows蓝屏,linux panic等。异常一览表如下:
20到31被预留将来使用。硬件中断往往就从32开始。
4
中断优先级
pic模式irq数目越低就意味着优先级越高。而在apic模式下,ioapic连接的24个irq是平权的,先后并不关乎优先级高低。决定中断优先级的是它对应的中断向量的大小,x86体系有256个vector, 中断优先级的计算公式是:
优先级 = vector num / 16
即每16个中断一组,共享一个优先级,共16个。因为32以下vector被异常和保留占据,2到15是中断的优先级。数字越大越高优先级。中断优先级的控制是靠lapic的tpr(task priority register,任务优先级寄存器)来控制的,它的结构如下:
tr只有4位标识可以接受的中断优先级,即16个。cpu内核只处理优先级比tr大的中断,也意味着tr每提高一个数字,就有16个中断被遮蔽!看来我们的中断要想被赶快处理,必须占个好位置。那么是不是irq数目越大,vector就越大呢?这是谁来决定的呢?这事可不由bios做主,os是设置vector的主人。而不同的os的处理也不近相同,我们具体看一下。
中断处理实践
windows、linux和bios在处理中断上有很多区别。我们从几个方面浮光掠影了解一二。
1
中断向量设置
pic如何设置中断向量已经过时,我们就不提了。这里只介绍apic模式,如果你还记得上节关于ioapic的内容,其中最重要的prt表,它由24个rte( redirectiontableentry)项组成,每一项对应一个irq引脚。它的内容除了上节介绍过的destination field之外,最低8位是该irq对应的vector,可以表示256个vector。os根据自己的策略,为irq分配不同的vector。
1. windows:
windows的hal在设置vector时是根据系统枚举硬件时挨个设置的,因为先枚举的设备其irq的大小不确定,所以优先级并无一定之规。从vector不能推导irq,irq也不能推导vector,可以说全凭运气。为硬件irq分配的vector往往从0x31开始分配,应该是为了配合windows的irql概念。大家可以在windbg里输入命令
!idt -a
查看一下自己机器的vector分配情况。这个irql比较让人混淆,实际上它并不是个硬件概念,和中断优先级并不同,它是微软定义的一套软件优先级方案。windows用0到31来表示优先级,数值越大,优先级越高。如下图:
其中dpc/dispatch是个分水岭,运行在这个优先级的线程不会被其他线程抢占。其上3到26是为了外围硬件保留的。最高的31显得很高大上,谁的地位这么高?你一定见过它,它就是在windows蓝屏时的irql。hal会把irql翻译到不同的硬件平台上,它和x86的中断优先级不是一个概念。
2. linux:
linux没有irql的概念,他的vector就从0x20(32)开始分配,但是因为0x80(128)因为历史原因,被保留做系统调用(后改用sysenter指令,但为了兼容,还是保留),整个空间被一份为二。后面到0xee(238)为止。因为vector的大小关系到优先级,分配的时候为了保证对各个ioapic公平,分配的时候在各个ioapic间轮流分配。大家可以在shell里输入以下命令查看一下中断向量的分配情况:
cat /proc/interrupts
2
irq在多处理器的分发
还有个问题十分重要。某个vector由哪个cpu内核负责处理呢?linux为了公平起见,并不会对bsp(bootstrap processor)另眼看待,所有内核一视同仁。linux通过填写ioapic的rte中的delivery mode选择最低优先级策略,让trp都被初始化做固定值,因此irq信号就可以公平的在cpu之间分发。感觉很民主有没有?(分分钟被linus的独裁作风打脸)。有时为了优化性能,我们可以通过linux的irq亲缘性来让特定内核为我们服务。我们可以通过命令
cat /proc/irq/xx/smp_affinity
查看xx irq由谁处理,如果是f的话代表是缺省策略,即大家都可以处理。我们可以通过下面命令分配个专有内核处理
echo 2 >/proc/irq/xx/smp_affinity
让apic id为2的内核处理。或者通过一些irqbalance类似的工具来帮我们配置。
3
uefi固件中的中断
uefi固件内核中对异常和中断都有处理,还包含很多使用ipi调度内核的源程序,程序短小精干,包括大量注释。感兴趣的同学可以通过它学习中断处理和cpu内核调度。
1. 异常
uefi内核对idt的初始化程序在ueficpupkg的library/cpuexceptionhandlerlib下。内核为所有的的中断和异常都分配了统一的入口commonexceptionhandler。它对任何中断和异常没有任何特殊处理,如果没有人对该中断或异常做处理就会dump一些现在的cpu状态如apic id, 异常类型等,然后调用cpudeadloop陷入死循环,这也是uefi工程师常见的画面。uefi驱动可以在自己关心的异常中添加自己的处理函数,如支持通过串口和usb源程序级调试uefi程序的source level debugger就是个典型的例子,它hook住了很多异常,用于调试和捕捉错误,
2. 中断
uefi的csm模块还兼容以前bios使用的int x软中断方式调用bios服务。随着uefi的广泛推广和传统os的渐渐淘汰,csm也日薄西山,有些仅仅面向最新os的项目都不含csm的支持,所以关于它的内容这里略过。在保护模式下,uefi内核仅仅对时钟中断进行了处理,并通过timer architectural protocol开放出来供所有uefi程序调用。也许你会好奇,那么多种usb设备和网卡等等的uefi驱动难道不需要中断处理?是的,他们的中断在uefi阶段都没有开启,他们的驱动通过timer加polling的方式来处理。举个例子,我们在uefi shell 下插入键盘,它能立刻起作用不是如在os中usb控制器产生了中断。而是usb驱动注册了个timer,过一会就poll一下看看有没有新设备插入。就是这个timer发现了新插入的键盘的。
这种仅仅依靠timer的做法在os阶段是行不通的,会带来严重的效能和功耗问题。但是在boot阶段却问题不大,而且这样做保证了uefi内核的简洁性。事实上,uefi并不禁止驱动自己开启中断,但开启中断需要处理的中断共享、ioapic设置等等问题需要驱动自己解决,uefi并不提供支持。
3. ipi
内核可以通过写自己lapic的icr(interrupt command register)发出ipi((inter-processor interrupt)调度别的内核完成任务,这也是任务调度的基本方法。事实上,因为apic id的不连续性,我们正是通过发送ipi的方法来统计内核的数量。bsp在启动时需要统计系统中可用的内核时,发送广播ipi,让大家都来报道,bsp开始点数,1,2,3。。。并一一记录在案。在启动os前,通过acpi table告诉os有多少个内核。os不应该自己统计内核数目,事实上固件可以通过瞒报内核的方式将部分内核挪作他用,但谁会这么做呢?
如何发起ipi在cpu package里有大量实例和库,大家可以参考。
其他
一些容易混淆的名词这里要特别说明一下
irq x:起源于pic,指中断引脚,后在apic时代沿用,泛指中断号。
vector x/int x: x是中断向量,如前文所说 irq不等于int和vector.
pirq : pci irq。它是描述南桥内部pci设备的irq配置关系的。我们下一篇文章介绍。
gsi :global system interrupt,是acpi spec规定的全局中断表。它为多ioapic情况下确定了系统唯一的一个中断号。例如ioapic1有24个irq,ioapic2也有24个irq,则ioapic2 的gsi是从24开始,gsi = 24 + irq(ioapic2)。
sci :system control interrupt,系统控制中断,是acpi定义的,专用于acpi电源管理的一个irq。它在intel平台上常常与南桥的电源管理模块一起,当外部ec等发生event后会引发sci。windows的sci isr程序就是著名的acpi.sys。acpi.sys在收到sci后会检查gpe状态寄存器以确定是谁引发的event,然后按照acpi spec要求调用相应method。详情请参照acpi spec。可以认为sci是acpi定义的所有电源管理事件的总入口,它对应的irq在一般情况下是不能修改的。sci是如何报告和简单的gpe method我们在下一篇中会详细介绍。
结语
说了这么多,如果我们从硬件和软件方面,梳理整个中断设置和处理的链条,会发现还有个环节没有解决。那就设备的irq是谁来决定的?是硬件hard wired?还是软件可以配置?os是如何知道这些信息的呢?os又是怎么知道ioapic的数目和位置的呢?这些都是uefi固件需要解决的问题,我们在下一篇文章中会详细说明。在此之前,如以往一样,有几个思考问题可以让大家加深对中断和uefi的理解:
1.中断的引入,必然带来了代码重入的问题。我们知道,这可以通过设定优先级、信号量/临界区等等办法来解决。uefi是通过什么方法呢?tpl和irql的相似和区别又是什么呢?
2.uefi内核还不支持多线程,我们如果需要增加多线程调度,仅仅依靠时钟中断,够不够用呢?
3.os利用缺页异常可以调度内存到硬盘上和实现lazy loading等等实用的功能。uefi的smm内核也开启了缺页异常,但是却为了另外一个目的,你能看出是为了什么吗?

小米6或下月发布:顶级的配置,不变的价格
中国联通周晶:RedCap将真正激活5G市场
库克在接受媒体采访时透露,将大力进军电视和电影产业
如何加快数十亿门级低功耗SoC验证呢
在英特尔Xeon Phi™协作处理器上为数学内核库做好准备编译4第1部分
UEFI中的中断处理流程
三星折叠屏手机正式发布_携手三星S10系列惊艳亮相
电机控制器的主要功能及组成
医用防护服阻燃测试仪技术特点
Verizon打算今年秋季在洛杉矶推出5G网络
温湿度传感器选型的注意事项
福日电子发布公告称,公司拟非公开发行A股股票
定时限过电流保护的基本工作原理
TCL8公斤全自动波轮洗衣机搭载8段电子水位 四重智控更健康
特思迪再获融资,带动8英寸SiC量产!曾获华为哈勃投资
土壤养分快速检测仪农业生产中发挥着怎样的作用
AGV机器人具备有哪些优势
海底大地电磁探测数据畸变校正方法的研究
7月18日 助力制造企业“鹏城起飞”,2022华南国际工业博览会将于九月深圳举办
实现云计算和边缘计算协同作用所需的关键技术是边缘缓存