linux-2.6.26内核ARM中断实现过程详解(2)
更新时间:2024-01-23 14:31:02 阅读量: 教育文库 文档下载
linux-2.6.26
三、中断处理过程
内核中ARM中断实现详解(2)
华清远见 刘洪涛
这一节将以S3C2410为例,描述linux-2.6.26内核中,从中断开始,中断是如何一步一步执行到我们注册函数的。
3.1 中断向量表 arch\\arm\\kernel\\entry-armv.S __vectors_start: swi SYS_ERROR0
b vector_und + stubs_offset ldr pc, .LCvswi + stubs_offset b vector_pabt + stubs_offset b vector_dabt + stubs_offset
b vector_addrexcptn + stubs_offset b vector_irq + stubs_offset b vector_fiq + stubs_offset .globl __vectors_end __vectors_end:
中断发生后,跳转到b vector_irq + stubs_offset的位置执行。注意现在的向量表的初始位置是0xffff0000。
3.2 中断跳转的入口位置 arch\\arm\\kernel\\entry-armv.S .globl __stubs_start __stubs_start: /*
* Interrupt dispatcher */
vector_stub irq, IRQ_MODE, 4 @IRQ_MODE在include\\asm\\ptrace.h中定义:0x12 .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
1
.long __irq_invalid @ f 上面代码中vector_stub宏的定义为:
.macro vector_stub, name, mode, correction=0 .align 5 vector_\\name:
.if \\correction
sub lr, lr, #\\correction .endif @
@ Save r0, lr_
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 @为后面进入svc模式做准备
@
@ the branch table must immediately follow this code @
and lr, lr, #0x0f @进入中断前的mode的后4位 @#define USR_MODE 0x00000010
@#define FIQ_MODE 0x00000011 @#define IRQ_MODE 0x00000012 @#define SVC_MODE 0x00000013 @#define ABT_MODE 0x00000017 @#define UND_MODE 0x0000001b @#define SYSTEM_MODE 0x0000001f
mov r0, sp ldr lr, [pc, lr, lsl #2] @如果进入中断前是usr,则取出PC+4*0的内容,即__irq_usr @如果进入中断前是svc,则取出PC+4*3的内容,即__irq_svc movs pc, lr @ 当指令的目标寄存器是PC,且指令以S结束,则它会把 @ spsr的值恢复给cpsr branch to handler in SVC mode .endm
.globl __stubs_start __stubs_start: /*
* Interrupt dispatcher */
2
vector_stub irq, 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)
用“irq, IRQ_MODE, 4”代替宏vector_stub中的“name, mode, correction”,找到了我们中断处理的入口位置为vector_irq(宏里面的vector_\\name)。 从上面代码中的注释可以看出,根据进入中断前的工作模式不同,程序下一步将跳转到__irq_usr、或__irq_svc等位置。我们先选择__irq_usr作为下一步跟踪的目标。 3.3 __irq_usr的实现 arch\\arm\\kernel\\entry-armv.S __irq_usr:
usr_entry @后面有解释 kuser_cmpxchg_check
#ifdef CONFIG_TRACE_IRQFLAGS bl trace_hardirqs_off #endif
get_thread_info tsk @获取当前进程的进程描述符中的成员变量thread_info的地址,并将该地址保存到寄存器tsk等于r9(在entry-header.S中定义) #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 @中断处理,我们最关心的地方,3.4节有实现过程。 #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 @中断处理完成,返回中断产生的位置,3.7节有实现过程
上面代码中的usr_entry是一个宏,主要实现了将usr模式下的寄存器、中断返回地址保存到堆栈中。
.macro usr_entry
sub sp, sp, #S_FRAME_SIZE @ S_FRAME_SIZE的值在arch\\arm\\kernel\\asm-offsets.c
3
@ 中定义 DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs));实际上等于72
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 \ @ from the exception stack
@
@ We are now ready to fill in the remaining blanks on the stack: @
@ r2 - lr_
@ 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
上面的这段代码主要在填充结构体pt_regs ,这里提到的struct pt_regs,在include/asm/ptrace.h中定义。此时sp指向struct pt_regs。
struct pt_regs { long uregs[18]; }; #define ARM_cpsr uregs[16] #define ARM_pc uregs[15] #define ARM_lr uregs[14] #define ARM_sp uregs[13] #define ARM_ip uregs[12]
4
#define ARM_fp uregs[11] #define ARM_r10 uregs[10] #define ARM_r9 uregs[9] #define ARM_r8 uregs[8] #define ARM_r7 uregs[7] #define ARM_r6 uregs[6] #define ARM_r5 uregs[5] #define ARM_r4 uregs[4] #define ARM_r3 uregs[3] #define ARM_r2 uregs[2] #define ARM_r1 uregs[1] #define ARM_r0 uregs[0] #define ARM_ORIG_r0 uregs[17]
3.4 irq_handler的实现过程,arch\\arm\\kernel\\entry-armv.S .macro irq_handler
get_irqnr_preamble r5, lr
@在include/asm/arch-s3c2410/entry-macro.s中定义了宏get_irqnr_preamble为空操作,什么都不做
1: get_irqnr_and_base r0, r6, r5, lr @判断中断号,通过R0返回,3.5节有实现过程 movne r1, sp @
@ routine called with r0 = irq number, r1 = struct pt_regs * @
adrne lr, 1b
bne asm_do_IRQ @进入中断处理。 ??
.endm
3.5 get_irqnr_and_base中断号判断过程,include/asm/arch-s3c2410/entry-macro.s .macro get_irqnr_and_base, irqnr, irqstat, base, tmp mov \\base, #S3C24XX_VA_IRQ
@@ try the interrupt offset register, since it is there ldr \\irqstat, [ \\base, #INTPND ] teq \\irqstat, #0 beq 1002f
ldr \\irqnr, [ \\base, #INTOFFSET ] @通过判断INTOFFSET寄存器得到中断位置 mov \\tmp, #1
tst \\irqstat, \\tmp, lsl \\irqnr bne 1001f
@@ the number specified is not a valid irq, so try
5
@@ and work it out for ourselves mov \\irqnr, #0 @@ start here @@ work out which irq (if any) we got movs \\tmp, \\irqstat, lsl#16 addeq \\irqnr, \\irqnr, #16
moveq \\irqstat, \\irqstat, lsr#16 tst \\irqstat, #0xff
addeq \\irqnr, \\irqnr, #8
moveq \\irqstat, \\irqstat, lsr#8 tst \\irqstat, #0xf
addeq \\irqnr, \\irqnr, #4
moveq \\irqstat, \\irqstat, lsr#4 tst \\irqstat, #0x3
addeq \\irqnr, \\irqnr, #2
moveq \\irqstat, \\irqstat, lsr#2 tst \\irqstat, #0x1
addeq \\irqnr, \\irqnr, #1 @@ we have the value 1001:
adds \\irqnr, \\irqnr, #IRQ_EINT0 @加上中断号的基准数值,得到最终的中断号,注意:此时没有考虑子中断的具体情况,(子中断的问题后面会有讲解)。IRQ_EINT0在include/asm/arch-s3c2410/irqs.h中定义.从这里可以看出,中断号的具体值是有平台相关的代码决定的,和硬件中断挂起寄存器中的中断号是不等的。 1002:
@@ exit here, Z flag unset if IRQ .endm
3.6 asm_do_IRQ实现过程,arch/arm/kernel/irq.c
asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs) {
struct pt_regs *old_regs = set_irq_regs(regs);
struct irq_desc *desc = irq_desc + irq;//根据中断号找到对应的irq_desc /*
* Some hardware gives randomly wrong interrupts. Rather * than crashing, do something sensible. */
if (irq >= NR_IRQS)
desc = &bad_irq_desc;
irq_enter();//没做什么特别的工作,可以跳过不看
desc_handle_irq(irq, desc);// 根据中断号和desc进入中断处理 /* AT91 specific workaround */ irq_finish(irq); irq_exit();
set_irq_regs(old_regs);
6
}
static inline void desc_handle_irq(unsigned int irq, struct irq_desc *desc) {
desc->handle_irq(irq, desc);//中断处理 }
上述asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)使用了asmlinkage标识。那么这个标识的含义如何理解呢?
该符号定义在kernel/include/linux/linkage.h中,如下所示:
#include //各个具体处理器在此文件中定义asmlinkage #ifdef __cplusplus
#define CPP_ASMLINKAGE extern \#else
#define CPP_ASMLINKAGE #endif
#ifndef asmlinkage//如果以前没有定义asmlinkage #define asmlinkage CPP_ASMLINKAGE #endif
对于ARM处理器的,没有定义asmlinkage,所以没有意义(不要以为参数是从堆栈传递的,对于ARM平台来说还是符合ATPCS过程调用标准,通过寄存器传递的)。
但对于X86处理器的中是这样定义的:
#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0))) 表示函数的参数传递是通过堆栈完成的。
3.7 描述3.3节中的ret_to_user 中断返回过程,/arch/arm/kernel/entry-common.S ENTRY(ret_to_user) ret_slow_syscall:
disable_irq @ disable interrupts ldr r1, [tsk, #TI_FLAGS] tst r1, #_TIF_WORK_MASK bne work_pending no_work_pending:
/* perform architecture specific actions before user return */ arch_ret_to_user r1, lr
@ slow_restore_user_regs
ldr r1, [sp, #S_PSR] @ get calling cpsr ldr lr, [sp, #S_PC]! @ get pc
msr spsr_cxsf, r1 @ save in spsr_svc
ldmdb sp, {r0 - lr}^ @ get calling r0 - lr mov r0, r0
7
add sp, sp, #S_FRAME_SIZE - S_PC
movs pc, lr @ return & move spsr_svc into cpsr
第三章主要跟踪了从中断发生到调用到对应中断号的desc->handle_irq(irq, desc)中断函数的过程。后面的章节还会继续讲解后面的内容。
8
正在阅读:
linux-2.6.26内核ARM中断实现过程详解(2)01-23
宿舍楼监控安装设计方案09-25
《会计学》最新教学大纲03-17
《职场第一个十年》观后感04-02
1-3岁宝宝开心午餐08-10
如何分解工作目标(时代光华 课后测试)06-05
几种常见香肠的加工方法10-13
中考名著《水浒传》(71--80回)练习09-19
安全生产知识试卷(答案)03-24
- exercise2
- 铅锌矿详查地质设计 - 图文
- 厨余垃圾、餐厨垃圾堆肥系统设计方案
- 陈明珠开题报告
- 化工原理精选例题
- 政府形象宣传册营销案例
- 小学一至三年级语文阅读专项练习题
- 2014.民诉 期末考试 复习题
- 巅峰智业 - 做好顶层设计对建设城市的重要意义
- (三起)冀教版三年级英语上册Unit4 Lesson24练习题及答案
- 2017年实心轮胎现状及发展趋势分析(目录)
- 基于GIS的农用地定级技术研究定稿
- 2017-2022年中国医疗保健市场调查与市场前景预测报告(目录) - 图文
- 作业
- OFDM技术仿真(MATLAB代码) - 图文
- Android工程师笔试题及答案
- 生命密码联合密码
- 空间地上权若干法律问题探究
- 江苏学业水平测试《机械基础》模拟试题
- 选课走班实施方案
- 内核
- 中断
- 详解
- 过程
- 实现
- linux
- 2.6
- ARM
- 26
- 施工组织设计方案
- 高级宏观经济学(复旦大学) Exercise 1
- 中学生推铅球中“掉肘”原因探析
- 2015咨询工程师再教育课件及试题-燃气热力
- 生物化学第七章脂类代谢习题
- 十堰市中等职业学校部分专业教学标准 目录
- 安全生产管理机构设置和专职安全生产管理人员配备情况(企业套用版本)
- 大学英语四级答题技巧和写作模板
- 历任国务院主要领导人名单
- 延边朝鲜族自治州人民政府办公室关于印发全州城市棚户区改造政策暂行规定的通知
- 长方体和正方体的认识教学设计 反思 康巧红
- 考研英语阅读理解的必胜解题思路(80分过来人倾力奉献) - 考研资料里最珍珠级别
- 2018年4月个人工作计划范文与2018年4月乡政府个人总结范文汇编 doc
- 九级物理全册第十二章运动和力第-节复习学案(无答案)新人教版(新)-课件
- 中式面点试题及答案
- 量学战法汇总重点讲义资料
- GS、BV、TUV、UL、ITS、CE、WEEE、SGS、RoHS各大认证详解
- 第五章课后习题答案
- 2014版英语复习方略(外研版通用) 阶段评估检测(四) 必修4
- 化学实验简易读本22