【ARM裸板】软件中断分析及示例

示例代码下载

1.APP如何切换模式

  • APP一般运行于User Mode下,受到限制(例如不可访问硬件)
  • 如果APP想要访问硬件,必须切换模式
  • 如何切换?发生异常即可
    • 软中断,swi #val
    • 中断
    • 未定义指令异常

2.SWI中软处理过程

  • 执行异常处理函数之前,硬件会处理的事情:
  • 1.lr_svc保存有被中断模式中的下一条即将执行的指令的地址
  • 2.SPSR_svc保存被中断模式CPSR
  • 3.CPSR的[M4:M0]=[11011],进入到svc模式
  • 4.跳到0x08的模式执行程序,即跳到b do_svc这一指令
/*====================================异常向量表===========================================*/
_start:
	b reset   		 //vector 0: reset(0地址对应reset)
 	ldr pc, und_addr //vector 4: und  (发生未定义指令异常,则进入“处理未定义异常函数”)绝对跳转,跳转至sdram中
 	ldr pc, swi_addr //vector 8: swi

und_addr:
	.word do_und //存放地址,确保这一地址存放在内存的前4K中

swi_addr:
	.word do_swi

 /*=================================处理软中断异常=========================================*/
 do_swi:

	/*执行到这里之前:
	 *1.lr_svc保存有被中断模式中的下一条即将执行的指令的地址
	 *2.SPSR_svc保存被中断模式CPSR
	 *3.CPSR的[M4:M0]=[10011],进入到svc模式
	 *4.跳到0x08的模式执行程序,即跳到`b do_swi`这一指令
	 */
    /* 1.sp_svc 设置栈,因为后面函数需要栈 */
    ldr sp, =0x33E00000

    /* 2.保存现场 */
    /* lr是异常处理完后的返回地址,也需要保存 */
    stmdb sp!, {r0-r12,lr} //在swi异常处理函数总有可能需要用到r0~r12,因此先保存下来

    mov r4,lr //将lr存放在r4中,调用c函数不会破坏r4
    /* 3.处理swi异常 */
    mrs r0,cpsr //把cpsr的值放入r0
    ldr r1, =swi_string
    bl printException

    sub r0,r4,#4
    bl printSWIVal

    /* 4.恢复现场 */
    ldmia sp,{r0-r12,pc}^ //将lr的值赋给pc ,`^`会把spsr的值恢复到cpsr中

swi_string:
	.string "swi exception"
.align 4  //确保4字节对齐

2.1设置栈

  • sp_svc 设置栈,因为后面有函数需要用到栈
ldr sp, =0x33E00000

2.2 保存现场

  • stmdb:stm(m为many),即写多个内存,db预先减少(Decrement Before),即先减后写
  • r是异常处理完后的返回地址,也需要保存
stmdb sp!, {r0-r12,lr}` //在swi异常处理函数总有可能需要用到r0~r12,因此先保存下来

2.3 处理swi异常

  • 打印提示发生未定义异常,并调用打印函数显示CPSR的值
mrs r0,cpsr //把cpsr的值放入r0

、预先增加(Increment Before)、过后减少(Decrement After)、。

2.4 恢复现场

  • ldmia:ldm(m为many)即读多个内存,ia(Increment After)过后增加,即先读后加
  • 将lr的值赋给pc ,^会把spsr的值恢复到cpsr中
ldmia sp,{r0-r12,pc}^ 

3.取出SWI指令中的值

  • 在swi异常处理函数中,先将lr的值保存在r4中,因为执行完swi指令后,发生异常,lr会保存下一条指令的地址,因此lr-4即是swi指令的地址
  • 用r0 = r4-4
  • 传给打印函数
    sub r0,r4,#4
    bl printSWIVal
  • 由下表可知,swi中断指令高8位可以忽略,即取后24位即可
void printSWIVal(unsigned int *pSWI)
{
	unsigned int val = *pSWI & (~0xff000000);
	printf("SWI val = %x\r\n",val);
}

在这里插入图片描述

发布了42 篇原创文章 · 获赞 176 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/qq_39492932/article/details/104111499