zoukankan      html  css  js  c++  java
  • 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定位函数位置

  • 相关阅读:
    Truck History(poj 1789)
    Highways poj 2485
    117. Populating Next Right Pointers in Each Node II
    116. Populating Next Right Pointers in Each Node
    115. Distinct Subsequences
    114. Flatten Binary Tree to Linked List
    113. Path Sum II
    109. Convert Sorted List to Binary Search Tree
    106. Construct Binary Tree from Inorder and Postorder Traversal
    105. Construct Binary Tree from Preorder and Inorder Traversal
  • 原文地址:https://www.cnblogs.com/zyly/p/14855319.html
Copyright © 2011-2022 走看看