ARM基础学习-SWI异常中断处理
2017-05-07 18:18
281 查看
在ARM处理器中,我们常常使用SWI指令来产生一个软中断。软中断指令SWI指令中包含了一个24位的立即数,这个立即数指示了用户请求的特定的SWI功能,即这个立即数表示的是SWI指令所想要触发中断的中断号。
所以,当SWI指令触发了一次异常后进入异常处理的程序时,异常程序必须要从SWI指令中提取出来中断号,即提出出来SWI指令中低24位的值,从而得到用户请求的特定的SWI功能。
SWI异常处理程序
通常情况下,SWI异常中断处理函数分为两级,第一级的SWI处理函数用于从SWI指令中提取24位的立即数即中断号,通第一级函数通过汇编语言、内嵌汇编来完成。第二级SWI异常中断处理程序实现各个SWI的具体功能,第二级程序可以是汇编程序,也可以是C程序。
第一级SWI异常处理程序通过LR寄存器内容得到SWI指令地址,LR寄存器中保存的是该SWI指令的下一条指令的地址,并从存储器中得到SWI指令编码,从而提取出来24位中断号。下面的例子显示了提取中断向量号的标准过程。
第二级中断处理函数(根据提取的中断向量号,跳转到具体处理函数)却可以使用C语言来完成。因为第一级的中断处理函数已经将中断号提取到寄存器r0中,所以根据AAPCS函数调用规则,可以直接使用BL指令跳转到C语言函数,而且中断向量号作为第一个参数被传递到C函数。
另外,如果需要传递的参数多于1个,那么可以使用堆栈,将堆栈指针作为函数的参数传递给C类型的二级中断处理程序,就可以实现在两级中断之间传递多个参数。
例如:
相应的C函数的入口变为:
在2级中断处理程序,可以通过下面的操作数读取参数,这些参数是在SWI异常中断产生时各寄存器的值,这些寄存器保存在SWI异常中断的数据栈中:
SWI异常中断调用
(1) 在特权模式下调用SWI
比如在中断模式下调用SWI,系统此时已经属于特权模式,这是在调用SWI会破坏SPSR_svc和寄存器LR_svc,所以在调用SWI前保存SPSR_svc和寄存器LR_svc在数据栈中:
(2)应用程序中调用SWI
最简单的是用汇编:
MOV r0,#100;
SWI 0x0;
C语言调用SWI比较复杂,因为这时需要将一个C程序的子程序调用映射到一个SWI异常中断程序,这些被映射的C语言子程序使用编译器伪操作_SWI来声明,如果该子程序需要的参数和返回结果只使用R0~R3寄存器,则该SWI可以编译成inline,不需要使用子程序调用过程,否则编译器需要用数据结构来返回参数,这时需要用伪操作_value_in_reg声明该C语言程序;
需要安装异常中断处理程序到向量表中相对位置;
详细参考ARM体系结构与编程P-272;
所以,当SWI指令触发了一次异常后进入异常处理的程序时,异常程序必须要从SWI指令中提取出来中断号,即提出出来SWI指令中低24位的值,从而得到用户请求的特定的SWI功能。
SWI异常处理程序
通常情况下,SWI异常中断处理函数分为两级,第一级的SWI处理函数用于从SWI指令中提取24位的立即数即中断号,通第一级函数通过汇编语言、内嵌汇编来完成。第二级SWI异常中断处理程序实现各个SWI的具体功能,第二级程序可以是汇编程序,也可以是C程序。
第一级SWI异常处理程序通过LR寄存器内容得到SWI指令地址,LR寄存器中保存的是该SWI指令的下一条指令的地址,并从存储器中得到SWI指令编码,从而提取出来24位中断号。下面的例子显示了提取中断向量号的标准过程。
.SWI_Handler: STMFD sp!,{r0-r12,lr} ;保存寄存器 LDR r0,[lr,#-4] ;计算SWI指令地址 BIC r0,r0,#0xff000000 ;提取指令编码的后24位 ; ; 提取出的中断号放r0寄存器,函数返回 ; LDMFD sp!, {r0-r12,pc}^ ;恢复寄存器
第二级中断处理函数(根据提取的中断向量号,跳转到具体处理函数)却可以使用C语言来完成。因为第一级的中断处理函数已经将中断号提取到寄存器r0中,所以根据AAPCS函数调用规则,可以直接使用BL指令跳转到C语言函数,而且中断向量号作为第一个参数被传递到C函数。
void C_SWI_handler (unsigned number) { switch (number) { case 0 : /* SWI number 0 code */ break; case 1 : /* SWI number 1 code */ break; ... default : /* Unknown SWI - report error */ } }
另外,如果需要传递的参数多于1个,那么可以使用堆栈,将堆栈指针作为函数的参数传递给C类型的二级中断处理程序,就可以实现在两级中断之间传递多个参数。
例如:
MOV r1, sp ;将传递的第二个参数(堆栈指针)放到r1中 BL C_SWI_Handler ;调用C函数
相应的C函数的入口变为:
void C_SWI_handler(unsigned number, unsigned *reg)
在2级中断处理程序,可以通过下面的操作数读取参数,这些参数是在SWI异常中断产生时各寄存器的值,这些寄存器保存在SWI异常中断的数据栈中:
value_in_reg_0 =reg [0]; value_in_reg_1 =reg [1]; value_in_reg_2 =reg [2]; value_in_reg_3= reg [3];
SWI异常中断调用
(1) 在特权模式下调用SWI
比如在中断模式下调用SWI,系统此时已经属于特权模式,这是在调用SWI会破坏SPSR_svc和寄存器LR_svc,所以在调用SWI前保存SPSR_svc和寄存器LR_svc在数据栈中:
STMFD sp!,{r0-r3,r12,lr} MOV r1,sp; MRS r0,spsr; STMFD sp!,[r0]; ... SWI ... LDMFD sp!,{r0}; MSR spsr_cf,r0; LDMFD sp!, {r0-r3,r12,pc}^ ;
(2)应用程序中调用SWI
最简单的是用汇编:
MOV r0,#100;
SWI 0x0;
C语言调用SWI比较复杂,因为这时需要将一个C程序的子程序调用映射到一个SWI异常中断程序,这些被映射的C语言子程序使用编译器伪操作_SWI来声明,如果该子程序需要的参数和返回结果只使用R0~R3寄存器,则该SWI可以编译成inline,不需要使用子程序调用过程,否则编译器需要用数据结构来返回参数,这时需要用伪操作_value_in_reg声明该C语言程序;
需要安装异常中断处理程序到向量表中相对位置;
详细参考ARM体系结构与编程P-272;
相关文章推荐
- ARM基础学习-异常中断处理
- ARM的SWI异常中断处理程序设计
- ARM中断学习一/[友善2440test中的中断处理部分]
- ARM中断学习一/[友善2440test中的中断处理部分]
- 【ARM】arm异常中断处理知识点
- ogre3D学习基础11 -- 日志文件的使用与异常处理
- 【ARM】arm异常中断处理知识点
- Arm异常中断返回时的处理
- 异常处理与调试 - 零基础入门学习Delphi50
- ARM中断异常处理的返回
- 异常处理与调试 - 零基础入门学习Delphi50
- ARM中断异常处理的返回
- 学习笔记之C#类、循环中的语句、基础知识和异常处理
- arm异常中断处理中pc指向何处
- ARM基础知识教程(三):ARM中异常中断的种类
- ARM中断异常处理的返回
- ARM中断学习一/[友善2440test中的中断处理部分]
- 函数指针数组在ARM异常中断处理中的应用
- 【ARM】arm异常中断处理知识点
- ARM基础:系统调用与软件中断SWI的实现