推荐北大陈向群教授讲解的操作系统的网课和intel的编程手册,非常清楚
实例:X86的中断与异常机制 - 操作系统运行环境 | Coursera
英特尔助力京东云构建“重载型”海量内存云主机及“轻量级”容器服务-英特尔® 官网
doc/linux_interrupt.md at master · GiantVM/doc · GitHub
LINUX-内核-中断分析-中断向量表(1)-x86_liangll的博客-优快云博客_linux中断向量表
下面两个源码分析的很好
Linux中断机制之三:中断的执行_phenix_lord的专栏-优快云博客
Linux操作系统学习笔记(十五)中断 | Ty-Chen's Home
- 中断向量
为了处理中断,处理器给每个中断分配一个ID号,这个ID号码就是vector number(中断向量)。处理器利用中断向量作为索引从IDT(中断描述符表)中找到对应entry,进而找到中断服务程序入口地址。
vector number的范围是0-255(2^8),。
vector number范围是0-255(2^8),在Intel 64和IA-32架构下vector 0-31是reserved的。Intel 64和IA-32架构下,vector 32-255是用户定义的中断,不做预留。这些中断通常被分配给外部IO设备,这样IO设备就可以向处理器发送中断。
- 软件产生中断
INT n指令可以允许软件参数中断,其中n就是vector number。
- IDT中断描述符表
IDT(中断描述符表)使用门描述符(gate descriptor)表示中断向量。在保护模式下,IDT其实就是8byte大小的描述符数组。
IDT可以存放在内存中任意的线性地址区间,处理器使用IDTR寄存器找到IDT表的起始地址。
IDTR寄存器保存着32位的基地址和16位的limit。
当操作系统创建或者修改IDT时,使用LIDT指令(load IDT register)把memory中的IDT加载到IDTR寄存器。
使用SIDT指令(store IDT register)把IDTR寄存器中的基地址和limit拷贝到内存。
- IDT 描述符
IDT中每个entry都是一个IDT描述符,总共有三种描述符
- Task门描述符
- 中断门描述符
- 陷阱门描述符
每一种门描述符格式如下:
- 中断处理过程
CPU收到一个中断后的处理流程如下:
- 确定中断向量i。
- 根据IDTR指向的IDT起始地址和中断向量i,从IDT中找到中断向量i对应的entry。
- 读取中断门描述符的segment selector,从segment selector找到索引和GDT/LDT的标志。
- 根据GDTR寄存器找到GDT的起始地址,通过segment selector中的索引从GDT表中获取段描述符地址
- 从段描述符中获取段基址
- 中断服务函数的入口地址=段描述符中的段基址+中断描述符中的偏移
- 通过IDT中的中断描述符,调用common_interrupt;
- 通过common_interrupt,调用do_IRQ,完成vector到irq_desc的转换,进入Generic interrupt layer(调用处理函数generic_handle_irq_desc);
- 调用在中断初始化的时候,按照中断特性(level触发,edge触发等、simple等)初始化的irq_desc:: handle_irq,执行不同的通用处理接口,比如handle_simple_irq;
- 这些通用处理接口会调用中断初始化的时候注册的外部中断处理函数;完成EOI等硬件相关操作;并完成中断处理的相关控制。
具体这么从common_interrupt到各个驱动的注册的ISR参考下面文章
Linux操作系统学习笔记(十五)中断 | Ty-Chen's Home