Linux ARMv7架构通用中断流程(1)【转】

一、ARMv7 Cortex-A系列处理器寄存器组介绍及其功能介绍

1. ARMv7 Cortex-A处理器一般共有37寄存器,其中包括:

(1) 31个通用寄存器,包括PC(程序计数器)在内,都是32位的寄存器。

(2) 6个状态寄存器,都是32位的寄存器。

2. ARMv7 Cortex-A系列处理器的模式

ARMv7 Cortex-A系列处理器共有7种处理器模式分别是:用户模式(User)、快速中断模式(FIQ)、普通中断模式(IRQ)、管理模式(Supervisor SVC)、数据访问中止模式(Abort)、未定义指令中止模式(Undefined)、系统模式(System)。在每一种处理器模式中有一组相应的寄存器。在任意一种寄存器模式下,可见的寄存器包括15个通用寄存器(R0~R14)、程序计数器(PC)、一个或者两个状态寄存器(CPSR、SPSR)。在所有寄存器中,有些是各个模式共用同一个物理寄存器,有些寄存器是各个模式自己拥有独立的物理寄存器。各种模式下的寄存器组如下入所示。

Linux ARMv7架构通用中断流程(1)【转】

其中R0~R3主要用于子程序间传递参数,R4~R11主要用于保存局部变量, 但在Thumb程序中,通常智能使用R4~R7来保存局部变量;R12(Intra-Procedure-call scratch register,详细介绍参见”Procedure Call Standard for the ARM Architecture”,)用作子程序间的scratch 寄存器,即IP;R13通常用作栈指针,即SP;R14寄存器又被称为连接寄存器,即LR,用于保存子程序以及中断的返回地址;R15用作程序计数器(PC),由于ARM采用流水线机制,PC的值当前正在指令地址加8个字节,即PC指向当前指令的下两条指令地址。CPSR和SPSR都是程序状态寄存器,其中SPSR是用来保存中断前的CPSR中的值,一边在中断返回后恢复处理器状态。

3. CPSR寄存器详解

Linux ARMv7架构通用中断流程(1)【转】

所有处理器模式下都可访问当前程序状态寄存器CPSR。CPSR中包含条件码标志、中断禁止位、当前处理器模式以及其他状态和控制信息。在每种异常模式下都有一个对应的程序状态寄存器SPSR。当异常出现时,SPSR用于保存CPSR的状态,以便异常返回后恢复异常发生时的工作状态。

(1)条件码标志

程序状态寄存器CPSR的最高4位N、Z、C、V是条件码标志。ARM的大多数指令可条件执行,即通过检测这些条件码标志来决定程序指令如何执行。

各个标志的含义如下:

N: 在结果有符号的二进制补码的情况下,如果结果为负数,则N=1;如果为非负数,则N=0.

Z:如果结果为0,则Z=1;如果结果为非零,则Z=0;

C:其设置分一下几种情况:

(1)对于加法指令(包括比较指令CMN),如果产生进位,则C=1;否则C=0。

(2)对于减法指令(包括比较指令CMP),如果产生借位,则C=0;否则C=1。

(3)对于有移位操作的非法指令,C为移位操作中最后移出位的值。

(4) 对于其他指令,C通常不变。

V:对于加减法指令,在操作数和结果是有符号的整数时,如果发生溢出,则V=1;如果无溢出发生,则V=0;对于其他指令,V通常不发生变化。

(2)控制位的作用在上图中可以看出来。

4. CPSR与CPSR_c的区别

CPSR有4个8位区域:标志域(F)、状态域(S)、扩展域(X)、控制域(C).

C控制域屏蔽字节(CPSR[7:0])

X扩展域屏蔽字节(CPSR[15:8])

S状态域屏蔽字节(CPSR[23:16])

F标志域屏蔽字节(CPSR[31:24])

常用于MRS或MSR指令,用于CPSR的值转移到寄存器或把寄存器的内容加载到CPSR中。如:

MSR CPSR_c , #0xd3

二、Linux ARMv7 Cortex-A系列处理器中断向量表处理和代码分析

1. ARMv7 Cortex-A系列处理器打开关闭irq中断

ARMv7 Cortex-A系列处理器打开关闭irq中断是通过改变CPSR寄存器的bit7位完成的。

开启和关闭当前处理器的本地中断,会产生中断信号,但不处理 。

local_irq_disable()关闭中断指令:cpsid i;

local_irq_enable()开启中断指令:cpsie i;

关闭和开启中断,不会产生中断信号。

disable_irq/enable_irq

2. linux系统为了实现异常处理引入了栈帧的概念

// arch/arm/include/uapi/asm/ptrace.h/** This struct defines the way the registers are stored on the* stack during a system call. Note that sizeof(struct pt_regs)* has to be a multiple of 8.*/#ifndef __KERNEL__struct pt_regs {long uregs[18];};#endif /* __KERNEL__ */#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]#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]//arch/arm/kernel/asm-offsets.cDEFINE(S_R0, offsetof(struct pt_regs, ARM_r0));DEFINE(S_R1, offsetof(struct pt_regs, ARM_r1));DEFINE(S_R2, offsetof(struct pt_regs, ARM_r2));DEFINE(S_R3, offsetof(struct pt_regs, ARM_r3));DEFINE(S_R4, offsetof(struct pt_regs, ARM_r4));DEFINE(S_R5, offsetof(struct pt_regs, ARM_r5));DEFINE(S_R6, offsetof(struct pt_regs, ARM_r6));DEFINE(S_R7, offsetof(struct pt_regs, ARM_r7));DEFINE(S_R8, offsetof(struct pt_regs, ARM_r8));DEFINE(S_R9, offsetof(struct pt_regs, ARM_r9));DEFINE(S_R10, offsetof(struct pt_regs, ARM_r10));DEFINE(S_FP, offsetof(struct pt_regs, ARM_fp));DEFINE(S_IP, offsetof(struct pt_regs, ARM_ip));DEFINE(S_SP, offsetof(struct pt_regs, ARM_sp));DEFINE(S_LR, offsetof(struct pt_regs, ARM_lr));DEFINE(S_PC, offsetof(struct pt_regs, ARM_pc));DEFINE(S_PSR, offsetof(struct pt_regs, ARM_cpsr));DEFINE(S_OLD_R0, offsetof(struct pt_regs, ARM_ORIG_r0));DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs));

3. ARM异常处理类型和模式

ARM的各种异常类型和每种异常类型处于的处理器模式,如下表所示:

Linux ARMv7架构通用中断流程(1)【转】

4. ARM中断处理汇编代码分析(基于LINUX 4.4.49内核分析)

4.1 arm中断处理总入口

//arch/arm/kernel/entry-armv.S/**注释:* 1)ARM架构异常处理向量表起始地址__vectors_start(定义在arch/arm/kernel/vmlinux.lds).* 2)ARM架构定义7种异常包括中断、系统调用、缺页异常等,发生异常时处理器会跳转到相应入口。* 3)异常向量表的起始位置由CP15协处理器的控制寄存器C1的bit13决定:* v=0,Normal exception vectors, base address 0x00000000. Software can remap this* base address using the VBAR(CP15 C12寄存器);* v=1,High exception vectors, base address 0xFFFF0000-0xFFFF001C. This base address* is never remapped.* The primary input VINITHI defines the reset value of the V bit.* VINITHI: Controls the location of the exception vectors at reset:* 0 = starts exception vectors at address 0x00000000* 1 = starts exception vectors at address 0xFFFF0000.* This pin is only sampled during reset of the processor*/        .section .vectors, "ax", %progbits__vectors_start:        W(b)     vector_rst        W(b)     vector_und/**系统调用入口点:* __vectors_start + 0x1000 = __stubs_start(由arch/arm/kernel/vmlinux.lds链接脚本可知)* 此时PC指向系统调用异常的处理入口:vector_swi用户态通过swi指令产生软中断。因为vector_swi系统* 调用异常代码在(arch/arm/kernel/entry-common.S),其入口地址与异常向量相隔较远,使用b指令无* 法跳转过去。b指令只能相对当前PC跳转 +/-32M范围)。*/        W(ldr)    pc, __vectors_start + 0x1000        W(b)      vector_pabt //取指令异常        W(b)      vector_dabt //数据异常--缺页异常        W(b)      vector_addrexcptn        W(b)      vector_irq //irq中断异常        W(b)      vector_fiq

4.2 以vector_irq为例进行深入分析

vector_irq是通过vector_stub宏定义的,vector_stub宏定义尤为关键,ARM任何异常都是通过将r0,lr,spsr保存到异常模式的栈中(每种异常模式都有自己的栈,栈的初始化在cpu_init,见下面分析), vector_stub通过vector_\name实现其功能。

//arch/arm/kernel/entry-armv.S/**注释:*当irq发生时,硬件自动完成如下操作:*1. arm在irq模式下有自己的lr寄存器lr_irq、spsr_irq、sp_irq.* r14_irq = lr_irq = address pf next instruction to be executed+4;*2. spsr_irq = cpsr,保存了处理器当前的状态,中断屏蔽位以及各种条件标志位,保存后cpsr会切换到* irq模式。*3. cpsr[4 :0] = 0b10010,设置arm为irq模式*4. cpsr[5] = 0,arm状态执行*5. cpsr[7] = 1,禁止irq*6. pc = 0xffff0018(High exception vectors,取决于CP15协处理器的C1寄存器的配置,参看上面的分* 析), 将pc值设置成异常中断的中断向量地址,即vectot_irq.*//** Interrupt dispatcher*/    vector_stub irq, IRQ_MODE, 4    .long __irq_usr     @ 0 (USR_26 / USR_32) 从用户态下进入的irq,执行__irq_usr代码    .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_svc代码    .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

sp在不同的模式下有不同寄存器,在cpu_init中进行初始化。

/* arch/arm/kernel/setup.c* cpu_init - initialise one CPU.** cpu_init sets up the per-CPU stacks.*/void notrace cpu_init(void){#ifndef CONFIG_CPU_V7M        unsigned int cpu = smp_processor_id();        struct stack *stk = &stacks[cpu];        if (cpu >= NR_CPUS) {            pr_crit("CPU%u: bad primary CPU number\n", cpu);            BUG();        }        /*        * This only works on resume and secondary cores. For booting on the        * boot cpu, smp_prepare_boot_cpu is called after percpu area setup.        */        set_my_cpu_offset(per_cpu_offset(cpu));        cpu_proc_init();        /*        * Define the placement constraint for the inline asm directive below.        * In Thumb-2, msr with an immediate value is not allowed.        */#ifdef CONFIG_THUMB2_KERNEL //此宏为定义#define PLC "r"#else#define PLC "I" //表示是立即数,其他定义可以查看GCC ARM C语言嵌入汇编语法#endif        /*        * setup stacks for re-entrant exception handlers        * 修改几种模式下的sp指向struct stack结构体类型变量stacks中定义的各个变量,每种模式下的栈为3个字        */        __asm__ (        "msr cpsr_c, %1\n\t" //msr cpsr_c,(PSR_F_BIT|PSR_I_BIT|IRQ_MODE)切换为irq模式        "add r14, %0, %2\n\t" //r14 = r +offset(struct stack, irq[0])        "mov sp, r14\n\t"        "msr cpsr_c, %3\n\t" //msr cpsr_c,(PSR_F_BIT|PSR_I_BIT|ABT_MODE)切换为abt模式        "add r14, %0, %4\n\t" //r14 = r +offset(struct stack, abt[0])        "mov sp, r14\n\t"        "msr cpsr_c, %5\n\t" //msr cpsr_c,(PSR_F_BIT|PSR_I_BIT|UND_MODE)切换为und模式        "add r14, %0, %6\n\t" //r14 = r +offset(struct stack, und[0])        "mov sp, r14\n\t"        "msr cpsr_c, %7\n\t" //msr cpsr_c,(PSR_F_BIT|PSR_I_BIT|FIQ_MODE)切换为fiq模式        "add r14, %0, %8\n\t" //r14 = r +offset(struct stack, fiq[0])        "mov sp, r14\n\t"        "msr cpsr_c, %9" //msr cpsr_c,(PSR_F_BIT|PSR_I_BIT|FIQ_MODE)切换为svc模式        :        : "r" (stk),        PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),        "I" (offsetof(struct stack, irq[0])),        PLC (PSR_F_BIT | PSR_I_BIT | ABT_MODE),        "I" (offsetof(struct stack, abt[0])),        PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),        "I" (offsetof(struct stack, und[0])),        PLC (PSR_F_BIT | PSR_I_BIT | FIQ_MODE),        "I" (offsetof(struct stack, fiq[0])),        PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)        : "r14");#endif}//arch/arm/kernel/setup.cstruct stack {    u32 irq[3];    u32 abt[3];    u32 und[3];    u32 fiq[3];} ____cacheline_aligned;#ifndef CONFIG_CPU_V7M    static struct stack stacks[NR_CPUS];#endif//arch/arm/include/uapi/asm/ptrace.h    #define USR26_MODE    0x00000000    #define FIQ26_MODE    0x00000001    #define IRQ26_MODE    0x00000002    #define SVC26_MODE    0x00000003    #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    #define MODE32_BIT    0x00000010    #define MODE_MASK     0x0000001f    #define PSR_T_BIT     0x00000020    #define PSR_F_BIT     0x00000040    #define PSR_I_BIT     0x00000080    #define PSR_A_BIT     0x00000100    #define PSR_E_BIT     0x00000200    #define PSR_J_BIT     0x01000000    #define PSR_Q_BIT     0x08000000    #define PSR_V_BIT     0x10000000    #define PSR_C_BIT     0x20000000    #define PSR_Z_BIT     0x40000000    #define PSR_N_BIT     0x80000000

vector_stub宏定义的分析如下:

//arch/arm/kernel/entry-armv.S/**注释:*1. 该接口负责保存异常发生前一时刻cpu寄存器到异常模式的栈中,保存r0,lr,spsr寄存器的值到* sp_dabt或sp_irq上。*2. 此时的sp是异常状态下的sp,这个栈只有12byte大小,在cpu_init()中初始化。*3. arm在irq/svc/abort几种模式下sp是不能共用的。*4. 此时lr中保存的实际上是异常的返回地址,异常发生,切换到svc模式后,会将lr保存到svc模式栈中* (pt_reg->pc),最后从异常返回时再将pt_reg->pc加载如arm寄存器pc中,实现异常返回。本函数只是* 其中一个步骤,即为将异常发生时刻lr保存到svc模式栈中(pt_reg->pc)做准备。*5. spsr是异常发生那一刻(即进入异常模式前是什么模式)的cpsr状态,如内核态下发生中断,则spsr是* svc模式下10011,如用户态下发生中断,则spsr是user模式10000。*6. 此时cpu正处于异常状态(如中断),此时cpsr为10010。*7. 要进行真正的异常处理,需要退出异常模式进入svc模式。*//** Vector stubs.** This code is copied to 0xffff1000 so we can use branches in the* vectors, rather than ldr's. Note that this code must not exceed* a page size.** Common stub entry macro:* Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC* * SP points to a minimal amount of processor-private memory, the address* of which is copied into r0 for the mode specific abort handler.*/        .macro vector_stub, name, mode, correction=0        .align 5 //强制对齐32字节对齐vector_\name:        .if \correction/* *需要调整返回值,对应irq异常将lr减去4,因为异常发生时,arm将pc地址+4赋值给了lr。 */        sub lr, lr, #\correction        .endif        @        @ Save r0, lr_ (parent PC) and spsr_        @ (parent CPSR)        @/* *1. spsr中保存异常发生时刻的cpsr。 *2. 此时的栈sp是异常时(irq mode或abt mode)的栈sp和svc mode里的栈sp不同。 *3. save r0,lr;将r0和lr保存到异常模式的栈上[sp] = r0;[sp+4] = lr_irq; * stmia sp,{r0, lr}没有sp!,因此sp不变。 *4. r0也要入栈,r0用作传递参数(异常状态下的sp)。 */        stmia sp, {r0, lr} @ save r0, lr        mrs lr, spsr //得到异常发生时所处模式得信息/* *将spsr保存到异常模式的栈上[sp+8]=spsr_irq=lr */        str lr, [sp, #8] @ save spsr       @       @ Prepare for SVC32 mode. IRQs remain disabled.       @/* *cpsr中保存的是异常模式:如irq 10010;dabt 10111 */       mrs r0, cpsr/* *1. dabt处理时,r0=r0^(0x17^0x13)=r0^0x4,bit3取反之后10011变为svc模式; *2. irq处理时:r0=10010=r0^(0x12^0x13)=r0^0x1=10011变为svc模式 */       eor r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)       msr spsr_cxsf, r0       @       @ the branch table must immediately follow this code       @       and lr, lr, #0x0f //用户态(user mode)lr=0;内核态(svn mode)lr=3;THUMB( adr r0, 1f )THUMB( ldr lr, [r0, lr, lsl #2] )/**r0=sp;*注意:*1. 此时r0中保存了异常状态下sp栈地址,这个栈上保存了r0,lr(异常返回地址),spsr(异常发生时,cpu* 的状态,当然异常返回时需要恢复该状态)*2. 之后的函数会把r0中保存的异常模式的sp上信息,加载到svc模式下的sp栈上。异常处理返回时再将svc* mode 的栈加载到arm寄存器上。*/        mov r0, sp/**lr中保存发生异常时arm的cpsr状态到spsr*1. usr模式发生异常则lr=10000&0x0f;lr=pc+lr<*2. svc模式发生异常则lr=10011&0x0f;lr=pc+lr<*/        ARM( ldr lr, [pc, lr, lsl #2] )/* movs中s表示把spsr恢复给cpsr,上面可知spsr保存的是svc模式,不过此时中断还是关闭的 * 异常处理一定要进入svc模式原因: *(1)异常处理一定要PL1特权级。 *(2)使能嵌套中断。 * 如果一个中断模式(例如用户态发生中断,arm从usr进入irq模式)中重新允许中断, * 且这个中断模式中使用了bl指令,bl会把pc放到lr_irq中,这个地址会被当前模式下产生的中断破坏 * 这种情况下中断无法返回。所以为了避免这种情况,中断处理过程应该切换到svc模式,bl指令可以把 * pc(即子程序返回地址)保存到lr_svc. */        movs pc, lr @ branch to handler in SVC modeENDPROC(vector_\name)

vector_irq完整代码 (vector_stub irq, IRQ_MODE, 4)

//arch/arm/kernel/entry-armv.Svector_irq:        sub lr, lr, 4        stmia sp, {r0, lr} @ save r0, lr        mrs lr, spsr        str lr, [sp, #8] @ save spsr        mrs r0, cpsr //读取现在cpsr寄存器,        eor r0, r0, #1 //r0的第0位翻转,在cpsr的模式M定义 usr:0b10000; svc:0b10011;        msr spsr_cxsf, r0 //r0寄存器写入spsr/* *异常发生时cpsr被保存到irq模式下的spsr中,在mrs lr, spsr中将spsr保存到lr中, *因为linux用户态处于usr模式,内核态处于svc模式,这两种模式在cpsr模式控制域M中只有最低两位不同, *得到低四位,就可以判断进入异常前处于usr模式还是svc模式,从判断是执行下面的__irq_usr还是  *__irq_svc */        and lr, lr, #0x0f         mov r0, sp        ldr lr, [pc, lr, lsl #2]        movs pc, lr         @ branch to handler in SVC mode //发生条状,进入svc模式        .long __irq_usr     @ 0 (USR_26 / USR_32) 从用户态下进入的irq,执行__irq_usr代码        .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_svc代码        .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

从用户态进入irq中断执行的是irq_usr代码

//arch/arm/kernel/entry-armv.S//此时arm处于svc模式执行下面代码__irq_usr:        usr_entry        kuser_cmpxchg_check        irq_handler //irq处理函数        get_thread_info tsk        mov why, #0        b ret_to_user_from_irq //中断处理完成返回UNWIND(.fnend )ENDPROC(__irq_usr)/** User mode handlers** EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE*/#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)#error "sizeof(struct pt_regs) must be a multiple of 8"#endif        .macro usr_entry, trace=1, uaccess=1UNWIND(.fnstart )UNWIND(.cantunwind ) @ don't unwind the user space/* *arch/arm/kernel/asm-offsets.c中定义DEFINE(S_FRAME_SIZE,sizeof(struct pt_regs))  *S_FRAME_SIZE=72 */        sub sp, sp, #S_FRAME_SIZE/**注释:*stmib r0!,{r1,r2} 将r1,r2的值保存到r0指向的存储单元中(r0自动加4)*将r1-r12全部入栈,因为没有!号所以入完栈后sp不变化,因为r1-r12在所有模式下是一组,*此时r1-r12里的值还是进入irq中断时的值,将这些值保存到svc模式下的栈中*/ARM( stmib sp, {r1 - r12} )THUMB( stmia sp, {r0 - r12} )/**注释:(cortex_a8_r3p2.pdf Cortex™-A8 Technical Reference Manual)*To access the Control Register, read or write CP15 with:*MRC p15, 0, , c1, c0, 0 ; Read Control Registe*/ATRAP( mrc p15, 0, r7, c1, c0, 0)/**注释:*.LCcralign:* .word cr_alignment*/ATRAP( ldr r8, .LCcralign)/**注释:*ldmia r0!,{r1,r2} 将r0指向的单元中的数据读出到r1,r2中(r0自动加4)*因r0为irq模式时sp的值,所以就是将irq模式下sp栈的内容保存到r3、r4、r5中,其中的内容irq异常发生*时r0、lr、cpsr。*/        ldmia r0, {r3 - r5}        add r0, sp, #S_PC             @ here for interlock avoidance        mov r6, #-1                   @ "" "" "" ""        str r3, [sp]                  @ save the "real" r0 copied                                      @ from the exception stackATRAP( ldr r8, [r8, #0])        @        @ We are now ready to fill in the remaining blanks on the stack:        @        @ r4 - lr_, already fixed up for correct return/restart        @ r5 - spsr_        @ r6 - orig_r0 (see pt_regs definition in ptrace.h)        @        @ Also, separately save sp_usr and lr_usr        @        stmia r0, {r4 - r6}ARM(    stmdb r0, {sp, lr}^ )THUMB(  store_user_sp_lr r0, r1, S_SP - S_PC )        .if \uaccess            uaccess_disable ip        .endif        @ Enable the alignment trap while in kernel modeATRAP(  teq r8, r7)ATRAP(  mcrne p15, 0, r8, c1, c0, 0)        @        @ Clear FP to mark the first stack frame        @        zero_fp        .if \trace#ifdef CONFIG_TRACE_IRQFLAGS        bl trace_hardirqs_off#endif        ct_user_exit save = 0        .endif        .endm        .macro kuser_cmpxchg_check#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS)#ifndef CONFIG_MMU#warning "NPTL on non MMU needs fixing"#else        @ Make sure our user space atomic helper is restarted        @ if it was interrupted in a critical region. Here we        @ perform a quick test inline since it should be false        @ 99.9999% of the time. The rest is done out of line.        cmp r4, #TASK_SIZE        blhs kuser_cmpxchg64_fixup#endif#endif        .endm

irq_handler 宏为中断处理的关键部分,从这里会进入C语言编写的代码,进入linux对中断的通用处理框架里。

//arch/arm/kernel/entry-armv.S/**注释:*宏CONFIG_MULTI_IRQ_HANDLER在.config中有定义,会将handle_arch_irq里的值赋值给pc去执行。*给handle_arch_irq请看后面的C语言阶段分析*//** Interrupt handling.*/        .macro irq_handler#ifdef CONFIG_MULTI_IRQ_HANDLER        ldr r1, =handle_arch_irq        mov r0, sp        badr lr, 9997f        ldr pc, [r1] //进入C语言阶段的中断处理#else        arch_irq_handler_default#endif9997:        .endm//arch/arm/kernel/entry-armv.S#ifdef CONFIG_MULTI_IRQ_HANDLER        .globl handle_arch_irqhandle_arch_irq:        .space 4#endif

以上分析是linux对于armv架构中断通用处理的代码,该部分代码跟arm架构紧密相关,此部分汇编代码在中断发生时执行。

下篇文章分析Linux系统在启动阶段对中断向量表的搬移。

Original: https://www.cnblogs.com/yifeichongtian2021/p/15512128.html
Author: 壹飞冲天
Title: Linux ARMv7架构通用中断流程(1)【转】

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/585779/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 不自由的自由职业

    大家好。我叫梁旭,以前是农民,现在是自由职业者。 [En] Hello, everyone. I’m Liangxu, a former farmer, and now…

    Linux 2023年5月27日
    0123
  • AI芯片的软件挑战

    本文是记录会议【ICPA联盟微课 | 第1期】燧原科技李彬:AI芯片的软件挑战内容。不得不说,什么叫高屋建瓴。 芯片软件的5个衡量指标:算力利用率、开发效率、生态兼容性、可移植性、…

    Linux 2023年6月7日
    089
  • python爬虫配置随机请求头headers伪装User-Agent

    fake_useragent 库 调用方法 ua.random可以随机返回一个headers(User-Agent) from fake_useragent import User…

    Linux 2023年6月14日
    089
  • java 连接 redis

    Jedis 导入对应的依赖 redis.clients jedis 4.2.3 com.alibaba fastjson 1.2.79 连接数据库 记得在本地打开 redis //…

    Linux 2023年6月7日
    093
  • HTML笔记整理–下节

    欢迎来到HTML基础笔记下节部分! 内联样式 当特殊的样式需要应用到个别元素时,就可以使用内联样式。 使用内联样式的方法是在相关的标签中使用样式属性。样式属性可以包含任何 CSS …

    Linux 2023年6月13日
    081
  • 嵌入式软件架构设计-程序分层

    1 前言 在嵌入式MCU软件开发过程中,程序分层设计也是重中之重,关系到整个软件开发过程中的协同开发,降低系统软件的复杂度(复杂问题分解)和依赖关系、同时有利于标准化,便于管理各层…

    Linux 2023年6月7日
    0142
  • Linux服务器文件打包

    1,一般打包:: 文件路径是相对路径,打包后文件也是相对路径,无论是否添加P参数. 文件目录是绝对路径,但不加P参数打包可能会报错[删除/之类的错误],.加P参数打包正确无错误.打…

    Linux 2023年5月27日
    0114
  • MySQL-创建表

    如何在指定数据库中创建表 我们先来了解一下在数据库中创建表的规则: CREATE TABLE 表名 ( 字段名,数据类型, 字段名,数据类型, ….. ) 例如: 添加…

    Linux 2023年6月8日
    0118
  • LeetCode 907: 子数组的最小值之和-单调栈的运用 |Sum of Subarray Minimums-Fantasy use of Monotonic Stack

    Tags: #MonoStack #Stack Problem Description Given an array of integers arr, find the sum o…

    Linux 2023年6月13日
    074
  • python3安装pyhook3遇到的问题

    一、 解决办法:安装好:使用C++的桌面开发即可完成。 打开官方网址:Visual Studio: 面向软件开发人员和 Teams 的 IDE 和代码编辑器 (microsoft….

    Linux 2023年6月13日
    0107
  • 防数据泄露_MySQL库和数据安全

    攻击场景 外部入侵 内部盗取 防御体系建设 参考 在企业安全建设中有一个方向是防数据泄露,其中一块工作就是保障数据库安全,毕竟这里是数据的源头。当然数据库也分不同的种类,不同类型的…

    Linux 2023年6月6日
    0105
  • rocksdb列族笔记

    1、简介 列族(Column Families)是rocksdb3.0提出的一个机制,用于对同一个数据库的记录(键值对)进行逻辑划分。默认情况下所有的记录都会存储在一个默认列族里(…

    Linux 2023年6月7日
    0107
  • Flink 集群搭建,Standalone,集群部署,HA高可用部署

    基础环境 准备3台虚拟机 配置无密码登录 配置方法:https://ipooli.com/2020/04/linux_host/ 并且做好主机映射。 https://www.apa…

    Linux 2023年6月7日
    0119
  • phpweb成品网站最新版(注入、上传、写shell)

    注入:之所以鸡肋就是该漏洞利用安装文件 重新生成 配置文件 写入可执行代码 鸡肋1: 具有破坏性 动作非常大 重新写了配置文件 数据库连接文件鸡肋2: 有一定安全常识的站长都会删掉…

    Linux 2023年5月28日
    081
  • 离线版centos8环境部署迁移监控操作笔记

    嗨咯,前两天总结记录了离线版centos8下docker的部署笔记,今天正好是2021年的最后一天,今天正好坐在本次出差回家的列车上,车上没有上面事做,索性不如把本次离线版cent…

    Linux 2023年6月14日
    0105
  • 如何写好倒计时

    引言 本文讲解倒计时为什么建议使用 setTimeout而不使用 setInterval,倒计时为什么存在误差,以及如何解决。 倒计时器 在前端开发中,倒计时器功能比较常见,比如活…

    Linux 2023年6月7日
    0330
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球