linux2.4启动分析(1)---内核启动地址的确定 vmlinux LOAD_ADDR ZRELADDR

本文详细解析了Linux内核在ARM架构下的启动地址设置,包括虚拟地址与物理地址的区别,以及不同配置下启动地址的变化。同时介绍了vmlinux与zImage的生成过程。

http://blog.chinaunix.net/u/31100/showart_244622.html


================================

Author: taoyuetao
Email: tao_yuetao@yahoo.com.cn
Blog: taoyuetao.cublog.cn

2006-11-03

================================

内核编译链接过程是依靠vmlinux.lds文件,以arm为例vmlinux.lds文件位于kernel/arch/arm/vmlinux.lds,
但是该文件是由vmlinux-armv.lds.in生成的,根据编译选项的不同源文件还可以是vmlinux-armo.lds.in,
vmlinux-armv-xip.lds.in。

vmlinux-armv.lds的生成过程在kernel/arch/arm/Makefile中

(在2.6中没有找到这个,在/arch/arm/boot/Makefile)

LDSCRIPT     = arch/arm/vmlinux-armv.lds.in

arch/arm/vmlinux.lds: arch/arm/Makefile $(LDSCRIPT) /
 $(wildcard include/config/cpu/32.h) /
 $(wildcard include/config/cpu/26.h) /
 $(wildcard include/config/arch/*.h)
 @echo '  Generating $@'
 @sed 's/TEXTADDR/$(TEXTADDR)/;s/DATAADDR/$(DATAADDR)/' $(LDSCRIPT) >$@

vmlinux-armv.lds.in文件的内容:

OUTPUT_ARCH(arm)
ENTRY(stext)
SECTIONS
{
    . = TEXTADDR;
    .init : {           /* Init code and data       */
        _stext = .;
        __init_begin = .;
            *(.text.init)
        __proc_info_begin = .;
            *(.proc.info)
        __proc_info_end = .;
        __arch_info_begin = .;
            *(.arch.info)
        __arch_info_end = .;
        __tagtable_begin = .;
            *(.taglist)
        __tagtable_end = .;
            *(.data.init)
        . = ALIGN(16);
        __setup_start = .;
            *(.setup.init)
        __setup_end = .;
        __initcall_start = .;
            *(.initcall.init)
        __initcall_end = .;
        . = ALIGN(4096);
        __init_end = .;
    }
   
其中TEXTADDR就是内核启动的虚拟地址,定义在kernel/arch/arm/Makefile中:
ifeq ($(CONFIG_CPU_32),y)
PROCESSOR    = armv
TEXTADDR     = 0xC0008000
LDSCRIPT     = arch/arm/vmlinux-armv.lds.in
endif
需要注意的是这里是虚拟地址而不是物理地址。

一般情况下都在生成vmlinux后,再对内核进行压缩成为zImage,压缩的目录是kernel/arch/arm/boot。
下载到flash中的是压缩后的zImage文件,zImage是由压缩后的vmlinux和解压缩程序组成,如下图所示:

            |-----------------|/    |-----------------|
            |                    | /   |                    |
            |                    |  /  | decompress code |
            |     vmlinux        /  |-----------------|    zImage
            |                    |    /|                    |
            |                    |     |                    |
            |                    |     |                    |   
            |                    |     |                    |
            |                    |    /|-----------------|
            |                    |   /
            |                    |  /
            |                    | /
            |-----------------|/
           
zImage链接脚本也叫做vmlinux.lds,位于kernel/arch/arm/boot/compressed。
是由同一目录下的vmlinux.lds.in文件生成的,内容如下:
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
 {
   . = LOAD_ADDR;   //这个在2.6中已经去掉了
   _load_addr = .;    //也去掉
 
   . = TEXT_START;
   _text = .;
 
   .text : {
     _start = .;
    
其中LOAD_ADDR就是zImage中解压缩代码的ram偏移地址,TEXT_START是内核ram启动的偏移地址,这个地址是物理地址。
在kernel/arch/arm/boot/Makefile文件中定义了:
ZTEXTADDR   =0
ZRELADDR     = 0xa0008000  //这个在2.6中是makefile.boot定义


ZTEXTADDR就是解压缩代码的ram偏移地址,ZRELADDR是内核ram启动的偏移地址,这里看到指定ZTEXTADDR的地址为0,
明显是不正确的,因为我的平台上的ram起始地址是0xa0000000,在Makefile文件中看到了对该地址设置的几行注释:
# We now have a PIC decompressor implementation.  Decompressors running
# from RAM should not define ZTEXTADDR.  Decompressors running directly
# from ROM or Flash must define ZTEXTADDR (preferably via the config)
他的意识是如果是在ram中进行解压缩时,不用指定它在ram中的运行地址,如果是在flash中就必须指定他的地址。所以
这里将ZTEXTADDR指定为0,也就是没有真正指定地址。

在kernel/arch/arm/boot/compressed/Makefile文件有一行脚本:


SEDFLAGS    = s/TEXT_START/$(ZTEXTADDR)/;s/LOAD_ADDR/$(ZRELADDR)/;s/BSS_START/$(ZBSSADDR)/

//2.6改为s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/

 

 

使得TEXT_START = ZTEXTADDR,LOAD_ADDR = ZRELADDR。

这样vmlinux.lds的生成过程如下:
vmlinux.lds:    vmlinux.lds.in Makefile $(TOPDIR)/arch/$(ARCH)/boot/Makefile $(TOPDIR)/.config
 @sed "$(SEDFLAGS)" < vmlinux.lds.in > $@
 
以上就是我对内核启动地址的分析,总结一下内核启动地址的设置:
1、设置kernel/arch/arm/Makefile文件中的
   TEXTADDR     = 0xC0008000 //2.6暂时没找到
   内核启动的虚拟地址
2、设置kernel/arch/arm/boot/Makefile文件中的
   ZRELADDR     = 0xa0008000
   内核启动的物理地址
   如果需要从flash中启动还需要设置
   ZTEXTADDR地址。

# # arch/arm/boot/Makefile # # This file is included by the global makefile so that you can add your own # architecture-specific flags and dependencies. # # This file is subject to the terms and conditions of the GNU General Public # License. See the file "COPYING" in the main directory of this archive # for more details. # # Copyright (C) 1995-2002 Russell King # OBJCOPYFLAGS :=-O binary -R .comment -S ifneq ($(CONFIG_ARM_PATCH_PHYS_VIRT),) LOADADDR = 0x20008000 else LOADADDR = $(shell /bin/bash -c 'printf "0x%08x" $$[$(CONFIG_PHYS_OFFSET) + 0x8000]') endif MKIMAGE_BIN = $(srctree)/scripts/mkimage MZ_BIN = $(srctree)/scripts/mz SZ_BIN = $(srctree)/scripts/sstar_sz.sh XZ_BIN = xz KERNEL_RELEASE_FILE = include/config/kernel.release ROOTFS = $(obj)/ramdisk_linaro4.8_minit.img.xz ifneq ($(wildcard $(srctree)/arch/arm/boot/dts/$(subst ",,$(CONFIG_SSTAR_DTB_NAME)).dts),) SSTAR_DTB_NAME=arch/arm/boot/dts/$(subst ",,$(CONFIG_SSTAR_DTB_NAME)).dtb endif CHIP_NAME := $(subst ",,$(CONFIG_SSTAR_CHIP_NAME)) ifeq ($(findstring fpga, $(SSTAR_DTB_NAME)), fpga) SSTAR_FPGA_DTB_NAME = $(SSTAR_DTB_NAME) else SSTAR_FPGA_DTB_NAME = arch/arm/boot/dts/$(CHIP_NAME)-fpga.dtb endif ifneq ($(MACHINE),) include $(MACHINE)/Makefile.boot endif # Note: the following conditions must always be true: # ZRELADDR == virt_to_phys(PAGE_OFFSET + TEXT_OFFSET) # PARAMS_PHYS must be within 4MB of ZRELADDR # INITRD_PHYS must be in RAM ZRELADDR := $(zreladdr-y) PARAMS_PHYS := $(params_phys-y) INITRD_PHYS := $(initrd_phys-y) export ZRELADDR INITRD_PHYS PARAMS_PHYS targets := Image zImage xipImage bootpImage uImage ifeq ($(CONFIG_XIP_KERNEL),y) cmd_deflate_xip_data = $(CONFIG_SHELL) -c \ '$(srctree)/$(src)/deflate_xip_data.sh $< $@' ifeq ($(CONFIG_XIP_DEFLATED_DATA),y) quiet_cmd_mkxip = XIPZ $@ cmd_mkxip = $(cmd_objcopy) && $(cmd_deflate_xip_data) else quiet_cmd_mkxip = $(quiet_cmd_objcopy) cmd_mkxip = $(cmd_objcopy) endif $(obj)/xipImage: vmlinux FORCE $(call if_changed,mkxip) @$(kecho) ' Physical Address of xipImage: $(CONFIG_XIP_PHYS_ADDR)' $(obj)/Image $(obj)/zImage: FORCE @echo 'Kernel configured for XIP (CONFIG_XIP_KERNEL=y)' @echo 'Only the xipImage target is available in this case' @false else $(obj)/xipImage: FORCE @echo 'Kernel not configured for XIP (CONFIG_XIP_KERNEL!=y)' @false $(obj)/Image: vmlinux FORCE $(call if_changed,objcopy) $(obj)/compressed/vmlinux: $(obj)/Image FORCE $(Q)$(MAKE) $(build)=$(obj)/compressed $@ $(obj)/zImage: $(obj)/compressed/vmlinux FORCE $(call if_changed,objcopy) endif ifneq ($(LOADADDR),) UIMAGE_LOADADDR=$(LOADADDR) else ifeq ($(CONFIG_ZBOOT_ROM),y) UIMAGE_LOADADDR=$(CONFIG_ZBOOT_ROM_TEXT) else UIMAGE_LOADADDR=$(ZRELADDR) endif endif check_for_multiple_loadaddr = \ if [ $(words $(UIMAGE_LOADADDR)) -ne 1 ]; then \ echo 'multiple (or no) load addresses: $(UIMAGE_LOADADDR)'; \ echo 'This is incompatible with uImages'; \ echo 'Specify LOADADDR on the commandline to build an uImage'; \ false; \ fi clean-files += uImage.xz uImage.mz Image.xz Image.mz Image-fpga ifeq ($(CONFIG_ARCH_SSTAR),) $(obj)/uImage: $(obj)/zImage FORCE @$(check_for_multiple_loadaddr) $(call if_changed,uimage) else # add dtc flags '-@' to support dtb overlay DTC_FLAGS_$(basename $(notdir $(SSTAR_DTB_NAME))) := -@ DTC_FLAGS_$(basename $(notdir $(SSTAR_FPGA_DTB_NAME))) := -@ $(obj)/uImage: $(obj)/Image $(SSTAR_DTB_NAME) $(SSTAR_FPGA_DTB_NAME) FORCE ifeq ($(CONFIG_SSTAR_BUILTIN_DTB), y) #update builtin DTB @test "${SSTAR_DTB_NAME}" = "" || \ if [ -e ${SSTAR_DTB_NAME} ]; then \ echo " IMAGE $(obj)/Image"; \ echo " BNDTB ${SSTAR_DTB_NAME}"; \ python $(srctree)/scripts/ms_builtin_dtb_update.py $(obj)/Image ${SSTAR_DTB_NAME}; \ echo; \ fi; #update Image-fpga DTB @if [ -e ${SSTAR_FPGA_DTB_NAME} ]; then \ echo " IMAGE $(obj)/Image-fpga"; \ cp -f $(obj)/Image $(obj)/Image-fpga; \ echo " BNDTB ${SSTAR_FPGA_DTB_NAME}"; \ python $(srctree)/scripts/ms_builtin_dtb_update.py $(obj)/Image-fpga ${SSTAR_FPGA_DTB_NAME}; \ echo; \ fi; endif ifeq ($(CONFIG_SS_BUILTIN_UNFDT), y) #update builtin UNFDT @test "${SSTAR_DTB_NAME}" = "" || \ if [ -e ${SSTAR_DTB_NAME} ]; then \ echo " BNDTB ${SSTAR_DTB_NAME}"; \ chmod 755 scripts/dtc/dtb2unfdt/dtb2unfdt; \ scripts/dtc/dtb2unfdt/dtb2unfdt ${SSTAR_DTB_NAME} $(obj)/unfdt.bin; \ python $(srctree)/scripts/ms_builtin_unfdt_update.py $(obj)/Image $(obj)/unfdt.bin; \ echo; \ fi; endif ifneq ($(wildcard $(srctree)/scripts/ss_padmux_check.py),) @echo "$(srctree)/scripts/dtc/dtx_diff ${SSTAR_DTB_NAME} > $(CONFIG_SSTAR_DTB_NAME).dts" @$(srctree)/scripts/dtc/dtx_diff ${SSTAR_DTB_NAME} > $(CONFIG_SSTAR_DTB_NAME).dts ifneq ($(wildcard drivers/sstar/gpio/$(CHIP_NAME)/hal_pinmux.o),) @$(CROSS_COMPILE)objdump -D -j .rodata drivers/sstar/gpio/$(CHIP_NAME)/hal_pinmux.o > pinmux_table @python $(srctree)/scripts/ss_padmux_check.py $(CONFIG_SSTAR_DTB_NAME).dts pinmux_table @rm pinmux_table endif @rm $(CONFIG_SSTAR_DTB_NAME).dts endif ifneq ($(wildcard scripts/ss_puse_check.py),) @python scripts/ss_puse_check.py drivers/sstar/include/drv_puse.h endif #update the image size into Image @python $(srctree)/scripts/ms_bin_option_update_int.py $(obj)/Image '#IMG_SZ#' $$(stat -c %s $(obj)/Image) #build uImage @IMGNAME=$(shell /usr/bin/strings -a -T binary $(obj)/Image | grep 'MVX' | grep 'LX' | sed 's/\\*MVX/MVX/g' | cut -c 1-32 ); \ if [ -e ${MKIMAGE_BIN} ]; then \ ${MKIMAGE_BIN} -A arm -O linux -T kernel -C none -a ${LOADADDR} -e ${LOADADDR} -n $${IMGNAME} -d $(obj)/Image $(obj)/uImage; \ echo '$(IMGNAME)'; \ echo 'Compress Kernel Image'; \ ${MZ_BIN} c $(obj)/Image $(obj)/Image.mz ; \ ${SZ_BIN} -d $(obj)/uImage -b 4; \ ${XZ_BIN} -z -k -f $(obj)/Image; \ echo; \ ${MKIMAGE_BIN} -A arm -O linux -C lzma -a ${LOADADDR} -e ${LOADADDR} -n $${IMGNAME} -d $(obj)/Image.xz $(obj)/uImage.xz; \ echo; \ ${MKIMAGE_BIN} -A arm -O linux -C mz -a ${LOADADDR} -e ${LOADADDR} -n $${IMGNAME} -d $(obj)/Image.mz $(obj)/uImage.mz; \ echo; \ ${MKIMAGE_BIN} -A arm -O linux -C lzma2 -a $(shell awk 'BEGIN{printf("%#x", '${LOADADDR}-0x40')}') -e 0 -n $${IMGNAME} -d $(obj)/uImage.sz $(obj)/u1Image.sz; \ mv $(obj)/u1Image.sz $(obj)/uImage.sz; \ echo; \ lz4 -9 -f -q $(obj)/Image $(obj)/Image.lz4; \ ${MKIMAGE_BIN} -A arm -O linux -C lz4 -a ${LOADADDR} -e ${LOADADDR} -n $${IMGNAME} -d $(obj)/Image.lz4 $(obj)/uImage.lz4; \ echo; \ else \ echo ">> Can't find $${MKIMAGE_BIN}. <<"; \ fi; \ if [ -e $(ROOTFS) ]; then \ ${MKIMAGE_BIN} -A arm -O linux -T multi -C none -a ${LOADADDR} -e ${LOADADDR} -n $${IMGNAME} -d $(obj)/Image:$(ROOTFS) $(obj)/kernel.img; \ echo; \ ${MKIMAGE_BIN} -A arm -O linux -T multi -C lzma -a ${LOADADDR} -e ${LOADADDR} -n $${IMGNAME} -d $(obj)/Image.xz:$(ROOTFS) $(obj)/kernel.xz.img; \ echo; \ ${MKIMAGE_BIN} -A arm -O linux -T multi -C mz -a ${LOADADDR} -e ${LOADADDR} -n $${IMGNAME} -d $(obj)/Image.mz:$(ROOTFS) $(obj)/kernel.mz.img; \ echo; \ ${MKIMAGE_BIN} -A arm -O linux -T multi -C lz4 -a ${LOADADDR} -e ${LOADADDR} -n $${IMGNAME} -d $(obj)/Image.lz4:$(ROOTFS) $(obj)/kernel.lz4.img; \ echo; \ fi; @echo endif $(obj)/bootp/bootp: $(obj)/zImage initrd FORCE $(Q)$(MAKE) $(build)=$(obj)/bootp $@ $(obj)/bootpImage: $(obj)/bootp/bootp FORCE $(call if_changed,objcopy) PHONY += initrd install zinstall uinstall initrd: @test "$(INITRD_PHYS)" != "" || \ (echo This machine does not support INITRD; exit -1) @test "$(INITRD)" != "" || \ (echo You must specify INITRD; exit -1) install: $(CONFIG_SHELL) $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" \ $(obj)/Image System.map "$(INSTALL_PATH)" zinstall: $(CONFIG_SHELL) $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" \ $(obj)/zImage System.map "$(INSTALL_PATH)" uinstall: $(CONFIG_SHELL) $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" \ $(obj)/uImage System.map "$(INSTALL_PATH)" subdir- := bootp compressed dts
11-11
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值