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的内容。
uboot启动常见的错误汇总
【uboot启动常见的错误汇总】1. operating at 100M full duplex mode*** ERROR: `ethaddr' not setdm9000 i/o: 0x5000000, id: 0x90000a46DM9000: running in 16 bit modeMAC: 00:00:00:00:00:00operating at 100M full duplex modeWrong Image Format for bootm commandERROR: can't get kernel image!原因是:没有设置mac地址,需要重新设置setenv ethaddr 01:02:03:04:05:06saveenv/save2.在开发板上ping ubuntu的ip地址ping不通1.网线没插2.ubuntu没有打开3.ping 的过程中,ubuntu会扫描ip地址,会一直去获取ip地址,但是开发板没有分配ip地址的权利,也就是ubuntu获取不了ip地址,同时查看ubuntu 的ip地址是没有的。
1.设置临时的ip地址sudo ifconfig eth0 192.168.1.*2.永久生效在ubuntu的右上角添加静态ip地址。
3.发现ubuntu的右上角网络图标类似于wifi的图标,如何将这个图标改成网络的图标sudo /etc//init.d/network-manager restart如何执行之后,还是wifi图标sudo vi /etc/NetworkManager/NetworkManager.confmanaged=false false --->truesudo /etc//init.d/network-manager restart如果执行之后,还是wifi图标重启系统4.你的pc电脑已经打开wifi网,需要将无线网关闭5.虚拟机网卡设置出错,需要将nat设置为桥接6.换开发板4.ping ubuntu是可以ping通,但是当启动内核的时候出现T TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTubuntu的tftp服务没有开启,重启tftp服务sudo /etc/init.d/tftpd-hpa restartTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTubuntu的ip没了,需要再次设置ip地址sudo ifconfig eth0 192.168.1.*5.uboot启动内核是提示文件没找到,需要将内核和设备树拷贝到tftp服务器的目录6.nfs在启动nfs服务器时,exportfs: /etc/exports [2]: Neither 'subtree_check' or 'no_subtree_check' specified for export "*:/rootfs".Assuming default behaviour ('no_subtree_check').NOTE: this default has changed since nfs-utils version 1.0.x解决方法:/rootfs *(rw,sync,no_root_squash,no_subtree_check)7.vfs:为应用程序提供统一的接口程序--》fopen ---->open---->vfs---->内核函数---》硬件7.] VFS: Mounted root (nfs filesystem) on device 0:10.[ 2.130000] devtmpfs: error mounting -2[ 2.135000] Freeing unused kernel memory: 232K (c0655000 - c068f000)[ 2.140000] hub 1-3:1.0: USB hub found[ 2.145000] hub 1-3:1.0: 3 ports detected[ 2.150000] Failed to execute /linuxrc (error -2). Attempting defaults...[ 2.160000] Kernel panic - not syncing: No working init found. Try passing init= option to kernel. See Linux Documentation/init.txt for guidance.解决方法:需要将文件系统拷贝到这个目录。
uboot启动参数设置
nand erase 40000 1c0000 nand erase offset size
nand write 30800000 40000 1c0000 存放内存30800000位置上的uImge,烧写到nandflash的40000位置上
=========================================================================================
例如如下:
FS2410# setenv serverip 192.168.7.x (其中X是虚拟机中IP的最后的数字[用ifconfig可以获取])
farsight_N中的N用座位号来表示,比如座位4即为farsight_4 //设置uboot传给内核的参数
saveenv
自定义参数版本:
4.设置UBOOT参数
确保一下FS2410的核心班上的JP1跳线帽短接了,给板子上电,
查看板子启动信息,如果板子启动信息中,有U-Boot 1.3.1(Oct 25 2008 - 15:45:21)或者更新的版本,则直接设置下面的参数,否则根据文档烧录 u-boot131-for-farsight-shenzhen-advanced-drivers.bin(请参考文档"farsight-实验前的准备步骤-v2.3.doc")
setenv bootargs console=ttySAC0,115200 init=/linuxrc root=/dev/nfs nfsroot=192.168.7.113:/opt/filesystem ip=192.168.7.173:192.168.7.113:192.168.7.1:255.255.255.0:farsight_13:eth0:off //或者console=ttySAC0,115200 root=1f02 rootfstype=jffs2 rw init=/linuxrc mem=64M
Uboot启动流程
U-Boot启动过程问题:u-boot入口点?C语言是main. U-boot是lds链接器脚本开发板上电后,执行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 //中断向量,在程序执行中发生中断了,CPU会跳转到这里来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语言函数,完成系统初始化工作,进入主循环,处理用户输入的命令。
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/中还有这些异常对应的异常处理程序。
全志T3启动-uBoot+SylixOS
T3-Uboot开发笔记及SylixOS启动1.全志T3Uboot概述1.1.Brom阶段:全志SoC有一个非常具体的启动过程。
首先,它执行一个微小的片上Boot ROM(BROM),然后检查按钮的FEL模式,然后开始检查各种存储选项的有效的引导签名在正确的位置。
上电后,SoC开始从BROM所在的地址0xffff0000获取指令。
BROM分为两部分:第一部分(0xffff0000)是FEL模式,第二部分是eGON.BRM(位于0xffff4000)。
FEL:FEL是包含在Allwinner设备上的BootROM中的低级子例程。
它用于使用USB 的设备的初始编程和恢复。
一般来说,BROM首先检查SD卡(SD/MMC)启动可用性,其次再检查Nand Flash 是否可以启动,然后再检查SPI Nor Flash的启动可用性,如果都无法启动则进入FEL模式。
当程序初始化启动介质成功后,就从固定位置读入bootloader的Boot0到SRAM,然后跳到SRAM执行。
1.2.Bootloader阶段Bootloader是全志平台上从小系统一直沿用下来的内核加载器,在这里的主要职责是加载U-Boot到DRAM。
Bootloader分为两个部分,分别是Boot0和Boot1。
Boot0:初始化DRAM,加载Boot1到DRAM;Boot1:调频,加载U-Boot 到DRAM;为什么Bootloader要划分成Boot0和Boot1两个部分?因为在Bootloader阶段,使用的SRAM大小是32KB,除去C运行环境需要的栈空间,可用的空间在24KB左右,这点不足以载入整个Bootloader。
因此,需要将Bootloader划分成两个部分,尽可能将繁重的任务放在Boot1执行,这个情况类似于Linux系统中断执行环境的上半部和下半部。
1.boot0执行过程2.boot1的执行过程Boot1会进行一次系统调频,将CPU的频率调到用户在sys_config1.fex target段配置的boot_clock。
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启动流程详细分析(一)
海思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控制,⼀般不需要打开。
U-boot启动流程
1.1U-Boot工作过程U-Boot启动内核的过程可以分为两个阶段,两个阶段的功能如下:(1)第一阶段的功能硬件设备初始化加载U-Boot第二阶段代码到RAM空间设置好栈跳转到第二阶段代码入口(2)第二阶段的功能初始化本阶段使用的硬件设备检测系统内存映射将内核从Flash读取到RAM中为内核设置启动参数调用内核1.1.1U-Boot启动第一阶段代码分析第一阶段对应的文件是cpu/arm920t/start.S和board/samsung/mini2440/lowlevel_init.S。
U-Boot启动第一阶段流程如下:图 2.1 U-Boot启动第一阶段流程根据cpu/arm920t/u-boot.lds中指定的连接方式:ENTRY(_start)SECTIONS{. = 0x00000000;. = ALIGN(4);.text :{cpu/arm920t/start.o (.text)board/samsung/mini2440/lowlevel_init.o (.text)board/samsung/mini2440/nand_read.o (.text)*(.text)}… …}第一个链接的是cpu/arm920t/start.o,因此u-boot.bin的入口代码在cpu/arm920t/start.o中,其源代码在cpu/arm920t/start.S中。
下面我们来分析cpu/arm920t/start.S的执行。
1.硬件设备初始化(1)设置异常向量cpu/arm920t/start.S开头有如下的代码:.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异常向量表,各个异常向量介绍如下:表 2.1 ARM异常向量表在cpu/arm920t/start.S中还有这些异常对应的异常处理程序。
uboot 代码运行流程
uboot 代码运行流程U-Boot代码运行流程U-Boot(Universal Bootloader)是一个开源的引导加载程序,广泛应用于嵌入式系统中。
它负责在系统上电后初始化硬件并加载操作系统内核,是系统启动的重要一环。
下面将从U-Boot代码的运行流程方面进行介绍。
1. 启动阶段当系统上电后,处理器会从预定义的存储器地址开始运行代码。
U-Boot的启动代码通常存放在ROM中,处理器会从ROM的起始地址开始执行。
启动代码负责初始化处理器和一些外设,然后跳转到U-Boot的入口点。
2. 入口点U-Boot的入口点是指U-Boot的main()函数。
在启动代码的最后,会调用main()函数,从而进入U-Boot的主循环。
U-Boot的主循环负责处理用户输入的命令,并根据命令执行相应的操作。
3. 硬件初始化在main()函数中,首先会进行硬件的初始化工作。
这包括初始化串口、初始化存储器控制器、初始化网络接口等。
硬件初始化的目的是为了确保系统能够正常运行,并为后续的操作做好准备。
4. 系统启动硬件初始化完成后,U-Boot会尝试从存储设备(如闪存、SD卡)中加载操作系统内核镜像。
U-Boot会根据预定义的启动命令(例如bootcmd)来确定从哪个设备加载内核镜像,并执行相应的加载操作。
加载完成后,U-Boot会将控制权交给操作系统内核,进入操作系统的启动阶段。
5. 用户交互一般情况下,U-Boot会在系统启动后进入命令行界面,等待用户输入命令。
用户可以通过串口、网络等方式与U-Boot进行交互,执行各种操作,例如烧写固件、修改配置等。
U-Boot提供了丰富的命令集,可以满足不同的需求。
6. 系统重启当用户输入重启命令或系统发生异常时,U-Boot会执行系统重启操作。
重启操作包括重新初始化硬件、重新加载内核镜像等步骤,以重新启动系统。
U-Boot会将控制权交给重新加载的内核,然后进入内核的启动流程。
总结:U-Boot代码的运行流程包括启动阶段、入口点、硬件初始化、系统启动、用户交互和系统重启等几个关键步骤。
U-Boot启动过程--详细版的完全分析
(一)U-Boot启动过程--详细版的完全分析我们知道,bootloader是系统上电后最初加载运行的代码。
它提供了处理器上电复位后最开始需要执行的初始化代码。
在PC机上引导程序一般由BIOS开始执行,然后读取硬盘中位于MBR(Main Boot Record,主引导记录)中的Bootloader(例如LILO或GRUB),并进一步引导操作系统的启动。
然而在嵌入式系统中通常没有像BIOS那样的固件程序,因此整个系统的加载启动就完全由bootloader来完成。
它主要的功能是加载与引导内核映像一个嵌入式的存储设备通过通常包括四个分区:第一分区:存放的当然是u-boot第二个分区:存放着u-boot要传给系统内核的参数第三个分区:是系统内核(kernel)第四个分区:则是根文件系统如下图所示:u-boot是一种普遍用于嵌入式系统中的Bootloader。
Bootloader介绍Bootloader是进行嵌入式开发必然会接触的一个概念,它是嵌入式学院<嵌入式工程师职业培训班>二期课程中嵌入式linux系统开发方面的重要内容。
本篇文章主要讲解Bootloader 的基本概念以及内部原理,这部分内容的掌握将对嵌入式linux系统开发的学习非常有帮助!Bootloader的定义:Bootloader是在操作系统运行之前执行的一小段程序,通过这一小段程序,我们可以初始化硬件设备、建立内存空间的映射表,从而建立适当的系统软硬件环境,为最终调用操作系统内核做好准备。
意思就是说如果我们要想让一个操作系统在我们的板子上运转起来,我们就必须首先对我们的板子进行一些基本配置和初始化,然后才可以将操作系统引导进来运行。
具体在Bootloader中完成了哪些操作我们会在后面分析到,这里我们先来回忆一下PC的体系结构:PC机中的引导加载程序是由BIOS和位于硬盘MBR中的OS Boot Loader(比如LILO和GRUB等)一起组成的,BIOS在完成硬件检测和资源分配后,将硬盘MBR中的Boot Loader读到系统的RAM中,然后将控制权交给OS Boot Loader。
UBOOT从NAND FLASH启动分析
UBOOT从NAND FLASH启动分析UBOOT从NAND FLASH启动分析在分析启动代码之前先看一下S3C2440的NAND启动:在配置NAND启动模式之后,S3C2440上电会先将NAND中的0x0 - 0x1000共4096字节的数据拷贝到位于Bank0中的Boot Internal SRAM上Bank0如下图:可以看出Boot Internal SRAM为4KB大小,也正是因为Boot Internal SRAM只有4KB 大小,所以只能从NAND中拷贝4K的内容= 3= 这个Boot Internal SRAM是配置为NAND FLASH启动模式才有的这4K内容是什么呢?~ 这就要看Uboot的镜像文件中是如何进行连接的了~连接脚本在board/smdk2440/u-boot.lds中,如下SECTIONS{. = 0x00000000;. = ALIGN(4);.text :{cpu/arm920t/start.o (.text)cpu/arm920t/s3c24x0/nand_read.o (.text)*(.text)}. = ALIGN(4);.rodata : { *(.rodata) }. = ALIGN(4);.data : { *(.data) }. = ALIGN(4);.got : { *(.got) }. = .;__u_boot_cmd_start = .;.u_boot_cmd : { *(.u_boot_cmd) }__u_boot_cmd_end = .;. = ALIGN(4);__bss_start = .;.bss : { *(.bss) }_end = .;}.text为代码段,可以看出cpu/arm920t/start.o在代码段的最前面,所以会先执行start.o 中的代码连接完成后的镜像文件的前4K如下cpu/arm920t/start.o(.text).text 0x33f80000 0x4e0 cpu/arm920t/start.o0x33f80050 IRQ_STACK_START0x33f80048 _bss_start0x33f8004c _bss_end0x33f80044 _armboot_start0x33f80000 _start0x33f80054 FIQ_STACK_STARTcpu/arm920t/s3c24x0/nand_read.o(.text).text 0x33f804e0 0x1b8 cpu/arm920t/s3c24x0/nand_read.o0x33f804e0 nand_read_ll*(.text).text 0x33f80698 0x64 board/smdk2440/libsmdk2440.a(lowlevel_init.o)0x33f8069c lowlevel_init.text 0x33f806fc 0x280 cpu/arm920t/libarm920t.a(interrupts.o)0x33f80934 do_fiq0x33f80880 do_undefined_instruction0x33f80744 show_regs0x33f80958 do_irq0x33f80728 bad_mode0x33f808c8 do_prefetch_abort0x33f8070c disable_interrupts0x33f80910 do_not_used0x33f808ec do_data_abort0x33f808a4 do_software_interrupt0x33f806fc enable_interrupts.text 0x33f8097c 0x250 cpu/arm920t/s3c24x0/libs3c24x0.a(interrupts.o)0x33f80aa4 set_timer0x33f80a20 reset_timer0x33f8097c interrupt_init0x33f80ba0 get_tbclk0x33f80a90 get_timer0x33f809f0 reset_timer_masked0x33f80a24 get_timer_masked0x33f80ab4 udelay0x33f80b10 udelay_masked0x33f80bac reset_cpu0x33f80b8c get_ticks.text 0x33f80bcc 0x150 cpu/arm920t/s3c24x0/libs3c24x0.a(speed.o)0x33f80c4c get_HCLK0x33f80cec get_PCLK0x33f80c44 get_FCLK0x33f80d14 get_UCLK.text 0x33f80d1c 0x1e8 cpu/arm920t/s3c24x0/libs3c24x0.a(cmd_s3c24xx.o) 0x33f80d8c do_s3c24xx.text 0x33f80f04 0xdc cpu/arm920t/s3c24x0/libs3c24x0.a(serial.o)0x33f80f04 serial_setbrg0x33f80fa8 serial_tstc0x33f80f80 serial_putc0x33f80f58 serial_init0x33f80fb8 serial_puts0x33f80f68 serial_getc.text 0x33f80fe0 0x140 lib_arm/libarm.a(_divsi3.o)0x33f80fe0 __divsi3如何设置从0x33f80000开始呢?~这是链接的时候指定的在根目录下面的config.mk中有下面一句LDFLAGS += -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE) $(PLATFORM_LDFLAGS)关键就是其中的-Ttext $(TEXT_BASE),这句指明了代码段的起始地址而TEXT_BASE在board/smdk2440/config.mk中定义TEXT_BASE = 0x33F8 0000 为什么是0x33F8 0000呢?~这是将NAND中Uboot拷贝到RAM中的起始地址,所以在代码拷贝到RAM之前不能使用绝对地址来寻址数据,只能用相对地址在以下将用虚拟地址来指Uboot在RAM中的地址,也就是0x33F8 0000现在来看代码cpu/arm920t/start.S_start: ;异常处理向量表b start_codeldr pc, _undefined_instruction ;未定义指令异常:0x00000004ldr pc, _software_interrupt ;软中断异常:0x00000008ldr pc, _prefetch_abort ;预取异常:0x0000000Cldr pc, _data_abort ;数据异常:0x00000010ldr pc, _not_used ;未使用:0x00000014ldr pc, _irq ;外部中断请求IRQ:0x00000018ldr pc, _fiq ;快束中断请求FIQ:0x0000001Cb start_code在虚拟地址0x33F8 0000处, 拷贝到Boot Internal SRAM后则位于0x0处,所以b start_code是第一条执行的指令,start_code在cpu/arm920t/start.S中代码如下://读取CPSR寄存器的内容到R0mrs r0,cpsr//清除R0中的0 - 4 这5个位后保存到R0中//也就是清除用户模式位bic r0,r0,#0x1f//置R0的0 1 4 6 7 位为真//也就是选择SVC模式,同时IRQ和FIQ被禁止,处理器处于ARM状态//关闭中断和快速中断orr r0,r0,#0xd3//将R0中的值保存到CPSR上msr cpsr,r0# define pWTCON 0x53000000 ;看门狗控制寄存器WTCON# define INTMSK 0x4A000008 ;中断屏蔽寄存器INTMSK# define INTSUBMSK 0x4A00001C ;辅助中断屏蔽寄存器,由于外设中断源太多,要用此寄存器屏蔽剩余的中断源# define LOCKTIME 0x4c000000 ;PLL锁定时间计数寄存器# define MPLLCON 0x4c000004 ;主时钟锁相环控制寄存器# define UPLLCON 0x4c000008# define CLKDIVN 0x4C000014 ;时钟分频寄存器/* clock divisor register */# define INTSUBMSK_val 0xffff# define MPLLCON_val ((184 12) + (2 4) + 2) /*406M*/# define UPLLCON_val ((60 12) + (4 4) + 2) /* 47M */# define CLKDIVN_val 7 /* FCLK:HCLK:PCLK = 1:3:6 */# define CAMDIVN 0x4C000018//取得看门狗寄存器的地址ldr r0, =pWTCON//将R1寄存器清0mov r1, #0x0//将看门狗寄存器清0,即将看门狗禁止,包括定时器定时,溢出中断及溢出复位等str r1, [r0]/** mask all IRQs by setting all bits in the INTMR - default*///设R1寄存器为0xFFFF FFFFmov r1, #0xffffffff//读取中断屏蔽寄存器的地址ldr r0, =INTMSK//将中断屏蔽寄存器中的位全设1,屏蔽所有中断str r1, [r0]//# define INTSUBMSK_val 0xffff//设R1寄存器为0xFFFFldr r1, =INTSUBMSK_val//读取辅助中断屏蔽寄存器的地址ldr r0, =INTSUBMSK//将辅助中断屏蔽寄中的11个中断信号屏蔽掉,本人觉得INTSUBMS_val应设成7ff str r1, [r0]//# define LOCKTIME 0x4c000000//读取PLL锁频计数器寄存器地址到R0中ldr r0,=LOCKTIME//将R1设为0x00FF FFFFldr r1,=0xffffff//M_LTIME为最大的0xFFF//U_LTIME为最大的0xFFFstr r1,[r0] ;0xfff=4096>1800,远远满足锁定要求/* FCLK:HCLK:PCLK = 1:2:4 *//* default FCLK is 120 MHz ! *///# define CLKDIVN 0x4C000014 /* clock divisor register *///读取时钟分频寄存器的地址ldr r0, =CLKDIVN//# define CLKDIVN_val 7 /* FCLK:HCLK:PCLK = 1:3:6 *///将R1设为0x7mov r1, #CLKDIVN_va//PDIVN - 1: PCLK has the clock same as the HCLK/2.//HDIVN - 11 : HCLK = FCLK/3 when CAMDIVN[8] = 0.// HCLK = FCLK/6 when CAMDIVN[8] = 1.str r1, [r0]/* Make sure we get FCLK:HCLK:PCLK = 1:3:6 *///# define CAMDIVN 0x4C000018//读取摄像头时钟分频寄存器的地址ldr r0, =CAMDIVN//将R1设为0mov r1, #0//将摄像头时钟分频寄存器清0str r1, [r0]/* Clock asynchronous mode *///MRC p15, 0, Rd, c1, c0, 0 ; read control register//读取控制寄存器中的值到R1中mrc p15, 0, r1, c1, c0, 0 ;将协处理器p15的寄存器c1和c0的值传到arm处理器的R1寄存器中//31 iA bit Asynchronous clock select//30 nF bit notFastBus selectorr r1, r1, #0xc0000000 ;将最高两位置1//MCR p15, 0, Rd, c1, c0, 0 ; write control register//将R1中的值写到控制寄存器中mcr p15, 0, r1, c1, c0, 0 将arm的寄存器R1的32位数据传到协处理器p15的两个16位寄存器c1和c0//# define UPLLCON 0x4c000008//读取UPLL设置寄存器的地址到R0中ldr r0,=UPLLCON//# define UPLLCON_val ((60ldr r1,=UPLLCON_val//将R1中的值写入UPLL设置寄存器中str r1,[r0]//ARM920T为5级流水线,需要至少5个周期来让指令生效nopnopnopnopnopnopnopnop//读取MPLL设置寄存器的地址到R0中ldr r0,=MPLLCON//# define MPLLCON_val ((184ldr r1,=MPLLCON_val//将R1中的值写入MPLL设置寄存器中str r1,[r0]#define GPJCON 0x560000D0#define GPJDAT 0x560000D4#define GPJUP 0x560000D8//跳转到cpu_init_crit处执行//并将下一条指令的地址写入LR寄存器中bl cpu_init_critcpu_init_crit在cpu/arm920t/start.S中代码如下:cpu_init_crit:/** flush v4 I/D caches*///将R0寄存器置0mov r0, #0//Invalidate ICache and DCache SBZ MCR p15,0,Rd,c7,c7,0 //禁止指令和数据cachemcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache *///Invalidate TLB(s) SBZ MCR p15,0,Rd,c8,c7,0mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB *//** disable MMU stuff and caches*///MRC p15, 0, Rd, c1, c0, 0 ; read control registermrc p15, 0, r0, c1, c0, 0//清除[8] [9] [13] 这3个位//8 - System protection//9 - ROM protection//13 - Base location of exception registers - 0 = Low addresses = 0x00000000. bic r0, r0, #0x00002300 // clear bits 13, 9:8 (--V- --RS)//清除[0] [1] [2] [7] 这4个位// 0 - MMU enable - 0 = MMU disabled.// 1 - Alignment fault enable - 0 = Fault checking disabled.// 2 - DCache enable - 0 = DCache disabled.// 7 - Endianness - 0 = Little-endian operation.bic r0, r0, #0x00000087 // clear bits 7, 2:0 (B--- -CAM)//设置位[1]为真// 1 - Alignment fault enable - 1 = Fault checking enabled.orr r0, r0, #0x00000002 // set bit 2 (A) Align//设置位[12]为真//12 - ICache enable - 1 = ICache enabled.orr r0, r0, #0x00001000 // set bit 12 (I) I-Cache//MCR p15, 0, Rd, c1, c0, 0 ; write control registermcr p15, 0, r0, c1, c0, 0//将返回地址保存到IP中mov ip, lr//跳转到lowlevel_init中执行bl lowlevel_initcpu_init_crit在cpu/arm920t/start.S中代码如下:.globl lowlevel_init//读取下面标号为SMRDATA处的地址到R0中ldr r0, =SMRDATA//读取上面标号为_TEXT_BASE处的地址内容到R1中//也就是取得TEXT_BASE的值到R1中ldr r1, _TEXT_BASE//计算SMRDATA的相对地址保存到R0中//SMRDATA为虚拟地址,而TEXT_BASE为虚拟地址的起始地址//而现在Uboot的起始地址并不为虚拟地址//TEXT_BASE为0x33F8 0000,SMRDATA为0x33F8 06C8//而现在程序运行在起始地址为0x0000 0000的地方//所以需要计算以0x0000 0000为标准的相对地址sub r0, r0, r1//取得带宽与等待状态控制寄存器地址到R1中ldr r1, =BWSCON /* Bus Width Status Controller *///一共需要设置13个寄存器,每个寄存器4字节add r2, r0, #13*40://读取R0所指的项的值到R3中后R0自加4字节ldr r3, [r0], #4//将R3中的值保存到R1所指的地址中后R1自加4字节str r3, [r1], #4//比较R0和R2是否相等,相等则说明13个寄存器全部设置完毕cmp r2, r0//不等则跳转到上面标号为0处的地址继续执行bne 0b//跳回到返回地址中继续执行mov pc, lr.ltorg/* the literal pools origin */SMRDATA:.word(0+(B1_BWSCON4)+(B2_BWSCON8)+(B3_BWSCON12)+(B4_BWSCON16)+( B5_BWSCON20)+(B6_BWSCON24)+(B7_BWSCON28)).word((B0_Tacs13)+(B0_Tcos11)+(B0_T acc8)+(B0_Tcoh6)+(B0_T ah4)+(B0_T acp2) +(B0_PMC)).word((B1_Tacs13)+(B1_Tcos11)+(B1_T acc8)+(B1_Tcoh6)+(B1_T ah4)+(B1_T acp2) +(B1_PMC)).word((B2_Tacs13)+(B2_Tcos11)+(B2_T acc8)+(B2_Tcoh6)+(B2_T ah4)+(B2_T acp2) +(B2_PMC)).word((B3_Tacs13)+(B3_Tcos11)+(B3_T acc8)+(B3_Tcoh6)+(B3_T ah4)+(B3_T acp2) +(B3_PMC)).word((B4_Tacs13)+(B4_Tcos11)+(B4_T acc8)+(B4_Tcoh6)+(B4_T ah4)+(B4_T acp2) +(B4_PMC)).word((B5_Tacs13)+(B5_Tcos11)+(B5_T acc8)+(B5_Tcoh6)+(B5_T ah4)+(B5_T acp2) +(B5_PMC)).word ((B6_MT15)+(B6_Trcd2)+(B6_SCAN)).word ((B7_MT15)+(B7_Trcd2)+(B7_SCAN)).word ((REFEN23)+(TREFMD22)+(Trp20)+(Trc18)+(Tchr16)+REFCNT).word 0x32.word 0x30.word 0x30执行mov pc, lr后将返回到cpu_init_crit中剩下来还有2条指令//恢复返回地址到LRmov lr, ip//跳转到返回地址mov pc, lr执行完毕之后将返回到start_code中执行接下来的代码代码如下://#define GPJCON 0x560000D0//取得J端口控制寄存器的地址到R0中LDR R0, = GPJCON//将R1设置为0x1 5555LDR R1, = 0x15555//将R1中的值保存到J端口控制寄存器//GPJ0 - 01 - Output//GPJ1 - 01 - Output//GPJ2 - 01 - Output//GPJ3 - 01 - Output//GPJ4 - 01 - OutputSTR R1, [R0]//#define GPJUP 0x560000D8//取得J端口上拉功能寄存器的地址到R0中LDR R0, = GPJUP//将R1设置为0x1FLDR R1, = 0x1f//将R1中的值保存到J端口上拉功能寄存器//禁止GPJ0 - GPJ4的上拉功能STR R1, [R0]//#define GPJDAT 0x560000D4//取得J端口数据寄存器的地址到R0中LDR R0, = GPJDAT//将R1设为0x0LDR R1, = 0x00//将R1中的值保存到J端口数据寄存器//将J端口数据寄存器清0STR R1, [R0]//下面是NAND数据拷贝过程//relocate:copy_myself://#define S3C2440_NAND_BASE 0x4E000000//取得Nand Flash设置寄存器的地址mov r1, #S3C2440_NAND_BASE//将R2设为0xFFF0ldr r2, =0xfff0 // initial value tacls=3,rph0=7,rph1=7 //#define oNFCONF 0x00//读取Nand Flash设置寄存器中的值到R3中ldr r3, [r1, #oNFCONF]//将R3或上R2后保存到R3中orr r3, r3, r2//将R3中的值保存到Nand Flash设置寄存器中//TWRPH0 - 111 - Duration = HCLK * (TWRPH0 + 1) //TACLS - 11 - Duration = HCLK * TACLSstr r3, [r1, #oNFCONF]//#define oNFCONT 0x04//读取Nand Flash控制寄存器中的值到R3中ldr r3, [r1, #oNFCONT]//将R3的[0]位置1orr r3, r3, #1 // enable nand controller//将R3中的值保存到Nand Flash控制寄存器中//Mode - 1:Nand Flash Controller Enablestr r3, [r1, #oNFCONT]//读取虚拟起始地址到R0中ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot *///预留malloc所需要的空间sub r0, r0, #CFG_MALLOC_LEN /* malloc area *///预留bdinfo所需要的空间sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo *///预留中断和快速中断向量表空间sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)//预留12字节给中断栈sub sp, r0, #12 /* leave 3 words for abort-stack */// copy u-boot to RAM//读取虚拟起始地址到R0中,作为目标地址ldr r0, _TEXT_BASE//将R1设为0,作为源地址mov r1, #0x0//将UBOOT大小的值保存在R2中,作为数据大小mov r2, #CFG_UBOOT_SIZE//跳转到nand_read_ll处执行//并将下一条指令的地址保存在LR中bl nand_read_llnand_read_ll的原型为int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size) 之前设置的R0 R1 R2为它的3个参数R0 - bufR1 - start_addrR2 - sizenand_read_ll的代码在cpu/arm920t/s3c24x0/nand_read.c中int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size) {int i, j;//检测源地址和大小是否在NandFlash的边界上if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) //不在边界上则返回-1表示出错return -1; /* invalid alignment *//* chip Enable */// #define nand_select() (NFCONT &= ~(1//置NAND Flash控制寄存器中除Reg_nCE外所有的位为1//Reg_nCE - NAND FLASH Memory nFCE signal control//0 - Force nFCE to low (Enable chip select)nand_select();// #define nand_clear_RnB() (NFSTAT |= (1//置NAND Flash操作状态寄存器中的RnB_TransDetect位为1//When RnB low to high transition is occurred, this value set and issue interrupt if enabled.//To clear this value write '1'//1: RnB transition is detectednand_clear_RnB();for (i=0; i10; i++);//从源地址的首地址开始历便所要拷贝的数据大小for (i=start_addr; i (start_addr + size);){//检测地址是否在NAND Flash的边界上if (start_addr % NAND_BLOCK_SIZE == 0){//检测是否为坏块if (is_bad_block(i)){/* Bad block *///向后延伸一个存储块i += NAND_BLOCK_SIZE;size += NAND_BLOCK_SIZE;//跳到下一块continue;}}j = nand_read_page_ll(buf, i);//指向下一块i += j;buf += j;// LED_FLASH();}/* chip Disable */// #define nand_deselect() (NFCONT |= (1//置Reg_nCE位为1//NAND Flash Memory nFCE signal control//1: Force nFCE to High(Disable chip select)nand_deselect();return 0;}nand_read_ll将Uboot从NAND中拷贝到RAM中拷贝完成后将返回到start_code接下来的代码如下://检测R0是否为0,R0为nand_read_ll的返回值tst r0, #0x0//为0则说明无错,跳转到ok_nand_read处执行beq ok_nand_readok_nand_read://将R0设为0mov r0, #0//ldr r1, =0x33f00000//将R1设为虚拟地址起始处ldr r1, _TEXT_BASE//检测0x400个字节mov r2, #0x400 // 4 bytes * 1024 = 4K-bytesgo_next://读取R0处地址的数据到R3中//然后R0自加4字节ldr r3, [r0], #4//读取R1处地址的数据到R4中//然后R1自加4字节ldr r4, [r1], #4//比较R3和R4的数据是否相等//也就是检测Boot Internal SRAM和RAM中的数据是否相等//以保证数据无错teq r3, r4//不等则跳转到notmatchbne notmatch//相等则R2自减4subs r2, r2, #4//当R2为0则跳转到done_nand_readbeq done_nand_read//R2不为0则跳转回go_next继续检测bne go_nextdone_nand_read:LDR R0, = GPJDATLDR R1, = 0x2STR R1, [R0]stack_setup://读取虚拟起始地址到R0中ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */ //预留malloc所需要的空间sub r0, r0, #CFG_MALLOC_LEN /* malloc area *///预留bdinfo所需要的空间sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo *///预留中断和快速中断向量表空间sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)//预留12字节给中断栈sub sp, r0, #12 /* leave 3 words for abort-stack */clear_bss://读取BSS段的起始地址ldr r0, _bss_start /* find start of bss segment *///读取BSS段的结束地址ldr r1, _bss_end /* stop here *///将R2设为0x0mov r2, #0x00000000 /* clear */clbss_l://将R2中的值保存在R0所指的地址str r2, [r0] /* clear loop... *///R0自加4字节add r0, r0, #4//比较R0和R1是否相等cmp r0, r1//不等则说明清0还没结束ble clbss_lLDR R0, = GPJDATLDR R1, = 0x1STR R1, [R0]//跳转到start_armboot处执行ldr pc, _start_armboot_start_armboot: .word start_armboot这里start_armboot是一个绝对地址,在朗成所修改的这个Uboot中为0x33F8 13F4 执行ldr pc, _start_armboot之后将会跳到RAM中的绝对地址继续执行整理了一个流程图,分为3个存储器:1 Boot Internal SRAM , 接在BANK0,起始地址为0x02 RAM , 接在BANK6,起始地址为0x3000 00003 NAND FLASH,为单独寻址流程如下图:红字为流程序号:1. 首先将NAND FLASH中的前0x1000字节内容拷贝到Boot Internal SRAM中2. 从Boot Internal SRAM的0x0地址处开始执行指令3. 将Uboot从Flash拷贝到RAM中4. 执行ldr pc, _start_armboot从Boot Internal SRAM中跳转到RAM中的绝对地址0x33F8 13F4处继续执行。
[uboot](第五章)uboot流程——uboot启动流程
[uboot](第五章)uboot流程——uboot启动流程/ooonebook/article/details/53070065以下例⼦都以project X项⽬tiny210(s5pv210平台,armv7)为例[uboot] uboot流程系列:建议先看《[project X] tiny210(s5pv210)上电启动流程(BL0-BL2)》,根据例⼦了解⼀下上电之后的BL0\BL1\BL2阶段,以及各个阶段的运⾏位置,功能。
建议可以和《[uboot] (番外篇)global_data介绍》和《[uboot] (番外篇)uboot relocation介绍》结合起来看。
=================================================================================⼀、uboot说明1、uboot要做的事情CPU初始刚上电的状态。
需要⼩⼼的设置好很多状态,包括cpu状态、中断状态、MMU状态等等。
其次,就是要根据硬件资源进⾏板级的初始化,代码重定向等等。
最后,就是进⼊命令⾏状态,等待处理命令。
在armv7架构的uboot,主要需要做如下事情arch级的初始化关闭中断,设置svc模式禁⽤MMU、TLB关键寄存器的设置,包括时钟、看门狗的寄存器板级的初始化堆栈环境的设置代码重定向之前的板级初始化,包括串⼝、定时器、环境变量、I2C\SPI等等的初始化进⾏代码重定向代码重定向之后的板级初始化,包括板级代码中定义的初始化操作、emmc、nand flash、⽹络、中断等等的初始化。
进⼊命令⾏状态,等待终端输⼊命令以及对命令进⾏处理上述⼯作,也就是uboot流程的核⼼。
2、疑问在前⾯的⽂章中虽然已经说明了,在spl的阶段中已经对arch级进⾏了初始化了,为什么uboot⾥⾯还要对arch再初始化⼀遍?回答:spl对于启动uboot来说并不是必须的,在某些情况下,上电之后uboot可能在ROM上或者flash上开始执⾏⽽并没有使⽤spl。
面试 uboot的启动流程
面试 uboot的启动流程英文回答:The boot process of U-Boot can be divided into several stages. First, when the system is powered on, the CPUstarts executing the initial bootstrap code stored in the ROM. This code is responsible for initializing the CPU and memory, and then it transfers control to the second stage bootloader, which is typically stored in some non-volatile memory like flash or SD card.In the second stage, the bootloader performs some basic hardware initialization, such as setting up the clocks, enabling the cache, and configuring the memory controller. It then loads the U-Boot image from the storage device into the RAM and transfers control to it.Once U-Boot is running, it performs further initialization, such as setting up the environment variables and initializing the drivers for the peripherals.It also provides a command-line interface for interacting with the user.After the initialization is complete, U-Boot executes the boot script, which is a set of commands that define the boot process. This script typically sets up the kernel command line and loads the kernel image from the storage device into the RAM.Finally, U-Boot transfers control to the loaded kernel image, which starts the operating system and continues the boot process.中文回答:U-Boot的启动流程可以分为几个阶段。
Android系统启动过程-uBoot+Kernel+Android
Android系统启动过程-uBoot+Kernel+Android摘要:本⽂是参考⼤量⽹上资源在结合⾃⼰查看源代码总结出来的,让⾃⼰同时也让⼤家加深对Android系统启动过程有⼀个更加深⼊的了解!再次强调,本⽂的⼤多数功劳应归功于那些原创者们,同时⼀些必要的参考链接我会⼀⼀附上。
注:由于本⼈采⽤Exynos4412开发板学习,所以本⽂⼤部分资料都是基于此处理器的简介:对于整个Android系统的启动总的来说分为三个阶段: BootLoader引导即uBoot.bin linux内核启动即zImage Android系统启动即ramdisk.img与system.img 以上四个⽂件都是经过⾃⼰编译后⽣成的且通过烧写测试,接下来开始说这三⼤部分的启动过程。
⽬录:⼀、BootLoader的启动 1.汇编部分 2.c部分 ⼆、Kernel的启动 1.zImage解压缩 2.kernel的汇编启动阶段 3.kernel的c启动阶段 三、Android的启动 1.init进程 2.init启动的各种服务 3.android启动图⽰第⼀部分:BootLoader的启动流程 uBoot的第⼀条指令从cpu/arm920t/start.S⽂件开始 1. 设置CPU进⼊SVC模式(系统管理模式),cpsr[4:0]=0xd3。
1 #include <common.h>2 #include <config.h>34/*5 *************************************************************************6 *7 * Jump vector table as in table 3.1 in [1]8 *9 *************************************************************************10*/111213 .globl _start14 _start: b start_code15 ldr pc, _undefined_instruction16 ldr pc, _software_interrupt17 ldr pc, _prefetch_abort18 ldr pc, _data_abort19 ldr pc, _not_used20 ldr pc, _irq21 ldr pc, _fiq2223 _undefined_instruction: .word undefined_instruction24 _software_interrupt: .word software_interrupt25 _prefetch_abort: .word prefetch_abort26 _data_abort: .word data_abort27 _not_used: .word not_used28 _irq: .word irq29 _fiq: .word fiq3031 .balignl 16,0xdeadbeef 接着进⼊Start_code中:设置CPU进⼊SVC模式。
uboot启动流程
uboot启动流程U-Boot是一款开源的嵌入式引导加载程序(bootloader),主要用于嵌入式系统的引导启动。
它是一个跨平台的引导加载程序,可以在不同的处理器架构和操作系统上运行。
下面将介绍U-Boot的启动流程。
U-Boot启动流程主要包括三个阶段:启动ROM代码、启动SPL(Secondary Program Loader)和启动U-Boot。
首先,当嵌入式设备上电后,处理器会首先执行固定在芯片内部的启动ROM代码。
这些代码主要完成一些基本的硬件初始化工作,例如设置栈指针、初始化外设等。
然后,启动ROM 代码会从预定义的启动设备(例如闪存、SD卡等)中加载SPL。
接下来,SPL(Secondary Program Loader)被加载到内存中执行。
SPL是一个较小的引导加载程序,主要作用是完成一些必要的初始化和硬件配置。
SPL会初始化内存控制器、外设等,并加载U-Boot镜像到内存中。
最后,U-Boot被加载到内存中执行。
U-Boot是一个功能强大的引导加载程序,拥有丰富的命令和功能。
它可以根据不同的系统配置进行配置和扩展,并提供了丰富的调试和测试功能。
U-Boot的启动流程主要可以分为以下几个步骤:1. CPU初始化:U-Boot开始执行后,首先进行CPU的初始化工作,包括设置栈指针、cache的初始化等。
2. 设备初始化:接下来,U-Boot会初始化外设设备,例如串口、网络接口等。
这些设备的初始化是为了后续的调试和配置工作做准备。
3. 系统环境的初始化:U-Boot会读取存储在非易失性存储设备(例如NAND闪存、SD卡等)中的环境变量,根据这些变量进行系统的初始化配置。
4. 设备驱动的加载:U-Boot会加载并初始化必要的设备驱动程序,以便后续的硬件操作可以正常进行。
5. 启动命令的执行:U-Boot会根据配置文件中的设置,执行预定义的启动命令。
这些命令可以是启动操作系统、加载应用程序等。
uboot学习之uboot启动流程简述
uboot学习之uboot启动流程简述⼀、uboot启动分为了三个阶段BL0、BL1、BL2;BL0表⽰上电后运⾏ROM中固化的⼀段程序,其中ROM中的程序是⼚家写进去的,所以具体功能可能根据⼚家芯⽚⽽有所不同。
功能如下:1. 初始化系统时钟、特殊设备的控制器、启动设备、看门狗、堆栈、SRAM等硬件;2. 验证B1镜像,并且加载BL1镜像到SRAM中,然后跳转到BL1镜像的地址上。
BL0需要将BL1加载到对应的RAM上,这就涉及到它的启动模式,详细如下:1.OneNand Boot模式要了解OneNAND先得了解NOR Flash和NAND Flash。
与NOR Flash相⽐,NAND Flash的读数据速度稍慢,但是擦写速度快得多,并且在容量、使⽤寿命、成本上也占有较⼤优势。
NOR Flash的编程简单,⽽NAND Flash的编程较为复杂(因为它的flash管理需要特殊的接⼝)。
NAND Flash⼀般⽤于存储数据,⽽NOR Flash⼀般⽤于存储启动代码。
NOR Flash带有SRAM接⼝,有⾜够的地址引脚来寻址,可以很容易地存取其内容的每⼀字节(有限的地址引脚是限制其容量的因素之⼀)。
NAND Flash使⽤复杂的I/O⼝来串⾏地存取数据,各个产品或⼚商的⽅法可能各不相同。
为了弥补NAND Flash的不⾜,三星公司在NAND Flash芯⽚内集成了⼀个RAM接⼝,命名为OneNAND Flash,这类Flash拥有与NOR Flash相同的简单接⼝,⽽且不受地址引脚的限制,即容量与地址引脚⽆关。
其实OneNAND 其实就是采⽤了NOR的接⼝,NAND的架构,是两者的性能得到了综合。
这就有了X-LOADER的产⽣,以前我们接触到的都是BOOTLOADER,其实这个X-LOADER也起到初始化的作⽤,因为我们的BOOTLOADER是放在NAND的架构下的,⽽CPU却是从NOR的接⼝下读取BOOTLOADER到SDRAM中的,所以现在要做⼀个⼯作就是要如何将BOOTLOADER在OneNAND的架构下从NAND复制到SDRAM中,这就是X-LOADER的功能了,它不仅初始化OneNAND,并且把U-BOOT从NAND的架构下复制到BufferRam中,再复制到SDRAM中。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Uboot启动U-boot主要完成硬件初始化,设置启动参数,引导操作系统等功能Bootloader介绍:是在操作系统运行前执行的一小段代码,通过这一小段代码,我们可以初始化硬件设备,建立内存空间映射表,从而建立适当的系统软硬件环境,为最终调用操作系统内核做好准备,nand布局从0地址开始是uboot之后是env再是内核,最后是文件系统。
Bootloader的启动方式主要有网络启动方式、磁盘启动方式和Flash启动方式U-boot的环境变量值得注意的有两个:bootcmd 和bootargs。
u-bootcmd:前面有说过bootcmd是自动启动时默认执行的一些命令,因此你可以在当前环境中定义各种不同配置,不同环境的参数设置,然后设置bootcmd为你经常使用的那种参数。
一种是u-boot启动用tftp下载在nand erase和read一种是linux启动,要把u-boot和uImage写到SD卡在用SD 卡烧写u-bootargs:bootargs整个环境变量都是围绕着bootargs来设置的,内核和文件系统的不同搭配就会有不同的设置方法,甚至你也可以不设置bootargs,而直接将其写到内核中去(在配置内核的选项中可以进行这样的设置)1. root用来指定rootfs的设备文件,常见的情况有:root=/dev/ram rwroot=/dev/ram0 rw请注意上面的这两种设置情况是通用的,我做过测试甚至root=/dev/ram1 rw和root=/dev/ram2 rw也是可以的,网上有人说在某些情况下是不通用的,即必须设置成ram或者ram0,但是目前还没有遇到,还需要进一步确认,遇到不行的时候可以逐一尝试。
root=/dev/mtdx rwroot=/dev/mtdblockx roroot=/dev/mtdblock/x rwroot=31:0x上面的这几个在一定情况下是通用的,当然这要看你当前的系统是否支持,不过mtd是字符设备一般都是指定字符像u-boot,uImage对于文件系统是不可使用的要用mtdblock,而mtdblock是块设备,有时候你的挨个的试到底当前的系统支持上面那种情况下,不过root=/dev/mtdblockx rw比较通用。
此外,如果直接指定设备名可以的话,那么使用此设备的设备号也是可以的。
root=/dev/nfs在文件系统为基于nfs的文件系统的时候使用。
当然指定root=/dev/nfs之后,还需要指定nfsroot=serverip:nfs_dir,即指明文件系统存在那个主机的那个目录下面。
2. rootfstype这个选项需要跟root一起配合使用,一般如果根文件系统是ext2的话,有没有这个选项是无所谓的,但是如果是jffs2,squashfs等文件系统的话,就需要rootfstype指明文件系统的类型,不然会无法挂载根分区.3. consoleconsole=tty 使用虚拟串口终端设备 .console=ttyS[,options] 使用特定的串口,options可以是这样的形式bbbbpnx,这里bbbb是指串口的波特率,p是奇偶位(从来没有看过使用过),n是指的bits。
console=ttySAC[,options] 同上面。
所以应该是跟内核版本没有关联的。
可以查看Documentation/serial-console.txt找到相关描述。
4. memmem=xxM 指定内存的大小,嵌入式平台是必须的mem=128M@0x80000000一般默认是起始地址是0x80000000mem=128M@0x80000000 mem=128M@0xC0000000支持内存空洞,存储不连续下一块要指定地址5. ramdisk_sizeramdisk=xxxxx 不推荐ramdisk_size=xxxxx 推荐上面这两个都可以告诉ramdisk 驱动,创建的ramdisk的size,默认情况下是4m(s390默认8M),你可以查看Documentation/ramdisk.txt找到相关的描述,不过ramdisk=xxxxx 在新版的内核都已经没有提了,不推荐使用。
6. initrd, noinitrd当你没有使用ramdisk启动系统的时候,你需要使用noinitrd这个参数,但是如果使用了的话,就需要指定initrd=r_addr,size, r_addr表示initrd 在内存中的位置,size表示initrd的大小。
7. initinit 指定的是内核启起来后,进入系统中运行的第一个脚本,一般init=/linuxrc, 或者init=/etc/preinit,preinit的内容一般是创建console,null设备节点,运行init程序,挂载一些文件系统等等操作。
请注意,很多初学者以为init=/linuxrc是固定写法,其实不然,/linuxrc指的是/目录下面的linuxrc脚本,一般是一个连接罢了。
8. mtdpartsmtdparts=fc000000.nor_flash:1920k(linux),128k(fdt),20M(ra mdisk),4 M(jffs2),38272k(user),256k(env),384k(uboot) 要想这个参数起作用,内核中的mtd驱动必须要支持,即内核配置时需要选上Device Drivers ---> Memory Technology Device (MTD) support ---> Command line partition table parsing mtdparts的格式如下:mtdparts=[;:= :[,]:= [@offset][][ro]:= unique id used in mapping driver/device:= standard linux memsize OR "-" to denote all remaining space := (NAME)因此你在使用的时候需要按照下面的格式来设置:mtdparts=mtd-id:@(),@()这里面有几个必须要注意的:a. mtd-id 必须要跟你当前平台的flash的mtd-id一致,不然整个mtdparts 会失效b. size在设置的时候可以为实际的size(xxM,xxk,xx),也可以为'-'这表示剩余的所有空间。
举例:假设flash 的mtd-id是sa1100,那么你可以使用下面的方式来设置:mtdparts=sa1100:- →只有一个分区mtdparts=sa1100:256k(ARMboot)ro,-(root) →有两个分区可以查看drivers/mtd/cmdlinepart.c中的注释找到相关描述。
9. ip更改IP在/etc/network/interfaces指定系统启动之后网卡的ip地址,如果你使用基于nfs的文件系统,那么必须要有这个参数,其他的情况下就看你自己的喜好了。
设置ip有两种方法:ip = ip addrip=ip addr:server ip addr:gateway:netmask::which netcard:off这两种方法可以用,不过很明显第二种要详细很多,请注意第二种中which netcard 是指开发板上的网卡,而不是主机上的网卡。
说完常见的几种bootargs,那么我们来讨论平常我经常使用的几种组合:1). 假设文件系统是ramdisk,且直接就在内存中,bootargs的设置应该如下:setenv bootargs ‘initrd=0x32000000,0xa00000 root=/dev/ram0console=ttySAC0 mem=64M init=/linuxrc’2). 假设文件系统是ramdisk,且在flash中,bootargs的设置应该如下:setenv bootargs ‘mem=32M console=ttyS0,115200 root=/dev/ram rwinit=/linuxrc’注意这种情况下你应该要在bootm命令中指定ramdisk在flash 中的地址,如bootm kernel_addr ramdisk_addr (fdt_addr)3). 假设文件系统是jffs2类型的,且在flash中,bootargs的设置应该如下setenv bootargs ‘mem=32M console=ttyS0,115200 noinitrdroot=/dev/mtdblock2 rw rootfstype=jffs2 init=/linuxrc’4). 假设文件系统是基于nfs的,bootargs的设置应该如下setenv bootargs ‘noinitrd mem=64M con sole=ttySAC0 root=/dev/nfs nfsroot=192.168.0.3:/nfsip=192.168.0.5:192.168.0.3:192.168.0.1:255.255.255.0::eth0:o ff’或者setenv bo otargs ‘noinitrd mem=64M console=ttySAC0 root=/dev/nfs nfsroot=192.168.0.3:/nfs ip=192.168.0.5’下载与烧写使用U-boot将映像文件烧写到板上的Flash,一般步骤是:1) 通过网络、串口、U盘、SD卡等方式将文件传输到SDRAM;2) 使用Nand Flash或Nor Flash相关的读写命令将SDRAM中的数据烧入Flash。
下面是烧写范例:如果使用 SD卡或者U盘形式更新U-boot,那么首先SD卡或者U盘中必须有FAT32文件系统,并在里面存放了u-boot.bin 文件。
1、通过SD卡烧入Nand Flash[u-boot@apple_guet]#mmc init[u-boot@apple_guet]#fatload mmc 1 0x30008000 u-boot.bin[u-boot@apple_guet]#nand erase 0 0x40000[u-boot@apple_guet]#nand write 0x30008000 0 0x400002、通过U盘烧入Nor Flash[u-boot@apple_guet]#usb start[u-boot@apple_guet]#usb part0[u-boot@apple_guet]#fatload usb 0:4 0x30008000 u-boot.bin[u-boot@apple_guet]#protect off all[u-boot@apple_guet]#erase 0x0 0x3ffff[u-boot@MINI2440]#cp.b 0x30008000 0x0 0x3ffff3、通过TFTP服务烧入Nand Flash[u-boot@apple_guet]#tftpboot 30008000 192.168.1.100:u-boot.bin [u-boot@MINI2440]#nand erase 0 0x40000 [u-boot@apple_guet]#nand write 0x30008000 0 0x400004、通过NFS 服务烧入Nand Flash[u-boot@apple_guet]#nfs 30008000192.168.1.100:/home/tekkaman/development/share/u-boot.bin[u-boot@apple_guet]#nand erase 0 0x40000[u-boot@apple_guet]#nand write 0x30008000 0 0x40000。