微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > arm linux 下中断流程简要分析初始化

arm linux 下中断流程简要分析初始化

时间:11-09 来源:互联网 点击:
上面的这个表我们称之为”异常中断向量表”,表中的IRQ和FIQ位置就是用来存放处理中断函数的地址。至于选择何处存放该表,可由CPU的协处理器完成。如s3c2410下由CP15中寄存器1的位13来决定,我们可以通过设置该位来告诉系统我们的向量表在哪。具体可参考<>

因此,在中断初始化的时候我们要做的就是在IRQ和FIQ的位置处放置我们的中断处理函数地址或跳转语句跳转到我们的中断处理函数。这个过程是在trap_init中完成的,而他由start_kernel()调用。

arch/arm/kernel/traps.c:

void __init trap_init(void)

{

unsigned long vectors = CONFIG_VECTORS_BASE;/*跳转表的存放位置(即上面那表的存放位置)*/

/*这些都在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.

*/

/*跳转表内容到指定的位置*/

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);

/*

* Copy signal return handlers into the vector page, and

* set sigreturn to be a pointer to these.

*/

memcpy((void *)KERN_SIGRETURN_CODE, sigreturn_codes,

sizeof(sigreturn_codes));

flush_icache_range(vectors, vectors + PAGE_SIZE);

modify_domain(DOMAIN_USER, DOMAIN_CLIENT);

}

上面这个函数主要就是在CONFIG_VECTORS_BASE处设置好那张跳转表,CONFIG_VECTORS_BASE在autoconf.h中定义(该文件自动成生),值为0xffff0000,而CP15下的r1[13]在系统启动的时候在汇编部分就已经设置好了。

接下来我们就看下__vectors_start,__vectors_end,__stubs_start,__stubs_end之间的内容。

arch/arm/kernel/entry-armv.S:

.globl__vectors_start

__vectors_start:

swiSYS_ERROR0

bvector_und + stubs_offset

ldrpc, .LCvswi + stubs_offset

bvector_pabt + stubs_offset

bvector_dabt + stubs_offset

bvector_addrexcptn + stubs_offset

bvector_irq + stubs_offset

bvector_fiq + stubs_offset

.globl__vectors_end

__vectors_end:

.data

看到了吧, 就是那张跳转表。vector_irq,vector_fiq等函数我们后面在分析,他们就定义在__stubs_start,__stubs_end中。

至此经过traps_init后,在0xffff0000处的跳转表就形成了。当产生IRQ时,将调用bvector_irq + stubs_offset

在系统初始化的时候还会调用init_IRQ函数(也由start_kernel调用),它初始化了一个全局中断描述符表(该表保存了每个中断的所有属性信息)。并调用特定平台的中断初始化函数。

arm/arm/kernel/Irq.c:

void __init init_IRQ(void)

{

int irq;

/*初始化中断描述符表*/

for (irq = 0; irq < NR_IRQS; irq++)

irq_desc[irq].status |= IRQ_NOREQUEST | IRQ_DELAYED_DISABLE |

IRQ_NOPROBE;

#ifdef CONFIG_SMP

bad_irq_desc.affinity = CPU_MASK_ALL;

bad_irq_desc.cpu = smp_processor_id();

#endif

init_arch_irq();/*特定平台的中断初始化*/

}

系统中总共有NR_IRQS个中断,并且每个中断都有一个中断描述符,保存在irq_desc中,该描述符保存了该中断的所有属性信息。

对于平台smdk2410来说init_arch_irq()就是s3c24xx_init_irq()函数,这是在setup_arch()里面赋值的。

后面的内容我们都以中断号:IRQ_WDT为例来讲解:

arch/arm/mach-s3c2410/Irq.c:

/* s3c24xx_init_irq

*

* Initialise S3C2410 IRQ system

*/

void __init s3c24xx_init_irq(void)

{

unsigned long pend;

unsigned long last;

int irqno;

int i;

irqdbf("s3c2410_init_irq: clearing interrupt status flags/n");

/* first, clear all interrupts pending... */

/*先清掉所有的pending标志位,该位代表是否系统中触发了一个中断*/

last = 0;

for (i = 0; i < 4; i++) {

pend = __raw_readl(S3C24XX_EINTPEND);

if (pend == 0 || pend == last)

break;

__raw_writel(pend, S3C24XX_EINTPEND);

printk("irq: clearing pending ext status %08x/n", (int)pend);

last = pend;

}

last = 0;

for (i =

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

网站地图

Top