下面是
;函数原型: void__asm_start_thread(struct thread_vm *new_vm);
;-----------------------------------------------------------------------------
__asm_start_threadPROC
EXPORT __asm_start_thread
mov r1,#2
msr control,r1 ;切换到特权线程模式,栈指针用psp
ldr sp,[r0] ;取得新上下文指针
bl int_restore_asyn_signal ;对应done函数开头的 int_save_asyn_signal 调用
svc 0 ;切入新上下文
ENDP
4、切入线程
__asm_turnto_context函数不保存当前线程的上下文,直接把新线程的上下文恢复到cpu中。当一条事件处理完毕,该事件的线程可能被销毁,这种情况下,就无需保存当前线程的上下文,直接切入新线程的上下文即可。__asm_turnto_context函数只做一件事:调用svc0恢复新线程上下文:
;函数原型: void__asm_turnto_context(struct thread_vm *new_vm);
;-----------------------------------------------------------------------------
__asm_turnto_contextPROC
EXPORT __asm_turnto_context
ldr sp,[r0] ;取得新上下文指针
bl int_restore_asyn_signal ;对应done函数开头的 int_save_asyn_signal 调用
svc 0 ;切入新上下文
ENDP
5、复位旧线程,切入新线程
当一条事件处理完成,如果系统调度发现该事件的线程应该予以保留,就调用__asm_reset_switch复位该线程,然后切入新的最高优先级的就绪线程。__asm_reset_switch函数是__asm_reset_thread和__asm_turnto_context的结合体。代码如下:
;函数原型:void__asm_reset_switch(void (*thread_routine)(struct event_script*),
; struct thread_vm *new_vm,struct thread_vm *old_vm);
;-----------------------------------------------------------------------------
__asm_reset_switchPROC
EXPORT __asm_reset_switch
ldr sp,[r2,#4] ;取老虚拟机栈顶指针
mov r12,#0x01000000 ;xpsr的初始值
ldr r11,=__djy_vm_engine ;取虚拟机引擎指针
push {r11,r12} ;存pc,xpsr
sub sp,sp,#14*4 ;后退14个寄存器,初始状态r0-r12中,除r0外均无意义,
;__vm_engine函数不返回,lr也无意义
;至此,完成老虚拟机复位
str r0,[sp,#8*4] ;保存 thread_routine指针.至此,完成老线程重置
str sp,[r2] ;保存当前栈指针到old_vm->stack中
ldr sp,[r1] ;取得新上下文指针
bl int_restore_asyn_signal ;对应done函数开头的 int_save_asyn_signal 调用
svc 0 ;切入新上下文
ENDP
6、中断服务例程中的上下文切换
最后一级异步信号(包括systick,由于djyos forcm3把所有异步信号优先级设为相同,故不会嵌套)返回前,即将返回线程模式时,系统将检查在中断服务例程的执行过程中是否有更高优先级的事件(线程)就绪。如果有,则调用__asm_switch_context_int函数执行上下文切换,该函数完成2个操作:
a、把当前PSP保存在被ISR中断的线程虚拟机的线程控制块中。
b、从高优先级的事件的线程控制块中取出SP,放到PSP寄存器中。
函数代码如下:
;函数原型: void__asm_switch_context_int(struct thread_vm *new_vm,struct thread_vm*old_vm);
;-----------------------------------------------------------------------------
__asm_switch_context_int PROC
EXPORT __asm_switch_context_int
mrs r2,psp ;取被中断线程的psp
str r2,[r1] ;把psp写入虚拟机数据结构中
ldr r2,[r0] ;取待切入线程的psp
msr psp,r2 ;待切入线程的当前栈指针写入psp,中断返回恢复上下文将以此为准
bx lr
ENDP
7、一点小经验
cm3中从异常返回必须用bxlr,不能用mov pc,lr,否则会发生存储器管理fault(取址违例)
读函数名得到奇数地址。
中断压栈的PC是偶数地址。
中断返回时,无论栈中的PC值是奇数还是偶数,都能正确返回。 |