0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

bootloader的原理及实现过程详解

嵌入式应用开发 来源:嵌入式应用开发 作者:嵌入式应用开发 2022-06-18 17:57 次阅读

一、背景

嵌入式操作系统中,BootLoader是在操作系统内核运行之前运行。可以初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境。在嵌入式系统中,通常并没有像BIOS那样的固件程序

二、实现思路

bootloader其实就是一段启动程序,它在芯片启动的时候首先被执行,它可以用来做一些硬件的初始化,当初始化完成之后跳转到对应的应用程序中去。

我们可以将内存分为两个区,一个是启动程序区(0x0800 0000 - 0x0800 2000 )大小为8K Bytes,剩下的为应用程序区(0x0800 2000 - 0x0801 0000)。

芯片上电时先运行启动程序,然后跳转到应用程序区执行应用程序。

三、程序跳转

bootloader一个主要的功能就是首先程序的跳转。在STM32中只要将要跳转的地址直接写入PC寄存器,就可以跳转到对应的地址中去。

怎么实现呢?

当我们实现一个函数的时候,这个函数最终会占用一段内存,而它的函数名代表的就是这段内存的起始地址。当我们调用这个函数的时候,单片机会将这段

内存的首地址(函数名对应的地址)加载到PC寄存器中,从而跳转到这段代码来执行。那么我们也可以利用这个原理,定义一个函数指针,将这个指针指向我们

想要跳转的地址,然后调用这个函数,就可以实现程序的跳转了。

代码如下:

#define  APP_ADDR  0x08002000   //应用程序首地址定义 
typedef void (*APP_FUNC)(); //函数指针类型定义

APP_FUNC jump2app; //定义一个函数指针

jump2app = ( APP_FUNC )(APP_ADDR + 4); //给函数指针赋值
jump2app(); //调用函数指针,实现程序跳转

上面的代码实现了我们要的跳转功能,但是为什么要跳转到(APP_ADDR + 4) 这个地址,而不是APP_ADDR.

首先我们要了解主控芯片的启动过程。以STM32为例,在芯片上电的时候,首先会从内存地址位0x0800 0000(由启动模式决定)的地方加载栈顶地址(4字节),从0x0800 0004的地方加载程序复位地址(4字节),然后跳转到对应的复位地址去执行。

所以上面的程序会中,jump2app这个函数指针的地址为(APP_ADDR + 4),调用这个函数指针的时候,芯片内核会自动跳转到这个指针指向的内存地址,也即是应用程序的复位地址。

四、加载栈地址

实际运行会发现,上面的程序可能会出现问题。因为我们还缺少了一个栈地址的加载过程,也就是芯片上电的第一个动作。这里要用到一点汇编的知识:

__asm void MSR_MSP(uint32_t addr)
{
    MSR MSP, r0
    BX r14;
}
__asm void MSR_MSP(uint32_t addr) 是MDK嵌入式汇编形式。

MSR MSP, r0 意思是将r0寄存器中的值加载到MSP(主栈寄存器,复位时默认使用)寄存器中,r0中保存的是参数值,即addr的值

BX r14 跳转到连接寄存器保存的地址中,即退出函数,跳转到函数调用地址

完整的程序如下:

#define APP_ADDR 0x08002000 //应用程序首地址定义 
typedef void (*APP_FUNC)(); //函数指针类型定义

/**
  * @brief
  * @param
  * @retval
  */
__asm void MSR_MSP(uint32_t addr)
{
    MSR MSP, r0
    BX r14;
}


/**
  * @brief
  * @param
  * @retval
  */
void run_app(uint32_t app_addr)
{
    uint32_t reset_addr = 0;
    APP_FUNC jump2app;
    
    /* 跳转之前关闭相应的中断 */
    NVIC_DisableIRQ(SysTick_IRQn);
    NVIC_DisableIRQ(LPUART_IRQ);
    
    /* 栈顶地址是否合法(这里sram大小为8k) */
    if(((*(uint32_t *)app_addr)&0x2FFFE000) == 0x20000000)
    {
        /* 设置栈指针 */
        MSR_MSP(app_addr);
        /* 获取复位地址 */
        reset_addr = *(uint32_t *)(app_addr+4);
        jump2app = ( APP_FUNC )reset_addr;
        jump2app();
    }
    else
    {
        printf("APP Not Found!n");
    }
}

五、编译设置

我们需要在设置界面将默认(0x8000000)改为我们的应用程序地址(0x8002000)

poYBAGKtoIGAOtpZAAGKkMPFU-E907.png

六、中断向量表重映射

完成了上面的工作,实际测试发现程序还是无法正确运行。原因是我们没有进行中断向量表的重映射。向量表映射?什么时候有做过这个工作,我们来看一下:

.s文件里有如下代码:

; Reset handler routine
Reset_Handler    PROC
                 EXPORT  Reset_Handler                 [WEAK]
        IMPORT  __main
        IMPORT  SystemInit  
                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main
                 BX      R0
                 ENDP

这代码表示,程序在执行main函数之前,会先执行SystemInit这个函数。下面看看这个函数:

/**
  * @brief  Setup the microcontroller system.
  * @param  None
  * @retval None
  */
void SystemInit (void)
{
/*!< Set MSION bit */
  RCC->CR |= (uint32_t)0x00000100U;

  /*!< Reset SW[1:0], HPRE[3:0], PPRE1[2:0], PPRE2[2:0], MCOSEL[2:0] and MCOPRE[2:0] bits */
  RCC->CFGR &= (uint32_t) 0x88FF400CU;

  /*!< Reset HSION, HSIDIVEN, HSEON, CSSON and PLLON bits */
  RCC->CR &= (uint32_t)0xFEF6FFF6U;

  /*!< Reset HSI48ON  bit */
  RCC->CRRCR &= (uint32_t)0xFFFFFFFEU;

  /*!< Reset HSEBYP bit */
  RCC->CR &= (uint32_t)0xFFFBFFFFU;

  /*!< Reset PLLSRC, PLLMUL[3:0] and PLLDIV[1:0] bits */
  RCC->CFGR &= (uint32_t)0xFF02FFFFU;

  /*!< Disable all interrupts */
  RCC->CIER = 0x00000000U;

  /* Configure the Vector Table location add offset address ------------------*/
#ifdef VECT_TAB_SRAM
  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
#else
  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
#endif
}

从上面的代码可以看到,这个函数主要是做了时钟的初始化和中断初始化,还有就是中断向量表的映射,就是最后那一段代码

poYBAGKtoMKAO1bzAAD8OXA5lO8440.png

再看看FLASH_BASE 和 VECT_TAB_OFFSET的定义:

poYBAGKtoOCAIUjEAAEZB3-GFsQ012.png

这里默认映射地址就是FLASH的初始地址,所以只要将其改成我们程序的起始地址就行了: SCB->VTOR = 0x08002000

编译,运行,下载.

七、总结

程序跳转完成,对于bootloader来说也就完成了一大半。剩下的就是根据自己的需求去完善相应功能了,比如我的在线升级功能,就要在bootloader里做固件接收和校验的功能。这里有一点需要特别注意的是,跳转程序之前最好把你用到的中断都关了,不然跳转之后的程序没有对应的中断处理函数,那就又可能使得程序进入死循环中。

审核编辑:符乾江

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式
    +关注

    关注

    5082

    文章

    19104

    浏览量

    304759
  • Boot
    +关注

    关注

    0

    文章

    149

    浏览量

    35822
收藏 人收藏

    评论

    相关推荐

    自定义RISC V的bootloader-v2

    在生成SoC时,会生成一个预定义bootloader .bin文件,用于指定soc的工程运行的地址,这包括在flash的存储地址 ,加载到外存中的运行地址及在外存中分配的存储空间的大小 。下面我们
    的头像 发表于 10-31 12:37 598次阅读
    自定义RISC V的<b class='flag-5'>bootloader</b>-v2

    SATA主机协议的物理层的实现过程

    这里讲解SATA主机协议的物理层的实现过程
    的头像 发表于 10-22 15:17 269次阅读
    SATA主机协议的物理层的<b class='flag-5'>实现</b><b class='flag-5'>过程</b>

    bootloader和应用程序之间共享FEE块

    电子发烧友网站提供《在bootloader和应用程序之间共享FEE块.pdf》资料免费下载
    发表于 10-10 09:18 0次下载
    在<b class='flag-5'>bootloader</b>和应用程序之间共享FEE块

    如何开发不带Flash API 的Bootloader实现在线升级

    电子发烧友网站提供《如何开发不带Flash API 的Bootloader实现在线升级.pdf》资料免费下载
    发表于 09-12 09:41 0次下载
    如何开发不带Flash API 的<b class='flag-5'>Bootloader</b><b class='flag-5'>实现</b>在线升级

    简述拉曼散射效应的实现过程

    拉曼散射效应,作为一种重要的光学现象,其实现过程涉及光与物质之间复杂的相互作用。以下将详细阐述拉曼散射效应的实现过程,包括基本原理、实验观察、理论解释以及应用等方面。
    的头像 发表于 08-16 17:08 489次阅读

    PLC对模拟量信号的处理过程及方法 详解

    )。 PLC通过计算转换,将这些模拟量信号转换为内部的数值信号。从而实现系统的监控及控制。从现场的物理信号到PLC内部处理的数值信号,有以下几个步骤: 从以上PLC模拟量的信号输入流程可以看到,在自动化过程控制系统中,模拟量信号的输入是非
    的头像 发表于 07-30 16:31 400次阅读
    PLC对模拟量信号的处理<b class='flag-5'>过程</b>及方法 <b class='flag-5'>详解</b>版

    YTM32的HA系列微控制器启动过程详解

    见,以确保信息安全的需要。然而,开发者在自行编译固件时,需要配合BOOT ROM中的bootloader,才能正常地引导到用户应用程序,完成启动过程
    的头像 发表于 07-15 09:24 407次阅读
    YTM32的HA系列微控制器启动<b class='flag-5'>过程</b><b class='flag-5'>详解</b>

    LwIP协议栈源码详解—TCP/IP协议的实现

    电子发烧友网站提供《LwIP协议栈源码详解—TCP/IP协议的实现.pdf》资料免费下载
    发表于 07-03 11:22 3次下载

    IDF-4.4.2在修改boot过程中,编译有提示bootloader受到partition-table offset的限制,为什么?

    我在 IDF-4.4.2在修改boot过程中,编译有提示bootloader受到partition-table offset的限制,如下图 可当我用menuconfig修改后,发现从0XC000
    发表于 06-14 06:27

    如何才能将Bootloader和Application关联起来

    接下来,我们要利用该Bootloader调试目标Application Project,如何才能将Bootloader和Application关联起来呢?就需要借助刚才提到的Bootloader Project Build所生成
    的头像 发表于 06-12 14:32 684次阅读
    如何才能将<b class='flag-5'>Bootloader</b>和Application关联起来

    请问STM32的bootloader怎么制作?

    我对STM32也算是比较熟悉了,但是呢, 没有弄过 STM32的bootloader。也不知道怎么弄的。像,Linux,蓝牙等 都有 类型的demo 供你学习和开发。 请问,STM32的bootloader 官方有Demo吗?谢谢!
    发表于 03-07 07:50

    STM32案例:BootLoader是怎么跳到App

    BootLoader项目程序和App项目程序是分开的,所以需要分别搭建对应的项目工程文件,分开搭建文件是为了好配置,同时也是方便对项目进行管理。
    发表于 03-04 09:35 4210次阅读
    STM32案例:<b class='flag-5'>BootLoader</b>是怎么跳到App

    关于bootloader与bootloadable img合并的问题求解

    我们实现bootloader功能时, app0 当作bootloader, app1 当作bootloadable image,我们想让app0和app1 访问同一片EEPROM 8K的空间。但我
    发表于 02-21 08:17

    STM32无法进入片上Bootloader的处理方法

    STM32无法进入片上Bootloader的处理方法  当STM32芯片无法进入片上Bootloader时,我们需要采取一系列的处理方法来解决这个问题。以下将详细介绍一些常见的处理方法。 1.编程器
    的头像 发表于 02-02 14:33 2039次阅读

    请问IMC101T-038是否支持bootloader下载程序?

    想请问一下,038这款MCU是否支持bootloader下载程序呢?现在用这款芯片作为内置的风机驱动板,但用户后期想升级程序,请问一下可以怎么实现呢?如果这个实现不了,有没有其他型号的产品可以进行替换呢?只要能
    发表于 01-23 07:07