Uboot启动代码解析

合集下载

uboot代码完全解析

uboot代码完全解析
1.相关文件 ....................................................................................................................................28 2.数据结构 ....................................................................................................................................28 3.ENV 的初始化...........................................................................................................................30
目录
u-boot-1.1.6 之 cpu/arm920t........................................................................2 u-boot 中.lds 连接脚本文件的分析 ...................................................................................................12 分享一篇我总结的 uboot 学习笔记(转) .....................................................................................15 U-BOOT 内存布局及启动过程浅析 ...................................................................................................22 u-boot 中的命令实现 ..........................................................................................................................25 U-BOOT 环境变量实现 ........................................................................................................................28

u-boot启动分析

u-boot启动分析

背景:Board →ar7240(ap93)Cpu →mips1、首先弄清楚什么是u-bootUboot是德国DENX小组的开发,它用于多种嵌入式CPU的bootloader程序, uboot不仅支持嵌入式linux系统的引导,当前,它还支持其他的很多嵌入式操作系统。

除了PowerPC系列,还支持MIPS,x86,ARM,NIOS,XScale。

2、下载完uboot后解压,在根目录下,有如下重要的信息(目录或者文件):以下为为每个目录的说明:Board:和一些已有开发板有关的文件。

每一个开发板都以一个子目录出现在当前目录中,子目录存放和开发板相关的配置文件。

它的每个子文件夹里都有如下文件(以ar7240/ap93为例):MakefileConfig.mkAp93.c 和板子相关的代码Flash.c Flash操作代码u-boot.lds 对应的链接文件common:实现uboot命令行下支持的命令,每一条命令都对应一个文件。

例如bootm命令对应就是cmd_bootm.ccpu:与特定CPU架构相关目录,每一款Uboot下支持的CPU在该目录下对应一个子目录,比如有子目录mips等。

它的每个子文件夹里都有入下文件:MakefileConfig.mkCpu.c 和处理器相关的代码sInterrupts.c 中断处理代码Serial.c 串口初始化代码Start.s 全局开始启动代码Disk:对磁盘的支持Doc:文档目录。

Uboot有非常完善的文档。

Drivers:Uboot支持的设备驱动程序都放在该目录,比如网卡,支持CFI的Flash,串口和USB等。

Fs:支持的文件系统,Uboot现在支持cramfs、fat、fdos、jffs2和registerfs。

Include:Uboot使用的头文件,还有对各种硬件平台支持的汇编文件,系统的配置文件和对文件系统支持的文件。

该目下configs目录有与开发板相关的配置文件,如ar7240_soc.h。

U-boot解析

U-boot解析

u-boot源码解析u-boot介绍Uboot是德国DENX小组的开发用于多种嵌入式CPU的bootloader程序, UBoot不仅仅支持嵌入式Linux系统的引导,当前,它还支持NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS 嵌入式操作系统。

UBoot除了支持PowerPC系列的处理器外,还能支持MIPS、 x86、ARM、NIOS、XScale等诸多常用系列的处理器。

board:和一些已有开发板有关的文件。

每一个开发板都以一个子目录出现在当前目录中,子目录中存放与开发板相关的配置文件。

它的每个子文件夹里都有如下文件:makefileconfig.mksmdk2410.c 和板子相关的代码(以smdk2410为例)flash.c Flash操作代码memsetup.s 初始化SDRAM代码u-boot.lds 对应的连接文件common:实现uboot命令行下支持的命令,每一条命令都对应一个文件。

例如bootm命令对应就是cmd_bootm.c。

cpu:与特定CPU架构相关目录,每一款Uboot下支持的CPU在该目录下对应一个子目录,比如有子目录arm920t等。

cpu/ 它的每个子文件夹里都有如下文件:makefileconfig.mkcpu.c 和处理器相关的代码interrupts.c 中断处理代码serial.c 串口初始化代码start.s 全局开始启动代码disk:对磁盘的支持。

doc:文档目录。

Uboot有非常完善的文档,推荐大家参考阅读。

drivers:Uboot支持的设备驱动程序都放在该目录,比如各种网卡、支持CFI的Flash、串口和USB等。

fs: 支持的文件系统,Uboot现在支持cramfs、fat、fdos、jffs2和registerfs。

include:Uboot使用的头文件,还有对各种硬件平台支持的汇编文件,系统的配置文件和对文件系统支持的文件。

UBOOT源码分析

UBOOT源码分析

UBOOT源码分析UBOOT是一种开放源码的引导加载程序。

作为嵌入式系统启动的第一阶段,它负责初始化硬件设备、设置系统环境变量、加载内核镜像以及跳转到内核开始执行。

Uboot的源码是开放的,让我们可以深入了解其内部工作机制和自定义一些功能。

Uboot源码的文件组织结构非常清晰,主要分为三个大类:目录、文件和配置。

其中目录包含了一系列相关的文件,文件存放具体的源码实现代码,配置文件包含了针对特定硬件平台的配置选项。

Uboot源码的核心部分是启动代码,位于arch目录下的CPU架构相关目录中。

不同的CPU架构拥有不同的启动代码实现,如arm、x86等。

这些启动代码主要包括以下几个关键功能:1. 初始化硬件设备:Uboot首先需要初始化硬件设备,例如设置时钟、中断控制器、串口等设备。

这些初始化操作是在启动代码中完成的。

通过查看该部分代码,我们可以了解硬件的初始化过程,以及如何配置相关寄存器。

2. 设置启动参数:Uboot启动参数存储在一个称为"bd_info"的数据结构中,它包含了一些关键的设备和内存信息,例如DRAM大小、Flash 大小等。

这些参数是在启动代码中设置的,以便内核启动时能够正确识别硬件情况。

3. 加载内核镜像:Uboot负责加载内核镜像到内存中,以便内核可以正确执行。

在启动代码中,会通过读取Flash设备或者网络等方式,将内核镜像加载到指定的内存地址处。

加载过程中,可能会进行一些校验和修正操作,以确保内核数据的完整性。

4. 启动内核:在内核镜像加载完成后,Uboot会设置一些寄存器的值,并执行一个汇编指令,跳转到内核开始执行。

此时,Uboot的使命即结束,控制权交由内核处理。

除了启动代码,Uboot源码中还包含了许多其他功能模块,如命令行解析器、存储设备驱动、网络协议栈等。

这些功能模块可以根据需求进行配置和编译,以满足不同平台的需求。

例如,可以通过配置文件选择启用一些功能模块,或者自定义一些新的功能。

MIPS uboot代码注释

MIPS uboot代码注释

MIPS U-Boot——by M.CUboot启动流程关中断设置kseg0no cache初始化gp指针lowlevel_init mips_cache_reset 设置kseg0cache mips_cache_lockBoard_init_f relocate_code Board_init_r启动内核根据CPU rate初始化外部时钟、内存初始化cachecache未初始化前不能用cache已初始化设置临时cache栈把uboot程序从flash搬到ram执行start.Smtc0zero, CP0_WATCHLO mtc0zero, CP0_WATCHHI 清除硬件数据断点,防止产生调试断点,导致程序停止。

芯片在复位后,某些寄存器的内容也许是你想要的结果,但是谁知道呢,为了保证准确无误,最好还是重新进行手动初始化mfc0k0, CP0_STATUSli k1, ~ST0_IEand k0, k1mtc0k0, CP0_STATUS禁止全局中断mtc0zero, CP0_CAUSE初始化异常寄存器,清除异常原因指示mtc0zero, CP0_COUNTmtc0zero, CP0_COMPARE初始化时钟寄存器,防止产生计数器中断li t0, CONF_CM_UNCACHEDmtc0t0, CP0_CONFIG设置kseg0区不经过cache。

cache需要先初始化才能使用。

bal1fnop.word_gp1:lw gp, 0(ra)bal分支调用,ra返回地址指向下下一条指令,即.word _gp把.word_gp的存储位置载入gp寄存器,即设置GOT表的起始位置la t9, lowlevel_init jalr t9nop 根据CPU rate初始化外部时钟、内存。

lowlevel_init函数定义见lowlevel_init.Sla t9, mips_cache_reset jalr t9nop 初始化高速缓存cache。

uboot笔记uboot命令分析+实现

uboot笔记uboot命令分析+实现

uboot笔记uboot命令分析+实现uboot笔记:uboot命令分析+实现Ubootuboot命令分析+实现先贴⼀个重要结构,位于uboot/include/command.h,这个结构代表每个uboot命令struct cmd_tbl_s {char *name; /* Command Name */int maxargs; /* maximum number of arguments*/int repeatable;/* autorepeat allowed? *//* Implementation function */int (*cmd)(struct cmd_tbl_s *, int, int, char *[]);char *usage; /* Usage message (short)简短⽤法信息*/#ifdef CFG_LONGHELPchar *help; /* Help message (long) 长的帮助信息*/#endif#ifdef CONFIG_AUTO_COMPLETE/* do auto completion on the arguments */ int (*complete)(intargc, char *argv[], charlast_char, intmaxv, char *cmdv[]); #endif};typedefstruct cmd_tbl_s cmd_tbl_t;============================================================uboot的第⼀阶段:硬件相关初始化0.reset执⾏arm920t/start.s 过程如下1.设置cpu svc管理模式2.关看门狗中断,mmu等3.设置时钟,sdram,外部总线4.代码重定位,搬运代码,从flash到sdram5.设置栈,bss段清零, bss⽤于未初始化的全局变量和静态变量6.ldr pc, _start_armboot即进⼊uboot启动的第⼆阶段,调⽤c函数start_armboot()从start_armboot开始经过⼀系列外设初始化⽐如falsh_initnand_init...最后循环调⽤mian_loop()main_loop主要流程{1. ⽣成环境变量mtdparts, 调⽤mtdparts_init2. 在启动过程中若⽆空格键按下则boot_zImage,即run_command(getenv("bootcmd"),0)有空格键按下则run_command("menu",0)3. shell过程,读取⽤户的输⼊并执⾏相应的命令{从控制台获得命令,保存在全局变量comsole_buffer中解析命令⾏字符串,分割命令与参数,最后执⾏run_command(...); }}也就是说在mian_loop中,是处理环境变量和控制台⼈机交互,mian_loop调⽤readline ()读取命令⾏到console_buffer,再把console_buffer复制到lastcommand中去,还要设置flag,最后调⽤run_command (lastcommand, flag)函数,run_command (lastcommand, flag)函数中,⾸先定义cmd_tbl_t *cmdtp,再解析命令⾏。

uboot源码分析(2)uboot环境变量实现简析

uboot源码分析(2)uboot环境变量实现简析

uboot源码分析(2)uboot环境变量实现简析uboot 环境变量实现简析----------基于u-boot-2010.03u-boot的环境变量是使⽤u-boot的关键,它可以由你⾃⼰定义的,但是其中有⼀些也是⼤家经常使⽤,约定熟成的,有⼀些是u-boot⾃⼰定义的,更改这些名字会出现错误,下⾯的表中我们列出了⼀些常⽤的环境变量:bootdelay 执⾏⾃动启动的等候秒数baudrate 串⼝控制台的波特率netmask 以太⽹接⼝的掩码ethaddr 以太⽹卡的⽹卡物理地址bootfile 缺省的下载⽂件bootargs 传递给内核的启动参数bootcmd ⾃动启动时执⾏的命令serverip 服务器端的ip地址ipaddr 本地ip 地址stdin 标准输⼊设备stdout 标准输出设备stderr 标准出错设备上⾯只是⼀些最基本的环境变量,请注意,板⼦⾥原本是没有环境变量的,u-boot的缺省情况下会有⼀些基本的环境变量,在你执⾏了saveenv之后,环境变量会第⼀次保存到flash或者eeprom中,之后你对环境变量的修改,保存都是基于保存在flash中的环境变量的操作。

环境变量可以通过printenv命令查看环境变量的设置描述,通过setenv 命令进⾏重新设置,设置完成后可以通过saveenv将新的设置保存在⾮易失的存储设备中(nor flash 、nand flash 、eeprom)。

例如:setenv bootcmd "nand read 0x30008000 0x80000 0x500000;bootm 0x30008000"saveenv通过这两条命令就完成了环境变量bootcmd的重新设置,并讲其保存在固态存储器中。

下⾯简单分析下uboot中环境变量的实现流程。

uboot启动后,执⾏玩start.S中的汇编程序,将跳⼊board.c 中定义的start_arm_boot()函数中,在该函数中,uboot讲完成板⼦外设和相关系统环境的初始化,然后进⼊main_loop循环中进⾏系统启动或者等待与⽤户交互,这其中就包括环境变量的初始化和重定位。

Uboot代码分析

Uboot代码分析

UBOOT分析报告整理修改中2011-3-10目录Uboot介绍 (2)Uboot 启动流程 (2)I.Uboot启动过程 (2)II.Uboot启动汇编代码部分 (3)III.Uboot启动C代码部分 (4)IV.Uboot中初试环境变量位置及调整方法 (6)V.Uboot c代码中gd(全局数据)的保存位置 (6)Uboot的编译生成 (6)Uboot 汇编代码探究 (6)Uboot C代码探究 (6)一、Uboot下命令实现 (6)二、env_* 环境变量操作函数实现(如saveenv) (7)1、env_sf.c环境变量要保存在spi flash时调用 (7)Uboot 内部宏定义 (7)1.DECLARE_GLOBLE_DATA_PTR (7)2. CONFIG_ENV_ADDR (8)3. CONFIG_ENV_OFFSET (8)4. CONFIG_ENV_SECT_SIZE (8)5. CONFIG_ENV_IS_EMBEDDED (8)6. CONFIG_ENV_IS_IN_NAND (9)Uboot 目录结构功能 (10)Uboot介绍Uboot全写Universal Boot Loader,是芯片加电或复位后进入操作系统之前运行的一段代码,用于完成从硬件到操作系统的过度。

Uboot 启动流程I.Uboot启动过程Uboot启动过程主要分为7块:1.CPU初始化:设置CPU工作模式与工作频率2.时钟、串口、内存初始化3.划分内存:分配堆、栈,设置环境变量位置、Uboot自身代码位置、指定程序代码入口4.根据Uboot启动选项将自身加载至内存5.加载环境变量6.初始化flash pci以及网口等7.进入命令行或者根据环境变量启动Linux的kernelUboot的启动过程中会有两大步骤,一部分是汇编代码部分,一部分是C代码部分,由于运行C代码部分需要配置堆栈所以前一部分初始化主要由汇编语言完成。

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启动过程分析

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 命令详解

u-boot 技术文档1.U boot 命令详解1.1查看帮助命令使用help 或者?1.2环境变量打印环境变量:printenv设置环境变量:setenv(不会保存)保存环境变量:saveenv这个时候就有了1.3nandflash命令使用nand查看nandflash 所有指令擦除nand erase1.4norflash命令查看Flash信息命令: flinfo加/解写保护命令: protect擦除命令: erase1.5内存命令nm1.5USB指令使用help usb 查看usb具体指令使用usb 启动使用usb tree查看信息f atls usb 0 罗列u盘信息1.5.1实例演练usb指令烧写1.6实例演练ftp指令烧写环境变量中体现了开发板上的IP地址为192.168.0.2,网关为192.168.0.1,要求电上的tftp 服务器的IP为192.168.0.1;运行电脑上tftp服务器,指定好根目录,将内核和根文件系统放在根目录下。

注:线接上后,电脑上的本地连接可能是显示网络电缆没插好,这很正常!在使用过程中它们会自动去连接!<2>分别下载内核和根文件系统到内存0x30008000开始的空间先检查坏块nand bad再擦除坏块清理某个区域0x560000 0x3b22c00将根文件系统加载到0x30008000然后再将根文件系统写到0x560000 0x3b22c00这个位置然后重启:重复上面的步骤:nand erase 0x60000 0x267000将内核文件保存到0x60000 0x267000这块区域运行1.8系统重启指令2.U boot 内核移植在cpu/arm920t/start.S中添加以下代码在修改并添加为以下代码在include/configs/mini2440.h修改为如下:将以下代码修改为:将以下代码修改为:将以下代码修改为:在drivers/mtd/nand/s3c2410_nand.h 在最后下面代码上添加如下带码:。

uboot启动代码详细讲解

uboot启动代码详细讲解

·1 引言在专用的嵌入式板子运行 GNU/Linux 系统已经变得越来越流行。

一个嵌入式 Linux 系统从软件的角度看通常可以分为四个层次:1. 引导加载程序。

固化在固件(firmware)中的 boot 代码,也就是 Boot Loader,它的启动通常分为两个阶段。

2. Linux 核。

特定于嵌入式板子的定制核以及核的启动参数。

3. 文件系统。

包括根文件系统和建立于 Flash 存设备之上文件系统,root fs。

4. 用户应用程序。

特定于用户的应用程序。

有时在用户应用程序和核层之间可能还会包括一个嵌入式图形用户界面。

常用的嵌入式 GUI 有:MicroWindows 和 MiniGUI 等。

引导加载程序是系统加电后运行的第一段软件代码。

回忆一下 PC 的体系结构我们可以知道,PC 机中的引导加载程序由 BIOS(其本质就是一段固件程序)和位于硬盘 MBR 中的 OS Boot Loader(比如,LILO 和 GRUB 等)一起组成。

BIOS 在完成硬件检测和资源分配后,将硬盘 MBR 中的 Boot Loader 读到系统的 RAM 中,然后将控制权交给 OS Boot Loader。

Boot Loader 的主要运行任务就是将核映象从硬盘上读到 RAM 中,然后跳转到核的入口点去运行,也即开始启动操作系统。

而在嵌入式系统中,通常并没有像 BIOS 那样的固件程序(注,有的嵌入式 CPU 也会嵌一段短小的启动程序),因此整个系统的加载启动任务就完全由 Boot Loader 来完成。

比如在一个基于 ARM7TDMI core 的嵌入式系统中,系统在上电或复位时通常都从地址0x00000000 处开始执行,而在这个地址处安排的通常就是系统的 Boot Loader 程序。

·2 bootloader简介简单地说,Boot Loader (引导加载程序)就是在操作系统核运行之前运行的一段小程序,它的作用就是加载操作系统,它是系统加电后运行的第一段软件代码。

Uboot之hush方式解析用户命令

Uboot之hush方式解析用户命令

uboot 命令解析流程简析uboot正常启动后,会调用main_loop(void)函数,进入main_loop()之后,如果在规定的时间(CONFIG_BOOTDELAY)内,没有检查到任何按键事件的发生,就会去加载OS,并启动系统,比如把linux内核压缩镜像从nand flash中读到sdram ,然后执行它。

如果在CONFIG_BOOTDELAY时间内,用户按下键盘上的任意一个按键,uboot 就会进入与用户交互的状态。

如果用户在配置文件中定义了CONFIG_SYS_HUSH_PARSER,就会通过parse_file_outer(),去接收并解析用户命令,否则进入一个for(;;)循环中,通过readline (CONFIG_SYS_PROMPT)接收用户命令,然后调用run_command(cmd,flag)去解析并执行命令。

代码如下:void main_loop(void){..............................#ifdef CONFIG_SYS_HUSH_PARSERparse_file_outer();/* This point is never reached */for (;;);#elsefor (;;){#ifdef CONFIG_BOOT_RETRY_TIMEif (rc >= 0) {/* Saw enough of a valid command to* restart the timeout.*/reset_cmd_timeout();}#endiflen = readline (CONFIG_SYS_PROMPT);printf("after readline:%d\n",len);flag = 0; /* assume no special flags for now */if (len > 0)strcpy (lastcommand, console_buffer);else if (len == 0)flag |= CMD_FLAG_REPEAT;#ifdef CONFIG_BOOT_RETRY_TIMEelse if (len == -2) {/* -2 means timed out, retry autoboot*/puts ("\nTimed out waiting for command\n");# ifdef CONFIG_RESET_TO_RETRY/* Reinit board to run initialization code again */do_reset (NULL, 0, 0, NULL);# elsereturn; /* retry autoboot */# endif}#endifif (len == -1)puts ("<INTERRUPT>\n");elserc = run_command (lastcommand, flag);.....................................}如果定义了CONFIG_SYS_HUSH_PARSER,命令接收和解析讲采用busybox 中的hush(对应hush.c)工具来实现,与uboot原始的命令解析方法相比,该工具更加智能。

海思uboot启动流程详细分析(一)

海思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控制,⼀般不需要打开。

uboot 代码运行流程

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启动过程--详细版的完全分析

(一)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启动分析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处继续执行。

4.3.1U-Boot代码结构分析

4.3.1U-Boot代码结构分析

4.3.1U-Boot代码结构分析4.3 Bootloader之U-BootU-Boot是在PPC-Boot的基础上进化⽽来的⼀个开放源码的嵌⼊式BootROM程序,本⼩节将使⽤1.1.4版本的代码来分析U-Boot的代码结构,以及如何将它移植到基于S3C2410X的开发板上来。

4.3.1 U-Boot代码结构分析U-Boot4-9所⽰。

board:这个⽬录存放了所有U-Boot⽀持的⽬标板的⼦⽬录,如board/smdk2410/*就和我们的开发平台fs2410相类似。

要将U-Boot移植到⾃⼰的S3C2410X⽬标板上,必须参考这个⽬录下的内容,⽐如对Flash 以及Flash宽度和⼤⼩的定制等就要修改其中的flash.c。

cpu:这个⽬录存放了U-Boot⽀持的CPU类型,因为我们的开发平台是S3C2410X,所以只关⼼cpu/arm920t,CPU相关的⽂件主要是初始化⼀个执⾏环境,包括中断的初始化;start.S是整个u-boot.bin ⽬标可执⾏代码的第⼀段代码,它们是从Flash开始运⾏的,其主要⼯作就是对整个U-Boot⽬标代码的重定位,即将U-Boot转移到内存中去运⾏。

common:这个⽬录存放了U-Boot的⼀些公共命令的实现,像那些以cmd_*.c为名字的⽂件就是对应U-Boot的每个命令的实现代码,我们通常关⼼cmd_boot.c和cmd_bootm.c(它们和内核的引导相关)。

drivers:这个⽬录中存放了各种外设接⼝的驱动程序。

fs:这个⽬录中存放了U-Boot⽀持的⽂件系统。

lib_arm:这个⽬录存放了ARM平台公共的接⼝代码。

include:这个⽬录存放头⽂件的公共⽬录,其中的include/configs/smdk2410.h定义了所有和S3C2410X 相关的资源的配置参数,我们往往只需修改这个⽂件就可以配置⽬标板的参数,如波特率、引导参数、物理内存映射等。

ubootmmc命令详解Nandflashuboot命令详解

ubootmmc命令详解Nandflashuboot命令详解

ubootmmc命令详解Nandflashuboot命令详解
md指令
uboot下输⼊指令md,会提⽰md的⽤法,memory display,即内存显⽰。

b:8位
w:16位
l:32位(默认值)
⽰例:
上述0x10000000是要显⽰内存的那个地址,后⾯的数字是输出的个数,注意是16进制的。

直接输⼊md来显⽰,默认是以32位为单位输出。

mw指令
uboot下输⼊指令mw,会提⽰md的⽤法,memory write,即向内存中写⼊数据。

b\w\l的意思同上,address是要写⼊内存的地址,value是要写⼊的值,count是从address开始要写⼊多少个数,这些都是16进制数。

⽰例:
⽰例
在0x10000000地址内存的起始位置写⼊0x12345678,打印出内存的输出。

发现低位0x78是写在低地址0x10000000,⾼位0x12是写在⾼地址0x10000003上,也就是常说的⼩端模式(little endian),简单记忆:低低模式,即低位在低地址。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 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函数。

相关文档
最新文档