UBoot启动分析.docx

上传人:b****7 文档编号:8974427 上传时间:2023-02-02 格式:DOCX 页数:22 大小:153.94KB
下载 相关 举报
UBoot启动分析.docx_第1页
第1页 / 共22页
UBoot启动分析.docx_第2页
第2页 / 共22页
UBoot启动分析.docx_第3页
第3页 / 共22页
UBoot启动分析.docx_第4页
第4页 / 共22页
UBoot启动分析.docx_第5页
第5页 / 共22页
点击查看更多>>
下载资源
资源描述

UBoot启动分析.docx

《UBoot启动分析.docx》由会员分享,可在线阅读,更多相关《UBoot启动分析.docx(22页珍藏版)》请在冰豆网上搜索。

UBoot启动分析.docx

UBoot启动分析

U-Boot启动流程(Linux内核)的分析

(一)

  前面一段时间一直在移植U-Boot,Linux内核和构建根文件系统,其中有些地方还不是很明白,现在回过头来,理解一下U-boot的启动流程,以及u-Boot是如何加载引导内核启动的。

这里的分析也都是以U-Boot-2009.08版本为基础的,可能会和以前的版本有所不同。

在这里也不打算一句句分析U-Boot的源码,只是想把U-Boot一步一步怎么最终能够加载Linux内核的过程,分析一下。

  首先,我们应该理解Bootloader是什么?

它有什么作用?

其实它就是系统上电后运行的和小段程序。

1BootLoader的概念

  在系统上电后,需要一段程序来进行初始化:

关闭WATCHDOG,改变系统时钟,初始化存储控制器,将更多的代码复制到内存中。

并将操作系统内核复制到内存中运行,这就段程序代码就叫做Bootloader。

没有一个Bootloader完全支持所有CPU,所以我们要想使用Bootloaser一般情况下要自己进行修改,我们可以增强Bootloader的功能,让它具有网络功能,可以通过NFS远程下载Linux内核和根文件系统,可以烧写Linux内核和根文件系统到NandFlash中,而这些功能对于最终的用户来说是没有什么意义的,它们看到的只是Bootloader引导Linux内核启动这一个功能,而其余的功能只对开发人员很有用处。

也就是说在开发期间这些功能是必不可少的。

(1)启动加载模式:

这种模式也称为“自主”模式。

也就是Bootloader从目标机上的某个固态存储设备上将操作系统加载到RAM中运行,整个过程并没有用户的介入,这种模式是在嵌入式产品发布里的通用模式。

(2)下载模式:

在这种模式下,目标机上的Bootloader将通过串口连接或网络连接等通信手段从主机下载文件,例如:

下载内核映像和根文件系统映像等。

从主机下载的文件通常首先被Bootloader保存到目标机的RAM中,然后再被Bootloader写到目标上的Flash类的固态存储设备中,Bootloader的这种模式是在在开发时使用的工作于这种模式的Bootloader通常都会向它的终端用户提供一个简单的命令行接口。

在嵌入式Linux系统中从软件的角度通常可以分为4个层次:

(1)引导加载程序,包括固化在固件中的boot代码(可选)和Bootloader两大部分。

   有些CPU在运行Bootloader之前运行一段固化的程序,比如x86结构的CPU就是先运行BIOS中的固件,然后才运行硬盘的第一个分区中的BootLoader。

在大多数的嵌入式系统中并没有固件,Bootloader是上电后第一个执行的程序。

(2)Linux内核

    嵌入式定制的内核以及启动参数,启动参数可以是Bootloader传递给内核的,也可以是内核默认的。

(3)文件系统

  包括根文件系统和建立于Flash内存设备之上的文件系统。

里面包括了Linux系统能够运行所必要的应用程序和库文件等。

比如可以给用户提供操作Linux的控制shell程序。

(4)用户应用程序

特定于用户的应用程序,它们也存储在文件系统中,有时在用户应用程序和内核层之间可以还会包括一个嵌入式图形用户界面。

2.Bootloader启动的两个阶段

 从固态存储设备上启动的Bootloader大多都是两阶段的启动过程,第一阶段使用汇编来实现。

它完成一些依赖于CPU体系结构的初始化,并调用第二阶段的代码,第二阶段则通常使用C语言来实现,这样可以实现更复杂的功能,而且代码会有更好的可读性和可移植性。

(1)Bootloader第一阶段的功能

  1)硬件设备初始化

  2)为加载Bootloader的第二阶段准备RAM空间。

  3)复制Bootloader的第二阶段代码到RAM空间中。

  4)设置好栈

  5)跳转到第二阶段代码的C入口点。

在第一阶段进行的硬件初始化一般包括:

关闭WATCHDOG,关中断,设置CPU的速度和时钟频率RAM初始化等。

这些不都是必需的。

(2)Bootloader第二阶段的功能

  1)初始化本阶段要使用的硬件设备

  2)检测系统内存映射

  3)将内核映像和根文件系映象从Flash望到RAM空间中

  4)为内核设置启动参数

  5)调用内核

将内核存放在适当的位置后,直接跳到它的入口点即可调用内核,调用内核之前,下列条件要满足

(1)CPU寄存器的设置

 R0=0.

 R1=机器类型ID;对于ARM结构的CPU,其机器类型ID在linux/arch/arm/tools/mach-types

 R2=启动参数标记列表在RAM中起始基地址

(2)CPU工作模式

    必须禁止中断(IRQs和FIQs)

    CPU必须为SVC模式

(3)Cach和MMU的设置

    MMU必须关闭

     指令Cach可以打开也可以关闭

    数据Cach必须关闭

U-Boot启动流程(Linux内核)的分析

(二)

    这一篇主要就是U-Boot的config.mk进行了分析。

如果要使用开发板board/,就先执行“make_config”命令进行配置,然后执行”makeall“,就可以生成如下3个文件。

U-boot.bin:

二进制可执行文件,它就是可以直接烧入ROM,NORFlash的文件

u-Boot:

ELF格式的可执行文件,

U-Boot.srec:

MotorlaS-Record格式的可执行文件

   对于S3C2410的开发板,执行”makesmdk2410_config“."makeall"后生成的U-Boot.bin可以烧入NORFlash中运行,启动后可以看到串口输出一些信息后进行控制界面。

1。

U-boot的配置过程

在顶层Makefile中可以看到如下代码:

...........

MKCONFIG    :

=$(SRCTREE)/mkconfig

........

smdk2410_config    :

    unconfig

    @$(MKCONFIG)$(@:

_config=)armarm920tsmdk2410samsungs3c24x0

 这是在根目录下的MAKEFILE文件中的两个语句,其中的MKCONFIG就是根目录下的mkconfi文件。

$(@:

_config=)的结果就是将”smdk2410_config“中的_config去掉,结果为“smdk2410”.所以“makesmdk2410_config”实际上就是执行如下命令:

 

./mkconfigsmdk2410armarm920tsmdk2410NULLs3c24x0

mkconfig的作用,在mkconfig文件开头第6行给出了它的用法

#Parameters:

TargetArchitectureCPUBoard[VENDOR][SOC]

  对于S3C2410S3C2440,它们被称为Soc(systmeonchip),上面除CPU外,还集成了包括UART,USB控制器,NANDFlash控制器等设备,称为片上外设。

                  下面看一下makeconfig的作用。

(1)确定开发板名称BOARD_NAME,相关代码如下:

APPEND=no    #Default:

Createnewconfigfile

BOARD_NAME=""    #Nametoprintinmakeoutput

while[$#-gt0];do

    case"$1"in

    --)shift;break;;

    -a)shift;APPEND=yes;;

    -n)shift;BOARD_NAME="${1%%_config}";shift;;

    *)break;;

    esac

done

  对于./mkconfigsmdk2410armarm920tsmdk2410NULLs3c24x0命令,其中没有"--","-a","-n"等符号,所以上面几行不会执行。

["${BOARD_NAME}"]||BOARD_NAME="$1"

执行完上面的这句后,BOADR_NAME的值等于第1个参数,即"s3ck2410"

(2)创建到平台开发板相关折头文件的链接

if["$SRCTREE"!

="$OBJTREE"];then//判断源代码目录和目标文件目录是否是一样

    mkdir-p${OBJTREE}/include

    mkdir-p${OBJTREE}/include2

    cd${OBJTREE}/include2

    rm-fasm

    ln-s${SRCTREE}/include/asm-$2asm

    LNPREFIX="../../include2/asm/"

    cd../include

    rm-rfasm-$2

    rm-fasm

    mkdirasm-$2

    ln-sasm-$2asm

else

    cd./include

    rm-fasm

    ln-sasm-$2asm

fi

  直接在源代码目录下编译时,条件不满足,将执行else分支的代码,在else分支中,进入include目录,删除asm文件,然后再次建立asm文件,并令它链接向asm-$2目录,即asm-arm。

rm-fasm-$2/arch//删除asm-$2/arch目录,即asm-arm/arch

if[-z"$6"-o"$6"="NULL"];then//$6="s3c24x0"不为空,也不为NULL,执行else分支

    ln-s${LNPREFIX}arch-$3asm-$2/arch//LNPREFIX为空,这个命令实际上等同于"ln-sarch-s3c24x0asm-arm/arch"

else

    ln-s${LNPREFIX}arch-$6asm-$2/arch

fi

if["$2"="arm"];then//重新建立/asm-arm/proc文件,并让它链接向proc-armv目录

    rm-fasm-$2/proc

    ln-s${LNPREFIX}proc-armvasm-$2/proc

fi

(3)创建顶层MAKEFILE包含的文件include/config.mk

#

#CreateincludefileforMake

#

echo"ARCH=$2">config.mk

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

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

["$5"]&&["$5"!

="NULL"]&&echo"VENDOR=$5">>config.mk

["$6"]&&["$6"!

="NULL"]&&echo"SOC=$6">>config.mk

  对于./mkconfigsmdk2410armarm920tsmdk2410NULLs3c24x0命令,上面几行创建的config.mk文件的内容如下:

ARCH=arm

CPU=arm920t

BOARD=smdk2410

SOC =s3c24x0

(4)创建开发板相关的头文件include/config.h

#

#Createboardspecificheaderfile

#

if["$APPEND"="yes"]    #Appendtoexistingconfigfile

then

    echo>>config.h

else

    >config.h        #Createnewconfigfile

fi

echo"/*Automaticallygenerated-donotedit*/">>config.h

echo"#include">>config.h

echo"#include">>config.h

exit0

APPEND维持原值"NO",所以config.h被重新建立,也就是执行echo"#include">>config.h

#include

总之,当你执行makesmdk2410_config,实际的作用就是执行./mkconfigsmdk2410armarm920tsmdk2410NULLs3c24x0,它将产生如下的

几种作用

(1)开发板的名称BOARD_NAME等于$1

(2)创建到平台,开发板相关的头文件的链接,如下所示

ln-sasm-$2asm

ln-sarch-$6asm-S2/arch

ln-sproc-armvasmn-$2/proc如果$2不是arm的话,此行没有

(3)创建顶层Makefile包含的incldue/config.mk,如下所示

ARCH=$2

CPU=$3

BOARD=$4

VENDOR=$$5 为空,或者NULL的话,些行没有

SOC=$6

(4)创建开发板相关的头文件include/config.h,如下所示

#include

  从上面执行完命令后的结果,可以看出来,如果要在board目录下新建一个开发板的目录,则在include/configs目录下也要建立一个文件.h,里面存放的就是开发板的配置信息。

3.U-Boot的编译,连接过程

#loadARCH,BOARD,andCPUconfiguration

include$(obj)include/config.mk

export    ARCHCPUBOARDVENDORSOC

#setdefaulttonothingfornativebuilds

ifeq($(HOSTARCH),$(ARCH))

CROSS_COMPILE?

=

endif

#loadotherconfiguration

include$(TOPDIR)/config.mk

这是根目录下的Makefile中与ARM相关的代码。

第一行中包含的config.mk文件,就是在第一开始配置过程中制作出来的include/conifg.mk文件,我们在一开始配置U-boot时执行过mkconfig。

mini2440时生成的文件,其中定义了ARCH,CPU,BOARD,SOC等。

4个变量的值为arm,arm920t,smdk2410,s3c24x0.我们在执行mkconfig。

mini2440时,其实执行的是如下的命令:

./mkconfigsmdk2410armarm920tsmdk2410NULLs3c24x0

  最后一句话include$(TOPDIR)/config.mk包含顶层目录的config.mk文件。

它根据上面4个变量的值确定了编译器。

编译选项等。

在顶层的config.mk中可以看到:

fdef    VENDOR

BOARDDIR=$(VENDOR)/$(BOARD)

else

BOARDDIR=$(BOARD)

endif

ifdef    BOARD

sinclude$(TOPDIR)/board/$(BOARDDIR)/config.mk    #includeboardspecificrules

endif

LDSCRIPT:

=$(TOPDIR)/board/$(BOARDDIR)/u-boot.lds

LDFLAGS+=-Bstatic-T$(obj)u-boot.lds$(PLATFORM_LDFLAGS)

ifneq($(TEXT_BASE),)

LDFLAGS+=-Ttext$(TEXT_BASE)

endif

  在u-boot-2009.08\board\samsung\smdk2410\config.mk中定义了“TEXT_BASE=0x33F80000”.所以最终结果是:

BOARDDIR为smdk2410;LDFLAGS中有“-T\cpu\arm920t\u-boot.lds-Ttext0x33f80000”.其中的-Ttext$(TEXT_BASE),这句指明了代码段的起始地址。

为什么是0x33F80000呢?

这是将NAND中Uboot拷贝到RAM中的起始地址,所以在代码拷贝到RAM之前不能使用绝对地址来寻址数据,只能用相对地址,在以下将用虚拟地址来指Uboot在RAM中的地址,也就是0x33F80000

继续分析MAKEFIle文件:

OBJS=cpu/$(CPU)/start.o

LIBS=lib_generic/libgeneric.a

LIBS+=lib_generic/lzma/liblzma.a

LIBS+=lib_generic/lzo/liblzo.a

LIBS+=$(shellif[-fboard/$(VENDOR)/common/Makefile];thenecho\

    "board/$(VENDOR)/common/lib$(VENDOR).a";fi)

LIBS+=cpu/$(CPU)/lib$(CPU).a

   从上面的第一行我们可以看到OBJS的第一个值为"cpu/$(CPU)/start.o",即"cpu/arm920t/start.o"。

下面的几行指定了LIBS变量,也就是平台,开发板相关的各个目录,通用目录下相应的库。

OBJSLIBS所代表的.o,.a文件构成了U-Boot,它们通过下面相应的源文件编译得到。

$(OBJS):

    depend

        $(MAKE)-Ccpu/$(CPU)$(if$(REMOTE_BUILD),$@,$(notdir$@))

$(LIBS):

    depend$(SUBDIRS)

        $(MAKE)-C$(dir$(subst$(obj),,$@))

   对于OBJS中的每个成员,都将进入cpu/$(CPU)目录编译它们,现在的OBJS为cpu/arm920t/start.o。

它由cpu/arm920t/start.S编译得到。

对于LIBS中的每个成员,都将进入相应的子目录执行"make命令"。

当所有的OBJS,LIBS所表示的.o.a文件都生成后,就剩最后的连接了,这对应MAKEFILE中的下面几行:

$(obj)u-boot.srec:

    $(obj)u-boot

        $(OBJCOPY)-Osrec$<$@

$(obj)u-boot.bin:

    $(obj)u-boot

        $(OBJCOPY)${OBJCFLAGS}-Obinary$<$@

$(obj)u-boot.ldr:

    $(obj)u-boot

        $(obj)tools/envcrc--binary>$(obj)env-ldr.o

        $(LDR)-T$(CONFIG_BFIN_CPU)-c$@$<$(LDR_FLAGS)

$(obj)u-boot.ldr.hex:

    $(obj)u-boot.ldr

        $(OBJCOPY)${OBJCFLAGS}-Oihex$<$@-Ibinary

$(obj)u-boot.ldr.srec:

    $(obj)u-boot.ldr

        $(OBJCOPY)${OBJCFLAGS}-Osrec$<$@-Ibinary

$(obj)u-boot.img:

    $(obj)u-boot.bin

        ./tools/mkimage-A$(ARCH)-Tfirmware-Cnone\

        -a$(TEXT_BASE)-e0\

        -n$(shellsed-n-e's/.*U_BOOT_VERSION//p'$(VERSION_FILE)|\

            sed-e's/"[    ]*$$/for$(BOARD)board"/')\

        -d$<$@

................

GEN_UBOOT=\

        UNDEF_SYM=`$(OBJDUMP)-x$(LIBBOARD)$(LIBS)|\

        sed-n-e's/.*\($(SYM_PREFIX)__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\

        cd$(LNDIR)&&$(LD)$(LDFLAGS)$$UNDEF_SYM$(__OBJS)\

            --start-group$(__LIBS)--end-group$(PLATFORM_LIBS)\

            -Mapu-boot.map-ou-boot

$(obj)u-boot:

    depend$(SUBDIRS)$(OBJS)$(LIBBOARD)$(LIBS)$(LDSCRIPT)$(obj)u-boot.lds

        $(GEN_UBOOT)

  先使用$(obj)u-boot:

规则连接得到ELF格式的U-Boot,最后转换为二进制格式u-boot.bin.S-Record格式u-Boot.srec.其中LDFLAGS确定了连接方式,也就是-T\cpu\arm920t\u-boot.lds-Ttext0x33f80000指定了程序的布局地址,\cpu\arm920t\U-Boot.lds文件如下:

UTPUT_FORMAT("elf32-littlearm","elf32-littlearm","elf32-littlearm")

OUTPUT_ARCH(arm)

ENTRY(_start)

SECTIONS

{

    .=0x00000000;

    .=ALIGN(4);

    .text:

    {

        cpu/arm920t/start.o

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 幼儿教育 > 唐诗宋词

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1