您好,欢迎访问三七文档
U-Boot启动过程(国嵌)开发板上电后,执行U-Boot的第一条指令,然后顺序执行U-Boot启动函数。看一下board/smdk2410/u-boot.lds这个链接脚本,可以知道目标程序的各部分链接顺序。第一个要链接的是cpu/arm920t/start.o,那么U-Boot的入口指令一定位于这个程序中。下面分两阶段介绍启动流程:第一阶段1.cpu/arm920t/start.S这个汇编程序是U-Boot的入口程序,开头就是复位向量的代码。_start:breset//复位向量ldrpc,_undefined_instructionldrpc,_software_interruptldrpc,_prefetch_abortldrpc,_data_abortldrpc,_not_usedldrpc,_irq//中断向量ldrpc,_fiq//中断向量…/*theactualresetcode*/reset://复位启动子程序/*设置CPU为SVC32模式*/mrsr0,cpsrbicr0,r0,#0x1forrr0,r0,#0xd3msrcpsr,r0/*关闭看门狗*/…………relocate:/*把U-Boot重新定位到RAM*/adrr0,_start/*r0是代码的当前位置*/ldrr1,_TEXT_BASE/*_TEXT_BASE是RAM中的地址*/cmpr0,r1/*比较r0和r1,判断当前是从Flash启动,还是RAM*/beqstack_setup/*如果r0等于r1,跳过重定位代码*//*准备重新定位代码*/ldrr2,_armboot_startldrr3,_bss_startsubr2,r3,r2/*r2得到armboot的大小*/addr2,r0,r2/*r2得到要复制代码的末尾地址*/copy_loop:/*重新定位代码*/ldmiar0!,{r3-r10}/*从源地址[r0]复制*/stmiar1!,{r3-r10}/*复制到目的地址[r1]*/cmpr0,r2/*复制数据块直到源数据末尾地址[r2]*/blecopy_loop/*初始化堆栈等*/stack_setup:ldrr0,_TEXT_BASE/*上面是128KiB重定位的u-boot*/subr0,r0,#CFG_MALLOC_LEN/*向下是内存分配空间*/subr0,r0,#CFG_GBL_DATA_SIZE/*然后是bdinfo结构体地址空间*/#ifdefCONFIG_USE_IRQsubr0,r0,#(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)#endifsubsp,r0,#12/*为abort-stack预留3个字*/clear_bss:ldrr0,_bss_start/*找到bss段起始地址*/ldrr1,_bss_end/*bss段末尾地址*/movr2,#0x00000000/*清零*/clbss_l:strr2,[r0]/*bss段地址空间清零循环...*/addr0,r0,#4cmpr0,r1bneclbss_l/*跳转到start_armboot函数入口,_start_armboot字保存函数入口指针*/ldrpc,_start_armboot_start_armboot:.wordstart_armboot//start_armboot函数在lib_arm/board.c中实现第二阶段2.lib_arm/board.cstart_armboot是U-Boot执行的第一个C语言函数,完成系统初始化工作,进入主循环,处理用户输入的命令。3.init_sequence[]init_sequence[]数组保存着基本的初始化函数指针。init_fnc_t*init_sequence[]={cpu_init,/*基本的处理器相关配置--cpu/arm920t/cpu.c*/board_init,/*基本的板级相关配置--board/smdk2410/smdk2410.c*/interrupt_init,/*初始化中断处理--cpu/arm920t/s3c24x0/interrupt.c*/env_init,/*初始化环境变量--common/cmd_flash.c*/init_baudrate,/*初始化波特率设置--lib_arm/board.c*/serial_init,/*串口通讯设置--cpu/arm920t/s3c24x0/serial.c*/console_init_f,/*控制台初始化阶段1--common/console.c*/display_banner,/*打印u-boot信息--lib_arm/board.c*/dram_init,/*配置可用的RAM--board/smdk2410/smdk2410.c*/display_dram_config,/*显示RAM的配置大小--lib_arm/board.c*/NULL,};voidstart_armboot(void){/*顺序执行init_sequence数组中的初始化函数*/for(init_fnc_ptr=init_sequence;*init_fnc_ptr;++init_fnc_ptr){if((*init_fnc_ptr)()!=0){hang();}}/*配置可用的Flash*/size=flash_init();display_flash_config(size);/*_armboot_start在u-boot.lds链接脚本中定义*/mem_malloc_init(_armboot_start-CFG_MALLOC_LEN);/*配置环境变量*/env_relocate();/*从环境变量中获取IP地址*/gd-bd-bi_ip_addr=getenv_IPaddr(ipaddr);/*以太网接口MAC地址*/……devices_init();/*获取列表中的设备*/jumptable_init();console_init_r();/*完整地初始化控制台设备*/enable_interrupts();/*使能中断处理*//*通过环境变量初始化*/if((s=getenv(loadaddr))!=NULL){load_addr=simple_strtoul(s,NULL,16);}/*main_loop()循环不断执行*/for(;;){main_loop();/*主循环函数处理执行用户命令--common/main.c*/}命令实现U-Boot作为Bootloader,具备多种引导内核启动的方式。常用的go和bootm命令可以直接引导内核映像启动。U-Boot与内核的关系主要是内核启动过程中参数的传递。1.go命令的实现/*common/cmd_boot.c*/intdo_go(cmd_tbl_t*cmdtp,intflag,intargc,char*argv[]){ulongaddr,rc;intrcode=0;if(argc2){printf(Usage:\n%s\n,cmdtp-usage);return1;}addr=simple_strtoul(argv[1],NULL,16);printf(##Startingapplicationat0x%08lX...\n,addr);rc=((ulong(*)(int,char[]))addr)(--argc,&argv[1]);/*运行程序*/if(rc!=0)rcode=1;printf(##Applicationterminated,rc=0x%lX\n,rc);/*如果是运行linux,这条指令是否能运行?*/returnrcode;}go命令调用do_go()函数,跳转到某个地址执行的。如果在这个地址准备好了自引导的内核映像,就可以启动了。尽管go命令可以带变参,实际使用时不用来传递参数。2.bootm命令的实现/*common/cmd_bootm.c*/intdo_bootm(cmd_tbl_t*cmdtp,intflag,intargc,char*argv[]){…………/*检查头部*/if(crc32(0,(uchar*)data,len)!=checksum){puts(BadHeaderChecksum\n);SHOW_BOOT_PROGRESS(-2);return1;}…………/*解压缩*/switch(hdr-ih_comp){caseIH_COMP_NONE:if(ntohl(hdr-ih_load)==addr){printf(XIP%s...,name);}else{#ifdefined(CONFIG_HW_WATCHDOG)||defined(CONFIG_WATCHDOG)size_tl=len;void*to=(void*)ntohl(hdr-ih_load);void*from=(void*)data;printf(Loading%s...,name);while(l0){size_ttail=(lCHUNKSZ)?CHUNKSZ:l;WATCHDOG_RESET();memmove(to,from,tail);to+=tail;from+=tail;l-=tail;}#else/*!(CONFIG_HW_WATCHDOG||CONFIG_WATCHDOG)*/memmove((void*)ntohl(hdr-ih_load),(uchar*)data,len);#endif/*CONFIG_HW_WATCHDOG||CONFIG_WATCHDOG*/}break;caseIH_COMP_GZIP:printf(Uncompressing%s...,name);if(gunzip((void*)ntohl(hdr-ih_load),unc_len,(uchar*)data,&len)!=0){puts(GUNZIPERROR-mustRESETboardtorecover\n);SHOW_BOOT_PROGRESS(-6);do_reset(cmdtp,flag,argc,argv);}break;#ifdefCONFIG_BZIP2caseIH_COMP_BZIP2:printf(Uncompressing%s...,name);/**Ifwe'vegotlessthan4MBofmalloc()space,*useslowerdecompressionalgorithmwhichrequires*atmost2300KBofmemory.*/i=BZ2_bzBuffToBuffDecompress((char*)ntohl(hdr-ih_load),&unc_len,(char*)data,len,CFG_MALLOC_LEN(4096*1024),0);if(i!=BZ_OK){printf(BUNZIP2ERROR%d-mustRESETboardtorecover\n,i);SHOW_BOOT_PROGRESS(-6);udelay(100000);do_reset(cmdtp,flag,argc,argv);}break;#endif/*CONFIG_BZIP2*/default:if(iflag)enable_interrupts();printf(Unimplementedcompressiontype%d\n,hdr-ih_comp);SHOW_BOOT_PROGRESS(-7);return1;}}………………switch(hdr-ih_os){default:/*handledby(original)Linuxcase*/caseIH_OS_LINUX:do_bootm_linux(cmdtp,flag,argc,argv,addr,len_ptr,verify);break;caseIH_OS_NETBSD:do_bootm_n
本文标题:Uboot启动流程
链接地址:https://www.777doc.com/doc-638743 .html