uc/OS II移植中软件中断的理解与应用
1. 软件中断SWI
SWI(software interrupt)软件中断,由用户定义的中断指令.可以用于用户模式下的程序调用特权操作指令.在实时操作系统中可以通过该机制实现系统调用.
一个 SWI 所做的一切就是把模式改变成超级用户并设置 PC 来执行在地址 &08 处的下一个指令!
编程异常通常叫做软中断.软中断是通讯进程之间用来模拟硬中断的一种信号通讯方式。中断源发中断请求或软中断信号后,CPU或接收进程在适当的时机自动进行中断处理或完成软中断信号对应的功能.
软中断是软件实现的中断,也就是程序运行时其他程序对它的中断;而硬中断是硬件实现的中断,是程序运行时设备对它的中断。
1.软中断发生的时间是由程序控制的,而硬中断发生的时间是随机的
2.软中断是由程序调用发生的,而硬中断是由外设引发的
3.硬件中断处理程序要确保它能快速地完成它的任务,这样程序执行时才不会等待较长时间
2. 软件中断使用的始末
2.1 SWI指令
SWI{cond} immed_24
其中,immed_24位24位立即数
2.2 ADS编译器中软中断的规定
ADS编译器规定,用户可使用关键字__swi作为前缀来声明一个利用软中断的调用,其格式如下:
__swi(功能号) 返回值类型名称(参数列表);
其中关键字__swi后面的括号中的字段叫做软中断的功能编号。系统是根据这个编号在软中断服务程序户中来确定应执行的程序段的。用户可以在用户程序中像调用一个普通函数那样实现软中断的调用。只是该“函数”没有普通函数那样明显的函数实现体。至于软件中断具体的函数实体后面会讲到。
利用软中断服务程序可以规避由于ARM处在不同工作模式时所造成的访问限制(如资源的访问限制)。
2.3 在Uc/OS-II中软中断来实现的函数的声明
函数注册软中断号
__swi(0x00) void OS_TASK_SW(void); /* 任务级任务切换函数 */
__swi(0x01) void __OSStartHighRdy(void); /* 运行优先级最高的任务 */
__swi(0x02) void OS_ENTER_CRITICAL(void); /* 关中断 */
__swi(0x03) void OS_EXIT_CRITICAL(void); /* 开中断 */
__swi(0x40) void *GetOSFunctionAddr(int Index); /* 获取系统服务函数入口 */
__swi(0x41) void *GetUsrFunctionAddr(int Index); /* 获取自定义服务函数入口 */
__swi(0x42) void OSISRBegin(void); /* 中断开始处理 */
__swi(0x43) int OSISRNeedSwap(void); /* 判断中断是否需要切换 */
__swi(0x80) void ChangeToSYSMode(void); /* 任务切换到系统模式 */
__swi(0x81) void ChangeToUSRMode(void); /* 任务切换到用户模式 */
__swi(0x82) void TaskIsARM(INT8U prio); /* 任务代码是ARM代码 */
__swi(0x83) void TaskIsTHUMB(INT8U prio); /* 任务代码是THUMB */
这些函数不是通常意义上的函数,只是可以让用户在应用程序中使用这些“函数名”去引发一个携带功能号的软中断SWI,即ADS编译器在编译这些函数时,把他们编译成SWI指令的二进制代码。
注:软中断功能号为0x00、0x01的函数使用汇编语言写的,而其他的函数是用c语言写的。具体代码见下面。
注:遵照ATPCS函数调用标准,一个SWI调用允许带1~4个字型参数和1~4个字型返回值,触发SWI调用时四个参数依次保存在R0~R3中,返回值也存于R0~R3内。所以在软中断服务程序中应函数所需要的参数按顺序保存到R0~R3中。
2.4 软中断具体实现始末
以两个具体的函数调用来说明软中断具体的实现。一个是任务级切换函数void OS_TASK_SW(void),一个是任务模式切换函数void ChangeToSYSMode(void).
2.4.1. 从启动代码中开始
硬件平台为ARM7内核。当有软中断发生(即调用2.2中某一个函数时)时,系统首先自动调转到0x0008处执行。
1、第一级中断向量
AREA Init,CODE,READONLY
ENTRY
b ResetHandler ;for debug
b HandlerUndef ;handlerUndef
b HandlerSWI ;SWI interrupt handler
b HandlerPabort ;handlerPAbort
b HandlerDabort ;handlerDAbort
b . ;handlerReserved
b HandlerIRQ
b HandlerFIQ
2、宏展开
继续找HandlerSWI。
HandlerSWI HANDLER HandleSWI
3、内存第二级中断向量
再找HandleSWI。
^ _ISR_STARTADDRESS
HandleReset # 4
HandleUndef # 4
HandleSWI # 4
HandlePabort # 4
HandleDabort # 4
HandleReserved # 4
HandleIRQ # 4
HandleFIQ # 4
现在我们知道软中断的服务程序跑到了内存中去了,我们可以编写相应的代码来实现不同功能号下的不同功能。
2.4.2. 在文件OS_CPU_A.S中编写软中断服务程序
1、软中断服务代码。
HandleSWI
LDR sp, StackSvc;
STMFD sp!, {r0-r3, r12, lr};// STMDB,保护现场
MOV r1, sp ;// 若SWI调用带参,将R1指向第二个参数
;// 遵照ATPCS标准,第一个参数存于R0中
MRS r3, spsr
TST r3, #0x20 ;//检查时ARM还是THUMB指令
STMFD sp!, {r0} ;// spsr入栈
LDRNEH r0, [lr,# -2] ;// THUMB指令时执行,获取SWI指令码
BICNE r0, r0, #0xFF00 ;// 获取SWI number
;// r0 now contains SWI number
;// r1 now contains pointer to stacked registers
LDREQ r0, r0, #0xFF000000;//ro中存放着软中断的功能号
CMP r0, #1;
LDRLO pc, =OSIntCtxSw ;//LDRLO=LDRCC r0=0时跳转到汇编语言处理
LDREQ pc, =__OSStartHighRdy ;//r0=1时跳转到汇编语言处理
BL SWI_Exception ;// r0>1时跳转,调用C编写的SWI处理函数
LDMFD sp!, {r0-r3, r12, pc}^ ;// 恢复现场
我们可以看出当调用2.2中某一个函数并且函数具有两个参数时,函数的第一个参数存放在r0中,第二个参数存放在r1中。
2、OSIntCtxSw的实现
OSIntCtxSw
LDR R2, [SP,#20]
…//具体代码间参考文献[1]P218
3、__OSStartHighRdy的实现
//具体代码间参考文献[1]P219
2.4.3. 在文件OS_CPU_C.C中编写软中断服务程序
为了使uC/OS-II的一些底层系统函数在调用时与处理器工作模式无关,所以在移植时采用软中断来实现.除了功能号01、02的软中断函数是用汇编语言,其他的软中断函数都是用C语言编写的.
void SWI_Exception( int SWI_Num,//软中断功能号
int *Regs //为指向堆栈中保存寄存器的值的指针
)
{
OS_TCB *ptch;
Switch(SWI_Num)// 具体代码间参考文献[1]P214
{
case 0x02://宏OS_ENTER_CRITICAL()的代码
case 0x03://宏OS_EXIT_CRITICAL()的代码
case 0x80://宏ChangeToSYSMode ()的代码
case 0x81://宏ChangeToUSRMode ()的代码
case 0x82://宏TaskIsARM ()的代码
case 0x83://宏TaskIsTHUMB ()的代码
default:break;
}
}
3. 参考文献
[1] 任哲.嵌入式实时操作系统uc/OS-II原来及应用.北京:北京航空航天大学出版社,2005.8
[2] Labrosse Jean J. 嵌入式实时操作系统uc/OS-II(第二版). 邵贝贝等译. 北京: 北京航空航天大学出版社,2003
[3] http://blog.csdn.net/zhhg_1220/archive/ 2006/12/21 /1451199.aspx