Loading

x86架构中的外部中断结构-Part 1:中断控制器的演化

      本文主要讲解了x86体系架构从外部设备接受中断的过程,本文是系列文章的第一部分,试图回答以下问题:

  • 什么是PIC以及它的用途是什么?
  • 什么是APIC以及它的用途是什么?LAPICI/O APIC的目的是什么?
  • APIC,xAPIC以及x2APIC之间的区别在哪儿?
  • 什么是MSI? MSI以及MSI-X之间的存在哪些区别?
  • $PIR, MPtable, ACPI tables的用途是什么?

       如果你想知道上述问题的答案,或者仅仅想简单了解一下中断控制器的发展过程,耐心看完本文,你一定会有收获。

原文地址:

     本文是翻译的国外大佬的文章,根据自己的理解稍加修改了语序,由于自己也在学习阶段,翻译难免有纰漏,如果感觉有些地方读不懂,建议可以去看看原文,并向我提出翻译修改的建议,谢谢。

《External Interrupts in the x86 system. Part 1. Interrupt controller evolution》

Introduction

       对于那些不了解中断(interrupt)是啥的同学,这里引用Wikipedia的内容进行简单的介绍:

       在系统编程中,中断是由硬件或软件向CPU(处理器)发出的一种信号,提示CPU需要立即处理一些高优先级任务。 中断提醒CPU注意高优先级任务,同时停止CPU当前正在执行的代码。 随后CPU暂停当前运行的代码、保存程序状态、转而去执行一个中断处理程序(或中断服务程序,ISR)来响应中断事件。 中断是暂时的,在中断处理程序完成后,处理器恢复到之前运行的代码。

        中断一般分为两类:硬件中断和软件中断。

  • 硬件中断:外设一般使用硬件中断向操作系统传递自身需要运行的信号,在计算机内部,外部设备通过向处理器发送电子警报信号实现硬件中断,例如磁盘控制器,或者外部设备,当按下键盘上的键或移动鼠标时会触发硬件中断,从而使处理器读取按键值或鼠标位置。启动硬件中断的行为被称为中断请求(IRQ)。
  • 软件中断:软件中断是由处理器本身的异常,或者是指令集中特殊指令在执行时引起的中断。 前者通常称为陷阱(trap)或异常(exception),用于处理程序执行期间发生的错误或事件,这些错误或事件无法在程序内处理。 例如,数字除以零,会引发除零异常,由此产生软件中断。

       本文主要讲解的是硬件中断IRQ

       中断的目的是什么? 举个例子,在网卡传输数据包的过程中,我们希望数据包到达后立即对来自网卡的传入数据包执行操作,而不是cpu连续询问网卡«我的数据包到达了吗?»,轮询方式会浪费cpu处理的时间,在这个案例之下可以使用外部硬件中断 IRQ,网卡的中断线应该连接到 CPU 的 INTR 线,网卡每收到一个数据包,就通过中断线发出信号,通知cpu数据包已经收到,然后cpu停下手头的工作,去读取这个数据包。

         但是如果有很多外部设备我们该怎么办?不可能将每个设备的中断线直接连接到CPU上,虽然通信效率高,但 在 CPU 上制作大量的 INTR 引脚是不现实的。

 

       为了解决多个外设的中断线连接CPU的问题,一个特殊的芯片被设计出来,这就是中断控制器(an interrupt controller)。

PIC(可编程中断控制器 Programm Interrupt Controller

      第一个中断控制器芯片是 Intel 8259 PIC。 它有 8 条输入线(IRQ0-7)和 1 条输出线(连接中断控制器和 CPU 的 INTR 线)。 当其输入线上的任意一个设备发生中断时,8259 将通过 INTR 线发出中断信号。 于是CPU 知道某个设备请求了中断,处理器将询问 PIC的 8 条输入线(IRQx),并判断哪条是此中断的来源。 这个轮询有一些开销,但现在我们有 8 条中断线而不是 1 条。

     

         很快 8 条输入线就不够用了。 为了增加中断线的总数,两个 8259 控制器(主控制器master和从控制器slave)以级联方式进行连接(Dual PIC)。

           0 7 IRQ 由第一个 Intel 8259 PIC(主)处理,从 8 15 IRQ 由第二个 Intel 8259 PIC(从)处理。 只有主设备直接连接到 CPU 并可以发出中断信号。 如果第 8-15 行有中断,第二个 PIC(从机)将通过 IRQ2 线向主机发送中断信号,然后主机向 CPU 发送中断信号。 这种级联中断占用了 16 条线路中的 1 条,但对所有外部设备总共产生了 15 条中断线(8+7

         

     上述中断控制器级联方案很快被开发社区采用,现在当有人谈论PIC(可编程中断控制器)时,通常是指Dual PIC system即双PIC级联系统。过了一段时间,8259改进为8259A。有了这个控制器,芯片组中就包含了双PIC系统。当外部设备连接的主总线是ISA时,这个系统就足够了。不同的设备需要连接到不同的IRQ线路,因为ISA总线的中断是不可共享的。       设备中断几乎都按照如下标准进行映射:   

Example (from here):

IRQ 0 — system timer

IRQ 1 — keyboard controller

IRQ 2 — cascade (interrupt from slave controller)

IRQ 3 — serial port COM2

IRQ 4 — serial port COM1

IRQ 5 — parallel port 2 and 3 or sound card

IRQ 6 — floppy controller

IRQ 7 — parallel port 1

IRQ 8 — RTC timer

IRQ 9 — ACPI

IRQ 10 — open/SCSI/NIC

IRQ 11 — open/SCSI/NIC

IRQ 12 — mouse controller

IRQ 13 — math co-processor

IRQ 14 — ATA channel 1

IRQ 15 — ATA chanel2

Intel 8259芯片的配置和工作通过I如下I/O端口进行:

     

Chip

Register

I/O port

Master PIC

Command

0x0020

Master PIC

Data

0x0021

Slave PIC

Command

0x00A0

Slave PIC

Data

0x00A1

8259A更加完整的说明文档在此链接here

         后来,外设数量超过了15台,PCI总线也逐渐替代了ISA总线,相比于静态的ISA总线,PCI总线上的设备可以动态的加入到系统中,同时总线上的中断可以共享,这样可以实现利用一条中断线IRQ连接多个设备。最后,为了解决中断线不足的问题,设计者决定将所有PCI设备的中断分配到PIRQ线(Programmable Interrupt Request 可编程中断请求)。

         例如,假设我们在PIC控制器和20个PCI设备上有4条空闲的中断线。我们可以将来自5台设备的中断合并成一条PIRQx线,并将这些PIRQx线连接到PIC控制器。在这种情况下,如果一条PIRQx线路上出现中断,处理器必须询问与该线路相连的所有设备的中断情况,确定对哪个设备响应。由此将PCI中断线与PIRQx线连接的设备称为PIR路由器。使用这种方法必须要确保PIRQx线路没有连接到ISA总线中断上(这会产生冲突),同时要确保PIRQx线路分布是均衡的(我们连接到一条线路的设备越多,CPU在响应哪个设备的中断时需要轮询的次数就越多)。

           

 

        Note:上图展示了PCI设备->PIR的连接过程,在实际电路中,它们之间的连接更加复杂。实际上,每个PCI设备有4条中断线(INTA、INTB、INTC、INTD)和多达8个中断函数,其中每个函数只能有一个INTx中断。每个中断函数将使用哪条INTx线取决于芯片组配置。

       从本质上讲,中断函数彼此间是独立的。例如,一个PCI设备可以具有Smbus控制器函数、SATA控制器函数和LPC桥接函数。从操作系统(OS)的角度来看,每个函数就像一个单独的设备,有自己的配置空间(PCI配置)。 PIC控制器的中断路由信息由BIOS发送给操作系统,BIOS主要通过$PIR 、3Ch寄存器、3Dh寄存器来对PCI 进行配置。

       $PIR 表规范可以在微软提供的网站查询,或者从 PCI BIOS Specification获取相关信息。

APIC

        最后一种方法主要用于多处理器系统。本质上,PIC只能向一个CPU发送中断,在多处理器系统中,需要均衡的向CPU通知中断。这个问题的解决方案是添加一种新的PIC接口----APIC(Advanced PIC)。

       每一个处理器都添加一个特殊的控制器LAPIC(local APIC),以及提供外部设备中断路由的I/O APIC控制器。这些所有的控制器都连接在APIC 总线上,设备连接示意图如下。

   

         当一个外部中断信号输入到 APIC的I/O口上,这个控制器会将该中断信号传送到系统中任意一个CPU上的LAPIC上,在上述传输方式中,APIC控制器可以均衡的将中断信号传入不同的处理器上。第一款APIC芯片是82489DX,它是一个单独的芯片,内部含有LAPIC和APIC,对于上图中的双处理器系统,需要三个这样的芯片:两个用于LAPIC,一个用于I/O APIC。后来,LAPIC功能直接包含在处理器中,APIC部分与82093AA芯片分离。

         APIC 82093AA芯片有24个输入,APIC体系架构最多可支持16个CPU。中断0-15用于旧的ISA中断,以便与旧的系统兼容,中断16-23用于所有PCI设备。通过这种划分,ISA和PCI中断之间的所有冲突都可以轻松避免。随着空闲中断线数量的增加,也可以用来增加PIRQx线的数量。APIC和LAPIC编程可以通过MMIO完成。LAPIC寄存器通常放在地址0xFEE00000上,APIC寄存器放在地址0xFEС00000上,因此可以需要重新配置它们。与PIC的情况一样,最初独立的芯片后来会成为芯片组(处理器)的一部分。

        APIC 体系结构的下一代是xAPIC (x -extended),可以完全向后兼容,并且系统支持的CPU个数增加到了256。xAPIC的下一代体系架构是x2APIC.该系统可以支持的CPUs数量增加到了  2^32。可以在xAPIC模式下运行,也可以在新的x2APIC模式下运行。在这种新模式下,控制器编程不是通过MMIO完成的,而是通过MSR寄存器(速度快得多)。根据该链接(this link,),IOMMU来支持该模式的编程。

        值得一提的是,系统中可能有多个APIC控制器。例如,南桥中的APIC负责24次中断,北桥中的另一个APIC负责32次中断。在APIC系统中,中断通常被称为GSI(全局系统中断)。因此,上述南北桥系统整体的GSIs为0-55。我们如何确定CPU内部是否含有LAPIC,以及它支持哪种APIC体系结构?我们可以通过检查CPUID中的标志位来确定。

        为了帮助OS 发现 LAPIC 和 APIC硬件的存在,以及使用它们。BIOS可以通过MPtable(旧方法)或ACPI表(在本例中是MADT表)来提供有关它们的信息,并加载到OS中。除了上述信息,MPtable和ACPI都应该包含具体的中断路由信息。这包含着哪个设备具体使用哪个中断线的信息(类似于$PIR表),以及相互映射关系。

        我们可以通过查看官方文档(official specification)来了解MPtable,早些时候,该规范出现在英特尔网站上,但目前只能在存档版本中找到。ACPI规范可在UEFI网站上找到(当前版本为6.2)。

MSI

        随着APIC的发展,所有设备的中断线导致系统变得异常复杂并且增加了错误概率。同时PCI express总线也取代了PCI总线,PCIe总线简化了中断系统,该总线中没有中断线,但是为了向下兼容,中断信号(INTx#)用一种单独的消息进行模拟。PCI总线中,中断的连接是通过物理布线实现的。而PCIe总线中的中断是逻辑连接的,并通过PCIe 桥接器进行传输。PCI express引入了一种全新的中断传递方法——MSI(消息信号中断)。在这种方式中,设备只需将数据写入CPU LAPICMMIO区域中的一个特殊位置,即可发出有关中断的信号。信号传输示意图如下:

       

       早些时候,单个PCI设备只包含4个中断,但是现在可以提供多达32个中断。在MSI的情况下,没有共享的中断线:每个中断自然地对应于它的设备。 MSI中断还解决了另一个问题。例如,一个设备进行一个内存写入事务,并希望通过中断发出其完成的信号。但是,写入事务在传输过程中可能会在总线上延迟(设备无法知道)。在这种情况下,中断信号可能提前到达CPU,因此处理器将读取尚未生效的数据。如果使用MSI,MSI信息将以与数据消息相同的方式传输,因此不能提前发送,从而不会出现冲突的情况。

       需要注意的是,没有LAPIC,MSI中断将无法工作,但是MSI可以取代APIC(正如上图所示,进一步简化了电路的设计)。随和一段时间的发展,MSI扩展到了MSI-X,现在每个设备最多可以处理2048个中断,并且可以指定哪一个CPU去处理哪一个中断,这对网卡等高负载设备都非常的有用。MSI不需要单独的BIOS表来支持,但外设需要指明它自身与哪一个MSI信号相对应,这些信息都需要包含在外设的驱动程序中。

Сonclusion

   在本文中,我们学习了有关中断控制器演变的相关知识,并大致了解了x86中断外设的一些基本知识。

    在Part2部分中,我们将进行练习,了解如何在Linux中使用前面提到的每个中断控制器。

    在Part3部分,我们将研究coreboot代码,并查看芯片组中需要哪些设置才能实现正确的中断路由信息。

Links:

Acknowledgments

Special thanks to Jacob Garber from the coreboot community for helping me with this article translation.

Special thanks to Alex's suggestion for Computer architecture review

  

        

 

posted @ 2022-02-17 21:00  aalanwyr  阅读(1189)  评论(0编辑  收藏  举报