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

ARM linux的中断处理过程

时间:11-09 来源:互联网 点击:
一、前言

本文主要以ARM体系结构下的中断处理为例,讲述整个中断处理过程中的硬件行为和软件动作。具体整个处理过程分成三个步骤来描述:

1、第二章描述了中断处理的准备过程

2、第三章描述了当发生中的时候,ARM硬件的行为

3、第四章描述了ARM的中断进入过程

4、第五章描述了ARM的中断退出过程

本文涉及的代码来自3.14内核。另外,本文注意描述ARM指令集的内容,有些source code为了简短一些,删除了THUMB相关的代码,除此之外,有些debug相关的内容也会删除。

二、中断处理的准备过程

1、中断模式的stack准备

ARM处理器有多种process mode,例如user mode(用户空间的AP所处于的模式)、supervisor mode(即SVC mode,大部分的内核态代码都处于这种mode)、IRQ mode(发生中断后,处理器会切入到该mode)等。对于linux kernel,其中断处理处理过程中,ARM 处理器大部分都是处于SVC mode。但是,实际上产生中断的时候,ARM处理器实际上是进入IRQ mode,因此在进入真正的IRQ异常处理之前会有一小段IRQ mode的操作,之后会进入SVC mode进行真正的IRQ异常处理。由于IRQ mode只是一个过度,因此IRQ mode的栈很小,只有12个字节,具体如下:

struct stack {
u32 irq[3];
u32 abt[3];
u32 und[3];
} ____cacheline_aligned;

static struct stack stacks[NR_CPUS];

除了irq mode,linux kernel在处理abt mode(当发生data abort exception或者prefetch abort exception的时候进入的模式)和und mode(处理器遇到一个未定义的指令的时候进入的异常模式)的时候也是采用了相同的策略。也就是经过一个简短的abt或者und mode之后,stack切换到svc mode的栈上,这个栈就是发生异常那个时间点current thread的内核栈。anyway,在irq mode和svc mode之间总是需要一个stack保存数据,这就是中断模式的stack,系统初始化的时候,cpu_init函数中会进行中断模式stack的设定:

void notrace cpu_init(void)
{

unsigned int cpu = smp_processor_id();------获取CPU ID
struct stack *stk = &stacks[cpu];---------获取该CPU对于的irq abt和und的stack指针

……

#ifdef CONFIG_THUMB2_KERNEL
#define PLC "r"------Thumb-2下,msr指令不允许使用立即数,只能使用寄存器。
#else
#define PLC "I"
#endif

__asm__ (
"msr cpsr_c, %1\n\t"------让CPU进入IRQ mode
"add r14, %0, %2\n\t"------r14寄存器保存stk->irq
"mov sp, r14\n\t"--------设定IRQ mode的stack为stk->irq
"msr cpsr_c, %3\n\t"
"add r14, %0, %4\n\t"
"mov sp, r14\n\t"--------设定abt mode的stack为stk->abt
"msr cpsr_c, %5\n\t"
"add r14, %0, %6\n\t"
"mov sp, r14\n\t"--------设定und mode的stack为stk->und
"msr cpsr_c, %7"--------回到SVC mode
:--------------------上面是code,下面的output部分是空的
: "r" (stk),----------------------对应上面代码中的%0
PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),------对应上面代码中的%1
"I" (offsetof(struct stack, irq[0])),------------对应上面代码中的%2
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 | SVC_MODE)
: "r14");--------上面是input操作数列表,r14是要clobbered register列表
}

嵌入式汇编的语法格式是:asm(code : output operand list : input operand list : clobber list);大家对着上面的code就可以分开各段内容了。在input operand list中,有两种限制符(constraint),"r"或者"I","I"表示立即数(Immediate operands),"r"表示用通用寄存器传递参数。clobber list中有一个r14,表示在汇编代码中修改了r14的值,这些信息是编译器需要的内容。

2、SVC模式的stack准备

我们经常说进程的用户空间和内核空间,对于一个应用程序而言,可以运行在用户空间,也可以通过系统调用进入内核空间。在用户空间,使用的是用户栈,也就是我们软件工程师编写用户空间程序的时候,保存局部变量的stack。陷入内核后,当然不能用用户栈了,这时候就需要使用到内核栈。所谓内核栈其实就是处于SVC mode时候使用的栈。

Linux kernel在创建进程(包括用户进程和内核线程

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

网站地图

Top