一、U-boot分析与使用
启动内核需要u-boot能做些什么
关闭看门狗
初始化时钟
初始化sdram
串口初始化、收、发
生产时烧写flash(usb、网卡方式等)
读flash写入sdram
u-boot 如何编译安装
1、网上下载、解压缩u-boot
2、打补丁,
linux 下 patch -px < 补丁文件(x代表忽略掉补丁目录的几个/)
3、配置
make xxxx_config
4、编译
make
5、烧录到裸板
oflash u-boot.bin
u-boot 的makefile 分析
首先要make xxx_config
make xxx_config的时候执行这个命令
@$(MKCONFIG) $(@: __config=) arm arm920t 100ask24x0 NULL s3c24x0
相当于
mkconfig 100ask24x0 arm arm920t 100ask24x0 NULL s3c24x0
mkconfig 是一个脚本文件
(个人理解,mkconfig里面的命令,指定了接下来makefile编译哪些文件,从而可以选择性的来编译符合当前硬件的程序文件)
下面对mkconfig进行分析
分析命令里面传入的参数
确定BOARD_NAMR
如果没有定义BOARD_NAMR,就认为$1为BOARD_NAMR
参数个数校验
$#代表参数的个数。如果参数小于4个大于6个就退出脚本
串口打印文字
建立新的asm文件
建立链接文件 asm 指向 asm-arm
(个人理解,makefile会去asm读取文件来编译,这里删除了原先的asm,然后建立链接文件 asm 指向 asm-arm,相当于编译的时候,就选择了asm-arm目录的文件来编译,这个arm($2)就是xxxconfig指定的)
建立新的asm-arm/arch
执行ln -s arch-s3c24x0 asm-arm/arch
asm-arm/arch 指向arch-s3c24x0
建立新的asm-arm/proc
为 make 生成一个配置文件
这里的 > 代表生成新文件
这里的 >>代表追加到文件
相当于:
ARCH = arm
CPU = arm920t
BOARD = 100ask24x0
如果第5个参数存在且不为空的话。。。
如果第6个参数存在且不为空的话
SOC = S3C24X0
(个人理解,是将参数保存在这个文件内,然后接下来的make还会使用到这些参数)
创建一个单板相关的头文件
新建一个config.h文件
追加一个注释:自动生成不可修改
追加#include <configs/100ask24x0.h>
(个人理解,100ask24x0.h根据某种规范编写,有统一的接口,为代码一致性方便维护,u-boot内很多文件会包含config.h这个文件,只要更换config.h内的包含,就可以改变很多文件的编译结果)
makefile编译过程分析
编译过程会使用到配置过程中生成的config.mk
ARCH = arm
CPU = arm920t
BOARD = 100ask24x0
SOC = S3C24X0
定义OBJS、以及LIBS
(个人理解,从这一步makefile就可以根据配置文件来选择CPU的启动文件以及库文件)
u-boot的目标文件
u-boot要用到哪些文件
小技巧:只需要执行make命令,查看最后面的链接命令用到了哪些文件
链接命令需要连接 脚本 和 链接的原材料 。
分析编译需要分析哪几个文件
1、cpu/arm920t/Start.S
2、链接脚本board/100ask24x0/u-boot.lds
链接命令的 0x33f80000在board/100ask24x0/mkconfig内定义
u-boot源码分析
第一阶段: start.S,硬件相关初始化
设置cpu为管理模式
关看门狗
关中断
查看当前程序所在位置
如果还在片内内存中,那么说明刚上电,
程序还没有进行初始化以及重定位
初始化(主要是sdram)
设置栈
初始化时钟
重定位:把代码复制到链接脚本指定的位置
清除bss段
调用strat_armboot
第二阶段:start_armboot
flash_init 初始化 norflash
堆的实现,初始化
初始化nandflash
环境变量初始化
。。。
main_loop循环主任务
怎么启动内核
1、依赖于bootcmd的环境变量
s = getenv(“bootcmd”)
run_command(s)
2、u-boot 界面
readline 读入串口的数据
u-boot 的核心是命令
命令是怎么实现的
解析输入的字符串命令,并执行对应的程序
命令与函数对应关系由一个结构体来储存
struct cmd_tbl_s
{
//名称
//最大参数
//是否可重复
//函数指针(命令调用的函数)
//短的帮助信息
//长的帮助信息
}
链接脚本里面,有一个ubootcmd段
搜索u_boot_cmd得到
所有的U_BOOT_CMD段的代码,都会以 cmd_tbl_s结构体的形式被储存到U_BOOT_CMD段
怎么自己增加一个命令
1、自己新建一个helloworld.c 文件,放在common目录下面
2、复制其他cmd的C文件的头文件到helloworld.c 文件
3、新建一个函数 :
4、定义一个U_BOOT_CMD,
(个人理解,这个U_BOOT_CMD 定义之后,链接的时候就会把括号内的内容放入U_BOOT_CMD段,然后uboot下输入命令后就会查找到这个命令,执行do_hello)
5、把helloworld.c加入u-boot
修改common目录的makefile
,在makefile的objs依赖文件变量里加入helloworld.o
6、测试命令
由测试可知,argc 是指参数个数
argv[]储存的是命令字符串
uboot怎么启动内核
uboot启动内核依赖两条代码:
查找bootcmd命令,得到:
这两条命令第一条从nandflash上面把内核读到0x30007fc0,
第二条 是从0x30007fc0启动内核
从nand读出内核,从哪里读
从kernel分区读取
嵌入式分区的概念
与pc的分区不同,flash没有分区
为了体现分区,只能在源码(100ask24x0.h)里把分区写死
第一条命令解析
JFF2是文件格式,不用管
nand read.jff2 xxx yyy
把nandflash的yyy地址数据读到xxx上
第二条命令 bootm 0x30007fc0解析
这条命令主要是从0x30007fc0启动内核。
这个0x30007fc0 ,可以在未使用的空间随便取值,因为:
flash上存的内核:分为头部+真正的内核
头部结构体如下:
主要存放这些参数,
其中ih_load 代表加载地址
ih_ep 代表入口地址
在使用bootm的时候,会在0x30007fc0地方读取内核头部。
然后会根据读取的头部,把内核移动到ih_load(加载地址),再从ih_ep(入口地址)启动内核
启动内核上一步要告诉内核一些启动参数,还有机器ID
如何告诉内核、、?
1、在某个地址,(0x30000100)
2、按照某个格式,(tag结构体的格式)
3、保存数据
怎么启动内核?
1、定义一个函数指针
2、设置thekernel为入口地址
3、运行thekernel,把启动参数放到栈中?
从零开始写bootloader
总体需要做什么
1、从flash把内核读入内存
2、启动