您尚未登录。

楼主 #1 2020-08-09 17:12:09

f_Endman
会员
注册时间: 2020-04-16
已发帖子: 55
积分: 137

分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

刚入门F1C没多久,自己写了个BootLoader玩,一定程度上参考了达克罗德大神的minimal

我把代码尽量优化了,最终Boot0总共不到3KB,这里面大部分都是设置DDR控制器的代码,但由于DDR控制器的资料太少了,我没有头绪怎么去编写和优化,就只好照搬了达神的代码。

这个BootLoader有一个比较大的特点就是Boot0部分链接到了SRAM里,而其他程序链接到DDR里,在加载程序到DDR时只加载用户代码,这样应该使用绝对地址码也不会出错。实现这一点的链接脚本下文会提到。

在时钟的初始化中,我把ARM内核频率和DDR频率都设置为了408MHz,受DDR1限制再高就说不准会出问题了。

仿照达神的信息头,我写了一个简化版的,只有加载长度和校验和两个变量,校验和由我写的一个工具在编译时生成,加载长度通过链接脚本可以得知,在编译时进行字节对齐即可。

与BootLoader有关的代码都在Boot0里,还有一个引用的头文件是我自己编写的寄存器结构体(写这个老费劲了XD)文件,如果一定要移到别的工程里只需要移植这几个文件即可,需要注意的是链接脚本的修改,可以参考下文。代码整体实现了较高的内聚度和较低的耦合度。在用户代码中可以完全当BootLoader不存在,值得注意的是跳转到DDR时直接跳转到链接首地址,此后BootLoader就永久留在了SRAM里。

目前Boot0部分关闭了中断,如果需要使用中断可以在用户程序里把中断向量表啥的设置好,然后CPSR里把bit[7:6]都置零以开启中断。

在编写过程中遇到过的几个比较大的坑:

  1. SRAM的地址和BROM是重合的,都是0x0开始,这与手册不一致,但影响不大,即使不知道也可以用位置无关码避免

  2. 手动设置SP指针时尽量不要指向DDR以外的区域比如SRAM,因为某些玄学因素我设置SP指针在SRAM里后入栈出栈就会出问题,这时使用上电自动设置好的SP指针即可(上电后SP指针指向0x9FE4)

  3. 硬件SPI的FIFO如果设置成字节读写,那就必须使用BYTE大小的指针读写,这其实是个比较低级的错误,但我查了好久。。Orz

  4. 链接脚本中如果把两段代码链接到不同的内存区域,这两个内存区域之间没用的部分也会被写入生成的文件,导致编译完的文件有好几个G大。。解决办法也很简单,只需要指定SRAM段后第一个DDR段在生成文件中的相对地址即可,这需要用AT()关键字实现,下面是链接脚本的一部分:

MEMORY
{
    sram : ORIGIN = 0x00000000, LENGTH = 24K
    ddr  : ORIGIN = 0x80000000, LENGTH = 32M
}

SECTIONS
{
    .boot0 :
    {
        Obj/Boot0.o (.text)
        Obj/ClockInit.o (.text)
        Obj/DDRInit.o (.text)
        Obj/SPIFlashInit.o (.text)
        Obj/CodeLoader.o (.text)
    } > sram
    __boot0_size = SIZEOF(.boot0);

    __image_file_start = .;

    .text : AT(__image_file_start)       //就是这里,表示代码链接到DDR内,但编译时存放在文件的__image_file_start处
    {
        PROVIDE(__image_start = .);
        Obj/start.o (.text)
        Obj/main.o (.text)
        *(.text)
        *(.note.gnu.build-id)
    } > ddr

    ……………………

}

这个文件里我的用户程序初始化了串口,打印测试了Data段、RoData段和BSS段的读写,然后就一直闪灯,需要注意的是我用的是一个外接的LED接到了PA0上灌电流驱动,大家如果需要测试可以修改或是直接删掉。

编译只需要make就行。
伪目标recompile用来重新编译工程。
伪目标write用来写入SPI Flash,这会调用sunxi-fel,这个工具所需要的运行库似乎在Ubuntu18下apt-get不到,我重装了Ubuntu16才能使用
伪目标maketool用来编译那个加载信息头的程序,一般应该用不到
伪目标clean用来清理工程,不用多说

目前只支持SPI Flash启动,大家可以自己添加SDIO的驱动来从SD卡加载程序

我写这段代码使用的是VSCode,这里面有些关于VSCode的文件忽略掉就行。

代码中对寄存器的每一位操作都有非常详细的注释,觉得看手册晕的可以瞄一眼0v0

其实这段代码要说实用性多高估计也谈不上,发出来主要是跟大家共同学习一下,以后有新人入坑也能多一个参考,少踩点坑

工程下载:BootLoader.zip

离线

#2 2020-08-09 18:51:15

达克罗德
会员
注册时间: 2018-04-10
已发帖子: 1,134
积分: 1086.5

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

支持,鼓励一下!

离线

#3 2020-08-09 20:41:24

三木同子
会员
注册时间: 2020-06-09
已发帖子: 42
积分: 32

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

这个可以用来启动 Kernel 吗?
UBoot 太复杂了

离线

#4 2020-08-09 20:43:47

明月照我沟渠
会员
注册时间: 2020-07-09
已发帖子: 120
积分: 114

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

Q群看到有朋友用 u-boot的spl直接引导Linux, 但是不知道怎么玩.

离线

#5 2020-08-09 20:50:42

Quotation
会员
注册时间: 2018-10-04
已发帖子: 289
积分: 271.5

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

不错,很精简。

离线

楼主 #6 2020-08-09 21:20:32

f_Endman
会员
注册时间: 2020-04-16
已发帖子: 55
积分: 137

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

三木同子 说:

这个可以用来启动 Kernel 吗?
UBoot 太复杂了

没试过,应该够呛,这个写来主要是引导裸机程序用的

离线

楼主 #7 2020-08-09 21:21:13

f_Endman
会员
注册时间: 2020-04-16
已发帖子: 55
积分: 137

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

达克罗德 说:

支持,鼓励一下!

惊现大佬(ΩДΩ)

离线

#8 2020-08-10 00:15:24

kesion
会员
注册时间: 2020-07-03
已发帖子: 45
积分: 32

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

厉害了,顺便也弄一个V3s的裸机开发程序吧,楼主

离线

#9 2020-08-10 09:53:40

jkl
会员
注册时间: 2019-11-18
已发帖子: 251
积分: 139.5

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

感谢楼主分享,正在纠结这个!!!!!

离线

楼主 #10 2020-08-10 14:30:56

f_Endman
会员
注册时间: 2020-04-16
已发帖子: 55
积分: 137

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

kesion 说:

厉害了,顺便也弄一个V3s的裸机开发程序吧,楼主

我手上目前只有个荔枝派Nano,等以后有机会再研究研究Zero吧,就启动程序来说应该区别不会很大,你可以仿照我这个思路试试弄一个V3s的

离线

#11 2020-08-10 17:43:37

zzm24
会员
注册时间: 2018-05-07
已发帖子: 113
积分: 105

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

有空我也开源我的BootLoader
IAR环境,SPI DMA读取kernel,然后直接启动kernel

离线

#12 2020-08-10 17:51:28

有梦的地方
会员
注册时间: 2020-03-17
已发帖子: 284
积分: 284

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

zzm24 说:

有空我也开源我的BootLoader
IAR环境,SPI DMA读取kernel,然后直接启动kernel

爆炸性好消息,坐等.gif

离线

楼主 #13 2020-08-10 22:59:27

f_Endman
会员
注册时间: 2020-04-16
已发帖子: 55
积分: 137

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

zzm24 说:

有空我也开源我的BootLoader
IAR环境,SPI DMA读取kernel,然后直接启动kernel

听上去很不错,期待一下

离线

#14 2020-08-11 09:36:31

打盹的消防车
会员
注册时间: 2020-08-10
已发帖子: 3
积分: 2.5

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

支持支持

离线

#15 2021-04-01 11:59:21

wapxiaoming
会员
注册时间: 2021-04-01
已发帖子: 0
积分: 0

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

该评论内容与本帖子无关,鼓励各位坑友积极发言讨论与帖子有关的内容!

离线

  • 不通过:与技术无关

#16 2021-05-01 08:22:44

xjf
会员
注册时间: 2021-04-30
已发帖子: 4
积分: 2

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

该评论内容与本帖子无关,鼓励各位坑友积极发言讨论与帖子有关的内容!

离线

  • 不通过:与技术无关

#17 2021-06-23 16:34:36

szchen2006
会员
注册时间: 2019-10-09
已发帖子: 216
积分: 166.5

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

该评论内容与本帖子无关,鼓励各位坑友积极发言讨论与帖子有关的内容!

离线

  • 不通过:与技术无关

#18 2021-09-01 09:47:21

三哥
会员
注册时间: 2018-08-03
已发帖子: 67
积分: 64.5

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

我也出现设置sp后程序出问题的情况,我启用了MMU,设置sp使用虚拟地址,这个地址映射到DDR物理地址上。但跑这段设置sp的代码程序就飞了

离线

#19 2021-09-04 21:35:15

chenqy2018
会员
注册时间: 2018-05-25
已发帖子: 3
积分: 2.5

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

厉害,要是可以启动kernel就更好了,可以先试试直接启动未压缩的内核比较简单些,这块boot与kernel参数传递好直接跳转就可以了。

离线

#20 2021-12-23 12:01:44

三木同子
会员
注册时间: 2020-06-09
已发帖子: 42
积分: 32

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

自己做了一块板,用这个可以出打印信息。
20211223115155.png

这个程序对自己做板子的用户来说,初期用来调试板子的一些基本功能非常有用,感谢。

最近编辑记录 三木同子 (2021-12-23 12:04:43)

离线

#21 2021-12-25 12:45:47

zhong
会员
注册时间: 2020-02-20
已发帖子: 3
积分: 3

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

该评论内容与本帖子无关,鼓励各位坑友积极发言讨论与帖子有关的内容!

离线

  • 不通过:其他

#22 2021-12-26 16:04:14

l09046162
会员
注册时间: 2019-07-03
已发帖子: 1
积分: 1

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

该评论内容与本帖子无关,鼓励各位坑友积极发言讨论与帖子有关的内容!

离线

  • 不通过:其他

#23 2022-03-05 08:28:09

234336283
会员
注册时间: 2021-03-05
已发帖子: 8
积分: 8

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

学习学习,是不是就当裸机运行一样

离线

#24 2022-05-23 10:32:47

kekemuyu
会员
注册时间: 2018-12-13
已发帖子: 841
积分: 721

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

有个地方不太理解:

__image_file_start = .;

    .text : AT(__image_file_start)       //就是这里,表示代码链接到DDR内,但编译时存放在文

这里有几个地址没有想明白,依我看启动过程是:brom程序从spi flash拷贝固定大小(不记得是多大了)的二进制文件到sram中,cpu开始从sram的0地址执行指令,指令中有个拷贝代码的程序如下:

/* 加载程序 */
void Boot_Load_Code(void)
{
    Boot_SPI0_Init();
    Boot_SPI_Flash_Read((unsigned int)&__image_file_start, &__image_start, &__image_end - &__image_start);
    Boot_SPI0_Exit();
}

__image_file_start是spi flash的存放位置,二进制程序被拷贝到ddr的地址起始位置,然后cpu跳转到ddr开始执行。

我所不理解的是__image_file_start如果是二进制文件在spi flash的存储位置,那__image_start应该是ddr的开始位置

    .text : AT(__image_file_start)
    {
        PROVIDE(__image_start = .);
        Obj/start.o (.text)
        Obj/main.o (.text)
        *(.text)
		*(.note.gnu.build-id)
    } > ddr

那__image_start的地址具体是多少呢?为何不把二进制程序拷贝到ddr的起始位置呢?由于对链接脚本不太熟,决定做实验验证:先直接修改链接脚本,把__image_start 的地址直接修改成0x80000000

离线

楼主 #26 2022-05-23 23:28:54

f_Endman
会员
注册时间: 2020-04-16
已发帖子: 55
积分: 137

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

@kekemuyu
注意到text代码块最后有个>ddr,意味着text块内所有内容链接到ddr所在地址
而链接脚本开头定义了ddr=0x80000000
text代码块最前面定义有PROVIDE(__image_start = .),“.”的意思就是当前链接“指针”,所以此处的__image_start确实就是0x80000000

离线

#27 2022-05-24 10:30:22

kekemuyu
会员
注册时间: 2018-12-13
已发帖子: 841
积分: 721

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

@f_Endman
和实验不符呀,改成0x80000000,似乎没有进入ddr启动应用。是不是可以用ida pro分析二进制程序,找到__image_start 的实际地址

离线

楼主 #28 2022-05-24 12:36:29

f_Endman
会员
注册时间: 2020-04-16
已发帖子: 55
积分: 137

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

kekemuyu 说:

@f_Endman
和实验不符呀,改成0x80000000,似乎没有进入ddr启动应用。是不是可以用ida pro分析二进制程序,找到__image_start 的实际地址

我试了一下,在main.c中

extern unsigned int __image_start;
……
    puts("__image_start: ");
    PrintHex(&__image_start);

可输出__image_start: 0x80000000
而如果直接

extern unsigned int __image_start;
……
    puts("__image_start: ");
    PrintHex(__image_start);

输出则是__image_start: 0xEA00009D,这应该是一条机器码,对应的大概是start.s中的那句b main


可得出结论:链接脚本中定义__image_start=.对应的是定义一个__image_start“指针变量”,指向定位器符号“.”,在这里是0x80000000(实质就是定义了一个汇编标号,指向0x80000000)


进一步验证的话,我把boot0.s中第58行改成

    /* 跳转到DDR */
    /* b __image_start */
    b 0x80000000

codeloder.c中Boot_Load_Code函数改成

/* 加载程序 */
void Boot_Load_Code(void)
{
    Boot_SPI0_Init();
    Boot_SPI_Flash_Read((unsigned int)&__image_file_start, (unsigned int*)0x80000000/*&__image_start*/, &__image_end - &__image_start);
    Boot_SPI0_Exit();
}

程序正常启动并运行

链接脚本的逻辑过于贴近底层,设计上就是为了汇编服务的,内部定义的“变量”直接就是汇编里的标号,可以直接作为b指令的地址参数。

又经过一系列实验,发现在链接脚本里定义标号似乎只能通过

.=0x80000000;
__image_start=.;

直接__image_start=0x80000000则是直接定义了一个指向0x00000000的标号

最近编辑记录 f_Endman (2022-05-24 12:47:40)

离线

#29 2022-05-24 14:03:01

kekemuyu
会员
注册时间: 2018-12-13
已发帖子: 841
积分: 721

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

@f_Endman
感谢分享,学到了。更进一步的想到__image_file_start的地址在不同介质都是一样的吗?spi flash,nand flash,sd卡,如果应用是在其他两种介质,代码拷贝程序需要做相应移植吧。

离线

#30 2022-05-24 15:33:06

hameyou
会员
注册时间: 2018-04-15
已发帖子: 171
积分: 8.5

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

不错,F1c100S逻辑启动,学习了,等有时间也折腾下

离线

楼主 #31 2022-05-24 16:21:05

f_Endman
会员
注册时间: 2020-04-16
已发帖子: 55
积分: 137

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

kekemuyu 说:

@f_Endman
感谢分享,学到了。更进一步的想到__image_file_start的地址在不同介质都是一样的吗?spi flash,nand flash,sd卡,如果应用是在其他两种介质,代码拷贝程序需要做相应移植吧。

除了要写相应介质的读写函数,全志的brom是从sd卡第8k字节开始读的,对于nand,brom更是会只读每块的前1k字节,这些需要程序来区分相应操作。
我这里可以直接使用__image_file_start是因为sram阶段的代码是位置无关码,是从0地址开始链接的,则此处__image_file_start的大小就是sram阶段代码的大小

离线

#32 2022-05-24 23:30:08

kekemuyu
会员
注册时间: 2018-12-13
已发帖子: 841
积分: 721

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

谢谢大佬,搞清了地址。下一步想把boot和应用分开编译、烧录,因为应用部分是用go语言编写生成的elf文件,只需要boot从指定地址将应用拷贝到ddr跳转执行。

离线

#33 2022-06-12 20:23:11

Ican
会员
注册时间: 2022-06-11
已发帖子: 30
积分: 0

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

在这颗芯片官网找了半天没有找到一点资料,想知道大家的资料都是怎么找到的?

离线

楼主 #34 2022-06-12 23:05:53

f_Endman
会员
注册时间: 2020-04-16
已发帖子: 55
积分: 137

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

Ican 说:

在这颗芯片官网找了半天没有找到一点资料,想知道大家的资料都是怎么找到的?

论坛里搜索资料,大部分都有,全志的很多芯片手册是不公开的,论坛里的都是大佬在各种地方扒来的

离线

#36 2022-07-06 16:26:32

xk2yx
会员
注册时间: 2020-12-19
已发帖子: 4
积分: 9

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

f_Endman 说:
Ican 说:

在这颗芯片官网找了半天没有找到一点资料,想知道大家的资料都是怎么找到的?

论坛里搜索资料,大部分都有,全志的很多芯片手册是不公开的,论坛里的都是大佬在各种地方扒来的

大佬,高考怎么样?准备上什么学校?

离线

楼主 #37 2022-07-06 23:15:24

f_Endman
会员
注册时间: 2020-04-16
已发帖子: 55
积分: 137

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

@xk2yx
啊这,考的还行,比平时高出几十分。人在北京,应该能上北工大(211)但专业不会太理想。学校有个特殊的学院,比较看重工科特长,我初期投简历应该能过,获得进入夏令营面试的资格,,夏令营里有学科能力考察以及一些实践项目考察,比较头疼的是要英语面试,我英语虽然最后也不低,但都是高三补上去的,基础不牢,但英语口语面试权重又很大。。如果能进,大二就能任选专业,进不去应该会被测控技术与仪器录走,自动化专业还差那么几分估计比较悬。。

离线

#38 2022-09-17 01:14:57

Hydrion
会员
注册时间: 2021-08-11
已发帖子: 2
积分: 2

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

感谢楼主分享,学习了,尤其是看到回帖,楼主年轻有为,令人羡慕。

离线

#42 2022-11-18 10:33:05

astankvai
会员
注册时间: 2021-02-23
已发帖子: 36
积分: 36

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

这个要板凳,  ARM9上的BOOT,  学习学习。

离线

#44 2023-04-26 23:23:34

huy666
会员
注册时间: 2018-02-24
已发帖子: 26
积分: 11

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

搬个板凳,努力学习。
能否不写到FLASH,只在DDR内运行?

最近编辑记录 huy666 (2023-04-26 23:26:07)

离线

#45 2023-05-07 23:26:32

hang
会员
注册时间: 2023-05-07
已发帖子: 7
积分: 2

Re: 分享一个自己试着写的裸机BootLoader,和编写过程中的大坑

能否移植rtthread?

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn