linux中的中断,linux 中断(一)

对于arm的设备,有七个异常中断向量+一个保留向量一共8个。

是按照顺序排列的。每个向量地址对应一个字大小的空间用于跳转到特定的处理函数。

1 复位向量                       0X00000000/0XFFFF0000

2 未定义指令终止向量   0X00000004/0XFFFF0004

3SWI向量                         0X00000008/0XFFFF0008

4预取指令终止向量        0X0000000c/0XFFFF000c

5数据访问终止向量        0X00000010/0XFFFF0010

6保留                                0X00000014/0XFFFF0014

7外部中断向量                0X00000018/0XFFFF0018

8快速中断向量                0X0000001c/0XFFFF001c

地址一般是固定的

从0X00000000-0x0000001c或者 0XFFFF0000-0XFFFF001C。通过CP15协处理器的寄存器的某个寄存器可以控制。

当然也有可以自定义的。比如树莓派的BCM2835芯片armv7就可以使用CP2来自定义异常中断向量的地址。

当CPU遇到特定的异常的时候就会跳转到对应的地址上,执行指令,比如当前CPU执行的指令是一个未定义的指令,CPU出现异常。就会跳到未定义指令终止向量(0x00000004/0xffff0004)去执行这里的指令。访问数据出现错误的时候就会跳转到5数据访问终止向量 (0X00000010/0XFFFF0010)这里执行。

外部中断就会跳转到 (外部中断向量  0X00000018/0XFFFF0018)。比如插入了一个USB设备,网卡接收到了数据,就会跳转到这里来执行。

7 外部中断向量IRQ 和快速中断向量FIQ的区别是。FIQ一般用于处理耗时比较短的一些中断,因为FIQ有R8-R14寄存器,比IRQ的R13和R14寄存器要多一些,IRQ例程里面可能要先保护R8-R12,执行完中断函数后再恢复,FIQ就不需要,中断如何区分是插入了USB设备还是网卡接收到了数据呢?这就要通过中断号来区分了。后续再看。

这里先看这几个例程的定义。

arm\kernel\entry-armv.S里面定义了这几个向量 。

__vectors_start:

W(b)vector_rst

W(b)vector_und

W(ldr)pc, __vectors_start + 0x1000

W(b)vector_pabt

W(b)vector_dabt

W(b)vector_addrexcptn

W(b)vector_irq

W(b)vector_fiq

b表示跳转到xxx。

比如W(b)vector_irq

vector_irq的定义是

vector_stubirq, IRQ_MODE, 4

vector_stub是一个宏,可以展开。

在进入这些模式之前,会执行一系列的操作,并且这些操作不可以被打断,可以参看page44-46。

进入irq模式之前

1将处理器设置成ARM状态和外部中断模式

2把中断后将要执行的第二条指令(参看ARM流水线)的地址放到中断模式下的R14(lr)寄存器中。将CPSR放到外部中断模式的SPSR寄存器中

3禁止外部设备中断

4设置R15位外部中断向量。也就是PC=vector_irq 跳转到这里执行

看一下vector_irq函数执行的操作。展开vector_stubirq, IRQ_MODE, 4以后。

.macrovector_stub, name, mode, correction=0

.align5

vector_\name:

.if \correction

sublr, lr, #\correction correction=4 因为执行当前指令发生中断的时候,PC已经指向了后续第2条指令(参看ARM指令流水线),所以这里lr=lr-4,处理完毕以后。回到当前中断的下一条指令执行,注意这里的LR已经是IRQ模式下的LR寄存器了。

.endif

@

@ Save r0, lr_(parent PC) and spsr_@ (parent CPSR)

@

stmiasp, {r0, lr}@ save r0, lr 保存R0和R14到堆栈(IRQ模式的堆栈)中。保存被中断的下一条指令lr,r0和lr都用于后续的临时操作r0也要保存。

mrslr, spsr 将SPSR放到LR中

strlr, [sp, #8]@ save spsr 将SPSR放到SP+8的地址里面 地址从低到高分别是R0 LR SPSR(中断前的CPSR)

@

@ Prepare for SVC32 mode. IRQs remain disabled. 准备从中断模式切换到管理模式(切换过去以后,SP和LR不一样了)

@

mrsr0, cpsr

eorr0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)

msrspsr_cxsf, r0 切换CPSR进入SVC模式

@

@ the branch table must immediately follow this code

@

andlr, lr, #0x0f lr=IRQ模式spsr=中断前的CPSR。这里是获取中断之前的模式.取得cpsr的后四位。

movr0, sp 让R0指向IRQ中断模式的堆栈指针

ldrlr, [pc, lr, lsl #2]根据之前的模式取得将要跳转的地址。

movspc, lr@ branch to handler in SVC mode

ENDPROC(vector_\name)

首先堆栈如下

spsr (中断前的cpsr)

lr

r0

执行 ldr lr,[pc,lr,lsl#2]时。PC等于 movs pc,lr下面一条指令。也就是此时的PC指向.long __irq_usr

vector_stubirq, IRQ_MODE, 4

.long__irq_usr@ 0 (USR_26 / USR_32)

.long__irq_invalid@ 1 (FIQ_26 / FIQ_32)

.long__irq_invalid@ 2 (IRQ_26 / IRQ_32)

.long__irq_svc@ 3 (SVC_26 / SVC_32)

.long__irq_invalid@ 4

.long__irq_invalid@ 5

.long__irq_invalid@ 6

.long__irq_invalid@ 7

.long__irq_invalid@ 8

.long__irq_invalid@ 9

.long__irq_invalid@ a

.long__irq_invalid@ b

.long__irq_invalid@ c

.long__irq_invalid@ d

.long__irq_invalid@ e

.long__irq_invalid@ f

此时的lr是cpsr的后四位 ,0-0xf 跳转到下面的@对应的位置上

ldr lr,[pc,lr,lsl#2] 这句意思是 先把 lr右移两位(也就是乘4,移动一个long的长度)再把PC+lr里面的值赋值给lr。

也就是根据之前的模式跳转到特定的函数位置。如果之前是usr模式0。那么跳转到__irq_usr。如果是3 跳转到__irq_svc。

假设之前是usr模式。那么就跳转到__irq_usr执行

__irq_usr:

usr_entry

kuser_cmpxchg_check

irq_handler

get_thread_info tsk

movwhy, #0

bret_to_user_from_irq

UNWIND(.fnend)

ENDPROC(__irq_usr)

user_entry是一个宏。主要是保护寄存器

.macrousr_entry, trace=1

subsp, sp, #S_FRAME_SIZE 预留一部分栈空间 (我这里大小是0X48)

ARM(stmibsp, {r1 - r12}) 保护用户空间的R1-R12寄存器

ATRAP(mrcp15, 0, r7, c1, c0, 0)

ATRAP(ldrr8, .LCcralign)

ldmiar0, {r3 - r5}

addr0, sp, #S_PC@ here for interlock avoidance

movr6, #-1@ "" "" "" ""

strr3, [sp]@ save the "real" r0 copied

@ from the exception stack

ATRAP(ldrr8, [r8, #0])

@

@ We are now ready to fill in the remaining blanks on the stack:

@

@ r4 - lr_, already fixed up for correct return/restart

@ r5 - spsr_@ r6 - orig_r0 (see pt_regs definition in ptrace.h)

@

@ Also, separately save sp_usr and lr_usr

@

stmiar0, {r4 - r6}

ARM(stmdbr0, {sp, lr}^)

THUMB(store_user_sp_lr r0, r1, S_SP - S_PC)

@ Enable the alignment trap while in kernel mode

ATRAP(teqr8, r7)

ATRAP( mcrnep15, 0, r8, c1, c0, 0)

@

@ Clear FP to mark the first stack frame

@

zero_fp

.if\trace

#ifdef CONFIG_IRQSOFF_TRACER

bltrace_hardirqs_off

#endif

ct_user_exit save = 0

.endif

.endm

目前由于对arm中断了解得不多。汇编部分 主要参看。。。。到时候具体处理再来看

http://blog.csdn.net/xiaojsj111/article/details/14129661

__irq_usr:

usr_entry

kuser_cmpxchg_check

irq_handler

get_thread_info tsk

movwhy, #0

bret_to_user_from_irq

UNWIND(.fnend)

ENDPROC(__irq_usr)

这里可以简单理解为 保存之前模式的寄存器。执行irq_handler函数。恢复寄存器,跳转到原来的指令的下一条来执行。

后续把重点放在irq_handler里面

.macroirq_handler

#ifdef CONFIG_MULTI_IRQ_HANDLER

ldrr1, =handle_arch_irq

movr0, sp

adrlr, BSYM(9997f)

ldrpc, [r1]

#else

arch_irq_handler_default

#endif

9997:

.endm

对于多个irq_handler。跳转到handle_arch_irq执行。对于单个handler就是arch_irq_handler_default

一下根据树莓派来确定执行流程。

我的树莓派是单个处理irq。因此跳转到arch_irq_handler_default执行

arch_irq_handler_default定义在arch\arm\include\asm\entry-macro-multi.S的line7

.macroarch_irq_handler_default

get_irqnr_preamble r6, lr

1:get_irqnr_and_base r0, r2, r6, lr

movner1, sp

@

@ routine called with r0 = irq number, r1 = struct pt_regs *

@

adrnelr, BSYM(1b)

bneasm_do_IRQ

#ifdef CONFIG_SMP

/*

* XXX

*

* this macro assumes that irqstat (r2) and base (r6) are

* preserved from get_irqnr_and_base above

*/

ALT_SMP(test_for_ipi r0, r2, r6, lr)

ALT_UP_B(9997f)

movner1, sp

adrnelr, BSYM(1b)

bnedo_IPI

#endif

9997:

.endm上面的代码使用到的宏都定义在

arch\arm\mach-bcm2708\include\mach\entry-macro.S里面

.macro  get_irqnr_preamble, base, tmp

ldr\base, =IO_ADDRESS(ARMCTRL_IC_BASE)

.endm

get_irqnr_and_base得到了中断的号码等等信息。随后调用asm_do_IRQ,在编译链接的时候会连接成另外一个名字__irqentry_text_start

在arch\arm\kernel\irq.c里面

void handle_IRQ(unsigned int irq, struct pt_regs *regs)

{

__handle_domain_irq(NULL, irq, false, regs);

}

/*

* asm_do_IRQ is the interface to be used from assembly code.

*/

asmlinkage void __exception_irq_entry

asm_do_IRQ(unsigned int irq, struct pt_regs *regs)

{

handle_IRQ(irq, regs);

}asm_do_IRQ->handle_IRQ->__handle_domain_irq(arch\arm\kernel\irqdesc.c)执行

详细看一下 树莓派中

get_irqnr_preamble r6, lr

1:get_irqnr_and_base r0, r2, r6, lr

movner1, sp

@

@ routine called with r0 = irq number, r1 = struct pt_regs *

@

adrnelr, BSYM(1b)

bneasm_do_IRQ

展开以后的代码如下

.text:C05340E4 LDR R6, =0xF200B200 这里R6=0XF200B200的来源参看BCM2835手册。外设的物理地址是0X20000000,映射到虚拟地址后是F2000000(Page6.(page 112)7.5 Registers定义了bcm2835中断寄存器的基地址为0XB000。而IRQ BASIC PENDING的偏移是0X200,因此这里就是取得IRQbasic Pending寄存器的位置

.text:C05340E8

.text:C05340E8 loc_C05340E8 ; DATA XREF: __irq_usr+A0o

.text:C05340E8 LDR R2, [R6]

.text:C05340EC MOV R0, #0x5F ; '_'

.text:C05340F0 AND LR, R2, #0x300

.text:C05340F4 BICS R2, R2, #0x300

.text:C05340F8 BNE loc_C053412C

.text:C05340FC TST LR, #0x100

.text:C0534100 LDRNE R2, [R6,#4]

.text:C0534104 MOVNE R0, #0x1F

.text:C0534108 BICNE R2, R2, #0x680

.text:C053410C BICNE R2, R2, #0xC0000

.text:C0534110 BNE loc_C053412C

.text:C0534114 TST LR, #0x200

.text:C0534118 LDRNE R2, [R6,#8]

.text:C053411C MOVNE R0, #0x3F ; '?'

.text:C0534120 BICNE R2, R2, #0x3E00000

.text:C0534124 BICNE R2, R2, #0x40000000

.text:C0534128 BEQ loc_C053413C

.text:C053412C

.text:C053412C loc_C053412C ; CODE XREF: __irq_usr+58j

.text:C053412C ; __irq_usr+70j

.text:C053412C SUB LR, R2, #1

.text:C0534130 EOR R2, R2, LR

.text:C0534134 CLZ LR, R2

.text:C0534138 SUB R0, R0, LR

.text:C053413C

.text:C053413C loc_C053413C ; CODE XREF: __irq_usr+88j

.text:C053413C MOVNE R1, SP

.text:C0534140 ADRNE LR, loc_C05340E8

.text:C0534144 BNE __irqentry_text_start

具体的irq注册和会有第二篇

看到这里我明白了,当有外部设备发生中断的时候。比如USB插入。键盘按键。CPU接收到信号。进入中断向量中。获取中断的号码等信息。后续就是根据中断的号码执行对应的函数了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值