从裸机到嵌入式Linux——芯片是怎么启动的

如何定义“启动”

本节内容依然是为从裸机到嵌入式Linux做前期知识储备。主要是探究STM32芯片的启动过程,就像我们写一个C程序总是从main函数开始到return 0结束一样,我们首先明确本节所谓“芯片启动“的开始节点和终止节点:
开始节点:按下电源/复位键。
终止节点:程序跳转到main函数。
从main函数之后就是我们熟悉的内容了,因此我们将程序跳转到main函数这条指令作为芯片启动的终点。

启动阶段分析

接下来我们看一下芯片的启动共有哪些阶段,我用一张图进行表示。

1.寄存器清零

上电之后,CPU内核中所有的寄存器全部被初始化成0。

2.Boot0/Boot1 启动方式选择

时钟的第4个周期进行Boot启动方式的确认,将Boot的结果保存到一个寄存器中,这个寄存器中的值能够影响最终的地址有映射,也正是这个寄存器的值,让STM32的程序能够从0x08000000启动。

3. 加载SP寄存器值

从0x0000_0000 处加载 SP 寄存器的值,SP这个寄存器里面一直存放栈顶指针吗?那这个效率有点低哦,如果不是,又该是什么样的处理方式呢?

4. 加载PC寄存器值

从 0x0000_0004 处加载PC指针寄存器的值。

4 之后,5 之前都是硬件强行拉的?ARM启动过程分析?

5. 跳转到reset_Handler

0x0000_0004 中的内容是待跳转的地址,这个地址指向Reset_Handler

5.1 跳转到system_init

Reset_Handle 中第一个函数就是System_init,用于初始化时钟。

5.2 跳转到__main

5.2.1 初始化向量表
5.2.2 C库代码和分散加载
5.2.3 C语言环境初始化

6.跳转到main

这里要注意两个特殊寄存器 SP(栈指针寄存器) 和 PC(程序技术器),因此上电和复位之后,这两个寄存器中的值为0x0000_0000 (这是ARMCPU内核决定的,ST无权更改)。因此为了能让程序正常的跑起来,必须从0x0000_0000开始放指令。
0x0000_0000 放的是SP的内容,然后是0x0000_0004 放PC指针。


目前已知的就这些,后续学到了在回来更新!

参考链接:

  1. STM32上电启动代码详解
  2. arm Cortex-m 启动流程分析
### 关于ARMv7l架构的相关资料 #### ARMv7l架构概述 ARMv7l 是基于ARMv7架构的一个变体,主要用于支持Linux操作系统的设备。它属于ARMv7系列中的A类(Application Profile),适用于复杂操作系统和高性能计算场景[^1]。ARMv7l 的“l”表示该架构运行在little-endian模式下。 #### 嵌入式系统开发文档推荐 对于嵌入式系统开发人员而言,以下文档可以作为重要参考资料: 1. **《ARMv7-A and ARMv7-R Series Architecture Reference Manual》** 这份文档提供了关于ARMv7-A/R架构的详尽描述,涵盖了核心概念、指令集结构以及内存管理等内容[^2]。尽管这份文档主要针对ARMv7-A和R系列,但它也包含了大量通用的信息,可以帮助理解整个ARMv7家族的特点。 2. **《ARM Cortex-A Series Programmers Guide》** 此程序员指南专注于Cortex-A系列处理器的设计理念及其优化方法。通过学习此书,开发者能够掌握如何充分利用硬件特性来提升软件性能。 3. **《Embedded Linux Primer: A Practical Real-Time Approach》 by Christopher Hallinan** 本书虽然不是专门讨论ARMv7l架构的书籍,但其内容涉及到了许多与之相关的主题——比如如何构建适合特定SoC平台的定制化Linux发行版,并且书中还提到了一些实际案例研究,这些都可以为从事基于ARMv7l芯片组项目的工程师提供宝贵的实践经验。 #### 技术细节说明 - **异常处理机制**: 在设计可靠的实时控制系统时非常重要的一环就是妥善管理和响应各种类型的中断请求(IRQs)和服务调用(SVCs)。了解并实现高效的异常处理流程有助于提高整体系统的稳定性和反应速度。 - **存储器保护单元(MPU)**: 对于那些需要额外安全防护措施或者隔离不同进程之间访问权限的应用场合来说,合理配置MPU显得尤为必要。它可以防止恶意代码破坏敏感数据区域或是未经授权擅自修改关键参数设置等情况发生。 ```c // 示例:初始化MPU区域 void mpu_configure_region(uint32_t base_address, uint32_t size, uint8_t access_permissions){ // 设置基址寄存器 MPU->RBAR = (base_address & ~0xFF) | REGION_VALID; // 配置属性字段 MPU->RASR = ((size - 1) << 1) | XN_BIT | AP_BITS(access_permissions); } ``` 上述函数展示了如何利用裸机环境下的汇编语言去定义一个新的受控内存区间;其中`access_permissions`变量决定了目标区域内对象可被执行还是仅限读写操作等功能选项。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雷达爆破手

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值