uboot移植——uboot启动回顾

简介:

一:uboot启动的第一阶段start.S(路径uboot/cpu/s5pc11x/start.S)


1:#include <config.h> //头文件包含,config.h文件源码中不存

在,配置后自动生成;路径/include/linux/config.h;


2:#include <version.h>//头文件包含,version.h文件源码中不存

在,配置后自动生成;路径/include/version.h;


3:#include <asm/proc/domain.h> //头文件包含,asm/proc是链接

符号,实际指向include/asm-arm/proc-armv/domain.h;

4:填充uboot的前16字节,为后面的CRC校验占位;


5:构建异常向量表,但uboot中并没有设置异常处理,发生异常时重

启即可;


6:balignl 16,0xdeadbeef 内存对齐,如果不对齐则用0xdeadbeef进行填充;

7:复位函数,通过msr命令来操作CP15协处理器的后8位,设置为SVC模式;


8:l2cache设置相关;关闭MMU;


9:读取OMpin引脚的电平高低来判断启动方式(SD卡 nand等);


10:第一次设置栈,因为这个时候DDR还没有被初始化,所以这次设置栈是在SDRAM中;


11:lowlevel_init函数;

(1)check reset status :检查CPU复位状态(热上电,睡眠模式唤醒不需要初始化DDR;冷上电需要初始化DDR);

(2) IO Retention release :复位后IO口的保存与恢复;

(3)Disable Watchdog :关看门狗;

(4)PS_HOLD pin(GPH0_0) set to high :设置开发板供电锁存

(5)判断当前代码执行的位置是在SDRAM还是DDR中,主要思路是通过

bic将当前PC位置和_TEXT_BASE(uboot在DDR的起始地址)的高8位和

低12位清零,比较剩下的中间12位是否相等,如果相等,则在当前代

码则在DDR中运行,如果不相等,则当前代码在SDRAM中运行;在DDR中

运行则不需要初始化时钟和DDR,在SDRAM中运行则需要初始化时钟和

DDR;

(6)串口初始化,并打印出'OK',OK是一个中间的检查标志,如果没

有看到OK则代表是lowlevel_init函数之前出了问题,如果打印了OK则

代表是lowlevel_init后面出了问题;


12:set PS_HOLD signal to high :再次设置开发板供电锁存


13:get ready to call C functions:第二次设置栈,在DDR中,位

置是0x33e00000;


14:判断当前代码运行位置是在DDR还是SDRAM,如果在SDRAM则完成重

定位,将BL2(整个uboot)复制到链接地址33e00000处


15:开启MMU,进行虚拟地址映射;


16:第三次设置栈,目的是为了使栈更加安全,内存使用合理,地址

是0x33e00000+2M-1K;


17:clear_bss: 清bss段;


18:ldr    pc, _start_armboot 短跳转到start_armboot函数,进行

uboot启动的第二阶段;

二:uboot启动的第二阶段start_armboot()函数(路径 uboot/lib_arm/Board.c)
1:gd bd地址的设置:gd在DDR中的位置33e00000+2M-912k-512k,bd

在gd下面,紧挨着;gd是一个结构体指针,放在寄存器r8中,gd所指

向的结构体中存放的都是一些全局变量gd->bd也是一个结构体里面存

放着bi_baudrate 波特率(开发板的波特率);  

bi_ip_addr IP地址;  bi_enetaddr MAC地址;  bi_arch_number  

机器码;

bi_boot_params  将来给内核传参的参数的存放地址0x30000010 

struct {ulong start;ulong size; } 

bi_dram[CONFIG_NR_DRAM_BANKS];DDR的起始地址和大小;

2:通过一个for循环来遍历init_sequence函数指针数组中的指针,最

后通过判断最后一个函数是不是NULL来跳出这个循环

(1)cpu_init:一个空函数,返回0

(2)reloc_init

(3)board_init:初始化网卡(DM9000),获取机器码

bi_arch_number 和分配bi_boot_params的内存地址;

(4)interrupt_init:初始化定时器4,设置10ms定时,用于

bootdelay ;

(5)env_init:环境变量的设置;

(6)init_baudrate:初始化波特率(控制台的波特率,数值上和开

发板的波特率相等);

(7)serial_init:初始化串口,串口在第一阶段start.S 中就已经

初始化了,所以这个函数什么也没做;

(8)console_init_f:控制台初始化的第一阶段,在uboot中没有用

到控制台,而是直接调用串口发送函数puts();

(9)display_banner:打印uboot的版本信息,也就是我们在主

Makefile设置的uboot的版本号;

(10)print_cpuinfo:初始化时钟;

(11)checkboard:打印开发板信息 ,Board:   X210;

(12)init_func_i2c:这里没使用i2c,所以这个函数实际没起作

用;

(13)dram_init():gd-bd.bi_dram结构体内各个变量的赋值,也就

是每片DDR的起始地址和大小;

(14)display_dram_config:打印DDR的配置信息;

3:mem_malloc_init (CFG_UBOOT_BASE + CFG_UBOOT_SIZE - 

CFG_MALLOC_LEN - CFG_STACK_SIZE); 分配堆空间,        

33e00000+2M-896K-512K

4:#if defined(CONFIG_X210):不同开发板独有的初始化,我们是

x210,所以执行这个条件编译。这里面主要是初始化MMC控制器,并打

印SD/MMC 的大小;
            
5:env_relocate();环境变量的重定位,将SD卡中的环境变量读取到

DDR中,需要注意的是第一次启动uboot的时候SD卡时没有env分区,而

是使用uboot内部硬编码的一套环境变量,然后写到SD卡中。

6:gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr"); 获取开发板

的IP地址,这个IP地址在x210_sd.h中有定义,并通过gd->bd来维护

(下面是MAC地址,同IP一样)
                                                 
7:devices_init();设备初始化;

8:jumptable_init();跳转表初始化,因为这里的跳转表只被赋值,

而没有被引用,所以并无实际作用;

9:console_init_r ();控制台初始化的第二阶段,控制台初始化的主

要部分都在第二阶段完成;

10:enable_interrupts();中断初始化,这里是CPSR寄存器中总中断

标志位的使能,但是由于uboot中并没有使用到中断所以这个函数并没

实际作用;
    
11:loadaddr;bootfile;这两个环境变量都是内核启动相关的环境变

量;

12:board_late_init (); 开发板级别的晚期初始化,也是最后的初

始化,实际是一个空函数;

13:x210_preboot_init();x210开发板在启动起来之前的初始化,主

要是led的初始化和logo的显示;

14:check menukey to update from sd :uboot提供了一种方便的刷

机方式,当我们需要升级系统时,只需要将系统烧录到SD卡的相应扇

区,在启动时按下LEFT按键,便可实现简便地升级系统;


15:for (;;) {  main_loop ();} //死循环  输入命令 解析命令   

输入命令  解析命令.... ; 
uboot启动第二阶段结束



本文转自 菜鸟养成记 51CTO博客,原文链接:http://blog.51cto.com/11674570/1830939

相关文章
|
3月前
|
安全 Linux Android开发
【ATF】bootloader与安全相关启动分析
【ATF】bootloader与安全相关启动分析
47 0
|
8月前
|
存储 数据库
飞腾uboot命令简单介绍
飞腾uboot命令简单介绍
455 0
飞腾uboot命令简单介绍
|
内存技术
判断uboot启动方式:norflash还是nandflash
判断uboot启动方式:norflash还是nandflash
146 0
判断uboot启动方式:norflash还是nandflash
|
Linux 内存技术
uboot设置bootargs启动根文件系统
uboot设置bootargs启动根文件系统