linux中断

基于linux2.6.30.4, arm-s3c2440板

参考了韦东山老师的<第4.1节 字符设备驱动程序之中断方式的按键驱动_Linux异常处理结构>

中断向量表

  • 向量加载处理调用栈

decompressor code ->
    stext ->
        __switch_data ->
            __mmap_switched ->
                start_kernel ->
                    setup_arch ->
                        early_trap_init ->

  • early_tray_init中的处理节选
early_trap_init
    unsigned long vectors = CONFIG_VECTORS_BASE; //zImage制作时.config文件中定义CONFIG_VECTORS_BASE=0xffff0000,这个地址就是mmu启用时中断向量表的虚拟首地址
    memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start); //拷贝中断向量表
    memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start); //拷贝各种中断服务程序
  • 加载后的的情况
    +-----------------------------+-  <- __stubs_start`, +0x1000(4096)
    |                             |
    | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ |   <- __stubs_end`
    |   ...                       |
    |   func vector_dabt          |      stubs(exception services)
    |   func vector_irq           |
    +-----------------------------+-  <- __stubs_start`, +0x200(512)
    |                             |
    | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ |  <- __vectors_end`
    |   ...                       |
    |   b	vector_und`           |      vector table
    |   swi	SYS_ERROR0            |
    +-----------------------------+  <- __vectors_start`, 0xffff0000(va)

     

  • 来看一下__vectors_start
//entry-armv.S
	.equ	stubs_offset, __vectors_start + 0x200 - __stubs_start

	.globl	__vectors_start
__vectors_start:
	swi	SYS_ERROR0                   @on reset
	b	vector_und + stubs_offset    @on undine
	ldr	pc, .LCvswi + stubs_offset   @on swi
	b	vector_pabt + stubs_offset   @on prefetch abort
	b	vector_dabt + stubs_offset   @on data abort
	b	vector_addrexcptn + stubs_offset @reserved
	b	vector_irq + stubs_offset    @on irq
	b	vector_fiq + stubs_offset    @on fiq
	.globl	__vectors_end
__vectors_end:

exceptionEntry

 

 中断服务程序

  • 再来看__stubs_start~__stubs_end内容

   包含了如下几个函数,这正好是异常发生时,branch到的目标

vector_irq

vector_dabt

vector_pabt

vector_und

vector_fiq

vector_addrexcptn

LCvswi(应该说是一个函数的地址基地)

  • 异常服务程序的实现

这里选取vector_und来分析


	.align	5   @//对齐到2^5,即32b 4字
vector_und: @//为了说明方便,这里局部位置假设了进入本异常前的mode为user mode
	@// Save r0, lr_<exception> (parent PC) and spsr_<exception>
	@// (parent CPSR)
	stmia	sp, {r0, lr}		@// save r0, lr
        @//stmia      before                  after 
        @//           |         |             |                    | high addr
        @//           | ???     |             | ???                |
        @//           | ???     |             | lr                 | next addr in usr mode
        @// und_sp--->| ???     |   und_sp--->| r0                 | user mode 's r0
        @//           | ???     |             | ???                |
    
	mrs	lr, spsr            @//将user mode下的cpsr值赋于lr
	str	lr, [sp, #8]		@// save spsr  将lr保存到*(sp+8)  
        @//stmia      before                  after 
        @//           |         |             |                    | high addr
        @//           | ???     |             | spsr               | the cpsr in user mode
        @//           | lr      |             | lr                 | next addr in usr mode
        @// und_sp--->| r0      |   und_sp--->| r0                 | user mode 's r0
        @//           | ???     |             | ???                |

	@// Prepare for SVC32 mode.  IRQs remain disabled.
	mrs	r0, cpsr                    @//将undefine mode下的cpsr值保存到r0
	eor	r0, r0, #(\mode ^ SVC_MODE) @//r0 = r0 ^ (0b11011 ^ 10011),其实就是将低5位清0然后设置为SVC_MODE 0b10011
        @//这里包含了一个基本的算法知识,就是异或运算的结合律,即a ⊕ b ⊕ c = a ⊕ (b ⊕ c) = (a ⊕ b) ⊕ c
        @//r0 ^ 当前mode的cpsr.mode,也就是自身异或自身,当然就是清零了
        @//然后0异或上x,那么就相当于或运算(异或运算又称为不带进位的半加运算 0+0=0 0+1=1+0=1 1+1=0),也就是设置为SVC_MODE了
	msr	spsr_cxsf, r0 @//将仅修改了mode为SVC_MODE的cpsr写回,以强制进入SVC mode

	@// the branch table must immediately follow this code
	and	lr, lr, #0x0f        @//由手册可知mode是用一个5bit来表示的,而所有mode的bit4(第5位)又都是1,所以低4位就可以唯一标识一个mode
                             @//所以这里的与运算之后的lr就是进入本异常前的mode的标识
	mov	r0, sp     @//set r0=sp,对于即将的函数调用来说,也就是参数1为und_sp
	ldr	lr, [pc, lr, lsl #2] @//lr = *(pc + lr*4),这当中的玄机看[Table 2-1. PSR Mode Bit Values]的低4位就明白了吧
                             @//由于三级流水线机制,执行到本指令时,pc应该是指向了__und_usr数据的地址
                             @//由Table 2-1可以知道,未使用的4,5,6等的坑是预留的,并且不可能有routine进来
	movs	pc, lr			@// branch to handler in SVC mode
                            @//所进入本异常前的mode,进入子服务程序
ENDPROC(vector_und)

	.long	__und_usr			@//  0 (USR_26 / USR_32)
	.long	__und_invalid			@//  1 (FIQ_26 / FIQ_32)
	.long	__und_invalid			@//  2 (IRQ_26 / IRQ_32)
	.long	__und_svc			@//  3 (SVC_26 / SVC_32)
	.long	__und_invalid			@//  4
	.long	__und_invalid			@//  5
	.long	__und_invalid			@//  6
	.long	__und_invalid			@//  7
	.long	__und_invalid			@//  8
	.long	__und_invalid			@//  9
	.long	__und_invalid			@//  a
	.long	__und_invalid			@//  b
	.long	__und_invalid			@//  c
	.long	__und_invalid			@//  d
	.long	__und_invalid			@//  e
	.long	__und_invalid			@//  f

allExceptionMode

 

常用irq情况的进一步处理

由上面的分析可知,应该是进入子函数__irq_usr,做进一上的处理.

	.align	5  @align to 32bit
__irq_usr:
	usr_entry
	kuser_cmpxchg_check
	get_thread_info tsk
	ldr	r8, [tsk, #TI_PREEMPT]		@ get preempt count
	add	r7, r8, #1			@ increment it
	str	r7, [tsk, #TI_PREEMPT]

	irq_handler         @主处理
	mov	why, #0
	b	ret_to_user
 UNWIND(.fnend		)
ENDPROC(__irq_usr)
	.macro	irq_handler  @irq_handler是一个宏,并不是一个函数,编译时嵌入展开
	get_irqnr_preamble r5, lr
1:	get_irqnr_and_base r0, r6, r5, lr
	movne	r1, sp
	@ routine called with r0 = irq number, r1 = struct pt_regs *
	adrne	lr, 1b
	bne	asm_do_IRQ    @调用c子函数,有啥要处理的,在这里面去搞吧
	.endm

 

(完)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值