Uboot启动流程
IMX6uboot的启动流程

IMX6uboot的启动流程⽹上看了后,做了个记录,主要是⼀个流程,具体代码没有分析,有空再细看。
cpu在上电之后,它们会⼲些什么?答:检查电压⼤⼩,确定启动模式等。
简单的检查之后呢?答:⼀般从固化在cpu内部的rom⾥⾯执⾏⼀⼩段code。
这⼀⼩段code具体做了些什么呢?各个cpu⼚商会不同,具体我也不知道。
但是我们应该知道,这⼩段code必须完成确认启动模式,并初始化启动设备,搬移烧录在启动设备⾥⾯的代码到ddr⾥⾯。
ok,搬移了代码后,cpu如何识别代码?将doc,txt⽂件烧进去⾏么?答:当然不⾏,烧录的⽂件也是有格式要求的。
格式在哪⾥定呢?稍等,先要知道⽣成的uboot.bin⽂件需要有个指导⽂件,就是uboot.lds,它的作⽤是在编译过程中,决定各个可执⾏程序段的位置。
其代码如下:1 OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")2 OUTPUT_ARCH(arm)3 ENTRY(_start)4 SECTIONS5 {6 . = 0x00000000;78 . = ALIGN(4);9 .text :10 {11/* WARNING - the following is hand-optimized to fit within */12/* the sector layout of our flash chips! XXX FIXME XXX */13 board/freescale/mx6q_sabreauto/flash_header.o (.text.flasheader)14 cpu/arm_cortexa8/start.o15 board/freescale/mx6q_sabreauto/libmx6q_sabreauto.a (.text)16 lib_arm/libarm.a (.text)17 net/libnet.a (.text)18 drivers/mtd/libmtd.a (.text)19 drivers/mmc/libmmc.a (.text)2021 . = DEFINED(env_offset) ? env_offset : .;22 common/env_embedded.o(.text)2324 *(.text)25 }2627 . = ALIGN(4);28 .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }2930 . = ALIGN(4);31 .data : { *(.data) }3233 . = ALIGN(4);34 .got : { *(.got) }3536 . = .;37 __u_boot_cmd_start = .;38 .u_boot_cmd : { *(.u_boot_cmd) }39 __u_boot_cmd_end = .;4041 . = ALIGN(4);42 _end_of_copy = .; /* end_of ROM copy code here */43 __bss_start = .;44 .bss : { *(.bss) }45 _end = .;46 }View Code代码咱不分析,只看.text :{/* WARNING - the following is hand-optimized to fit within *//* the sector layout of our flash chips! XXX FIXME XXX */board/freescale/mx6q_sabreauto/flash_header.o (.text.flasheader)......}它的第⼀要存储的⽂件是flash_header的内容。
[精]UBOOT2017+FIT启动流程详尽分析
![[精]UBOOT2017+FIT启动流程详尽分析](https://img.taocdn.com/s3/m/7e15528ab8d528ea81c758f5f61fb7360b4c2b3c.png)
[精]UBOOT2017+FIT启动流程详尽分析开发环境:Nanopi-neo-plus2软件版本:uboot-2017软件版本:linux-4.14买这个板⼦有⼀段时间了,并没有全⾝⼼的投⼊在上⾯,有时间了的话就搞⼀搞,这篇随笔算是对这个版本的 uboot 启动流程做个⼤概的梳理和记录,体系结构相关的内容不作分析。
我这⾥会从 SPL(Secondary programloader) 阶段开始⼊⼿,按流程整理出 SPL 是怎样⼀步⼀步启动的 uboot,⽽ uboot ⼜是怎样加载并启动的 kernel。
废话不多说,以内容为重点来打通整体脉络。
⼀、从SPL⼊⼝点开始:阅读uboot源码时需注意:源码中存在众多 CONFIG_SPL_BUILD 宏的区分,使⽤了该宏的代码段,只有在 SPL 阶段时才会被编译进程序。
[ start.S armV8 ]_start:b resetreset: ... bl lowlevel_init ... bl _main[ lowlevel_init.S armV8 ]ENTRY(lowlevel_init) ldr w0, =CONFIG_SPL_STACK bic sp, x0, #0xf stp x29, x30, [sp, #-16]! bl s_initENDPROC(lowlevel_init)[ crt0_64.S arm/lib ]ENTRY(_main) ldr x0, =(CONFIG_SPL_STACK) bic sp, x0, #0xf ... mov x18, x0 bl board_init_f_init_reserve mov x0, #0 bl board_init_f ... mov x0, x18 /* gd_t */ ldr x1, [x18, #GD_RELOCADDR] /* dest_addr */ b board_init_r /* PC relative jump */ENDPROC(_main)[ Board.c mach-sunxi ]void board_init_f(ulong dummy){spl_init();preloader_console_init();#ifdef CONFIG_SPL_I2C_SUPPORT/* Needed early by sunxi_board_init if PMU is enabled */i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);#endifsunxi_board_init();#ifdef CONFIG_SPL_BUILDspl_mem_test();#endif}[ spl.c spl ]void board_init_r(gd_t *dummy1, ulong dummy2){...board_boot_order(spl_boot_list);if (boot_from_devices(&spl_image, spl_boot_list,ARRAY_SIZE(spl_boot_list))) {puts("SPL: failed to boot from all boot devices\n");hang();} switch (spl_image.os) { case IH_OS_U_BOOT: debug("Jumping to U-Boot\n"); break;#ifdef CONFIG_SPL_OS_BOOT case IH_OS_LINUX: debug("Jumping to Linux\n"); spl_fixup_fdt(); spl_board_prepare_for_linux(); jump_to_image_linux(&spl_image);#endif default: debug("Unsupported OS image.. Jumping nevertheless..\n"); } ... if (CONFIG_IS_ENABLED(ATF_SUPPORT)) { debug("loaded - jumping to U-Boot via ATF BL31.\n"); bl31_entry(); } debug("loaded - jumping to U-Boot...\n"); spl_board_prepare_for_boot(); jump_to_image_no_args(&spl_image);}[ spl.c spl ]board_boot_order(spl_boot_list);==>boot_source = readb(SPL_ADDR + 0x28);switch (boot_source) {case SUNXI_BOOTED_FROM_MMC0:return BOOT_DEVICE_MMC1;case SUNXI_BOOTED_FROM_NAND:return BOOT_DEVICE_NAND;case SUNXI_BOOTED_FROM_MMC2:return BOOT_DEVICE_MMC2;case SUNXI_BOOTED_FROM_SPI:return BOOT_DEVICE_SPI;};[ spl.c spl ]static int boot_from_devices(struct spl_image_info *spl_image,u32 spl_boot_list[], int count){loader = spl_ll_find_loader(spl_boot_list[i]);==> struct spl_image_loader *drv = ll_entry_start(struct spl_image_loader, spl_image_loader); const int n_ents = ll_entry_count(struct spl_image_loader, spl_image_loader); struct spl_image_loader *entry; for (entry = drv; entry != drv + n_ents; entry++) { if (boot_device == entry->boot_device) return entry; } ... if (loader && !spl_load_image(spl_image, loader)) return 0;}代码中使⽤了 ll_entry_start 宏,就可以联想到 ll_entry_declare 声明,随后通过搜索可找到#define SPL_LOAD_IMAGE(__name) \ll_entry_declare(struct spl_image_loader, __name, spl_image_loader)宏定义,进⼀步找到#define SPL_LOAD_IMAGE_METHOD(_name, _priority, _boot_device, _method) \SPL_LOAD_IMAGE(_method ## _priority ## _boot_device) = { \.name = _name, \.boot_device = _boot_device, \.load_image = _method, \}我们假设设备以SD卡的⽅式启动,SD对应着 BOOT_DEVICE_MMC1,那么通过搜索 SPL_LOAD_IMAGE_METHOD 筛选 BOOT_DEVICE_MMC1 就可以定位到驱动的本源,即[ spl_mmc.c spl ]SPL_LOAD_IMAGE_METHOD("MMC1", 0, BOOT_DEVICE_MMC1, spl_mmc_load_image);继续分析启动流程spl_load_image(spl_image, loader)==>int spl_mmc_load_image(struct spl_image_info *spl_image,struct spl_boot_device *bootdev){...spl_boot_mode(bootdev->boot_device);return MMCSD_MODE_RAW;.../* 通过宏 CONFIG_SPL_OS_BOOT 选择,spl直接启动OS还是启动uboot,这⾥返回1,启动uboot */spl_start_uboot()return1;...mmc_load_image_raw_sector(spl_image, mmc, CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR);...mmc_load_legacy(spl_image, mmc, sector, header);spl_parse_image_header(spl_image, header);spl_set_header_raw_uboot(spl_image); spl_image->size = CONFIG_SYS_MONITOR_LEN; spl_image->entry_point = CONFIG_SYS_UBOOT_START; spl_image->load_addr = CONFIG_SYS_TEXT_BASE; spl_image->os = IH_OS_U_BOOT; spl_image->name = "U-Boot"; ... }回到 board_init_r 继续分析,spl_image->os 赋值为 IH_OS_U_BOOT ,所以 break 直接跳出;接下来有执⾏ATF的bl31部分(这部分暂不做分析),最后执⾏ jump_to_image_no_args 跳转到 spl_image->entry_point ,也就是正式的uboot阶段。
u_boot初始化流程

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设备。
(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 long 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));/* 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-boot映像的大小其中_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。
uboot启动流程分析

uboot启动流程分析Uboot启动流程分析。
Uboot是一种常用的嵌入式系统启动加载程序,它的启动流程对于嵌入式系统的正常运行至关重要。
本文将对Uboot启动流程进行分析,以便更好地理解其工作原理。
首先,Uboot的启动流程可以分为以下几个步骤,Reset、初始化、设备初始化、加载内核。
接下来我们将逐一进行详细的分析。
Reset阶段是整个启动流程的起点,当系统上电或者复位时,CPU会跳转到Uboot的入口地址开始执行。
在这个阶段,Uboot会进行一些基本的硬件初始化工作,包括设置栈指针、初始化CPU寄存器等。
接着是初始化阶段,Uboot会进行一系列的初始化工作,包括初始化串口、初始化内存控制器、初始化时钟等。
这些初始化工作是为了确保系统能够正常地运行,并为后续的工作做好准备。
设备初始化阶段是Uboot启动流程中的一个重要环节,它包括对外设的初始化和检测。
在这个阶段,Uboot会初始化各种外设,如网卡、存储设备等,并对其进行检测,以确保它们能够正常工作。
最后一个阶段是加载内核,Uboot会从存储设备中加载操作系统的内核镜像到内存中,并跳转到内核的入口地址开始执行。
在这个过程中,Uboot会进行一些必要的设置,如传递启动参数给内核,并最终将控制权交给内核。
总的来说,Uboot的启动流程是一个非常重要的过程,它涉及到系统的硬件初始化、外设的初始化和内核的加载等工作。
只有当这些工作都顺利完成时,系统才能够正常地启动运行。
因此,对Uboot启动流程的深入理解对于嵌入式系统的开发和调试具有重要意义。
通过本文对Uboot启动流程的分析,相信读者对Uboot的工作原理有了更清晰的认识。
希望本文能够对大家有所帮助,谢谢阅读!。
uboot启动流程

U-Boot工作过程U-Boot启动内核的过程可以分为两个阶段,两个阶段的功能如下:(1)第一阶段的功能硬件设备初始化加载U-Boot第二阶段代码到RAM空间设置好栈跳转到第二阶段代码入口(2)第二阶段的功能初始化本阶段使用的硬件设备检测系统内存映射将内核从Flash读取到RAM中为内核设置启动参数调用内核1.1.1 U-Boot启动第一阶段代码分析第一阶段对应的文件是cpu/arm920t/和board/samsung/mini2440/。
U-Boot启动第一阶段流程如下:图 U-Boot启动第一阶段流程根据cpu/arm920t/中指定的连接方式:ENTRY(_start)SECTIONS{. = 0x00000000;. = ALIGN(4);.text :{cpu/arm920t/ (.text)board/samsung/mini2440/ (.text)board/samsung/mini2440/ (.text)*(.text)}… …}第一个链接的是cpu/arm920t/,因此的入口代码在cpu/arm920t/中,其源代码在cpu/arm920t/中。
下面我们来分析cpu/arm920t/的执行。
1. 硬件设备初始化(1)设置异常向量cpu/arm920t/开头有如下的代码:.globl _start_start: b start_code /* 复位*/ldr pc, _undefined_instruction /*未定义指令向量 */ldr pc, _software_interrupt /* 软件中断向量 */ldr pc, _prefetch_abort /* 预取指令异常向量 */ldr pc, _data_abort /* 数据操作异常向量 */ldr pc, _not_used /* 未使用 */ldr pc, _irq /* irq中断向量 */ldr pc, _fiq /* fiq中断向量 */ /* 中断向量表入口地址 */_undefined_instruction: .word undefined_instruction_software_interrupt: .word software_interrupt_prefetch_abort: .word prefetch_abort_data_abort: .word data_abort_not_used: .word not_used_irq: .word irq_fiq: .word fiq.balignl 16,0xdeadbeef以上代码设置了ARM异常向量表,各个异常向量介绍如下:表 ARM异常向量表在cpu/arm920t/中还有这些异常对应的异常处理程序。
am335xu-boot启动过程分析

am335xu-boot启动过程分析 u-boot属于两阶段的bootloader,第⼀阶段的⽂件为 arch/arm/cpu/armv7/start.S 和 arch/arm/cpu/armv7/lowlevel_init.S,前者是平台相关的,后者是开发板相关的。
1. u-boot第⼀阶段代码分析 (1)硬件设备初始化 将CPU的⼯作模式设为管理模式(SVC); 关闭中断; 禁⽤MMU,TLB ; 板级初始化; (2)为加载Bootloader的第⼆阶段代码准备RAM空间 加载u-boot.img,跳转到u-boot.img; 上述⼯作,也就是uboot-spl代码流程的核⼼。
代码如下:arch/arm/cpu/armv7/start.S1/*2 * the actual reset code3*/4reset:5 bl save_boot_params6/*7 * disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,8 * except if in HYP mode already9*/10 mrs r0, cpsr11 and r1, r0, #0x1f @ mask mode bits12 teq r1, #0x1a @ test for HYP mode13 bicne r0, r0, #0x1f @ clear all mode bits14 orrne r0, r0, #0x13 @ set SVC mode15 orr r0, r0, #0xc0 @ disable FIQ and IRQ16 msr cpsr,r017@@ 以上通过设置CPSR寄存器⾥设置CPU为SVC模式,禁⽌中断18@@ 具体操作可以参考《[kernel 启动流程] (第⼆章)第⼀阶段之——设置SVC、关闭中断》的分析1920/* the mask ROM code should have PLL and others stable */21#ifndef CONFIG_SKIP_LOWLEVEL_INIT22 bl cpu_init_cp1523@@ 调⽤cpu_init_cp15,初始化协处理器CP15,从⽽禁⽤MMU和TLB。
Uboot启动流程分析和移植介绍

基于MPC83xx 的U-boot 启动流程分析和移植董 闯北京邮电大学信息与通信工程学院,北京(100876)E-mail :donix.dong@摘 要:本文首先引入Bootloader 的概念,接着介绍U-boot 这种引导程序,并以Freescale 32位微处理器MPC83xx 为例,结合代码详细分析了U-boot 的启动的各个阶段及最终引导Linux 内核的过程,最后,建立交叉编译环境,针对TC8313E 目标板,给出U-boot 移植与编译的基本步骤。
关键词:U-boot;MPC83xx;交叉编译;移植;嵌入式系统中图分类号:TP393.051.引言引导程序(Bootloader)是系统加电后运行的第一段软件代码,类似于PC 机中的引导加载程序BIOS 。
虽然引导程序仅在系统启动时运行非常短的时间,但对于嵌入式系统来说,这是一个非常重要的组成部分。
通过这段小程序,初始化必要的硬件设备,创建内核需要的一些信息并将这些信息传递给内核,从而将系统的软、硬件环境配置到一个合适的状态,最终调用操作系统内核,真正起到引导和加载内核的作用。
2. U-boot 介绍目前,嵌入式领域里出现了很多种类的Bootloader ,如Armboot 、Blob 、Redboot 、vivi 和U-boot 等,其中U-boot 是使用最广泛,功能最完善的。
U-boot (Universal Boot Loader)是从PPCBOOT 发展演化而来[1],其源码目录、编译形式与Linux 内核很相似,事实上,不少U-boot 源码就是相应的Linux 内核源程序的简化,尤其是一些设备的驱动程序,这从U-boot 源码的注释中就能体现。
U-boot 中Universal 有两层含义,一是U-boot 除了支持PowerPC 系列的处理器外,还能支持MIPS 、x86、ARM 、NIOS 、XScale 等诸多常用系列的处理器;另外一层含义则是U-boot 不仅仅支持嵌入式Linux 操作系统的引导,还支持OpenBSD, NetBSD, FreeBSD, SVR4, Solaris, VxWorks, LynxOS, pSOS, lrix, RTEMS, QNX, ARTOS 等操作系统的引导。
海思uboot启动流程详细分析(一)

海思uboot启动流程详细分析(⼀)第⼀阶段 start.S⾸先我们可以在u-boot.lds中看到ENTRY(_start),即指定了⼊⼝_start,_start也就是整个start.S的最开始;1. reset在arch\arm\cpu\armv8\hi3559av100中的start.S注意x30在ARMV8中代表lr寄存器reset:/** Could be EL3/EL2/EL1, Initial State:* Little Endian, MMU Disabled, i/dCache Disabled*/adr x0, vectorsswitch_el x1, 3f, 2f, 1f3: msr vbar_el3, x0mrs x0, scr_el3orr x0, x0, #0xf /* SCR_EL3.NS|IRQ|FIQ|EA */msr scr_el3, x0msr cptr_el3, xzr /* Enable FP/SIMD */#ifdef COUNTER_FREQUENCYldr x0, =COUNTER_FREQUENCYmsr cntfrq_el0, x0 /* Initialize CNTFRQ */#endifb 0f2: msr vbar_el2, x0mov x0, #0x33ffmsr cptr_el2, x0 /* Enable FP/SIMD */b 0f1: msr vbar_el1, x0mov x0, #3 << 20msr cpacr_el1, x0 /* Enable FP/SIMD */0:/** Cache/BPB/TLB Invalidate* i-cache is invalidated before enabled in icache_enable()* tlb is invalidated before mmu is enabled in dcache_enable()* d-cache is invalidated before enabled in dcache_enable()*//** read system register REG_SC_GEN2* check if ziju flag*/ldr x0, =SYS_CTRL_REG_BASEldr w1, [x0, #REG_SC_GEN2]ldr w2, =0x7a696a75 /* magic for "ziju" */cmp w1, w2bne normal_start_flowmov x1, sp /* save sp */str w1, [x0, #REG_SC_GEN2] /* clear ziju flag */adr x0, vectors,其中的vectors代表了异常向量表主要做了如下事情:1)reset SCTRL寄存器具体可参考reset_sctrl函数,由CONFIG_SYS_RESET_SCTRL控制,⼀般不需要打开。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
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: b reset //复位向量ldr pc, _undefined_instructionldr pc, _software_interruptldr pc, _prefetch_abortldr pc, _data_abortldr pc, _not_usedldr pc, _irq //中断向量ldr pc, _fiq //中断向量…/* the actual reset code */reset: //复位启动子程序/* 设置CPU为SVC32模式 */mrs r0,cpsrbic r0,r0,#0x1forr r0,r0,#0xd3msr cpsr,r0/* 关闭看门狗 */…… ……relocate: /* 把U-Boot重新定位到RAM */adr r0, _start /* r0是代码的当前位置 */ldr r1, _TEXT_BASE /*_TEXT_BASE是RAM中的地址 */cmp r0, r1 /* 比较r0和r1,判断当前是从Flash启动,还是RAM */beq stack_setup /* 如果r0等于r1,跳过重定位代码 *//* 准备重新定位代码 */ldr r2, _armboot_startldr r3, _bss_startsub r2, r3, r2 /* r2 得到armboot的大小 */add r2, r0, r2 /* r2 得到要复制代码的末尾地址 */copy_loop: /* 重新定位代码 */ldmia r0!, {r3-r10} /*从源地址[r0]复制 */stmia r1!, {r3-r10} /* 复制到目的地址[r1] */cmp r0, r2 /* 复制数据块直到源数据末尾地址[r2] */ble copy_loop/* 初始化堆栈等 */stack_setup:ldr r0, _TEXT_BASE /* 上面是128 KiB重定位的u-boot */sub r0, r0, #CFG_MALLOC_LEN /* 向下是内存分配空间 */sub r0, r0, #CFG_GBL_DATA_SIZE /* 然后是bdinfo结构体地址空间 */#ifdef CONFIG_USE_IRQsub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)#endifsub sp, r0, #12 /* 为abort-stack预留3个字 */clear_bss:ldr r0, _bss_start /* 找到bss段起始地址 */ldr r1, _bss_end /* bss段末尾地址 */mov r2, #0x00000000 /* 清零 */clbss_l:str r2, [r0]/* bss段地址空间清零循环... */add r0, r0, #4cmp r0, r1bne clbss_l/* 跳转到start_armboot函数入口,_start_armboot字保存函数入口指针 */ldr pc, _start_armboot_start_armboot: .word start_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,};void start_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 */int do_go (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){ulong addr, rc;int rcode = 0;if (argc < 2) {printf ("Usage:\n%s\n", cmdtp->usage);return 1;}addr = simple_strtoul(argv[1], NULL, 16);printf ("## Starting application at 0x%08lX ...\n", addr);rc = ((ulong (*)(int, char []))addr) (--argc, &argv[1]); /* 运行程序 */if (rc != 0) rcode = 1;printf ("## Application terminated, rc = 0x%lX\n", rc); /*如果是运行linux,这条指令是否能运行?*/return rcode;}go命令调用do_go()函数,跳转到某个地址执行的。
如果在这个地址准备好了自引导的内核映像,就可以启动了。
尽管go命令可以带变参,实际使用时不用来传递参数。
2.bootm命令的实现/* common/cmd_bootm.c */int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){…… ……/* 检查头部 */if (crc32 (0, (uchar *)data, len) != checksum) {puts ("Bad Header Checksum\n");SHOW_BOOT_PROGRESS (-2);return 1;}…… ……/*解压缩*/switch (hdr->ih_comp) {case IH_COMP_NONE:if(ntohl(hdr->ih_load) == addr) {printf (" XIP %s ... ", name);} else {#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)size_t l = len;void *to = (void *)ntohl(hdr->ih_load);void *from = (void *)data;printf (" Loading %s ... ", name);while (l > 0) {size_t tail = (l > CHUNKSZ) ? 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;case IH_COMP_GZIP:printf (" Uncompressing %s ... ", name);if (gunzip ((void *)ntohl(hdr->ih_load), unc_len,(uchar *)data, &len) != 0) {puts ("GUNZIP ERROR - must RESET board to recover\n");SHOW_BOOT_PROGRESS (-6);do_reset (cmdtp, flag, argc, argv);}break;#ifdef CONFIG_BZIP2case IH_COMP_BZIP2:printf (" Uncompressing %s ... ", name);/** If we've got less than 4 MB of malloc() space,* use slower decompression algorithm which requires* at most 2300 KB of memory.*/i = BZ2_bzBuffToBuffDecompress ((char*)ntohl(hdr->ih_load),&unc_len, (char *)data, len,CFG_MALLOC_LEN < (4096 * 1024), 0);if (i != BZ_OK) {printf ("BUNZIP2 ERROR %d - must RESET board to recover\n", i);SHOW_BOOT_PROGRESS (-6);udelay(100000);do_reset (cmdtp, flag, argc, argv);}break;#endif /* CONFIG_BZIP2 */default:if (iflag)enable_interrupts();printf ("Unimplemented compression type %d\n", hdr->ih_comp);SHOW_BOOT_PROGRESS (-7);return 1;}}…… …… ……switch (hdr->ih_os) {default: /* handled by (original) Linux case */case IH_OS_LINUX:do_bootm_linux (cmdtp, flag, argc, argv,addr, len_ptr, verify);break;case IH_OS_NETBSD:do_bootm_netbsd (cmdtp, flag, argc, argv,addr, len_ptr, verify);break;case IH_OS_RTEMS:do_bootm_rtems (cmdtp, flag, argc, argv,addr, len_ptr, verify);break;case IH_OS_VXWORKS:do_bootm_vxworks (cmdtp, flag, argc, argv,addr, len_ptr, verify);break;case IH_OS_QNX:do_bootm_qnxelf (cmdtp, flag, argc, argv,addr, len_ptr, verify);break;}bootm命令调用do_bootm函数。