Uboot 启动流程分析:启动阶段2board.c

xiaoxiao2021-02-28  100

转载请注明原地址:http://blog.csdn.net/oyhb_1992/article/category/7082238

Uboot 启动流程分析:启动阶段2  board.c

         由启动阶段一,ldr         pc, _start_armboot这条语句绝对跳转到内存中继续执行_start_armboot这个函数,开始阶段2的代码。

首先要介绍几个结构体

 

1.gd_t全局数据结构,主要保存了uboot的配置信息。include/asm-arm/global_data.h中定义:

typedef struct global_data {  bd_t  *bd;//板子相关的结构体  unsigned long flags;   //是否跳转到内存中执行代码

 unsigned long baudrate;//波特率  unsigned long have_console; /* 串口调用*/  unsigned long reloc_off; /* Relocation Offset 重定位偏移*/  unsigned long env_addr; /* 环境变量基址*/  unsigned long env_valid; /* 环境变量是否有效 */  unsigned long fb_base; /*LCD帧缓冲基地址*/ #ifdef CONFIG_VFD  unsigned char vfd_type; /* display type */ #endif #if 0        //这段代码屏蔽掉  unsigned long cpu_clk; /* cpu频率*/  unsigned long bus_clk;/*总线频率*/  phys_size_t ram_size; /* RAM大小设置,64M*/  unsigned long reset_status; /* 重新设置状态地址*/ #endif  void  **jt;  /* jump table 保存着些函数的入口地址,在           common/Exports.c中进行填充*/ } gd_t;

 

2.bd_t板子数据结构体,主要保存与板子相关的信息。定义在include/asm-arm/u-boot.h

typedef struct bd_info {     int   bi_baudrate; /* 串口频率*/     unsigned long bi_ip_addr; /*IP地址*/     structenvironment_s        *bi_env;环境变量指针     ulong        bi_arch_number; /* 板子ID*/     ulong        bi_boot_params; /* 启动参数存放地址*/     struct    /* RAM configuration */     {

 ulong start;

 ulong size;     }   bi_dram[CONFIG_NR_DRAM_BANKS];//SDRAM的大小,此处的CONFIG_NR_DRAM_BANKS在smdk2410.h中宏定义 } bd_t;

3.环境变量结构体

#define ENV_SIZE (CONFIG_ENV_SIZE - ENV_HEADER_SIZE)

 

typedef         structenvironment_s {

     uint32_t   crc;            /*CRC32 over data bytes         */

#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT

     unsigned char  flags;                  /*active/obsolete flags   */

#endif

     unsigned char  data[ENV_SIZE]; /* Environment data             */

} env_t;

4.初始化函数队列。定义在lib_arm/Board.c

typedef int (init_fnc_t) (void);定义函数指针;

下面是函数指针数组

init_fnc_t *init_sequence[] = {  cpu_init,  /* CPU初始化,定义在cpu/arm920t/cpu.c*/ #if defined(CONFIG_ARCH_CPU_INIT)  arch_cpu_init,  /* 相关体系结构CPU初始化cpu/.../arch/cpu.c */ #endif  board_init,  /* 相关板子初始化board/sbc2410x/sbc2410.c*/  interrupt_init,  /* 中断初始化cpu/arm920t/s3c24x0/interrupts.c*/  env_init,  /* 环境变量初始化*/  init_baudrate,  /* 初始化波特率*/  serial_init,  /* 串口初始化drivers/serial/serial.c*/  console_init_f,  /* stage 1 init of console ??? */  display_banner,  /* say that we are here */ #if defined(CONFIG_DISPLAY_CPUINFO)  print_cpuinfo,  /* 打印CPU信息 */ #endif #if defined(CONFIG_DISPLAY_BOARDINFO)  checkboard,  /* 显示板块信息*/ #endif #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)  init_func_i2c,//IIC初始化函数 #endif  dram_init,  /* configure available RAM banks */ #if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI)  arm_pci_init, #endif  display_dram_config,存储器件初始化  NULL,

}

start_armboot函数主要是初始化外设,  和初始化gd数据结构,以便后来Linux内核访问。

下面开始分析start_armboot函数流程

 

void start_armboot (void)

{

         init_fnc_t**init_fnc_ptr;   //定义了一个二级指针,用来指向函数数组,实现遍历调用函数数组里的函数。

         char*s;

#if defined(CONFIG_VFD) || defined(CONFIG_LCD)

         unsignedlong addr;

#endif

 

         /*Pointer is writable since we allocated a register for it */

         /*_armboot_startuboot下载到内存中的地址值,减掉CONFIG_SYS_MALLOC_LENgd_t结构体大小就是gd变量的地址,看博文http://blog.csdn.net/oyhb_1992/article/details/76994140*/

   /*gd指针变量分配内存*/

         gd= (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));

         /*compiler optimization barrier needed for GCC >= 3.4 */

         __asm____volatile__("": : :"memory");

    /*清零gd结构体变量的内存*/

         memset((void*)gd, 0, sizeof (gd_t));

          /*注意:内存上gd_t结构体的后面存的是bd_t结构体*/

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

         memset(gd->bd, 0, sizeof (bd_t));

 

         gd->flags|= GD_FLG_RELOC;//标志代码已经调到内存中运行了

   /*_armboot_start=_start*/

         /*得到uboot代码在内存中的存储区域大小*/

         monitor_flash_len= _bss_start - _armboot_start;

         /*执行函数数组里的函数,在下一篇博客启动阶段3中分析*/

         for(init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {

                   if((*init_fnc_ptr)() != 0) {

                            hang();

                   }

         }

         /*初始化堆空间*/

         /*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自己对flash分区,更好管理*/

         display_flash_config(flash_init ());

#endif /* CONFIG_SYS_NO_FLASH */

 

#ifdef CONFIG_VFD

#       ifndefPAGE_SIZE

#         define PAGE_SIZE 4096

#       endif

         /*

          * reserve memory for VFD display (always fullpages)

          */

         /*bss_end is defined in the board-specific linker script */

         addr= (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);

         vfd_setmem(addr);  //分配VFD显示的帧缓存

         gd->fb_base= addr;

#endif /* CONFIG_VFD */

 

#ifdef CONFIG_LCD

         /*board init may have inited fb_base */

         if(!gd->fb_base) {

#                ifndefPAGE_SIZE

#                  define PAGE_SIZE 4096

#                endif

                   /*

                    * reserve memory for LCD display (always fullpages)

                    */

                   /*bss_end is defined in the board-specific linker script */

                   addr= (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);

                   lcd_setmem(addr);     //分配LCD显示的帧缓存

                   gd->fb_base= addr;

         }

#endif /* CONFIG_LCD */

 

#if defined(CONFIG_CMD_NAND)

         puts("NAND:  ");

         nand_init();                /* go init the NAND初始化NAND flash控制器*/

#endif

 

#if defined(CONFIG_CMD_ONENAND)

         onenand_init();   /*很复杂! */

#endif

#ifdef CONFIG_HAS_DATAFLASH

         /*AT91F_DataflashInit()完成 DataFlash的初始化。这个函数在drivers/dataflash.c中。首先调用AT91F_SpiInit ()初始化SPI接口,然后调用AT91F_DataflashProbe()扫描所有的 SPI片选,检测DataFlash是否存在,实现原理和NAND Flash类似,都是向芯片发送查询ID命令,根据返回值判断芯片的类型和容量。*/

         AT91F_DataflashInit();

         dataflash_print_info();

#endif

         /*初始化环境参数,就是UBOOT启动时输入命令printenv,setenv里面的参数*/

         /*initialize environment */

         env_relocate();

 

#ifdef CONFIG_VFD

         /*must do this after the framebuffer is allocated */

         /*初始化framebuff*/

         drv_vfd_init();

#endif /* CONFIG_VFD */

 

#ifdef CONFIG_SERIAL_MULTI

         serial_initialize();

#endif

 

         /*IP Address */

//通过命令行参数传递获取ip地址

         gd->bd->bi_ip_addr= getenv_IPaddr ("ipaddr");

 

         stdio_init();      /* get the devices list going. */

 

         jumptable_init();

 

#if defined(CONFIG_API)

         /*Initialize API */

         api_init();

#endif

 

         console_init_r();      /* fully init console as a device*/

 

#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

 

         /*enable exceptions */

         enable_interrupts();

 

         /*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 (constu_int8_t *addr);

         if(getenv ("ethaddr")) {

                   ucharenetaddr[6];

                   eth_getenv_enetaddr("ethaddr",enetaddr);

                   davinci_eth_set_mac_addr(enetaddr);

         }

#endif

 

#if defined(CONFIG_DRIVER_SMC91111) ||defined (CONFIG_DRIVER_LAN91C96)

         /*XXX: this needs to be moved to board init */

         if(getenv ("ethaddr")) {

                   ucharenetaddr[6];

                   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);

         }

#if defined(CONFIG_CMD_NET)

         if((s = getenv ("bootfile")) != NULL) {

                   copy_filename(BootFile, s, sizeof (BootFile));

         }

#endif

 

#ifdef BOARD_LATE_INIT

         board_late_init();

#endif

 

#ifdef CONFIG_GENERIC_MMC

         puts("MMC:   ");

         mmc_initialize(gd->bd);

#endif

 

#ifdef CONFIG_BITBANGMII

         bb_miiphy_init();

#endif

#if defined(CONFIG_CMD_NET)

#if defined(CONFIG_NET_MULTI)

         puts("Net:   ");

#endif

         eth_initialize(gd->bd);

#if defined(CONFIG_RESET_PHY_R)

         debug("Reset Ethernet PHY\n");

         reset_phy();

#endif

#endif

 

         /*main_loop() can return to retry autoboot, if so just run it again. */

         for(;;) {

                   main_loop();

         }

 

         /*NOTREACHED - no way out of command loop except booting */

}

 

void hang (void)

{

         puts("### ERROR ### Please RESET the board ###\n");

         for(;;);

}

 

 

 

 

参照文章:http://www.360doc.com/content/14/1101/11/19351147_421634710.shtml

转载请注明原文地址: https://www.6miu.com/read-28505.html

最新回复(0)