UBOOT 学习心得(UBOOT流程分析)

网上找到的UBOOT研究文章,结合自己这几天看的。目前是明白了UBOOT主干程序流程了。开始分析细节部分了。下面是别人写的UBOOT分析。

参考了fzb和赵春江两位大牛的,研究了2010.06版本的和2011.06版本两个经典版本,也对比了TQ(我买的板是天嵌的)自己写的U-BOOT,学到了不少,也发现了很多东西,以下便记录以下自己的心得吧,以便以后可以自己参考下。

U-BOOT的两个阶段启动过程:(2010.06经典版来说)

第一阶段:start.S的路径位于arch\arm\cpu\arm920t\这段汇编代码一般被称作第一阶段初始化代码。主要作用是初始化运行环境;初始化内存;重新放置UBOOT代码到内存中;跳入到内存中执行第二段初始化代码

1、    关闭开门狗,屏蔽所有中断

2、    设置分频比

3、    bl     cpu_init_crit()    关MMU,初始化内存

bl     lowlevel_init()      配置内存,修改内存刷新率参数等

4、    relocate          判断当前代码是在NORFLASH还是RAM

copy_loop循环            将FLASH代码复制至RAM中

 5、   stack_setup   栈设置

clear_bss _bss_start到_bss_end之间的数据清0

 6、   ldr     pc , start_armboot     跳转到第二阶段

//=====================================================================

第二阶段:board.c的路径位于arch/arm/lib/board.c,这段代码为U-BOOT的第二阶段初始化代码。主要作用是初始化两个重要数据结构,对SDRAM的内存分配设置,对各种需要用到的外设进行初始化,最后循环跳入main_loop()函数

二阶段start_armboot分为board_init_f 和 board_init_r两部分

先执行的board_init_f部分:

1、为gd数据结构分配地址,并清零

2、执行init_fnc_ptr函数指针数组中的各个初始化函数,如下

board_early_init_f    , timer_init       , env_init       init_baudrate serial_init     

console_init_f       display_banner           dram_init

3、A、 分配SDRAM高64KB为TLB,用于U-BOOT

B、分配SDRAM下一单元为U-BOOT代码段,数据段,BSS段

(这里插一句,原来BSS段是用来存放未初始化的全局变量与静态变量)

      C、接着开辟malloc空间,存bd , gd , 3个字大小的异常堆空间

4、将relorate的地址值赋给gd结构体相应变量(2011.06版本的,用于返回start.S)

后执行的board_init_r部分:

1、对gd , bd 数据结构赋值初始化

2、各种外设初始化:

初始化NORFLASH,     NANDFLASH,            初始化ONENAND FLASH

初始化环境变量     初始化PCI    设置IP地址 初始化各类外设:IIC、LCD、键盘、USB        初始化控制台              建立IRQ中断堆栈    初始化以太网

初始化跳转表(定义了U-Boot中基本的常用函数库)。。这不算外设

3、一个死循环执行   main_loop()函数

-------------------------------------------------

两个版本的U-BOOT启动对比:

-------------------------------------------------

其实在总体上都差不多,只不过相对于经典版(2010.06版),新版之后都变恶心了

主要有这样的区别:

1、原版本第一阶段的第5步栈设置被放到第4步relorate前(这个没什么)

2、原版第二阶段的board_init_f被放到第一阶段第4步relorate前,就是说执行完

stack_setup栈设置后变进入了第二阶段的部分初始化,然后通过4、将relorate的地址值赋给gd结构体相应变量(2011.06版本的,用于返回start.S)又返回来第一阶段。。。感觉新版改后很乱,很没条理(开源的每年改,就是烦呀,哈哈)

//=================================================

以下列出两个阶段可能要用到的函数的路径,方便以后找:(按2011.06版本)

一阶段:

lowlevel_init函数,它是在board/samsung/smdk2410目录下的lowlevel_init.s文件中定义

二阶段:

gd是一个保存在ARM的r8寄存器中的gd_t结构体的指针,它是在/include/asm目录下的global_data.h文件内被定义的

bd结构体的数据原型为bd_t数据结构,它表示的是“板级信息”结构体,它是在/include/asm目录下的u-boot.h文件中定义的。

init_fnc_ptr函数指针数组中的各个初始化函数:

board_early_init_f函数在board/samsung/smdk2410目录下的smdk2410.c文件内timer_init函数在arch/arm/cpu/arm920t/s3c24x0目录下的timer.c文件内

env_init函数在common目录下的env_flash.c文件内

init_baudrate函数在arch/arm/lib目录下的board.c文件内

serial_init函数在drivers/serial目录下的serial_s3c24x0.c文件内,在include/configs/smdk2410.h中定义了CONFIG_S3C24X0_SERIAL

console_init_f函数在common目录下的console.c文件内

display_banner函数在arch/arm/lib目录下的board.c文件内

dram_init函数在board/samsung/smdk2410目录下的smdk2410.c文件内

各种外设的初始化:

flash_init函数是在drivers/mtd目录下的cfi_flash.c文件内(因为include/configs/smdk2410.h中定义了CONFIG_FLASH_CFI_DRIVER)

nand_init函数是在divers/mtd/nand目录下的nand.c文件内定义的

env_relocate函数是在common目录下的env_common.c文件中定义的

stdio_init ()在common目录下的stdio.c文件中定义的

jumptable_init ()在common目录下的exports.c文件中定义的

console_init_r ()是在common目录下的console.c文件中定义的

interrupt_init () enable_interrupts ()都是在arch/arm/lib目录下的interrupts.c文件中定义

eth_initialize()函数是在net目录下的eth.c文件的第209行至第298行定义的

main_loop()在common目录下的main.c文件内定义的

--------------------------------------------------

天嵌与自己移植的U-BOOT的差别分析和领悟

先列出天嵌公司里研发人员写的 和 我们自己移植(小移植)的最大不同:

对比了一下,发现最大的不同在于common/main.c文件中,即在两阶段启动过程基本一样

不同点:(行数按天嵌版本的)

abortboot()函数(在main_loop()中被调用)

 Ln239: printf ( “ Press Space key to Download Mode ! ” ) ;

 Ln303 :在检测是否 a key press 时,加入了显示LOGO程序:embedsky_tq_logo();

main_loop()函数

 Ln 381: LCD初始化程序

 Ln481 :分支选择 下载 OR 加载模式:

if ( BootFrmNORFLASH() )

  run_command (“menu”,0 );

else

 {Printf (“ Booting Linux \n ”);run_command (“boot_zImage”,0 );}

解析一下:

前面几点都是关于LCD和LOGO显示的不多说(因为自己移植是没弄到LCD的移植)

说一下main_loop()函数中Ln481 :分支选择 下载 OR 加载模式

首先,run_command 这个是执行命令函数,一看名字就知道,也是在/common/main.c中定义的

说说最重要的“menu”和“boot_zImage”吧

1、    If从NORFLASH进行启动,则为下载模式,则执行menu()这个函数,在/common/cmd_menu.c中定义

       打开cmd_menu.c文件会发现,里面都是一些串口选项列表,我们打开2440电源发现的下载列表都是从 main_menu_usage()函数中打印出来的,而选择的项又通过menu_shell()通过控制台执行各种我们的选项,每个选项的如何执行过程都列得很清楚,感觉就像跑裸机时,自己按照fzb的串口控制台弄出来一样

   2、    Else 从NANDFLASH进行启动,    则为加载模式,进行LINUX系统的配置和启动。

       在lib_arm /boot_zImage.c 文件:里的boot_zImage( )函数

       函数执行的内容大概如下:

       1、 copy   kernel image

       2、setup linux   parameters

       3、get   machine   type

       4、GO   -> call-linux

对比后的一些感悟:

虽说自己也跟着移植过U-BOOT,也能建立自己的板级支持包,能实现基本的串口控制台,NAND OR NOR FLASH,DM9000网络,JFFS2文件系统等基本功能,但比起天嵌这个,能下载 和   加载模式,还是有很多不足

所以说,自己移植只是感觉其中的方法,领悟之后还是在天嵌的基础上再加进一步移植吧,感觉没必要从头到尾都自己搞一遍,方法懂了,框架熟悉了就好。

//===================================================================

移植过程的一个简单举例:

因为移植很多都是基于smdk2410来改的,首先要对2410和2440的区别有一定了解,再者就是自己在裸机上是编写过改外设的驱动的,这样移植起来就比较舒服,不会说什么都跟着做,感觉很虚,学不到东西。

举个例子让U-BOOT支持NANDFLASH的读写

 1、 先是在总的宏定义头文件中加上你外设所需的宏定义

总的宏定义路径为 /include /configs / XX.h/ (最后这个.h文件一般是以板的名称命名)

    添加宏定义,如:#define   CONFIG_NAND_BASE   0      

                            。。。 等等

    那怎么知道添加什么宏定义呢?一般来说看对外设初始化函数,和U-BOOT二阶段启动函数要用到哪些就定义哪些。。。

 2、 改相应的初始化函数:如board_nand_init函数和s3c2440_hwcontrol函数

因为U-BOOT里初始化函数基本基于2410的,而2440的NAND配置参数和它不同,需要改部分地方

3、 添加初始化函数到第二阶段board_init_r处,一般来说基本外设都已添加了,看你是否定义宏来让其编译这函数

移植一些规律总结:

其实多移植几次就会发现,UBOOT的移植修改还是遵循着一定的规律。即是先在配置头文件中打开相关宏定义支持,在到板级初始化(一般是第二阶段初始化过程)代码中添加需要支持功能的初始化函数。

如果初始化函数对应的板版本不兼容或不存在,就要自己编写了。

----------------------------------------------------

最后,说说U-BOOT的编译吧

说到编译,建议去看《从庖丁解牛说uboot如何编译》,说得很好。

而说到编译的执行过程,建议看看

http://hi.baidu.com/serial_story/blog/item/871fc30311670783d53f7c74.html

详细分析make uboot 最后的编译链接的具体执行过程》

最后谈谈编译不通过的问题,如果是内部自己程序出错,可以通过提示信息查出

如果是出现ERROR一百多个,或者什么arm-linux-ld的问题,那应该是编译器版本不兼容问题,建议换换新的版本或更旧的版本再试试。

猜你喜欢

转载自blog.csdn.net/xiaolei251990/article/details/88720428