ARM-A7通用中断服务函数-1

中断流程

保存现场-执行中断服务函数-返回现场

.S文件的修改

先看代码:

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寄存器中* 参考文档ARM Cortex-A(armV7)编程手册V4.0.pdf P49* Cortex-A7 Technical ReferenceManua.pdf P68 P138*/							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 */

以下分析代码。
前面几行都是在保存寄存器,例如lr、r0这些。为什么不保存所有的寄存器是因为进入IRQ模式后,系统会自动保存一部分寄存器,而那些没有自动保存的就需要手动保存了。
然后是第一个需要仔细理解的:

mrc p15, 4, r1, c15, c0, 0

mrc是从CP15里读寄存器c15寄存器中的CBAR寄存器,存储到r1里。
CBAR寄存器是保存GIC(Generic Interrupt Controller)寄存器组的物理地址(首地址)。

GIC分发器

GIC寄存器组偏移0x1000~0x1FFF为GIC的分发器(Distributer)。分发器复杂处理各个中断事件的分发,也就是中断事件应该发送到哪个CPU接口上去。分发器收集所有的中断源,可以控制中断优先级,它总是将优先级最高的中断时间紧发送到CPU接口端。

GIC CPU接口

GIC寄存器组偏移0x2000~0x3FFF为GIC的CPU接口端。CPU接口端负责将分发器与CPU Core连接。

到这里,我们就可以访问GIC控制器了。类似STM32里的NVIC。
继续看代码:

add r1, r1, #0X2000	
ldr r0, [r1, #0XC]	

第一句是将r1的值偏移了0x2000,注意此时r1寄存器里面是GIC寄存器组的基地址,偏移之后就是CPU接口的基地址了。
第二句是将r1的值+0xC后写到r0寄存器里。注意此时r1寄存器里的值是CPU接口的基地址,+0xC之后得到的就是GICC_IAR寄存器的地址。那么r0寄存器里面保存的就是GICC_IAR寄存器的

GICC_IAR寄存器

CPU会读取这个寄存器的值,得到中断对应的ID。这次读取也意味着中断被感知到。
GICC_IAR[9:0]: 中断ID
GICC_IAR[12:10]: CPU ID
有了中断ID之后,才可以知道具体触发了哪个中断,进而执行这个ID对应的中断处理函数。

之后通过push将r0(中断ID) 和r1(CPU接口首地址)保存。

然后,通过cps #0x13 再次进入SVC模式。因为触发了IRQ后,CPU会工作在IRQ模式下。由于我们需要执行system_irqhandler函数,因此需要先进入SVC模式,然后保存SVC模式下的lr寄存器,然后将system_irqhandler放到r2寄存器里。之后执行blx r2 ,跳转到r2里面,执行system_irqhandler。注意,system_irqhandler是具体的中断处理函数,此函数有一个参数,为GICC_IAR寄存的值。
执行完毕后pop {lr} lr寄存器出栈。然后cps #0x12再次进入IRQ模式。

GICC_EOIR寄存器

之后的代码仔细分析一下:

	pop {r0, r1}				str r0, [r1, #0X10]	

首先将r0、r1寄存器出栈,此时r0保存的是GICC_IAR寄存器的值,r1保存的是GIC寄存器组中CPU接口的基地址。
然后将r0的值写入到GIC基地址+0X10的位置去。
GIC+0x10是GICC_EOIR寄存器。意思是中断结束寄存器。所以这两句代码的意思是将GIC_IAR寄存器的值写到GIC_EOIR寄存器里。
A7的架构决定了说任何一个CPU核在读取到有效的中断ID值(GICC_IAR)后,都必须将这个值写到GICC_EOIR中去。
GICC_EOIR寄存器的功能: 被写入时,标识一个中断处理的完成。

之后就是出栈了。不易理解的是:

	subs pc, lr, #4	

这里是将lr-4之后赋值给pc。
lr: link register 保存中断点
pc: program counter 当前运行的代码地址。
那么为什么要lr-4之后赋值给PC呢? 这里和CPU架构有关。ARM芯片是Fetch-Decode-Execute 这种三级流水线的架构。而PC的值是当前执行的指令地址+8.例如:

0X2000 MOV R1, R0 //EXECUTE
0X2004 MOV R2, R3 //DECODE
0X2008 MOV R4, R5 //FETCH

假设CPU已经在执行0X2000处的代码,那么此时PC里面已经保存了0X2008地址处的指令。假设此时发生中断,则lr寄存器里保存的地址就是pc的值,也就是0x2008。中断执行完成后,如果直接跳转到lr保存的地址处,就会出现位于0X2004处的指令没有执行。这样是不对的。因此,需要将lr-4的值赋予pc,此时pc = 0x2004,继续执行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/49897.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

分布式:RocketMQ/Kafka总结(附下载链接)

文章目录 下载链接思维导图 本文总结的是关于消息队列的常见知识总结。消息队列和分布式系统息息相关,因此这里就将消息队列放到分布式中一并进行处理关联 下载链接 链接: https://pan.baidu.com/s/1hRTh7rSesikisgRUO2GBpA?pwdutgp 提取码: utgp 思维导图

刷题了:150. 逆波兰表达式求值 |239. 滑动窗口最大值 |347.前 K 个高频元素

150. 逆波兰表达式求值 题目链接:https://leetcode.cn/problems/evaluate-reverse-polish-notation/description/ 文章讲解:https://programmercarl.com/0150.%E9%80%86%E6%B3%A2%E5%85%B0%E8%A1%A8%E8%BE%BE%E5%BC%8F%E6%B1%82%E5%80%BC.html 视频讲解:https://www.bilibili.…

crack 基于golang的多并发爆破工具

一款轻巧的内网弱口令枚举工具,项目地址:GitHub - oksbsb/crack: 支持 ftp ssh smb mysql mssql postgres 安装 ​ git clone https://github.com/yanweijin/crack go build main.go基于用法 ➜ crack git:(master) ✗ go run main.go --help …

UE4调试UE4Editor-Cmd.exe

在工作中,我们看到这样的构建命令: %EnginePath%\Binaries\Win64\UE4Editor-Cmd.exe %ClientPath%\%ProjectName%.uproject -runHotPatcher {其它参数} 我们应该如何调试UE4Editor-Cmd.exe呢?其实调试 UE4Editor.exe 就可以了(参考…

1111111111111111111111

https://chat18.aichatos.xyz/#/chat/1716220931748File "D:\微信\venv\Lib\site-packages\pyautogui\__init__.py", line 228, in _couldNotImportPyScreezeraise PyAutoGUIException( pyautogui.PyAutoGUIException: PyAutoGUI was unable to import pyscreeze. (T…

LabVIEW程序员以后会不会被ai取代?

关于LabVIEW程序员未来的就业前景和AI的影响,可以从多个角度进行分析: AI对LabVIEW程序员的影响 自动化和AI辅助编程: AI正在迅速发展,可以在某些领域自动生成代码、优化代码和检测错误。对于标准化的、重复性的编程任务&#xf…

解决:Maven模块项目引入其他模块项目依赖,却无法引用对方文件异常

解决:Maven模块项目引入其他模块项目依赖,却无法引用对方文件异常 一问题描述:Maven模块项目引入其他模块项目依赖,却无法引用对方文件二问题原因:三解决方案: 一问题描述:Maven模块项目引入其他…

【优秀python系统毕设】基于Python flask的气象数据可视化系统设计与实现,有LSTM算法预测气温

第一章 绪论 1.1 研究背景 在当今信息爆炸的时代,气象数据作为重要的环境信息资源,扮演着关键的角色。然而,传统的气象数据呈现方式存在信息量庞大、难以理解的问题,限制了用户对气象信息的深入理解和利用。因此,基…

React的img图片路径怎么写

在React中,图片路径的写法取决于你的图片资源是如何被管理和存放的。这里有几种常见的情况和对应的写法: 1. 图片作为React组件的静态资源 如果你的图片文件放在React项目的public文件夹下(这是Create React App项目的默认结构)…

List容器

此处是带头双向链表 对于List,不像string、vector之类的,没有reserve的说法,也不支持[ ]和下标,只有一种方式遍历List也就是采用迭代器(范围for的底层也是迭代器)。 insert函数和erase函数(需要配合std库里…

Java入门TCP客户端和服务器应用程序 2024.7.27 22:14

下面是一个完整的示例,展示如何使用 Java 的 Socket 和 ServerSocket 类编写一个简单的 TCP 客户端和服务器应用程序,以及一个简单的聊天应用程序。代码包括客户端和服务器的实现,能够通过 TCP 连接进行消息交换。 1. TCP 服务器程序 首先&…

文件包含漏洞及利用

一、文件包含功能 1、文件包含的作用:减小代码的荣誉 2、文件包含函数: include 、 require 3、文件包含的方式 静态文件包含------文件名是固定的------ a.php中存在普通的字符串,被b.php包含, a.php中的字符串会直接完成输出 a…

CSS:mix-blend-mode属性(设置元素的混合模式)

目录 一、mix-blend-mode属性介绍 二、mix-blend-mode常用属性值 三、mix-blend-mode属性应用 四、文字智能适配背景 1、原始样式 2、添加混合 3、实现代码 一、mix-blend-mode属性介绍 CSS中的【mix-blend-mode属性】描述了元素的内容应该与元素的直系父元素的内容和…

C# 植物大战僵尸

Winform 版本开发 高效率、流畅植物大战僵尸 git地址:冯腾飞/植物大战僵尸

3. 类的生命周期

类的生命周期是指一个类被加载,使用,卸载的一个过程,如下图: 类的加载阶段: 加载(Loading)阶段第一步是类加载器根据类的**全限定名(也就是类路径)**通过不同的渠道以二进制流的方式获取字节码…

使用Java和Spring State Machine实现状态管理

使用Java和Spring State Machine实现状态管理 大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!今天我们来聊聊如何使用Java和Spring State Machine实现状态管理。 一、Spring State Machine简介 Spr…

postgres数据库连接超时问题处理

postgres数据库连接超时问题处理 在操作系统层面 Keepalive 是 TCP 协议的一项功能。当您在TCP network socket中使用SO_KEEPALIVE选项时,一旦socket idle,计时器就会开始运行。当**keepalive idle time* *到期,并且socket上没有进一步的活动时,kernel内核将向通信伙伴发…

[C#]调用本地摄像头录制视频并保存

AForge.NET是一个基于C#框架设计的开源计算机视觉和人工智能库,专为开发者和研究者设计。它提供了丰富的图像处理和视频处理算法、机器学习和神经网络模型,具有高效、易用、稳定等特点。AForge库由多个组件模块组成,包括AForge.Imaging&#…

Lua Debug.GetInfo

在 Lua 中,debug.getinfo 函数的第一个参数指定了要获取信息的函数的级别。这个级别是一个整数,表示调用栈的深度。以下是一些常见的级别和它们的含义: - 1:当前函数(即调用 debug.getinfo 的函数)。 - 2&a…

go语言day19 使用git上传包文件到github Gin框架入门

git分布式版本控制系统_git切换head指针-CSDN博客 获取请求参数并和struct结构体绑定_哔哩哔哩_bilibili (gin框架) GO: 引入GIn框架_go 引入 gin-CSDN博客 使用git上传包文件 1)创建一个github账户,进入Repositories个人仓…