Cortex-M3 SoC的启动过程

   日期:2021-04-13     浏览:216    评论:0    
核心提示:介绍从C语言程序的编写到在裸机上运行的详细流程基本概念几种不同类型的存储器在过去的20年里,嵌入式系统一直使用ROM(EPROM)作为它们的存储设备,然而近年来Flash全面代替了ROM(EPROM)在嵌入式系统中的地位,用作存储Bootloader以及操作系统或者程序代码或者直接当硬盘使用(U盘)。...

ARM Cortex-M3 SoC运行程序的详细流程

目录

基本概念

几种不同类型的存储器

startup.s vs bootloader

启动模式

启动流程

1、编译链接

The _start Function

2、ROM的烧写

3、系统上电复位执行

4、main函数执行

基本概念

几种不同类型的存储器

RAM的读写速度比ROM快

在过去的20年里,嵌入式系统一直使用ROM(EPROM)作为它们的存储设备,然而近年来Flash全面代替了ROM(EPROM)在嵌入式系统中的地位,用作存储Bootloader以及操作系统或者程序代码或者直接当硬盘使用(U盘)。

参考链接:

https://www.huaweicloud.com/articles/9d767b49832fd1fd5c6d23163d87b83e.html

https://blog.csdn.net/u012351051/article/details/81034661

startup.s vs bootloader

相信很多嵌入式的Developer肯定知道startup.s(汇编文件)

它是系统的启动文件,程序上电复位之后第一个执行的程序,一般用来堆栈的初始化,设置中断向量表,以及跳转到main函数

但是学过操作系统的肯定知道bootloader,是一个系统的引导程序,同样是上电复位之后第一个执行的程序

那么两者到底是啥关系呢?谁先开始执行,谁后执行?哪一个执行哪一个不执行?如何执行?(可能自己之前是计算机专业的,对startup.s有困惑)

实际上:两者是干同样的事情的:先进行系统初始化,然后跳转到main函数运行程序

堆栈初始化

建立向量表

跳转到main函数

如果硬是要说区别的话,那就是bootloader要更加的复杂,能干的事情更多,通常如果要启动操作系统的话,或者写很复杂的程序的话就会使用到bootloader,说到这计算机背景的肯定就知道自己只接触过bootload了,因为基本计算机都要运行操作系统的

如果是普通的嵌入式应用的话,使用startup.s就好,

那具体分析一下,到底复杂到哪里

bootloader会有文件驱动或者网络驱动,因为通常操作系统是放在硬盘中的,boloader如果要加载操作系统到系统RAM的话,就必须能够读取文件内容,而有的操作系统是通过网络启动

还有一个就是重映射的问题remap:

一般来说,ROM存储器从0x0处开始编址,里面存放有异常中断向量,但是ROM的读写速度是没有RAM高的

为了提高系统的性能,bootloader会将ROM中的数据copy到RAM中,然后进行地址的重映射,即将RAM映射到0x0地址处,这样在发生异常中断的时候,访问的就是RAM,而不是ROM

参考链接:

https://stackoverflow.com/questions/15696258/what-is-the-bootloader-and-startup-code-in-embedded-systems

https://www.cnblogs.com/no7dw/archive/2012/06/28/2567113.html

https://blog.csdn.net/weiLongElectrophile/article/details/75043746

启动模式

从ROM启动/boot ROM启动

这里我所理解的是如果要使用bootloader的话,就从boot ROM启动,这是可选的模块,可以通过参数配置来设置启动的模式

 

一般简单的嵌入式是用不到boot ROM的,(M3默认是不启用boot ROM)

这部分的内容也看了相关的文章,感觉有一些地方不是很通顺,我还是把链接放过来

参考链接:

https://stackoverflow.com/questions/15665052/what-is-the-difference-between-a-bootrom-vs-bootloader-on-arm-systems

https://www.huaweicloud.com/articles/e7597769b186ee314625969ffa806654.html 

启动流程

从上面的分析可以知道M3 SoC是从room启动,使用的是startup.s

1、编译链接

C语言程序 + startup.s + libc库文件

ps:这里使用的编译工具是arm-none-eabi-gcc。arm的gcc工具链有好几种,都有不同的应用场景,不要弄混了

gcc工具在编译之后,会使用链接程序linker将它们链接到一起,至于为什么还有会用到libc库文件,这和startup.s有关

The _start Function

For most C and C++ programs, the true entry point is not main, it’s the _start function. This function initializes the program runtime and invokes the program’s main function.

The use of _start is merely a general convention. The entry function can vary depending on the system, compiler, and standard libraries. For example, OS X only has dynamically linked applications; the loader takes care of setup, and the entry point to the program is actually main.

The linker controls the program’s entry point. The default entry point can be overridden by clang and GCC linkers using the -e flag, although this is rarely done for most programs.

The implementation of the _start function is usually supplied by libc. The _start function is often written in assembly. Many implementations store the _start function in a file called crt0.s. Compilers typically ship with pre-compiled crt0.o object files for each supported architecture.

大概的意思是:

  • C程序的入口点通常并不是main,而是start。
  • 是在start中跳转到main函数执行用户程序。这是通常的一种做法
  • start的实现依赖操作系统,编译器以及标准库等等

最后在编译之后,将这三部分链接形成一个完整的程序(通常这并不是直接能够运行在裸机上的文件,还需要转换成hex文件)

ps:这里分析一波startup.s文件干了什么事情

通常linker会将startup.s的相关内容放在这个完整的程序的开头

那么它干了什么事呢?

看图

解释一波:

首先就是堆栈的初始化(记住:裸机上要执行程序,首先就是要初始化一个堆栈,建立一个程序执行的环境)

然后是设置中断向量表(中断向量表第一个字是MSP,第二个字是reset handler的入口地址,后面解释)

最后是跳转到start函数,然后再跳转到main函数

 

2、ROM的烧写

有了可执行的程序了,接下来就是通过烧写工具将其烧写到ROM中,(不需要关心,知道ROM的数据是如何来的就好)

3、系统上电复位执行

由上面的分析可以知道:

0x0:存放的是MSP(主栈指针)

0x4:存放的是PC(reset handler的入口地址)

系统上电复位之后,PC指针指向0x0出

处理器自动读取0x0的MSP指针存放到处理器的内部状态寄存器,PC指向0x4地址处(一个字32位)

然后跳转到reset handler执行

那么reset handler干了什么事情呢?

  1. 就是将一些程序运行过程中的临时变量等需要改变的数据copy到RAM中(因为ROM在烧录之后是不能在写数据的),通常是.data段以及.bass段;而指令还是存放在ROM中的,因为指令只是读取,ROM允许读
  2. systemInit系统的初始化,
  3. 跳转到start函数

4、main函数执行

从start跳到main函数,这样就执行用户程序了~~

OK,OK(OK怪上线,哈哈哈),明白了吧~~哈哈

ps:start通常会干啥事?

Program startup code behavior is not specified by the C and C++ standards. Instead, the standards describe the conditions that must be true when the main function is called. However, there are many steps that are commonly performed across the majority of _start implementations.

At a high level, the _start function handles:

  1. Early low-level initialization, such as:
    1. Configuring processor registers
    2. Initializing external memory
    3. Enabling caches
    4. Configuring the MMU
  2. Stack initialization, making sure that the stack is properly aligned per the ABI requirements
  3. Frame pointer initialization
  4. C/C++ runtime setup
  5. Initializing other scaffolding required by the system
  6. Jumping to main
  7. Exiting the program with the return code from main

While the _start routine typically encompasses these activities, the specific order and implementation varies from system to system. For example, early low-level initialization code is commonly found with bare-metal embedded systems, but rarely on host machines with an OS. Your Linux or OS X program startup code will have multiple scaffolding functions which you will not find in embedded startup code.

(这里我就不说了,感兴趣的自己去了解~)

下面贴了链接~~~

 

最后最后,上面都是自己个人的总结和见解,希望能够帮到大家

另外这里的谁太深了,还有很多东西我没有分析,这里就不在多少了,够用就好~~~,感兴趣的自己去看吧~,就在下面最后的链接 investigating what it takes to get to main。

谢谢大家,能够看到这里,希望能够帮到你们~~~哈哈

 

参考链接:

https://www.jianshu.com/p/fd0103d59d8e

https://blog.csdn.net/kagaobin/article/details/84198141

investigating what it takes to get to main

 

 

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
更多>相关资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服