前言:
本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM(MX6U)裸机篇”视频的学习笔记,在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。
引用:
正点原子IMX6U仓库 (GuangzhouXingyi) - Gitee.com
《【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.5.2.pdf》
正点原子资料下载中心 — 正点原子资料下载中心 1.0.0 文档
正文:
本文是 “正点原子[第二期]Linux之ARM(MX6U)裸机篇--第15.4 讲” 的读书笔记。第15讲主要是介绍I.MX6U处理器GPIO中断控制实验。本节将参考正点原子的视频教程第15讲和配套的正点原子开发指南文档进行学习。在第15.4讲视频教程中,正点原子会讲解如何实现自己的 IRQ中断服务函数。
0. 概述
1. GIC中断控制器的基地址
1.1 GIC 中断寄存器内存映射基地址
在文档《Cortex-A7 Technical ReferenceManua.pdf》章节“Chapter 8Generic Interrupt Controller”中介绍了Cortex-A7 GIC 中断控制器的内存映射起始基地址,GIC分发器端寄存器描述和偏移,GIC CPU接口端寄存器描述和偏移。
在GIC中断控制器寄存器的内存映射如下表所示,从表中可以看到GIC中断控制器的寄存器内存映射中 GIC 的 CPU Interface(内核接口端)寄存地址范围从 0x2000(4KB)地址偏移开始,到 0x3ffff结束,地址范围为 0x2000~0x3fff。
1.2 GIC的CPU接口端寄存器 GICC_IAR
在GIC中断控制器CPU Interface(内核接口端)寄存器中本节教程我们需要关注的是 GICC_IAR(Interrupt Acknowledge Register) 寄存器:
1.3 GIC的CPU接口端寄存器 ICC_EOIR 寄存器
当在 IRQ 中断服务函数里中断ID处理完成之后,需要向 GICC_EIOR (End Of Interrupt Register)寄存器写回之前从 GICC_IAR 中读取到的中断ID号,通知 GIC 控制器该中断ID已经处理完成。
2. 正点原子第15.4讲视频教程“IRQ中断服务函数”B站视频弹幕问题的分析
2.1. 问题1:r0,r1不是已经入栈了么?为什么不能直接使用软?
为什么不能直接使用源码第121行里保存入栈r0,r1寄存器,在调用函数system_irqhandler()的时候,r0,r1不是已经入栈了么?为什么不能直接使用栈里面的r0和r1?
我的理解:
1. 因为在IRQ中断服务函数的起始为止入栈的时候处理器是IRQ模式,此时是将 r0, r1 入栈到了IRQ(sp_irq)模式下的栈中保存。此时在通过 'bl system_irqhandler()' 调用C函数的时处理器是SVC模式,在SVC模式下不能访问到 sp_irq 栈里保存的r0, iq,这个只是原因之一。
2. 另一个原因是ARM的 ATPCS(ARM-Thumb Procedure Call Standard) C语言函数调用约定标准,ARM C语言函数如果形参小于等于4个,使用寄存器 r0,r1,r2,r3 来传递C函数形参。我们这里调用 system_irqhandler() 的时候就使用 r0 来传递参数。
2.2 问题2:调用C函数之前为什么要对lr机型入栈?
第一次进来保存的是IRQ模式下的lr
lr入栈是因为切换模式了,不同的模式都要保存一次不同的现场
lr是中断返回地址一定要保持一致,这里跳转了lr的值会被修改,因此使用栈保存
lr是函数返回地址,调用函数前需要保存当前lr,不然会在执行blx时被覆盖
我的理解:
1. 此时处理器是SVC模式,使用'bl system_irqhandler()' 调用C函数时,在 'bl' 跳转时会自动修改 lr_svc 寄存器的值,如果不在'bl'跳转之前将 'sp_svc' 寄存器的值入栈保存,那从C函数 system_irqhandler() 调用返回之后之前的 'sp_svc' 寄存器的值就丢失了。所以需要再调用C函数 ‘bl’ 跳转之前,先将 'lr_svc' 入栈,C函数调用结束之后再将 'lr_svc' 出栈。
2. ARM 函数调用通过 'bl' 跳转的一个通用流程就是,先 lr 入栈,bl 跳转到函数(处理器会自动修改lr),函数返回后 lr 出栈。
2.3 问题3:忘记了恢复了CPSR?
2.4 问题4:IRQ中断返回时为什么 pc=lr-4?
参考链接:ARM异常中断返回地址计算:
ARM中断异常处理的返回_为什么预取中止是减4-CSDN博客
ARM异常中断返回的几种情况_fiq中断的返回地址-CSDN博客
ARM处理器异常返回地址_arm下触发软中断返回地址出错-CSDN博客
嵌入式系统Linux内核开发实战指南(ARM平台)_7.4 ARM处理器的中断(IRQ或FIQ)在线阅读-QQ阅读
我的理解:
阅读了如上参考链接里的博文,我的理解是这样子的,ARM 指令集的内核在执行完指令之后,开始执行新指令之前,此时PC已经更新 PC=新指令+8(原因是ARM三级流水线),ARM内核在这个点上检查当前是否有IRQ中断需要处理,如果有就跳转到中断(异常)服务函数,在跳转到异常处理函数时处理器会自动更新 LR=PC-4 也就是 LR=(新指令+8)-4,LR指向新指令的下一条。当IRQ中断服务函数中断ID处理完成,需要返回到被中断的还未执行的新指令处继续执行,此时需要更新 PC 为 LR 的值再减去4,PC = ((新指令+8)-4)-4 ,更新PC寄存器会引起ARM多级流水线重新刷新,这样就返回了被中断的新指令处继续执行了。
这也就是为什么在IRQ中断服务函数返回的时候,PC=LR-4 的原因。