|  | 
 
| uclinux-2.4.24-uc0支持44B0X开发板----异常处理向量表的处理 
 由于Flash在地址0,所以uclinux不能修改存储于Flash 0 地址的异常向量表。在Flash 0地址我们存放以下跳转指令(DRAM_BASE = 0C000000):
 b      ResetHandler               ;    Reset
 ldr    pc, =(DRAM_BASE + 0x04)    ;    HandlerUndef
 ldr    pc, =(DRAM_BASE + 0x0
  ;    HandlerSWI ldr    pc, =(DRAM_BASE + 0x0C)    ;    HandlerPabort
 ldr    pc, =(DRAM_BASE + 0x10)    ;    HandlerDAbort
 ldr    pc, =(DRAM_BASE + 0x14)    ;    HandlerReserved
 ldr    pc, =(DRAM_BASE + 0x1
  ;    HandlerIRQ ldr    pc, =(DRAM_BASE + 0x1C)    ;    HandlerFIQ
 Reset之后调用Bootloader的ResetHandler,而其他异常模式都跳转到内存首地址的另一份中断向量表中。在DRAM_BASE位置,我们的Bootloader将会安装另一份异常向量表:
 BootloaderEVBegin   ; Bootloader s own Exception Vectors
 b .    ; Should be installed into DRAM_BASE
 ldr pc, pHandlerUndef
 ldr pc, pHandlerSWI
 ldr pc, pHandlerPabort
 ldr pc, pHandlerDabort
 b .    ; HandlerReserved
 ldr pc, pHandlerIRQ
 ldr pc, pHandlerFIQ
 
 pHandlerUndef DCD HandlerUndef
 pHandlerSWI DCD HandlerSWI
 pHandlerPabort DCD HandlerPabort
 pHandlerDabort DCD HandlerDabort
 pHandlerIRQ DCD HandlerIRQ
 pHandlerFIQ DCD HandlerFIQ
 BootloaderEVEnd    ; Bootloader s own Exception Vector End
 在Bootloader的ResetHandler函数中,我们会将自己(Bootloader)从Flash中搬移到内存高地址中运行,并将上面的Exception Vectors安装到内存首地址。
 
 这样做我们相当于有了两级的跳转表,当有异常(IRQ)发生时,首先跳转到0x18,这里又是一条跳转指令,再到DRAM_BASE + 0x18,执行中断处理函数。而uclinux的异常向量表只要安装在这里就可以了。
 
 为此,我们需要修改uclinux内核的include/asm-armnommu/proc-armv/system.h头文件,将vectors_base()这个宏修改为内存首地址:
 #if defined(CONFIG_BOARD_SAMPLE44B0X)
 #undef vectors_base()
 #define vectors_base() (DRAM_BASE)
 #endif
 
 当uclinux kernel运行到start_kernel()函数(init/main.c),调用trap_init()函数(arch/armnommu/kernel/traps.c),trap_init()将调用__trap_init((void *)vectors_base());来安装它的异常向量表,这个函数在entry_armv.S源文件中,代码的注释如下:
 .equ __real_stubs_start, .LCvectors + 0x200
 
 .LCvectors:
 swi SYS_ERROR0
 b __real_stubs_start + (vector_undefinstr - __stubs_start)
 /*
 * vector_undefinstr - __stubs_start 等于vector_undefinstr()函数相对于__stubs_start的偏移
 * 我们最终会将.LCvectors复制到0c000000,__stubs_start ~ __stubs_end之间的代码复制到0c000000 + 0x200的位置
 * __real_stubs_start是一个宏,是相对于PC的偏移量。
 */
 ldr pc, __real_stubs_start + (.LCvswi - __stubs_start)
 b __real_stubs_start + (vector_prefetch - __stubs_start)
 b __real_stubs_start + (vector_data - __stubs_start)
 b __real_stubs_start + (vector_addrexcptn - __stubs_start)
 b __real_stubs_start + (vector_IRQ - __stubs_start)
 b __real_stubs_start + (vector_FIQ - __stubs_start)
 ......
 ENTRY(__trap_init) /* 此时 r0 = vectors_base() = 0c000000 */
 stmfd sp!, {r4 - r9, lr}
 
 mrs r1, cpsr   @ code from 2.0.38
 bic r1, r1, #MODE_MASK  @ clear mode bits
 orr r1, r1, #I_BIT|F_BIT|MODE_SVC @ set SVC mode, disable IRQ,FIQ
 msr cpsr, r1
 /* 以上代码切换CPU status */
 ......
 adr r1, .LCvectors   @ 安装异常向量表到0c000000
 ldmia r1, {r2, r3, r4, r5, r6, r7, r8, r9}
 stmia r0, {r2, r3, r4, r5, r6, r7, r8, r9}
 ......
 #ifdef CONFIG_CPU_S3C44B0X
 /*
 * Initialize the IRQ-Controller to use non-vectored mode
 * We will use the S3C44B0X_I_ISPR register to determine
 * the current interrupt to be serviced.
 */
 adr r4, .INTCON
 ldr r4, [r4]
 /* non-vectored and enable FIQ/IRQ controlling */
 ldr r3, =0x4
 str r3, [r4]
 /* 以上代码设置44b0x的中断模式控制寄存器,参考44b0x的datasheet。*/
 
 mov r4, r0
 /* 保存 r0 = 0c000000 */
 #ifdef CONFIG_BOARD_SAMPLE44B0X // John modififed
 add r0, r0, #(8*4)  @ R0 = 0x0c000080 (RAM)
 /* 设置vector-mode Interrupt vectors的首地址,原先的代码不适合我们的开发板 */
 #else
 mov  r0, #(0x0080)  @ R0 = 0x0080 (RAM)
 /* 这是原先的代码,指向Flash地址 */
 #endif /* CONFIG_BOARD_SAMPLE44B0X */
 add r1, r1, #(8*4)  @ R1 = start of vectors (ROM)
 add r2, r1, #(32*4)  @ R2 = end of vectors (ROM)
 2:  ldr r3, [r1], #4
 str r3, [r0], #4
 cmp r1, r2
 blt 2b
 /* 以上代码复制vector-mode interrupt vectors到 0c000080,对于44b0x而言没有意义,因为是non-vector 模式 */
 mov r0, r4
 /* 恢复r0 = 0c000000 */
 #endif /* CONFIG_CPU_S3C44B0X */
 add r2, r0, #0x200
 adr r0, __stubs_start  @ copy stubs to 0x200
 adr r1, __stubs_end
 1:  ldr r3, [r0], #4
 str r3, [r2], #4
 cmp r0, r1
 blt 1b
 /*
 * copy __stubs_start ~ __stubs_end之间的代码,到0c000200位置,
 * 这段代码包括除了vectors_swi()之外的所有异常处理函数定义
 */
 LOADREGS(fd, sp!, {r4 - r9, pc}) /* 返回 */
 
 以上是uclinux安装异常处理向量表的过程,也因此,在arch/armnommu/Makefile中,TEXTADDR不能定义为DRAM_BASE(0x0c000000),否则,当uclinux kernel解压到DRAM_BASE处,并且运行到__trap_init()时,会覆盖掉一部分代码。
 
 在uclinux 2.4.24-uc0内核中,也有对MBA44这块开发板的支持,他的思路与上述有些不同,
 首先,它不修改vectors_base()宏,所以vectors_base() = 0。
 其次,在arch/armnommu/kernel/head-armv.S源文件中,在最开始有Exception Vectors,所以MBA44在arch/armnommu/Makefile中定义的
 
 TEXTADDR倒是0x0c000000,它不需要__trap_init(),所以比较好的做法应该是把上面说到的安装.LCvectors,安装__stubs_*的代码都注释起
 
 来,为什么他没有注释,因为它没有设置vectors_base(),所以对Flash的写操作都不成功就是了。这是没什么问题,不过真的没有问题么?
 ENTRY(stext)
 #if defined(CONFIG_CPU_S3C44B0X)
 /*
 * We assume that there is a bootloader that has jump instructions at all
 * exception vectors that lead to their position shifted to the start of
 * RAM. Further on we assume that the following code gets linked to the
 * start of RAM, so that all jumps match again.
 */
 b    99f   /* 0x00 reset vector */
 b vector_undefinstr /* 0x04 undefined instruction  */
 b vector_swi  /* 0x08 software interrupt */
 b vector_prefetch  /* 0x0C prefetch abort */
 b vector_data  /* 0x10 data abort */
 b vector_addrexcptn /* 0x14 address exception */
 b vector_IRQ  /* 0x18 IRQ */
 b vector_FIQ  /* 0x1C FIQ */
 99:
 #endif
 | 
 |