![1594b413de11eaf83b5cff6638134ef0.png](https://i-blog.csdnimg.cn/blog_migrate/3412b3f35e3f6dbfb23cb757eabe4ed3.png)
中断系统是现代PC的基础架构之一,我们常常能听到很多相关概念:IRQ,PIRQ,PCI Interrupt PIN,MSI,GSI,Vector(中断向量)。这些术语有些是硬件概念,有些是软件概念,他们时常混在一起,让人十分迷惑。本系列希望能通过三篇文章来帮助大家厘清其中的关联和区别,它们分别是历史和原理篇(偏硬件)、软件篇(关于OS和BIOS如何设置和使用中断)和固件篇(BIOS如何根据硬件配置中断和向OS报告中断表)。
历史
![b9bbe4fd5136d389e5df8a1b7ef618eb.png](https://i-blog.csdnimg.cn/blog_migrate/81740fe65220bf08aabd228509f7e7aa.png)
当我们在操作电脑时,很多事情在同时发生,磁盘在飞速读写,网络在收发消息,而你也往往开了不少个任务在同时运行。这些能够发生,中断系统扮演了关键角色。在中断系统出现之前,人们(那时都是计算机专家)往往要等上一个任务结束才能进行下一个任务,这在今天是不能想象的。事实上中断系统出现的很早,Intel的传奇中断控制芯片8259在1976年就被用在8085系列产品中。PC在1981年出生时借鉴了这种思想,8259的升级版8259A被用于中断控制,而其统治PC长达近10年,直到486电脑的诞生!
1PIC时代
PIC(Programmable Interrupt Controller)就是我们的8259A,让我们来瞻仰一下它的样子:
![97ee8a6d3727c79dcb1c3bd49e21664d.png](https://i-blog.csdnimg.cn/blog_migrate/c8479909431bb4d61d6e0383c5e10dd3.jpeg)
其中最重要的管脚是IR0~IR7,也就是能相应8个中断。后期由于中断不足,被扩展为级联的形式,如图:
![d427be3cd885b4f5ba7ca20482affd45.png](https://i-blog.csdnimg.cn/blog_migrate/3f8c1e4bc6aafd1b46de86e4adc4a23a.jpeg)
分为主和从两块8259,这样我们就有了16 -1 = 15个中断源。8259一直工作的很好,中断如果还不够我们还可以通过中断共享或者再多级联几个8259,就可解决问题,直到多CPU的出现。这时候问题出现了,我们的主8259到底连接哪个CPU好呢?这是个大问题。
2
APIC来了
80486DX在1990年上市,其引入了SMP的概念,即多CPU(注意不是多核)。Intel为了适应SMP提出APIC(Advanced Programmable Interrupt Controller,高级中断控制器)的新技术。APIC 由两部分组成,一个称为LAPIC(Local APIC,本地高级中断控制器),一个称为IOAPIC(I/O APCI,I/O 高级中断控制器)。前者位于CPU中,在SMP 平台,每个CPU 都有一个自己的LAPIC(后期多核后,每个逻辑核都有个LAPIC)。后者通常位于外部设备芯片上,例如南桥上。像PIC 一样,连接各个产生中断的设备。而IOAPIC和LAPIC通过APIC Bus连接在一起。如图:
![602b9bff26f70841c5c2f2efdf7ff891.png](https://i-blog.csdnimg.cn/blog_migrate/14284261e4f8cd9c022193a1f25ce332.png)
3
XAPIC,小小的改进
单独的3根线的APIC bus给系统设计带来了不少困扰,在奔腾4上其被取消而由系统总线代替,其他则区别不大,新的示意图如下:
![d03f49dc8a321a689e8d006fdc19bb69.png](https://i-blog.csdnimg.cn/blog_migrate/4eae4ec02d1c9da9b73588f535943316.png)
系统中的IOAPIC可以有很多,在北桥被并入CPU中后,甚至CPU中也有IOAPIC(同时有LAPIC,感觉好方便)。这种架构极具伸缩性,被使用了很多年,直到核战争的爆发。
3
X2APIC
核战争,什么鬼?!其实是内核数目的战争。Intel和AMD不断的增加内核的数目,加上SMT(HT)技术,内核数目不断上升。在服务器上,至强CPU往往提供高达40到60个内核,如果是8路服务器,内核总数目可以高达60 × 8 = 480个!即使实际没有这么多内核,虚拟机技术的出现也往往成倍的需要虚拟内核。而唯一标识CPU内核身份的APIC ID在APIC寄存器中却只有8位(其细分为多个域,这里略过),也就是最多可以有255个内核(1个保留做广播用)。APIC不够用了!Intel大手一挥,推出了X2APIC,把APIC ID从8位扩展为32个bit,这下可以支持4G -1 (1个保留做广播用)个逻辑核,你们该满足了吧!顺便将原来略显怪异的MMIO访问方式变成MSR方式(后文详细介绍)。
我们现在的计算机几乎都是用APIC方式处理中断的,我们接下来看看他们是怎么工作的。
原理
![b9bbe4fd5136d389e5df8a1b7ef618eb.png](https://i-blog.csdnimg.cn/blog_migrate/81740fe65220bf08aabd228509f7e7aa.png)
CPU在运行目前任务时,当有特别事件发生时,CPU应当暂停正在执行的程序,转向执行处理该事件的子程序;事件处理完毕后,恢复原来的状态,再继续执行原来的程序。这种对这些事件的处理模式,称为程序中断(Interrupt)控制模式,简称中断控制或中断。这种处理紧急事件的服务子程序称为中断子程序。这种引起中断的事件称为中断源。这些事件包括磁盘、键盘等等输入输出设备,异常错误的发生甚至另一个CPU的调用。
1PIC模式
在PIC时代,外部中断源都要连接到8259的IRQ引脚上,8259会通过INTR告诉CPU发生了中断。这时OS或者BIOS的中断控制程序会检查谁发生了中断,从而调用相应的中断相应历程。 其中的细节我们这里就不细述了,其过程大概分为以下几步:
1、一个或多个IR 引脚被触发中断(脉冲或者边缘),若对应的中断没有被屏蔽,8259 拉高INTR 管脚通知CPU 或上一级8259中断发生。
2、CPU 通过INTA 引脚响应8259,表示中断请求收到。8259则将IRR 中具有最高优先级位 清零,并设置ISR 中对应的位。在CPU发出中断查询脉冲后,8259将中断号提交到数据线上。
3、中断号对应的中断向量处理程序被调用,OS或者BIOS中断处理程序开始处理中断,完毕后写EOI并扫尾。
在这样一个周期完毕后,CPU继续处理之前的任务,像什么事也没有发生一样,一般用户甚至感受不到(实际上OS的中断处理例程有严格的时间要求,处理过长会触发watch dog 导致蓝屏)。
古老的PC留下了很多兼容性的问题,很多古老的设备占据了大量中断源,如图:
![19fb135f8d1bdafeb79c22fc3822a6f4.png](https://i-blog.csdnimg.cn/blog_migrate/d4f6f9db0507ed3d259b6a84d5a6bf7e.jpeg)
现在谁还有这么多串口并口呢,还有键盘和FDD?可是为了向前兼容,这些IRQ都被保留而不能做它用,甚至在APIC模式也是这样。向前兼容真是个沉重的包袱!
注意这里中断是有优先级的,IRQ数字越小优先级就越高。
2
APIC模式
如前所述,APIC 由两部分组成,一个称为LAPIC(Local APIC,本地高级中断控制器),一个称为IOAPIC(I/O APCI,I/O 高级中断控制器)。前者位于CPU中,在SMP 平台,每个内核都有一个自己的LAPIC。后者通常位于外部设备芯片上,例如南桥上。典型的连接关系如下图:
![d03f49dc8a321a689e8d006fdc19bb69.png](https://i-blog.csdnimg.cn/blog_migrate/4eae4ec02d1c9da9b73588f535943316.png)
每个LAPIC都有自己唯一的APIC ID,每个IOAPIC也有自己唯一的ID。和PIC模式显著的区别是连接关系不再是硬件连线而是通过message。IOAPIC内部有个PRT(Programmable Redirection Table)表,里面的Destination Field标识了中断的目的地。在Physical模式下,含有目标APIC ID(Logical模式略)。在中断发生时,IOAPIC收到中断,会将中断转化为message放入系统总线,而CPU中只有APIC ID和Destination Field域中一致的LAPIC才会处理这条中断。用于处理来自IOAPIC 的中断消息的LAPIC内容就更多了,但最重要的寄存器还是IRR、ISR 以及EOI。其流程和PIC类似,这里就不在详述了。OS如何处理我们会在下一篇中介绍。
值得一提的是,为了保证向前兼容性,Intel在1997年发布的MultiProcessor Specification(MP spec)中要求APIC提供PIC兼容模式或Virtual Wire Mode(虚拟连线模式)。PIC模式如下图:
![e8f25608db3764623ebea5d2e5c0de64.png](https://i-blog.csdnimg.cn/blog_migrate/84f6306e8d98847df627e75d3a631409.jpeg)
虚线代表了中断传递的过程,注意其中的IOAPIC被旁路了,而一个8259A的模拟硬件(通常是南桥芯片内置)则起到作用,它连接了CPU的INTR引脚。这样会对主板电路设计造成很多麻烦,而虚拟连线模式则更加常见,其如下图:
![fabb81efea0c16bc48b3d36655b9667a.png](https://i-blog.csdnimg.cn/blog_migrate/9e7aa404e5239800356cfa8b9916d1b9.jpeg)
IOAPIC会将8259A模拟硬件的信号放入ICC Bus(后是系统总线),由LAPIC处理交给BSP,处理效果和原来一样而不要增加连线。
3
MSI
普通的PCI设备支持四个INTx,MSI(Message Signaled Interrupts)在1999年随着PCI 2.2规范被引入,在PCI 3.0中提出了MSI-X。MSI支持32个中断,而MSI-X将其扩展到了2048个。当一个PCI设备想发送中断时,它会向其PCI配置空间Capability结构中的Message Address的地址(通常是0xFEExxxxx)写Message Data数据,消息会被该设备连接的root complex转给LAPIC(多CPU时,有可能要通过QPI),而不需要通过IOAPIC中转。Message Address中和IOAPIC类似,也有目标APIC ID,而message Data中同样有Vector的数目。这样从电气机械的角度,MSI减少了对interrupt pin个数的需求。从而使得连接变得更简单,而且据研究,其相比INTx,有时能提高1/3的效能。
微软在Vista后全面支持MSI和MSI-x,而Linux也早已经支持MSI。
其他
![b9bbe4fd5136d389e5df8a1b7ef618eb.png](https://i-blog.csdnimg.cn/blog_migrate/81740fe65220bf08aabd228509f7e7aa.png)
还有些杂项这里要特别说明一下
1APIC ID
APIC ID并一定从0开始,数字也不一定连续,在任何地方的代码里都不能有这种假设。APIC ID可以被BIOS重置,但几乎没有BIOS这样做。
2
IOAPIC ID
随着北桥被移入了CPU ,一些北桥的除了内存控制器外其他的功能也被引入CPU。其中最重要的是PCIe的root complex和一个至少x16的root port用于连接显卡。如果CPU内置的显卡,也会连接到这个root port上,所以Intel平台除了在南桥外,在CPU内也有IOAPIC。在一个4路的志强服务器中就会有4 + 1 = 5个IOAPIC, 每个IOAPIC有24个入口,就可以支持24 * 5 = 120个中断入口。
3
LAPIC
除了IOAPIC能发送中断消息外,内核的LAPIC也可以通过发送IPI(Inter-Processor Interrupts)的方式发送中断给其他的内核。这种方式是OS和BIOS调度CPU内核的基本方式。
尾声
![b9bbe4fd5136d389e5df8a1b7ef618eb.png](https://i-blog.csdnimg.cn/blog_migrate/81740fe65220bf08aabd228509f7e7aa.png)
在下一篇中将介绍IRQ,PIRQ,PCI Interrupt PIN,MSI,GSI,Vector(中断向量)的关系和谁负责设置它们,敬请期待。这里有几个思考问题,大家可以查查资料:
1. 那么对于多CPU的情况下,初始的APIC ID是谁来决定的呢?注意CPU可以互换。
2. IOAPIC都要有不同的ID,这些ID是谁给设置上去的呢?
![5589c10ae9b34ed82c9057eccadc5634.png](https://i-blog.csdnimg.cn/blog_migrate/67cb4776a6fc9246baac9df4b21740e0.jpeg)
![bcd01365486adb973003eabbc0c7401b.gif](https://i-blog.csdnimg.cn/blog_migrate/1901f68ebe109924fc7a914ff29fbbd2.gif)