+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

看到不错的文章。不要加入收藏夹,想着以后有时间再看。由于非常有可能你以后再也不会看它们了。

想写总结的文章。不要想着等到以后有时间了再总结,由于非常有可能你以后更没有时间总结它们了。

——送给自己

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

要想知道一个程序的作用。最好的办法是分析程序的源代码。这一方法对了解u-boot的功能也适用,因此。我们首先看u-boot的源代码结构,然后依据源代码结构总结出u-boot的主要特性。

最后,依据配置、编译的过程,简单分析u-boot。

(一)

以u-boot-1.1.6为例分析文件夹结构例如以下:

1、平台相关的或开发板相关的文件夹:board、cpu、lib_i386类似

2、通用函数的文件夹:include、lib_generic、common

3、通用的设备驱动程序:disk、drivers、dtt、fs、nand_spl、net、post、rtc

4、u-boot工具、演示样例程序、文档:doc、example、tools

u-boot顶层文件夹说明

文件夹 特性 解释说明
board 开发板相关 相应不同配置的电路板(即使CPU同样),比方smdk2410等
cpu 平台相关 相应不同的CPU,如arm920t、i386等。
lib_i386 平台相关 某一架构下通用的文件
include 通用函数 头文件和开发板配置文件,开发板的配置文件都放在include/configs文件夹下
lib_generic 通用函数 须要通用的库函数。比方printf等
common 通用函数 通用函数,多是对下一层驱动程序的进一步封装
disk 通用设备驱动程序 硬盘接口程序
drivers 通用设备驱动程序

各类详细设备的驱动程序
dtt 通用设备驱动程序

数字温度測量或者传感器的驱动
fs 通用设备驱动程序

文件系统
nand_spl 通用设备驱动程序

u-boot一般从ROM、NORFLASH等设备启动。如今開始支持NAND Flash启动
net 通用设备驱动程序

各种网络协议
post 通用设备驱动程序

上电自检程序
rtc 通用设备驱动程序

实时时钟的驱动
doc 文档 开发、使用文档
example 演示样例程序 一些測试程序。能够使用u-boot下载后执行
tools 工具 制作S-Record、u-boot格式映像的工具,如mkimage

从上表中u-boot文件夹的分析能够看出u-boot的一些特性:支持多种嵌入式操作系统内核,如Linux、Vxworks等;支持多个处理器系列。如PowerPC、ARM、x86等;丰富的设备驱动源代码,如串口、SDRAM、Flash、以太网等;支持NFS挂载、RAMDISK形式的根文件系统、从Flash中引导压缩或非压缩系统内核;支持目标板环境变量多种存储方式。如Flash等。CRC32校验、上电自检功能等。



u-boot中各文件夹间也是层次结构的,这有助于在移植过程中为我们须要改动哪些文件提供信息。由下图能够知道。仅仅需改动board、cpu、lib_xxx文件夹下的文件。就可以完毕移植过程。假设想要加入其它的命令等,则须要改动其它文件。

lib_generic    common
post    net    fs   disk
dtt      nand_spl   rtc   drivers
board   cpu  lib_xxx



(二)配置

上一篇的u-boot概述中配置u-boot时使用了命令:make 100ask24x0_config命令。

运行该命令时运行Makefile中的例如以下一行规则:

100ask24x0_config	:	unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t 100ask24x0 NULL s3c24x0

该规则解释为:

100ask24x0_config	:	unconfig
mkconfig 100ask24x0 arm arm920t 100ask24x0 NULL s3c24x0

因此配置过程。我们能够分析根文件夹下的mkconfig文件。从而了解配置过程,做了哪些工作。逐行分析例如以下:

#!/bin/sh -e

# Script to create header files and links to configure
# U-Boot for a specific board.
#
# Parameters: Target Architecture CPU Board [VENDOR] [SOC]
#
# (C) 2002-2006 DENX Software Engineering, Wolfgang Denk <wd@denx.de>
# APPEND=no # Default: Create new config file
BOARD_NAME="" # Name to print in make output mkconfig 100ask24x0 arm arm920t smdk2410 NULL s3c24x0
$0 $1 $2 $3 $4 $5 $6 while [ $# -gt 0 ] ; do <span style="color:#ff6666;">/*$ # :保存程序命令行參数的数目*/</span>
case "$1" in
--) shift ; break ;;
-a) shift ; APPEND=yes ;;
-n) shift ; BOARD_NAME="${1%%_config}" ; shift ;;
*) break ;;
esac
done [ "${BOARD_NAME}" ] || BOARD_NAME="$1" <span style="color:#ff6666;">/*由于上面定义了BOARD_NAME="",所以该句得到结果为BOARD_NAME=100ask24x0*/
</span>
[ $# -lt 4 ] && exit 1
[ $# -gt 6 ] && exit 1 <span style="color:#ff6666;">/*$#是參数的个数。此处$#=6。所以这两句都不会运行到exit 1语句*/</span> echo "Configuring for ${BOARD_NAME} board..."
<span style="color:#ff6666;">/*此句便是运行make 100ask24x0_config时显示的那条语句:Configuring for 100ask24x0 board...*/</span>
#
# Create link to architecture specific headers
#
<span style="color:#ff6666;">/*查看Makefile可知。
*OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR))
*SRCTREE := $(CURDIR)
*所以if语句不运行,而是运行以下的else语句
*/</span>
if [ "$SRCTREE" != "$OBJTREE" ] ; then
mkdir -p ${OBJTREE}/include
mkdir -p ${OBJTREE}/include2
cd ${OBJTREE}/include2
rm -f asm
ln -s ${SRCTREE}/include/asm-$2 asm
LNPREFIX="../../include2/asm/"
cd ../include
rm -rf asm-$2
rm -f asm
mkdir asm-$2
ln -s asm-$2 asm
else
cd ./include
rm -f asm
ln -s asm-$2 asm <span style="color:#ff6666;">/*删除asm文件。然后再次建立asm文件,并令它链接向asm-$2文件夹。即asm-arm文件夹*/</span>
fi rm -f asm-$2/arch <span style="color:#ff6666;">/*删除asm-$2/arch文件,即asm-arm/arch文件*/</span> if [ -z "$6" -o "$6" = "NULL" ] ; then <span style="color:#ff6666;">/* -z string表示string为null $6也不是NULL,因此运行else分支*/</span>
ln -s ${LNPREFIX}arch-$3 asm-$2/arch
else
ln -s ${LNPREFIX}arch-$6 asm-$2/arch <span style="color:#ff6666;">/*由于LNPREFIX为空,该句为ln -s arch-s3c24x0 asm-arm/arch*/</span>
fi if [ "$2" = "arm" ] ; then
rm -f asm-$2/proc
ln -s ${LNPREFIX}proc-armv asm-$2/proc <span style="color:#ff6666;">/*又一次建立asm-arm/proc文件。并让它链接向proc-armv文件夹*/</span>
fi #
# Create include file for Make
#
<span style="color:#ff6666;">/*
*创建config.mk文件
*ARCH = arm
*CPU = arm920t
*BOARD= smdk2410
*SOC = s3c24x0
*/</span>
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 #
# Create board specific header file
#
<span style="color:#ff6666;">/*创建config.h文件*/</span>
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 exit 0

总结配置的作用有以下4点:

1、开发板名称BOARD_NAME等于$1

2、创建到平台/开发板相关的头文件的链接。例如以下所看到的

	ln -s asm-$2 asm
ln -s arch-$6 asm-$2/arch
ln -s proc-armv asm-$2/proc

3、创建顶层Makefile包括的文件include/config.mk

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

(三)编译、链接

既然在编译之前必须经过上面的配置过程,那么配置过程一定为编译过程提供了某些东西。否则的话,我们直接编译就能够了。那么。上面配置过程生成的文件、改动的地方是怎样在编译过程中体现的呢。

事实上,这在Makefile文件里有所体现。

如:

include $(OBJTREE)/include/config.mk  <span style="color:#ff6666;">//包括了配置过程中宏生成的include/config.mk文件</span>
export ARCH CPU BOARD VENDOR SOC
include $(TOPDIR)/config.mk <span style="color:#ff6666;">//包括了配置过程中生成的顶层的config.mk文件</span>

配置完毕后,运行make命令就可以链接。运行make。我们运行的是Makefile里的make all语句,它的命令例如以下:

ALL = $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND)

all:		$(ALL)

$(obj)u-boot.hex:	$(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@ $(obj)u-boot.srec: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O srec $< $@ $(obj)u-boot.bin: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@ $(obj)u-boot.img: $(obj)u-boot.bin
./tools/mkimage -A $(ARCH) -T firmware -C none \
-a $(TEXT_BASE) -e 0 \
-n $(shell sed -n -e 's/.*U_BOOT_VERSION//p' $(VERSION_FILE) | \
sed -e 's/"[ ]*$$/ for $(BOARD) board"/') \
-d $< $@ $(obj)u-boot.dis: $(obj)u-boot
$(OBJDUMP) -d $< > $@ $(obj)u-boot: depend version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT)
<span style="color:#ff6666;">UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\
cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \
--start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \
-Map u-boot.map -o u-boot

从执行结果反看Makefile的执行:

UNDEF_SYM=</span>`arm-linux-objdump -x lib_generic/libgeneric.a board/100ask24x0/lib100ask24x0.a cpu/arm920t/libarm920t.a cpu/arm920t/s3c24x0/libs3c24x0.a lib_arm/libarm.a fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a net/libnet.a disk/libdisk.a rtc/librtc.a dtt/libdtt.a drivers/libdrivers.a drivers/nand/libnand.a drivers/nand_legacy/libnand_legacy.a drivers/usb/libusb.a drivers/sk98lin/libsk98lin.a common/libcommon.a |sed  -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\
cd /work/system/u-boot-1.1.6</span> && arm-linux-ld -Bstatic -T /work/system/u-boot-1.1.6/board/100ask24x0/u-boot.lds -Ttext 0x33F80000  $UNDEF_SYM cpu/arm920t/start.o \
<span style="color:#ff6666;">--start-group</span> lib_generic/libgeneric.a board/100ask24x0/lib100ask24x0.a cpu/arm920t/libarm920t.a cpu/arm920t/s3c24x0/libs3c24x0.a lib_arm/libarm.a fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a net/libnet.a disk/libdisk.a rtc/librtc.a dtt/libdtt.a drivers/libdrivers.a drivers/nand/libnand.a drivers/nand_legacy/libnand_legacy.a drivers/usb/libusb.a drivers/sk98lin/libsk98lin.a common/libcommon.a --end-group -L /work/tools/gcc-3.4.5-glibc-2.3.6/lib/gcc/arm-linux/3.4.5 -lgcc \
<span style="color:#ff6666;">-Map u-boot.map -o u-boot

总结编译流程:

1、编译cpu/$(CPU)/start.S。

2、然后,对于平台/开发板相关的每一个文件夹、每一个通用文件夹都使用它们各自的Makefile生成对应的库。

3、将1、2步骤生成的.o、.a文件依照board/$(BOARDDIR)/config.mk文件里指定的代码段起始地址、board/$(BOARDDIR)/U-Boot.lds链接脚本进行链接。

4、第3步得到的ELF格式的U-Boot,后面Makefile还会将它转换为二进制格式S-Record格式。

(四)逐行分析链接文件

/*
* (C) Copyright 2002
* Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/ OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") <span style="color:#ff6666;">/*定义3种输出文件的格式(大小端)*/</span>
/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
OUTPUT_ARCH(arm) <span style="color:#ff6666;">/*设置输出文件的machine architecture(体系结构)*/</span>
ENTRY(_start) <span style="color:#ff6666;">/*将符号_start的值设置成入口地址*/</span>
SECTIONS
{
. = 0x00000000; . = ALIGN(4);
.text :
{
cpu/arm920t/start.o (.text)
board/100ask24x0/boot_init.o (.text)
*(.text)
} <span style="color:#ff6666;">/*将start.o boot_init.o 以及除此之外的全部(*符号代表随意输入文件)
*输入文件的.text section 以4字节对齐的方式合并成一个.text section,
*该section的地址由定位器符号的值指定,即为0x00000000
*/</span> . = ALIGN(4);
.rodata : { *(.rodata) }
<span style="color:#ff6666;">/*将全部输入文件的仅仅读数据段.rodata section 以4字节对齐的方式
*合并成一个.rodata section,该section的地址为
*0x00000000+.text section的大小
*/</span>
. = ALIGN(4);
.data : { *(.data) }
<span style="color:#ff6666;">/*将全部输入文件的数据段.data section 以4字节对齐的方式
*合并成一个.data section,该section的地址为
*0x00000000+.text section的大小+.rodata section的大小
*/</span>
. = 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 = .;
}



參考:韦东山《嵌入式Linux应用开发全然手冊》

    Linux下的lds链接脚本基础



















版权声明:本文博客原创文章,博客,未经同意,不得转载。

u-boot学习(两):u-boot简要分析的更多相关文章

  1. Spring Boot学习笔记---Spring Boot 基础及使用idea搭建项目

    最近一段时间一直在学习Spring Boot,刚进的一家公司也正好有用到这个技术.虽然一直在学习,但是还没有好好的总结,今天周末先简单总结一下基础知识,等有时间再慢慢学习总结吧. Spring Boo ...

  2. spring boot 学习(二)spring boot 框架整合 thymeleaf

    spring boot 框架整合 thymeleaf spring boot 的官方文档中建议开发者使用模板引擎,避免使用 JSP.因为若一定要使用 JSP 将无法使用. 注意:本文主要参考学习了大神 ...

  3. spring boot 学习(六)spring boot 各版本中使用 log4j2 记录日志

    spring boot 各版本中使用 log4j2 记录日志 前言 Spring Boot中默认日志工具是 logback,只不过我不太喜欢 logback.为了更好支持 spring boot 框架 ...

  4. Spring Boot学习笔记——Spring Boot与ActiveMQ的集成

    Spring Boot对JMS(Java Message Service,Java消息服务)也提供了自动配置的支持,其主要支持的JMS实现有ActiveMQ.Artemis等.这里以ActiveMQ为 ...

  5. Spring Boot学习笔记——Spring Boot与Redis的集成

    一.添加Redis缓存 1.添加Redis起步依赖 在pom.xml中添加Spring Boot支持Redis的依赖配置,具体如下: <dependency> <groupId> ...

  6. Spring Boot学习笔记——Spring Boot与MyBatis的集成(项目示例)

    1.准备数据库环境 # 创建数据库 CREATE DATABASE IF NOT EXISTS zifeiydb DEFAULT CHARSET utf8 COLLATE utf8_general_c ...

  7. Spring Boot学习 之 Spring Boot Actuator(一)

    Spring Boot版本:2.1.4.RELEASE 启用: spring-boot-actuator模块提供了一系列的用于监控的端点.最简单的开启这个功能的方法就是,在pom文件中添加如下的依赖. ...

  8. spring boot 学习10 定义springboot的两种方法

    使用spring boot的两种方法: A:继承spring-boot-starter-parent项目 这种方式很简单,只需要在POM里面添加parent父工程即可. B: 如果你不喜欢继承spri ...

  9. 转载:spring boot学习

    Spring Boot学习 Spring Boot是为了简化Spring应用的创建.运行.调试.部署等而出现的,使用它可以做到专注于Spring应用的开发,而无需过多关注XML的配置. 简单来说,它提 ...

随机推荐

  1. HihoCoder——Trie树

    本文出自:http://blog.csdn.net/svitter 原题:http://hihocoder.com/contest/hiho2/problem/1 题解:使用Trie树..基础题目.一 ...

  2. RecyclerView0基于使用

    (转载请注明出处:http://www.kennethyo.me/post/android/recyclerviewchu-ji-shi-yong) RecyclerView是Android在v7包中 ...

  3. SharePoint 2013 中将 HTML文件转换为母版页

    原文:SharePoint 2013 中将 HTML文件转换为母版页 SharePoint 2013提供了很多新功能,下面我们看看将Html页面,转换为母版页的功能.这个功能更加方便设计人员设计母版页 ...

  4. unity3d 依据指定的Assets下的目录路径 返回这个路径下的全部文件名称

    using UnityEngine; using System.Collections; using System.Collections.Generic; using System.IO; < ...

  5. Java虚拟机参数设置(转)

    今天在加载一幅图片时,eclipse报出如下错误: “Exception in thread "main" java.lang.OutOfMemoryError: Java hea ...

  6. [DB][mybatis]MyBatis mapper文件引用变量#{}与${}差异

    MyBatis mapper文件引用变量#{}与${}差异 默认,使用#{}语法,MyBatis会产生PreparedStatement中.而且安全的设置PreparedStatement參数,这个过 ...

  7. JavaScript之对象序列化详解

    一.什么是对象序列化? 对象序列化是指将对象的状态转换为字符串(来自我这菜鸟的理解,好像有些书上也是这么说的,浅显易懂!): 序列化(Serialization)是将对象的状态信息转换为可以存储或传输 ...

  8. 阐述linux IPC(两):基于socket进程间通信(下一个)

    [版权声明:尊重原创.转载请保留源:blog.csdn.net/shallnet 要么 .../gentleliu,文章学习交流.请勿用于商业用途]     其中两个进程通信,有两个过程,以彼此的过程 ...

  9. ASP.NET MVC+EF框架+EasyUI实现权限管理系列(18)-过滤器的使用和批量删除数据(伪删除和直接删除)

    原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(18)-过滤器的使用和批量删除数据(伪删除和直接删除) ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇)   ...

  10. NYoj The partial sum problem(简单深搜+优化)

    题目链接:http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=927 代码: #include <stdio.h> #include & ...