免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1650 | 回复: 0
打印 上一主题 下一主题

entry-armv.S的分析 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-04-14 11:35 |只看该作者 |倒序浏览

      这里分析异常向量的处理:
在这个文件的最后一部分,是关于异常向量的处理代码,是很重要的。
基本的思路就是,对于有MMU的系统,异常向量的虚拟地址被映射到0xFFFF0000,
所以,真正的7个异常向量(__vectors_start~__vectors_end)是被拷贝到
这个0xFFFF0000开始的地方了。接着,异常处理代码块(__stubs_start~__stubs_end)
被拷贝到0xFFFF0200处。异常向量表的写法主要使用跳转指令B来进行,因为异常
向量表和异常处理代码块之间没有超过B指令要求的2^24=32MB,仅仅相差0x200。但是因为
vertor_swi不是在这个文件中定义的,所以,只能用LDR指令来进行处理了。实际上完成
上述拷贝动作是在start_kernel()[init/main.c]中调用trap_init()[arch/arm/kernel/traps.c]
来完成的。
void __init trap_init(void)
{
    unsigned long vectors = CONFIG_VECTORS_BASE;
    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);
}
这里我们关注两个很有特色的的方:
其一,使用宏vector_stub来定义异常处理块,显得简洁明了。每种异常一进入,就需要根据
异常模式下的LR寄存器来获得发生异常时的PC,以及通过异常模式的SPSR来获得发生异常时的
CPSR;并且需要把这两个寄存器连同R0一道保存到异常模式下的SP所指向的堆栈区域中。保存
R0的原因就在于,R0会在后面保存发生异常的时的堆栈指针SP,并在进一步调用异常处理函数时被当
作参数。
其二,我们看到,只有irq,dabt,pabt,und等4个模式用了vector_stub,其他的还是按照自己的
写法进行。其中对于fiq,直接disable fiq并返回异常之前的模式地址;addrexcptn当死循环处理;
swi实际上是ARM Linux实现系统调用的;我们可以看到,异常向量表的reset异常就直接用了swi来进行
系统调用,并且调用号是SYS_ERROR0;这是对系统运行过程中发生reset异常时的处理方式,
和上电reset时bootloader进行的reset 异常处理是不一样的。
/*
* Vector stubs.
*
* This code is copied to 0xffff0200 so we can use branches in the
* vectors, rather than ldr's.  Note that this code must not
* exceed 0x300 bytes.
*
* Common stub entry macro:
*   Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
*
* SP points to a minimal amount of processor-private memory, the address
* of which is copied into r0 for the mode specific abort handler.
*/
    .macro    vector_stub, name, mode, correction=0
    .align    5
vector_\name:
    .if \correction
    sub    lr, lr, #\correction
    .endif
    @
    @ Save r0, lr_ (parent PC) and spsr_
    @ (parent CPSR)
    @
    stmia    sp, {r0, lr}        @ save r0, lr
    mrs    lr, spsr @LR实际上保存了发生异常时的CPSR,后面与0xF相与,实际上就是发生异常
                        @时的异常模式的编号,其值为0x0~0xF,但是只有0x0(user mode)和
                        @0x3(SVC mode)是可能的,其他的都是当作无效处理。
    str    lr, [sp, #8]        @ save spsr
    @
    @ Prepare for SVC32 mode.  IRQs remain disabled.
    @
    mrs    r0, cpsr
    eor    r0, r0, #(\mode ^ SVC_MODE)@强制进入SVC模式
    msr    spsr_cxsf, r0
    @
    @ the branch table must immediately follow this code
    @
    and    lr, lr, #0x0f
    mov    r0, sp
    ldr    lr, [pc, lr, lsl #2]@这里LR就是前面所说的发生异常时处理器模式的编号,
                                    @以PC作为基地址,编号作为索引,将此后的内存区域(数组)
                                     @中的相应异常的处理函数的地址加载到LR中,并通过下面的
                                    @指令实现了跳转;所以,紧接vector_stub宏后面应该是一个
                                    @处理函数的地址数组。
    movs    pc, lr            @ branch to handler in SVC mode
    .endm
    .globl    __stubs_start
__stubs_start:
/*
* Interrupt dispatcher
*/
    vector_stub    irq, IRQ_MODE, 4
    .long    __irq_usr            @  0  (USR_26 / USR_32)
    .long    __irq_invalid            @  1  (FIQ_26 / FIQ_32)
    .long    __irq_invalid            @  2  (IRQ_26 / IRQ_32)
    .long    __irq_svc            @  3  (SVC_26 / SVC_32)
    .long    __irq_invalid            @  4
    .long    __irq_invalid            @  5
    .long    __irq_invalid            @  6
    .long    __irq_invalid            @  7
    .long    __irq_invalid            @  8
    .long    __irq_invalid            @  9
    .long    __irq_invalid            @  a
    .long    __irq_invalid            @  b
    .long    __irq_invalid            @  c
    .long    __irq_invalid            @  d
    .long    __irq_invalid            @  e
    .long    __irq_invalid            @  f
/*
* Data abort dispatcher
* Enter in ABT mode, spsr = USR CPSR, lr = USR PC
*/
    vector_stub    dabt, ABT_MODE, 8
    .long    __dabt_usr            @  0  (USR_26 / USR_32)
    .long    __dabt_invalid            @  1  (FIQ_26 / FIQ_32)
    .long    __dabt_invalid            @  2  (IRQ_26 / IRQ_32)
    .long    __dabt_svc            @  3  (SVC_26 / SVC_32)
    .long    __dabt_invalid            @  4
    .long    __dabt_invalid            @  5
    .long    __dabt_invalid            @  6
    .long    __dabt_invalid            @  7
    .long    __dabt_invalid            @  8
    .long    __dabt_invalid            @  9
    .long    __dabt_invalid            @  a
    .long    __dabt_invalid            @  b
    .long    __dabt_invalid            @  c
    .long    __dabt_invalid            @  d
    .long    __dabt_invalid            @  e
    .long    __dabt_invalid            @  f
/*
* Prefetch abort dispatcher
* Enter in ABT mode, spsr = USR CPSR, lr = USR PC
*/
    vector_stub    pabt, ABT_MODE, 4
    .long    __pabt_usr            @  0 (USR_26 / USR_32)
    .long    __pabt_invalid            @  1 (FIQ_26 / FIQ_32)
    .long    __pabt_invalid            @  2 (IRQ_26 / IRQ_32)
    .long    __pabt_svc            @  3 (SVC_26 / SVC_32)
    .long    __pabt_invalid            @  4
    .long    __pabt_invalid            @  5
    .long    __pabt_invalid            @  6
    .long    __pabt_invalid            @  7
    .long    __pabt_invalid            @  8
    .long    __pabt_invalid            @  9
    .long    __pabt_invalid            @  a
    .long    __pabt_invalid            @  b
    .long    __pabt_invalid            @  c
    .long    __pabt_invalid            @  d
    .long    __pabt_invalid            @  e
    .long    __pabt_invalid            @  f
/*
* Undef instr entry dispatcher
* Enter in UND mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
*/
    vector_stub    und, UND_MODE
    .long    __und_usr            @  0 (USR_26 / USR_32)
    .long    __und_invalid            @  1 (FIQ_26 / FIQ_32)
    .long    __und_invalid            @  2 (IRQ_26 / IRQ_32)
    .long    __und_svc            @  3 (SVC_26 / SVC_32)
    .long    __und_invalid            @  4
    .long    __und_invalid            @  5
    .long    __und_invalid            @  6
    .long    __und_invalid            @  7
    .long    __und_invalid            @  8
    .long    __und_invalid            @  9
    .long    __und_invalid            @  a
    .long    __und_invalid            @  b
    .long    __und_invalid            @  c
    .long    __und_invalid            @  d
    .long    __und_invalid            @  e
    .long    __und_invalid            @  f
    .align    5
/*=============================================================================
* Undefined FIQs
*-----------------------------------------------------------------------------
* Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
* MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
* Basically to switch modes, we *HAVE* to clobber one register...  brain
* damage alert!  I don't think that we can execute any code in here in any
* other mode than FIQ...  Ok you can switch to another mode, but you can't
* get out of that mode without clobbering one register.
*/
vector_fiq:
    disable_fiq
    subs    pc, lr, #4
/*=============================================================================
* Address exception handler
*-----------------------------------------------------------------------------
* These aren't too critical.
* (they're not supposed to happen, and won't happen in 32-bit data mode).
*/
vector_addrexcptn:
    b    vector_addrexcptn
/*
* We group all the following data together to optimise
* for CPUs with separate I & D caches.
*/
    .align    5
.LCvswi:
    .word    vector_swi
    .globl    __stubs_end
__stubs_end:
    .equ    stubs_offset, __vectors_start + 0x200 - __stubs_start
    .globl    __vectors_start
__vectors_start:
    swi    SYS_ERROR0
    b    vector_und + stubs_offset
    ldr    pc, .LCvswi + stubs_offset
    b    vector_pabt + stubs_offset
    b    vector_dabt + stubs_offset
    b    vector_addrexcptn + stubs_offset
    b    vector_irq + stubs_offset
    b    vector_fiq + stubs_offset
    .globl    __vectors_end
__vectors_end:
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/66439/showart_530484.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP