uboot启动之uboot第二阶段(BL2)

uboot第二阶段分析主要是start_armboot的分析

一、这个函数是uboot/lib_arm/board.c的444行开始到908行结束。

    1、首先分析一下uboot第二阶段应该做些什么?

        (1)、第一阶段主要初始化SoC内部的一些部件(看门狗,时钟等)

        (2)、uboot第二阶段就是初始化剩下的还没被初始的硬件。(譬如iNand,网卡芯片....)、uboot本身的一些

         东西(uboot的命令、环境变量等....)。最终初始化完成必要的东西后进入uboot的命令行准备接收命令。

     2、uboot第二阶段完结于何处?

        (1)、uboot启动后自动运行打印出很多信息(这些信息就是uboot在第一和第二阶段不断进行初始化时,打印出

            来的信息)。然后uboot进入了倒数bootdelay秒然后执行bootcmd对应的启动命令。

        (2)、如果用户没有干涉则会执行bootcmd进入自动启动内核流程(uboot死掉);若你在bootdelay秒前按下回

            车则进入uboot命令行中,可以执行ubootcmd对应的命令。

        (3)、uboot的命令行就是一个死循环,循环体内不断重复:接收命令,解析命令,执行命令。这就是uboot最终

            的归宿。

    3、start_armboot解析

        (1)、typedef int (init_fnc_t) (void); 这是一个函数类型

        (2)、init_fnc_ptr是一个二重函数指针:二重指针的作用有2个(其中一个是用来 指向一重指针),一个是用来

         指向指针数组。因此这里的init_fuc_ptr可以用来指向一个函数指针数组。

    4、DECLARE_GLOBAL_DATA_PTR

        (1)#define DECLARE_GLOBAL_DATA_PTR     register volatile gd_t *gd asm ("r8")

        定义了一个全局变量名字叫gd,这个全局变量是一个指针类型,占4字节。用volatile修饰表示可变的,用register

        修饰表示这个变量要尽量放到寄存器中,后面的asm("r8")是gcc支持的一种语法,意思就是要把gd放到寄存器r8中。

        (2)综合分析,DECLARE_GLOBAL_DATA_PTR就是定义了一个要放在寄存器r8中的全局变量,名字叫gd,类型是

        一个指向gd_t类型变量的指针。

        (3)为什么要定义为register?因为这个全局变量gd(global data的简称)是uboot中很重要的一个全局变量

      (准确的说这个全局变量是一个结构体,里面有很多内容,这些内容加起来构成的结构体就是uboot中常用的所有

        的全局变量),这个gd在程序中经常被访问,因此放在register中提升效率。因此纯粹是运行效率方面考虑,和功

        能要求无关。并不是必须的。

        (4)gd_t定义在include/asm-arm/global_data.h中。

        gd_t中定义了很多全局变量,都是整个uboot使用的;其中有一个bd_t类型的指针,指向一个bd_t类型的变量,

        这个bd是开发板的板级信息的结构体,里面有不少硬件相关的参数,譬如波特率、IP地址、机器码、DDR内存分布。

    5、为什么要分配内存

        (1)DECLARE_GLOBAL_DATA_PTR只能定义了一个指针,也就是说gd里的这些全局变量并没有被分配内存,

        我们在使用gd之前要给他分配内存,否则gd也只是一个野指针而已。

        (2)gd和bd需要内存,内存当前没有被人管理(因为没有操作系统统一管理内存),大片的DDR内存散放着可以

        随意使用(只要使用内存地址直接去访问内存即可)。但是因为uboot中后续很多操作还需要大片的连着内存块,

        因此这里使用内存要本着够用就好,紧凑排布的原则。所以我们在uboot中需要有一个整体规划。

    6、内存排布

        (1)uboot区 CFG_UBOOT_BASE-xx(长度为uboot的实际长度)

        (2)堆区 长度为CFG_MALLOC_LEN,实际为912KB

        (3)栈区 长度为CFG_STACK_SIZE,实际为512KB

        (4)gd 长度为sizeof(gd_t),实际36字节

        (5)bd 长度为sizeof(bd_t),实际为44字节左右

        (6)内存间隔 为了防止高版本的gcc的优化造成错误。

    7、start_armboot解析2

    (1)、init_sequence是一个函数指针数组,数组中存储了很多个函数指针,这些指针指向的函数都是init_fnc_t类型。

    (2)、Init_sequence在定义时就同时给了初始化,初始化的函数指针是一些函数名。

    (3)、init_sequence中这些函数,都是board级别的各种硬件初始化。

    8、cpu_init和board_init前者是CPU内部的初始化,board_init是开发板相关的初始化。

    9、gd->bd->bi_arch_number:bi_arch_number是board_info中的一个元素,含义是:开发板的机器码。所谓机器

     码就是uboot给这个开发板定义的一个唯一编号。

    10、gd->bd->bi_boot_params:

        (1)、bd_info中另一个主要元素,bi_boot_params表示uboot给linux kernel启动时的传参的内存地址。

          也就是说uboot给linux内核传参的时候是这么传的:uboot事先将准备好的传参(字符串,就是bootargs)

          放在内存的一个地址处(就是bi_boot_params),然后uboot就启动了内核(uboot在启动内核时真正是通过

          寄存器r0 r1 r2来直接传递参数的,其中有一个寄存器中就是bi_boot_params)。内核启动后从寄存器中读取

          bi_boot_params就知道了uboot给我传递的参数到底在内存的哪里。然后自己去内存的那个地方去找bootargs。

        (2)、经过计算得知:X210中bi_boot_params的值为0x30000100,这个内存地址就被分配用来做内核传参了。

         所以在uboot的其他地方使用内存时要注意,千万不敢把这里给淹没了。

    11、interrupt_init

        (1)看名字函数是和中断初始化有关的,但是实际上不是,实际上这个函数是用来初始化定时器的(实际使用的是

        Timer4)。

        (2)使用Timer4来定时,因为没有中断支持,所以CPU不能做其他事情同时定时,CPU只能使用轮询方式来不断查看

        TCNTO寄存器才能知道定时时间到了没。因为Timer4的定时是不能实现微观上的并行。uboot中定时就是通过Timer4

        来现定时的。所以uboot中定时时不能做其他事(考虑下,典型的就是bootdelay,bootdelay中实现定时并且检查用

        户输入是用轮询方式实现的)。

    12、env_init

        (1)、和环境变量相关的初始化,有很多的env_init函数,主要原因是uboot支持各种不同的启动介质,我们一般从

          哪里启动就把环境变量env放在哪里。而各种介质操作env的方法都是不一样的。因此uboot支持了各种不同介质中

           env的操作方法。

    13、init_baudrate:初始化波特率的,getenv_r函数用来读取环境变量的值。用getenv函数读取环境变量

            中“baudrate”的值(注意读取到的不是int型而是字符串类型),然后用simple_strtoul函数将字符串转成数字

            格式的波特率。

    14、serial_init:串口初始化,我们在第一阶段已经初始化过串口了,所以在这里的serial_init其实什么都没干。

    15、console_init_f

        (1)、console_init_f是console(控制台)的第一阶段初始化。_f表示是第一阶段初始化,_r表示第二阶段初始化。

        有时候初始化函数不能一次一起完成,中间必须要夹杂一些代码,因此将完整的一个模块的初始化分成了2个阶段。

      (我们的uboot中start_armboot的826行进行了console_init_r的初始化)。      

        (2)、console_init_f在uboot/common/console.c中,仅仅是对gd->have_console设置为1而已,其他事情都没做。 

    16、display_banner

        (1)、display_banner用来串口输出显示uboot的logo。

    17、uboot启动过程

          CPU:  S5PV210@1000MHz(OK)

          APLL = 1000MHz, HclkMsys = 200MHz, PclkMsys = 100MHz

          MPLL = 667MHz, EPLL = 96MHz

                       HclkDsys = 166MHz, PclkDsys = 83MHz

                       HclkPsys = 133MHz, PclkPsys = 66MHz

                       SCLKA2M  = 200MHz

Serial = CLKUART 

这些信息都是print_cpuinfo打印出来的。  

    18、checkboard:checkboard看名字是检查、确认开发板的意思。这个函数的作用就是检查当前开发板是哪个

            开发板并且打印出开发板的名字。

     20、init_func_i2c:这个函数实际没有被执行,X210的uboot中并没有使用I2C。如果将来我们的开发板要扩展I2C来

            接外接硬件,则在x210_sd.h中配置相应的宏即可开启。   

    21、dram_init

            关于DDR的初始化。但是在BL1中已经初始化过了,这里为什么要进行第二次初始化?

            是给gb->bd里面关于DDR配置部分的全局变量赋值。让gb->bd数据记录下当前开发板的DDR的配置信息,以便

            uboot总是用内存。其实就是在初始化gd->bd->bi_dram。

    22、display_dram_config

            打印显示dram的配置信息。启动信息中的:(DRAM :512MB)就是在这个函数中打印出来的。

    23、mem_malloc_init函数用来初始化uboot的堆管理器。mmc_initialize是用来初始化SoC内部的SD/MMC控制器的

            env_relocate是环境变量的重定位,devices_init是设备的初始化,jumptable_init实现一个函数指针到具体函数

            的映射关系,将来通过跳转表中的函数指针就可以执行具体的函数,console_init_r控制台第二阶段初始化,

            enable_interrupts是CPSR中总中断标志位的使能,loadaddr、bootfile两个环境变量这两个环境变量都是内核

            启动有关的,在启动linux内核时会参考这两个环境变量的值;board_late_init对于X210来说,这个函数是空的

            (板级硬件初始化完成了)。eth_initialize网卡相关的初始化;x210_preboot_init(LCD和logo显示);

     24 、check menukey to update from sd

            uboot启动的最后阶段设计了一个自动更新的功能。就是:我们可以将要升级的镜像放到SD卡的固定目录中,

            然后开机时在uboot启动的最后阶段检查升级标志(是一个按键。按键中标志为"LEFT"的那个按键,这个按键如果

            按下则表示update mode,如果启动时未按下则表示boot mode)。如果进入update mode则uboot会自动从

            SD卡中读取镜像文件然后烧录到iNand中;如果进入boot mode则uboot不执行update,直接启动正常运行。

第二阶段启动总结:

        (1)第二阶段主要是对开发板级别的硬件、软件数据结构进行初始化。

        (2)

init_sequence

        cpu_init 空的

        board_init 网卡、机器码、内存传参地址

dm9000_pre_init 网卡

gd->bd->bi_arch_number 机器码

gd->bd->bi_boot_params 内存传参地址

interrupt_init 定时器

env_init

init_baudrate gd数据结构中波特率

serial_init 空的

console_init_f 空的

display_banner 打印启动信息

print_cpuinfo 打印CPU时钟设置信息

checkboard 检验开发板名字

dram_init gd数据结构中DDR信息

display_dram_config 打印DDR配置信息表

mem_malloc_init 初始化uboot自己维护的堆管理器的内存

mmc_initialize inand/SD卡的SoC控制器和卡的初始化

env_relocate 环境变量重定位

gd->bd->bi_ip_addr gd数据结构赋值

gd->bd->bi_enetaddr gd数据结构赋值

devices_init 空的

jumptable_init 不用关注的

console_init_r 真正的控制台初始化

enable_interrupts 空的

loadaddr、bootfile  环境变量读出初始化全局变量

board_late_init 空的

eth_initialize 空的

x210_preboot_init LCD初始化和显示logo

check_menu_update_from_sd 检查自动更新

main_loop 主循环

欢迎各位指出不足之处


猜你喜欢

转载自blog.csdn.net/qq_41003024/article/details/80390275
今日推荐