思路:
1.分析启动流程
2.移植config文件(smdk440_config)
3.移植包含控制条件编译宏的.h文件(configs/s3c2440.h)
4.移植板级初始化.c文件(s3c2440.c)
5.移植RAM初始化?DDR?
6.移植NorFlash
7.移植NandFlash
8.uboot应该能启动了?
//分析启动流程
1.make xx_config
2.在makefile中有以下依赖关系
%_config:
$(MKCONFIG)
3.在mkconfig中会去解析board.cfg,根据输入的xx去匹配board.cfg中的TARGET项,提取出ARCH、CPU、SOC、VENDOR等
然后自动生成config.h,其中config.h中定义了一些关于ARCH、SOC等的宏,以及包含configs/xx.h头文件来控制uboot中的条件编译
4. make 生成 uboot.bin
uboot.bin依赖于 OBJ LIB LDS,其中LIB变量为cpu/ drivers/ board/
随后依次进入各文件夹进行make,生成buitin.o,最后链接成uboot.bin
start.s
...
lowlevel_init.S
...
_main(arm/lib/crt0.S)
board_init_f
board_early_init_f
board_init_r
board_init
start.S主要完成了:
a.初始化异常向量表
b.设置cpu svc模式,关中断
c.配置cp15协处理器,设置异常向量入口
d.配置cp15,初始化mmu cache tlb
e.板级初始化,pll memory初始化
一、Uboot从norflash启动和nandflash启动的区别
1.norflash启动
norflash是可以片上执行代码(XIP)的,也就是说,将bootloader烧写到norflash的开始地址后,开发板上电以后,cpu直接从0x00开始执行(也就是在norflash中执行)整个uboot,直到引导内核启动。
2.nandflash启动
由于norflash有地址线,因此可以直接执行代码,而nandflash只有数据线,因此无法片上执行。开发板上电以后,nandflash控制器会自动把nandflash中的前4K代码拷贝至CPU内部RAM(SRAM-CACHE),
同时把片内SRAM映射到0x00,随后CPU从0x00开始执行,这个过程程序不需要干涉。但是uboot肯定是大于4K,这样的话4K以后的代码怎么办?
所以如果是从nandflash启动,前4K代码首先会设置CPU运行模式,关看门狗,设置时钟,关中断,初始化内存,初始化nandflash,设置堆栈,然后把整个bootloader搬运到SDRAM中,并跳转到SDRAM中
执行。
一、总结:
对于Uboot来说,主要有两大阶段,第一阶段主要使用汇编语言实现,包括cpu、时钟、关watchdog、mmu等初始化,并设置堆栈,为C语言调用做好准备。
随后进入board_init_f阶段,该阶段的主要工作就是初始化Clock、serial和RAM,实现最精简系统启动。
最后调用board_init_r函数,该阶段主要是做了一些mmc、flash、eth等外设的初始化以及环境变量的设置等,最后进入main_loop死循环,打印命令行,等待命令输入和解析。
uboot移植主要涉及几方面:
1.向board_cfg文件中添加需要支持的新板,包括SOC、CPU、VENDOR、TARGET等项
2.向board/文件夹中添加对应的板级函数,如board/samsung/mini2440(mini2440.c Makefile)等
3.向include/configs文件夹中添加对应的头文件如mini2440.h,这个文件在mkconfig时会被包含进config.h,用于控制Uboot编译过程的各条件编译。
4.修改arch/cpu文件夹下对应的start.S,适配对应的cpu型号(比如主频、时钟等)。
5.Uboot可以从norflash、nandflash、RAM启动,不同的启动方式在start.S会有不同。
本次Uboot移植主要修改了的文件夹:
u-boot-2012.10oardsamsungmini2440
u-boot-2012.10includeconfigsmini2440.h
u-boot-2012.10archarmcpuu-boot.lds
u-boot-2012.10archarmcpuarm920tstart.S
本次uboot移植遇到的坑:
1.一操作全局变量(赋值等操作)就卡死;一打印(如puts、printf)就卡死,最后发现原因是使用的arm-linux-gcc4.7.3交叉编译器的原因,换成4.4.3就好了,原因未明。
uboot移植需要知道的点:
1.要完整一个完全新板的uboot移植并没有想象的那么简单:
a.需要对所使用的cpu型号很熟悉(datasheet) ------> 因为要配置时钟、各寄存器等;
b.需要对某一架构(如arm、ppc)熟悉 ------> 因为在start.S中要配置svc32模式等;
c.需要对某一体系下的汇编指令熟悉(如arm) -----> 因为start.S都是用汇编实现的;
d.需要对外设的硬件特性熟悉 -----> 比如uboot对nandflash的裸读/写(还有要熟悉cpu中的nandflash控制器的寄存器读写)
2.uboot编译过程是通过config.h(会包含板级头文件,如mini2440.h)文件内定义的宏去控制条件编译,这是要重点关注的:
a.由于第一点所需要的知识点太过底层,而且一般由芯片厂商实现,如果不想进芯片公司的话,没有兴趣去深入了解。因此,关注重点放在了第二点。
在实际的产品开发时,芯片厂商会提供SDK,内含移植好的uboot,但是自研板子的外设不可能和芯片厂商的完全一样。所以,我们就需要知道如何控制uboot
支持不同的外设。
b.如何知道某个driver是由哪个宏控制的?-----> 可以去driver/文件夹内找,在Makefile中会通过宏去控制对应的c文件是否要包含进去进行编译。
c.除了支持不同的外设,还需要知道uboot的默认配置在哪改。------> 也是在config.g文件中的各种宏定义。
3.uboot的调试方式:
a.uboot在第一阶段没有初始化串口,所以是没有打印的,这个时候的调试方式主要是通过点灯来查看运行状态。
b.还有可以通过汇编直接操作寄存器来输出相关信息。
c.本次调试还是在确认硬件工作正常的情况下调试的,因此不会去怀疑硬件问题,只需关注代码实现。如果真的是全新的板子,那么Uboot的调试难度肯定大幅增加。
UBOOT启动流程:
时钟初始化、关看门狗、MMU、TLB初始化 ---> RAM初始化 ---> FLASH_TO_RAM ---> ---> board_init_f --->
串口初始化 ---> RAM信息配置 ---> 代码重定位(对RAM空间进行规划,如堆栈空间等)---> board_init_r --->
NORFLASH初始化 ---> NANDFLASH初始化 ---> ETH以太网PHY初始化 ---> main_loop ---> 接收命令解析命令