0


【BES2500x系列 -- RTX5操作系统】系统执行流程 -- 引导程序(boot loader)--(十)

请添加图片描述

  • 💌 所属专栏:【BES2500x系列】
  • 😀 作  者:我是夜阑的狗🐶
  • 🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询!
  • 💖 欢迎大家:这里是CSDN,我总结知识的地方,喜欢的话请三连,有问题请私信 😘 😘 😘

您的点赞、关注、收藏、评论,是对我最大的激励和支持!!!🤩 🤩 🤩

请添加图片描述

文章目录


<<【系列文章索引】>>

前言

  大家好,又见面了,我是夜阑的狗🐶,本文是专栏【BES2500x系列】专栏的第10篇文章;
  今天开始学习BES2500x系列的一天💖💖💖,开启新的征程,记录最美好的时刻🎉,每天进步一点点。
  专栏地址:【BES2500x系列】, 此专栏是我是夜阑的狗对BES2500x系列开发过程的总结,希望能够加深自己的印象,以及帮助到其他的小伙伴😉😉。
  如果文章有什么需要改进的地方还请大佬不吝赐教👏👏。


1 引导程序(boot loader)

  前面学习了嵌入式系统启动的基本流程,可以分为 引导程序 和 系统初始化程序 这两部分,也对一些概念进行了讲解。接下来就来 引导程序 是怎么跑的吧,也就是 boot loader。话不多说,让我们原文再续,书接上回吧。

请添加图片描述

1.1 启动文件

  从上一篇文章中可以知道,引导程序一般都是以 汇编语言编写,所以其文件后缀为 .s 文件,在

platform/main

就能看到有这么一个文件:

startup_main.S

,如下图所示:

在这里插入图片描述

  很明显这个就是

boot loader

的启动文件里,接下来就让我们来看里面具体都干了什么吧,启动文件由汇编编写,是系统上电复位后第一个执行的程序。主要做了以下工作:

Step 1、配置汇编启动文件
Step 2、初始化堆栈指针

 SP

(__initial_sp);
Step 3、初始化

PC

指针(Reset_Handler);
Step 4、初始化中断向量表(__Vectors);
Step 5、配置系统时钟(SystemInit);
Step 6、数据段初始化;
Step 7、一般情况是调用C库函数_main来初始化用户堆栈,从而最终调用main函数去到C的世界;

1.1.1 启动加载程序
  • 代码

  在讲解启动代码的时候,会涉及到

ARM

的汇编指令和

Cortex

内核的指令

.syntax    unified

    .section .boot_loader,"ax",%progbits
    .thumb
    .thumb_func
    .align  2.globl  Boot_Loader
    .type   Boot_Loader,%function
  • 参数/函数讲解

  这段代码是用 ARM 汇编语言编写的启动加载程序(

boot loader

)。让我们来逐行解释:
序号参数/函数说明1.syntax unified这是汇编器指示使用统一语法格式的指令2.section .boot_loader, “ax”, %progbits这条指令定义了一个名为 .boot_loader 的段,属性为可执行(a)和可读(x),内容类型为程序代码(%progbits)3.thumb该指令告诉汇编器使用Thumb指令集,Thumb是ARM处理器的一种指令集,它可以使得代码更加紧凑4.thumb_func同上5.align 2这是对齐指令,确保后续指令在内存中按2字节对齐6.globl Boot_Loader这是一个全局符号定义指令,声明了一个名为 Boot_Loader 的全局符号,使得它可以在其他文件中访问7.type Boot_Loader, %function这是类型定义指令,将 Boot_Loader 标记为一个函数

1.1.2 设置堆栈指针
  • 代码

  这段代码的作用是设置堆栈指针,为程序的执行做准备。接下来是函数的实现:

Boot_Loader:
    ldr     r0,=__StackTop
    msr     msp, r0
/* Always use MSP and set privileged mode */
    movs    r0, #0
    msr     control, r0
    isb

#ifndefNO_NVIC_INIT
    bl      NVIC_InitVectors
#endif#ifndefNO_BOOT_INIT
    bl      BootInit
#endif#ifndefNO_SYSTEM_INIT
    bl      SystemInit
#endif
  • 参数/函数讲解

  这段代码的作用是在设置好堆栈指针后,进行一些系统的初始化工作,包括设置特权级别、执行启动前初始化钩子、初始化中断向量表、执行启动初始化和系统初始化。条件编译部分根据预定义的宏来选择是否执行相应的初始化操作。
序号参数/函数说明1ldr r0, =__StackTop这条指令将栈顶地址 __StackTop 的值加载到寄存器 r0 中2msr msp, r0这条指令将寄存器 r0 中的值(即栈顶地址)写入主堆栈指针寄存器 msp 中,从而设置了栈顶地址3movs r0, #0这条指令将常数0移动到寄存器 r0 中4msr control, r0这条指令将寄存器 r0 中的值(即常数0)写入到控制寄存器 control 中,用于设置特权级别。并且决定使用哪一个堆栈指针5isb这是指令同步栅栏指令,确保在修改特权级别后立即执行。
  接下来是一些条件编译的部分:
序号参数/函数说明1#ifndef NO_NVIC_INIT这是另一个预处理器指令,用于检查是否没有定义 NO_NVIC_INIT 宏。如果没有定义,那么会调用 NVIC_InitVectors 函数,用于初始化中断向量表。2#ifndef NO_BOOT_INIT同样是预处理器指令,用于检查是否没有定义 NO_BOOT_INIT 宏。如果没有定义,那么会调用 BootInit 函数,用于执行启动初始化,配置系统时钟3#ifndef NO_SYSTEM_INIT同样是预处理器指令,用于检查是否没有定义 NO_SYSTEM_INIT 宏。如果没有定义,那么会调用 SystemInit 函数,用于执行系统初始化

1.1.3 数据段初始化
  • 代码
    ldr    r1,=__etext
    ldr    r2,=__data_start__
    ldr    r3,=__data_end__

.L_loop1:
    cmp    r2, r3
    ittt    lt
    ldrlt    r0,[r1], #4
    strlt    r0,[r2], #4
    blt    .L_loop1
  • 参数/函数讲解

  这部分代码执行了数据段的初始化,将程序的只读数据段(

.text 段

)中的数据复制到RAM中的数据段(

.data 段

)中。
序号参数/函数说明1ldr r1, =__etext将只读数据段的结束地址 __etext 加载到寄存器 r1 中2ldr r2, =__data_start__将RAM中数据段的起始地址 data_start 加载到寄存器 r2 中3ldr r3, =__data_end__将RAM中数据段的结束地址 data_end 加载到寄存器 r3 中
  然后,使用一个循环(

标签 .L_loop1

)来逐个复制数据:
序号参数/函数说明1cmp r2, r3比较寄存器 r2 和 r3 中的值,检查是否到达数据段的结束地址2ittt lt这是一个条件执行指令,当 lt(小于)条件成立时,执行后续的指令3ldrlt r0, [r1], #4如果 r2 小于 r3,则从只读数据段中加载一个32位数据到寄存器 r0 中,并递增只读数据段的地址4strlt r0, [r2], #4如果 r2 小于 r3,则从只读数据段中加载一个32位数据到寄存器 r0 中,并递增只读数据段的地址5blt .L_loop1如果 r2 小于 r3,则继续循环,否则跳出循环
  这段代码的作用是将只读数据段中的初始化数据复制到

RAM

中的数据段中,以便程序运行时可以修改这些数据。

1.1.4 调用 main 函数
  • 代码
#ifdefined(__ARMCC_VERSION)&&!defined(NOSTD)||defined(NUTTX_BUILD)
    bl    __rt_entry
#else
    bl    _start
#endif.pool
    .size    Boot_Loader,.- Boot_Loader

    .end
  • 参数/函数讲解

  这段代码根据条件调用不同的函数作为程序的入口点:如果使用的是

ARMCC

编译器且未定义

NOSTD

宏,或者是

NuttX

构建环境,那么将调用

__rt_entry

函数。否则,将调用

_start

函数。基本到这里上

bootloader

算是完成它的工作了。 然后,使用

.pool

指令和

.size

指令对

Boot_Loader

函数进行处理。
序号参数/函数说明1.pool这个指令用于池区,是一种链接指令,用于优化分支指令。它的存在告诉链接器将后续的分支指令(例如 bl)尽可能地放在一起2.size这个指令指定了 Boot_Loader 函数的大小,用于告诉链接器该函数的长度。. Boot_Loader 表示从当前位置到 Boot_Loader 标签之间的距离,即函数的长度。3.end指明了汇编文件的结束<<【系列文章索引】>>
请添加图片描述


总结

**  感谢观看,这里就是 boot loader 引导程序的讲解,如果觉得有帮助,请给文章点个赞吧,让更多的人看到。🌹 🌹 🌹**

在这里插入图片描述

**  也欢迎你,关注我。👍 👍 👍**

**  原创不易,还希望各位大佬支持一下,你们的点赞、收藏和留言对我真的很重要!!!💕 💕 💕 最后,本文仍有许多不足之处,欢迎各位认真读完文章的小伙伴们随时私信交流、批评指正!下期再见。🎉**

**更多专栏订阅: **

  • 😀 【LeetCode题解(持续更新中)】
  • 🥇 【恒玄BES】
  • 🌼 【鸿蒙系统】
  • 💎 【蓝牙协议栈】
  • 🎃 【死机分析】
  • 👑 【Python脚本笔记】
  • 🚝 【Java Web项目构建过程】
  • 💛 【微信小程序开发教程】
  • ⚽ 【JavaScript随手笔记】
  • 🤩 【大数据学习笔记(华为云)】
  • 🦄 【程序错误解决方法(建议收藏)】
  • 🔐 【Git 学习笔记】
  • 🚀 【软件安装教程】

订阅更多,你们将会看到更多的优质内容!!

标签: arm stm32 系统架构

本文转载自: https://blog.csdn.net/csh1807266489/article/details/138521241
版权归原作者 我是夜阑的狗 所有, 如有侵权,请联系我们删除。

“【BES2500x系列 -- RTX5操作系统】系统执行流程 -- 引导程序(boot loader)--(十)”的评论:

还没有评论