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