瑞芯微Rockchip开发者社区
直播中

一曲作罢

10年用户 958经验值
擅长:可编程逻辑 电源/新能源 MEMS/传感技术
私信 关注
[问答]

如何对RK1808 uboot及其makefile的编译进行分析呢

如何对RK1808 uboot的编译进行分析呢?
如何对RK1808  makefile的编译进行分析呢?



回帖(2)

王秀云

2022-2-15 10:00:59
为了更深入了解rk1808 sdk,对其中关于uboot部分的脚本和makefile等做一个分析


主要参考文件:Rockchip_Developer_Guide_Linux_Software_CN.pdf


uboot的编译
根据文档的说法,编译uboot有两种方法


在uboot目录下编译
这种方法,先cd到uboot目录下,然后执行


sudo ./make.sh rk1808


在顶层目录下编译
这种方法,利用底层目录的build.sh,传递参数uboot进行编译


sudo ./build.sh uboot


其实利用build.sh脚本,实际上也是cd到uboot目录下,去调用make.sh脚本进行编译,因此这两种方式其实可以认为是一种,那要想弄清楚来龙去脉,就得先分析build.sh脚本


build.sh分析
直接跳到末尾,有这样一段话,首先判断是不是需要打印usage,如果不是,然后再对输入的参数,也就是$@进行遍历,并判断它是什么


例如我这样输入sudo ./build.sh uboot,在下面的case分支语句中,就会进入eval build_$option || usage,这个意思是||前能执行,就去执行,不能执行,就打印usage


#=========================
# build targets
#=========================


if echo $@|grep -wqE "help|-h"; then
        usage
        exit 0
fi


OPTIONS="$@"
for option in ${OPTIONS:-allsave}; do
        echo "processing option: $option"
        case $option in
                BoardConfig*.mk)
            option=$TOP_DIR/device/rockchip/$RK_TARGET_PRODUCT/$option
            ;&  
        *.mk)
            CONF=$(realpath $option)
            echo "switching to board: $CONF"
            if [ ! -f $CONF ]; then
                echo "not exist!"
                exit 1
            fi  
                        ln -sf $CONF $BOARD_CONFIG
                        ;;  
                buildroot|debian|distro|yocto)
            build_rootfs $option
            ;;  
                recovery)
            build_kernel
            ;&  
        *)  
            eval build_$option || usage
            ;;  
        esac
done


再往上看,可以找到编译uboot的函数,它首先删除了一个loader什么的bin文件,据说是用于初始化ddr的,这个暂时没太想明白


然后cd到uboot的目录下,执行./make.sh rk1808,它这个参数$RK_UBOOT_DEFCONFIG通过打印可以很清楚地知道,其实就是rk1808,然后判断上一个命令的退出状态,来确定执行成功与否


接下来就是分析make.sh了


function build_uboot(){
        echo "============Start build uboot============"
        echo "TARGET_UBOOT_CONFIG=$RK_UBOOT_DEFCONFIG"
        echo "========================================="
        if [ -f u-boot/*_loader_*.bin ]; then
                rm u-boot/*_loader_*.bin
        fi
        cd u-boot && ./make.sh $RK_UBOOT_DEFCONFIG && cd -
        if [ $? -eq 0 ]; then
                echo "====Build uboot ok!===="
        else
                echo "====Build uboot failed!===="
                exit 1
        fi
}
make.sh
这个脚本比刚才的复杂的多,因为瑞星微的sdk是针对所有产品的,一份sdk可以编译出多款芯片的镜像文件,所以这个makefile、编译脚本等都很复杂,但是我们只要抽丝剥茧,抓住核心即可


还是老规矩,直接跳到末尾,看它调用了哪些函数


prepare
select_toolchain
select_chip_info
fixup_platform_configure
sub_commands
make CROSS_COMPILE=${TOOLCHAIN_GCC}  all --jobs=${JOB} ${OUTOPT}
pack_uboot_image
pack_loader_image
pack_trust_image
finish     


prepare
prepare()
{
        local absolute_path cmd dir count


        # Parse output directory 'O='
        cmd=${OUTDIR%=*}
        `if [ "${cmd}" = 'O' ]; then`
        OUTDIR=${OUTDIR#*=}
        OUTOPT=O=${OUTDIR}
        else
                case $BOARD in
            # Parse from exit .config
            ''|elf*|loader*|spl*|itb|debug*|trust|uboot|map|sym)
                count=`find -name .config | wc -l`
                dir=`find -name .config`
                # Good, find only one .config
                if [ $count -eq 1 ]; then
                    dir=${dir%/*}
                    OUTDIR=${dir#*/}
                    # Set OUTOPT if not current directory
                    if [ $OUTDIR != '.' ]; then
                        OUTOPT=O=${OUTDIR}
                    fi
                elif [ $count -eq 0 ]; then
                    echo
                    echo "Build failed, Can't find .config"
                    help
                    exit 1
                else
                    echo
                    echo "Build failed, find $count '.config': "
                    echo "$dir"
                    echo "Please leave only one of them"
                    exit 1
                fi
                ;;
            *)
                OUTDIR=.
                ;;
                esac
        fi


    # Parse help and make defconfig
    case $BOARD in
            #Help
            --help|-help|help|--h|-h)
                            help
                    exit 0
                        ;;


            #Subcmd
        ''|elf*|loader*|spl*|itb|debug*|trust*|uboot|map|sym)
            ;;


                *)
            #Func address is valid ?
            if [ -z $(echo ${FUNCADDR} | sed 's/[0-9,a-f,A-F,x,X,-]//g') ]; then
                    return
            elif [ ! -f configs/${BOARD}_defconfig ]; then
                echo
                echo "Can't find: configs/${BOARD}_defconfig"
                echo
                echo "******** Rockchip Support List *************"
                echo "${SUPPORT_LIST}"
                echo "********************************************"
                echo
                exit 1
            else
                    echo "make for ${BOARD}_defconfig by -j${JOB}"
                            make ${BOARD}_defconfig ${OUTOPT}
            fi
                        ;;
        esac
       
    # Initialize RKBIN
    if [ -d ${RKBIN_TOOLS} ]; then
            absolute_path=$(cd `dirname ${RKBIN_TOOLS}`; pwd)
            RKBIN=${absolute_path}
    else
        echo
        echo "Can't find '../rkbin/' repository, please download it before pack image!"
        echo "How to obtain? 3 ways:"
        echo "  1. Login your Rockchip gerrit account: "Projects" -> "List" -> search "rk/rkbin" repository"
        echo "  2. Github repository: https://github.com/rockchip-linux/rkbin"
        echo "  3. Download full release SDK repository"
        exit 1
    fi
}


这个函数很长,首先出现了几个变量,然后先看分析第一段# Parse output directory 'O='


BOARD=$1
OUTDIR=$2
OUTOPT=


我们传进来的$1是rk1808,后面两个OUT都是空,因此,不会进入if [ "${cmd}" = 'O' ]; then这个条件里面


进到第二个条件后,会去遍历我们传进来的参数 $1,也就是BOARD,然后第一个case条件是''|elf*|loader*|spl*|itb|debug*|trust|uboot|map|sym)很明显rk1808不满足这个,所以会执行末尾的*),这个条件里面,只做了一件事,那就是OUTDIR=.


然后分析第二段,# Parse help and make defconfig


可以看到注释的help和subcmd仍然是不会被执行的,所以直接看Func address is valid ?部分


这个if条件的结果,是rk,不为空,所以不会return


然后判断configs/rk1808_defconfig这个默认配置文件在不在


最后唯一有用的部分,就是执行make ${BOARD}_defconfig ${OUTOPT},也就是make rk1808_defconfig .


这句话的作用是从configs中拷贝配置文件到当前目录下


case $BOARD in                                                                                                                                            
        #Help
        --help|-help|help|--h|-h)
        help
        exit 0
        ;;  


        #Subcmd
        ''|elf*|loader*|spl*|itb|debug*|trust*|uboot|map|sym)
        ;;  


                *)  
        #Func address is valid ?
        if [ -z $(echo ${FUNCADDR} | sed 's/[0-9,a-f,A-F,x,X,-]//g') ]; then
                return
        elif [ ! -f configs/${BOARD}_defconfig ]; then
                echo
                echo "Can't find: configs/${BOARD}_defconfig"
                echo
                echo "******** Rockchip Support List *************"
                echo "${SUPPORT_LIST}"
                echo "********************************************"
                echo
                exit 1
        else
                echo "make for ${BOARD}_defconfig by -j${JOB}"
                make ${BOARD}_defconfig ${OUTOPT}
        fi  
        ;;  
esac


然后分析第三段# Initialize RKBIN


在uboot的同级目录下,有个rkbin目录,编译uboot时需要用到这里面的bin文件,这里就是为了将它的绝对路径赋值给RKBIN


# Initialize RKBIN                                                                                                                                       
if [ -d ${RKBIN_TOOLS} ]; then
        absolute_path=$(cd `dirname ${RKBIN_TOOLS}`; pwd)
        RKBIN=${absolute_path}
else   
        echo   
        echo "Can't find '../rkbin/' repository, please download it before pack image!"
        echo "How to obtain? 3 ways:"
        echo "  1. Login your Rockchip gerrit account: "Projects" -> "List" -> search "rk/rkbin" repository"
        echo "  2. Github repository: https://github.com/rockchip-linux/rkbin"
        echo "  3. Download full release SDK repository"
        exit 1  
fi


select_toolchain
根据当前目录下的.config文件,判断是否有CONFIG_ARM64=y,然后给TOOLCHAIN_GCC等变量赋一个绝对路径


select_toolchain()
{
    local absolute_path


    if grep  -q '^CONFIG_ARM64=y' ${OUTDIR}/.config ; then
        if [ -d ${TOOLCHAIN_ARM64} ]; then
            absolute_path=$(cd `dirname ${TOOLCHAIN_ARM64}`; pwd)
            TOOLCHAIN_GCC=${absolute_path}/bin/${GCC_ARM64}
            TOOLCHAIN_OBJDUMP=${absolute_path}/bin/${OBJ_ARM64}
            TOOLCHAIN_ADDR2LINE=${absolute_path}/bin/${ADDR2LINE_ARM64}
        else
            echo "Can't find toolchain: ${TOOLCHAIN_ARM64}"
            exit 1
        fi  
    else
        if [ -d ${TOOLCHAIN_ARM32} ]; then
            absolute_path=$(cd `dirname ${TOOLCHAIN_ARM32}`; pwd)
            TOOLCHAIN_GCC=${absolute_path}/bin/${GCC_ARM32}
            TOOLCHAIN_OBJDUMP=${absolute_path}/bin/${OBJ_ARM32}
            TOOLCHAIN_ADDR2LINE=${absolute_path}/bin/${ADDR2LINE_ARM32}
        else
            echo "Can't find toolchain: ${TOOLCHAIN_ARM32}"
            exit 1
        fi  
    fi  


    # echo "toolchain: ${TOOLCHAIN_GCC}"
}
举报

李妍

2022-2-15 10:01:05
select_chip_info
这个函数个人感觉不怎么重要,所以代码就不贴了,它的作用也是从.config读取一些信息,然后给以下变量赋值


RKCHIP_LABEL、RKCHIP_LOADER、RKCHIP_TRUST


fixup_platform_configure
这个函数也没什么意思,也是在赋值


PLATFORM_RSA="--rsa 3"
PLATFORM_UBOOT_IMG_SIZE="--size 1024 2"
PLATFORM_TRUST_IMG_SIZE="--size 1024 2"


sub_commands
说实话我没看懂他要干啥


make
make CROSS_COMPILE=${TOOLCHAIN_GCC}  all --jobs=${JOB} ${OUTOPT}


这个其实就没啥好说的了,那个jobs是编译所用的线程数,output应该是生成文件的路径,默认是空的


最终是生成u-boot.img u-boot-dtb.img u-boot.bin u-boot-dtb.bin等文件


pack_uboot_image
打包uboot前,先检查u-boot.bin的大小,超过10M,就报错了


# Check file size
    UBOOT_KB=`ls -l u-boot.bin | awk '{print $5}'`
    if [ "$PLATFORM_UBOOT_IMG_SIZE" = "" ]; then
        UBOOT_MAX_KB=1046528
    else
        UBOOT_MAX_KB=`echo $PLATFORM_UBOOT_IMG_SIZE | awk '{print strtonum($2)}'`
        UBOOT_MAX_KB=$(((UBOOT_MAX_KB-HEAD_KB)*1024))
    fi  


    if [ $UBOOT_KB -gt $UBOOT_MAX_KB ]; then
        echo   
        echo "ERROR: pack uboot failed! u-boot.bin actual: $UBOOT_KB bytes, max limit: $UBOOT_MAX_KB bytes"
        exit 1  
    fi
最终在当前目录下,生成了uboot.img,并删除了其它的img结尾的中间文件


# Pack image
    UBOOT_LOAD_ADDR=`sed -n "/CONFIG_SYS_TEXT_BASE=/s/CONFIG_SYS_TEXT_BASE=//p" ${OUTDIR}/include/autoconf.mk|tr -d 'r'`
    if [ ! $UBOOT_LOAD_ADDR ]; then
        UBOOT_LOAD_ADDR=`sed -n "/CONFIG_SYS_TEXT_BASE=/s/CONFIG_SYS_TEXT_BASE=//p" ${OUTDIR}/.config|tr -d 'r'`
    fi


    ${RKTOOLS}/loaderimage --pack --uboot ${OUTDIR}/u-boot.bin uboot.img ${UBOOT_LOAD_ADDR} ${PLATFORM_UBOOT_IMG_SIZE}                                                        


    # Delete u-boot.img and u-boot-dtb.img, which makes users not be confused with final uboot.img
    if [ -f ${OUTDIR}/u-boot.img ]; then
        rm ${OUTDIR}/u-boot.img
    fi


    if [ -f ${OUTDIR}/u-boot-dtb.img ]; then
        rm ${OUTDIR}/u-boot-dtb.img
    fi
    echo "pack uboot okay! Input: ${OUTDIR}/u-boot.bin"


pack_loader_image
这一步最终生成这个文件rk1808_loader_v1.04.105.bin,并拷贝到当前目录下


pack_trust_image
这一步生成trust.img,这是arm搞的一个跟安全有关的东西Trustzone,大致是为了保护内存中的数据不被别人窃取之类的


finish
最后一步就是打印一点信息,就ok了


总结
从结果来看,执行make.sh一共得到了以下几个东西


uboot.img
rk1808_loader_v1.04.105.bin
trust.img
我们烧录的时候,是在顶层目录的rockdev去取镜像文件,在linux下,可以很清晰得看到链接的关系,所生成的这三个文件,都会被链接到


boot.img -> ../kernel/boot.img
MiniLoaderAll.bin -> ../u-boot/rk1808_loader_v1.04.105.bin
misc.img -> ../device/rockchip/rockimg/wipe_all-misc.img
oem.img
parameter.txt -> ../device/rockchip/rk1808/parameter-buildroot.txt
recovery.img -> ../buildroot/output/rockchip_rk1808_recovery/images/recovery.img
rootfs.ext4 -> ../buildroot/output/rockchip_rk1808/images/rootfs.ext2
rootfs.img -> ../buildroot/output/rockchip_rk1808/images/rootfs.ext2
trust.img -> ../u-boot/trust.img
uboot.img -> ../u-boot/uboot.img
update.img
userdata.img


除此之外,如果希望自己修改一些uboot的内容,可以通过类似内核的make menuconfig取修改.config文件,不过注意修改完了,一定要记得将该文件写回原来的位置,就是那个默认的deconfig所在的位置,否则每次编译,当前目录下的.config都会被configs目录下的xxx_deconfig覆盖掉。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分