嵌入式系统学习(六)-bootloader基础及分析

为启动ARM Linux系统,BootLoader需要初始化多种设备,最终调用Linux内核,并向内核传递硬件相关的信息。

    BootLoader最终需要提供以下功能:

a. 建立和初始化内存

b. 初始化一个串口

c. 检测设备类型

d. 设置内核tagged列表(描述硬件参数)

e. 加载initramfs

f. 调用内核镜像

    调用内核时,需要满足以下要求:

(1)CPU寄存器设置

r0 =0,

r1 = 机器类型,

r2 =tagged list在内存中的物理地址或设备树块(dtb)在内存中的物理地址。

(2)CPU模式

所有形式的中断必须被禁止;

对于不包含ARM虚拟化扩展的CPU,CPU必须处于SVC模式;

包含虚拟化扩展支持的CPU必须进入HYP模式。

(3) 缓存,MMU

MMU必须关闭;

指令缓存可以是打开或者关闭;

数据缓存必须关闭。

(4)BootLoader应该通过直接跳至内核镜像的第一条指令地址来调用内核。

Bootloader
代码运行流程如下:

 首先,可以看到Bootloader的源码目录如下:



U-boot 的启动流程包括两个阶段,第一阶段进行一些基本的初始化动作,为启动第二阶段的主体做准备,此阶段代码由汇编代码写成。第二阶段是进行系统的初始化工作,并准备引导操作系统。下面对这两个阶段进行详细的分析。

从链接脚本文件u-boot.lds(\uboot_nanopi2-nanopi2-lollipop-mr1\arch\arm\cpu\slsiap\u-boot.lds)中可以找到代码的起始:


从中知道程序的入口点是_start,定位于arch/arm/cpu/slsiap/s5p4418/start.o (即u-boot启动的第一阶段),我们通过分析start.S来看第一阶段进行了怎样的设置.

在start.S中,有:


在上面代码中,设置了u-boot的主入口,跳入了后面的reset。还有对PC赋值,即是实现代码跳转,设置发生“未定义指令”, “软件中断”,“预取指错误”,“数据错误”,“未定义”,“(普通)中断”,“快速中断”的时候,系统所要去执行的代码地址。

Uboot代码从这里开始执行,让系统进入SVC管理模式。首先mrs    r0, cpsr 初始化cpsr,而bic   r0, r0, #0x1f 使用r0[0:5] = 0, bic=位清零。在orr   r0, r0, #0xd3 中,11010011cpsr的最终值,其中中断关闭, 模式设置为SVC模式 。最后一句代码将CPSR的值赋给R0寄存器。

上述代码是对cp15协处理器进行初始化设置,进行了TLBs、icache、BP数组的无效处理,并禁止MMU代理和caches。

在这段代码中,跳入了主板确切的初始化位置来进行各种参数的设置。在这里调用board/lowlevel_init.S中的lowlevel_init函数,对系统总线的初始化,初始化了连接存储器的位宽、速度、刷新率等重要参数。经过这个函数的正确初始化,Nor FlashSDRAM才可以被系统使用。


在上述代码中,比较r0和r1,如果不相等,就把代码从flash中复制到ram中。然后进行BSS数据段清理。如果MMU被设置为可使用的话,则可以跳到mmu_turn_on中进行打开处理。

在上面代码中,设置了第二阶段的入口位置,即第二阶段入口函数board_init_r,下面我们进入board.c文件中分析:

在这个源代码文件中,完成的主要工作包括:

(1)  为U-boot内部私有数据分配存储空间,并清零;

(2)  依次调用函数指针数组init_sequence 中定义的函数进行一系列的初始化

(3)  如果系统支持 NOR Flash,调用flash_init ()和display_flash_config()初始化并显示检测到的器件信息(AT91SAM9260EK 不需要);

(4)  如果系统支持 LCD 或VFD,调用lcd_setmem()或vfd_setmem()计算帧缓冲(Framebuffer)大小,然后在BSS 数据段之后为Framebuffer 分配空间,初始化gd->fb_base为Framebuffer的起始地址(AT91SAM9260EK 不需要);

(5)  调用mem_malloc_init()进行存储分配系统(类似于C 语言中的堆)的初始化和空间分配;

(6)  如果系统支持 NAND Flash,调用nand_init ()进行初始化;

(7)  如果系统支持 DataFlash,调用AT91F_DataflashInit()和dataflash_print_info()进行初始化并显示检测到的器件信息;

(8)  调用 env_relocate()进行环境变量的重定位,即从Flash 中搬移到RAM 中;

(9)  如果系统支持 VFD,调用drv_vfd_init()进行VFD 设备初始化(AT91SAM9260EK不需要);

(10)调用 jumptable_init()进行跳转表初始化,跳转表在global_data中;

(11)调用 console_init_r()进行控制台初始化;

(12)如果需要,调用 misc_init_r ()进行杂项初始化;

(13)调用 enable_interrupts()打开中断;

(14)如果需要,调用board_late_init()进行单板后期初始化

(15)进入主循环:根据用户的选择启动 linux,或者进入命令循环执行用户输入的命令;

进行源代码流程分析,首先进行一些基本设置:


在上面,第一个方法进行波特率的初始化;第二个方法显示_STACK_START等的地址,比如_start, _bss_start,_bss_end 这些值。

上面的函数用来显示内存的配置,打印出DRAM的大小。


在上面,定义一个初始化的整型指针数组,将在后面被调用。在调用过程中,会依次进行一系列的初始化,分别是初始化环境变量、初始化波特率设置、串口通讯设置、控制台初始化阶段1、打印u-boot信息、显示CPU的配置大小、根据需要显示板的信息、配置可用的RAM。

以下函数内容:


该函数是启动阶段1结束后开始执行的函数,进行主板的初始化配置。我们从上面可以获悉该函数给全局数据变量gd分配内存,对FDT进行地址和空间分配,并且顺序执行init_sequence数组中的初始化函数。该数组在上面分析过,它将依次触发init_sequence定义的函数来进行一系列的初始化操作。

接着有这样一个函数should_load_env

该函数用来判断是否进行完了uboot的环境加载设置,如果是的话返回1,否则返回0。当进行完环境配置后,会被调用来进行判断。如果是成功的话,进行下一部分的初始化,即进入board_init_r(gd_t *id, ulong dest_addr)函数。


从上面可以看出来,主要有以下几个作用:

a)    itor_flash_len =(ulong)&__rel_dyn_end - (ulong)_start: 设置了flash的长度;

b)    enable_caches():使缓存可以使用;

c)    set_cpu_clk_info():根据需要启动计时器;

d)    serial_initialize():串口初始化;

e)    mem_malloc_init(malloc_start, TOTAL_MALLOC_LEN):初始化堆空间;


f)    flash_size =flash_init():根据需要配置可用的flash

g)    nand_init():根据命令初始化nandflash

h)  mmc_initialize(gd->bd):根据需要MMC初始化;


i)    env_relocate():重新定位环境变量;

j)    stdio_init():调用相应驱动函数对硬件设备进行初始化;

k)    jumptable_init():初始化跳转表;

l)    api_init():如果配置了接口,初始化各个接口;

m)    console_init_r():完整地初始化控制台设备;

n)    interrupt_init():中断初始化;enable_interrupts():能使中断处理;

o)    board_late_init():进行单板后期初始化;

p)    eth_initialize(gd->bd):以太网初始化;

在board_init_r(gd_t *id, ulong dest_addr)函数的最后,调用一个for循环,跳入main.c中的main_loop()中去进行uboot启动后的操作,如下:


main_loop()在uboot初始化后,等待进程命令来执行。在该函数里面,进行了Modem功能的设置,打开该功能可以接受其他用户通过电话网络的拨号请求。同时设置U-Boot的版本号,启动延迟功能(s= bootdelay_process())。如果用户按下任意键打断,启动流程,会向终端打印出一个启动菜单。最后自动运行引导内核的命令(autoboot_command(s))。


  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值