linux kenrel 基本组成部分——中断(一)

来源:互联网 发布:淘小白自动发货软件 编辑:程序博客网 时间:2024/05/23 00:06

硬件部分

    驱动工程师对中断这个词并不陌生,几乎每个器件都会产生中断,大家也都会用kernel 提供的API request_thread_irq(requst_irq)接口,多少会写一写softirq、tasklet、workqueue来完成处理,本文就扒一扒中断那些事。

    简单的硬件拓扑结构如图一所示,各个外设产生的中断电平信号都通过reqest irq line上的电平变化传递给CPU,但CPU并没有那么多中断服务引脚提供连接,于是就找中断控制器帮忙,各外设的中断引脚先连接到中断控制器上,统一由中断控制器来做中断优先级处理,这样排好队后再一一上报给CPU做处理。


                                                                                                                        (图一)

中断需要CPU支持,就要了解CPU关于中断这部分的结构:

(1)ARM体系结构

User&SystemFIQIRQSVCUndefAbtR0     R1     R2     R3     R4     R5     R6     R7     R8R8(FIQ)    R9R9(FIQ)    R10R10(FIQ)    R11R11(FIQ)    R12R12(FIQ)    R13(SP)R13(FIQ)R13(IRQ)R13(SVC)R13(Undef)R13(Abort)R14(LR)R14(FIQ)R14(IRQ)R14(SVC)R14(Undef)R14(Abort)R15(PC)     CPSR     SPSRSPSR(FIQ)SPSR(IRQ)SPSR(SVC)SPSR(Undef)SPSR(Abort)

在ARM 7种工作模式下共有37个寄存器

通用寄存器:一般R0 - R12用作通用寄存器( fiq 只有R0 - R7)在各个模式下共享这些 寄存器

特殊用途寄存器:

R13       用作堆栈寄存器 SP

R14       链接寄存器 LR 用于保存调用子程序的返回地址

R15       程序计数器 PC

CPSR      程序状态寄存器

SPSR      备份程序状态寄存器

通用程序状态寄存器cpsr

3130292827~87654~0NZCVreservedIFTMode

条件标志位     中断屏蔽位 thumb  处理器模式  

处理器模式:

用户模式  10000

系统模式  11111

管理模式  10011

中断请求  10010

    当处理器处于中断模式时,执行的指令仍然可以访问名字R13、R14 但实际上他们是分组寄存器R13_IRQ、R14_IRQ, 用户模式的R13、R14不会受到影响。


(2)ARM  处理器对异常中断的响应过程(硬件行为)

1 把CPSR保存到相应异常模式下的SPSR, cpsr -> spsr

2 把PC保存到相应异常模式下的LR

3 设置CPSR为相应的模式

4 设置PC为相应异常处理程序的入口地址(异常向量表)

产生IRQ中断如下图所示


                                          (图二)


注:进入异常ARM处理器在硬件上会自动工作,但要还原user/system 这两种模式则必须认为软件修改CPSR。


异常发生时ARM内核跳转到对应的中断向量表

异常低地址高地址RESET0x000000000xffff0000UNDEF0x000000040xffff0004SWI0x000000080xffff0008PABT0x0000000c0xffff000cDABT0x000000100xffff0010RESERVED0x000000140xffff0014IRQ0x000000180xffff0018FIQ0x0000001c0xffff001c

    ARMV4以及ARMV4以后的大部分处理器中,中断向量表的位置可以有两个,一个是0x00000000, 一个是0xffff0000, 可以通过CP15协处理器c1寄存器中V位(bit[13])控制, V和中断向量表的关系如下: 

V=00x00000000 ~ 0x0000001cV=10xffff0000 ~ 0xffff001c

Linux kernel 在arch/arm/mm/proc-v7.S文件中的__v7_setup函数中设置


(3)ARM处理器流水线

    使用流水线可以取下一条指令的同时译码和执行其他指令,从而加快执行速度。

三级流水

取址    fetch    从存储器装载一条指令

译码    decode   识别将被执行的指令 

执行    excute   处理指令并把结果写回寄存器


                                                        (图三)

    如图, 由于流水线的关系PC取址0x8008的地址上的指令时, CPU刚刚执行到0x8000地址里的指令,换句话说PC = execute_address + 8,ARM之后的CPU有5级流水6级流水但都兼容ARM7

 

注:如果执行分支指令或产生中断 PC发生跳转时,流水线会清空。ARM10使用分支预测技术来减少清空流水线的影响。

 

    由于流水线的关系,当一个异常发生时,链接寄存器就设置成基于当前PC值的一个特定地址,例如,当发生IRQ中断时,链接寄存器LR指向最后执行的指令地址加上8. 但异常返回时应该返回异常发生时要执行的指令的下一条地址,即lr - 4


基于链接寄存器的有用地址

异常地址用法复位--  复位没有定义LR数据终止LR - 8指向导致数据终止异常那条指令FIQLR - 4返回地址IRQLR - 4返回地址预取指终止LR - 4指向导致预取指令终止异常的那条指令SWIlr指向SWI指令的下一条指令未定义指令lr指向未定义指令的下一条指令


例:几种从IRQ异常处理程序返回的事例

 

1)hander:

xxx
    xxx
    SUBS pc, r14,#4

2) hander:
SUB r14, r14,#4
xxx
xxx
movs pc, r14


SWI可以产生一个软件中断,这为应用程序调用系统例程提供了一种机制

语法:

SWI {<cond>} SWI_number

SWI软中断

Lr_svc = SWI指令后面的指令地址

Spsr_svc = cpsr

Pc = vectors + 0x8

Cpsr模式 = SVC

Cpsr I = 1(屏蔽IRQ中断)


理解几个简单的指令:

单寄存器load-store指令

LDR r0 [r1] ; 将r1中存的地址中的数据写入寄存器r0中  读取数据

STR r0, [r1]; 把r0的值写入寄存器r1所指向的地址中     存储数据

LDMIA =r0!, {r1 - r3};将[r0] -> r1 [r0 + 4] -> r2 [r0 + 8] -> r3 如果有 !将r0更新

IA是执行后增长

STMIA  r10!, {r0-r7}; r0 ~ r7依次存储到[r10] 并更新r10指针


1 0
原创粉丝点击