从0写bootloader — Bootloader重定位APP

Bootloader重定位APP

一般情况下,不会采用APP重定位自己。假如APP程序存放在外接的SPI Flash或者SD卡上,
SPI Flash和SD卡是不支持XIP的,APP代码无法执行,重定位代码也是APP代码的一部分,何谈重定位自己。

此时就需要要采用Bootloader重定位APP的策略了。

Bootloader重定位APP程序需要知道APP的加载地址和链接地址,但是Bootloader程序和APP一般在是不同Project的程序,无法直接得到加载地址和链接地址。

a、固定地址重定位,可以写死加载地址和链接地址,还要计算APP程序的大,不太可靠的样子
b、给APP程序加上头部,头部包含加载地址、链接地址、长度、CRC校验等,APP可以决定APP的链接地址和加载地址,而不是写死。


Bootloader重定位APP实现

使用u-boot的mkimage给APP加头部

执行./mkimage可以查看用法,mkimage.exe用window cmd和powershell无法执行,需要使用git bash
在这里插入图片描述

使用mkimage工具给APP加头部

opto@DESKTOP-ET42CRG MINGW64 /g/Myself/myself/bootloader_stm32/03_Bootloader_relocate_app/app
$ ./mkimage -C none -a 0x800B000 -e 0x20000000 -d app.bin app_with_header.bin
Image Name:
Created:      Mon Jul 18 10:36:44 2022
Image Type:   PowerPC Linux Kernel Image (uncompressed)
Data Size:    420 Bytes = 0.41 KiB = 0.00 MiB
Load Address: 0800b000
Entry Point:  20000000

Bootloader解析头部重定位执行APP

mkimage给APP添加的头部信息的格式如下结构体:
u-boot源码include/image.h中定义

#define IH_NMLEN		32	     /* Image Name Length  */

typedef struct image_header {
	__be32		ih_magic;	/* Image Header Magic Number	*/
	__be32		ih_hcrc;	/* Image Header CRC Checksum	*/
	__be32		ih_time;	/* Image Creation Timestamp	*/
	__be32		ih_size;	/* Image Data Size		*/
	__be32		ih_load;	/* Data	 Load  Address		*/
	__be32		ih_ep;		/* Entry Point Address		*/
	__be32		ih_dcrc;	/* Image Data CRC Checksum	*/
	uint8_t		ih_os;		/* Operating System		*/
	uint8_t		ih_arch;	/* CPU architecture		*/
	uint8_t		ih_type;	/* Image Type			*/
	uint8_t		ih_comp;	/* Compression Type		*/
	uint8_t		ih_name[IH_NMLEN];	/* Image Name		*/
} image_header_t;
  • __be32 表示该字段是使用的是大端字节序,在解析头部时还需要将该字段转换成使用的MCU对应的字节序。

程序实现:
start.s:

				PRESERVE8    ; instruct is aligned by 8 bytes 指令集8字节对齐
                THUMB        ; use Thumb instruction set    使用thumb指令集
					
				AREA    RESET, DATA, READONLY  ;DATA定义数据段,READONLY只读
				EXPORT  __Vectors

VECTOR_REG_ADD  EQU    0xE000ED08   

__Vectors       DCD     0                          ; CPU自动将该处的值设置给sp,Top of Stack
                DCD     Reset_Handler              ; Reset Handler 指令地址,CPU首先执行此句
				
				AREA    |.text|, CODE, READONLY    ; CODE表示定义代码段,READONLY只读
; Reset handler
Reset_Handler    PROC                 ; 子程序开始标志
				 EXPORT  Reset_Handler             [WEAK]   ; 
				 IMPORT  main               ; 
					
                 LDR     sp, = (0x20000000+0x10000)  ; 
			
                 BL     main                         ; 跳到C语言世界执行
         
                 ENDP				;
					 
boot_app    	PROC       ; 
				 EXPORT  boot_app    
				 
				 LDR R1, = VECTOR_REG_ADD
				 STR R0, [R1]  ; 向中断向量寄存器写入程序链接地址0x800B000
				 
				 LDR sp, [R0]  ;0x800B000地址处的值写入sp即设置栈
				 
				 ;LDR R3, [R1]
				 
				 LDR R2, [R0, #4]  ;  0x20000000 + 4 = 0x20000004,取出0x20000004地址处的值赋值给R2
				 		 
				 ;ADD R2, R0, #9
				 
                 BX     R2    ; 跳去执行APP
         
                 ENDP
				
				 END     ;汇编文件结
			 

main.c:

#include "usart.h"

typedef unsigned int __be32;
typedef unsigned char uint8_t;
typedef unsigned int uint32_t;

#define BOOTLOADER_VERSION    "1.4" 

#define APP_BIN_ADDR   0x800B000   /* APP在加载地址,自定义,放在哪都无所谓, */

#define IH_MAGIC	0x27051956	 /* Image Magic Number		*/
#define IH_NMLEN		32	     /* Image Name Length  */

#define __BE32_TO_CPU(x)   ( ( (x & 0x000000FF) << 24 ) | ( ( (x & 0x0000FF00)  >> 8 ) << 16) |  \
                           ( ( (x & 0x00FF0000) >> 16 ) << 8)  | ( ( (x & 0xFF000000 ) >> 24 ) ) )

typedef struct image_header {
	__be32		ih_magic;	/* Image Header Magic Number	*/
	__be32		ih_hcrc;	/* Image Header CRC Checksum	*/
	__be32		ih_time;	/* Image Creation Timestamp	*/
	__be32		ih_size;	/* Image Data Size		*/
	__be32		ih_load;	/* Data	 Load  Address		*/
	__be32		ih_ep;		/* Entry Point Address		*/
	__be32		ih_dcrc;	/* Image Data CRC Checksum	*/
	uint8_t		ih_os;		/* Operating System		*/
	uint8_t		ih_arch;	/* CPU architecture		*/
	uint8_t		ih_type;	/* Image Type			*/
	uint8_t		ih_comp;	/* Compression Type		*/
	uint8_t		ih_name[IH_NMLEN];	/* Image Name		*/
} image_header_t;

static void parse_head(uint32_t bin_addr, uint32_t *load, uint32_t *entry, uint32_t *size)
{
    image_header_t *hdr;
    
    hdr = (image_header_t *)bin_addr;
    
    uint32_t _load = __BE32_TO_CPU(hdr->ih_load);    /* 加载地址 */
    uint32_t _entry = __BE32_TO_CPU(hdr->ih_ep);     /* 链接地址 */
    
    uint32_t _size = __BE32_TO_CPU(hdr->ih_size);    /* 链接地址 */
        
    *load = bin_addr + sizeof(image_header_t);       /* APP真正开始的地址 */
    *entry = _entry;
    *size = _size;
}

static void relocate_app(char *from, char *to, unsigned int len)
{
	while (len--)
	{
		*to++ = *from++;
	}
}

void boot_app(uint32_t start_addr);

int main(void)
{
    uint32_t s_addr = APP_BIN_ADDR;
    uint32_t entry;
    uint32_t load;
    uint32_t size;
    
    uart_init();
    
    myputstr("\r\nBootloader: ");  
    myputstr(BOOTLOADER_VERSION);
	myputstr("  ");
    myputstr(__DATE__);
	myputstr("  ");
    myputstr(__TIME__);
    
    parse_head(s_addr, &load, &entry, &size);
    relocate_app((char *)load, (char *)entry, size);
    boot_app(entry);
	
	return 0;
}
  • #define APP_BIN_ADDR 0x800B000, APP在加载地址,自定义,放在哪都无所谓,此处放在STM32内部Flash,如果有外部SPI Flash或SD卡,也可以放在它们之中。
  • __BE32_TO_CPU,大端字节序转小端字节序
  • parse_head, 解析头部,获取加载地址、链接地址、程序大小等
  • relocate_app,重定位APP
  • boot_app,跳转执行APP
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

欲盖弥彰1314

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

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

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

打赏作者

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

抵扣说明:

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

余额充值