SPARC结构与实时内核的移植

时间:2012-05-17来源:网络

中断堆栈

由于编译器不能在编译之初就给外部中断分配一个堆栈帧,所以需要根据常规的堆栈帧模拟一个执行中断服务程序的栈结构。由于中断存在嵌套,即在中断过程中发生更高优先级中断,并且在运行中断服务子程序的时候有可能改变被中断线程的寄存器值,所以在中断服务子程序中有必要进行“保护现场”和“恢复现场”。这样统一考虑,可以将中断的栈结构设计成图2所示的结构。其中,除了常规栈结构以外还包括具有控制信息的几个寄存器%psr,%pc,%npc, %y,%tbr。和被中断线程的另外两组寄存器,global寄存器和inputs寄存器。因为当进入中断服务子程序时,CWP已经减小了1,所以此时的inputs寄存器应该是被中断线程的outputs寄存器。%g0寄存器的值永远为0,所以就不再保存。同时这样的结构能尽量使每组寄存器的第0个寄存器,如%i0,%l0,%g2,%o0的偏移量为8的倍数,可以使用双字操作来优化寄存器保存与恢复的时间。

3.任务切换功能实现

对于一个支持多任务的实时内核,在实现移植时,最基本的任务就是用CPU支持的汇编语言实现任务切换的功能,在uC/OS中就是实现OSCtxSw( )的功能。

任务堆栈初始化

一般内核在创建新任务时都将初始化一个新的任务堆栈,其包含有该任务的入口地址信息,即在任务切换函数中需要设置的PC值。设置当前的堆栈指针(SP),当前堆栈帧指针(FP),处理器状态寄存器(PSR)中与寄存器窗口相关的值等。

任务堆栈的设计可以同中断堆栈的结构相同。由于任务切换更接近于子线程的调用,所以在进行上下文切换时只需保存PSR的值和当前窗口对应的32个寄存器的值即可。任务堆栈相对中断堆栈结构更简单。

当前任务的SP,FP保存在%sp(%o6)和%fp(%i6)中,并且SPARC支持对%sp和%fp的读写操作,可以将当前的%sp值读出由 WR指令写入%i6,再将(%sp-0x148)的值写入%o6,这样通过分配一个大小为148H的堆栈帧完成新任务堆栈指针的初始化。

任务级切换

uC/OS中任务切换函数是由软中断(TA指令)来实现的。SPARC不支持对PC的直接操作,但在发生软中断时,CPU会自动将当前PC,NPC 的值写入到%l1,%l2寄存器。而在中断结束返回时,CPU再自动将%l1,%l2的值写入PC,NPC。根据CPU这一操作,可以将任务的入口地址以及入口地址的下一个地址分别写入%l1,%l2。这样在中断返回后的下一条指令就是要切换任务的入口地址,从而实现了任务切换。

uC/OS中的两个变量OSTCBCur和OSTCBHighRdy 分别指向当前任务和新任务的任务控制块,查考其数据结构可以发现它们实际上是两个分别为指向当前任务和新任务的任务堆栈的指针。在实现任务级切换时,由于当前任务已经执行完毕,没有保存当前环境变量的必要,所以切换函数主要任务是更新OSTCBCur的值为OSTCBHighRdy,并将更新后的 OSTCBCur所指向的任务堆栈,即在上一节中初始化好的任务堆栈中的值写入对应的寄存器,这一操作好比“恢复现场”。

在切换函数执行完,中断返回时执行语句“JMP %l1;RETT %l2”将新任务的入口地址写入到CPU的PC和NPC,完成任务级切换。

中断级切换

如果内核为可抢占实时内核,任务调度(通常在中断中被调用)将高优先级的任务置为有效时,需要在当前中断中完成任务的切换,使高优先级任务尽快得到CPU使用权,并在该高优先级任务执行完,且没有其它高优先任务被响应时,继续执行之前被中断的任务。

中断级切换函数必须对被中断的任务进行“现场保护”,因为每个中断函数都有“保护现场”功能,所以这一操作不难实现。此外,中断级切换函数还需要为新任务分配一组新的寄存器窗口,即保存当前所有Used态的窗口寄存器的值到堆栈对应的帧中。可以称之为Windows_flush,这也是寄存器窗口相关的操作。最简单的flush就是在%WIM中将当前窗口置为无效窗口,通过SAVE语句将当前窗口对应的inputs和locals寄存器的值写入堆栈。通过循环控制,可以将8个寄存器窗口的值全部保存,并且SAVE指令通过将%o6的值写入%i6,能自动实现栈帧的切换。在执行 Windows_flush后,当前任务以及其中调用的各线程的堆栈帧才全部被填充,成为一个连续堆栈,这样才做好了到更高优先级切换的准备。中断级任务切换的流程图如图3。

1 2 3

关键词: 寄存器窗口 SPARC 任务切换 中断

加入微信
获取电子行业最新资讯
搜索微信公众号:EEPW

或用微信扫描左侧二维码

相关文章

查看电脑版