• Mini440之uboot移植流程分析(一)


    在前面的文章我们已经介绍了如何自己去实现一个BootLoader,今天我们来介绍u-boot的移植,u-boot是一种通用的BootLoader。

    嵌入式Linux之uboot源码make配置编译正向分析中我们已经介绍了如何通过Source Insight打开u-boot源码,以及uboot的编译过程。这一节我们将对u-boot源码进行分析,并且将uboot移植到Mini2440开发板。

    在移植之前,我们首先需要明确Mini2440开发板具有的硬件资源:

    • CPU:S3C2440;
    • NAND:K9F2G08U0C;
    • 网卡:DM9000A;
    • SDRAM:HY57V561620FTP;

    从网站上下载得到u-boot源码包,例如:u-boot-2016.05.tar.bz2 (最新的u-boot版本已经不支持s3c2440)。

    一、uboot编译

    在之前的文章中我们介绍过smdk2410的编译过程,这里在啰嗦一遍,uboot的编译分为两步:配置、编译:

    1.1 配置

    配置选择所要使用的board ,我调试使用的是S3C2440,但是./configs目录下没有smdk2440_defconfig这个文件,只有smdk2410_defconfig,因此执行如下命令,生成.config文件:

    make smdk2410_defconfig

    .config文件定义如下:

    #
    # Automatically generated file; DO NOT EDIT.
    # U-Boot 2016.05 Configuration
    #
    CONFIG_CREATE_ARCH_SYMLINK=y
    CONFIG_HAVE_GENERIC_BOARD=y
    CONFIG_SYS_GENERIC_BOARD=y
    # CONFIG_ARC is not set
    CONFIG_ARM=y
    # CONFIG_AVR32 is not set
    # CONFIG_BLACKFIN is not set
    # CONFIG_M68K is not set
    # CONFIG_MICROBLAZE is not set
    # CONFIG_MIPS is not set
    # CONFIG_NDS32 is not set
    # CONFIG_NIOS2 is not set
    # CONFIG_OPENRISC is not set
    # CONFIG_PPC is not set
    # CONFIG_SANDBOX is not set
    # CONFIG_SH is not set
    # CONFIG_SPARC is not set
    # CONFIG_X86 is not set
    CONFIG_SYS_ARCH="arm"
    CONFIG_SYS_CPU="arm920t"
    CONFIG_SYS_SOC="s3c24x0"
    CONFIG_SYS_VENDOR="samsung"
    CONFIG_SYS_BOARD="smdk2410"
    CONFIG_SYS_CONFIG_NAME="smdk2410"
    
    #
    # ARM architecture
    #
    CONFIG_CPU_ARM920T=y
    # CONFIG_SEMIHOSTING is not set
    # CONFIG_SYS_L2CACHE_OFF is not set
    # CONFIG_ARCH_AT91 is not set
    # CONFIG_TARGET_EDB93XX is not set
    # CONFIG_TARGET_VCMA9 is not set
    CONFIG_TARGET_SMDK2410=y
    # CONFIG_TARGET_ASPENITE is not set
    # CONFIG_TARGET_GPLUGD is not set
    # CONFIG_ARCH_DAVINCI is not set
    # CONFIG_KIRKWOOD is not set
    # CONFIG_ARCH_MVEBU is not set
    # CONFIG_TARGET_DEVKIT3250 is not set
    # CONFIG_TARGET_WORK_92105 is not set
    # CONFIG_TARGET_MX25PDK is not set
    # CONFIG_TARGET_ZMX25 is not set
    # CONFIG_TARGET_APF27 is not set
    # CONFIG_TARGET_APX4DEVKIT is not set
    # CONFIG_TARGET_XFI3 is not set
    # CONFIG_TARGET_M28EVK is not set
    # CONFIG_TARGET_MX23EVK is not set
    # CONFIG_TARGET_MX28EVK is not set
    # CONFIG_TARGET_MX23_OLINUXINO is not set
    # CONFIG_TARGET_BG0900 is not set
    # CONFIG_TARGET_SANSA_FUZE_PLUS is not set
    # CONFIG_TARGET_SC_SPS_1 is not set
    # CONFIG_ORION5X is not set
    # CONFIG_TARGET_SPEAR300 is not set
    # CONFIG_TARGET_SPEAR310 is not set
    # CONFIG_TARGET_SPEAR320 is not set
    # CONFIG_TARGET_SPEAR600 is not set
    # CONFIG_TARGET_STV0991 is not set
    # CONFIG_TARGET_X600 is not set
    # CONFIG_TARGET_IMX31_PHYCORE is not set
    # CONFIG_TARGET_MX31ADS is not set
    # CONFIG_TARGET_MX31PDK is not set
    # CONFIG_TARGET_WOODBURN is not set
    # CONFIG_TARGET_WOODBURN_SD is not set
    # CONFIG_TARGET_FLEA3 is not set
    # CONFIG_TARGET_MX35PDK is not set
    # CONFIG_ARCH_BCM283X is not set
    # CONFIG_TARGET_VEXPRESS_CA15_TC2 is not set
    # CONFIG_TARGET_VEXPRESS_CA5X2 is not set
    # CONFIG_TARGET_VEXPRESS_CA9X4 is not set
    # CONFIG_TARGET_KWB is not set
    # CONFIG_TARGET_TSERIES is not set
    # CONFIG_TARGET_CM_T335 is not set
    # CONFIG_TARGET_PEPPER is not set
    # CONFIG_TARGET_AM335X_IGEP0033 is not set
    # CONFIG_TARGET_PCM051 is not set
    # CONFIG_TARGET_DRACO is not set
    # CONFIG_TARGET_THUBAN is not set
    # CONFIG_TARGET_RASTABAN is not set
    # CONFIG_TARGET_PXM2 is not set
    # CONFIG_TARGET_RUT is not set
    # CONFIG_TARGET_PENGWYN is not set
    # CONFIG_TARGET_AM335X_BALTOS is not set
    # CONFIG_TARGET_AM335X_EVM is not set
    # CONFIG_TARGET_AM335X_SL50 is not set
    # CONFIG_TARGET_AM43XX_EVM is not set
    # CONFIG_TARGET_BAV335X is not set
    # CONFIG_TARGET_TI814X_EVM is not set
    # CONFIG_TARGET_TI816X_EVM is not set
    # CONFIG_TARGET_BCM28155_AP is not set
    # CONFIG_TARGET_BCMCYGNUS is not set
    # CONFIG_TARGET_BCMNSP is not set
    # CONFIG_ARCH_EXYNOS is not set
    # CONFIG_ARCH_S5PC1XX is not set
    # CONFIG_ARCH_HIGHBANK is not set
    # CONFIG_ARCH_INTEGRATOR is not set
    # CONFIG_ARCH_KEYSTONE is not set
    # CONFIG_ARCH_MX7 is not set
    # CONFIG_ARCH_MX6 is not set
    # CONFIG_ARCH_MX5 is not set
    # CONFIG_TARGET_M53EVK is not set
    # CONFIG_TARGET_MX51EVK is not set
    # CONFIG_TARGET_MX53ARD is not set
    # CONFIG_TARGET_MX53EVK is not set
    # CONFIG_TARGET_MX53LOCO is not set
    # CONFIG_TARGET_MX53SMD is not set
    # CONFIG_OMAP34XX is not set
    # CONFIG_OMAP44XX is not set
    # CONFIG_OMAP54XX is not set
    # CONFIG_RMOBILE is not set
    # CONFIG_ARCH_SNAPDRAGON is not set
    # CONFIG_ARCH_SOCFPGA is not set
    # CONFIG_TARGET_CM_T43 is not set
    # CONFIG_ARCH_SUNXI is not set
    # CONFIG_TARGET_TS4800 is not set
    # CONFIG_TARGET_VF610TWR is not set
    # CONFIG_TARGET_COLIBRI_VF is not set
    # CONFIG_TARGET_PCM052 is not set
    # CONFIG_ARCH_ZYNQ is not set
    # CONFIG_ARCH_ZYNQMP is not set
    # CONFIG_TEGRA is not set
    # CONFIG_TARGET_VEXPRESS64_AEMV8A is not set
    # CONFIG_TARGET_VEXPRESS64_BASE_FVP is not set
    # CONFIG_TARGET_VEXPRESS64_BASE_FVP_DRAM is not set
    # CONFIG_TARGET_VEXPRESS64_JUNO is not set
    # CONFIG_TARGET_LS2080A_EMU is not set
    # CONFIG_TARGET_LS2080A_SIMU is not set
    # CONFIG_TARGET_LS2080AQDS is not set
    # CONFIG_TARGET_LS2080ARDB is not set
    # CONFIG_TARGET_HIKEY is not set
    # CONFIG_TARGET_LS1021AQDS is not set
    # CONFIG_TARGET_LS1021ATWR is not set
    # CONFIG_TARGET_LS1043AQDS is not set
    # CONFIG_TARGET_LS1043ARDB is not set
    # CONFIG_TARGET_H2200 is not set
    # CONFIG_TARGET_ZIPITZ2 is not set
    # CONFIG_TARGET_COLIBRI_PXA270 is not set
    # CONFIG_ARCH_UNIPHIER is not set
    # CONFIG_STM32 is not set
    # CONFIG_ARCH_ROCKCHIP is not set
    # CONFIG_TARGET_THUNDERX_88XX is not set
    # CONFIG_SYS_MALLOC_F is not set
    
    #
    # ARM debug
    #
    # CONFIG_DEBUG_LL is not set
    
    #
    # General setup
    #
    CONFIG_LOCALVERSION=""
    CONFIG_LOCALVERSION_AUTO=y
    CONFIG_CC_OPTIMIZE_FOR_SIZE=y
    CONFIG_EXPERT=y
    CONFIG_SYS_MALLOC_CLEAR_ON_INIT=y
    
    #
    # Boot images
    #
    # CONFIG_FIT is not set
    CONFIG_SYS_EXTRA_OPTIONS=""
    
    #
    # Boot timing
    #
    # CONFIG_BOOTSTAGE is not set
    CONFIG_BOOTSTAGE_USER_COUNT=20
    CONFIG_BOOTSTAGE_STASH_ADDR=0
    CONFIG_BOOTSTAGE_STASH_SIZE=4096
    # CONFIG_CONSOLE_RECORD is not set
    
    #
    # Command line interface
    #
    CONFIG_CMDLINE=y
    CONFIG_HUSH_PARSER=y
    CONFIG_SYS_HUSH_PARSER=y
    CONFIG_SYS_PROMPT="SMDK2410 # "
    
    #
    # Autoboot options
    #
    # CONFIG_AUTOBOOT_KEYED is not set
    
    #
    # Commands
    #
    
    #
    # Info commands
    #
    CONFIG_CMD_BDI=y
    CONFIG_CMD_CONSOLE=y
    # CONFIG_CMD_CPU is not set
    # CONFIG_CMD_LICENSE is not set
    
    #
    # Boot commands
    #
    CONFIG_CMD_BOOTD=y
    CONFIG_CMD_BOOTM=y
    # CONFIG_CMD_BOOTZ is not set
    CONFIG_CMD_ELF=y
    CONFIG_CMD_GO=y
    CONFIG_CMD_RUN=y
    CONFIG_CMD_IMI=y
    CONFIG_CMD_IMLS=y
    CONFIG_CMD_XIMG=y
    
    #
    # Environment commands
    #
    # CONFIG_CMD_ASKENV is not set
    CONFIG_CMD_EXPORTENV=y
    CONFIG_CMD_IMPORTENV=y
    CONFIG_CMD_EDITENV=y
    # CONFIG_CMD_GREPENV is not set
    CONFIG_CMD_SAVEENV=y
    CONFIG_CMD_ENV_EXISTS=y
    
    #
    # Memory commands
    #
    CONFIG_CMD_MEMORY=y
    CONFIG_CMD_CRC32=y
    # CONFIG_LOOPW is not set
    # CONFIG_CMD_MEMTEST is not set
    # CONFIG_CMD_MX_CYCLIC is not set
    # CONFIG_CMD_MEMINFO is not set
    
    #
    # Device access commands
    #
    CONFIG_CMD_LOADB=y
    CONFIG_CMD_LOADS=y
    CONFIG_CMD_FLASH=y
    # CONFIG_CMD_ARMFLASH is not set
    # CONFIG_CMD_MMC is not set
    # CONFIG_CMD_NAND is not set
    # CONFIG_CMD_SF is not set
    # CONFIG_CMD_SPI is not set
    # CONFIG_CMD_I2C is not set
    CONFIG_CMD_USB=y
    # CONFIG_CMD_DFU is not set
    # CONFIG_CMD_USB_MASS_STORAGE is not set
    CONFIG_CMD_FPGA=y
    # CONFIG_CMD_GPIO is not set
    
    #
    # Shell scripting commands
    #
    CONFIG_CMD_ECHO=y
    CONFIG_CMD_ITEST=y
    CONFIG_CMD_SOURCE=y
    # CONFIG_CMD_SETEXPR is not set
    
    #
    # Network commands
    #
    CONFIG_CMD_NET=y
    # CONFIG_CMD_TFTPPUT is not set
    # CONFIG_CMD_TFTPSRV is not set
    # CONFIG_CMD_RARP is not set
    CONFIG_CMD_DHCP=y
    CONFIG_CMD_NFS=y
    # CONFIG_CMD_MII is not set
    CONFIG_CMD_PING=y
    # CONFIG_CMD_CDP is not set
    # CONFIG_CMD_SNTP is not set
    # CONFIG_CMD_DNS is not set
    # CONFIG_CMD_LINK_LOCAL is not set
    
    #
    # Misc commands
    #
    CONFIG_CMD_CACHE=y
    # CONFIG_CMD_TIME is not set
    CONFIG_CMD_MISC=y
    # CONFIG_CMD_TIMER is not set
    
    #
    # Power commands
    #
    
    #
    # Security commands
    #
    
    #
    # Filesystem commands
    #
    CONFIG_CMD_EXT2=y
    # CONFIG_CMD_EXT4 is not set
    CONFIG_CMD_FAT=y
    # CONFIG_CMD_FS_GENERIC is not set
    CONFIG_SUPPORT_OF_CONTROL=y
    
    #
    # Device Tree Control
    #
    # CONFIG_OF_CONTROL is not set
    CONFIG_NET=y
    # CONFIG_NET_RANDOM_ETHADDR is not set
    # CONFIG_NETCONSOLE is not set
    CONFIG_NET_TFTP_VARS=y
    
    #
    # Device Drivers
    #
    
    #
    # Generic Driver Options
    #
    # CONFIG_DM is not set
    # CONFIG_ADC is not set
    # CONFIG_ADC_EXYNOS is not set
    # CONFIG_ADC_SANDBOX is not set
    # CONFIG_BLOCK_CACHE is not set
    
    #
    # Clock
    #
    # CONFIG_CPU is not set
    
    #
    # Hardware crypto devices
    #
    # CONFIG_FSL_CAAM is not set
    
    #
    # Demo for driver model
    #
    
    #
    # DFU support
    #
    # CONFIG_DFU_TFTP is not set
    
    #
    # DMA Support
    #
    # CONFIG_TI_EDMA3 is not set
    
    #
    # GPIO Support
    #
    
    #
    # I2C support
    #
    # CONFIG_CROS_EC_KEYB is not set
    
    #
    # LED Support
    #
    
    #
    # Memory Controller drivers
    #
    
    #
    # Multifunction device drivers
    #
    # CONFIG_CROS_EC is not set
    # CONFIG_FSL_SEC_MON is not set
    # CONFIG_MXC_OCOTP is not set
    # CONFIG_PCA9551_LED is not set
    # CONFIG_WINBOND_W83627 is not set
    
    #
    # MMC Host controller Support
    #
    
    #
    # MTD Support
    #
    
    #
    # NAND Device Support
    #
    # CONFIG_NAND_DENALI is not set
    # CONFIG_NAND_VF610_NFC is not set
    # CONFIG_NAND_PXA3XX is not set
    # CONFIG_NAND_ARASAN is not set
    
    #
    # Generic NAND options
    #
    
    #
    # SPI Flash Support
    #
    # CONFIG_SPI_FLASH is not set
    # CONFIG_PHYLIB is not set
    # CONFIG_NETDEVICES is not set
    
    #
    # PCI
    #
    
    #
    # Pin controllers
    #
    
    #
    # Power
    #
    
    #
    # Remote Processor drivers
    #
    
    #
    # Real Time Clock
    #
    
    #
    # Serial drivers
    #
    # CONFIG_DEBUG_UART is not set
    # CONFIG_DEBUG_UART_SKIP_INIT is not set
    # CONFIG_FSL_LPUART is not set
    # CONFIG_SYS_NS16550 is not set
    
    #
    # Sound support
    #
    # CONFIG_SOUND is not set
    
    #
    # SPI Support
    #
    # CONFIG_FSL_ESPI is not set
    # CONFIG_TI_QSPI is not set
    
    #
    # SPMI support
    #
    # CONFIG_DM_THERMAL is not set
    
    #
    # Timer Support
    #
    
    #
    # TPM support
    #
    # CONFIG_USB is not set
    
    #
    # Graphics support
    #
    
    #
    # TrueType Fonts
    #
    # CONFIG_VIDEO_VESA is not set
    # CONFIG_VIDEO_LCD_ANX9804 is not set
    # CONFIG_VIDEO_LCD_SSD2828 is not set
    # CONFIG_VIDEO_MVEBU is not set
    # CONFIG_PHYS_TO_BUS is not set
    
    #
    # File systems
    #
    
    #
    # Library routines
    #
    # CONFIG_CC_OPTIMIZE_LIBS_FOR_SPEED is not set
    CONFIG_HAVE_PRIVATE_LIBGCC=y
    # CONFIG_USE_PRIVATE_LIBGCC is not set
    CONFIG_SYS_HZ=1000
    # CONFIG_USE_TINY_PRINTF is not set
    CONFIG_REGEX=y
    # CONFIG_LIB_RAND is not set
    # CONFIG_CMD_DHRYSTONE is not set
    # CONFIG_RSA is not set
    
    #
    # Hashing Support
    #
    # CONFIG_SHA1 is not set
    # CONFIG_SHA256 is not set
    # CONFIG_SHA_HW_ACCEL is not set
    
    #
    # Compression Support
    #
    # CONFIG_LZ4 is not set
    # CONFIG_ERRNO_STR is not set
    # CONFIG_OF_LIBFDT is not set
    # CONFIG_SPL_OF_LIBFDT is not set
    # CONFIG_UNIT_TEST is not set
    View Code

    这个文件和include/config/auto.conf文件内容大致差不多:

    #
    # Automatically generated file; DO NOT EDIT.
    # U-Boot 2016.05 Configuration
    #
    CONFIG_CMD_BOOTM=y
    CONFIG_CMD_USB=y
    CONFIG_CMD_EDITENV=y
    CONFIG_SYS_GENERIC_BOARD=y
    CONFIG_CMD_CONSOLE=y
    CONFIG_CMD_BOOTD=y
    CONFIG_CMD_IMLS=y
    CONFIG_BOOTSTAGE_STASH_ADDR=0
    CONFIG_HAVE_PRIVATE_LIBGCC=y
    CONFIG_CMD_BDI=y
    CONFIG_ARM=y
    CONFIG_CREATE_ARCH_SYMLINK=y
    CONFIG_SYS_VENDOR="samsung"
    CONFIG_CMD_PING=y
    CONFIG_CMD_SAVEENV=y
    CONFIG_CMD_MISC=y
    CONFIG_SYS_CPU="arm920t"
    CONFIG_BOOTSTAGE_USER_COUNT=20
    CONFIG_CC_OPTIMIZE_FOR_SIZE=y
    CONFIG_CMD_FLASH=y
    CONFIG_REGEX=y
    CONFIG_CMD_ENV_EXISTS=y
    CONFIG_HAVE_GENERIC_BOARD=y
    CONFIG_CMD_EXPORTENV=y
    CONFIG_CMD_DHCP=y
    CONFIG_SYS_EXTRA_OPTIONS=""
    CONFIG_CMD_CRC32=y
    CONFIG_SYS_BOARD="smdk2410"
    CONFIG_SYS_CONFIG_NAME="smdk2410"
    CONFIG_CMD_NFS=y
    CONFIG_NET=y
    CONFIG_TARGET_SMDK2410=y
    CONFIG_CMD_GO=y
    CONFIG_SYS_MALLOC_CLEAR_ON_INIT=y
    CONFIG_CMD_IMI=y
    CONFIG_SYS_HZ=1000
    CONFIG_SUPPORT_OF_CONTROL=y
    CONFIG_CMD_EXT2=y
    CONFIG_LOCALVERSION=""
    CONFIG_CMDLINE=y
    CONFIG_CMD_LOADB=y
    CONFIG_CMD_RUN=y
    CONFIG_SYS_HUSH_PARSER=y
    CONFIG_SYS_PROMPT="SMDK2410 # "
    CONFIG_CMD_MEMORY=y
    CONFIG_HUSH_PARSER=y
    CONFIG_CMD_XIMG=y
    CONFIG_CMD_ECHO=y
    CONFIG_LOCALVERSION_AUTO=y
    CONFIG_SYS_ARCH="arm"
    CONFIG_EXPERT=y
    CONFIG_SYS_SOC="s3c24x0"
    CONFIG_CMD_ITEST=y
    CONFIG_CMD_CACHE=y
    CONFIG_BOOTSTAGE_STASH_SIZE=4096
    CONFIG_CMD_LOADS=y
    CONFIG_CMD_FAT=y
    CONFIG_CMD_NET=y
    CONFIG_CMD_FPGA=y
    CONFIG_NET_TFTP_VARS=y
    CONFIG_CPU_ARM920T=y
    CONFIG_CMD_IMPORTENV=y
    CONFIG_CMD_ELF=y
    CONFIG_CMD_SOURCE=y
    View Code

    include/config/auto.conf是由fixdep在编译时生成的依赖文件。在顶层Makefile会引入auto.conf文件:

    ifeq ($(dot-config),1)
    # Read in config
    -include include/config/auto.conf

    1.2 编译

    编译、执行make命令,生成u-boot:

     make ARCH=arm CROSS_COMPILE=arm-linux-

    如果需要输出u-boot反汇编代码,执行时加入-j4参数,会在u-boot根目录下生成u-boot.map文件,在map文件中,包含函数名以及函数所在文件。

     make ARCH=arm CROSS_COMPILE=arm-linux- -j4

    直接反汇编u-boot文件,可以得到反汇编代码:

    arm-linux-objdump -D u-boot > u-boot.dis

    CROSS-COPILE是在Makefile文件中定义的变量,是用来指定交叉工具链,ARCH用来指定处理器架构。此外,我们可以在u-boot的顶层Makefile中定义:

    CROSS_COMPILE=arm-linux-
    ARCH=arm

    这样就省去了每次编译都要在控制台输入的麻烦。

    编译成功后会生成一个u-boot.bin,可以烧写到开发板上,不过一般是用不起来的,需要进一步修改。

    我们在编译u-boot的时候加入V=1参数:

     make ARCH=arm CROSS_COMPILE=arm-linux- V=1

    将会输出u-boot编译的完整步骤:

    set -e; : '  CHK     include/config/uboot.release'; mkdir -p include/config/;   echo "2016.05$(/bin/bash ./scriptfig/uboot.release.tmp; then rm -f include/config/uboot.release.tmp; else : '  UPD     include/config/uboot.releas
    set -e; : '  CHK     include/generated/version_autogenerated.h'; mkdir -p include/generated/;   (echo #define PLVERSION_STRING "$(arm-linux-ld --version | head -n 1)"; ) < include/config/uboot.release > include/generated/vemp; then rm -f include/generated/version_autogenerated.h.tmp; else : '  UPD     include/generated/version_autogen
    set -e; : '  CHK     include/generated/timestamp_autogenerated.h'; mkdir -p include/generated/;         (if test te}"; done; if test -n "${DATE}"; then LC_ALL=C ${DATE} -u -d "${SOURCE_DATE}" +'#define U_BOOT_DATE "%b %d %C%y"TE}" +'#define U_BOOT_DMI_DATE "%m/%d/%Y"'; else return 42; fi; else LC_ALL=C date +'#define U_BOOT_DATE "%b %d %ated/timestamp_autogenerated.h.tmp; if [ -r include/generated/timestamp_autogenerated.h ] && cmp -s include/generd/timestamp_autogenerated.h'; mv -f include/generated/timestamp_autogenerated.h.tmp include/generated/timestamp_a
    make -f ./scripts/Makefile.build obj=scripts/basic
    rm -f .tmp_quiet_recordmcount
    make -f ./scripts/Makefile.build obj=.
    mkdir -p lib/
    set -e; : '  CHK     include/generated/generic-asm-offsets.h'; mkdir -p include/generated/;     (set -e; echo "#i" */"; echo ""; sed -ne         "s:[[:space:]]*.ascii[[:space:]]*"(.*)":1:; /^->/{s:->#(.*):/* 1 */:; s:-offsets.s > include/generated/generic-asm-offsets.h.tmp; if [ -r include/generated/generic-asm-offsets.h ] && cmnerated/generic-asm-offsets.h'; mv -f include/generated/generic-asm-offsets.h.tmp include/generated/generic-asm-o
    mkdir -p arch/arm/lib/
    set -e; : '  CHK     include/generated/asm-offsets.h'; mkdir -p include/generated/;     (set -e; echo "#ifndef __"s:[[:space:]]*.ascii[[:space:]]*"(.*)":1:; /^->/{s:->#(.*):/* 1 */:; s:^->([^ ]*) [$#]*([-0-9]*) 
    erated/asm-offsets.h.tmp; if [ -r include/generated/asm-offsets.h ] && cmp -s include/generated/asm-offsets.h inmp include/generated/asm-offsets.h; fi
    make -f ./scripts/Makefile.build obj=tools
      cc -Wp,-MD,tools/.mkenvimage.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer   -include ./include/libfdtvimage.o tools/mkenvimage.c
      cc  -o tools/mkenvimage tools/mkenvimage.o tools/os_support.o tools/lib/crc32.o
      cc -Wp,-MD,tools/.fit_image.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer   -include ./include/libfdt_mage.o tools/fit_image.c
      cc -Wp,-MD,tools/.image-host.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer   -include ./include/libfdte-host.o tools/image-host.c
      cc -Wp,-MD,tools/.dumpimage.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer   -include ./include/libfdt_mage.o tools/dumpimage.c
      cc  -o tools/dumpimage tools/aisimage.o tools/atmelimage.o tools/common/bootm.o tools/lib/crc32.o tools/defaulttools/common/image.o tools/imagetool.o tools/imximage.o tools/kwbimage.o tools/lib/md5.o tools/lpc32xximage.o tooaimage.o tools/lib/sha1.o tools/lib/sha256.o tools/common/hash.o tools/ublimage.o tools/zynqimage.o tools/lib/lib.o tools/dumpimage.o
      cc -Wp,-MD,tools/.mkimage.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer   -include ./include/libfdt_en.o tools/mkimage.c
      cc  -o tools/mkimage tools/aisimage.o tools/atmelimage.o tools/common/bootm.o tools/lib/crc32.o tools/default_iols/common/image.o tools/imagetool.o tools/imximage.o tools/kwbimage.o tools/lib/md5.o tools/lpc32xximage.o toolsmage.o tools/lib/sha1.o tools/lib/sha256.o tools/common/hash.o tools/ublimage.o tools/zynqimage.o tools/lib/libfd tools/mkimage.o
    make -f ./scripts/Makefile.build obj=arch/arm/cpu
    make -f ./scripts/Makefile.build obj=arch/arm/cpu/arm920t
    make -f ./scripts/Makefile.build obj=arch/arm/cpu/arm920t/s3c24x0
    make -f ./scripts/Makefile.build obj=arch/arm/lib
    make -f ./scripts/Makefile.build obj=board/samsung/common
    make -f ./scripts/Makefile.build obj=board/samsung/smdk2410
    make -f ./scripts/Makefile.build obj=cmd
      arm-linux-gcc -Wp,-MD,cmd/.version.o.d  -nostdinc -isystem /usr/local/arm/4.3.2/bin/../lib/gcc/arm-none-linux-g-ffreestanding -Os -fno-stack-protector -fno-delete-null-pointer-checks -g -Wno-format-nonliteral -D__ARM__ -marmTR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(version)"  -D"KBUILD_MODNAME=KBUILD_STR(version)" -c -o cmd/version.o cmd
       arm-linux-ld     -r -o cmd/built-in.o cmd/boot.o cmd/bootm.o cmd/help.o cmd/version.o cmd/source.o cmd/bdinfo.cmd/net.o cmd/pcmcia.o cmd/reginfo.o cmd/test.o cmd/ubi.o cmd/ubifs.o cmd/usb.o cmd/ximg.o cmd/yaffs2.o cmd/nvedi
    make -f ./scripts/Makefile.build obj=common
    make -f ./scripts/Makefile.build obj=common/init
      arm-linux-gcc -Wp,-MD,common/.main.o.d  -nostdinc -isystem /usr/local/arm/4.3.2/bin/../lib/gcc/arm-none-linux-g-ffreestanding -Os -fno-stack-protector -fno-delete-null-pointer-checks -g -Wno-format-nonliteral -D__ARM__ -marmTR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(main)"  -D"KBUILD_MODNAME=KBUILD_STR(main)" -c -o common/main.o common/ma
      arm-linux-gcc -Wp,-MD,common/.board_f.o.d  -nostdinc -isystem /usr/local/arm/4.3.2/bin/../lib/gcc/arm-none-linuin -ffreestanding -Os -fno-stack-protector -fno-delete-null-pointer-checks -g -Wno-format-nonliteral -D__ARM__ -mD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(board_f)"  -D"KBUILD_MODNAME=KBUILD_STR(board_f)" -c -o common/board_f
       arm-linux-ld     -r -o common/built-in.o common/init/built-in.o common/main.o common/exports.o common/hash.o cags.o common/env_flash.o common/usb.o common/usb_hub.o common/usb_storage.o common/flash.o common/splash.o common/command.o common/s_record.o common/xyzModem.o
    make -f ./scripts/Makefile.build obj=disk
    make -f ./scripts/Makefile.build obj=drivers
    make -f ./scripts/Makefile.build obj=drivers/adc
    make -f ./scripts/Makefile.build obj=drivers/block
    make -f ./scripts/Makefile.build obj=drivers/crypto
    make -f ./scripts/Makefile.build obj=drivers/crypto/fsl
    make -f ./scripts/Makefile.build obj=drivers/crypto/rsa_mod_exp
    make -f ./scripts/Makefile.build obj=drivers/dfu
    make -f ./scripts/Makefile.build obj=drivers/hwmon
    make -f ./scripts/Makefile.build obj=drivers/input
    make -f ./scripts/Makefile.build obj=drivers/memory
    make -f ./scripts/Makefile.build obj=drivers/misc
    make -f ./scripts/Makefile.build obj=drivers/pcmcia
    make -f ./scripts/Makefile.build obj=drivers/pwm
    make -f ./scripts/Makefile.build obj=drivers/rtc
    make -f ./scripts/Makefile.build obj=drivers/soc
    make -f ./scripts/Makefile.build obj=drivers/sound
    make -f ./scripts/Makefile.build obj=drivers/spmi
    make -f ./scripts/Makefile.build obj=drivers/thermal
    make -f ./scripts/Makefile.build obj=drivers/timer
    make -f ./scripts/Makefile.build obj=drivers/tpm
    make -f ./scripts/Makefile.build obj=drivers/twserial
    make -f ./scripts/Makefile.build obj=drivers/video
    make -f ./scripts/Makefile.build obj=drivers/video/bridge
    make -f ./scripts/Makefile.build obj=drivers/watchdog
    make -f ./scripts/Makefile.build obj=drivers/dma
    make -f ./scripts/Makefile.build obj=drivers/gpio
    make -f ./scripts/Makefile.build obj=drivers/i2c
    make -f ./scripts/Makefile.build obj=drivers/mmc
    make -f ./scripts/Makefile.build obj=drivers/mtd
    make -f ./scripts/Makefile.build obj=drivers/mtd/nand
    make -f ./scripts/Makefile.build obj=drivers/mtd/onenand
    make -f ./scripts/Makefile.build obj=drivers/mtd/spi
    make -f ./scripts/Makefile.build obj=drivers/mtd/ubi
    make -f ./scripts/Makefile.build obj=drivers/net
    make -f ./scripts/Makefile.build obj=drivers/net/phy
    make -f ./scripts/Makefile.build obj=drivers/pci
    make -f ./scripts/Makefile.build obj=drivers/power
    make -f ./scripts/Makefile.build obj=drivers/power/battery
    make -f ./scripts/Makefile.build obj=drivers/power/fuel_gauge
    make -f ./scripts/Makefile.build obj=drivers/power/mfd
    make -f ./scripts/Makefile.build obj=drivers/power/pmic
    make -f ./scripts/Makefile.build obj=drivers/power/regulator
    make -f ./scripts/Makefile.build obj=drivers/serial
    make -f ./scripts/Makefile.build obj=drivers/spi
    make -f ./scripts/Makefile.build obj=drivers/usb/common
    make -f ./scripts/Makefile.build obj=drivers/usb/dwc3
    make -f ./scripts/Makefile.build obj=drivers/usb/emul
    make -f ./scripts/Makefile.build obj=drivers/usb/eth
    make -f ./scripts/Makefile.build obj=drivers/usb/gadget
    make -f ./scripts/Makefile.build obj=drivers/usb/gadget/udc
    make -f ./scripts/Makefile.build obj=drivers/usb/host
    make -f ./scripts/Makefile.build obj=drivers/usb/musb-new
    make -f ./scripts/Makefile.build obj=drivers/usb/musb
    make -f ./scripts/Makefile.build obj=drivers/usb/phy
    make -f ./scripts/Makefile.build obj=drivers/usb/ulpi
    make -f ./scripts/Makefile.build obj=fs
    make -f ./scripts/Makefile.build obj=fs/ext4
    make -f ./scripts/Makefile.build obj=fs/fat
    make -f ./scripts/Makefile.build obj=fs/ubifs
    make -f ./scripts/Makefile.build obj=fs/yaffs2
    make -f ./scripts/Makefile.build obj=lib
    make -f ./scripts/Makefile.build obj=lib/bzip2
    make -f ./scripts/Makefile.build obj=lib/lzma
    make -f ./scripts/Makefile.build obj=lib/lzo
    make -f ./scripts/Makefile.build obj=lib/zlib
      arm-linux-gcc -Wp,-MD,lib/.display_options.o.d  -nostdinc -isystem /usr/local/arm/4.3.2/bin/../lib/gcc/arm-nonebuiltin -ffreestanding -Os -fno-stack-protector -fno-delete-null-pointer-checks -g -Wno-format-nonliteral -D__ARMKBUILD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(display_options)"  -D"KBUILD_MODNAME=KBUILD_STR(display_options)"
       arm-linux-ld     -r -o lib/built-in.o lib/lzma/built-in.o lib/lzo/built-in.o lib/zlib/built-in.o lib/bzip2/bui/hashtable.o lib/errno.o lib/display_options.o lib/crc32.o lib/ctype.o lib/div64.o lib/hang.o lib/linux_compat.o
    make -f ./scripts/Makefile.build obj=net
    make -f ./scripts/Makefile.build obj=test
    make -f ./scripts/Makefile.build obj=test/dm
    make -f ./scripts/Makefile.build obj=examples
    make -f ./scripts/Makefile.build obj=examples/standalone
      arm-linux-ld   -pie  --gc-sections -Bstatic -Ttext 0x0 -o u-boot -T u-boot.lds arch/arm/cpu/arm920t/start.o --sn.o  common/built-in.o  disk/built-in.o  drivers/built-in.o  drivers/dma/built-in.o  drivers/gpio/built-in.o  dribuilt-in.o  drivers/net/built-in.o  drivers/net/phy/built-in.o  drivers/pci/built-in.o  drivers/power/built-in.o rs/serial/built-in.o  drivers/spi/built-in.o  drivers/usb/common/built-in.o  drivers/usb/dwc3/built-in.o  drivers.o  drivers/usb/musb/built-in.o  drivers/usb/phy/built-in.o  drivers/usb/ulpi/built-in.o  fs/built-in.o  lib/buil -lgcc -Map u-boot.map
      arm-linux-objcopy --gap-fill=0xff  -j .text -j .secure_text -j .rodata -j .hash -j .data -j .got -j .got.plt -j
      arm-linux-objcopy --gap-fill=0xff  -j .text -j .secure_text -j .rodata -j .hash -j .data -j .got -j .got.plt -j
      cp u-boot-nodtb.bin u-boot.bin
      arm-linux-objdump -t u-boot > u-boot.sym

    我们大致看一下输出能容,主要包括以下两点:

    • 先利用./scripts/Makefile.build编译各个built-in.o目标文件;

    • 再将各个bult-in.o文件链接成u-boot;

    二、 u-boot.lds

    想要分析启动流程,第一步就是分析链接文件,弄清楚程序入口是哪里。在分析Makefile中,u-boot的依赖中可以看到链接脚本文件是u-boot.lds,u-boot.lds依赖于$(LDSCRIPT)和prepare。

    通过对u-boot源代码编译会在顶层目录生成u-boot.lds,打开u-boot.lds:

    $(LDSCRIPT)变量值为arch/arm/cpu/u-boot.lds,定位到该文件:

    #include <config.h>
    
    OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
    OUTPUT_ARCH(arm)
    ENTRY(_start)
    SECTIONS
    {
    #ifndef CONFIG_CMDLINE
        /DISCARD/ : { *(.u_boot_list_2_cmd_*) }
    #endif
    #if defined(CONFIG_ARMV7_SECURE_BASE) && defined(CONFIG_ARMV7_NONSEC)
        /*
         * If CONFIG_ARMV7_SECURE_BASE is true, secure code will not
         * bundle with u-boot, and code offsets are fixed. Secure zone
         * only needs to be copied from the loading address to
         * CONFIG_ARMV7_SECURE_BASE, which is the linking and running
         * address for secure code.
         *
         * If CONFIG_ARMV7_SECURE_BASE is undefined, the secure zone will
         * be included in u-boot address space, and some absolute address
         * were used in secure code. The absolute addresses of the secure
         * code also needs to be relocated along with the accompanying u-boot
         * code.
         *
         * So DISCARD is only for CONFIG_ARMV7_SECURE_BASE.
         */
        /DISCARD/ : { *(.rel._secure*) }
    #endif
        . = 0x00000000;
    
        . = ALIGN(4);
        .text :
        {
            *(.__image_copy_start)
            *(.vectors)
            CPUDIR/start.o (.text*)
            *(.text*)
        }
    
    #ifdef CONFIG_ARMV7_NONSEC
    
    #ifndef CONFIG_ARMV7_SECURE_BASE
    #define CONFIG_ARMV7_SECURE_BASE
    #endif
    
        .__secure_start : {
            . = ALIGN(0x1000);
            *(.__secure_start)
        }
    
        .secure_text CONFIG_ARMV7_SECURE_BASE :
            AT(ADDR(.__secure_start) + SIZEOF(.__secure_start))
        {
            *(._secure.text)
        }
    
        . = LOADADDR(.__secure_start) +
            SIZEOF(.__secure_start) +
            SIZEOF(.secure_text);
    
        __secure_end_lma = .;
        .__secure_end : AT(__secure_end_lma) {
            *(.__secure_end)
            LONG(0x1d1071c);    /* Must output something to reset LMA */
        }
    #endif
    
        . = ALIGN(4);
        .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
    
        . = ALIGN(4);
        .data : {
            *(.data*)
        }
    
        . = ALIGN(4);
    
        . = .;
    
        . = ALIGN(4);
        .u_boot_list : {
            KEEP(*(SORT(.u_boot_list*)));
        }
    
        . = ALIGN(4);
    
        .__efi_runtime_start : {
            *(.__efi_runtime_start)
        }
    
        .efi_runtime : {
            *(efi_runtime_text)
            *(efi_runtime_data)
        }
    
        .__efi_runtime_stop : {
            *(.__efi_runtime_stop)
        }
    
        .efi_runtime_rel_start :
        {
            *(.__efi_runtime_rel_start)
        }
    
        .efi_runtime_rel : {
            *(.relefi_runtime_text)
            *(.relefi_runtime_data)
        }
    
        .efi_runtime_rel_stop :
        {
            *(.__efi_runtime_rel_stop)
        }
    
        . = ALIGN(4);
    
        .image_copy_end :
        {
            *(.__image_copy_end)
        }
    
        .rel_dyn_start :
        {
            *(.__rel_dyn_start)
        }
    
        .rel.dyn : {
            *(.rel*)
        }
    
        .rel_dyn_end :
        {
            *(.__rel_dyn_end)
        }
    
        .end :
        {
            *(.__end)
        }
    
        _image_binary_end = .;
    
        /*
         * Deprecated: this MMU section is used by pxa at present but
         * should not be used by new boards/CPUs.
         */
        . = ALIGN(4096);
        .mmutable : {
            *(.mmutable)
        }
    
    /*
     * Compiler-generated __bss_start and __bss_end, see arch/arm/lib/bss.c
     * __bss_base and __bss_limit are for linker only (overlay ordering)
     */
    
        .bss_start __rel_dyn_start (OVERLAY) : {
            KEEP(*(.__bss_start));
            __bss_base = .;
        }
    
        .bss __bss_base (OVERLAY) : {
            *(.bss*)
             . = ALIGN(4);
             __bss_limit = .;
        }
    
        .bss_end __bss_limit (OVERLAY) : {
            KEEP(*(.__bss_end));
        }
    
        .dynsym _image_binary_end : { *(.dynsym) }
        .dynbss : { *(.dynbss) }
        .dynstr : { *(.dynstr*) }
        .dynamic : { *(.dynamic*) }
        .plt : { *(.plt*) }
        .interp : { *(.interp*) }
        .gnu.hash : { *(.gnu.hash) }
        .gnu : { *(.gnu*) }
        .ARM.exidx : { *(.ARM.exidx*) }
        .gnu.linkonce.armexidx : { *(.gnu.linkonce.armexidx.*) }
    }
    • OUTPUT_FORMAT:指定输出可执行文件是elf格式,32位ARM指令,小端;
    • OUTPUT_ARCH:指出输出可执行文件的平台是ARM;
    • ENTRY:指定输出可执行文件的起始入口码段是_start,_start在arch/arm/cpu/armv7/start.S;
    • 0x00000000是程序的链接起始地点,arm-linux-ld最终生成的uboot.bin链接地址是从0x00000000开始;
    • .text{}:声明该段是代码段,在此段中依次存放section(.__image_copy_start)、section(.vectors)、 section(start.o中所有的代码段 (.text*))、section(*(.text*))剩余的所有代码段。
      • *(.__image_copy_start):这里比较有意思的是section(.__image_copy_start),在arch/arm/lib/sections.c中有如下定义:
        char __image_copy_start[0] __attribute__((section(".__image_copy_start")));
        这是一个0长度的数组,GNU 对C的扩展,实际达到的目的就是section(.__image_copy_start)在链接时不占用链接地址空间,其后的section(.vectors)起始地址依然是0x00000000,然后在__image_copy_start存放了一个地址,也就是0x00000000,相当于创建一个位置标签;代表程序重定位(relocate)时拷贝的起始地址;
      • *(.vectors):字面上的意思就是向量段,在arch/arm/lib/vectors.S中定义了.verctos段:.section ".vectors", "ax";这是一个自定义的段标签的伪操作,含义是:定义一个段标签名为.vectors,且为允许、可执行段;
      • CPUDIR/start.o (.text*):CPUDIR在根目录的Makefile中定义,根据芯片;选择不同的start.S编译,编译出的start.o中.text段,链接到此处;在这里CPUDIR=arch/arm/cpu/arm920t;
      • *(.text*):剩余所有的代码都放到此段;
    • .rodata{}:声明只读数据段,简称rodata段,存放常量,字符常量,const常量,据说还存放调试信息;
    • .data{}:声明初始化数据段(Initialized data segment),简称data段,存放程序中已经初始化全局与初始化静态变量;
    • .bss{}:声明未始化数据段(Uninitialized data segment),简称bss段,存放程序中未初始化全局与未初始化静态变量,该区域会在程序载入时由内核清零;

    __image_copy_start、__image_copy_end用于u-boot搬移本身image到指定的ddr地址处;

    __rel_dyn_start、__rel_dyn_end用于重定位代码;

    __bss_start、__bss_end是bss段的开始、结束地址;

    这几个变量在arch/arm/lib/sections.c中使用,定义一些全局变量作用于各个段的起始地址:

    //C文件中利用这种方式把一个变量或者函数标记到指定段。
    char __bss_start[0] __attribute__((section(".__bss_start")));
    char __bss_end[0] __attribute__((section(".__bss_end")));
    char __image_copy_start[0] __attribute__((section(".__image_copy_start")));
    char __image_copy_end[0] __attribute__((section(".__image_copy_end")));
    char __rel_dyn_start[0] __attribute__((section(".__rel_dyn_start")));
    char __rel_dyn_end[0] __attribute__((section(".__rel_dyn_end")));
    char __secure_start[0] __attribute__((section(".__secure_start")));
    char __secure_end[0] __attribute__((section(".__secure_end")));

    我们接下来分析start.S,程序的第一条指令就是在arch/arm/cpu/arm920t/start.S中。

    三、分析start.S(arch/arm/cpu/arm920t/start.S)

    /*
     *  armboot - Startup Code for ARM920 CPU-core
     *
     *  Copyright (c) 2001  Marius Gröger <mag@sysgo.de>
     *  Copyright (c) 2002  Alex Züpke <azu@sysgo.de>
     *  Copyright (c) 2002  Gary Jennejohn <garyj@denx.de>
     *
     * SPDX-License-Identifier: GPL-2.0+
     */
    
    #include <asm-offsets.h>
    #include <common.h>
    #include <config.h>
    
    /*
     *************************************************************************
     *
     * Startup Code (called from the ARM reset exception vector)
     *
     * do important init only if we don't start from memory!
     * relocate armboot to ram
     * setup stack
     * jump to second stage
     *
     *************************************************************************
     */
    
        .globl  reset
    
    reset:
        /*
         * set the cpu to SVC32 mode    1. 设置为SVC模式
         */
        mrs r0, cpsr
        bic r0, r0, #0x1f
        orr r0, r0, #0xd3
        msr cpsr, r0    
    
    #if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK)
        /*
         * relocate exception table
         */
        ldr r0, =_start
        ldr r1, =0x0
        mov r2, #16
    copyex:
        subs    r2, r2, #1
        ldr r3, [r0], #4
        str r3, [r1], #4
        bne copyex
    #endif
    
    #ifdef CONFIG_S3C24X0
        /* turn off the watchdog */
    
    # if defined(CONFIG_S3C2400)
    #  define pWTCON    0x15300000
    #  define INTMSK    0x14400008  /* Interrupt-Controller base addresses */
    #  define CLKDIVN   0x14800014  /* clock divisor register */
    #else
    #  define pWTCON    0x53000000  /* 看门狗控制寄存器地址 */
    #  define INTMSK    0x4A000008  /* Interrupt-Controller base addresses */
    #  define INTSUBMSK 0x4A00001C
    #  define CLKDIVN   0x4C000014  /* clock divisor register */
    # endif
    
        ldr r0, =pWTCON        //2. 关看门狗
        mov r1, #0x0
        str r1, [r0]
    
        /*
         * mask all IRQs by setting all bits in the INTMR - default
         */
        mov r1, #0xffffffff    //3. 屏蔽中断
        ldr r0, =INTMSK
        str r1, [r0]
    # if defined(CONFIG_S3C2410)
        ldr r1, =0x3ff
        ldr r0, =INTSUBMSK
        str r1, [r0]
    # endif
    
        /* FCLK:HCLK:PCLK = 1:2:4 */
        /* default FCLK is 120 MHz ! */
        ldr r0, =CLKDIVN      //4. 设置分频系数,未设置时钟频率
        mov r1, #3
        str r1, [r0]
    #endif  /* CONFIG_S3C24X0 */
    
        /*
         * we do sys-critical inits only at reboot,
         * not when booting from ram!
         */
    #ifndef CONFIG_SKIP_LOWLEVEL_INIT
        bl  cpu_init_crit    //5. 跳到cpu_init_crit函数
    #endif
    
        bl  _main           //6. 进入arch/arm/lib/crt0.S的_main函数,进行其他初始化
    
    /*------------------------------------------------------------------------------*/
    
        .globl  c_runtime_cpu_setup
    c_runtime_cpu_setup:
    
        mov pc, lr
    
    /*
     *************************************************************************
     *
     * CPU_init_critical registers
     *
     * setup important registers
     * setup memory timing
     *
     *************************************************************************
     */
    
    
    #ifndef CONFIG_SKIP_LOWLEVEL_INIT
    cpu_init_crit:
        /*
         * flush v4 I/D caches      [1]. 清除cache
         */
        mov r0, #0
        mcr p15, 0, r0, c7, c7, 0   /* flush v3/v4 cache */
        mcr p15, 0, r0, c8, c7, 0   /* flush v4 TLB */
    
        /*
         * disable MMU stuff and caches  [2]. 禁止MMU
         */
        mrc p15, 0, r0, c1, c0, 0
        bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)
        bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)
        orr r0, r0, #0x00000002 @ set bit 1 (A) Align
        orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache
        mcr p15, 0, r0, c1, c0, 0
    
    #ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLY
        /*
         * before relocating, we have to setup RAM timing
         * because memory timing is board-dependend, you will
         * find a lowlevel_init.S in your board directory.
         */
        mov ip, lr
    
        bl  lowlevel_init          //[3]. 进入board/samsung/smdk2410/lowlevel_init.S执行,
                                   //     设置内存控制寄存器时序参数
        mov lr, ip
    #endif
        mov pc, lr
    #endif /* CONFIG_SKIP_LOWLEVEL_INIT */

    我们总结以下start.S文件主要做了哪些事情:

    • 开启SVC模式,关闭fiq,irq中断;
    • 关闭看门狗
    • 屏蔽所有中断;

    • 设置系统时钟;

    • 执行cpu_init_crit函数;

      • 关闭关闭MMU和cache;
      • 执行lowlevel_init函数(board/samsung/smdk2410/lowlevel_init.S),初始化SDRAM;
    • 执行_main(arch/arm/lib/crt0.S);

    四、make编译过程

    make在编译过程中,会根据不用的obj,编译生成相应的xxx/.../xxxx/built-in.o文件。

    make -f ./scripts/Makefile.build obj=目标路径  #执行目标下的Makefile生成build-in.o

    然后由这些文件最终链接连接成u-boot文件:

      arm-linux-ld   -pie  --gc-sections -Bstatic -Ttext 0x0 -o u-boot -T u-boot.lds arch/arm/cpu/arm920t/start.o --sn.o  common/built-in.o  disk/built-in.o  drivers/built-in.o  drivers/dma/built-in.o  drivers/gpio/built-in.o  dribuilt-in.o  drivers/net/built-in.o  drivers/net/phy/built-in.o  drivers/pci/built-in.o  drivers/power/built-in.o rs/serial/built-in.o  drivers/spi/built-in.o  drivers/usb/common/built-in.o  drivers/usb/dwc3/built-in.o  drivers.o  drivers/usb/musb/built-in.o  drivers/usb/phy/built-in.o  drivers/usb/ulpi/built-in.o  fs/built-in.o  lib/buil -lgcc -Map u-boot.map

    不知道你们有没有留意到吗,在make的编译过程中,有以下几个步骤:

    make -f ./scripts/Makefile.build obj=arch/arm/cpu
    make -f ./scripts/Makefile.build obj=arch/arm/cpu/arm920t
    make -f ./scripts/Makefile.build obj=arch/arm/cpu/arm920t/s3c24x0

    我们从最后一个来说,这里将会跳转到./script/Makefile.build文件中去执行,然后include obj路径下的Makefile文件,即arch/arm/cpu/arm920t/s3c24x0/Makefile。

    4.1 arch/arm/cpu/arm920t/s3c24x0/Makefile

    arch/arm/cpu/arm920t/s3c24x0/Makefile:

    #
    # (C) Copyright 2000-2006
    # Wolfgang Denk, DENX Software Engineering, wd@denx.de.
    #
    # SPDX-License-Identifier:    GPL-2.0+
    #
    
    obj-$(CONFIG_USE_IRQ) += interrupts.o
    obj-$(CONFIG_DISPLAY_CPUINFO)    += cpu_info.o
    obj-y    += speed.o
    obj-y    += timer.o

    obj-y是在./script/Makefile.build文件中定义:

    obj-y :=

    最终目标arch/arm/cpu/arm920t/s3c24x0/built-in.o依赖的obj-y如下:

    • arch/arm/cpu/arm920t/s3c24x0/cpu_info.o
    • arch/arm/cpu/arm920t/s3c24x0/speed.o
    • arch/arm/cpu/arm920t/s3c24x0/timer.o

    4.2 arch/arm/cpu/arm920t/Makefile

    同理,arch/arm/cpu/arm920t/Makefile:

    #
    # (C) Copyright 2000-2006
    # Wolfgang Denk, DENX Software Engineering, wd@denx.de.
    #
    # SPDX-License-Identifier:    GPL-2.0+
    #
    
    extra-y    = start.o
    
    obj-y    += cpu.o
    obj-$(CONFIG_USE_IRQ)    += interrupts.o
    
    obj-$(CONFIG_EP93XX) += ep93xx/
    obj-$(CONFIG_IMX) += imx/
    obj-$(CONFIG_S3C24X0) += s3c24x0/  #以%/结尾最终会被替换成%/built-in.o
    
    # some files can only build in ARM mode
    
    ifdef CONFIG_SYS_THUMB_BUILD
    CFLAGS_cpu.o := -marm
    endif

    最终目标arch/arm/cpu/arm920t/built-in.o以来的obj-y如下:

    • arch/arm/cpu/arm920t/cpu.o
    • arch/arm/cpu/arm920t/s3c24x0/built-in.o

    4.3 arch/arm/cpu/Makefile

    arch/arm/cpu/Makefile:

    #
    # SPDX-License-Identifier:    GPL-2.0+
    #
    
    obj- += dummy.o

    最终obj-y为空,所以生成的arch/arm/cpu/built-in.o文件实际是空的。

    4.4 ./scripts/Makefile.build

    我们在之前介绍过,u-boot目标依赖于$(u-boot-main)、$(u-boot-init)、u-boot.lds。

    u-boot-init := $(head-y)
    u-boot-main := $(libs-y)

    而libs-y由若干个以built-in.o结尾的文件组成,lib-y大致如下:

    libs-y = lib/built-in.o fs/built-in.o net/built-in.o disk/built-in.o drivers/built-in.o drivers/dma/built-in.o drivers/gpio/built-in.o ...

    而libs-y中的各个built-in.o文件由./scripts/Makefile.build编译而成:

    ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)),)
    builtin-target := $(obj)/built-in.o
    endif
    $(builtin-target): $(obj-y) FORCE
        $(call if_changed,link_o_target)

     

    比如make -f ./scripts/Makefile.build obj=arch/arm/cpu编译生成了arch/arm/cpu/build-in.o(builtin-target=arch/arm/cpu/built-in.o)。

    而obj-y是由若干个.o目标文件组成,这里我将上面三条步骤中的obj-y输出,如下:

    make -f ./scripts/Makefile.build obj=arch/arm/cpu
    make -f ./scripts/Makefile.build obj=arch/arm/cpu/arm920t
    make -f ./scripts/Makefile.build obj=arch/arm/cpu/arm920t/s3c24x0
    ---------------------------------------
    arch/arm/cpu/arm920t/s3c24x0/cpu_info.o arch/arm/cpu/arm920t/s3c24x0/speed.o arch/arm/cpu/arm920t/s3c24x0/timer.o
    arch/arm/cpu/arm920t/cpu.o arch/arm/cpu/arm920t/s3c24x0/built-in.o
    不存在

    obj-y依赖的.o文件又是怎么生成的,生成规则也是在./scripts/Makefile.build有定义:

    $(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE
        $(call cmd,force_checksrc)
        $(call if_changed_rule,cc_o_c)

    这里src可以看做和obj相同:

    • 当obj=arch/arm/cpu时,即定义了arch/arm/cpu/%.o文件的生成规则;
    • 当obj=arch/arm/cpu/arm920t时,即定义了arch/arm/cpu/arm920t/%.o文件的生成规则;
    • 当obj=arch/arm/cpu/arm920t/s3c24x0时,即定义了arch/arm/cpu/arm920t/s3c24x0/%.o文件的生成规则;

    命令中的if_changed_rule函数定义在scripts/Kbuild.include文件中

    # Usage: $(call if_changed_rule,foo)
    # Will check if $(cmd_foo) or any of the prerequisites changed,
    # and if so will execute $(rule_foo).
    if_changed_rule = $(if $(strip $(any-prereq) $(arg-check) ),                 
        @set -e;                                                             
        $(rule_$(1)))

    在./scripts/Makefile.build有如下定义:

    define rule_cc_o_c
        $(call echo-cmd,checksrc) $(cmd_checksrc)              
        $(call echo-cmd,cc_o_c) $(cmd_cc_o_c);                  
        $(cmd_modversions)                          
        $(call echo-cmd,record_mcount)                      
        $(cmd_record_mcount)                          
        scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,cc_o_c)' >    
                                                      $(dot-target).tmp;  
        rm -f $(depfile);                          
        mv -f $(dot-target).tmp $(dot-target).cmd
    endef
    cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<

    所以调用$(call if_changed_rule,cc_o_c)等价于执行cmd_cc_o_c。

    这里我们重点介绍一下cmc_cc_o_c,因为这里在使用arm-linux-gcc编译时指定了c_flags参数(在顶层Makefile中定义):

       ifeq ($(dot-config),1)
       # Read in config
      -include include/config/auto.conf

    # Use UBOOTINCLUDE when you must reference the include/ directory.
    # Needed to be compatible with the O= option
    UBOOTINCLUDE    := 
            -Iinclude 
            $(if $(KBUILD_SRC), -I$(srctree)/include) 
            $(if $(CONFIG_SYS_THUMB_BUILD), $(if $(CONFIG_HAS_THUMB2),, 
                -I$(srctree)/arch/$(ARCH)/thumb1/include),) 
            -I$(srctree)/arch/$(ARCH)/include 
            -include $(srctree)/include/linux/kconfig.h
    
    NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include)
    CHECKFLAGS     += $(NOSTDINC_FLAGS)
    
    # FIX ME
    cpp_flags := $(KBUILD_CPPFLAGS) $(PLATFORM_CPPFLAGS) $(UBOOTINCLUDE) 
                                $(NOSTDINC_FLAGS)
    c_flags := $(KBUILD_CFLAGS) $(cpp_flags)

    include/config/auto.conf.cmd是由fixdep在编译时生成的依赖文件,主要定义了常量,包含CPU信息、系统配置参数:

    这里我们重点关注UBOOTINCLUDE和PLATFORM_CPPFLAGS:

    • PLATFORM_CPPFLAGS是干嘛用的呢,之前我们介绍过built-in.o在生成时,依赖若干个.o目标文件,这些.o文件在生成时也会引入一些头文件,这些头文件一般都位于built-in.o同路径下得include 文件下,通过-I参数指定搜索的头路径,从而将这些头文件包含进来,比如arcm/arm/Makefile文件中指定了(需要注意的是这个追加的参数只有在编译arcm/arm/built-in.o时有效):
    PLATFORM_CPPFLAGS += $(patsubst %,-I$(srctree)/%include,$(machdirs))
    • UBOOTINCLUDE 引入了./include、./arch/arm/include目录下的头文件、以及./include/linux/kconfig.h文件。

    4.5 arch/arm/Makefile

    arch/arm/Makefile:

    #
    # SPDX-License-Identifier:    GPL-2.0+
    #
    
    ifeq ($(CONFIG_SPL_BUILD)$(CONFIG_TEGRA),yy)
    CONFIG_CPU_V7=
    CONFIG_CPU_ARM720T=y
    endif
    
    # This selects which instruction set is used.
    arch-$(CONFIG_CPU_ARM720T)    =-march=armv4
    arch-$(CONFIG_CPU_ARM920T)    =-march=armv4t
    arch-$(CONFIG_CPU_ARM926EJS)    =-march=armv5te
    arch-$(CONFIG_CPU_ARM946ES)    =-march=armv4
    arch-$(CONFIG_CPU_SA1100)    =-march=armv4
    arch-$(CONFIG_CPU_PXA)        =
    arch-$(CONFIG_CPU_ARM1136)    =-march=armv5
    arch-$(CONFIG_CPU_ARM1176)    =-march=armv5t
    arch-$(CONFIG_CPU_V7)        =$(call cc-option, -march=armv7-a, 
                     $(call cc-option, -march=armv7, -march=armv5))
    arch-$(CONFIG_ARM64)        =-march=armv8-a
    
    # Evaluate arch cc-option calls now
    arch-y := $(arch-y)
    
    # This selects how we optimise for the processor.
    tune-$(CONFIG_CPU_ARM720T)    =-mtune=arm7tdmi
    tune-$(CONFIG_CPU_ARM920T)    =
    tune-$(CONFIG_CPU_ARM926EJS)    =
    tune-$(CONFIG_CPU_ARM946ES)    =
    tune-$(CONFIG_CPU_SA1100)    =-mtune=strongarm1100
    tune-$(CONFIG_CPU_PXA)        =-mcpu=xscale
    tune-$(CONFIG_CPU_ARM1136)    =
    tune-$(CONFIG_CPU_ARM1176)    =
    tune-$(CONFIG_CPU_V7)        =
    tune-$(CONFIG_ARM64)        =
    
    # Evaluate tune cc-option calls now
    tune-y := $(tune-y)
    
    PLATFORM_CPPFLAGS += $(arch-y) $(tune-y)
    
    # Machine directory name.  This list is sorted alphanumerically
    # by CONFIG_* macro name.
    machine-$(CONFIG_ARCH_AT91)        += at91
    machine-$(CONFIG_ARCH_BCM283X)        += bcm283x
    machine-$(CONFIG_ARCH_DAVINCI)        += davinci
    machine-$(CONFIG_ARCH_EXYNOS)        += exynos
    machine-$(CONFIG_ARCH_HIGHBANK)        += highbank
    machine-$(CONFIG_ARCH_KEYSTONE)        += keystone
    # TODO: rename CONFIG_KIRKWOOD -> CONFIG_ARCH_KIRKWOOD
    machine-$(CONFIG_KIRKWOOD)        += kirkwood
    machine-$(CONFIG_ARCH_MVEBU)        += mvebu
    # TODO: rename CONFIG_TEGRA -> CONFIG_ARCH_TEGRA
    # TODO: rename CONFIG_ORION5X -> CONFIG_ARCH_ORION5X
    machine-$(CONFIG_ORION5X)        += orion5x
    machine-$(CONFIG_ARCH_S5PC1XX)        += s5pc1xx
    machine-$(CONFIG_ARCH_SUNXI)        += sunxi
    machine-$(CONFIG_ARCH_SNAPDRAGON)    += snapdragon
    machine-$(CONFIG_ARCH_SOCFPGA)        += socfpga
    machine-$(CONFIG_ARCH_ROCKCHIP)        += rockchip
    machine-$(CONFIG_STM32)            += stm32
    machine-$(CONFIG_TEGRA)            += tegra
    machine-$(CONFIG_ARCH_UNIPHIER)        += uniphier
    machine-$(CONFIG_ARCH_ZYNQ)        += zynq
    
    machdirs := $(patsubst %,arch/arm/mach-%/,$(machine-y))    #取出$(machine-y)所有值,并替换追加arch/arm/mach-xx/  这里machdirs最终为空
    
    PLATFORM_CPPFLAGS += $(patsubst %,-I$(srctree)/%include,$(machdirs))  #machdirs路径下的include文件  gcc编译时,头文件指定
    
    libs-y += $(machdirs)
    
    head-y := arch/arm/cpu/$(CPU)/start.o
    
    ifeq ($(CONFIG_SPL_BUILD),y)
    ifneq ($(CONFIG_SPL_START_S_PATH),)
    head-y := $(CONFIG_SPL_START_S_PATH:"%"=%)/start.o
    endif
    endif
    
    libs-y += arch/arm/cpu/$(CPU)/
    libs-y += arch/arm/cpu/
    libs-y += arch/arm/lib/
    
    ifeq ($(CONFIG_SPL_BUILD),y)
    ifneq (,$(CONFIG_MX23)$(CONFIG_MX28)$(CONFIG_MX35)$(filter $(SOC), mx25 mx27 mx5 mx6 mx7 mx31 mx35))
    libs-y += arch/arm/imx-common/
    endif
    else
    ifneq (,$(filter $(SOC), mx25 mx27 mx5 mx6 mx7 mx31 mx35 mxs vf610))
    libs-y += arch/arm/imx-common/
    endif
    endif
    
    ifneq (,$(filter $(SOC), kirkwood))
    libs-y += arch/arm/mach-mvebu/
    endif
    
    # deprecated
    -include $(machdirs)/config.mk

    CONFIG_CPU_ARM920T=y在include/config/auto.conf文件中定义,而auto.conf文件是通过./srcipts/Makefile.build文件引入的:

    [root@longmax2002 u-boot-2016.05]# grep "CONFIG_CPU_ARM920T" * -nR
    arch/arm/mach-at91/Makefile:19:obj-$(CONFIG_CPU_ARM920T)        += arm920t/
    arch/arm/Makefile:12:arch-$(CONFIG_CPU_ARM920T) =-march=armv4t
    arch/arm/Makefile:28:tune-$(CONFIG_CPU_ARM920T) =
    drivers/usb/host/ohci-hcd.c:53:#if defined(CONFIG_CPU_ARM920T) || 
    include/config/auto.conf:65:CONFIG_CPU_ARM920T=y
    include/generated/autoconf.h:67:#define CONFIG_CPU_ARM920T 1
    u-boot.cfg:144:#define CONFIG_CPU_ARM920T 1
    -include include/config/auto.conf

    如果想知道machdirs的值,修改该Makefile文件,在变量后面追加:

    print_machdirs::
            @echo "===================== WARNING ======================"
            @echo $(machdirs)
            @echo $(PLATFORM_CPPFLAGS)

    在顶层执行make ARCH=arm CROSS_COMPILE=arm-linux- V=1  print_machdirs,可以获取变量的值:

    其中machdirs为空,arm-linux-gcc编译参数PLATFORM_CPPFLAGS如下:

    -D__ARM__ -marm -mno-thumb-interwork -mabi=aapcs-linux -mword-relocations -fno-pic -ffunction-sections -fdata-sections -fno-common -ffixed-r9 -msoft-float -pipe -march=armv4t

    五 、config.h(./include/config.h)

    start.S文件的开始,#include <config.h>,config.h从哪里来的呢?在上一小节中我们已经介绍了Make在编译过程中,arm-linux-gcc指定了头文件路径:

    • UBOOTINCLUDE:引入了./include、./arch/arm/include目录下的头文件、以及./include/linux/kconfig.h文件。
    • PLATFORM_CPPFLAGS

    至于这里写成#include<config.h>而不是#include<include/config.h>是因为arm-linux-gcc在编译的时候通过-I参数指定了搜索头文件的目录有./include:

    include/config.h文件在make smdk2410_config时创建,主要包含以下信息:

    /* Automatically generated - do not edit */
    #define CONFIG_BOARDDIR board/samsung/smdk2410
    #include <config_defaults.h>
    #include <config_uncmd_spl.h>
    #include <configs/smdk2410.h>
    #include <asm/config.h>
    #include <config_fallbacks.h>

    #include <configs/smdk2410.h> 从这里可以看出在include/configs目录下,包含smdk2410.h文件,如果在board目录下新建一个开发板的目录,则在include/configs目录下要创建一个.h文件,里面存放的开发板配置信息。

    #include <asm/config.h>来自arch/arm/include/asm目录:

    /*
     * Copyright 2009 Freescale Semiconductor, Inc.
     *
     * SPDX-License-Identifier:    GPL-2.0+
     */
    
    #ifndef _ASM_CONFIG_H_
    #define _ASM_CONFIG_H_
    
    #define CONFIG_LMB
    #define CONFIG_SYS_BOOT_RAMDISK_HIGH
    
    #ifdef CONFIG_ARM64
    #define CONFIG_PHYS_64BIT
    #define CONFIG_STATIC_RELA
    #endif
    
    #if defined(CONFIG_LS102XA) || 
        defined(CONFIG_CPU_PXA27X) || 
        defined(CONFIG_CPU_MONAHANS) || 
        defined(CONFIG_CPU_PXA25X) || 
        defined(CONFIG_FSL_LAYERSCAPE)
    #include <asm/arch/config.h>
    #endif
    
    #endif

    六、smdk2410.h(./include/configs/smdk2410.h)

    这个文件很重要,这里主要用来配置编译u-boot时是否启用某些功能,比如网卡,LCD等,如果定义了,那么将会编译相关模块的代码。

    /*
     * (C) Copyright 2002
     * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
     * Marius Groeger <mgroeger@sysgo.de>
     * Gary Jennejohn <garyj@denx.de>
     * David Mueller <d.mueller@elsoft.ch>
     *
     * Configuation settings for the SAMSUNG SMDK2410 board.
     *
     * SPDX-License-Identifier:    GPL-2.0+
     */
    
    #ifndef __CONFIG_H
    #define __CONFIG_H
    
    /*
     * High Level Configuration Options
     * (easy to change)
     */
    #define CONFIG_S3C24X0        /* This is a SAMSUNG S3C24x0-type SoC */
    #define CONFIG_S3C2410        /* specifically a SAMSUNG S3C2410 SoC */
    #define CONFIG_SMDK2410        /* on a SAMSUNG SMDK2410 Board */
    
    #define CONFIG_SYS_TEXT_BASE    0x0
    
    #define CONFIG_SYS_ARM_CACHE_WRITETHROUGH
    
    /* input clock of PLL (the SMDK2410 has 12MHz input clock) */
    #define CONFIG_SYS_CLK_FREQ    12000000
    
    #define CONFIG_CMDLINE_TAG    /* enable passing of ATAGs */
    #define CONFIG_SETUP_MEMORY_TAGS
    #define CONFIG_INITRD_TAG
    
    /*
     * Hardware drivers
     */
    #define CONFIG_CS8900        /* we have a CS8900 on-board */
    #define CONFIG_CS8900_BASE    0x19000300
    #define CONFIG_CS8900_BUS16    /* the Linux driver does accesses as shorts */
    
    /*
     * select serial console configuration
     */
    #define CONFIG_S3C24X0_SERIAL
    #define CONFIG_SERIAL1        1    /* we use SERIAL 1 on SMDK2410 */
    
    /************************************************************
     * USB support (currently only works with D-cache off)
     ************************************************************/
    #define CONFIG_USB_OHCI
    #define CONFIG_USB_OHCI_S3C24XX
    #define CONFIG_USB_KEYBOARD
    #define CONFIG_USB_STORAGE
    #define CONFIG_DOS_PARTITION
    
    /************************************************************
     * RTC
     ************************************************************/
    #define CONFIG_RTC_S3C24X0
    
    #define CONFIG_BAUDRATE        115200
    
    /*
     * BOOTP options
     */
    #define CONFIG_BOOTP_BOOTFILESIZE
    #define CONFIG_BOOTP_BOOTPATH
    #define CONFIG_BOOTP_GATEWAY
    #define CONFIG_BOOTP_HOSTNAME
    
    /*
     * Command line configuration.
     */
    #define CONFIG_CMD_BSP
    #define CONFIG_CMD_DATE
    #define CONFIG_CMD_NAND
    #define CONFIG_CMD_REGINFO
    
    #define CONFIG_CMDLINE_EDITING
    
    /* autoboot */
    #define CONFIG_BOOTDELAY    5
    #define CONFIG_BOOT_RETRY_TIME    -1
    #define CONFIG_RESET_TO_RETRY
    #define CONFIG_ZERO_BOOTDELAY_CHECK
    
    #define CONFIG_NETMASK        255.255.255.0
    #define CONFIG_IPADDR        10.0.0.110
    #define CONFIG_SERVERIP        10.0.0.1
    
    #if defined(CONFIG_CMD_KGDB)
    #define CONFIG_KGDB_BAUDRATE    115200    /* speed to run kgdb serial port */
    #endif
    
    /*
     * Miscellaneous configurable options
     */
    #define CONFIG_SYS_LONGHELP        /* undef to save memory */
    #define CONFIG_SYS_CBSIZE    256
    /* Print Buffer Size */
    #define CONFIG_SYS_PBSIZE    (CONFIG_SYS_CBSIZE + 
                    sizeof(CONFIG_SYS_PROMPT)+16)
    #define CONFIG_SYS_MAXARGS    16
    #define CONFIG_SYS_BARGSIZE    CONFIG_SYS_CBSIZE
    
    #define CONFIG_DISPLAY_CPUINFO                /* Display cpu info */
    
    #define CONFIG_SYS_MEMTEST_START    0x30000000    /* memtest works on */
    #define CONFIG_SYS_MEMTEST_END        0x33F00000    /* 63 MB in DRAM */
    
    #define CONFIG_SYS_LOAD_ADDR        0x30800000
    
    /* support additional compression methods */
    #define CONFIG_BZIP2
    #define CONFIG_LZO
    #define CONFIG_LZMA
    
    /*-----------------------------------------------------------------------
     * Physical Memory Map
     */
    #define CONFIG_NR_DRAM_BANKS    1          /* we have 1 bank of DRAM */
    #define PHYS_SDRAM_1        0x30000000 /* SDRAM Bank #1 */
    #define PHYS_SDRAM_1_SIZE    0x04000000 /* 64 MB */
    
    #define PHYS_FLASH_1        0x00000000 /* Flash Bank #0 */
    
    #define CONFIG_SYS_FLASH_BASE    PHYS_FLASH_1
    
    /*-----------------------------------------------------------------------
     * FLASH and environment organization
     */
    
    #define CONFIG_SYS_FLASH_CFI
    #define CONFIG_FLASH_CFI_DRIVER
    #define CONFIG_FLASH_CFI_LEGACY
    #define CONFIG_SYS_FLASH_LEGACY_512Kx16
    #define CONFIG_FLASH_SHOW_PROGRESS    45
    
    #define CONFIG_SYS_MAX_FLASH_BANKS    1
    #define CONFIG_SYS_FLASH_BANKS_LIST     { CONFIG_SYS_FLASH_BASE }
    #define CONFIG_SYS_MAX_FLASH_SECT    (19)
    
    #define CONFIG_ENV_ADDR            (CONFIG_SYS_FLASH_BASE + 0x070000)
    #define CONFIG_ENV_IS_IN_FLASH
    #define CONFIG_ENV_SIZE            0x10000
    /* allow to overwrite serial and ethaddr */
    #define CONFIG_ENV_OVERWRITE
    
    /*
     * Size of malloc() pool
     * BZIP2 / LZO / LZMA need a lot of RAM
     */
    #define CONFIG_SYS_MALLOC_LEN    (4 * 1024 * 1024)
    
    #define CONFIG_SYS_MONITOR_LEN    (448 * 1024)
    #define CONFIG_SYS_MONITOR_BASE    CONFIG_SYS_FLASH_BASE
    
    /*
     * NAND configuration
     */
    #ifdef CONFIG_CMD_NAND
    #define CONFIG_NAND_S3C2410
    #define CONFIG_SYS_S3C2410_NAND_HWECC
    #define CONFIG_SYS_MAX_NAND_DEVICE    1
    #define CONFIG_SYS_NAND_BASE        0x4E000000
    #endif
    
    /*
     * File system
     */
    #define CONFIG_CMD_UBI
    #define CONFIG_CMD_UBIFS
    #define CONFIG_CMD_MTDPARTS
    #define CONFIG_MTD_DEVICE
    #define CONFIG_MTD_PARTITIONS
    #define CONFIG_YAFFS2
    #define CONFIG_RBTREE
    
    /* additions for new relocation code, must be added to all boards */
    #define CONFIG_SYS_SDRAM_BASE    PHYS_SDRAM_1
    #define CONFIG_SYS_INIT_SP_ADDR    (CONFIG_SYS_SDRAM_BASE + 0x1000 - 
                    GENERATED_GBL_DATA_SIZE)
    
    #define CONFIG_BOARD_EARLY_INIT_F
    
    #endif /* __CONFIG_H */

    七、分析crt0.S(arch/arm/lib/crt0.S)

    这块代码也比较多,这里就一点一点的展示,并进行讲解。

    7.1 引入头文件

    这里首先是引入头文件:

    #include <config.h>
    #include <asm-offsets.h>
    #include <linux/linkage.h>
    #ifdef CONFIG_CPU_V7M
    #include <asm/armv7m.h>
    #endif

    然后接着,是作者对这个文件的一大堆介绍:

    /*
     * This file handles the target-independent stages of the U-Boot
     * start-up where a C runtime environment is needed. Its entry point
     * is _main and is branched into from the target's start.S file.
     *
     * _main execution sequence is:
     *
     * 1. Set up initial environment for calling board_init_f().
     *    This environment only provides a stack and a place to store
     *    the GD ('global data') structure, both located in some readily
     *    available RAM (SRAM, locked cache...). In this context, VARIABLE
     *    global data, initialized or not (BSS), are UNAVAILABLE; only
     *    CONSTANT initialized data are available. GD should be zeroed
     *    before board_init_f() is called.
     *
     * 2. Call board_init_f(). This function prepares the hardware for
     *    execution from system RAM (DRAM, DDR...) As system RAM may not
     *    be available yet, , board_init_f() must use the current GD to
     *    store any data which must be passed on to later stages. These
     *    data include the relocation destination, the future stack, and
     *    the future GD location.
     *
     * 3. Set up intermediate environment where the stack and GD are the
     *    ones allocated by board_init_f() in system RAM, but BSS and
     *    initialized non-const data are still not available.
     *
     * 4a.For U-Boot proper (not SPL), call relocate_code(). This function
     *    relocates U-Boot from its current location into the relocation
     *    destination computed by board_init_f().
     *
     * 4b.For SPL, board_init_f() just returns (to crt0). There is no
     *    code relocation in SPL.
     *
     * 5. Set up final environment for calling board_init_r(). This
     *    environment has BSS (initialized to 0), initialized non-const
     *    data (initialized to their intended value), and stack in system
     *    RAM (for SPL moving the stack and GD into RAM is optional - see
     *    CONFIG_SPL_STACK_R). GD has retained values set by board_init_f().
     *
     * 6. For U-Boot proper (not SPL), some CPUs have some work left to do
     *    at this point regarding memory, so call c_runtime_cpu_setup.
     *
     * 7. Branch to board_init_r().
     *
     * For more information see 'Board Initialisation Flow in README.
     */

    这里作者罗列了七条内容,这里我大致翻译一下:

    • 函数首先设置栈,然后在栈底预留一定的内存空间给gd_t结构体并清零,用来存放全局参数, 然后调用board_init_f();这里作者提到在当前上下文,已经初始化的全局变量(位于.data段)或者是未初始化的全局变量(位于.bss段)是无法访问到的,这主要是因为还没将代码从NAND或者NOR拷贝到SDRAM。
    • 调用board_init_f(),这个函数调用一系列函数来初始化硬件以使程序能够在SDRAM中执行,且这个函数需要使用设置好的gd_t结构体来存放初始化中的各个参数以备后用,比如:重定位地址,重定位后的栈地址、重定位后的gd_t的地址;
    • 由于bss段还没初始化,board_init_f()设置gd_t时不能使用全局变量、静态变量等,  所以设置的环境参数不是最终的;
    • smdk2410.h没有定义SPL,所以会在_main()函数中根据board_init_f()设置的重定位参数进行代码重定位;
    • 重定位后,bss和non-const data都被初始化了,在进入board_init_r()函数之前应先设置最终的环境参数;
    • 调用board_init_r()函数;

    7.2 初始化栈空间,栈底为gd_t全局变量预留内存空间

    /*
     * entry point of crt0 sequence
     */
    
    ENTRY(_main)
    
    /*
     * Set up initial C runtime environment and call board_init_f(0).
     */
    
    #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
        ldr sp, =(CONFIG_SPL_STACK)
    #else
        ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)    //1. 设置栈    0x30000f50
    #endif
    #if defined(CONFIG_CPU_V7M) /* v7M forbids using SP as BIC destination */
        mov r3, sp
        bic r3, r3, #7
        mov sp, r3
    #else
        bic sp, sp, #7  /* 8-byte alignment for ABI compliance */
    #endif
        mov r0, sp
        bl  board_init_f_alloc_reserve    //2. 为gd_t结构体保留空间
        mov sp, r0
        /* set up gd here, outside any C code */
        mov r9, r0
        bl  board_init_f_init_reserve    //3. 初始化gd_t(清零)
                        //gd_t的地址存在r9寄存器中,结构体中存放的是全局参数
    
        mov r0, #0
        bl  board_init_f           //4. 进入board_init_f进行各种初始化,分配SDRAM内存空间,填充进gd_t结构体中

    smdk2410.h文件中没有定义SPL,所以sp设置为CONFIG_SYS_INIT_SP_ADDR:    

    #define PHYS_SDRAM_1        0x30000000 /* SDRAM Bank #1 */
    #define CONFIG_SYS_SDRAM_BASE    PHYS_SDRAM_1
    #define CONFIG_SYS_INIT_SP_ADDR    (CONFIG_SYS_SDRAM_BASE + 0x1000 - 
                    GENERATED_GBL_DATA_SIZE)

    查找board_init_f_alloc_reserve函数,位于common/init/board_ibnit.c文件中:

    这里top传入的为sp的值,并在栈顶底预留了global_data结构体大小的数据,然后设置栈底为16字节对齐,同时将gd_t结构体的起始地址保存到r9寄存器。

    DECLARE_GLOBAL_DATA_PTR定义了一个gd_t全局数据结构的指针,这个指针存放在指定的寄存器r9中。这个声明也避免了编译器把r9分配给其他的变量,任何想要访问访问全局数据区的代码,只要代码开头加DECLARE_GLOBAL_DATA_PTR一行代码,然后就可以使用gd指针来访问全局数据区了。

    #define DECLARE_GLOBAL_DATA_PTR        register volatile gd_t *gd asm ("r9")

    u-boot启动内核时要给内核传递参数,这时就要使用gd_t,结构体中的信息来设置标记列表。

    查找board_init_f_init_reserve函数,该函数用于初始化gd_t内存空间为0。

    void board_init_f_init_reserve(ulong base)
    {
        struct global_data *gd_ptr;
    #ifndef _USE_MEMCPY
        int *ptr;
    #endif
    
        /*
         * clear GD entirely and set it up.
         * Use gd_ptr, as gd may not be properly set yet.
         */
    
        gd_ptr = (struct global_data *)base;
        /* zero the area */
    #ifdef _USE_MEMCPY
        memset(gd_ptr, '', sizeof(*gd));   #*gd大小0xa8
    #else
        for (ptr = (int *)gd_ptr; ptr < (int *)(gd_ptr + 1); )
            *ptr++ = 0;
    #endif
        /* set GD unless architecture did it already */
    #if !defined(CONFIG_ARM)
        arch_setup_gd(gd_ptr);
    #endif
        /* next alloc will be higher by one GD plus 16-byte alignment */
        base += roundup(sizeof(struct global_data), 16);
    
        /*
         * record early malloc arena start.
         * Use gd as it is now properly set for all architectures.
         */
    
    #if defined(CONFIG_SYS_MALLOC_F)
        /* go down one 'early malloc arena' */
        gd->malloc_base = base;
        /* next alloc will be higher by one 'early malloc arena' size */
        base += CONFIG_SYS_MALLOC_F_LEN;
    #endif
    }

    指定位置base作结构体gd的存放地。

    7.3 执行board_init_f()

    该函数位于common/board.c文件:

    void board_init_f(ulong boot_flags)
    {
    #ifdef CONFIG_SYS_GENERIC_GLOBAL_DATA
        /*
         * For some archtectures, global data is initialized and used before
         * calling this function. The data should be preserved. For others,
         * CONFIG_SYS_GENERIC_GLOBAL_DATA should be defined and use the stack
         * here to host global data until relocation.
         */
        gd_t data;
    
        gd = &data;
    
        /*
         * Clear global data before it is accessed at debug print
         * in initcall_run_list. Otherwise the debug print probably
         * get the wrong vaule of gd->have_console.
         */
        zero_global_data();
    #endif
    
        gd->flags = boot_flags;  #0x00
        gd->have_console = 0;    #0x00  
    
        if (initcall_run_list(init_sequence_f))
            hang();
    
    #if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && 
            !defined(CONFIG_EFI_APP)
        /* NOTREACHED - jump_to_copy() does not return */
        hang();
    #endif
    }

    填充了flags和have_console字段后就执行一个初始化列表循环,这个循环里面有很多的函数,只要其中一个出错,u-boot启动就会停止。

    initcall_run_list位于lib/initcall.c文件中:

    int initcall_run_list(const init_fnc_t init_sequence[])
    {
        const init_fnc_t *init_fnc_ptr;
    
        for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
            unsigned long reloc_ofs = 0;
            int ret;
    
            if (gd->flags & GD_FLG_RELOC)
                reloc_ofs = gd->reloc_off;
    #ifdef CONFIG_EFI_APP
            reloc_ofs = (unsigned long)image_base;
    #endif
            debug("initcall: %p", (char *)*init_fnc_ptr - reloc_ofs);
            if (gd->flags & GD_FLG_RELOC)
                debug(" (relocated to %p)
    ", (char *)*init_fnc_ptr);
            else
                debug("
    ");
            ret = (*init_fnc_ptr)();
            if (ret) {
                printf("initcall sequence %p failed at call %p (err=%d)
    ",
                       init_sequence,
                       (char *)*init_fnc_ptr - reloc_ofs, ret);
                return -1;
            }
        }
        return 0;
    }

    board_init_f(),这个函数调用一系列函数来初始化硬件以使程序能够在SDRAM中执行,且这个函数需要使用设置好的gd结构体来存放初始化中的各个参数以备后用,比如:重定位地址,重定位后的栈地址、重定位后的gd_t的地址。

    这里我们记录gd_t这个数据结构:

    typedef struct global_data {
        bd_t *bd;
        unsigned long flags;
        unsigned int baudrate;
        unsigned long cpu_clk;    /* CPU clock in Hz!        */
        unsigned long bus_clk;
        /* We cannot bracket this with CONFIG_PCI due to mpc5xxx */
        unsigned long pci_clk;
        unsigned long mem_clk;
    #if defined(CONFIG_LCD) || defined(CONFIG_VIDEO)
        unsigned long fb_base;    /* Base address of framebuffer mem */
    #endif
    #if defined(CONFIG_POST) || defined(CONFIG_LOGBUFFER)
        unsigned long post_log_word;  /* Record POST activities */
        unsigned long post_log_res; /* success of POST test */
        unsigned long post_init_f_time;  /* When post_init_f started */
    #endif
    #ifdef CONFIG_BOARD_TYPES
        unsigned long board_type;
    #endif
        unsigned long have_console;    /* serial_init() was called */
    #ifdef CONFIG_PRE_CONSOLE_BUFFER
        unsigned long precon_buf_idx;    /* Pre-Console buffer index */
    #endif
        unsigned long env_addr;    /* Address  of Environment struct */
        unsigned long env_valid;    /* Checksum of Environment valid? */
    
        unsigned long ram_top;    /* Top address of RAM used by U-Boot */
    
        unsigned long relocaddr;    /* Start address of U-Boot in RAM */
        phys_size_t ram_size;    /* RAM size */
    #ifdef CONFIG_SYS_MEM_RESERVE_SECURE
    #define MEM_RESERVE_SECURE_SECURED    0x1
    #define MEM_RESERVE_SECURE_MAINTAINED    0x2
    #define MEM_RESERVE_SECURE_ADDR_MASK    (~0x3)
        /*
         * Secure memory addr
         * This variable needs maintenance if the RAM base is not zero,
         * or if RAM splits into non-consecutive banks. It also has a
         * flag indicating the secure memory is marked as secure by MMU.
         * Flags used: 0x1 secured
         *             0x2 maintained
         */
        phys_addr_t secure_ram;
    #endif
        unsigned long mon_len;    /* monitor len */
        unsigned long irq_sp;        /* irq stack pointer */
        unsigned long start_addr_sp;    /* start_addr_stackpointer */
        unsigned long reloc_off;
        struct global_data *new_gd;    /* relocated global data */
    
    #ifdef CONFIG_DM
        struct udevice    *dm_root;    /* Root instance for Driver Model */
        struct udevice    *dm_root_f;    /* Pre-relocation root instance */
        struct list_head uclass_root;    /* Head of core tree */
    #endif
    #ifdef CONFIG_TIMER
        struct udevice    *timer;    /* Timer instance for Driver Model */
    #endif
    
        const void *fdt_blob;    /* Our device tree, NULL if none */
        void *new_fdt;        /* Relocated FDT */
        unsigned long fdt_size;    /* Space reserved for relocated FDT */
        struct jt_funcs *jt;        /* jump table */
        char env_buf[32];    /* buffer for getenv() before reloc. */
    #ifdef CONFIG_TRACE
        void        *trace_buff;    /* The trace buffer */
    #endif
    #if defined(CONFIG_SYS_I2C)
        int        cur_i2c_bus;    /* current used i2c bus */
    #endif
    #ifdef CONFIG_SYS_I2C_MXC
        void *srdata[10];
    #endif
        unsigned long timebase_h;
        unsigned long timebase_l;
    #ifdef CONFIG_SYS_MALLOC_F_LEN
        unsigned long malloc_base;    /* base address of early malloc() */
        unsigned long malloc_limit;    /* limit address */
        unsigned long malloc_ptr;    /* current address */
    #endif
    #ifdef CONFIG_PCI
        struct pci_controller *hose;    /* PCI hose for early use */
        phys_addr_t pci_ram_top;    /* top of region accessible to PCI */
    #endif
    #ifdef CONFIG_PCI_BOOTDELAY
        int pcidelay_done;
    #endif
        struct udevice *cur_serial_dev;    /* current serial device */
        struct arch_global_data arch;    /* architecture-specific data */
    #ifdef CONFIG_CONSOLE_RECORD
        struct membuff console_out;    /* console output */
        struct membuff console_in;    /* console input */
    #endif
    #ifdef CONFIG_DM_VIDEO
        ulong video_top;        /* Top of video frame buffer area */
        ulong video_bottom;        /* Bottom of video frame buffer area */
    #endif
    } gd_t;
    #endif
    
    /*
     * Global Data Flags - the top 16 bits are reserved for arch-specific flags
     */
    #define GD_FLG_RELOC        0x00001    /* Code was relocated to RAM       */
    #define GD_FLG_DEVINIT        0x00002    /* Devices have been initialized   */
    #define GD_FLG_SILENT        0x00004    /* Silent mode               */
    #define GD_FLG_POSTFAIL        0x00008    /* Critical POST test failed       */
    #define GD_FLG_POSTSTOP        0x00010    /* POST seqeunce aborted       */
    #define GD_FLG_LOGINIT        0x00020    /* Log Buffer has been initialized */
    #define GD_FLG_DISABLE_CONSOLE    0x00040    /* Disable console (in & out)       */
    #define GD_FLG_ENV_READY    0x00080    /* Env. imported into hash table   */
    #define GD_FLG_SERIAL_READY    0x00100    /* Pre-reloc serial console ready  */
    #define GD_FLG_FULL_MALLOC_INIT    0x00200    /* Full malloc() is ready       */
    #define GD_FLG_SPL_INIT        0x00400    /* spl_init() has been called       */
    #define GD_FLG_SKIP_RELOC    0x00800    /* Don't relocate */
    #define GD_FLG_RECORD        0x01000    /* Record console */
    
    #endif /* __ASM_GENERIC_GBL_DATA_H */

    7.4 init_sequence_f

    init_sequence_f是一个函数指针数组,里面存放着各种初始化的函数指针,其中大部分函数只有定义了指定了宏才会生效,后面会针对其中比较重要的函数进行一一介绍。

    static init_fnc_t init_sequence_f[] = {
    #ifdef CONFIG_SANDBOX
        setup_ram_buf,
    #endif
        setup_mon_len,
    #ifdef CONFIG_OF_CONTROL
        fdtdec_setup,
    #endif
    #ifdef CONFIG_TRACE
        trace_early_init,
    #endif
        initf_malloc,
        initf_console_record,
    #if defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx)
        /* TODO: can this go into arch_cpu_init()? */
        probecpu,
    #endif
    #if defined(CONFIG_X86) && defined(CONFIG_HAVE_FSP)
        x86_fsp_init,
    #endif
        arch_cpu_init,        /* basic arch cpu dependent setup */
        initf_dm,
        arch_cpu_init_dm,
        mark_bootstage,        /* need timer, go after init dm */
    #if defined(CONFIG_BOARD_EARLY_INIT_F)
        board_early_init_f,
    #endif
        /* TODO: can any of this go into arch_cpu_init()? */
    #if defined(CONFIG_PPC) && !defined(CONFIG_8xx_CPUCLK_DEFAULT)
        get_clocks,        /* get CPU and bus clocks (etc.) */
    #if defined(CONFIG_TQM8xxL) && !defined(CONFIG_TQM866M) 
            && !defined(CONFIG_TQM885D)
        adjust_sdram_tbs_8xx,
    #endif
        /* TODO: can we rename this to timer_init()? */
        init_timebase,
    #endif
    #if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || 
            defined(CONFIG_BLACKFIN) || defined(CONFIG_NDS32) || 
            defined(CONFIG_SPARC)
        timer_init,        /* initialize timer */
    #endif
    #ifdef CONFIG_SYS_ALLOC_DPRAM
    #if !defined(CONFIG_CPM2)
        dpram_init,
    #endif
    #endif
    #if defined(CONFIG_BOARD_POSTCLK_INIT)
        board_postclk_init,
    #endif
    #if defined(CONFIG_SYS_FSL_CLK) || defined(CONFIG_M68K)
        get_clocks,
    #endif
        env_init,        /* initialize environment */
    #if defined(CONFIG_8xx_CPUCLK_DEFAULT)
        /* get CPU and bus clocks according to the environment variable */
        get_clocks_866,
        /* adjust sdram refresh rate according to the new clock */
        sdram_adjust_866,
        init_timebase,
    #endif
        init_baud_rate,        /* initialze baudrate settings */
        serial_init,        /* serial communications setup */
        console_init_f,        /* stage 1 init of console */
    #ifdef CONFIG_SANDBOX
        sandbox_early_getopt_check,
    #endif
    #ifdef CONFIG_OF_CONTROL
        fdtdec_prepare_fdt,
    #endif
        display_options,    /* say that we are here */
        display_text_info,    /* show debugging info if required */
    #if defined(CONFIG_MPC8260)
        prt_8260_rsr,
        prt_8260_clks,
    #endif /* CONFIG_MPC8260 */
    #if defined(CONFIG_MPC83xx)
        prt_83xx_rsr,
    #endif
    #if defined(CONFIG_PPC) || defined(CONFIG_M68K)
        checkcpu,
    #endif
        print_cpuinfo,        /* display cpu info (and speed) */
    #if defined(CONFIG_MPC5xxx)
        prt_mpc5xxx_clks,
    #endif /* CONFIG_MPC5xxx */
    #if defined(CONFIG_DISPLAY_BOARDINFO)
        show_board_info,
    #endif
        INIT_FUNC_WATCHDOG_INIT
    #if defined(CONFIG_MISC_INIT_F)
        misc_init_f,
    #endif
        INIT_FUNC_WATCHDOG_RESET
    #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C)
        init_func_i2c,
    #endif
    #if defined(CONFIG_HARD_SPI)
        init_func_spi,
    #endif
        announce_dram_init,
        /* TODO: unify all these dram functions? */
    #if defined(CONFIG_ARM) || defined(CONFIG_X86) || defined(CONFIG_NDS32) || 
            defined(CONFIG_MICROBLAZE) || defined(CONFIG_AVR32)
        dram_init,        /* configure available RAM banks */
    #endif
    #if defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_M68K)
        init_func_ram,
    #endif
    #ifdef CONFIG_POST
        post_init_f,
    #endif
        INIT_FUNC_WATCHDOG_RESET
    #if defined(CONFIG_SYS_DRAM_TEST)
        testdram,
    #endif /* CONFIG_SYS_DRAM_TEST */
        INIT_FUNC_WATCHDOG_RESET
    
    #ifdef CONFIG_POST
        init_post,
    #endif
        INIT_FUNC_WATCHDOG_RESET
        /*
         * Now that we have DRAM mapped and working, we can
         * relocate the code and continue running from DRAM.
         *
         * Reserve memory at end of RAM for (top down in that order):
         *  - area that won't get touched by U-Boot and Linux (optional)
         *  - kernel log buffer
         *  - protected RAM
         *  - LCD framebuffer
         *  - monitor code
         *  - board info struct
         */
        setup_dest_addr,
    #if defined(CONFIG_BLACKFIN)
        /* Blackfin u-boot monitor should be on top of the ram */
        reserve_uboot,
    #endif
    #if defined(CONFIG_SPARC)
        reserve_prom,
    #endif
    #if defined(CONFIG_LOGBUFFER) && !defined(CONFIG_ALT_LB_ADDR)
        reserve_logbuffer,
    #endif
    #ifdef CONFIG_PRAM
        reserve_pram,
    #endif
        reserve_round_4k,
    #if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) && 
            defined(CONFIG_ARM)
        reserve_mmu,
    #endif
    #ifdef CONFIG_DM_VIDEO
        reserve_video,
    #else
    # ifdef CONFIG_LCD
        reserve_lcd,
    # endif
        /* TODO: Why the dependency on CONFIG_8xx? */
    # if defined(CONFIG_VIDEO) && (!defined(CONFIG_PPC) || defined(CONFIG_8xx)) && 
            !defined(CONFIG_ARM) && !defined(CONFIG_X86) && 
            !defined(CONFIG_BLACKFIN) && !defined(CONFIG_M68K)
        reserve_legacy_video,
    # endif
    #endif /* CONFIG_DM_VIDEO */
        reserve_trace,
    #if !defined(CONFIG_BLACKFIN)
        reserve_uboot,
    #endif
    #ifndef CONFIG_SPL_BUILD
        reserve_malloc,
        reserve_board,
    #endif
        setup_machine,
        reserve_global_data,
        reserve_fdt,
        reserve_arch,
        reserve_stacks,
        setup_dram_config,
        show_dram_config,
    #if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_MIPS)
        setup_board_part1,
    #endif
    #if defined(CONFIG_PPC) || defined(CONFIG_M68K)
        INIT_FUNC_WATCHDOG_RESET
        setup_board_part2,
    #endif
        display_new_sp,
    #ifdef CONFIG_SYS_EXTBDINFO
        setup_board_extra,
    #endif
        INIT_FUNC_WATCHDOG_RESET
        reloc_fdt,
        setup_reloc,
    #if defined(CONFIG_X86) || defined(CONFIG_ARC)
        copy_uboot_to_ram,
        clear_bss,
        do_elf_reloc_fixups,
    #endif
    #if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX)
        jump_to_copy,
    #endif
        NULL,
    };
    View Code

    函数指针类型:

    typedef int (*init_fnc_t)(void);

    由于这个数组太长了,下面列出定义函数(如何知道哪些函数被定义了呢,查看反汇编代码u-boot.map和u-boot.dis)

    然后我们打开u-boot.dis文件,找到init_sequence_f定义:

    0007217c <init_sequence_f>:
       7217c:    0000e70c     .word    0x0000e70c
       72180:    00014964     .word    0x00014964
       72184:    0000e894     .word    0x0000e894
       72188:    0000e72c     .word    0x0000e72c
       7218c:    0000e89c     .word    0x0000e89c
       72190:    0000e8ac     .word    0x0000e8ac
       72194:    0000ea78     .word    0x0000ea78
       72198:    00000fd8     .word    0x00000fd8
       7219c:    00000634     .word    0x00000634
       721a0:    00010610     .word    0x00010610
       721a4:    0000ea4c     .word    0x0000ea4c
       721a8:    0002ea38     .word    0x0002ea38
       721ac:    000144d0     .word    0x000144d0
       721b0:    0005a428     .word    0x0005a428
       721b4:    0000e704     .word    0x0000e704
       721b8:    000003b0     .word    0x000003b0
       721bc:    0000ea34     .word    0x0000ea34
       721c0:    000010e4     .word    0x000010e4
       721c4:    0000e9b4     .word    0x0000e9b4
       721c8:    0000e750     .word    0x0000e750
       721cc:    0000e768     .word    0x0000e768
       721d0:    0000e7a0     .word    0x0000e7a0
       721d4:    0000e7a8     .word    0x0000e7a8
       721d8:    0000e7d8     .word    0x0000e7d8
       721dc:    0000e97c     .word    0x0000e97c
       721e0:    0000e7ec     .word    0x0000e7ec
       721e4:    0000e7f4     .word    0x0000e7f4
       721e8:    0000e810     .word    0x0000e810
       721ec:    0000e8a4     .word    0x0000e8a4
       721f0:    0000e870     .word    0x0000e870
       721f4:    0000ea24     .word    0x0000ea24
       721f8:    0000e944     .word    0x0000e944
       721fc:    0000e88c     .word    0x0000e88c
       72200:    0000e908     .word    0x0000e908
       72204:    0000e8dc     .word    0x0000e8dc
       72208:    00000000     .word    0x00000000

    然后我们找到每个函数指针地址,就可以看到对应的函数,最终得到如下函数:

    /*虽然未定义的都删除了,但是还是有这么多*/
    static const init_fnc_t init_sequence_f[] = {
        setup_mon_len,
        initf_malloc,
        initf_console_record,
        arch_cpu_init,        /* basic arch cpu dependent setup */
        initf_dm,
        arch_cpu_init_dm,
    mark_bootstage,
    board_early_init_f, timer_init,
    /* initialize timer */ env_init, /* initialize environment */ init_baud_rate, /* initialze baudrate settings */ serial_init, /* serial communications setup */ console_init_f, display_options, display_text_info, print_cpuinfo, announce_dram_init, dram_init, /* configure available RAM banks *//* * Now that we have DRAM mapped and working, we can * relocate the code and continue running from DRAM. * * Reserve memory at end of RAM for (top down in that order): * - area that won't get touched by U-Boot and Linux (optional) * - kernel log buffer * - protected RAM * - LCD framebuffer * - monitor code * - board info struct */ setup_dest_addr, reserve_round_4k, reserve_mmu, reserve_trace, reserve_uboot, reserve_malloc, reserve_board, setup_machine, reserve_global_data, reserve_fdt, reserve_arch, reserve_stacks, setup_dram_config, show_dram_config, display_new_sp, reloc_fdt, setup_reloc, NULL, };

    参考文章:

    [1]U-BOOT-2016.07移植 (第一篇) 初步分析

    [2]uboot启动 -- uboot基本启动流程

    [3]从零开始之uboot、移植uboot2017.01(五、board_init_f分析)

    [4]u-boot2020.04移植(4、board_init_f)

    [5]U-boot源码阅读-使用u-boot.map定位函数位置

  • 相关阅读:
    P3 创建项目(下)
    P2 创建项目(中)
    P1 创建项目(上)
    ASP.NET Core 3.x 入门视频(完结)
    网易云微专业《职场人必学的Python技能课》
    01.Python配置与运行
    阶段一-03.地址,订单,支付,定时任务开发-第1章 收货地址功能开发-1-6 收货地址
    ASYNC PROGRAMING IN JAVASCRIPT[转]
    Bluebird-NodeJs的Promise
    理解Nodejs的Event Loop
  • 原文地址:https://www.cnblogs.com/zyly/p/14855319.html
Copyright © 2020-2023  润新知