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定义之前的那个段作为当前段

Linux.中断处理.入口x86平台entry_32.S的更多相关文章

  1. linux内核移植X86平台的例子

    bootloader支持启动多个Linux 内核安装(X86平台) 1. cparch/x86/boot/bzImage /boot/vmlinuz-$version 2. cp $initrd /b ...

  2. Linux 定制X86平台操作系统

    /********************************************************************************* * Linux 定制X86平台操作 ...

  3. X86平台下嵌入式linux触摸屏解决方案(usb触摸屏控制器+完美校准方案+触摸屏QTE开发环境搭建)

    一直在用X86平台,真心不想用WINCE和XPE,一些大的硬件供应商都不提供linux平台下的技术支持,比如研华的3343PC104系列的板子... 开发的问题如下: 1 USB控制器目前只有台湾和竹 ...

  4. X86平台乱序执行简要分析(翻译为主)

    多处理器使用松散的内存模型可能会非常混乱,写操作可能会无序,读操作可能会返回不是我们想要的值,为了解决这些问题,我们需要使用内存栅栏(memory fences),或者说内存屏障(memory bar ...

  5. Linux中断处理体系结构分析

    Linux中断处理体系结构分析(一) 异常,就是可以打断CPU正常运行流程的一些事情,比如外部中断.未定义指令.试图修改只读的数据.执行swi指令(Software Interrupt Instruc ...

  6. [国嵌攻略][119][Linux中断处理程序设计]

    裸机中断: 1.中断统一入口. 2.注册中断处理程序. 3.根据中断源编号,调用中断处理程序. Linux中断 1.在entry-armv.S中的_irq_svc是中断统一入口. 2.获取产生中断源的 ...

  7. Linux系统下x86和ARM的区别有哪些?

    问题: 最近在用三星的一款i5处理器的Windows平板,和iPad,以及其他使用ARM处理器的手机相比,发热量大很多,甚至需要借助风扇来散热,耗电量也大了不少. 那么就很奇怪,在主频相差不大,并且实 ...

  8. Linux 中断处理

    HardIRQ 和 softirq : http://www.it165.net/os/html/201211/3766.html 博文:http://blog.csdn.net/yin262/art ...

  9. Qt在各平台上的搭建qt-everywhere(Qt for windows7-64bit, Ubuntu 12.04-32bit, 嵌入式x86平台, 嵌入式arm平台)

    下载地址:http://download.qt.io/ 当进入解压好的源码包后,使用./configure –help命令,可以获得相应帮助,前面是*号的表示默认参数. +号表示该功能要求被评估,评估 ...

随机推荐

  1. android 好的源码链接

    1.自定义表情键盘:https://github.com/w446108264/XhsEmoticonsKeyboard 2.底部导航栏https://github.com/Ashok-Varma/B ...

  2. ssh-add - 向认证代理添加 RSA 或 DSA 身份数据

    总览 (SYNOPSIS) ssh-add [-lLdDx ] [-t life ] [file ... ] ssh-add -s reader ssh-add -e reader 描述 (DESCR ...

  3. 系统调用的API以及汇编代码实现

    作者:严哲璟 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 系统调用过程为 ...

  4. Gradle构建SpringBoot并打包可运行的jar配置

    使用Gradle构建项目,继承了Ant的灵活和Maven的生命周期管理,不再使用XML作为配置文件格式,采用了DSL格式,使得脚本更加简洁. 构建环境: jdk1.6以上,此处使用1.8 Gradle ...

  5. CSS Reset(样式重置)

    CSS Reset,意为重置默认样式.HTML中绝大部分标签元素在网页显示中都有一个默认属性值,通常为了避免重复定义元素样式,需要进行重置默认样式(CSS Reset).举几个例子:1.淘宝(CSS ...

  6. centos7系统中忘记了root管理员账号密码的解决方式(转)

    随着计算机的使用越来越普遍,现在的用户都会有多个密码,不是这软件的密码就是那个的,QQ.邮箱.游戏,还有系统的登录密码!每一个密码都不一样!所以越来越多的密码需要去记住!也因为这样,只要其中一个长时间 ...

  7. Jenkins ant打包部署

    选择项目 自由风格

  8. Flutter-ListView

    return Container( child: ListView( children: <Widget>[ Column( children: <Widget>[ Conta ...

  9. bzoj4489 [Jsoi2015]地铁线路 最短路

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4489 题解 感觉又被骗了.看这道题的 AC 人数不多,以为是一道很好的题目.结果发现是一个非常 ...

  10. [BZOJ4826] [HNOI2017] 影魔 单调栈 主席树

    题面 因为是一个排列,所以不会有重复的.如果有重复就没法做了.一开始没有仔细看题目想了半天. 发现,如果是第一种情况,那么边界\(l\)和\(r\)就应该分别是整个区间的最大值和次大值. 然后,对于那 ...