u_boot初始化流程_第1页
u_boot初始化流程_第2页
u_boot初始化流程_第3页
u_boot初始化流程_第4页
u_boot初始化流程_第5页
已阅读5页,还剩5页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、U-Boot启动代码分析 U-boot的启动顺序分为stage1和stage2两部分,见下图。依赖于CPU体系结构的代码(如设备初始化代码等)通常放在stage1中用汇编语言实现,而在stage2则通常由C语言实现,这样可以实现复杂的功能,而且有更好的可读性和移植性。以下主要梳理了stage2阶段函数的调用顺序以及每个函数的功能。 U-boot的启动顺序 C语言代码部分lib_arm/board.c中的start_armboot既是C语言开始的函数也是整个启动代码中C语言的主函数,同时还是整个U-boot的主函数,该函数只要完成如下操作。 (1)调用一系列的初始化函数。 (2)初始化Flash

2、设备。 (3)初始化系统内存分配函数 (4)如果目标系统拥有NAND设备,则初始化NAND设备 (5)如果目标系统有显示设备,则初始化该类设备。 (6)初始化相关网络设备,填写IP、MAC地址等。 (7)进入命令循环(即整个Boot的工作循环),接收用户从串口输入的命令,然后进行相应的工作。下面结合源码分析函数调用顺序以及函功能:代码:void start_armboot (void)init_fnc_t *init_fnc_ptr;char *s;int mmc_exist = 0;#if defined(CONFIG_VFD) | defined(CONFIG_LCD)unsigned l

3、ong addr;#endif注释:从U-boot stage1中start.s程序调到这里执行start_armboot函数,这一段代码进行了变量声明,其中定义了一个名为init_fnc_ptr的双重指针。如果CONFIG_VFD或者CONFIG_LCD被定义了则声明一无符号长整型变量addr,本开发板中没有定义无需声明addr。代码:/* Pointer is writable since we allocated a register for it */gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t);/

4、* compiler optimization barrier needed for GCC = 3.4 */_asm_ _volatile_(: : :memory); /内存屏障,告诉编译器内存被修改过了memset (void*)gd, 0, sizeof (gd_t); gd-bd = (bd_t*)(char*)gd - sizeof(bd_t); /指向gd之前memset (gd-bd, 0, sizeof (bd_t);/gd-flags |= GD_FLG_RELOC;monitor_flash_len = _bss_start - _armboot_start; /u-bo

5、ot映像的大小其中_armboot_start为 code start ,_bss_start为 code + data end = BSS start.注释:gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t);/内存强制转换,gd为全局环境变量,gd指向uboot之前的地址;memset ():void * memset(void * s,char c,size_t count)将指针s所指地址以及之后count个地址中数值赋值为c。memset (void*)gd, 0, sizeof (gd_t)的作用为:

6、gd整个地址的值初始化为0;memset (gd-bd, 0, sizeof (bd_t)的作用为bd地址的值初始化为0。代码:for (init_fnc_ptr = init_sequence; *init_fnc_ptr; +init_fnc_ptr) if (*init_fnc_ptr)() != 0) /相当于调用指针中的一个函数,如果不为0就表示死机hang ();注释:将init_squence数组送给init_fnc_ptr,利用循环调用init_squence数组中的多个初始化函数,包括初始化CPU、board、中断、时钟、NOR Flash、NAND Flash等,后面根据代

7、码进行分析。初始化完成之后进入hang()处于死循环即完成U-boot使命。init_sequence 数组保存基本的初始化函数指针,在board.c中对数组进行了定义:#if defined(CONFIG_ARCH_CPU_INIT)arch_cpu_init,/* basic arch cpu dependent setup */#endifboard_init,/* basic board dependent setup */#if defined(CONFIG_USE_IRQ)interrupt_init,/* set up exceptions */#endif/timer_init

8、,/* initialize timer */#ifdef CONFIG_FSL_ESDHC/get_clocks,#endifenv_init,/* initialize environment */ init_baudrate,/* initialze baudrate settings */serial_init,/* serial communications setup */ console_init_f,/* stage 1 init of console */ off_charge,/ xiebin.wang ,for charger&power off device.displ

9、ay_banner,/* say that we are here */#if defined(CONFIG_DISPLAY_CPUINFO)print_cpuinfo,/* display cpu info (and speed) */ #endif#if defined(CONFIG_DISPLAY_BOARDINFO)checkboard,/* display board info */#endif#if defined(CONFIG_HARD_I2C) | defined(CONFIG_SOFT_I2C)/init_func_i2c,#endifdram_init,/* configu

10、re available RAM banks */#if defined(CONFIG_CMD_PCI) | defined (CONFIG_PCI)/arm_pci_init,#endifdisplay_dram_config, NULL,;注释:下面按照顺序依次分析各个初始化函数作用(绿色代码是被注释掉的并不执行):arch_cpu_init():基本处理器相关配置。如果定义了CONFIG_ARCH_CPU_INIT则执行此函数,本开发板在include/configs/smdkc100.h中定义了此变量。最终在串口打印:CPU: SMDK4412-AP1.1 e APLL = 1000M

11、Hz, MPLL = 800MHz ARM_CLOCK = 1000MHz board_init():基本的板级相关配置,设置了一些寄存器,如时钟,IO口,串口,机器类型,启动参数,指令cache,数据cache.env_init():初始化环境变量,这个函数主要是在gd里保存环境变量的存放地址。一般使用默认的环境变量值即default_environment数组。init_baudrate():初始化波特率设置,调用getenv_r()函数来获取环境变量,从上面刚初始化好的环境变量列表里找波特率值,如果没有就赋初始值为CONFIG_BAUDRATE,一般在board.c中定义函数。seria

12、l_init():串口通信设置, 在cpu/Arm-cortexa9的serial.c中定义了该函数。console_init_f():控制台初始化阶段,初始化了几个控制台相关的标记。在common/Console.c中定义。off_charge():管理和关闭设备。display_banner():打印U-boot信息,包括了一些显示函数,在board.c中定义了该函数。print_cpuinfo():打印cpu信息,如果定义了CONFIG_DISPLAY_CPUINFO,则执行该函数,本开发板定义了此变量。checkboard():如果定义了CONFIG_DISPLAY_BOARDINFO

13、,则执行函数。dram_init():配置可用的RAMdisplay_dram_config():显示RAM的配置,打印出DRAM的大小,在board.c中定义了该函数。代码:/* armboot_start is defined in the board-specific linker script */mem_malloc_init (_armboot_start - CONFIG_SYS_MALLOC_LEN,CONFIG_SYS_MALLOC_LEN); #ifndef CONFIG_SYS_NO_FLASH/* configure available FLASH banks */di

14、splay_flash_config (flash_init ();注释:mem_malloc_init():初始化堆空间,malloc使用的内存空间地址。在common/Dlmalloc.c中定义了该函数。flash_init ():记录下flash的大小,数量,sector的大小数量等,并对flash上重要的数据进行保护。display_flash_config():通过调用flash_init ()来打印flash的大小信息,在board.c中定义了该函数。代码:#ifdef CONFIG_VFD#ifndef PAGE_SIZE# define PAGE_SIZE 4096#endif

15、/* * reserve memory for VFD display (always full pages) */* bss_end is defined in the board-specific linker script */addr = (_bss_end + (PAGE_SIZE - 1) & (PAGE_SIZE - 1);vfd_setmem (addr);gd-fb_base = addr;#endif /* CONFIG_VFD 注释:如果CONFIG_VFD被定义PAGE_SIZE没有被定义,则定义PAGE_SIZE为4096,为VFD保存内存空间,以页为单位。vfd_s

16、etmem(addr):计算VFD内存大小。代码:#ifdef CONFIG_LCD/* board init may have inited fb_base */if (!gd-fb_base) #ifndef PAGE_SIZE# define PAGE_SIZE 4096#endif/* * reserve memory for LCD display (always full pages) */* bss_end is defined in the board-specific linker script */addr = (_bss_end + (PAGE_SIZE - 1) & (

17、PAGE_SIZE - 1);lcd_setmem (addr);gd-fb_base = addr;#endif /* CONFIG_LCD */注释:如果定义了CONFIG_LCD,则执行这段代码。为LCD保存内存空间。lcd_setmem (addr):计算LCD内存大小。代码:#if defined(CONFIG_CMD_NAND)puts (NAND:);、nand_init();/* go init the NAND */#endif注释:如果定义了CONFIG_CMD_NAND,则执行该段代码。这一段代码实现:打印NAND1024MB。nand_init():NAND Flash

18、初始化,在drivers/mtd/nand/nand.c中定义了该函数。代码:#if defined(CONFIG_CMD_ONENAND)onenand_init();#endif注释:如果定义了CONFIG_CMD_ONENAND,则执行该段代码,本开发板中定义了此变量。onenand_init():初始化ONENAND FLASH。代码:#ifdef CONFIG_GENERIC_MMCputs (MMC: );mmc_exist = mmc_initialize (gd-bd);if (mmc_exist != 0)puts (0 MBn);#endif注释:CONFIG_GENERI

19、C_MMC被定义则执行该段代码。这段代码实现初始化SD/MMC。mmc_initialize():会初始化主机端接口,调用board_mmc_init,board_mmc_init需要根据项目对系统内的sdhc接口进行初始化。在drivers/mmc/mmc.c中定义了该函数。代码:#ifdef CONFIG_HAS_DATAFLASHAT91F_DataflashInit();dataflash_print_info();#endif注释:CONFIG_HAS_DATAFLASH被定义则执行该段代码。若系统支持 DataFlash,调用 AT91F_DataflashInit()和 data

20、flash_print_info()进行初始化并显示检测到的器件信息。AT91F_DataflashInit():首先调用AT91F_SpiInit ()初始化SPI接口,然后调用扫描所有的 SPI 片选,检测DataFlash是否存在,实现原理和NAND Flash类似,都是向芯片发送查询ID命令,根据返回值判断芯片的类型和容量。 代码:/* initialize environment */env_relocate ();注释: env_relocate ():进行环境变量的重定位,即从 Flash中搬移到 RAM 中代码:#ifdef CONFIG_VFD/* must do this

21、after the framebuffer is allocated */drv_vfd_init();#endif /* CONFIG_VFD */注释:CONFIG_VFD被定义则执行。drv_vfd_init():VFD 设备初始化代码:#ifdef CONFIG_SERIAL_MULTIserial_initialize();#endif注释:CONFIG_SERIAL_MULTI被定义了则执行该段代码。serial_initialize():所有的设备都在serial_initialize()中注册到链表中,,serial_initialize包含了uboot能支持的各种mcu串口初

22、始化函数。如果你想支持一种新的MCU,则必须修改serial.c文件,将初始化函数加入到serial_initialize。serial_initialize中虽然包含了很多初始化函数,但不是每个函数都需要加入到编译中。代码:/* IP Address */gd-bd-bi_ip_addr = getenv_IPaddr (ipaddr);stdio_init ();/* get the devices list going. */jumptable_init ();注释:getenv_IPaddr():会返回IPaddr_t(unsigned long)类型的IP地址赋值给gd-bd-bi_

23、ip_addr全局变量。调用了getenv(var)函数,返回这个索引所在的环境环境变量的地址,其中有两个for循环,外层for循环在遍历default_environment数组,内层判断是否超出环境变量的大小。外层循环中调用了envmatch(),函数里面使用while循环去找环境变量中的=号前面的是否有ipaddr字符串,有则返回ipaddr在环境变量中的索引。stdio_init ():初始化各类外设,如IIC、LCD、键盘、USB等,当然只有在定义了这些外设的前提下,才对这些外设进行初始化。该函数是在common目录下的stdio.c文件中定义的。jumptable_init ():

24、初始化跳转表gd-jt,该跳转表是一个函数指针数组,它定义了U-Boot中基本的常用函数库。该函数是在common目录下的exports.c文件中定义的。代码:#if defined(CONFIG_API)/* Initialize API */api_init ();#endifconsole_init_r ();/* fully init console as a device */注释:api_init ():初始化API,用于为U-boot编写的“应用程序”。如果CONFIG_API被定义了则执行api_init ()函数。console_init_r ():主要完成的工作将扫描设备表

25、中注册的设备,并将扫描到得设备和控制台绑定,以从特定的设备完成输入输出。代码:#if defined(CONFIG_ARCH_MISC_INIT)/* miscellaneous arch dependent initialisations */arch_misc_init ();#endif#if defined(CONFIG_MISC_INIT_R)/* miscellaneous platform dependent initialisations */misc_init_r (); #endif注释:arch_misc_init ():依赖于arch的杂项初始化misc_init_r

26、():依赖于平台进行杂项初始化代码:/* enable exceptions */enable_interrupts (); 注释:enable_interrupts ():使能IRQ中断,在arch/arm/lib目录下的interrupts.c文件中定义的。代码:/* Perform network card initialisation if necessary */#ifdef CONFIG_DRIVER_TI_EMAC/* XXX: this needs to be moved to board init */extern void davinci_eth_set_mac_addr

27、(const u_int8_t *addr);if (getenv (ethaddr) uchar enetaddr6;eth_getenv_enetaddr(ethaddr, enetaddr);davinci_eth_set_mac_addr(enetaddr);#endif注释:TI芯片中的内置MAC初始化。eth_getenv_enetaddr:读取环境变量代码:#if defined(CONFIG_DRIVER_SMC91111) | defined (CONFIG_DRIVER_LAN91C96)/* XXX: this needs to be moved to board ini

28、t */if (getenv (ethaddr) uchar enetaddr6;eth_getenv_enetaddr(ethaddr, enetaddr);smc_set_mac_addr(enetaddr);#endif /* CONFIG_DRIVER_SMC91111 | CONFIG_DRIVER_LAN91C96 */注释:网卡芯片的初始化代码:/* Initialize from environment */if (s = getenv (loadaddr) != NULL) load_addr = simple_strtoul (s, NULL, 16);注释:本段代码实现 从环境变量中获取loadaddr参数,得到需要加载的地址。代码:#if defined(CONFIG_CMD_NET)if (s = getenv (bootfile) != NULL) copy_filename (BootFile, s, sizeof (BootFile);#endif注释:本段代码实现从环境变量中获取bootfile参数,得到通过TFTP加载的镜像文件名。代码:#ifde

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论