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

ARM Linux中断机制之中断处理

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

宏vector_stub代表的程序段如下:name, mode, correction存储传入的参数之

.macrovector_stub, name, mode, correction=0
.align5

vector_\name:
.if \correction
sublr, lr, #\correction//修正返回地址,也就是中断处理完之后要执行的指令的地址
.endif

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

///保存返回地址到堆栈,因为很快要使用r0寄存器,所以也要保存r0。sp后没有!所以sp指向的位置并没有变化。

stmiasp, {r0, lr}@ save r0, lr

mrslr, spsr
strlr, [sp, #8]@ save spsr

// 向上增长的栈。

// 此时的这个栈是中断模式下的栈,ARM下中断模式下和系统模式下的

// 栈是不同的。虽然ARM提供了七个模式,但Linux只使用了两个,一

// 个是用户模式,另一个为系统模式,所以这个栈只是一个临时性的栈。

/*

在arch/arm/include/asm/ptrace.h中有处理器的七种工作模式的定义

#define USR_MODE0x00000010
#define FIQ_MODE0x00000011
#define IRQ_MODE0x00000012
#define SVC_MODE0x00000013
#define ABT_MODE0x00000017
#define UND_MODE0x0000001b
#define SYSTEM_MODE0x0000001f

*/
mrsr0, cpsr
eorr0, r0, #(\mode ^ SVC_MODE)
msrspsr_cxsf, r0////把spsr设置为管理模式。//对spsr的所有控制为进行写操作,将r0的值全部注入spsr

@
@ the branch table must immediately follow this code
@
//andlr, lr, #0x0f// 这条指令之后lr中位spsr的低4位,上面跳转表有16项就是对应这16个状态
//movr0, sp//用r0保存堆栈指针的地址

//在对这段程序分析时要记住这段程序是以宏vector_stub的形式放在跳转表前面的。

//将跳转表中对应的地址条目存入lr。因为跳转表中每一个条目都是4个字节long,所以此处左移两位
ldrlr, [pc, lr, lsl #2]

movspc, lr@ branch to handler in SVC mode//程序跳转。
ENDPROC(vector_\name)
.endm

在此我们以在用户空间发生中断异常为例,即程序跳转到__irq_usr处。

.align5
__irq_usr:
usr_entry//usr_entry是一个宏代表一段程序插入此处,宏usr_entry所代表的程序段将在下面分析(1)

kuser_cmpxchg_check

#ifdef CONFIG_TRACE_IRQFLAGS
bltrace_hardirqs_off
#endif

//接着看get_thread_info, 它也是个宏,用来获取当前线程的地址。也将在后续分析。tsk存放的是线程结构体的地址。

/*

线程结构体原型如下在文件include/linux/sched.h中

struct thread_info {
struct task_struct*task;/* main task structure */
unsigned longflags;
struct exec_domain*exec_domain;/* execution domain */
intpreempt_count;/* 0 => preemptable, <0 => BUG */
__u32 cpu; /* should always be 0 on m68k */
struct restart_block restart_block;
};

*/
get_thread_info tsk(2)
#ifdef CONFIG_PREEMPT

//TI_PREEMPT在文件arch\arm\kernel\asm-offsets.c中定义是线程结构体thread_info 的成员preempt_count在

//结构体thread_info中的偏移

/*

内核态可剥夺内核,只有在 preempt_count 为 0 时, schedule() 才会被调用,其检查
是否需要进行进程切换,需要的话就切换。

*/
ldrr8, [tsk, #TI_PREEMPT]//获取preempt_count
addr7, r8, #1@ increment it//将该成员加一
strr7, [tsk, #TI_PREEMPT]//间改变后的值存入preempt_count
#endif

irq_handler//调用中断操作函数,irq_handler是一个宏,在后续描述(3)
#ifdef CONFIG_PREEMPT
ldrr0, [tsk, #TI_PREEMPT]
strr8, [tsk, #TI_PREEMPT]
teqr0, r7
strner0, [r0, -r0]
#endif
#ifdef CONFIG_TRACE_IRQFLAGS
bltrace_hardirqs_on
#endif

movwhy, #0//why在文件arch/arm/kernel/entry-header.S中定义为r8。:why.reqr8
bret_to_user//返回到用户态,该宏在文件 linux/arch/arm/kernel/entry-common.S中定义。(4)
UNWIND(.fnend)
ENDPROC(__irq_usr)

下面分别对上面四处宏进行分析。(usr_entry,get_thread_info tsk,irq_handler,ret_to_user)

(1)

.macrousr_entry
UNWIND(.fnstart)
UNWIND(.cantunwind)@ dont unwind the user space

//S_FRAME_SIZE在文件arch\arm\kernel\asm-offsets.c中定义表示 寄存器结构体pt_regs的大小结构体

//pt_regs中有 r0~cpsr 18个寄存器即72个字节。
subsp, sp, #S_FRAME_SIZE//为寄存器pt_regs结构体建立堆栈空间,让堆栈指针sp 指向r0 。

//stmib为存储前加,所以此处留出了用于存储r0的空间,将r1 - r12存入堆栈。sp后没加!

//所以sp指向的堆栈位置没有变,一直指向用于存储r0的存储空间。

stmibsp, {r1 - r12}

//将中断前r0,lr,spsr的值取出存放在r1 - r3中,此时的r

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

网站地图

Top