vesperW · 2023年08月07日

ARM处理器Bootloader底层流程

前面给大家分享过Bootloader从应用角度执行的相关文章,今天从底层原理来给大家描述ARM处理器如何编写Bootloader,以及底层流程。

关于Bootloader

Bootloader顾名思义就是引导加载程序,是在操作系统或应用程序运行之前的一段程序,是在系统上电后执行的一段程序代码。

BootLoader是严重地依赖于硬件而实现的,特别是在嵌入式平台。因此,在嵌入式平台里建立一个通用的BootLoader几乎是不可能的。尽管如此,我们仍然可以对bootloader归纳出一些通用的概念来,以指导用户特定的BootLoader设计与实现。

---来源百度百科

Bootloader在手机、电脑、众多嵌入式系统中都存在,它的作用有很多,比如:初始化底层应用驱动、加载应用程序、更新应用程序等。

不同的设备,Bootloader可能差异很大,通常来说Bootloader比较依赖底层硬件和实际项目需求。

如何编写bootloader

bootloader是一段引导加载程序代码,它更新用户的应用程序代码,可以使用很多硬件下载通道(例如USB、网络端口)获得新代码。

在执行引导ROM之后,将执行bootloader程序,并在需要时进行更新,然后执行最终用户应用程序。

引导加载程序和用户应用程序应作为两个独立的Project或Object进行编写和编译,从而产生两个独立且可执行的(bin/hex)文件。

引导加载程序的主要任务是在必要时对用户应用程序进行重新编程/替换,并跳转至用户应用程序以执行该程序,应用程序不一定需要知道引导加载程序的存在。

引导加载程序通常位于芯片闪存基址,下面通过一张图来描述内存和Flash代码映射关系:

image.png

有很多方法可以引导bootloader进入编程模式,以将用户应用程序重新编程到Flash中,或者直接跳转到现有的用户应用程序来执行。最简单的方法是检查GPIO引脚以确定是否应进入编程模式。

大多数芯片供应商为用户提供了一种方便的方式,例如 ISP 和 IAP 接口,bootloader将使用它们来更新闪存内容。

当Flash内容已更新或已经是最新时,引导加载程序将跳转到用户应用程序。在执行用户应用程序之前,这需要许多步骤:

1.确保CPU处于特权模式。
2.禁用NVIC中所有启用的中断。
3.禁用所有可能产生中断请求的使能外设,并清除这些外设中的所有未使用中断标志。
4.清除NVIC中所有未使用的中断请求。
5.禁用SysTick并清除其异常挂起位。
6.如果引导加载程序使用了单个故障处理程序,请禁用它们。
7.如果发现内核当前与PSP一起运行,则激活MSP(由于编译器可能仍在使用堆栈,因此在此之前需要将PSP复制到MSP)。
8.将用户应用程序的向量表地址加载到SCB-> VTOR寄存器中。确保地址符合对齐要求。
9.最后一部分是将MSP设置为用户应用程序向量表中找到的值,然后将用户应用程序的重置向量值加载到PC中,也就是跳转功能。

比如通过调用下面的示例BootJump()这样的函数来完成此操作:

static void BootJump(uint32_t *Address)``{` `//1.确保CPU处于特权模式。``  if( CONTROL_nPRIV_Msk & __get_CONTROL())` `{  /* not in privileged mode */``    EnablePrivilegedMode() ;` `}` `//2.禁用NVIC中所有启用的中断。` `Disable_All_Peripherals();` `//3.禁用所有可能产生中断请求的使能外设,并清除这些外设中的所有未使用中断标志。` `NVIC->ICER[ 0 ] = 0xFFFFFFFF;` `NVIC->ICER[ 1 ] = 0xFFFFFFFF;` `NVIC->ICER[ 2 ] = 0xFFFFFFFF;` `NVIC->ICER[ 3 ] = 0xFFFFFFFF;` `NVIC->ICER[ 4 ] = 0xFFFFFFFF;` `NVIC->ICER[ 5 ] = 0xFFFFFFFF;` `NVIC->ICER[ 6 ] = 0xFFFFFFFF;` `NVIC->ICER[ 7 ] = 0xFFFFFFFF;` `//4.清除NVIC中所有未使用的中断请求。` `NVIC->ICPR[ 0 ] = 0xFFFFFFFF;` `NVIC->ICPR[ 1 ] = 0xFFFFFFFF;` `NVIC->ICPR[ 2 ] = 0xFFFFFFFF;` `NVIC->ICPR[ 3 ] = 0xFFFFFFFF;` `NVIC->ICPR[ 4 ] = 0xFFFFFFFF;` `NVIC->ICPR[ 5 ] = 0xFFFFFFFF;` `NVIC->ICPR[ 6 ] = 0xFFFFFFFF;` `NVIC->ICPR[ 7 ] = 0xFFFFFFFF;` `//5.禁用SysTick并清除其异常挂起位。` `SysTick->CTRL = 0;` `SCB->ICSR |= SCB_ICSR_PENDSTCLR_Msk;` `//6.如果引导加载程序使用了单个故障处理程序,请禁用它们。` `SCB->SHCSR &= ~( SCB_SHCSR_USGFAULTENA_Msk | \`` SCB_SHCSR_BUSFAULTENA_Msk | \ `` SCB_SHCSR_MEMFAULTENA_Msk ) ;` `//7.如果发现内核当前与PSP一起运行,则激活MSP``  if( CONTROL_SPSEL_Msk & __get_CONTROL())` `{  /* MSP is not active */``    __set_MSP( __get_PSP()) ;``    __set_CONTROL( __get_CONTROL() & ~CONTROL_SPSEL_Msk);` `}` `//8.将用户应用程序的向量表地址加载到SCB-> VTOR寄存器中。` `SCB->VTOR = ( uint32_t )Address ;` `//9.跳转``  BootJumpASM( Address[ 0 ], Address[ 1 ]);``}

再次说明bootloader与底层硬件和实际需求有关,以上代码仅供参考,主要是提供思路,方便大家理解。

如果还不能理解,建议结合bootloader实际项目进行理解,比如之前给大家分享过的:STM32官方IAP例程详细说明

END

作者:strongerHuang
文章来源:strongerHuang

推荐阅读

欢迎大家点赞留言,更多Arm技术文章动态请关注极术社区嵌入式客栈专栏欢迎添加极术小姐姐微信(id:aijishu20)加入技术交流群,请备注研究方向。
推荐阅读
关注数
2839
内容数
172
分享一些在嵌入式应用开发方面的浅见,广交朋友
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息