u-boot的启动、编译过程和命令添加

MCU:s5pv210

开发板:unsp210

u-boot:1.3.4

一、简介

U-Boot是一种支持多架构,多操作系统的Bootloader(启动引导程序)

u-boot目前最新版本是:http://ftp.denx.de/pub/u-boot/

二、启动过程

嵌入式Bootloader的启动过程可以分为单阶段(Single-Stage)和多阶段(Multi-Stage)

通常多阶段的Bootloader能够提供更复杂的功能,及更好的可读性和移植性。

从外部存储设备上启动的Bootloader大多是两阶段的启动过程

第一阶段通常用汇编实现,完成一些依赖于CPU体系结构的初始化,并调用第二阶段代码

第二阶段通常用C语言实现,完成体系结构之外的功能,主要提供多种复杂命令并引导操作系统

u-boot两阶段入口代码位置为:

第一阶段位于:cpu/s5pc11x/start.S

第二阶段位于:lib_arm/board.c

三、启动流程分析

以s5pv210为例分析一下u-boot的启动流程:

上电之后,从iROM(BL0)里面执行出厂时固化的代码,获取6位OM状态,检测相应的控制器(controller),选择启动方式(ps:有的芯片也可以通过设置优先级的方式省去拨码开关,如s5p6818设置启动方式SD->USB->nand)。

通过控制器选择对应的启动设备(SD/USB/Nand/MMC/NOR),从中读取数据,将其中的BL1拷贝到芯片内部iRAM(BL1),开始从BL1运行,BL1运行结束后将BL2拷贝到SDRAM,在SDRAM里面运行BL2,BL2运行结束后将内核拷贝到SDRAM,运行内核,挂载根文件系统...

BL0:获取OM状态,选择控制器,拷贝外部BL1到内部BL1(iRAM)

BL1;把BL2拷贝到SDRAM,初始化SDRAM Controller

BL2;把OS拷贝到SDRAM

为什么把BL1拷贝到iRAM,BL2拷贝到SDRAM?

因为第一阶段要初始化SDRAM Controller才能使用外存SDRAM,所以第一阶段必须在内部进行,第二阶段如果芯片内部存储空间够大的话也可以在内部运行,但一般都是在外部运行,BL2运行结束后启动内核,内核直接从Bootloader的地址启动,覆盖Bootloader的地址空间,Bootloader被擦除

内核传参过程:

传递给内核的参数由多个结构体组成(面向对象),各结构体放在一段连续的内存空间,起始地址为0x3000_0100每一个结构体代表一条信息并首尾相连,内核引导起来以后,将从指定内存按照同样的数据结构将数据取出。

四、两个阶段的任务

u-boot第一阶段完成任务:

涉及两个文件:

u-boot/cpu/s5pc11x/start.S

u-boot/board/sumsung/unsp210/lowlevel_init.S

1、禁用看门狗

lowlevel_init.S(line:61)

/* Disable Watchdog */

ldr r0, =ELFIN_WATCHDOG_BASE /* 0xE2700000 */

mov r1, #0

str r1, [r0]

2、关中断

start.S(line:141)

reset:

/*

* set the cpu to SVC32 mode and IRQ & FIQ disable

*/

@;mrs r0,cpsr

@;bic r0,r0,#0x1f

@;orr r0,r0,#0xd3

@;msr cpsr,r0

msr cpsr_c, #0xd3 @ I & F disable, Mode: 0x13 - SVC

3、初始化系统时钟

lowlevel_init.S(line:122)

/* init system clock */

bl system_clock_init

lowlevel_init.S(line:209)

/*

* system_clock_init: Initialize core clock and bus clock.

* void system_clock_init(void)

*/

system_clock_init:

ldr r0, =ELFIN_CLOCK_POWER_BASE @0xe0100000

/* Set Mux to FIN */

ldr r1, =0x0

str r1, [r0, #CLK_SRC0_OFFSET]

ldr r1, =APLL_LOCKTIME_VAL

str r1, [r0, #APLL_LOCK_OFFSET]

4、设置异常向量表(用到中断的情况下设置)

start.S(line:56)

.globl _start

_start: b reset

ldr pc, _undefined_instruction

ldr pc, _software_interrupt

ldr pc, _prefetch_abort

ldr pc, _data_abort

ldr pc, _not_used

ldr pc, _irq

ldr pc, _fiq

5、内存控制器配置

lowlevel_init.S(line:125)

/* Memory initialize */

bl mem_ctrl_asm_init

/cpu/s5pc11x/s5pc110/cpu_init.S(line:5)

.globl mem_ctrl_asm_init

mem_ctrl_asm_init:

......

6、初始化调试指示灯(可选)

lowlevel_init.S(line:99)

/* PS_HOLD pin(GPH0_0) set to high */

ldr r0, =(ELFIN_CLOCK_POWER_BASE + PS_HOLD_CONTROL_OFFSET)

ldr r1, [r0]

orr r1, r1, #0x300

orr r1, r1, #0x1

str r1, [r0]

7、初始化UART,用于开发调试(可选)

lowlevel_init.S(line:129)

/* for UART */

bl uart_asm_init

lowlevel_init.S(line:355)

/*

* uart_asm_init: Initialize UART in asm mode, 115200bps fixed.

* void uart_asm_init(void)

*/

uart_asm_init:

/* set GPIO(GPA) to enable UART */

@ GPIO setting for UART

ldr r0, =ELFIN_GPIO_BASE

ldr r1, =0x22222222

str   r1, [r0, #GPA0CON_OFFSET]

ldr     r1, =0x2222

str     r1, [r0, #GPA1CON_OFFSET]

8、从NAND、NOR或SD卡中复制代码到SDRAM

NAND:

start.S(line:337)

nand_boot:

mov r0, #0x1000

bl copy_from_nand

b after_copy

start.S(line:435)

/*

* copy U-Boot to SDRAM and jump to ram (from NAND or OneNAND)

* r0: size to be compared

* Load 1'st 2blocks to RAM because U-boot's size is larger than 1block(128k) size

*/

.globl copy_from_nand

copy_from_nand:

push {lr} /* save return address */

mov r9, r0

mov r9, #0x100 /* Compare about 8KB */

bl copy_uboot_to_ram

tst r0, #0x0

bne copy_failed

NOR:

start.S(line:355, 356)

nor_boot:

bl      read_hword

b       after_copy

/board/sumsung/unsp210/flash.c(line:590)

/*-----------------------------------------------------------------------

* Copy flash to memory

*/

void read_hword (void)

{

volatile u32 *buf = CFG_PHY_UBOOT_BASE;

volatile u32 *nor_base = CFG_FLASH_BASE;

memcpy ((void *)buf, (void *)nor_base, COPY_BL2_SIZE);

}

SD:

start.S(line:346~353)

mmcsd_boot:

#if DELETE

ldr     sp, _TEXT_PHY_BASE

sub     sp, sp, #12

mov     fp, #0

#endif

bl      movi_bl2_copy

b       after_copy

/cpu/s5pc11x/movi.c(line:19)

void movi_bl2_copy(void)

{

......

......

}

9、 初始化堆栈:start.S(line:389)

stack_setup:

#if defined(CONFIG_MEMORY_UPPER_CODE)

ldr sp, =(CFG_UBOOT_BASE + CFG_UBOOT_SIZE - 0x1000)

#else

ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot   */

sub r0, r0, #CFG_MALLOC_LEN /* malloc area                      */

sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo                        */

#if defined(CONFIG_USE_IRQ)

sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)

#endif

sub sp, r0, #12 /* leave 3 words for abort-stack    */

清除bss段:start.S(line:408)

clear_bss:

ldr r0, _bss_start /* find start of bss segment        */

ldr r1, _bss_end /* stop here                        */

mov r2, #0x00000000 /* clear                            */

10、跳转到start_armboot,进入Bootloader第二阶段

start.S(line:419, 421, 422)

ldr pc, _start_armboot

_start_armboot:

.word start_armboot

u-boot第二阶段完成任务:

涉及一个文件:/u-boot/lib_arm/board.c

1.开发板相关的初始化:

u-boot/lib_arm/board.c(483行)

#if defined(CONFIG_SMDKC110)

2.加载环境变量:

u-boot/lib_arm/board.c(650行)

/* initialize environment */

env_relocate ();

3.使能中断:

u-boot/lib_arm/board.c(705行)

/* enable exceptions */

enable_interrupts ();

4.主循环:

main_loop(756行)

/* main_loop() can return to retry autoboot, if so just run it again. */

for (;;) {

main_loop ();

}

->     s = getenv ("bootcmd");

->     parse_string_outer(s, FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP);

->     rcode = parse_stream_outer(&input, flag);

->     code = run_list(ctx.list_head);

->     rcode = run_list_real(pi);

->     rcode = run_pipe_real(pi);

->     if ((cmdtp = find_cmd(child->argv[i])) == NULL)

(common/hush.c  1679行)

->     rcode = (cmdtp->cmd)(cmdtp, flag,child->argc-i,&child->argv[i]);

(common/hush.c  1710行)

五、配置编译过程

以s5pv210开发板为例

u-boot的配置编译需要经过以下步骤:

1、在u-boot的根目录下执行:#make unsp210_config  //对应开发板配置

Makefile 会构建编译结构,如:架构、cpu、开发板、厂商、芯片、目录等,为下一步真正编译链接做准备。

2、修改include/configs/unsp210.h配置文件

3、在根目录下执行:make

根据以上两步产生编译和连接所需文件的信息

最终make完成,在根目录下将生成:

u-boot.bin   u-boot.dis   u-boot.map...

编译过程如下:

u-boot的根目录下执行:#make unsp210_config 打开Makefile在2581行找到

unsp210_config : unconfig

@$(MKCONFIG) $(@:_config=) arm s5pc11x unsp210 samsung s5pc110

@echo "TEXT_BASE = 0xc3e00000" > $(obj)board/samsung/unsp210/config.mk

可以去掉@符号让信息输出到屏幕

其中第一句的$(MKCONFIG)表示引用第101行指定的mkconfig文件路径

$(@:_config=)表示目标去掉_config

后面的是编译参数

第二句表示将信息输出到文件board/samsung/unsp210/config.mk

打开mkconfig看到第23行如下:

[ "${BOARD_NAME}" ] || BOARD_NAME="$1" 给BOARD_NAME赋值$1

继续往下执行mkconfig发现都是一些mkdir, rm, cd, ln命令,删除旧的链接建立新的文件链接

mkconfig第123行

echo "ARCH   = $2" >  config.mk

echo "CPU    = $3" >> config.mk

echo "BOARD  = $4" >> config.mk

将信息输出到include/config.mk文件中,在config.mk文件114行引用环境变量

mkconfig第134行

if [ "$APPEND" = "yes" ] # Append to existing config file

then

echo >> config.h

else

> config.h # Create new config file

fi

echo "/* Automatically generated - do not edit */" >>config.h

echo "#include <configs/$1.h>" >>config.h

添加平台头文件(unsp210.h)创建config.h加入"#include <configs/$1.h>"

链接过程:

链接地址定义在board/samsung/unsp210/config.mk中

链接脚本board/samsung/unsp210/u-boot.lds

/board/samsung/unsp210/config.mk被顶层config.mk包含并设置链接选项LDFLAGS(arm-linux-ld)

config.mk第198行

LDFLAGS += -Text $(TEXT_BASE)

这个TEXT_BASE就是Makefile第2583行的这句里

@echo "TEXT_BASE = 0xc3e00000" > $(obj)board/samsung/unsp210/config.mk

LDFLAGS在makefile链接时发挥作用

最终用OBJCOPY去掉ELF格式信息得到可以直接在裸机上执行的u-boot.bin

$(OBJCOPY)${OBJCFLAGS} -O binary $< [email protected]

六、命令添加

u-boot的每一个命令都是通过U_BOOT_CMD宏定义来实现的,这个宏在include/command.h头文件中

U_BOOT_CMD(name,maxargs,rep,cmd,usage,help)

每一个命令定义了一个cmd_tbl_t结构体,结构体包含的成员变量有:命令名称、最大参数个数、重复次数、命令执行函数、用法、帮助。

从控制台输入的命令都被送到common/command.c中的find_cmd()函数解释执行,根据匹配输入的命令,从列表中找出对应的命令结构体,并调用其回调处理函数完成命令处理,命令响应的过程,就是命令的查找与回调函数处理的过程

find_cmd()部分代码如下:

for(cmdtp=&__u_boot_cmd_start;cmdtp != &__u_boot_cmd_end;cmdtp++)

{

if(strncmp(cmd, cmdtp->name, len)==0)

{

if(len == strlen(cmdtp->name))

return cmdtp;

cmdtp_temp=cmdtp;

n_found++;

}

}

if(n_found==0){

return cmdtp_temp;

}

实现了输入部分命令可以代替全部命令的效果,如输入print和输入pri结果一样

原理:输入时用len保存命令长度,比较前len个长度的输入与命令,如果全部匹配直接返回命令结构体,如果部分匹配,存入临时结构体cmdtp_temp,并且n_found++,最后判断如果n_found==1则返回cmdtp_temp

怎样添加一个u-boot命令(三步)

假如要添加一个helloworld命令

1、在include/configs/unsp210.h中增加一项宏定义 这样通过改变宏定义的值(1打开或0关闭)进行选择性的编译

#define CONFIG_CMD_HELLOWORLD  1

2、在common/文件夹下建立cmd_helloworld.c文件

#include<common.h>

#include<command.h>

#ifdef CONFIG_CMD_HELLOWORLD

void helloworld(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])

{

int i=0;

for(i=0;i<argc;i++)

{

printf("Hello World!\n");

printf("argv[%d]=$s\n", i, argv[i]);

}

}

//命令名称、最大参数个数、重复次数、命令执行函数、用法、帮助

U_BOOT_CMD(hello,3,2,helloworld,"hello command","add u-boot command!\n");

#endif

3、在common/Makefile中增加一项

COBJS-y += cmd_helloworld.o

make重新下载u-boot.bin在命令行输入help和hello命令查看结果

原文地址:http://blog.51cto.com/13603157/2118481

时间: 2024-10-10 20:20:52

u-boot的启动、编译过程和命令添加的相关文章

gcc 编译过程及有关命令详解

用gcc编译.c文件流程 1 预处理阶段,输入c的源文件,编译器分析处理源代码文件中的各种宏指令,如"#ifdef,#endif,#include"等,进行去注释,头文件展开,宏替换等操作 .用户可以用 -E 参数让GCC在预处理结束后停止编译过程(gcc -E [source file(.c)] -o [output file(.i)]. 2 编译阶段,从高级语言转换为汇编语言,GCC在预处理后要检查代码规范,是否有语法错误.无误后翻译为汇编语言. GCC 的 -S 选项让GCC在进

第8章2节《MonkeyRunner源码剖析》MonkeyRunner启动运行过程-解析处理命令行参数

MonkeyRunnerStarter是MonkeyRunner启动时的入口类,因为它里面包含了main方法.它的整个启动过程主要做了以下几件事情: 解析用户启动MonkeyRunner时从命令行传输进来的参数: 因为MonkeyRunner需要根据指定的参数才能做事情,比如输入的一个需要执行的脚本.如果确实不知道任何参数的话它就会进入MonkeyRunner的交互模式,其实就是Jythong的交互模式,让用户可以边写代码边执行 启动AndroidDebugBridge: 其实就是启动ADB服务

第8章2节《MonkeyRunner源代码剖析》MonkeyRunner启动执行过程-解析处理命令行參数

MonkeyRunnerStarter是MonkeyRunner启动时的入口类,由于它里面包括了main方法.它的整个启动过程主要做了以下几件事情: 解析用户启动MonkeyRunner时从命令行传输进来的參数: 由于MonkeyRunner须要依据指定的參数才干做事情,比方输入的一个须要执行的脚本. 假设确实不知道不论什么參数的话它就会进入MonkeyRunner的交互模式,事实上就是Jythong的交互模式,让用户能够边写代码边执行 启动AndroidDebugBridge: 事实上就是启动

Linux系统GCC常用命令和GCC编译过程描述

前言: GCC 原名为 GNU C 语言编译器(GNU C Compiler),因为它原本只能处理 C语言.GCC 很快地扩展,变得可处理 C++.后来又 扩展能够支持更多编程语言,如Fortran.Pascal.Objective-C.Java.Ada.Go以及各类处理器架构上的汇编语言等,所以改 名GNU编译器套件(GNU Compiler Collection).(百度百科,想了解自己查询) 一.GCC程序的编译过程大概分四个阶段 预处理(Pre-Processing) 编译(Compil

2.4、uboot配置和编译过程详解

2.4.1.uboot主Makefile分析1 2.4.1.1.uboot version分析 (1)uboot版本号分为3个级别: VERSION:主版本号 PATCHLEVEL:次版本号 SUBLEVEL:再次版本号 EXTRAVERSION:另外附加的版本信息 这四个用.隔开共同构成了最终的版本号. (2)Makefile中版本号最终生成了一个变量U_BOOT_VERSION,这个变量记录了Makefile中配置的版本号 (3)include/version_autogenerated.h

#24 centos6(RHEL)系列操作系统的启动流程、与命令chkconfig、grub的使用

所有由rc脚本关闭或启动的链接文件的原文件都存在于/etc/rc.d/init.d,系统为了方便使用,为此目录创建了链接/etc/init.d 所有/etc/inid.d(/etc/rc.d/init.d)目录中的脚本执行方式: # /etc/init.d/srv_script {start|stop|restart|status} # service srv_script {start|stop|restart|status} chkconfig命令: chkconfig - updates

简单了解一下c编译过程

大一的时候,学习c语言,用的是VC6.0.用了1年多,到后来了解了Linux,知道了gcc编译器,开始使用gcc Hello.c -o a.out 这样的命令进行编译.后来又学了gcc的一些其他的命令,不同的命令可以编译出不同的目标代码.现在想想类似于VC这种IDE虽然方便,但是对于具体是怎样的一个过程就不得而知了.作为一个优秀的程序员怎么可以不了解这个过程呢. Gcc/g++ 在执行编译工作的时候,总共4步 1.预处理,生成.i的文件  (预处理器cpp) 2.将预处理后的文件转换成汇编语言,

3DSlicer源代码编译过程vs2008+windows xp [转]

一 下载QT源代码编译 1.  简述   在 Windows2000/xp/vista 下,安装 VS2008, QT 4.7.2 :并在 VS2008上建立 QT 的集成开发环境,利用 VS2008 开发环境开发,调试 QT 程序:2. 所需程序   VS2008以及VS2008Sp1                                  //  VS2008 的安装程序:   qt-everywhere-opensource-src-4.7.4.tar.gz          /

uboot主Makefile分析(t配置和编译过程详解)

1.编译uboot前需要三次make make distcleanmake x210_sd_configmake -j4 make distclean为清楚dist文件. make x210_sd_config  跳转执行mkconfig用来配置并生成config.mk(board/samsung/x210目录下为指定链接地址的与主uboot目录的config.mk不同) autuconfig.mk 2.框图 3.uboot主Makefile分析 3.1.uboot version确定(Make