关于正点原子的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开发板的启动函数(汇编,自己的认识)
我傻逼了,这里的注释还是不要用; 全部换成 /* */ 这里就分为两块,一部分是复位中断部分,第二部分就是IRQ部分(中断部分最重要) 我就围绕着两部分来展开我的认识 首先声明全局 .global_start 在 ARM 架…...
Deep Layer Aggregation【方法部分解读】
摘要: 视觉识别需要跨越从低到高的层次、从小到大的尺度以及从精细到粗略的分辨率的丰富表示。即使卷积网络的特征层次很深,单独的一层信息也不足够:复合和聚合这些表示可以改进对“是什么”和“在哪里”的推断。架构上的努力正在探索网络骨干的许多维度,设计更深或更宽的架…...
大数据面试SQL题-笔记01【运算符、条件查询、语法顺序、表连接】
大数据面试SQL题复习思路一网打尽!(文档见评论区)_哔哩哔哩_bilibiliHive SQL 大厂必考常用窗口函数及相关面试题 大数据面试SQL题-笔记01【运算符、条件查询、语法顺序、表连接】大数据面试SQL题-笔记02【...】 目录 01、力扣网-sql题 1、高频SQL50题(…...
零基础自学爬虫技术该从哪里开始入手?
零基础自学爬虫技术可以从以下几个方面入手: 一、学习基础编程语言 Python 是爬虫开发的首选语言,因此首先需要学习 Python 编程语言的基础知识。这包括: 语法基础:学习 Python 的基本语法,如变量定义、数据类型、控…...
CV11_模型部署pytorch转ONNX
如果自己的模型中的一些算子,ONNX内部没有,那么需要自己去实现。 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本质上就是一个缓存框架,所以我们需要研究如何使用redis来缓存数据,并且如何解决缓存中的常见问题,缓存穿透,缓存击穿,缓存雪崩,以及如何来解决缓存一致性问题。 2.缓存的优缺点 2.1 缓存的…...
BERT架构的深入解析
BERT(Bidirectional Encoder Representations from Transformers)是由Google在2018年提出的一种基于Transformer架构的预训练模型,迅速成为自然语言处理(NLP)领域的一个里程碑。BERT通过双向编码器表示和预训练策略&am…...
数字孪生技术如何助力低空经济飞跃式发展?
一、什么是低空经济? 低空经济,是一个以通用航空产业为主导的经济形态,它涵盖了低空飞行、航空旅游、航空物流、应急救援等多个领域。它以垂直起降型飞机和无人驾驶航空器为载体,通过载人、载货及其他作业等多场景低空飞行活动&a…...
HTTP背后的故事:理解现代网络如何工作的关键(二)
一.认识请求方法(method) 1.GET方法 请求体中的首行包括:方法,URL,版本号 方法描述的是这次请求,是具体去做什么 GET方法: 1.GET 是最常用的 HTTP 方法. 常用于获取服务器上的某个资源。 2.在浏览器中直接输入 UR…...
数据流通环节如何规避安全风险
由于参与数据流通与交易的数据要素资源通常是经过组织加工的高质量数据集,甚至可能涉及国家核心战略利益,一旦发生针对数据流通环节的恶意事件,将造成较大负面影响,对数据要素市场的价值激活造成潜在威胁。具体来说,数…...
部署k8s 1.28.9版本
继上篇通过vagrant与virtualBox实现虚拟机的安装。笔者已经将原有的vmware版本的虚拟机卸载掉了。这个场景下,需要重新安装k8s 相关组件。由于之前写的一篇文章本身也没有截图。只有命令。所以趁着现在。写一篇,完整版带截图的步骤。现在行业这么卷。离…...
实验二:图像灰度修正
目录 一、实验目的 二、实验原理 三、实验内容 四、源程序和结果 源程序(python): 结果: 五、结果分析 一、实验目的 掌握常用的图像灰度级修正方法,包括图象的线性和非线性灰度点运算和直方图均衡化法,加深对灰度直方图的理解。掌握对比度增强、直方图增强的原理,…...
bash: ip: command not found
输入: ip addr 报错: bash: ip: command not found 报错解释: 这个错误表明在Docker容器中尝试执行ip addr命令时,找不到ip命令。这通常意味着iproute2包没有在容器的Linux发行版中安装或者没有正确地设置在容器的环境变量PA…...
全开源TikTok跨境商城源码/TikTok内嵌商城/前端uniapp+后端+搭建教程
多语言跨境电商外贸商城 TikTok内嵌商城,商家入驻一键铺货一键提货 全开源完美运营 海外版抖音TikTok商城系统源码,TikToK内嵌商城,跨境商城系统源码 接在tiktok里面的商城。tiktok内嵌,也可单独分开出来当独立站运营 二十一种…...
云原生、Serverless、微服务概念
云原生(Cloud Native) 云原生是一种设计和构建应用程序的方法,旨在充分利用云计算的优势。云原生应用程序通常具有以下特征: 容器化:应用程序和其依赖项被打包在容器中,确保一致的运行环境。常用的容器技…...
Windows上LabVIEW编译生成可执行程序
LabVIEW项目浏览器(Project Explorer)中的"Build Specifications"就是用来配置项目发布方法的。在"Build Specifications"右键菜单中选取"New",可以看到程序有几种不同的发布方法:Application(EXE)、Installer、.Net Inte…...
ref 和 reactive 区别
在Vue 3中,ref和reactive都是用于创建响应式数据的API,但它们之间存在一些关键的区别。以下是ref和reactive的主要区别: 1. 数据类型处理 ref:主要用于定义基本类型的数据(如字符串、数字、布尔值等)以及…...
深度学习计算机视觉中, 多尺度特征和上下文特征的区别是?
在深度学习和计算机视觉中,多尺度特征和上下文特征都是用来捕捉和理解图像中复杂模式和关系的重要概念,但它们的侧重点有所不同。 多尺度特征 (Multi-scale Features) 多尺度特征是指在不同尺度上对图像进行特征提取,以捕捉不同尺度的物体特…...
Facebook未来展望:数字社交平台的进化之路
在信息技术日新月异的时代,社交媒体平台不仅是人们交流沟通的重要工具,更是推动社会进步和变革的重要力量。作为全球最大的社交媒体平台之一,Facebook在过去十多年里,不断创新和发展,改变了数十亿用户的社交方式。展望…...
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…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...
让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...
jmeter聚合报告中参数详解
sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample(样本数) 表示测试中发送的请求数量,即测试执行了多少次请求。 单位,以个或者次数表示。 示例:…...
[ACTF2020 新生赛]Include 1(php://filter伪协议)
题目 做法 启动靶机,点进去 点进去 查看URL,有 ?fileflag.php说明存在文件包含,原理是php://filter 协议 当它与包含函数结合时,php://filter流会被当作php文件执行。 用php://filter加编码,能让PHP把文件内容…...
关于uniapp展示PDF的解决方案
在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项: 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库: npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...
HTML前端开发:JavaScript 获取元素方法详解
作为前端开发者,高效获取 DOM 元素是必备技能。以下是 JS 中核心的获取元素方法,分为两大系列: 一、getElementBy... 系列 传统方法,直接通过 DOM 接口访问,返回动态集合(元素变化会实时更新)。…...
