6410之异常处理

ARM的工作模式分为下面几种:


共有七种工作模式,他们分别为:

1.System & User模式

2.Fiq快速中断模式

3.SVC管理模式

4.abt终止模式

5.irq普通中断模式

6.und未定义指令模式

其中:

1.黑三角表示该模式下所特有的寄存器

2.R13:链接寄存器LR

3.R14:栈指针寄存器SP

4.R15:程序指令计数器PC


ARM模式之间切换过程

1.ARM一上电,CPU就处于了SVC模式
2.当发生了中断,CPU将进入IRQ模式,R13,R14会切换到IRQ模式下的R13,R14,然后跳到0x18出取执行(0x18地址是ARM规定好的,该地址就是中断入口地址)
3.当碰到了一条机器码CPU不认识,CPU将进入undefined模式,R13,R14切换到undefined模式下的R13,R14,最后跳转到0x4地址去执行(0x4也是ARM规定好的
4.当执行了swi #val,CPU将进入SVC模式,R13,R14也就切换到SVC模式下的R13,R14,最后跳转到0x8去执行

5.当切换到另一种模式时,会将当前的cpsr保存到另一种模式下的spsr中。


总结:
当发生了swi #val
硬件上:
1.CPU进入SVC模式
2.当前的CPSR状态被保存到SVC模式下的SPSR中
3.R13,R14切换到SVC模式下的R13,R14
4.把当前下一条指令的地址存放到SVC模式下的R14(lr)中
5.跳转到 0x8地址执行

软件上:
1.在地址0x8地方,放一条跳转指令
2.保存现场
3.处理异常
4.恢复现场

测试程序如下:

.globl _start
_start:

	/* 0 地址 */
	b reset                 /* 复位时,cpu跳到0地址 */
	ldr pc, =undefined_instruction  /* cpu遇到不能识别的指令时 */
	ldr pc, _vector_swi             /* 当执行swi指令时, 进入SVC模 式 */
	@ldr	pc, _prefetch_abort /* 预取中止异常 */
	@ldr	pc, _data_abort     /* 数据访问异常 */
	@ldr	pc, _not_used       /* 没用到 */
	@ldr	pc, _irq            /* 中断异常 */
	@ldr	pc, _fiq            /* 快中断异常 */

_vector_swi:
	.word vector_swi
		
vector_swi:
	/* 1. 保存现场 */
	ldr sp, =0x56000000 /* sp,r13, r13_svc */
	stmdb sp!, {r0-r12, lr}  /* lr就是swi的下一条指令地址 */

	/* 2. 处理异常 */
	mrs r0, cpsr
	ldr r1, =swi_str
	bl print_cpsr

	/* 3. 恢复现场 */
	ldmia sp!, {r0-r12, pc}^ /* ^表示把spsr恢复到cpsr */
	
swi_str:
	.word 0x00697773  /* swi */
	
undefined_instruction:
	/* 1. 保存现场 */
	ldr sp, =0x55000000
	stmdb sp!, {r0-r12, lr}

	/* 2. 处理异常 */
	mrs r0, cpsr
	ldr r1, =und_str
	bl print_cpsr

	/* 3. 恢复现场 */
	ldmia sp!, {r0-r12, pc}^  /* ^表示把spsr恢复到cpsr */

und_str:
	.word 0x00646e75  /* und */

usr_str:
	.word 0x00727375  /* usr */

reset:
/* 硬件相关的设置 */
    /* Peri port setup */
    ldr r0, =0x70000000
    orr r0, r0, #0x13
    mcr p15,0,r0,c15,c2,4       @ 256M(0x70000000-0x7fffffff)
    
/* 关看门狗 */
/* 往WTCON(0x7E004000)写0 */
	
	ldr r0, =0x7E004000
	mov r1, #0
	str r1, [r0]
	
	/* 设置时钟 */
	bl clock_init
	
	/* 设置栈 */
	ldr sp, =8*1024

	bl ddr_init
	bl init_uart

/* 把程序的代码段、数据段复制到它的链接地址去 */	
	ldr r0, =_start  /* _start的链接地址 0x51000000 */
	adr r1, _start   /* 获得_start指令当前所在的地址 : 0*/
	
	ldr r2, =bss_start      /* bss段的起始链接地址 */
	
	sub r2, r2, r0
	
	cmp r0,r1
	beq clean_bss
	
	bl nand_read
	cmp r0, #0
	bne halt
		
	/* 清BSS */
/* 把BSS段对应的内存清零 */
clean_bss:
	ldr r0, =bss_start
	ldr r1, =bss_end
	mov r3, #0
	cmp r0, r1
	ldreq pc, =on_ddr
clean_loop:
	str r3, [r0], #4
	cmp r0, r1	
	bne clean_loop		
	ldr pc, =on_ddr

on_ddr:	

	mrs r0, cpsr   
	bic	r0,r0,#0x1f
	orr	r0,r0,#0x10
	msr	cpsr,r0      /* 进入user mode */

	ldr sp, =0x57000000  //设置用户模式下的sp

	ldr r1, =usr_str
	bl print_cpsr
	
	swi 0    /*
	          * cpu进入svc模式
	          * 把之前的cpsr保存到spsr_svc 
	          * 切换到r13_svc, r14_svc
	          * 把swi的下一条指令存到r14(lr)_svc
	          * 跳到地址8
	          */
	bl hello
undef:
	.word 0xff000000 /*
			          * cpu进入Undefined模式
			          * 把之前的cpsr保存到spsr_und 
			          * 切换到r13_und, r14_und
			          * 把下一条指令存到r14(lr)_und
			          * 跳到地址4
			          */
	
swi_ret:
	bl main
	

halt:
	b halt

从上面代码可以看到从一种模式进入另一种模式都需要进行相关的工作。如前面所述。



你可能感兴趣的:(异常处理,异常)