ARM架构生成uImage过程

内核编译完成之后首先在顶层目录中生成vmlinux名称的原始ELF文件,接着在arch/arm/boot/Makefile文件中,使用objcopy工具,将vmlinux转化为Image镜像,用到的参数由变量OBJCOPYFLAGS和$(OBJCOPYFLAGS_$(@F)指定,makefile编译目标位于scripts/Makefile.lib文件中。

arch/arm/boot/Makefile

OBJCOPYFLAGS    :=-O binary -R .comment -S

$(obj)/Image: vmlinux FORCE
    $(call if_changed,objcopy)

arm64架构与arm架构不同,其指定了OBJCOPYFLAGS_Image变量,来规定objcopy使用的参数。

arch/arm64/boot/Makefile

OBJCOPYFLAGS_Image :=-O binary -R .note -R .note.gnu.build-id -R .comment -S

$(obj)/Image: vmlinux FORCE
    $(call if_changed,objcopy)

文件scripts/Makefile.lib中定义的objcopy命令。

# Objcopy
# ---------------------------------------------------------------------------

quiet_cmd_objcopy = OBJCOPY $@
cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@

压缩版vmlinux


其次,在得到Image文件后,内核对其进行压缩处理生成名称为vmlinux的文件,与最初的ELF格式的vmlinux不同,并且结果保存在arch/arm/boot/compressed目录下。生成过程由compressed下的代码完成。

arch/arm/boot/Makefile

$(obj)/compressed/vmlinux: $(obj)/Image FORCE
    $(Q)$(MAKE) $(build)=$(obj)/compressed $@

参见文件arch/arm/boot/compressed/Makefile,此目录下的编译文件除了本目录下的head.S、misc.c和decompress.c等文件,还需要用到arch/arm/boot/lib目录下的以下基础库函数文件:bswapsdi2.S、ashldi3.S和lib1funcs.S等。

HEAD    = head.o
OBJS    += misc.o decompress.o

targets       := vmlinux vmlinux.lds piggy_data piggy.o lib1funcs.o ashldi3.o bswapsdi2.o head.o $(OBJS)

$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.o \
        $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) $(ashldi3) $(bswapsdi2) $(efi-obj-y) FORCE
    @$(check_for_multiple_zreladdr)
    $(call if_changed,ld)
    @$(check_for_bad_syms)

以上所有的文件编译完成之后,由ld命令连接成压缩版的vmlinux文件。ld命令参见scripts/Makefile.lib文件中的LD目标。

scripts/Makefile.lib

# Linking
# ---------------------------------------------------------------------------

quiet_cmd_ld = LD      $@
cmd_ld = $(LD) $(LDFLAGS) $(ldflags-y) $(LDFLAGS_$(@F)) $(filter-out FORCE,$^) -o $@

内核支持对Image目标文件进行压缩处理,支持的压缩算法有gzip、lzo、lzma、xzkern和lz4,假设选择的为gzip压缩。如下arch/arm/boot/compressed/Makefile所示,将Image应用gzip压缩之后,生成piggy_data文件,压缩命令参见文件scripts/Makefile.lib。

$(obj)/piggy_data: $(obj)/../Image FORCE
    $(call if_changed,$(compress-y))

$(obj)/piggy.o: $(obj)/piggy_data

scripts/Makefile.lib:

# Gzip
# ---------------------------------------------------------------------------

quiet_cmd_gzip = GZIP    $@
cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -n -f -9 > $@) ||  (rm -f $@ ; false)

需要注意的是piggy.S文件,其全部代码如下,功能为将以上压缩的piggy_data使用incbin命令打包进piggy.o目标文件中。以便Image镜像文件与其它compressed目录下的文件最终打包到一起。Image存放在最终镜像的.piggydata段,参见连接文件vmlinux.lds.S。

    .section .piggydata,#alloc
    .globl  input_data
input_data:
    .incbin "arch/arm/boot/compressed/piggy_data"
    .globl  input_data_end
input_data_end:

arch/arm/boot/compressed/vmlinux.lds.S
  
.piggydata : {
  *(.piggydata)
  __piggy_size_addr = . - 4;
}

关于解压缩程序decompress.c,其中根据内核配置,包含了具体的压缩文件。比如如果配置了lzma压缩算法,此处会包含对应的解压文件lib/decompress_unlzma.c,或者如果定义了gzip压缩,此处包含的为lib/decompress_inflate.c解压算法。在uboot将启动内核之后,内核将首先解压自身的代码,如下函数decompress_kernel,其在head.S中被调用,屏幕上打印Uncompressing Linux...。

void decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p, unsigned long free_mem_ptr_end_p, int arch_id)
{
    putstr("Uncompressing Linux...");
}

zImage文件生成


参见arch/arm/boot/Makefile文件,zImage的生成比较简单,使用objcopy命令拷贝而成,命令参数参见变量OBJCOPYFLAGS。

OBJCOPYFLAGS    :=-O binary -R .comment -S

$(obj)/zImage:  $(obj)/compressed/vmlinux FORCE
    $(call if_changed,objcopy)

 

uImage文件生成


参见文件arch/arm/boot/Makefile,uImage根据scripts/Makefile.lib中的uimage目标生成。

ifneq ($(LOADADDR),)
  UIMAGE_LOADADDR=$(LOADADDR)
else
  ifeq ($(CONFIG_ZBOOT_ROM),y)
    UIMAGE_LOADADDR=$(CONFIG_ZBOOT_ROM_TEXT)
  else
    UIMAGE_LOADADDR=$(ZRELADDR)
  endif
endif

$(obj)/uImage:  $(obj)/zImage FORCE
    @$(check_for_multiple_loadaddr)
    $(call if_changed,uimage)

在文件scripts/Makefile.lib中,由shell脚本mkuboot.sh生成uImage,其中的参数UIMAGE_LOADADDR在以上arch/arm/boot/Makefile文件中指定,输入文件变量UIMAGE_IN为zImage,输出文件UIMAGE_OUT为最终的uImage。

# U-Boot mkimage
# ---------------------------------------------------------------------------

MKIMAGE := $(srctree)/scripts/mkuboot.sh

# SRCARCH just happens to match slightly more than ARCH (on sparc), so reduces
# the number of overrides in arch makefiles
UIMAGE_ARCH ?= $(SRCARCH)
UIMAGE_COMPRESSION ?= $(if $(2),$(2),none)
UIMAGE_OPTS-y ?=
UIMAGE_TYPE ?= kernel
UIMAGE_LOADADDR ?= arch_must_set_this
UIMAGE_ENTRYADDR ?= $(UIMAGE_LOADADDR)
UIMAGE_NAME ?= 'Linux-$(KERNELRELEASE)'
UIMAGE_IN ?= $<
UIMAGE_OUT ?= $@

quiet_cmd_uimage = UIMAGE  $(UIMAGE_OUT)
      cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A $(UIMAGE_ARCH) -O linux -C $(UIMAGE_COMPRESSION) $(UIMAGE_OPTS-y) -T $(UIMAGE_TYPE) \
            -a $(UIMAGE_LOADADDR) -e $(UIMAGE_ENTRYADDR) -n $(UIMAGE_NAME) -d $(UIMAGE_IN) $(UIMAGE_OUT)

文件scripts/mkuboot.sh比较简单,找到交叉编译系统中的mkimage工具,如果没有,使用自身系统中的mkimage工具,运行以生成uImage镜像。

#
# Build U-Boot image when `mkimage' tool is available.
#

MKIMAGE=$(type -path "${CROSS_COMPILE}mkimage")

if [ -z "${MKIMAGE}" ]; then
    MKIMAGE=$(type -path mkimage)
    if [ -z "${MKIMAGE}" ]; then
        # Doesn't exist
        echo '"mkimage" command not found - U-Boot images will not be built' >&2
        exit 1;
    fi
fi

# Call "mkimage" to create U-Boot image
${MKIMAGE} "$@"

最后,当前的arm64体系架构已经不支持zImage和uImage的编译目标,可使用mkimage工具给不经压缩的Image镜像加上uboot头部信息,生成uImage启动镜像,由u-boot来启动。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值