当前位置: 首页 > news >正文

关于正点原子的alpha开发板的启动函数(汇编,自己的认识)

我傻逼了,这里的注释还是不要用;

全部换成

/* */

这里就分为两块,一部分是复位中断部分,第二部分就是IRQ部分(中断部分最重要)

我就围绕着两部分来展开我的认识

首先声明全局 .global_start

在 ARM 架构的程序中,_start 常常是 C 程序的 main 函数之前的汇编代码,它负责设置程序的初始状态,比如初始化堆栈指针、设置 BSS 段、调用 C/C++ 运行时初始化代码等,然后将控制权传递给 main 函数

不知道为什么视频里的清楚和设置bss段,后面的代码没有了

第一步:设置中断向量表

这里设置中断向量表的顺序是固定的,依照架构技术手册设置。

发生了哪个中断就把其地址加载给pc指针

;中断向量表ldr pc,=Reset_Handlerldr pc,=Undefined_Handlerldr pc,=SVC_Handlerldr pc,=PrefAbort_Handlerldr pc,=DataAbort_Handlerldr pc,=NotUsed_Handlerldr pc,=IRQ_Handlerldr pc,=FIQ_Handler

一共有8种中断类型,我们最关心的两种一个是系统复位中断,第二种是外设中断IRQ中断,其他的目前是不太关心。所以其实现也是一个死循环,如下

SVC_Handler:
ldr r0,=SVC_Handler
bx r0

第二步:实现复位中断函数和IRQ中断函数

关闭C1寄存器里的几个功能,主要是操作SCTLR寄存器

	mrc p15,0,r0,c1,c0,0 /* 读取CP15的C1寄存器到R0中   */bic r0,r0,#(1<<12)/*清除C1寄存器的bit12位(I位),关闭I Cache */bic r0,r0,#(1<<11) /*清除C1寄存器的bit11(Z位),关闭分支预测 */bic r0,r0,#(1<<2)/*清除C1寄存器的bit2(C位),关闭D Cache */bic r0,r0,#(1<<1)/*清除C1寄存器的bit1(A位),关闭对齐 */bic r0,r0,#(1<<0)/*清除C1寄存器的bit0(M位),关闭MMU */mcr p15,0,r0,c1,c0,0 /* 将r0寄存器中的值写入到CP15的C1寄存器中*/

配置完该寄存器后就开始设置中断向量表基地址,这几个中断的偏移是在基地址为0x0的基础上的,但是我们存放其位置是在0x87800000

		/* 中断向量表偏移*/ldr r0,=0x87800000dsbisbmcr p15,0,r0,c12,c0,0dsbisb

其中dsb和isb是为了保障操作完成。

mcr p15,0,r0,c12,c0,0

该段代码意思是从CP15协处理器c12存入这个偏移地址

而c12里的VBAR是一个用来存放中断向量偏移基地址的寄存器

初始化这八种中断情况下的pc堆栈指针了。

当然可以全部实现,也可以只实现我们需要的

/* 设置各个模式下的堆栈指针*//* IRQ模式*/mrs r0,spsr;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模式*/mrs r0,spsr;bic r0,r0,#(0x1f) /*将r0寄存器中的低5位清零,也就是cpsr的M0~M4 */orr r0,r0,#(0x1f)/* r0或上0x1f,表示使用SYS模式*/msr cpsr,r0/*将r0 的数据写入到cpsr_c中 */ldr sp,=0x80400000/* 设置IRQ模式下的栈首地址为0X80400000,大小为2MB*//* IRQ模式*/mrs r0,spsr;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 */

在 ARM 架构中,状态寄存器 `SPSR`(Saved Program Status Register)用于保存当前的程序状态信息,包括处理器模式。

以下是切换处理器模式的几种常见方法:

1. **使用 `CPS` 指令**:ARM 架构提供了 `CPS`(Change Processor State)指令,用于切换处理器模式。例如,`CPS #0x13` 将切换到 SVC(Supervisor)模式,其中 `0x13` 是模式值加上一个优先级级别。

2. **修改 `CPSR` 寄存器**:直接修改 `CPSR` 寄存器可以改变处理器模式,但这通常不是安全的编程实践,因为它可能影响当前的程序状态。

3. **使用 `MSR` 指令**:`MSR`(Move to Status Register)指令可以用来修改 `CPSR` 或 `SPSR` 的某些字段。例如,`MSR spsr_cxsf, r0` 可以将寄存器 `r0` 的值写入 `SPSR` 的控制和状态字段。

4. **异常和中断处理**:当异常或中断发生时,处理器会自动切换到相应的模式,并保存当前的 `CPSR` 到相应的 `SPSR`。处理完异常或中断后,处理器会从 `SPSR` 恢复 `CPSR` 的值,从而切换回原来的模式。

5. **使用 `BX` 指令**:在某些情况下,使用 `BX` 指令跳转到一个具有不同模式的代码位置也可以实现模式切换。被跳转的目标代码需要设置正确的模式。

`SPSR` 主要用于异常和中断处理中保存和恢复程序状态,而不是直接用来切换模式。在编写程序时,应该使用 `CPS` 指令或 `MSR` 指令来安全地切换处理器模式,并确保程序状态的正确性。直接修改 `SPSR` 可能会导致不可预测的行为,因为 `SPSR` 也包含了其他状态信息,如中断屏蔽位等。

SPSR寄存器用来改变状态的就是低5位,当然我们也可以直接用cps 加上那5位切换到对应模式

cps #0x13/*切换到SVC模式*/
ldr sp,=0x80600000/*设置堆栈指针*/

这样也许更简洁。

设置完堆栈指针就该跳转到 main函数了,但是前面的设置过程为保证安全会关闭全局中断,设置完后再打开,类似于freertos里的进入临界区

2.1 具体的复位函数实现

Reset_Handler:cpsid i				/* 关闭全局中断*/mrc p15,0,r0,c1,c0,0 /* 读取CP15的C1寄存器到R0中   */bic r0,r0,#(1<<12)/*清除C1寄存器的bit12位(I位),关闭I Cache */bic r0,r0,#(1<<11) /*清除C1寄存器的bit11(Z位),关闭分支预测 */bic r0,r0,#(1<<2)/*清除C1寄存器的bit2(C位),关闭D Cache */bic r0,r0,#(1<<1)/*清除C1寄存器的bit1(A位),关闭对齐 */bic r0,r0,#(1<<0)/*清除C1寄存器的bit0(M位),关闭MMU */mcr p15,0,r0,c1,c0,0 /* 将r0寄存器中的值写入到CP15的C1寄存器中*//* 设置各个模式下的堆栈指针*//* IRQ模式*/mrs r0,spsr;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模式*/mrs r0,spsr;bic r0,r0,#(0x1f) /*将r0寄存器中的低5位清零,也就是cpsr的M0~M4 */orr r0,r0,#(0x1f)/* r0或上0x1f,表示使用SYS模式*/msr cpsr,r0/*将r0 的数据写入到cpsr_c中 */ldr sp,=0x80400000/* 设置IRQ模式下的栈首地址为0X80400000,大小为2MB*//* IRQ模式*/mrs r0,spsr;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	/*打开全局中断 */b main/*跳转到main函数 */

然后就是最重要的IRQ中断函数的编写

2.2 具体IRQ函数的实现

首先保存lr寄存器的值,也就是保存现场,也就是入栈操作,把寄存器中的值保存进内存中去。

入栈 r0-r3,r12,因为这几个寄存器不会自动保存,要手动保存

然后就使spsr状态寄存器,它也不会自动保存

好了这几个寄存器全部压入栈内了,等于中断前的现场已经保存完整

进入协处理器CP15的C15经过操作数4的选择后最终我们选择读取CBAR寄存器的值

这个寄存器全名叫做配置基地址寄存器

我们为什么要得到该寄存器的值呢,因为我们要进一步得到GIC控制器的基地址。GIC的基地址存在CBAR里,这点是最重要的。没有CBAR的读取就找不到GIC的基地址

通过找到GIC的基地址,再经过偏移0x2000我们就得到GIC-CPU接口的基地址再偏移0xc我们得到了GIC-IAR寄存器的地址。这个GIC-IAR寄存器就是我们干这麽久最关键的地方。如果是知道这个偏移,那我们这样就更便捷,但是可读性就差了一些。

add r1,r1,#(0x200C);

 找到IAR寄存器后读取寄存器里的值我们就得到了CPUID和中断号,他们被存入r0寄存器

 得到中断号后我们的目的就得到了,就能找到对应的中断函数地址了。入栈r0,r1,把中断号和GIC-CPU接口的地址保存下来

切换到SVC模式,保存当前模式下的lr寄存器

r0,r1都用了,根据system_irqhandler得到入口地址存到r2寄存器内

blx跳到对应函数。

出栈SVC模式下的lr寄存器,切换到IRQ模式。出栈r0,r1。在不同的处理模式下出入栈lr都是成对的,它们拥有不完全公用的堆栈空间。这里的出栈入栈都是针对内存而言的,出栈就是内存到寄存器,入栈就使寄存器到内存。此刻r0存的是中断号,r1存的是GIC-CPU的基地址。把中断号存入GIC-CPU的基地址偏移0x10处的寄存器内表示中断执行完成,写EOIR 出栈r0恢复状态寄存器也就是

当前堆栈里还存有r0,r0-r3,r12的值,其中第一个r0存的是spsr寄存器的值

pop {r0}
msr spsr, r0

 这个与那个应该是等价的,都是接受栈内原本存入的spsr寄存器的值

然后恢复现场,还IRQ中断发生前的r0-r3,r12寄存器的内容

弹出lr-4的值给pc

这里我开始困惑的地方就是为什么没有-8,后来我才知道运行那段会被强制执行完,所以-4就可以了。

IRQ_Handler:push {lr}	/*保存当前运行地址 */push {r0-r3, r12}  /* 其他寄存器会自动保存,这几个要手动*/mrs r0 ,spsr  /*读取状态寄存器 */push {r0}  /*保存 */mrc p15,4,r1,c15,c0,0 /*读取CP15的CBAR寄存器 */add r1,r1,#(0x2000) /*基地址偏移0x2000得到GIC-CPU接口的基地址 */ldr r0,[r1,#(0xc)] /* 将GIC-CPU基地址再偏移0xc得到GICC-IAR寄存器的基地址,取该地址的值*//*得到中断号及CPUID */push {r0,r1}cps #(0x13) /* 切换到SVC模式*/push {lr} /*保存svc模式下的lr寄存器 */ldr r2,=system_irqhandler  /* 加载C语言的IRQ中断处理函数*/blx r2 /*跳转到对应的IRQ中断函数 */pop {lr}cps #0x12 /* 进入IRQ模式*/pop {r0,r1}str r0,[r1,#(0x10)] /*将其中断ID号写入r0保存的地址中,也就是IAR基地址 */pop {r0}msr spsr_cxsf, r0 /*恢复状态寄存器 */pop {r0-r3,r12}pop {lr}subs pc,lr,#4

经过我的测试,把中断向量基地址的偏移放在 _start:下也是没有问题的。
 

相关文章:

关于正点原子的alpha开发板的启动函数(汇编,自己的认识)

我傻逼了&#xff0c;这里的注释还是不要用&#xff1b; 全部换成 /* */ 这里就分为两块&#xff0c;一部分是复位中断部分&#xff0c;第二部分就是IRQ部分&#xff08;中断部分最重要&#xff09; 我就围绕着两部分来展开我的认识 首先声明全局 .global_start 在 ARM 架…...

Deep Layer Aggregation【方法部分解读】

摘要: 视觉识别需要跨越从低到高的层次、从小到大的尺度以及从精细到粗略的分辨率的丰富表示。即使卷积网络的特征层次很深,单独的一层信息也不足够:复合和聚合这些表示可以改进对“是什么”和“在哪里”的推断。架构上的努力正在探索网络骨干的许多维度,设计更深或更宽的架…...

大数据面试SQL题-笔记01【运算符、条件查询、语法顺序、表连接】

大数据面试SQL题复习思路一网打尽&#xff01;(文档见评论区)_哔哩哔哩_bilibiliHive SQL 大厂必考常用窗口函数及相关面试题 大数据面试SQL题-笔记01【运算符、条件查询、语法顺序、表连接】大数据面试SQL题-笔记02【...】 目录 01、力扣网-sql题 1、高频SQL50题&#xff08…...

零基础自学爬虫技术该从哪里开始入手?

零基础自学爬虫技术可以从以下几个方面入手&#xff1a; 一、学习基础编程语言 Python 是爬虫开发的首选语言&#xff0c;因此首先需要学习 Python 编程语言的基础知识。这包括&#xff1a; 语法基础&#xff1a;学习 Python 的基本语法&#xff0c;如变量定义、数据类型、控…...

CV11_模型部署pytorch转ONNX

如果自己的模型中的一些算子&#xff0c;ONNX内部没有&#xff0c;那么需要自己去实现。 1.1 配置环境 安装ONNX pip install onnx -i https://pypi.tuna.tsinghua.edu.cn/simple 安装推理引擎ONNX Runtime pip install onnxruntime -i https://pypi.tuna.tsinghua.edu.cn/si…...

Redis的使用(四)常见使用场景-缓存使用技巧

1.绪论 redis本质上就是一个缓存框架&#xff0c;所以我们需要研究如何使用redis来缓存数据&#xff0c;并且如何解决缓存中的常见问题&#xff0c;缓存穿透&#xff0c;缓存击穿&#xff0c;缓存雪崩&#xff0c;以及如何来解决缓存一致性问题。 2.缓存的优缺点 2.1 缓存的…...

BERT架构的深入解析

BERT&#xff08;Bidirectional Encoder Representations from Transformers&#xff09;是由Google在2018年提出的一种基于Transformer架构的预训练模型&#xff0c;迅速成为自然语言处理&#xff08;NLP&#xff09;领域的一个里程碑。BERT通过双向编码器表示和预训练策略&am…...

数字孪生技术如何助力低空经济飞跃式发展?

一、什么是低空经济&#xff1f; 低空经济&#xff0c;是一个以通用航空产业为主导的经济形态&#xff0c;它涵盖了低空飞行、航空旅游、航空物流、应急救援等多个领域。它以垂直起降型飞机和无人驾驶航空器为载体&#xff0c;通过载人、载货及其他作业等多场景低空飞行活动&a…...

HTTP背后的故事:理解现代网络如何工作的关键(二)

一.认识请求方法(method) 1.GET方法 请求体中的首行包括&#xff1a;方法&#xff0c;URL&#xff0c;版本号 方法描述的是这次请求&#xff0c;是具体去做什么 GET方法&#xff1a; 1.GET 是最常用的 HTTP 方法. 常用于获取服务器上的某个资源。 2.在浏览器中直接输入 UR…...

数据流通环节如何规避安全风险

由于参与数据流通与交易的数据要素资源通常是经过组织加工的高质量数据集&#xff0c;甚至可能涉及国家核心战略利益&#xff0c;一旦发生针对数据流通环节的恶意事件&#xff0c;将造成较大负面影响&#xff0c;对数据要素市场的价值激活造成潜在威胁。具体来说&#xff0c;数…...

部署k8s 1.28.9版本

继上篇通过vagrant与virtualBox实现虚拟机的安装。笔者已经将原有的vmware版本的虚拟机卸载掉了。这个场景下&#xff0c;需要重新安装k8s 相关组件。由于之前写的一篇文章本身也没有截图。只有命令。所以趁着现在。写一篇&#xff0c;完整版带截图的步骤。现在行业这么卷。离…...

实验二:图像灰度修正

目录 一、实验目的 二、实验原理 三、实验内容 四、源程序和结果 源程序(python): 结果: 五、结果分析 一、实验目的 掌握常用的图像灰度级修正方法,包括图象的线性和非线性灰度点运算和直方图均衡化法,加深对灰度直方图的理解。掌握对比度增强、直方图增强的原理,…...

bash: ip: command not found

输入&#xff1a; ip addr 报错&#xff1a; bash: ip: command not found 报错解释&#xff1a; 这个错误表明在Docker容器中尝试执行ip addr命令时&#xff0c;找不到ip命令。这通常意味着iproute2包没有在容器的Linux发行版中安装或者没有正确地设置在容器的环境变量PA…...

全开源TikTok跨境商城源码/TikTok内嵌商城/前端uniapp+后端+搭建教程

多语言跨境电商外贸商城 TikTok内嵌商城&#xff0c;商家入驻一键铺货一键提货 全开源完美运营 海外版抖音TikTok商城系统源码&#xff0c;TikToK内嵌商城&#xff0c;跨境商城系统源码 接在tiktok里面的商城。tiktok内嵌&#xff0c;也可单独分开出来当独立站运营 二十一种…...

云原生、Serverless、微服务概念

云原生&#xff08;Cloud Native&#xff09; 云原生是一种设计和构建应用程序的方法&#xff0c;旨在充分利用云计算的优势。云原生应用程序通常具有以下特征&#xff1a; 容器化&#xff1a;应用程序和其依赖项被打包在容器中&#xff0c;确保一致的运行环境。常用的容器技…...

Windows上LabVIEW编译生成可执行程序

LabVIEW项目浏览器(Project Explorer)中的"Build Specifications"就是用来配置项目发布方法的。在"Build Specifications"右键菜单中选取"New"&#xff0c;可以看到程序有几种不同的发布方法&#xff1a;Application(EXE)、Installer、.Net Inte…...

ref 和 reactive 区别

在Vue 3中&#xff0c;ref和reactive都是用于创建响应式数据的API&#xff0c;但它们之间存在一些关键的区别。以下是ref和reactive的主要区别&#xff1a; 1. 数据类型处理 ref&#xff1a;主要用于定义基本类型的数据&#xff08;如字符串、数字、布尔值等&#xff09;以及…...

深度学习计算机视觉中, 多尺度特征和上下文特征的区别是?

在深度学习和计算机视觉中&#xff0c;多尺度特征和上下文特征都是用来捕捉和理解图像中复杂模式和关系的重要概念&#xff0c;但它们的侧重点有所不同。 多尺度特征 (Multi-scale Features) 多尺度特征是指在不同尺度上对图像进行特征提取&#xff0c;以捕捉不同尺度的物体特…...

Facebook未来展望:数字社交平台的进化之路

在信息技术日新月异的时代&#xff0c;社交媒体平台不仅是人们交流沟通的重要工具&#xff0c;更是推动社会进步和变革的重要力量。作为全球最大的社交媒体平台之一&#xff0c;Facebook在过去十多年里&#xff0c;不断创新和发展&#xff0c;改变了数十亿用户的社交方式。展望…...

uniapp-vue3-vite 搭建小程序、H5 项目模板

uniapp-vue3-vite 搭建小程序、H5 项目模板 特色准备拉取默认UniApp模板安装依赖启动项目测试结果 配置自动化导入安装依赖在vite.config.js中配置 引入 prerttier eslint stylelint.editorconfig.prettierrc.cjs.eslintrc.cjs.stylelintrc.cjs 引入 husky lint-staged com…...

sealos快速安装k8s

Sealos 提供一套强大的工具&#xff0c;使得用户可以便利地管理整个集群的生命周期。 功能介绍 使用 Sealos&#xff0c;您可以安装一个不包含任何组件的裸 Kubernetes 集群。此外&#xff0c;Sealos 还可以在 Kubernetes 之上&#xff0c;通过集群镜像能力组装各种上层分布式…...

智慧水利:迈向水资源管理的新时代,结合物联网、云计算等先进技术,阐述智慧水利解决方案在提升水灾害防控能力、优化水资源配置中的关键作用

本文关键词&#xff1a;智慧水利、智慧水利工程、智慧水利发展前景、智慧水利技术、智慧水利信息化系统、智慧水利解决方案、数字水利和智慧水利、数字水利工程、数字水利建设、数字水利概念、人水和协、智慧水库、智慧水库管理平台、智慧水库建设方案、智慧水库解决方案、智慧…...

MATLAB——字符串处理

文章目录 MATLAB——字符串处理字符串处理函数字符串或字符串数组构造 MATLAB——字符串处理 字符串处理函数 MATLAB中的字符串处理函数如下&#xff1a; 函数名称说明eval(string)作为一个MATLAb命令求字符串的值blanks(n)返回一个具有n个空格的字符串deblank去掉字符串末尾…...

Qt实现一个简单的视频播放器

目录 1 工程配置 1.1 创建新工程 1.2 ui界面配置 1.3 .pro配置 2 代码 2.1 main.c代码 2.2 widget.c 2.3 widget.h 本文主要记述了如何使用Qt编写一个简单的视频播放器&#xff0c;整个示例采用Qt自带组件就可以完成。可以实现视频的播放和暂停等功能。 1 工程配置 1.…...

微服务治理新篇章:Eureka中细粒度策略管理实现

微服务治理新篇章&#xff1a;Eureka中细粒度策略管理实现 在微服务架构中&#xff0c;服务的治理和管理是确保系统稳定性和可扩展性的关键。Eureka作为Netflix开源的服务发现框架&#xff0c;提供了基本的服务注册与发现功能。然而&#xff0c;随着微服务规模的扩大和业务需求…...

快排的3种方式

//&#xff08;前两种时间复杂度为o(n^2) , 最后一种为o(n*logn&#xff09;public static void swap(int[] arr , int i , int j){arr[i] arr[i] ^arr[j];arr[j] arr[i] ^arr[j];arr[i] arr[i] ^arr[j]; } //使数组中以arr[R]划分&#xff0c;返回循环后arr[R]的所在地 public…...

el-date-picker手动输入日期,通过设置开始时间和阶段自动填写结束时间

需求&#xff1a;根据开始时间&#xff0c;通过填写阶段时长&#xff0c;自动填写结束时间&#xff0c;同时开始时间和节数时间可以手动输入 代码如下&#xff1a; <el-form ref"ruleForm2" :rules"rules2" :model"formData" inline label-po…...

springboot 适配ARM 架构

下载对应的maven https://hub.docker.com/_/maven/tags?page&page_size&ordering&name3.5.3-alpinedocker pull maven:3.5.3-alpinesha256:4c4e266aacf8ea6976b52df8467134b9f628cfed347c2f6aaf9e6aff832f7c45 2、下载对应的jdk https://hub.docker.com/_/o…...

ElementUI el-select 组件动态设置disabled后,高度变更的问题解决办法

问题描述 Vue2 项目在使用 el-select 组件时&#xff0c;动态将disabled变更为了 true&#xff0c;元素的高度发生了变化。 问题原因 通过浏览器开发人员工具面板&#xff0c;发现&#xff0c;组件内的 input 元素被动态设置了height的样式&#xff1a; 在项目中检查后并…...

写个网络爬虫

网络爬虫是一种自动化程序&#xff0c;通过发送HTTP请求并解析HTML等网页内容&#xff0c;获取指定网页数据的工具。下面是一个简单的Python代码示例&#xff0c;用于实现一个基本的网络爬虫&#xff1a; import requests from bs4 import BeautifulSoupdef get_html(url):try…...