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

ARM Linux中断机制分析

时间:11-09 来源:互联网 点击:

个函数指针,它用来实现中断处理器的电流处理。电流处理分为边

//沿跳变处理和电平处理。

static inline void generic_handle_irq(unsigned int irq)//该函数是与体系结构无关的通用逻辑层API

{

generic_handle_irq_desc(irq, irq_to_desc(irq));

}

2.2.11 ret_to_user

以上内容处理结束后,退回用户层。

arch/arm/kernel/entry-common.S

/*

* "slow" syscall return path. "why" tells us if this was a real syscall.

*/

ENTRY(ret_to_user)

ret_slow_syscall:

disable_irq @ disable interrupts

ldr r1, [tsk, #TI_FLAGS]//从任务的TI_FLAGS标志判断是否需要处理抢占或者信号。

tst r1, #_TIF_WORK_MASK

bne work_pending//处理抢占或者信号

no_work_pending: //没有抢占或者信号需要处理,或者已经处理完毕,开始退回用户态

#if defined(CONFIG_IRQSOFF_TRACER)//退回用户态必然会打开中断,这里记录下打开中断的事实,供调试用。

asm_trace_hardirqs_on

#endif

/* perform architecture specific actions before user return */

arch_ret_to_user r1, lr//在返回用户态前,处理各个体系结构的钩子

restore_user_regs fast = 0, offset = 0//恢复寄存器现场,并切回用户态。这里不再具体分析恢复方式。

ENDPROC(ret_to_user)


3.问题及解答

问题1:vector_irq已经是异常、中断处理的入口函数了,为什么还要加stubs_offset?( b vector_irq + stubs_offset)

答:(1)内核刚启动时(head.S文件)通过设置CP15的c1寄存器已经确定了异常向量表的起始地址(例如0xffff0000),因此需要把已经写好的内核代码中的异常向量表考到0xffff0000处,只有这样在发生异常时内核才能正确的处理异常。

(2)从上面代码看出向量表和stubs(中断处理函数)都发生了搬移,如果还用bvector_irq,那么实际执行的时候就无法跳转到搬移后的vector_irq处,因为指令码里写的是原来的偏移量,所以需要把指令码中的偏移量写成搬移后的。至于为什么搬移后的地址是vector_irq+stubs_offset,如图一所示。下图是搬移示意图更加清晰说明了搬移过程。。

问题2:为什么在异常向量表中,用b指令跳转而不是用ldr绝对跳转?

答:因为使用b指令跳转比绝对跳转(ldr pc,XXXX)效率高,正因为效率高,所以把__stubs_start~__stubs_end之间的代码考到了0xffff0200起始处。

注意:

因为b跳转指令只能在+/-32MB之内跳转,所以必须拷贝到0xffff0000附近。

b指令是相对于当前PC的跳转,当汇编器看到 B 指令后会把要跳转的标签转化为相对于当前PC的偏移量写入指令码。

经过Uboot的启动,内核跳入linux/arch/arm/kernel/head.S开始执行。

问题1:为什么首先进入head.S开始执行?

问题3:为什么首先进入head.S开始执行?

答:内核源代码顶层目录下的Makefile制定了vmlinux生成规则:

# vmlinux image - includingupdated kernel symbols

vmlinux: $(vmlinux-lds)$(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o)FORCE

其中$(vmlinux-lds)是编译连接脚本,对于ARM平台,就是arch/arm/kernel/vmlinux-lds文件。vmlinux-init也在顶层Makefile中定义:

vmlinux-init := $(head-y)$(init-y)

head-y 在arch/arm/Makefile中定义:

head-y:=arch/arm/kernel/head$(MMUEX T).o arch/arm/kernel/init_task.o

ifeq ($(CONFIG_MMU),)

MMUEXT := -nommu

endif

对于有MMU的处理器,MMUEXT为空白字符串,所以arch/arm/kernel/head.O 是第一个连接的文件,而这个文件是由arch/arm/kernel/head.S编译产生成的。

综合以上分析,可以得出结论,非压缩ARM Linux内核的入口点在arch/arm/kernel/head.s中。

问题4: 中断为什么必须进入svc模式?

一个最重要原因是:

如果一个中断模式(例如从usr进入irq模式,在irq模式中)中重新允许了中断,并且在这个中断例程中使用了BL指令调用子程序,BL指令会自动将子程序返回地址保存到当前模式的lr(即r14_irq)中,这个地址随后会被在当前模式下产生的中断所破坏,因为产生中断时CPU会将当前模式的PC保存到r14_irq,这样就把刚刚保存的子程序返回地址冲掉。为了避免这种情况,中断例程应该切换到SVC或者系统模式,这样的话,BL指令可以使用r14_svc来保存子程序的返回地址。

问题5:为什么跳转表中有的用了b指令跳转,而有的用了ldr px,xxxx?

W(b) vector_und+ stubs_offset

W(ldr) pc, .LCvswi + stubs_offset

W(b) vector_pabt+ stubs_offset

W(b) vector_dabt+ stubs_offset

W(b) vector_addrexcptn+ stubs_offset

W(b) v

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

网站地图

Top