微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > ARM+Linux中断系统详细分析

ARM+Linux中断系统详细分析

时间:11-09 来源:互联网 点击:
ULK第四章里明确讲到“Linux实现了一种没有优先级的中断模型”,并且“Linux中断和异常都支持嵌套”。这个我不太理解了,这两种说法都与我以前的理解刚好相反,核对了原书,翻译没有错。

Linux中断系统到底是否支持优先级,可否嵌套,中断号又是怎么来确定的,中断产生时又是如何一步步执行到中断处理函数的。为了彻底搞懂Linux中断系统,我决定从最原始材料出发,一探究竟。(s3c2440+linux2.6.21)

先来看看ARM的硬件执行流程

异常是ARM处理器模式分类,ARM有七种运行模式USR,SYS,SVC,IRQ,FIQ,UND,ABT

五种异常模式:SVC,IRQ,FIQ,UND,ABT

中断模式是ARM异常模式之一(IRQ模式,FIQ模式),是一种异步事件,如外部按键产生中断,内部定时器产生中断,通信数据口数据收发产生中断等。

1.当一个异常产生时,以FIQ为例,CPU切入FIQ模式时,

①将原来执行程序的下一条指令地址保存到LR中,就是将R14保存到R14_fiq里面。

②拷贝CPSR到SPSR_fiq。

③改变CPSR模式位的值,改到FIQ模式。

④改变PC值,将其指向相应的异常处理向量表。

离开异常处理的时候,

①将LR(R14_fiq)赋给PC。

②将SPSR(SPSR_fiq)拷贝到CPSR。

③清除中断禁止标志(如果开始时置位了)。

ARM一般在某个固定地址中有一个异常向量表,比如0x0

当一个外部IRQ中断产生时

①处理器切换到IRQ模式

②PC跳到0x18处运行,因为这是IRQ的中断入口。

③通过0x18:LDR PC, IRQ_ADDR,跳转到相应的中断服务程序。这个中断服务程序就要确定中断源,每个中断源会有自己独立的中断服务程序。

④得到中断源,然后执行相应中断服务程序

⑤清除中断标志,返回

这就是一个外部中断完整的执行流程了,下面以具体寄存器来更具体的了解ARM的中断机制。

假设ARM核有两个中断引脚,一根是irq pin,一根是fiq pin,正常情况下,ARM核只是机械地随着PC指示去执行,当CPSR中的I位和F位都为1时,IRQ和FIQ都处于禁止状态,这时候无论发什么信号,ARM都不会理睬。

当I位或F位为0时,irq pin有中断信号过来时,ARM当前工作就会被打断,切换到IRQ模式,并且跳转到异常向量表的中断入口0x18,SRCPND中相应位置1,经过检查中断优先级寄存器以及屏蔽寄存器,确定中断源,INTPND相应位置1(经过仲裁,只有一位置1),这过程由ARM自动完成。0x18存放的是总的中断处理函数,在这个函数里,可以建立一个二级中断向量表,先清除SRCPND相应位,然后根据中断源执行相应中断服务程序,清除INTPND,返回。

及时清除中断Pending寄存器的标志位是为了避免两个问题:①发生中断返回后,立即又被中断,不断的重复响应②丢失中断处理过程中发生的中断,返回后不响应。

在某个IRQ中断程序执行过程中,有另外一个外部IRQ中断产生,会将SRCPND相应位置1,等该中断服务执行完,经过仲裁决定下一个要响应的中断。但是假如当产生的是FIQ,则保存当前IRQ的现场,嵌套响应FIQ,FIQ服务程序执行完,再继续执行IRQ服务。那么当一个FIQ正在服务,产生另外一个FIQ,会怎样呢,答案是不会被打断,跟IRQ一样等当前中断服务完成,再仲裁剩余需要相应的中断。

所以得出这样的结论:

①关于中断嵌套:IRQ模式只能被FIQ模式打断,FIQ模式下谁也打不断。

②关于优先级:ARM核对中断优先级,有明确的可编程管理。

下面再来看看Linux对ARM是怎么处理的,记住一个前提:Linux对ARM的硬件特性可以取舍,但不可更改。

1.建立异常向量表:

系统从arch/arm/kernel/head.S的ENTRY(stext)开始执行,__lookup_processor_type检查处理器ID,__lookup_machine_type检查机器ID,__create_page_tables创建页表,启动MMU,然后由arch/arm/kernel/head_common.S跳到start_kernel()->trap_init()

点击(此处)折叠或打开

  1. void __init trap_init(void)
  2. {
  3. unsigned long vectors=CONFIG_VECTORS_BASE;
  4. memcpy((void*)vectors,__vectors_start,__vectors_end-__vectors_start);
  5. memcpy((void*)vectors+0x200,__stubs_start,__stubs_end-__stubs_start);
  6. memcpy((void*)vectors+0x1000-kuser_sz,__kuser_helper_start,kuser_sz);
  7. }
  8. #define CONFIG_VECTORS_BASE 0xffff0000

CONFIG_VECTORS_BASE在autoconf.h定义,在ARMV4及V4T以后的大部分处理器中,中断向量表的位置可以有两个位置:一个是0,另一个是0xffff0000。可以通过CP15协处理器c1寄存器中V位(bit[13])控制。V和中断向量表的对应关系如下:
V=0~0x00000000~0x0000001C
V=1~0xffff0000~0xffff001C

__vectors_end至__vectors_start之间为异常向量表,

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top