ID和内核ID关系:
http://blog.csdn.net/quannii/article/details/8665931
博客:
http://blog.csdn.net/zjq77700/article/details/51191738
http://www.cnblogs.com/pengdonglin137/archive/2015/12/27/5080645.html
http://blog.csdn.net/techping/article/details/69911634
http://blog.sina.com.cn/s/blog_80b0774a0102vmcj.html
http://blog.csdn.net/abcamus/article/details/51326881
分析:
http://blog.csdn.net/abcamus/article/details/51326881
globl_data http://blog.csdn.net/fulinus/article/details/8682127
http://blog.csdn.net/hahachenchen789/article/details/52939174
http://www.cnblogs.com/amanlikethis/p/3675486.html
总结:(基于2013.01)
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
0. 命令和自定义命令
即使是内核的启动,也是通过U-Boot命令来实现的。U-Boot中每个命令都是通过 U_BOOT_CMD 宏来定义的,格式如下:
U_BOOT_CMD(name,maxargs,repeatable,command,"usage","help")
各项参数的意义如下:
1) -- name:命令的名字,注意,它不是一个字符串(不要用双引号括起来);
2)-- maxargs:最大的参数个数;
3)-- repeatable:命令是否可以重复,可重复是指运行一个命令后,下次敲回车即可再次运行;
4)-- command:对应的函数指针,类型为(*cmd)(struct cmd_tbl_s *, int, int, char *[]);
5) -- usage:简单的使用说明,这是个字符串;
6)-- help:较详细的使用说明,这是个字符串。
U_BOOT_CMD 是用一个struct cmd_tbl_s 结构体定义,这个结构体仍是在include/command.h中实现
对于每个使用U_BOOT_CMD 宏来定义的命令,就是宏 U_BOOT_CMD(name,maxargs,rep,cmd,usage,help)将struct cmd_tbl_s这样的一个命令结构体放到U-BOOT连接脚本 board/xxx/u-boot.lds中定义的".u-boot_cmd"段所在的内存区域,即在".u_boot_list.cmd"段中定义一个 cmd_tbl_t 结构。
自定义命令
a.include/configs/XXX.h 添加命令行配置信息
b.common/ 编写命令行对应的源程序
注意命名的规范,必须是cmd_xxx.c才行。里面的内容也是有格式要求的,如函数的格式,必须指定参数的;还有相应结尾部分的U_BOOT_CMD定义部分,使不能缺省的。如果命令不需要跟参数,则把maxargs设置为1即可了。
c.在common/Makefile中增加一项.
d. 编译
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
0. 依赖过程
Makefile--分支执行mkconfig--解析boards.cfg--创建--include/ config.mk,inlucde/config.h
--依赖inlucde/configs/
--分支执行编译(根据第一个目标all,根据其下的依赖一步步编译成u-boot.bin和其他)
--分支执行其他
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1. 链接过程
a -- 首先编译 cpu /$(CPU)/start.S,对于不同的CPU,还可能编译 cpu/$(CPU)下的其他文件;
b -- 然后,对于平台/开发板相关的目录、和每个通用目录都使用它们个字的Makefile生成相应的库;
c -- 将a、b 步骤生成的.o .a文件按照 board / $(BOARDDIR)/config.mk文件中指定的代码段起始地址、board/$(BOARDDIR)/config.mk文件中指定的代码段起始地址、board/$(BOARDDIR)/U-Boot.lds链接脚本进行链接。
d -- 第c步得到的是ELF格式的U-Boot,后面的Makefile还会将它转换成二进制格式、S-Record格式。
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2. 启动过程
可抽象化为如下:
第一阶段:
a -- 设置cpu工作模式为SVC模式
b -- 关闭中断,mmu,cache
v -- 关看门狗
d -- 初始化内存,串口
e -- 设置栈
f -- 代码自搬移
g -- 清bss
h -- 跳c
第二阶段
a -- 初始化外设,进入超循环
b -- 超循环处理用户命令
第一阶段的文件:
arch/arm/cpu/armv7 /start.S 平台相关,CPU工作模式设为SVC模式,关MMU,关icahce(CPU相关)
board/《某厂商》/《board name》/lowlevel_init.S 开发板相关:关看门狗,内存初始化,时钟初始化,串口初始化(board相关,初始化最基本设备)
第二阶段的文件:
arch/arm/lib/crt0.S _main 函数所在处,初始化SP,为C语言准备,代码重定位,清BSS,设置R0 R1 R2 R8相应寄存器
arch/arm/lib/board.c board_init_f 函数 ,填充GD结构体,初始化外设,对sdram空间进行规划
board_init_r 函数,再初始化外设,main_loop()函数超循环
arch/arm/cpu/armv7 /start.S 代码自搬移时会用到(大概就是BL2搬移到内存,因为对cpu本身内存来说太大了)以上文件间,还会相互调用定义的其他函数
最后进入 board.c 的 board_init_r 中,最后循环进入main_loop()进入命令行状态
Main_loop函数主要功能是处理环境变量,解析命令
install_auto_complete(); //安装自动补全的函数,分析如下 。
getenv(bootcmd)
bootdelay(自启动)
如果延时大于等于零,并且没有在延时过程中接收到按键,则引导内核。
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
3. uboot引导内核启动
bootloader 要想启动内核,可以直接跳到内核的第一个指令处,即内核的起始地址,这样便可以完成内核的启动工作了。但是要想启动内核还需要满足一些条件,如下所示:
1、cpu 寄存器设置
* R0 = 0
* R1 = 机器类型 id
* R2 = 启动参数在内存中的起始地址
2、cpu 模式
* 禁止所有中断
* 必须为SVC(超级用户)模式
3、Cache、MMU
* 关闭 MMU
* 指令Cache可以开启或者关闭
* 数据Cache必须关闭
4、设备
* DMA 设备应当停止工作
5、PC为内核的起始地址
这些需求都由 boot loader 实现,在常用的 uboot 中完成一系列的初始化后最后通过 bootm 命令加载 Linux 内核。bootm 向将内核映像从各种媒介中读出,存放在指定的位置;然后设置标记列表给内核传递参数;最后跳到内核的入口点去执行。
a. 在 common/cmd_bootm.c 可以看到 bootm 命令使调用了do_bootm 函数
b. 在 common/cmd_bootm.c 的do_bootm 函数
该函数的实现分为 3 个部分:
-- 首先通过 bootm_start 函数分析镜像的信息; 在cmd_bootm.c
-- 如果满足判定条件则进入 bootm_load_os 函数进行加载; 在cmd_bootm.c
-- 加载完成后就可以调用 boot_fn 开始启动。 从一个函数数组中根据数组下标获得其中的 do_bootm_linux 函数并执行
其位于 arch/arm/lib/bootm.c ,其最终调用 boot_jump_linux(也在同个文件内)
boot_jump_linux 最终会调用kernel_entry将控制权交给内核
其中 boot_jump_linux 会获得 机器ID 和 启动参数并传给 kernel_entry
从而满足arm架构linux内核启动时的寄存器设置条件:第一个参数为0 ;第二个参数为板子id需与内核中的id匹配,第三个参数为启动参数地址 。
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
4. 为内核设置启动参数
Uboot 也是通过标记列表向内核传递参数,标记在源代码中定义为tag,是一个结构体,在 arch/arm/include/asm/setup.h 中定义。
在一些内存标记、命令行标记的示例代码就是取自Uboot 中的 setup_memory_tags、setup_commandline_tag函数,他们都是在arch/arm/lib/bootm.c中定义。
一般有 setup_memory_tags、setup_commandline_tag 这两个标记就可以了,在配置文件Include/configs/《board name》.h中定义:(将相关宏定义即可,一般也有定义)