nbsp; undefexception sub lr, lr, #4 ; (lr) = address of undefined instruction stmdb sp, {r0-r3, lr} mov r1, #id_undef_instr b commonhandler entry_end undefexception 上面就是undef exception的服务程序的入口处(已经将不参与编译和thumb模式下的代码去掉),通过lr-=4计算出触发异常前的指令地址,同时保存r0-r3和lr入undef_exception stack用于最后恢复现场和取得异常指令本身,随后进入分发程序commonhandler.commonhandler是一个公共的异常服务程序,它通过不同的传入参数来进行处理,在这里mov r1,#id_undef_instr就是指定异常模式为undef exception. 2-2.swi服务程序 按在arm处理器的设计意图,系统软件的系统调用(systemcalls)都是通过swi指令完成。swi相当于一个中断指令,不同的是swi不是由外部中断源产生的,同时对应于swi的异常向量位于0xc的位置或0xffff 000c的位置。也就是说当执行一个swi指令后,当前程序流中断,并转入0xc或0xffff000c执行,同时将cpsr_mode(当前程序状态寄存器)复制入spsr_svc,转入svc模式运行(使用特权模式的寄存器组)。也就是说系统通过执行swi引发系统swi异常后切换入特权模式,系统调用功能号由swi xx后的xx决定,在运行完指定功能的代码后返回异常时的地址并恢复用户模式。我们看看,wince中这部分代码是如何实现的。 dcd swihandler ; svc<<--------------------------swi入口点。 leaf_entry swihandler if ... endif movs pc, lr entry_end swihandler 上面if 到endif之间的代码在编译的时候是得不到编译的(事实上这部分代码是用于开发中调试使用的,针对特殊的硬件平台,一般与我们使用的硬件平台无关。所以下面摘抄的代码都不将不参与编译的内容写入),因此swi服务程序就是一句话。movs pc, lr也就是直接回到swi的地方,同时将spsr_svc恢复到cpsr_mode中。这个过程中并没有进行在系统态执行特定系统指令序的工作,而仅仅是简单的返回,所以这不是系统调用,系统调用还需要根据调用号的不同运行指定的核心态代码。也就是说wince的系统调用不是通过swi来完成的,而是通过其他的异常处理手段达成的。 2-3 中断服务程序
irq(大概是最熟悉的异常方式了)在外部中断源在需要向处理器请求服务时发生,比如:时钟、外围器件fifo上/下溢出、按键等等。irqhandler就是中断的处理句柄,下面我们来具体看看。 ---------------------------------------------------------------------------------- nested_entry irqhandler sub lr, lr, #4 ; fix return address stmfd sp!, {r0-r3, r12, lr} ;保存将要用到的寄存器和lr压入stack_irq prolog_end 和上面一样,服务程序的入口处都是例行公事的计算返回位置以抵消流水线误差。再将要用到的寄存器压入stack_irq,这样,准备工作就做完了。 ; test interlocked api status. ;interlocked_start equ user_kpage+0x380 ;interlocked_end equ user_kpage+0x400 sub r0, lr, #interlocked_start cmp r0, #interlocked_end-interlocked_start bllo checkinterlockedrestart 上面这部分的内容是关于互锁的检测,由于如信号量这些同步手段都必须作为原子操作进行,不允许打断。所以如果中断发生在互锁api的执行过程中,就需要专门的处理了。这些api都是放在interlocked_start和interlocked_end之间的,通过lr很容易就检查出是否是interlockedxxx的过程中。这里并不关心互锁的实现就绕开这部分代码继续往下看,当作中断没有发生在interlock过程处理。 ; ; careful! the stack frame is being altered here. it"s ok since ; the only routine relying on this was the interlock check. note that ; we re-push lr onto the stack so that the incoming argument area to ; oeminterrupthandler will be correct. ; mrs r1, spsr ; (r1) = saved status reg stmfd sp!, ; save spsr onto the irq stack mov r0,lr & |