简单来说,CPU正忙着做自己的事情,这时硬件(例如键盘按下)触发了一个电信号,该信号通过中断线传给中断控制器,中断控制器接收到这个信号,向CPU发送一个信号,申请CPU执行刚才的硬件操作, 然后在执行后向中断控制器发送信号,告知它已被处理。
中断演进 : INTX -》MSI -》 MSI-X
先说 INTX:
如下一个CPU图:
标记为红色的两个引脚是 80386 处理器为中断保留的两个引脚。其中 INTR 是可屏蔽的中断输入端口,NMI 是不可屏蔽的中断输入端口。
问:如何将中断输入到处理器? 外部设备那么多,但 cpu 只有一个输入引脚?
那就需要用到中断控制器了
可编程中断控制器 (PIC)如下:
IR0-IR7:负责连接外部设备,中断输入。
D0-d7:连接系统总线的数据线,数据输入,对应上面CPU d0-d31。
INT:中断请求信号,输出,连接CPU INTR。
通常,8259A芯片是两级级联,总共可以连接8 x 8=64个外围设备。
连接拓扑如下:
中断处理过程
当键盘发生中断事件时。此事件通过 IRQ1 中断线通知主PIC。经过一些内部判断和处理后,主PIC通过int向CPU侧的“INT”发送电信号。执行当前指令后,CPU检查“INT”中是否有信号,表示有中断请求。然后它检查如果 EFLAGS 不为零,表示当前允许处理中断,就向 pic 的“INTA”发送信号,告诉它发送该中断的“vector number”。在接收到信号后,该向量通过d0-d7引脚将中断编号发送到CPU。CPU 获取此编号后,可以从 IDT 中找到中断服务例程 (ISR) 进行处理。执行后,向 i8259a 发送 “INTA” 信号,表示它已经完成了刚才的请求。
IDT 中断向量表,或者叫门描述符,对应了各个中断号的处理函数,大概如下的形式:
32 |
Intr_deal_function_32 |
33 |
Intr_deal_function_33 |
34 |
Intr_deal_function_34 |
35 |
35 |
IDTR 寄存器保留 IDT 表的基址
中断编号 +32 = 中断向量 Linux
中断编号 +48 = 中断向量 Win
再说MSI:
INTX 最多支持 64 个中断,随着中断数量的增加,芯片组引脚不够用,因此引入了 MSI。
英文:Message Signaled Interrupt
MSI 允许设备将一小段数据(消息数据)写入指定的 MMIO 地址(消息地址),然后芯片组生成中断给 CPU
配置空间如下:
Capability ID = 0x5
Message Control bit :
Bit-0 : MSI enable
Bit1-3 : the number of interrupts supported,4^xx
Bit4-6 : the number of interrupts enabled, 4^xx
Bit7 : 1=64-bit address structure ,0=32-bit
Bit8 : 1=support mask , 0= not support
Why is only 32 interrupts supported?
Why it require a continuous interrupt number?
常常看到MSI单设备支持32个中断,为什么呢,从上图可以看到
MASK BIT就只有32位,所以只能支持32个中断。
Bit4-6来看,enable的中断只能是1,4,8,16,32,并不能指定1 3 5这样的enable方式,
所以msi支持的中断号必须是连续的。
Message Address
Message Address :当中断来临时,PCIE将消息数据写入此地址
Message Address格式如图
Address Format : 0xFEEx-xxxx
Destination Id : target cpu id
RH : 0= sent to the specify cpu; 1= select one from the all CPUs
DM : 0= physical cpu; 1= virtual cpu
当我们把数据写给0FEEXXXX的时候,实际上是写给LAPIC的,所以当我们写地址的时候,会触发CPU中断。
Linux系统上面可以尝试一下操作:
MSI Message Data
Message Data :存放MSI消息使用的数据。
Message Data和Message Address由系统在计算机启动时就已经配置好了。
Message Data格式如下:
Bit0-7 : 此 8 位字段包含与消息关联的中断向量。取值范围从 010H 到 0FEH。
Trigger Mode :0=表示边缘敏感。1=表示电平敏感。
Bit8-10 : Delivery Mode,This 3-bit field specifies how the interrupt receipt is handled.
0= Fixed Mode
1= Lowest Priority
10= System Management Interrupt or SMI
100=NMI
最后是MSI-X:
MSI 要求中断数是连续的,现在单个设备 32 个中断也不够用,所以引入了 MSI-X。
MSI-X 不要求中断数是连续的,单个设备支持 2048 个中断。
MSI-X 如何支持 2048 中断?
配置空间如下:
Message Control
Bit0-10 : Table size, 2^10=Max 2048 interrupts
Bit14 : 1 = Mask all interrupt
MSI-x table offset : the offset over bar
Table BIR : the number of the bar
MSI-x 信息记录到BAR上面,每个中断会在BAR上有一条记录,中断信息在BAR上的记录的样子如下:
每个中断都使用单独的“消息地址”字段和“消息数据”字段。
一些实践性操作
Linux下小实验:
Watch ‘cat /proc/interrupts’
设置亲和性:
Windows 中断亲和性
注册表中配置:
windows亲和性工具:
Interrupt_Affinity_Policy_Tool