使用汇编编写中断向量表,复位中断服务函数,以及IRQ中断服务函数。
.global _start /* 全局标号 */
/*
* 描述: _start函数,程序从此函数开始执行,此函数主要功能是设置C
* 运行环境。
*/
_start:
/*中断向量表*/
ldr pc, =Reset_Handler /*复位中断函数*/
ldr pc, =Undefined_Handler /*未定义指令中断*/
ldr pc, =SVC_Handler /*SVC*/
ldr pc, =PreAbort_Handler /*预取终止中断*/
ldr pc, =DataAbort_Handler /*数据终止中断 */
ldr pc, =NotUsed_Handler /*未使用*/
ldr pc, =IRQ_Handler /*IRQ中断*/
ldr pc, =FIQ_Handler /*FIQ中断*/
/*复位中断服务函数*/
Reset_Handler:
cpsid i /*关闭IRQ中断 */
/*关闭I,D Cache和MMU */
/*修改SCTLR寄存器,采用读-改写的方式 */
MRC p15, 0, r0, c1, c0, 0 /*读取SCTLR寄存器的数据到r0寄存器里面 */
bic r0, r0, #(1 << 12) /*关闭I Cache bic是对某位置0*/
bic r0, r0, #(1 << 11) /*关闭分支预测 */
bic r0, r0, #(1 << 2) /*关闭D Cache */
bic r0, r0, #(1 << 1) /*关闭对齐*/
bic r0, r0, #(1 << 0) /*关闭MMU */
MCR p15, 0, r0, c1, c0, 0 /* 将r0寄存器数据写入SCTLR寄存器里*/
/*设置中断向量偏移 */
ldr r0, =0x87800000
/*指令同步数据同步 */
dsb
isb
MCR p15, 0, r0, c12, c0, 0 /*设置VBAR寄存器=0x87800000 */
/*指令同步数据同步 */
dsb
isb
/*进入IRQ模式设置sp指针 */
mrs r0, cpsr
bic r0, r0, #0x1f /* 将r0寄存器中的低5位清零,也就是cpsr的M0~M4*/
orr r0, r0, #0x12 /* r0或上0x12,表示使用IRQ模式*/
msr cpsr, r0 /* 将r0 的数据写入到cpsr_c中*/
ldr sp,=0X80600000 /* 设置IRQ模式下栈首地址为0X80600000,大小为2MB*/
/*进入SYS模式设置sp指针 */
mrs r0, cpsr
bic r0, r0, #0x1f /* 将r0寄存器中的低5位清零,也就是cpsr的M0~M4*/
orr r0, r0, #0x1f /* r0或上0x12,表示使用IRQ模式*/
msr cpsr, r0 /* 将r0 的数据写入到cpsr_c中*/
ldr sp,=0X80400000 /* 设置SYS模式下栈首地址为0X80400000,大小为2MB*/
/*进入SVC模式*/
/* 设置栈指针,
* 注意:IMX6UL的堆栈是向下增长的!
* 堆栈指针地址一定要是4字节地址对齐的!!!
* DDR范围:0X80000000~0X9FFFFFFF
*/
mrs r0, cpsr
bic r0, r0, #0x1f /* 将r0寄存器中的低5位清零,也就是cpsr的M0~M4*/
orr r0, r0, #0x13 /* r0或上0x13,表示使用SVC模式*/
msr cpsr, r0 /* 将r0 的数据写入到cpsr_c中*/
ldr sp,=0X80200000 /* 设置SVC模式下栈首地址为0X80200000,大小为2MB*/
cpsie i /*打开IRQ中断使能 */
b main /* 跳转到main函数 */
/*未定义指令中断服务函数*/
Undefined_Handler:
/*死循环 */
ldr r0, =Undefined_Handler
bx r0
/*SVC中断服务函数*/
SVC_Handler:
/*死循环 */
ldr r0, =SVC_Handler
bx r0
/*预取终止中断服务函数*/
PreAbort_Handler:
/*死循环 */
ldr r0, =PreAbort_Handler
bx r0
/*数据终止中断服务函数*/
DataAbort_Handler:
/*死循环 */
ldr r0, =DataAbort_Handler
bx r0
/*未使用*/
NotUsed_Handler:
/*死循环 */
ldr r0, =NotUsed_Handler
bx r0
/*IRQ中断服务函数*/
IRQ_Handler:
push {lr} /* 保存lr地址 */
push {r0-r3, r12} /* 保存r0-r3,r12寄存器 */
mrs r0, spsr /* 读取spsr寄存器 */
push {r0} /* 保存spsr寄存器 */
mrc p15, 4, r1, c15, c0, 0 /* 从CP15的C0寄存器内的值到R1寄存器中*/
add r1, r1, #0X2000 /* GIC基地址加0X2000,也就是GIC的CPU接口端基地址 */
ldr r0, [r1, #0XC] /* GIC的CPU接口端基地址加0X0C就是GICC_IAR寄存器,
* GICC_IAR寄存器保存这当前发生中断的中断号,我们要根据
* 这个中断号来绝对调用哪个中断服务函数
*/
push {r0, r1} /* 保存r0,r1 */
cps #0x13 /* 进入SVC模式,允许其他中断再次进去 */
push {lr} /* 保存SVC模式的lr寄存器 */
ldr r2, =system_irqhandler /* 加载C语言中断处理函数到r2寄存器中*/
blx r2 /* 运行C语言中断处理函数,带有一个参数,保存在R0寄存器中 */
pop {lr} /* 执行完C语言中断服务函数,lr出栈 */
cps #0x12 /* 进入IRQ模式 */
pop {r0, r1}
str r0, [r1, #0X10] /* 中断执行完成,写EOIR */
pop {r0}
msr spsr_cxsf, r0 /* 恢复spsr */
pop {r0-r3, r12} /* r0-r3,r12出栈 */
pop {lr} /* lr出栈 */
subs pc, lr, #4 /* 将lr-4赋给pc */
/*FIQ中断服务函数*/
FIQ_Handler:
/*死循环 */
ldr r0, =FIQ_Handler
bx r0