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

ARM Linux中断机制分析

时间:11-09 来源:互联网 点击:
——以用户模式产生irq中断为例

以下代码基于内核linux2.6.38.3(trimslice官网下载)

本文主要分析ARM发生中断时的处理流程,以在usr态发生IRQ为例,即usr—>irq为例讨论。

1.内核异常向量表的初始化

1.1初始化大致流程

ARM linux内核启动时,首先运行的是linux/arch/arm/kernel/head.S,进行一些初始化工作,然后调用main.c->start_kernel()函数,进而调用trap_init()(或者调用early_trap_init()函数进行初始化)、init_IRQ()函数进行中断初始化、建立异常向量表.

1.2异常向量表的建立

异常向量表的建立过程就是拷贝过程,为了将内核代码写成位置无关的,有很多地方需要注意。

1.2.1异常向量表基地址确定

在ARM V4及V4T以后的大部分处理器中,中断向量表的位置可以有两个位置:一个是0x00000000,另一个是0xffff0000。可以通过CP15协处理器c1寄存器中V位(bit[13])控制。V和中断向量表的对应关系如下:

V=0 ~ 0x00000000~0x0000001C

V=1 ~ 0xffff0000~0xffff001C

注:CP15控制寄存器说明详见ARM ARMB4-1690.

在异常向量表初始化前运行的文件linux/arch/arm/kernel/head.S中设置了CP15寄存器(在~/arch/arm/mm/proc-v7.S文件中的__v7_setup函数中设置),这里通过设置CP15的c1寄存器已经确定了异常向量表的基地址(0xffff0000)。

1.2.2 异常向量表拷贝过程

内核代码编译生成后,需要将异常向量表拷贝到指定位置(0x00000000 or 0xffff0000),这就需要将内核中的异常向量表设计成与位置无关的。

本文所使用内核版本使用了early_trap_init()代替trap_init()来初始化异常。

early_trap_init()在linux/arch/arm/kernel/traps.c中,代码如下:

1、CONFIG_VECTORS_BASE在处理器型号确定后就已经确定,其值在内核配置完成后自动生成,保存在.config文件中。本文使用内核版本在maketrimslice_deconfig后自动生成的.config中定义:CONFIG_VECTORS_BASE=0xffff0000,也就是说,异常向量表的基地址0xffff0000。

~/arch/arm/kernel/traps.c line783

void __init early_trap_init(void)

{

#if defined(CONFIG_CPU_USE_DOMAINS)

unsigned longvectors = CONFIG_VECTORS_BASE; //vectors是中断向量基地址

#else

unsigned long vectors = (unsigned long)vectors_page;

#endif

/*以下这些都在arch/arm/kernel/entry-armv.S下定义*/

extern char __stubs_start[], __stubs_end[];

extern char __vectors_start[], __vectors_end[];

extern char __kuser_helper_start[], __kuser_helper_end[];

int kuser_sz = __kuser_helper_end - __kuser_helper_start;

/*

* Copy the vectors, stubs and kuser helpers (in entry-armv.S)

* into the vector page, mapped at 0xffff0000, and ensure these

* are visible to the instruction stream.

*/

/*__vectors_end至__vectors_start之间为异常向量表。__stubs_end至__stubs_start之间是异常处理的位置。这些变量定义都在arch/arm/kernel/entry-armv.S中*/

memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);

memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);

memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);

/*

* Do processor specific fixups for the kuser helpers

*/

kuser_get_tls_init(vectors);

/*

* Copy signal return handlers into the vector page, and

* set sigreturn to be a pointer to these.

*/

memcpy((void *)(vectors + KERN_SIGRETURN_CODE - CONFIG_VECTORS_BASE),

sigreturn_codes, sizeof(sigreturn_codes));

memcpy((void *)(vectors + KERN_RESTART_CODE - CONFIG_VECTORS_BASE),

syscall_restart_code, sizeof(syscall_restart_code));

flush_icache_range(vectors, vectors + PAGE_SIZE);

modify_domain(DOMAIN_USER, DOMAIN_CLIENT);

}


以下是__vectors_start, __vectors_end,__stubs_end__stubs_start的定义。

arch/arm/kernel/entry-armv.S

.globl__vectors_start

__vectors_start:

ARM( swi SYS_ERROR0 )

THUMB( svc #0 )

THUMB( nop )

W(b) vector_und + stubs_offset

W(ldr) pc, .LCvswi + stubs_offset

W(b) vector_pabt + stubs_offset

W(b) vector_dabt + stubs_offset

W(b) vector_addrexcptn + stubs_offset

W(b) vector_irq + stubs_offset

W(b) vector_fiq + stubs_offset

.globl__vectors_end

.globl__stubs_start

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

网站地图

Top