简单分析RTEMS基于S3C2440 的中断处理原理

来源:互联网 发布:变声器男变女软件 编辑:程序博客网 时间:2024/06/04 18:35

看连接脚本,异常向量连接在开始的 0x100 地址(空位填充0,ALIGN 控制)
如果 RTEMS 是放到SDRAM中运行,0x30000000 - 0x30000100 就应该是异常向量。
然后 0x30000100 开始的是 _start 这个entry,代码从这里开始。
从start.S 的开始部分没有看到常见的向量表。因为RTEMS期望有一个bootloader将它
本身复制到SDRAM中并且运行。然后RTEMS自己创建动态的向量表(在RAM中的向量表)
当然了,其实可以使用自己写的代码,实现.text .data 段的复制等。
而ARM的异常向量固定在 0x0 开始的地址,所以start.S 中使能了 MMU,将 0x30000000
地址映射到 0 地址。
ARM发生异常时,经过MMU的映射,实际上执行的是 0x30000000 开始的向量表中的操作。

  .base :
  {
    arm_exception_table = .;   
    arm_reset_vect    = .;     /* 0x00 */
    . += 4;
    arm_undef_vect    = .;     /* 0x04 */
    . += 4;
    arm_swi_vect      = .;     /* 0x08 */
    . += 4;
    arm_iabrt_vect    = .;     /* 0x0c */
    . += 4;
    arm_dabrt_vect    = .;     /* 0x10 */
    . += 4;
    /* no vector here */
    . += 4;
    arm_irq_vect      = .;     /* 0x18 */
    . += 4;
    arm_fiq_vect      = .;     /* 0x1c */
    . += 4;
         /* FIXME: */
    rtems_vector_table = .;
    . += (8 * 4);                     /* 8 ARM interrupts */
    bsp_vector_table = .;
    . += (32 * 4);                    /* 32 S3C2400 interrupts */
    . = ALIGN (0x100);


接着 start.S 中看到如下代码,很显然这里是安装句柄。但是问题来了,为什么这些句柄都是
简单的死循环?实际的操作是怎么样的呢?这个问题我确实思考了好几天。后来明白了,这里仅仅
是占个茅坑。做好基本的向量捕捉,至少让系统不能死,发生异常能捕捉到。至于怎么处理这些异常,
可以通过后面注册的处理句柄去做处理。

        mov     r0, #0
        adr     r1, vector_block
        ldmia   r1!, {r2-r9}
        stmia   r0!, {r2-r9}
        ldmia   r1!, {r2-r9}
        stmia   r0!, {r2-r9}

vector_block:
        ldr     pc, Reset_Handler
        ldr     pc, Undefined_Handler
        ldr     pc, SWI_Handler
        ldr     pc, Prefetch_Handler
        ldr     pc, Abort_Handler
        nop
        ldr     pc, IRQ_Handler
        ldr     pc, FIQ_Handler

Reset_Handler:          b       bsp_reset
Undefined_Handler:      b       Undefined_Handler
SWI_Handler:            b       SWI_Handler
Prefetch_Handler:       b       Prefetch_Handler
Abort_Handler:          b       Abort_Handler
                        nop
IRQ_Handler:            b       IRQ_Handler
FIQ_Handler:            b       FIQ_Handler


比如常用的 IRQ 中断,系统是怎么做的呢?
虽然说写文章一般用顺序,但是我打算我分析的时候的思路写下来,看看怎么思考这个问题的。

首先看 RTEMS 的例子和doc文档,应该不难发现RTEMS有这么一个函数
rtems_status_code rtems_interrupt_catch(
  rtems_isr_entry      new_isr_handler,
  rtems_vector_number  vector,
  rtems_isr_entry     *old_isr_handler
)
catch就是捕捉的意思,看这里的参数,应该就是注册一个新的中断处理句柄,然后返回旧的句柄。
至于 vector 这里不知道含义是什么,一般的推断应该就是中断号,比如s3c2440 有几个异常向量
IRQ中断也有很多个不同的中断源,这里的vector到底是指什么?这里其实并不知道的。

接着就应该想,这个函数到底被谁调用,或者这个函数调用谁?这就是思路。
rtems_interrupt_catch 已经是用户可以调用的函数了。(其实我是在看网络驱动代码的时候发现的)

#define _ISR_Install_vector( _vector, _new_handler, _old_handler ) \
  _CPU_ISR_install_vector( _vector, _new_handler, _old_handler )
最后发现
  if (current_handler != (uint32_t) new_handler) {
    table [vector] = (uint32_t) new_handler;
  }
所谓的安装句柄,就是将句柄(也就是函数了)加入到 table 数组当中。
  volatile uint32_t *table = (volatile uint32_t *) (MAX_EXCEPTIONS * 4);

这里可以看出table是指向一个绝对地址,MAX_EXCEPTIONS 是 8,每个异常向量是 4byte
很自然就想到,这个table 就是跟在所有的异常向量的后面。

看会 link脚本,应该就是指向这个地址了。
    rtems_vector_table = .;
    . += (8 * 4);                     /* 8 ARM interrupts */
    bsp_vector_table = .;
    . += (32 * 4);                    /* 32 S3C2400 interrupts */
可见,这是rtems自己的向量表,在看看哪里有使用这个标号,在 s3c2410.h 中定义了


#define _ISR_STARTADDRESS rtems_vector_table
/* ISR */
#define pISR_RESET      (*(unsigned *)(_ISR_STARTADDRESS+0x0))
#define pISR_UNDEF      (*(unsigned *)(_ISR_STARTADDRESS+0x4))


看 bootcard.c
bsp_start();
void bsp_start_default( void )
(应为属性是 weak 函数,所以被替换掉了)
void bsp_start (void) __attribute__ ((weak, alias("bsp_start_default")));字面意思猜

在这个bsp的初始化函数里面,(注意这个函数很早被执行,因为需要安装异常句柄。
rtems_exception_init_mngt();

      _CPU_ISR_install_vector(ARM_EXCEPTION_IRQ,
                              _Exception_Handler_Abort,
                              NULL);
安装的函数使用之前的函数,先指向 abort处理句柄,然后执行下面的
bsp_interrupt_initialize 中断初始化。
接着执行
bsp_interrupt_facility_initialize();
实际上就是安装IRQ处理句柄为  arm_exc_interrupt
_CPU_ISR_install_vector(ARM_EXCEPTION_IRQ, arm_exc_interrupt, NULL);

这个函数在 arm_exc_interrupt.S 中,是汇编写的。
因为还有内核调度等功能,所以这个函数看起来有点复杂,但是我们留意有下面一句
bl bsp_interrupt_dispatch

void bsp_interrupt_dispatch(void)
{
  rtems_vector_number vector = *((uint32_t *) rINTOFFSET_ADDR);

  bsp_interrupt_handler_dispatch(vector);
}

将 INTOFFSET 的内容作为 vector 的参数,传递给bsp_interrupt_handler_dispatch
然后根据 bsp_interrupt_handler_table 的内容(之前或者用户自己安装的句柄),执行具体的函数。


当分析到这里的时候,上层的基本原理都明白了。但是始终还是不明白,RTEMS 的中断句柄表是 (MAX_EXCEPTIONS * 4) 的偏移
到底为什么能将ARM的IRQ中断转为RTEMS的中断的??
想了整整一个中午,没睡觉,下午在google看了篇文章突然间明白了。

rtems_exception_init_mngt 安装的是在 (MAX_EXCEPTIONS * 4) 偏移处,也就是 0x20
这个时候看看 start.S 里面安装的处理句柄,不就是这个地址么!!!!!
vector_block:
        ldr     pc, Reset_Handler
        ldr     pc, Undefined_Handler
于是一切问题都解决了。

Etual
2012-12-21 (对的,末日)

原创粉丝点击