韦东山uboot_内核_根文件系统学习笔记5.6-第005课_字符设备驱动_第006节_字符设备驱动程序之中断方式的按键驱动_Linux异常处理结构

一 Linux 异常处理体系结构/框架

通用异常处理机制
在这里插入图片描述

二 linux内核对于异常的设置(P397)

对于下面分析的小结:
(1)异常向量起始地址__vector_start的代码拷贝到vectors地址去
(2)一旦出现中断就会跳转到vector_irq开始的代码;该代码用宏的形式实现的
(3)宏:计算返回地址->保存现场->调用中断处理的c函数->恢复现场

  1. trap_init函数分析
    在这里插入图片描述
    在这里插入图片描述
    代码如下:
    在这里插入图片描述
    其中:其中:
    vectors=0xffff0000
    __vectors_start=异常代码存储地址,这段代码都是跳转指令,
    例如
    LINE1064:出现未定义的指令
    LINE1069:中断跳转指令
    在这里插入图片描述
  2. 追踪vector_und变量
    继续追踪上图vector_und变量,我们搜遍代码也找不到…实际上该变量是一个宏定义。(详细说明参见:Linux异常体系之vector_stub宏解析
    下图代码是对于宏vector_stub的引用:
    在这里插入图片描述
    下图是代码中对于宏vector_stub的定义:
    在这里插入图片描述
    在这里插入图片描述
  3. 追踪vector_irq变量
    下面代码是对于宏vector_stub的引用
    在这里插入图片描述
    按照宏定义展开可以得到如下实际代码:
/*
 * Interrupt dispatcher
 */
	/*
		vector_stub	irq, IRQ_MODE, 4
	*/
		/*
		.	macro	vector_stub, name, mode, correction=0
			参数赋值:
			name=irq
			mode=IRQ_MODE
			correction=4
		*/
	.align	5

vector_irq:
	@计算返回地址,与单片机程序一致
	sub	lr, lr, #4

	@
	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
	@ (parent CPSR)
	@
	stmia	sp, {r0, lr}		@ save r0, lr
	mrs	lr, spsr
	str	lr, [sp, #8]		@ save spsr

	@
	@ Prepare for SVC32 mode.  IRQs remain disabled.
	@转换到管理模式
	mrs	r0, cpsr
	eor	r0, r0, #(\mode ^ SVC_MODE)
	msr	spsr_cxsf, r0

	@
	@ the branch table must immediately follow this code
	@向下面的列表跳转
	and	lr, lr, #0x0f
	mov	r0, sp
	ldr	lr, [pc, lr, lsl #2]
	movs	pc, lr			@ branch to handler in SVC mode

	.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
  1. 追踪__irq_usr对应的代码
__irq_usr:
	usr_entry

#ifdef CONFIG_TRACE_IRQFLAGS
	bl	trace_hardirqs_off
#endif
	get_thread_info tsk
#ifdef CONFIG_PREEMPT
	ldr	r8, [tsk, #TI_PREEMPT]		@ get preempt count
	add	r7, r8, #1			@ increment it
	str	r7, [tsk, #TI_PREEMPT]
#endif

	irq_handler
#ifdef CONFIG_PREEMPT
	ldr	r0, [tsk, #TI_PREEMPT]
	str	r8, [tsk, #TI_PREEMPT]
	teq	r0, r7
	strne	r0, [r0, -r0]
#endif
#ifdef CONFIG_TRACE_IRQFLAGS
	bl	trace_hardirqs_on
#endif

	mov	why, #0
	b	ret_to_user

	.ltorg

	.align	5

其中usr_entry也是宏,定义如下:

//功能:保存现场
	.macro	usr_entry
	sub	sp, sp, #S_FRAME_SIZE
	stmib	sp, {r1 - r12}

	ldmia	r0, {r1 - r3}
	add	r0, sp, #S_PC		@ here for interlock avoidance
	mov	r4, #-1			@  ""  ""     ""        ""

	str	r1, [sp]		@ save the "real" r0 copied
					@ from the exception stack

#if __LINUX_ARM_ARCH__ < 6 && !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
#ifndef CONFIG_MMU
#warning "NPTL on non MMU needs fixing"
#else
	@ make sure our user space atomic helper is aborted
	cmp	r2, #TASK_SIZE
	bichs	r3, r3, #PSR_Z_BIT
#endif
#endif

	@
	@ We are now ready to fill in the remaining blanks on the stack:
	@
	@  r2 - lr_<exception>, already fixed up for correct return/restart
	@  r3 - spsr_<exception>
	@  r4 - orig_r0 (see pt_regs definition in ptrace.h)
	@
	@ Also, separately save sp_usr and lr_usr
	@
	stmia	r0, {r2 - r4}
	stmdb	r0, {sp, lr}^

	@
	@ Enable the alignment trap while in kernel mode
	@
	alignment_trap r0

	@
	@ Clear FP to mark the first stack frame
	@
	zero_fp
	.endm

其中,irq_handler也是宏,定义如下

/*
 * Interrupt handling.  Preserves r7, r8, r9
 */
	.macro	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 *
	@最终调用了函数asm_do_IRQ
	adrne	lr, 1b
	bne	asm_do_IRQ
	...
	.endm

那么,追踪函数asm_do_IRQ即中断处理函数
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/xiaoaojianghu09/article/details/104254624
今日推荐