Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3010686
  • 博文数量: 674
  • 博客积分: 17881
  • 博客等级: 上将
  • 技术积分: 4849
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-17 10:15
文章分类

全部博文(674)

文章存档

2013年(34)

2012年(146)

2011年(197)

2010年(297)

分类: LINUX

2010-03-31 08:44:49

一、arm中断的相关硬件知识:

正常的程序执行流程发生暂时的停止时,称之为异常。例如处理一个外部的中断请求。在处理异常之前,当前处理器的状态必须保留,这样当异常处理完成之后,当前程序可以继续执行。处理器允许多个异常同时发生,它们将会按固定的优先级进行处理。ARM体系结构中的异常,与8/16位体系结构的中断有很大的相似之处,但异常与中断的概念并不完全等同。

ARM的异常有七种

复位异常、SWI异常、未定义指令异常、数据中止和指令中止异常。外部中断分为FIQIRQ两种,分别为快速中断和通用中断。都可以通过CPSR中的相应位来屏蔽。

CPU知道一个source触发了中断,怎么调用执行一些函数(汇编,或者c语言),就是靠异常向量表(事实上,exception vector table 也是由汇编组成的)

 

Arm7种异常对应的模式

进入模式
5
个异常模式

优先级

6最低

0x0000,0000

复位

管理模式

1

0x0000,0004

未定义指令

未定义模式

6

0x0000,0008

软件中断

管理模式

6

0x0000,000C

中止(预取指令)

中止模式

5

0x0000,0010

中止(数据)

中止模式

2

0x0000,0014

保留

保留

未使用

0x0000,0018

IRQ

IRQ

4

0x0000,001C

FIQ

FIQ

3

 

arm异常表,对应模式及向量表偏移 (摘自arm体系结构与编程一书)

 

当一个异常/中断出现后, 4020系统中ARM处理器对其的响应过程如下:

 

 (1)  保存处理器当前状态、中断屏蔽位以及各条件标志位。将当前程序状态寄存器CPSR的内容保存到将要执行的异常中断对应的SPSR寄存器中。

 

(2)  设置当前程序状态寄存器CPSR中相应的位。包括设置CPSR中的位,使处理器进入相应的执行模式;设置CPSR中的位,禁止IRQ中断,当进入FIQ模式时,禁止FIQ中断。

 

(3) 将寄存器lr_mode设置成返回地址。

 

(4) 将程序计数器值(PC),设置成该异常中断的中断向量地址,从而跳转到相应的异常中断处理程序执行。即处理器跳转到异常向量表中相应的入口(对于IRQ 显然pc=0x18

 

所以当触发IRQ后,CPU会最后跳入0x18 这个入口,定制kernel时只需在这个入口填入自己的指令(当然是汇编语句) ,即可调用中断处理函数,可能这样:

 

而对于4020 linux系统中断向量的含义是:

触发IRQCPU jump 0x18,同时要把irqno传入相应的寄存器调用一个中断通用处理函数如:asm_do_IRQ(unsigned int irqno)  asm_do_IRQ() 这个函数根据irqno 就可以找到对应的中断描述符,然后调用中断描述符里面的handler()了。

 

二、linux中中断向量表的初始化

ARM linux内核启动时,通过start_kernel()->trap_init()的调用关系,初始化内核的中断异常向量表。

linux/init/main.c    Start_kernel中的中断向量表初始化

asmlinkage void __init start_kernel(void)
{
.....
trap_init();
init_IRQ();
....

}

中断的初始化主要和这两个函数相关

1trap_init函数

这个trap_init函数主要起到搬运中断向量到高地址的作用

void __init trap_init(void)

{

       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 *)0xffff0000, __vectors_start, __vectors_end - __vectors_start);

       memcpy((void *)0xffff0200, __stubs_start, __stubs_end - __stubs_start);

       memcpy((void *)0xffff1000 - 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(0xffff0000, 0xffff0000 + PAGE_SIZE);

       modify_domain(DOMAIN_USER, DOMAIN_CLIENT);

}

 

2init_IRQ函数

void __init init_IRQ(void)

{

       struct irqdesc *desc;

       int irq;

 

#ifdef CONFIG_SMP

       bad_irq_desc.affinity = CPU_MASK_ALL;

       bad_irq_desc.cpu = smp_processor_id();

#endif

// irq_desc数组是用来描述IRQ的请求队列,每一个中断号分配一个

//irq_desc结构,组成了一个数组。

       for (irq = 0, desc = irq_desc; irq < NR_IRQS; irq++, desc++) {

              *desc = bad_irq_desc; /* 把每个中断先初始化为bad_irq*/

              INIT_LIST_HEAD(&desc->pend);

       }

 

       init_arch_irq();  /* 调用4020自己sep4020_init_irq函数来初始化各个中断句柄为do_level_IRQ*/

}

 

其中关键函数为:init_arch_irq();
阅读(744) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~