linux-2.6.26内核ARM中断实现过程详解(2)

2019-08-29 20:08

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_ (parent PC) and spsr_ @ (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 @为后面进入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_, already fixed up for correct return/restart @ r3 - spsr_

@ 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


linux-2.6.26内核ARM中断实现过程详解(2).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:5跨20米简支空心板梁毕业设计

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: