Linux.中断处理.入口x86平台entry_32.S

Linux.中断处理.入口x86平台entry_32.S

在保护模式下处理器是通过中断号和IDTR找到中断处理程序的入口地址的。IDTR存的是一个32位的IDT起始地址和一个16位的IDT长度,理论上IDTR和GDTR一样都能支持8192个中断门(65536字节),但x86只能支持256个中断,所以实际上IDTR的最大有效限长只是2048字节。

在这256个中断中,前0×20个中断号被处理器保留用作陷阱(Trap)、故障(Fault)和终止(Abort)。而第0×80号中断号则被Linux用来提供作为用户层程序陷入内核的系统调用之用。所以实际可用的中断号为0×20~0x7F、0×81~0xFF。
Linux内核初始化中断是从init/main.c中的start_kernel调用trap_init和init_IRQ开始的。trap_init 是在arch/x86/kernel/traps.c中定义而init_IRQ是在arch/x86/kernel/irqinit.c中定义的。
先来看trap_init很简单,就是初始化前0×20个保留的中断号。

接下来看init_IRQ很简单就是简单地调用了intr_init。而intr_init这个函数是在arch/x86/kernel/x86_init.c中设定的。

我们可以看到intr_init其实就是native_init_IRQ,它是在irqinit.c中定义的。该程序主要做了两件事:一是调用pre_vector_init实际上就是init_ISA_irqs;二是将所有的中断门设为interrupt数组里的函数。

interrupt是在entry_32.S中定义的

这里实际是上是生成NR_VECTORS-FIRST_EXTERNAL_VECTOR个函数入口,每个函数都在入口处压入一个中断号,然后jmpcommon_interrupt。

init_ISA_irqs是在irqinit.c中定义的,它主要初始化8259芯片为非AEOI模式,并将中断起始向量设为0×20。接着将中断描述符的硬件芯片设为i8259A_chip.其实这里8259的中断号与中断描述符的数组是一一对应的,只不过是0×20号对应irq_desc中的0,依此类推。

现在可以大致总结一下,凡是小于0×20的中断号都由traps.c中的init_trap所初始化的函数接管。而这之后内核将IDT中0×20以后的项的入口都初始化为不同的函数,这些函数都做相同的一件事情就是压入中断号,注意这个中断号是实际的中断号减去0×20得到的逻辑中断号,然后再跳转到common_interrupt中执行真正的中断处理程序。

http://acm.hrbeu.edu.cn/~puppy/2010/12/13/linux-%E4%B8%AD%E6%96%AD%E5%A4%84%E7%90%86-%E5%85%A5%E5%8F%A3/

http://www.cnblogs.com/hustcat/archive/2009/08/14/1546011.html

http://blog.csdn.net/tommy_wxie/article/details/7425692

http://www.cnblogs.com/openix/archive/2012/05/30/2526595.html

http://bbs.csdn.net/topics/340191300

详解entry_32.S

http://blog.csdn.net/jinhongzhou/article/details/6015551

interrupt被定义在arch/x86/kernel/entry_32.S中;
下面,我们来详细理解一下entry_32.S中定义interrupt的这段代码:

.section .init.rodata,"a"  //定义一个段,.init.rodata表示该段可以被读写操作,"a"表示需要为该段分配内存
ENTRY(interrupt)           //定义数据段的入口为interrupt

.text     //是告诉连接器,这部分数据是程序代码
    .p2align 5     //advances the locationcounter until it a multiple of 32. If the location counter is already amultiple of 32, no change is needed. //按32字节对齐
                      ///.p2align指定下一行代码的对齐方式,第1参数表示按2的多少次幂字节对齐,第2参数表示对齐是跨越的位置用什么数据来填充,第3字节表示最多允许跨越多少字节。

.p2alignCONFIG_X86_L1_CACHE_SHIFT         //如果上一行.p2align 5没有执行,那么执行这一条:按2的CONFIG_X86_L1_CACHE_SHIFT次幂的字节对齐,其中CONFIG_X86_L1_CACHE_SHIFT是在内核配置中设定的

ENTRY(irq_entries_start)   //代码段的入口定义为irq_entries_start

RING0_INT_FRAME       //宏展开:.macro RING0_INT_FRAME        //#can't unwind into user space anyway
                                       CFI_STARTPROC simple   #define CFI_STARTPROC .cfi_startproc //用在每个函数的开始,用于初始化一些内部数据结构
                                       CFI_SIGNAL_FRAME      //#defineCFI_SIGNAL_FRAME    .cfi_signal_frame;作用和上面一句类似
                                       CFI_DEF_CFA esp, 3*4  #define CFI_DEF_CFA .cfi_def_cfa //定义计算CFA的规则
                                       /*CFI_OFFSET cs, -2*4;*/
                                       CFI_OFFSET eip, -3*4  //#define CFI_OFFSET .cfi_offset //xx reg ,offsetreg中的值保存在offset中,offset是CFA的
                                       .endm

NOTE:
通用Flash存储器接口(CFI)是一种由Intel、AMD、Sharp和Fujutsu共同制订的规格,是为了提高由不同的供应商现在或者将来所提 供的Flash器件的互换性的工业行业广大成果之一。CFI使得用户只需要一套驱动程序就可以识别并使用各种类型的Flash产品,因为器件的所有识别信息,诸如存储器大小、字节/字配置、块配置、必须的供电电压和时序信息等,都直接保存在芯片上。

vector=FIRST_EXTERNAL_VECTOR   //#defineFIRST_EXTERNAL_VECTOR        0x20  在irq_verctors.h中,定义了0~31号内部中断
.rept(NR_VECTORS-FIRST_EXTERNAL_VECTOR+6)/7             //.rept表示循环,#define NR_VECTORS            256,为256-32+6=230;230/7=32
    .balign32                                      //按32字节对齐

NOTE:
.balign[wl] abs-expr, abs-expr, abs-expr

加位置计数器(在当前子段)使它指向规定的存储边界。第一个表达式参数(结果必须是纯粹的数字)是必需参数:边界基准,单位为字节。例
如,'.balign
8'向后移动位置计数器直至计数器的值等于8的倍数。如果位置计数器已经是8的倍数,则无需移动。第2个表达式参数(结果必须是纯粹的数字)给出填充字节
的值,用这个值填充位置计数器越过的地方。第2个参数(和逗点)可以省略。如果省略它,填充字节的值通常是0。但在某些系统上,如果本段标识为包含代码,
而填充值被省略,则使用no-op指令填充空白区。第3个参数的结果也必须是纯粹的数字,这个参数是可选的。如果存在第3个参数,它代表本对齐命令允许跳
过字节数的最大值。如果完成这个对齐需要跳过的字节数比规定的最大值还多,则根本无法完成对齐。您可以在边界基准参数后简单地使用两个逗号,以省略填充值
参数(第二参数);如果您在想在适当的时候,对齐操作自动使用no-op指令填充,本方法将非常奏效。
.balignw
和.balignl是.balign命令的变化形式。.balignw使用2个字节来填充空白区。.balignl使用4字节来填充。例
如,.balignw
4,0x368d将地址对齐到4的倍数,如果它跳过2个字节,GAS将使用0x368d填充这2个字节(字节的确切存放位置视处理器的存储方式而定)。
如果它跳过1或3个字节,则填充值不明确。

.rept   7                                              //加上前面的那个rept,则需要循环32*7=224次,这有点类似于两个for循环,在每次进行内循环时都要进行32字节的对齐操作

.if vector <NR_VECTORS              //vector=0x20;NR_VECCTORS=256;        
      .if vector <> FIRST_EXTERNAL_VECTOR
    CFI_ADJUST_CFA_OFFSET -4     //#defineCFI_ADJUST_CFA_OFFSET .cfi_adjust_cfa_offset //xx offset 修改计算CFA的规则,修改前面一个offset。达到按4字节对齐
      .endif
1:    pushl $(~vector+0x80)    /* Note: always insigned byte range */   ????
    CFI_ADJUST_CFA_OFFSET 4     //4字节对齐
      .if ((vector-FIRST_EXTERNAL_VECTOR)%7) <>6    //当vector=41,48 等等时,if为假,则不jmp到标号2执行,而这样的情况总共有32次:我不知道为什么??
    jmp2f                  //数字定义的标号为临时标号,可以任意重复定义,例如:"2f"代表正向第一次出现的标号"2:",3b代表反向第一次出现的标号"3:"
      .endif
      .previous     //.previous使汇编器返回到该自定义段之前的段进行汇编,则回到上面的数据段
    .long 1b     //在数据段中执行标号1的操作
     .text          //回到代码段
vector=vector+1      //vector增加1
    .endif
  .endr      
2:    jmp common_interrupt
.endr   //结束224次循环
END(irq_entries_start)  //结束代码段

.previous  //返回数据段,结束数据段的interrupt
END(interrupt)
.previous  //返回定义数据段之前定义的那个段

common_interrupt:
    addl $-0x80,(%esp)    /* Adjust vector intothe [-256,-1] range */
   SAVE_ALL           ////保存系统寄存器信息
    TRACE_IRQS_OFF      //在irqflags.h # define TRACE_IRQS_OFF                          /
                                   jal    trace_hardirqs_off
    movl %esp,%eax
    call do_IRQ
    jmp ret_from_intr     //返回

附:

.p2align指定下一行代码的对齐方式,第1参数表示按2的多少次幂字节对齐,第2参数表示对齐是跨越的位置用什么数据来填充,第3字节表示最多允许跨越多少字节。

previous表示恢复到当前.section定义之前的那个段作为当前段

最新文章

  1. js实现多张图片每隔一秒换一张图片
  2. [Matlab] tic toc
  3. .NET 文件相关的所有操作
  4. PHP博客小项目之知识点(1)
  5. JavaScript DOM编程艺术-学习笔记
  6. tablespace
  7. 什么是TNB?如何买TNB?
  8. 正负样本比率失衡SMOTE
  9. MySQL中四种常用存储引擎的介绍
  10. 【20190405】JavaScript-整理一些常用正则式
  11. Prometheus Operator - 每天5分钟玩转 Docker 容器技术(177)
  12. sql语句性能优化
  13. 说说GIL
  14. mongo 删除内嵌数组元素
  15. win10屏幕变灰怎么解决?
  16. Factor Graph因子图
  17. access导入报错 请求筛选模块被配置为拒绝超过请求内容长度的请求
  18. 正则和xpath在网页中匹配字段的效率比较
  19. C语言 一些算法
  20. 路由跟踪工具0trace

热门文章

  1. Python之文件路径名的操作
  2. Java加密与解密的艺术 读书心得
  3. 解决chrome浏览器安装不上的问题
  4. 2019-8-31-C#-条件编译
  5. 微信小程序(6)--获取屏幕宽度及弹窗滚动与页面滚动冲突
  6. MySQL--15 MHA简介
  7. C Primer Plus 学习 第四章
  8. procixx地址
  9. python之chardet用来检测字符串编码的
  10. yml文件 参数中的逗号 &#39;,&#39;