Uboot的前尘后事

Uboot作为引导Linux Kernel启动的引导程序,从其开始被加载到DDR到bootdelay时间到执行bootcmd环境变量中的命令(bootm)从而结束生命,其一生都在为启动kernel而服务。

一、主要作用:

1.提供一个shell命令行,用以设定环境变量,执行各种命令,来影响kernel启动运行过程

2.必要的硬件初始化工作,如对内存DDR、系统时钟、串口等硬件的初始化

3.向kernel传参,以引导内核正常启动

4.将内核从启动介质中重定位到DDR中运行

.......(目前就想到这些,以后会补充)

二、运行时的阶段

分为两步:

第一阶段是前16K大小,主要为汇编代码:soc上电后其内部irom内固化的代码会做一些初始化设置工作,如判断出启动介质的类型(emmc、nand、sd、inand)后初始化启动介质,初步设置系统时钟,然后从启动介质中将uboot的前16k加载到soc内部iram中运行,这前16k代码会初始化串口、DDR等硬件,然后从启动介质中将uboot整个加载到DDR中运行(重定位)。

第二阶段是整个uboot,主要为c代码:第一部分将uboot加载到DDR中后,uboot就在ddr中运行进入第二阶段,主要负责硬件的初始化、环境变量的设置以及向内核传参等工作。

三、小结

第一阶段注重SoC内部、第二阶段注重SoC外部Board内部

第一阶段做的主要工作有:建立异常向量表、设置cpu进入SVC模式、判断启动方式(emmc、nand、sd、inand)、关看门狗、供电锁存、时钟初始化、ddr初始化(硬件层次的,目的是让ddr能使用)、初始化uart串口并打印“OK”、ddr中设置栈、重定位uboot、建立粗页表(mmu)、长条转至第二阶段。

第二阶段做的主要工作有:

1.设置gd_base (gd_base为gd_t结构体类型变量的基地址,该结构体变量中包含许多开发板启动的相关信息):

                    gd_base = CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE - sizeof(gd_t);

2.设置gd->bd (gd->bd 为gd所指向的结构体变量中的一个指针成员,它指向bd_t类型的结构体变量,bd_t结构体变量里面是和开发板硬件相关的一些信息):

                     gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));

3.执行函数指针数组init_sequence中各函数指针所指向的函数体:

                        3.1 cpu_init:cpu初始化相关,此处为空,因为在uboot第一阶段已经做好了对cpu的相关初始化工作。

                        3.2 board_init:开翻版相关初始化,包含:

                                                   3.2.1 dm9000_pre_init网:卡初始化

                                                    3.2.2 gd->bd->bi_arch_number:开发板机器码初始化

                                                     3.2.3 gd->bd->bi_boot_params:设置uboot启动内核时向内核传递的参数的首地址

                         3.3 interrupt_init:看名字像是中断初始化,其实不是,这里是将timer4定时器设置为定时10ms

                         3.4 env_init:环境变量初始化

                         3.5 init_baudrate:gd->baudrate和gd->bd->baudrate中波特率设置。

                         3.6 serial_init:串口初始化,内容为空,因为在uboot第一阶段已经初始化过了

                         3.7 console_init_f:控制台初步初始化,为空

                         3.8 display_banner:打印uboot启动信息,比如uboot版本号

                         3.9 print_cpuinfo:打印cpu相关信息,比如cpu时钟

                         3.10 checkboard:打印开发板型号 BOARD:x210

                         3.11 dram_init:dram(ddr)软件相关初始化

                         3.12 display_dram_config:打印dram相关信息。如容量等。

4.mem_malloc_init:初始化uboot自己维护的堆内存

5.mmc_exist=mmc_initialize():初始化sd/inand,并打印容量信息

6.env_relocate:环境变量重定位

7.gd->bd->bi_ip_addr :获取开发板ip地址

8.gd->bd->bi_enetaddr:获取开发板MAC

9.devices_init:开发板板载设备初始化,此处为空

10.jumptable_init:跳转表初始化,不用关注。

11.enable_interrupts:中断使能,为空

12.getenv ("loadaddr"):获取loadaddr环境变量,与启动内核有关

13.getenv ("bootfile"):获取bootfile环境变量,与启动内核有关

14.board_late_init:为空

15.eth_initialize:网卡初始化

                            15.1miiphy_init

16.x210_preboot_init:uboot启动时lcd显示相关设置

                                    16.1mpadfb_init:

                                                          16.1.1 fb_init:初始化fb

                                                          16.1.2  lcd_port_init:lcd显示相关设置

                                                          16.1.3 lcd_reg_init:lcd显示相关设置

                                                          16.1.4 display_logo:显示uboot启动时的logo

17.update_all:设置uboot启动时自动更新功能

18.main_loop:进入死循环。不断解析uboot的命令并执行命令。

四、启动内核的四个步骤

第一步:将内核搬移到DDR中(内核重定位)
第二步:校验内核格式、CRC等(检验内核是zImage/uImage)
第三步:准备传参(tag形式传参)
第四步:跳转执行内核

补充一点关于uboot启动内核时的一些小细节:

1.内核最初被编译连接成elf格式的二进制可执行文件,这种文件可以再操作系统环境下直接运行,但无法被烧录,且文件占内存很大。因此需要对原始的elf文件进行处理操作(主要是压缩)形成image镜像文件,image文件再进一步处理(进一步压缩,且将头校验信息放到镜像头部)形成zImage镜像文件,这个文件才是最终被烧录运行的镜像文件(注意在zImage最头部还要添加未经压缩的解压缩代码,用来将之前压缩的内核代码解压开来)。

2.可见uboot要启动内核首先要对zImage文件进行解压缩,解压缩代码就添加在zImage的最开始处,且这段解压缩代码未被压缩,可供uboot直接调用,去压缩zImage中后面那部分被压缩的真正的内核程序。

3.uboot向内核传参时是通过cpu的特殊功能寄存器r0、r1、r2进行的,即调用函数:thekernel(0,machid,bd->bi_boot_params),三个参数分别存入r0、r1、r2中。第一个参数是默认参数0,第二个是设备机器码,内核校验用,第三个是uboot传给kernel的参数所在的内存地址,内核从该地址处可取出uboot传递的参数。

 

你可能感兴趣的:(嵌入式Linux:uboot)