4412uboot移植


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 在include/command.h中定义

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/.h

           --分支执行编译(根据第一个目标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中定义:(将相关宏定义即可,一般也有定义)




你可能感兴趣的:(ARM-Linux底层基础,uboot)