; (r2) = pending interrupt event mask mov r1, #1 orr r2, r2, r1, lsl r0 ; (r2) = new pending mask str r2, [lr, #pendevents] ; save it ;*pendevents = *pendevents|(1<<interruptno); ; ; mark reschedule needed ;情况1:r0=sysintr_resched=1 ;情况2: r0 =r0-sysintr_devices>=sysintr_max_devices 10 ldrb r0, [lr, #bresched] ; (r0) = reschedule flag orr r0, r0, #1 ; set "reschedule needed bit" strb r0, [lr, #bresched] ; up-date flag 20 mrs r1, spsr ; (r1) = saved status register value and r1, r1, #0x1f ; (r1) = interrupted mode cmp r1, #user_mode ; previously in user mode? cmpne r1, #system_mode ; if not, was it system mode? cmpeq r0, #1 ; user or system: is resched == 1 ;if(sytemmode(spsr)||usermode(spsr))&&r0!=1) return; ldmnefd sp!, {r0-r3, r12, pc}^ ; can"t reschedule right now so return ************************************************************************************* sub lr, lr, #4 ldmfd sp!, {r0-r3, r12} stmdb lr, ldmfd sp!, str r0, [lr] ; save resume address mov r1, #id_reschedule ; (r1) = exception id b commonhandler entry_end irqhandler 将spsr_irq压入irq堆栈保存。为调用oeminterrupthandler作准备。(通常中断处理程序切换入系统态执行的目的在于避免使用终端模式下的寄存器,以方便是实现终端套嵌,这儿切入系统态时终端使能是关闭的,对于模态切换的原因我很迷惑。)oeminterrupt需要在特权模式下执行,所以这里增加了切换入特权(svc)模式的内容。紧接着将要用与传递参数的寄存器保存。设定传入参数,r0就可以开始调用oeminterrupthandler了,这里的调用规则遵循windowsce的规范而不是atpcs的规范。具体过程参考arm parameter passing@msdn。下面是函数原形。int oeminterrupthandler(unsigned int ra);这里传入的参数就是上面的r0,事实上r0代表的参数ra并没有实质的作用在这里仅仅是形式上的实现一下而已,不过在这儿可以看到这个传入的ra实际上就是被中断的地址,如果需要知道被中断的位置可以通过ra来查询,而msdn里面说这个参数是保留的。返回的参数也是保存在r0中。其中返回值是系统中断类型。其中sysintr_resched为系统时钟中断,每次时间片用完,该时钟便产生中断,并设置kdata结构的bresched位,进入调度流程。如果中断类型是系统设备中断,那就设置pendevents,待再次调度的时候处理中断。所以oeminterrupthandler必须提前就要对中断进行响应对该中断源设置mask,防止在这过程中同一中断不停发生,导致中断饱和影响程序流的执行,直道中断处理真正完成后再次开放该中断的mask。在这里还可以看到的是系统设备中断号的范围是从sysintr_devices到sysintr_max_devices,也就是从9-40一共32个设备中断号,其中sysintr_firmware为8+16号,这个在编写oal的中断服务程序时需要注意。如果当前的返回值既不是设备中断号又不是调度中断号,则读出当前调度标示,根据该标示进行判断是否调度/或返回.如果是进入调度流程则恢复初始的寄存器状态,再按commonhandler的要求保存寄存 |