uboot 启动流程分析.docx

上传人:b****5 文档编号:7597012 上传时间:2023-01-25 格式:DOCX 页数:12 大小:58.75KB
下载 相关 举报
uboot 启动流程分析.docx_第1页
第1页 / 共12页
uboot 启动流程分析.docx_第2页
第2页 / 共12页
uboot 启动流程分析.docx_第3页
第3页 / 共12页
uboot 启动流程分析.docx_第4页
第4页 / 共12页
uboot 启动流程分析.docx_第5页
第5页 / 共12页
点击查看更多>>
下载资源
资源描述

uboot 启动流程分析.docx

《uboot 启动流程分析.docx》由会员分享,可在线阅读,更多相关《uboot 启动流程分析.docx(12页珍藏版)》请在冰豆网上搜索。

uboot 启动流程分析.docx

uboot启动流程分析

U-Boot启动流程

大多数bootloader都分为stage1和stage2两大部分,u-boot也不例外。

依赖于CPU体系结构的代码(如设备初始化代码等)通常都放在stage1,且可以用汇编语言来实现,而stage2则通常用C语言来实现,这样可以实现复杂的功能,而且有更好的可读性和移植性。

u-boot启动大致流程如图1所示:

                                                                                       图1

>Stage1

在flash中执行的引导代码,也就是bootloader中的stage1,负责初始化硬件环境,把u-boot从flash加载到RAM中去,然后跳到lib_arm/board.c中的start_armboot中去执行。

u-boot的stage1代码通常放在文件中,它用汇编语言写成,其主要代码部分如下:

1)  定义入口由于一个可执行的Image必须有一个入口点,并且只能有一个全局入口,通常这个入口放在ROM(Flash)的0x0地址,因此,必须通知编译器以使其知道这个入口,该工作可通过修改连接器脚本来完成。

2)  设置异常向量(ExceptionVector)。

3)  设置CPU的速度、时钟频率及中断控制寄存器。

4)  初始化内存控制器

5)  将ROM中的程序复制到RAM中。

6)  初始化堆栈

7)  转到RAM中执行,该工作可使用指令ldrpc,_start_armboot来完成。

>Stage2

lib_arm/board.c中的start_armboot是C语言开始的函数,也是整个启动代码中C语言的主函数,同时还是整个u-boot(armboot)的主函数,该函数主要流程分析如下:

voidstart_armboot(void)

{

   init_fnc_t**init_fnc_ptr;

   char*s;

#if!

defined(CFG_NO_FLASH)||defined(CONFIG_VFD)||defined(CONFIG_LCD)

   ulongsize;

#endif

#ifdefined(CONFIG_VFD)||defined(CONFIG_LCD)

   unsignedlongaddr;

#endif

   /*Pointeriswritablesinceweallocatedaregisterforit*/

   /*给全局数据变量gd安排空间*/

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

   

   /*compileroptimizationbarrierneededforGCC>=3.4*/

   __asm____volatile__("":

:

:

"memory");

   /*给板子数据变量gd->bd安排空间*/

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

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

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

   monitor_flash_len=_bss_start-_armboot_start;

   

   /*顺序执行init_sequence数组中的初始化函数*/

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

       if((*init_fnc_ptr)()!

=0){

           hang();

       }

   }

   /*初始化函数列表:

   init_fnc_t*init_sequence[]={

   cpu_init,                /*basiccpudependentsetup*/

#ifdefined(CONFIG_SKIP_RELOCATE_UBOOT)

   reloc_init,           /*Settherelocationdoneflag,must

                          dothisAFTERcpu_init(),butassoon

                          aspossible*/

#endif

   board_init,           /*basicboarddependentsetup*/

   interrupt_init,       /*setupexceptions*/

   env_init,             /*initializeenvironment*/

   init_baudrate,        /*initialzebaudratesettings*/

   serial_init,          /*serialcommunicationssetup*/

   console_init_f,       /*stage1initofconsole*/

   display_banner,       /*saythatwearehere*/

#ifdefined(CONFIG_HW_WATCHDOG)

   hw_watchdog_init,     /*watchdogsetup*/

#endif

#ifdefined(CONFIG_DISPLAY_CPUINFO)

   print_cpuinfo,        /*displaycpuinfo(andspeed)*/

#endif

#ifdefined(CONFIG_DISPLAY_BOARDINFO)

   checkboard,           /*displayboardinfo*/

#endif

#ifdefined(CONFIG_HARD_I2C)||defined(CONFIG_SOFT_I2C)

   init_func_i2c,

#endif

   dram_init,               /*configureavailableRAMbanks*/

   display_dram_config,

   NULL,

};

   */

   /*armboot_startisdefinedintheboard-specificlinkerscript*/

   mem_malloc_init(_armboot_start-CFG_MALLOC_LEN);

#ifdefined(CONFIG_CMD_NAND)

   puts("NAND:

");

   /*NANDFLASH初始化*/

   nand_init();       /*goinittheNAND*/

#endif

   /*重新定位环境变量*/

   env_relocate();

#ifdefCONFIG_VFD

   /*mustdothisaftertheframebufferisallocated*/

   drv_vfd_init();

#endif/*CONFIG_VFD*/

#ifdefCONFIG_SERIAL_MULTI

   /*串口初始化*/

   serial_initialize();

#endif

   /*从环境变量中获取IP地址和MAC地址*/

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

   /*MACAddress*/

   {

       inti;

       ulongreg;

       char*s,*e;

       chartmp[64];

       i=getenv_r("ethaddr",tmp,sizeof(tmp));

       s=(i>0)?

tmp:

NULL;

       for(reg=0;reg<6;++reg){

           gd->bd->bi_enetaddr[reg]=s?

simple_strtoul(s,&e,16):

0;

           if(s)

               s=(*e)?

e+1:

e;

       }

#ifdefCONFIG_HAS_ETH1

       i=getenv_r("eth1addr",tmp,sizeof(tmp));

       s=(i>0)?

tmp:

NULL;

       for(reg=0;reg<6;++reg){

           gd->bd->bi_enet1addr[reg]=s?

simple_strtoul(s,&e,16):

0;

           if(s)

               s=(*e)?

e+1:

e;

       }

#endif

   }

   devices_init();   /*getthedeviceslistgoing.*/

#ifdefCONFIG_CMC_PU2

   load_sernum_ethaddr();

#endif/*CONFIG_CMC_PU2*/

   

   /*跳转表的初始化*/

   jumptable_init();

   /*控制台的初始化*/

   console_init_r();   /*fullyinitconsoleasadevice*/

   /*IRQ中断使能*/

   enable_interrupts();

   /*各种型号网络设备的初始化*/

#ifdefCONFIG_DRIVER_TI_EMAC

externvoiddm644x_eth_set_mac_addr(constu_int8_t*addr);

   if(getenv("ethaddr")){

       dm644x_eth_set_mac_addr(gd->bd->bi_enetaddr);

   }

#endif

#ifdefCONFIG_DRIVER_CS8900

   cs8900_get_enetaddr(gd->bd->bi_enetaddr);

#endif

   /*通过环境变量初始化load_addr

默认定义ulongload_addr=CFG_LOAD_ADDR;*/

   if((s=getenv("loadaddr"))!

=NULL){

       load_addr=simple_strtoul(s,NULL,16);

   }

   /**/

#ifdefined(CONFIG_CMD_NET)

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

=NULL){

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

   }

#endif

#ifdefBOARD_LATE_INIT

   board_late_init();

#endif

#ifdefined(CONFIG_CMD_NET)

#ifdefined(CONFIG_NET_MULTI)

   puts("Net:

  ");

#endif

   eth_initialize(gd->bd);

#ifdefined(CONFIG_RESET_PHY_R)

   debug("ResetEthernetPHY\n");

   reset_phy();

#endif

#endif

   /*循环不断地执行main_loop()函数

main_loop()主要处理用户命令*/

   for(;;){

       main_loop();

   }

}

整个u-boot的执行就进入等待用户输入命令,解析并执行命令的死循环中。

 

也许细心的你会问:

我在用UBoot的时候并没有直接进入用户命令界面呀,而是在倒计时结束后自动引导kernel。

这是怎么回事呢?

在main_loop()函数当中有如下一段代码:

#ifdefined(CONFIG_BOOTDELAY)&&(CONFIG_BOOTDELAY>=0)

     •

     •

     •

s=getenv("bootcmd");

       /*获取bootcmd的内容*/

       /*bootcmd=nandread0x220000000xB00000x200000;bootm*/

     •

     •

#ifndefCFG_HUSH_PARSER

       run_command(s,0);

       /*运行s包含的命令*/

       /*运行nandread0x220000000xB00000x200000表示将NANDFLASH

     0xB0000处数据读取放于0x22000000处,读取长度为0x200000

       */

       /*运行bootm命令,引导内核启动*/

#else

       parse_string_outer(s,FLAG_PARSE_SEMICOLON|

                   FLAG_EXIT_FROM_LOOP);

#endif

     •

     •

     •

#endif   /*CONFIG_BOOTDELAY*/

bootm命令是什么?

它是怎样引导内核的?

要知道想解决这个问题,就要分析中的函数do_bootm,因为引导kernel就是bootm这条命令的工作,do_bootm是命令bootm的执行函数。

现在我们来分析一下中的函数do_bootm,这是bootm命令的处理函数。

intdo_bootm(cmd_tbl_t*cmdtp,intflag,intargc,char*argv[])

{

   ulong       iflag;

   constchar   *type_name;

   uint       unc_len=CFG_BOOTM_LEN;

   uint8_t       comp,type,os;

   void       *os_hdr;

   ulong       os_data,os_len;

   ulong       image_start,image_end;

   ulong       load_start,load_end;

   ulong       mem_start;

   phys_size_t   mem_size;

   structlmblmb;

   memset((void*)&images,0,sizeof(images));

   =getenv_yesno("verify");

   =&lmb;

   lmb_init(&lmb);

   mem_start=getenv_bootm_low();

   mem_size=getenv_bootm_size();

   lmb_add(&lmb,(phys_addr_t)mem_start,mem_size);

   board_lmb_reserve(&lmb);

   /*getkernelimageheader,startaddressandlength*/

   /*获取内核镜像头信息*/

   /*打印“##BootingkernelfromLegacyImageat22000000...

          ImageName:

  Linux-

          ImageType:

  ARMLinuxKernelImage(uncompressed)

          DataSize:

   1507760Bytes=1.4MB

          LoadAddress:

20008000

          EntryPoint:

20008000

          VerifyingChecksum...OK”*/

   os_hdr=boot_get_kernel(cmdtp,flag,argc,argv,

           &images,&os_data,&os_len);

   if(os_len==0){

       puts("ERROR:

can'tgetkernelimage!

\n");

       return1;

   }

   /*getimageparameters*/

   /*获取内核镜像格式*/

   switch(genimg_get_format(os_hdr)){

   caseIMAGE_FORMAT_LEGACY:

       /*获取内核镜像参数*/

       type=image_get_type(os_hdr);

       comp=image_get_comp(os_hdr);

       os=image_get_os(os_hdr);

       image_end=image_get_image_end(os_hdr);

       load_start=image_get_load(os_hdr);

       break;

   }

   image_start=(ulong)os_hdr;

   load_end=0;

   type_name=genimg_get_type_name(type);

   /*禁止所有中断*/

   iflag=disable_interrupts();

#ifdefCONFIG_AMIGAONEG3SE

   /*

    *We'vepossibleleftthecachesenabledduring

    *biosemulation,soturnthemoffagain

    */

   icache_disable();

   invalidate_l1_instruction_cache();

   flush_data_cache();

   dcache_disable();

#endif

   switch(comp){

   caseIH_COMP_NONE:

       /*加载内核镜像*/

       /*打印“LoadingKernelImage...OK”*/

       if(load_start==(ulong)os_hdr){

           printf("  XIP%s...",type_name);

       }else{

           printf("  Loading%s...",type_name);

           memmove_wd((void*)load_start,

                  (void*)os_data,os_len,CHUNKSZ);

       }

       load_end=load_start+os_len;

       puts("OK\n");

       break;

   }

   puts("OK\n");

   debug("  kernelloadedat0x%08lx,end=0x%08lx\n",load_start,load_end);

   show_boot_progress(7);

   

   /*加载错误*/

   if((load_startimage_start)){

       debug("image_start=0x%lX,image_end=0x%lx\n",image_start,image_end);

       debug("load_start=0x%lx,load_end=0x%lx\n",load_start,load_end);

       if(){

           if(image_get_type()==IH_TYPE_MULTI)

               puts("WARNING:

legacyformatmulticomponent"

                   "imageoverwritten\n");

       }else{

           puts("ERROR:

newformatimageoverwritten-"

               "mustRESETtheboardtorecover\n");

           show_boot_progress(-113);

           do_reset(cmdtp,flag,argc,argv);

       }

   }

 

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > PPT模板 > 商务科技

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1